From 5029c85a46a8c366c4bf272d503e22bbcd624ece Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 9 Oct 2008 13:29:12 +0100 Subject: [PATCH 0001/1776] Initial import --- AUTHORS | 1 + COPYING | 481 +++++++ COPYING.LIB | 481 +++++++ ChangeLog | 0 Makefile.am | 32 + NEWS | 1 + README | 18 + RELEASE | 0 REQUIREMENTS | 3 + TODO | 4 + autogen.sh | 103 ++ common/ChangeLog | 1041 ++++++++++++++ common/Makefile.am | 15 + common/c-to-xml.py | 34 + common/check.mak | 149 ++ common/coverage/coverage-report-entry.pl | 70 + common/coverage/coverage-report.pl | 125 ++ common/coverage/coverage-report.xsl | 235 +++ common/coverage/lcov.mak | 29 + common/gettext.patch | 23 + common/glib-gen.mak | 42 + common/gst-autogen.sh | 308 ++++ common/gst-xmlinspect.py | 168 +++ common/gst.supp | 1660 ++++++++++++++++++++++ common/gstdoc-scangobj | 1562 ++++++++++++++++++++ common/gtk-doc-plugins.mak | 358 +++++ common/gtk-doc.mak | 260 ++++ common/m4/Makefile.am | 28 + common/m4/README | 3 + common/m4/as-ac-expand.m4 | 43 + common/m4/as-auto-alt.m4 | 50 + common/m4/as-compiler-flag.m4 | 33 + common/m4/as-compiler.m4 | 44 + common/m4/as-docbook.m4 | 66 + common/m4/as-libtool-tags.m4 | 83 ++ common/m4/as-libtool.m4 | 45 + common/m4/as-python.m4 | 152 ++ common/m4/as-scrub-include.m4 | 36 + common/m4/as-version.m4 | 71 + common/m4/ax_create_stdint_h.m4 | 569 ++++++++ common/m4/check.m4 | 181 +++ common/m4/glib-gettext.m4 | 380 +++++ common/m4/gst-arch.m4 | 123 ++ common/m4/gst-args.m4 | 276 ++++ common/m4/gst-check.m4 | 138 ++ common/m4/gst-debuginfo.m4 | 46 + common/m4/gst-default.m4 | 45 + common/m4/gst-doc.m4 | 148 ++ common/m4/gst-error.m4 | 71 + common/m4/gst-feature.m4 | 285 ++++ common/m4/gst-function.m4 | 63 + common/m4/gst-gettext.m4 | 21 + common/m4/gst-glib2.m4 | 26 + common/m4/gst-libxml2.m4 | 43 + common/m4/gst-plugindir.m4 | 17 + common/m4/gst-valgrind.m4 | 35 + common/m4/gtk-doc.m4 | 53 + common/m4/pkg.m4 | 131 ++ common/mangle-tmpl.py | 155 ++ common/plugins.xsl | 200 +++ common/po.mak | 4 + common/release.mak | 25 + common/scangobj-merge.py | 226 +++ common/upload.mak | 33 + configure.ac | 222 +++ docs/design/gst-rtp-server-design | 35 + gst-rtsp.spec.in | 54 + m4/Makefile.am | 18 + m4/codeset.m4 | 23 + src/Makefile.am | 20 + src/main.c | 43 + src/rtsp-client.c | 811 +++++++++++ src/rtsp-client.h | 89 ++ src/rtsp-media.c | 266 ++++ src/rtsp-media.h | 79 + src/rtsp-server.c | 232 +++ src/rtsp-server.h | 86 ++ src/rtsp-session-pool.c | 165 +++ src/rtsp-session-pool.h | 69 + src/rtsp-session.c | 503 +++++++ src/rtsp-session.h | 138 ++ 81 files changed, 14004 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 COPYING.LIB create mode 100644 ChangeLog create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 RELEASE create mode 100644 REQUIREMENTS create mode 100644 TODO create mode 100755 autogen.sh create mode 100644 common/ChangeLog create mode 100644 common/Makefile.am create mode 100644 common/c-to-xml.py create mode 100644 common/check.mak create mode 100644 common/coverage/coverage-report-entry.pl create mode 100644 common/coverage/coverage-report.pl create mode 100644 common/coverage/coverage-report.xsl create mode 100644 common/coverage/lcov.mak create mode 100644 common/gettext.patch create mode 100644 common/glib-gen.mak create mode 100644 common/gst-autogen.sh create mode 100644 common/gst-xmlinspect.py create mode 100644 common/gst.supp create mode 100755 common/gstdoc-scangobj create mode 100644 common/gtk-doc-plugins.mak create mode 100644 common/gtk-doc.mak create mode 100644 common/m4/Makefile.am create mode 100644 common/m4/README create mode 100644 common/m4/as-ac-expand.m4 create mode 100644 common/m4/as-auto-alt.m4 create mode 100644 common/m4/as-compiler-flag.m4 create mode 100644 common/m4/as-compiler.m4 create mode 100644 common/m4/as-docbook.m4 create mode 100644 common/m4/as-libtool-tags.m4 create mode 100644 common/m4/as-libtool.m4 create mode 100644 common/m4/as-python.m4 create mode 100644 common/m4/as-scrub-include.m4 create mode 100644 common/m4/as-version.m4 create mode 100644 common/m4/ax_create_stdint_h.m4 create mode 100644 common/m4/check.m4 create mode 100644 common/m4/glib-gettext.m4 create mode 100644 common/m4/gst-arch.m4 create mode 100644 common/m4/gst-args.m4 create mode 100644 common/m4/gst-check.m4 create mode 100644 common/m4/gst-debuginfo.m4 create mode 100644 common/m4/gst-default.m4 create mode 100644 common/m4/gst-doc.m4 create mode 100644 common/m4/gst-error.m4 create mode 100644 common/m4/gst-feature.m4 create mode 100644 common/m4/gst-function.m4 create mode 100644 common/m4/gst-gettext.m4 create mode 100644 common/m4/gst-glib2.m4 create mode 100644 common/m4/gst-libxml2.m4 create mode 100644 common/m4/gst-plugindir.m4 create mode 100644 common/m4/gst-valgrind.m4 create mode 100644 common/m4/gtk-doc.m4 create mode 100644 common/m4/pkg.m4 create mode 100644 common/mangle-tmpl.py create mode 100644 common/plugins.xsl create mode 100644 common/po.mak create mode 100644 common/release.mak create mode 100755 common/scangobj-merge.py create mode 100644 common/upload.mak create mode 100644 configure.ac create mode 100644 docs/design/gst-rtp-server-design create mode 100644 gst-rtsp.spec.in create mode 100644 m4/Makefile.am create mode 100644 m4/codeset.m4 create mode 100644 src/Makefile.am create mode 100644 src/main.c create mode 100644 src/rtsp-client.c create mode 100644 src/rtsp-client.h create mode 100644 src/rtsp-media.c create mode 100644 src/rtsp-media.h create mode 100644 src/rtsp-server.c create mode 100644 src/rtsp-server.h create mode 100644 src/rtsp-session-pool.c create mode 100644 src/rtsp-session-pool.h create mode 100644 src/rtsp-session.c create mode 100644 src/rtsp-session.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000..ecef28eff3 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Wim Taymans diff --git a/COPYING b/COPYING new file mode 100644 index 0000000000..eb685a5ec9 --- /dev/null +++ b/COPYING @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, 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 library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + 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 Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, 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 or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the 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 a program 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. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + 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, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile 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) 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. + + c) 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. + + d) 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 source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000000..eb685a5ec9 --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, 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 library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + 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 Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, 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 or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the 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 a program 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. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + 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, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile 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) 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. + + c) 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. + + d) 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 source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000000..289f1620be --- /dev/null +++ b/Makefile.am @@ -0,0 +1,32 @@ +DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc + +SUBDIRS = \ + src \ + m4 \ + common + +DIST_SUBDIRS = $(SUBDIRS) + +EXTRA_DIST = \ + ChangeLog autogen.sh depcomp \ + AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \ + gst-rtsp.spec docs/design/gst-rtp-server-design + +ACLOCAL_AMFLAGS = -I common/m4 -I m4 + +DISTCLEANFILES = _stdint.h gst-rtsp.spec + +include $(top_srcdir)/common/release.mak +include $(top_srcdir)/common/po.mak + +check-valgrind: + cd tests/check && make check-valgrind + +if HAVE_CHECK +check-torture: + cd tests/check && make torture +else +check-torture: + true +endif + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000000..6abbfaa4e2 --- /dev/null +++ b/NEWS @@ -0,0 +1 @@ +This is GstRTSP diff --git a/README b/README new file mode 100644 index 0000000000..a785c592c8 --- /dev/null +++ b/README @@ -0,0 +1,18 @@ +GstRTSP is an RTSP server built on top of GStreamer (http://gstreamer.net). + +Currently there is no configuration tools for this server so any streamed +files need to be hardcoded into the file: +src/rtsp-media.c + +Edit in your sources after the examples found under the section headlines by +* STREAMING CONFIGURATION + +Once the server is started you should be able to view the streams at: +rtsp://localhost:1554/@name_of_stream@ + +The replacement for @name_of_stream@ is from the rtsp-media.c editing you did above. + +You should be able to get the http proxy link working without any editing of the rtsp-media.c file as it points to an online http file: + +rtsp://localhost:1554/rtphttpproxy + diff --git a/RELEASE b/RELEASE new file mode 100644 index 0000000000..e69de29bb2 diff --git a/REQUIREMENTS b/REQUIREMENTS new file mode 100644 index 0000000000..14e4172e5e --- /dev/null +++ b/REQUIREMENTS @@ -0,0 +1,3 @@ +You need to have GStreamer. You can use an installed version of +GStreamer or from its build dir. + diff --git a/TODO b/TODO new file mode 100644 index 0000000000..1b28c23ea5 --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ + + - implement multicast and TCP transports + - use a config file to configure the server + - error recovery diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000000..0a8c579abe --- /dev/null +++ b/autogen.sh @@ -0,0 +1,103 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +DIE=0 +package=gst-rtsp +srcfile=src/rtsp-server.c + +# a quick cvs co to ease the transition +if test ! -d common; +then + echo "+ getting common/ from cvs" + if test -e CVS/Tag + then + TAG="-r `tail -c +2 CVS/Tag`" + fi + cvs co $TAG common +fi + +# source helper functions +if test ! -f common/gst-autogen.sh; +then + echo There is something wrong with your source tree. + echo You are missing common/gst-autogen.sh + exit 1 +fi +. common/gst-autogen.sh + +CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc' + +autogen_options $@ + +echo -n "+ check for build tools" +if test ! -z "$NOCHECK"; then echo ": skipped version checks"; else echo; fi +version_check "autoconf" "$AUTOCONF autoconf autoconf259 autoconf257 autoconf-2.54 autoconf-2.53 autoconf253 autoconf-2.52 autoconf252" \ + "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 52 || DIE=1 +version_check "automake" "$AUTOMAKE automake automake-1.9 automake19 automake-1.8 automake18 automake-1.7 automake17 automake-1.6 automake16" \ + "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 libtoolize15 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 + +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 + +toplevel_check $srcfile + +tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS" +tool_run "$libtoolize" "--copy --force" +tool_run "$autoheader" + +# touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode -- wingo +echo timestamp > stamp-h.in 2> /dev/null + +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 +} diff --git a/common/ChangeLog b/common/ChangeLog new file mode 100644 index 0000000000..8f8b8537fd --- /dev/null +++ b/common/ChangeLog @@ -0,0 +1,1041 @@ +2007-09-21 Sebastian Dröge + + * m4/gst-args.m4: + Let the AG_GST_ARG_ENABLE_EXPERIMENTAL macro default to disable + building of experimental plugins. Nobody uses it yet and the + --enable--experimental stuff from gst-plugins-good defaults to + disable too. + +2007-09-06 Tim-Philipp Müller + + * gtk-doc-plugins.mak: + Just use the normal 'check' target and avoid a circular + dependency. + +2007-09-06 Tim-Philipp Müller + + * gtk-doc-plugins.mak: + Add rule to error out if .hierarchy file contains tabs. + +2007-08-20 Tim-Philipp Müller + + * download-translations: + * po.mak: + If there are new languages, they need to be added to po/LINGUAS. + +2007-08-20 Tim-Philipp Müller + + * download-translations: + * po.mak: + Fix up 'download-po' a bit, so that we find new translations + for languages that aren't in our po/LINGUAS file yet too. + +2007-07-16 Jan Schmidt + + * gst.supp: + Add a suppression for GLib caching the tmp dir seen on an + Ubuntu Feisty system. + +2007-07-13 Jan Schmidt + + * m4/gst-feature.m4: + If we want to use 'echo -e', call /bin/echo instead of the shell's + since -e is a bash extension, and our /bin/sh might not be being + provided by bash. + +2007-07-01 Thomas Vander Stichele + + * po.mak: + Translation project has moved. Also, no idea how this used to + work given that we weren't downloading a .po file. + +2007-06-25 Stefan Kost + + * gst-xmlinspect.py: + * plugins.xsl: + Also extract element caps for plugin-docs. Fixes parts of #117692. + +2007-06-21 Tim-Philipp Müller + + Patch by: Andreas Schwab + + * m4/gst-feature.m4: + Fix quoting (#449493). + +2007-06-10 Sebastian Dröge + + * m4/gst-parser.m4: + Only generate the parser if bison >= 1.875 _and_ flex >= 2.5.31 is + installed and use pre-generated sources otherwise. Fixes bug #444820. + +2007-05-11 Michael Smith + + * gst.supp: + Suppression variant for our good friend the TLS leak, this time for + Ubuntu Feisty/x86. + +2007-05-09 Tim-Philipp Müller + + * gtk-doc-plugins.mak: + Fix make distcheck again; change some spaces to tabs in makefile. + +2007-04-29 Thomas Vander Stichele + + * gtk-doc-plugins.mak (-module): + Error out when the html build step gives warnings, so they get + fixed properly. + +2007-04-23 Stefan Kost + + * m4/gst-feature.m4: + Add macro AG_GST_PARSE_SUBSYSTEM_DISABLES that checks the defines in + the configuration header and AC_DEFINES the setings. + +2007-04-19 Sebastian Dröge + + Patch by: Vincent Torri + + * m4/gst-parser.m4: + Put the AC_MSG_RESULT output in brackets to get it properly written to + the terminal. + +2007-04-18 Sebastian Dröge + + * m4/gst-parser.m4: + Check for flex >= 2.5.31 and set GENERATE_PARSER if we have at least + that version. Otherwise use pre-generated parser sources as we can't + raise the required flex version. HAVE_MT_SAVE_FLEX is obsolete now + as we use a new enough flex version anyway. First part of #349180 + +2007-04-10 Thomas Vander Stichele + + * m4/gst-check.m4: + Allow pre-setting the GST(PB)_TOOLS/PLUGINS_DIR variables to help + builds against older GStreamer. + +2007-03-25 Sebastian Dröge + + * m4/gst-parser.m4: + Fix the flex version check. It ignored the micro version before. + +2007-03-09 Jan Schmidt + + * check.mak: + Use the same timeout when generating valgrind suppressions as + running the valgrind test. + + * gst.supp: + Add some more suppressions and stuff. + +2007-03-08 Jan Schmidt + + * check.mak: + Make sure GSlice is disabled when building suppressions too. + + * gst.supp: + Add around *850* lines of suppressions for one-time initialisations + inside libasound and gconf/bonobo/ORBit. I feel so dirty. + +2007-03-07 Jan Schmidt + + * gst.supp: + add a suppression for this GConf flup on the FC5 buildbot. + +2007-03-06 Jan Schmidt + + * gst.supp: + Make the suppression a little more generic, to catch the FC5 + backtrace too. + +2007-03-06 Jan Schmidt + + * gst.supp: + Add a suppression for libcdio 0.76. It leaks an internal struct + when the CD-ROM device is not accessible. + +2007-02-28 Thomas Vander Stichele + + * m4/gst-arch.m4: + Move a line that was in the wrong macro + +2007-02-28 Thomas Vander Stichele + + * m4/gst.m4: + Add + * m4/gst-arch.m4: + * m4/gst-args.m4: + * m4/gst-check.m4: + * m4/gst-debuginfo.m4: + * m4/gst-default.m4: + * m4/gst-doc.m4: + * m4/gst-error.m4: + * m4/gst-feature.m4: + * m4/gst-function.m4: + * m4/gst-gettext.m4: + * m4/gst-glib2.m4: + * m4/gst-libxml2.m4: + * m4/gst-parser.m4: + * m4/gst-plugin-docs.m4: + * m4/gst-plugindir.m4: + * m4/gst-valgrind.m4: + * m4/gst-x11.m4: + Convert all macros to use AG_GST style so we can properly warn + when they're missing if configure.ac calls AG_GST_INIT + Will require update in all GStreamer modules. + +2007-02-11 Stefan Kost + + * m4/gst-args.m4: + Remove 'enable' from configure switch description as this leads to + confusing lines like "disable enable builing ...". + * m4/gst-feature.m4: + Fix comment to sound less horrible. + +2007-02-07 Tim-Philipp Müller + + Patch by: Will Newton + + * m4/gst-check.m4: + Use $PKG_CONFIG rather than pkg-config directly, the one in our path + might not be the one we want, like when cross-compiling. Also, other + macros such as PKG_CHECK_MODULES use $PKG_CONFIG, so we should + probably too just for consistency. Fixes #405288. + +2007-01-08 Tim-Philipp Müller + + * m4/gst-parser.m4: + Need to use double square brackets again so m4 doesn't remove them + (fixes #378931). + + * m4/gst-args.m4: + Use double square brackets here as well, for the same reason. + +2007-01-05 Tim-Philipp Müller + + * m4/gst-parser.m4: + Use 'sed' rather than 'tr' to strip trailing letters from version + numbers, since 'tr' might not be available and we know sed is + (#378931). + +2006-10-21 Tim-Philipp Müller + + * check.mak: + Increase default timeout under valgrind, 60 is just too short and + some tests take a bit longer these days and not everyone has a + beefy machine. + +2006-09-29 Michael Smith + + * gst.supp: + More suppressions for edgy. + +2006-09-28 Jan Schmidt + + * m4/gst-glib2.m4: + Use gmodule-no-export-2.0.pc instead of gmodule-2.0.pc - we neither + want nor need --export-dynamic (which ends up making us export a bunch + of unneeded symbols) + +2006-09-14 Tim-Philipp Müller + + * gst.supp: + Some suppressions for the more recent ld.so in ubuntu edgy. + +2006-08-23 Tim-Philipp Müller + + * gst.supp: + Shorten function trail so the suppression works on + my ubuntu dapper system with core cvs as well. + +2006-07-28 Jan Schmidt + + * gst.supp: + Extra suppressions from my Ubuntu x86_64 machine + +2006-07-24 Tim-Philipp Müller + + Patch by: Frederic Peters + + * m4/gst-parser.m4: + Need to double square brackets in .m4 files. Should fix bison + version detection with version numbers like 1.23a (#348354). + +2006-07-24 Jan Schmidt + + * check.mak: + Valgrind fails to find tests written in tests/check/ directly (rather + than a subdir) - because valgrind gets run with a filename that + doesn't contain a relative path, it goes searching /usr/bin instead. + Run with ./.... to make things work either way. + + * gtk-doc-plugins.mak: + Add $(top_builddir)/src as a place to look for plugins + when building too, since that's where gst-template keeps things + +2006-07-23 Stefan Kost + + Patch by: Frederic Peters + + * m4/gst-parser.m4: + Fix bison detection (#348354) + +2006-07-21 Stefan Kost + + * m4/gst-parser.m4: + check for bison and flex + +2006-07-13 Thomas Vander Stichele + + * m4/gst-plugin-docs.m4: + remove the configure argument for enabling plugin doc build; + having gtk-doc enabled and pyxml present is enough of a trigger + +2006-07-03 Thomas Vander Stichele + + * coverage/lcov.mak: + fix up rules to work with gst-python as well + run "make lcov" to test and generate the reports + run "make lcov-reset" to redo it after that + +2006-07-02 Thomas Vander Stichele + + * Makefile.am: + * check.mak: + add an inspect target that inspects every element feature, + so we can have that added for coverage + * coverage/lcov.mak: + add support for lcov + +2006-07-02 Thomas Vander Stichele + + * m4/gst-args.m4: + when building with gcov, reset CFLAGS and friends to O0 + +2006-07-02 Thomas Vander Stichele + + * m4/gst-args.m4: + Find the gcov that matches the gcc version + Only allow gcov if we use gcc + +2006-07-02 Thomas Vander Stichele + + * Makefile.am: + * coverage/coverage-report-entry.pl: + * coverage/coverage-report.pl: + * coverage/coverage-report.xsl: + copy coverage reporting files from dbus + +2006-07-01 Thomas Vander Stichele + + * m4/gst-args.m4: + libtool strips gcov's -f flags, so libgcov does not get + linked in. Setting GCOV_LIBS with -lgcov fixes libtool's + stripping + also show what pkg-config-path we set + +2006-06-22 Tim-Philipp Müller + + Patch by: Peter Kjellerstedt + + * m4/gst-feature.m4: + Show list of plugins without external dependencies that + will not be built as well (#344136). + +2006-06-15 Tim-Philipp Müller + + * m4/gst-plugin-docs.m4: + add GST_PLUGIN_DOCS, which checks for everything needed + to build the plugin docs (namely gtk-doc and pyxml); also + adds a new --enable-plugin-docs configure switch; will + set ENABLE_PLUGIN_DOCS conditional for use in Makefile.am + files (see #344039). + +2006-06-11 Thomas Vander Stichele + + * m4/gst-check.m4: + add GST_PKG_CHECK_MODULES, which in the normal case of checking + for a dependency lib for a plug-in only needs two arguments + to do the right thing. + * m4/gst-feature.m4: + clean up output a little of feature checking; also deal with + non-plug-in feature checks + * m4/Makefile.am: + * m4/gst-gstreamer.m4: + remove this file; it's a useless check + +2006-06-06 Thomas Vander Stichele + + * m4/gst-arch.m4: + add PPC64 so we can have separate structure sizes for it + +2006-06-05 Edward Hervey + + * gtk-doc.mak: + Check for the proper .devhelp2 file to remove. + +2006-05-31 Thomas Vander Stichele + + * gtk-doc.mak: + allow a magic variable to suppress errors from docbuilding + +2006-05-30 Thomas Vander Stichele + + * gtk-doc.mak: + error out if gtkdoc-mktmpl finds unused declarations + +2006-05-28 Edward Hervey + + * gst.supp: + Reverting previous commit. That's good to know, Edward, but why ? + +2006-05-28 Edward Hervey + + * gst.supp: + Added suppresion for memleak in g_option_context_parse on fc5-64 + +2006-05-19 Thomas Vander Stichele + + * m4/gst-check.m4: + set GSTPB_PLUGINS_DIR just like GST_PLUGINS_DIR + +2006-05-18 Tim-Philipp Müller + + * check.mak: + Fix 'make help' in check directories, it should be + 'valgrind.gen-suppressions' not 'valgrind-gen-suppressions' + (not changing target to match help string on purpose to keep + scripts etc. functional). + +2006-05-18 Thomas Vander Stichele + + Patch by: Peter Kjellerstedt + + * m4/gst-arch.m4: + add support for CRIS and CRISv32. + +2006-05-17 Jan Schmidt + + * m4/gst-args.m4: + Fix the macros for command-line supplied package and origin names + so they don't end up being configure as "" (Fixes #341479) + +2006-05-14 Jan Schmidt + + * gtk-doc.mak: + Add uninstall rule to remove .devhelp2 files. + +2006-05-09 Edward Hervey + + * gst.supp: + Add suppression for GSlice version of + g_type_init calloc leak + +2006-04-05 Michael Smith + + * gst.supp: + Delete a bogus suppression for the registry code. + Generalise a suppression for a glib bug (see #337404) + +2006-04-04 Michael Smith + + * gst.supp: + Add a leak suppression: the existing glibc-doesn't-free-TLS one + wasn't triggering here. + +2006-04-04 Michael Smith + + * gst.supp: + Add some minimally-neccesary suppressions for my x86/dapper system. + +2006-04-01 Thomas Vander Stichele + + * plugins.xsl: + Do not display an origin link if origin does not start with http + See #323798 + +2006-04-01 Thomas Vander Stichele + + * m4/gst-args.m4: + * m4/gst-feature.m4: + add more macros + * m4/gst-x11.m4: + X11-related checks + +2006-04-01 Thomas Vander Stichele + + * m4/as-version.m4: + newer version + * m4/gst-args.m4: + * m4/gst-doc.m4: + update and add other macros to be shared across projects + +2006-03-24 Thomas Vander Stichele + + * gst.supp: + add a suppression for g_parse_debug_string + +2006-03-23 Stefan Kost + + * gstdoc-scangobj: + sync fully with gtkdoc-0.15 + +2006-03-23 Stefan Kost + + * gstdoc-scangobj: + * gtk-doc.mak: + sync a little with gtk-doc mainline + +2006-03-17 Wim Taymans + + * gst.supp: + add another clone suppression + change all glibc suppressions to match 2.3.* + +2006-03-09 Thomas Vander Stichele + + * m4/check.m4: + fix test so it actually works when the normal check is used + over debian's/ubuntu's + +2006-03-08 Jan Schmidt + + * check.mak: + Set G_SLICE=always-malloc when valgrinding tests + (closes #333272) + +2006-02-21 Jan Schmidt + + * m4/gst-glib2.m4: + Fix debug output when the GLib version prerequisite is not found + +2006-02-13 Andy Wingo + + * m4/check.m4: Hack around Debian/Ubuntu's broken installation of + the PIC version of check as libcheck_pic.a. Should work with + cross-compilation too. Grr. + +2006-02-06 Thomas Vander Stichele + + * m4/gst-default.m4: + switch to auto* sinks for defaults + +2006-02-02 Wim Taymans + + * check.mak: + add a .valgrind.gen-suppressions target to aid in generating + suppressions + * gst.supp: + add more repressions from my debian glibc as of today + +2006-02-02 Thomas Vander Stichele + + * gtk-doc-plugins.mak: + only add srcdir/gst if it exists + +2006-01-30 Thomas Vander Stichele + + * release.mak: + don't complain about disted enums in win32 + +2006-01-20 Thomas Vander Stichele + + * m4/gst-check.m4: + AC_SUBST CFLAGS and LIBS + do a non-command because something is stripping out our AC_SUBST + +2006-01-20 Thomas Vander Stichele + + * m4/gst-args.m4: + * m4/gst-valgrind.m4: + properly give a "no" result manually when providing a + not-found action to fix configure output + +2006-01-20 Thomas Vander Stichele + + * m4/pkg.m4: + update with a more recent version + +2006-01-07 Thomas Vander Stichele + + * gettext.patch: + make Makefile depend on LINGUAS, so rebuilds work when adding + a language + +2006-01-03 Michael Smith + + * check.mak: + Clarify error message from valgrind test runs. + +2005-12-16 Thomas Vander Stichele + + * m4/gst-arch.m4: + define HOST_CPU + +2005-11-29 Thomas Vander Stichele + + * check.mak: + add a valgrind-forever target for tests + +2005-11-28 Thomas Vander Stichele + + * check.mak: + when a "make test.check" run fails, make it rerun the test with + at least debug level 2 + +2005-11-14 Thomas Vander Stichele + + * m4/Makefile.am: + * m4/gst-check.m4: + fix check for base plugins + * m4/gst-default.m4: + add m4 to set default elements + +2005-10-18 Thomas Vander Stichele + + * m4/gst-check.m4: + check for tools correctly + +2005-10-18 Thomas Vander Stichele + + * gtk-doc.mak: + only enable breaking on new API when make distcheck passes, + not before + +2005-10-18 Thomas Vander Stichele + + * m4/gst-check.m4: + Resurrect Julien's dead body and wipe his mind clean + +2005-10-18 Thomas Vander Stichele + + * m4/gst-check.m4: + Kill Julien + +2005-10-17 Julien MOUTTE + + * m4/gst-check.m4: I know Thomas will kill me but this + ifelse statement seems incorrect as it is always setting + required to "yes". With this one it seems to work. Fixes + build of gst-plugins-base on my setup where gstreamer-check + is definitely not present/required. + +2005-10-18 Stefan Kost + + * gtk-doc.mak: + make build break on new api that has not been added to the + sections file + +2005-10-17 Thomas Vander Stichele + + * m4/gst-glib2.m4: + * m4/Makefile.am: + * m4/gst-check.m4: + add macro for easy checks for GStreamer libs + +2005-10-16 Thomas Vander Stichele + + * m4/gst-glib2.m4: + update, warn in error cases + +2005-10-16 Thomas Vander Stichele + + * m4/gst-error.m4: + add GST_SET_DEFAULT_LEVEL + +2005-10-16 Thomas Vander Stichele + + * m4/Makefile.am: + * m4/gst-gettext.m4: + remove the AM_GNU_GETTEXT* calls, they need to be in configure.ac + * m4/gst-glib2.m4: + clean up and re-use in core soon + * m4/gst-plugindir.m4: + macro to set up PLUGINDIR and plugindir define/var + +2005-10-15 Thomas Vander Stichele + + * m4/Makefile.am: + * m4/gst-gettext.m4: + add macro for setting up gettext + +2005-10-15 Thomas Vander Stichele + + * m4/gst-args.m4: + add some .m4's for argument checking that can be shared among modules + +2005-10-15 Thomas Vander Stichele + + * m4/as-libtool.m4: + set _LT_LDFLAGS + * m4/gst-libxml2.m4: + document + +2005-10-15 Thomas Vander Stichele + + * m4/gst-arch.m4: + indent a little + add AC_REQUIRE + * m4/gst-error.m4: + clean up + +2005-10-12 Thomas Vander Stichele + + * gst-autogen.sh: + update version detection expression to catch stuff like + Libtool (libtool15) 1.5.0 + +2005-10-11 Thomas Vander Stichele + + * gst.supp: + commit 6 new suppressions related to g_module_open; can these + really not be folded into one ? + +2005-10-11 Edward Hervey + + * gst.supp: + made the suppression more generic + Added pthread memleak suppresions + Added nss_parse_* memleak suppresion (used by g_option_context_parse) + +2005-10-11 Thomas Vander Stichele + + * check.mak: + be more strict, more leak resolution + * gst.supp: + clean up the g_type_init suppressions + +2005-10-07 Thomas Vander Stichele + + * m4/Makefile.am: + * m4/gst-valgrind.m4: + put the valgrind detection in an .m4 + +2005-09-29 Thomas Vander Stichele + + * check.mak: + add some more targets, like "help", but also more intensive tests + +2005-09-23 Thomas Vander Stichele + + * gtk-doc.mak: + make certain doc warnings fatal so people maintain docs again + +2005-09-23 Thomas Vander Stichele + + * Makefile.am: + * gtk-doc-plugins.mak: + * scangobj-merge.py: + merge additions from the .signals.new and .args.new file in + the original ones, only updating if necessary + +2005-09-23 Thomas Vander Stichele + + * gst-xmlinspect.py: + * gstdoc-scangobj: + * gtk-doc-plugins.mak: + fix properly for new API; make update in plugins dir now works + +2005-09-20 Thomas Vander Stichele + + * gst-xmlinspect.py: + * gstdoc-scangobj: + some fixes for new API + * gtk-doc-plugins.mak: + set environment properly + +2005-09-17 David Schleef + + * gtk-doc-plugins.mak: Use new environment variables. + +2005-09-16 Michael Smith + + * gstdoc-scangobj: + Make the scanobj code reflect registry/plugin API changes + +2005-09-15 Thomas Vander Stichele + + * gtk-doc-plugins.mak: + split out scanobj step (which will be run by doc maintainer) + from scan step (which will be run on every build) + clean up some of the commands for make distcheck + +2005-09-15 Thomas Vander Stichele + + * gtk-doc-plugins.mak: + * mangle-tmpl.py: + first stab at reorganizing the plugins build so we can maintain + element docs + +2005-09-14 David Schleef + + * as-libtool.mak: Remove + * m4/as-libtool.m4: The libtool bug that this worked around has + been fixed. + * m4/as-version.m4: Don't define GST_RELEASE, since it causes + config.h to be regenerated needlessly, and we don't use it. + +2005-09-14 Thomas Vander Stichele + + * gtk-doc-plugins.mak: + error out on inspect failure + +2005-09-14 Michael Smith + + * glib-gen.mak: + Don't call glib-mkenums with arguments that confuse/break MinGW, + fixes 316155. + +2005-09-03 Thomas Vander Stichele + + * gtk-doc-plugins.mak: + * gtk-doc.mak: + * m4/gst-doc.m4: + separate out gtk-doc and docbook stuff + have two separate --enable configure flags + +2005-08-26 Thomas Vander Stichele + + * check.mak: + add a .gdb target; rebuild registry for each target, otherwise + a code rebuild always triggers a reg rebuild, and it's just too + annoying + * gstdoc-scangobj: + +2005-08-21 Thomas Vander Stichele + + * check.mak: + separate out REGISTRY_ENVIRONMENT; we want to use that from + our valgrind runs, but we also want TESTS_ENVIRONMENT to contain + everything that the first test, gst-register, needs + +2005-08-21 Thomas Vander Stichele + + * check.mak: + parse output of valgrind and check for definitely lost, and error + out; somehow I was led to believe valgrind returns non-zero for + leaks, but I can't make it do that, so let's parse + +2005-08-20 Thomas Vander Stichele + + * check.mak: + for some weird reason valgrind does not report actual memleaks + if GST_PLUGIN_PATH is set to anything but the core gstreamer dir + while valgrind is running. Since the registry is going to go + anyway, I don't want to waste any more time on this; I just run + valgrind without GST_PLUGIN_PATH set. Since the registry loading + doesn't check if GST_PLUGIN_PATH got changed as a reason to rebuild + the registry, that's actually fine. + +2005-08-15 Thomas Vander Stichele + + * mangle-tmpl.py: + keep original Long_Description; only insert an include if it's + not already the first line in there + * plugins.xsl: + output more information for plugins, including an origin hyperlink + +2005-08-15 Thomas Vander Stichele + + * gst-xmlinspect.py: + a first stab at inspecting plugins and outputting an xml description + * gtk-doc-plugins.mak: + a gtk-doc using snippet for plugins documentation + * plugins.xsl: + a stylesheet to convert gst-xmlinspect.py output to docbook output + for inclusion in the gtk-doc stuff + +2005-07-20 Ronald S. Bultje + + * m4/gst-doc.m4: + s/pdf/eps/ in test for whether we output EPS images (#309379). + +2005-07-18 Andy Wingo + + * m4/as-libtool-tags.m4: Ooh, backported from libtool 1.6. Much + better. Thanks, Paolo Bonzini! + + * m4/Makefile.am (EXTRA_DIST): + * m4/as-libtool-tags.m4: New file, tries to disable some CXX and + fortran checks. + +2005-07-08 Thomas Vander Stichele + + * m4/gst-error.m4: + add macro to set ERROR_CFLAGS + +2005-06-30 Jan Schmidt + + * gst-autogen.sh: + Remove the old autoregen.sh if it exists before recreating it, + to prevent confusing any shell process that might be reading it + currently. + +2005-06-29 Thomas Vander Stichele + + * m4/gtk-doc.m4: + added + +2005-06-03 Stefan Kost + + * gst-autogen.sh: create autoregen.sh *before* shifting the options + +2005-05-17 Thomas Vander Stichele + + * gst-autogen.sh: only update autoregen.sh on actual runs + +2005-03-11 Thomas Vander Stichele + + * m4/check.m4: m4 from the check unit test suite + +2004-12-14 David Schleef + + * m4/gst-arch.m4: remove MMX stuff, since it doesn't work and + isn't needed anywhere + +2004-12-08 Thomas Vander Stichele + + * gst-autogen.sh: + allow failure command to be run so we can clean upfrom autopoint + +2004-09-03 Zeeshan Ali Khattak + * m4/gst-feature.m4: Trying to correct the GST_CHECK_CONFIGPROG macro + +2004-07-21 Benjamin Otte + + * m4/.cvsignore: exciting updates for libtool m4 files + +2004-07-12 David Schleef + + * m4/as-objc.m4: Add a macro to test for objective C + +2004-06-12 Thomas Vander Stichele + + * m4/gst-feature.m4: + not all of them support --plugin-libs, so redirect stderr + +2004-06-12 Thomas Vander Stichele + + * m4/as-scrub-include.m4: + sync with upstream to 0.1.4. Fixes #132440 + +2004-06-07 Benjamin Otte + + * m4/gst-feature.m4: + write a big marker into configure output when checking next plugin + to allow easier parsing of why plugins are(n't) built. + +2004-06-01 Thomas Vander Stichele + + * m4/as-compiler-flag.m4: + * m4/as-compiler.m4: + * m4/as-libtool.m4: + * m4/as-version.m4: + sync with upstream, change sticky options to -ko + +2004-05-24 Thomas Vander Stichele + + * m4/as-scrub-include.m4: synced with upstream + +2004-05-03 Thomas Vander Stichele + + * po.mak: + snippet for updating .po files + +2004-03-18 Thomas Vander Stichele + + * Makefile.am: + * m4/Makefile.am: + integrate these with the dist + +2004-03-17 Thomas Vander Stichele + + * release.mak: add a release target + +2004-03-09 Thomas Vander Stichele + + patch by: Stephane Loeuillet + + * m4/ax_create_stdint_h.m4: + use head -n instead of head - (#136500) + +2004-03-05 Thomas Vander Stichele + + * m4/gst-doc.m4: don't build PS without dvips binary + +2004-02-22 Julio M. Merino Vidal + + reviewed by: Benjamin Otte + + * m4/as-docbook.m4: + don't use == operator with test(1) (fixes #135115) + +2004-02-16 Thomas Vander Stichele + + * common/m4/gst-arch.m4: x86_64 is x86 too (clue from Fedora 2 test) + +2004-02-13 Thomas Vander Stichele + + * m4/gst-feature.m4: + remove AM_CONDITIONAL for the subsystem since automake 1.6.x + requires that call be in configure.ac + +2004-02-13 Thomas Vander Stichele + + * m4/gst-libxml2.m4: + take required version as argument, and default to 2.4.9 if not + specified + +2004-02-12 Thomas Vander Stichele + + * m4/gst-feature.m4: + rename and fix up GST_CHECK_DISABLE_SUBSYSTEM + +2004-02-11 Thomas Vander Stichele + + * common/m4/as-ac-expand.m4: + * common/m4/as-auto-alt.m4: + * common/m4/as-compiler-flag.m4: + * common/m4/as-compiler.m4: + * common/m4/as-docbook.m4: + * common/m4/as-libtool.m4: + * common/m4/as-scrub-include.m4: + * common/m4/as-version.m4: + * common/m4/glib-gettext.m4: + * common/m4/gst-arch.m4: + * common/m4/gst-debuginfo.m4: + * common/m4/gst-doc.m4: + * common/m4/gst-feature.m4: + * common/m4/gst-function.m4: + * common/m4/gst-glib2.m4: + * common/m4/gst-gstreamer.m4: + * common/m4/gst-libxml2.m4: + * common/m4/gst-makecontext.m4: + * common/m4/gst-mcsc.m4: + * common/m4/pkg.m4: + fix underquoted macros as reported by automake 1.8.x (#133800) + +2004-02-11 Johan Dahlin + + * gst-autogen.sh: Use A-Z instead of A-z in sed expression to + avoid a warning + +2004-02-05 Thomas Vander Stichele + + * m4/gst-doc.m4: + we use --output-format=xml and --ingnore-files options to + gtkdoc-mkdb, which got added between 0.9 and 1.0 + +2004-02-04 Thomas Vander Stichele + + * m4/as-libtool.m4: remove AM_PROG_LIBTOOL so it can move back + to configure.ac to shut up libtoolize + +2004-02-03 Thomas Vander Stichele + + * glib-gen.mak: added; used to generate enums and marshal code + +2004-01-13 Thomas Vander Stichele + + * gettext.patch: added; used by autogen.sh to make sure + GETTEXT_PACKAGE is understood from po/Makefile.in.in -> po/Makefile.in + diff --git a/common/Makefile.am b/common/Makefile.am new file mode 100644 index 0000000000..ca8c02916e --- /dev/null +++ b/common/Makefile.am @@ -0,0 +1,15 @@ +SUBDIRS = m4 + +EXTRA_DIST = \ + ChangeLog \ + gettext.patch \ + glib-gen.mak gtk-doc.mak upload.mak release.mak \ + gst-autogen.sh \ + c-to-xml.py gst-xmlinspect.py mangle-tmpl.py scangobj-merge.py \ + gtk-doc-plugins.mak \ + plugins.xsl gstdoc-scangobj \ + gst.supp check.mak \ + coverage/lcov.mak \ + coverage/coverage-report.pl \ + coverage/coverage-report.xsl \ + coverage/coverage-report-entry.pl diff --git a/common/c-to-xml.py b/common/c-to-xml.py new file mode 100644 index 0000000000..8448fd248d --- /dev/null +++ b/common/c-to-xml.py @@ -0,0 +1,34 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +""" +Convert a C program to valid XML to be included in docbook +""" + +import sys +import os +from xml.sax import saxutils + +def main(): + if len(sys.argv) == 1: + sys.stderr.write("Please specify a source file to convert") + sys.exit(1) + source = sys.argv[1] + + if not os.path.exists(source): + sys.stderr.write("%s does not exist.\n" % source) + sys.exit(1) + + content = open(source, "r").read() + + # print header + print '' + print '' + print + print '' + + # print content + print saxutils.escape(content).encode('UTF-8') + print '' + +main() diff --git a/common/check.mak b/common/check.mak new file mode 100644 index 0000000000..9ac509d901 --- /dev/null +++ b/common/check.mak @@ -0,0 +1,149 @@ +clean-local-check: + for i in `find . -name ".libs" -type d`; do \ + rm -rf $$i; \ + done + +if HAVE_VALGRIND +# hangs spectacularly on some machines, so let's not do this by default yet +check-valgrind: + make valgrind +else +check-valgrind: + @true +endif + +LOOPS = 10 + +# run any given test by running make test.check +# if the test fails, run it again at at least debug level 2 +%.check: % + @$(TESTS_ENVIRONMENT) \ + CK_DEFAULT_TIMEOUT=20 \ + $* || \ + $(TESTS_ENVIRONMENT) \ + GST_DEBUG=$$GST_DEBUG,*:2 \ + CK_DEFAULT_TIMEOUT=20 \ + $* + +# run any given test in a loop +%.torture: % + @for i in `seq 1 $(LOOPS)`; do \ + $(TESTS_ENVIRONMENT) \ + CK_DEFAULT_TIMEOUT=20 \ + $*; done + +# run any given test in an infinite loop +%.forever: % + @while true; do \ + $(TESTS_ENVIRONMENT) \ + CK_DEFAULT_TIMEOUT=20 \ + $* || break; done + +# valgrind any given test by running make test.valgrind +%.valgrind: % + $(TESTS_ENVIRONMENT) \ + CK_DEFAULT_TIMEOUT=360 \ + G_SLICE=always-malloc \ + libtool --mode=execute \ + $(VALGRIND_PATH) -q \ + $(foreach s,$(SUPPRESSIONS),--suppressions=$(s)) \ + --tool=memcheck --leak-check=full --trace-children=yes \ + --leak-resolution=high --num-callers=20 \ + ./$* 2>&1 | tee valgrind.log + @if grep "==" valgrind.log > /dev/null 2>&1; then \ + rm valgrind.log; \ + exit 1; \ + fi + @rm valgrind.log + +# valgrind any given test and generate suppressions for it +%.valgrind.gen-suppressions: % + $(TESTS_ENVIRONMENT) \ + CK_DEFAULT_TIMEOUT=360 \ + G_SLICE=always-malloc \ + libtool --mode=execute \ + $(VALGRIND_PATH) -q \ + $(foreach s,$(SUPPRESSIONS),--suppressions=$(s)) \ + --tool=memcheck --leak-check=full --trace-children=yes \ + --leak-resolution=high --num-callers=20 \ + --gen-suppressions=all \ + ./$* 2>&1 | tee suppressions.log + +# valgrind any given test until failure by running make test.valgrind-forever +%.valgrind-forever: % + @while make $*.valgrind; do \ + true; done + +# gdb any given test by running make test.gdb +%.gdb: % + $(TESTS_ENVIRONMENT) \ + CK_FORK=no \ + libtool --mode=execute \ + gdb $* + +# torture tests +torture: $(TESTS) + -rm test-registry.xml + @echo "Torturing tests ..." + for i in `seq 1 $(LOOPS)`; do \ + make check || \ + (echo "Failure after $$i runs"; exit 1) || \ + exit 1; \ + done + @banner="All $(LOOPS) loops passed"; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo $$dashes; echo $$banner; echo $$dashes + +# forever tests +forever: $(TESTS) + -rm test-registry.xml + @echo "Forever tests ..." + while true; do \ + make check || \ + (echo "Failure"; exit 1) || \ + exit 1; \ + done + +# valgrind all tests +valgrind: $(TESTS) + @echo "Valgrinding tests ..." + @failed=0; \ + for t in $(filter-out $(VALGRIND_TESTS_DISABLE),$(TESTS)); do \ + make $$t.valgrind; \ + if test "$$?" -ne 0; then \ + echo "Valgrind error for test $$t"; \ + failed=`expr $$failed + 1`; \ + whicht="$$whicht $$t"; \ + fi; \ + done; \ + if test "$$failed" -ne 0; then \ + echo "$$failed tests had leaks or errors under valgrind:"; \ + echo "$$whicht"; \ + false; \ + fi + +# inspect every plugin feature +GST_INSPECT = $(GST_TOOLS_DIR)/gst-inspect-$(GST_MAJORMINOR) +inspect: + @echo "Inspecting features ..." + for e in `$(TESTS_ENVIRONMENT) $(GST_INSPECT) | head -n -2 \ + | cut -d: -f2`; \ + do echo Inspecting $$e; \ + $(GST_INSPECT) $$e > /dev/null 2>&1; done + +help: + @echo "make check -- run all checks" + @echo "make torture -- run all checks $(LOOPS) times" + @echo "make (dir)/(test).check -- run the given check once" + @echo "make (dir)/(test).forever -- run the given check forever" + @echo "make (dir)/(test).torture -- run the given check $(LOOPS) times" + @echo + @echo "make (dir)/(test).gdb -- start up gdb for the given test" + @echo + @echo "make valgrind -- valgrind all tests" + @echo "make (dir)/(test).valgrind -- valgrind the given test" + @echo "make (dir)/(test).valgrind-forever -- valgrind the given test forever" + @echo "make (dir)/(test).valgrind.gen-suppressions -- generate suppressions" + @echo " and save to suppressions.log" + @echo "make inspect -- inspect all plugin features" + diff --git a/common/coverage/coverage-report-entry.pl b/common/coverage/coverage-report-entry.pl new file mode 100644 index 0000000000..8f653afe69 --- /dev/null +++ b/common/coverage/coverage-report-entry.pl @@ -0,0 +1,70 @@ +#!/usr/bin/perl +# +# Copyright (C) 2006 Daniel Berrange +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +print < + +Coverage report for $ARGV[0] + + + +

Coverage report for $ARGV[0]

+ +
+EOF
+
+
+while (<>) {
+    s/&/&/g;
+    s//>/g;
+
+    if (/^\s*function (\S+) called (\d+) returned \d+% blocks executed \d+%/) {
+	my $class = $2 > 0 ? "perfect" : "terrible";
+	$_ = "$_";
+    } elsif (/^\s*branch\s+\d+\s+taken\s+(\d+)%\s+.*$/) {
+	my $class = $1 > 0 ? "perfect" : "terrible";
+	$_ = "$_";
+    } elsif (/^\s*branch\s+\d+\s+never executed.*$/) {
+	my $class = "terrible";
+	$_ = "$_";
+    } elsif (/^\s*call\s+\d+\s+never executed.*$/) {
+	my $class = "terrible";
+	$_ = "$_";
+    } elsif (/^\s*call\s+\d+\s+returned\s+(\d+)%.*$/) {
+	my $class = $1 > 0 ? "perfect" : "terrible";
+	$_ = "$_";
+    }
+    
+
+    print;
+}
+
+print <
+
+
+EOF
diff --git a/common/coverage/coverage-report.pl b/common/coverage/coverage-report.pl
new file mode 100644
index 0000000000..046bc370c5
--- /dev/null
+++ b/common/coverage/coverage-report.pl
@@ -0,0 +1,125 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2006 Daniel Berrange
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+use warnings;
+use strict;
+
+my %coverage = ( functions => {}, files => {} );
+
+my %filemap;
+
+my $type;
+my $name;
+
+my @functions;
+
+while (<>) {
+    if (/^Function '(.*)'\s*$/) {
+	$type = "function";
+	$name = $1;
+	$coverage{$type}->{$name} = {};
+	push @functions, $name;
+    } elsif (/^File '(.*?)'\s*$/) {
+	$type = "file";
+	$name = $1;
+	$coverage{$type}->{$name} = {};
+	
+	foreach my $func (@functions) {
+	    $coverage{"function"}->{$func}->{file} = $name;
+	}
+	@functions = ();
+    } elsif (/^Lines executed:(.*)%\s*of\s*(\d+)\s*$/) {
+	$coverage{$type}->{$name}->{lines} = $2;
+	$coverage{$type}->{$name}->{linesCoverage} = $1;
+    } elsif (/^Branches executed:(.*)%\s*of\s*(\d+)\s*$/) {
+	$coverage{$type}->{$name}->{branches} = $2;
+	$coverage{$type}->{$name}->{branchesCoverage} = $1;
+    } elsif (/^Taken at least once:(.*)%\s*of\s*(\d+)\s*$/) {
+	$coverage{$type}->{$name}->{conds} = $2;
+	$coverage{$type}->{$name}->{condsCoverage} = $1;
+    } elsif (/^Calls executed:(.*)%\s*of\s*(\d+)\s*$/) {
+	$coverage{$type}->{$name}->{calls} = $2;
+	$coverage{$type}->{$name}->{callsCoverage} = $1;
+    } elsif (/^No branches$/) {
+	$coverage{$type}->{$name}->{branches} = 0;
+	$coverage{$type}->{$name}->{branchesCoverage} = "100.00";
+	$coverage{$type}->{$name}->{conds} = 0;
+	$coverage{$type}->{$name}->{condsCoverage} = "100.00";
+    } elsif (/^No calls$/) {
+	$coverage{$type}->{$name}->{calls} = 0;
+	$coverage{$type}->{$name}->{callsCoverage} = "100.00";
+    } elsif (/^\s*(.*):creating '(.*)'\s*$/) {
+	$filemap{$1} = $2;
+    } elsif (/^\s*$/) {
+	# nada
+    } else {
+	warn "Shit [$_]\n";
+    }
+}
+
+my %summary;
+foreach my $type ("function", "file") {
+    $summary{$type} = {};
+    foreach my $m ("lines", "branches", "conds", "calls") {
+	my $totalGot = 0;
+	my $totalMiss = 0;
+	my $count = 0;
+	foreach my $func (keys %{$coverage{function}}) {
+	    $count++;
+	    my $got = $coverage{function}->{$func}->{$m};
+	    $totalGot += $got;
+	    my $miss = $got * $coverage{function}->{$func}->{$m ."Coverage"} / 100;
+	    $totalMiss += $miss;
+	}
+	$summary{$type}->{$m} = sprintf("%d", $totalGot);
+	$summary{$type}->{$m . "Coverage"} = sprintf("%.2f", $totalMiss / $totalGot * 100);
+    }
+}
+
+
+
+print "\n";
+
+foreach my $type ("function", "file") {
+    printf "<%ss>\n", $type;
+    foreach my $name (sort { $a cmp $b } keys %{$coverage{$type}}) {
+	my $rec = $coverage{$type}->{$name};
+	printf "  \n", $name, ($type eq "file" ? $filemap{$name} : $filemap{$rec->{file}});
+	printf "    \n", $rec->{lines}, $rec->{linesCoverage};
+	if (exists $rec->{branches}) {
+	    printf "    \n", $rec->{branches}, $rec->{branchesCoverage};
+	}
+	if (exists $rec->{conds}) {
+	    printf "    \n", $rec->{conds}, $rec->{condsCoverage};
+	}
+	if (exists $rec->{calls}) {
+	    printf "    \n", $rec->{calls}, $rec->{callsCoverage};
+	}
+	print  "  \n";
+    }
+    
+    printf "  \n";
+    printf "    \n", $summary{$type}->{lines}, $summary{$type}->{linesCoverage};
+    printf "    \n", $summary{$type}->{branches}, $summary{$type}->{branchesCoverage};
+    printf "    \n", $summary{$type}->{conds}, $summary{$type}->{condsCoverage};
+    printf "    \n", $summary{$type}->{calls}, $summary{$type}->{callsCoverage};
+    printf  "  \n";
+    printf "\n", $type;
+}
+
+print "\n";
diff --git a/common/coverage/coverage-report.xsl b/common/coverage/coverage-report.xsl
new file mode 100644
index 0000000000..b19ebb638b
--- /dev/null
+++ b/common/coverage/coverage-report.xsl
@@ -0,0 +1,235 @@
+
+
+
+
+  
+
+  
+    
+      
+        Coverage report
+        
+      
+      
+        

Coverage report

+ + + +
+ + +

Function coverage

+ + + +
+ + + +

File coverage

+ + + +
+ + + + + + + + + + + + + + + + + + + + + odd + + + even + + + + + + + + + + + + + + odd + + + even + + + + + + +
NameLinesBranchesConditionsCalls
+
+ + + + + + + + + + + + + + Summary + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + perfect + + + excellant + + + good + + + poor + + + bad + + + terrible + + + + + % of + + +
diff --git a/common/coverage/lcov.mak b/common/coverage/lcov.mak new file mode 100644 index 0000000000..6d848f5245 --- /dev/null +++ b/common/coverage/lcov.mak @@ -0,0 +1,29 @@ +# run lcov from scratch, always +lcov-reset: + make lcov-run + make lcov-report + +# run lcov from scratch if the dir is not there +lcov: + make lcov-reset + +# reset run coverage tests +lcov-run: + @-rm -rf lcov + find . -name "*.gcda" -exec rm {} \; + if test -d tests/check; then make -C tests/check inspect; fi + make check + +# generate report based on current coverage data +lcov-report: + mkdir lcov + lcov --directory . --capture --output-file lcov/lcov.info + lcov -l lcov/lcov.info | grep -v "`cd $(top_srcdir) && pwd`" | cut -d: -f1 > lcov/remove + lcov -l lcov/lcov.info | grep "tests/check/" | cut -d: -f1 >> lcov/remove + lcov -r lcov/lcov.info `cat lcov/remove` > lcov/lcov.cleaned.info + rm lcov/remove + mv lcov/lcov.cleaned.info lcov/lcov.info + genhtml -t "$(PACKAGE_STRING)" -o lcov lcov/lcov.info + +lcov-upload: lcov + rsync -rvz -e ssh --delete lcov/* gstreamer.freedesktop.org:/srv/gstreamer.freedesktop.org/www/data/coverage/lcov/$(PACKAGE) diff --git a/common/gettext.patch b/common/gettext.patch new file mode 100644 index 0000000000..659718e3af --- /dev/null +++ b/common/gettext.patch @@ -0,0 +1,23 @@ +--- po/Makefile.in.in.orig 2006-01-07 12:03:45.000000000 +0100 ++++ po/Makefile.in.in 2006-01-07 12:04:23.000000000 +0100 +@@ -11,6 +11,9 @@ + PACKAGE = @PACKAGE@ + VERSION = @VERSION@ + ++# thomas: add GETTEXT_PACKAGE substitution as used in Makevars ++GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ ++ + SHELL = /bin/sh + @SET_MAKE@ + +@@ -305,7 +308,9 @@ + update-gmo: Makefile $(GMOFILES) + @: + +-Makefile: Makefile.in.in $(top_builddir)/config.status POTFILES.in ++# thomas: add LINGUAS as a dependency so that the Makefile gets rebuilt ++# properly when we add languages ++Makefile: Makefile.in.in $(top_builddir)/config.status POTFILES.in LINGUAS + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \ + $(SHELL) ./config.status diff --git a/common/glib-gen.mak b/common/glib-gen.mak new file mode 100644 index 0000000000..eff414714a --- /dev/null +++ b/common/glib-gen.mak @@ -0,0 +1,42 @@ +# these are the variables your Makefile.am should set +# the example is based on the colorbalance interface + +#glib_enum_headers=$(colorbalance_headers) +#glib_enum_define=GST_COLOR_BALANCE +#glib_enum_prefix=gst_color_balance + +# these are all the rules generating the relevant files +%-marshal.h: %-marshal.list + glib-genmarshal --header --prefix=$(glib_enum_prefix)_marshal $^ > $*-marshal.h.tmp + mv $*-marshal.h.tmp $*-marshal.h + +%-marshal.c: %-marshal.list + echo "#include \"$*-marshal.h\"" >> $*-marshal.c.tmp + glib-genmarshal --body --prefix=$(glib_enum_prefix)_marshal $^ >> $*-marshal.c.tmp + mv $*-marshal.c.tmp $*-marshal.c + +%-enumtypes.h: $(glib_enum_headers) + glib-mkenums \ + --fhead "#ifndef __$(glib_enum_define)_ENUM_TYPES_H__\n#define __$(glib_enum_define)_ENUM_TYPES_H__\n\n#include \n\nG_BEGIN_DECLS\n" \ + --fprod "\n/* enumerations from \"@filename@\" */\n" \ + --vhead "GType @enum_name@_get_type (void);\n#define GST_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \ + --ftail "G_END_DECLS\n\n#endif /* __$(glib_enum_define)_ENUM_TYPES_H__ */" \ + $^ > $@ + +%-enumtypes.c: $(glib_enum_headers) + @if test "x$(glib_enum_headers)" == "x"; then echo "ERROR: glib_enum_headers is empty, please fix Makefile"; exit 1; fi + glib-mkenums \ + --fhead "#include <$*.h>" \ + --fprod "\n/* enumerations from \"@filename@\" */" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \ + $^ > $@ + +# a hack rule to make sure .Plo files exist because they get include'd +# from Makefile's +.deps/%-marshal.Plo: + touch $@ + +.deps/%-enumtypes.Plo: + touch $@ diff --git a/common/gst-autogen.sh b/common/gst-autogen.sh new file mode 100644 index 0000000000..7b312124b7 --- /dev/null +++ b/common/gst-autogen.sh @@ -0,0 +1,308 @@ +# a silly hack that generates autoregen.sh but it's handy +# Remove the old autoregen.sh first to create a new file, +# as the current one may be being read by the shell executing +# this script. +if [ -f "autoregen.sh" ]; then + rm autoregen.sh +fi +echo "#!/bin/sh" > autoregen.sh +echo "./autogen.sh $@ \$@" >> autoregen.sh +chmod +x autoregen.sh + +# helper functions for autogen.sh + +debug () +# print out a debug message if DEBUG is a defined variable +{ + if test ! -z "$DEBUG" + then + echo "DEBUG: $1" + fi +} + +version_check () +# check the version of a package +# first argument : package name (executable) +# second argument : optional path where to look for it instead +# third argument : source download url +# rest of arguments : major, minor, micro version +# all consecutive ones : suggestions for binaries to use +# (if not specified in second argument) +{ + PACKAGE=$1 + PKG_PATH=$2 + URL=$3 + MAJOR=$4 + MINOR=$5 + MICRO=$6 + + # for backwards compatibility, we let PKG_PATH=PACKAGE when PKG_PATH null + if test -z "$PKG_PATH"; then PKG_PATH=$PACKAGE; fi + debug "major $MAJOR minor $MINOR micro $MICRO" + VERSION=$MAJOR + if test ! -z "$MINOR"; then VERSION=$VERSION.$MINOR; else MINOR=0; fi + if test ! -z "$MICRO"; then VERSION=$VERSION.$MICRO; else MICRO=0; fi + + debug "major $MAJOR minor $MINOR micro $MICRO" + + for SUGGESTION in $PKG_PATH; do + COMMAND="$SUGGESTION" + + # don't check if asked not to + test -z "$NOCHECK" && { + echo -n " checking for $COMMAND >= $VERSION ... " + } || { + # we set a var with the same name as the package, but stripped of + # unwanted chars + VAR=`echo $PACKAGE | sed 's/-//g'` + debug "setting $VAR" + eval $VAR="$COMMAND" + return 0 + } + + debug "checking version with $COMMAND" + ($COMMAND --version) < /dev/null > /dev/null 2>&1 || + { + echo "not found." + continue + } + # strip everything that's not a digit, then use cut to get the first field + pkg_version=`$COMMAND --version|head -n 1|sed 's/^.*)[^0-9]*//'|cut -d' ' -f1` + debug "pkg_version $pkg_version" + # remove any non-digit characters from the version numbers to permit numeric + # comparison + pkg_major=`echo $pkg_version | cut -d. -f1 | sed s/[a-zA-Z\-].*//g` + pkg_minor=`echo $pkg_version | cut -d. -f2 | sed s/[a-zA-Z\-].*//g` + pkg_micro=`echo $pkg_version | cut -d. -f3 | sed s/[a-zA-Z\-].*//g` + test -z "$pkg_major" && pkg_major=0 + test -z "$pkg_minor" && pkg_minor=0 + test -z "$pkg_micro" && pkg_micro=0 + debug "found major $pkg_major minor $pkg_minor micro $pkg_micro" + + #start checking the version + debug "version check" + + # reset check + WRONG= + + if [ ! "$pkg_major" -gt "$MAJOR" ]; then + debug "major: $pkg_major <= $MAJOR" + if [ "$pkg_major" -lt "$MAJOR" ]; then + debug "major: $pkg_major < $MAJOR" + WRONG=1 + elif [ ! "$pkg_minor" -gt "$MINOR" ]; then + debug "minor: $pkg_minor <= $MINOR" + if [ "$pkg_minor" -lt "$MINOR" ]; then + debug "minor: $pkg_minor < $MINOR" + WRONG=1 + elif [ "$pkg_micro" -lt "$MICRO" ]; then + debug "micro: $pkg_micro < $MICRO" + WRONG=1 + fi + fi + fi + + if test ! -z "$WRONG"; then + echo "found $pkg_version, not ok !" + continue + else + echo "found $pkg_version, ok." + # we set a var with the same name as the package, but stripped of + # unwanted chars + VAR=`echo $PACKAGE | sed 's/-//g'` + debug "setting $VAR" + eval $VAR="$COMMAND" + return 0 + fi + done + + echo "not found !" + echo "You must have $PACKAGE installed to compile $package." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at $URL" + return 1; +} + +aclocal_check () +{ + # normally aclocal is part of automake + # so we expect it to be in the same place as automake + # so if a different automake is supplied, we need to adapt as well + # so how's about replacing automake with aclocal in the set var, + # and saving that in $aclocal ? + # note, this will fail if the actual automake isn't called automake* + # or if part of the path before it contains it + if [ -z "$automake" ]; then + echo "Error: no automake variable set !" + return 1 + else + aclocal=`echo $automake | sed s/automake/aclocal/` + debug "aclocal: $aclocal" + if [ "$aclocal" != "aclocal" ]; + then + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-aclocal=$aclocal" + fi + if [ ! -x `which $aclocal` ]; then + echo "Error: cannot execute $aclocal !" + return 1 + fi + fi +} + +autoheader_check () +{ + # same here - autoheader is part of autoconf + # use the same voodoo + if [ -z "$autoconf" ]; then + echo "Error: no autoconf variable set !" + return 1 + else + autoheader=`echo $autoconf | sed s/autoconf/autoheader/` + debug "autoheader: $autoheader" + if [ "$autoheader" != "autoheader" ]; + then + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-autoheader=$autoheader" + fi + if [ ! -x `which $autoheader` ]; then + echo "Error: cannot execute $autoheader !" + return 1 + fi + fi + +} +autoconf_2_52d_check () +{ + # autoconf 2.52d has a weird issue involving a yes:no error + # so don't allow it's use + test -z "$NOCHECK" && { + ac_version=`$autoconf --version|head -n 1|sed 's/^[a-zA-Z\.\ ()]*//;s/ .*$//'` + if test "$ac_version" = "2.52d"; then + echo "autoconf 2.52d has an issue with our current build." + echo "We don't know who's to blame however. So until we do, get a" + echo "regular version. RPM's of a working version are on the gstreamer site." + exit 1 + fi + } + return 0 +} + +die_check () +{ + # call with $DIE + # if set to 1, we need to print something helpful then die + DIE=$1 + if test "x$DIE" = "x1"; + then + echo + echo "- Please get the right tools before proceeding." + echo "- Alternatively, if you're sure we're wrong, run with --nocheck." + exit 1 + fi +} + +autogen_options () +{ + if test "x$1" = "x"; then + return 0 + fi + + while test "x$1" != "x" ; do + optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + case "$1" in + --noconfigure) + NOCONFIGURE=defined + AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --noconfigure" + echo "+ configure run disabled" + shift + ;; + --nocheck) + AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --nocheck" + NOCHECK=defined + echo "+ autotools version check disabled" + shift + ;; + --debug) + DEBUG=defined + AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --debug" + echo "+ debug output enabled" + shift + ;; + --prefix=*) + CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT --prefix=$optarg" + echo "+ passing --prefix=$optarg to configure" + shift + ;; + --prefix) + shift + echo "DEBUG: $1" + CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT --prefix=$1" + echo "+ passing --prefix=$1 to configure" + shift + ;; + + -h|--help) + echo "autogen.sh (autogen options) -- (configure options)" + echo "autogen.sh help options: " + echo " --noconfigure don't run the configure script" + echo " --nocheck don't do version checks" + echo " --debug debug the autogen process" + echo " --prefix will be passed on to configure" + echo + echo " --with-autoconf PATH use autoconf in PATH" + echo " --with-automake PATH use automake in PATH" + echo + echo "to pass options to configure, put them as arguments after -- " + exit 1 + ;; + --with-automake=*) + AUTOMAKE=$optarg + echo "+ using alternate automake in $optarg" + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-automake=$AUTOMAKE" + shift + ;; + --with-autoconf=*) + AUTOCONF=$optarg + echo "+ using alternate autoconf in $optarg" + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-autoconf=$AUTOCONF" + shift + ;; + --disable*|--enable*|--with*) + echo "+ passing option $1 to configure" + CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT $1" + shift + ;; + --) shift ; break ;; + *) echo "- ignoring unknown autogen.sh argument $1"; shift ;; + esac + done + + for arg do CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT $arg"; done + if test ! -z "$CONFIGURE_EXT_OPT" + then + echo "+ options passed to configure: $CONFIGURE_EXT_OPT" + fi +} + +toplevel_check () +{ + srcfile=$1 + test -f $srcfile || { + echo "You must run this script in the top-level $package directory" + exit 1 + } +} + + +tool_run () +{ + tool=$1 + options=$2 + run_if_fail=$3 + echo "+ running $tool $options..." + $tool $options || { + echo + echo $tool failed + eval $run_if_fail + exit 1 + } +} diff --git a/common/gst-xmlinspect.py b/common/gst-xmlinspect.py new file mode 100644 index 0000000000..0d7f696122 --- /dev/null +++ b/common/gst-xmlinspect.py @@ -0,0 +1,168 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +""" +examine all plugins and elements and output xml documentation for them +used as part of the plugin documentation build +""" + +import sys +import os +import pygst +pygst.require('0.10') +import gst + +INDENT_SIZE = 2 + +# all templates + +PAD_TEMPLATE = """ + %(name)s + %(direction)s + %(presence)s +
%(details)s
+
""" + +ELEMENT_TEMPLATE = """ + %(name)s + %(longname)s + %(class)s + %(description)s + %(author)s + +%(pads)s + +""" + +PLUGIN_TEMPLATE = """ + %(name)s + %(description)s + %(filename)s + %(basename)s + %(version)s + %(license)s + %(source)s + %(package)s + %(origin)s + +%(elements)s + +""" + +def xmlencode(line): + """ + Replace &, <, and > + """ + line = "&".join(line.split("&")) + line = "<".join(line.split("<")) + line = ">".join(line.split(">")) + return line + +def get_offset(indent): + return " " * INDENT_SIZE * indent + +def output_pad_template(pt, indent=0): + print "PAD TEMPLATE", pt.name_template + paddir = ("unknown","source","sink") + padpres = ("always","sometimes","request") + + d = { + 'name': xmlencode(pt.name_template), + 'direction': xmlencode(paddir[pt.direction]), + 'presence': xmlencode(padpres[pt.presence]), + 'details': xmlencode(pt.static_caps.string), + } + block = PAD_TEMPLATE % d + + offset = get_offset(indent) + return offset + ("\n" + offset).join(block.split("\n")) + +def output_element_factory(elf, indent=0): + print "ELEMENT", elf.get_name() + + padsoutput = [] + padtemplates = elf.get_static_pad_templates() + for padtemplate in padtemplates: + padsoutput.append(output_pad_template(padtemplate, indent)) + + d = { + 'name': xmlencode(elf.get_name()), + 'longname': xmlencode(elf.get_longname()), + 'class': xmlencode(elf.get_klass()), + 'description': xmlencode(elf.get_description()), + 'author': xmlencode(elf.get_author()), + 'pads': "\n".join(padsoutput), + } + block = ELEMENT_TEMPLATE % d + + offset = get_offset(indent) + return offset + ("\n" + offset).join(block.split("\n")) + +def output_plugin(plugin, indent=0): + print "PLUGIN", plugin.get_name() + version = plugin.get_version() + + elements = {} + gst.debug('getting features for plugin %s' % plugin.get_name()) + registry = gst.registry_get_default() + features = registry.get_feature_list_by_plugin(plugin.get_name()) + gst.debug('plugin %s has %d features' % (plugin.get_name(), len(features))) + for feature in features: + if isinstance(feature, gst.ElementFactory): + elements[feature.get_name()] = feature + #gst.debug("got features") + + elementsoutput = [] + keys = elements.keys() + keys.sort() + for name in keys: + feature = elements[name] + elementsoutput.append(output_element_factory(feature, indent + 2)) + + filename = plugin.get_filename() + basename = filename + if basename: + basename = os.path.basename(basename) + d = { + 'name': xmlencode(plugin.get_name()), + 'description': xmlencode(plugin.get_description()), + 'filename': filename, + 'basename': basename, + 'version': version, + 'license': xmlencode(plugin.get_license()), + 'source': xmlencode(plugin.get_source()), + 'package': xmlencode(plugin.get_package()), + 'origin': xmlencode(plugin.get_origin()), + 'elements': "\n".join(elementsoutput), + } + block = PLUGIN_TEMPLATE % d + + offset = get_offset(indent) + return offset + ("\n" + offset).join(block.split("\n")) + +def main(): + if len(sys.argv) == 1: + sys.stderr.write("Please specify a source module to inspect") + sys.exit(1) + source = sys.argv[1] + + if len(sys.argv) > 2: + os.chdir(sys.argv[2]) + + registry = gst.registry_get_default() + all = registry.get_plugin_list() + for plugin in all: + gst.debug("inspecting plugin %s from source %s" % ( + plugin.get_name(), plugin.get_source())) + # this skips gstcoreelements, with bin and pipeline + if plugin.get_filename() is None: + continue + if plugin.get_source() != source: + continue + + filename = "plugin-%s.xml" % plugin.get_name() + handle = open(filename, "w") + handle.write(output_plugin(plugin)) + handle.close() + +main() diff --git a/common/gst.supp b/common/gst.supp new file mode 100644 index 0000000000..ce0daa2568 --- /dev/null +++ b/common/gst.supp @@ -0,0 +1,1660 @@ +### this file contains suppressions for valgrind when running +### the gstreamer unit tests +### it might be useful for wider use as well + +### syscall suppressions + +{ + + Memcheck:Param + clone(parent_tidptr) + fun:clone + fun:clone +} + +{ + + Memcheck:Param + clone(child_tidptr) + fun:clone + fun:clone +} + +{ + + Memcheck:Param + clone(tlsinfo) + fun:clone + fun:clone +} + +### glibc suppressions + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open + fun:gst_plugin_load_file +} + +# glibc does not deallocate thread-local storage + +{ + + Memcheck:Leak + fun:calloc + fun:_dl_allocate_tls + fun:pthread_create@@* +} + +# I get an extra stack entry on x86/dapper +{ + + Memcheck:Leak + fun:calloc + obj:/lib/ld-2.3.*.so + fun:_dl_allocate_tls + fun:pthread_create@@* +} + + +{ + + Memcheck:Cond + fun:strstr + fun:__pthread_initialize_minimal + obj:/lib/libpthread-*.so + obj:/lib/libpthread-*.so + fun:call_init + fun:_dl_init + obj:/lib/ld-*.so +} + +# a thread-related free problem in glibc from Edgard +{ + __libc_freeres_rw_acess + Memcheck:Addr4 + obj:* + obj:* + obj:* + obj:* + obj:* + fun:__libc_freeres +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so +} + +# g_module_open-related problems +{ + + Memcheck:Addr2 + fun:memcpy + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open + fun:gst_plugin_load_file + fun:gst_registry_scan_path_level + fun:gst_registry_scan_path_level + fun:gst_registry_scan_path_level + fun:init_post + fun:g_option_context_parse + fun:gst_init_check + fun:gst_init + fun:gst_check_init + fun:main +} + +{ + + Memcheck:Addr4 + fun:memcpy + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open + fun:gst_plugin_load_file + fun:gst_registry_scan_path_level + fun:gst_registry_scan_path_level + fun:gst_registry_scan_path_level + fun:init_post + fun:g_option_context_parse + fun:gst_init_check + fun:gst_init + fun:gst_check_init + fun:main +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:do_sym + fun:_dl_sym + fun:dlsym_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlsym + fun:g_module_symbol + fun:g_module_open + fun:gst_plugin_load_file +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open + fun:gst_plugin_load_file +} +{ + + Memcheck:Cond + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open + fun:gst_plugin_load_file + fun:gst_plugin_load_by_name + fun:gst_plugin_feature_load +} + +{ + + Memcheck:Leak + fun:malloc + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open + fun:gst_plugin_load_file + fun:gst_plugin_load_by_name +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:do_sym + fun:_dl_sym + fun:dlsym_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlsym + fun:g_module_symbol + fun:g_module_open +} + +{ + + Memcheck:Param + futex(uaddr2) + fun:pthread_once + obj:/lib/libc-2.3.*.so + obj:/lib/libc-2.3.*.so + fun:mbsnrtowcs + fun:vfprintf + fun:vsprintf + fun:sprintf + obj:/lib/libc-2.3.*.so + fun:tmpfile + fun:setup_pipe + fun:setup_messaging_with_key + fun:setup_messaging +} + +# valgrind doesn't allow me to specify a suppression for Addr1, Addr2, Addr4 +# as Addr*, so 3 copies for that; and then 2 of each for that pesky memcpy +{ + + Memcheck:Addr1 + fun:_dl_signal_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} + +{ + + Memcheck:Addr2 + fun:_dl_signal_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} +{ + + Memcheck:Addr4 + fun:_dl_signal_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} + +{ + + Memcheck:Addr1 + fun:memcpy + fun:_dl_signal_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} + +{ + + Memcheck:Addr2 + fun:memcpy + fun:_dl_signal_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} +{ + + Memcheck:Addr4 + fun:memcpy + fun:_dl_signal_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} + +{ + + Memcheck:Addr8 + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/libc-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:_dl_open + obj:/lib/libdl-2.3.*.so + obj:/lib/ld-2.3.*.so +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.*.so + obj:/lib/libc-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:_dl_open + obj:/lib/libdl-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/libdl-2.3.*.so + fun:dlopen + fun:g_module_open + fun:gst_plugin_load_file + fun:gst_plugin_load_by_name + fun:gst_plugin_feature_load +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/tls/i686/cmov/libdl-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libdl-2.3.6.so + fun:dlopen +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/tls/i686/cmov/libdl-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libdl-2.3.6.so + fun:dlopen +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/tls/i686/cmov/libdl-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libdl-2.3.6.so + fun:dlopen +} + +### glib suppressions +{ + + Memcheck:Cond + fun:g_parse_debug_string + obj:/usr/lib*/libglib-2.0.so.* + fun:g_slice_alloc + fun:g_slice_alloc0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + fun:g_quark_from_string + obj:* + obj:* + fun:g_type_register_fundamental + obj:* + fun:g_type_init_with_debug_flags + fun:g_type_init + fun:init_pre +} + +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + obj:* + obj:* + fun:g_type_register_fundamental +} + +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + obj:* + obj:* + fun:g_type_init_with_debug_flags +} + +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:g_slice_alloc + obj:* + obj:* + fun:g_type_init_with_debug_flags +} + +#pthread memleaks + +{ + Thread creation leak + Memcheck:Leak + fun:calloc + fun:allocate_dtv + fun:_dl_allocate* + fun:_dl_allocate* + fun:__pthread_initialize_minimal +} + +{ + Thread management leak + Memcheck:Leak + fun:calloc + fun:allocate_dtv + fun:_dl_allocate* + fun:_dl_allocate* + fun:__pthread_* +} + +{ + Thread management leak 2 + Memcheck:Leak + fun:memalign + fun:_dl_allocate* + fun:_dl_allocate* + fun:__pthread_* +} + +{ + pthread_create Syscall param write(buf) points to uninitialised byte(s) + Memcheck:Param + write(buf) + fun:pthread_create@@GLIBC_2.2.5 + fun:g_thread_create* + +} + +# nss_parse_* memleak (used by g_option_context_parse) +{ + nss_parse_* memleak + Memcheck:Leak + fun:malloc + fun:nss_parse_service_list + fun:__nss_database_lookup +} + +# liboil suppressions +{ + + Memcheck:Value8 + obj:/usr/lib/liboil-0.3.so.0.1.0 + obj:/usr/lib/liboil-0.3.so.0.1.0 + obj:/usr/lib/liboil-0.3.so.0.1.0 + fun:oil_cpu_fault_check_try + fun:oil_test_check_impl + fun:oil_class_optimize + fun:oil_optimize_all + fun:oil_init +} + +{ + + Memcheck:Addr8 + obj:/lib/ld-2.3.6.so +} + +{ + + Memcheck:Param + futex(uaddr2) + fun:pthread_once + obj:/lib/libc-2.3.6.so + obj:/lib/libc-2.3.6.so + fun:setlocale + fun:init_pre + fun:g_option_context_parse + fun:gst_init_check + fun:gst_init + fun:gst_check_init + fun:main +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/libdl-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/libdl-2.3.6.so + fun:dlopen + fun:g_module_open + fun:gst_plugin_load_file +} +# this exists in a bunch of different variations, hence the short tail/trace +{ + + Memcheck:Addr4 + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so +} +{ + + Memcheck:Addr8 + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so +} + +# More edgy suppressions (Mike) +{ + + Memcheck:Cond + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + fun:dlopen_doit + obj:/lib/ld-2.4.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + fun:dlopen_doit + obj:/lib/ld-2.4.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + fun:do_sym + fun:_dl_sym +} + +# This one's overly general, but there's zero other information in the stack +# trace - just these five lines! +{ + + Memcheck:Cond + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so +} + +{ + + Memcheck:Leak + fun:calloc + obj:/lib/ld-2.4.so + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_2.1 +} + +# TLS leaks for feisty/x86 +{ + + Memcheck:Leak + fun:calloc + fun:allocate_dtv + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_2.1 +} + +{ + + Memcheck:Leak + fun:calloc + obj:/usr/lib/libcdio.so.6.0.1 + fun:cdio_open_am_linux + obj:/usr/lib/libcdio.so.6.0.1 + fun:cdio_open_am +} + +{ + + Memcheck:Addr8 + obj:/lib/ld-2.5.so +} + +{ + + Memcheck:Cond + fun:snd_pcm_direct_shm_create_or_connect + fun:snd_pcm_dsnoop_open + fun:_snd_pcm_dsnoop_open + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_plug_open + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_asym_open + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 +} + +{ + + Memcheck:Cond + fun:snd_pcm_hw_param_set_near + fun:set_hwparams +} + +{ + + Memcheck:Cond + fun:_snd_pcm_hw_param_set_min + fun:snd_pcm_hw_param_set_min + fun:snd_pcm_hw_param_set_near + fun:set_hwparams +} + +{ + + Memcheck:Cond + fun:_snd_pcm_hw_param_set_min + fun:snd_pcm_hw_param_set_min + fun:snd_pcm_hw_param_set_near + fun:set_hwparams +} + +{ + + Memcheck:Cond + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_hw_param_set_near + fun:set_hwparams +} +{ + + Memcheck:Cond + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_close + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Cond + fun:snd_pcm_direct_shm_create_or_connect + fun:snd_pcm_dmix_open + fun:_snd_pcm_dmix_open + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_softvol_open + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_plug_open + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_asym_open + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:malloc + fun:strdup + fun:snd_dlobj_cache_add + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:snd_pcm_dsnoop_open + fun:_snd_pcm_dsnoop_open + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_plug_open + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_asym_open + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 +} +# Catch about 15 variations on inserting info into an ALSA +# internal cache +{ + + Memcheck:Leak + fun:malloc + fun:snd_dlobj_cache_add + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:malloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks +} +{ + + Memcheck:Leak + fun:malloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:malloc + obj:/lib/libc*.so + fun:__nss_database_lookup + obj:* + obj:* + fun:getgrnam_r + fun:getgrnam + fun:snd_pcm_direct_parse_open_conf +} + +{ + + Memcheck:Leak + fun:calloc + fun:_XCBInitDisplayLock + fun:XOpenDisplay +} + +# GConf internal initialisations related to getting the default client. +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_tcval + obj:/usr/lib/libORBit-2.so.* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:CORBA_ORB_string_to_object + obj:/usr/lib/libgconf-2.so.* + fun:gconf_get_current_lock_holder + fun:gconf_activate_server + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_tcval + obj:/usr/lib/libORBit-2.so.* + fun:PortableServer_POA_servant_to_reference + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_tcval + obj:/usr/lib/libORBit-2.so.* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:CORBA_ORB_string_to_object + obj:/usr/lib/libgconf-2.so.* + fun:gconf_get_current_lock_holder + fun:gconf_activate_server + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + obj:/usr/lib/libORBit-2.so.* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:ORBit_demarshal_value + obj:/usr/lib/libORBit-2.so.* + fun:ORBit_small_invoke_stub + fun:ConfigServer_get_default_database + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + obj:/usr/lib/libORBit-2.so.* + fun:IOP_generate_profiles + fun:ORBit_marshal_object + fun:ORBit_marshal_value + obj:/usr/lib/libORBit-2.so.* + fun:ORBit_small_invoke_stub + fun:ConfigServer_add_client + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_by_tc + obj:/usr/lib/libORBit-2.so.* + fun:PortableServer_POA_servant_to_reference + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_by_tc + obj:/usr/lib/libORBit-2.so.* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:CORBA_ORB_string_to_object + obj:/usr/lib/libgconf-2.so.* + fun:gconf_get_current_lock_holder + fun:gconf_activate_server + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} + +# Some libORBit/bonobo initialisation stuff +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:ORBit_alloc_string + fun:CORBA_string_dup + fun:Bonobo_ActivationEnvValue_set + fun:bonobo_activation_init_activation_env + fun:bonobo_activation_orb_init + fun:bonobo_activation_init +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_alloc* + obj:/usr/lib/libORBit-2.so* + fun:PortableServer_POA_servant_to_reference + obj:/usr/lib/libbonobo-2.so* +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_tcval + fun:ORBit_small_allocbuf + fun:ORBit_adaptor_setup + obj:/usr/lib/libORBit-2.so* + fun:ORBit_POA_setup_root + fun:ORBit_init_internals + fun:CORBA_ORB_init +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_tcval + fun:ORBit_adaptor_setup + obj:/usr/lib/libORBit-2.so* + fun:ORBit_POA_setup_root + fun:ORBit_init_internals + fun:CORBA_ORB_init +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_allocbuf + fun:bonobo_activation_init_activation_env + fun:bonobo_activation_orb_init + fun:bonobo_activation_init +} + +# More GConf stuff from the FC5 buildbot, mostly variations on the +# above stack traces +{ + + Memcheck:Param + writev(vector[...]) + fun:writev + obj:/usr/lib/libORBit-2.so* + fun:link_connection_writev + fun:giop_send_buffer_write + obj:/usr/lib/libORBit-2.so* + fun:ORBit_small_invoke_stub + fun:ORBit_small_invoke_stub_n + fun:ORBit_c_stub_invoke + fun:ConfigServer_ping + fun:gconf_activate_server + obj:/usr/lib/libgconf-2.so* + obj:/usr/lib/libgconf-2.so* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_alloc* + obj:/usr/lib/libORBit-2.so* + fun:PortableServer_POA_servant_to_reference + obj:/usr/lib/libgconf-2.so* + obj:/usr/lib/libgconf-2.so* + obj:/usr/lib/libgconf-2.so* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_alloc + obj:/usr/lib/libORBit-2.so* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:CORBA_ORB_string_to_object + obj:/usr/lib/libgconf-2.so* + fun:gconf_get_current_lock_holder + fun:gconf_activate_server + obj:/usr/lib/libgconf-2.so* + obj:/usr/lib/libgconf-2.so* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_alloc* + obj:/usr/lib/libORBit-2.so* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:CORBA_ORB_string_to_object + obj:/usr/lib/libgconf-2.so* + fun:gconf_get_current_lock_holder + fun:gconf_activate_server + obj:/usr/lib/libgconf-2.so* + obj:/usr/lib/libgconf-2.so* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_alloc* + obj:/usr/lib/libORBit-2.so* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:ORBit_demarshal_value + obj:/usr/lib/libORBit-2.so* + fun:ORBit_small_invoke_stub + fun:ORBit_small_invoke_stub_n + fun:ORBit_c_stub_invoke + fun:ConfigServer_get_default_database + obj:/usr/lib/libgconf-2.so* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_alloc* + obj:/usr/lib/libORBit-2.so* + fun:ORBit_OAObject_object_to_objkey + fun:IOP_generate_profiles + fun:ORBit_marshal_object + fun:ORBit_marshal_value + obj:/usr/lib/libORBit-2.so* + fun:ORBit_small_invoke_stub + fun:ORBit_small_invoke_stub_n + fun:ORBit_c_stub_invoke + fun:ConfigServer_add_client + obj:/usr/lib/libgconf-2.so* + obj:/usr/lib/libgconf-2.so* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:malloc + obj:/lib/libc-*.so + fun:__nss_database_lookup + obj:* + obj:* + fun:getpwnam_r + fun:g_get_any_init_do + fun:g_get_home_dir +} +{ + + Memcheck:Leak + fun:malloc + obj:/lib/libc-*.so + fun:__nss_database_lookup + obj:* + obj:* + fun:getpwnam_r + fun:g_get_any_init_do + fun:g_get_user_name +} +{ + + Memcheck:Leak + fun:malloc + obj:/lib/libc-*.so + fun:__nss_database_lookup + obj:* + obj:* + fun:getpwnam_r + obj:/usr/lib*/libglib-2.0.so.* + fun:g_get_tmp_dir +} + + +## Some Fontconfig errors. +{ + + Memcheck:Leak + fun:malloc + fun:FcPatternObjectInsertElt + fun:FcPatternObjectAddWithBinding + fun:FcPatternAppend + fun:FcEndElement + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + fun:XML_ParseBuffer + fun:FcConfigParseAndLoad + fun:FcConfigParseAndLoad + fun:FcParseInclude + fun:FcEndElement + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + fun:XML_ParseBuffer + fun:FcConfigParseAndLoad +} +{ + + Memcheck:Leak + fun:malloc + fun:FcStrCopy + fun:FcEndElement + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + fun:XML_ParseBuffer + fun:FcConfigParseAndLoad + fun:FcConfigParseAndLoad + fun:FcParseInclude + fun:FcEndElement + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + fun:XML_ParseBuffer + fun:FcConfigParseAndLoad + fun:FcInitLoadConfig + fun:FcInitLoadConfigAndFonts +} + diff --git a/common/gstdoc-scangobj b/common/gstdoc-scangobj new file mode 100755 index 0000000000..0ff1b54960 --- /dev/null +++ b/common/gstdoc-scangobj @@ -0,0 +1,1562 @@ +#!/usr/bin/perl -w +# -*- cperl -*- +# +# gtk-doc - GTK DocBook documentation generator. +# Copyright (C) 1998 Damon Chaplin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# +# This gets information about object heirarchies and signals +# by compiling a small C program. CFLAGS and LDFLAGS must be +# set appropriately before running this script. +# +# NOTE: the lookup_signal_arg_names() function contains the argument names of +# standard GTK signal handlers. This may need to be updated for new +# GTK signals or Gnome widget signals. + +use Getopt::Long; + +unshift @INC, '/usr/share/gtk-doc/data'; +require "gtkdoc-common.pl"; + +# Options + +# name of documentation module +my $MODULE; +my $OUTPUT_DIR; +my $PRINT_VERSION; +my $PRINT_HELP; +my $TYPE_INIT_FUNC="g_type_init ()"; + +# --nogtkinit is deprecated, as it is the default now anyway. +%optctl = (module => \$MODULE, + source => \$SOURCE, + types => \$TYPES_FILE, + nogtkinit => \$NO_GTK_INIT, + 'type-init-func' => \$TYPE_INIT_FUNC, + 'output-dir' => \$OUTPUT_DIR, + 'version' => \$PRINT_VERSION, + 'help' => \$PRINT_HELP); + +GetOptions(\%optctl, "module=s", "source=s", "types:s", "output-dir:s", "nogtkinit", "type-init-func:s", "version", "help"); + +if ($NO_GTK_INIT) { + # Do nothing. This just avoids a warning. +} + +if ($PRINT_VERSION) { + print "1.5\n"; + exit 0; +} + +if (!$MODULE) { + $PRINT_HELP = 1; +} + +if ($PRINT_HELP) { + print "gstdoc-scangobj version 1.5\n"; + print "\n--module=MODULE_NAME Name of the doc module being parsed"; + print "\n--source=SOURCE_NAME Name of the source module for plugins"; + print "\n--types=FILE The name of the file to store the types in"; + print "\n--type-init-func=FUNC The init function to call instead of g_type_init ()"; + print "\n--output-dir=DIRNAME The directory where the results are stored"; + print "\n--version Print the version of this program"; + print "\n--help Print this help\n"; + exit 0; +} + +$OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : "."; + +# THOMAS: dynamic types; only use types file for headers + $TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types"; + +open (TYPES, $TYPES_FILE) || die "Cannot open $TYPES_FILE: $!\n"; +open (OUTPUT, ">$MODULE-scan.c") || die "Cannot open $MODULE-scan.c: $!\n"; + +my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals"; +my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new"; +my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy"; +my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new"; +my $old_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces"; +my $new_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces.new"; +my $old_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites"; +my $new_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites.new"; +my $old_args_filename = "$OUTPUT_DIR/$MODULE.args"; +my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new"; + +# write a C program to scan the types + +$includes = ""; +#@types = (); + +for () { + if (/^#include/) { + $includes .= $_; +# } elsif (/^%/) { +# next; +# } elsif (/^\s*$/) { +# next; +# } else { +# chomp; +# push @types, $_; + } +} + +#$ntypes = @types + 1; + +print OUTPUT < +#include +#include +#include + +$includes +#ifdef GTK_IS_WIDGET_CLASS +#include +#endif +GType *object_types = NULL; + +static GType * +get_object_types (void) +{ + GList *plugins = NULL; + GList *factories = NULL; + GList *l; + GstElementFactory *factory = NULL; + + gint i = 0; + + /* get a list of features from plugins in our source module */ + plugins = gst_registry_get_plugin_list (gst_registry_get_default()); + + while (plugins) { + GList *features; + GstPlugin *plugin; + const gchar *source; + + plugin = (GstPlugin *) (plugins->data); + plugins = g_list_next (plugins); + source = gst_plugin_get_source (plugin); + g_print ("source: %s\\n", source); + if (!source || strcmp (gst_plugin_get_source (plugin), "$SOURCE") != 0) { + continue; + } + + features = + gst_registry_get_feature_list_by_plugin (gst_registry_get_default (), + plugin->desc.name); + while (features) { + GstPluginFeature *feature; + feature = GST_PLUGIN_FEATURE (features->data); + feature = gst_plugin_feature_load (feature); + if (!feature) { + g_warning ("Could not load plugin feature %s", + gst_plugin_feature_get_name (feature)); + } + + if (GST_IS_ELEMENT_FACTORY (feature)) { + factory = GST_ELEMENT_FACTORY (feature); + factories = g_list_append (factories, factory); + } + features = g_list_next (features); + } + } + + g_message ("number of element factories: %d", g_list_length (factories)); + + /* allocate the object_types array to hold them */ + object_types = g_new0 (GType, g_list_length (factories)+1); + + l = factories; + i = 0; + + /* fill it */ + while (l) { + GType type; + factory = GST_ELEMENT_FACTORY (l->data); + g_message ("adding type for factory %s", gst_element_factory_get_longname (factory)); + type = gst_element_factory_get_element_type (factory); + g_message ("adding type %p", (void *) type); + object_types[i] = type; + i++; + l = g_list_next (l); + } + object_types[i] = 0; +EOT + +print OUTPUT <\\n%s::%s\\n%s\\n%s\\n%s\\n\\n", + object_name, query_info.signal_name, ret_type_buffer, flags, buffer); +} + + +/* Returns the type name to use for a signal argument or return value, given + the GtkType from the signal info. It also sets is_pointer to TRUE if the + argument needs a '*' since it is a pointer. */ +static const gchar * +get_type_name (GType type, gboolean * is_pointer) +{ + const gchar *type_name; + + *is_pointer = FALSE; + type_name = g_type_name (type); + + switch (type) { + case G_TYPE_NONE: + case G_TYPE_CHAR: + case G_TYPE_UCHAR: + case G_TYPE_BOOLEAN: + case G_TYPE_INT: + case G_TYPE_UINT: + case G_TYPE_LONG: + case G_TYPE_ULONG: + case G_TYPE_FLOAT: + case G_TYPE_DOUBLE: + case G_TYPE_POINTER: + /* These all have normal C type names so they are OK. */ + return type_name; + + case G_TYPE_STRING: + /* A GtkString is really a gchar*. */ + *is_pointer = TRUE; + return "gchar"; + + case G_TYPE_ENUM: + case G_TYPE_FLAGS: + /* We use a gint for both of these. Hopefully a subtype with a decent + name will be registered and used instead, as GTK+ does itself. */ + return "gint"; + + case G_TYPE_BOXED: + /* The boxed type shouldn't be used itself, only subtypes. Though we + return 'gpointer' just in case. */ + return "gpointer"; + + case G_TYPE_PARAM: + /* A GParam is really a GParamSpec*. */ + *is_pointer = TRUE; + return "GParamSpec"; + + default: + break; + } + + /* For all GObject subclasses we can use the class name with a "*", + e.g. 'GtkWidget *'. */ + if (g_type_is_a (type, G_TYPE_OBJECT)) + *is_pointer = TRUE; + + if (G_TYPE_IS_CLASSED (type)) + *is_pointer = TRUE; + + /* All boxed subtypes will be pointers as well. */ + if (g_type_is_a (type, G_TYPE_BOXED)) + *is_pointer = TRUE; + + /* All pointer subtypes will be pointers as well. */ + if (g_type_is_a (type, G_TYPE_POINTER)) + *is_pointer = TRUE; + + return type_name; +} + + +static const gchar * +get_gdk_event (const gchar * signal_name) +{ + static const gchar *GbGDKEvents[] = + { + "button_press_event", "GdkEventButton", + "button_release_event", "GdkEventButton", + "motion_notify_event", "GdkEventMotion", + "delete_event", "GdkEvent", + "destroy_event", "GdkEvent", + "expose_event", "GdkEventExpose", + "key_press_event", "GdkEventKey", + "key_release_event", "GdkEventKey", + "enter_notify_event", "GdkEventCrossing", + "leave_notify_event", "GdkEventCrossing", + "configure_event", "GdkEventConfigure", + "focus_in_event", "GdkEventFocus", + "focus_out_event", "GdkEventFocus", + "map_event", "GdkEvent", + "unmap_event", "GdkEvent", + "property_notify_event", "GdkEventProperty", + "selection_clear_event", "GdkEventSelection", + "selection_request_event", "GdkEventSelection", + "selection_notify_event", "GdkEventSelection", + "proximity_in_event", "GdkEventProximity", + "proximity_out_event", "GdkEventProximity", + "drag_begin_event", "GdkEventDragBegin", + "drag_request_event", "GdkEventDragRequest", + "drag_end_event", "GdkEventDragRequest", + "drop_enter_event", "GdkEventDropEnter", + "drop_leave_event", "GdkEventDropLeave", + "drop_data_available_event", "GdkEventDropDataAvailable", + "other_event", "GdkEventOther", + "client_event", "GdkEventClient", + "no_expose_event", "GdkEventNoExpose", + "visibility_notify_event", "GdkEventVisibility", + "window_state_event", "GdkEventWindowState", + "scroll_event", "GdkEventScroll", + NULL + }; + + gint i; + + for (i = 0; GbGDKEvents[i]; i += 2) + { + if (!strcmp (signal_name, GbGDKEvents[i])) + return GbGDKEvents[i + 1]; + } + return "GdkEvent"; +} + + +/* This returns argument names to use for some known GTK signals. + It is passed a widget name, e.g. 'GtkCList' and a signal name, e.g. + 'select_row' and it returns a pointer to an array of argument types and + names. */ +static const gchar ** +lookup_signal_arg_names (const gchar * type, const gchar * signal_name) +{ + /* Each arg array starts with the object type name and the signal name, + and then signal arguments follow. */ + static const gchar *GbArgTable[][16] = + { + {"GtkCList", "select_row", + "gint row", + "gint column", + "GdkEventButton *event"}, + {"GtkCList", "unselect_row", + "gint row", + "gint column", + "GdkEventButton *event"}, + {"GtkCList", "click_column", + "gint column"}, + + {"GtkCList", "resize_column", + "gint column", + "gint width"}, + + {"GtkCList", "extend_selection", + "GtkScrollType scroll_type", + "gfloat position", + "gboolean auto_start_selection"}, + {"GtkCList", "scroll_vertical", + "GtkScrollType scroll_type", + "gfloat position"}, + {"GtkCList", "scroll_horizontal", + "GtkScrollType scroll_type", + "gfloat position"}, + + {"GtkCTree", "tree_select_row", + "GtkCTreeNode *node", + "gint column"}, + {"GtkCTree", "tree_unselect_row", + "GtkCTreeNode *node", + "gint column"}, + {"GtkCTree", "tree_expand", + "GtkCTreeNode *node"}, + {"GtkCTree", "tree_collapse", + "GtkCTreeNode *node"}, + {"GtkCTree", "tree_move", + "GtkCTreeNode *node", + "GtkCTreeNode *new_parent", + "GtkCTreeNode *new_sibling"}, + {"GtkCTree", "change_focus_row_expansion", + "GtkCTreeExpansionType expansion"}, + + {"GtkEditable", "insert_text", + "gchar *new_text", + "gint new_text_length", + "gint *position"}, + {"GtkEditable", "delete_text", + "gint start_pos", + "gint end_pos"}, + {"GtkEditable", "set_editable", + "gboolean is_editable"}, + {"GtkEditable", "move_cursor", + "gint x", + "gint y"}, + {"GtkEditable", "move_word", + "gint num_words"}, + {"GtkEditable", "move_page", + "gint x", + "gint y"}, + {"GtkEditable", "move_to_row", + "gint row"}, + {"GtkEditable", "move_to_column", + "gint column"}, + + {"GtkEditable", "kill_char", + "gint direction"}, + {"GtkEditable", "kill_word", + "gint direction"}, + {"GtkEditable", "kill_line", + "gint direction"}, + + + {"GtkInputDialog", "enable_device", + "GdkDevice *deviceid"}, + {"GtkInputDialog", "disable_device", + "GdkDevice *deviceid"}, + + {"GtkListItem", "extend_selection", + "GtkScrollType scroll_type", + "gfloat position", + "gboolean auto_start_selection"}, + {"GtkListItem", "scroll_vertical", + "GtkScrollType scroll_type", + "gfloat position"}, + {"GtkListItem", "scroll_horizontal", + "GtkScrollType scroll_type", + "gfloat position"}, + + {"GtkMenuShell", "move_current", + "GtkMenuDirectionType direction"}, + {"GtkMenuShell", "activate_current", + "gboolean force_hide"}, + + + {"GtkNotebook", "switch_page", + "GtkNotebookPage *page", + "guint page_num"}, + {"GtkStatusbar", "text_pushed", + "guint context_id", + "gchar *text"}, + {"GtkStatusbar", "text_popped", + "guint context_id", + "gchar *text"}, + {"GtkTipsQuery", "widget_entered", + "GtkWidget *widget", + "gchar *tip_text", + "gchar *tip_private"}, + {"GtkTipsQuery", "widget_selected", + "GtkWidget *widget", + "gchar *tip_text", + "gchar *tip_private", + "GdkEventButton *event"}, + {"GtkToolbar", "orientation_changed", + "GtkOrientation orientation"}, + {"GtkToolbar", "style_changed", + "GtkToolbarStyle style"}, + {"GtkWidget", "draw", + "GdkRectangle *area"}, + {"GtkWidget", "size_request", + "GtkRequisition *requisition"}, + {"GtkWidget", "size_allocate", + "GtkAllocation *allocation"}, + {"GtkWidget", "state_changed", + "GtkStateType state"}, + {"GtkWidget", "style_set", + "GtkStyle *previous_style"}, + + {"GtkWidget", "install_accelerator", + "gchar *signal_name", + "gchar key", + "gint modifiers"}, + + {"GtkWidget", "add_accelerator", + "guint accel_signal_id", + "GtkAccelGroup *accel_group", + "guint accel_key", + "GdkModifierType accel_mods", + "GtkAccelFlags accel_flags"}, + + {"GtkWidget", "parent_set", + "GtkObject *old_parent"}, + + {"GtkWidget", "remove_accelerator", + "GtkAccelGroup *accel_group", + "guint accel_key", + "GdkModifierType accel_mods"}, + {"GtkWidget", "debug_msg", + "gchar *message"}, + {"GtkWindow", "move_resize", + "gint *x", + "gint *y", + "gint width", + "gint height"}, + {"GtkWindow", "set_focus", + "GtkWidget *widget"}, + + {"GtkWidget", "selection_get", + "GtkSelectionData *data", + "guint info", + "guint time"}, + {"GtkWidget", "selection_received", + "GtkSelectionData *data", + "guint time"}, + + {"GtkWidget", "drag_begin", + "GdkDragContext *drag_context"}, + {"GtkWidget", "drag_end", + "GdkDragContext *drag_context"}, + {"GtkWidget", "drag_data_delete", + "GdkDragContext *drag_context"}, + {"GtkWidget", "drag_leave", + "GdkDragContext *drag_context", + "guint time"}, + {"GtkWidget", "drag_motion", + "GdkDragContext *drag_context", + "gint x", + "gint y", + "guint time"}, + {"GtkWidget", "drag_drop", + "GdkDragContext *drag_context", + "gint x", + "gint y", + "guint time"}, + {"GtkWidget", "drag_data_get", + "GdkDragContext *drag_context", + "GtkSelectionData *data", + "guint info", + "guint time"}, + {"GtkWidget", "drag_data_received", + "GdkDragContext *drag_context", + "gint x", + "gint y", + "GtkSelectionData *data", + "guint info", + "guint time"}, + + {NULL} + }; + + gint i; + + for (i = 0; GbArgTable[i][0]; i++) + { +#if 1 + if (!strcmp (type, GbArgTable[i][0]) + && !strcmp (signal_name, GbArgTable[i][1])) + return &GbArgTable[i][2]; +#endif + } + return NULL; +} + +/* This outputs the hierarchy of all objects which have been initialized, + i.e. by calling their XXX_get_type() initialization function. */ +static void +output_object_hierarchy (void) +{ + FILE *fp; + gint i; + + fp = fopen (hierarchy_filename, "w"); + if (fp == NULL) + { + g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, strerror(errno)); + return; + } + output_hierarchy (fp, G_TYPE_OBJECT, 0); + output_hierarchy (fp, G_TYPE_INTERFACE, 0); + + for (i=0; object_types[i]; i++) { + if (!g_type_parent (object_types[i]) && + (object_types[i] != G_TYPE_OBJECT) && + (object_types[i] != G_TYPE_INTERFACE) + ) { + output_hierarchy (fp, object_types[i], 0); + } + } + + fclose (fp); +} + +/* This is called recursively to output the hierarchy of a widget. */ +static void +output_hierarchy (FILE *fp, + GType type, + guint level) +{ + guint i; + GType *children; + guint n_children; + + if (!type) + return; + + for (i = 0; i < level; i++) + fprintf (fp, " "); + fprintf (fp, g_type_name (type)); + fprintf (fp, "\\n"); + + children = g_type_children (type, &n_children); + + for (i=0; i < n_children; i++) + output_hierarchy (fp, children[i], level + 1); + + g_free (children); +} + +static void output_object_interfaces (void) +{ + FILE *fp; + + fp = fopen (interfaces_filename, "w"); + if (fp == NULL) + { + g_warning ("Couldn't open output file: %s : %s", interfaces_filename, strerror(errno)); + return; + } + output_interfaces (fp, G_TYPE_OBJECT); + fclose (fp); +} + +static void +output_interfaces (FILE *fp, + GType type) +{ + guint i; + GType *children, *interfaces; + guint n_children, n_interfaces; + + if (!type) + return; + + interfaces = g_type_interfaces (type, &n_interfaces); + + if (n_interfaces > 0) + { + fprintf (fp, g_type_name (type)); + for (i=0; i < n_interfaces; i++) + fprintf (fp, " %s", g_type_name (interfaces[i])); + fprintf (fp, "\\n"); + } + g_free (interfaces); + + children = g_type_children (type, &n_children); + + for (i=0; i < n_children; i++) + output_interfaces (fp, children[i]); + + g_free (children); +} + +static void output_interface_prerequisites (void) +{ + FILE *fp; + + fp = fopen (prerequisites_filename, "w"); + if (fp == NULL) + { + g_warning ("Couldn't open output file: %s : %s", prerequisites_filename, strerror(errno)); + return; + } + output_prerequisites (fp, G_TYPE_INTERFACE); + fclose (fp); +} + +static void +output_prerequisites (FILE *fp, + GType type) +{ +#if GLIB_CHECK_VERSION(2,1,0) + guint i; + GType *children, *prerequisites; + guint n_children, n_prerequisites; + + if (!type) + return; + + prerequisites = g_type_interface_prerequisites (type, &n_prerequisites); + + if (n_prerequisites > 0) + { + fprintf (fp, g_type_name (type)); + for (i=0; i < n_prerequisites; i++) + fprintf (fp, " %s", g_type_name (prerequisites[i])); + fprintf (fp, "\\n"); + } + g_free (prerequisites); + + children = g_type_children (type, &n_children); + + for (i=0; i < n_children; i++) + output_prerequisites (fp, children[i]); + + g_free (children); +#endif +} + +static void +output_args (void) +{ + FILE *fp; + gint i; + + fp = fopen (args_filename, "w"); + if (fp == NULL) + { + g_warning ("Couldn't open output file: %s : %s", args_filename, strerror(errno)); + return; + } + + for (i = 0; object_types[i]; i++) { + output_object_args (fp, object_types[i]); + } + + fclose (fp); +} + +static gint +compare_param_specs (const void *a, const void *b) +{ + GParamSpec *spec_a = *(GParamSpec **)a; + GParamSpec *spec_b = *(GParamSpec **)b; + + return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b)); +} + +/* Its common to have unsigned properties restricted + * to the signed range. Therefore we make this look + * a bit nicer by spelling out the max constants. + */ + +/* Don't use "==" with floats, it might trigger a gcc warning. */ +#define GTKDOC_COMPARE_FLOAT(x, y) (x <= y && x >= y) + +static gchar* +describe_double_constant (gdouble value) +{ + gchar *desc; + + if (GTKDOC_COMPARE_FLOAT (value, G_MAXDOUBLE)) + desc = g_strdup ("G_MAXDOUBLE"); + else if (GTKDOC_COMPARE_FLOAT (value, G_MINDOUBLE)) + desc = g_strdup ("G_MINDOUBLE"); + else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXDOUBLE)) + desc = g_strdup ("-G_MAXDOUBLE"); + else if (GTKDOC_COMPARE_FLOAT (value, G_MAXFLOAT)) + desc = g_strdup ("G_MAXFLOAT"); + else if (GTKDOC_COMPARE_FLOAT (value, G_MINFLOAT)) + desc = g_strdup ("G_MINFLOAT"); + else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXFLOAT)) + desc = g_strdup ("-G_MAXFLOAT"); + else + desc = g_strdup_printf ("%lg", value); + + return desc; +} + +static gchar* +describe_signed_constant (gint64 value) +{ + gchar *desc; + + if (value == G_MAXINT) + desc = g_strdup ("G_MAXINT"); + else if (value == G_MININT) + desc = g_strdup ("G_MININT"); + else if (value == G_MAXUINT) + desc = g_strdup ("G_MAXUINT"); + else if (value == G_MAXLONG) + desc = g_strdup ("G_MAXLONG"); + else if (value == G_MINLONG) + desc = g_strdup ("G_MINLONG"); + else if (value == G_MAXULONG) + desc = g_strdup ("G_MAXULONG"); + else if (value == G_MAXINT64) + desc = g_strdup ("G_MAXINT64"); + else if (value == G_MININT64) + desc = g_strdup ("G_MININT64"); + else + desc = g_strdup_printf ("%" G_GINT64_FORMAT, value); + + return desc; +} + +static gchar* +describe_unsigned_constant (guint64 value) +{ + gchar *desc; + + if (value == G_MAXINT) + desc = g_strdup ("G_MAXINT"); + else if (value == G_MININT) + desc = g_strdup ("G_MININT"); + else if (value == G_MAXUINT) + desc = g_strdup ("G_MAXUINT"); + else if (value == G_MAXLONG) + desc = g_strdup ("G_MAXLONG"); + else if (value == G_MINLONG) + desc = g_strdup ("G_MINLONG"); + else if (value == G_MAXULONG) + desc = g_strdup ("G_MAXULONG"); + else if (value == G_MAXINT64) + desc = g_strdup ("G_MAXINT64"); + else if (value == G_MININT64) + desc = g_strdup ("G_MININT64"); + else if (value == G_MAXUINT64) + desc = g_strdup ("G_MAXUINT64"); + else + desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value); + + return desc; +} + +static gchar* +describe_type (GParamSpec *spec) +{ + gchar *desc; + gchar *lower; + gchar *upper; + + if (G_IS_PARAM_SPEC_CHAR (spec)) + { + GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec); + + lower = describe_signed_constant (pspec->minimum); + upper = describe_signed_constant (pspec->maximum); + if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8) + desc = g_strdup (""); + else if (pspec->minimum == G_MININT8) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXINT8) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_UCHAR (spec)) + { + GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec); + + lower = describe_unsigned_constant (pspec->minimum); + upper = describe_unsigned_constant (pspec->maximum); + if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8) + desc = g_strdup (""); + else if (pspec->minimum == 0) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXUINT8) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_INT (spec)) + { + GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec); + + lower = describe_signed_constant (pspec->minimum); + upper = describe_signed_constant (pspec->maximum); + if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT) + desc = g_strdup (""); + else if (pspec->minimum == G_MININT) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXINT) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_UINT (spec)) + { + GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec); + + lower = describe_unsigned_constant (pspec->minimum); + upper = describe_unsigned_constant (pspec->maximum); + if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT) + desc = g_strdup (""); + else if (pspec->minimum == 0) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXUINT) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_LONG (spec)) + { + GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec); + + lower = describe_signed_constant (pspec->minimum); + upper = describe_signed_constant (pspec->maximum); + if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG) + desc = g_strdup (""); + else if (pspec->minimum == G_MINLONG) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXLONG) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_ULONG (spec)) + { + GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec); + gchar *upper; + + lower = describe_unsigned_constant (pspec->minimum); + upper = describe_unsigned_constant (pspec->maximum); + if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG) + desc = g_strdup (""); + else if (pspec->minimum == 0) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXULONG) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_INT64 (spec)) + { + GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec); + + lower = describe_signed_constant (pspec->minimum); + upper = describe_signed_constant (pspec->maximum); + if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64) + desc = g_strdup (""); + else if (pspec->minimum == G_MININT64) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXINT64) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_UINT64 (spec)) + { + GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec); + + lower = describe_unsigned_constant (pspec->minimum); + upper = describe_unsigned_constant (pspec->maximum); + if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64) + desc = g_strdup (""); + else if (pspec->minimum == 0) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXUINT64) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_FLOAT (spec)) + { + GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec); + + lower = describe_double_constant (pspec->minimum); + upper = describe_double_constant (pspec->maximum); + if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXFLOAT)) + { + if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT)) + desc = g_strdup (""); + else + desc = g_strdup_printf ("<= %s", upper); + } + else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT)) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_DOUBLE (spec)) + { + GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec); + + lower = describe_double_constant (pspec->minimum); + upper = describe_double_constant (pspec->maximum); + if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXDOUBLE)) + { + if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE)) + desc = g_strdup (""); + else + desc = g_strdup_printf ("<= %s", upper); + } + else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE)) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else + { + desc = g_strdup (""); + } + + return desc; +} + +static gchar* +describe_default (GParamSpec *spec) +{ + gchar *desc; + + if (G_IS_PARAM_SPEC_CHAR (spec)) + { + GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec); + + desc = g_strdup_printf ("%d", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_UCHAR (spec)) + { + GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec); + + desc = g_strdup_printf ("%u", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_BOOLEAN (spec)) + { + GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec); + + desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE"); + } + else if (G_IS_PARAM_SPEC_INT (spec)) + { + GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec); + + desc = g_strdup_printf ("%d", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_UINT (spec)) + { + GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec); + + desc = g_strdup_printf ("%u", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_LONG (spec)) + { + GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec); + + desc = g_strdup_printf ("%ld", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_LONG (spec)) + { + GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec); + + desc = g_strdup_printf ("%lu", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_INT64 (spec)) + { + GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec); + + desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value); + } + else if (G_IS_PARAM_SPEC_UINT64 (spec)) + { + GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec); + + desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value); + } + else if (G_IS_PARAM_SPEC_UNICHAR (spec)) + { + GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec); + + if (g_unichar_isprint (pspec->default_value)) + desc = g_strdup_printf ("'%c'", pspec->default_value); + else + desc = g_strdup_printf ("%u", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_ENUM (spec)) + { + GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec); + + GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value); + if (value) + desc = g_strdup_printf ("%s", value->value_name); + else + desc = g_strdup_printf ("%d", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_FLAGS (spec)) + { + GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec); + guint default_value; + GString *acc; + + default_value = pspec->default_value; + acc = g_string_new (""); + + while (default_value) + { + GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value); + + if (!value) + break; + + if (acc->len > 0) + g_string_append (acc, "|"); + g_string_append (acc, value->value_name); + + default_value &= ~value->value; + } + + if (default_value == 0) + desc = g_string_free (acc, FALSE); + else + { + desc = g_strdup_printf ("%d", pspec->default_value); + g_string_free (acc, TRUE); + } + } + else if (G_IS_PARAM_SPEC_FLOAT (spec)) + { + GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec); + + desc = g_strdup_printf ("%g", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_DOUBLE (spec)) + { + GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec); + + desc = g_strdup_printf ("%lg", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_STRING (spec)) + { + GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec); + + if (pspec->default_value) + { + gchar *esc = g_strescape (pspec->default_value, NULL); + + desc = g_strdup_printf ("\\"%s\\"", esc); + + g_free (esc); + } + else + desc = g_strdup_printf ("NULL"); + } + else + { + desc = g_strdup (""); + } + + return desc; +} + + +static void +output_object_args (FILE *fp, GType object_type) +{ + gpointer class; + const gchar *object_class_name; + guint arg; + gchar flags[16], *pos; + GParamSpec **properties; + guint n_properties; + gboolean child_prop; + gboolean style_prop; + gchar *type_desc; + gchar *default_value; + + if (G_TYPE_IS_CLASSED (object_type)) + { + class = g_type_class_peek (object_type); + if (!class) + return; + + properties = g_object_class_list_properties (class, &n_properties); + } +#if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3) + else if (G_TYPE_IS_INTERFACE (object_type)) + { + class = g_type_default_interface_ref (object_type); + + if (!class) + return; + + properties = g_object_interface_list_properties (class, &n_properties); + } +#endif + else + return; + + object_class_name = g_type_name (object_type); + + child_prop = FALSE; + style_prop = FALSE; + + while (TRUE) { + qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs); + for (arg = 0; arg < n_properties; arg++) + { + GParamSpec *spec = properties[arg]; + const gchar *nick, *blurb, *dot; + + if (spec->owner_type != object_type) + continue; + + pos = flags; + /* We use one-character flags for simplicity. */ + if (child_prop && !style_prop) + *pos++ = 'c'; + if (style_prop) + *pos++ = 's'; + if (spec->flags & G_PARAM_READABLE) + *pos++ = 'r'; + if (spec->flags & G_PARAM_WRITABLE) + *pos++ = 'w'; + if (spec->flags & G_PARAM_CONSTRUCT) + *pos++ = 'x'; + if (spec->flags & G_PARAM_CONSTRUCT_ONLY) + *pos++ = 'X'; + *pos = 0; + + nick = g_param_spec_get_nick (spec); + blurb = g_param_spec_get_blurb (spec); + + dot = ""; + if (blurb) { + int str_len = strlen (blurb); + if (str_len > 0 && blurb[str_len - 1] != '.') + dot = "."; + } + + type_desc = describe_type (spec); + default_value = describe_default (spec); + fprintf (fp, "\\n%s::%s\\n%s\\n%s\\n%s\\n%s\\n%s%s\\n%s\\n\\n\\n", + object_class_name, g_param_spec_get_name (spec), g_type_name (spec->value_type), type_desc, flags, nick ? nick : "(null)", blurb ? blurb : "(null)", dot, default_value); + g_free (type_desc); + g_free (default_value); + } + + g_free (properties); + +#ifdef GTK_IS_CONTAINER_CLASS + if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) { + properties = gtk_container_class_list_child_properties (class, &n_properties); + child_prop = TRUE; + continue; + } +#endif + +#ifdef GTK_IS_WIDGET_CLASS +#if GTK_CHECK_VERSION(2,1,0) + if (!style_prop && GTK_IS_WIDGET_CLASS (class)) { + properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties); + style_prop = TRUE; + continue; + } +#endif +#endif + + break; + } +} +EOT + +close OUTPUT; + +# Compile and run our file + +$CC = $ENV{CC} ? $ENV{CC} : "gcc"; +$LD = $ENV{LD} ? $ENV{LD} : $CC; +$CFLAGS = $ENV{CFLAGS} ? "$ENV{CFLAGS} -Wall -g" : "-Wall -g"; +$LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : ""; + +my $o_file; +if ($CC =~ /libtool/) { + $o_file = "$MODULE-scan.lo" +} else { + $o_file = "$MODULE-scan.o" +} + +print "gtk-doc: Compiling scanner\n"; +$command = "$CC $CFLAGS -c -o $o_file $MODULE-scan.c"; +system($command) == 0 or die "Compilation of scanner failed: $!\n"; + +print "gtk-doc: Linking scanner\n"; +$command = "$LD -o $MODULE-scan $o_file $LDFLAGS"; +system($command) == 0 or die "Linking of scanner failed: $!\n"; + +print "gtk-doc: Running scanner $MODULE-scan\n"; +system("sh -c ./$MODULE-scan") == 0 or die "Scan failed: $!\n"; + +unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan"; + +#&UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0); +#&UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0); +#&UpdateFileIfChanged ($old_interfaces_filename, $new_interfaces_filename, 0); +#&UpdateFileIfChanged ($old_prerequisites_filename, $new_prerequisites_filename, 0); +#&UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0); + + diff --git a/common/gtk-doc-plugins.mak b/common/gtk-doc-plugins.mak new file mode 100644 index 0000000000..4bb57a4566 --- /dev/null +++ b/common/gtk-doc-plugins.mak @@ -0,0 +1,358 @@ +# This is an include file specifically tuned for building documentation +# for GStreamer plug-ins + +help: + @echo "If you are a doc maintainer, run 'make update' to update" + @echo "the documentation files maintained in CVS" + +# update the stuff maintained by doc maintainers +update: + make inspect-update + make scanobj-update + +# We set GPATH here; this gives us semantics for GNU make +# which are more like other make's VPATH, when it comes to +# whether a source that is a target of one rule is then +# searched for in VPATH/GPATH. +# +GPATH = $(srcdir) + +# thomas: make docs parallel installable +TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@ + +EXTRA_DIST = \ + scanobj-build.stamp \ + $(srcdir)/inspect/*.xml \ + inspect.stamp \ + inspect-build.stamp \ + $(SCANOBJ_FILES) \ + $(content_files) \ + $(extra_files) \ + $(HTML_IMAGES) \ + $(DOC_MAIN_SGML_FILE) \ + $(DOC_MODULE).types \ + $(DOC_OVERRIDES) \ + $(DOC_MODULE)-sections.txt + +MAINTAINER_DOC_STAMPS = \ + scanobj-build.stamp \ + inspect-build.stamp \ + inspect.stamp + +# we don't add inspect-build.stamp and scanobj-build.stamp here since they are +# built manually by docs maintainers and result is commited to CVS +DOC_STAMPS = \ + scan-build.stamp \ + tmpl-build.stamp \ + sgml-build.stamp \ + html-build.stamp \ + scan.stamp \ + tmpl.stamp \ + sgml.stamp \ + html.stamp + +# files generated/updated by gtkdoc-scangobj +SCANOBJ_FILES = \ + $(DOC_MODULE).signals \ + $(DOC_MODULE).hierarchy \ + $(DOC_MODULE).interfaces \ + $(DOC_MODULE).prerequisites \ + $(DOC_MODULE).args + +SCANOBJ_FILES_O = \ + .libs/$(DOC_MODULE)-scan.o + +# files generated/updated by gtkdoc-scan +SCAN_FILES = \ + $(DOC_MODULE)-sections.txt \ + $(DOC_MODULE)-overrides.txt \ + $(DOC_MODULE)-undocumented.txt \ + $(DOC_MODULE)-decl.txt \ + $(DOC_MODULE)-decl-list.txt + +if ENABLE_GTK_DOC +all-local: html-build.stamp + +#### scan gobjects; done by documentation maintainer #### +scanobj-update: + -rm scanobj-build.stamp + make scanobj-build.stamp + +# in the case of non-srcdir builds, the built gst directory gets added +# to gtk-doc scanning; but only then, to avoid duplicates +# FIXME: since we don't have the scan step as part of the build anymore, +# we could remove that +# TODO: finish elite script that updates the output files of this step +# instead of rewriting them, so that multiple maintainers can generate +# a collective set of args and signals +scanobj-build.stamp: $(SCANOBJ_DEPS) $(basefiles) + @echo '*** Scanning GObjects ***' + if test x"$(srcdir)" != x. ; then \ + for f in $(SCANOBJ_FILES); \ + do \ + cp $(srcdir)/$$f . ; \ + done; \ + else \ + $(INSPECT_ENVIRONMENT) \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" \ + CFLAGS="-g $(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" \ + $(GST_DOC_SCANOBJ) --type-init-func="gst_init(NULL,NULL)" \ + --module=$(DOC_MODULE) --source=$(PACKAGE) && \ + $(PYTHON) \ + $(top_srcdir)/common/scangobj-merge.py $(DOC_MODULE); \ + fi + touch scanobj-build.stamp + +$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(SCANOBJ_FILES_O): scan-build.stamp + @true + +### inspect GStreamer plug-ins; done by documentation maintainer ### + +# only look at the plugins in this module when building inspect .xml stuff +INSPECT_REGISTRY=$(top_builddir)/docs/plugins/inspect-registry.xml +INSPECT_ENVIRONMENT=\ + GST_PLUGIN_SYSTEM_PATH= \ + GST_PLUGIN_PATH=$(top_builddir)/gst:$(top_builddir)/sys:$(top_builddir)/ext:$(top_builddir)/plugins:$(top_builddir)/src \ + GST_REGISTRY=$(INSPECT_REGISTRY) + +# update the element and plugin XML descriptions; store in inspect/ +inspect: + mkdir inspect + +inspect-update: inspect + -rm $(INSPECT_REGISTRY) + -rm inspect-build.stamp + make inspect-build.stamp + +# FIXME: inspect.stamp should be written to by gst-xmlinspect.py +# IFF the output changed; see gtkdoc-mktmpl +inspect-build.stamp: + @echo '*** Rebuilding plugin inspection files ***' + if test x"$(srcdir)" != x. ; then \ + cp $(srcdir)/inspect.stamp . ; \ + cp $(srcdir)/inspect-build.stamp . ; \ + else \ + $(INSPECT_ENVIRONMENT) $(PYTHON) \ + $(top_srcdir)/common/gst-xmlinspect.py $(PACKAGE) inspect && \ + echo -n "timestamp" > inspect.stamp && \ + touch inspect-build.stamp; \ + fi + +### scan headers; done on every build ### +scan-build.stamp: $(HFILE_GLOB) $(EXTRA_HFILES) $(basefiles) scanobj-build.stamp inspect-build.stamp + if test "x$(top_srcdir)" != "x$(top_builddir)" && \ + test -d "$(top_builddir)/gst"; \ + then \ + export BUILT_OPTIONS="--source-dir=$(top_builddir)/gst"; \ + fi; \ + gtkdoc-scan \ + $(SCAN_OPTIONS) $(EXTRA_HFILES) \ + --module=$(DOC_MODULE) \ + $$BUILT_OPTIONS \ + --ignore-headers="$(IGNORE_HFILES)"; \ + touch scan-build.stamp + +#### update templates; done on every build #### + +### FIXME: make this error out again when docs are fixed for 0.9 +# in a non-srcdir build, we need to copy files from the previous step +# and the files from previous runs of this step +tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_OVERRIDES) + @echo '*** Rebuilding template files ***' + if test x"$(srcdir)" != x. ; then \ + for f in $(SCANOBJ_FILES) $(SCAN_FILES); \ + do \ + if test -e $(srcdir)/$$f; then cp $(srcdir)/$$f . ; fi; \ + done; \ + fi + gtkdoc-mktmpl --module=$(DOC_MODULE) | tee tmpl-build.log + $(PYTHON) \ + $(top_srcdir)/common/mangle-tmpl.py $(srcdir)/inspect tmpl + @cat $(DOC_MODULE)-unused.txt + rm -f tmpl-build.log + touch tmpl-build.stamp + +tmpl.stamp: tmpl-build.stamp + @true + +#### build xml; done on every build #### + +### FIXME: make this error out again when docs are fixed for 0.9 +sgml-build.stamp: tmpl.stamp inspect.stamp $(CFILE_GLOB) $(top_srcdir)/common/plugins.xsl + @echo '*** Building XML ***' + @-mkdir -p xml + @for a in $(srcdir)/inspect/*.xml; do \ + xsltproc --stringparam module $(MODULE) \ + $(top_srcdir)/common/plugins.xsl $$a > xml/`basename $$a`; done + @for f in $(EXAMPLE_CFILES); do \ + $(PYTHON) $(top_srcdir)/common/c-to-xml.py $$f > xml/element-`basename $$f .c`.xml; done + gtkdoc-mkdb \ + --module=$(DOC_MODULE) \ + --source-dir=$(DOC_SOURCE_DIR) \ + --main-sgml-file=$(srcdir)/$(DOC_MAIN_SGML_FILE) \ + --output-format=xml \ + --ignore-files="$(IGNORE_HFILES) $(IGNORE_CFILES)" \ + $(MKDB_OPTIONS) \ + | tee sgml-build.log + @if grep "WARNING:" sgml-build.log > /dev/null; then true; fi # exit 1; fi + cp ../version.entities xml + rm sgml-build.log + touch sgml-build.stamp + +sgml.stamp: sgml-build.stamp + @true + +#### build html; done on every step #### + +html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) + @echo '*** Building HTML ***' + if test -d html; then rm -rf html; fi + mkdir html + cp $(srcdir)/$(DOC_MAIN_SGML_FILE) html + @for f in $(content_files); do cp $(srcdir)/$$f html; done + cp -pr xml html + cp ../version.entities html + cd html && gtkdoc-mkhtml $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) \ + 2>&1 | tee ../html-build.log + @if grep "warning:" html-build.log > /dev/null; then \ + echo "ERROR"; grep "warning:" html-build.log; exit 1; fi + @rm html-build.log + rm -f html/$(DOC_MAIN_SGML_FILE) + rm -rf html/xml + rm -f html/version.entities + test "x$(HTML_IMAGES)" = "x" || for i in "" $(HTML_IMAGES) ; do \ + if test "$$i" != ""; then cp $(srcdir)/$$i html ; fi; done + @echo '-- Fixing Crossreferences' + gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) + touch html-build.stamp +else +all-local: +endif + +# FC3 seems to need -scan.c to be part of CLEANFILES for distcheck +# no idea why FC4 can do without +CLEANFILES = \ + $(SCANOBJ_FILES_O) \ + $(DOC_MODULE)-scan.c \ + $(DOC_MODULE)-unused.txt \ + $(DOC_STAMPS) \ + inspect-registry.xml + +# FIXME: these rules need a little cleaning up +clean-local: + rm -f *~ *.bak + rm -rf .libs +# clean files generated for tmpl build + -rm -rf tmpl +# clean files copied/generated for nonsrcdir tmpl build + if test x"$(srcdir)" != x. ; then \ + rm -rf $(SCANOBJ_FILES) $(SCAN_FILES); \ + fi +# clean files generated for xml build + -rm -rf xml +# clean files generate for html build + -rm -rf html + +distclean-local: clean + rm -rf tmpl/*.sgml.bak + rm -f *.stamp || true + rm -rf *.o + +# thomas: make docs parallel installable; devhelp requires majorminor too +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR) + (installfiles=`echo ./html/*.html`; \ + if test "$$installfiles" = './html/*.html'; \ + then echo '-- Nothing to install' ; \ + else \ + for i in $$installfiles; do \ + echo '-- Installing '$$i ; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ + done; \ + pngfiles=`echo ./html/*.png`; \ + if test "$$pngfiles" != './html/*.png'; then \ + for i in $$pngfiles; do \ + echo '-- Installing '$$i ; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ + done; \ + fi; \ + echo '-- Installing $(srcdir)/html/$(DOC_MODULE).devhelp' ; \ + $(INSTALL_DATA) $(srcdir)/html/$(DOC_MODULE).devhelp \ + $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ + echo '-- Installing $(srcdir)/html/index.sgml' ; \ + $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR); \ + if test -e $(srcdir)/html/style.css; then \ + echo '-- Installing $(srcdir)/html/style.css' ; \ + $(INSTALL_DATA) $(srcdir)/html/style.css $(DESTDIR)$(TARGET_DIR); \ + fi; \ + fi) +uninstall-local: + (installfiles=`echo ./html/*.html`; \ + if test "$$installfiles" = './html/*.html'; \ + then echo '-- Nothing to uninstall' ; \ + else \ + for i in $$installfiles; do \ + rmfile=`basename $$i` ; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ + done; \ + pngfiles=`echo ./html/*.png`; \ + if test "$$pngfiles" != './html/*.png'; then \ + for i in $$pngfiles; do \ + rmfile=`basename $$i` ; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ + done; \ + fi; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE).devhelp' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/index.sgml' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/index.sgml; \ + if test -e $(DESTDIR)$(TARGET_DIR)/style.css; then \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/style.css' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/style.css; \ + fi; \ + fi) + if test -d $(DESTDIR)$(TARGET_DIR); then rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(TARGET_DIR) 2>/dev/null; fi; true + +# +# Checks +# +check-hierarchy: $(DOC_MODULE).hierarchy + @if grep ' ' $(DOC_MODULE).hierarchy; then \ + echo "$(DOC_MODULE).hierarchy contains tabs, please fix"; \ + /bin/false; \ + fi + +check: check-hierarchy + + +# +# Require gtk-doc when making dist +# +if ENABLE_GTK_DOC +dist-check-gtkdoc: +else +dist-check-gtkdoc: + @echo "*** gtk-doc must be installed and enabled in order to make dist" + @false +endif + +# FIXME: decide whether we want to dist generated html or not +dist-hook: dist-check-gtkdoc dist-hook-local + mkdir $(distdir)/tmpl + mkdir $(distdir)/xml + mkdir $(distdir)/html + -cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl + -cp $(srcdir)/sgml/*.xml $(distdir)/xml + -cp $(srcdir)/html/index.sgml $(distdir)/html + -cp $(srcdir)/html/*.html $(srcdir)/html/*.css $(distdir)/html + -cp $(srcdir)/html/$(DOC_MODULE).devhelp $(distdir)/html + + images=$(HTML_IMAGES) ; \ + for i in "" $$images ; do \ + if test "$$i" != ""; then cp $(srcdir)/$$i $(distdir)/html ; fi; \ + done + +.PHONY : dist-hook-local + diff --git a/common/gtk-doc.mak b/common/gtk-doc.mak new file mode 100644 index 0000000000..ea203d8745 --- /dev/null +++ b/common/gtk-doc.mak @@ -0,0 +1,260 @@ +########################################################################### +# Everything below here is generic and you shouldn't need to change it. +########################################################################### +# thomas: except of course that we did + +# thomas: copied from glib-2 +# We set GPATH here; this gives us semantics for GNU make +# which are more like other make's VPATH, when it comes to +# whether a source that is a target of one rule is then +# searched for in VPATH/GPATH. +# +GPATH = $(srcdir) + +# thomas: make docs parallel installable +TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@ + +EXTRA_DIST = \ + $(content_files) \ + $(extra_files) \ + $(HTML_IMAGES) \ + $(DOC_MAIN_SGML_FILE) \ + $(DOC_MODULE).types \ + $(DOC_OVERRIDES) \ + $(DOC_MODULE)-sections.txt + +DOC_STAMPS = \ + scan-build.stamp \ + tmpl-build.stamp \ + sgml-build.stamp \ + html-build.stamp \ + $(srcdir)/tmpl.stamp \ + $(srcdir)/sgml.stamp \ + $(srcdir)/html.stamp + +SCANOBJ_FILES = \ + $(DOC_MODULE).args \ + $(DOC_MODULE).hierarchy \ + $(DOC_MODULE).interfaces \ + $(DOC_MODULE).prerequisites \ + .libs/$(DOC_MODULE)-scan.o \ + $(DOC_MODULE).signals + +CLEANFILES = $(SCANOBJ_FILES) $(DOC_MODULE)-unused.txt $(DOC_STAMPS) + +if ENABLE_GTK_DOC +all-local: html-build.stamp + +#### scan #### + +# in the case of non-srcdir builds, the built gst directory gets added +# to gtk-doc scanning; but only then, to avoid duplicates +scan-build.stamp: $(HFILE_GLOB) $(SCANOBJ_DEPS) $(basefiles) + @echo '*** Scanning header files ***' + if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null; \ + then \ + if test x"$(srcdir)" != x. ; then \ + cp $(srcdir)/$(DOC_MODULE).types . ; \ + chmod u+w $(DOC_MODULE).types ; \ + fi ; \ + GST_PLUGIN_SYSTEM_PATH=`cd $(top_builddir) && pwd` \ + GST_PLUGIN_PATH= \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" \ + CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" \ + gtkdoc-scangobj --type-init-func="gst_init(NULL,NULL)" \ + --module=$(DOC_MODULE) ; \ + else \ + cd $(srcdir) ; \ + for i in $(SCANOBJ_FILES) ; do \ + test -f $$i || touch $$i ; \ + done \ + fi + if test "x$(top_srcdir)" != "x$(top_builddir)"; \ + then \ + export BUILT_OPTIONS="--source-dir=$(DOC_BUILD_DIR)"; \ + fi; \ + gtkdoc-scan \ + $(SCAN_OPTIONS) $(EXTRA_HFILES) \ + --module=$(DOC_MODULE) \ + --source-dir=$(DOC_SOURCE_DIR) \ + $$BUILT_OPTIONS \ + --ignore-headers="$(IGNORE_HFILES)" + touch scan-build.stamp + +$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES): scan-build.stamp + @true + +#### templates #### + +tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_OVERRIDES) + @echo '*** Rebuilding template files ***' + if test x"$(srcdir)" != x. ; then \ + cp $(srcdir)/$(DOC_MODULE)-sections.txt . ; \ + touch $(DOC_MODULE)-decl.txt ; \ + fi + gtkdoc-mktmpl --module=$(DOC_MODULE) | tee tmpl-build.log + @if test -s $(DOC_MODULE)-unused.txt; then \ + exit $(if $(DOCS_ARE_INCOMPLETE_PLEASE_FIXME),0,1); fi + rm -f tmpl-build.log + touch tmpl-build.stamp + +tmpl.stamp: tmpl-build.stamp + @true + +#### xml #### + +### FIXME: make this error out again when docs are fixed for 0.9 +sgml-build.stamp: tmpl.stamp $(CFILE_GLOB) + @echo '*** Building XML ***' + gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --main-sgml-file=$(srcdir)/$(DOC_MAIN_SGML_FILE) --output-format=xml $(MKDB_OPTIONS) | tee sgml-build.log + @if grep "WARNING:" sgml-build.log > /dev/null; then true; fi # exit 1; fi + rm sgml-build.log + touch sgml-build.stamp + +sgml.stamp: sgml-build.stamp + @true + +#### html #### + +html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) + @echo '*** Building HTML ***' + if test -d html; then rm -rf html; fi + mkdir html + cp $(srcdir)/$(DOC_MAIN_SGML_FILE) html + @for f in $(content_files); do cp $(srcdir)/$$f html; done + cp -pr xml html + cp ../version.entities html + cd html && gtkdoc-mkhtml $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) + rm -f html/$(DOC_MAIN_SGML_FILE) + rm -rf html/xml + rm -f html/version.entities + test "x$(HTML_IMAGES)" = "x" || for i in "" $(HTML_IMAGES) ; do \ + if test "$$i" != ""; then cp $(srcdir)/$$i html ; fi; done + @echo '-- Fixing Crossreferences' + gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) + touch html-build.stamp +else +all-local: +endif + +clean-local: + rm -f *~ *.bak + rm -rf xml html + rm -rf .libs + +maintainer-clean-local: clean + cd $(srcdir) && rm -rf xml html $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt + +# company: don't delete .sgml and -sections.txt as they're in CVS +# FIXME : thomas added all sgml files and some other things to make +# make distcheck work +distclean-local: clean + rm -f $(DOC_MODULE)-decl-list.txt + rm -f $(DOC_MODULE)-decl.txt + rm -f $(DOC_MODULE)-undocumented.txt + rm -f $(DOC_MODULE)-unused.txt + rm -rf tmpl/*.sgml.bak + rm -f $(DOC_MODULE).hierarchy + rm -f *.stamp || true + if test x"$(srcdir)" != x. ; then \ + rm -f $(DOC_MODULE)-docs.sgml ; \ + rm -f $(DOC_MODULE).types ; \ + rm -f $(DOC_MODULE).interfaces ; \ + rm -f $(DOC_MODULE)-overrides.txt ; \ + rm -f $(DOC_MODULE).prerequisites ; \ + rm -f $(DOC_MODULE)-sections.txt ; \ + rm -rf tmpl/*.sgml ; \ + fi + rm -rf *.o + +# thomas: make docs parallel installable; devhelp requires majorminor too +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR) + (installfiles=`echo ./html/*.html`; \ + if test "$$installfiles" = './html/*.html'; \ + then echo '-- Nothing to install' ; \ + else \ + for i in $$installfiles; do \ + echo '-- Installing '$$i ; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ + done; \ + pngfiles=`echo ./html/*.png`; \ + if test "$$pngfiles" != './html/*.png'; then \ + for i in $$pngfiles; do \ + echo '-- Installing '$$i ; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ + done; \ + fi; \ + echo '-- Installing $(srcdir)/html/$(DOC_MODULE).devhelp' ; \ + $(INSTALL_DATA) $(srcdir)/html/$(DOC_MODULE).devhelp \ + $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ + if test -e $(srcdir)/html/$(DOC_MODULE).devhelp2; then \ + $(INSTALL_DATA) $(srcdir)/html/$(DOC_MODULE).devhelp2 \ + $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; \ + fi; \ + echo '-- Installing $(srcdir)/html/index.sgml' ; \ + $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR); \ + if test -e $(srcdir)/html/style.css; then \ + echo '-- Installing $(srcdir)/html/style.css' ; \ + $(INSTALL_DATA) $(srcdir)/html/style.css $(DESTDIR)$(TARGET_DIR); \ + fi; \ + fi) +uninstall-local: + (installfiles=`echo ./html/*.html`; \ + if test "$$installfiles" = './html/*.html'; \ + then echo '-- Nothing to uninstall' ; \ + else \ + for i in $$installfiles; do \ + rmfile=`basename $$i` ; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ + done; \ + pngfiles=`echo ./html/*.png`; \ + if test "$$pngfiles" != './html/*.png'; then \ + for i in $$pngfiles; do \ + rmfile=`basename $$i` ; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ + done; \ + fi; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE).devhelp' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ + if test -e $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; then \ + rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; \ + fi; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/index.sgml' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/index.sgml; \ + if test -e $(DESTDIR)$(TARGET_DIR)/style.css; then \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/style.css' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/style.css; \ + fi; \ + fi) + if test -d $(DESTDIR)$(TARGET_DIR); then rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(TARGET_DIR) 2>/dev/null; fi; true + +# +# Require gtk-doc when making dist +# +if ENABLE_GTK_DOC +dist-check-gtkdoc: +else +dist-check-gtkdoc: + @echo "*** gtk-doc must be installed and enabled in order to make dist" + @false +endif + +dist-hook: dist-check-gtkdoc dist-hook-local + mkdir $(distdir)/tmpl + mkdir $(distdir)/xml + mkdir $(distdir)/html + -cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl + -cp $(srcdir)/sgml/*.xml $(distdir)/xml + -cp $(srcdir)/html/index.sgml $(distdir)/html + -cp $(srcdir)/html/*.html $(srcdir)/html/*.css $(distdir)/html + -cp $(srcdir)/html/$(DOC_MODULE).devhelp* $(distdir)/html + + images=$(HTML_IMAGES) ; \ + for i in "" $$images ; do \ + if test "$$i" != ""; then cp $(srcdir)/$$i $(distdir)/html ; fi; \ + done + +.PHONY : dist-hook-local diff --git a/common/m4/Makefile.am b/common/m4/Makefile.am new file mode 100644 index 0000000000..3bbf0e96bc --- /dev/null +++ b/common/m4/Makefile.am @@ -0,0 +1,28 @@ +EXTRA_DIST = \ + README \ + as-ac-expand.m4 \ + as-auto-alt.m4 \ + as-compiler-flag.m4 \ + as-compiler.m4 \ + as-docbook.m4 \ + as-libtool.m4 \ + as-libtool-tags.m4 \ + as-python.m4 \ + as-scrub-include.m4 \ + as-version.m4 \ + ax_create_stdint_h.m4 \ + glib-gettext.m4 \ + gst-arch.m4 \ + gst-args.m4 \ + gst-check.m4 \ + gst-debuginfo.m4 \ + gst-default.m4 \ + gst-doc.m4 \ + gst-feature.m4 \ + gst-function.m4 \ + gst-gettext.m4 \ + gst-glib2.m4 \ + gst-libxml2.m4 \ + gst-plugindir.m4 \ + gst-valgrind.m4 \ + pkg.m4 diff --git a/common/m4/README b/common/m4/README new file mode 100644 index 0000000000..f044598500 --- /dev/null +++ b/common/m4/README @@ -0,0 +1,3 @@ +All aclocal .m4 files we need are put here and cat'd to acinclude.m4 in +the source root. Official ones (taken from the relevant devel packages) +are named as-is, unofficial ones (or changed ones) get a gst-prefix. diff --git a/common/m4/as-ac-expand.m4 b/common/m4/as-ac-expand.m4 new file mode 100644 index 0000000000..d6c9e33060 --- /dev/null +++ b/common/m4/as-ac-expand.m4 @@ -0,0 +1,43 @@ +dnl as-ac-expand.m4 0.2.0 +dnl autostars m4 macro for expanding directories using configure's prefix +dnl thomas@apestaart.org + +dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR) +dnl example +dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir) +dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local + +AC_DEFUN([AS_AC_EXPAND], +[ + EXP_VAR=[$1] + FROM_VAR=[$2] + + dnl first expand prefix and exec_prefix if necessary + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + dnl if no prefix given, then use /usr/local, the default prefix + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + dnl if no exec_prefix given, then use prefix + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + dnl loop until it doesn't change anymore + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + dnl clean up + full_var=$new_full_var + AC_SUBST([$1], "$full_var") + + dnl restore prefix and exec_prefix + prefix=$prefix_save + exec_prefix=$exec_prefix_save +]) diff --git a/common/m4/as-auto-alt.m4 b/common/m4/as-auto-alt.m4 new file mode 100644 index 0000000000..3f7920dd23 --- /dev/null +++ b/common/m4/as-auto-alt.m4 @@ -0,0 +1,50 @@ +dnl as-auto-alt.m4 0.0.2 +dnl autostars m4 macro for supplying alternate autotools versions to configure +dnl thomas@apestaart.org +dnl +dnl AS_AUTOTOOLS_ALTERNATE() +dnl +dnl supplies --with arguments for autoconf, autoheader, automake, aclocal + +AC_DEFUN([AS_AUTOTOOLS_ALTERNATE], +[ + dnl allow for different autoconf version + AC_ARG_WITH(autoconf, + AC_HELP_STRING([--with-autoconf], + [use a different autoconf for regeneration of Makefiles]), + [ + unset AUTOCONF + AM_MISSING_PROG(AUTOCONF, ${withval}) + AC_MSG_NOTICE([Using $AUTOCONF as autoconf]) + ]) + + dnl allow for different autoheader version + AC_ARG_WITH(autoheader, + AC_HELP_STRING([--with-autoheader], + [use a different autoheader for regeneration of Makefiles]), + [ + unset AUTOHEADER + AM_MISSING_PROG(AUTOHEADER, ${withval}) + AC_MSG_NOTICE([Using $AUTOHEADER as autoheader]) + ]) + + dnl allow for different automake version + AC_ARG_WITH(automake, + AC_HELP_STRING([--with-automake], + [use a different automake for regeneration of Makefiles]), + [ + unset AUTOMAKE + AM_MISSING_PROG(AUTOMAKE, ${withval}) + AC_MSG_NOTICE([Using $AUTOMAKE as automake]) + ]) + + dnl allow for different aclocal version + AC_ARG_WITH(aclocal, + AC_HELP_STRING([--with-aclocal], + [use a different aclocal for regeneration of Makefiles]), + [ + unset ACLOCAL + AM_MISSING_PROG(ACLOCAL, ${withval}) + AC_MSG_NOTICE([Using $ACLOCAL as aclocal]) + ]) +]) diff --git a/common/m4/as-compiler-flag.m4 b/common/m4/as-compiler-flag.m4 new file mode 100644 index 0000000000..aba31b1c9d --- /dev/null +++ b/common/m4/as-compiler-flag.m4 @@ -0,0 +1,33 @@ +dnl as-compiler-flag.m4 0.1.0 + +dnl autostars m4 macro for detection of compiler flags + +dnl David Schleef + +dnl $Id: as-compiler-flag.m4,v 1.1 2004/06/01 09:33:45 thomasvs Exp $ + +dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_COMPILER_FLAG], +[ + AC_MSG_CHECKING([to see if compiler understands $1]) + + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + + AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) + CFLAGS="$save_CFLAGS" + + if test "X$flag_ok" = Xyes ; then + $2 + true + else + $3 + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + diff --git a/common/m4/as-compiler.m4 b/common/m4/as-compiler.m4 new file mode 100644 index 0000000000..233a719d44 --- /dev/null +++ b/common/m4/as-compiler.m4 @@ -0,0 +1,44 @@ +dnl as-compiler.m4 0.1.0 + +dnl autostars m4 macro for detection of compiler flavor + +dnl Thomas Vander Stichele + +dnl $Id: as-compiler.m4,v 1.4 2004/06/01 09:33:45 thomasvs Exp $ + +dnl AS_COMPILER(COMPILER) +dnl will set variable COMPILER to +dnl - gcc +dnl - forte +dnl - (empty) if no guess could be made + +AC_DEFUN([AS_COMPILER], +[ + as_compiler= + AC_MSG_CHECKING(for compiler flavour) + + dnl is it gcc ? + if test "x$GCC" = "xyes"; then + as_compiler="gcc" + fi + + dnl is it forte ? + AC_TRY_RUN([ +int main +(int argc, char *argv[]) +{ +#ifdef __sun + return 0; +#else + return 1; +#endif +} + ], as_compiler="forte", ,) + + if test "x$as_compiler" = "x"; then + AC_MSG_RESULT([unknown !]) + else + AC_MSG_RESULT($as_compiler) + fi + [$1]=$as_compiler +]) diff --git a/common/m4/as-docbook.m4 b/common/m4/as-docbook.m4 new file mode 100644 index 0000000000..6a2aa458d8 --- /dev/null +++ b/common/m4/as-docbook.m4 @@ -0,0 +1,66 @@ +dnl AS_DOCBOOK([, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl checks if xsltproc can build docbook documentation +dnl (which is possible if the catalog is set up properly +dnl I also tried checking for a specific version and type of docbook +dnl but xsltproc seemed to happily run anyway, so we can't check for that +dnl and version +dnl this macro takes inspiration from +dnl http://www.movement.uklinux.net/docs/docbook-autotools/configure.html +AC_DEFUN([AS_DOCBOOK], +[ + XSLTPROC_FLAGS=--nonet + DOCBOOK_ROOT= + TYPE_LC=xml + TYPE_UC=XML + DOCBOOK_VERSION=4.1.2 + + if test ! -f /etc/xml/catalog; then + for i in /usr/share/sgml/docbook/stylesheet/xsl/nwalsh /usr/share/sgml/docbook/xsl-stylesheets/; + do + if test -d "$i"; then + DOCBOOK_ROOT=$i + fi + done + else + XML_CATALOG=/etc/xml/catalog + CAT_ENTRY_START='' + fi + + dnl We need xsltproc to process the test + AC_CHECK_PROG(XSLTPROC,xsltproc,xsltproc,) + XSLTPROC_WORKS=no + if test -n "$XSLTPROC"; then + AC_MSG_CHECKING([whether xsltproc docbook processing works]) + + if test -n "$XML_CATALOG"; then + DB_FILE="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl" + else + DB_FILE="$DOCBOOK_ROOT/docbook.xsl" + fi + $XSLTPROC $XSLTPROC_FLAGS $DB_FILE >/dev/null 2>&1 << END + + + + +END + if test "$?" = 0; then + XSLTPROC_WORKS=yes + fi + AC_MSG_RESULT($XSLTPROC_WORKS) + fi + + if test "x$XSLTPROC_WORKS" = "xyes"; then + dnl execute ACTION-IF-FOUND + ifelse([$1], , :, [$1]) + else + dnl execute ACTION-IF-NOT-FOUND + ifelse([$2], , :, [$2]) + fi + + AC_SUBST(XML_CATALOG) + AC_SUBST(XSLTPROC_FLAGS) + AC_SUBST(DOCBOOK_ROOT) + AC_SUBST(CAT_ENTRY_START) + AC_SUBST(CAT_ENTRY_END) +]) diff --git a/common/m4/as-libtool-tags.m4 b/common/m4/as-libtool-tags.m4 new file mode 100644 index 0000000000..69f775e7da --- /dev/null +++ b/common/m4/as-libtool-tags.m4 @@ -0,0 +1,83 @@ +dnl as-libtool-tags.m4 0.1.4 + +dnl autostars m4 macro for selecting libtool "tags" (languages) + +dnl Andy Wingo does not claim credit for this macro +dnl backported from libtool 1.6 by Paolo Bonzini +dnl see http://lists.gnu.org/archive/html/libtool/2003-12/msg00007.html + +dnl $Id: as-libtool-tags.m4,v 1.3 2006/04/01 15:30:56 thomasvs Exp $ + +dnl AS_LIBTOOL_TAGS([tags...]) + +dnl example +dnl AS_LIBTOOL_TAGS([]) for only C (no fortran, etc) + +dnl When AC_LIBTOOL_TAGS is used, I redefine _LT_AC_TAGCONFIG +dnl to be more similar to the libtool 1.6 implementation, which +dnl uses an m4 loop and m4 case instead of a shell loop. This +dnl way the CXX/GCJ/F77/RC tests are not always expanded. + +dnl AS_LIBTOOL_TAGS +dnl --------------- +dnl tags to enable +AC_DEFUN([AS_LIBTOOL_TAGS], +[m4_define([_LT_TAGS],[$1]) +m4_define([_LT_AC_TAGCONFIG], [ + # redefined LT AC TAGCONFIG + if test -f "$ltmain"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + + AC_FOREACH([_LT_TAG], _LT_TAGS, + echo THOMAS: tag _LT_TAG + [m4_case(_LT_TAG, + [CXX], [ + if test -n "$CXX" && test "X$CXX" != "Xno"; then + echo "THOMAS: YAY CXX" + AC_LIBTOOL_LANG_CXX_CONFIG + available_tags="$available_tags _LT_TAG" + fi], + [F77], [ + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + available_tags="$available_tags _LT_TAG" + fi], + [GCJ], [ + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + available_tags="$available_tags _LT_TAG" + fi], + [RC], [ + if test -n "$RC" && test "X$RC" != "Xno"; then + AC_LIBTOOL_LANG_RC_CONFIG + available_tags="$available_tags _LT_TAG" + fi], + [m4_errprintn(m4_location[: error: invalid tag name: ]"_LT_TAG") + m4_exit(1)]) + ]) + echo THOMAS: available tags: $available_tags + fi + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + AC_MSG_NOTICE([updated available libtool tags with $available_tags.]) + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + + fi + +])dnl _LT_AC_TAG_CONFIG +]) diff --git a/common/m4/as-libtool.m4 b/common/m4/as-libtool.m4 new file mode 100644 index 0000000000..73dec1f408 --- /dev/null +++ b/common/m4/as-libtool.m4 @@ -0,0 +1,45 @@ +dnl as-libtool.m4 0.1.4 + +dnl autostars m4 macro for libtool versioning + +dnl Thomas Vander Stichele + +dnl $Id: as-libtool.m4,v 1.6 2004/06/01 10:04:44 thomasvs Exp $ + +dnl AS_LIBTOOL(PREFIX, CURRENT, REVISION, AGE, [RELEASE]) + +dnl example +dnl AS_LIBTOOL(GST, 2, 0, 0) + +dnl this macro +dnl - defines [$PREFIX]_CURRENT, REVISION and AGE +dnl - defines [$PREFIX]_LIBVERSION +dnl - defines [$PREFIX]_LT_LDFLAGS to set versioning +dnl - AC_SUBST's them all + +dnl if RELEASE is given, then add a -release option to the LDFLAGS +dnl with the given release version +dnl then use [$PREFIX]_LT_LDFLAGS in the relevant Makefile.am's + +dnl call AM_PROG_LIBTOOL after this call + +AC_DEFUN([AS_LIBTOOL], +[ + [$1]_CURRENT=[$2] + [$1]_REVISION=[$3] + [$1]_AGE=[$4] + [$1]_LIBVERSION=[$2]:[$3]:[$4] + AC_SUBST([$1]_CURRENT) + AC_SUBST([$1]_REVISION) + AC_SUBST([$1]_AGE) + AC_SUBST([$1]_LIBVERSION) + + [$1]_LT_LDFLAGS="$[$1]_LT_LDFLAGS -version-info $[$1]_LIBVERSION" + if test ! -z "[$5]" + then + [$1]_LT_LDFLAGS="$[$1]_LT_LDFLAGS -release [$5]" + fi + AC_SUBST([$1]_LT_LDFLAGS) + + AC_LIBTOOL_DLOPEN +]) diff --git a/common/m4/as-python.m4 b/common/m4/as-python.m4 new file mode 100644 index 0000000000..eb9b1754de --- /dev/null +++ b/common/m4/as-python.m4 @@ -0,0 +1,152 @@ +## ------------------------ +## Python file handling +## From Andrew Dalke +## Updated by James Henstridge +## Updated by Andy Wingo to loop through possible pythons +## ------------------------ + +# AS_PATH_PYTHON([MINIMUM-VERSION]) + +# Adds support for distributing Python modules and packages. To +# install modules, copy them to $(pythondir), using the python_PYTHON +# automake variable. To install a package with the same name as the +# automake package, install to $(pkgpythondir), or use the +# pkgpython_PYTHON automake variable. + +# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as +# locations to install python extension modules (shared libraries). +# Another macro is required to find the appropriate flags to compile +# extension modules. + +# If your package is configured with a different prefix to python, +# users will have to add the install directory to the PYTHONPATH +# environment variable, or create a .pth file (see the python +# documentation for details). + +# If the MINIMUM-VERSION argument is passed, AS_PATH_PYTHON will +# cause an error if the version of python installed on the system +# doesn't meet the requirement. MINIMUM-VERSION should consist of +# numbers and dots only. + +# Updated to loop over all possible python binaries by Andy Wingo +# +# Updated to only warn and unset PYTHON if no good one is found + +AC_DEFUN([AS_PATH_PYTHON], + [ + dnl Find a version of Python. I could check for python versions 1.4 + dnl or earlier, but the default installation locations changed from + dnl $prefix/lib/site-python in 1.4 to $prefix/lib/python1.5/site-packages + dnl in 1.5, and I don't want to maintain that logic. + + dnl should we do the version check? + PYTHON_CANDIDATES="python python2.2 python2.1 python2.0 python2 \ + python1.6 python1.5" + ifelse([$1],[], + [AC_PATH_PROG(PYTHON, $PYTHON_CANDIDATES)], + [ + AC_MSG_NOTICE(Looking for Python version >= $1) + changequote(<<, >>)dnl + prog=" +import sys, string +minver = '$1' +# split string by '.' and convert to numeric +minver_info = map(string.atoi, string.split(minver, '.')) +# we can now do comparisons on the two lists: +if sys.version_info >= tuple(minver_info): + sys.exit(0) +else: + sys.exit(1)" + changequote([, ])dnl + + python_good=false + for python_candidate in $PYTHON_CANDIDATES; do + unset PYTHON + AC_PATH_PROG(PYTHON, $python_candidate) 1> /dev/null 2> /dev/null + + if test "x$PYTHON" = "x"; then continue; fi + + if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC; then + AC_MSG_CHECKING(["$PYTHON":]) + AC_MSG_RESULT([okay]) + python_good=true + break; + else + dnl clear the cache val + unset ac_cv_path_PYTHON + fi + done + ]) + + if test "$python_good" != "true"; then + AC_MSG_WARN([No suitable version of python found]) + PYTHON= + else + + AC_MSG_CHECKING([local Python configuration]) + + dnl Query Python for its version number. Getting [:3] seems to be + dnl the best way to do this; it's what "site.py" does in the standard + dnl library. Need to change quote character because of [:3] + + AC_SUBST(PYTHON_VERSION) + changequote(<<, >>)dnl + PYTHON_VERSION=`$PYTHON -c "import sys; print sys.version[:3]"` + changequote([, ])dnl + + + dnl Use the values of $prefix and $exec_prefix for the corresponding + dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made + dnl distinct variables so they can be overridden if need be. However, + dnl general consensus is that you shouldn't need this ability. + + AC_SUBST(PYTHON_PREFIX) + PYTHON_PREFIX='${prefix}' + + AC_SUBST(PYTHON_EXEC_PREFIX) + PYTHON_EXEC_PREFIX='${exec_prefix}' + + dnl At times (like when building shared libraries) you may want + dnl to know which OS platform Python thinks this is. + + AC_SUBST(PYTHON_PLATFORM) + PYTHON_PLATFORM=`$PYTHON -c "import sys; print sys.platform"` + + + dnl Set up 4 directories: + + dnl pythondir -- where to install python scripts. This is the + dnl site-packages directory, not the python standard library + dnl directory like in previous automake betas. This behaviour + dnl is more consistent with lispdir.m4 for example. + dnl + dnl Also, if the package prefix isn't the same as python's prefix, + dnl then the old $(pythondir) was pretty useless. + + AC_SUBST(pythondir) + pythondir=$PYTHON_PREFIX"/lib/python"$PYTHON_VERSION/site-packages + + dnl pkgpythondir -- $PACKAGE directory under pythondir. Was + dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is + dnl more consistent with the rest of automake. + dnl Maybe this should be put in python.am? + + AC_SUBST(pkgpythondir) + pkgpythondir=\${pythondir}/$PACKAGE + + dnl pyexecdir -- directory for installing python extension modules + dnl (shared libraries) Was PYTHON_SITE_EXEC in previous betas. + + AC_SUBST(pyexecdir) + pyexecdir=$PYTHON_EXEC_PREFIX"/lib/python"$PYTHON_VERSION/site-packages + + dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) + dnl Maybe this should be put in python.am? + + AC_SUBST(pkgpyexecdir) + pkgpyexecdir=\${pyexecdir}/$PACKAGE + + AC_MSG_RESULT([looks good]) + + fi +]) diff --git a/common/m4/as-scrub-include.m4 b/common/m4/as-scrub-include.m4 new file mode 100644 index 0000000000..96dfb8f088 --- /dev/null +++ b/common/m4/as-scrub-include.m4 @@ -0,0 +1,36 @@ +dnl as-scrub-include.m4 0.0.4 + +dnl autostars m4 macro for scrubbing CFLAGS of system include dirs +dnl because gcc 3.x complains about including system including dirs + +dnl Thomas Vander Stichele + +dnl $Id: as-scrub-include.m4,v 1.5 2004/06/12 08:19:09 thomasvs Exp $ + +dnl This macro uses output of cpp -v and expects it to contain text that +dnl looks a little bit like this: +dnl #include <...> search starts here: +dnl /usr/local/include +dnl /usr/lib/gcc-lib/i386-redhat-linux/3.2/include +dnl /usr/include +dnl End of search list. + +dnl AS_SCRUB_INCLUDE(VAR) +dnl example +dnl AS_SCRUB_INCLUDE(CFLAGS) +dnl will remove all system include dirs from the given CFLAGS + +AC_DEFUN([AS_SCRUB_INCLUDE], +[ + GIVEN_CFLAGS=$[$1] + INCLUDE_DIRS=`echo | cpp -v 2>&1` + + dnl remove everything from this output between the "starts here" and "End of" + dnl line + INCLUDE_DIRS=`echo $INCLUDE_DIRS | sed -e 's/.*<...> search starts here://' | sed -e 's/End of search list.*//'` + for dir in $INCLUDE_DIRS; do + dnl use "" as the sed script so $dir gets expanded + GIVEN_CFLAGS=`echo $GIVEN_CFLAGS | sed -e "s#-I$dir ##"` + done + [$1]=$GIVEN_CFLAGS +]) diff --git a/common/m4/as-version.m4 b/common/m4/as-version.m4 new file mode 100644 index 0000000000..a5b439903e --- /dev/null +++ b/common/m4/as-version.m4 @@ -0,0 +1,71 @@ +dnl as-version.m4 0.2.0 + +dnl autostars m4 macro for versioning + +dnl Thomas Vander Stichele + +dnl $Id: as-version.m4,v 1.4 2004/06/01 09:40:05 thomasvs Exp $ + +dnl AS_VERSION + +dnl example +dnl AS_VERSION + +dnl this macro +dnl - AC_SUBST's PACKAGE_VERSION_MAJOR, _MINOR, _MICRO +dnl - AC_SUBST's PACKAGE_VERSION_RELEASE, +dnl which can be used for rpm release fields +dnl - doesn't call AM_INIT_AUTOMAKE anymore because it prevents +dnl maintainer mode from running correctly +dnl +dnl don't forget to put #undef PACKAGE_VERSION_RELEASE in acconfig.h +dnl if you use acconfig.h + +AC_DEFUN([AS_VERSION], +[ + PACKAGE_VERSION_MAJOR=$(echo AC_PACKAGE_VERSION | cut -d'.' -f1) + PACKAGE_VERSION_MINOR=$(echo AC_PACKAGE_VERSION | cut -d'.' -f2) + PACKAGE_VERSION_MICRO=$(echo AC_PACKAGE_VERSION | cut -d'.' -f3) + + AC_SUBST(PACKAGE_VERSION_MAJOR) + AC_SUBST(PACKAGE_VERSION_MINOR) + AC_SUBST(PACKAGE_VERSION_MICRO) +]) + +dnl AS_NANO(ACTION-IF-NO-NANO, [ACTION-IF-NANO]) + +dnl requires AC_INIT to be called before +dnl For projects using a fourth or nano number in your versioning to indicate +dnl development or prerelease snapshots, this macro allows the build to be +dnl set up differently accordingly. + +dnl this macro: +dnl - parses AC_PACKAGE_VERSION, set by AC_INIT, and extracts the nano number +dnl - sets the variable PACKAGE_VERSION_NANO +dnl - sets the variable PACKAGE_VERSION_RELEASE, which can be used +dnl for rpm release fields +dnl - executes ACTION-IF-NO-NANO or ACTION-IF-NANO + +dnl example: +dnl AS_NANO(RELEASE="yes", RELEASE="no") + +AC_DEFUN([AS_NANO], +[ + AC_MSG_CHECKING(nano version) + + NANO=$(echo AC_PACKAGE_VERSION | cut -d'.' -f4) + + if test x"$NANO" = x || test "x$NANO" = "x0" ; then + AC_MSG_RESULT([0 (release)]) + NANO=0 + PACKAGE_VERSION_RELEASE=1 + ifelse([$1], , :, [$1]) + else + AC_MSG_RESULT($NANO) + PACKAGE_VERSION_RELEASE=0.`date +%Y%m%d.%H%M%S` + ifelse([$2], , :, [$2]) + fi + PACKAGE_VERSION_NANO=$NANO + AC_SUBST(PACKAGE_VERSION_NANO) + AC_SUBST(PACKAGE_VERSION_RELEASE) +]) diff --git a/common/m4/ax_create_stdint_h.m4 b/common/m4/ax_create_stdint_h.m4 new file mode 100644 index 0000000000..061619fb1f --- /dev/null +++ b/common/m4/ax_create_stdint_h.m4 @@ -0,0 +1,569 @@ +dnl @synopsis AX_CREATE_STDINT_H [( HEADER-TO-GENERATE [, HEDERS-TO-CHECK])] +dnl +dnl the "ISO C9X: 7.18 Integer types " section requires the +dnl existence of an include file that defines a set of +dnl typedefs, especially uint8_t,int32_t,uintptr_t. +dnl Many older installations will not provide this file, but some will +dnl have the very same definitions in . In other enviroments +dnl we can use the inet-types in which would define the +dnl typedefs int8_t and u_int8_t respectivly. +dnl +dnl This macros will create a local "_stdint.h" or the headerfile given as +dnl an argument. In many cases that file will just "#include " +dnl or "#include ", while in other environments it will provide +dnl the set of basic 'stdint's definitions/typedefs: +dnl int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,intptr_t,uintptr_t +dnl int_least32_t.. int_fast32_t.. intmax_t +dnl which may or may not rely on the definitions of other files, +dnl or using the AC_CHECK_SIZEOF macro to determine the actual +dnl sizeof each type. +dnl +dnl if your header files require the stdint-types you will want to create an +dnl installable file mylib-int.h that all your other installable header +dnl may include. So if you have a library package named "mylib", just use +dnl AX_CREATE_STDINT_H(mylib-int.h) +dnl in configure.ac and go to install that very header file in Makefile.am +dnl along with the other headers (mylib.h) - and the mylib-specific headers +dnl can simply use "#include " to obtain the stdint-types. +dnl +dnl Remember, if the system already had a valid , the generated +dnl file will include it directly. No need for fuzzy HAVE_STDINT_H things... +dnl +dnl @, (status: used on new platforms) (see http://ac-archive.sf.net/gstdint/) +dnl @version $Id: ax_create_stdint_h.m4,v 1.2 2004/03/09 14:57:53 thomasvs Exp $ +dnl @author Guido Draheim + +AC_DEFUN([AX_CREATE_STDINT_H], +[# ------ AX CREATE STDINT H ------------------------------------- +AC_MSG_CHECKING([for stdint types]) +ac_stdint_h=`echo ifelse($1, , _stdint.h, $1)` +# try to shortcircuit - if the default include path of the compiler +# can find a "stdint.h" header then we assume that all compilers can. +AC_CACHE_VAL([ac_cv_header_stdint_t],[ +old_CXXFLAGS="$CXXFLAGS" ; CXXFLAGS="" +old_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS="" +old_CFLAGS="$CFLAGS" ; CFLAGS="" +AC_TRY_COMPILE([#include ],[int_least32_t v = 0;], +[ac_cv_stdint_result="(assuming C99 compatible system)" + ac_cv_header_stdint_t="stdint.h"; ], +[ac_cv_header_stdint_t=""]) +CXXFLAGS="$old_CXXFLAGS" +CPPFLAGS="$old_CPPFLAGS" +CFLAGS="$old_CFLAGS" ]) + +v="... $ac_cv_header_stdint_h" +if test "$ac_stdint_h" = "stdint.h" ; then + AC_MSG_RESULT([(are you sure you want them in ./stdint.h?)]) +elif test "$ac_stdint_h" = "inttypes.h" ; then + AC_MSG_RESULT([(are you sure you want them in ./inttypes.h?)]) +elif test "_$ac_cv_header_stdint_t" = "_" ; then + AC_MSG_RESULT([(putting them into $ac_stdint_h)$v]) +else + ac_cv_header_stdint="$ac_cv_header_stdint_t" + AC_MSG_RESULT([$ac_cv_header_stdint (shortcircuit)]) +fi + +if test "_$ac_cv_header_stdint_t" = "_" ; then # can not shortcircuit.. + +dnl .....intro message done, now do a few system checks..... +dnl btw, all CHECK_TYPE macros do automatically "DEFINE" a type, therefore +dnl we use the autoconf implementation detail _AC CHECK_TYPE_NEW instead + +inttype_headers=`echo $2 | sed -e 's/,/ /g'` + +ac_cv_stdint_result="(no helpful system typedefs seen)" +AC_CACHE_CHECK([for stdint uintptr_t], [ac_cv_header_stdint_x],[ + ac_cv_header_stdint_x="" # the 1997 typedefs (inttypes.h) + AC_MSG_RESULT([(..)]) + for i in stdint.h inttypes.h sys/inttypes.h $inttype_headers ; do + unset ac_cv_type_uintptr_t + unset ac_cv_type_uint64_t + _AC_CHECK_TYPE_NEW(uintptr_t,[ac_cv_header_stdint_x=$i],dnl + continue,[#include <$i>]) + AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) + ac_cv_stdint_result="(seen uintptr_t$and64 in $i)" + break; + done + AC_MSG_CHECKING([for stdint uintptr_t]) + ]) + +if test "_$ac_cv_header_stdint_x" = "_" ; then +AC_CACHE_CHECK([for stdint uint32_t], [ac_cv_header_stdint_o],[ + ac_cv_header_stdint_o="" # the 1995 typedefs (sys/inttypes.h) + AC_MSG_RESULT([(..)]) + for i in inttypes.h sys/inttypes.h stdint.h $inttype_headers ; do + unset ac_cv_type_uint32_t + unset ac_cv_type_uint64_t + AC_CHECK_TYPE(uint32_t,[ac_cv_header_stdint_o=$i],dnl + continue,[#include <$i>]) + AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) + ac_cv_stdint_result="(seen uint32_t$and64 in $i)" + break; + done + AC_MSG_CHECKING([for stdint uint32_t]) + ]) +fi + +if test "_$ac_cv_header_stdint_x" = "_" ; then +if test "_$ac_cv_header_stdint_o" = "_" ; then +AC_CACHE_CHECK([for stdint u_int32_t], [ac_cv_header_stdint_u],[ + ac_cv_header_stdint_u="" # the BSD typedefs (sys/types.h) + AC_MSG_RESULT([(..)]) + for i in sys/types.h inttypes.h sys/inttypes.h $inttype_headers ; do + unset ac_cv_type_u_int32_t + unset ac_cv_type_u_int64_t + AC_CHECK_TYPE(u_int32_t,[ac_cv_header_stdint_u=$i],dnl + continue,[#include <$i>]) + AC_CHECK_TYPE(u_int64_t,[and64="/u_int64_t"],[and64=""],[#include<$i>]) + ac_cv_stdint_result="(seen u_int32_t$and64 in $i)" + break; + done + AC_MSG_CHECKING([for stdint u_int32_t]) + ]) +fi fi + +dnl if there was no good C99 header file, do some typedef checks... +if test "_$ac_cv_header_stdint_x" = "_" ; then + AC_MSG_CHECKING([for stdint datatype model]) + AC_MSG_RESULT([(..)]) + AC_CHECK_SIZEOF(char) + AC_CHECK_SIZEOF(short) + AC_CHECK_SIZEOF(int) + AC_CHECK_SIZEOF(long) + AC_CHECK_SIZEOF(void*) + ac_cv_stdint_char_model="" + ac_cv_stdint_char_model="$ac_cv_stdint_char_model$ac_cv_sizeof_char" + ac_cv_stdint_char_model="$ac_cv_stdint_char_model$ac_cv_sizeof_short" + ac_cv_stdint_char_model="$ac_cv_stdint_char_model$ac_cv_sizeof_int" + ac_cv_stdint_long_model="" + ac_cv_stdint_long_model="$ac_cv_stdint_long_model$ac_cv_sizeof_int" + ac_cv_stdint_long_model="$ac_cv_stdint_long_model$ac_cv_sizeof_long" + ac_cv_stdint_long_model="$ac_cv_stdint_long_model$ac_cv_sizeof_voidp" + name="$ac_cv_stdint_long_model" + case "$ac_cv_stdint_char_model/$ac_cv_stdint_long_model" in + 122/242) name="$name, IP16 (standard 16bit machine)" ;; + 122/244) name="$name, LP32 (standard 32bit mac/win)" ;; + 122/*) name="$name (unusual int16 model)" ;; + 124/444) name="$name, ILP32 (standard 32bit unixish)" ;; + 124/488) name="$name, LP64 (standard 64bit unixish)" ;; + 124/448) name="$name, LLP64 (unusual 64bit unixish)" ;; + 124/*) name="$name (unusual int32 model)" ;; + 128/888) name="$name, ILP64 (unusual 64bit numeric)" ;; + 128/*) name="$name (unusual int64 model)" ;; + 222/*|444/*) name="$name (unusual dsptype)" ;; + *) name="$name (very unusal model)" ;; + esac + AC_MSG_RESULT([combined for stdint datatype model... $name]) +fi + +if test "_$ac_cv_header_stdint_x" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_x" +elif test "_$ac_cv_header_stdint_o" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_o" +elif test "_$ac_cv_header_stdint_u" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_u" +else + ac_cv_header_stdint="stddef.h" +fi + +AC_MSG_CHECKING([for extra inttypes in chosen header]) +AC_MSG_RESULT([($ac_cv_header_stdint)]) +dnl see if int_least and int_fast types are present in _this_ header. +unset ac_cv_type_int_least32_t +unset ac_cv_type_int_fast32_t +AC_CHECK_TYPE(int_least32_t,,,[#include <$ac_cv_header_stdint>]) +AC_CHECK_TYPE(int_fast32_t,,,[#include<$ac_cv_header_stdint>]) +AC_CHECK_TYPE(intmax_t,,,[#include <$ac_cv_header_stdint>]) + +fi # shortcircut to system "stdint.h" +# ------------------ PREPARE VARIABLES ------------------------------ +if test "$GCC" = "yes" ; then +ac_cv_stdint_message="using gnu compiler "`$CC --version | head -n 1` +else +ac_cv_stdint_message="using $CC" +fi + +AC_MSG_RESULT([make use of $ac_cv_header_stdint in $ac_stdint_h dnl +$ac_cv_stdint_result]) + +# ----------------- DONE inttypes.h checks START header ------------- +AC_CONFIG_COMMANDS([$ac_stdint_h],[ +AC_MSG_NOTICE(creating $ac_stdint_h : $_ac_stdint_h) +ac_stdint=$tmp/_stdint.h + +echo "#ifndef" $_ac_stdint_h >$ac_stdint +echo "#define" $_ac_stdint_h "1" >>$ac_stdint +echo "#ifndef" _GENERATED_STDINT_H >>$ac_stdint +echo "#define" _GENERATED_STDINT_H '"'$PACKAGE $VERSION'"' >>$ac_stdint +echo "/* generated $ac_cv_stdint_message */" >>$ac_stdint +if test "_$ac_cv_header_stdint_t" != "_" ; then +echo "#define _STDINT_HAVE_STDINT_H" "1" >>$ac_stdint +fi + +cat >>$ac_stdint < +#else +#include + +/* .................... configured part ............................ */ + +STDINT_EOF + +echo "/* whether we have a C99 compatible stdint header file */" >>$ac_stdint +if test "_$ac_cv_header_stdint_x" != "_" ; then + ac_header="$ac_cv_header_stdint_x" + echo "#define _STDINT_HEADER_INTPTR" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_INTPTR */" >>$ac_stdint +fi + +echo "/* whether we have a C96 compatible inttypes header file */" >>$ac_stdint +if test "_$ac_cv_header_stdint_o" != "_" ; then + ac_header="$ac_cv_header_stdint_o" + echo "#define _STDINT_HEADER_UINT32" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_UINT32 */" >>$ac_stdint +fi + +echo "/* whether we have a BSD compatible inet types header */" >>$ac_stdint +if test "_$ac_cv_header_stdint_u" != "_" ; then + ac_header="$ac_cv_header_stdint_u" + echo "#define _STDINT_HEADER_U_INT32" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_U_INT32 */" >>$ac_stdint +fi + +echo "" >>$ac_stdint + +if test "_$ac_header" != "_" ; then if test "$ac_header" != "stddef.h" ; then + echo "#include <$ac_header>" >>$ac_stdint + echo "" >>$ac_stdint +fi fi + +echo "/* which 64bit typedef has been found */" >>$ac_stdint +if test "$ac_cv_type_uint64_t" = "yes" ; then +echo "#define _STDINT_HAVE_UINT64_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_UINT64_T */" >>$ac_stdint +fi +if test "$ac_cv_type_u_int64_t" = "yes" ; then +echo "#define _STDINT_HAVE_U_INT64_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_U_INT64_T */" >>$ac_stdint +fi +echo "" >>$ac_stdint + +echo "/* which type model has been detected */" >>$ac_stdint +if test "_$ac_cv_stdint_char_model" != "_" ; then +echo "#define _STDINT_CHAR_MODEL" "$ac_cv_stdint_char_model" >>$ac_stdint +echo "#define _STDINT_LONG_MODEL" "$ac_cv_stdint_long_model" >>$ac_stdint +else +echo "/* #undef _STDINT_CHAR_MODEL // skipped */" >>$ac_stdint +echo "/* #undef _STDINT_LONG_MODEL // skipped */" >>$ac_stdint +fi +echo "" >>$ac_stdint + +echo "/* whether int_least types were detected */" >>$ac_stdint +if test "$ac_cv_type_int_least32_t" = "yes"; then +echo "#define _STDINT_HAVE_INT_LEAST32_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INT_LEAST32_T */" >>$ac_stdint +fi +echo "/* whether int_fast types were detected */" >>$ac_stdint +if test "$ac_cv_type_int_fast32_t" = "yes"; then +echo "#define _STDINT_HAVE_INT_FAST32_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INT_FAST32_T */" >>$ac_stdint +fi +echo "/* whether intmax_t type was detected */" >>$ac_stdint +if test "$ac_cv_type_intmax_t" = "yes"; then +echo "#define _STDINT_HAVE_INTMAX_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INTMAX_T */" >>$ac_stdint +fi +echo "" >>$ac_stdint + + cat >>$ac_stdint <= 199901L +#define _HAVE_UINT64_T +typedef long long int64_t; +typedef unsigned long long uint64_t; + +#elif !defined __STRICT_ANSI__ +#if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ +#define _HAVE_UINT64_T +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +#elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__ +/* note: all ELF-systems seem to have loff-support which needs 64-bit */ +#if !defined _NO_LONGLONG +#define _HAVE_UINT64_T +typedef long long int64_t; +typedef unsigned long long uint64_t; +#endif + +#elif defined __alpha || (defined __mips && defined _ABIN32) +#if !defined _NO_LONGLONG +typedef long int64_t; +typedef unsigned long uint64_t; +#endif + /* compiler/cpu type to define int64_t */ +#endif +#endif +#endif + +#if defined _STDINT_HAVE_U_INT_TYPES +/* int8_t int16_t int32_t defined by inet code, redeclare the u_intXX types */ +typedef u_int8_t uint8_t; +typedef u_int16_t uint16_t; +typedef u_int32_t uint32_t; + +/* glibc compatibility */ +#ifndef __int8_t_defined +#define __int8_t_defined +#endif +#endif + +#ifdef _STDINT_NEED_INT_MODEL_T +/* we must guess all the basic types. Apart from byte-adressable system, */ +/* there a few 32-bit-only dsp-systems that we guard with BYTE_MODEL 8-} */ +/* (btw, those nibble-addressable systems are way off, or so we assume) */ + +dnl /* have a look at "64bit and data size neutrality" at */ +dnl /* http://unix.org/version2/whatsnew/login_64bit.html */ +dnl /* (the shorthand "ILP" types always have a "P" part) */ + +#if defined _STDINT_BYTE_MODEL +#if _STDINT_LONG_MODEL+0 == 242 +/* 2:4:2 = IP16 = a normal 16-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef long int32_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL == 444 +/* 2:4:4 = LP32 = a 32-bit system derived from a 16-bit */ +/* 4:4:4 = ILP32 = a normal 32-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 484 || _STDINT_LONG_MODEL+0 == 488 +/* 4:8:4 = IP32 = a 32-bit system prepared for 64-bit */ +/* 4:8:8 = LP64 = a normal 64-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +/* this system has a "long" of 64bit */ +#ifndef _HAVE_UINT64_T +#define _HAVE_UINT64_T +typedef unsigned long uint64_t; +typedef long int64_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 448 +/* LLP64 a 64-bit system derived from a 32-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +/* assuming the system has a "long long" */ +#ifndef _HAVE_UINT64_T +#define _HAVE_UINT64_T +typedef unsigned long long uint64_t; +typedef long long int64_t; +#endif +#else +#define _STDINT_NO_INT32_T +#endif +#else +#define _STDINT_NO_INT8_T +#define _STDINT_NO_INT32_T +#endif +#endif + +/* + * quote from SunOS-5.8 sys/inttypes.h: + * Use at your own risk. As of February 1996, the committee is squarely + * behind the fixed sized types; the "least" and "fast" types are still being + * discussed. The probability that the "fast" types may be removed before + * the standard is finalized is high enough that they are not currently + * implemented. + */ + +#if defined _STDINT_NEED_INT_LEAST_T +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +#ifdef _HAVE_UINT64_T +typedef int64_t int_least64_t; +#endif + +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +#ifdef _HAVE_UINT64_T +typedef uint64_t uint_least64_t; +#endif + /* least types */ +#endif + +#if defined _STDINT_NEED_INT_FAST_T +typedef int8_t int_fast8_t; +typedef int int_fast16_t; +typedef int32_t int_fast32_t; +#ifdef _HAVE_UINT64_T +typedef int64_t int_fast64_t; +#endif + +typedef uint8_t uint_fast8_t; +typedef unsigned uint_fast16_t; +typedef uint32_t uint_fast32_t; +#ifdef _HAVE_UINT64_T +typedef uint64_t uint_fast64_t; +#endif + /* fast types */ +#endif + +#ifdef _STDINT_NEED_INTMAX_T +#ifdef _HAVE_UINT64_T +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; +#else +typedef long intmax_t; +typedef unsigned long uintmax_t; +#endif +#endif + +#ifdef _STDINT_NEED_INTPTR_T +#ifndef __intptr_t_defined +#define __intptr_t_defined +/* we encourage using "long" to store pointer values, never use "int" ! */ +#if _STDINT_LONG_MODEL+0 == 242 || _STDINT_LONG_MODEL+0 == 484 +typedef unsinged int uintptr_t; +typedef int intptr_t; +#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL+0 == 444 +typedef unsigned long uintptr_t; +typedef long intptr_t; +#elif _STDINT_LONG_MODEL+0 == 448 && defined _HAVE_UINT64_T +typedef uint64_t uintptr_t; +typedef int64_t intptr_t; +#else /* matches typical system types ILP32 and LP64 - but not IP16 or LLP64 */ +typedef unsigned long uintptr_t; +typedef long intptr_t; +#endif +#endif +#endif + + /* shortcircuit*/ +#endif + /* once */ +#endif +#endif +STDINT_EOF + if cmp -s $ac_stdint_h $ac_stdint 2>/dev/null; then + AC_MSG_NOTICE([$ac_stdint_h is unchanged]) + else + ac_dir=`AS_DIRNAME(["$ac_stdint_h"])` + AS_MKDIR_P(["$ac_dir"]) + rm -f $ac_stdint_h + mv $ac_stdint $ac_stdint_h + fi +],[# variables for create stdint.h replacement +PACKAGE="$PACKAGE" +VERSION="$VERSION" +ac_stdint_h="$ac_stdint_h" +_ac_stdint_h=AS_TR_CPP(_$PACKAGE-$ac_stdint_h) +ac_cv_stdint_message="$ac_cv_stdint_message" +ac_cv_header_stdint_t="$ac_cv_header_stdint_t" +ac_cv_header_stdint_x="$ac_cv_header_stdint_x" +ac_cv_header_stdint_o="$ac_cv_header_stdint_o" +ac_cv_header_stdint_u="$ac_cv_header_stdint_u" +ac_cv_type_uint64_t="$ac_cv_type_uint64_t" +ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t" +ac_cv_stdint_char_model="$ac_cv_stdint_char_model" +ac_cv_stdint_long_model="$ac_cv_stdint_long_model" +ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t" +ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t" +ac_cv_type_intmax_t="$ac_cv_type_intmax_t" +]) +]) diff --git a/common/m4/check.m4 b/common/m4/check.m4 new file mode 100644 index 0000000000..19784ae01f --- /dev/null +++ b/common/m4/check.m4 @@ -0,0 +1,181 @@ +dnl _AM_TRY_CHECK(MINIMUM-VERSION, EXTRA-CFLAGS, EXTRA-LIBS, CHECK-LIB-NAME +dnl [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for check, and define CHECK_CFLAGS and CHECK_LIBS +dnl Done this way because of the brokenness that is +dnl https://launchpad.net/distros/ubuntu/+source/check/+bug/5840 +dnl + +AC_DEFUN([_AM_TRY_CHECK], +[ + min_check_version=$1 + extra_cflags=$2 + extra_libs=$3 + check_lib_name=$4 + + CHECK_CFLAGS="$extra_cflags" + CHECK_LIBS="$extra_libs -l$check_lib_name" + + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + + CFLAGS="$CFLAGS $CHECK_CFLAGS" + LIBS="$CHECK_LIBS $LIBS" + + AC_MSG_CHECKING(for check named $check_lib_name - version >= $min_check_version) + + rm -f conf.check-test + dnl unset no_check, since in our second run it would have been set to yes + dnl before + no_check= + AC_TRY_RUN([ +#include +#include + +#include + +int main () +{ + int major, minor, micro; + char *tmp_version; + + system ("touch conf.check-test"); + + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = strdup("$min_check_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_check_version"); + return 1; + } + + if ((CHECK_MAJOR_VERSION != check_major_version) || + (CHECK_MINOR_VERSION != check_minor_version) || + (CHECK_MICRO_VERSION != check_micro_version)) + { + printf("\n*** The check header file (version %d.%d.%d) does not match\n", + CHECK_MAJOR_VERSION, CHECK_MINOR_VERSION, CHECK_MICRO_VERSION); + printf("*** the check library (version %d.%d.%d).\n", + check_major_version, check_minor_version, check_micro_version); + return 1; + } + + if ((check_major_version > major) || + ((check_major_version == major) && (check_minor_version > minor)) || + ((check_major_version == major) && (check_minor_version == minor) && (check_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of check (%d.%d.%d) was found.\n", + check_major_version, check_minor_version, check_micro_version); + printf("*** You need a version of check being at least %d.%d.%d.\n", major, minor, micro); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the check library and header\n"); + printf("*** file is being found. Rerun configure with the --with-check=PATH option\n"); + printf("*** to specify the prefix where the correct version was installed.\n"); + } + + return 1; +} +],, no_check=yes, [echo $ac_n "cross compiling; assumed OK... $ac_c"]) + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + + if test "x$no_check" = x ; then + AC_MSG_RESULT(yes) + ifelse([$5], , :, [$5]) + else + AC_MSG_RESULT(no) + if test -f conf.check-test ; then + : + else + echo "*** Could not run check test program, checking why..." + CFLAGS="$CFLAGS $CHECK_CFLAGS" + LIBS="$CHECK_LIBS $LIBS" + AC_TRY_LINK([ +#include +#include + +#include +], , [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding check. You'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], + [ echo "*** The test program failed to compile or link. See the file config.log for" + echo "*** the exact error that occured." ]) + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + + CHECK_CFLAGS="" + CHECK_LIBS="" + + rm -f conf.check-test + ifelse([$6], , AC_MSG_ERROR([check not found]), [$6]) + fi +]) + + +dnl AM_PATH_CHECK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for check, and define CHECK_CFLAGS and CHECK_LIBS +dnl + +AC_DEFUN([AM_PATH_CHECK], +[ + AC_ARG_WITH(check, + [ --with-check=PATH prefix where check is installed [default=auto]]) + + AC_ARG_WITH(checklibname, + AC_HELP_STRING([--with-check-lib-name=NAME], + [name of the PIC check library (default=check)])) + + min_check_version=ifelse([$1], ,0.8.2,$1) + + if test x$with_check = xno; then + AC_MSG_RESULT(disabled) + ifelse([$3], , AC_MSG_ERROR([disabling check is not supported]), [$3]) + else + if test "x$with_check" != x; then + CHECK_EXTRA_CFLAGS="-I$with_check/include" + CHECK_EXTRA_LIBS="-L$with_check/lib" + else + CHECK_EXTRA_CFLAGS="" + CHECK_EXTRA_LIBS="" + fi + + if test x$with_checklibname = x; then + _AM_TRY_CHECK($min_check_version, $CHECK_EXTRA_CFLAGS, $CHECK_EXTRA_LIBS, + check_pic, [have_check=true], [have_check=false]) + if test x$have_check = xtrue; then + ifelse([$2], , :, [$2]) + else + _AM_TRY_CHECK($min_check_version, $CHECK_EXTRA_CFLAGS, $CHECK_EXTRA_LIBS, + check, [have_check=true], [have_check=false]) + if test x$have_check = xtrue; then + ifelse([$2], , :, [$2]) + else + ifelse([$3], , AC_MSG_ERROR([check not found]), [$3]) + fi + fi + else + _AM_TRY_CHECK($min_check_version, $CHECK_EXTRA_CFLAGS, $CHECK_EXTRA_LIBS, + $with_checklibname, [have_check=true], [have_check=false]) + if test x$have_check = xtrue; then + ifelse([$2], , :, [$2]) + else + ifelse([$3], , AC_MSG_ERROR([check not found]), [$3]) + fi + fi + + AC_SUBST(CHECK_CFLAGS) + AC_SUBST(CHECK_LIBS) + rm -f conf.check-test + fi +]) diff --git a/common/m4/glib-gettext.m4 b/common/m4/glib-gettext.m4 new file mode 100644 index 0000000000..5a4ef2814e --- /dev/null +++ b/common/m4/glib-gettext.m4 @@ -0,0 +1,380 @@ +# Copyright (C) 1995-2002 Free Software Foundation, Inc. +# Copyright (C) 2001-2003 Red Hat, Inc. +# +# This file is free software, distributed under the terms of the GNU +# General Public License. As a special exception to the GNU General +# Public License, this file may be distributed as part of a program +# that contains a configuration script generated by Autoconf, under +# the same distribution terms as the rest of that program. +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# +# Macro to add for using GNU gettext. +# Ulrich Drepper , 1995, 1996 +# +# Modified to never use included libintl. +# Owen Taylor , 12/15/1998 +# +# Major rework to remove unused code +# Owen Taylor , 12/11/2002 +# +# Added better handling of ALL_LINGUAS from GNU gettext version +# written by Bruno Haible, Owen Taylor 5/30/3002 + +# +# We need this here as well, since someone might use autoconf-2.5x +# to configure GLib then an older version to configure a package +# using AM_GLIB_GNU_GETTEXT +AC_PREREQ(2.53) + +dnl +dnl We go to great lengths to make sure that aclocal won't +dnl try to pull in the installed version of these macros +dnl when running aclocal in the glib directory. +dnl +m4_copy([AC_DEFUN],[glib_DEFUN]) +m4_copy([AC_REQUIRE],[glib_REQUIRE]) +dnl +dnl At the end, if we're not within glib, we'll define the public +dnl definitions in terms of our private definitions. +dnl + +# GLIB_LC_MESSAGES +#-------------------- +glib_DEFUN([GLIB_LC_MESSAGES], + [AC_CHECK_HEADERS([locale.h]) + if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, + [Define if your file defines LC_MESSAGES.]) + fi + fi]) + +# GLIB_PATH_PROG_WITH_TEST +#---------------------------- +dnl GLIB_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +glib_DEFUN([GLIB_PATH_PROG_WITH_TEST], +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + +# GLIB_WITH_NLS +#----------------- +glib_DEFUN([GLIB_WITH_NLS], + dnl NLS is obligatory + [USE_NLS=yes + AC_SUBST(USE_NLS) + + gt_cv_have_gettext=no + + CATOBJEXT=NONE + XGETTEXT=: + INTLLIBS= + + AC_CHECK_HEADER(libintl.h, + [gt_cv_func_dgettext_libintl="no" + libintl_extra_libs="" + + # + # First check in libc + # + AC_CACHE_CHECK([for dgettext in libc], gt_cv_func_dgettext_libc, + [AC_TRY_LINK([ +#include +], + [return (int) dgettext ("","")], + gt_cv_func_dgettext_libc=yes, + gt_cv_func_dgettext_libc=no) + ]) + + if test "$gt_cv_func_dgettext_libc" = "yes" ; then + AC_CHECK_FUNCS(bind_textdomain_codeset) + fi + + # + # If we don't have everything we want, check in libintl + # + if test "$gt_cv_func_dgettext_libc" != "yes" \ + || test "$ac_cv_func_bind_textdomain_codeset" != "yes" ; then + + AC_CHECK_LIB(intl, bindtextdomain, + [AC_CHECK_LIB(intl, dgettext, + gt_cv_func_dgettext_libintl=yes)]) + + if test "$gt_cv_func_dgettext_libintl" != "yes" ; then + AC_MSG_CHECKING([if -liconv is needed to use gettext]) + AC_MSG_RESULT([]) + AC_CHECK_LIB(intl, dcgettext, + [gt_cv_func_dgettext_libintl=yes + libintl_extra_libs=-liconv], + :,-liconv) + fi + + # + # If we found libintl, then check in it for bind_textdomain_codeset(); + # we'll prefer libc if neither have bind_textdomain_codeset(), + # and both have dgettext + # + if test "$gt_cv_func_dgettext_libintl" = "yes" ; then + glib_save_LIBS="$LIBS" + LIBS="$LIBS -lintl $libintl_extra_libs" + unset ac_cv_func_bind_textdomain_codeset + AC_CHECK_FUNCS(bind_textdomain_codeset) + LIBS="$glib_save_LIBS" + + if test "$ac_cv_func_bind_textdomain_codeset" = "yes" ; then + gt_cv_func_dgettext_libc=no + else + if test "$gt_cv_func_dgettext_libc" = "yes"; then + gt_cv_func_dgettext_libintl=no + fi + fi + fi + fi + + if test "$gt_cv_func_dgettext_libc" = "yes" \ + || test "$gt_cv_func_dgettext_libintl" = "yes"; then + gt_cv_have_gettext=yes + fi + + if test "$gt_cv_func_dgettext_libintl" = "yes"; then + INTLLIBS="-lintl $libintl_extra_libs" + fi + + if test "$gt_cv_have_gettext" = "yes"; then + AC_DEFINE(HAVE_GETTEXT,1, + [Define if the GNU gettext() function is already present or preinstalled.]) + GLIB_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl + if test "$MSGFMT" != "no"; then + glib_save_LIBS="$LIBS" + LIBS="$LIBS $INTLLIBS" + AC_CHECK_FUNCS(dcgettext) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + GLIB_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + AC_TRY_LINK(, [extern int _nl_msg_cat_cntr; + return _nl_msg_cat_cntr], + [CATOBJEXT=.gmo + DATADIRNAME=share], + [case $host in + *-*-solaris*) + dnl On Solaris, if bind_textdomain_codeset is in libc, + dnl GNU format message catalog is always supported, + dnl since both are added to the libc all together. + dnl Hence, we'd like to go with DATADIRNAME=share and + dnl and CATOBJEXT=.gmo in this case. + AC_CHECK_FUNC(bind_textdomain_codeset, + [CATOBJEXT=.gmo + DATADIRNAME=share], + [CATOBJEXT=.mo + DATADIRNAME=lib]) + ;; + *) + CATOBJEXT=.mo + DATADIRNAME=lib + ;; + esac]) + LIBS="$glib_save_LIBS" + INSTOBJEXT=.mo + else + gt_cv_have_gettext=no + fi + fi + ]) + + if test "$gt_cv_have_gettext" = "yes" ; then + AC_DEFINE(ENABLE_NLS, 1, + [always defined to indicate that i18n is enabled]) + fi + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is not GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext program is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + + # We need to process the po/ directory. + POSUB=po + + AC_OUTPUT_COMMANDS( + [case "$CONFIG_FILES" in *po/Makefile.in*) + sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile + esac]) + + dnl These rules are solely for the distribution goal. While doing this + dnl we only have to keep exactly one list of the available catalogs + dnl in configure.in. + for lang in $ALL_LINGUAS; do + GMOFILES="$GMOFILES $lang.gmo" + POFILES="$POFILES $lang.po" + done + + dnl Make all variables we use known to autoconf. + AC_SUBST(CATALOGS) + AC_SUBST(CATOBJEXT) + AC_SUBST(DATADIRNAME) + AC_SUBST(GMOFILES) + AC_SUBST(INSTOBJEXT) + AC_SUBST(INTLLIBS) + AC_SUBST(PO_IN_DATADIR_TRUE) + AC_SUBST(PO_IN_DATADIR_FALSE) + AC_SUBST(POFILES) + AC_SUBST(POSUB) + ]) + +# AM_GLIB_GNU_GETTEXT +# ------------------- +# Do checks necessary for use of gettext. If a suitable implementation +# of gettext is found in either in libintl or in the C library, +# it will set INTLLIBS to the libraries needed for use of gettext +# and AC_DEFINE() HAVE_GETTEXT and ENABLE_NLS. (The shell variable +# gt_cv_have_gettext will be set to "yes".) It will also call AC_SUBST() +# on various variables needed by the Makefile.in.in installed by +# glib-gettextize. +dnl +glib_DEFUN([GLIB_GNU_GETTEXT], + [AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + + GLIB_LC_MESSAGES + GLIB_WITH_NLS + + if test "$gt_cv_have_gettext" = "yes"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "${LINGUAS-%UNSET%}"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + NEW_LINGUAS="$NEW_LINGUAS $presentlang" + fi + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly + dnl find the mkinstalldirs script in another subdir but ($top_srcdir). + dnl Try to locate is. + MKINSTALLDIRS= + if test -n "$ac_aux_dir"; then + MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" + fi + if test -z "$MKINSTALLDIRS"; then + MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" + fi + AC_SUBST(MKINSTALLDIRS) + + dnl Generate list of files to be processed by xgettext which will + dnl be included in po/Makefile. + test -d po || mkdir po + if test "x$srcdir" != "x."; then + if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then + posrcprefix="$srcdir/" + else + posrcprefix="../$srcdir/" + fi + else + posrcprefix="../" + fi + rm -f po/POTFILES + sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \ + < $srcdir/po/POTFILES.in > po/POTFILES + ]) + +# AM_GLIB_DEFINE_LOCALEDIR(VARIABLE) +# ------------------------------- +# Define VARIABLE to the location where catalog files will +# be installed by po/Makefile. +glib_DEFUN([GLIB_DEFINE_LOCALEDIR], +[glib_REQUIRE([GLIB_GNU_GETTEXT])dnl +glib_save_prefix="$prefix" +glib_save_exec_prefix="$exec_prefix" +test "x$prefix" = xNONE && prefix=$ac_default_prefix +test "x$exec_prefix" = xNONE && exec_prefix=$prefix +if test "x$CATOBJEXT" = "x.mo" ; then + localedir=`eval echo "${libdir}/locale"` +else + localedir=`eval echo "${datadir}/locale"` +fi +prefix="$glib_save_prefix" +exec_prefix="$glib_save_exec_prefix" +AC_DEFINE_UNQUOTED($1, "$localedir", + [Define the location where the catalogs will be installed]) +]) + +dnl +dnl Now the definitions that aclocal will find +dnl +ifdef(glib_configure_in,[],[ +AC_DEFUN([AM_GLIB_GNU_GETTEXT],[GLIB_GNU_GETTEXT($@)]) +AC_DEFUN([AM_GLIB_DEFINE_LOCALEDIR],[GLIB_DEFINE_LOCALEDIR($@)]) +])dnl diff --git a/common/m4/gst-arch.m4 b/common/m4/gst-arch.m4 new file mode 100644 index 0000000000..8a32bd23b5 --- /dev/null +++ b/common/m4/gst-arch.m4 @@ -0,0 +1,123 @@ +dnl AG_GST_ARCH +dnl sets up defines and automake conditionals for host architecture +dnl checks endianness +dnl defines HOST_CPU + +AC_DEFUN([AG_GST_ARCH], +[ + AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use host_ variables + + dnl Determine CPU + case "x${host_cpu}" in + xi?86 | xk? | xi?86_64) + HAVE_CPU_I386=yes + AC_DEFINE(HAVE_CPU_I386, 1, [Define if the host CPU is an x86]) + + dnl FIXME could use some better detection + dnl (ie CPUID) + case "x${host_cpu}" in + xi386 | xi486) ;; + *) + AC_DEFINE(HAVE_RDTSC, 1, [Define if RDTSC is available]) ;; + esac ;; + xpowerpc) + HAVE_CPU_PPC=yes + AC_DEFINE(HAVE_CPU_PPC, 1, [Define if the host CPU is a PowerPC]) ;; + xpowerpc64) + HAVE_CPU_PPC64=yes + AC_DEFINE(HAVE_CPU_PPC64, 1, [Define if the host CPU is a 64 bit PowerPC]) ;; + xalpha*) + HAVE_CPU_ALPHA=yes + AC_DEFINE(HAVE_CPU_ALPHA, 1, [Define if the host CPU is an Alpha]) ;; + xarm*) + HAVE_CPU_ARM=yes + AC_DEFINE(HAVE_CPU_ARM, 1, [Define if the host CPU is an ARM]) ;; + xsparc*) + HAVE_CPU_SPARC=yes + AC_DEFINE(HAVE_CPU_SPARC, 1, [Define if the host CPU is a SPARC]) ;; + xmips*) + HAVE_CPU_MIPS=yes + AC_DEFINE(HAVE_CPU_MIPS, 1, [Define if the host CPU is a MIPS]) ;; + xhppa*) + HAVE_CPU_HPPA=yes + AC_DEFINE(HAVE_CPU_HPPA, 1, [Define if the host CPU is a HPPA]) ;; + xs390*) + HAVE_CPU_S390=yes + AC_DEFINE(HAVE_CPU_S390, 1, [Define if the host CPU is a S390]) ;; + xia64*) + HAVE_CPU_IA64=yes + AC_DEFINE(HAVE_CPU_IA64, 1, [Define if the host CPU is a IA64]) ;; + xm68k*) + HAVE_CPU_M68K=yes + AC_DEFINE(HAVE_CPU_M68K, 1, [Define if the host CPU is a M68K]) ;; + xx86_64) + HAVE_CPU_X86_64=yes + AC_DEFINE(HAVE_CPU_X86_64, 1, [Define if the host CPU is a x86_64]) ;; + xcris) + HAVE_CPU_CRIS=yes + AC_DEFINE(HAVE_CPU_CRIS, 1, [Define if the host CPU is a CRIS]) ;; + xcrisv32) + HAVE_CPU_CRISV32=yes + AC_DEFINE(HAVE_CPU_CRISV32, 1, [Define if the host CPU is a CRISv32]) ;; + esac + + dnl Determine endianness + AC_C_BIGENDIAN + + AM_CONDITIONAL(HAVE_CPU_I386, test "x$HAVE_CPU_I386" = "xyes") + AM_CONDITIONAL(HAVE_CPU_PPC, test "x$HAVE_CPU_PPC" = "xyes") + AM_CONDITIONAL(HAVE_CPU_PPC64, test "x$HAVE_CPU_PPC64" = "xyes") + AM_CONDITIONAL(HAVE_CPU_ALPHA, test "x$HAVE_CPU_ALPHA" = "xyes") + AM_CONDITIONAL(HAVE_CPU_ARM, test "x$HAVE_CPU_ARM" = "xyes") + AM_CONDITIONAL(HAVE_CPU_SPARC, test "x$HAVE_CPU_SPARC" = "xyes") + AM_CONDITIONAL(HAVE_CPU_HPPA, test "x$HAVE_CPU_HPPA" = "xyes") + AM_CONDITIONAL(HAVE_CPU_MIPS, test "x$HAVE_CPU_MIPS" = "xyes") + AM_CONDITIONAL(HAVE_CPU_S390, test "x$HAVE_CPU_S390" = "xyes") + AM_CONDITIONAL(HAVE_CPU_IA64, test "x$HAVE_CPU_IA64" = "xyes") + AM_CONDITIONAL(HAVE_CPU_M68K, test "x$HAVE_CPU_M68K" = "xyes") + AM_CONDITIONAL(HAVE_CPU_X86_64, test "x$HAVE_CPU_X86_64" = "xyes") + AM_CONDITIONAL(HAVE_CPU_CRIS, test "x$HAVE_CPU_CRIS" = "xyes") + AM_CONDITIONAL(HAVE_CPU_CRISV32, test "x$HAVE_CPU_CRISV32" = "xyes") + + AC_DEFINE_UNQUOTED(HOST_CPU, "$host_cpu", [the host CPU]) +]) + +dnl check if unaligned memory access works correctly +AC_DEFUN([AG_GST_UNALIGNED_ACCESS], [ + AC_MSG_CHECKING([if unaligned memory access works correctly]) + if test x"$as_cv_unaligned_access" = x ; then + case $host in + alpha*|arm*|hp*|mips*|sh*|sparc*|ia64*) + _AS_ECHO_N([(blacklisted) ]) + as_cv_unaligned_access=no + ;; + i?86*|powerpc*|m68k*|cris*) + _AS_ECHO_N([(whitelisted) ]) + as_cv_unaligned_access=yes + ;; + esac + else + _AS_ECHO_N([(cached) ]) + fi + if test x"$as_cv_unaligned_access" = x ; then + AC_TRY_RUN([ +int main(int argc, char **argv) +{ + char array[] = "ABCDEFGH"; + unsigned int iarray[2]; + memcpy(iarray,array,8); +#define GET(x) (*(unsigned int *)((char *)iarray + (x))) + if(GET(0) != 0x41424344 && GET(0) != 0x44434241) return 1; + if(GET(1) != 0x42434445 && GET(1) != 0x45444342) return 1; + if(GET(2) != 0x43444546 && GET(2) != 0x46454443) return 1; + if(GET(3) != 0x44454647 && GET(3) != 0x47464544) return 1; + return 0; +} + ], as_cv_unaligned_access="yes", as_cv_unaligned_access="no") + fi + AC_MSG_RESULT($as_cv_unaligned_access) + if test "$as_cv_unaligned_access" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_UNALIGNED_ACCESS, 1, + [defined if unaligned memory access works correctly]) + fi +]) diff --git a/common/m4/gst-args.m4 b/common/m4/gst-args.m4 new file mode 100644 index 0000000000..a326f96f2b --- /dev/null +++ b/common/m4/gst-args.m4 @@ -0,0 +1,276 @@ +dnl configure-time options shared among gstreamer modules + +dnl AG_GST_ARG_DEBUG +dnl AG_GST_ARG_PROFILING +dnl AG_GST_ARG_VALGRIND +dnl AG_GST_ARG_GCOV + +dnl AG_GST_ARG_EXAMPLES + +dnl AG_GST_ARG_WITH_PKG_CONFIG_PATH +dnl AG_GST_ARG_WITH_PACKAGE_NAME +dnl AG_GST_ARG_WITH_PACKAGE_ORIGIN + +dnl AG_GST_ARG_WITH_PLUGINS + +dnl AG_GST_ARG_ENABLE_EXTERNAL +dnl AG_GST_ARG_ENABLE_EXPERIMENTAL +dnl AG_GST_ARG_ENABLE_BROKEN + +AC_DEFUN([AG_GST_ARG_DEBUG], +[ + dnl debugging stuff + AC_ARG_ENABLE(debug, + AC_HELP_STRING([--disable-debug],[disable addition of -g debugging info]), + [ + case "${enableval}" in + yes) USE_DEBUG=yes ;; + no) USE_DEBUG=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; + esac + ], + [USE_DEBUG=yes]) dnl Default value +]) + +AC_DEFUN([AG_GST_ARG_PROFILING], +[ + AC_ARG_ENABLE(profiling, + AC_HELP_STRING([--enable-profiling], + [adds -pg to compiler commandline, for profiling]), + [ + case "${enableval}" in + yes) USE_PROFILING=yes ;; + no) USE_PROFILING=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-profiling) ;; + esac + ], + [USE_PROFILING=no]) dnl Default value +]) + +AC_DEFUN([AG_GST_ARG_VALGRIND], +[ + dnl valgrind inclusion + AC_ARG_ENABLE(valgrind, + AC_HELP_STRING([--disable-valgrind],[disable run-time valgrind detection]), + [ + case "${enableval}" in + yes) USE_VALGRIND="$USE_DEBUG" ;; + no) USE_VALGRIND=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-valgrind) ;; + esac + ], + [USE_VALGRIND="$USE_DEBUG"]) dnl Default value + VALGRIND_REQ="2.1" + if test "x$USE_VALGRIND" = xyes; then + PKG_CHECK_MODULES(VALGRIND, valgrind > $VALGRIND_REQ, + USE_VALGRIND="yes", + [ + USE_VALGRIND="no" + AC_MSG_RESULT([no]) + ]) + fi + if test "x$USE_VALGRIND" = xyes; then + AC_DEFINE(HAVE_VALGRIND, 1, [Define if valgrind should be used]) + AC_MSG_NOTICE(Using extra code paths for valgrind) + fi +]) + +AC_DEFUN([AG_GST_ARG_GCOV], +[ + AC_ARG_ENABLE(gcov, + AC_HELP_STRING([--enable-gcov], + [compile with coverage profiling instrumentation (gcc only)]), + enable_gcov=$enableval, + enable_gcov=no) + if test x$enable_gcov = xyes ; then + if test "x$GCC" != "xyes" + then + AC_MSG_ERROR([gcov only works if gcc is used]) + fi + + AS_COMPILER_FLAG(["-fprofile-arcs"], + [GCOV_CFLAGS="$GCOV_CFLAGS -fprofile-arcs"], + true) + AS_COMPILER_FLAG(["-ftest-coverage"], + [GCOV_CFLAGS="$GCOV_CFLAGS -ftest-coverage"], + true) + dnl remove any -O flags - FIXME: is this needed ? + GCOV_CFLAGS=`echo "$GCOV_CFLAGS" | sed -e 's/-O[[0-9]]*//g'` + dnl libtool 1.5.22 and lower strip -fprofile-arcs from the flags + dnl passed to the linker, which is a bug; -fprofile-arcs implicitly + dnl links in -lgcov, so we do it explicitly here for the same effect + GCOV_LIBS=-lgcov + AC_SUBST(GCOV_CFLAGS) + AC_SUBST(GCOV_LIBS) + GCOV=`echo $CC | sed s/gcc/gcov/g` + AC_SUBST(GCOV) + + GST_GCOV_ENABLED=yes + AC_DEFINE_UNQUOTED(GST_GCOV_ENABLED, 1, + [Defined if gcov is enabled to force a rebuild due to config.h changing]) + dnl if gcov is used, we do not want default -O2 CFLAGS + if test "x$GST_GCOV_ENABLED" = "xyes" + then + CFLAGS="-O0" + AC_SUBST(CFLAGS) + CXXFLAGS="-O0" + AC_SUBST(CXXFLAGS) + FFLAGS="-O0" + AC_SUBST(FFLAGS) + CCASFLAGS="-O0" + AC_SUBST(CCASFLAGS) + AC_MSG_NOTICE([gcov enabled, setting CFLAGS and friends to $CFLAGS]) + fi + fi + AM_CONDITIONAL(GST_GCOV_ENABLED, test x$enable_gcov = xyes) +]) + +AC_DEFUN([AG_GST_ARG_EXAMPLES], +[ + AC_ARG_ENABLE(examples, + AC_HELP_STRING([--disable-examples], [disable building examples]), + [ + case "${enableval}" in + yes) BUILD_EXAMPLES=yes ;; + no) BUILD_EXAMPLES=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-examples) ;; + esac + ], + [BUILD_EXAMPLES=yes]) dnl Default value + AM_CONDITIONAL(BUILD_EXAMPLES, test "x$BUILD_EXAMPLES" = "xyes") +]) + +AC_DEFUN([AG_GST_ARG_WITH_PKG_CONFIG_PATH], +[ + dnl possibly modify pkg-config path + AC_ARG_WITH(pkg-config-path, + AC_HELP_STRING([--with-pkg-config-path], + [colon-separated list of pkg-config(1) dirs]), + [ + export PKG_CONFIG_PATH=${withval} + AC_MSG_NOTICE(Set PKG_CONFIG_PATH to $PKG_CONFIG_PATH) + ]) +]) + + +dnl This macro requires that GST_CVS is set to yes or no (release) +AC_DEFUN([AG_GST_ARG_WITH_PACKAGE_NAME], +[ + dnl package name in plugins + AC_ARG_WITH(package-name, + AC_HELP_STRING([--with-package-name], + [specify package name to use in plugins]), + [ + case "${withval}" in + yes) AC_MSG_ERROR(bad value ${withval} for --with-package-name) ;; + no) AC_MSG_ERROR(bad value ${withval} for --with-package-name) ;; + *) GST_PACKAGE_NAME="${withval}" ;; + esac + ], + [ + P=$1 + if test "x$P" = "x" + then + P=$PACKAGE_NAME + fi + + dnl default value + if test "x$GST_CVS" = "xyes" + then + dnl nano >= 1 + GST_PACKAGE_NAME="$P CVS/prerelease" + else + GST_PACKAGE_NAME="$P source release" + fi + ] + ) + AC_MSG_NOTICE(Using $GST_PACKAGE_NAME as package name) + AC_DEFINE_UNQUOTED(GST_PACKAGE_NAME, "$GST_PACKAGE_NAME", + [package name in plugins]) + AC_SUBST(GST_PACKAGE_NAME) +]) + +AC_DEFUN([AG_GST_ARG_WITH_PACKAGE_ORIGIN], +[ + dnl package origin URL + AC_ARG_WITH(package-origin, + AC_HELP_STRING([--with-package-origin], + [specify package origin URL to use in plugins]), + [ + case "${withval}" in + yes) AC_MSG_ERROR(bad value ${withval} for --with-package-origin) ;; + no) AC_MSG_ERROR(bad value ${withval} for --with-package-origin) ;; + *) GST_PACKAGE_ORIGIN="${withval}" ;; + esac + ], + [GST_PACKAGE_ORIGIN="[Unknown package origin]"] dnl Default value + ) + AC_MSG_NOTICE(Using $GST_PACKAGE_ORIGIN as package origin) + AC_DEFINE_UNQUOTED(GST_PACKAGE_ORIGIN, "$GST_PACKAGE_ORIGIN", + [package origin]) + AC_SUBST(GST_PACKAGE_ORIGIN) +]) + +dnl sets GST_PLUGINS_SELECTED to the list given as an argument, or to +dnl GST_PLUGINS_ALL +AC_DEFUN([AG_GST_ARG_WITH_PLUGINS], +[ + AC_ARG_WITH(plugins, + AC_HELP_STRING([--with-plugins], + [comma-separated list of dependencyless plug-ins to compile]), + [ + for i in `echo $withval | tr , ' '`; do + if echo $GST_PLUGINS_ALL | grep $i > /dev/null + then + GST_PLUGINS_SELECTED="$GST_PLUGINS_SELECTED $i" + else + echo "plug-in $i not recognized, ignoring..." + fi + done], + [GST_PLUGINS_SELECTED=$GST_PLUGINS_ALL]) +]) + +AC_DEFUN([AG_GST_ARG_ENABLE_EXTERNAL], +[ + AG_GST_CHECK_FEATURE(EXTERNAL, [enable building of plug-ins with external deps],, + HAVE_EXTERNAL=yes, enabled, + [ + AC_MSG_NOTICE(building external plug-ins) + BUILD_EXTERNAL="yes" + ],[ + AC_MSG_WARN(all plug-ins with external dependencies will not be built) + BUILD_EXTERNAL="no" + ]) + # make BUILD_EXTERNAL available to Makefile.am + AM_CONDITIONAL(BUILD_EXTERNAL, test "x$BUILD_EXTERNAL" = "xyes") +]) + +dnl experimental plug-ins; stuff that hasn't had the dust settle yet +dnl read 'builds, but might not work' +AC_DEFUN([AG_GST_ARG_ENABLE_EXPERIMENTAL], +[ + AG_GST_CHECK_FEATURE(EXPERIMENTAL, + [building of experimental plug-ins],, + HAVE_EXPERIMENTAL=yes, disabled, + [ + AC_MSG_WARN(building experimental plug-ins) + BUILD_EXPERIMENTAL="yes" + ],[ + AC_MSG_NOTICE(not building experimental plug-ins) + BUILD_EXPERIMENTAL="no" + ]) + # make BUILD_EXPERIMENTAL available to Makefile.am + AM_CONDITIONAL(BUILD_EXPERIMENTAL, test "x$BUILD_EXPERIMENTAL" = "xyes") +]) + +dnl broken plug-ins; stuff that doesn't seem to build at the moment +AC_DEFUN([AG_GST_ARG_ENABLE_BROKEN], +[ + AG_GST_CHECK_FEATURE(BROKEN, [enable building of broken plug-ins],, + HAVE_BROKEN=yes, disabled, + [ + AC_MSG_WARN([building broken plug-ins -- no bug reports on these, only patches ...]) + ],[ + AC_MSG_NOTICE([not building broken plug-ins]) + ]) +]) diff --git a/common/m4/gst-check.m4 b/common/m4/gst-check.m4 new file mode 100644 index 0000000000..3f6b8ffd46 --- /dev/null +++ b/common/m4/gst-check.m4 @@ -0,0 +1,138 @@ +dnl pkg-config-based checks for GStreamer modules and dependency modules + +dnl generic: +dnl AG_GST_PKG_CHECK_MODULES([PREFIX], [WHICH], [REQUIRED]) +dnl sets HAVE_[$PREFIX], [$PREFIX]_* +dnl AG_GST_CHECK_MODULES([PREFIX], [MODULE], [MINVER], [NAME], [REQUIRED]) +dnl sets HAVE_[$PREFIX], [$PREFIX]_* + +dnl specific: +dnl AG_GST_CHECK_GST([MAJMIN], [MINVER], [REQUIRED]) +dnl also sets/ACSUBSTs GST_TOOLS_DIR and GST_PLUGINS_DIR +dnl AG_GST_CHECK_GST_BASE([MAJMIN], [MINVER], [REQUIRED]) +dnl AG_GST_CHECK_GST_GDP([MAJMIN], [MINVER], [REQUIRED]) +dnl AG_GST_CHECK_GST_CONTROLLER([MAJMIN], [MINVER], [REQUIRED]) +dnl AG_GST_CHECK_GST_CHECK([MAJMIN], [MINVER], [REQUIRED]) +dnl AG_GST_CHECK_GST_PLUGINS_BASE([MAJMIN], [MINVER], [REQUIRED]) +dnl also sets/ACSUBSTs GSTPB_PLUGINS_DIR + +AC_DEFUN([AG_GST_PKG_CHECK_MODULES], +[ + which="[$2]" + dnl not required by default, since we use this mostly for plugin deps + required=ifelse([$3], , "no", [$3]) + + PKG_CHECK_MODULES([$1], $which, + [ + HAVE_[$1]="yes" + ], + [ + HAVE_[$1]="no" + AC_MSG_RESULT(no) + if test "x$required" = "xyes"; then + AC_MSG_ERROR($[$1]_PKG_ERRORS) + else + AC_MSG_NOTICE($[$1]_PKG_ERRORS) + fi + ]) + + dnl AC_SUBST of CFLAGS and LIBS was not done before automake 1.7 + dnl It gets done automatically in automake >= 1.7, which we now require +])) + +AC_DEFUN([AG_GST_CHECK_MODULES], +[ + module=[$2] + minver=[$3] + name="[$4]" + required=ifelse([$5], , "yes", [$5]) dnl required by default + + PKG_CHECK_MODULES([$1], $module >= $minver, + [ + HAVE_[$1]="yes" + ], + [ + HAVE_[$1]="no" + AC_MSG_RESULT(no) + AC_MSG_NOTICE($[$1]_PKG_ERRORS) + if test "x$required" = "xyes"; then + AC_MSG_ERROR([no $module >= $minver ($name) found]) + else + AC_MSG_NOTICE([no $module >= $minver ($name) found]) + fi + ]) + + dnl AC_SUBST of CFLAGS and LIBS was not done before automake 1.7 + dnl It gets done automatically in automake >= 1.7, which we now require +])) + +AC_DEFUN([AG_GST_CHECK_GST], +[ + AG_GST_CHECK_MODULES(GST, gstreamer-[$1], [$2], [GStreamer], [$3]) + dnl allow setting before calling this macro to override + if test -z $GST_TOOLS_DIR; then + GST_TOOLS_DIR=`$PKG_CONFIG --variable=toolsdir gstreamer-[$1]` + if test -z $GST_TOOLS_DIR; then + AC_MSG_ERROR( + [no tools dir set in GStreamer pkg-config file, core upgrade needed.]) + fi + fi + AC_MSG_NOTICE([using GStreamer tools in $GST_TOOLS_DIR]) + AC_SUBST(GST_TOOLS_DIR) + + dnl check for where core plug-ins got installed + dnl this is used for unit tests + dnl allow setting before calling this macro to override + if test -z $GST_PLUGINS_DIR; then + GST_PLUGINS_DIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-[$1]` + if test -z $GST_PLUGINS_DIR; then + AC_MSG_ERROR( + [no pluginsdir set in GStreamer pkg-config file, core upgrade needed.]) + fi + fi + AC_MSG_NOTICE([using GStreamer plug-ins in $GST_PLUGINS_DIR]) + AC_SUBST(GST_PLUGINS_DIR) +]) + +AC_DEFUN([AG_GST_CHECK_GST_BASE], +[ + AG_GST_CHECK_MODULES(GST_BASE, gstreamer-base-[$1], [$2], + [GStreamer Base Libraries], [$3]) +]) + +AC_DEFUN([AG_GST_CHECK_GST_GDP], +[ + AG_GST_CHECK_MODULES(GST_GDP, gstreamer-dataprotocol-[$1], [$2], + [GStreamer Data Protocol Library], [$3]) +]) + +AC_DEFUN([AG_GST_CHECK_GST_CONTROLLER], +[ + AG_GST_CHECK_MODULES(GST_CONTROLLER, gstreamer-controller-[$1], [$2], + [GStreamer Controller Library], [$3]) +]) + +AC_DEFUN([AG_GST_CHECK_GST_CHECK], +[ + AG_GST_CHECK_MODULES(GST_CHECK, gstreamer-check-[$1], [$2], + [GStreamer Check unittest Library], [$3]) +]) + +AC_DEFUN([AG_GST_CHECK_GST_PLUGINS_BASE], +[ + AG_GST_CHECK_MODULES(GST_PLUGINS_BASE, gstreamer-plugins-base-[$1], [$2], + [GStreamer Base Plug-ins Library], [$3]) + + dnl check for where base plug-ins got installed + dnl this is used for unit tests + dnl allow setting before calling this macro to override + if test -z $GSTPB_PLUGINS_DIR; then + GSTPB_PLUGINS_DIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-plugins-base-[$1]` + if test -z $GSTPB_PLUGINS_DIR; then + AC_MSG_ERROR( + [no pluginsdir set in GStreamer Base Plug-ins pkg-config file]) + fi + fi + AC_MSG_NOTICE([using GStreamer Base Plug-ins in $GSTPB_PLUGINS_DIR]) + AC_SUBST(GSTPB_PLUGINS_DIR) +]) diff --git a/common/m4/gst-debuginfo.m4 b/common/m4/gst-debuginfo.m4 new file mode 100644 index 0000000000..b48854d97a --- /dev/null +++ b/common/m4/gst-debuginfo.m4 @@ -0,0 +1,46 @@ +AC_DEFUN([AG_GST_DEBUGINFO], [ +AC_ARG_ENABLE(debug, +AC_HELP_STRING([--disable-debug],[disable addition of -g debugging info]), +[case "${enableval}" in + yes) USE_DEBUG=yes ;; + no) USE_DEBUG=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; +esac], +[USE_DEBUG=yes]) dnl Default value + +AC_ARG_ENABLE(DEBUG, +AC_HELP_STRING([--disable-DEBUG],[disables compilation of debugging messages]), +[case "${enableval}" in + yes) ENABLE_DEBUG=yes ;; + no) ENABLE_DEBUG=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-DEBUG) ;; +esac], +[ENABLE_DEBUG=yes]) dnl Default value +if test x$ENABLE_DEBUG = xyes; then + AC_DEFINE(GST_DEBUG_ENABLED, 1, [Define if DEBUG statements should be compiled in]) +fi + +AC_ARG_ENABLE(INFO, +AC_HELP_STRING([--disable-INFO],[disables compilation of informational messages]), +[case "${enableval}" in + yes) ENABLE_INFO=yes ;; + no) ENABLE_INFO=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-INFO) ;; +esac], +[ENABLE_INFO=yes]) dnl Default value +if test x$ENABLE_INFO = xyes; then + AC_DEFINE(GST_INFO_ENABLED, 1, [Define if INFO statements should be compiled in]) +fi + +AC_ARG_ENABLE(debug-color, +AC_HELP_STRING([--disable-debug-color],[disables color output of DEBUG and INFO output]), +[case "${enableval}" in + yes) ENABLE_DEBUG_COLOR=yes ;; + no) ENABLE_DEBUG_COLOR=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug-color) ;; +esac], +[ENABLE_DEBUG_COLOR=yes]) dnl Default value +if test "x$ENABLE_DEBUG_COLOR" = xyes; then + AC_DEFINE(GST_DEBUG_COLOR, 1, [Define if debugging messages should be colorized]) +fi +]) diff --git a/common/m4/gst-default.m4 b/common/m4/gst-default.m4 new file mode 100644 index 0000000000..da1a81c938 --- /dev/null +++ b/common/m4/gst-default.m4 @@ -0,0 +1,45 @@ +dnl default elements used for tests and such + +dnl AG_GST_DEFAULT_ELEMENTS + +AC_DEFUN([AG_GST_DEFAULT_ELEMENTS], +[ + dnl decide on default elements + dnl FIXME: provide configure-time options for this + dnl FIXME: describe where exactly this gets used + dnl FIXME: decide if it's a problem that this could point to sinks from + dnl depending plugin modules + DEFAULT_AUDIOSINK="autoaudiosink" + DEFAULT_VIDEOSINK="autovideosink" + DEFAULT_AUDIOSRC="alsasrc" + DEFAULT_VIDEOSRC="v4lsrc" + DEFAULT_VISUALIZER="goom" + case "$host" in + *-sun-* | *pc-solaris* ) + DEFAULT_AUDIOSINK="sunaudiosink" + DEFAULT_VIDEOSINK="ximagesink" + DEFAULT_AUDIOSRC="sunaudiosrc" + ;; + *-darwin* ) + DEFAULT_AUDIOSINK="osxaudiosink" + DEFAULT_AUDIOSRC="osxaudiosrc" + DEFAULT_VIDEOSINK="osxvideosink" + ;; + esac + + AC_SUBST(DEFAULT_AUDIOSINK) + AC_DEFINE_UNQUOTED(DEFAULT_AUDIOSINK, "$DEFAULT_AUDIOSINK", + [Default audio sink]) + AC_SUBST(DEFAULT_AUDIOSRC) + AC_DEFINE_UNQUOTED(DEFAULT_AUDIOSRC, "$DEFAULT_AUDIOSRC", + [Default audio source]) + AC_SUBST(DEFAULT_VIDEOSINK) + AC_DEFINE_UNQUOTED(DEFAULT_VIDEOSINK, "$DEFAULT_VIDEOSINK", + [Default video sink]) + AC_SUBST(DEFAULT_VIDEOSRC) + AC_DEFINE_UNQUOTED(DEFAULT_VIDEOSRC, "$DEFAULT_VIDEOSRC", + [Default video source]) + AC_SUBST(DEFAULT_VISUALIZER) + AC_DEFINE_UNQUOTED(DEFAULT_VISUALIZER, "$DEFAULT_VISUALIZER", + [Default visualizer]) +]) diff --git a/common/m4/gst-doc.m4 b/common/m4/gst-doc.m4 new file mode 100644 index 0000000000..7000c17ad1 --- /dev/null +++ b/common/m4/gst-doc.m4 @@ -0,0 +1,148 @@ +AC_DEFUN([AG_GST_DOCBOOK_CHECK], +[ + dnl choose a location to install docbook docs in + if test "x$PACKAGE_TARNAME" = "x" + then + AC_MSG_ERROR([Internal error - PACKAGE_TARNAME not set]) + fi + docdir="\$(datadir)/doc/$PACKAGE_TARNAME-$GST_MAJORMINOR" + + dnl enable/disable docbook documentation building + AC_ARG_ENABLE(docbook, + AC_HELP_STRING([--enable-docbook], + [use docbook to build documentation [default=no]]),, + enable_docbook=no) + + have_docbook=no + + if test x$enable_docbook = xyes; then + dnl check if we actually have everything we need + + dnl check for docbook tools + AC_CHECK_PROG(HAVE_DOCBOOK2PS, docbook2ps, yes, no) + AC_CHECK_PROG(HAVE_DOCBOOK2HTML, docbook2html, yes, no) + AC_CHECK_PROG(HAVE_JADETEX, jadetex, yes, no) + AC_CHECK_PROG(HAVE_PS2PDF, ps2pdf, yes, no) + + # -V option appeared in 0.6.10 + docbook2html_min_version=0.6.10 + if test "x$HAVE_DOCBOOK2HTML" != "xno"; then + docbook2html_version=`docbook2html --version` + AC_MSG_CHECKING([docbook2html version ($docbook2html_version) >= $docbook2html_min_version]) + if perl -w < \$min_version_major) || + ((\$docbook2html_version_major == \$min_version_major) && + (\$docbook2html_version_minor >= \$min_version_minor)) || + ((\$docbook2html_version_major == \$min_version_major) && + (\$docbook2html_version_minor >= \$min_version_minor) && + (\$docbook2html_version_micro >= \$min_version_micro))) + ? 0 : 1); +EOF + then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + HAVE_DOCBOOK2HTML=no + fi + fi + + dnl check if we can process docbook stuff + AS_DOCBOOK(have_docbook=yes, have_docbook=no) + + dnl check for extra tools + AC_CHECK_PROG(HAVE_DVIPS, dvips, yes, no) + AC_CHECK_PROG(HAVE_XMLLINT, xmllint, yes, no) + + dnl check for image conversion tools + AC_CHECK_PROG(HAVE_FIG2DEV, fig2dev, yes, no) + if test "x$HAVE_FIG2DEV" = "xno" ; then + AC_MSG_WARN([Did not find fig2dev (from xfig), images will not be generated.]) + fi + + dnl The following is a hack: if fig2dev doesn't display an error message + dnl for the desired type, we assume it supports it. + HAVE_FIG2DEV_EPS=no + if test "x$HAVE_FIG2DEV" = "xyes" ; then + fig2dev_quiet=`fig2dev -L eps &1 >/dev/null` + if test "x$fig2dev_quiet" = "x" ; then + HAVE_FIG2DEV_EPS=yes + fi + fi + HAVE_FIG2DEV_PNG=no + if test "x$HAVE_FIG2DEV" = "xyes" ; then + fig2dev_quiet=`fig2dev -L png &1 >/dev/null` + if test "x$fig2dev_quiet" = "x" ; then + HAVE_FIG2DEV_PNG=yes + fi + fi + HAVE_FIG2DEV_PDF=no + if test "x$HAVE_FIG2DEV" = "xyes" ; then + fig2dev_quiet=`fig2dev -L pdf &1 >/dev/null` + if test "x$fig2dev_quiet" = "x" ; then + HAVE_FIG2DEV_PDF=yes + fi + fi + + AC_CHECK_PROG(HAVE_PNGTOPNM, pngtopnm, yes, no) + AC_CHECK_PROG(HAVE_PNMTOPS, pnmtops, yes, no) + AC_CHECK_PROG(HAVE_EPSTOPDF, epstopdf, yes, no) + + dnl check if we can generate HTML + if test "x$HAVE_DOCBOOK2HTML" = "xyes" && \ + test "x$enable_docbook" = "xyes" && \ + test "x$HAVE_XMLLINT" = "xyes" && \ + test "x$HAVE_FIG2DEV_PNG" = "xyes"; then + DOC_HTML=yes + AC_MSG_NOTICE(Will output HTML documentation) + else + DOC_HTML=no + AC_MSG_NOTICE(Will not output HTML documentation) + fi + + dnl check if we can generate PS + if test "x$HAVE_DOCBOOK2PS" = "xyes" && \ + test "x$enable_docbook" = "xyes" && \ + test "x$HAVE_XMLLINT" = "xyes" && \ + test "x$HAVE_JADETEX" = "xyes" && \ + test "x$HAVE_FIG2DEV_EPS" = "xyes" && \ + test "x$HAVE_DVIPS" = "xyes" && \ + test "x$HAVE_PNGTOPNM" = "xyes" && \ + test "x$HAVE_PNMTOPS" = "xyes"; then + DOC_PS=yes + AC_MSG_NOTICE(Will output PS documentation) + else + DOC_PS=no + AC_MSG_NOTICE(Will not output PS documentation) + fi + + dnl check if we can generate PDF - using only ps2pdf + if test "x$DOC_PS" = "xyes" && \ + test "x$enable_docbook" = "xyes" && \ + test "x$HAVE_XMLLINT" = "xyes" && \ + test "x$HAVE_PS2PDF" = "xyes"; then + DOC_PDF=yes + AC_MSG_NOTICE(Will output PDF documentation) + else + DOC_PDF=no + AC_MSG_NOTICE(Will not output PDF documentation) + fi + + dnl if we don't have everything, we should disable + if test "x$have_docbook" != "xyes"; then + enable_docbook=no + fi + fi + + dnl if we're going to install documentation, tell us where + if test "x$have_docbook" = "xyes"; then + AC_MSG_NOTICE(Installing documentation in $docdir) + AC_SUBST(docdir) + fi + + AM_CONDITIONAL(ENABLE_DOCBOOK, test x$enable_docbook = xyes) + AM_CONDITIONAL(DOC_HTML, test x$DOC_HTML = xyes) + AM_CONDITIONAL(DOC_PDF, test x$DOC_PDF = xyes) + AM_CONDITIONAL(DOC_PS, test x$DOC_PS = xyes) +]) diff --git a/common/m4/gst-error.m4 b/common/m4/gst-error.m4 new file mode 100644 index 0000000000..4c3f12c4df --- /dev/null +++ b/common/m4/gst-error.m4 @@ -0,0 +1,71 @@ +dnl handle various error-related things + +dnl Thomas Vander Stichele + +dnl Last modification: 2005-10-16 + +dnl AG_GST_SET_ERROR_CFLAGS([ADD-WERROR]) +dnl AG_GST_SET_LEVEL_DEFAULT([IS-CVS-VERSION]) + + +dnl Sets ERROR_CFLAGS to something the compiler will accept. +dnl AC_SUBST them so they are available in Makefile + +dnl -Wall is added if it is supported +dnl -Werror is added if ADD-WERROR is not "no" + +dnl These flags can be overridden at make time: +dnl make ERROR_CFLAGS= +AC_DEFUN([AG_GST_SET_ERROR_CFLAGS], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AS_COMPILER_FLAG]) + + + dnl if we support -Wall, set it unconditionally + AS_COMPILER_FLAG(-Wall, + ERROR_CFLAGS="-Wall", + ERROR_CFLAGS="") + + dnl if asked for, add -Werror if supported + if test "x$1" != "xno" + then + AS_COMPILER_FLAG(-Werror, ERROR_CFLAGS="$ERROR_CFLAGS -Werror") + + dnl if -Werror isn't suported + if test "x$ERROR_CFLAGS" == "x" + then + dnl try -errwarn=%all,no%E_EMPTY_DECLARATION,no%E_STATEMENT_NOT_REACHED (Sun Forte case) + dnl For Forte we need disable "empty declaration" warning produced by un-needed semicolon + dnl "statement not reached" disabled because there is g_assert_not_reached () in some places + AS_COMPILER_FLAG([-errwarn=%all,no%E_EMPTY_DECLARATION,no%E_STATEMENT_NOT_REACHED], + [ERROR_CFLAGS="-errwarn=%all,no%E_EMPTY_DECLARATION,no%E_STATEMENT_NOT_REACHED"]) + + dnl if this also isn't suported, try only for -errwarn=%all + if test "x$ERROR_CFLAGS" == "x" + then + AS_COMPILER_FLAG(-errwarn=%all, + ERROR_CFLAGS="-errwarn=%all") + fi + fi + fi + + AC_SUBST(ERROR_CFLAGS) + AC_MSG_NOTICE([set ERROR_CFLAGS to $ERROR_CFLAGS]) +]) + +dnl Sets the default error level for debugging messages +AC_DEFUN([AG_GST_SET_LEVEL_DEFAULT], +[ + dnl define correct errorlevel for debugging messages. We want to have + dnl GST_ERROR messages printed when running cvs builds + if test "x[$1]" = "xyes"; then + GST_LEVEL_DEFAULT=GST_LEVEL_ERROR + else + GST_LEVEL_DEFAULT=GST_LEVEL_NONE + fi + AC_DEFINE_UNQUOTED(GST_LEVEL_DEFAULT, $GST_LEVEL_DEFAULT, + [Default errorlevel to use]) + dnl AC_SUBST so we can use it for win32/common/config.h + AC_SUBST(GST_LEVEL_DEFAULT) +]) diff --git a/common/m4/gst-feature.m4 b/common/m4/gst-feature.m4 new file mode 100644 index 0000000000..510d228d9a --- /dev/null +++ b/common/m4/gst-feature.m4 @@ -0,0 +1,285 @@ +dnl Perform a check for a feature for GStreamer +dnl Richard Boulton +dnl Thomas Vander Stichele added useful stuff +dnl Last modification: 25/06/2001 +dnl AG_GST_CHECK_FEATURE(FEATURE-NAME, FEATURE-DESCRIPTION, +dnl DEPENDENT-PLUGINS, TEST-FOR-FEATURE, +dnl DISABLE-BY-DEFAULT, ACTION-IF-USE, ACTION-IF-NOTUSE) +dnl +dnl This macro adds a command line argument to allow the user to enable +dnl or disable a feature, and if the feature is enabled, performs a supplied +dnl test to check if the feature is available. +dnl +dnl The test should define HAVE_ to "yes" or "no" depending +dnl on whether the feature is available. +dnl +dnl The macro will set USE_ to "yes" or "no" depending on +dnl whether the feature is to be used. +dnl Thomas changed this, so that when USE_ was already set +dnl to no, then it stays that way. +dnl +dnl The macro will call AM_CONDITIONAL(USE_<, ...) to allow +dnl the feature to control what is built in Makefile.ams. If you want +dnl additional actions resulting from the test, you can add them with the +dnl ACTION-IF-USE and ACTION-IF-NOTUSE parameters. +dnl +dnl FEATURE-NAME is the name of the feature, and should be in +dnl purely upper case characters. +dnl FEATURE-DESCRIPTION is used to describe the feature in help text for +dnl the command line argument. +dnl DEPENDENT-PLUGINS lists any plug-ins which depend on this feature. +dnl TEST-FOR-FEATURE is a test which sets HAVE_ to "yes" +dnl or "no" depending on whether the feature is +dnl available. +dnl DISABLE-BY-DEFAULT if "disabled", the feature is disabled by default, +dnl if any other value, the feature is enabled by default. +dnl ACTION-IF-USE any extra actions to perform if the feature is to be +dnl used. +dnl ACTION-IF-NOTUSE any extra actions to perform if the feature is not to +dnl be used. +dnl +dnl +dnl thomas : +dnl we also added a history. +dnl GST_PLUGINS_YES will contain all plugins to be built +dnl that were checked through AG_GST_CHECK_FEATURE +dnl GST_PLUGINS_NO will contain those that won't be built + +AC_DEFUN([AG_GST_CHECK_FEATURE], +[echo +AC_MSG_NOTICE(*** checking feature: [$2] ***) +if test "x[$3]" != "x" +then + AC_MSG_NOTICE(*** for plug-ins: [$3] ***) +fi +dnl +builtin(define, [gst_endisable], ifelse($5, [disabled], [enable], [disable]))dnl +dnl if it is set to NO, then don't even consider it for building +NOUSE= +if test "x$USE_[$1]" = "xno"; then + NOUSE="yes" +fi +AC_ARG_ENABLE(translit([$1], A-Z, a-z), + [ ]builtin(format, --%-26s gst_endisable %s, gst_endisable-translit([$1], A-Z, a-z), [$2]ifelse([$3],,,: [$3])), + [ case "${enableval}" in + yes) USE_[$1]=yes;; + no) USE_[$1]=no;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-translit([$1], A-Z, a-z)) ;; + esac], + [ USE_$1=]ifelse($5, [disabled], [no], [yes])) dnl DEFAULT + +dnl *** set it back to no if it was preset to no +if test "x$NOUSE" = "xyes"; then + USE_[$1]="no" + AC_MSG_WARN(*** $3 pre-configured not to be built) +fi +NOUSE= + +dnl *** If it's enabled + +if test x$USE_[$1] = xyes; then + dnl save compile variables before the test + + gst_check_save_LIBS=$LIBS + gst_check_save_LDFLAGS=$LDFLAGS + gst_check_save_CFLAGS=$CFLAGS + gst_check_save_CPPFLAGS=$CPPFLAGS + gst_check_save_CXXFLAGS=$CXXFLAGS + + HAVE_[$1]=no + dnl TEST_FOR_FEATURE + $4 + + LIBS=$gst_check_save_LIBS + LDFLAGS=$gst_check_save_LDFLAGS + CFLAGS=$gst_check_save_CFLAGS + CPPFLAGS=$gst_check_save_CPPFLAGS + CXXFLAGS=$gst_check_save_CXXFLAGS + + dnl If it isn't found, unset USE_[$1] + if test x$HAVE_[$1] = xno; then + USE_[$1]=no + else + ifelse([$3], , :, [AC_MSG_NOTICE(*** These plugins will be built: [$3])]) + fi +fi +dnl *** Warn if it's disabled or not found +if test x$USE_[$1] = xyes; then + ifelse([$6], , :, [$6]) + if test "x$3" != "x"; then + GST_PLUGINS_YES="\t[$3]\n$GST_PLUGINS_YES" + fi + AC_DEFINE(HAVE_[$1], , [support for features: $3]) +else + ifelse([$3], , :, [AC_MSG_NOTICE(*** These plugins will not be built: [$3])]) + if test "x$3" != "x"; then + GST_PLUGINS_NO="\t[$3]\n$GST_PLUGINS_NO" + fi + ifelse([$7], , :, [$7]) +fi +dnl *** Define the conditional as appropriate +AM_CONDITIONAL(USE_[$1], test x$USE_[$1] = xyes) +]) + +dnl Use a -config program which accepts --cflags and --libs parameters +dnl to set *_CFLAGS and *_LIBS and check existence of a feature. +dnl Richard Boulton +dnl Last modification: 26/06/2001 +dnl AG_GST_CHECK_CONFIGPROG(FEATURE-NAME, CONFIG-PROG-FILENAME, MODULES) +dnl +dnl This check was written for GStreamer: it should be renamed and checked +dnl for portability if you decide to use it elsewhere. +dnl +AC_DEFUN([AG_GST_CHECK_CONFIGPROG], +[ + AC_PATH_PROG([$1]_CONFIG, [$2], no) + if test x$[$1]_CONFIG = xno; then + [$1]_LIBS= + [$1]_CFLAGS= + HAVE_[$1]=no + else + if [$2] --plugin-libs [$3] &> /dev/null; then + [$1]_LIBS=`[$2] --plugin-libs [$3]` + else + [$1]_LIBS=`[$2] --libs [$3]` + fi + [$1]_CFLAGS=`[$2] --cflags [$3]` + HAVE_[$1]=yes + fi + AC_SUBST([$1]_LIBS) + AC_SUBST([$1]_CFLAGS) +]) + +dnl Use AC_CHECK_LIB and AC_CHECK_HEADER to do both tests at once +dnl sets HAVE_module if we have it +dnl Richard Boulton +dnl Last modification: 26/06/2001 +dnl AG_GST_CHECK_LIBHEADER(FEATURE-NAME, LIB NAME, LIB FUNCTION, EXTRA LD FLAGS, +dnl HEADER NAME, ACTION-IF-FOUND, ACTION-IF-NOT-FOUND) +dnl +dnl This check was written for GStreamer: it should be renamed and checked +dnl for portability if you decide to use it elsewhere. +dnl +AC_DEFUN([AG_GST_CHECK_LIBHEADER], +[ + AC_CHECK_LIB([$2], [$3], HAVE_[$1]=yes, HAVE_[$1]=no,[$4]) + if test "x$HAVE_[$1]" = "xyes"; then + AC_CHECK_HEADER([$5], :, HAVE_[$1]=no) + if test "x$HAVE_[$1]" = "xyes"; then + dnl execute what needs to be + ifelse([$6], , :, [$6]) + else + ifelse([$7], , :, [$7]) + fi + else + ifelse([$7], , :, [$7]) + fi + AC_SUBST(HAVE_[$1]) +] +) + +dnl 2004-02-14 Thomas - changed to get set properly and use proper output +dnl 2003-06-27 Benjamin Otte - changed to make this work with gstconfig.h +dnl +dnl Add a subsystem --disable flag and all the necessary symbols and substitions +dnl +dnl AG_GST_CHECK_SUBSYSTEM_DISABLE(SYSNAME, [subsystem name]) +dnl +AC_DEFUN([AG_GST_CHECK_SUBSYSTEM_DISABLE], +[ + dnl this define will replace each literal subsys_def occurrence with + dnl the lowercase hyphen-separated subsystem + dnl e.g. if $1 is GST_DEBUG then subsys_def will be a macro with gst-debug + define([subsys_def],translit([$1], _A-Z, -a-z)) + + AC_ARG_ENABLE(subsys_def, + AC_HELP_STRING(--disable-subsys_def, [disable $2]), + [ + case "${enableval}" in + yes) GST_DISABLE_[$1]=no ;; + no) GST_DISABLE_[$1]=yes ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-subsys_def]) ;; + esac + ], + [GST_DISABLE_[$1]=no]) dnl Default value + + if test x$GST_DISABLE_[$1] = xyes; then + AC_MSG_NOTICE([disabled subsystem [$2]]) + GST_DISABLE_[$1]_DEFINE="#define GST_DISABLE_$1 1" + else + GST_DISABLE_[$1]_DEFINE="/* #undef GST_DISABLE_$1 */" + fi + AC_SUBST(GST_DISABLE_[$1]_DEFINE) + undefine([subsys_def]) +]) + + +dnl Parse gstconfig.h for feature and defines add the symbols and substitions +dnl +dnl AG_GST_PARSE_SUBSYSTEM_DISABLE(GST_CONFIGPATH, FEATURE) +dnl +AC_DEFUN([AG_GST_PARSE_SUBSYSTEM_DISABLE], +[ + grep >/dev/null "#undef GST_DISABLE_$2" $1 + if test $? = 0; then + GST_DISABLE_[$2]=0 + else + GST_DISABLE_[$2]=1 + fi + AC_SUBST(GST_DISABLE_[$2]) +]) + +dnl Parse gstconfig.h and defines add the symbols and substitions +dnl +dnl GST_CONFIGPATH=`$PKG_CONFIG --variable=includedir gstreamer-0.10`"/gst/gstconfig.h" +dnl AG_GST_PARSE_SUBSYSTEM_DISABLES(GST_CONFIGPATH) +dnl +AC_DEFUN([AG_GST_PARSE_SUBSYSTEM_DISABLES], +[ + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,GST_DEBUG) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,LOADSAVE) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,PARSE) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,TRACE) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,ALLOC_TRACE) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,REGISTRY) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,ENUMTYPES) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,INDEX) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,PLUGIN) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,URI) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,XML) +]) + + + +dnl relies on GST_PLUGINS_ALL, GST_PLUGINS_SELECTED, GST_PLUGINS_YES, +dnl GST_PLUGINS_NO, and BUILD_EXTERNAL +AC_DEFUN([AG_GST_OUTPUT_PLUGINS], [ + +echo "configure: *** Plug-ins without external dependencies that will be built:" +( for i in $GST_PLUGINS_SELECTED; do /bin/echo -e '\t'$i; done ) | sort +echo + +echo "configure: *** Plug-ins without external dependencies that will NOT be built:" +( for i in $GST_PLUGINS_ALL; do + case $GST_PLUGINS_SELECTED in + *$i*) + ;; + *) + /bin/echo -e '\t'$i + ;; + esac + done ) | sort +echo + +if test "x$BUILD_EXTERNAL" = "xno"; then + echo "configure: *** No plug-ins with external dependencies will be built" +else + /bin/echo -n "configure: *** Plug-ins with dependencies that will be built:" + /bin/echo -e "$GST_PLUGINS_YES" | sort + /bin/echo + /bin/echo -n "configure: *** Plug-ins with dependencies that will NOT be built:" + /bin/echo -e "$GST_PLUGINS_NO" | sort + /bin/echo +fi +]) + diff --git a/common/m4/gst-function.m4 b/common/m4/gst-function.m4 new file mode 100644 index 0000000000..12166214d5 --- /dev/null +++ b/common/m4/gst-function.m4 @@ -0,0 +1,63 @@ +dnl +dnl Check for compiler mechanism to show functions in debugging +dnl copied from an Ali patch floating on the internet +dnl +AC_DEFUN([AG_GST_CHECK_FUNCTION],[ + dnl #1: __PRETTY_FUNCTION__ + AC_MSG_CHECKING(whether $CC implements __PRETTY_FUNCTION__) + AC_CACHE_VAL(have_pretty_function,[ + AC_TRY_LINK([#include ], + [printf("%s", __PRETTY_FUNCTION__);], + have_pretty_function=yes, + have_pretty_function=no) + ]) + AC_MSG_RESULT($have_pretty_function) + if test "$have_pretty_function" = yes; then + AC_DEFINE(HAVE_PRETTY_FUNCTION, 1, + [defined if the compiler implements __PRETTY_FUNCTION__]) + fi + +dnl #2: __FUNCTION__ + AC_MSG_CHECKING(whether $CC implements __FUNCTION__) + AC_CACHE_VAL(have_function,[ + AC_TRY_LINK([#include ], + [printf("%s", __FUNCTION__);], + have_function=yes, + have_function=no) + ]) + AC_MSG_RESULT($have_function) + if test "$have_function" = yes; then + AC_DEFINE(HAVE_FUNCTION, 1, + [defined if the compiler implements __FUNCTION__]) + fi + +dnl #3: __func__ + AC_MSG_CHECKING(whether $CC implements __func__) + AC_CACHE_VAL(have_func,[ + AC_TRY_LINK([#include ], + [printf("%s", __func__);], + have_func=yes, + have_func=no) + ]) + AC_MSG_RESULT($have_func) + if test "$have_func" = yes; then + AC_DEFINE(HAVE_FUNC, 1, + [defined if the compiler implements __func__]) + fi + +dnl now define FUNCTION to whatever works, and fallback to "" + if test "$have_pretty_function" = yes; then + function=__PRETTY_FUNCTION__ + else + if test "$have_function" = yes; then + function=__FUNCTION__ + else + if test "$have_func" = yes; then + function=__func__ + else + function=\"\" + fi + fi + fi + AC_DEFINE_UNQUOTED(GST_FUNCTION, $function, [macro to use to show function name]) +]) diff --git a/common/m4/gst-gettext.m4 b/common/m4/gst-gettext.m4 new file mode 100644 index 0000000000..a63651bf84 --- /dev/null +++ b/common/m4/gst-gettext.m4 @@ -0,0 +1,21 @@ +dnl gettext setup + +dnl AG_GST_GETTEXT([gettext-package]) +dnl defines GETTEXT_PACKAGE and LOCALEDIR + +AC_DEFUN([AG_GST_GETTEXT], +[ + if test "$USE_NLS" = "yes"; then + GETTEXT_PACKAGE=[$1] + else + GETTEXT_PACKAGE=[NULL] + fi + AC_SUBST(GETTEXT_PACKAGE) + AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], "$GETTEXT_PACKAGE", + [gettext package name]) + + dnl define LOCALEDIR in config.h + AS_AC_EXPAND(LOCALEDIR, $datadir/locale) + AC_DEFINE_UNQUOTED([LOCALEDIR], "$LOCALEDIR", + [gettext locale dir]) +]) diff --git a/common/m4/gst-glib2.m4 b/common/m4/gst-glib2.m4 new file mode 100644 index 0000000000..71e293b279 --- /dev/null +++ b/common/m4/gst-glib2.m4 @@ -0,0 +1,26 @@ +dnl check for a minimum version of GLib + +dnl AG_GST_GLIB_CHECK([minimum-version-required]) + +AC_DEFUN([AG_GST_GLIB_CHECK], +[ + dnl Minimum required version of GLib + GLIB_REQ=[$1] + if test "x$GLIB_REQ" = "x" + then + AC_MSG_ERROR([Please specify a required version for GLib 2.0]) + fi + AC_SUBST(GLIB_REQ) + + dnl Check for glib with everything + PKG_CHECK_MODULES(GLIB, + glib-2.0 >= $GLIB_REQ gobject-2.0 gthread-2.0 gmodule-no-export-2.0, + HAVE_GLIB=yes,HAVE_GLIB=no) + + if test "x$HAVE_GLIB" = "xno"; then + AC_MSG_ERROR([This package requires GLib >= $GLIB_REQ to compile.]) + fi + + dnl for the poor souls who for example have glib in /usr/local + AS_SCRUB_INCLUDE(GLIB_CFLAGS) +]) diff --git a/common/m4/gst-libxml2.m4 b/common/m4/gst-libxml2.m4 new file mode 100644 index 0000000000..001d67b827 --- /dev/null +++ b/common/m4/gst-libxml2.m4 @@ -0,0 +1,43 @@ +dnl call this macro with the minimum required version as an argument +dnl this macro sets and AC_SUBSTs XML_CFLAGS and XML_LIBS +dnl it also sets LIBXML_PKG, used for the pkg-config file + +AC_DEFUN([AG_GST_LIBXML2_CHECK], +[ + dnl Minimum required version of libxml2 + dnl default to 2.4.9 if not specified + LIBXML2_REQ=ifelse([$1],,2.4.9,[$1]) + AC_SUBST(LIBXML2_REQ) + + dnl check for libxml2 + PKG_CHECK_MODULES(XML, libxml-2.0 >= $LIBXML2_REQ, + HAVE_LIBXML2=yes, HAVE_LIBXML2=no) + if test "x$HAVE_LIBXML2" = "xyes"; then + AC_DEFINE(HAVE_LIBXML2, 1, [Define if libxml2 is available]) + else + AC_MSG_ERROR([Need libxml2 for glib2 builds -- you should be able to do without it -- this needs fixing]) + fi + dnl this is for the .pc file + LIBXML_PKG=', libxml-2.0' + AC_SUBST(LIBXML_PKG) + AC_SUBST(XML_LIBS) + AC_SUBST(XML_CFLAGS) + + dnl XML_LIBS might pull in -lz without zlib actually being on the system, so + dnl try linking with these LIBS and CFLAGS + ac_save_CFLAGS=$CFLAGS + ac_save_LIBS=$LIBS + CFLAGS="$CFLAGS $XML_CFLAGS" + LIBS="$LIBS $XML_LIBS" + AC_TRY_LINK([ +#include +#include +],[ +/* function body */ +], + AC_MSG_NOTICE([Test xml2 program linked]), + AC_MSG_ERROR([Could not link libxml2 test program. Check if you have the necessary dependencies.]) + ) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" +]) diff --git a/common/m4/gst-plugindir.m4 b/common/m4/gst-plugindir.m4 new file mode 100644 index 0000000000..09989d0742 --- /dev/null +++ b/common/m4/gst-plugindir.m4 @@ -0,0 +1,17 @@ +dnl AG_GST_SET_PLUGINDIR + +dnl AC_DEFINE PLUGINDIR to the full location where plug-ins will be installed +dnl AC_SUBST plugindir, to be used in Makefile.am's + +AC_DEFUN([AG_GST_SET_PLUGINDIR], +[ + dnl define location of plugin directory + AS_AC_EXPAND(PLUGINDIR, ${libdir}/gstreamer-$GST_MAJORMINOR) + AC_DEFINE_UNQUOTED(PLUGINDIR, "$PLUGINDIR", + [directory where plugins are located]) + AC_MSG_NOTICE([Using $PLUGINDIR as the plugin install location]) + + dnl plugin directory configure-time variable for use in Makefile.am + plugindir="\$(libdir)/gstreamer-$GST_MAJORMINOR" + AC_SUBST(plugindir) +]) diff --git a/common/m4/gst-valgrind.m4 b/common/m4/gst-valgrind.m4 new file mode 100644 index 0000000000..93c26357b9 --- /dev/null +++ b/common/m4/gst-valgrind.m4 @@ -0,0 +1,35 @@ +AC_DEFUN([AG_GST_VALGRIND_CHECK], +[ + dnl valgrind inclusion + AC_ARG_ENABLE(valgrind, + AC_HELP_STRING([--disable-valgrind], [disable run-time valgrind detection]), + [ + case "${enableval}" in + yes) USE_VALGRIND="$USE_DEBUG" ;; + no) USE_VALGRIND=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-valgrind) ;; + esac], + [ + USE_VALGRIND="$USE_DEBUG" + ]) dnl Default value + + VALGRIND_REQ="2.1" + if test "x$USE_VALGRIND" = xyes; then + PKG_CHECK_MODULES(VALGRIND, valgrind > $VALGRIND_REQ, + USE_VALGRIND="yes", + [ + USE_VALGRIND="no" + AC_MSG_RESULT([no]) + ]) + fi + + if test "x$USE_VALGRIND" = xyes; then + AC_DEFINE(HAVE_VALGRIND, 1, [Define if valgrind should be used]) + AC_MSG_NOTICE(Using extra code paths for valgrind) + fi + AC_SUBST(VALGRIND_CFLAGS) + AC_SUBST(VALGRIND_LIBS) + + AC_PATH_PROG(VALGRIND_PATH, valgrind, no) + AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") +]) diff --git a/common/m4/gtk-doc.m4 b/common/m4/gtk-doc.m4 new file mode 100644 index 0000000000..af73800bf2 --- /dev/null +++ b/common/m4/gtk-doc.m4 @@ -0,0 +1,53 @@ +dnl -*- mode: autoconf -*- + +# serial 1 + +dnl Usage: +dnl GTK_DOC_CHECK([minimum-gtk-doc-version]) +AC_DEFUN([GTK_DOC_CHECK], +[ + AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first + dnl for overriding the documentation installation directory + AC_ARG_WITH(html-dir, + AC_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),, + [with_html_dir='${datadir}/gtk-doc/html']) + HTML_DIR="$with_html_dir" + AC_SUBST(HTML_DIR) + + dnl enable/disable documentation building + AC_ARG_ENABLE(gtk-doc, + AC_HELP_STRING([--enable-gtk-doc], + [use gtk-doc to build documentation [default=no]]),, + enable_gtk_doc=no) + + have_gtk_doc=no + if test x$enable_gtk_doc = xyes; then + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + if test "$PKG_CONFIG" != "no" && $PKG_CONFIG --exists gtk-doc; then + have_gtk_doc=yes + fi + + dnl do we want to do a version check? +ifelse([$1],[],, + [gtk_doc_min_version=$1 + if test "$have_gtk_doc" = yes; then + AC_MSG_CHECKING([gtk-doc version >= $gtk_doc_min_version]) + if $PKG_CONFIG --atleast-version $gtk_doc_min_version gtk-doc; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + have_gtk_doc=no + fi + fi +]) + if test "$have_gtk_doc" != yes; then + enable_gtk_doc=no + fi + fi + + AM_CONDITIONAL(ENABLE_GTK_DOC, test x$enable_gtk_doc = xyes) + AM_CONDITIONAL(GTK_DOC_USE_LIBTOOL, test -n "$LIBTOOL") +]) diff --git a/common/m4/pkg.m4 b/common/m4/pkg.m4 new file mode 100644 index 0000000000..6c35916f6b --- /dev/null +++ b/common/m4/pkg.m4 @@ -0,0 +1,131 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# +# Copyright © 2004 Scott James Remnant . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_ifval([$1], [$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi + +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# +# Similar to PKG_CHECK_MODULES, make sure that the first instance of +# this or PKG_CHECK_MODULES is called, or make sure to call +# PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_ifval([$2], [$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], + [pkg_failed=yes]) +else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +if test $pkg_failed = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" 1>&AS_MESSAGE_LOG_FD + + ifelse([$4], , [AC_MSG_ERROR(dnl +[Package requirements ($2) were not met. +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively you may set the $1_CFLAGS and $1_LIBS environment variables +to avoid the need to call pkg-config. See the pkg-config man page for +more details.])], + [$4]) +elif test $pkg_failed = untried; then + ifelse([$4], , [AC_MSG_FAILURE(dnl +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively you may set the $1_CFLAGS and $1_LIBS environment variables +to avoid the need to call pkg-config. See the pkg-config man page for +more details. + +To get pkg-config, see .])], + [$4]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + ifelse([$3], , :, [$3]) +fi[]dnl +])# PKG_CHECK_MODULES diff --git a/common/mangle-tmpl.py b/common/mangle-tmpl.py new file mode 100644 index 0000000000..d3190402b6 --- /dev/null +++ b/common/mangle-tmpl.py @@ -0,0 +1,155 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +""" +use the output from gst-xmlinspect.py to mangle tmpl/*.sgml and +insert/overwrite Short Description and Long Description +""" + +# FIXME: right now it uses pygst and scans on its own; +# we really should use inspect/*.xml instead since the result of +# gst-xmlinspect.py is commited by the docs maintainer, who can be +# expected to have pygst, but this step should be done for every docs build, +# so no pygst allowed + +# read in inspect/*.xml +# for every tmpl/element-(name).xml: mangle with details from element + +import glob +import re +import sys +import os + +class Tmpl: + def __init__(self, filename): + self.filename = filename + self._sectionids = [] + self._sections = {} + + def read(self): + """ + Read and parse the sections from the given file. + """ + lines = open(self.filename).readlines() + matcher = re.compile("\n") + id = None + + for line in lines: + match = matcher.search(line) + if match: + id = match.expand("\\1") + self._sectionids.append(id) + self._sections[id] = [] + else: + if not id: + sys.stderr.write( + "WARNING: line before a SECTION header: %s" % line) + else: + self._sections[id].append(line) + + def get_section(self, id): + """ + Get the content from the given section. + """ + return self._sections[id] + + def set_section(self, id, content): + """ + Replace the given section id with the given content. + """ + self._sections[id] = content + + def output(self): + """ + Return the output of the current template in the tmpl/*.sgml format. + """ + lines = [] + for id in self._sectionids: + lines.append("\n" % id) + for line in self._sections[id]: + lines.append(line) + + return "".join(lines) + + def write(self, backup=False): + """ + Write out the template file again, backing up the previous one. + """ + if backup: + target = self.filename + ".mangle.bak" + os.rename(self.filename, target) + + handle = open(self.filename, "w") + handle.write(self.output()) + handle.close() + +from xml.dom.ext.reader import Sax2 +from xml.dom.NodeFilter import NodeFilter + +def get_elements(file): + elements = {} + handle = open(file) + reader = Sax2.Reader() + doc = reader.fromStream(handle) + handle.close() + + walker = doc.createTreeWalker(doc.documentElement, + NodeFilter.SHOW_ELEMENT, None, 0) + while walker.currentNode and walker.currentNode.tagName != 'elements': + walker.nextNode() + + # we're at elements now + el = walker.firstChild() + while walker.currentNode: + element = walker.firstChild() + # loop over children of + name = None + description = None + while walker.currentNode: + if walker.currentNode.tagName == 'name': + name = walker.currentNode.firstChild.data.encode('UTF-8') + if walker.currentNode.tagName == 'description': + description = walker.currentNode.firstChild.data.encode('UTF-8') + if not walker.nextSibling(): break + # back up to + walker.parentNode() + elements[name] = {'description': description} + + if not walker.nextSibling(): break + + return elements + + +def main(): + if not len(sys.argv) == 3: + sys.stderr.write('Please specify the inspect/ dir and the tmpl/ dir') + sys.exit(1) + + inspectdir = sys.argv[1] + tmpldir = sys.argv[2] + + # parse all .xml files; build map of element name -> short desc + #for file in glob.glob("inspect/plugin-*.xml"): + elements = {} + for file in glob.glob("%s/plugin-*.xml" % inspectdir): + elements.update(get_elements(file)) + + for file in glob.glob("%s/element-*.sgml" % tmpldir): + base = os.path.basename(file) + element = base[len("element-"):-len(".sgml")] + tmpl = Tmpl(file) + tmpl.read() + if element in elements.keys(): + description = elements[element]['description'] + tmpl.set_section("Short_Description", "%s\n\n" % description) + + # put in an include if not yet there + line = '\n' + section = tmpl.get_section("Long_Description") + if not section[0] == line: + section.insert(0, line) + tmpl.set_section("Long_Description", section) + tmpl.write() + +main() diff --git a/common/plugins.xsl b/common/plugins.xsl new file mode 100644 index 0000000000..150087f53d --- /dev/null +++ b/common/plugins.xsl @@ -0,0 +1,200 @@ + + + + + + + + + + + + -plugins- + + + + + + + + + + + + + Element Information + + + + + plugin + + + + plugin- + + + + + + + + author + + + + + + + class + + + + + + + + Element Pads + + + + + name + + + + + + + direction + + + + + + + presence + + + + + + + details + + + + + + + + + + + + + + + + + + -plugins-plugin- + + + + + + 3 + FIXME Library + + + + + + plugin- + + + + + + + + + + + Plugin Information + + + + filename + + + + + + + version + + + + + + + run-time license + + + + + + + package + + + + + + + origin + + + + + + + + + + + + + + + + + + + + + + + Elements + + + + + + + + + + + + + + diff --git a/common/po.mak b/common/po.mak new file mode 100644 index 0000000000..e019fac121 --- /dev/null +++ b/common/po.mak @@ -0,0 +1,4 @@ +# rule to download the latest .po files +download-po: $(top_srcdir)/common/download-translations + $(top_srcdir)/common/download-translations $(PACKAGE) + diff --git a/common/release.mak b/common/release.mak new file mode 100644 index 0000000000..373146537a --- /dev/null +++ b/common/release.mak @@ -0,0 +1,25 @@ +# include this snippet to add a common release: target by using +# include $(top_srcdir)/common/release.mak + +# make bz2 as well +AUTOMAKE_OPTIONS = dist-bzip2 + +release: dist + make $(PACKAGE)-$(VERSION).tar.gz.md5 + make $(PACKAGE)-$(VERSION).tar.bz2.md5 + +# generate md5 sum files +%.md5: % + md5sum $< > $@ + +# check that no marshal or enumtypes files are included +# this in turn ensures that distcheck fails for missing .list files which is currently +# shadowed when the corresponding .c and .h files are included. +distcheck-hook: + @test "x" = "x`find $(distdir) -name \*-enumtypes.[ch] | grep -v win32`" && \ + test "x" = "x`find $(distdir) -name \*-marshal.[ch]`" || \ + ( $(ECHO) "*** Leftover enumtypes or marshal files in the tarball." && \ + $(ECHO) "*** Make sure the following files are not disted:" && \ + find $(distdir) -name \*-enumtypes.[ch] | grep -v win32 && \ + find $(distdir) -name \*-marshal.[ch] && \ + false ) diff --git a/common/scangobj-merge.py b/common/scangobj-merge.py new file mode 100755 index 0000000000..4917255da5 --- /dev/null +++ b/common/scangobj-merge.py @@ -0,0 +1,226 @@ +#!/usr/bin/python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +""" +parse, update and write .signals and .args files +""" + +from twisted.python import util + +import sys +import os + +def debug(*args): + pass + +class Object: + def __init__(self, name): + self._signals = util.OrderedDict() + self._args = util.OrderedDict() + self.name = name + + def __repr__(self): + return "" % self.name + + def add_signal(self, signal, overwrite=True): + if not overwrite and self._signals.has_key(signal.name): + raise IndexError, "signal %s already in %r" % (signal.name, self) + self._signals[signal.name] = signal + + def add_arg(self, arg, overwrite=True): + if not overwrite and self._args.has_key(arg.name): + raise IndexError, "arg %s already in %r" % (arg.name, self) + self._args[arg.name] = arg + +class Docable: + def __init__(self, **kwargs): + for key in self.attrs: + setattr(self, key, kwargs[key]) + self.dict = kwargs + + def __repr__(self): + return "<%r %s>" % (str(self.__class__), self.name) + +class Signal(Docable): + attrs = ['name', 'returns', 'args'] + +class Arg(Docable): + attrs = ['name', 'type', 'range', 'flags', 'nick', 'blurb', 'default'] + +class GDoc: + def load_file(self, filename): + try: + lines = open(filename).readlines() + self.load_data("".join(lines)) + except IOError: + print "WARNING - could not read from %s" % filename + + def save_file(self, filename, backup=False): + """ + Save the signals information to the given .signals file if the + file content changed. + """ + olddata = None + try: + lines = open(filename).readlines() + olddata = "".join(lines) + except IOError: + print "WARNING - could not read from %s" % filename + newdata = self.get_data() + if olddata and olddata == newdata: + return + + if olddata: + if backup: + os.rename(filename, filename + '.bak') + + handle = open(filename, "w") + handle.write(newdata) + handle.close() + +class Signals(GDoc): + def __init__(self): + self._objects = util.OrderedDict() + + def load_data(self, data): + """ + Load the .signals lines, creating our list of objects and signals. + """ + import re + smatcher = re.compile( + '(?s)' # make . match \n + '\n(.*?)\n' + ) + nmatcher = re.compile( + '' + '(?P\S*)' # store object + '::' + '(?P\S*)' # store signal + '' + ) + rmatcher = re.compile( + '(?s)' # make . match \n + '(?P\S*)\n' # store returns + '(?P.*)' # store args + ) + for block in smatcher.findall(data): + nmatch = nmatcher.search(block) + if nmatch: + o = nmatch.group('object') + debug("Found object", o) + debug("Found signal", nmatch.group('signal')) + if not self._objects.has_key(o): + object = Object(o) + self._objects[o] = object + + rmatch = rmatcher.search(block) + if rmatch: + dict = rmatch.groupdict().copy() + dict['name'] = nmatch.group('signal') + signal = Signal(**dict) + self._objects[o].add_signal(signal) + + def get_data(self): + lines = [] + for o in self._objects.values(): + for s in o._signals.values(): + block = """ +%(object)s::%(name)s +%(returns)s +%(args)s +""" + d = s.dict.copy() + d['object'] = o.name + lines.append(block % d) + + return "\n".join(lines) + '\n' + +class Args(GDoc): + def __init__(self): + self._objects = util.OrderedDict() + + def load_data(self, data): + """ + Load the .args lines, creating our list of objects and args. + """ + import re + amatcher = re.compile( + '(?s)' # make . match \n + '\n(.*?)\n' + ) + nmatcher = re.compile( + '' + '(?P\S*)' # store object + '::' + '(?P\S*)' # store arg + '' + ) + rmatcher = re.compile( + '(?s)' # make . match \n + '(?P\S*)\n' # store type + '(?P.*?)\n' # store range + '(?P\S*)\n' # store flags + '(?P.*?)\n' # store nick + '(?P.*?)\n' # store blurb + '(?P.*?)\n' # store default + ) + for block in amatcher.findall(data): + nmatch = nmatcher.search(block) + if nmatch: + o = nmatch.group('object') + debug("Found object", o) + debug("Found arg", nmatch.group('arg')) + if not self._objects.has_key(o): + object = Object(o) + self._objects[o] = object + + rmatch = rmatcher.search(block) + if rmatch: + dict = rmatch.groupdict().copy() + dict['name'] = nmatch.group('arg') + arg = Arg(**dict) + self._objects[o].add_arg(arg) + else: + print "ERROR: could not match arg from block %s" % block + + def get_data(self): + lines = [] + for o in self._objects.values(): + for a in o._args.values(): + block = """ +%(object)s::%(name)s +%(type)s +%(range)s +%(flags)s +%(nick)s +%(blurb)s +%(default)s + +""" + d = a.dict.copy() + d['object'] = o.name + lines.append(block % d) + + return "\n".join(lines) + '\n' + +def main(argv): + modulename = None + try: + modulename = argv[1] + except IndexError: + sys.stderr.write('Pleae provide a documentation module name\n') + sys.exit(1) + + print "Merging scangobj output for %s" % modulename + signals = Signals() + signals.load_file(modulename + '.signals') + signals.load_file(modulename + '.signals.new') + signals.save_file(modulename + '.signals', backup=True) + + args = Args() + args.load_file(modulename + '.args') + args.load_file(modulename + '.args.new') + args.save_file(modulename + '.args', backup=True) + +main(sys.argv) diff --git a/common/upload.mak b/common/upload.mak new file mode 100644 index 0000000000..60731e5783 --- /dev/null +++ b/common/upload.mak @@ -0,0 +1,33 @@ +# this snippet is to be included by both our docbook manuals +# and gtk-doc API references + +# it adds an upload target to each of these dir's Makefiles + +# each Makefile.am should define the following variables: +# - DOC: the base name of the documentation +# (faq, manual, pwg, gstreamer, gstreamer-libs) +# - FORMATS: the formats in which DOC is output +# (html ps pdf) + +# if you want to use it, make sure your $HOME/.ssh/config file contains the +# correct User entry for the Host entry for the DOC_SERVER + +# these variables define the location of the online docs +DOC_SERVER = gstreamer.freedesktop.org +DOC_BASE = /srv/gstreamer.freedesktop.org/www/data/doc +DOC_URL = $(DOC_SERVER):$(DOC_BASE) + +upload: $(FORMATS) + @if test "x$(PACKAGE_VERSION_NANO)" = x0; then \ + export DOCVERSION=$(VERSION); \ + else export DOCVERSION=head; \ + fi; \ + export DIR=$(DOC_BASE)/gstreamer/$$DOCVERSION/$(DOC); \ + ssh $(DOC_SERVER) mkdir -p $$DIR; \ + if echo $(FORMATS) | grep html > /dev/null; then export SRC="$$SRC html"; fi; \ + if echo $(FORMATS) | grep ps > /dev/null; then export SRC="$$SRC $(DOC).ps"; fi; \ + if echo $(FORMATS) | grep pdf > /dev/null; then export SRC="$$SRC $(DOC).pdf"; fi; \ + echo Uploading $$SRC to $(DOC_SERVER):$$DIR; \ + rsync -rv -e ssh --delete $$SRC $(DOC_SERVER):$$DIR; \ + ssh $(DOC_SERVER) chmod -R g+w $$DIR; \ + echo Done diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000000..63a2231d41 --- /dev/null +++ b/configure.ac @@ -0,0 +1,222 @@ +AC_PREREQ(2.52) + +dnl initialize autoconf +dnl when going to/from release please set the nano (fourth number) right ! +dnl releases only do Wall, cvs and prerelease does Werror too +AC_INIT(Gst-RTSP, 0.10.0.1, + http://gstreamer.net/, + gst-rtsp) + +dnl initialize automake +AM_INIT_AUTOMAKE + +dnl define PACKAGE_VERSION_* variables +AS_VERSION + +dnl check if this is a release version +AS_NANO(GST_CVS="no", GST_CVS="yes") + +dnl can autoconf find the source ? +AC_CONFIG_SRCDIR([src/rtsp-server.c]) + +dnl define the output header for config +AM_CONFIG_HEADER([config.h]) + +dnl AM_MAINTAINER_MODE only provides the option to configure to enable it +AM_MAINTAINER_MODE + +dnl sets host_* variables +AC_CANONICAL_HOST + +dnl our libraries and install dirs use major.minor as a version +GST_MAJORMINOR=$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR +dnl we override it here if we need to for the release candidate of new series +GST_MAJORMINOR=0.10 +AC_SUBST(GST_MAJORMINOR) + +AM_PROG_LIBTOOL + +dnl *** required versions of GStreamer stuff *** +GST_REQ=0.10.20 +GSTPB_REQ=0.10.20 + +dnl export for .pc files +AC_SUBST([GST_REQ]) +AC_SUBST([GSTPB_REQ]) + +dnl *** autotools stuff **** + +dnl allow for different autotools +AS_AUTOTOOLS_ALTERNATE + +dnl Add parameters for aclocal +AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4") + +dnl *** check for arguments to configure *** + +AG_GST_ARG_DEBUG +AG_GST_ARG_VALGRIND +AG_GST_ARG_GCOV +AG_GST_ARG_WITH_PACKAGE_NAME +AG_GST_ARG_WITH_PACKAGE_ORIGIN + +dnl *** checks for platform *** + +dnl * hardware/architecture * + +dnl *** checks for programs *** + +dnl find a compiler +AC_PROG_CC + +AC_PATH_PROG(VALGRIND_PATH, valgrind, no) +AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") + +dnl check for documentation tools +AG_GST_DOCBOOK_CHECK +GTK_DOC_CHECK([1.3]) + +dnl GTK is optional and used in examples +HAVE_GTK=NO +PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.8.0, HAVE_GTK=yes, HAVE_GTK=no) +AM_CONDITIONAL(HAVE_GTK, test "x$HAVE_GTK" = "xyes") + +dnl *** checks for libraries *** + +dnl *** checks for header files *** + +dnl *** checks for types/defines *** + +dnl *** checks for structures *** + +dnl *** checks for compiler characteristics *** + +dnl *** checks for library functions *** + +dnl *** checks for dependancy libraries *** + +dnl GLib is required (GStreamer is ok with GLib-2.8, but we want at least 2.10) +GLIB_REQ=2.10.0 +AC_SUBST([GLIB_REQ]) +AG_GST_GLIB_CHECK([$GLIB_REQ]) + +dnl checks for gstreamer +dnl uninstalled is selected preferentially -- see pkg-config(1) +AG_GST_CHECK_GST($GST_MAJORMINOR, [$GST_REQ]) + +GST_TOOLS_DIR=`$PKG_CONFIG --variable=toolsdir gstreamer-$GST_MAJORMINOR` +if test -z $GST_TOOLS_DIR; then + AC_MSG_ERROR([no tools dir defined in GStreamer pkg-config file; core upgrade needed.]) +fi +AC_SUBST(GST_TOOLS_DIR) + +GST_PLUGINS_DIR=`$PKG_CONFIG gstreamer-$GST_MAJORMINOR --variable pluginsdir` +AC_SUBST(GST_PLUGINS_DIR) +AC_MSG_NOTICE(Using GStreamer Core Plugins in $GST_PLUGINS_DIR) + +AG_GST_CHECK_GST_BASE($GST_MAJORMINOR, [$GST_REQ]) + +AG_GST_CHECK_GST_PLUGINS_BASE($GST_MAJORMINOR, [$GSTPB_REQ]) +GSTPB_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-base-$GST_MAJORMINOR --variable pluginsdir` +AC_SUBST(GSTPB_PLUGINS_DIR) +AC_MSG_NOTICE(Using GStreamer Base Plugins in $GSTPB_PLUGINS_DIR) + +AG_GST_CHECK_GST_CHECK($GST_MAJORMINOR, [$GST_REQ], no) + +dnl FIXME: get rid of this by making sure gstreamer-check brings it in +dnl check for "check", unit testing library/header +AM_PATH_CHECK(0.9.2, HAVE_CHECK=yes, HAVE_CHECK=no) +AM_CONDITIONAL(HAVE_CHECK, test "x$HAVE_CHECK" = "xyes") + +dnl *** set variables based on configure arguments *** + +dnl set license and copyright notice +GST_LICENSE="LGPL" +AC_DEFINE_UNQUOTED(GST_LICENSE, "$GST_LICENSE", [GStreamer license]) +AC_SUBST(GST_LICENSE) + +dnl set location of plugin directory +AG_GST_SET_PLUGINDIR + +dnl define an ERROR_CFLAGS Makefile variable +AG_GST_SET_ERROR_CFLAGS($GST_CVS) + +dnl define correct level for debugging messages +AG_GST_SET_LEVEL_DEFAULT($GST_CVS) + +dnl used in examples +AG_GST_DEFAULT_ELEMENTS + +dnl *** finalize CFLAGS, LDFLAGS, LIBS + +dnl Overview: +dnl GST_OPTION_CFLAGS: common flags for profiling, debugging, errors, ... +dnl GST_*: flags shared by built objects to link against GStreamer +dnl GST_ALL_LDFLAGS: linker flags shared by all +dnl GST_LIB_LDFLAGS: additional linker flags for all libaries +dnl GST_LT_LDFLAGS: library versioning of our libraries +dnl GST_PLUGIN_LDFLAGS: flags to be used for all plugins + +dnl GST_OPTION_CFLAGS +if test "x$USE_DEBUG" = xyes; then + PROFILE_CFLAGS="-g" +fi +AC_SUBST(PROFILE_CFLAGS) + +DEPRECATED_CFLAGS="-DGST_DISABLE_DEPRECATED" +AC_SUBST(DEPRECATED_CFLAGS) + +dnl every flag in GST_OPTION_CFLAGS can be overridden at make time +GST_OPTION_CFLAGS="\$(ERROR_CFLAGS) \$(DEBUG_CFLAGS) \$(PROFILE_CFLAGS) \$(GCOV_CFLAGS) \$(OPT_CFLAGS) \$(DEPRECATED_CFLAGS)" +AC_SUBST(GST_OPTION_CFLAGS) + +dnl FIXME: do we want to rename to GST_ALL_* ? +dnl prefer internal headers to already installed ones +dnl add GST_OPTION_CFLAGS, but overridable +GST_CFLAGS="$GST_CFLAGS \$(GST_OPTION_CFLAGS)" +AC_SUBST(GST_CFLAGS) +AC_SUBST(GST_LIBS) + +dnl GST_ALL_* +dnl vars common to for all internal objects (core libs, elements, applications) +dnl CFLAGS: +dnl - src and build dirs need to be added because every piece that gets built +dnl will need the GStreamer source and generated headers +GST_ALL_CFLAGS="-I\$(top_srcdir) -I\$(top_builddir) $GST_CFLAGS \$(GST_OPTION_CFLAGS)" +AC_SUBST([GST_ALL_CFLAGS]) + +dnl FIXME: check if LTLIBINTL is needed everywhere +dnl I presume it is given that it contains the symbols that _() stuff maps to +GST_ALL_LIBS="$GST_LIBS $LTLIBINTL \$(GCOV_LIBS)" +AC_SUBST([GST_ALL_LIBS]) + +dnl LDFLAGS really should only contain flags, not libs - they get added before +dnl whatevertarget_LIBS and -L flags here affect the rest of the linking +GST_ALL_LDFLAGS="-no-undefined" +AC_SUBST(GST_ALL_LDFLAGS) + +dnl GST_OBJ_* +dnl default vars for all internal objects built on libgstphonon +dnl includes GST_ALL_* +GST_OBJ_CFLAGS="\$(GST_ALL_CFLAGS)" +AC_SUBST([GST_OBJ_CFLAGS]) +GST_OBJ_LIBS="\$(top_builddir)/gst-phonon/libgstphonon.la \$(GST_ALL_LIBS)" +AC_SUBST([GST_OBJ_LIBS]) + +dnl this really should only contain flags, not libs - they get added before +dnl whatevertarget_LIBS and -L flags here affect the rest of the linking + +dnl *** output files *** + +dnl keep this alphabetic per directory, please +AC_CONFIG_FILES([ +Makefile +gst-rtsp.spec +common/Makefile +common/m4/Makefile +m4/Makefile +src/Makefile +]) +AC_OUTPUT + +echo "Gst-rtsp-server configured. Type 'make' to build." diff --git a/docs/design/gst-rtp-server-design b/docs/design/gst-rtp-server-design new file mode 100644 index 0000000000..7da8283078 --- /dev/null +++ b/docs/design/gst-rtp-server-design @@ -0,0 +1,35 @@ +RTSP server +----------- + +This directory contains an example RTSP server built with various GStreamer +components and libraries. It also uses GStreamer for all of the multimedia +procesing and RTP bits. The following features are implemented: + + - + +Server Design +------------- + +The toplevel component of the server is a GstRTSPServer object. This object +creates and binds on the server socket and attaches into the mainloop. + +For each request a new GstRTSPClient object is created that will accept the +request and a thread is started to handle further communication with the +client until the connection is closed. + +When a client issues a SETUP request we create a GstRTSPSession object, +identified with a sessionid, that will keep track of the state of a client. +The object is destroyed when a TEARDOWN request is made for that sessionid. + +We also maintain a pool of URL to media pipeline mappings. Each url is mapped to +an object that is able to provide a pipeline for that media. We provide +pipelines to stream live captured data, on-demand file streaming or on-demand +transcoding of a file or stream. + +A pool of currently active pipelines is also maintained. Usually the active +pipelines are in use by one or more GstRTSPSession objects. An active pipeline +becomes inactive when no more sessions refer to it. + +A client can choose to start a new pipeline or join a currently active pipeline. +Some active pipeline cannot be joined (such as on-demand streams) but a new +instance of that pipeline can be created. diff --git a/gst-rtsp.spec.in b/gst-rtsp.spec.in new file mode 100644 index 0000000000..2c4eebcb5a --- /dev/null +++ b/gst-rtsp.spec.in @@ -0,0 +1,54 @@ +%define gst_majorminor @GST_MAJORMINOR@ + +Name: gstreamer-rtsp-server +Version: @VERSION@ +Release: 1%{?dist} +Summary: GStreamer based RTSP server +Vendor: Collabora Multimedia +Group: Applications/Multimedia +License: LGPLv2+ +Source0: gst-rtsp-%{version}.tar.bz2 +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +BuildRequires: gstreamer-devel >= 0.10.11 + + +%description +This is a RTSP server using the GStreamer framework. + + +%prep +%setup -q -n gst-rtsp-%{version} + + +%build +%configure + +make + +%install +%makeinstall + +# Clean out files that should not be part of the rpm. +rm -f $RPM_BUILD_ROOT%{_libdir}/gstreamer-%{majorminor}/*.a +rm -f $RPM_BUILD_ROOT%{_libdir}/*.a +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +%clean +rm -rf $RPM_BUILD_ROOT + + +%post -p /sbin/ldconfig + + +%postun -p /sbin/ldconfig + + +%files +%defattr(-,root,root,-) +%doc AUTHORS COPYING README INSTALL docs/design/gst-rtp-server-design +%{_bindir}/gst-rtsp-server + +%changelog +* Thu Oct 9 2008 Christian Schaller +- First spec file diff --git a/m4/Makefile.am b/m4/Makefile.am new file mode 100644 index 0000000000..226cc479db --- /dev/null +++ b/m4/Makefile.am @@ -0,0 +1,18 @@ +EXTRA_DIST = \ + codeset.m4 + gettext.m4 + glibc21.m4 \ + iconv.m4 \ + intdiv0.m4 \ + inttypes-pri.m4 \ + nttypes.m4 \ + inttypes_h.m4 \ + isc-posix.m4 \ + lcmessage.m4 \ + lib-ld.m4 \ + lib-link.m4 \ + lib-prefix.m4 \ + progtest.m4 \ + stdint_h.m4 \ + uintmax_t.m4 \ + ulonglong.m4 diff --git a/m4/codeset.m4 b/m4/codeset.m4 new file mode 100644 index 0000000000..59535ebcff --- /dev/null +++ b/m4/codeset.m4 @@ -0,0 +1,23 @@ +# codeset.m4 serial AM1 (gettext-0.10.40) +dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +AC_DEFUN([AM_LANGINFO_CODESET], +[ + AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, + [AC_TRY_LINK([#include ], + [char* cs = nl_langinfo(CODESET);], + am_cv_langinfo_codeset=yes, + am_cv_langinfo_codeset=no) + ]) + if test $am_cv_langinfo_codeset = yes; then + AC_DEFINE(HAVE_LANGINFO_CODESET, 1, + [Define if you have and nl_langinfo(CODESET).]) + fi +]) diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000000..82674faf5f --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,20 @@ +bin_PROGRAMS = gst-rtsp-server + +gst_rtsp_server_SOURCES = main.c \ + rtsp-server.c \ + rtsp-client.c \ + rtsp-media.c \ + rtsp-session-pool.c \ + rtsp-session.c + +gst_rtsp_server_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +gst_rtsp_server_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ + -lgstsdp-@GST_MAJORMINOR@ $(GST_LIBS) $(LIBM) +gst_rtsp_server_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +noinst_HEADERS = rtsp-server.h \ + rtsp-client.h \ + rtsp-session.h \ + rtsp-session-pool.h \ + rtsp-media.h diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000000..70b1fdc9d2 --- /dev/null +++ b/src/main.c @@ -0,0 +1,43 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "rtsp-server.h" + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + g_main_loop_run (loop); + + return 0; +} diff --git a/src/rtsp-client.c b/src/rtsp-client.c new file mode 100644 index 0000000000..b4bcbc1b85 --- /dev/null +++ b/src/rtsp-client.c @@ -0,0 +1,811 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + +#include "rtsp-client.h" + +#undef DEBUG + +G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); + +static void +gst_rtsp_client_class_init (GstRTSPClientClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); +} + +static void +gst_rtsp_client_init (GstRTSPClient * client) +{ +} + +/** + * gst_rtsp_client_new: + * + * Create a new #GstRTSPClient instance. + */ +GstRTSPClient * +gst_rtsp_client_new (void) +{ + GstRTSPClient *result; + + result = g_object_new (GST_TYPE_RTSP_CLIENT, NULL); + + return result; +} + +static void +handle_generic_response (GstRTSPClient *client, GstRTSPStatusCode code, + GstRTSPMessage *request) +{ + GstRTSPMessage response = { 0 }; + + gst_rtsp_message_init_response (&response, code, + gst_rtsp_status_as_text (code), request); + + gst_rtsp_connection_send (client->connection, &response, NULL); +} + +static gboolean +handle_teardown_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request) +{ + GstRTSPResult res; + GstRTSPSessionMedia *media; + GstRTSPSession *session; + gchar *sessid; + GstRTSPMessage response = { 0 }; + GstRTSPStatusCode code; + + res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); + if (res == GST_RTSP_OK) { + /* we had a session in the request, find it again */ + if (!(session = gst_rtsp_session_pool_find (client->pool, sessid))) + goto session_not_found; + } + else + goto service_unavailable; + + /* get a handle to the configuration of the media in the session */ + media = gst_rtsp_session_get_media (session, client->media); + + gst_rtsp_session_media_stop (media); + + gst_rtsp_session_pool_remove (client->pool, session); + g_object_unref (session); + + /* remove the session id from the request, which will also remove it from the + * response */ + gst_rtsp_message_remove_header (request, GST_RTSP_HDR_SESSION, -1); + + /* construct the response now */ + code = GST_RTSP_STS_OK; + gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); + + gst_rtsp_connection_send (client->connection, &response, NULL); + + return FALSE; + + /* ERRORS */ +session_not_found: + { + handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + return FALSE; + } +service_unavailable: + { + return FALSE; + } +} + +static gboolean +handle_pause_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request) +{ + GstRTSPResult res; + GstRTSPSessionMedia *media; + GstRTSPSession *session; + gchar *sessid; + GstRTSPMessage response = { 0 }; + GstRTSPStatusCode code; + + res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); + if (res == GST_RTSP_OK) { + /* we had a session in the request, find it again */ + if (!(session = gst_rtsp_session_pool_find (client->pool, sessid))) + goto session_not_found; + } + else + goto service_unavailable; + + /* get a handle to the configuration of the media in the session */ + media = gst_rtsp_session_get_media (session, client->media); + + gst_rtsp_session_media_pause (media); + g_object_unref (session); + + /* construct the response now */ + code = GST_RTSP_STS_OK; + gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); + + gst_rtsp_connection_send (client->connection, &response, NULL); + + return FALSE; + + /* ERRORS */ +session_not_found: + { + handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + return FALSE; + } +service_unavailable: + { + return FALSE; + } +} + +static gboolean +handle_play_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request) +{ + GstRTSPResult res; + GstRTSPSessionMedia *media; + GstRTSPSession *session; + gchar *sessid; + GstRTSPMessage response = { 0 }; + GstRTSPStatusCode code; + GstStateChangeReturn ret; + GString *rtpinfo; + guint n_streams, i; + guint timestamp, seqnum; + + res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); + if (res == GST_RTSP_OK) { + /* we had a session in the request, find it again */ + if (!(session = gst_rtsp_session_pool_find (client->pool, sessid))) + goto session_not_found; + } + else + goto service_unavailable; + + /* get a handle to the configuration of the media in the session */ + media = gst_rtsp_session_get_media (session, client->media); + + /* wait for paused to get the caps */ + ret = gst_rtsp_session_media_pause (media); + switch (ret) { + case GST_STATE_CHANGE_NO_PREROLL: + break; + case GST_STATE_CHANGE_SUCCESS: + break; + case GST_STATE_CHANGE_FAILURE: + goto service_unavailable; + case GST_STATE_CHANGE_ASYNC: + ret = gst_element_get_state (media->pipeline, NULL, NULL, -1); + break; + } + + /* grab RTPInfo from the payloaders now */ + rtpinfo = g_string_new (""); + n_streams = gst_rtsp_media_n_streams (client->media); + for (i = 0; i < n_streams; i++) { + GstRTSPMediaStream *stream; + + stream = gst_rtsp_media_get_stream (client->media, i); + + g_object_get (G_OBJECT (stream->payloader), "seqnum", &seqnum, NULL); + g_object_get (G_OBJECT (stream->payloader), "timestamp", ×tamp, NULL); + + if (i > 0) + g_string_append (rtpinfo, ", "); + g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", uri, i, seqnum, timestamp); + } + + /* construct the response now */ + code = GST_RTSP_STS_OK; + gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); + + /* add the RTP-Info header */ + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_RTP_INFO, rtpinfo->str); + g_string_free (rtpinfo, TRUE); + + gst_rtsp_connection_send (client->connection, &response, NULL); + + /* start playing after sending the request */ + gst_rtsp_session_media_play (media); + g_object_unref (session); + + return FALSE; + + /* ERRORS */ +session_not_found: + { + handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + return FALSE; + } +service_unavailable: + { + handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + return FALSE; + } +} + +static gboolean +handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request) +{ + GstRTSPResult res; + gchar *sessid; + gchar *transport; + gchar **transports; + gboolean have_transport; + GstRTSPTransport *ct, *st; + GstRTSPSession *session; + gint i; + GstRTSPLowerTrans supported; + GstRTSPMessage response = { 0 }; + GstRTSPStatusCode code; + GstRTSPSessionStream *stream; + gchar *trans_str, *pos; + guint streamid; + GstRTSPSessionMedia *media; + gboolean need_session; + + /* find the media associated with the uri */ + if (client->media == NULL) { + if ((client->media = gst_rtsp_media_new (uri)) == NULL) + goto not_found; + } + + /* parse the transport */ + res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_TRANSPORT, &transport, 0); + if (res != GST_RTSP_OK) + goto unsupported_transports; + + transports = g_strsplit (transport, ",", 0); + gst_rtsp_transport_new (&ct); + + /* loop through the transports, try to parse */ + have_transport = FALSE; + for (i = 0; transports[i]; i++) { + + gst_rtsp_transport_init (ct); + res = gst_rtsp_transport_parse (transports[i], ct); + if (res == GST_RTSP_OK) { + have_transport = TRUE; + break; + } + } + g_strfreev (transports); + + /* we have not found anything usable, error out */ + if (!have_transport) { + gst_rtsp_transport_free (ct); + goto unsupported_transports; + } + + /* we have a valid transport, check if we can handle it */ + if (ct->trans != GST_RTSP_TRANS_RTP) + goto unsupported_transports; + if (ct->profile != GST_RTSP_PROFILE_AVP) + goto unsupported_transports; + supported = GST_RTSP_LOWER_TRANS_UDP | + GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP; + if (!(ct->lower_transport & supported)) + goto unsupported_transports; + + /* a setup request creates a session for a client, check if the client already + * sent a session id to us */ + res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); + if (res == GST_RTSP_OK) { + /* we had a session in the request, find it again */ + if (!(session = gst_rtsp_session_pool_find (client->pool, sessid))) + goto session_not_found; + need_session = FALSE; + } + else { + /* create a session if this fails we probably reached our session limit or + * something. */ + if (!(session = gst_rtsp_session_pool_create (client->pool))) + goto service_unavailable; + need_session = TRUE; + } + + /* get a handle to the configuration of the media in the session */ + media = gst_rtsp_session_get_media (session, client->media); + + /* parse the stream we need to configure */ + if (!(pos = strstr (uri, "stream="))) + goto bad_request; + + pos += strlen ("stream="); + if (sscanf (pos, "%u", &streamid) != 1) + goto bad_request; + + /* get a handle to the stream in the media */ + stream = gst_rtsp_session_get_stream (media, streamid); + + /* setup the server transport from the client transport */ + st = gst_rtsp_session_stream_set_transport (stream, inet_ntoa (client->address.sin_addr), ct); + + /* serialize the server transport */ + trans_str = gst_rtsp_transport_as_text (st); + + /* construct the response now */ + code = GST_RTSP_STS_OK; + gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); + + if (need_session) + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_SESSION, session->sessionid); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str); + g_free (trans_str); + g_object_unref (session); + + gst_rtsp_connection_send (client->connection, &response, NULL); + + return TRUE; + + /* ERRORS */ +not_found: + { + handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + return FALSE; + } +bad_request: + { + handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); + return FALSE; + } +session_not_found: + { + handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + return FALSE; + } +unsupported_transports: + { + handle_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request); + return FALSE; + } +service_unavailable: + { + handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + return FALSE; + } +} + +static gboolean +handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request) +{ + GstRTSPMessage response = { 0 }; + GstSDPMessage *sdp; + guint n_streams, i; + gchar *sdptext; + GstRTSPMedia *media; + + /* check what kind of format is accepted */ + + + /* for the describe we must generate an SDP */ + if (!(media = gst_rtsp_media_new (uri))) + goto no_media; + + /* create a pipeline if we have to */ + if (client->pipeline == NULL) { + client->pipeline = gst_pipeline_new ("client-pipeline"); + } + + /* prepare the media into the pipeline */ + if (!gst_rtsp_media_prepare (media, GST_BIN (client->pipeline))) + goto no_media; + + /* link fakesink to all stream pads and set the pipeline to PLAYING */ + n_streams = gst_rtsp_media_n_streams (media); + for (i = 0; i < n_streams; i++) { + GstRTSPMediaStream *stream; + GstElement *sink; + GstPad *sinkpad; + + stream = gst_rtsp_media_get_stream (media, i); + + sink = gst_element_factory_make ("fakesink", NULL); + gst_bin_add (GST_BIN (client->pipeline), sink); + + sinkpad = gst_element_get_static_pad (sink, "sink"); + gst_pad_link (stream->srcpad, sinkpad); + gst_object_unref (sinkpad); + } + + /* now play and wait till we get the pads blocked. At that time the pipeline + * is prerolled and we have the caps on the streams too. */ + gst_element_set_state (client->pipeline, GST_STATE_PLAYING); + + /* wait for state change to complete */ + gst_element_get_state (client->pipeline, NULL, NULL, -1); + + /* we should now be able to construct the SDP message */ + gst_sdp_message_new (&sdp); + + /* some standard things first */ + gst_sdp_message_set_version (sdp, "0"); + gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", "IP4", "127.0.0.1"); + gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer"); + gst_sdp_message_set_information (sdp, "rtsp-server"); + gst_sdp_message_add_time (sdp, "0", "0", NULL); + gst_sdp_message_add_attribute (sdp, "tool", "GStreamer"); + gst_sdp_message_add_attribute (sdp, "type", "broadcast"); + + for (i = 0; i < n_streams; i++) { + GstRTSPMediaStream *stream; + GstSDPMedia *smedia; + GstStructure *s; + const gchar *caps_str, *caps_enc, *caps_params; + gchar *tmp; + gint caps_pt, caps_rate; + guint n_fields, j; + gboolean first; + GString *fmtp; + + stream = gst_rtsp_media_get_stream (media, i); + gst_sdp_media_new (&smedia); + + s = gst_caps_get_structure (stream->caps, 0); + + /* get media type and payload for the m= line */ + caps_str = gst_structure_get_string (s, "media"); + gst_sdp_media_set_media (smedia, caps_str); + + gst_structure_get_int (s, "payload", &caps_pt); + tmp = g_strdup_printf ("%d", caps_pt); + gst_sdp_media_add_format (smedia, tmp); + g_free (tmp); + + gst_sdp_media_set_port_info (smedia, 0, 1); + gst_sdp_media_set_proto (smedia, "RTP/AVP"); + + /* for the c= line */ + gst_sdp_media_add_connection (smedia, "IN", "IP4", "127.0.0.1", 0, 0); + + /* get clock-rate, media type and params for the rtpmap attribute */ + gst_structure_get_int (s, "clock-rate", &caps_rate); + caps_enc = gst_structure_get_string (s, "encoding-name"); + caps_params = gst_structure_get_string (s, "encoding-params"); + + if (caps_params) + tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate, + caps_params); + else + tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate); + + gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); + g_free (tmp); + + /* the config uri */ + tmp = g_strdup_printf ("stream=%d", i); + gst_sdp_media_add_attribute (smedia, "control", tmp); + g_free (tmp); + + /* collect all other properties and add them to fmtp */ + fmtp = g_string_new (""); + g_string_append_printf (fmtp, "%d ", caps_pt); + first = TRUE; + n_fields = gst_structure_n_fields (s); + for (j = 0; j < n_fields; j++) { + const gchar *fname, *fval; + + fname = gst_structure_nth_field_name (s, j); + + /* filter out standard properties */ + if (!strcmp (fname, "media")) + continue; + if (!strcmp (fname, "payload")) + continue; + if (!strcmp (fname, "clock-rate")) + continue; + if (!strcmp (fname, "encoding-name")) + continue; + if (!strcmp (fname, "encoding-params")) + continue; + if (!strcmp (fname, "ssrc")) + continue; + if (!strcmp (fname, "clock-base")) + continue; + if (!strcmp (fname, "seqnum-base")) + continue; + + if ((fval = gst_structure_get_string (s, fname))) { + g_string_append_printf (fmtp, "%s%s=%s", first ? "":";", fname, fval); + first = FALSE; + } + } + if (!first) { + tmp = g_string_free (fmtp, FALSE); + gst_sdp_media_add_attribute (smedia, "fmtp", tmp); + g_free (tmp); + } + else { + g_string_free (fmtp, TRUE); + } + gst_sdp_message_add_media (sdp, smedia); + } + /* go back to NULL */ + gst_element_set_state (client->pipeline, GST_STATE_NULL); + + g_object_unref (media); + + gst_object_unref (client->pipeline); + client->pipeline = NULL; + + gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, + gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); + + /* add SDP to the response body */ + sdptext = gst_sdp_message_as_text (sdp); + gst_rtsp_message_take_body (&response, (guint8 *)sdptext, strlen (sdptext)); + gst_sdp_message_free (sdp); + + gst_rtsp_connection_send (client->connection, &response, NULL); + + return TRUE; + + /* ERRORS */ +no_media: + { + handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + return FALSE; + } +} + +static void +handle_options_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request) +{ + GstRTSPMessage response = { 0 }; + GstRTSPMethod options; + GString *str; + + gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, + gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); + + options = GST_RTSP_DESCRIBE | + GST_RTSP_OPTIONS | + // GST_RTSP_PAUSE | + GST_RTSP_PLAY | + GST_RTSP_SETUP | + GST_RTSP_TEARDOWN; + + /* always return options.. */ + str = g_string_new ("OPTIONS"); + + if (options & GST_RTSP_DESCRIBE) + g_string_append (str, ", DESCRIBE"); + if (options & GST_RTSP_ANNOUNCE) + g_string_append (str, ", ANNOUNCE"); + if (options & GST_RTSP_GET_PARAMETER) + g_string_append (str, ", GET_PARAMETER"); + if (options & GST_RTSP_PAUSE) + g_string_append (str, ", PAUSE"); + if (options & GST_RTSP_PLAY) + g_string_append (str, ", PLAY"); + if (options & GST_RTSP_RECORD) + g_string_append (str, ", RECORD"); + if (options & GST_RTSP_REDIRECT) + g_string_append (str, ", REDIRECT"); + if (options & GST_RTSP_SETUP) + g_string_append (str, ", SETUP"); + if (options & GST_RTSP_SET_PARAMETER) + g_string_append (str, ", SET_PARAMETER"); + if (options & GST_RTSP_TEARDOWN) + g_string_append (str, ", TEARDOWN"); + + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str->str); + + g_string_free (str, TRUE); + + gst_rtsp_connection_send (client->connection, &response, NULL); +} + +/* this function runs in a client specific thread and handles all rtsp messages + * with the client */ +static gpointer +handle_client (GstRTSPClient *client) +{ + GstRTSPMessage request = { 0 }; + GstRTSPResult res; + GstRTSPMethod method; + const gchar *uri; + GstRTSPVersion version; + + while (TRUE) { + /* start by waiting for a message from the client */ + res = gst_rtsp_connection_receive (client->connection, &request, NULL); + if (res < 0) + goto receive_failed; + +#ifdef DEBUG + gst_rtsp_message_dump (&request); +#endif + + gst_rtsp_message_parse_request (&request, &method, &uri, &version); + + if (version != GST_RTSP_VERSION_1_0) { + /* we can only handle 1.0 requests */ + handle_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, &request); + continue; + } + + /* now see what is asked and dispatch to a dedicated handler */ + switch (method) { + case GST_RTSP_OPTIONS: + handle_options_response (client, uri, &request); + break; + case GST_RTSP_DESCRIBE: + handle_describe_response (client, uri, &request); + break; + case GST_RTSP_SETUP: + handle_setup_response (client, uri, &request); + break; + case GST_RTSP_PLAY: + handle_play_response (client, uri, &request); + break; + case GST_RTSP_PAUSE: + handle_pause_response (client, uri, &request); + break; + case GST_RTSP_TEARDOWN: + handle_teardown_response (client, uri, &request); + break; + case GST_RTSP_ANNOUNCE: + case GST_RTSP_GET_PARAMETER: + case GST_RTSP_RECORD: + case GST_RTSP_REDIRECT: + case GST_RTSP_SET_PARAMETER: + handle_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &request); + break; + case GST_RTSP_INVALID: + default: + handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &request); + break; + } + } + g_object_unref (client); + return NULL; + + /* ERRORS */ +receive_failed: + { + g_print ("receive failed, disconnect client %p\n", client); + gst_rtsp_connection_close (client->connection); + g_object_unref (client); + return NULL; + } +} + +/* called when we need to accept a new request from a client */ +static gboolean +client_accept (GstRTSPClient *client, GIOChannel *source) +{ + /* a new client connected. */ + int server_sock_fd; + unsigned int address_len; + GstRTSPConnection *conn; + + conn = client->connection; + + server_sock_fd = g_io_channel_unix_get_fd (source); + + address_len = sizeof (client->address); + memset (&client->address, 0, address_len); + + conn->fd.fd = accept (server_sock_fd, (struct sockaddr *) &client->address, + &address_len); + if (conn->fd.fd == -1) + goto accept_failed; + + g_print ("added new client %p ip %s with fd %d\n", client, + inet_ntoa (client->address.sin_addr), conn->fd.fd); + + /* FIXME some hackery, we need to have a connection method to accept server + * connections */ + gst_poll_add_fd (conn->fdset, &conn->fd); + + return TRUE; + + /* ERRORS */ +accept_failed: + { + g_error ("Could not accept client on server socket %d: %s (%d)", + server_sock_fd, g_strerror (errno), errno); + return FALSE; + } +} + +/** + * gst_rtsp_client_set_session_pool: + * @client: a #GstRTSPClient + * @pool: a #GstRTSPSessionPool + * + * Set @pool as the sessionpool for @client which it will use to find + * or allocate sessions. + */ +void +gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool) +{ + GstRTSPSessionPool *old; + + old = client->pool; + if (pool) + g_object_ref (pool); + client->pool = pool; + if (old) + g_object_unref (old); +} + +/** + * gst_rtsp_client_get_session_pool: + * @client: a #GstRTSPClient + * + * Get the #GstRTSPSessionPool object that @client uses to manage its sessions. + * + * Returns: a #GstRTSPSessionPool, unref after usage. + */ +GstRTSPSessionPool * +gst_rtsp_client_get_session_pool (GstRTSPClient *client) +{ + GstRTSPSessionPool *result; + + if ((result = client->pool)) + g_object_ref (result); + + return result; +} + + +/** + * gst_rtsp_client_attach: + * @client: a #GstRTSPClient + * @context: a #GMainContext + * + * Attaches @client to @context. When the mainloop for @context is run, the + * client will be dispatched. + * + * This function should be called when the client properties and urls are fully + * configured and the client is ready to start. + * + * Returns: %TRUE if the client could be accepted. + */ +gboolean +gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *source) +{ + gst_rtsp_connection_create (NULL, &client->connection); + + if (!client_accept (client, source)) + goto accept_failed; + + /* client accepted, spawn a thread for the client */ + g_object_ref (client); + client->thread = g_thread_create ((GThreadFunc)handle_client, client, TRUE, NULL); + + return TRUE; + + /* ERRORS */ +accept_failed: + { + gst_rtsp_connection_close (client->connection); + return FALSE; + } +} diff --git a/src/rtsp-client.h b/src/rtsp-client.h new file mode 100644 index 0000000000..a29e6887ee --- /dev/null +++ b/src/rtsp-client.h @@ -0,0 +1,89 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef __GST_RTSP_CLIENT_H__ +#define __GST_RTSP_CLIENT_H__ + +#include "rtsp-media.h" +#include "rtsp-session-pool.h" + +G_BEGIN_DECLS + +#define GST_TYPE_RTSP_CLIENT (gst_rtsp_client_get_type ()) +#define GST_IS_RTSP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_CLIENT)) +#define GST_IS_RTSP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_CLIENT)) +#define GST_RTSP_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_CLIENT, GstRTSPClientClass)) +#define GST_RTSP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_CLIENT, GstRTSPClient)) +#define GST_RTSP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_CLIENT, GstRTSPClientClass)) +#define GST_RTSP_CLIENT_CAST(obj) ((GstRTSPClient*)(obj)) +#define GST_RTSP_CLIENT_CLASS_CAST(klass) ((GstRTSPClientClass*)(klass)) + +typedef struct _GstRTSPClient GstRTSPClient; +typedef struct _GstRTSPClientClass GstRTSPClientClass; + +struct _GstRTSPClient { + GObject parent; + + GstRTSPConnection *connection; + struct sockaddr_in address; + + GstRTSPMedia *media; + GstElement *pipeline; + + GstRTSPSessionPool *pool; + GstRTSPSession *session; + + GThread *thread; +}; + +struct _GstRTSPClientClass { + GObjectClass parent_class; +}; + +GType gst_rtsp_client_get_type (void); + +GstRTSPClient * gst_rtsp_client_new (void); + +void gst_rtsp_client_set_session_pool (GstRTSPClient *client, + GstRTSPSessionPool *pool); +GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client); + +gboolean gst_rtsp_client_accept (GstRTSPClient *client, + GIOChannel *source); + +G_END_DECLS + +#endif /* __GST_RTSP_CLIENT_H__ */ diff --git a/src/rtsp-media.c b/src/rtsp-media.c new file mode 100644 index 0000000000..c7e181dc77 --- /dev/null +++ b/src/rtsp-media.c @@ -0,0 +1,266 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "rtsp-media.h" + +G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); + +static void gst_rtsp_media_finalize (GObject * obj); + +static void +gst_rtsp_media_class_init (GstRTSPMediaClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gst_rtsp_media_finalize; +} + +static void +gst_rtsp_media_init (GstRTSPMedia * media) +{ + media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); +} + +static void +gst_rtsp_media_stream_free (GstRTSPMediaStream *stream) +{ +} + +static void +gst_rtsp_media_finalize (GObject * obj) +{ + GstRTSPMedia *media; + guint i; + + media = GST_RTSP_MEDIA (obj); + + g_free (media->location); + gst_rtsp_url_free (media->url); + + for (i = 0; i < media->streams->len; i++) { + GstRTSPMediaStream *stream; + + stream = g_array_index (media->streams, GstRTSPMediaStream *, i); + + gst_rtsp_media_stream_free (stream); + } + g_array_free (media->streams, TRUE); + + G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); +} + +/** + * gst_rtsp_media_new: + * @location: the URL of the media + * + * Create a new #GstRTSPMedia instance. + * + * Returns: a new #GstRTSPMedia object or %NULL when location did not contain a + * valid or understood URL. + */ +GstRTSPMedia * +gst_rtsp_media_new (const gchar *location) +{ + GstRTSPMedia *result; + GstRTSPUrl *url; + + url = NULL; + + if (gst_rtsp_url_parse (location, &url) != GST_RTSP_OK) + goto invalid_url; + + result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL); + result->location = g_strdup (location); + result->url = url; + + return result; + + /* ERRORS */ +invalid_url: + { + return NULL; + } +} + +static void +caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) +{ + if (stream->caps) + gst_caps_unref (stream->caps); + if ((stream->caps = GST_PAD_CAPS (pad))) + gst_caps_ref (stream->caps); +} + +/** + * + * STREAMING CONFIGURATION + * + * gst_rtsp_media_prepare: + * @media: a #GstRTSPMedia + * @bin: the parent bin to create the elements in. + * + * Prepare the media object so that it creates its streams. Implementations + * should crate the needed gstreamer elements and add them to @bin. No state + * changes should be performed on them yet. + * + * One or more GstRTSPMediaStream objects should be added to @media with the + * srcpad member set to a source pad that produces buffer of type + * application/x-rtp. + * + * Returns: %TRUE if the media could be prepared. + */ +gboolean +gst_rtsp_media_prepare (GstRTSPMedia *media, GstBin *bin) +{ + GstRTSPMediaStream *stream; + GstElement *pay, *element; + GstPad * pad; + gint i; + + /* if we're already prepared we must exit */ + g_return_val_if_fail (media->prepared == FALSE, FALSE); + + g_print ("%s\n", media->url->abspath); + + if (g_str_has_prefix (media->url->abspath, "/camera")) { + /* live */ + element = gst_parse_launch ("( " + "v4l2src ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " + "queue ! videorate ! ffmpegcolorspace ! " + "x264enc bitrate=300 ! rtph264pay name=pay0 " + "alsasrc ! audio/x-raw-int,rate=8000 ! queue ! " + "amrnbenc ! rtpamrpay name=pay1 " + ")", NULL); + } + else if (g_str_has_prefix (media->url->abspath, "/h264")) { + /* transcode h264 */ + element = gst_parse_launch ("( uridecodebin " + "uri=file:///home/cschalle/Videos/mi2.avi ! " + "x264enc bitrate=300 ! rtph264pay name=pay0 )", NULL); + } + else if (g_str_has_prefix (media->url->abspath, "/theora")) { + /* transcode theora */ + element = gst_parse_launch ("( uridecodebin " + "uri=file:///home/wim/data/mi2.avi ! " + "theoraenc ! rtptheorapay name=pay0 )", NULL); + } + else if (g_str_has_prefix (media->url->abspath, "/macpclinux")) { + /* theora/vorbis */ + element = gst_parse_launch ("( filesrc " + "location=/home/cschalle/Videos/mac_pc_linux_2.ogg ! oggdemux name=d ! " + "queue ! theoraparse ! rtptheorapay name=pay0 " + "d. ! queue ! vorbisparse ! rtpvorbispay name=pay1 )", NULL); + } + else if (g_str_has_prefix (media->url->abspath, "/rtspproxy")) { + /* proxy RTSP transcode */ + element = gst_parse_launch ("( uridecodebin " + "uri=rtsp://ia300135.us.archive.org:554/0/items/uncovered_interviews/uncovered_interviews_3_256kb.mp4 ! " + "x264enc bitrate=1800 ! rtph264pay name=pay0 )", NULL); + } + else if (g_str_has_prefix (media->url->abspath, "/httpproxy")) { + /* proxy HTTP transcode */ + element = gst_parse_launch ("( uridecodebin " + "uri=http://movies.apple.com/movies/fox/maxpayne/maxpayne-tlre_h480.mov name=d " + "d. ! queue ! x264enc bitrate=1800 ! rtph264pay name=pay0 " + "d. ! queue ! faac ! rtpmp4gpay name=pay1 )", NULL); + } + else + return FALSE; + + gst_bin_add (bin, element); + + for (i = 0; ; i++) { + gchar *name; + + name = g_strdup_printf ("pay%d", i); + + if (!(pay = gst_bin_get_by_name (GST_BIN (element), name))) { + g_free (name); + break; + } + + /* create the stream */ + stream = g_new0 (GstRTSPMediaStream, 1); + stream->media = media; + stream->element = element; + stream->payloader = pay; + stream->idx = media->streams->len; + + pad = gst_element_get_static_pad (pay, "src"); + + stream->srcpad = gst_ghost_pad_new (name, pad); + gst_element_add_pad (stream->element, stream->srcpad); + + stream->caps_sig = g_signal_connect (pad, "notify::caps", (GCallback) caps_notify, stream); + gst_object_unref (pad); + + /* add stream now */ + g_array_append_val (media->streams, stream); + gst_object_unref (pay); + + g_free (name); + } + + media->prepared = TRUE; + + return TRUE; +} + +/** + * gst_rtsp_media_n_streams: + * @media: a #GstRTSPMedia + * + * Get the number of streams in this media. + * + * Returns: The number of streams. + */ +guint +gst_rtsp_media_n_streams (GstRTSPMedia *media) +{ + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0); + g_return_val_if_fail (media->prepared, 0); + + return media->streams->len; +} + +/** + * gst_rtsp_media_get_stream: + * @media: a #GstRTSPMedia + * @idx: the stream index + * + * Retrieve the stream with index @idx from @media. + * + * Returns: the #GstRTSPMediaStream at index @idx. + */ +GstRTSPMediaStream * +gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx) +{ + GstRTSPMediaStream *res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + g_return_val_if_fail (media->prepared, 0); + g_return_val_if_fail (idx < media->streams->len, NULL); + + res = g_array_index (media->streams, GstRTSPMediaStream *, idx); + + return res; +} + diff --git a/src/rtsp-media.h b/src/rtsp-media.h new file mode 100644 index 0000000000..bf4bede1ad --- /dev/null +++ b/src/rtsp-media.h @@ -0,0 +1,79 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include + +#ifndef __GST_RTSP_MEDIA_H__ +#define __GST_RTSP_MEDIA_H__ + +G_BEGIN_DECLS + +#define GST_TYPE_RTSP_MEDIA (gst_rtsp_media_get_type ()) +#define GST_IS_RTSP_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA)) +#define GST_IS_RTSP_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA)) +#define GST_RTSP_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMediaClass)) +#define GST_RTSP_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMedia)) +#define GST_RTSP_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA, GstRTSPMediaClass)) +#define GST_RTSP_MEDIA_CAST(obj) ((GstRTSPMedia*)(obj)) +#define GST_RTSP_MEDIA_CLASS_CAST(klass) ((GstRTSPMediaClass*)(klass)) + +typedef struct _GstRTSPMedia GstRTSPMedia; +typedef struct _GstRTSPMediaStream GstRTSPMediaStream; +typedef struct _GstRTSPMediaClass GstRTSPMediaClass; + +struct _GstRTSPMediaStream { + GstRTSPMedia *media; + + guint idx; + gchar *name; + + GstElement *element; + GstPad *srcpad; + GstElement *payloader; + gulong caps_sig; + GstCaps *caps; +}; + +struct _GstRTSPMedia { + GObject parent; + + gchar *location; + GstRTSPUrl *url; + + gboolean prepared; + GArray *streams; +}; + +struct _GstRTSPMediaClass { + GObjectClass parent_class; +}; + +GType gst_rtsp_media_get_type (void); + +GstRTSPMedia * gst_rtsp_media_new (const gchar *name); + +gboolean gst_rtsp_media_prepare (GstRTSPMedia *media, GstBin *bin); + +guint gst_rtsp_media_n_streams (GstRTSPMedia *media); +GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); + +G_END_DECLS + +#endif /* __GST_RTSP_MEDIA_H__ */ diff --git a/src/rtsp-server.c b/src/rtsp-server.c new file mode 100644 index 0000000000..524275275a --- /dev/null +++ b/src/rtsp-server.c @@ -0,0 +1,232 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "rtsp-server.h" +#include "rtsp-client.h" + +#define TCP_BACKLOG 5 +#define DEFAULT_PORT 1554 + +G_DEFINE_TYPE (GstRTSPServer, gst_rtsp_server, G_TYPE_OBJECT); + +static void +gst_rtsp_server_class_init (GstRTSPServerClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); +} + +static void +gst_rtsp_server_init (GstRTSPServer * server) +{ + server->server_port = DEFAULT_PORT; + server->pool = gst_rtsp_session_pool_new (); +} + +/** + * gst_rtsp_server_new: + * + * Create a new #GstRTSPServer instance. + */ +GstRTSPServer * +gst_rtsp_server_new (void) +{ + GstRTSPServer *result; + + result = g_object_new (GST_TYPE_RTSP_SERVER, NULL); + + return result; +} + +static gboolean +gst_rtsp_server_sink_init_send (GstRTSPServer * server) +{ + int ret; + + /* create server socket */ + if ((server->server_sock.fd = socket (AF_INET, SOCK_STREAM, 0)) == -1) + goto no_socket; + + GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d", + server->server_sock.fd); + + /* make address reusable */ + ret = 1; + if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_REUSEADDR, + (void *) &ret, sizeof (ret)) < 0) + goto reuse_failed; + + /* keep connection alive; avoids SIGPIPE during write */ + ret = 1; + if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_KEEPALIVE, + (void *) &ret, sizeof (ret)) < 0) + goto keepalive_failed; + + /* name the socket */ + memset (&server->server_sin, 0, sizeof (server->server_sin)); + server->server_sin.sin_family = AF_INET; /* network socket */ + server->server_sin.sin_port = htons (server->server_port); /* on port */ + server->server_sin.sin_addr.s_addr = htonl (INADDR_ANY); /* for hosts */ + + /* bind it */ + GST_DEBUG_OBJECT (server, "binding server socket to address"); + ret = bind (server->server_sock.fd, (struct sockaddr *) &server->server_sin, + sizeof (server->server_sin)); + if (ret) + goto bind_failed; + + /* set the server socket to nonblocking */ + fcntl (server->server_sock.fd, F_SETFL, O_NONBLOCK); + + GST_DEBUG_OBJECT (server, "listening on server socket %d with queue of %d", + server->server_sock.fd, TCP_BACKLOG); + if (listen (server->server_sock.fd, TCP_BACKLOG) == -1) + goto listen_failed; + + GST_DEBUG_OBJECT (server, + "listened on server socket %d, returning from connection setup", + server->server_sock.fd); + + return TRUE; + + /* ERRORS */ +no_socket: + { + GST_ERROR_OBJECT (server, "failed to create socket: %s", g_strerror (errno)); + return FALSE; + } +reuse_failed: + { + if (server->server_sock.fd >= 0) { + close (server->server_sock.fd); + server->server_sock.fd = -1; + } + GST_ERROR_OBJECT (server, "failed to reuse socket: %s", g_strerror (errno)); + return FALSE; + } +keepalive_failed: + { + if (server->server_sock.fd >= 0) { + close (server->server_sock.fd); + server->server_sock.fd = -1; + } + GST_ERROR_OBJECT (server, "failed to configure keepalive socket: %s", g_strerror (errno)); + return FALSE; + } +listen_failed: + { + if (server->server_sock.fd >= 0) { + close (server->server_sock.fd); + server->server_sock.fd = -1; + } + GST_ERROR_OBJECT (server, "failed to listen on socket: %s", g_strerror (errno)); + return FALSE; + } +bind_failed: + { + if (server->server_sock.fd >= 0) { + close (server->server_sock.fd); + server->server_sock.fd = -1; + } + GST_ERROR_OBJECT (server, "failed to bind on socket: %s", g_strerror (errno)); + return FALSE; + } +} + +/* called when an event is available on our server socket */ +static gboolean +server_dispatch (GIOChannel *source, GIOCondition condition, GstRTSPServer *server) +{ + if (condition & G_IO_IN) { + GstRTSPClient *client; + + /* a new client connected, create a session to handle the client. */ + client = gst_rtsp_client_new (); + + /* set the session pool that this client should use */ + gst_rtsp_client_set_session_pool (client, server->pool); + + /* accept connections for that client, this function returns after accepting + * the connection and will run the remainder of the communication with the + * client asyncronously. */ + if (!gst_rtsp_client_accept (client, source)) + goto accept_failed; + + /* can unref the client now, when the request is finished, it will be + * unreffed async. */ + gst_object_unref (client); + } + else { + g_print ("received unknown event %08x", condition); + } + return TRUE; + + /* ERRORS */ +accept_failed: + { + g_error ("Could not accept client on server socket %d: %s (%d)", + server->server_sock.fd, g_strerror (errno), errno); + return FALSE; + } +} + +/** + * gst_rtsp_server_attach: + * @server: a #GstRTSPServer + * @context: a #GMainContext + * + * Attaches @server to @context. When the mainloop for @context is run, the + * server will be dispatched. + * + * This function should be called when the server properties and urls are fully + * configured and the server is ready to start. + * + * Returns: the ID (greater than 0) for the source within the GMainContext. + */ +guint +gst_rtsp_server_attach (GstRTSPServer *server, GMainContext *context) +{ + guint res; + + if (!gst_rtsp_server_sink_init_send (server)) + goto init_failed; + + /* create IO channel for the socket */ + server->io_channel = g_io_channel_unix_new (server->server_sock.fd); + + /* create a watch for reads (new connections) and possible errors */ + server->io_watch = g_io_create_watch (server->io_channel, G_IO_IN | + G_IO_ERR | G_IO_HUP | G_IO_NVAL); + + /* configure the callback */ + g_source_set_callback (server->io_watch, (GSourceFunc) server_dispatch, server, NULL); + + res = g_source_attach (server->io_watch, context); + + return res; + + /* ERRORS */ +init_failed: + { + return 0; + } +} diff --git a/src/rtsp-server.h b/src/rtsp-server.h new file mode 100644 index 0000000000..93bc820d8c --- /dev/null +++ b/src/rtsp-server.h @@ -0,0 +1,86 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "rtsp-session-pool.h" + +#ifndef __GST_RTSP_SERVER_H__ +#define __GST_RTSP_SERVER_H__ + +G_BEGIN_DECLS + +#define GST_TYPE_RTSP_SERVER (gst_rtsp_server_get_type ()) +#define GST_IS_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SERVER)) +#define GST_IS_RTSP_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SERVER)) +#define GST_RTSP_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_SERVER, GstRTSPServerClass)) +#define GST_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_SERVER, GstRTSPServer)) +#define GST_RTSP_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_SERVER, GstRTSPServerClass)) +#define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj)) +#define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass)) + +typedef struct _GstRTSPServer GstRTSPServer; +typedef struct _GstRTSPServerClass GstRTSPServerClass; + +struct _GstRTSPServer { + GObject parent; + + /* server information */ + int server_port; + gchar *host; + struct sockaddr_in server_sin; + + /* socket */ + GstPollFD server_sock; + + GIOChannel *io_channel; + GSource *io_watch; + + /* sessions on this server */ + GstRTSPSessionPool *pool; +}; + +struct _GstRTSPServerClass { + GObjectClass parent_class; +}; + +GType gst_rtsp_server_get_type (void); + +GstRTSPServer * gst_rtsp_server_new (void); + +guint gst_rtsp_server_attach (GstRTSPServer *server, + GMainContext *context); + +G_END_DECLS + +#endif /* __GST_RTSP_SERVER_H__ */ diff --git a/src/rtsp-session-pool.c b/src/rtsp-session-pool.c new file mode 100644 index 0000000000..716e88827b --- /dev/null +++ b/src/rtsp-session-pool.c @@ -0,0 +1,165 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "rtsp-session-pool.h" + +#undef DEBUG + +G_DEFINE_TYPE (GstRTSPSessionPool, gst_rtsp_session_pool, G_TYPE_OBJECT); + +static void +gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); +} + +static void +gst_rtsp_session_pool_init (GstRTSPSessionPool * pool) +{ + pool->lock = g_mutex_new (); + pool->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); +} + +/** + * gst_rtsp_session_pool_new: + * + * Create a new #GstRTSPSessionPool instance. + */ +GstRTSPSessionPool * +gst_rtsp_session_pool_new (void) +{ + GstRTSPSessionPool *result; + + result = g_object_new (GST_TYPE_RTSP_SESSION_POOL, NULL); + + return result; +} + +/** + * gst_rtsp_session_pool_find: + * @pool: the pool to search + * @sessionid: the session id + * + * Find the session with @sessionid in @pool. + * + * Returns: the #GstRTSPSession with @sessionid or %NULL when the session did + * not exist. g_object_unref() after usage. + */ +GstRTSPSession * +gst_rtsp_session_pool_find (GstRTSPSessionPool *pool, const gchar *sessionid) +{ + GstRTSPSession *result; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL); + g_return_val_if_fail (sessionid != NULL, NULL); + + g_mutex_lock (pool->lock); + result = g_hash_table_lookup (pool->sessions, sessionid); + if (result) + g_object_ref (result); + g_mutex_unlock (pool->lock); + + return result; +} + +static gchar * +create_session_id (void) +{ + gchar id[16]; + gint i; + + for (i = 0; i < 16; i++) { + id[i] = g_random_int_range ('a', 'z'); + } + + return g_strndup (id, 16); +} + +/** + * gst_rtsp_session_pool_create: + * @pool: a #GstRTSPSessionPool + * + * Create a new #GstRTSPSession object in @pool. + * + * Returns: a new #GstRTSPSession. + */ +GstRTSPSession * +gst_rtsp_session_pool_create (GstRTSPSessionPool *pool) +{ + GstRTSPSession *result = NULL; + gchar *id; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL); + + do { + /* start by creating a new random session id, we assume that this is random + * enough to not cause a collision, which we will check later */ + id = create_session_id (); + + g_mutex_lock (pool->lock); + /* check if the sessionid existed */ + result = g_hash_table_lookup (pool->sessions, id); + if (result) { + /* found, retry with a different session id*/ + result = NULL; + } + else { + /* not found, create session and insert it in the pool */ + result = gst_rtsp_session_new (id); + /* take additional ref for the pool */ + g_object_ref (result); + g_hash_table_insert (pool->sessions, result->sessionid, result); + } + g_mutex_unlock (pool->lock); + + g_free (id); + } while (result == NULL); + + return result; +} + +/** + * gst_rtsp_session_pool_remove: + * @pool: a #GstRTSPSessionPool + * @sess: a #GstRTSPSession + * + * Remove @sess from @pool and Clean it up. + * + * Returns: a new #GstRTSPSession. + */ +void +gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, GstRTSPSession *sess) +{ + gboolean found; + + g_return_if_fail (GST_IS_RTSP_SESSION_POOL (pool)); + g_return_if_fail (GST_IS_RTSP_SESSION (sess)); + + g_mutex_lock (pool->lock); + found = g_hash_table_remove (pool->sessions, sess); + g_mutex_unlock (pool->lock); + + if (found) { + g_object_unref (sess); + } +} + diff --git a/src/rtsp-session-pool.h b/src/rtsp-session-pool.h new file mode 100644 index 0000000000..9336647d4d --- /dev/null +++ b/src/rtsp-session-pool.h @@ -0,0 +1,69 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#ifndef __GST_RTSP_SESSION_POOL_H__ +#define __GST_RTSP_SESSION_POOL_H__ + +#include "rtsp-session.h" + +G_BEGIN_DECLS + +#define GST_TYPE_RTSP_SESSION_POOL (gst_rtsp_session_pool_get_type ()) +#define GST_IS_RTSP_SESSION_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SESSION_POOL)) +#define GST_IS_RTSP_SESSION_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SESSION_POOL)) +#define GST_RTSP_SESSION_POOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_SESSION_POOL, GstRTSPSessionPoolClass)) +#define GST_RTSP_SESSION_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_SESSION_POOL, GstRTSPSessionPool)) +#define GST_RTSP_SESSION_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_SESSION_POOL, GstRTSPSessionPoolClass)) +#define GST_RTSP_SESSION_POOL_CAST(obj) ((GstRTSPSessionPool*)(obj)) +#define GST_RTSP_SESSION_POOL_CLASS_CAST(klass) ((GstRTSPSessionPoolClass*)(klass)) + +typedef struct _GstRTSPSessionPool GstRTSPSessionPool; +typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; + +/** + * GstRTSPSessionPool: + * + * An object that keeps track of the active sessions. + */ +struct _GstRTSPSessionPool { + GObject parent; + + GMutex *lock; + GHashTable *sessions; +}; + +struct _GstRTSPSessionPoolClass { + GObjectClass parent_class; +}; + +GType gst_rtsp_session_pool_get_type (void); + +GstRTSPSessionPool * gst_rtsp_session_pool_new (void); + +GstRTSPSession * gst_rtsp_session_pool_find (GstRTSPSessionPool *pool, + const gchar *sessionid); +GstRTSPSession * gst_rtsp_session_pool_create (GstRTSPSessionPool *pool); +void gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, + GstRTSPSession *sess); + +G_END_DECLS + +#endif /* __GST_RTSP_SESSION_POOL_H__ */ diff --git a/src/rtsp-session.c b/src/rtsp-session.c new file mode 100644 index 0000000000..7893632c42 --- /dev/null +++ b/src/rtsp-session.c @@ -0,0 +1,503 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "rtsp-session.h" + +#undef DEBUG + +static void gst_rtsp_session_finalize (GObject * obj); + +G_DEFINE_TYPE (GstRTSPSession, gst_rtsp_session, G_TYPE_OBJECT); + +static void +gst_rtsp_session_class_init (GstRTSPSessionClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gst_rtsp_session_finalize; +} + +static void +gst_rtsp_session_init (GstRTSPSession * session) +{ +} + +static void +gst_rtsp_session_free_stream (GstRTSPSessionStream *stream) +{ + if (stream->client_trans) + gst_rtsp_transport_free (stream->client_trans); + g_free (stream->destination); + if (stream->server_trans) + gst_rtsp_transport_free (stream->server_trans); + + if (stream->udpsrc[0]) + gst_object_unref (stream->udpsrc[0]); + + g_free (stream); +} + +static void +gst_rtsp_session_free_media (GstRTSPSessionMedia *media) +{ + GList *walk; + + gst_element_set_state (media->pipeline, GST_STATE_NULL); + + if (media->media) + g_object_unref (media->media); + + for (walk = media->streams; walk; walk = g_list_next (walk)) { + GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data; + + gst_rtsp_session_free_stream (stream); + } + if (media->pipeline) + gst_object_unref (media->pipeline); + g_list_free (media->streams); +} + +static void +gst_rtsp_session_finalize (GObject * obj) +{ + GstRTSPSession *session; + GList *walk; + + session = GST_RTSP_SESSION (obj); + + g_free (session->sessionid); + + for (walk = session->medias; walk; walk = g_list_next (walk)) { + GstRTSPSessionMedia *media = (GstRTSPSessionMedia *) walk->data; + + gst_rtsp_session_free_media (media); + } + g_list_free (session->medias); + + G_OBJECT_CLASS (gst_rtsp_session_parent_class)->finalize (obj); +} + +/** + * gst_rtsp_session_get_media: + * @sess: a #GstRTSPSession + * @media: a #GstRTSPSessionMedia + * + * Get or create the session information for @media. + * + * Returns: the configuration for @media in @sess. + */ +GstRTSPSessionMedia * +gst_rtsp_session_get_media (GstRTSPSession *sess, GstRTSPMedia *media) +{ + GstRTSPSessionMedia *result; + GList *walk; + + for (walk = sess->medias; walk; walk = g_list_next (walk)) { + result = (GstRTSPSessionMedia *) walk->data; + + if (result->media == media) + break; + + result = NULL; + } + if (result == NULL) { + result = g_new0 (GstRTSPSessionMedia, 1); + result->media = media; + result->pipeline = gst_pipeline_new ("pipeline"); + + /* prepare media into the pipeline */ + if (!gst_rtsp_media_prepare (media, GST_BIN (result->pipeline))) + goto no_media; + + result->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin"); + + /* add stuf to the bin */ + gst_bin_add (GST_BIN (result->pipeline), result->rtpbin); + + gst_element_set_state (result->pipeline, GST_STATE_READY); + + sess->medias = g_list_prepend (sess->medias, result); + } + return result; + + /* ERRORS */ +no_media: + { + gst_rtsp_session_free_media (result); + return FALSE; + } +} + +/** + * gst_rtsp_session_get_stream: + * @media: a #GstRTSPSessionMedia + * @idx: the stream index + * + * Get a previously created or create a new #GstRTSPSessionStream at @idx. + * + * Returns: a #GstRTSPSessionStream that is valid until the session of @media + * is unreffed. + */ +GstRTSPSessionStream * +gst_rtsp_session_get_stream (GstRTSPSessionMedia *media, guint idx) +{ + GstRTSPSessionStream *result; + GList *walk; + + for (walk = media->streams; walk; walk = g_list_next (walk)) { + result = (GstRTSPSessionStream *) walk->data; + + if (result->idx == idx) + break; + + result = NULL; + } + if (result == NULL) { + result = g_new0 (GstRTSPSessionStream, 1); + result->idx = idx; + result->media = media; + result->media_stream = gst_rtsp_media_get_stream (media->media, idx); + + media->streams = g_list_prepend (media->streams, result); + } + return result; +} + +/** + * gst_rtsp_session_new: + * + * Create a new #GstRTSPSession instance. + */ +GstRTSPSession * +gst_rtsp_session_new (const gchar *sessionid) +{ + GstRTSPSession *result; + + result = g_object_new (GST_TYPE_RTSP_SESSION, NULL); + result->sessionid = g_strdup (sessionid); + + return result; +} + +static gboolean +alloc_udp_ports (GstRTSPSessionStream * stream) +{ + GstStateChangeReturn ret; + GstElement *udpsrc0, *udpsrc1; + GstElement *udpsink0, *udpsink1; + gint tmp_rtp, tmp_rtcp; + guint count; + gint rtpport, rtcpport, sockfd; + gchar *name; + + udpsrc0 = NULL; + udpsrc1 = NULL; + udpsink0 = NULL; + udpsink1 = NULL; + count = 0; + + /* Start with random port */ + tmp_rtp = 0; + + /* try to allocate 2 UDP ports, the RTP port should be an even + * number and the RTCP port should be the next (uneven) port */ +again: + udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL); + if (udpsrc0 == NULL) + goto no_udp_protocol; + g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL); + + ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED); + if (ret == GST_STATE_CHANGE_FAILURE) { + if (tmp_rtp != 0) { + tmp_rtp += 2; + if (++count > 20) + goto no_ports; + + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + + goto again; + } + goto no_udp_protocol; + } + + g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); + + /* check if port is even */ + if ((tmp_rtp & 1) != 0) { + /* port not even, close and allocate another */ + if (++count > 20) + goto no_ports; + + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + + tmp_rtp++; + goto again; + } + + /* allocate port+1 for RTCP now */ + udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL); + if (udpsrc1 == NULL) + goto no_udp_rtcp_protocol; + + /* set port */ + tmp_rtcp = tmp_rtp + 1; + g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL); + + ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED); + /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */ + if (ret == GST_STATE_CHANGE_FAILURE) { + + if (++count > 20) + goto no_ports; + + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + + gst_element_set_state (udpsrc1, GST_STATE_NULL); + gst_object_unref (udpsrc1); + + tmp_rtp += 2; + goto again; + } + + /* all fine, do port check */ + g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL); + g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL); + + /* this should not happen... */ + if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) + goto port_error; + + name = g_strdup_printf ("udp://%s:%d", stream->destination, stream->client_trans->client_port.min); + udpsink0 = gst_element_make_from_uri (GST_URI_SINK, name, NULL); + g_free (name); + + if (!udpsink0) + goto no_udp_protocol; + + g_object_get (G_OBJECT (udpsrc0), "sock", &sockfd, NULL); + g_object_set (G_OBJECT (udpsink0), "sockfd", sockfd, NULL); + g_object_set (G_OBJECT (udpsink0), "closefd", FALSE, NULL); + + name = g_strdup_printf ("udp://%s:%d", stream->destination, stream->client_trans->client_port.max); + udpsink1 = gst_element_make_from_uri (GST_URI_SINK, name, NULL); + g_free (name); + + if (!udpsink1) + goto no_udp_protocol; + + g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL); + g_object_set (G_OBJECT (udpsink1), "sockfd", sockfd, NULL); + g_object_set (G_OBJECT (udpsink1), "closefd", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); + + + /* we keep these elements, we configure all in configure_transport when the + * server told us to really use the UDP ports. */ + stream->udpsrc[0] = gst_object_ref (udpsrc0); + stream->udpsrc[1] = gst_object_ref (udpsrc1); + stream->udpsink[0] = gst_object_ref (udpsink0); + stream->udpsink[1] = gst_object_ref (udpsink1); + stream->server_trans->server_port.min = rtpport; + stream->server_trans->server_port.max = rtcpport; + + /* they are ours now */ + gst_object_sink (udpsrc0); + gst_object_sink (udpsrc1); + gst_object_sink (udpsink0); + gst_object_sink (udpsink1); + + return TRUE; + + /* ERRORS */ +no_udp_protocol: + { + goto cleanup; + } +no_ports: + { + goto cleanup; + } +no_udp_rtcp_protocol: + { + goto cleanup; + } +port_error: + { + goto cleanup; + } +cleanup: + { + if (udpsrc0) { + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + } + if (udpsrc1) { + gst_element_set_state (udpsrc1, GST_STATE_NULL); + gst_object_unref (udpsrc1); + } + if (udpsink0) { + gst_element_set_state (udpsink0, GST_STATE_NULL); + gst_object_unref (udpsink0); + } + if (udpsink1) { + gst_element_set_state (udpsink1, GST_STATE_NULL); + gst_object_unref (udpsink1); + } + return FALSE; + } +} + + +/** + * gst_rtsp_session_stream_init_udp: + * @stream: a #GstRTSPSessionStream + * @ct: a client #GstRTSPTransport + * + * Set @ct as the client transport and create and return a matching server + * transport. After this call the needed ports and elements will be created and + * initialized. + * + * Returns: a server transport or NULL if something went wrong. + */ +GstRTSPTransport * +gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, + const gchar *destination, GstRTSPTransport *ct) +{ + GstRTSPTransport *st; + GstPad *pad; + gchar *name; + GstRTSPSessionMedia *media; + + media = stream->media; + + /* prepare the server transport */ + gst_rtsp_transport_new (&st); + + st->trans = ct->trans; + st->profile = ct->profile; + st->lower_transport = ct->lower_transport; + st->client_port = ct->client_port; + + /* keep track of the transports */ + g_free (stream->destination); + stream->destination = g_strdup (destination); + if (stream->client_trans) + gst_rtsp_transport_free (stream->client_trans); + stream->client_trans = ct; + if (stream->server_trans) + gst_rtsp_transport_free (stream->server_trans); + stream->server_trans = st; + + alloc_udp_ports (stream); + + gst_bin_add (GST_BIN (media->pipeline), stream->udpsink[0]); + gst_bin_add (GST_BIN (media->pipeline), stream->udpsink[1]); + gst_bin_add (GST_BIN (media->pipeline), stream->udpsrc[1]); + + /* hook up the stream to the RTP session elements. */ + name = g_strdup_printf ("send_rtp_sink_%d", stream->idx); + stream->send_rtp_sink = gst_element_get_request_pad (media->rtpbin, name); + g_free (name); + name = g_strdup_printf ("send_rtp_src_%d", stream->idx); + stream->send_rtp_src = gst_element_get_static_pad (media->rtpbin, name); + g_free (name); + name = g_strdup_printf ("send_rtcp_src_%d", stream->idx); + stream->send_rtcp_src = gst_element_get_request_pad (media->rtpbin, name); + g_free (name); + name = g_strdup_printf ("recv_rtcp_sink_%d", stream->idx); + stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name); + g_free (name); + + gst_pad_link (stream->media_stream->srcpad, stream->send_rtp_sink); + pad = gst_element_get_static_pad (stream->udpsink[0], "sink"); + gst_pad_link (stream->send_rtp_src, pad); + gst_object_unref (pad); + pad = gst_element_get_static_pad (stream->udpsink[1], "sink"); + gst_pad_link (stream->send_rtcp_src, pad); + gst_object_unref (pad); + pad = gst_element_get_static_pad (stream->udpsrc[1], "src"); + gst_pad_link (pad, stream->recv_rtcp_sink); + gst_object_unref (pad); + + return st; +} + +/** + * gst_rtsp_session_media_play: + * @media: a #GstRTSPSessionMedia + * + * Tell the media object @media to start playing and streaming to the client. + * + * Returns: a #GstStateChangeReturn + */ +GstStateChangeReturn +gst_rtsp_session_media_play (GstRTSPSessionMedia *media) +{ + GstStateChangeReturn ret; + + ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); + + return ret; +} + +/** + * gst_rtsp_session_media_pause: + * @media: a #GstRTSPSessionMedia + * + * Tell the media object @media to pause. + * + * Returns: a #GstStateChangeReturn + */ +GstStateChangeReturn +gst_rtsp_session_media_pause (GstRTSPSessionMedia *media) +{ + GstStateChangeReturn ret; + + ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); + + return ret; +} + +/** + * gst_rtsp_session_media_stop: + * @media: a #GstRTSPSessionMedia + * + * Tell the media object @media to stop playing. After this call the media + * cannot be played or paused anymore + * + * Returns: a #GstStateChangeReturn + */ +GstStateChangeReturn +gst_rtsp_session_media_stop (GstRTSPSessionMedia *media) +{ + GstStateChangeReturn ret; + + ret = gst_element_set_state (media->pipeline, GST_STATE_NULL); + + return ret; +} + + diff --git a/src/rtsp-session.h b/src/rtsp-session.h new file mode 100644 index 0000000000..5ad4b3b9b7 --- /dev/null +++ b/src/rtsp-session.h @@ -0,0 +1,138 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + +#include "rtsp-media.h" + +#ifndef __GST_RTSP_SESSION_H__ +#define __GST_RTSP_SESSION_H__ + +G_BEGIN_DECLS + +#define GST_TYPE_RTSP_SESSION (gst_rtsp_session_get_type ()) +#define GST_IS_RTSP_SESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SESSION)) +#define GST_IS_RTSP_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SESSION)) +#define GST_RTSP_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_SESSION, GstRTSPSessionClass)) +#define GST_RTSP_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_SESSION, GstRTSPSession)) +#define GST_RTSP_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_SESSION, GstRTSPSessionClass)) +#define GST_RTSP_SESSION_CAST(obj) ((GstRTSPSession*)(obj)) +#define GST_RTSP_SESSION_CLASS_CAST(klass) ((GstRTSPSessionClass*)(klass)) + +typedef struct _GstRTSPSession GstRTSPSession; +typedef struct _GstRTSPSessionClass GstRTSPSessionClass; + +typedef struct _GstRTSPSessionStream GstRTSPSessionStream; +typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia; + +/** + * GstRTSPSessionStream: + * + * Configuration of a stream. + */ +struct _GstRTSPSessionStream +{ + guint idx; + + /* the owner media */ + GstRTSPSessionMedia *media; + + GstRTSPMediaStream *media_stream; + + /* client and server transports */ + gchar *destination; + GstRTSPTransport *client_trans; + GstRTSPTransport *server_trans; + + /* pads on the rtpbin */ + GstPad *recv_rtcp_sink; + GstPad *send_rtp_sink; + GstPad *send_rtp_src; + GstPad *send_rtcp_src; + + /* sinks used for sending and receiving RTP and RTCP, they share sockets */ + GstElement *udpsrc[2]; + GstElement *udpsink[2]; +}; + +/** + * GstRTSPSessionMedia: + * + * State of a client session regarding a specific media. + */ +struct _GstRTSPSessionMedia +{ + /* the owner session */ + GstRTSPSession *session; + + /* the media we are handling */ + GstRTSPMedia *media; + + /* the pipeline for the media */ + GstElement *pipeline; + + /* RTP session manager */ + GstElement *rtpbin; + + /* for TCP transport */ + GstElement *fdsink; + + /* configuration for the different streams */ + GList *streams; +}; + +/** + * GstRTSPSession: + * + * Session information kept by the server for a specific client. + */ +struct _GstRTSPSession { + GObject parent; + + gchar *sessionid; + + GList *medias; +}; + +struct _GstRTSPSessionClass { + GObjectClass parent_class; +}; + +GType gst_rtsp_session_get_type (void); + +GstRTSPSession * gst_rtsp_session_new (const gchar *sessionid); + +GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, + GstRTSPMedia *media); +GstRTSPSessionStream * gst_rtsp_session_get_stream (GstRTSPSessionMedia *media, + guint idx); + +GstStateChangeReturn gst_rtsp_session_media_play (GstRTSPSessionMedia *media); +GstStateChangeReturn gst_rtsp_session_media_pause (GstRTSPSessionMedia *media); +GstStateChangeReturn gst_rtsp_session_media_stop (GstRTSPSessionMedia *media); + +GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, + const gchar *destination, + GstRTSPTransport *ct); + +G_END_DECLS + +#endif /* __GST_RTSP_SESSION_H__ */ From cd10a8c87e9fbc0421e60ad8a5c0c726800f41d6 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Thu, 9 Oct 2008 13:30:47 +0100 Subject: [PATCH 0002/1776] Add a reasonable generic .gitignore --- .gitignore | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..03cd96b64e --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +*.[oa] +*.gcda +*.gcno +*.la +*.lo +*.loT +*.sw[po] +*.tar.* +*~ +.deps +.libs +INSTALL +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +compile +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +install-sh +libtool +ltmain.sh +missing +stamp-h1 From 5e32c2282866939808e111228da42de47f9407c2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 23 Oct 2008 12:14:55 +0200 Subject: [PATCH 0003/1776] Initialize variable to avoid compiler warning. --- src/rtsp-session.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rtsp-session.c b/src/rtsp-session.c index 7893632c42..a7cf3ee1f6 100644 --- a/src/rtsp-session.c +++ b/src/rtsp-session.c @@ -110,6 +110,8 @@ gst_rtsp_session_get_media (GstRTSPSession *sess, GstRTSPMedia *media) GstRTSPSessionMedia *result; GList *walk; + result = NULL; + for (walk = sess->medias; walk; walk = g_list_next (walk)) { result = (GstRTSPSessionMedia *) walk->data; From 1f35c93f0abc8f699f72c9e49b44e7f550aee155 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 23 Oct 2008 12:23:27 +0200 Subject: [PATCH 0004/1776] Initialize some more vars. --- src/rtsp-session.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rtsp-session.c b/src/rtsp-session.c index a7cf3ee1f6..05ca1f3ede 100644 --- a/src/rtsp-session.c +++ b/src/rtsp-session.c @@ -164,6 +164,8 @@ gst_rtsp_session_get_stream (GstRTSPSessionMedia *media, guint idx) GstRTSPSessionStream *result; GList *walk; + result = NULL; + for (walk = media->streams; walk; walk = g_list_next (walk)) { result = (GstRTSPSessionStream *) walk->data; From f205f8a9d1843979b308ded05e9ab1637b4e971f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 8 Jan 2009 11:22:58 +0100 Subject: [PATCH 0005/1776] Set the payload types for the different payloaders. Maybe this shoulde be done automatically instead. --- src/rtsp-media.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rtsp-media.c b/src/rtsp-media.c index c7e181dc77..c02173416f 100644 --- a/src/rtsp-media.c +++ b/src/rtsp-media.c @@ -145,9 +145,9 @@ gst_rtsp_media_prepare (GstRTSPMedia *media, GstBin *bin) element = gst_parse_launch ("( " "v4l2src ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " "queue ! videorate ! ffmpegcolorspace ! " - "x264enc bitrate=300 ! rtph264pay name=pay0 " + "x264enc bitrate=300 ! rtph264pay name=pay0 pt=96 " "alsasrc ! audio/x-raw-int,rate=8000 ! queue ! " - "amrnbenc ! rtpamrpay name=pay1 " + "amrnbenc ! rtpamrpay name=pay1 pt=97 " ")", NULL); } else if (g_str_has_prefix (media->url->abspath, "/h264")) { @@ -179,8 +179,8 @@ gst_rtsp_media_prepare (GstRTSPMedia *media, GstBin *bin) /* proxy HTTP transcode */ element = gst_parse_launch ("( uridecodebin " "uri=http://movies.apple.com/movies/fox/maxpayne/maxpayne-tlre_h480.mov name=d " - "d. ! queue ! x264enc bitrate=1800 ! rtph264pay name=pay0 " - "d. ! queue ! faac ! rtpmp4gpay name=pay1 )", NULL); + "d. ! queue ! x264enc bitrate=1800 ! rtph264pay name=pay0 pt=96 " + "d. ! queue ! faac ! rtpmp4gpay name=pay1 pt=97 )", NULL); } else return FALSE; From ea0531e4617df92ca8470d958180fa8107934268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Mon, 10 Nov 2008 21:03:15 +0100 Subject: [PATCH 0006/1776] Removed pipeline variable GstRTSPClient, because it's only used in one function --- src/rtsp-client.c | 19 ++++++++++--------- src/rtsp-client.h | 1 - 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/rtsp-client.c b/src/rtsp-client.c index b4bcbc1b85..9bfb6f858a 100644 --- a/src/rtsp-client.c +++ b/src/rtsp-client.c @@ -398,6 +398,7 @@ handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag guint n_streams, i; gchar *sdptext; GstRTSPMedia *media; + GstElement *pipeline = NULL; /* check what kind of format is accepted */ @@ -407,12 +408,12 @@ handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag goto no_media; /* create a pipeline if we have to */ - if (client->pipeline == NULL) { - client->pipeline = gst_pipeline_new ("client-pipeline"); + if (pipeline == NULL) { + pipeline = gst_pipeline_new ("client-pipeline"); } /* prepare the media into the pipeline */ - if (!gst_rtsp_media_prepare (media, GST_BIN (client->pipeline))) + if (!gst_rtsp_media_prepare (media, GST_BIN (pipeline))) goto no_media; /* link fakesink to all stream pads and set the pipeline to PLAYING */ @@ -425,7 +426,7 @@ handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag stream = gst_rtsp_media_get_stream (media, i); sink = gst_element_factory_make ("fakesink", NULL); - gst_bin_add (GST_BIN (client->pipeline), sink); + gst_bin_add (GST_BIN (pipeline), sink); sinkpad = gst_element_get_static_pad (sink, "sink"); gst_pad_link (stream->srcpad, sinkpad); @@ -434,10 +435,10 @@ handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag /* now play and wait till we get the pads blocked. At that time the pipeline * is prerolled and we have the caps on the streams too. */ - gst_element_set_state (client->pipeline, GST_STATE_PLAYING); + gst_element_set_state (pipeline, GST_STATE_PLAYING); /* wait for state change to complete */ - gst_element_get_state (client->pipeline, NULL, NULL, -1); + gst_element_get_state (pipeline, NULL, NULL, -1); /* we should now be able to construct the SDP message */ gst_sdp_message_new (&sdp); @@ -545,12 +546,12 @@ handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag gst_sdp_message_add_media (sdp, smedia); } /* go back to NULL */ - gst_element_set_state (client->pipeline, GST_STATE_NULL); + gst_element_set_state (pipeline, GST_STATE_NULL); g_object_unref (media); - gst_object_unref (client->pipeline); - client->pipeline = NULL; + gst_object_unref (pipeline); + pipeline = NULL; gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); diff --git a/src/rtsp-client.h b/src/rtsp-client.h index a29e6887ee..b8a3e7f81b 100644 --- a/src/rtsp-client.h +++ b/src/rtsp-client.h @@ -61,7 +61,6 @@ struct _GstRTSPClient { struct sockaddr_in address; GstRTSPMedia *media; - GstElement *pipeline; GstRTSPSessionPool *pool; GstRTSPSession *session; From c91ec684e973e15699e8f6e08945ee0cf8df4571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Mon, 10 Nov 2008 20:59:35 +0100 Subject: [PATCH 0007/1776] Removed obsolete variable --- src/rtsp-client.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/rtsp-client.h b/src/rtsp-client.h index b8a3e7f81b..da09684284 100644 --- a/src/rtsp-client.h +++ b/src/rtsp-client.h @@ -63,7 +63,6 @@ struct _GstRTSPClient { GstRTSPMedia *media; GstRTSPSessionPool *pool; - GstRTSPSession *session; GThread *thread; }; From 78893957870ab6146d3bcf9add9a94e111803d2f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 8 Jan 2009 13:18:55 +0100 Subject: [PATCH 0008/1776] Split in library and example program --- Makefile.am | 5 ++-- autogen.sh | 2 +- configure.ac | 6 +++-- examples/Makefile.am | 11 ++++++++ {src => examples}/main.c | 2 +- gst/Makefile.am | 1 + gst/rtsp-server/Makefile.am | 28 ++++++++++++++++++++ {src => gst/rtsp-server}/rtsp-client.c | 0 {src => gst/rtsp-server}/rtsp-client.h | 0 {src => gst/rtsp-server}/rtsp-media.c | 0 {src => gst/rtsp-server}/rtsp-media.h | 0 {src => gst/rtsp-server}/rtsp-server.c | 0 {src => gst/rtsp-server}/rtsp-server.h | 0 {src => gst/rtsp-server}/rtsp-session-pool.c | 0 {src => gst/rtsp-server}/rtsp-session-pool.h | 0 {src => gst/rtsp-server}/rtsp-session.c | 0 {src => gst/rtsp-server}/rtsp-session.h | 0 src/Makefile.am | 20 -------------- 18 files changed, 49 insertions(+), 26 deletions(-) create mode 100644 examples/Makefile.am rename {src => examples}/main.c (96%) create mode 100644 gst/Makefile.am create mode 100644 gst/rtsp-server/Makefile.am rename {src => gst/rtsp-server}/rtsp-client.c (100%) rename {src => gst/rtsp-server}/rtsp-client.h (100%) rename {src => gst/rtsp-server}/rtsp-media.c (100%) rename {src => gst/rtsp-server}/rtsp-media.h (100%) rename {src => gst/rtsp-server}/rtsp-server.c (100%) rename {src => gst/rtsp-server}/rtsp-server.h (100%) rename {src => gst/rtsp-server}/rtsp-session-pool.c (100%) rename {src => gst/rtsp-server}/rtsp-session-pool.h (100%) rename {src => gst/rtsp-server}/rtsp-session.c (100%) rename {src => gst/rtsp-server}/rtsp-session.h (100%) delete mode 100644 src/Makefile.am diff --git a/Makefile.am b/Makefile.am index 289f1620be..0e57eb3b53 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,10 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc SUBDIRS = \ - src \ + gst \ m4 \ - common + common \ + examples DIST_SUBDIRS = $(SUBDIRS) diff --git a/autogen.sh b/autogen.sh index 0a8c579abe..737032a07c 100755 --- a/autogen.sh +++ b/autogen.sh @@ -3,7 +3,7 @@ DIE=0 package=gst-rtsp -srcfile=src/rtsp-server.c +srcfile=gst/rtsp-server/rtsp-server.c # a quick cvs co to ease the transition if test ! -d common; diff --git a/configure.ac b/configure.ac index 63a2231d41..8d281d37b0 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl check if this is a release version AS_NANO(GST_CVS="no", GST_CVS="yes") dnl can autoconf find the source ? -AC_CONFIG_SRCDIR([src/rtsp-server.c]) +AC_CONFIG_SRCDIR([gst/rtsp-server/rtsp-server.c]) dnl define the output header for config AM_CONFIG_HEADER([config.h]) @@ -215,7 +215,9 @@ gst-rtsp.spec common/Makefile common/m4/Makefile m4/Makefile -src/Makefile +gst/Makefile +gst/rtsp-server/Makefile +examples/Makefile ]) AC_OUTPUT diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000000..f5b20c4555 --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,11 @@ + +noinst_PROGRAMS = gst-rtsp-server + +gst_rtsp_server_SOURCES = \ + main.c + +gst_rtsp_server_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +gst_rtsp_server_LDFLAGS = \ + $(GST_LIBS) \ + $(top_builddir)/gst/rtsp-server/libgstrtspserver.la + diff --git a/src/main.c b/examples/main.c similarity index 96% rename from src/main.c rename to examples/main.c index 70b1fdc9d2..41a1cb91ad 100644 --- a/src/main.c +++ b/examples/main.c @@ -19,7 +19,7 @@ #include -#include "rtsp-server.h" +#include int main (int argc, char *argv[]) diff --git a/gst/Makefile.am b/gst/Makefile.am new file mode 100644 index 0000000000..e37bbc66e9 --- /dev/null +++ b/gst/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = rtsp-server diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am new file mode 100644 index 0000000000..752b55b564 --- /dev/null +++ b/gst/rtsp-server/Makefile.am @@ -0,0 +1,28 @@ +public_headers = \ + rtsp-server.h \ + rtsp-client.h \ + rtsp-media.h + +c_sources = \ + rtsp-server.c \ + rtsp-client.c \ + rtsp-media.c \ + rtsp-session-pool.c \ + rtsp-session.c + +lib_LTLIBRARIES = \ + libgstrtspserver.la + +libgstrtspserver_la_SOURCES = \ + $(c_sources) + +libgstrtspserver_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstrtspserver_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstrtspserver_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ + -lgstsdp-@GST_MAJORMINOR@ $(GST_LIBS) $(LIBM) +libgstrtspserver_la_LIBTOOLFLAGS = --tag=disable-static + +libgstrtspserver_includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/rtsp-server +libgstrtspserver_include_HEADERS = $(public_headers) diff --git a/src/rtsp-client.c b/gst/rtsp-server/rtsp-client.c similarity index 100% rename from src/rtsp-client.c rename to gst/rtsp-server/rtsp-client.c diff --git a/src/rtsp-client.h b/gst/rtsp-server/rtsp-client.h similarity index 100% rename from src/rtsp-client.h rename to gst/rtsp-server/rtsp-client.h diff --git a/src/rtsp-media.c b/gst/rtsp-server/rtsp-media.c similarity index 100% rename from src/rtsp-media.c rename to gst/rtsp-server/rtsp-media.c diff --git a/src/rtsp-media.h b/gst/rtsp-server/rtsp-media.h similarity index 100% rename from src/rtsp-media.h rename to gst/rtsp-server/rtsp-media.h diff --git a/src/rtsp-server.c b/gst/rtsp-server/rtsp-server.c similarity index 100% rename from src/rtsp-server.c rename to gst/rtsp-server/rtsp-server.c diff --git a/src/rtsp-server.h b/gst/rtsp-server/rtsp-server.h similarity index 100% rename from src/rtsp-server.h rename to gst/rtsp-server/rtsp-server.h diff --git a/src/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c similarity index 100% rename from src/rtsp-session-pool.c rename to gst/rtsp-server/rtsp-session-pool.c diff --git a/src/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h similarity index 100% rename from src/rtsp-session-pool.h rename to gst/rtsp-server/rtsp-session-pool.h diff --git a/src/rtsp-session.c b/gst/rtsp-server/rtsp-session.c similarity index 100% rename from src/rtsp-session.c rename to gst/rtsp-server/rtsp-session.c diff --git a/src/rtsp-session.h b/gst/rtsp-server/rtsp-session.h similarity index 100% rename from src/rtsp-session.h rename to gst/rtsp-server/rtsp-session.h diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index 82674faf5f..0000000000 --- a/src/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -bin_PROGRAMS = gst-rtsp-server - -gst_rtsp_server_SOURCES = main.c \ - rtsp-server.c \ - rtsp-client.c \ - rtsp-media.c \ - rtsp-session-pool.c \ - rtsp-session.c - -gst_rtsp_server_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) -gst_rtsp_server_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ - -lgstsdp-@GST_MAJORMINOR@ $(GST_LIBS) $(LIBM) -gst_rtsp_server_LDFLAGS = $(GST_PLUGIN_LDFLAGS) - -noinst_HEADERS = rtsp-server.h \ - rtsp-client.h \ - rtsp-session.h \ - rtsp-session-pool.h \ - rtsp-media.h From 55bdc67e49d3c459a21f7177e151b1d48ba0c054 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 8 Jan 2009 13:41:33 +0100 Subject: [PATCH 0009/1776] Added port property to GstRTSPServer class. --- gst/rtsp-server/rtsp-server.c | 50 ++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 524275275a..1c6d3ea983 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -24,15 +24,33 @@ #define TCP_BACKLOG 5 #define DEFAULT_PORT 1554 +enum +{ + ARG_0, + PROP_PORT +}; G_DEFINE_TYPE (GstRTSPServer, gst_rtsp_server, G_TYPE_OBJECT); +static void gst_rtsp_server_get_property (GObject *object, guint propid, + GValue *value, GParamSpec *pspec); +static void gst_rtsp_server_set_property (GObject *object, guint propid, + const GValue *value, GParamSpec *pspec); + static void gst_rtsp_server_class_init (GstRTSPServerClass * klass) -{ +{ GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->get_property = gst_rtsp_server_get_property; + gobject_class->set_property = gst_rtsp_server_set_property; + + g_object_class_install_property (gobject_class, PROP_PORT, + g_param_spec_int ("port", "Port", "The port the server uses", + 1, 65535, DEFAULT_PORT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void @@ -57,6 +75,36 @@ gst_rtsp_server_new (void) return result; } +static void +gst_rtsp_server_get_property (GObject *object, guint propid, + GValue *value, GParamSpec *pspec) +{ + GstRTSPServer *server = GST_RTSP_SERVER (object); + + switch (propid) { + case PROP_PORT: + g_value_set_int (value, server->server_port); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static void +gst_rtsp_server_set_property (GObject *object, guint propid, + const GValue *value, GParamSpec *pspec) +{ + GstRTSPServer *server = GST_RTSP_SERVER (object); + + switch (propid) { + case PROP_PORT: + server->server_port = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + static gboolean gst_rtsp_server_sink_init_send (GstRTSPServer * server) { From 36fb0de01c4f954f4f56751de8899643ac4e027b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 8 Jan 2009 13:51:26 +0100 Subject: [PATCH 0010/1776] Fix some issues to pass distcheck --- examples/Makefile.am | 2 ++ gst/rtsp-server/Makefile.am | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/examples/Makefile.am b/examples/Makefile.am index f5b20c4555..c25b521db5 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,6 +1,8 @@ noinst_PROGRAMS = gst-rtsp-server +INCLUDES = -I$(top_srcdir) -I$(srcdir) + gst_rtsp_server_SOURCES = \ main.c diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 752b55b564..7ae11756b2 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -9,6 +9,10 @@ c_sources = \ rtsp-media.c \ rtsp-session-pool.c \ rtsp-session.c + +noinst_HEADERS = \ + rtsp-session-pool.h \ + rtsp-session.h lib_LTLIBRARIES = \ libgstrtspserver.la From a8400faeab513157c3e2140d93166239431308ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Thu, 13 Nov 2008 19:43:10 +0100 Subject: [PATCH 0011/1776] Put GStreamer version in library name --- examples/Makefile.am | 2 +- gst/rtsp-server/Makefile.am | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/Makefile.am b/examples/Makefile.am index c25b521db5..062f595579 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -9,5 +9,5 @@ gst_rtsp_server_SOURCES = \ gst_rtsp_server_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) gst_rtsp_server_LDFLAGS = \ $(GST_LIBS) \ - $(top_builddir)/gst/rtsp-server/libgstrtspserver.la + $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_MAJORMINOR@.la diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 7ae11756b2..8547149517 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -15,18 +15,18 @@ noinst_HEADERS = \ rtsp-session.h lib_LTLIBRARIES = \ - libgstrtspserver.la + libgstrtspserver-@GST_MAJORMINOR@.la -libgstrtspserver_la_SOURCES = \ +libgstrtspserver_@GST_MAJORMINOR@_la_SOURCES = \ $(c_sources) -libgstrtspserver_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) -libgstrtspserver_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstrtspserver_la_LIBADD = \ +libgstrtspserver_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstrtspserver_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstrtspserver_@GST_MAJORMINOR@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ -lgstsdp-@GST_MAJORMINOR@ $(GST_LIBS) $(LIBM) -libgstrtspserver_la_LIBTOOLFLAGS = --tag=disable-static +libgstrtspserver_@GST_MAJORMINOR@_la_LIBTOOLFLAGS = --tag=disable-static -libgstrtspserver_includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/rtsp-server -libgstrtspserver_include_HEADERS = $(public_headers) +libgstrtspserver_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/rtsp-server +libgstrtspserver_@GST_MAJORMINOR@include_HEADERS = $(public_headers) From 51775b87d1d4d1cfdc9fe96c4549dbf899a070ae Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Sat, 25 Oct 2008 23:36:16 +0200 Subject: [PATCH 0012/1776] Change an obviously wrong return FALSE to return NULL; (cherry picked from commit 56d4fb48030db3ae45f3f0e60b29b36f3134322b) --- gst/rtsp-server/rtsp-session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 05ca1f3ede..6eddd12272 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -144,7 +144,7 @@ gst_rtsp_session_get_media (GstRTSPSession *sess, GstRTSPMedia *media) no_media: { gst_rtsp_session_free_media (result); - return FALSE; + return NULL; } } From ce20c2ff8c0d1e15b861fbc9bb43681d5d283344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Sun, 30 Nov 2008 23:41:20 +0100 Subject: [PATCH 0013/1776] Added Vala bindings --- bindings/vala/gst-rtsp-server.vapi | 113 ++++++++++ bindings/vala/packages/gst-rtsp-server.deps | 4 + bindings/vala/packages/gst-rtsp-server.files | 2 + bindings/vala/packages/gst-rtsp-server.gi | 213 ++++++++++++++++++ .../vala/packages/gst-rtsp-server.metadata | 5 + .../vala/packages/gst-rtsp-server.namespace | 1 + 6 files changed, 338 insertions(+) create mode 100644 bindings/vala/gst-rtsp-server.vapi create mode 100644 bindings/vala/packages/gst-rtsp-server.deps create mode 100644 bindings/vala/packages/gst-rtsp-server.files create mode 100644 bindings/vala/packages/gst-rtsp-server.gi create mode 100644 bindings/vala/packages/gst-rtsp-server.metadata create mode 100644 bindings/vala/packages/gst-rtsp-server.namespace diff --git a/bindings/vala/gst-rtsp-server.vapi b/bindings/vala/gst-rtsp-server.vapi new file mode 100644 index 0000000000..744b1d5928 --- /dev/null +++ b/bindings/vala/gst-rtsp-server.vapi @@ -0,0 +1,113 @@ +/* gst-rtsp-server.vapi generated by vapigen, do not modify. */ + +[CCode (cprefix = "Gst", lower_case_cprefix = "gst_")] +namespace Gst { + [CCode (cheader_filename = "gst/rtsp-server/rstp-client.h")] + public class RTSPClient : GLib.Object { + public void* address; + public weak Gst.RTSPConnection connection; + public weak Gst.RTSPMedia media; + public weak Gst.RTSPSessionPool pool; + public weak Gst.RTSPSession session; + public weak GLib.Thread thread; + public bool accept (GLib.IOChannel source); + public weak Gst.RTSPSessionPool get_session_pool (); + [CCode (has_construct_function = false)] + public RTSPClient (Gst.RTSPServer server); + public void set_session_pool (Gst.RTSPSessionPool pool); + [NoAccessorMethod] + public Gst.RTSPServer server { get; construct; } + } + [CCode (cheader_filename = "gst/rtsp-server/rstp-media.h")] + public class RTSPMedia : GLib.Object { + public bool prepared; + public weak GLib.Array streams; + public weak Gst.RTSPMediaStream get_stream (uint idx); + public uint n_streams (); + [CCode (has_construct_function = false)] + public RTSPMedia (string name); + [NoAccessorMethod] + public string location { get; construct; } + [NoAccessorMethod] + public Gst.RTSPUrl url { get; construct; } + } + [Compact] + [CCode (cheader_filename = "gst/rtsp-server/rstp-media.h")] + public class RTSPMediaStream { + public weak Gst.Caps caps; + public ulong caps_sig; + public weak Gst.Element element; + public uint idx; + public weak Gst.RTSPMedia media; + public weak string name; + public weak Gst.Element payloader; + public weak Gst.Pad srcpad; + } + [CCode (cheader_filename = "gst/rtsp-server/rstp-server.h")] + public class RTSPServer : Gst.Object { + public weak string host; + public weak GLib.IOChannel io_channel; + public weak GLib.TimeoutSource io_watch; + public weak Gst.RTSPSessionPool pool; + public int server_port; + public void* server_sin; + public weak Gst.PollFD server_sock; + public uint attach (GLib.MainContext context); + public virtual weak Gst.Element prepare_media (Gst.RTSPMedia media, Gst.Bin bin); + [NoAccessorMethod] + public int port { get; construct; } + } + [CCode (cheader_filename = "gst/gst.h")] + public class RTSPSession : GLib.Object { + public weak GLib.List medias; + public weak string sessionid; + public weak Gst.RTSPSessionMedia get_media (Gst.RTSPMedia media); + public static weak Gst.RTSPSessionStream get_stream (Gst.RTSPSessionMedia media, uint idx); + [CCode (has_construct_function = false)] + public RTSPSession (string sessionid); + } + [Compact] + [CCode (cheader_filename = "gst/gst.h")] + public class RTSPSessionMedia { + public weak Gst.Element fdsink; + public weak Gst.RTSPMedia media; + public weak Gst.Element pipeline; + public weak Gst.Element rtpbin; + public weak Gst.RTSPSession session; + public weak GLib.List streams; + public Gst.StateChangeReturn pause (); + public Gst.StateChangeReturn play (); + public Gst.StateChangeReturn stop (); + } + [CCode (cheader_filename = "gst/gst.h")] + public class RTSPSessionPool : GLib.Object { + public weak GLib.Mutex @lock; + public weak GLib.HashTable sessions; + public weak Gst.RTSPSession create (); + public weak Gst.RTSPSession find (string sessionid); + [CCode (has_construct_function = false)] + public RTSPSessionPool (); + public void remove (Gst.RTSPSession sess); + } + [Compact] + [CCode (cheader_filename = "gst/gst.h")] + public class RTSPSessionStream { + public weak Gst.RTSPTransport client_trans; + public weak string destination; + public uint idx; + public weak Gst.RTSPSessionMedia media; + public weak Gst.RTSPMediaStream media_stream; + public weak Gst.Pad recv_rtcp_sink; + public weak Gst.Pad send_rtcp_src; + public weak Gst.Pad send_rtp_sink; + public weak Gst.Pad send_rtp_src; + public weak Gst.RTSPTransport server_trans; + [NoArrayLength] + public weak Gst.Element[] udpsink; + [NoArrayLength] + public weak Gst.Element[] udpsrc; + public weak Gst.RTSPTransport set_transport (string destination, Gst.RTSPTransport ct); + } + [CCode (cheader_filename = "gst/gst.h")] + public const int HAVE_RTSP_URL_BOXED; +} diff --git a/bindings/vala/packages/gst-rtsp-server.deps b/bindings/vala/packages/gst-rtsp-server.deps new file mode 100644 index 0000000000..c8d8ea9d63 --- /dev/null +++ b/bindings/vala/packages/gst-rtsp-server.deps @@ -0,0 +1,4 @@ +gstreamer-0.10 +gstreamer-sdp-0.10 +gstreamer-rtsp-0.10 +gmodule-2.0 diff --git a/bindings/vala/packages/gst-rtsp-server.files b/bindings/vala/packages/gst-rtsp-server.files new file mode 100644 index 0000000000..f7e4d23730 --- /dev/null +++ b/bindings/vala/packages/gst-rtsp-server.files @@ -0,0 +1,2 @@ +include/gstreamer-0.10/gst/rtsp-server +lib/libgstrtspserver-0.10.so diff --git a/bindings/vala/packages/gst-rtsp-server.gi b/bindings/vala/packages/gst-rtsp-server.gi new file mode 100644 index 0000000000..cd1427092e --- /dev/null +++ b/bindings/vala/packages/gst-rtsp-server.gi @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/vala/packages/gst-rtsp-server.metadata b/bindings/vala/packages/gst-rtsp-server.metadata new file mode 100644 index 0000000000..1381c63db3 --- /dev/null +++ b/bindings/vala/packages/gst-rtsp-server.metadata @@ -0,0 +1,5 @@ +Gst cprefix="Gst" lower_case_cprefix="gst_" cheader_filename="gst/gst.h" +GstRTSPMediaStream cheader_filename="gst/rtsp-server/rstp-media.h" +GstRTSPMedia cheader_filename="gst/rtsp-server/rstp-media.h" +GstRTSPClient cheader_filename="gst/rtsp-server/rstp-client.h" +GstRTSPServer cheader_filename="gst/rtsp-server/rstp-server.h" diff --git a/bindings/vala/packages/gst-rtsp-server.namespace b/bindings/vala/packages/gst-rtsp-server.namespace new file mode 100644 index 0000000000..100750e4d7 --- /dev/null +++ b/bindings/vala/packages/gst-rtsp-server.namespace @@ -0,0 +1 @@ +Gst From eb68a892a6726838fcd5b448e60e55b4fd8777d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Sun, 30 Nov 2008 23:57:26 +0100 Subject: [PATCH 0014/1776] Adjusted included headersfor Vala bindings. Ignore rtsp-url-compat.h --- bindings/vala/gst-rtsp-server.vapi | 10 ++++------ bindings/vala/packages/gst-rtsp-server.excludes | 1 + bindings/vala/packages/gst-rtsp-server.gi | 3 --- bindings/vala/packages/gst-rtsp-server.metadata | 4 ++++ 4 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 bindings/vala/packages/gst-rtsp-server.excludes diff --git a/bindings/vala/gst-rtsp-server.vapi b/bindings/vala/gst-rtsp-server.vapi index 744b1d5928..90c85d21e9 100644 --- a/bindings/vala/gst-rtsp-server.vapi +++ b/bindings/vala/gst-rtsp-server.vapi @@ -57,7 +57,7 @@ namespace Gst { [NoAccessorMethod] public int port { get; construct; } } - [CCode (cheader_filename = "gst/gst.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] public class RTSPSession : GLib.Object { public weak GLib.List medias; public weak string sessionid; @@ -67,7 +67,7 @@ namespace Gst { public RTSPSession (string sessionid); } [Compact] - [CCode (cheader_filename = "gst/gst.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] public class RTSPSessionMedia { public weak Gst.Element fdsink; public weak Gst.RTSPMedia media; @@ -79,7 +79,7 @@ namespace Gst { public Gst.StateChangeReturn play (); public Gst.StateChangeReturn stop (); } - [CCode (cheader_filename = "gst/gst.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] public class RTSPSessionPool : GLib.Object { public weak GLib.Mutex @lock; public weak GLib.HashTable sessions; @@ -90,7 +90,7 @@ namespace Gst { public void remove (Gst.RTSPSession sess); } [Compact] - [CCode (cheader_filename = "gst/gst.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-session-pool.h")] public class RTSPSessionStream { public weak Gst.RTSPTransport client_trans; public weak string destination; @@ -108,6 +108,4 @@ namespace Gst { public weak Gst.Element[] udpsrc; public weak Gst.RTSPTransport set_transport (string destination, Gst.RTSPTransport ct); } - [CCode (cheader_filename = "gst/gst.h")] - public const int HAVE_RTSP_URL_BOXED; } diff --git a/bindings/vala/packages/gst-rtsp-server.excludes b/bindings/vala/packages/gst-rtsp-server.excludes new file mode 100644 index 0000000000..4d93f3b112 --- /dev/null +++ b/bindings/vala/packages/gst-rtsp-server.excludes @@ -0,0 +1 @@ +rtsp-url-compat.h diff --git a/bindings/vala/packages/gst-rtsp-server.gi b/bindings/vala/packages/gst-rtsp-server.gi index cd1427092e..2886d60c28 100644 --- a/bindings/vala/packages/gst-rtsp-server.gi +++ b/bindings/vala/packages/gst-rtsp-server.gi @@ -59,8 +59,6 @@ - - @@ -208,6 +206,5 @@ - diff --git a/bindings/vala/packages/gst-rtsp-server.metadata b/bindings/vala/packages/gst-rtsp-server.metadata index 1381c63db3..35cf4aabe9 100644 --- a/bindings/vala/packages/gst-rtsp-server.metadata +++ b/bindings/vala/packages/gst-rtsp-server.metadata @@ -3,3 +3,7 @@ GstRTSPMediaStream cheader_filename="gst/rtsp-server/rstp-media.h" GstRTSPMedia cheader_filename="gst/rtsp-server/rstp-media.h" GstRTSPClient cheader_filename="gst/rtsp-server/rstp-client.h" GstRTSPServer cheader_filename="gst/rtsp-server/rstp-server.h" +GstRTSPSession cheader_filename="gst/rtsp-server/rtsp-session.h" +GstRTSPSessionMedia cheader_filename="gst/rtsp-server/rtsp-session.h" +GstRTSPSessionPool cheader_filename="gst/rtsp-server/rtsp-session.h" +GstRTSPSessionStream cheader_filename="gst/rtsp-server/rtsp-session-pool.h" From 26745cdbf5e472fd12af97849f73f789ebfb273f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 8 Jan 2009 14:42:10 +0100 Subject: [PATCH 0015/1776] Added pkgconfig file --- Makefile.am | 1 + configure.ac | 5 +++++ pkgconfig/Makefile.am | 14 ++++++++++++++ pkgconfig/gst-rtsp-server.pc.in | 11 +++++++++++ 4 files changed, 31 insertions(+) create mode 100644 pkgconfig/Makefile.am create mode 100644 pkgconfig/gst-rtsp-server.pc.in diff --git a/Makefile.am b/Makefile.am index 0e57eb3b53..28d22999f2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,7 @@ SUBDIRS = \ gst \ m4 \ common \ + pkgconfig \ examples DIST_SUBDIRS = $(SUBDIRS) diff --git a/configure.ac b/configure.ac index 8d281d37b0..16126369fb 100644 --- a/configure.ac +++ b/configure.ac @@ -218,6 +218,11 @@ m4/Makefile gst/Makefile gst/rtsp-server/Makefile examples/Makefile +bindings/Makefile +bindings/python/Makefile +bindings/python/codegen/Makefile +pkgconfig/Makefile +pkgconfig/gst-rtsp-server.pc ]) AC_OUTPUT diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am new file mode 100644 index 0000000000..310dc8a3d2 --- /dev/null +++ b/pkgconfig/Makefile.am @@ -0,0 +1,14 @@ +pcfiles = \ + gst-rtsp-server-@GST_MAJORMINOR@.pc + +all-local: $(pcfiles) + +### how to generate pc files +%-@GST_MAJORMINOR@.pc: %.pc + cp $< $@ + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = $(pcfiles) + +EXTRA_DIST = gst-rtsp-server.pc.in +CLEANFILES = $(pcfiles) diff --git a/pkgconfig/gst-rtsp-server.pc.in b/pkgconfig/gst-rtsp-server.pc.in new file mode 100644 index 0000000000..ada1a15f8b --- /dev/null +++ b/pkgconfig/gst-rtsp-server.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gstreamer-@GST_MAJORMINOR@ + +Name: gst-rtsp-server +Description: GStreamer based RTSP server +Version: 0.10.1 +Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@ +Libs: -L${libdir} -lgstrtspserver-@GST_MAJORMINOR@ +Cflags: -I${includedir} From 469539530250c53ecf9a24f044e2ad8a25176b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Mon, 8 Dec 2008 13:19:40 +0100 Subject: [PATCH 0016/1776] Fixed typo in included headers for vala bindings --- bindings/vala/gst-rtsp-server.vapi | 6 +++--- bindings/vala/packages/gst-rtsp-server.metadata | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bindings/vala/gst-rtsp-server.vapi b/bindings/vala/gst-rtsp-server.vapi index 90c85d21e9..8c16997e78 100644 --- a/bindings/vala/gst-rtsp-server.vapi +++ b/bindings/vala/gst-rtsp-server.vapi @@ -2,7 +2,7 @@ [CCode (cprefix = "Gst", lower_case_cprefix = "gst_")] namespace Gst { - [CCode (cheader_filename = "gst/rtsp-server/rstp-client.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-client.h")] public class RTSPClient : GLib.Object { public void* address; public weak Gst.RTSPConnection connection; @@ -18,7 +18,7 @@ namespace Gst { [NoAccessorMethod] public Gst.RTSPServer server { get; construct; } } - [CCode (cheader_filename = "gst/rtsp-server/rstp-media.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] public class RTSPMedia : GLib.Object { public bool prepared; public weak GLib.Array streams; @@ -43,7 +43,7 @@ namespace Gst { public weak Gst.Element payloader; public weak Gst.Pad srcpad; } - [CCode (cheader_filename = "gst/rtsp-server/rstp-server.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-server.h")] public class RTSPServer : Gst.Object { public weak string host; public weak GLib.IOChannel io_channel; diff --git a/bindings/vala/packages/gst-rtsp-server.metadata b/bindings/vala/packages/gst-rtsp-server.metadata index 35cf4aabe9..adcd1e70c7 100644 --- a/bindings/vala/packages/gst-rtsp-server.metadata +++ b/bindings/vala/packages/gst-rtsp-server.metadata @@ -1,8 +1,8 @@ Gst cprefix="Gst" lower_case_cprefix="gst_" cheader_filename="gst/gst.h" GstRTSPMediaStream cheader_filename="gst/rtsp-server/rstp-media.h" -GstRTSPMedia cheader_filename="gst/rtsp-server/rstp-media.h" -GstRTSPClient cheader_filename="gst/rtsp-server/rstp-client.h" -GstRTSPServer cheader_filename="gst/rtsp-server/rstp-server.h" +GstRTSPMedia cheader_filename="gst/rtsp-server/rtsp-media.h" +GstRTSPClient cheader_filename="gst/rtsp-server/rtsp-client.h" +GstRTSPServer cheader_filename="gst/rtsp-server/rtsp-server.h" GstRTSPSession cheader_filename="gst/rtsp-server/rtsp-session.h" GstRTSPSessionMedia cheader_filename="gst/rtsp-server/rtsp-session.h" GstRTSPSessionPool cheader_filename="gst/rtsp-server/rtsp-session.h" From 60f1b91f1dc9e46552e11549e66650d3b6258b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Fri, 12 Dec 2008 16:22:02 +0100 Subject: [PATCH 0017/1776] Regenerated Vala bindings --- .../gst-rtsp-server.deps => gst-rtsp-server-0.10.deps} | 0 .../vala/{gst-rtsp-server.vapi => gst-rtsp-server-0.10.vapi} | 3 +-- bindings/vala/packages/gst-rtsp-server-0.10.deps | 4 ++++ ...gst-rtsp-server.excludes => gst-rtsp-server-0.10.excludes} | 0 .../{gst-rtsp-server.files => gst-rtsp-server-0.10.files} | 0 .../packages/{gst-rtsp-server.gi => gst-rtsp-server-0.10.gi} | 1 - ...gst-rtsp-server.metadata => gst-rtsp-server-0.10.metadata} | 0 ...t-rtsp-server.namespace => gst-rtsp-server-0.10.namespace} | 0 8 files changed, 5 insertions(+), 3 deletions(-) rename bindings/vala/{packages/gst-rtsp-server.deps => gst-rtsp-server-0.10.deps} (100%) rename bindings/vala/{gst-rtsp-server.vapi => gst-rtsp-server-0.10.vapi} (97%) create mode 100644 bindings/vala/packages/gst-rtsp-server-0.10.deps rename bindings/vala/packages/{gst-rtsp-server.excludes => gst-rtsp-server-0.10.excludes} (100%) rename bindings/vala/packages/{gst-rtsp-server.files => gst-rtsp-server-0.10.files} (100%) rename bindings/vala/packages/{gst-rtsp-server.gi => gst-rtsp-server-0.10.gi} (99%) rename bindings/vala/packages/{gst-rtsp-server.metadata => gst-rtsp-server-0.10.metadata} (100%) rename bindings/vala/packages/{gst-rtsp-server.namespace => gst-rtsp-server-0.10.namespace} (100%) diff --git a/bindings/vala/packages/gst-rtsp-server.deps b/bindings/vala/gst-rtsp-server-0.10.deps similarity index 100% rename from bindings/vala/packages/gst-rtsp-server.deps rename to bindings/vala/gst-rtsp-server-0.10.deps diff --git a/bindings/vala/gst-rtsp-server.vapi b/bindings/vala/gst-rtsp-server-0.10.vapi similarity index 97% rename from bindings/vala/gst-rtsp-server.vapi rename to bindings/vala/gst-rtsp-server-0.10.vapi index 8c16997e78..c9652c5561 100644 --- a/bindings/vala/gst-rtsp-server.vapi +++ b/bindings/vala/gst-rtsp-server-0.10.vapi @@ -1,4 +1,4 @@ -/* gst-rtsp-server.vapi generated by vapigen, do not modify. */ +/* gst-rtsp-server-0.10.vapi generated by vapigen, do not modify. */ [CCode (cprefix = "Gst", lower_case_cprefix = "gst_")] namespace Gst { @@ -8,7 +8,6 @@ namespace Gst { public weak Gst.RTSPConnection connection; public weak Gst.RTSPMedia media; public weak Gst.RTSPSessionPool pool; - public weak Gst.RTSPSession session; public weak GLib.Thread thread; public bool accept (GLib.IOChannel source); public weak Gst.RTSPSessionPool get_session_pool (); diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.deps b/bindings/vala/packages/gst-rtsp-server-0.10.deps new file mode 100644 index 0000000000..c8d8ea9d63 --- /dev/null +++ b/bindings/vala/packages/gst-rtsp-server-0.10.deps @@ -0,0 +1,4 @@ +gstreamer-0.10 +gstreamer-sdp-0.10 +gstreamer-rtsp-0.10 +gmodule-2.0 diff --git a/bindings/vala/packages/gst-rtsp-server.excludes b/bindings/vala/packages/gst-rtsp-server-0.10.excludes similarity index 100% rename from bindings/vala/packages/gst-rtsp-server.excludes rename to bindings/vala/packages/gst-rtsp-server-0.10.excludes diff --git a/bindings/vala/packages/gst-rtsp-server.files b/bindings/vala/packages/gst-rtsp-server-0.10.files similarity index 100% rename from bindings/vala/packages/gst-rtsp-server.files rename to bindings/vala/packages/gst-rtsp-server-0.10.files diff --git a/bindings/vala/packages/gst-rtsp-server.gi b/bindings/vala/packages/gst-rtsp-server-0.10.gi similarity index 99% rename from bindings/vala/packages/gst-rtsp-server.gi rename to bindings/vala/packages/gst-rtsp-server-0.10.gi index 2886d60c28..b9257179a0 100644 --- a/bindings/vala/packages/gst-rtsp-server.gi +++ b/bindings/vala/packages/gst-rtsp-server-0.10.gi @@ -92,7 +92,6 @@ - diff --git a/bindings/vala/packages/gst-rtsp-server.metadata b/bindings/vala/packages/gst-rtsp-server-0.10.metadata similarity index 100% rename from bindings/vala/packages/gst-rtsp-server.metadata rename to bindings/vala/packages/gst-rtsp-server-0.10.metadata diff --git a/bindings/vala/packages/gst-rtsp-server.namespace b/bindings/vala/packages/gst-rtsp-server-0.10.namespace similarity index 100% rename from bindings/vala/packages/gst-rtsp-server.namespace rename to bindings/vala/packages/gst-rtsp-server-0.10.namespace From 628fa854f0e8d7a5ce6b8b03260001b40d84df27 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 8 Jan 2009 14:49:57 +0100 Subject: [PATCH 0018/1776] Install Vala bindings if vala is available --- bindings/Makefile.am | 5 +++++ bindings/vala/Makefile.am | 9 +++++++++ configure.ac | 33 ++++++++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 bindings/Makefile.am create mode 100644 bindings/vala/Makefile.am diff --git a/bindings/Makefile.am b/bindings/Makefile.am new file mode 100644 index 0000000000..7a9ca5ad71 --- /dev/null +++ b/bindings/Makefile.am @@ -0,0 +1,5 @@ +SUBDIRS = + +if WITH_VALA + SUBDIRS += vala +endif diff --git a/bindings/vala/Makefile.am b/bindings/vala/Makefile.am new file mode 100644 index 0000000000..cd80cd4211 --- /dev/null +++ b/bindings/vala/Makefile.am @@ -0,0 +1,9 @@ + +VAPI_FILES = gst-rtsp-server-0.10.deps +DEPS_FILES = gst-rtsp-server-0.10.vapi + +gst-rtsp-server-0.10.deps: + cp packages/gst-rtsp-server-0.10.deps $@ + +vapidir = $(VAPIDIR) +vapi_DATA = $(VAPI_FILES) $(DEPS_FILES) diff --git a/configure.ac b/configure.ac index 16126369fb..cd78495957 100644 --- a/configure.ac +++ b/configure.ac @@ -81,6 +81,24 @@ HAVE_GTK=NO PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.8.0, HAVE_GTK=yes, HAVE_GTK=no) AM_CONDITIONAL(HAVE_GTK, test "x$HAVE_GTK" = "xyes") +dnl Check for vala +PKG_CHECK_EXISTS([vala-1.0], [HAVE_VALA="yes"], [HAVE_VALA="no"]) + +AM_CONDITIONAL(WITH_VALA, [test "x$HAVE_VALA" = "xyes"]) + +AC_ARG_WITH([vapidir], + AS_HELP_STRING([--with-vapidir], [Define where to install the VAPI files])) + +if test "x$HAVE_VALA" = "xyes"; then + if test "x$with_vapidir" = "x"; then + VAPIDIR="`pkg-config --variable vapidir vala-1.0`" + else + VAPIDIR="$with_vapidir" + fi +fi +AC_SUBST(VAPIDIR) + + dnl *** checks for libraries *** dnl *** checks for header files *** @@ -219,11 +237,20 @@ gst/Makefile gst/rtsp-server/Makefile examples/Makefile bindings/Makefile -bindings/python/Makefile -bindings/python/codegen/Makefile +bindings/vala/Makefile pkgconfig/Makefile pkgconfig/gst-rtsp-server.pc ]) AC_OUTPUT -echo "Gst-rtsp-server configured. Type 'make' to build." +echo " + +Configuration + Version : ${VERSION} + Source code location : ${srcdir} + Prefix : ${prefix} + Compiler : ${CC} + Vala bindings : ${HAVE_VALA} + +Gst-rtsp-server configured. Type 'make' to build. +" From 7bab61a10b13293725fbc28f28de6d07f2edbea0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 8 Jan 2009 14:53:47 +0100 Subject: [PATCH 0019/1776] Don't go into python dir when requirements for python bindings are missing --- bindings/Makefile.am | 4 ++++ configure.ac | 38 ++++++++++++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/bindings/Makefile.am b/bindings/Makefile.am index 7a9ca5ad71..b193731205 100644 --- a/bindings/Makefile.am +++ b/bindings/Makefile.am @@ -1,5 +1,9 @@ SUBDIRS = +if WITH_PYTHON + SUBDIRS += python +endif + if WITH_VALA SUBDIRS += vala endif diff --git a/configure.ac b/configure.ac index cd78495957..2f56d381ea 100644 --- a/configure.ac +++ b/configure.ac @@ -76,10 +76,40 @@ dnl check for documentation tools AG_GST_DOCBOOK_CHECK GTK_DOC_CHECK([1.3]) -dnl GTK is optional and used in examples -HAVE_GTK=NO -PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.8.0, HAVE_GTK=yes, HAVE_GTK=no) -AM_CONDITIONAL(HAVE_GTK, test "x$HAVE_GTK" = "xyes") +AC_SUBST(PYGOBJECT_REQ, 2.11.2) + +dnl check for pygobject (optional, used in the bindings) +PKG_CHECK_MODULES(PYGOBJECT, pygobject-2.0 >= $PYGOBJECT_REQ, + [ + HAVE_PYGOBJECT="yes" + ], + [ + HAVE_PYGOBJECT="no" + ]) +AC_SUBST(PYGOBJECT_CFLAGS) + +dnl check for gst-python +PKG_CHECK_MODULES(PYGST, gst-python-0.10, + [ + HAVE_PYGST="yes" + ], + [ + HAVE_PYGST="no" + ]) + +if test "x$HAVE_PYGST" = "xyes"; then + PYGST_DEFSDIR=`pkg-config gst-python-0.10 --variable=defsdir` +fi +AC_SUBST(PYGST_DEFSDIR, $PYGST_DEFSDIR) + +if test "x$HAVE_PYTHON_HEADERS" = "xyes" -a \ + "x$HAVE_PYGOBJECT" = "xyes" -a \ + "x$HAVE_PYGST" = "xyes"; then + HAVE_PYTHON_BINDINGS="yes" +else + HAVE_PYTHON_BINDINGS="no" +fi +AM_CONDITIONAL(WITH_PYTHON, [test "x$HAVE_PYTHON_BINDINGS" = "xyes"]) dnl Check for vala PKG_CHECK_EXISTS([vala-1.0], [HAVE_VALA="yes"], [HAVE_VALA="no"]) From 3f7bd9202269e6ae18f5f22b69175a1fce2f5bac Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 8 Jan 2009 14:57:55 +0100 Subject: [PATCH 0020/1776] Add python bindings. --- .gitignore | 3 + Makefile.am | 1 + acinclude.m4 | 66 + bindings/python/Makefile.am | 45 + bindings/python/arg-types.py | 376 +++++ bindings/python/codegen/Makefile.am | 15 + bindings/python/codegen/__init__.py | 15 + bindings/python/codegen/argtypes.py | 1075 +++++++++++++ bindings/python/codegen/code-coverage.py | 42 + bindings/python/codegen/codegen.py | 1572 +++++++++++++++++++ bindings/python/codegen/definitions.py | 607 +++++++ bindings/python/codegen/defsparser.py | 143 ++ bindings/python/codegen/docextract.py | 185 +++ bindings/python/codegen/docgen.py | 752 +++++++++ bindings/python/codegen/fileprefix.override | 12 + bindings/python/codegen/fileprefixmodule.c | 31 + bindings/python/codegen/h2def.py | 536 +++++++ bindings/python/codegen/mergedefs.py | 26 + bindings/python/codegen/mkskel.py | 89 ++ bindings/python/codegen/override.py | 288 ++++ bindings/python/codegen/reversewrapper.py | 771 +++++++++ bindings/python/codegen/scmexpr.py | 144 ++ bindings/python/rtspserver-types.defs | 6 + bindings/python/rtspserver.defs | 16 + bindings/python/rtspserver.override | 52 + bindings/python/rtspservermodule.c | 31 + configure.ac | 10 +- 27 files changed, 6908 insertions(+), 1 deletion(-) create mode 100644 acinclude.m4 create mode 100644 bindings/python/Makefile.am create mode 100644 bindings/python/arg-types.py create mode 100644 bindings/python/codegen/Makefile.am create mode 100644 bindings/python/codegen/__init__.py create mode 100644 bindings/python/codegen/argtypes.py create mode 100755 bindings/python/codegen/code-coverage.py create mode 100644 bindings/python/codegen/codegen.py create mode 100644 bindings/python/codegen/definitions.py create mode 100644 bindings/python/codegen/defsparser.py create mode 100644 bindings/python/codegen/docextract.py create mode 100644 bindings/python/codegen/docgen.py create mode 100644 bindings/python/codegen/fileprefix.override create mode 100644 bindings/python/codegen/fileprefixmodule.c create mode 100755 bindings/python/codegen/h2def.py create mode 100755 bindings/python/codegen/mergedefs.py create mode 100755 bindings/python/codegen/mkskel.py create mode 100644 bindings/python/codegen/override.py create mode 100644 bindings/python/codegen/reversewrapper.py create mode 100644 bindings/python/codegen/scmexpr.py create mode 100644 bindings/python/rtspserver-types.defs create mode 100644 bindings/python/rtspserver.defs create mode 100644 bindings/python/rtspserver.override create mode 100644 bindings/python/rtspservermodule.c diff --git a/.gitignore b/.gitignore index 03cd96b64e..cb3b21fe51 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.[oa] +*.pyc *.gcda *.gcno *.la @@ -28,3 +29,5 @@ libtool ltmain.sh missing stamp-h1 +bindings/python/rtspserver.c +tags diff --git a/Makefile.am b/Makefile.am index 28d22999f2..6936b37fec 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,6 +2,7 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc SUBDIRS = \ gst \ + bindings \ m4 \ common \ pkgconfig \ diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000000..04a283be5d --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,66 @@ +## this one is commonly used with AM_PATH_PYTHONDIR ... +dnl AM_CHECK_PYMOD(MODNAME [,SYMBOL [,ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]]]) +dnl Check if a module containing a given symbol is visible to python. +AC_DEFUN([AM_CHECK_PYMOD], +[AC_REQUIRE([AM_PATH_PYTHON]) +py_mod_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'` +AC_MSG_CHECKING(for ifelse([$2],[],,[$2 in ])python module $1) +AC_CACHE_VAL(py_cv_mod_$py_mod_var, [ +ifelse([$2],[], [prog=" +import sys +try: + import $1 +except ImportError: + sys.exit(1) +except: + sys.exit(0) +sys.exit(0)"], [prog=" +import $1 +$1.$2"]) +if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC + then + eval "py_cv_mod_$py_mod_var=yes" + else + eval "py_cv_mod_$py_mod_var=no" + fi +]) +py_val=`eval "echo \`echo '$py_cv_mod_'$py_mod_var\`"` +if test "x$py_val" != xno; then + AC_MSG_RESULT(yes) + ifelse([$3], [],, [$3 +])dnl +else + AC_MSG_RESULT(no) + ifelse([$4], [],, [$4 +])dnl +fi +]) + +dnl a macro to check for ability to create python extensions +dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE]) +dnl function also defines PYTHON_INCLUDES +AC_DEFUN([AM_CHECK_PYTHON_HEADERS], +[AC_REQUIRE([AM_PATH_PYTHON]) +AC_MSG_CHECKING(for headers required to compile python extensions) +dnl deduce PYTHON_INCLUDES +py_prefix=`$PYTHON -c "import sys; print sys.prefix"` +py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` +if $PYTHON-config --help 2>/dev/null; then + PYTHON_INCLUDES=`$PYTHON-config --includes 2>/dev/null` +else + PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" + if test "$py_prefix" != "$py_exec_prefix"; then + PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" + fi +fi +AC_SUBST(PYTHON_INCLUDES) +dnl check if the headers exist: +save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" +AC_TRY_CPP([#include ],dnl +[AC_MSG_RESULT(found) +$1],dnl +[AC_MSG_RESULT(not found) +$2]) +CPPFLAGS="$save_CPPFLAGS" +]) diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am new file mode 100644 index 0000000000..76dcf7ab9f --- /dev/null +++ b/bindings/python/Makefile.am @@ -0,0 +1,45 @@ +SUBDIRS = codegen +pkgpyexecdir = $(pyexecdir)/gst-$(GST_MAJORMINOR)/gst + +# we install everything in pyexecdir; otherwise you end up with a mess for +# multilib +pygstrtspserverdir = $(pkgpyexecdir) +pygstrtspserver_PYTHON = + +pygstrtspserverexecdir = $(pkgpyexecdir) +pygstrtspserverexec_LTLIBRARIES = rtspserver.la + +DEFS = rtspserver-types.defs rtspserver.defs +defs_DATA = $(DEFS) +defsdir = $(pkgdatadir)/$(GST_MAJORMINOR)/defs +OVERRIDES = rtspserver.override + +INCLUDES = $(PYTHON_INCLUDES) + +rtspserver_la_CFLAGS = -I$(top_srcdir)/src \ + $(PYGOBJECT_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +rtspserver_la_LDFLAGS = -export-symbols-regex "^(initrtspserver|_PyGObject_API).*" \ + -module -avoid-version $(GST_PLUGIN_LDFLAGS) +rtspserver_la_LIBADD = $(top_builddir)/src/libgst-rtsp-server.a \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ + -lgstsdp-@GST_MAJORMINOR@ $(GST_LIBS) $(LIBM) +rtspserver_la_SOURCES = rtspservermodule.c +nodist_rtspserver_la_SOURCES = rtspserver.c + +EXTRA_DIST = $(defs_DATA) $(OVERRIDES) arg-types.py + +CLEANFILES = rtspserver.c + +rtspserver.c: $(DEFS) $(OVERRIDES) arg-types.py + +.defs.c: + ($(PYTHON) $(srcdir)/codegen/codegen.py \ + --load-types $(srcdir)/arg-types.py \ + --register $(srcdir)/rtspserver-types.defs \ + --override $(srcdir)/$*.override \ + --extendpath $(top_builddir)/gst/ \ + --extendpath $(srcdir)/ \ + --prefix pygst_rtsp_server $<) > gen-$*.c \ + && cp gen-$*.c $*.c \ + && rm -f gen-$*.c diff --git a/bindings/python/arg-types.py b/bindings/python/arg-types.py new file mode 100644 index 0000000000..1963b9935b --- /dev/null +++ b/bindings/python/arg-types.py @@ -0,0 +1,376 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python +# Copyright (C) 2002 David I. Lehn +# 2004 Johan Dahlin +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Author: David I. Lehn + +from argtypes import UInt64Arg, Int64Arg, PointerArg, ArgMatcher, ArgType, matcher +from reversewrapper import Parameter, ReturnType, GBoxedParam, GBoxedReturn, IntParam, IntReturn + +class XmlNodeArg(ArgType): + """libxml2 node generator""" + + names = {"xobj":"xmlNode", + "xptr":"xmlNodePtr", + "xwrap":"libxml_xmlNodePtrWrap"} + + parm = (' if(xml == NULL) return NULL;\n' + ' xobj = PyObject_GetAttrString(xml, "%(xobj)s");\n' + ' if(!PyObject_IsInstance(py%(name)s, xobj)) {\n' + ' PyErr_Clear();\n' + ' PyErr_SetString(PyExc_RuntimeError,"%(name)s is not a %(xobj)s instance");\n' + ' Py_DECREF(xobj);Py_DECREF(xml);\n' + ' return NULL;\n' + ' }\n' + ' o = PyObject_GetAttrString(py%(name)s, "_o");\n' + ' %(name)s = PyCObject_AsVoidPtr(o);\n') + parmp = (' Py_DECREF(o); Py_DECREF(xobj);Py_DECREF(xml);\n') + + ret = (' if(xml == NULL) return NULL;\n') + retp = (' xargs = PyTuple_New(1);\n' + ' xobj = PyObject_GetAttrString(xml, "%(xobj)s");\n' + ' o = %(xwrap)s(ret);\n' + ' PyTuple_SetItem(xargs, 0, o);\n' + ' return PyInstance_New(xobj, xargs, PyDict_New());\n') + + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + info.varlist.add('PyObject', '*xml = _gst_get_libxml2_module()') + info.varlist.add('PyObject', '*o') + info.varlist.add('PyObject', '*xobj') + info.varlist.add('PyObject', '*py' + pname) + info.varlist.add(self.names["xptr"], pname) + #if pnull: + info.add_parselist('O', ['&py'+pname], [pname]) + info.arglist.append(pname) + self.names["name"] = pname + info.codebefore.append(self.parm % self.names) + info.codeafter.append(self.parmp % self.names); + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('PyObject', '*xml = _gst_get_libxml2_module()') + info.varlist.add('PyObject', '*xargs') + info.varlist.add('PyObject', '*xobj') + info.varlist.add('PyObject', '*o') + info.varlist.add(self.names["xptr"], 'ret') + info.codebefore.append(self.ret % self.names) + info.codeafter.append(self.retp % self.names) + +class XmlDocArg(XmlNodeArg): + """libxml2 doc generator""" + names = {"xobj":"xmlDoc", + "xptr":"xmlDocPtr", + "xwrap":"libxml_xmlDocPtrWrap"} + +class GstCapsArg(ArgType): + """GstCaps node generator""" + + before = (' %(name)s = pygst_caps_from_pyobject (py_%(name)s, %(namecopy)s);\n' + ' if (PyErr_Occurred())\n' + ' return NULL;\n') + beforenull = (' if (py_%(name)s == Py_None || py_%(name)s == NULL)\n' + ' %(name)s = NULL;\n' + ' else\n' + ' ' + before) + after = (' if (%(name)s && %(name)s_is_copy)\n' + ' gst_caps_unref (%(name)s);\n') + + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if ptype == 'const-GstCaps*': + self.write_const_param(pname, pdflt, pnull, info) + elif ptype == 'GstCaps*': + self.write_normal_param(pname, pdflt, pnull, info) + else: + raise RuntimeError, "write_param not implemented for %s" % ptype + + def write_const_param(self, pname, pdflt, pnull, info): + if pdflt: + assert pdflt == 'NULL' + info.varlist.add('PyObject', '*py_' + pname + ' = NULL') + else: + info.varlist.add('PyObject', '*py_' + pname) + info.varlist.add('GstCaps', '*'+pname) + info.varlist.add('gboolean', pname+'_is_copy') + info.add_parselist('O', ['&py_'+pname], [pname]) + info.arglist.append(pname) + if pnull: + info.codebefore.append (self.beforenull % { 'name' : pname, 'namecopy' : '&'+pname+'_is_copy' }) + else: + info.codebefore.append (self.before % { 'name' : pname, 'namecopy' : '&'+pname+'_is_copy' }) + info.codeafter.append (self.after % { 'name' : pname, 'namecopy' : '&'+pname+'_is_copy' }) + + def write_normal_param(self, pname, pdflt, pnull, info): + if pdflt: + assert pdflt == 'NULL' + info.varlist.add('PyObject', '*py_' + pname + ' = NULL') + else: + info.varlist.add('PyObject', '*py_' + pname) + info.varlist.add('GstCaps', '*'+pname) + info.add_parselist('O', ['&py_'+pname], [pname]) + info.arglist.append(pname) + if pnull: + info.codebefore.append (self.beforenull % { 'name' : pname, 'namecopy' : 'NULL' }) + else: + info.codebefore.append (self.before % { 'name' : pname, 'namecopy' : 'NULL' }) + + def write_return(self, ptype, ownsreturn, info): + if ptype == 'GstCaps*': + info.varlist.add('GstCaps', '*ret') + copyval = 'FALSE' + elif ptype == 'const-GstCaps*': + info.varlist.add('const GstCaps', '*ret') + copyval = 'TRUE' + else: + raise RuntimeError, "write_return not implemented for %s" % ptype + info.codeafter.append(' return pyg_boxed_new (GST_TYPE_CAPS, ret, '+copyval+', TRUE);') + +class GstIteratorArg(ArgType): + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('GstIterator', '*ret') + info.codeafter.append(' return pygst_iterator_new(ret);') + +class GstMiniObjectParam(Parameter): + + def get_c_type(self): + return self.props.get('c_type', 'GstMiniObject *') + + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name) + self.wrapper.write_code(code=("if (%s) {\n" + " py_%s = pygstminiobject_new((GstMiniObject *) %s);\n" + " gst_mini_object_unref ((GstMiniObject *) %s);\n" + "} else {\n" + " Py_INCREF(Py_None);\n" + " py_%s = Py_None;\n" + "}" + % (self.name, self.name, self.name, self.name, self.name)), + cleanup=("gst_mini_object_ref ((GstMiniObject *) %s);\nPy_DECREF(py_%s);" % (self.name, self.name))) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +matcher.register_reverse('GstMiniObject*', GstMiniObjectParam) + +class GstMiniObjectReturn(ReturnType): + + def get_c_type(self): + return self.props.get('c_type', 'GstMiniObject *') + + def write_decl(self): + self.wrapper.add_declaration("%s retval;" % self.get_c_type()) + + def write_error_return(self): + self.wrapper.write_code("return NULL;") + + def write_conversion(self): + self.wrapper.write_code("retval = (%s) pygstminiobject_get(py_retval);" + % self.get_c_type()) + self.wrapper.write_code("gst_mini_object_ref((GstMiniObject *) retval);") + +matcher.register_reverse_ret('GstMiniObject*', GstMiniObjectReturn) + +class GstCapsParam(Parameter): + + def get_c_type(self): + return self.props.get('c_type', 'GstCaps *') + + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name) + self.wrapper.write_code(code=("if (%s)\n" + " py_%s = pyg_boxed_new (GST_TYPE_CAPS, %s, FALSE, TRUE);\n" + "else {\n" + " Py_INCREF(Py_None);\n" + " py_%s = Py_None;\n" + "}" + % (self.name, self.name, self.name, self.name)), + cleanup=("gst_caps_ref(%s);\nPy_DECREF(py_%s);" % (self.name, self.name))) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +matcher.register_reverse('GstCaps*', GstCapsParam) + +class GstCapsReturn(ReturnType): + + def get_c_type(self): + return self.props.get('c_type', 'GstCaps *') + + def write_decl(self): + self.wrapper.add_declaration("%s retval;" % self.get_c_type()) + + def write_error_return(self): + self.wrapper.write_code("return NULL;") + + def write_conversion(self): + self.wrapper.write_code("retval = (%s) pygst_caps_from_pyobject (py_retval, NULL);" + % self.get_c_type()) +## self.wrapper.write_code("gst_mini_object_ref((GstMiniObject *) retval);") + +matcher.register_reverse_ret('GstCaps*', GstCapsReturn) + + +class Int64Param(Parameter): + + def get_c_type(self): + return self.props.get('c_type', 'gint64') + + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code(code=("py_%s = PyLong_FromLongLong(%s);" % + (self.name, self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +class Int64Return(ReturnType): + def get_c_type(self): + return self.props.get('c_type', 'gint64') + def write_decl(self): + self.wrapper.add_declaration("%s retval;" % self.get_c_type()) + def write_error_return(self): + self.wrapper.write_code("return -G_MAXINT;") + def write_conversion(self): + self.wrapper.write_code( + code=None, + failure_expression="!PyLong_Check(py_retval)", + failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be an long");') + self.wrapper.write_code("retval = PyLong_AsLongLong(py_retval);") + +class UInt64Param(Parameter): + + def get_c_type(self): + return self.props.get('c_type', 'guint64') + + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code(code=("py_%s = PyLong_FromUnsignedLongLong(%s);" % + (self.name, self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +class UInt64Return(ReturnType): + def get_c_type(self): + return self.props.get('c_type', 'guint64') + def write_decl(self): + self.wrapper.add_declaration("%s retval;" % self.get_c_type()) + def write_error_return(self): + self.wrapper.write_code("return -G_MAXINT;") + def write_conversion(self): + self.wrapper.write_code( + code=None, + failure_expression="!PyLong_Check(py_retval)", + failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be an long");') + self.wrapper.write_code("retval = PyLong_AsUnsignedLongLongMask(py_retval);") + +class ULongParam(Parameter): + + def get_c_type(self): + return self.props.get('c_type', 'gulong') + + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code(code=("py_%s = PyLong_FromUnsignedLong(%s);" % + (self.name, self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +class ULongReturn(ReturnType): + def get_c_type(self): + return self.props.get('c_type', 'gulong') + def write_decl(self): + self.wrapper.add_declaration("%s retval;" % self.get_c_type()) + def write_error_return(self): + self.wrapper.write_code("return -G_MAXINT;") + def write_conversion(self): + self.wrapper.write_code( + code=None, + failure_expression="!PyLong_Check(py_retval)", + failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be an long");') + self.wrapper.write_code("retval = PyLong_AsUnsignedLongMask(py_retval);") + +class ConstStringReturn(ReturnType): + + def get_c_type(self): + return "const gchar *" + + def write_decl(self): + self.wrapper.add_declaration("const gchar *retval;") + + def write_error_return(self): + self.wrapper.write_code("return NULL;") + + def write_conversion(self): + self.wrapper.write_code( + code=None, + failure_expression="!PyString_Check(py_retval)", + failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a string");') + self.wrapper.write_code("retval = g_strdup(PyString_AsString(py_retval));") + +class StringArrayArg(ArgType): + """Arg type for NULL-terminated string pointer arrays (GStrv, aka gchar**).""" + def write_return(self, ptype, ownsreturn, info): + if ownsreturn: + raise NotImplementedError () + else: + info.varlist.add("gchar", "**ret") + info.codeafter.append(" if (ret) {\n" + " guint size = g_strv_length(ret);\n" + " PyObject *py_ret = PyTuple_New(size);\n" + " gint i;\n" + " for (i = 0; i < size; i++)\n" + " PyTuple_SetItem(py_ret, i,\n" + " PyString_FromString(ret[i]));\n" + " return py_ret;\n" + " }\n" + " return PyTuple_New (0);\n") + +matcher.register('GstClockTime', UInt64Arg()) +matcher.register('GstClockTimeDiff', Int64Arg()) +matcher.register('xmlNodePtr', XmlNodeArg()) +matcher.register('xmlDocPtr', XmlDocArg()) +matcher.register('GstCaps', GstCapsArg()) #FIXME: does this work? +matcher.register('GstCaps*', GstCapsArg()) #FIXME: does this work? +matcher.register('const-GstCaps*', GstCapsArg()) +matcher.register('GstIterator*', GstIteratorArg()) + +arg = PointerArg('gpointer', 'G_TYPE_POINTER') +matcher.register('GstClockID', arg) + +for typename in ["GstPlugin", "GstStructure", "GstTagList", "GError", "GstDate", "GstSegment"]: + matcher.register_reverse(typename, GBoxedParam) + matcher.register_reverse_ret(typename, GBoxedReturn) + +for typename in ["GstBuffer*", "GstEvent*", "GstMessage*", "GstQuery*"]: + matcher.register_reverse(typename, GstMiniObjectParam) + matcher.register_reverse_ret(typename, GstMiniObjectReturn) + +for typename in ["gint64", "GstClockTimeDiff"]: + matcher.register_reverse(typename, Int64Param) + matcher.register_reverse_ret(typename, Int64Return) + +for typename in ["guint64", "GstClockTime"]: + matcher.register_reverse(typename, UInt64Param) + matcher.register_reverse_ret(typename, UInt64Return) + +matcher.register_reverse_ret("const-gchar*", ConstStringReturn) + +matcher.register_reverse("GType", IntParam) +matcher.register_reverse_ret("GType", IntReturn) + +matcher.register_reverse("gulong", ULongParam) +matcher.register_reverse_ret("gulong", ULongReturn) + +matcher.register("GStrv", StringArrayArg()) + +del arg diff --git a/bindings/python/codegen/Makefile.am b/bindings/python/codegen/Makefile.am new file mode 100644 index 0000000000..dd3eea0641 --- /dev/null +++ b/bindings/python/codegen/Makefile.am @@ -0,0 +1,15 @@ +EXTRA_DIST = \ + argtypes.py \ + code-coverage.py \ + codegen.py \ + definitions.py \ + defsparser.py \ + docextract.py \ + docgen.py \ + h2def.py \ + __init__.py \ + mergedefs.py \ + mkskel.py \ + override.py \ + reversewrapper.py \ + scmexpr.py diff --git a/bindings/python/codegen/__init__.py b/bindings/python/codegen/__init__.py new file mode 100644 index 0000000000..cfa896ee6a --- /dev/null +++ b/bindings/python/codegen/__init__.py @@ -0,0 +1,15 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- + +__all__ = [ + 'argtypes', + 'codegen', + 'definitions', + 'defsparser', + 'docextract', + 'docgen', + 'h2def', + 'mergedefs', + 'mkskel', + 'override', + 'scmexpr' +] diff --git a/bindings/python/codegen/argtypes.py b/bindings/python/codegen/argtypes.py new file mode 100644 index 0000000000..948bae106c --- /dev/null +++ b/bindings/python/codegen/argtypes.py @@ -0,0 +1,1075 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +import string +import keyword +import struct + +class VarList: + """Nicely format a C variable list""" + def __init__(self): + self.vars = {} + def add(self, ctype, name): + if self.vars.has_key(ctype): + self.vars[ctype] = self.vars[ctype] + (name,) + else: + self.vars[ctype] = (name,) + def __str__(self): + ret = [] + for type in self.vars.keys(): + ret.append(' ') + ret.append(type) + ret.append(' ') + ret.append(string.join(self.vars[type], ', ')) + ret.append(';\n') + if ret: + ret.append('\n') + return string.join(ret, '') + return '' + +class WrapperInfo: + """A class that holds information about variable defs, code + snippets, etcd for use in writing out the function/method + wrapper.""" + def __init__(self): + self.varlist = VarList() + self.parsestr = '' + self.parselist = ['', 'kwlist'] + self.codebefore = [] + self.codeafter = [] + self.arglist = [] + self.kwlist = [] + def get_parselist(self): + return string.join(self.parselist, ', ') + def get_codebefore(self): + return string.join(self.codebefore, '') + def get_codeafter(self): + return string.join(self.codeafter, '') + def get_arglist(self): + return string.join(self.arglist, ', ') + def get_varlist(self): + return str(self.varlist) + def get_kwlist(self): + ret = ' static char *kwlist[] = { %s };\n' % \ + string.join(self.kwlist + [ 'NULL' ], ', ') + if not self.get_varlist(): + ret = ret + '\n' + return ret + + def add_parselist(self, codes, parseargs, keywords): + self.parsestr = self.parsestr + codes + for arg in parseargs: + self.parselist.append(arg) + for kw in keywords: + if keyword.iskeyword(kw): + kw = kw + '_' + self.kwlist.append('"%s"' % kw) + +class ArgType: + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + """Add code to the WrapperInfo instance to handle + parameter.""" + raise RuntimeError, "write_param not implemented for %s" % \ + self.__class__.__name__ + def write_return(self, ptype, ownsreturn, info): + """Adds a variable named ret of the return type to + info.varlist, and add any required code to info.codeafter to + convert the return value to a python object.""" + raise RuntimeError, "write_return not implemented for %s" % \ + self.__class__.__name__ + +class NoneArg(ArgType): + def write_return(self, ptype, ownsreturn, info): + info.codeafter.append(' Py_INCREF(Py_None);\n' + + ' return Py_None;') + +class StringArg(ArgType): + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + if pdflt != 'NULL': pdflt = '"' + pdflt + '"' + info.varlist.add('char', '*' + pname + ' = ' + pdflt) + else: + info.varlist.add('char', '*' + pname) + info.arglist.append(pname) + if pnull: + info.add_parselist('z', ['&' + pname], [pname]) + else: + info.add_parselist('s', ['&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + if ownsreturn: + # have to free result ... + info.varlist.add('gchar', '*ret') + info.codeafter.append(' if (ret) {\n' + + ' PyObject *py_ret = PyString_FromString(ret);\n' + + ' g_free(ret);\n' + + ' return py_ret;\n' + + ' }\n' + + ' Py_INCREF(Py_None);\n' + + ' return Py_None;') + else: + info.varlist.add('const gchar', '*ret') + info.codeafter.append(' if (ret)\n' + + ' return PyString_FromString(ret);\n'+ + ' Py_INCREF(Py_None);\n' + + ' return Py_None;') + +class UCharArg(ArgType): + # allows strings with embedded NULLs. + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add('guchar', '*' + pname + ' = "' + pdflt + '"') + else: + info.varlist.add('guchar', '*' + pname) + info.varlist.add('int', pname + '_len') + info.arglist.append(pname) + if pnull: + info.add_parselist('z#', ['&' + pname, '&' + pname + '_len'], + [pname]) + else: + info.add_parselist('s#', ['&' + pname, '&' + pname + '_len'], + [pname]) + +class CharArg(ArgType): + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add('char', pname + " = '" + pdflt + "'") + else: + info.varlist.add('char', pname) + info.arglist.append(pname) + info.add_parselist('c', ['&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('gchar', 'ret') + info.codeafter.append(' return PyString_FromStringAndSize(&ret, 1);') +class GUniCharArg(ArgType): + ret_tmpl = ('#if !defined(Py_UNICODE_SIZE) || Py_UNICODE_SIZE == 2\n' + ' if (ret > 0xffff) {\n' + ' PyErr_SetString(PyExc_RuntimeError, "returned character can not be represented in 16-bit unicode");\n' + ' return NULL;\n' + ' }\n' + '#endif\n' + ' py_ret = (Py_UNICODE)ret;\n' + ' return PyUnicode_FromUnicode(&py_ret, 1);\n') + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add('gunichar', pname + " = '" + pdflt + "'") + else: + info.varlist.add('gunichar', pname) + info.arglist.append(pname) + info.add_parselist('O&', ['pyg_pyobj_to_unichar_conv', '&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('gunichar', 'ret') + info.varlist.add('Py_UNICODE', 'py_ret') + info.codeafter.append(self.ret_tmpl) + + +class IntArg(ArgType): + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add('int', pname + ' = ' + pdflt) + else: + info.varlist.add('int', pname) + info.arglist.append(pname) + info.add_parselist('i', ['&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('int', 'ret') + info.codeafter.append(' return PyInt_FromLong(ret);') + +class UIntArg(ArgType): + dflt = (' if (py_%(name)s) {\n' + ' if (PyLong_Check(py_%(name)s))\n' + ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n' + ' else if (PyInt_Check(py_%(name)s))\n' + ' %(name)s = PyInt_AsLong(py_%(name)s);\n' + ' else\n' + ' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n' + ' if (PyErr_Occurred())\n' + ' return NULL;\n' + ' }\n') + before = (' if (PyLong_Check(py_%(name)s))\n' + ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n' + ' else if (PyInt_Check(py_%(name)s))\n' + ' %(name)s = PyInt_AsLong(py_%(name)s);\n' + ' else\n' + ' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n' + ' if (PyErr_Occurred())\n' + ' return NULL;\n') + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if not pdflt: + pdflt = '0'; + + info.varlist.add(ptype, pname + ' = ' + pdflt) + info.codebefore.append(self.dflt % {'name':pname}) + info.varlist.add('PyObject', "*py_" + pname + ' = NULL') + info.arglist.append(pname) + info.add_parselist('O', ['&py_' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add(ptype, 'ret') + info.codeafter.append(' return PyLong_FromUnsignedLong(ret);') + +class SizeArg(ArgType): + + if struct.calcsize('P') <= struct.calcsize('l'): + llp64 = True + else: + llp64 = False + + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add(ptype, pname + ' = ' + pdflt) + else: + info.varlist.add(ptype, pname) + info.arglist.append(pname) + if self.llp64: + info.add_parselist('k', ['&' + pname], [pname]) + else: + info.add_parselist('K', ['&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add(ptype, 'ret') + if self.llp64: + info.codeafter.append(' return PyLong_FromUnsignedLongLong(ret);\n') + else: + info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n') + +class SSizeArg(ArgType): + + if struct.calcsize('P') <= struct.calcsize('l'): + llp64 = True + else: + llp64 = False + + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add(ptype, pname + ' = ' + pdflt) + else: + info.varlist.add(ptype, pname) + info.arglist.append(pname) + if self.llp64: + info.add_parselist('l', ['&' + pname], [pname]) + else: + info.add_parselist('L', ['&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add(ptype, 'ret') + if self.llp64: + info.codeafter.append(' return PyLong_FromLongLong(ret);\n') + else: + info.codeafter.append(' return PyLong_FromLong(ret);\n') + +class LongArg(ArgType): + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add(ptype, pname + ' = ' + pdflt) + else: + info.varlist.add(ptype, pname) + info.arglist.append(pname) + info.add_parselist('l', ['&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add(ptype, 'ret') + info.codeafter.append(' return PyInt_FromLong(ret);\n') + +class BoolArg(IntArg): + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('int', 'ret') + info.codeafter.append(' return PyBool_FromLong(ret);\n') + +class TimeTArg(ArgType): + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add('time_t', pname + ' = ' + pdflt) + else: + info.varlist.add('time_t', pname) + info.arglist.append(pname) + info.add_parselist('i', ['&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('time_t', 'ret') + info.codeafter.append(' return PyInt_FromLong(ret);') + +class ULongArg(ArgType): + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add('unsigned long', pname + ' = ' + pdflt) + else: + info.varlist.add('unsigned long', pname) + info.arglist.append(pname) + info.add_parselist('k', ['&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add(ptype, 'ret') + info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n') + +class UInt32Arg(ULongArg): + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + ULongArg.write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info) + ## if sizeof(unsigned long) > sizeof(unsigned int), we need to + ## check the value is within guint32 range + if struct.calcsize('L') > struct.calcsize('I'): + info.codebefore.append(( + ' if (%(pname)s > G_MAXUINT32) {\n' + ' PyErr_SetString(PyExc_ValueError,\n' + ' "Value out of range in conversion of"\n' + ' " %(pname)s parameter to unsigned 32 bit integer");\n' + ' return NULL;\n' + ' }\n') % vars()) + +class Int64Arg(ArgType): + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add('gint64', pname + ' = ' + pdflt) + else: + info.varlist.add('gint64', pname) + info.arglist.append(pname) + info.add_parselist('L', ['&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('gint64', 'ret') + info.codeafter.append(' return PyLong_FromLongLong(ret);') + +class UInt64Arg(ArgType): + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add('guint64', pname + ' = ' + pdflt) + else: + info.varlist.add('guint64', pname) + info.arglist.append(pname) + info.add_parselist('K', ['&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('guint64', 'ret') + info.codeafter.append(' return PyLong_FromUnsignedLongLong(ret);') + + +class DoubleArg(ArgType): + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add('double', pname + ' = ' + pdflt) + else: + info.varlist.add('double', pname) + info.arglist.append(pname) + info.add_parselist('d', ['&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('double', 'ret') + info.codeafter.append(' return PyFloat_FromDouble(ret);') + +class FileArg(ArgType): + nulldflt = (' if (py_%(name)s == Py_None)\n' + ' %(name)s = NULL;\n' + ' else if (py_%(name)s && PyFile_Check(py_%(name)s)\n' + ' %s = PyFile_AsFile(py_%(name)s);\n' + ' else if (py_%(name)s) {\n' + ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a file object or None");\n' + ' return NULL;\n' + ' }') + null = (' if (py_%(name)s && PyFile_Check(py_%(name)s)\n' + ' %(name)s = PyFile_AsFile(py_%(name)s);\n' + ' else if (py_%(name)s != Py_None) {\n' + ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a file object or None");\n' + ' return NULL;\n' + ' }\n') + dflt = (' if (py_%(name)s)\n' + ' %(name)s = PyFile_AsFile(py_%(name)s);\n') + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pnull: + if pdflt: + info.varlist.add('FILE', '*' + pname + ' = ' + pdflt) + info.varlist.add('PyObject', '*py_' + pname + ' = NULL') + info.codebefore.append(self.nulldflt % {'name':pname}) + else: + info.varlist.add('FILE', '*' + pname + ' = NULL') + info.varlist.add('PyObject', '*py_' + pname) + info.codebefore.append(self.null & {'name':pname}) + info.arglist.appned(pname) + info.add_parselist('O', ['&py_' + pname], [pname]) + else: + if pdflt: + info.varlist.add('FILE', '*' + pname + ' = ' + pdflt) + info.varlist.add('PyObject', '*py_' + pname + ' = NULL') + info.codebefore.append(self.dflt % {'name':pname}) + info.arglist.append(pname) + else: + info.varlist.add('PyObject', '*' + pname) + info.arglist.append('PyFile_AsFile(' + pname + ')') + info.add_parselist('O!', ['&PyFile_Type', '&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('FILE', '*ret') + info.codeafter.append(' if (ret)\n' + + ' return PyFile_FromFile(ret, "", "", fclose);\n' + + ' Py_INCREF(Py_None);\n' + + ' return Py_None;') + +class EnumArg(ArgType): + enum = (' if (pyg_enum_get_value(%(typecode)s, py_%(name)s, (gint *)&%(name)s))\n' + ' return NULL;\n') + def __init__(self, enumname, typecode): + self.enumname = enumname + self.typecode = typecode + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add(self.enumname, pname + ' = ' + pdflt) + else: + info.varlist.add(self.enumname, pname) + info.varlist.add('PyObject', '*py_' + pname + ' = NULL') + info.codebefore.append(self.enum % { 'typecode': self.typecode, + 'name': pname}) + info.arglist.append(pname) + info.add_parselist('O', ['&py_' + pname], [pname]); + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('gint', 'ret') + info.codeafter.append(' return pyg_enum_from_gtype(%s, ret);' % self.typecode) + +class FlagsArg(ArgType): + flag = (' if (%(default)spyg_flags_get_value(%(typecode)s, py_%(name)s, (gint *)&%(name)s))\n' + ' return NULL;\n') + def __init__(self, flagname, typecode): + self.flagname = flagname + self.typecode = typecode + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add(self.flagname, pname + ' = ' + pdflt) + default = "py_%s && " % (pname,) + else: + info.varlist.add(self.flagname, pname) + default = "" + info.varlist.add('PyObject', '*py_' + pname + ' = NULL') + info.codebefore.append(self.flag % {'default':default, + 'typecode':self.typecode, + 'name':pname}) + info.arglist.append(pname) + info.add_parselist('O', ['&py_' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('guint', 'ret') + info.codeafter.append(' return pyg_flags_from_gtype(%s, ret);' % self.typecode) + +class ObjectArg(ArgType): + # should change these checks to more typesafe versions that check + # a little further down in the class heirachy. + nulldflt = (' if ((PyObject *)py_%(name)s == Py_None)\n' + ' %(name)s = NULL;\n' + ' else if (py_%(name)s && pygobject_check(py_%(name)s, &Py%(type)s_Type))\n' + ' %(name)s = %(cast)s(py_%(name)s->obj);\n' + ' else if (py_%(name)s) {\n' + ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n' + ' return NULL;\n' + ' }\n') + null = (' if (py_%(name)s && pygobject_check(py_%(name)s, &Py%(type)s_Type))\n' + ' %(name)s = %(cast)s(py_%(name)s->obj);\n' + ' else if ((PyObject *)py_%(name)s != Py_None) {\n' + ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n' + ' return NULL;\n' + ' }\n') + dflt = ' if (py_%(name)s)\n' \ + ' %(name)s = %(cast)s(py_%(name)s->obj);\n' + def __init__(self, objname, parent, typecode): + self.objname = objname + self.cast = string.replace(typecode, '_TYPE_', '_', 1) + self.parent = parent + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pnull: + if pdflt: + info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt) + info.varlist.add('PyGObject', '*py_' + pname + ' = NULL') + info.codebefore.append(self.nulldflt % {'name':pname, + 'cast':self.cast, + 'type':self.objname}) + else: + info.varlist.add(self.objname, '*' + pname + ' = NULL') + info.varlist.add('PyGObject', '*py_' + pname) + info.codebefore.append(self.null % {'name':pname, + 'cast':self.cast, + 'type':self.objname}) + if ptype.endswith('*'): + typename = ptype[:-1] + try: + const, typename = typename.split('const-') + except ValueError: + const = '' + if typename != ptype: + info.arglist.append('(%s *) %s' % (ptype[:-1], pname)) + else: + info.arglist.append(pname) + + info.add_parselist('O', ['&py_' + pname], [pname]) + else: + if pdflt: + info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt) + info.varlist.add('PyGObject', '*py_' + pname + ' = NULL') + info.codebefore.append(self.dflt % {'name':pname, + 'cast':self.cast}) + info.arglist.append(pname) + info.add_parselist('O!', ['&Py%s_Type' % self.objname, + '&py_' + pname], [pname]) + else: + info.varlist.add('PyGObject', '*' + pname) + info.arglist.append('%s(%s->obj)' % (self.cast, pname)) + info.add_parselist('O!', ['&Py%s_Type' % self.objname, + '&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + if ptype.endswith('*'): + typename = ptype[:-1] + try: + const, typename = typename.split('const-') + except ValueError: + const = '' + info.varlist.add(typename, '*ret') + if ownsreturn: + info.varlist.add('PyObject', '*py_ret') + # < GLib 2.8: using our custom _new and _unref functions + # makes sure we update the proper GstObject refcount + info.codeafter.append(' py_ret = pygobject_new((GObject *)ret);\n' + ' if (ret != NULL)\n' + ' g_object_unref((GObject *)ret);\n' + ' return py_ret;') + else: + info.codeafter.append(' /* pygobject_new handles NULL checking */\n' + + ' return pygobject_new((GObject *)ret);') + +class MiniObjectArg(ArgType): + # should change these checks to more typesafe versions that check + # a little further down in the class heirachy. + nulldflt = (' if ((PyObject *)py_%(name)s == Py_None)\n' + ' %(name)s = NULL;\n' + ' else if (py_%(name)s) && pygstminiobject_check(py_%(name)s, &Py%(type)s_Type))\n' + ' %(name)s = %(cast)s(py_%(name)s->obj);\n' + ' else if (py_%(name)s) {\n' + ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n' + ' return NULL;\n' + ' }\n') + null = (' if (py_%(name)s && pygstminiobject_check(py_%(name)s, &Py%(type)s_Type))\n' + ' %(name)s = %(cast)s(py_%(name)s->obj);\n' + ' else if ((PyObject *)py_%(name)s != Py_None) {\n' + ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n' + ' return NULL;\n' + ' }\n') + dflt = ' if (py_%(name)s)\n' \ + ' %(name)s = %(cast)s(py_%(name)s->obj);\n' + def __init__(self, objname, parent, typecode): + self.objname = objname + self.cast = string.replace(typecode, '_TYPE_', '_', 1) + self.parent = parent + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pnull: + if pdflt: + info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt) + info.varlist.add('PyGstMiniObject', '*py_' + pname + ' = NULL') + info.codebefore.append(self.nulldflt % {'name':pname, + 'cast':self.cast, + 'type':self.objname}) + else: + info.varlist.add(self.objname, '*' + pname + ' = NULL') + info.varlist.add('PyGstMiniObject', '*py_' + pname) + info.codebefore.append(self.null % {'name':pname, + 'cast':self.cast, + 'type':self.objname}) + if ptype.endswith('*'): + typename = ptype[:-1] + try: + const, typename = typename.split('const-') + except ValueError: + const = '' + if typename != ptype: + info.arglist.append('(%s *) %s' % (ptype[:-1], pname)) + else: + info.arglist.append(pname) + + info.add_parselist('O', ['&py_' + pname], [pname]) + else: + if pdflt: + info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt) + info.varlist.add('PyGstMiniObject', '*py_' + pname + ' = NULL') + info.codebefore.append(self.dflt % {'name':pname, + 'cast':self.cast}) + info.arglist.append(pname) + info.add_parselist('O', ['&Py%s_Type' % self.objname, + '&py_' + pname], [pname]) + else: + info.varlist.add('PyGstMiniObject', '*' + pname) + info.arglist.append('%s(%s->obj)' % (self.cast, pname)) + info.add_parselist('O!', ['&Py%s_Type' % self.objname, + '&' + pname], [pname]) + if keeprefcount: + info.codebefore.append(' gst_mini_object_ref(GST_MINI_OBJECT(%s->obj));\n' % pname) + def write_return(self, ptype, ownsreturn, info): + if ptype.endswith('*'): + typename = ptype[:-1] + try: + const, typename = typename.split('const-') + except ValueError: + const = '' + info.varlist.add(typename, '*ret') + if ownsreturn: + info.varlist.add('PyObject', '*py_ret') + info.codeafter.append(' py_ret = pygstminiobject_new((GstMiniObject *)ret);\n' + ' if (ret != NULL)\n' + ' gst_mini_object_unref((GstMiniObject *)ret);\n' + ' return py_ret;') + else: + info.codeafter.append(' /* pygobject_new handles NULL checking */\n' + + ' return pygstminiobject_new((GstMiniObject *)ret);') + +class BoxedArg(ArgType): + # haven't done support for default args. Is it needed? + check = (' if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n' + ' %(name)s = pyg_boxed_get(py_%(name)s, %(typename)s);\n' + ' else {\n' + ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s");\n' + ' return NULL;\n' + ' }\n') + null = (' if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n' + ' %(name)s = pyg_boxed_get(py_%(name)s, %(typename)s);\n' + ' else if (py_%(name)s != Py_None) {\n' + ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s or None");\n' + ' return NULL;\n' + ' }\n') + def __init__(self, ptype, typecode): + self.typename = ptype + self.typecode = typecode + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pnull: + info.varlist.add(self.typename, '*' + pname + ' = NULL') + info.varlist.add('PyObject', '*py_' + pname + ' = Py_None') + info.codebefore.append(self.null % {'name': pname, + 'typename': self.typename, + 'typecode': self.typecode}) + else: + info.varlist.add(self.typename, '*' + pname + ' = NULL') + info.varlist.add('PyObject', '*py_' + pname) + info.codebefore.append(self.check % {'name': pname, + 'typename': self.typename, + 'typecode': self.typecode}) + if ptype[-1] == '*': + typename = ptype[:-1] + if typename[:6] == 'const-': typename = typename[6:] + if typename != self.typename: + info.arglist.append('(%s *)%s' % (ptype[:-1], pname)) + else: + info.arglist.append(pname) + else: + info.arglist.append(pname) + info.add_parselist('O', ['&py_' + pname], [pname]) + ret_tmpl = ' /* pyg_boxed_new handles NULL checking */\n' \ + ' return pyg_boxed_new(%(typecode)s, %(ret)s, %(copy)s, TRUE);' + def write_return(self, ptype, ownsreturn, info): + if ptype[-1] == '*': + info.varlist.add(self.typename, '*ret') + ret = 'ret' + else: + info.varlist.add(self.typename, 'ret') + ret = '&ret' + ownsreturn = 0 # of course it can't own a ref to a local var ... + info.codeafter.append(self.ret_tmpl % + { 'typecode': self.typecode, + 'ret': ret, + 'copy': ownsreturn and 'FALSE' or 'TRUE'}) + +class CustomBoxedArg(ArgType): + # haven't done support for default args. Is it needed? + null = (' if (%(check)s(py_%(name)s))\n' + ' %(name)s = %(get)s(py_%(name)s);\n' + ' else if (py_%(name)s != Py_None) {\n' + ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n' + ' return NULL;\n' + ' }\n') + def __init__(self, ptype, pytype, getter, new): + self.pytype = pytype + self.getter = getter + self.checker = 'Py' + ptype + '_Check' + self.new = new + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pnull: + info.varlist.add(ptype[:-1], '*' + pname + ' = NULL') + info.varlist.add('PyObject', '*py_' + pname + ' = Py_None') + info.codebefore.append(self.null % {'name': pname, + 'get': self.getter, + 'check': self.checker, + 'type': ptype[:-1]}) + info.arglist.append(pname) + info.add_parselist('O', ['&py_' + pname], [pname]) + else: + info.varlist.add('PyObject', '*' + pname) + info.arglist.append(self.getter + '(' + pname + ')') + info.add_parselist('O!', ['&' + self.pytype, '&' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add(ptype[:-1], '*ret') + info.codeafter.append(' if (ret)\n' + + ' return ' + self.new + '(ret);\n' + + ' Py_INCREF(Py_None);\n' + + ' return Py_None;') + +class PointerArg(ArgType): + # haven't done support for default args. Is it needed? + check = (' if (pyg_pointer_check(py_%(name)s, %(typecode)s))\n' + ' %(name)s = pyg_pointer_get(py_%(name)s, %(typename)s);\n' + ' else {\n' + ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s");\n' + ' return NULL;\n' + ' }\n') + null = (' if (pyg_pointer_check(py_%(name)s, %(typecode)s))\n' + ' %(name)s = pyg_pointer_get(py_%(name)s, %(typename)s);\n' + ' else if (py_%(name)s != Py_None) {\n' + ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s or None");\n' + ' return NULL;\n' + ' }\n') + def __init__(self, ptype, typecode): + self.typename = ptype + self.typecode = typecode + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pnull: + info.varlist.add(self.typename, '*' + pname + ' = NULL') + info.varlist.add('PyObject', '*py_' + pname + ' = Py_None') + info.codebefore.append(self.null % {'name': pname, + 'typename': self.typename, + 'typecode': self.typecode}) + else: + info.varlist.add(self.typename, '*' + pname + ' = NULL') + info.varlist.add('PyObject', '*py_' + pname) + info.codebefore.append(self.check % {'name': pname, + 'typename': self.typename, + 'typecode': self.typecode}) + info.arglist.append(pname) + info.add_parselist('O', ['&py_' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + if ptype[-1] == '*': + info.varlist.add(self.typename, '*ret') + info.codeafter.append(' /* pyg_pointer_new handles NULL checking */\n' + + ' return pyg_pointer_new(' + self.typecode + ', ret);') + else: + info.varlist.add(self.typename, 'ret') + info.codeafter.append(' /* pyg_pointer_new handles NULL checking */\n' + + ' return pyg_pointer_new(' + self.typecode + ', &ret);') + +class AtomArg(IntArg): + dflt = ' if (py_%(name)s) {\n' \ + ' %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n' \ + ' if (PyErr_Occurred())\n' \ + ' return NULL;\n' \ + ' }\n' + atom = (' %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n' + ' if (PyErr_Occurred())\n' + ' return NULL;\n') + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pdflt: + info.varlist.add('GdkAtom', pname + ' = ' + pdflt) + info.varlist.add('PyObject', '*py_' + pname + ' = NULL') + info.codebefore.append(self.dflt % {'name': pname}) + else: + info.varlist.add('GdkAtom', pname) + info.varlist.add('PyObject', '*py_' + pname + ' = NULL') + info.codebefore.append(self.atom % {'name': pname}) + info.arglist.append(pname) + info.add_parselist('O', ['&py_' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('GdkAtom', 'ret') + info.varlist.add('PyObject *', 'py_ret') + info.varlist.add('gchar *', 'name') + info.codeafter.append(' name = gdk_atom_name(ret);\n' + ' py_ret = PyString_FromString(name);\n' + ' g_free(name);\n' + ' return py_ret;') + +class GTypeArg(ArgType): + gtype = (' if ((%(name)s = pyg_type_from_object(py_%(name)s)) == 0)\n' + ' return NULL;\n') + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + info.varlist.add('GType', pname) + info.varlist.add('PyObject', '*py_' + pname + ' = NULL') + info.codebefore.append(self.gtype % {'name': pname}) + info.arglist.append(pname) + info.add_parselist('O', ['&py_' + pname], [pname]) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('GType', 'ret') + info.codeafter.append(' return pyg_type_wrapper_new(ret);') + +# simple GError handler. +class GErrorArg(ArgType): + handleerror = (' if (pyg_error_check(&%(name)s))\n' + ' return NULL;\n') + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + info.varlist.add('GError', '*' + pname + ' = NULL') + info.arglist.append('&' + pname) + info.codeafter.append(self.handleerror % { 'name': pname }) + +class GtkTreePathArg(ArgType): + # haven't done support for default args. Is it needed? + normal = (' %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n' + ' if (!%(name)s) {\n' + ' PyErr_SetString(PyExc_TypeError, "could not convert %(name)s to a GtkTreePath");\n' + ' return NULL;\n' + ' }\n') + null = (' if (py_%(name)s != Py_None) {\n' + ' %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n' + ' if (!%(name)s) {\n' + ' PyErr_SetString(PyExc_TypeError, "could not convert %(name)s to a GtkTreePath");\n' + ' return NULL;\n' + ' }\n' + ' }\n') + freepath = (' if (%(name)s)\n' + ' gtk_tree_path_free(%(name)s);\n') + def __init__(self): + pass + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pnull: + info.varlist.add('GtkTreePath', '*' + pname + ' = NULL') + info.varlist.add('PyObject', '*py_' + pname + ' = Py_None') + info.codebefore.append(self.null % {'name': pname}) + info.arglist.append(pname) + info.add_parselist('O', ['&py_' + pname], [pname]) + else: + info.varlist.add('GtkTreePath', '*' + pname) + info.varlist.add('PyObject', '*py_' + pname) + info.codebefore.append(self.normal % {'name': pname}) + info.arglist.append(pname) + info.add_parselist('O', ['&py_' + pname], [pname]) + info.codeafter.append(self.freepath % {'name': pname}) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('GtkTreePath', '*ret') + if ownsreturn: + info.codeafter.append(' if (ret) {\n' + ' PyObject *py_ret = pygtk_tree_path_to_pyobject(ret);\n' + ' gtk_tree_path_free(ret);\n' + ' return py_ret;\n' + ' }\n' + ' Py_INCREF(Py_None);\n' + ' return Py_None;') + else: + info.codeafter.append(' if (ret) {\n' + ' PyObject *py_ret = pygtk_tree_path_to_pyobject(ret);\n' + ' return py_ret;\n' + ' }\n' + ' Py_INCREF(Py_None);\n' + ' return Py_None;') + +class GdkRectanglePtrArg(ArgType): + normal = (' if (!pygdk_rectangle_from_pyobject(py_%(name)s, &%(name)s))\n' + ' return NULL;\n') + null = (' if (py_%(name)s == Py_None)\n' + ' %(name)s = NULL;\n' + ' else if (pygdk_rectangle_from_pyobject(py_%(name)s, &%(name)s_rect))\n' + ' %(name)s = &%(name)s_rect;\n' + ' else\n' + ' return NULL;\n') + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if pnull: + info.varlist.add('GdkRectangle', pname + '_rect = { 0, 0, 0, 0 }') + info.varlist.add('GdkRectangle', '*' + pname) + info.varlist.add('PyObject', '*py_' + pname + ' = Py_None') + info.add_parselist('O', ['&py_' + pname], [pname]) + info.arglist.append(pname) + info.codebefore.append(self.null % {'name': pname}) + else: + info.varlist.add('GdkRectangle', pname + ' = { 0, 0, 0, 0 }') + info.varlist.add('PyObject', '*py_' + pname) + info.add_parselist('O', ['&py_' + pname], [pname]) + info.arglist.append('&' + pname) + info.codebefore.append(self.normal % {'name': pname}) + +class GdkRectangleArg(ArgType): + def write_return(self, ptype, ownsreturn, info): + info.varlist.add('GdkRectangle', 'ret') + info.codeafter.append(' return pyg_boxed_new(GDK_TYPE_RECTANGLE, &ret, TRUE, TRUE);') + +class PyObjectArg(ArgType): + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + info.varlist.add('PyObject', '*' + pname) + info.add_parselist('O', ['&' + pname], [pname]) + info.arglist.append(pname) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add("PyObject", "*ret") + if ownsreturn: + info.codeafter.append(' if (ret) {\n' + ' return ret;\n' + ' }\n' + ' Py_INCREF(Py_None);\n' + ' return Py_None;') + else: + info.codeafter.append(' if (!ret) ret = Py_None;\n' + ' Py_INCREF(ret);\n' + ' return ret;') + +class ArgMatcher: + def __init__(self): + self.argtypes = {} + self.reverse_argtypes = {} + self.reverse_rettypes = {} + + def register(self, ptype, handler): + self.argtypes[ptype] = handler + def register_reverse(self, ptype, handler): + self.reverse_argtypes[ptype] = handler + def register_reverse_ret(self, ptype, handler): + self.reverse_rettypes[ptype] = handler + + def register_enum(self, ptype, typecode): + if typecode is None: + typecode = "G_TYPE_NONE" + self.register(ptype, EnumArg(ptype, typecode)) + def register_flag(self, ptype, typecode): + if typecode is None: + typecode = "G_TYPE_NONE" + self.register(ptype, FlagsArg(ptype, typecode)) + def register_object(self, ptype, parent, typecode): + oa = ObjectArg(ptype, parent, typecode) + self.register(ptype, oa) # in case I forget the * in the .defs + self.register(ptype+'*', oa) + self.register('const-'+ptype+'*', oa) + if ptype == 'GdkPixmap': + # hack to handle GdkBitmap synonym. + self.register('GdkBitmap', oa) + self.register('GdkBitmap*', oa) + def register_miniobject(self, ptype, parent, typecode): + oa = MiniObjectArg(ptype, parent, typecode) + self.register(ptype, oa) # in case I forget the * in the .defs + self.register(ptype+'*', oa) + def register_boxed(self, ptype, typecode): + if self.argtypes.has_key(ptype): return + arg = BoxedArg(ptype, typecode) + self.register(ptype, arg) + self.register(ptype+'*', arg) + self.register('const-'+ptype+'*', arg) + def register_custom_boxed(self, ptype, pytype, getter, new): + arg = CustomBoxedArg(ptype, pytype, getter, new) + self.register(ptype+'*', arg) + self.register('const-'+ptype+'*', arg) + def register_pointer(self, ptype, typecode): + arg = PointerArg(ptype, typecode) + self.register(ptype, arg) + self.register(ptype+'*', arg) + self.register('const-'+ptype+'*', arg) + + def get(self, ptype): + try: + return self.argtypes[ptype] + except KeyError: + if ptype[:8] == 'GdkEvent' and ptype[-1] == '*': + return self.argtypes['GdkEvent*'] + raise + def _get_reverse_common(self, ptype, registry): + props = dict(c_type=ptype) + try: + return registry[ptype], props + except KeyError: + try: + handler = self.argtypes[ptype] + except KeyError: + if ptype.startswith('GdkEvent') and ptype.endswith('*'): + handler = self.argtypes['GdkEvent*'] + else: + raise + if isinstance(handler, ObjectArg): + return registry['GObject*'], props + elif isinstance(handler, EnumArg): + props['typecode'] = handler.typecode + props['enumname'] = handler.enumname + return registry['GEnum'], props + elif isinstance(handler, FlagsArg): + props['typecode'] = handler.typecode + props['flagname'] = handler.flagname + return registry['GFlags'], props + elif isinstance(handler, BoxedArg): + props['typecode'] = handler.typecode + props['typename'] = handler.typename + return registry['GBoxed'], props + else: + raise + def get_reverse(self, ptype): + return self._get_reverse_common(ptype, self.reverse_argtypes) + def get_reverse_ret(self, ptype): + return self._get_reverse_common(ptype, self.reverse_rettypes) + + def object_is_a(self, otype, parent): + if otype == None: return 0 + if otype == parent: return 1 + if not self.argtypes.has_key(otype): return 0 + return self.object_is_a(self.get(otype).parent, parent) + +matcher = ArgMatcher() + +arg = NoneArg() +matcher.register(None, arg) +matcher.register('none', arg) + +arg = StringArg() +matcher.register('char*', arg) +matcher.register('gchar*', arg) +matcher.register('const-char*', arg) +matcher.register('char-const*', arg) +matcher.register('const-gchar*', arg) +matcher.register('gchar-const*', arg) +matcher.register('string', arg) +matcher.register('static_string', arg) + +arg = UCharArg() +matcher.register('unsigned-char*', arg) +matcher.register('const-guchar*', arg) +matcher.register('guchar*', arg) + +arg = CharArg() +matcher.register('char', arg) +matcher.register('gchar', arg) +matcher.register('guchar', arg) + +arg = GUniCharArg() +matcher.register('gunichar', arg) + +arg = IntArg() +matcher.register('int', arg) +matcher.register('gint', arg) +matcher.register('short', arg) +matcher.register('gshort', arg) +matcher.register('gushort', arg) +matcher.register('gsize', SizeArg()) +matcher.register('gssize', SSizeArg()) +matcher.register('guint8', arg) +matcher.register('gint8', arg) +matcher.register('guint16', arg) +matcher.register('gint16', arg) +matcher.register('gint32', arg) +matcher.register('GTime', arg) + +arg = LongArg() +matcher.register('long', arg) +matcher.register('glong', arg) + +arg = UIntArg() +matcher.register('guint', arg) + +arg = BoolArg() +matcher.register('gboolean', arg) + +arg = TimeTArg() +matcher.register('time_t', arg) + +matcher.register('guint32', UInt32Arg()) + +arg = ULongArg() +matcher.register('gulong', arg) + +arg = Int64Arg() +matcher.register('gint64', arg) +matcher.register('long-long', arg) + +arg = UInt64Arg() +matcher.register('guint64', arg) +matcher.register('unsigned-long-long', arg) + +arg = DoubleArg() +matcher.register('double', arg) +matcher.register('gdouble', arg) +matcher.register('float', arg) +matcher.register('gfloat', arg) + +arg = FileArg() +matcher.register('FILE*', arg) + +# enums, flags, objects + +matcher.register('GdkAtom', AtomArg()) + +matcher.register('GType', GTypeArg()) +matcher.register('GtkType', GTypeArg()) + +matcher.register('GError**', GErrorArg()) +matcher.register('GtkTreePath*', GtkTreePathArg()) +matcher.register('GdkRectangle*', GdkRectanglePtrArg()) +matcher.register('GtkAllocation*', GdkRectanglePtrArg()) +matcher.register('GdkRectangle', GdkRectangleArg()) +matcher.register('PyObject*', PyObjectArg()) + +matcher.register('GdkNativeWindow', ULongArg()) + +matcher.register_object('GObject', None, 'G_TYPE_OBJECT') +matcher.register_miniobject('GstMiniObject', None, 'GST_TYPE_MINI_OBJECT') + +del arg diff --git a/bindings/python/codegen/code-coverage.py b/bindings/python/codegen/code-coverage.py new file mode 100755 index 0000000000..fd15034736 --- /dev/null +++ b/bindings/python/codegen/code-coverage.py @@ -0,0 +1,42 @@ +from __future__ import generators +import sys, os + +def read_symbols(file, type=None, dynamic=0): + if dynamic: + cmd = 'nm -D %s' % file + else: + cmd = 'nm %s' % file + for line in os.popen(cmd, 'r'): + if line[0] != ' ': # has an address as first bit of line + while line[0] != ' ': + line = line[1:] + while line[0] == ' ': + line = line[1:] + # we should be up to "type symbolname" now + sym_type = line[0] + symbol = line[1:].strip() + + if not type or type == sym_type: + yield symbol + +def main(): + if len(sys.argv) != 3: + sys.stderr.write('usage: coverage-check library.so wrapper.so\n') + sys.exit(1) + library = sys.argv[1] + wrapper = sys.argv[2] + + # first create a dict with all referenced symbols in the wrapper + # should really be a set, but a dict will do ... + wrapper_symbols = {} + for symbol in read_symbols(wrapper, type='U', dynamic=1): + wrapper_symbols[symbol] = 1 + + # now go through the library looking for matches on the defined symbols: + for symbol in read_symbols(library, type='T', dynamic=1): + if symbol[0] == '_': continue + if symbol not in wrapper_symbols: + print symbol + +if __name__ == '__main__': + main() diff --git a/bindings/python/codegen/codegen.py b/bindings/python/codegen/codegen.py new file mode 100644 index 0000000000..8f20bf7089 --- /dev/null +++ b/bindings/python/codegen/codegen.py @@ -0,0 +1,1572 @@ +import getopt +import keyword +import os +import string +import sys + +import argtypes +import definitions +import defsparser +import override +import reversewrapper + +class Coverage(object): + def __init__(self, name): + self.name = name + self.wrapped = 0 + self.not_wrapped = 0 + + def declare_wrapped(self): + self.wrapped += 1 + + def declare_not_wrapped(self): + self.not_wrapped += 1 + + def printstats(self): + total = self.wrapped + self.not_wrapped + fd = sys.stderr + if total: + fd.write("***INFO*** The coverage of %s is %.2f%% (%i/%i)\n" % + (self.name, + float(self.wrapped*100)/total, + self.wrapped, + total)) + else: + fd.write("***INFO*** There are no declared %s." % self.name) + +functions_coverage = Coverage("global functions") +methods_coverage = Coverage("methods") +vproxies_coverage = Coverage("virtual proxies") +vaccessors_coverage = Coverage("virtual accessors") +iproxies_coverage = Coverage("interface proxies") + +def exc_info(): + #traceback.print_exc() + etype, value, tb = sys.exc_info() + ret = "" + try: + sval = str(value) + if etype == KeyError: + ret = "No ArgType for %s" % (sval,) + else: + ret = sval + finally: + del etype, value, tb + return ret + +def fixname(name): + if keyword.iskeyword(name): + return name + '_' + return name + +class FileOutput: + '''Simple wrapper for file object, that makes writing #line + statements easier.''' # " + def __init__(self, fp, filename=None): + self.fp = fp + self.lineno = 1 + if filename: + self.filename = filename + else: + self.filename = self.fp.name + # handle writing to the file, and keep track of the line number ... + def write(self, str): + self.fp.write(str) + self.lineno = self.lineno + string.count(str, '\n') + def writelines(self, sequence): + for line in sequence: + self.write(line) + def close(self): + self.fp.close() + def flush(self): + self.fp.flush() + + def setline(self, linenum, filename): + '''writes out a #line statement, for use by the C + preprocessor.''' # " + self.write('#line %d "%s"\n' % (linenum, filename)) + def resetline(self): + '''resets line numbering to the original file''' + self.setline(self.lineno + 1, self.filename) + +class Wrapper: + type_tmpl = ( + 'PyTypeObject Py%(typename)s_Type = {\n' + ' PyObject_HEAD_INIT(NULL)\n' + ' 0, /* ob_size */\n' + ' "%(classname)s", /* tp_name */\n' + ' sizeof(%(tp_basicsize)s), /* tp_basicsize */\n' + ' 0, /* tp_itemsize */\n' + ' /* methods */\n' + ' (destructor)%(tp_dealloc)s, /* tp_dealloc */\n' + ' (printfunc)0, /* tp_print */\n' + ' (getattrfunc)%(tp_getattr)s, /* tp_getattr */\n' + ' (setattrfunc)%(tp_setattr)s, /* tp_setattr */\n' + ' (cmpfunc)%(tp_compare)s, /* tp_compare */\n' + ' (reprfunc)%(tp_repr)s, /* tp_repr */\n' + ' (PyNumberMethods*)%(tp_as_number)s, /* tp_as_number */\n' + ' (PySequenceMethods*)%(tp_as_sequence)s, /* tp_as_sequence */\n' + ' (PyMappingMethods*)%(tp_as_mapping)s, /* tp_as_mapping */\n' + ' (hashfunc)%(tp_hash)s, /* tp_hash */\n' + ' (ternaryfunc)%(tp_call)s, /* tp_call */\n' + ' (reprfunc)%(tp_str)s, /* tp_str */\n' + ' (getattrofunc)%(tp_getattro)s, /* tp_getattro */\n' + ' (setattrofunc)%(tp_setattro)s, /* tp_setattro */\n' + ' (PyBufferProcs*)%(tp_as_buffer)s, /* tp_as_buffer */\n' + ' %(tp_flags)s, /* tp_flags */\n' + ' %(tp_doc)s, /* Documentation string */\n' + ' (traverseproc)%(tp_traverse)s, /* tp_traverse */\n' + ' (inquiry)%(tp_clear)s, /* tp_clear */\n' + ' (richcmpfunc)%(tp_richcompare)s, /* tp_richcompare */\n' + ' %(tp_weaklistoffset)s, /* tp_weaklistoffset */\n' + ' (getiterfunc)%(tp_iter)s, /* tp_iter */\n' + ' (iternextfunc)%(tp_iternext)s, /* tp_iternext */\n' + ' (struct PyMethodDef*)%(tp_methods)s, /* tp_methods */\n' + ' (struct PyMemberDef*)0, /* tp_members */\n' + ' (struct PyGetSetDef*)%(tp_getset)s, /* tp_getset */\n' + ' NULL, /* tp_base */\n' + ' NULL, /* tp_dict */\n' + ' (descrgetfunc)%(tp_descr_get)s, /* tp_descr_get */\n' + ' (descrsetfunc)%(tp_descr_set)s, /* tp_descr_set */\n' + ' %(tp_dictoffset)s, /* tp_dictoffset */\n' + ' (initproc)%(tp_init)s, /* tp_init */\n' + ' (allocfunc)%(tp_alloc)s, /* tp_alloc */\n' + ' (newfunc)%(tp_new)s, /* tp_new */\n' + ' (freefunc)%(tp_free)s, /* tp_free */\n' + ' (inquiry)%(tp_is_gc)s /* tp_is_gc */\n' + '};\n\n' + ) + + slots_list = [ + 'tp_getattr', 'tp_setattr', 'tp_getattro', 'tp_setattro', + 'tp_compare', 'tp_repr', + 'tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'tp_hash', + 'tp_call', 'tp_str', 'tp_as_buffer', 'tp_richcompare', 'tp_iter', + 'tp_iternext', 'tp_descr_get', 'tp_descr_set', 'tp_init', + 'tp_alloc', 'tp_new', 'tp_free', 'tp_is_gc', + 'tp_traverse', 'tp_clear', 'tp_dealloc', 'tp_flags', 'tp_doc' + ] + + getter_tmpl = ( + 'static PyObject *\n' + '%(funcname)s(PyObject *self, void *closure)\n' + '{\n' + '%(varlist)s' + ' ret = %(field)s;\n' + '%(codeafter)s\n' + '}\n\n' + ) + + parse_tmpl = ( + ' if (!PyArg_ParseTupleAndKeywords(args, kwargs,' + '"%(typecodes)s:%(name)s"%(parselist)s))\n' + ' return %(errorreturn)s;\n' + ) + + deprecated_tmpl = ( + ' if (PyErr_Warn(PyExc_DeprecationWarning, ' + '"%(deprecationmsg)s") < 0)\n' + ' return %(errorreturn)s;\n' + ) + + methdef_tmpl = ( + ' { "%(name)s", (PyCFunction)%(cname)s, %(flags)s,\n' + ' %(docstring)s },\n' + ) + + noconstructor = ( + 'static int\n' + 'pygobject_no_constructor(PyObject *self, PyObject *args, ' + 'PyObject *kwargs)\n' + '{\n' + ' gchar buf[512];\n' + '\n' + ' g_snprintf(buf, sizeof(buf), "%s is an abstract widget", ' + 'self->ob_type->tp_name);\n' + ' PyErr_SetString(PyExc_NotImplementedError, buf);\n' + ' return -1;\n' + '}\n\n' + ) + + function_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' %(begin_allow_threads)s\n' + ' %(setreturn)s%(cname)s(%(arglist)s);\n' + ' %(end_allow_threads)s\n' + '%(codeafter)s\n' + '}\n\n' + ) + + virtual_accessor_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n' + '{\n' + ' gpointer klass;\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' klass = g_type_class_ref(pyg_type_from_object(cls));\n' + ' if (%(class_cast_macro)s(klass)->%(virtual)s) {\n' + ' pyg_begin_allow_threads;\n' + ' %(setreturn)s%(class_cast_macro)s(klass)->' + '%(virtual)s(%(arglist)s);\n' + ' pyg_end_allow_threads;\n' + ' } else {\n' + ' PyErr_SetString(PyExc_NotImplementedError, ' + '"virtual method %(name)s not implemented");\n' + ' g_type_class_unref(klass);\n' + ' return NULL;\n' + ' }\n' + ' g_type_class_unref(klass);\n' + '%(codeafter)s\n' + '}\n\n' + ) + + # template for method calls + constructor_tmpl = None + method_tmpl = None + + def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)): + self.parser = parser + self.objinfo = objinfo + self.overrides = overrides + self.fp = fp + + def get_lower_name(self): + return string.lower(string.replace(self.objinfo.typecode, + '_TYPE_', '_', 1)) + + def get_field_accessor(self, fieldname): + raise NotImplementedError + + def get_initial_class_substdict(self): return {} + + def get_initial_constructor_substdict(self, constructor): + return { 'name': '%s.__init__' % self.objinfo.c_name, + 'errorreturn': '-1' } + def get_initial_method_substdict(self, method): + substdict = { 'name': '%s.%s' % (self.objinfo.c_name, method.name) } + substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;' + substdict['end_allow_threads'] = 'pyg_end_allow_threads;' + return substdict + + def write_class(self): + if self.overrides.is_type_ignored(self.objinfo.c_name): + return + self.fp.write('\n/* ----------- %s ----------- */\n\n' % + self.objinfo.c_name) + substdict = self.get_initial_class_substdict() + if not substdict.has_key('tp_flags'): + substdict['tp_flags'] = 'Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE' + substdict['typename'] = self.objinfo.c_name + if self.overrides.modulename: + substdict['classname'] = '%s.%s' % (self.overrides.modulename, + self.objinfo.name) + else: + substdict['classname'] = self.objinfo.name + substdict['tp_doc'] = self.objinfo.docstring + + # Maybe this could be done in a nicer way, but I'll leave it as it is + # for now: -- Johan + if not self.overrides.slot_is_overriden('%s.tp_init' % + self.objinfo.c_name): + substdict['tp_init'] = self.write_constructor() + substdict['tp_methods'] = self.write_methods() + substdict['tp_getset'] = self.write_getsets() + + # handle slots ... + for slot in self.slots_list: + + slotname = '%s.%s' % (self.objinfo.c_name, slot) + slotfunc = '_wrap_%s_%s' % (self.get_lower_name(), slot) + if slot[:6] == 'tp_as_': + slotfunc = '&' + slotfunc + if self.overrides.slot_is_overriden(slotname): + data = self.overrides.slot_override(slotname) + self.write_function(slotname, data) + substdict[slot] = slotfunc + else: + if not substdict.has_key(slot): + substdict[slot] = '0' + + self.fp.write(self.type_tmpl % substdict) + + self.write_virtuals() + + def write_function_wrapper(self, function_obj, template, + handle_return=0, is_method=0, kwargs_needed=0, + substdict=None): + '''This function is the guts of all functions that generate + wrappers for functions, methods and constructors.''' + if not substdict: substdict = {} + + info = argtypes.WrapperInfo() + + substdict.setdefault('errorreturn', 'NULL') + + # for methods, we want the leading comma + if is_method: + info.arglist.append('') + + if function_obj.varargs: + raise ValueError, "varargs functions not supported" + + for param in function_obj.params: + if param.pdflt and '|' not in info.parsestr: + info.add_parselist('|', [], []) + handler = argtypes.matcher.get(param.ptype) + handler.write_param(param.ptype, param.pname, param.pdflt, + param.pnull, param.keeprefcount, info) + + substdict['setreturn'] = '' + if handle_return: + if function_obj.ret not in ('none', None): + substdict['setreturn'] = 'ret = ' + handler = argtypes.matcher.get(function_obj.ret) + handler.write_return(function_obj.ret, + function_obj.caller_owns_return, info) + + if function_obj.deprecated != None: + deprecated = self.deprecated_tmpl % { + 'deprecationmsg': function_obj.deprecated, + 'errorreturn': substdict['errorreturn'] } + else: + deprecated = '' + + # if name isn't set, set it to function_obj.name + substdict.setdefault('name', function_obj.name) + + substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;' + substdict['end_allow_threads'] = 'pyg_end_allow_threads;' + + if self.objinfo: + substdict['typename'] = self.objinfo.c_name + substdict.setdefault('cname', function_obj.c_name) + substdict['varlist'] = info.get_varlist() + substdict['typecodes'] = info.parsestr + substdict['parselist'] = info.get_parselist() + substdict['arglist'] = info.get_arglist() + substdict['codebefore'] = deprecated + ( + string.replace(info.get_codebefore(), + 'return NULL', 'return ' + substdict['errorreturn']) + ) + substdict['codeafter'] = ( + string.replace(info.get_codeafter(), + 'return NULL', + 'return ' + substdict['errorreturn'])) + + if info.parsestr or kwargs_needed: + substdict['parseargs'] = self.parse_tmpl % substdict + substdict['extraparams'] = ', PyObject *args, PyObject *kwargs' + flags = 'METH_VARARGS|METH_KEYWORDS' + + # prepend the keyword list to the variable list + substdict['varlist'] = info.get_kwlist() + substdict['varlist'] + else: + substdict['parseargs'] = '' + substdict['extraparams'] = '' + flags = 'METH_NOARGS' + + return template % substdict, flags + + def write_constructor(self): + initfunc = '0' + constructor = self.parser.find_constructor(self.objinfo,self.overrides) + if not constructor: + return self.write_default_constructor() + + funcname = constructor.c_name + try: + if self.overrides.is_overriden(funcname): + data = self.overrides.override(funcname) + self.write_function(funcname, data) + self.objinfo.has_new_constructor_api = ( + self.objinfo.typecode in + self.overrides.newstyle_constructors) + else: + # ok, a hack to determine if we should use + # new-style constructores :P + property_based = getattr(self, + 'write_property_based_constructor', + None) + if property_based: + if (len(constructor.params) == 0 or + isinstance(constructor.params[0], + definitions.Property)): + # write_property_based_constructor is only + # implemented in GObjectWrapper + return self.write_property_based_constructor( + constructor) + else: + sys.stderr.write( + "Warning: generating old-style constructor for:" + + constructor.c_name + '\n') + + # write constructor from template ... + code = self.write_function_wrapper(constructor, + self.constructor_tmpl, + handle_return=0, is_method=0, kwargs_needed=1, + substdict=self.get_initial_constructor_substdict( + constructor))[0] + self.fp.write(code) + initfunc = '_wrap_' + funcname + except: + sys.stderr.write('Could not write constructor for %s: %s\n' + % (self.objinfo.c_name, exc_info())) + + initfunc = self.write_noconstructor() + return initfunc + + def write_noconstructor(self): + # this is a hack ... + if not hasattr(self.overrides, 'no_constructor_written'): + self.fp.write(self.noconstructor) + self.overrides.no_constructor_written = 1 + initfunc = 'pygobject_no_constructor' + return initfunc + + def write_default_constructor(self): + return self.write_noconstructor() + + def get_methflags(self, funcname): + if self.overrides.wants_kwargs(funcname): + flags = 'METH_VARARGS|METH_KEYWORDS' + elif self.overrides.wants_noargs(funcname): + flags = 'METH_NOARGS' + elif self.overrides.wants_onearg(funcname): + flags = 'METH_O' + else: + flags = 'METH_VARARGS' + if self.overrides.is_staticmethod(funcname): + flags += '|METH_STATIC' + elif self.overrides.is_classmethod(funcname): + flags += '|METH_CLASS' + return flags + + def write_function(self, funcname, data): + lineno, filename = self.overrides.getstartline(funcname) + self.fp.setline(lineno, filename) + self.fp.write(data) + self.fp.resetline() + self.fp.write('\n\n') + + def _get_class_virtual_substdict(self, meth, cname, parent): + substdict = self.get_initial_method_substdict(meth) + substdict['virtual'] = substdict['name'].split('.')[1] + substdict['cname'] = cname + substdict['class_cast_macro'] = parent.typecode.replace( + '_TYPE_', '_', 1) + "_CLASS" + substdict['typecode'] = self.objinfo.typecode + substdict['cast'] = string.replace(parent.typecode, '_TYPE_', '_', 1) + return substdict + + def write_methods(self): + methods = [] + klass = self.objinfo.c_name + # First, get methods from the defs files + for meth in self.parser.find_methods(self.objinfo): + method_name = meth.c_name + if self.overrides.is_ignored(method_name): + continue + try: + if self.overrides.is_overriden(method_name): + if not self.overrides.is_already_included(method_name): + data = self.overrides.override(method_name) + self.write_function(method_name, data) + + methflags = self.get_methflags(method_name) + else: + # write constructor from template ... + code, methflags = self.write_function_wrapper(meth, + self.method_tmpl, handle_return=1, is_method=1, + substdict=self.get_initial_method_substdict(meth)) + self.fp.write(code) + methods.append(self.methdef_tmpl % + { 'name': fixname(meth.name), + 'cname': '_wrap_' + method_name, + 'flags': methflags, + 'docstring': meth.docstring }) + methods_coverage.declare_wrapped() + except: + methods_coverage.declare_not_wrapped() + sys.stderr.write('Could not write method %s.%s: %s\n' + % (klass, meth.name, exc_info())) + + # Now try to see if there are any defined in the override + for method_name in self.overrides.get_defines_for(klass): + c_name = override.class2cname(klass, method_name) + if self.overrides.is_already_included(method_name): + continue + + try: + data = self.overrides.define(klass, method_name) + self.write_function(method_name, data) + methflags = self.get_methflags(method_name) + + methods.append(self.methdef_tmpl % + { 'name': method_name, + 'cname': '_wrap_' + c_name, + 'flags': methflags, + 'docstring': meth.docstring }) + methods_coverage.declare_wrapped() + except: + methods_coverage.declare_not_wrapped() + sys.stderr.write('Could not write method %s.%s: %s\n' + % (klass, meth.name, exc_info())) + + # Add GObject virtual method accessors, for chaining to parent + # virtuals from subclasses + methods += self.write_virtual_accessors() + + if methods: + methoddefs = '_Py%s_methods' % self.objinfo.c_name + # write the PyMethodDef structure + methods.append(' { NULL, NULL, 0, NULL }\n') + self.fp.write('static const PyMethodDef %s[] = {\n' % methoddefs) + self.fp.write(string.join(methods, '')) + self.fp.write('};\n\n') + else: + methoddefs = 'NULL' + return methoddefs + + def write_virtual_accessors(self): + klass = self.objinfo.c_name + methods = [] + for meth in self.parser.find_virtuals(self.objinfo): + method_name = self.objinfo.c_name + "__do_" + meth.name + if self.overrides.is_ignored(method_name): + continue + try: + if self.overrides.is_overriden(method_name): + if not self.overrides.is_already_included(method_name): + data = self.overrides.override(method_name) + self.write_function(method_name, data) + methflags = self.get_methflags(method_name) + else: + # temporarily add a 'self' parameter as first argument + meth.params.insert(0, definitions.Parameter( + ptype=(self.objinfo.c_name + '*'), + pname='self', pdflt=None, pnull=None)) + try: + # write method from template ... + code, methflags = self.write_function_wrapper( + meth, self.virtual_accessor_tmpl, + handle_return=True, is_method=False, + substdict=self._get_class_virtual_substdict( + meth, method_name, self.objinfo)) + self.fp.write(code) + finally: + del meth.params[0] + methods.append(self.methdef_tmpl % + { 'name': "do_" + fixname(meth.name), + 'cname': '_wrap_' + method_name, + 'flags': methflags + '|METH_CLASS', + 'docstring': 'NULL'}) + vaccessors_coverage.declare_wrapped() + except: + vaccessors_coverage.declare_not_wrapped() + sys.stderr.write( + 'Could not write virtual accessor method %s.%s: %s\n' + % (klass, meth.name, exc_info())) + return methods + + def write_virtuals(self): + ''' + Write _wrap_FooBar__proxy_do_zbr() reverse wrapers for + GObject virtuals + ''' + klass = self.objinfo.c_name + virtuals = [] + for meth in self.parser.find_virtuals(self.objinfo): + method_name = self.objinfo.c_name + "__proxy_do_" + meth.name + if self.overrides.is_ignored(method_name): + continue + try: + if self.overrides.is_overriden(method_name): + if not self.overrides.is_already_included(method_name): + data = self.overrides.override(method_name) + self.write_function(method_name, data) + else: + # write virtual proxy ... + ret, props = argtypes.matcher.get_reverse_ret(meth.ret) + wrapper = reversewrapper.ReverseWrapper( + '_wrap_' + method_name, is_static=True) + wrapper.set_return_type(ret(wrapper, **props)) + wrapper.add_parameter(reversewrapper.PyGObjectMethodParam( + wrapper, "self", method_name="do_" + meth.name, + c_type=(klass + ' *'))) + for param in meth.params: + handler, props = argtypes.matcher.get_reverse( + param.ptype) + props["direction"] = param.pdir + wrapper.add_parameter(handler(wrapper, + param.pname, **props)) + buf = reversewrapper.MemoryCodeSink() + wrapper.generate(buf) + self.fp.write(buf.flush()) + virtuals.append((fixname(meth.name), '_wrap_' + method_name)) + vproxies_coverage.declare_wrapped() + except (KeyError, ValueError): + vproxies_coverage.declare_not_wrapped() + virtuals.append((fixname(meth.name), None)) + sys.stderr.write('Could not write virtual proxy %s.%s: %s\n' + % (klass, meth.name, exc_info())) + if virtuals: + # Write a 'pygtk class init' function for this object, + # except when the object type is explicitly ignored (like + # GtkPlug and GtkSocket on win32). + if self.overrides.is_ignored(self.objinfo.typecode): + return + class_cast_macro = self.objinfo.typecode.replace( + '_TYPE_', '_', 1) + "_CLASS" + cast_macro = self.objinfo.typecode.replace('_TYPE_', '_', 1) + funcname = "__%s_class_init" % klass + self.objinfo.class_init_func = funcname + have_implemented_virtuals = not not [True + for name, cname in virtuals + if cname is not None] + self.fp.write( + ('\nstatic int\n' + '%(funcname)s(gpointer gclass, PyTypeObject *pyclass)\n' + '{\n') % vars()) + + if have_implemented_virtuals: + self.fp.write(' PyObject *o;\n') + self.fp.write( + ' %(klass)sClass *klass = ' + '%(class_cast_macro)s(gclass);\n' + ' PyObject *gsignals = ' + 'PyDict_GetItemString(pyclass->tp_dict, "__gsignals__");\n' + % vars()) + + for name, cname in virtuals: + do_name = 'do_' + name + if cname is None: + self.fp.write('\n /* overriding %(do_name)s ' + 'is currently not supported */\n' % vars()) + else: + self.fp.write(''' + o = PyObject_GetAttrString((PyObject *) pyclass, "%(do_name)s"); + if (o == NULL) + PyErr_Clear(); + else { + if (!PyObject_TypeCheck(o, &PyCFunction_Type) + && !(gsignals && PyDict_GetItemString(gsignals, "%(name)s"))) + klass->%(name)s = %(cname)s; + Py_DECREF(o); + } +''' % vars()) + self.fp.write(' return 0;\n}\n') + + def write_getsets(self): + lower_name = self.get_lower_name() + getsets_name = lower_name + '_getsets' + getterprefix = '_wrap_' + lower_name + '__get_' + setterprefix = '_wrap_' + lower_name + '__set_' + + # no overrides for the whole function. If no fields, + # don't write a func + if not self.objinfo.fields: + return '0' + getsets = [] + for ftype, cfname in self.objinfo.fields: + fname = cfname.replace('.', '_') + gettername = '0' + settername = '0' + attrname = self.objinfo.c_name + '.' + fname + if self.overrides.attr_is_overriden(attrname): + code = self.overrides.attr_override(attrname) + self.write_function(attrname, code) + if string.find(code, getterprefix + fname) >= 0: + gettername = getterprefix + fname + if string.find(code, setterprefix + fname) >= 0: + settername = setterprefix + fname + if gettername == '0': + try: + funcname = getterprefix + fname + info = argtypes.WrapperInfo() + handler = argtypes.matcher.get(ftype) + # for attributes, we don't own the "return value" + handler.write_return(ftype, 0, info) + self.fp.write(self.getter_tmpl % + { 'funcname': funcname, + 'varlist': info.varlist, + 'field': self.get_field_accessor(cfname), + 'codeafter': info.get_codeafter() }) + gettername = funcname + except: + sys.stderr.write( + "Could not write getter for %s.%s: %s\n" + % (self.objinfo.c_name, fname, exc_info())) + if gettername != '0' or settername != '0': + getsets.append(' { "%s", (getter)%s, (setter)%s },\n' % + (fixname(fname), gettername, settername)) + + if not getsets: + return '0' + self.fp.write('static const PyGetSetDef %s[] = {\n' % getsets_name) + for getset in getsets: + self.fp.write(getset) + self.fp.write(' { NULL, (getter)0, (setter)0 },\n') + self.fp.write('};\n\n') + + return getsets_name + + def write_functions(self, prefix): + self.fp.write('\n/* ----------- functions ----------- */\n\n') + functions = [] + + # First, get methods from the defs files + for func in self.parser.find_functions(): + funcname = func.c_name + if self.overrides.is_ignored(funcname): + continue + try: + if self.overrides.is_overriden(funcname): + data = self.overrides.override(funcname) + self.write_function(funcname, data) + + methflags = self.get_methflags(funcname) + else: + # write constructor from template ... + code, methflags = self.write_function_wrapper(func, + self.function_tmpl, handle_return=1, is_method=0) + self.fp.write(code) + functions.append(self.methdef_tmpl % + { 'name': func.name, + 'cname': '_wrap_' + funcname, + 'flags': methflags, + 'docstring': func.docstring }) + functions_coverage.declare_wrapped() + except: + functions_coverage.declare_not_wrapped() + sys.stderr.write('Could not write function %s: %s\n' + % (func.name, exc_info())) + + # Now try to see if there are any defined in the override + for funcname in self.overrides.get_functions(): + try: + data = self.overrides.function(funcname) + self.write_function(funcname, data) + methflags = self.get_methflags(funcname) + functions.append(self.methdef_tmpl % + { 'name': funcname, + 'cname': '_wrap_' + funcname, + 'flags': methflags, + 'docstring': 'NULL'}) + functions_coverage.declare_wrapped() + except: + functions_coverage.declare_not_wrapped() + sys.stderr.write('Could not write function %s: %s\n' + % (funcname, exc_info())) + + # write the PyMethodDef structure + functions.append(' { NULL, NULL, 0, NULL }\n') + + self.fp.write('const PyMethodDef ' + prefix + '_functions[] = {\n') + self.fp.write(string.join(functions, '')) + self.fp.write('};\n\n') + +class GObjectWrapper(Wrapper): + constructor_tmpl = ( + 'static int\n' + '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' self->obj = (GObject *)%(cname)s(%(arglist)s);\n' + '%(codeafter)s\n' + ' if (!self->obj) {\n' + ' PyErr_SetString(PyExc_RuntimeError, ' + '"could not create %(typename)s object");\n' + ' return -1;\n' + ' }\n' + '%(aftercreate)s' + ' pygobject_register_wrapper((PyObject *)self);\n' + ' return 0;\n' + '}\n\n' + ) + + method_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' %(begin_allow_threads)s\n' + ' %(setreturn)s%(cname)s(%(cast)s(self->obj)%(arglist)s);\n' + ' %(end_allow_threads)s\n' + '%(codeafter)s\n' + '}\n\n' + ) + def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)): + Wrapper.__init__(self, parser, objinfo, overrides, fp) + if self.objinfo: + self.castmacro = string.replace(self.objinfo.typecode, + '_TYPE_', '_', 1) + + def get_initial_class_substdict(self): + return { 'tp_basicsize' : 'PyGObject', + 'tp_weaklistoffset' : 'offsetof(PyGObject, weakreflist)', + 'tp_dictoffset' : 'offsetof(PyGObject, inst_dict)' } + + def get_field_accessor(self, fieldname): + castmacro = string.replace(self.objinfo.typecode, '_TYPE_', '_', 1) + return '%s(pygobject_get(self))->%s' % (castmacro, fieldname) + + def get_initial_constructor_substdict(self, constructor): + substdict = Wrapper.get_initial_constructor_substdict(self, + constructor) + if not constructor.caller_owns_return: + substdict['aftercreate'] = " g_object_ref(self->obj);\n" + else: + substdict['aftercreate'] = '' + return substdict + + def get_initial_method_substdict(self, method): + substdict = Wrapper.get_initial_method_substdict(self, method) + substdict['cast'] = string.replace(self.objinfo.typecode, + '_TYPE_', '_', 1) + return substdict + + def write_default_constructor(self): + try: + parent = self.parser.find_object(self.objinfo.parent) + except ValueError: + parent = None + if parent is not None: + ## just like the constructor is inheritted, we should + # inherit the new API compatibility flag + self.objinfo.has_new_constructor_api = ( + parent.has_new_constructor_api) + elif self.objinfo.parent == 'GObject': + self.objinfo.has_new_constructor_api = True + return '0' + + def write_property_based_constructor(self, constructor): + self.objinfo.has_new_constructor_api = True + out = self.fp + print >> out, "static int" + print >> out, '_wrap_%s(PyGObject *self, PyObject *args,' \ + ' PyObject *kwargs)\n{' % constructor.c_name + if constructor.params: + s = " GType obj_type = pyg_type_from_object((PyObject *) self);" + print >> out, s + + def py_str_list_to_c(arg): + if arg: + return "{" + ", ".join( + map(lambda s: '"' + s + '"', arg)) + ", NULL }" + else: + return "{ NULL }" + + classname = '%s.%s' % (self.overrides.modulename, + self.objinfo.name) + + if constructor.params: + mandatory_arguments = [param for param in constructor.params + if not param.optional] + optional_arguments = [param for param in constructor.params + if param.optional] + arg_names = py_str_list_to_c( + [param.argname + for param in mandatory_arguments + optional_arguments]) + + prop_names = py_str_list_to_c( + [param.pname + for param in mandatory_arguments + optional_arguments]) + + print >> out, " GParameter params[%i];" % \ + len(constructor.params) + print >> out, " PyObject *parsed_args[%i] = {NULL, };" % \ + len(constructor.params) + print >> out, " char *arg_names[] = %s;" % arg_names + print >> out, " char *prop_names[] = %s;" % prop_names + print >> out, " guint nparams, i;" + print >> out + if constructor.deprecated is not None: + out.write( + ' if (PyErr_Warn(PyExc_DeprecationWarning, ' + '"%s") < 0)\n' % + constructor.deprecated) + print >> out, ' return -1;' + print >> out + out.write(" if (!PyArg_ParseTupleAndKeywords(args, kwargs, ") + template = '"' + if mandatory_arguments: + template += "O"*len(mandatory_arguments) + if optional_arguments: + template += "|" + "O"*len(optional_arguments) + template += ':%s.__init__"' % classname + print >> out, template, ", arg_names", + for i in range(len(constructor.params)): + print >> out, ", &parsed_args[%i]" % i, + + out.write( + "))\n" + " return -1;\n" + "\n" + " memset(params, 0, sizeof(GParameter)*%i);\n" + " if (!pyg_parse_constructor_args(obj_type, arg_names,\n" + " prop_names, params, \n" + " &nparams, parsed_args))\n" + " return -1;\n" + " pygobject_constructv(self, nparams, params);\n" + " for (i = 0; i < nparams; ++i)\n" + " g_value_unset(¶ms[i].value);\n" + % len(constructor.params)) + else: + out.write( + " static char* kwlist[] = { NULL };\n" + "\n") + + if constructor.deprecated is not None: + out.write( + ' if (PyErr_Warn(PyExc_DeprecationWarning, "%s") < 0)\n' + ' return -1;\n' + '\n' % constructor.deprecated) + + out.write( + ' if (!PyArg_ParseTupleAndKeywords(args, kwargs,\n' + ' ":%s.__init__",\n' + ' kwlist))\n' + ' return -1;\n' + '\n' + ' pygobject_constructv(self, 0, NULL);\n' % classname) + out.write( + ' if (!self->obj) {\n' + ' PyErr_SetString(\n' + ' PyExc_RuntimeError, \n' + ' "could not create %s object");\n' + ' return -1;\n' + ' }\n' % classname) + + if not constructor.caller_owns_return: + print >> out, " g_object_ref(self->obj);\n" + + out.write( + ' return 0;\n' + '}\n\n') + + return "_wrap_%s" % constructor.c_name + + +## TODO : Add GstMiniObjectWrapper(Wrapper) +class GstMiniObjectWrapper(Wrapper): + constructor_tmpl = ( + 'static int\n' + '_wrap_%(cname)s(PyGstMiniObject *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' self->obj = (GstMiniObject *)%(cname)s(%(arglist)s);\n' + '%(codeafter)s\n' + ' if (!self->obj) {\n' + ' PyErr_SetString(PyExc_RuntimeError, ' + '"could not create %(typename)s miniobject");\n' + ' return -1;\n' + ' }\n' + '%(aftercreate)s' + ' pygstminiobject_register_wrapper((PyObject *)self);\n' + ' return 0;\n' + '}\n\n' + ) + method_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyGstMiniObject *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' %(begin_allow_threads)s\n' + ' %(setreturn)s%(cname)s(%(cast)s(self->obj)%(arglist)s);\n' + ' %(end_allow_threads)s\n' + '%(codeafter)s\n' + '}\n\n' + ) + def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)): + Wrapper.__init__(self, parser, objinfo, overrides, fp) + if self.objinfo: + self.castmacro = string.replace(self.objinfo.typecode, + '_TYPE_', '_', 1) + + def get_initial_class_substdict(self): + return { 'tp_basicsize' : 'PyGstMiniObject', + 'tp_weaklistoffset' : 'offsetof(PyGstMiniObject, weakreflist)', + 'tp_dictoffset' : 'offsetof(PyGstMiniObject, inst_dict)' } + + def get_field_accessor(self, fieldname): + castmacro = string.replace(self.objinfo.typecode, '_TYPE_', '_', 1) + return '%s(pygstminiobject_get(self))->%s' % (castmacro, fieldname) + + def get_initial_constructor_substdict(self, constructor): + substdict = Wrapper.get_initial_constructor_substdict(self, + constructor) + if not constructor.caller_owns_return: + substdict['aftercreate'] = " gst_mini_object_ref(self->obj);\n" + else: + substdict['aftercreate'] = '' + return substdict + + def get_initial_method_substdict(self, method): + substdict = Wrapper.get_initial_method_substdict(self, method) + substdict['cast'] = string.replace(self.objinfo.typecode, + '_TYPE_', '_', 1) + return substdict + + + +class GInterfaceWrapper(GObjectWrapper): + virtual_accessor_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n' + '{\n' + ' %(vtable)s *iface;\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' iface = g_type_interface_peek(' + 'g_type_class_peek(pyg_type_from_object(cls)), %(typecode)s);\n' + ' if (iface->%(virtual)s)\n' + ' %(setreturn)siface->%(virtual)s(%(arglist)s);\n' + ' else {\n' + ' PyErr_SetString(PyExc_NotImplementedError, ' + '"interface method %(name)s not implemented");\n' + ' return NULL;\n' + ' }\n' + '%(codeafter)s\n' + '}\n\n' + ) + + def get_initial_class_substdict(self): + return { 'tp_basicsize' : 'PyObject', + 'tp_weaklistoffset' : '0', + 'tp_dictoffset' : '0'} + + def write_constructor(self): + # interfaces have no constructors ... + return '0' + def write_getsets(self): + # interfaces have no fields ... + return '0' + + def _get_class_virtual_substdict(self, meth, cname, parent): + substdict = self.get_initial_method_substdict(meth) + substdict['virtual'] = substdict['name'].split('.')[1] + substdict['cname'] = cname + substdict['typecode'] = self.objinfo.typecode + substdict['vtable'] = self.objinfo.vtable + return substdict + + def write_virtuals(self): + ## Now write reverse method wrappers, which let python code + ## implement interface methods. + # First, get methods from the defs files + klass = self.objinfo.c_name + proxies = [] + for meth in self.parser.find_virtuals(self.objinfo): + method_name = self.objinfo.c_name + "__proxy_do_" + meth.name + if self.overrides.is_ignored(method_name): + continue + try: + if self.overrides.is_overriden(method_name): + if not self.overrides.is_already_included(method_name): + data = self.overrides.override(method_name) + self.write_function(method_name, data) + else: + # write proxy ... + ret, props = argtypes.matcher.get_reverse_ret(meth.ret) + wrapper = reversewrapper.ReverseWrapper( + '_wrap_' + method_name, is_static=True) + wrapper.set_return_type(ret(wrapper, **props)) + wrapper.add_parameter(reversewrapper.PyGObjectMethodParam( + wrapper, "self", method_name="do_" + meth.name, + c_type=(klass + ' *'))) + for param in meth.params: + handler, props = argtypes.matcher.get_reverse( + param.ptype) + props["direction"] = param.pdir + wrapper.add_parameter( + handler(wrapper, param.pname, **props)) + buf = reversewrapper.MemoryCodeSink() + wrapper.generate(buf) + self.fp.write(buf.flush()) + proxies.append((fixname(meth.name), '_wrap_' + method_name)) + iproxies_coverage.declare_wrapped() + except (KeyError, ValueError): + iproxies_coverage.declare_not_wrapped() + proxies.append((fixname(meth.name), None)) + sys.stderr.write('Could not write interface proxy %s.%s: %s\n' + % (klass, meth.name, exc_info())) + + if not proxies: + return + + # Make sure we have at least one proxy function + if not [cname for name,cname in proxies if not cname is None]: + return + + ## Write an interface init function for this object + funcname = "__%s__interface_init" % klass + vtable = self.objinfo.vtable + self.fp.write( + '\nstatic void\n' + '%(funcname)s(%(vtable)s *iface, PyTypeObject *pytype)\n' + '{\n' + ' %(vtable)s *parent_iface = ' + 'g_type_interface_peek_parent(iface);\n' + ' PyObject *py_method;\n' + '\n' + % vars()) + + for name, cname in proxies: + do_name = 'do_' + name + if cname is None: + continue + + self.fp.write(( + ' py_method = pytype? PyObject_GetAttrString(' + '(PyObject *) pytype, "%(do_name)s") : NULL;\n' + ' if (py_method && !PyObject_TypeCheck(py_method, ' + '&PyCFunction_Type)) {\n' + ' iface->%(name)s = %(cname)s;\n' + ' } else {\n' + ' PyErr_Clear();\n' + ' if (parent_iface) {\n' + ' iface->%(name)s = parent_iface->%(name)s;\n' + ' }\n' + ' Py_XDECREF(py_method);\n' + ' }\n' + ) % vars()) + self.fp.write('}\n\n') + interface_info = "__%s__iinfo" % klass + self.fp.write(''' +static const GInterfaceInfo %s = { + (GInterfaceInitFunc) %s, + NULL, + NULL +}; +''' % (interface_info, funcname)) + self.objinfo.interface_info = interface_info + +class GBoxedWrapper(Wrapper): + constructor_tmpl = ( + 'static int\n' + '_wrap_%(cname)s(PyGBoxed *self%(extraparams)s)\n' + '{\n' \ + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' self->gtype = %(typecode)s;\n' + ' self->free_on_dealloc = FALSE;\n' + ' self->boxed = %(cname)s(%(arglist)s);\n' + '%(codeafter)s\n' + ' if (!self->boxed) {\n' + ' PyErr_SetString(PyExc_RuntimeError, ' + '"could not create %(typename)s object");\n' + ' return -1;\n' + ' }\n' + ' self->free_on_dealloc = TRUE;\n' + ' return 0;\n' + '}\n\n' + ) + + method_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' %(begin_allow_threads)s\n' + ' %(setreturn)s%(cname)s(pyg_boxed_get(self, ' + '%(typename)s)%(arglist)s);\n' + ' %(end_allow_threads)s\n' + '%(codeafter)s\n' + '}\n\n' + ) + + def get_initial_class_substdict(self): + return { 'tp_basicsize' : 'PyGBoxed', + 'tp_weaklistoffset' : '0', + 'tp_dictoffset' : '0' } + + def get_field_accessor(self, fieldname): + return 'pyg_boxed_get(self, %s)->%s' % (self.objinfo.c_name, fieldname) + + def get_initial_constructor_substdict(self, constructor): + substdict = Wrapper.get_initial_constructor_substdict( + self, constructor) + substdict['typecode'] = self.objinfo.typecode + return substdict + +class GPointerWrapper(GBoxedWrapper): + constructor_tmpl = ( + 'static int\n' + '_wrap_%(cname)s(PyGPointer *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' self->gtype = %(typecode)s;\n' + ' self->pointer = %(cname)s(%(arglist)s);\n' + '%(codeafter)s\n' + ' if (!self->pointer) {\n' + ' PyErr_SetString(PyExc_RuntimeError, ' + '"could not create %(typename)s object");\n' + ' return -1;\n' + ' }\n' + ' return 0;\n' + '}\n\n' + ) + + method_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' %(setreturn)s%(cname)s(pyg_pointer_get(self, ' + '%(typename)s)%(arglist)s);\n' + '%(codeafter)s\n' + '}\n\n' + ) + + def get_initial_class_substdict(self): + return { 'tp_basicsize' : 'PyGPointer', + 'tp_weaklistoffset' : '0', + 'tp_dictoffset' : '0' } + + def get_field_accessor(self, fieldname): + return 'pyg_pointer_get(self, %s)->%s' % (self.objinfo.c_name, + fieldname) + + def get_initial_constructor_substdict(self, constructor): + substdict = Wrapper.get_initial_constructor_substdict( + self, constructor) + substdict['typecode'] = self.objinfo.typecode + return substdict + +def write_headers(data, fp): + fp.write('/* -- THIS FILE IS GENERATED - DO NOT EDIT */') + fp.write('/* -*- Mode: C; c-basic-offset: 4 -*- */\n\n') + fp.write('#include \n\n\n') + fp.write(data) + fp.resetline() + fp.write('\n\n') + +def write_body(data, fp): + fp.write(data) + fp.resetline() + fp.write('\n\n') + +def write_imports(overrides, fp): + fp.write('/* ---------- types from other modules ---------- */\n') + for module, pyname, cname in overrides.get_imports(): + fp.write('static PyTypeObject *_%s;\n' % cname) + fp.write('#define %s (*_%s)\n' % (cname, cname)) + fp.write('\n\n') + +def write_type_declarations(parser, fp): + fp.write('/* ---------- forward type declarations ---------- */\n') + for obj in parser.boxes: + fp.write('PyTypeObject Py' + obj.c_name + '_Type;\n') + for obj in parser.objects: + fp.write('PyTypeObject Py' + obj.c_name + '_Type;\n') + for obj in parser.miniobjects: + fp.write('PyTypeObject Py' + obj.c_name + '_Type;\n') + for interface in parser.interfaces: + fp.write('PyTypeObject Py' + interface.c_name + '_Type;\n') + fp.write('\n') + + +def sort_parent_children(objects): + objects = list(objects) + modified = True + while modified: + modified = False + parent_index = None + child_index = None + for i, obj in enumerate(objects): + if obj.parent == 'GObject': + continue + if obj.parent not in [info.c_name for info in objects[:i]]: + for j, info in enumerate(objects[i+1:]): + if info.c_name == obj.parent: + parent_index = i + 1 + j + child_index = i + break + else: + continue + break + if child_index is not None and parent_index is not None: + if child_index != parent_index: + objects.insert(child_index, objects.pop(parent_index)) + modified = True + return objects + +def write_classes(parser, overrides, fp): + ## Sort the objects, so that we generate code for the parent types + ## before their children. + objects = sort_parent_children(parser.objects) + for klass, items in ((GBoxedWrapper, parser.boxes), + (GPointerWrapper, parser.pointers), + (GObjectWrapper, objects), + (GstMiniObjectWrapper, parser.miniobjects), + (GInterfaceWrapper, parser.interfaces)): + for item in items: + instance = klass(parser, item, overrides, fp) + instance.write_class() + fp.write('\n') + +def write_enums(parser, overrides, prefix, fp=sys.stdout): + if not parser.enums: + return + fp.write('\n/* ----------- enums and flags ----------- */\n\n') + fp.write( + 'void\n' + prefix + + '_add_constants(PyObject *module, const gchar *strip_prefix)\n{\n') + + for enum in parser.enums: + if overrides.is_type_ignored(enum.c_name): + continue + if enum.typecode is None: + for nick, value in enum.values: + fp.write( + ' PyModule_AddIntConstant(module, ' + '(char *) pyg_constant_strip_prefix("%s", strip_prefix), %s);\n' + % (value, value)) + else: + if enum.deftype == 'enum': + fp.write(' pyg_enum_add(module, "%s", strip_prefix, %s);\n' + % (enum.name, enum.typecode)) + else: + fp.write(' pyg_flags_add(module, "%s", strip_prefix, %s);\n' + % (enum.name, enum.typecode)) + + fp.write('\n') + fp.write(' if (PyErr_Occurred())\n') + fp.write(' PyErr_Print();\n') + fp.write('}\n\n') + +def write_extension_init(overrides, prefix, fp): + fp.write('/* initialise stuff extension classes */\n') + fp.write('void\n' + prefix + '_register_classes(PyObject *d)\n{\n') + imports = overrides.get_imports()[:] + if imports: + bymod = {} + for module, pyname, cname in imports: + bymod.setdefault(module, []).append((pyname, cname)) + fp.write(' PyObject *module;\n\n') + for module in bymod: + fp.write( + ' if ((module = PyImport_ImportModule("%s")) != NULL) {\n' + % module) + fp.write( + ' PyObject *moddict = PyModule_GetDict(module);\n\n') + for pyname, cname in bymod[module]: + fp.write( + ' _%s = (PyTypeObject *)PyDict_GetItemString(' + 'moddict, "%s");\n' % (cname, pyname)) + fp.write(' if (_%s == NULL) {\n' % cname) + fp.write(' PyErr_SetString(PyExc_ImportError,\n') + fp.write(' "cannot import name %s from %s");\n' + % (pyname, module)) + fp.write(' return;\n') + fp.write(' }\n') + fp.write(' } else {\n') + fp.write(' PyErr_SetString(PyExc_ImportError,\n') + fp.write(' "could not import %s");\n' % module) + fp.write(' return;\n') + fp.write(' }\n') + fp.write('\n') + fp.write(overrides.get_init() + '\n') + fp.resetline() + +def write_registers(parser, overrides, fp): + for boxed in parser.boxes: + if overrides.is_type_ignored(boxed.c_name): + continue + fp.write(' pyg_register_boxed(d, "' + boxed.name + + '", ' + boxed.typecode + + ', &Py' + boxed.c_name + + '_Type);\n') + for pointer in parser.pointers: + if overrides.is_type_ignored(pointer.c_name): + continue + fp.write(' pyg_register_pointer(d, "' + pointer.name + + '", ' + pointer.typecode + + ', &Py' + pointer.c_name + '_Type);\n') + for interface in parser.interfaces: + if overrides.is_type_ignored(interface.c_name): + continue + fp.write(' pyg_register_interface(d, "' + interface.name + + '", '+ interface.typecode + ', &Py' + interface.c_name + + '_Type);\n') + if interface.interface_info is not None: + fp.write(' pyg_register_interface_info(%s, &%s);\n' % + (interface.typecode, interface.interface_info)) + + objects = parser.objects[:] + pos = 0 + while pos < len(objects): + parent = objects[pos].parent + for i in range(pos+1, len(objects)): + if objects[i].c_name == parent: + objects.insert(i+1, objects[pos]) + del objects[pos] + break + else: + pos = pos + 1 + for obj in objects: + if overrides.is_type_ignored(obj.c_name): + continue + bases = [] + if obj.parent != None: + bases.append(obj.parent) + bases = bases + obj.implements + if bases: + fp.write(' pygobject_register_class(d, "' + obj.c_name + + '", ' + obj.typecode + ', &Py' + obj.c_name + + '_Type, Py_BuildValue("(' + 'O' * len(bases) + ')", ' + + string.join(map(lambda s: '&Py'+s+'_Type', bases), ', ') + + '));\n') + else: + fp.write(' pygobject_register_class(d, "' + obj.c_name + + '", ' + obj.typecode + ', &Py' + obj.c_name + + '_Type, NULL);\n') + if obj.has_new_constructor_api: + fp.write(' pyg_set_object_has_new_constructor(%s);\n' % + obj.typecode) + else: + print >> sys.stderr, ( + "Warning: Constructor for %s needs to be updated to new API\n" + " See http://live.gnome.org/PyGTK_2fWhatsNew28" + "#update-constructors") % obj.c_name + if obj.class_init_func is not None: + fp.write(' pyg_register_class_init(%s, %s);\n' % + (obj.typecode, obj.class_init_func)) + #TODO: register mini-objects + miniobjects = parser.miniobjects[:] + for obj in miniobjects: + bases = [] + if obj.parent != None: + bases.append(obj.parent) + bases = bases + obj.implements + if bases: + fp.write(' pygstminiobject_register_class(d, "' + obj.c_name + + '", ' + obj.typecode + ', &Py' + obj.c_name + + '_Type, Py_BuildValue("(' + 'O' * len(bases) + ')", ' + + string.join(map(lambda s: '&Py'+s+'_Type', bases), ', ') + + '));\n') + else: + fp.write(' pygstminiobject_register_class(d, "' + obj.c_name + + '", ' + obj.typecode + ', &Py' + obj.c_name + + '_Type, NULL);\n') + + fp.write('}\n') + +def write_source(parser, overrides, prefix, fp=FileOutput(sys.stdout)): + write_headers(overrides.get_headers(), fp) + write_imports(overrides, fp) + write_type_declarations(parser, fp) + write_body(overrides.get_body(), fp) + write_classes(parser, overrides, fp) + + wrapper = Wrapper(parser, None, overrides, fp) + wrapper.write_functions(prefix) + + write_enums(parser, overrides, prefix, fp) + write_extension_init(overrides, prefix, fp) + write_registers(parser, overrides, fp) + +def register_types(parser): + for boxed in parser.boxes: + argtypes.matcher.register_boxed(boxed.c_name, boxed.typecode) + for pointer in parser.pointers: + argtypes.matcher.register_pointer(pointer.c_name, pointer.typecode) + for obj in parser.objects: + argtypes.matcher.register_object(obj.c_name, obj.parent, obj.typecode) + for obj in parser.miniobjects: + argtypes.matcher.register_miniobject(obj.c_name, obj.parent, obj.typecode) + for obj in parser.interfaces: + argtypes.matcher.register_object(obj.c_name, None, obj.typecode) + for enum in parser.enums: + if enum.deftype == 'flags': + argtypes.matcher.register_flag(enum.c_name, enum.typecode) + else: + argtypes.matcher.register_enum(enum.c_name, enum.typecode) + +usage = 'usage: codegen.py [-o overridesfile] [-p prefix] defsfile' +def main(argv): + o = override.Overrides() + prefix = 'pygtk' + outfilename = None + errorfilename = None + extendpath = [] + opts, args = getopt.getopt(argv[1:], "o:p:r:t:D:x", + ["override=", "prefix=", "register=", "outfilename=", + "load-types=", "errorfilename=", "extendpath="]) + defines = {} # -Dkey[=val] options + + for opt, arg in opts: + if opt in ('-x', '--extendpath'): + extendpath.append(arg) + extendpath.insert(0, os.getcwd()) + o = override.Overrides(path=extendpath) + + for opt, arg in opts: + if opt in ('-o', '--override'): + o = override.Overrides(arg, path=extendpath) + elif opt in ('-p', '--prefix'): + prefix = arg + elif opt in ('-r', '--register'): + # Warning: user has to make sure all -D options appear before -r + p = defsparser.DefsParser(arg, defines) + p.startParsing() + register_types(p) + del p + elif opt == '--outfilename': + outfilename = arg + elif opt == '--errorfilename': + errorfilename = arg + elif opt in ('-t', '--load-types'): + globals = {} + execfile(arg, globals) + elif opt == '-D': + nameval = arg.split('=') + try: + defines[nameval[0]] = nameval[1] + except IndexError: + defines[nameval[0]] = None + if len(args) < 1: + print >> sys.stderr, usage + return 1 + if errorfilename: + sys.stderr = open(errorfilename, "w") + p = defsparser.DefsParser(args[0], defines) + if not outfilename: + outfilename = os.path.splitext(args[0])[0] + '.c' + + p.startParsing() + + register_types(p) + write_source(p, o, prefix, FileOutput(sys.stdout, outfilename)) + + functions_coverage.printstats() + methods_coverage.printstats() + vproxies_coverage.printstats() + vaccessors_coverage.printstats() + iproxies_coverage.printstats() + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/bindings/python/codegen/definitions.py b/bindings/python/codegen/definitions.py new file mode 100644 index 0000000000..911c8ddb4b --- /dev/null +++ b/bindings/python/codegen/definitions.py @@ -0,0 +1,607 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +import copy +import sys + +def get_valid_scheme_definitions(defs): + return [x for x in defs if isinstance(x, tuple) and len(x) >= 2] + +def unescape(s): + s = s.replace('\r\n', '\\r\\n').replace('\t', '\\t') + return s.replace('\r', '\\r').replace('\n', '\\n') + +def make_docstring(lines): + return "(char *) " + '\n'.join(['"%s"' % unescape(s) for s in lines]) + +# New Parameter class, wich emulates a tuple for compatibility reasons +class Parameter(object): + def __init__(self, ptype, pname, pdflt, pnull, pdir=None, keeprefcount = False): + self.ptype = ptype + self.pname = pname + self.pdflt = pdflt + self.pnull = pnull + self.pdir = pdir + self.keeprefcount = keeprefcount + + def __len__(self): return 4 + def __getitem__(self, i): + return (self.ptype, self.pname, self.pdflt, self.pnull)[i] + + def merge(self, old): + if old.pdflt is not None: + self.pdflt = old.pdflt + if old.pnull is not None: + self.pnull = old.pnull + +# Parameter for property based constructors +class Property(object): + def __init__(self, pname, optional, argname): + self.pname = pname + self.optional = optional + self.argname = argname + + def merge(self, old): + if old.optional is not None: + self.optional = old.optional + if old.argname is not None: + self.argname = old.argname + + +class Definition: + docstring = "NULL" + def __init__(self, *args): + """Create a new defs object of this type. The arguments are the + components of the definition""" + raise RuntimeError, "this is an abstract class" + def merge(self, old): + """Merge in customisations from older version of definition""" + raise RuntimeError, "this is an abstract class" + def write_defs(self, fp=sys.stdout): + """write out this definition in defs file format""" + raise RuntimeError, "this is an abstract class" + + def guess_return_value_ownership(self): + "return 1 if caller owns return value" + if getattr(self, 'is_constructor_of', False): + self.caller_owns_return = True + elif self.ret in ('char*', 'gchar*', 'string'): + self.caller_owns_return = True + else: + self.caller_owns_return = False + + +class ObjectDef(Definition): + def __init__(self, name, *args): + self.name = name + self.module = None + self.parent = None + self.c_name = None + self.typecode = None + self.fields = [] + self.implements = [] + self.class_init_func = None + self.has_new_constructor_api = False + for arg in get_valid_scheme_definitions(args): + if arg[0] == 'in-module': + self.module = arg[1] + elif arg[0] == 'docstring': + self.docstring = make_docstring(arg[1:]) + elif arg[0] == 'parent': + self.parent = arg[1] + elif arg[0] == 'c-name': + self.c_name = arg[1] + elif arg[0] == 'gtype-id': + self.typecode = arg[1] + elif arg[0] == 'fields': + for parg in arg[1:]: + self.fields.append((parg[0], parg[1])) + elif arg[0] == 'implements': + self.implements.append(arg[1]) + def merge(self, old): + # currently the .h parser doesn't try to work out what fields of + # an object structure should be public, so we just copy the list + # from the old version ... + self.fields = old.fields + self.implements = old.implements + def write_defs(self, fp=sys.stdout): + fp.write('(define-object ' + self.name + '\n') + if self.module: + fp.write(' (in-module "' + self.module + '")\n') + if self.parent != (None, None): + fp.write(' (parent "' + self.parent + '")\n') + for interface in self.implements: + fp.write(' (implements "' + interface + '")\n') + if self.c_name: + fp.write(' (c-name "' + self.c_name + '")\n') + if self.typecode: + fp.write(' (gtype-id "' + self.typecode + '")\n') + if self.fields: + fp.write(' (fields\n') + for (ftype, fname) in self.fields: + fp.write(' \'("' + ftype + '" "' + fname + '")\n') + fp.write(' )\n') + fp.write(')\n\n') + +class MiniObjectDef(Definition): + def __init__(self, name, *args): + self.name = name + self.module = None + self.parent = None + self.c_name = None + self.typecode = None + self.fields = [] + self.implements = [] + for arg in args: + if type(arg) != type(()) or len(arg) < 2: + continue + if arg[0] == 'in-module': + self.module = arg[1] + elif arg[0] == 'parent': + self.parent = arg[1] + elif arg[0] == 'c-name': + self.c_name = arg[1] + elif arg[0] == 'gtype-id': + self.typecode = arg[1] + elif arg[0] == 'fields': + for parg in arg[1:]: + self.fields.append((parg[0], parg[1])) + elif arg[0] == 'implements': + self.implements.append(arg[1]) + def merge(self, old): + # currently the .h parser doesn't try to work out what fields of + # an object structure should be public, so we just copy the list + # from the old version ... + self.fields = old.fields + self.implements = old.implements + def write_defs(self, fp=sys.stdout): + fp.write('(define-object ' + self.name + '\n') + if self.module: + fp.write(' (in-module "' + self.module + '")\n') + if self.parent != (None, None): + fp.write(' (parent "' + self.parent + '")\n') + for interface in self.implements: + fp.write(' (implements "' + interface + '")\n') + if self.c_name: + fp.write(' (c-name "' + self.c_name + '")\n') + if self.typecode: + fp.write(' (gtype-id "' + self.typecode + '")\n') + if self.fields: + fp.write(' (fields\n') + for (ftype, fname) in self.fields: + fp.write(' \'("' + ftype + '" "' + fname + '")\n') + fp.write(' )\n') + fp.write(')\n\n') + + +class InterfaceDef(Definition): + def __init__(self, name, *args): + self.name = name + self.module = None + self.c_name = None + self.typecode = None + self.vtable = None + self.fields = [] + self.interface_info = None + for arg in get_valid_scheme_definitions(args): + if arg[0] == 'in-module': + self.module = arg[1] + elif arg[0] == 'docstring': + self.docstring = make_docstring(arg[1:]) + elif arg[0] == 'c-name': + self.c_name = arg[1] + elif arg[0] == 'gtype-id': + self.typecode = arg[1] + elif arg[0] == 'vtable': + self.vtable = arg[1] + if self.vtable is None: + self.vtable = self.c_name + "Iface" + def write_defs(self, fp=sys.stdout): + fp.write('(define-interface ' + self.name + '\n') + if self.module: + fp.write(' (in-module "' + self.module + '")\n') + if self.c_name: + fp.write(' (c-name "' + self.c_name + '")\n') + if self.typecode: + fp.write(' (gtype-id "' + self.typecode + '")\n') + fp.write(')\n\n') + +class EnumDef(Definition): + def __init__(self, name, *args): + self.deftype = 'enum' + self.name = name + self.in_module = None + self.c_name = None + self.typecode = None + self.values = [] + for arg in get_valid_scheme_definitions(args): + if arg[0] == 'in-module': + self.in_module = arg[1] + elif arg[0] == 'c-name': + self.c_name = arg[1] + elif arg[0] == 'gtype-id': + self.typecode = arg[1] + elif arg[0] == 'values': + for varg in arg[1:]: + self.values.append((varg[0], varg[1])) + def merge(self, old): + pass + def write_defs(self, fp=sys.stdout): + fp.write('(define-' + self.deftype + ' ' + self.name + '\n') + if self.in_module: + fp.write(' (in-module "' + self.in_module + '")\n') + fp.write(' (c-name "' + self.c_name + '")\n') + fp.write(' (gtype-id "' + self.typecode + '")\n') + if self.values: + fp.write(' (values\n') + for name, val in self.values: + fp.write(' \'("' + name + '" "' + val + '")\n') + fp.write(' )\n') + fp.write(')\n\n') + +class FlagsDef(EnumDef): + def __init__(self, *args): + apply(EnumDef.__init__, (self,) + args) + self.deftype = 'flags' + +class BoxedDef(Definition): + def __init__(self, name, *args): + self.name = name + self.module = None + self.c_name = None + self.typecode = None + self.copy = None + self.release = None + self.fields = [] + for arg in get_valid_scheme_definitions(args): + if arg[0] == 'in-module': + self.module = arg[1] + elif arg[0] == 'c-name': + self.c_name = arg[1] + elif arg[0] == 'gtype-id': + self.typecode = arg[1] + elif arg[0] == 'copy-func': + self.copy = arg[1] + elif arg[0] == 'release-func': + self.release = arg[1] + elif arg[0] == 'fields': + for parg in arg[1:]: + self.fields.append((parg[0], parg[1])) + def merge(self, old): + # currently the .h parser doesn't try to work out what fields of + # an object structure should be public, so we just copy the list + # from the old version ... + self.fields = old.fields + def write_defs(self, fp=sys.stdout): + fp.write('(define-boxed ' + self.name + '\n') + if self.module: + fp.write(' (in-module "' + self.module + '")\n') + if self.c_name: + fp.write(' (c-name "' + self.c_name + '")\n') + if self.typecode: + fp.write(' (gtype-id "' + self.typecode + '")\n') + if self.copy: + fp.write(' (copy-func "' + self.copy + '")\n') + if self.release: + fp.write(' (release-func "' + self.release + '")\n') + if self.fields: + fp.write(' (fields\n') + for (ftype, fname) in self.fields: + fp.write(' \'("' + ftype + '" "' + fname + '")\n') + fp.write(' )\n') + fp.write(')\n\n') + +class PointerDef(Definition): + def __init__(self, name, *args): + self.name = name + self.module = None + self.c_name = None + self.typecode = None + self.fields = [] + for arg in get_valid_scheme_definitions(args): + if arg[0] == 'in-module': + self.module = arg[1] + elif arg[0] == 'c-name': + self.c_name = arg[1] + elif arg[0] == 'gtype-id': + self.typecode = arg[1] + elif arg[0] == 'fields': + for parg in arg[1:]: + self.fields.append((parg[0], parg[1])) + def merge(self, old): + # currently the .h parser doesn't try to work out what fields of + # an object structure should be public, so we just copy the list + # from the old version ... + self.fields = old.fields + def write_defs(self, fp=sys.stdout): + fp.write('(define-pointer ' + self.name + '\n') + if self.module: + fp.write(' (in-module "' + self.module + '")\n') + if self.c_name: + fp.write(' (c-name "' + self.c_name + '")\n') + if self.typecode: + fp.write(' (gtype-id "' + self.typecode + '")\n') + if self.fields: + fp.write(' (fields\n') + for (ftype, fname) in self.fields: + fp.write(' \'("' + ftype + '" "' + fname + '")\n') + fp.write(' )\n') + fp.write(')\n\n') + +class MethodDefBase(Definition): + def __init__(self, name, *args): + dump = 0 + self.name = name + self.ret = None + self.caller_owns_return = None + self.unblock_threads = None + self.c_name = None + self.typecode = None + self.of_object = None + self.params = [] # of form (type, name, default, nullok) + self.varargs = 0 + self.deprecated = None + for arg in get_valid_scheme_definitions(args): + if arg[0] == 'of-object': + self.of_object = arg[1] + elif arg[0] == 'docstring': + self.docstring = make_docstring(arg[1:]) + elif arg[0] == 'c-name': + self.c_name = arg[1] + elif arg[0] == 'gtype-id': + self.typecode = arg[1] + elif arg[0] == 'return-type': + self.ret = arg[1] + elif arg[0] == 'caller-owns-return': + self.caller_owns_return = arg[1] in ('t', '#t') + elif arg[0] == 'unblock-threads': + self.unblock_threads = arg[1] in ('t', '#t') + elif arg[0] == 'parameters': + for parg in arg[1:]: + ptype = parg[0] + pname = parg[1] + pdflt = None + pnull = 0 + pdir = None + keeprefcount = False + for farg in parg[2:]: + assert isinstance(farg, tuple) + if farg[0] == 'default': + pdflt = farg[1] + elif farg[0] == 'null-ok': + pnull = 1 + elif farg[0] == 'direction': + pdir = farg[1] + elif farg[0] == 'keep-refcount': + keeprefcount = True + self.params.append(Parameter(ptype, pname, pdflt, pnull, pdir, + keeprefcount=keeprefcount)) + elif arg[0] == 'varargs': + self.varargs = arg[1] in ('t', '#t') + elif arg[0] == 'deprecated': + self.deprecated = arg[1] + else: + sys.stderr.write("Warning: %s argument unsupported.\n" + % (arg[0])) + dump = 1 + if dump: + self.write_defs(sys.stderr) + + if self.caller_owns_return is None and self.ret is not None: + self.guess_return_value_ownership() + + def merge(self, old, parmerge): + self.caller_owns_return = old.caller_owns_return + self.varargs = old.varargs + # here we merge extra parameter flags accross to the new object. + if not parmerge: + self.params = copy.deepcopy(old.params) + return + for i in range(len(self.params)): + ptype, pname, pdflt, pnull = self.params[i] + for p2 in old.params: + if p2[1] == pname: + self.params[i] = (ptype, pname, p2[2], p2[3]) + break + def _write_defs(self, fp=sys.stdout): + if self.of_object != (None, None): + fp.write(' (of-object "' + self.of_object + '")\n') + if self.c_name: + fp.write(' (c-name "' + self.c_name + '")\n') + if self.typecode: + fp.write(' (gtype-id "' + self.typecode + '")\n') + if self.caller_owns_return: + fp.write(' (caller-owns-return #t)\n') + if self.unblock_threads: + fp.write(' (unblock_threads #t)\n') + if self.ret: + fp.write(' (return-type "' + self.ret + '")\n') + if self.deprecated: + fp.write(' (deprecated "' + self.deprecated + '")\n') + if self.params: + fp.write(' (parameters\n') + for ptype, pname, pdflt, pnull in self.params: + fp.write(' \'("' + ptype + '" "' + pname +'"') + if pdflt: fp.write(' (default "' + pdflt + '")') + if pnull: fp.write(' (null-ok)') + fp.write(')\n') + fp.write(' )\n') + if self.varargs: + fp.write(' (varargs #t)\n') + fp.write(')\n\n') + + +class MethodDef(MethodDefBase): + def __init__(self, name, *args): + MethodDefBase.__init__(self, name, *args) + for item in ('c_name', 'of_object'): + if self.__dict__[item] == None: + self.write_defs(sys.stderr) + raise RuntimeError, "definition missing required %s" % (item,) + + def write_defs(self, fp=sys.stdout): + fp.write('(define-method ' + self.name + '\n') + self._write_defs(fp) + +class VirtualDef(MethodDefBase): + def write_defs(self, fp=sys.stdout): + fp.write('(define-virtual ' + self.name + '\n') + self._write_defs(fp) + +class FunctionDef(Definition): + def __init__(self, name, *args): + dump = 0 + self.name = name + self.in_module = None + self.is_constructor_of = None + self.ret = None + self.caller_owns_return = None + self.unblock_threads = None + self.c_name = None + self.typecode = None + self.params = [] # of form (type, name, default, nullok) + self.varargs = 0 + self.deprecated = None + for arg in get_valid_scheme_definitions(args): + if arg[0] == 'in-module': + self.in_module = arg[1] + elif arg[0] == 'docstring': + self.docstring = make_docstring(arg[1:]) + elif arg[0] == 'is-constructor-of': + self.is_constructor_of = arg[1] + elif arg[0] == 'c-name': + self.c_name = arg[1] + elif arg[0] == 'gtype-id': + self.typecode = arg[1] + elif arg[0] == 'return-type': + self.ret = arg[1] + elif arg[0] == 'caller-owns-return': + self.caller_owns_return = arg[1] in ('t', '#t') + elif arg[0] == 'unblock-threads': + self.unblock_threads = arg[1] in ('t', '#t') + elif arg[0] == 'parameters': + for parg in arg[1:]: + ptype = parg[0] + pname = parg[1] + pdflt = None + pnull = 0 + keeprefcount = False + for farg in parg[2:]: + if farg[0] == 'default': + pdflt = farg[1] + elif farg[0] == 'null-ok': + pnull = 1 + elif farg[0] == 'keep-refcount': + keeprefcount = True + self.params.append(Parameter(ptype, pname, pdflt, pnull, + keeprefcount = keeprefcount)) + elif arg[0] == 'properties': + if self.is_constructor_of is None: + print >> sys.stderr, "Warning: (properties ...) "\ + "is only valid for constructors" + for prop in arg[1:]: + pname = prop[0] + optional = False + argname = pname + for farg in prop[1:]: + if farg[0] == 'optional': + optional = True + elif farg[0] == 'argname': + argname = farg[1] + self.params.append(Property(pname, optional, argname)) + elif arg[0] == 'varargs': + self.varargs = arg[1] in ('t', '#t') + elif arg[0] == 'deprecated': + self.deprecated = arg[1] + else: + sys.stderr.write("Warning: %s argument unsupported\n" + % (arg[0],)) + dump = 1 + if dump: + self.write_defs(sys.stderr) + + if self.caller_owns_return is None and self.ret is not None: + self.guess_return_value_ownership() + for item in ('c_name',): + if self.__dict__[item] == None: + self.write_defs(sys.stderr) + raise RuntimeError, "definition missing required %s" % (item,) + + _method_write_defs = MethodDef.__dict__['write_defs'] + + def merge(self, old, parmerge): + self.caller_owns_return = old.caller_owns_return + self.varargs = old.varargs + if not parmerge: + self.params = copy.deepcopy(old.params) + return + # here we merge extra parameter flags accross to the new object. + def merge_param(param): + for old_param in old.params: + if old_param.pname == param.pname: + if isinstance(old_param, Property): + # h2def never scans Property's, therefore if + # we have one it was manually written, so we + # keep it. + return copy.deepcopy(old_param) + else: + param.merge(old_param) + return param + raise RuntimeError, "could not find %s in old_parameters %r" % ( + param.pname, [p.pname for p in old.params]) + try: + self.params = map(merge_param, self.params) + except RuntimeError: + # parameter names changed and we can't find a match; it's + # safer to keep the old parameter list untouched. + self.params = copy.deepcopy(old.params) + + if not self.is_constructor_of: + try: + self.is_constructor_of = old.is_constructor_of + except AttributeError: + pass + if isinstance(old, MethodDef): + self.name = old.name + # transmogrify from function into method ... + self.write_defs = self._method_write_defs + self.of_object = old.of_object + del self.params[0] + def write_defs(self, fp=sys.stdout): + fp.write('(define-function ' + self.name + '\n') + if self.in_module: + fp.write(' (in-module "' + self.in_module + '")\n') + if self.is_constructor_of: + fp.write(' (is-constructor-of "' + self.is_constructor_of +'")\n') + if self.c_name: + fp.write(' (c-name "' + self.c_name + '")\n') + if self.typecode: + fp.write(' (gtype-id "' + self.typecode + '")\n') + if self.caller_owns_return: + fp.write(' (caller-owns-return #t)\n') + if self.unblock_threads: + fp.write(' (unblock-threads #t)\n') + if self.ret: + fp.write(' (return-type "' + self.ret + '")\n') + if self.deprecated: + fp.write(' (deprecated "' + self.deprecated + '")\n') + if self.params: + if isinstance(self.params[0], Parameter): + fp.write(' (parameters\n') + for ptype, pname, pdflt, pnull in self.params: + fp.write(' \'("' + ptype + '" "' + pname +'"') + if pdflt: fp.write(' (default "' + pdflt + '")') + if pnull: fp.write(' (null-ok)') + fp.write(')\n') + fp.write(' )\n') + elif isinstance(self.params[0], Property): + fp.write(' (properties\n') + for prop in self.params: + fp.write(' \'("' + prop.pname +'"') + if prop.optional: fp.write(' (optional)') + fp.write(')\n') + fp.write(' )\n') + else: + assert False, "strange parameter list %r" % self.params[0] + if self.varargs: + fp.write(' (varargs #t)\n') + + fp.write(')\n\n') diff --git a/bindings/python/codegen/defsparser.py b/bindings/python/codegen/defsparser.py new file mode 100644 index 0000000000..e24a969674 --- /dev/null +++ b/bindings/python/codegen/defsparser.py @@ -0,0 +1,143 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +import os, sys +import scmexpr +from definitions import BoxedDef, EnumDef, FlagsDef, FunctionDef, \ + InterfaceDef, MethodDef, ObjectDef, MiniObjectDef, PointerDef, \ + VirtualDef + +class IncludeParser(scmexpr.Parser): + """A simple parser that follows include statements automatically""" + def include(self, filename): + if not os.path.isabs(filename): + filename = os.path.join(os.path.dirname(self.filename), filename) + + # set self.filename to the include name, to handle recursive includes + oldfile = self.filename + self.filename = filename + self.startParsing() + self.filename = oldfile + +class DefsParser(IncludeParser): + def __init__(self, arg, defines={}): + IncludeParser.__init__(self, arg) + self.objects = [] + self.miniobjects = [] + self.interfaces = [] + self.enums = [] # enums and flags + self.boxes = [] # boxed types + self.pointers = [] # pointer types + self.functions = [] # functions and methods + self.virtuals = [] # virtual methods + self.c_name = {} # hash of c names of functions + self.methods = {} # hash of methods of particular objects + self.defines = defines # -Dfoo=bar options, as dictionary + + def define_object(self, *args): + odef = apply(ObjectDef, args) + self.objects.append(odef) + self.c_name[odef.c_name] = odef + # TODO: define_mini_object + def define_miniobject(self, *args): + odef = apply(MiniObjectDef, args) + self.miniobjects.append(odef) + self.c_name[odef.c_name] = odef + def define_interface(self, *args): + idef = apply(InterfaceDef, args) + self.interfaces.append(idef) + self.c_name[idef.c_name] = idef + def define_enum(self, *args): + edef = apply(EnumDef, args) + self.enums.append(edef) + self.c_name[edef.c_name] = edef + def define_flags(self, *args): + fdef = apply(FlagsDef, args) + self.enums.append(fdef) + self.c_name[fdef.c_name] = fdef + def define_boxed(self, *args): + bdef = apply(BoxedDef, args) + self.boxes.append(bdef) + self.c_name[bdef.c_name] = bdef + def define_pointer(self, *args): + pdef = apply(PointerDef, args) + self.pointers.append(pdef) + self.c_name[pdef.c_name] = pdef + def define_function(self, *args): + fdef = apply(FunctionDef, args) + self.functions.append(fdef) + self.c_name[fdef.c_name] = fdef + def define_method(self, *args): + mdef = apply(MethodDef, args) + self.functions.append(mdef) + self.c_name[mdef.c_name] = mdef + def define_virtual(self, *args): + vdef = apply(VirtualDef, args) + self.virtuals.append(vdef) + def merge(self, old, parmerge): + for obj in self.objects: + if old.c_name.has_key(obj.c_name): + obj.merge(old.c_name[obj.c_name]) + for f in self.functions: + if old.c_name.has_key(f.c_name): + f.merge(old.c_name[f.c_name], parmerge) + + def printMissing(self, old): + for obj in self.objects: + if not old.c_name.has_key(obj.c_name): + obj.write_defs() + for f in self.functions: + if not old.c_name.has_key(f.c_name): + f.write_defs() + + def write_defs(self, fp=sys.stdout): + for obj in self.objects: + obj.write_defs(fp) + # TODO: Add miniobject + for obj in self.miniobjects: + obj.write_defs(fp) + for enum in self.enums: + enum.write_defs(fp) + for boxed in self.boxes: + boxed.write_defs(fp) + for pointer in self.pointers: + pointer.write_defs(fp) + for func in self.functions: + func.write_defs(fp) + + def find_object(self, c_name): + for obj in self.objects: + if obj.c_name == c_name: + return obj + else: + raise ValueError, 'object not found' + + def find_constructor(self, obj, overrides): + for func in self.functions: + if isinstance(func, FunctionDef) and \ + func.is_constructor_of == obj.c_name and \ + not overrides.is_ignored(func.c_name): + return func + + def find_methods(self, obj): + objname = obj.c_name + return filter(lambda func, on=objname: isinstance(func, MethodDef) and + func.of_object == on, self.functions) + + def find_virtuals(self, obj): + objname = obj.c_name + retval = filter(lambda func, on=objname: isinstance(func, VirtualDef) and + func.of_object == on, self.virtuals) + return retval + + def find_functions(self): + return filter(lambda func: isinstance(func, FunctionDef) and + not func.is_constructor_of, self.functions) + + def ifdef(self, *args): + if args[0] in self.defines: + for arg in args[1:]: + self.handle(arg) + + def ifndef(self, *args): + if args[0] not in self.defines: + for arg in args[1:]: + self.handle(arg) diff --git a/bindings/python/codegen/docextract.py b/bindings/python/codegen/docextract.py new file mode 100644 index 0000000000..e6c65053d6 --- /dev/null +++ b/bindings/python/codegen/docextract.py @@ -0,0 +1,185 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +'''Simple module for extracting GNOME style doc comments from C +sources, so I can use them for other purposes.''' + +import sys, os, string, re + +__all__ = ['extract'] + +class FunctionDoc: + def __init__(self): + self.name = None + self.params = [] + self.description = '' + self.ret = '' + def set_name(self, name): + self.name = name + def add_param(self, name, description): + if name == '...': + name = 'Varargs' + self.params.append((name, description)) + def append_to_last_param(self, extra): + self.params[-1] = (self.params[-1][0], self.params[-1][1] + extra) + def append_to_named_param(self, name, extra): + for i in range(len(self.params)): + if self.params[i][0] == name: + self.params[i] = (name, self.params[i][1] + extra) + return + # fall through to adding extra parameter ... + self.add_param(name, extra) + def append_description(self, extra): + self.description = self.description + extra + def append_return(self, extra): + self.ret = self.ret + extra + + def get_param_description(self, name): + for param, description in self.params: + if param == name: + return description + else: + return '' + +comment_start_pat = re.compile(r'^\s*/\*\*\s') +comment_end_pat = re.compile(r'^\s*\*+/') +comment_line_lead = re.compile(r'^\s*\*\s*') +funcname_pat = re.compile(r'^(\w+)\s*:?') +return_pat = re.compile(r'^(returns:|return\s+value:|returns\s*)(.*\n?)$', + re.IGNORECASE) +param_pat = re.compile(r'^@(\S+)\s*:(.*\n?)$') + +def parse_file(fp, doc_dict): + line = fp.readline() + in_comment_block = 0 + while line: + if not in_comment_block: + if comment_start_pat.match(line): + in_comment_block = 1 + cur_doc = FunctionDoc() + in_description = 0 + in_return = 0 + line = fp.readline() + continue + + # we are inside a comment block ... + if comment_end_pat.match(line): + if not cur_doc.name: + sys.stderr.write("no function name found in doc comment\n") + else: + doc_dict[cur_doc.name] = cur_doc + in_comment_block = 0 + line = fp.readline() + continue + + # inside a comment block, and not the end of the block ... + line = comment_line_lead.sub('', line) + if not line: line = '\n' + + if not cur_doc.name: + match = funcname_pat.match(line) + if match: + cur_doc.set_name(match.group(1)) + elif in_return: + match = return_pat.match(line) + if match: + # assume the last return statement was really part of the + # description + return_start = match.group(1) + cur_doc.ret = match.group(2) + cur_doc.description = cur_doc.description + return_start + \ + cur_doc.ret + else: + cur_doc.append_return(line) + elif in_description: + if line[:12] == 'Description:': + line = line[12:] + match = return_pat.match(line) + if match: + in_return = 1 + return_start = match.group(1) + cur_doc.append_return(match.group(2)) + else: + cur_doc.append_description(line) + elif line == '\n': + # end of parameters + in_description = 1 + else: + match = param_pat.match(line) + if match: + param = match.group(1) + desc = match.group(2) + if param == 'returns': + cur_doc.ret = desc + else: + cur_doc.add_param(param, desc) + else: + # must be continuation + try: + if param == 'returns': + cur_doc.append_return(line) + else: + cur_doc.append_to_last_param(line) + except: + sys.stderr.write('something weird while reading param\n') + line = fp.readline() + +def parse_dir(dir, doc_dict): + for file in os.listdir(dir): + if file in ('.', '..'): continue + path = os.path.join(dir, file) + if os.path.isdir(path): + parse_dir(path, doc_dict) + if len(file) > 2 and file[-2:] == '.c': + parse_file(open(path, 'r'), doc_dict) + +def extract(dirs, doc_dict=None): + if not doc_dict: doc_dict = {} + for dir in dirs: + parse_dir(dir, doc_dict) + return doc_dict + +tmpl_section_pat = re.compile(r'^$') +def parse_tmpl(fp, doc_dict): + cur_doc = None + + line = fp.readline() + while line: + match = tmpl_section_pat.match(line) + if match: + cur_doc = None # new input shouldn't affect the old doc dict + sect_type = match.group(1) + sect_name = match.group(2) + + if sect_type == 'FUNCTION': + cur_doc = doc_dict.get(sect_name) + if not cur_doc: + cur_doc = FunctionDoc() + cur_doc.set_name(sect_name) + doc_dict[sect_name] = cur_doc + elif line == '\n': + cur_doc = None # don't worry about unused params. + elif cur_doc: + if line[:10] == '@Returns: ': + if string.strip(line[10:]): + cur_doc.append_return(line[10:]) + elif line[0] == '@': + pos = string.find(line, ':') + if pos >= 0: + cur_doc.append_to_named_param(line[1:pos], line[pos+1:]) + else: + cur_doc.append_description(line) + else: + cur_doc.append_description(line) + + line = fp.readline() + +def extract_tmpl(dirs, doc_dict=None): + if not doc_dict: doc_dict = {} + for dir in dirs: + for file in os.listdir(dir): + if file in ('.', '..'): continue + path = os.path.join(dir, file) + if os.path.isdir(path): + continue + if len(file) > 2 and file[-2:] == '.sgml': + parse_tmpl(open(path, 'r'), doc_dict) + return doc_dict diff --git a/bindings/python/codegen/docgen.py b/bindings/python/codegen/docgen.py new file mode 100644 index 0000000000..6905a14bf8 --- /dev/null +++ b/bindings/python/codegen/docgen.py @@ -0,0 +1,752 @@ +#!/usr/bin/env python +# -*- Mode: Python; py-indent-offset: 4 -*- +import sys, os, string, re, getopt + +import defsparser +import definitions +import override +import docextract + +class Node: + def __init__(self, name, interfaces=[]): + self.name = name + self.interfaces = interfaces + self.subclasses = [] + def add_child(self, node): + self.subclasses.append(node) + +def build_object_tree(parser): + # reorder objects so that parent classes come first ... + objects = parser.objects[:] + pos = 0 + while pos < len(objects): + parent = objects[pos].parent + for i in range(pos+1, len(objects)): + if objects[i].c_name == parent: + objects.insert(i+1, objects[pos]) + del objects[pos] + break + else: + pos = pos + 1 + + root = Node(None) + nodes = { None: root } + for obj_def in objects: + print obj_def.name + parent_node = nodes[obj_def.parent] + node = Node(obj_def.c_name, obj_def.implements) + parent_node.add_child(node) + nodes[node.name] = node + + if parser.interfaces: + interfaces = Node('gobject.GInterface') + root.add_child(interfaces) + nodes[interfaces.name] = interfaces + for obj_def in parser.interfaces: + node = Node(obj_def.c_name) + interfaces.add_child(node) + nodes[node.name] = node + + if parser.boxes: + boxed = Node('gobject.GBoxed') + root.add_child(boxed) + nodes[boxed.name] = boxed + for obj_def in parser.boxes: + node = Node(obj_def.c_name) + boxed.add_child(node) + nodes[node.name] = node + + if parser.pointers: + pointers = Node('gobject.GPointer') + root.add_child(pointers) + nodes[pointers.name] = pointers + for obj_def in parser.pointers: + node = Node(obj_def.c_name) + pointers.add_child(node) + nodes[node.name] = node + + return root + +class DocWriter: + def __init__(self): + # parse the defs file + self.parser = defsparser.DefsParser(()) + self.overrides = override.Overrides() + self.classmap = {} + self.docs = {} + + def add_sourcedirs(self, source_dirs): + self.docs = docextract.extract(source_dirs, self.docs) + def add_tmpldirs(self, tmpl_dirs): + self.docs = docextract.extract_tmpl(tmpl_dirs, self.docs) + + def add_docs(self, defs_file, overrides_file, module_name): + '''parse information about a given defs file''' + self.parser.filename = defs_file + self.parser.startParsing(defs_file) + if overrides_file: + self.overrides.handle_file(overrides_file) + + for obj in self.parser.objects: + if not self.classmap.has_key(obj.c_name): + self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name) + for obj in self.parser.interfaces: + if not self.classmap.has_key(obj.c_name): + self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name) + for obj in self.parser.boxes: + if not self.classmap.has_key(obj.c_name): + self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name) + for obj in self.parser.pointers: + if not self.classmap.has_key(obj.c_name): + self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name) + + def pyname(self, name): + return self.classmap.get(name, name) + + def __compare(self, obja, objb): + return cmp(self.pyname(obja.c_name), self.pyname(objb.c_name)) + def output_docs(self, output_prefix): + files = [] + + # class hierarchy + hierarchy = build_object_tree(self.parser) + filename = self.create_filename('hierarchy', output_prefix) + fp = open(filename, 'w') + self.write_full_hierarchy(hierarchy, fp) + fp.close() + + obj_defs = self.parser.objects + self.parser.interfaces + \ + self.parser.boxes + self.parser.pointers + obj_defs.sort(self.__compare) + for obj_def in obj_defs: + filename = self.create_filename(obj_def.c_name, output_prefix) + fp = open(filename, 'w') + if isinstance(obj_def, definitions.ObjectDef): + self.output_object_docs(obj_def, fp) + elif isinstance(obj_def, definitions.InterfaceDef): + self.output_interface_docs(obj_def, fp) + elif isinstance(obj_def, definitions.BoxedDef): + self.output_boxed_docs(obj_def, fp) + elif isinstance(obj_def, definitions.PointerDef): + self.output_boxed_docs(obj_def, fp) + fp.close() + files.append((os.path.basename(filename), obj_def)) + + if files: + filename = self.create_toc_filename(output_prefix) + fp = open(filename, 'w') + self.output_toc(files, fp) + fp.close() + + def output_object_docs(self, obj_def, fp=sys.stdout): + self.write_class_header(obj_def.c_name, fp) + + self.write_heading('Synopsis', fp) + self.write_synopsis(obj_def, fp) + self.close_section(fp) + + # construct the inheritence hierarchy ... + ancestry = [ (obj_def.c_name, obj_def.implements) ] + try: + parent = obj_def.parent + while parent != None: + if parent == 'GObject': + ancestry.append(('GObject', [])) + parent = None + else: + parent_def = self.parser.find_object(parent) + ancestry.append((parent_def.c_name, parent_def.implements)) + parent = parent_def.parent + except ValueError: + pass + ancestry.reverse() + self.write_heading('Ancestry', fp) + self.write_hierarchy(obj_def.c_name, ancestry, fp) + self.close_section(fp) + + constructor = self.parser.find_constructor(obj_def, self.overrides) + if constructor: + self.write_heading('Constructor', fp) + self.write_constructor(constructor, + self.docs.get(constructor.c_name, None), + fp) + self.close_section(fp) + + methods = self.parser.find_methods(obj_def) + methods = filter(lambda meth, self=self: + not self.overrides.is_ignored(meth.c_name), methods) + if methods: + self.write_heading('Methods', fp) + for method in methods: + self.write_method(method, self.docs.get(method.c_name, None), fp) + self.close_section(fp) + + self.write_class_footer(obj_def.c_name, fp) + + def output_interface_docs(self, int_def, fp=sys.stdout): + self.write_class_header(int_def.c_name, fp) + + self.write_heading('Synopsis', fp) + self.write_synopsis(int_def, fp) + self.close_section(fp) + + methods = self.parser.find_methods(int_def) + methods = filter(lambda meth, self=self: + not self.overrides.is_ignored(meth.c_name), methods) + if methods: + self.write_heading('Methods', fp) + for method in methods: + self.write_method(method, self.docs.get(method.c_name, None), fp) + self.close_section(fp) + + self.write_class_footer(int_def.c_name, fp) + + def output_boxed_docs(self, box_def, fp=sys.stdout): + self.write_class_header(box_def.c_name, fp) + + self.write_heading('Synopsis', fp) + self.write_synopsis(box_def, fp) + self.close_section(fp) + + constructor = self.parser.find_constructor(box_def, self.overrides) + if constructor: + self.write_heading('Constructor', fp) + self.write_constructor(constructor, + self.docs.get(constructor.c_name, None), + fp) + self.close_section(fp) + + methods = self.parser.find_methods(box_def) + methods = filter(lambda meth, self=self: + not self.overrides.is_ignored(meth.c_name), methods) + if methods: + self.write_heading('Methods', fp) + for method in methods: + self.write_method(method, self.docs.get(method.c_name, None), fp) + self.close_section(fp) + + self.write_class_footer(box_def.c_name, fp) + + def output_toc(self, files, fp=sys.stdout): + fp.write('TOC\n\n') + for filename, obj_def in files: + fp.write(obj_def.c_name + ' - ' + filename + '\n') + + # override the following to create a more complex output format + def create_filename(self, obj_name, output_prefix): + '''Create output filename for this particular object''' + return output_prefix + '-' + string.lower(obj_name) + '.txt' + def create_toc_filename(self, output_prefix): + return self.create_filename(self, 'docs', output_prefix) + + def write_full_hierarchy(self, hierarchy, fp): + def handle_node(node, fp, indent=''): + for child in node.subclasses: + fp.write(indent + node.name) + if node.interfaces: + fp.write(' (implements ') + fp.write(string.join(node.interfaces, ', ')) + fp.write(')\n') + else: + fp.write('\n') + handle_node(child, fp, indent + ' ') + handle_node(hierarchy, fp) + + # these need to handle default args ... + def create_constructor_prototype(self, func_def): + return func_def.is_constructor_of + '(' + \ + string.join(map(lambda x: x[1], func_def.params), ', ') + \ + ')' + def create_function_prototype(self, func_def): + return func_def.name + '(' + \ + string.join(map(lambda x: x[1], func_def.params), ', ') + \ + ')' + def create_method_prototype(self, meth_def): + return meth_def.of_object + '.' + \ + meth_def.name + '(' + \ + string.join(map(lambda x: x[1], meth_def.params), ', ') + \ + ')' + + def write_class_header(self, obj_name, fp): + fp.write('Class %s\n' % obj_name) + fp.write('======%s\n\n' % ('=' * len(obj_name))) + def write_class_footer(self, obj_name, fp): + pass + def write_heading(self, text, fp): + fp.write('\n' + text + '\n' + ('-' * len(text)) + '\n') + def close_section(self, fp): + pass + def write_synopsis(self, obj_def, fp): + fp.write('class %s' % obj_def.c_name) + if isinstance(obj_def, definitions.ObjectDef): + bases = [] + if obj_def.parent: bases.append(obj_def.parent) + bases = bases = obj_def.implements + if bases: + fp.write('(%s)' % string.join(bases, ', ')) + fp.write(':\n') + + constructor = self.parser.find_constructor(obj_def, self.overrides) + if constructor: + prototype = self.create_constructor_prototype(constructor) + fp.write(' def %s\n' % prototype) + methods = self.parser.find_methods(obj_def) + methods = filter(lambda meth, self=self: + not self.overrides.is_ignored(meth.c_name), methods) + for meth in methods: + prototype = self.create_method_prototype(meth) + fp.write(' def %s\n' % prototype) + + def write_hierarchy(self, obj_name, ancestry, fp): + indent = '' + for name, interfaces in ancestry: + fp.write(indent + '+-- ' + name) + if interfaces: + fp.write(' (implements ') + fp.write(string.join(interfaces, ', ')) + fp.write(')\n') + else: + fp.write('\n') + indent = indent + ' ' + fp.write('\n') + def write_constructor(self, func_def, func_doc, fp): + prototype = self.create_constructor_prototype(func_def) + fp.write(prototype + '\n\n') + for type, name, dflt, null in func_def.params: + if func_doc: + descr = func_doc.get_param_description(name) + else: + descr = 'a ' + type + fp.write(' ' + name + ': ' + descr + '\n') + if func_def.ret and func_def.ret != 'none': + if func_doc and func_doc.ret: + descr = func_doc.ret + else: + descr = 'a ' + func_def.ret + fp.write(' Returns: ' + descr + '\n') + if func_doc and func_doc.description: + fp.write(func_doc.description) + fp.write('\n\n\n') + def write_method(self, meth_def, func_doc, fp): + prototype = self.create_method_prototype(meth_def) + fp.write(prototype + '\n\n') + for type, name, dflt, null in meth_def.params: + if func_doc: + descr = func_doc.get_param_description(name) + else: + descr = 'a ' + type + fp.write(' ' + name + ': ' + descr + '\n') + if meth_def.ret and meth_def.ret != 'none': + if func_doc and func_doc.ret: + descr = func_doc.ret + else: + descr = 'a ' + meth_def.ret + fp.write(' Returns: ' + descr + '\n') + if func_doc and func_doc.description: + fp.write('\n') + fp.write(func_doc.description) + fp.write('\n\n') + +class DocbookDocWriter(DocWriter): + def __init__(self, use_xml=0): + DocWriter.__init__(self) + self.use_xml = use_xml + + def create_filename(self, obj_name, output_prefix): + '''Create output filename for this particular object''' + stem = output_prefix + '-' + string.lower(obj_name) + if self.use_xml: + return stem + '.xml' + else: + return stem + '.sgml' + def create_toc_filename(self, output_prefix): + if self.use_xml: + return self.create_filename('classes', output_prefix) + else: + return self.create_filename('docs', output_prefix) + + # make string -> reference translation func + __transtable = [ '-' ] * 256 + for digit in '0123456789': + __transtable[ord(digit)] = digit + for letter in 'abcdefghijklmnopqrstuvwxyz': + __transtable[ord(letter)] = letter + __transtable[ord(string.upper(letter))] = letter + __transtable = string.join(__transtable, '') + + def make_class_ref(self, obj_name): + return 'class-' + string.translate(obj_name, self.__transtable) + def make_method_ref(self, meth_def): + return 'method-' + string.translate(meth_def.of_object, + self.__transtable) + \ + '--' + string.translate(meth_def.name, self.__transtable) + + __function_pat = re.compile(r'(\w+)\s*\(\)') + def __format_function(self, match): + info = self.parser.c_name.get(match.group(1), None) + if info: + if isinstance(info, defsparser.FunctionDef): + if info.is_constructor_of is not None: + # should have a link here + return '%s()' % \ + self.pyname(info.is_constructor_of) + else: + return '' + info.name + '()' + if isinstance(info, defsparser.MethodDef): + return '' + self.pyname(info.of_object) + '.' + \ + info.name + '()' + # fall through through + return '' + match.group(1) + '()' + __parameter_pat = re.compile(r'\@(\w+)') + def __format_param(self, match): + return '' + match.group(1) + '' + __constant_pat = re.compile(r'\%(-?\w+)') + def __format_const(self, match): + return '' + match.group(1) + '' + __symbol_pat = re.compile(r'#([\w-]+)') + def __format_symbol(self, match): + info = self.parser.c_name.get(match.group(1), None) + if info: + if isinstance(info, defsparser.FunctionDef): + if info.is_constructor_of is not None: + # should have a link here + return '' + self.pyname(info.is_constructor_of) + \ + '' + else: + return '' + info.name + '' + if isinstance(info, defsparser.MethodDef): + return '' + self.pyname(info.of_object) + '.' + \ + info.name + '' + if isinstance(info, defsparser.ObjectDef) or \ + isinstance(info, defsparser.InterfaceDef) or \ + isinstance(info, defsparser.BoxedDef) or \ + isinstance(info, defsparser.PointerDef): + return '' + self.pyname(info.c_name) + \ + '' + # fall through through + return '' + match.group(1) + '' + + def reformat_text(self, text, singleline=0): + # replace special strings ... + text = self.__function_pat.sub(self.__format_function, text) + text = self.__parameter_pat.sub(self.__format_param, text) + text = self.__constant_pat.sub(self.__format_const, text) + text = self.__symbol_pat.sub(self.__format_symbol, text) + + # don't bother with expansion for single line text. + if singleline: return text + + lines = string.split(string.strip(text), '\n') + for index in range(len(lines)): + if string.strip(lines[index]) == '': + lines[index] = '\n' + continue + lines.insert(0, '') + lines.append('') + return string.join(lines, '\n') + + # write out hierarchy + def write_full_hierarchy(self, hierarchy, fp): + def handle_node(node, fp, indent=''): + if node.name: + fp.write('%s%s' % + (indent, self.make_class_ref(node.name), + self.pyname(node.name))) + if node.interfaces: + fp.write(' (implements ') + for i in range(len(node.interfaces)): + fp.write('%s' % + (self.make_class_ref(node.interfaces[i]), + self.pyname(node.interfaces[i]))) + if i != len(node.interfaces) - 1: + fp.write(', ') + fp.write(')\n') + else: + fp.write('\n') + + indent = indent + ' ' + node.subclasses.sort(lambda a,b: + cmp(self.pyname(a.name), self.pyname(b.name))) + for child in node.subclasses: + handle_node(child, fp, indent) + if self.use_xml: + fp.write('\n') + fp.write('\n') + fp.write('') + handle_node(hierarchy, fp) + fp.write('\n') + + # these need to handle default args ... + def create_constructor_prototype(self, func_def): + sgml = [ '\n'] + sgml.append(' __init__\n') + for type, name, dflt, null in func_def.params: + sgml.append(' ') + sgml.append(name) + sgml.append('') + if dflt: + sgml.append('') + sgml.append(dflt) + sgml.append('') + sgml.append('\n') + if not func_def.params: + sgml.append(' ') + sgml.append(' ') + return string.join(sgml, '') + def create_function_prototype(self, func_def): + sgml = [ '\n \n'] + sgml.append(' ') + sgml.append(func_def.name) + sgml.append('\n') + for type, name, dflt, null in func_def.params: + sgml.append(' ') + sgml.append(name) + sgml.append('') + if dflt: + sgml.append('') + sgml.append(dflt) + sgml.append('') + sgml.append('\n') + if not func_def.params: + sgml.append(' \n ') + return string.join(sgml, '') + def create_method_prototype(self, meth_def, addlink=0): + sgml = [ '\n'] + sgml.append(' ') + if addlink: + sgml.append('' % self.make_method_ref(meth_def)) + sgml.append(self.pyname(meth_def.name)) + if addlink: + sgml.append('') + sgml.append('\n') + for type, name, dflt, null in meth_def.params: + sgml.append(' ') + sgml.append(name) + sgml.append('') + if dflt: + sgml.append('') + sgml.append(dflt) + sgml.append('') + sgml.append('\n') + if not meth_def.params: + sgml.append(' ') + sgml.append(' ') + return string.join(sgml, '') + + def write_class_header(self, obj_name, fp): + if self.use_xml: + fp.write('\n') + fp.write('\n') + fp.write('\n') + fp.write(' \n') + fp.write(' %s\n' + % self.pyname(obj_name)) + fp.write(' 3\n') + fp.write(' PyGTK Docs\n') + fp.write(' \n\n') + fp.write(' \n') + fp.write(' %s\n' + % self.pyname(obj_name)) + fp.write(' \n\n') + def write_class_footer(self, obj_name, fp): + fp.write('\n') + def write_heading(self, text, fp): + fp.write(' \n') + fp.write(' ' + text + '\n\n') + def close_section(self, fp): + fp.write(' \n') + + def write_synopsis(self, obj_def, fp): + fp.write('\n') + fp.write(' %s\n' + % self.pyname(obj_def.c_name)) + if isinstance(obj_def, definitions.ObjectDef): + if obj_def.parent: + fp.write(' %s' + '\n' + % (self.make_class_ref(obj_def.parent), + self.pyname(obj_def.parent))) + for base in obj_def.implements: + fp.write(' %s' + '\n' + % (self.make_class_ref(base), self.pyname(base))) + elif isinstance(obj_def, definitions.InterfaceDef): + fp.write(' gobject.GInterface' + '\n') + elif isinstance(obj_def, definitions.BoxedDef): + fp.write(' gobject.GBoxed' + '\n') + elif isinstance(obj_def, definitions.PointerDef): + fp.write(' gobject.GPointer' + '\n') + + constructor = self.parser.find_constructor(obj_def, self.overrides) + if constructor: + fp.write('%s\n' % self.create_constructor_prototype(constructor)) + methods = self.parser.find_methods(obj_def) + methods = filter(lambda meth, self=self: + not self.overrides.is_ignored(meth.c_name), methods) + for meth in methods: + fp.write('%s\n' % self.create_method_prototype(meth, addlink=1)) + fp.write('\n\n') + + def write_hierarchy(self, obj_name, ancestry, fp): + fp.write('') + indent = '' + for name, interfaces in ancestry: + fp.write(indent + '+-- '+ self.pyname(name) + '') + if interfaces: + fp.write(' (implements ') + for i in range(len(interfaces)): + fp.write('%s' % + (self.make_class_ref(interfaces[i]), + self.pyname(interfaces[i]))) + if i != len(interfaces) - 1: + fp.write(', ') + fp.write(')\n') + else: + fp.write('\n') + indent = indent + ' ' + fp.write('\n\n') + + def write_params(self, params, ret, func_doc, fp): + if not params and (not ret or ret == 'none'): + return + fp.write(' \n') + for type, name, dflt, null in params: + if func_doc: + descr = string.strip(func_doc.get_param_description(name)) + else: + descr = 'a ' + type + fp.write(' \n') + fp.write(' %s :\n' % name) + fp.write(' %s\n' % + self.reformat_text(descr, singleline=1)) + fp.write(' \n') + if ret and ret != 'none': + if func_doc and func_doc.ret: + descr = string.strip(func_doc.ret) + else: + descr = 'a ' + ret + fp.write(' \n') + fp.write(' Returns :\n') + fp.write(' %s\n' % + self.reformat_text(descr, singleline=1)) + fp.write(' \n') + fp.write(' \n') + + def write_constructor(self, func_def, func_doc, fp): + prototype = self.create_constructor_prototype(func_def) + fp.write('%s\n' % prototype) + self.write_params(func_def.params, func_def.ret, func_doc, fp) + + if func_doc and func_doc.description: + fp.write(self.reformat_text(func_doc.description)) + fp.write('\n\n\n') + + def write_method(self, meth_def, func_doc, fp): + fp.write(' \n') + fp.write(' ' + self.pyname(meth_def.of_object) + '.' + + meth_def.name + '\n\n') + prototype = self.create_method_prototype(meth_def) + fp.write('%s\n' % prototype) + self.write_params(meth_def.params, meth_def.ret, func_doc, fp) + if func_doc and func_doc.description: + fp.write(self.reformat_text(func_doc.description)) + fp.write(' \n\n\n') + + def output_toc(self, files, fp=sys.stdout): + if self.use_xml: + fp.write('\n') + fp.write('\n') + #for filename, obj_def in files: + # fp.write(' \n') + #fp.write(']>\n\n') + + #fp.write('\n') + #fp.write(' Class Documentation\n') + #for filename, obj_def in files: + # fp.write('&' + string.translate(obj_def.c_name, + # self.__transtable) + ';\n') + #fp.write('\n') + + fp.write('\n') + fp.write(' Class Reference\n') + for filename, obj_def in files: + fp.write(' \n' % filename) + fp.write('\n') + else: + fp.write('\n') + fp.write(']>\n\n') + + fp.write('\n\n') + fp.write(' \n') + fp.write(' PyGTK Docs\n') + fp.write(' \n') + fp.write(' \n') + fp.write(' James\n') + fp.write(' Henstridge\n') + fp.write(' \n') + fp.write(' \n') + fp.write(' \n\n') + + fp.write(' \n') + fp.write(' Class Hierarchy\n') + fp.write(' Not done yet\n') + fp.write(' \n\n') + + fp.write(' \n') + fp.write(' Class Documentation\n') + for filename, obj_def in files: + fp.write('&' + string.translate(obj_def.c_name, + self.__transtable) + ';\n') + + fp.write(' \n') + fp.write('\n') + +if __name__ == '__main__': + try: + opts, args = getopt.getopt(sys.argv[1:], "d:s:o:", + ["defs-file=", "override=", "source-dir=", + "output-prefix="]) + except getopt.error, e: + sys.stderr.write('docgen.py: %s\n' % e) + sys.stderr.write( + 'usage: docgen.py -d file.defs [-s /src/dir] [-o output-prefix]\n') + sys.exit(1) + defs_file = None + overrides_file = None + source_dirs = [] + output_prefix = 'docs' + for opt, arg in opts: + if opt in ('-d', '--defs-file'): + defs_file = arg + if opt in ('--override',): + overrides_file = arg + elif opt in ('-s', '--source-dir'): + source_dirs.append(arg) + elif opt in ('-o', '--output-prefix'): + output_prefix = arg + if len(args) != 0 or not defs_file: + sys.stderr.write( + 'usage: docgen.py -d file.defs [-s /src/dir] [-o output-prefix]\n') + sys.exit(1) + + d = DocbookDocWriter() + d.add_sourcedirs(source_dirs) + d.add_docs(defs_file, overrides_file, 'gtk') + d.output_docs(output_prefix) diff --git a/bindings/python/codegen/fileprefix.override b/bindings/python/codegen/fileprefix.override new file mode 100644 index 0000000000..4e280c5e6c --- /dev/null +++ b/bindings/python/codegen/fileprefix.override @@ -0,0 +1,12 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- */ +%% +headers +/* include any required headers here */ +%% +init + /* include any code here that needs to be executed before the + * extension classes get initialised */ +%% + +/* you should add appropriate ignore, ignore-glob and + * override sections here */ diff --git a/bindings/python/codegen/fileprefixmodule.c b/bindings/python/codegen/fileprefixmodule.c new file mode 100644 index 0000000000..4361d6484d --- /dev/null +++ b/bindings/python/codegen/fileprefixmodule.c @@ -0,0 +1,31 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include + +/* include any extra headers needed here */ + +void prefix_register_classes(PyObject *d); +extern PyMethodDef prefix_functions[]; + +DL_EXPORT(void) +initmodule(void) +{ + PyObject *m, *d; + + /* perform any initialisation required by the library here */ + + m = Py_InitModule("module", prefix_functions); + d = PyModule_GetDict(m); + + init_pygtk(); + + prefix_register_classes(d); + + /* add anything else to the module dictionary (such as constants) */ + + if (PyErr_Occurred()) + Py_FatalError("could not initialise module module"); +} diff --git a/bindings/python/codegen/h2def.py b/bindings/python/codegen/h2def.py new file mode 100755 index 0000000000..d4b21356c2 --- /dev/null +++ b/bindings/python/codegen/h2def.py @@ -0,0 +1,536 @@ +#!/usr/bin/env python +# -*- Mode: Python; py-indent-offset: 4 -*- +# Search through a header file looking for function prototypes. +# For each prototype, generate a scheme style definition. +# GPL'ed +# Toby D. Reeves +# +# Modified by James Henstridge to output stuff in +# Havoc's new defs format. Info on this format can be seen at: +# http://www.gnome.org/mailing-lists/archives/gtk-devel-list/2000-January/0085.shtml +# Updated to be PEP-8 compatible and refactored to use OOP + +import getopt +import os +import re +import string +import sys + +import defsparser + +# ------------------ Create typecodes from typenames --------- + +_upperstr_pat1 = re.compile(r'([^A-Z])([A-Z])') +_upperstr_pat2 = re.compile(r'([A-Z][A-Z])([A-Z][0-9a-z])') +_upperstr_pat3 = re.compile(r'^([A-Z])([A-Z])') + +def to_upper_str(name): + """Converts a typename to the equivalent upercase and underscores + name. This is used to form the type conversion macros and enum/flag + name variables""" + name = _upperstr_pat1.sub(r'\1_\2', name) + name = _upperstr_pat2.sub(r'\1_\2', name) + name = _upperstr_pat3.sub(r'\1_\2', name, count=1) + return string.upper(name) + +def typecode(typename): + """create a typecode (eg. GTK_TYPE_WIDGET) from a typename""" + return string.replace(to_upper_str(typename), '_', '_TYPE_', 1) + + +# ------------------ Find object definitions ----------------- + +def strip_comments(buf): + parts = [] + lastpos = 0 + while 1: + pos = string.find(buf, '/*', lastpos) + if pos >= 0: + parts.append(buf[lastpos:pos]) + pos = string.find(buf, '*/', pos) + if pos >= 0: + lastpos = pos + 2 + else: + break + else: + parts.append(buf[lastpos:]) + break + return string.join(parts, '') + +obj_name_pat = "[A-Z][a-z]*[A-Z][A-Za-z0-9]*" + +split_prefix_pat = re.compile('([A-Z]+[a-z]*)([A-Za-z0-9]+)') + +def find_obj_defs(buf, objdefs=[]): + """ + Try to find object definitions in header files. + """ + + # filter out comments from buffer. + buf = strip_comments(buf) + + maybeobjdefs = [] # contains all possible objects from file + + # first find all structures that look like they may represent a GtkObject + pat = re.compile("struct _(" + obj_name_pat + ")\s*{\s*" + + "(" + obj_name_pat + ")\s+", re.MULTILINE) + pos = 0 + while pos < len(buf): + m = pat.search(buf, pos) + if not m: break + maybeobjdefs.append((m.group(1), m.group(2))) + pos = m.end() + + # handle typedef struct { ... } style struct defs. + pat = re.compile("typedef struct\s+[_\w]*\s*{\s*" + + "(" + obj_name_pat + ")\s+[^}]*}\s*" + + "(" + obj_name_pat + ")\s*;", re.MULTILINE) + pos = 0 + while pos < len(buf): + m = pat.search(buf, pos) + if not m: break + maybeobjdefs.append((m.group(2), m.group(2))) + pos = m.end() + + # now find all structures that look like they might represent a class: + pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" + + "(" + obj_name_pat + ")Class\s+", re.MULTILINE) + pos = 0 + while pos < len(buf): + m = pat.search(buf, pos) + if not m: break + t = (m.group(1), m.group(2)) + # if we find an object structure together with a corresponding + # class structure, then we have probably found a GtkObject subclass. + if t in maybeobjdefs: + objdefs.append(t) + pos = m.end() + + pat = re.compile("typedef struct\s+[_\w]*\s*{\s*" + + "(" + obj_name_pat + ")Class\s+[^}]*}\s*" + + "(" + obj_name_pat + ")Class\s*;", re.MULTILINE) + pos = 0 + while pos < len(buf): + m = pat.search(buf, pos) + if not m: break + t = (m.group(2), m.group(1)) + # if we find an object structure together with a corresponding + # class structure, then we have probably found a GtkObject subclass. + if t in maybeobjdefs: + objdefs.append(t) + pos = m.end() + + # now find all structures that look like they might represent + # a class inherited from GTypeInterface: + pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" + + "GTypeInterface\s+", re.MULTILINE) + pos = 0 + while pos < len(buf): + m = pat.search(buf, pos) + if not m: break + t = (m.group(1), '') + t2 = (m.group(1)+'Class', 'GTypeInterface') + # if we find an object structure together with a corresponding + # class structure, then we have probably found a GtkObject subclass. + if t2 in maybeobjdefs: + objdefs.append(t) + pos = m.end() + + # now find all structures that look like they might represent + # an Iface inherited from GTypeInterface: + pat = re.compile("struct _(" + obj_name_pat + ")Iface\s*{\s*" + + "GTypeInterface\s+", re.MULTILINE) + pos = 0 + while pos < len(buf): + m = pat.search(buf, pos) + if not m: break + t = (m.group(1), '') + t2 = (m.group(1)+'Iface', 'GTypeInterface') + # if we find an object structure together with a corresponding + # class structure, then we have probably found a GtkObject subclass. + if t2 in maybeobjdefs: + objdefs.append(t) + pos = m.end() + +def sort_obj_defs(objdefs): + objdefs.sort() # not strictly needed, but looks nice + pos = 0 + while pos < len(objdefs): + klass,parent = objdefs[pos] + for i in range(pos+1, len(objdefs)): + # parent below subclass ... reorder + if objdefs[i][0] == parent: + objdefs.insert(i+1, objdefs[pos]) + del objdefs[pos] + break + else: + pos = pos + 1 + return objdefs + +# ------------------ Find enum definitions ----------------- + +def find_enum_defs(buf, enums=[]): + # strip comments + # bulk comments + buf = strip_comments(buf) + + buf = re.sub('\n', ' ', buf) + + enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)') + splitter = re.compile(r'\s*,\s', re.MULTILINE) + pos = 0 + while pos < len(buf): + m = enum_pat.search(buf, pos) + if not m: break + + name = m.group(2) + vals = m.group(1) + isflags = string.find(vals, '<<') >= 0 + entries = [] + for val in splitter.split(vals): + if not string.strip(val): continue + entries.append(string.split(val)[0]) + if name != 'GdkCursorType': + enums.append((name, isflags, entries)) + + pos = m.end() + +# ------------------ Find function definitions ----------------- + +def clean_func(buf): + """ + Ideally would make buf have a single prototype on each line. + Actually just cuts out a good deal of junk, but leaves lines + where a regex can figure prototypes out. + """ + # bulk comments + buf = strip_comments(buf) + + # compact continued lines + pat = re.compile(r"""\\\n""", re.MULTILINE) + buf = pat.sub('', buf) + + # Preprocess directives + pat = re.compile(r"""^[#].*?$""", re.MULTILINE) + buf = pat.sub('', buf) + + #typedefs, stucts, and enums + pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""", + re.MULTILINE) + buf = pat.sub('', buf) + + #strip DECLS macros + pat = re.compile(r"""G_BEGIN_DECLS|BEGIN_LIBGTOP_DECLS""", re.MULTILINE) + buf = pat.sub('', buf) + + #extern "C" + pat = re.compile(r"""^\s*(extern)\s+\"C\"\s+{""", re.MULTILINE) + buf = pat.sub('', buf) + + #multiple whitespace + pat = re.compile(r"""\s+""", re.MULTILINE) + buf = pat.sub(' ', buf) + + #clean up line ends + pat = re.compile(r""";\s*""", re.MULTILINE) + buf = pat.sub('\n', buf) + buf = buf.lstrip() + + #associate *, &, and [] with type instead of variable + #pat = re.compile(r'\s+([*|&]+)\s*(\w+)') + pat = re.compile(r' \s* ([*|&]+) \s* (\w+)', re.VERBOSE) + buf = pat.sub(r'\1 \2', buf) + pat = re.compile(r'\s+ (\w+) \[ \s* \]', re.VERBOSE) + buf = pat.sub(r'[] \1', buf) + + # make return types that are const work. + buf = string.replace(buf, 'G_CONST_RETURN ', 'const-') + buf = string.replace(buf, 'const ', 'const-') + + return buf + +proto_pat=re.compile(r""" +(?P(-|\w|\&|\*)+\s*) # return type +\s+ # skip whitespace +(?P\w+)\s*[(] # match the function name until the opening ( +\s*(?P.*?)\s*[)] # group the function arguments +""", re.IGNORECASE|re.VERBOSE) +#""" +arg_split_pat = re.compile("\s*,\s*") + +get_type_pat = re.compile(r'(const-)?([A-Za-z0-9]+)\*?\s+') +pointer_pat = re.compile('.*\*$') +func_new_pat = re.compile('(\w+)_new$') + +class DefsWriter: + def __init__(self, fp=None, prefix=None, verbose=False, + defsfilter=None): + if not fp: + fp = sys.stdout + + self.fp = fp + self.prefix = prefix + self.verbose = verbose + + self._enums = {} + self._objects = {} + self._functions = {} + if defsfilter: + filter = defsparser.DefsParser(defsfilter) + filter.startParsing() + for func in filter.functions + filter.methods.values(): + self._functions[func.c_name] = func + for obj in filter.objects + filter.boxes + filter.interfaces: + self._objects[obj.c_name] = func + for obj in filter.enums: + self._enums[obj.c_name] = func + + def write_def(self, deffile): + buf = open(deffile).read() + + self.fp.write('\n;; From %s\n\n' % os.path.basename(deffile)) + self._define_func(buf) + self.fp.write('\n') + + def write_enum_defs(self, enums, fp=None): + if not fp: + fp = self.fp + + fp.write(';; Enumerations and flags ...\n\n') + trans = string.maketrans(string.uppercase + '_', + string.lowercase + '-') + filter = self._enums + for cname, isflags, entries in enums: + if filter: + if cname in filter: + continue + name = cname + module = None + m = split_prefix_pat.match(cname) + if m: + module = m.group(1) + name = m.group(2) + if isflags: + fp.write('(define-flags ' + name + '\n') + else: + fp.write('(define-enum ' + name + '\n') + if module: + fp.write(' (in-module "' + module + '")\n') + fp.write(' (c-name "' + cname + '")\n') + fp.write(' (gtype-id "' + typecode(cname) + '")\n') + prefix = entries[0] + for ent in entries: + # shorten prefix til we get a match ... + # and handle GDK_FONT_FONT, GDK_FONT_FONTSET case + while ent[:len(prefix)] != prefix or len(prefix) >= len(ent): + prefix = prefix[:-1] + prefix_len = len(prefix) + fp.write(' (values\n') + for ent in entries: + fp.write(' \'("%s" "%s")\n' % + (string.translate(ent[prefix_len:], trans), ent)) + fp.write(' )\n') + fp.write(')\n\n') + + def write_obj_defs(self, objdefs, fp=None): + if not fp: + fp = self.fp + + fp.write(';; -*- scheme -*-\n') + fp.write('; object definitions ...\n') + + filter = self._objects + for klass, parent in objdefs: + if filter: + if klass in filter: + continue + m = split_prefix_pat.match(klass) + cmodule = None + cname = klass + if m: + cmodule = m.group(1) + cname = m.group(2) + fp.write('(define-object ' + cname + '\n') + if cmodule: + fp.write(' (in-module "' + cmodule + '")\n') + if parent: + fp.write(' (parent "' + parent + '")\n') + fp.write(' (c-name "' + klass + '")\n') + fp.write(' (gtype-id "' + typecode(klass) + '")\n') + # should do something about accessible fields + fp.write(')\n\n') + + def _define_func(self, buf): + buf = clean_func(buf) + buf = string.split(buf,'\n') + filter = self._functions + for p in buf: + if not p: + continue + m = proto_pat.match(p) + if m == None: + if self.verbose: + sys.stderr.write('No match:|%s|\n' % p) + continue + func = m.group('func') + if func[0] == '_': + continue + if filter: + if func in filter: + continue + ret = m.group('ret') + args = m.group('args') + args = arg_split_pat.split(args) + for i in range(len(args)): + spaces = string.count(args[i], ' ') + if spaces > 1: + args[i] = string.replace(args[i], ' ', '-', spaces - 1) + + self._write_func(func, ret, args) + + def _write_func(self, name, ret, args): + if len(args) >= 1: + # methods must have at least one argument + munged_name = name.replace('_', '') + m = get_type_pat.match(args[0]) + if m: + obj = m.group(2) + if munged_name[:len(obj)] == obj.lower(): + self._write_method(obj, name, ret, args) + return + + if self.prefix: + l = len(self.prefix) + if name[:l] == self.prefix and name[l] == '_': + fname = name[l+1:] + else: + fname = name + else: + fname = name + + # it is either a constructor or normal function + self.fp.write('(define-function ' + fname + '\n') + self.fp.write(' (c-name "' + name + '")\n') + + # Hmmm... Let's asume that a constructor function name + # ends with '_new' and it returns a pointer. + m = func_new_pat.match(name) + if pointer_pat.match(ret) and m: + cname = '' + for s in m.group(1).split ('_'): + cname += s.title() + if cname != '': + self.fp.write(' (is-constructor-of "' + cname + '")\n') + + self._write_return(ret) + self._write_arguments(args) + + def _write_method(self, obj, name, ret, args): + regex = string.join(map(lambda x: x+'_?', string.lower(obj)),'') + mname = re.sub(regex, '', name, 1) + if self.prefix: + l = len(self.prefix) + 1 + if mname[:l] == self.prefix and mname[l+1] == '_': + mname = mname[l+1:] + self.fp.write('(define-method ' + mname + '\n') + self.fp.write(' (of-object "' + obj + '")\n') + self.fp.write(' (c-name "' + name + '")\n') + self._write_return(ret) + self._write_arguments(args[1:]) + + def _write_return(self, ret): + if ret != 'void': + self.fp.write(' (return-type "' + ret + '")\n') + else: + self.fp.write(' (return-type "none")\n') + + def _write_arguments(self, args): + is_varargs = 0 + has_args = len(args) > 0 + for arg in args: + if arg == '...': + is_varargs = 1 + elif arg in ('void', 'void '): + has_args = 0 + if has_args: + self.fp.write(' (parameters\n') + for arg in args: + if arg != '...': + tupleArg = tuple(string.split(arg)) + if len(tupleArg) == 2: + self.fp.write(' \'("%s" "%s")\n' % tupleArg) + self.fp.write(' )\n') + if is_varargs: + self.fp.write(' (varargs #t)\n') + self.fp.write(')\n\n') + +# ------------------ Main function ----------------- + +def main(args): + verbose = False + onlyenums = False + onlyobjdefs = False + separate = False + modulename = None + defsfilter = None + opts, args = getopt.getopt(args[1:], 'vs:m:f:', + ['onlyenums', 'onlyobjdefs', + 'modulename=', 'separate=', + 'defsfilter=']) + for o, v in opts: + if o == '-v': + verbose = True + if o == '--onlyenums': + onlyenums = True + if o == '--onlyobjdefs': + onlyobjdefs = True + if o in ('-s', '--separate'): + separate = v + if o in ('-m', '--modulename'): + modulename = v + if o in ('-f', '--defsfilter'): + defsfilter = v + + if not args[0:1]: + print 'Must specify at least one input file name' + return -1 + + # read all the object definitions in + objdefs = [] + enums = [] + for filename in args: + buf = open(filename).read() + find_obj_defs(buf, objdefs) + find_enum_defs(buf, enums) + objdefs = sort_obj_defs(objdefs) + + if separate: + methods = file(separate + '.defs', 'w') + types = file(separate + '-types.defs', 'w') + + dw = DefsWriter(methods, prefix=modulename, verbose=verbose, + defsfilter=defsfilter) + dw.write_obj_defs(objdefs, types) + dw.write_enum_defs(enums, types) + print "Wrote %s-types.defs" % separate + + for filename in args: + dw.write_def(filename) + print "Wrote %s.defs" % separate + else: + dw = DefsWriter(prefix=modulename, verbose=verbose, + defsfilter=defsfilter) + + if onlyenums: + dw.write_enum_defs(enums) + elif onlyobjdefs: + dw.write_obj_defs(objdefs) + else: + dw.write_obj_defs(objdefs) + dw.write_enum_defs(enums) + + for filename in args: + dw.write_def(filename) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/bindings/python/codegen/mergedefs.py b/bindings/python/codegen/mergedefs.py new file mode 100755 index 0000000000..773e499bb0 --- /dev/null +++ b/bindings/python/codegen/mergedefs.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# -*- Mode: Python; py-indent-offset: 4 -*- + +import optparse + +import defsparser + +parser = optparse.OptionParser( + usage="usage: %prog [options] generated-defs old-defs") +parser.add_option("-p", "--merge-parameters", + help="Merge changes in function/methods parameter lists", + action="store_true", dest="parmerge", default=False) +(options, args) = parser.parse_args() + +if len(args) != 2: + parser.error("wrong number of arguments") + +newp = defsparser.DefsParser(args[0]) +oldp = defsparser.DefsParser(args[1]) + +newp.startParsing() +oldp.startParsing() + +newp.merge(oldp, options.parmerge) + +newp.write_defs() diff --git a/bindings/python/codegen/mkskel.py b/bindings/python/codegen/mkskel.py new file mode 100755 index 0000000000..61f520bf73 --- /dev/null +++ b/bindings/python/codegen/mkskel.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# -*- Mode: Python; py-indent-offset: 4 -*- + +import sys, os, getopt + +module_init_template = \ +'/* -*- Mode: C; c-basic-offset: 4 -*- */\n' + \ +'#ifdef HAVE_CONFIG_H\n' + \ +'# include "config.h"\n' + \ +'#endif\n' + \ +'#include \n' + \ +'#include \n' + \ +'\n' + \ +'/* include any extra headers needed here */\n' + \ +'\n' + \ +'void %(prefix)s_register_classes(PyObject *d);\n' + \ +'extern PyMethodDef %(prefix)s_functions[];\n' + \ +'\n' + \ +'DL_EXPORT(void)\n' + \ +'init%(module)s(void)\n' + \ +'{\n' + \ +' PyObject *m, *d;\n' + \ +'\n' + \ +' /* perform any initialisation required by the library here */\n' + \ +'\n' + \ +' m = Py_InitModule("%(module)s", %(prefix)s_functions);\n' + \ +' d = PyModule_GetDict(m);\n' + \ +'\n' + \ +' init_pygtk();\n' + \ +'\n' + \ +' %(prefix)s_register_classes(d);\n' + \ +'\n' + \ +' /* add anything else to the module dictionary (such as constants) */\n' +\ +'\n' + \ +' if (PyErr_Occurred())\n' + \ +' Py_FatalError("could not initialise module %(module)s");\n' + \ +'}\n' + +override_template = \ +'/* -*- Mode: C; c-basic-offset: 4 -*- */\n' + \ +'%%%%\n' + \ +'headers\n' + \ +'/* include any required headers here */\n' + \ +'%%%%\n' + \ +'init\n' + \ +' /* include any code here that needs to be executed before the\n' + \ +' * extension classes get initialised */\n' + \ +'%%%%\n' + \ +'\n' + \ +'/* you should add appropriate ignore, ignore-glob and\n' + \ +' * override sections here */\n' + +def open_with_backup(file): + if os.path.exists(file): + try: + os.rename(file, file+'~') + except OSError: + # fail silently if we can't make a backup + pass + return open(file, 'w') + +def write_skels(fileprefix, prefix, module): + fp = open_with_backup(fileprefix+'module.c') + fp.write(module_init_template % { 'prefix': prefix, 'module': module }) + fp.close() + fp = open_with_backup(fileprefix+'.override') + fp.write(override_template % { 'prefix': prefix, 'module': module }) + fp.close() + +if __name__ == '__main__': + opts, args = getopt.getopt(sys.argv[1:], 'f:p:m:h', + ['file-prefix=', 'prefix=', 'module=', 'help']) + fileprefix = None + prefix = None + module = None + for opt, arg in opts: + if opt in ('-f', '--file-prefix'): + fileprefix = arg + elif opt in ('-p', '--prefix'): + prefix = arg + elif opt in ('-m', '--module'): + module = arg + elif opt in ('-h', '--help'): + print 'usage: mkskel.py -f fileprefix -p prefix -m module' + sys.exit(0) + if not fileprefix or not prefix or not module: + print 'usage: mkskel.py -f fileprefix -p prefix -m module' + sys.exit(1) + write_skels(fileprefix, prefix, module) diff --git a/bindings/python/codegen/override.py b/bindings/python/codegen/override.py new file mode 100644 index 0000000000..2e8c6a4c30 --- /dev/null +++ b/bindings/python/codegen/override.py @@ -0,0 +1,288 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- + +# this file contains code for loading up an override file. The override file +# provides implementations of functions where the code generator could not +# do its job correctly. + +import fnmatch +import os +import re +import string +import sys + +def class2cname(klass, method): + c_name = '' + for c in klass: + if c.isupper(): + c_name += '_' + c.lower() + else: + c_name += c + return c_name[1:] + '_' + method + +import_pat = re.compile(r'\s*import\s+(\S+)\.([^\s.]+)\s+as\s+(\S+)') + +class Overrides: + def __init__(self, filename=None, path=[]): + self.modulename = None + self.ignores = {} + self.glob_ignores = [] + self.type_ignores = {} + self.overrides = {} + self.overridden = {} + self.kwargs = {} + self.noargs = {} + self.onearg = {} + self.staticmethod = {} + self.classmethod = {} + self.startlines = {} + self.override_attrs = {} + self.override_slots = {} + self.headers = '' + self.body = '' + self.init = '' + self.imports = [] + self.defines = {} + self.functions = {} + self.newstyle_constructors = {} + self.path = [os.path.abspath(x) for x in path] + if filename: + self.handle_file(filename) + + def handle_file(self, filename): + oldpath = os.getcwd() + + fp = None + for path in self.path: + os.chdir(oldpath) + os.chdir(path) + try: + fp = open(filename, 'r') + break + except: + os.chdir(oldpath) + if not fp: + raise Exception, "Couldn't find file %s" % filename + + dirname = path + + if dirname != oldpath: + os.chdir(dirname) + + # read all the components of the file ... + bufs = [] + startline = 1 + lines = [] + line = fp.readline() + linenum = 1 + while line: + if line == '%%\n' or line == '%%': + if lines: + bufs.append((string.join(lines, ''), startline)) + startline = linenum + 1 + lines = [] + else: + lines.append(line) + line = fp.readline() + linenum = linenum + 1 + if lines: + bufs.append((string.join(lines, ''), startline)) + if not bufs: return + + for buf, startline in bufs: + self.__parse_override(buf, startline, filename) + + os.chdir(oldpath) + + def __parse_override(self, buffer, startline, filename): + pos = string.find(buffer, '\n') + if pos >= 0: + line = buffer[:pos] + rest = buffer[pos+1:] + else: + line = buffer ; rest = '' + words = string.split(line) + command = words[0] + if (command == 'ignore' or + command == 'ignore-' + sys.platform): + "ignore/ignore-platform [functions..]" + for func in words[1:]: + self.ignores[func] = 1 + for func in string.split(rest): + self.ignores[func] = 1 + elif (command == 'ignore-glob' or + command == 'ignore-glob-' + sys.platform): + "ignore-glob/ignore-glob-platform [globs..]" + for func in words[1:]: + self.glob_ignores.append(func) + for func in string.split(rest): + self.glob_ignores.append(func) + elif (command == 'ignore-type' or + command == 'ignore-type-' + sys.platform): + "ignore-type/ignore-type-platform [typenames..]" + for typename in words[1:]: + self.type_ignores[typename] = 1 + for typename in string.split(rest): + self.type_ignores[typename] = 1 + elif command == 'override': + "override function/method [kwargs|noargs|onearg] [staticmethod|classmethod]" + func = words[1] + if 'kwargs' in words[1:]: + self.kwargs[func] = 1 + elif 'noargs' in words[1:]: + self.noargs[func] = 1 + elif 'onearg' in words[1:]: + self.onearg[func] = True + + if 'staticmethod' in words[1:]: + self.staticmethod[func] = True + elif 'classmethod' in words[1:]: + self.classmethod[func] = True + if func in self.overrides: + raise RuntimeError("Function %s is being overridden more than once" % (func,)) + self.overrides[func] = rest + self.startlines[func] = (startline + 1, filename) + elif command == 'override-attr': + "override-slot Class.attr" + attr = words[1] + self.override_attrs[attr] = rest + self.startlines[attr] = (startline + 1, filename) + elif command == 'override-slot': + "override-slot Class.slot" + slot = words[1] + self.override_slots[slot] = rest + self.startlines[slot] = (startline + 1, filename) + elif command == 'headers': + "headers" + self.headers = '%s\n#line %d "%s"\n%s' % \ + (self.headers, startline + 1, filename, rest) + elif command == 'body': + "body" + self.body = '%s\n#line %d "%s"\n%s' % \ + (self.body, startline + 1, filename, rest) + elif command == 'init': + "init" + self.init = '%s\n#line %d "%s"\n%s' % \ + (self.init, startline + 1, filename, rest) + elif command == 'modulename': + "modulename name" + self.modulename = words[1] + elif command == 'include': + "include filename" + for filename in words[1:]: + self.handle_file(filename) + for filename in string.split(rest): + self.handle_file(filename) + elif command == 'import': + "import module1 [\n module2, \n module3 ...]" + for line in string.split(buffer, '\n'): + match = import_pat.match(line) + if match: + self.imports.append(match.groups()) + elif command == 'define': + "define funcname [kwargs|noargs|onearg] [classmethod|staticmethod]" + "define Class.method [kwargs|noargs|onearg] [classmethod|staticmethod]" + func = words[1] + klass = None + if func.find('.') != -1: + klass, func = func.split('.', 1) + + if not self.defines.has_key(klass): + self.defines[klass] = {} + self.defines[klass][func] = rest + else: + self.functions[func] = rest + + if 'kwargs' in words[1:]: + self.kwargs[func] = 1 + elif 'noargs' in words[1:]: + self.noargs[func] = 1 + elif 'onearg' in words[1:]: + self.onearg[func] = 1 + + if 'staticmethod' in words[1:]: + self.staticmethod[func] = True + elif 'classmethod' in words[1:]: + self.classmethod[func] = True + + self.startlines[func] = (startline + 1, filename) + + elif command == 'new-constructor': + "new-constructor GType" + gtype, = words[1:] + self.newstyle_constructors[gtype] = True + + def is_ignored(self, name): + if self.ignores.has_key(name): + return 1 + for glob in self.glob_ignores: + if fnmatch.fnmatchcase(name, glob): + return 1 + return 0 + + def is_type_ignored(self, name): + return name in self.type_ignores + + def is_overriden(self, name): + return self.overrides.has_key(name) + + def is_already_included(self, name): + return self.overridden.has_key(name) + + def override(self, name): + self.overridden[name] = 1 + return self.overrides[name] + + def define(self, klass, name): + self.overridden[class2cname(klass, name)] = 1 + return self.defines[klass][name] + + def function(self, name): + return self.functions[name] + + def getstartline(self, name): + return self.startlines[name] + + def wants_kwargs(self, name): + return self.kwargs.has_key(name) + + def wants_noargs(self, name): + return self.noargs.has_key(name) + + def wants_onearg(self, name): + return self.onearg.has_key(name) + + def is_staticmethod(self, name): + return self.staticmethod.has_key(name) + + def is_classmethod(self, name): + return self.classmethod.has_key(name) + + def attr_is_overriden(self, attr): + return self.override_attrs.has_key(attr) + + def attr_override(self, attr): + return self.override_attrs[attr] + + def slot_is_overriden(self, slot): + return self.override_slots.has_key(slot) + + def slot_override(self, slot): + return self.override_slots[slot] + + def get_headers(self): + return self.headers + + def get_body(self): + return self.body + + def get_init(self): + return self.init + + def get_imports(self): + return self.imports + + def get_defines_for(self, klass): + return self.defines.get(klass, {}) + + def get_functions(self): + return self.functions diff --git a/bindings/python/codegen/reversewrapper.py b/bindings/python/codegen/reversewrapper.py new file mode 100644 index 0000000000..f528828ef1 --- /dev/null +++ b/bindings/python/codegen/reversewrapper.py @@ -0,0 +1,771 @@ +### -*- python -*- +### Code to generate "Reverse Wrappers", i.e. C->Python wrappers +### (C) 2004 Gustavo Carneiro +import argtypes +import os + +DEBUG_MODE = ('PYGTK_CODEGEN_DEBUG' in os.environ) + +def join_ctype_name(ctype, name): + '''Joins a C type and a variable name into a single string''' + if ctype[-1] != '*': + return " ".join((ctype, name)) + else: + return "".join((ctype, name)) + + +class CodeSink(object): + def __init__(self): + self.indent_level = 0 # current indent level + self.indent_stack = [] # previous indent levels + + def _format_code(self, code): + assert isinstance(code, str) + l = [] + for line in code.split('\n'): + l.append(' '*self.indent_level + line) + if l[-1]: + l.append('') + return '\n'.join(l) + + def writeln(self, line=''): + raise NotImplementedError + + def indent(self, level=4): + '''Add a certain ammount of indentation to all lines written + from now on and until unindent() is called''' + self.indent_stack.append(self.indent_level) + self.indent_level += level + + def unindent(self): + '''Revert indentation level to the value before last indent() call''' + self.indent_level = self.indent_stack.pop() + + +class FileCodeSink(CodeSink): + def __init__(self, fp): + CodeSink.__init__(self) + assert isinstance(fp, file) + self.fp = fp + + def writeln(self, line=''): + self.fp.write(self._format_code(line)) + +class MemoryCodeSink(CodeSink): + def __init__(self): + CodeSink.__init__(self) + self.lines = [] + + def writeln(self, line=''): + self.lines.append(self._format_code(line)) + + def flush_to(self, sink): + assert isinstance(sink, CodeSink) + for line in self.lines: + sink.writeln(line.rstrip()) + self.lines = [] + + def flush(self): + l = [] + for line in self.lines: + l.append(self._format_code(line)) + self.lines = [] + return "".join(l) + +class ReverseWrapper(object): + '''Object that generates a C->Python wrapper''' + def __init__(self, cname, is_static=True): + assert isinstance(cname, str) + + self.cname = cname + ## function object we will call, or object whose method we will call + self.called_pyobj = None + ## name of method of self.called_pyobj we will call + self.method_name = None + self.is_static = is_static + + self.parameters = [] + self.declarations = MemoryCodeSink() + self.post_return_code = MemoryCodeSink() + self.body = MemoryCodeSink() + self.cleanup_actions = [] + self.pyargv_items = [] + self.pyargv_optional_items = [] + self.pyret_parse_items = [] # list of (format_spec, parameter) + + def set_call_target(self, called_pyobj, method_name=None): + assert called_pyobj is not None + assert self.called_pyobj is None + self.called_pyobj = called_pyobj + self.method_name = method_name + + def set_return_type(self, return_type): + assert isinstance(return_type, ReturnType) + self.return_type = return_type + + def add_parameter(self, param): + assert isinstance(param, Parameter) + self.parameters.append(param) + + def add_declaration(self, decl_code): + self.declarations.writeln(decl_code) + + def add_pyargv_item(self, variable, optional=False): + if optional: + self.pyargv_optional_items.append(variable) + else: + self.pyargv_items.append(variable) + + def add_pyret_parse_item(self, format_specifier, parameter, prepend=False): + if prepend: + self.pyret_parse_items.insert(0, (format_specifier, parameter)) + else: + self.pyret_parse_items.append((format_specifier, parameter)) + + def write_code(self, code, + cleanup=None, + failure_expression=None, + failure_cleanup=None, + failure_exception=None, + code_sink=None): + '''Add a chunk of code with cleanup and error handling + + This method is to be used by TypeHandlers when generating code + + Keywork arguments: + code -- code to add + cleanup -- code to cleanup any dynamic resources created by @code + (except in case of failure) (default None) + failure_expression -- C boolean expression to indicate + if anything failed (default None) + failure_cleanup -- code to cleanup any dynamic resources + created by @code in case of failure (default None) + failure_exception -- code to raise an exception in case of + failure (which will be immediately + printed and cleared), (default None) + code_sink -- "code sink" to use; by default, + ReverseWrapper.body is used, which writes the + main body of the wrapper, before calling the + python method. Alternatively, + ReverseWrapper.after_pyret_parse can be used, to + write code after the PyArg_ParseTuple that + parses the python method return value. + ''' + if code_sink is None: + code_sink = self.body + if code is not None: + code_sink.writeln(code) + if failure_expression is not None: + code_sink.writeln("if (%s) {" % (failure_expression,)) + code_sink.indent() + if failure_exception is None: + code_sink.writeln("if (PyErr_Occurred())") + code_sink.indent() + code_sink.writeln("PyErr_Print();") + code_sink.unindent() + else: + code_sink.writeln(failure_exception) + code_sink.writeln("PyErr_Print();") + if failure_cleanup is not None: + code_sink.writeln(failure_cleanup) + for cleanup_action in self.cleanup_actions: + code_sink.writeln(cleanup_action) + self.return_type.write_error_return() + code_sink.unindent() + code_sink.writeln("}") + if cleanup is not None: + self.cleanup_actions.insert(0, cleanup) + + def generate(self, sink): + '''Generate the code into a CodeSink object''' + assert isinstance(sink, CodeSink) + + if DEBUG_MODE: + self.declarations.writeln("/* begin declarations */") + self.body.writeln("/* begin main body */") + self.post_return_code.writeln("/* begin post-return code */") + + self.add_declaration("PyGILState_STATE __py_state;") + self.write_code(code="__py_state = pyg_gil_state_ensure();", + cleanup="pyg_gil_state_release(__py_state);") + + for param in self.parameters: + param.convert_c2py() + + assert self.called_pyobj is not None,\ + "Parameters failed to provide a target function or method." + + if self.is_static: + sink.writeln('static %s' % self.return_type.get_c_type()) + else: + sink.writeln(self.return_type.get_c_type()) + c_proto_params = map(Parameter.format_for_c_proto, self.parameters) + sink.writeln("%s(%s)\n{" % (self.cname, ", ".join(c_proto_params))) + + self.return_type.write_decl() + self.add_declaration("PyObject *py_retval;") + + ## Handle number of arguments + if self.pyargv_items: + self.add_declaration("PyObject *py_args;") + py_args = "py_args" + if self.pyargv_optional_items: + self.add_declaration("int argc = %i;" % len(self.pyargv_items)) + argc = "argc" + for arg in self.pyargv_optional_items: + self.body.writeln("if (%s)" % arg) + self.body.indent() + self.body.writeln("++argc;") + self.body.unindent() + else: + argc = str(len(self.pyargv_items)) + else: + if self.pyargv_optional_items: + self.add_declaration("PyObject *py_args;") + py_args = "py_args" + self.add_declaration("int argc = 0;") + argc = "argc" + for arg in self.pyargv_optional_items: + self.body.writeln("if (%s)" % arg) + self.body.indent() + self.body.writeln("++argc;") + self.body.unindent() + else: + py_args = "NULL" + argc = None + + self.body.writeln() + + if py_args != "NULL": + self.write_code("py_args = PyTuple_New(%s);" % argc, + cleanup="Py_DECREF(py_args);") + pos = 0 + for arg in self.pyargv_items: + try: # try to remove the Py_DECREF cleanup action, if we can + self.cleanup_actions.remove("Py_DECREF(%s);" % arg) + except ValueError: # otherwise we have to Py_INCREF.. + self.body.writeln("Py_INCREF(%s);" % arg) + self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg)) + pos += 1 + for arg in self.pyargv_optional_items: + self.body.writeln("if (%s) {" % arg) + self.body.indent() + try: # try to remove the Py_DECREF cleanup action, if we can + self.cleanup_actions.remove("Py_XDECREF(%s);" % arg) + except ValueError: # otherwise we have to Py_INCREF.. + self.body.writeln("Py_INCREF(%s);" % arg) + self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg)) + self.body.unindent() + self.body.writeln("}") + pos += 1 + + self.body.writeln() + + ## Call the python method + if self.method_name is None: + self.write_code("py_retval = PyObject_Call(%s, %s);" + % (self.called_pyobj, py_args), + cleanup="Py_DECREF(py_retval);", + failure_expression="!py_retval") + else: + self.add_declaration("PyObject *py_method;") + self.write_code("py_method = PyObject_GetAttrString(%s, \"%s\");" + % (self.called_pyobj, self.method_name), + cleanup="Py_DECREF(py_method);", + failure_expression="!py_method") + self.write_code("py_retval = PyObject_CallObject(py_method, %s);" + % (py_args,), + cleanup="Py_DECREF(py_retval);", + failure_expression="!py_retval") + + ## -- Handle the return value -- + + ## we need to check if the return_type object is prepared to cooperate with multiple return values + len_before = len(self.pyret_parse_items) + self.return_type.write_conversion() + len_after = len(self.pyret_parse_items) + assert (self.return_type.get_c_type() == 'void' + or not (len_before == len_after and len_after > 0)),\ + ("Bug in reverse wrappers: return type handler %s" + " is not prepared to cooperate multiple return values") % (type(self.return_type),) + + sink.indent() + + if len(self.pyret_parse_items) == 1: + ## if retval is one item only, pack it in a tuple so we + ## can use PyArg_ParseTuple as usual.. + self.write_code('py_retval = Py_BuildValue("(N)", py_retval);') + if len(self.pyret_parse_items) > 0: + ## Parse return values using PyArg_ParseTuple + self.write_code(code=None, failure_expression=( + '!PyArg_ParseTuple(py_retval, "%s", %s)' % ( + "".join([format for format, param in self.pyret_parse_items]), + ", ".join([param for format, param in self.pyret_parse_items])))) + + if DEBUG_MODE: + self.declarations.writeln("/* end declarations */") + self.declarations.flush_to(sink) + sink.writeln() + if DEBUG_MODE: + self.body.writeln("/* end main body */") + self.body.flush_to(sink) + sink.writeln() + if DEBUG_MODE: + self.post_return_code.writeln("/* end post-return code */") + self.post_return_code.flush_to(sink) + sink.writeln() + + for cleanup_action in self.cleanup_actions: + sink.writeln(cleanup_action) + if self.return_type.get_c_type() != 'void': + sink.writeln() + sink.writeln("return retval;") + sink.unindent() + sink.writeln("}") + +class TypeHandler(object): + def __init__(self, wrapper, **props): + assert isinstance(wrapper, ReverseWrapper) + self.wrapper = wrapper + self.props = props + +class ReturnType(TypeHandler): + + def get_c_type(self): + raise NotImplementedError + + def write_decl(self): + raise NotImplementedError + + def write_error_return(self): + '''Write "return " code in case of error''' + raise NotImplementedError + + def write_conversion(self): + '''Writes code to convert Python return value in 'py_retval' + into C 'retval'. Returns a string with C boolean expression + that determines if anything went wrong. ''' + raise NotImplementedError + +class Parameter(TypeHandler): + + def __init__(self, wrapper, name, **props): + TypeHandler.__init__(self, wrapper, **props) + self.name = name + + def get_c_type(self): + raise NotImplementedError + + def convert_c2py(self): + '''Write some code before calling the Python method.''' + pass + + def format_for_c_proto(self): + return join_ctype_name(self.get_c_type(), self.name) + + +###--- +class StringParam(Parameter): + + def get_c_type(self): + return self.props.get('c_type', 'char *').replace('const-', 'const ') + + def convert_c2py(self): + if self.props.get('optional', False): + self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name) + self.wrapper.write_code(code=("if (%s)\n" + " py_%s = PyString_FromString(%s);\n" + % (self.name, self.name, self.name)), + cleanup=("Py_XDECREF(py_%s);" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name, optional=True) + else: + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" % + (self.name, self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name), + failure_expression=("!py_%s" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +for ctype in ('char*', 'gchar*', 'const-char*', 'char-const*', 'const-gchar*', + 'gchar-const*', 'string', 'static_string'): + argtypes.matcher.register_reverse(ctype, StringParam) +del ctype + +class StringReturn(ReturnType): + + def get_c_type(self): + return "char *" + + def write_decl(self): + self.wrapper.add_declaration("char *retval;") + + def write_error_return(self): + self.wrapper.write_code("return NULL;") + + def write_conversion(self): + self.wrapper.add_pyret_parse_item("s", "&retval", prepend=True) + self.wrapper.write_code("retval = g_strdup(retval);", code_sink=self.wrapper.post_return_code) + +for ctype in ('char*', 'gchar*'): + argtypes.matcher.register_reverse_ret(ctype, StringReturn) +del ctype + + +class VoidReturn(ReturnType): + + def get_c_type(self): + return "void" + + def write_decl(self): + pass + + def write_error_return(self): + self.wrapper.write_code("return;") + + def write_conversion(self): + self.wrapper.write_code( + code=None, + failure_expression="py_retval != Py_None", + failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be None");') + +argtypes.matcher.register_reverse_ret('void', VoidReturn) +argtypes.matcher.register_reverse_ret('none', VoidReturn) + +class GObjectParam(Parameter): + + def get_c_type(self): + return self.props.get('c_type', 'GObject *') + + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name) + self.wrapper.write_code(code=("if (%s)\n" + " py_%s = pygobject_new((GObject *) %s);\n" + "else {\n" + " Py_INCREF(Py_None);\n" + " py_%s = Py_None;\n" + "}" + % (self.name, self.name, self.name, self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +argtypes.matcher.register_reverse('GObject*', GObjectParam) + +class GObjectReturn(ReturnType): + + def get_c_type(self): + return self.props.get('c_type', 'GObject *') + + def write_decl(self): + self.wrapper.add_declaration("%s retval;" % self.get_c_type()) + + def write_error_return(self): + self.wrapper.write_code("return NULL;") + + def write_conversion(self): + self.wrapper.write_code( + code=None, + failure_expression="!PyObject_TypeCheck(py_retval, &PyGObject_Type)", + failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be a GObject");') + self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);" + % self.get_c_type()) + self.wrapper.write_code("g_object_ref((GObject *) retval);") + +argtypes.matcher.register_reverse_ret('GObject*', GObjectReturn) + + + +class IntParam(Parameter): + + def get_c_type(self): + return self.props.get('c_type', 'int') + + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code(code=("py_%s = PyInt_FromLong(%s);" % + (self.name, self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +class IntReturn(ReturnType): + def get_c_type(self): + return self.props.get('c_type', 'int') + def write_decl(self): + self.wrapper.add_declaration("%s retval;" % self.get_c_type()) + def write_error_return(self): + self.wrapper.write_code("return -G_MAXINT;") + def write_conversion(self): + self.wrapper.add_pyret_parse_item("i", "&retval", prepend=True) + +for argtype in ('int', 'gint', 'guint', 'short', 'gshort', 'gushort', 'long', + 'glong', 'gsize', 'gssize', 'guint8', 'gint8', 'guint16', + 'gint16', 'gint32', 'GTime'): + argtypes.matcher.register_reverse(argtype, IntParam) + argtypes.matcher.register_reverse_ret(argtype, IntReturn) +del argtype + +class IntPtrParam(Parameter): + def __init__(self, wrapper, name, **props): + if "direction" not in props: + raise ValueError("cannot use int* parameter without direction") + if props["direction"] not in ("out", "inout"): + raise ValueError("cannot use int* parameter with direction '%s'" % (props["direction"],)) + Parameter.__init__(self, wrapper, name, **props) + def get_c_type(self): + return self.props.get('c_type', 'int*') + def convert_c2py(self): + if self.props["direction"] == "inout": + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code(code=("py_%s = PyInt_FromLong(*%s);" % + (self.name, self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + self.wrapper.add_pyret_parse_item("i", self.name) +for argtype in ('int*', 'gint*'): + argtypes.matcher.register_reverse(argtype, IntPtrParam) +del argtype + + +class GEnumReturn(IntReturn): + def write_conversion(self): + self.wrapper.write_code( + code=None, + failure_expression=("pyg_enum_get_value(%s, py_retval, (gint *)&retval)" % + self.props['typecode'])) + +argtypes.matcher.register_reverse_ret("GEnum", GEnumReturn) + +class GEnumParam(IntParam): + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code(code=("py_%s = pyg_enum_from_gtype(%s, %s);" % + (self.name, self.props['typecode'], self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name), + failure_expression=("!py_%s" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +argtypes.matcher.register_reverse("GEnum", GEnumParam) + +class GFlagsReturn(IntReturn): + def write_conversion(self): + self.wrapper.write_code( + code=None, + failure_expression=("pyg_flags_get_value(%s, py_retval, (gint *)&retval)" % + self.props['typecode'])) + +argtypes.matcher.register_reverse_ret("GFlags", GFlagsReturn) + +class GFlagsParam(IntParam): + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code(code=("py_%s = pyg_flags_from_gtype(%s, %s);" % + (self.name, self.props['typecode'], self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name), + failure_expression=("!py_%s" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +argtypes.matcher.register_reverse("GFlags", GFlagsParam) + + +class GtkTreePathParam(IntParam): + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code(code=("py_%s = pygtk_tree_path_to_pyobject(%s);" % + (self.name, self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name), + failure_expression=("!py_%s" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +argtypes.matcher.register_reverse("GtkTreePath*", GtkTreePathParam) + + +class BooleanReturn(ReturnType): + def get_c_type(self): + return "gboolean" + def write_decl(self): + self.wrapper.add_declaration("gboolean retval;") + self.wrapper.add_declaration("PyObject *py_main_retval;") + def write_error_return(self): + self.wrapper.write_code("return FALSE;") + def write_conversion(self): + self.wrapper.add_pyret_parse_item("O", "&py_main_retval", prepend=True) + self.wrapper.write_code("retval = PyObject_IsTrue(py_main_retval)? TRUE : FALSE;", + code_sink=self.wrapper.post_return_code) +argtypes.matcher.register_reverse_ret("gboolean", BooleanReturn) + +class BooleanParam(Parameter): + def get_c_type(self): + return "gboolean" + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code("py_%s = %s? Py_True : Py_False;" + % (self.name, self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +argtypes.matcher.register_reverse("gboolean", BooleanParam) + + +class DoubleParam(Parameter): + def get_c_type(self): + return self.props.get('c_type', 'gdouble') + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code(code=("py_%s = PyFloat_FromDouble(%s);" % + (self.name, self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +class DoublePtrParam(Parameter): + def __init__(self, wrapper, name, **props): + if "direction" not in props: + raise ValueError("cannot use double* parameter without direction") + if props["direction"] not in ("out", ): # inout not yet implemented + raise ValueError("cannot use double* parameter with direction '%s'" % (props["direction"],)) + Parameter.__init__(self, wrapper, name, **props) + def get_c_type(self): + return self.props.get('c_type', 'double*') + def convert_c2py(self): + self.wrapper.add_pyret_parse_item("d", self.name) +for argtype in ('double*', 'gdouble*'): + argtypes.matcher.register_reverse(argtype, DoublePtrParam) +del argtype + +class DoubleReturn(ReturnType): + def get_c_type(self): + return self.props.get('c_type', 'gdouble') + def write_decl(self): + self.wrapper.add_declaration("%s retval;" % self.get_c_type()) + def write_error_return(self): + self.wrapper.write_code("return -G_MAXFLOAT;") + def write_conversion(self): + self.wrapper.write_code( + code=None, + failure_expression="!PyFloat_AsDouble(py_retval)", + failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a float");') + self.wrapper.write_code("retval = PyFloat_AsDouble(py_retval);") + +for argtype in ('float', 'double', 'gfloat', 'gdouble'): + argtypes.matcher.register_reverse(argtype, DoubleParam) + argtypes.matcher.register_reverse_ret(argtype, DoubleReturn) + + +class GBoxedParam(Parameter): + def get_c_type(self): + return self.props.get('c_type').replace('const-', 'const ') + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + ctype = self.get_c_type() + if ctype.startswith('const '): + ctype_no_const = ctype[len('const '):] + self.wrapper.write_code( + code=('py_%s = pyg_boxed_new(%s, (%s) %s, TRUE, TRUE);' % + (self.name, self.props['typecode'], + ctype_no_const, self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name)) + else: + self.wrapper.write_code( + code=('py_%s = pyg_boxed_new(%s, %s, FALSE, FALSE);' % + (self.name, self.props['typecode'], self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +argtypes.matcher.register_reverse("GBoxed", GBoxedParam) + +class GBoxedReturn(ReturnType): + def get_c_type(self): + return self.props.get('c_type') + def write_decl(self): + self.wrapper.add_declaration("%s retval;" % self.get_c_type()) + def write_error_return(self): + self.wrapper.write_code("return retval;") + def write_conversion(self): + self.wrapper.write_code( + failure_expression=("!pyg_boxed_check(py_retval, %s)" % + (self.props['typecode'],)), + failure_cleanup=('PyErr_SetString(PyExc_TypeError, "retval should be a %s");' + % (self.props['typename'],))) + self.wrapper.write_code('retval = pyg_boxed_get(py_retval, %s);' % + self.props['typename']) + +argtypes.matcher.register_reverse_ret("GBoxed", GBoxedReturn) + + +class GdkRectanglePtrParam(Parameter): + def get_c_type(self): + return self.props.get('c_type').replace('const-', 'const ') + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code( + code=('py_%s = pyg_boxed_new(GDK_TYPE_RECTANGLE, %s, TRUE, TRUE);' % + (self.name, self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam) +argtypes.matcher.register_reverse('GtkAllocation*', GdkRectanglePtrParam) + + +class PyGObjectMethodParam(Parameter): + def __init__(self, wrapper, name, method_name, **props): + Parameter.__init__(self, wrapper, name, **props) + self.method_name = method_name + + def get_c_type(self): + return self.props.get('c_type', 'GObject *') + + def convert_c2py(self): + self.wrapper.add_declaration("PyObject *py_%s;" % self.name) + self.wrapper.write_code(code=("py_%s = pygobject_new((GObject *) %s);" % + (self.name, self.name)), + cleanup=("Py_DECREF(py_%s);" % self.name), + failure_expression=("!py_%s" % self.name)) + self.wrapper.set_call_target("py_%s" % self.name, self.method_name) + +class CallbackInUserDataParam(Parameter): + def __init__(self, wrapper, name, free_it, **props): + Parameter.__init__(self, wrapper, name, **props) + self.free_it = free_it + + def get_c_type(self): + return "gpointer" + + def convert_c2py(self): + self.wrapper.add_declaration("PyObject **_user_data;") + cleanup = self.free_it and ("g_free(%s);" % self.name) or None + self.wrapper.write_code(code=("_real_user_data = (PyObject **) %s;" + % self.name), + cleanup=cleanup) + + self.wrapper.add_declaration("PyObject *py_func;") + cleanup = self.free_it and "Py_DECREF(py_func);" or None + self.wrapper.write_code(code="py_func = _user_data[0];", + cleanup=cleanup) + self.wrapper.set_call_target("py_func") + + self.wrapper.add_declaration("PyObject *py_user_data;") + cleanup = self.free_it and "Py_XDECREF(py_user_data);" or None + self.wrapper.write_code(code="py_user_data = _user_data[1];", + cleanup=cleanup) + self.wrapper.add_pyargv_item("py_user_data", optional=True) + +def _test(): + import sys + + if 1: + wrapper = ReverseWrapper("this_is_the_c_function_name", is_static=True) + wrapper.set_return_type(StringReturn(wrapper)) + wrapper.add_parameter(PyGObjectMethodParam(wrapper, "self", method_name="do_xxx")) + wrapper.add_parameter(StringParam(wrapper, "param2", optional=True)) + wrapper.add_parameter(GObjectParam(wrapper, "param3")) + #wrapper.add_parameter(InoutIntParam(wrapper, "param4")) + wrapper.generate(FileCodeSink(sys.stderr)) + + if 0: + wrapper = ReverseWrapper("this_a_callback_wrapper") + wrapper.set_return_type(VoidReturn(wrapper)) + wrapper.add_parameter(StringParam(wrapper, "param1", optional=False)) + wrapper.add_parameter(GObjectParam(wrapper, "param2")) + wrapper.add_parameter(CallbackInUserDataParam(wrapper, "data", free_it=True)) + wrapper.generate(FileCodeSink(sys.stderr)) + +if __name__ == '__main__': + _test() diff --git a/bindings/python/codegen/scmexpr.py b/bindings/python/codegen/scmexpr.py new file mode 100644 index 0000000000..d08c517adb --- /dev/null +++ b/bindings/python/codegen/scmexpr.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python +# -*- Mode: Python; py-indent-offset: 4 -*- +from __future__ import generators + +import string +import types +from cStringIO import StringIO + +class error(Exception): + def __init__(self, filename, lineno, msg): + Exception.__init__(self, msg) + self.filename = filename + self.lineno = lineno + self.msg = msg + def __str__(self): + return '%s:%d: error: %s' % (self.filename, self.lineno, self.msg) + +trans = [' '] * 256 +for i in range(256): + if chr(i) in string.letters + string.digits + '_': + trans[i] = chr(i) + else: + trans[i] = '_' +trans = string.join(trans, '') + +def parse(filename): + if isinstance(filename, str): + fp = open(filename, 'r') + else: # if not string, assume it is some kind of iterator + fp = filename + filename = getattr(fp, 'name', '') + whitespace = ' \t\n\r\x0b\x0c' + nonsymbol = whitespace + '();\'"' + stack = [] + openlines = [] + lineno = 0 + for line in fp: + pos = 0 + lineno += 1 + while pos < len(line): + if line[pos] in whitespace: # ignore whitespace + pass + elif line[pos] == ';': # comment + break + elif line[pos:pos+2] == "'(": + pass # the open parenthesis will be handled next iteration + elif line[pos] == '(': + stack.append(()) + openlines.append(lineno) + elif line[pos] == ')': + if len(stack) == 0: + raise error(filename, lineno, 'close parenthesis found when none open') + closed = stack[-1] + del stack[-1] + del openlines[-1] + if stack: + stack[-1] += (closed,) + else: + yield closed + elif line[pos] == '"': # quoted string + if not stack: + raise error(filename, lineno, + 'string found outside of s-expression') + endpos = pos + 1 + chars = [] + while endpos < len(line): + if endpos+1 < len(line) and line[endpos] == '\\': + endpos += 1 + if line[endpos] == 'n': + chars.append('\n') + elif line[endpos] == 'r': + chars.append('\r') + elif line[endpos] == 't': + chars.append('\t') + else: + chars.append('\\') + chars.append(line[endpos]) + elif line[endpos] == '"': + break + else: + chars.append(line[endpos]) + endpos += 1 + if endpos >= len(line): + raise error(filename, lineno, "unclosed quoted string") + pos = endpos + stack[-1] += (''.join(chars),) + else: # symbol/number + if not stack: + raise error(filename, lineno, + 'identifier found outside of s-expression') + endpos = pos + while endpos < len(line) and line[endpos] not in nonsymbol: + endpos += 1 + symbol = line[pos:endpos] + pos = max(pos, endpos-1) + try: symbol = int(symbol) + except ValueError: + try: symbol = float(symbol) + except ValueError: pass + stack[-1] += (symbol,) + pos += 1 + if len(stack) != 0: + msg = '%d unclosed parentheses found at end of ' \ + 'file (opened on line(s) %s)' % (len(stack), + ', '.join(map(str, openlines))) + raise error(filename, lineno, msg) + +class Parser: + def __init__(self, filename): + """Argument is either a string, a parse tree, or file object""" + self.filename = filename + def startParsing(self, filename=None): + statements = parse(filename or self.filename) + for statement in statements: + self.handle(statement) + def handle(self, tup): + cmd = string.translate(tup[0], trans) + if hasattr(self, cmd): + getattr(self, cmd)(*tup[1:]) + else: + self.unknown(tup) + def unknown(self, tup): + pass + +_testString = """; a scheme file +(define-func gdk_font_load ; a comment at end of line + GdkFont + ((string name))) + +(define-boxed GdkEvent + gdk_event_copy + gdk_event_free + "sizeof(GdkEvent)") +""" + +if __name__ == '__main__': + import sys + if sys.argv[1:]: + fp = open(sys.argv[1]) + else: + fp = StringIO(_testString) + statements = parse(fp) + for s in statements: + print `s` diff --git a/bindings/python/rtspserver-types.defs b/bindings/python/rtspserver-types.defs new file mode 100644 index 0000000000..133ed8ff87 --- /dev/null +++ b/bindings/python/rtspserver-types.defs @@ -0,0 +1,6 @@ +(define-object Server + (in-module "Gst.RTSPServer") + (parent "GObject") + (c-name "GstRTSPServer") + (gtype-id "GST_TYPE_RTSP_SERVER") +) diff --git a/bindings/python/rtspserver.defs b/bindings/python/rtspserver.defs new file mode 100644 index 0000000000..4442f9fcfb --- /dev/null +++ b/bindings/python/rtspserver.defs @@ -0,0 +1,16 @@ +(include "rtspserver-types.defs") + +(define-function rtsp_server_new + (c-name "gst_rtsp_server_new") + (is-constructor-of "GstRTSPServer") + (return-type "GstRTSPServer*") +) + +(define-method attach + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_attach") + (return-type "guint") + (parameters + '("GMainContext*" "context") + ) +) diff --git a/bindings/python/rtspserver.override b/bindings/python/rtspserver.override new file mode 100644 index 0000000000..ca705edd04 --- /dev/null +++ b/bindings/python/rtspserver.override @@ -0,0 +1,52 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- */ +%% +headers +/* include any required headers here */ +#define NO_IMPORT_PYGOBJECT +#include + +#ifdef HAVE_CONFIG_H +# include +#endif + +/* Boonky define that allows for backwards compatibility with Python 2.4 */ +#if PY_VERSION_HEX < 0x02050000 +#define Py_ssize_t int +#endif + +#include "rtsp-server.h" + +typedef struct { + PyObject_HEAD + GMainContext *context; +} PyGMainContext; + +%% +import gobject.GObject as PyGObject_Type +import gobject.MainContext as PyGMainContext_Type + +%% +override gst_rtsp_server_attach kwargs +static PyObject * +_wrap_gst_rtsp_server_attach (PyGObject *self, + PyObject *args, PyObject *keywords) +{ + static char *kwlist[] = {"context", NULL}; + PyGMainContext *py_context = NULL; + GMainContext *context = NULL; + guint res; + + if (!PyArg_ParseTupleAndKeywords (args, keywords, + "|O!:GstRTSPServer.__init__", kwlist, + &PyGMainContext_Type, &py_context)) + return NULL; + + if (py_context) + context = py_context->context; + + pyg_begin_allow_threads; + res = gst_rtsp_server_attach (GST_RTSP_SERVER (self->obj), context); + pyg_end_allow_threads; + + return PyLong_FromLong (res); +} diff --git a/bindings/python/rtspservermodule.c b/bindings/python/rtspservermodule.c new file mode 100644 index 0000000000..e5e7d56e67 --- /dev/null +++ b/bindings/python/rtspservermodule.c @@ -0,0 +1,31 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include + +/* include any extra headers needed here */ + +void pygst_rtsp_server_register_classes(PyObject *d); +extern PyMethodDef pygst_rtsp_server_functions[]; + +DL_EXPORT(void) +initrtspserver(void) +{ + PyObject *m, *d; + + /* perform any initialisation required by the library here */ + + m = Py_InitModule("rtspserver", pygst_rtsp_server_functions); + d = PyModule_GetDict(m); + + init_pygobject(); + + pygst_rtsp_server_register_classes(d); + + /* add anything else to the module dictionary (such as constants) */ + + if (PyErr_Occurred()) + Py_FatalError("could not initialise module rtspserver"); +} diff --git a/configure.ac b/configure.ac index 2f56d381ea..cfbbc2ec75 100644 --- a/configure.ac +++ b/configure.ac @@ -68,6 +68,11 @@ dnl *** checks for programs *** dnl find a compiler AC_PROG_CC +AM_PROG_CC_C_O + +dnl check for python +AM_PATH_PYTHON(2.3) +AM_CHECK_PYTHON_HEADERS([HAVE_PYTHON_HEADERS="yes"], [HAVE_PYTHON_HEADERS="no"]) AC_PATH_PROG(VALGRIND_PATH, valgrind, no) AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") @@ -109,6 +114,7 @@ if test "x$HAVE_PYTHON_HEADERS" = "xyes" -a \ else HAVE_PYTHON_BINDINGS="no" fi + AM_CONDITIONAL(WITH_PYTHON, [test "x$HAVE_PYTHON_BINDINGS" = "xyes"]) dnl Check for vala @@ -128,7 +134,6 @@ if test "x$HAVE_VALA" = "xyes"; then fi AC_SUBST(VAPIDIR) - dnl *** checks for libraries *** dnl *** checks for header files *** @@ -267,6 +272,8 @@ gst/Makefile gst/rtsp-server/Makefile examples/Makefile bindings/Makefile +bindings/python/Makefile +bindings/python/codegen/Makefile bindings/vala/Makefile pkgconfig/Makefile pkgconfig/gst-rtsp-server.pc @@ -281,6 +288,7 @@ Configuration Prefix : ${prefix} Compiler : ${CC} Vala bindings : ${HAVE_VALA} + Python bindings: : ${HAVE_PYTHON_BINDINGS} Gst-rtsp-server configured. Type 'make' to build. " From b6e7986f45631d759f10d66f9f74f4e21e898ae5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 8 Jan 2009 15:02:42 +0100 Subject: [PATCH 0021/1776] Install rtsp-session and rtsp-session-pool headers --- gst/rtsp-server/Makefile.am | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 8547149517..8fe6b19317 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -1,7 +1,9 @@ public_headers = \ rtsp-server.h \ rtsp-client.h \ - rtsp-media.h + rtsp-media.h \ + rtsp-session-pool.h \ + rtsp-session.h \ c_sources = \ rtsp-server.c \ @@ -10,10 +12,6 @@ c_sources = \ rtsp-session-pool.c \ rtsp-session.c -noinst_HEADERS = \ - rtsp-session-pool.h \ - rtsp-session.h - lib_LTLIBRARIES = \ libgstrtspserver-@GST_MAJORMINOR@.la From a76656ad8d032afe3cad4e377fd89df5e63364d6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 8 Jan 2009 16:28:24 +0100 Subject: [PATCH 0022/1776] Check if return value of gst_rtsp_session_get_media is not NULL --- gst/rtsp-server/Makefile.am | 2 +- gst/rtsp-server/rtsp-client.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 8fe6b19317..f073cde767 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -3,7 +3,7 @@ public_headers = \ rtsp-client.h \ rtsp-media.h \ rtsp-session-pool.h \ - rtsp-session.h \ + rtsp-session.h c_sources = \ rtsp-server.c \ diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 9bfb6f858a..9195084a63 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -88,6 +88,8 @@ handle_teardown_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag /* get a handle to the configuration of the media in the session */ media = gst_rtsp_session_get_media (session, client->media); + if (!media) + goto not_found; gst_rtsp_session_media_stop (media); @@ -116,6 +118,11 @@ service_unavailable: { return FALSE; } +not_found: + { + handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + return FALSE; + } } static gboolean @@ -139,6 +146,8 @@ handle_pause_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage * /* get a handle to the configuration of the media in the session */ media = gst_rtsp_session_get_media (session, client->media); + if (!media) + goto not_found; gst_rtsp_session_media_pause (media); g_object_unref (session); @@ -161,6 +170,11 @@ service_unavailable: { return FALSE; } +not_found: + { + handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + return FALSE; + } } static gboolean @@ -188,6 +202,8 @@ handle_play_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *r /* get a handle to the configuration of the media in the session */ media = gst_rtsp_session_get_media (session, client->media); + if (!media) + goto not_found; /* wait for paused to get the caps */ ret = gst_rtsp_session_media_pause (media); @@ -246,6 +262,11 @@ service_unavailable: handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); return FALSE; } +not_found: + { + handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + return FALSE; + } } static gboolean @@ -330,6 +351,8 @@ handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage * /* get a handle to the configuration of the media in the session */ media = gst_rtsp_session_get_media (session, client->media); + if (!media) + goto not_found; /* parse the stream we need to configure */ if (!(pos = strstr (uri, "stream="))) From 243b524f5140395c9786c1d2828b6bf54c06f961 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 19 Jan 2009 19:32:28 +0100 Subject: [PATCH 0023/1776] Do some more cleanup of the session pool. --- gst/rtsp-server/rtsp-session-pool.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 716e88827b..a58be9da43 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -21,6 +21,9 @@ #undef DEBUG +static void gst_rtsp_session_pool_finalize (GObject * object); + + G_DEFINE_TYPE (GstRTSPSessionPool, gst_rtsp_session_pool, G_TYPE_OBJECT); static void @@ -29,6 +32,8 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gst_rtsp_session_pool_finalize; } static void @@ -36,7 +41,18 @@ gst_rtsp_session_pool_init (GstRTSPSessionPool * pool) { pool->lock = g_mutex_new (); pool->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); + g_free, g_object_unref); +} + +static void +gst_rtsp_session_pool_finalize (GObject * object) +{ + GstRTSPSessionPool * pool = GST_RTSP_SESSION_POOL (object); + + g_mutex_free (pool->lock); + g_hash_table_unref (pool->sessions); + + G_OBJECT_CLASS (gst_rtsp_session_pool_parent_class)->finalize (object); } /** @@ -157,9 +173,5 @@ gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, GstRTSPSession *sess) g_mutex_lock (pool->lock); found = g_hash_table_remove (pool->sessions, sess); g_mutex_unlock (pool->lock); - - if (found) { - g_object_unref (sess); - } } From 8d2ace00262a30e83ec7493e3dbca0d7c7ab1af9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 19 Jan 2009 19:34:29 +0100 Subject: [PATCH 0024/1776] Name the parameters more appropriately. --- gst/rtsp-server/rtsp-client.c | 13 ++++++------- gst/rtsp-server/rtsp-client.h | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 9195084a63..d13787a6b4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -721,7 +721,7 @@ receive_failed: /* called when we need to accept a new request from a client */ static gboolean -client_accept (GstRTSPClient *client, GIOChannel *source) +client_accept (GstRTSPClient *client, GIOChannel *channel) { /* a new client connected. */ int server_sock_fd; @@ -730,7 +730,7 @@ client_accept (GstRTSPClient *client, GIOChannel *source) conn = client->connection; - server_sock_fd = g_io_channel_unix_get_fd (source); + server_sock_fd = g_io_channel_unix_get_fd (channel); address_len = sizeof (client->address); memset (&client->address, 0, address_len); @@ -802,10 +802,9 @@ gst_rtsp_client_get_session_pool (GstRTSPClient *client) /** * gst_rtsp_client_attach: * @client: a #GstRTSPClient - * @context: a #GMainContext + * @channel: a #GIOChannel * - * Attaches @client to @context. When the mainloop for @context is run, the - * client will be dispatched. + * Accept a new connection for @client on the socket in @source. * * This function should be called when the client properties and urls are fully * configured and the client is ready to start. @@ -813,11 +812,11 @@ gst_rtsp_client_get_session_pool (GstRTSPClient *client) * Returns: %TRUE if the client could be accepted. */ gboolean -gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *source) +gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel) { gst_rtsp_connection_create (NULL, &client->connection); - if (!client_accept (client, source)) + if (!client_accept (client, channel)) goto accept_failed; /* client accepted, spawn a thread for the client */ diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index da09684284..bbe85b7460 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -80,7 +80,7 @@ void gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client); gboolean gst_rtsp_client_accept (GstRTSPClient *client, - GIOChannel *source); + GIOChannel *channel); G_END_DECLS From 491b20bedd6f7989a29830d09c7906164e58483c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 19 Jan 2009 19:36:23 +0100 Subject: [PATCH 0025/1776] Make more properties configurable in the server. Expose the GIOChannel and GSource better to allow for more customisations. --- gst/rtsp-server/rtsp-server.c | 283 ++++++++++++++++++++++++++++++---- gst/rtsp-server/rtsp-server.h | 25 ++- 2 files changed, 274 insertions(+), 34 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 1c6d3ea983..ad1fdc71f4 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -22,12 +22,16 @@ #include "rtsp-server.h" #include "rtsp-client.h" -#define TCP_BACKLOG 5 +#define DEFAULT_BACKLOG 5 #define DEFAULT_PORT 1554 + enum { - ARG_0, - PROP_PORT + PROP_0, + PROP_BACKLOG, + PROP_PORT, + PROP_POOL, + PROP_LAST }; G_DEFINE_TYPE (GstRTSPServer, gst_rtsp_server, G_TYPE_OBJECT); @@ -47,16 +51,45 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) gobject_class->get_property = gst_rtsp_server_get_property; gobject_class->set_property = gst_rtsp_server_set_property; + /** + * GstRTSPServer::backlog + * + * The backlog argument defines the maximum length to which the queue of + * pending connections for the server may grow. If a connection request arrives + * when the queue is full, the client may receive an error with an indication of + * ECONNREFUSED or, if the underlying protocol supports retransmission, the + * request may be ignored so that a later reattempt at connection succeeds. + */ + g_object_class_install_property (gobject_class, PROP_BACKLOG, + g_param_spec_int ("backlog", "Backlog", "The maximum length to which the queue " + "of pending connections may grow", + 0, G_MAXINT, DEFAULT_BACKLOG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPServer::port + * + * The session port of the server. This is the port where the server will + * listen on. + */ g_object_class_install_property (gobject_class, PROP_PORT, - g_param_spec_int ("port", "Port", "The port the server uses", - 1, 65535, DEFAULT_PORT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_int ("port", "Port", "The port the server uses to listen on", + 1, 65535, DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPServer::pool + * + * The session pool of the server. By default each server has a separate + * session pool but sessions can be shared between servers by setting the same + * session pool on multiple servers. + */ + g_object_class_install_property (gobject_class, PROP_POOL, + g_param_spec_object ("pool", "Pool", "The session pool to use for client session", + GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void gst_rtsp_server_init (GstRTSPServer * server) { server->server_port = DEFAULT_PORT; + server->backlog = DEFAULT_BACKLOG; server->pool = gst_rtsp_session_pool_new (); } @@ -75,6 +108,117 @@ gst_rtsp_server_new (void) return result; } +/** + * gst_rtsp_server_set_port: + * @server: a #GstRTSPServer + * @port: the port + * + * Configure @server to accept connections on the given port. + * @port should be a port number between 1 and 65535. + * + * This function must be called before the server is bound. + */ +void +gst_rtsp_server_set_port (GstRTSPServer *server, gint port) +{ + g_return_if_fail (GST_IS_RTSP_SERVER (server)); + g_return_if_fail (port >= 1 && port <= 65535); + + server->server_port = port; +} + +/** + * gst_rtsp_server_get_port: + * @server: a #GstRTSPServer + * + * Get the port number on which the server will accept connections. + * + * Returns: the server port. + */ +gint +gst_rtsp_server_get_port (GstRTSPServer *server) +{ + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1); + + return server->server_port; +} + +/** + * gst_rtsp_server_set_backlog: + * @server: a #GstRTSPServer + * @backlog: the backlog + * + * configure the maximum amount of requests that may be queued for the + * server. + * + * This function must be called before the server is bound. + */ +void +gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog) +{ + g_return_if_fail (GST_IS_RTSP_SERVER (server)); + + server->backlog = backlog; +} + +/** + * gst_rtsp_server_get_backlog: + * @server: a #GstRTSPServer + * + * The maximum amount of queued requests for the server. + * + * Returns: the server backlog. + */ +gint +gst_rtsp_server_get_backlog (GstRTSPServer *server) +{ + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1); + + return server->backlog; +} + +/** + * gst_rtsp_server_set_session_pool: + * @server: a #GstRTSPServer + * @pool: a #GstRTSPSessionPool + * + * configure @pool to be used as the session pool of @server. + */ +void +gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool) +{ + g_return_if_fail (GST_IS_RTSP_SERVER (server)); + + if (server->pool) + g_object_unref (server->pool); + if (pool) + pool = g_object_ref (pool); + server->pool = pool; +} + + +/** + * gst_rtsp_server_get_session_pool: + * @server: a #GstRTSPServer + * + * Get the #GstRTSPSessionPool used as the session pool of @server. + * + * Returns: the #GstRTSPSessionPool used for sessions. g_object_unref() after + * usage. + */ +GstRTSPSessionPool * +gst_rtsp_server_get_session_pool (GstRTSPServer *server) +{ + GstRTSPSessionPool *result; + + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + + if ((result = server->pool)) + g_object_ref (result); + + return result; +} + static void gst_rtsp_server_get_property (GObject *object, guint propid, GValue *value, GParamSpec *pspec) @@ -83,7 +227,13 @@ gst_rtsp_server_get_property (GObject *object, guint propid, switch (propid) { case PROP_PORT: - g_value_set_int (value, server->server_port); + g_value_set_int (value, gst_rtsp_server_get_port (server)); + break; + case PROP_BACKLOG: + g_value_set_int (value, gst_rtsp_server_get_backlog (server)); + break; + case PROP_POOL: + g_value_take_object (value, gst_rtsp_server_get_session_pool (server)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -98,13 +248,20 @@ gst_rtsp_server_set_property (GObject *object, guint propid, switch (propid) { case PROP_PORT: - server->server_port = g_value_get_int (value); + gst_rtsp_server_set_port (server, g_value_get_int (value)); + break; + case PROP_BACKLOG: + gst_rtsp_server_set_backlog (server, g_value_get_int (value)); + break; + case PROP_POOL: + gst_rtsp_server_set_session_pool (server, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } } +/* Prepare a server socket for @server and make it listen on the configured port */ static gboolean gst_rtsp_server_sink_init_send (GstRTSPServer * server) { @@ -146,8 +303,8 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) fcntl (server->server_sock.fd, F_SETFL, O_NONBLOCK); GST_DEBUG_OBJECT (server, "listening on server socket %d with queue of %d", - server->server_sock.fd, TCP_BACKLOG); - if (listen (server->server_sock.fd, TCP_BACKLOG) == -1) + server->server_sock.fd, server->backlog); + if (listen (server->server_sock.fd, server->backlog) == -1) goto listen_failed; GST_DEBUG_OBJECT (server, @@ -200,13 +357,22 @@ bind_failed: } } -/* called when an event is available on our server socket */ -static gboolean -server_dispatch (GIOChannel *source, GIOCondition condition, GstRTSPServer *server) +/** + * gst_rtsp_server_io_func: + * @channel: a #GIOChannel + * @condition: the condition on @source + * + * A default #GIOFunc that creates a new #GstRTSPClient to accept and handle a + * new connection on @channel or @server. + * + * Returns: TRUE if the source could be connected, FALSE if an error occured. + */ +gboolean +gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, GstRTSPServer *server) { - if (condition & G_IO_IN) { - GstRTSPClient *client; + GstRTSPClient *client; + if (condition & G_IO_IN) { /* a new client connected, create a session to handle the client. */ client = gst_rtsp_client_new (); @@ -216,7 +382,7 @@ server_dispatch (GIOChannel *source, GIOCondition condition, GstRTSPServer *serv /* accept connections for that client, this function returns after accepting * the connection and will run the remainder of the communication with the * client asyncronously. */ - if (!gst_rtsp_client_accept (client, source)) + if (!gst_rtsp_client_accept (client, channel)) goto accept_failed; /* can unref the client now, when the request is finished, it will be @@ -233,10 +399,75 @@ accept_failed: { g_error ("Could not accept client on server socket %d: %s (%d)", server->server_sock.fd, g_strerror (errno), errno); + gst_object_unref (client); return FALSE; } } +/** + * gst_rtsp_server_get_io_channel: + * @server: a #GstRTSPServer + * + * Create a #GIOChannel for @server. + * + * Returns: the GIOChannel for @server or NULL when an error occured. + */ +GIOChannel * +gst_rtsp_server_get_io_channel (GstRTSPServer *server) +{ + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + + if (server->io_channel == NULL) { + if (!gst_rtsp_server_sink_init_send (server)) + goto init_failed; + + /* create IO channel for the socket */ + server->io_channel = g_io_channel_unix_new (server->server_sock.fd); + } + return server->io_channel; + +init_failed: + { + return NULL; + } +} + +/** + * gst_rtsp_server_create_watch: + * @server: a #GstRTSPServer + * + * Create a #GSource for @server. The new source will have a default + * #GIOFunc of gst_rtsp_server_io_func(). + * + * Returns: the #GSource for @server or NULL when an error occured. + */ +GSource * +gst_rtsp_server_create_watch (GstRTSPServer *server) +{ + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + + if (server->io_watch == NULL) { + GIOChannel *channel; + + channel = gst_rtsp_server_get_io_channel (server); + if (channel == NULL) + goto no_channel; + + /* create a watch for reads (new connections) and possible errors */ + server->io_watch = g_io_create_watch (channel, G_IO_IN | + G_IO_ERR | G_IO_HUP | G_IO_NVAL); + + /* configure the callback */ + g_source_set_callback (server->io_watch, (GSourceFunc) gst_rtsp_server_io_func, server, NULL); + } + return server->io_watch; + +no_channel: + { + return NULL; + } +} + /** * gst_rtsp_server_attach: * @server: a #GstRTSPServer @@ -254,26 +485,20 @@ guint gst_rtsp_server_attach (GstRTSPServer *server, GMainContext *context) { guint res; + GSource *source; - if (!gst_rtsp_server_sink_init_send (server)) - goto init_failed; + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), 0); - /* create IO channel for the socket */ - server->io_channel = g_io_channel_unix_new (server->server_sock.fd); + source = gst_rtsp_server_create_watch (server); + if (source == NULL) + goto no_source; - /* create a watch for reads (new connections) and possible errors */ - server->io_watch = g_io_create_watch (server->io_channel, G_IO_IN | - G_IO_ERR | G_IO_HUP | G_IO_NVAL); - - /* configure the callback */ - g_source_set_callback (server->io_watch, (GSourceFunc) server_dispatch, server, NULL); - - res = g_source_attach (server->io_watch, context); + res = g_source_attach (source, context); return res; /* ERRORS */ -init_failed: +no_source: { return 0; } diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 93bc820d8c..d23bdd014f 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -56,7 +56,8 @@ struct _GstRTSPServer { GObject parent; /* server information */ - int server_port; + gint server_port; + gint backlog; gchar *host; struct sockaddr_in server_sin; @@ -74,12 +75,26 @@ struct _GstRTSPServerClass { GObjectClass parent_class; }; -GType gst_rtsp_server_get_type (void); +GType gst_rtsp_server_get_type (void); -GstRTSPServer * gst_rtsp_server_new (void); +GstRTSPServer * gst_rtsp_server_new (void); -guint gst_rtsp_server_attach (GstRTSPServer *server, - GMainContext *context); +void gst_rtsp_server_set_port (GstRTSPServer *server, gint port); +gint gst_rtsp_server_get_port (GstRTSPServer *server); + +void gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog); +gint gst_rtsp_server_get_backlog (GstRTSPServer *server); + +void gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool); +GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *server); + +gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, + GstRTSPServer *server); + +GIOChannel * gst_rtsp_server_get_io_channel (GstRTSPServer *server); +GSource * gst_rtsp_server_create_watch (GstRTSPServer *server); +guint gst_rtsp_server_attach (GstRTSPServer *server, + GMainContext *context); G_END_DECLS From 74210e67be3e7db0da6b803caa28494cd8fb682f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Jan 2009 13:19:36 +0100 Subject: [PATCH 0026/1776] Make vmethod to create and accept new clients. Add some docs. --- gst/rtsp-server/rtsp-server.c | 61 ++++++++++++++++++++++++++--------- gst/rtsp-server/rtsp-server.h | 11 +++++++ 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index ad1fdc71f4..fce3aa5f3b 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -41,6 +41,9 @@ static void gst_rtsp_server_get_property (GObject *object, guint propid, static void gst_rtsp_server_set_property (GObject *object, guint propid, const GValue *value, GParamSpec *pspec); +static GstRTSPClient * gst_rtsp_server_accept_client (GstRTSPServer *server, + GIOChannel *channel); + static void gst_rtsp_server_class_init (GstRTSPServerClass * klass) { @@ -83,6 +86,8 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) g_object_class_install_property (gobject_class, PROP_POOL, g_param_spec_object ("pool", "Pool", "The session pool to use for client session", GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + klass->accept_client = gst_rtsp_server_accept_client; } static void @@ -357,6 +362,37 @@ bind_failed: } } +/* default method for creating a new client object in the server to accept and + * handle a client connection on this server */ +static GstRTSPClient * +gst_rtsp_server_accept_client (GstRTSPServer *server, GIOChannel *channel) +{ + GstRTSPClient *client; + + /* a new client connected, create a session to handle the client. */ + client = gst_rtsp_client_new (); + + /* set the session pool that this client should use */ + gst_rtsp_client_set_session_pool (client, server->pool); + + /* accept connections for that client, this function returns after accepting + * the connection and will run the remainder of the communication with the + * client asyncronously. */ + if (!gst_rtsp_client_accept (client, channel)) + goto accept_failed; + + return client; + + /* ERRORS */ +accept_failed: + { + g_error ("Could not accept client on server socket %d: %s (%d)", + server->server_sock.fd, g_strerror (errno), errno); + gst_object_unref (client); + return NULL; + } +} + /** * gst_rtsp_server_io_func: * @channel: a #GIOChannel @@ -370,20 +406,17 @@ bind_failed: gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, GstRTSPServer *server) { - GstRTSPClient *client; + GstRTSPClient *client = NULL; + GstRTSPServerClass *klass; if (condition & G_IO_IN) { - /* a new client connected, create a session to handle the client. */ - client = gst_rtsp_client_new (); + klass = GST_RTSP_SERVER_GET_CLASS (server); - /* set the session pool that this client should use */ - gst_rtsp_client_set_session_pool (client, server->pool); - - /* accept connections for that client, this function returns after accepting - * the connection and will run the remainder of the communication with the - * client asyncronously. */ - if (!gst_rtsp_client_accept (client, channel)) - goto accept_failed; + /* a new client connected, create a client object to handle the client. */ + if (klass->accept_client) + client = klass->accept_client (server, channel); + if (client == NULL) + goto client_failed; /* can unref the client now, when the request is finished, it will be * unreffed async. */ @@ -395,11 +428,9 @@ gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, GstRTSPSer return TRUE; /* ERRORS */ -accept_failed: +client_failed: { - g_error ("Could not accept client on server socket %d: %s (%d)", - server->server_sock.fd, g_strerror (errno), errno); - gst_object_unref (client); + GST_ERROR_OBJECT (server, "failed to create a client"); return FALSE; } } diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index d23bdd014f..a7d7b5c422 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -34,6 +34,7 @@ #include #include "rtsp-session-pool.h" +#include "rtsp-client.h" #ifndef __GST_RTSP_SERVER_H__ #define __GST_RTSP_SERVER_H__ @@ -71,8 +72,18 @@ struct _GstRTSPServer { GstRTSPSessionPool *pool; }; +/** + * GstRTSPServerClass: + * + * @accept_client: Create, configure, accept and return a new GstRTSPClient + * object that handles the new connection on @channel. + * + * The RTSP server class structure + */ struct _GstRTSPServerClass { GObjectClass parent_class; + + GstRTSPClient * (*accept_client) (GstRTSPServer *server, GIOChannel *channel); }; GType gst_rtsp_server_get_type (void); From b312f98627e2f19ec9d13894ccc37e6423efd292 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Jan 2009 13:57:47 +0100 Subject: [PATCH 0027/1776] Move the connection code in one place Add some comments --- gst/rtsp-server/rtsp-client.c | 22 ++++++++++++---------- gst/rtsp-server/rtsp-client.h | 11 +++++++++++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d13787a6b4..5249b4d952 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -215,6 +215,7 @@ handle_play_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *r case GST_STATE_CHANGE_FAILURE: goto service_unavailable; case GST_STATE_CHANGE_ASYNC: + /* wait for paused state change to complete */ ret = gst_element_get_state (media->pipeline, NULL, NULL, -1); break; } @@ -724,29 +725,33 @@ static gboolean client_accept (GstRTSPClient *client, GIOChannel *channel) { /* a new client connected. */ - int server_sock_fd; + int server_sock_fd, fd; unsigned int address_len; GstRTSPConnection *conn; - conn = client->connection; - server_sock_fd = g_io_channel_unix_get_fd (channel); address_len = sizeof (client->address); memset (&client->address, 0, address_len); - conn->fd.fd = accept (server_sock_fd, (struct sockaddr *) &client->address, + fd = accept (server_sock_fd, (struct sockaddr *) &client->address, &address_len); - if (conn->fd.fd == -1) + if (fd == -1) goto accept_failed; - g_print ("added new client %p ip %s with fd %d\n", client, - inet_ntoa (client->address.sin_addr), conn->fd.fd); + /* now create the connection object */ + gst_rtsp_connection_create (NULL, &conn); + conn->fd.fd = fd; /* FIXME some hackery, we need to have a connection method to accept server * connections */ gst_poll_add_fd (conn->fdset, &conn->fd); + g_print ("added new client %p ip %s with fd %d\n", client, + inet_ntoa (client->address.sin_addr), conn->fd.fd); + + client->connection = conn; + return TRUE; /* ERRORS */ @@ -814,8 +819,6 @@ gst_rtsp_client_get_session_pool (GstRTSPClient *client) gboolean gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel) { - gst_rtsp_connection_create (NULL, &client->connection); - if (!client_accept (client, channel)) goto accept_failed; @@ -828,7 +831,6 @@ gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel) /* ERRORS */ accept_failed: { - gst_rtsp_connection_close (client->connection); return FALSE; } } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index bbe85b7460..1f80480d6e 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -54,6 +54,17 @@ G_BEGIN_DECLS typedef struct _GstRTSPClient GstRTSPClient; typedef struct _GstRTSPClientClass GstRTSPClientClass; +/** + * GstRTSPClient: + * + * @connection: the connection object handling the client request. + * @address: the address of the connection + * @media: handle to the media handled by the client. + * @pool: handle to the session pool used by the client. + * @thread: thread to handle the client connection + * + * The client structure. + */ struct _GstRTSPClient { GObject parent; From f00188b50e09bb1f2c8d8225656228b9f4399173 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Jan 2009 19:40:42 +0100 Subject: [PATCH 0028/1776] Add some comments. --- gst/rtsp-server/rtsp-session.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 5ad4b3b9b7..c87a1396d1 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -46,7 +46,8 @@ typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia; /** * GstRTSPSessionStream: * - * Configuration of a stream. + * Configuration of a stream. A stream is an audio or video stream related to a + * media. */ struct _GstRTSPSessionStream { @@ -76,7 +77,9 @@ struct _GstRTSPSessionStream /** * GstRTSPSessionMedia: * - * State of a client session regarding a specific media. + * State of a client session regarding a specific media. The media is identified + * with the media factory. The media is typically composed of multiple streams, + * such as an audio and video stream. */ struct _GstRTSPSessionMedia { @@ -103,6 +106,8 @@ struct _GstRTSPSessionMedia * GstRTSPSession: * * Session information kept by the server for a specific client. + * One client session, identified with a session id, can handle multiple medias + * identified with the media factory. */ struct _GstRTSPSession { GObject parent; From a3522af4f8af10e8f352ca5d88cb7815c04ed35c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Jan 2009 19:41:53 +0100 Subject: [PATCH 0029/1776] Allow custom session pools to override the session id allocation algorithms Add some comments. --- gst/rtsp-server/rtsp-session-pool.c | 32 ++++++++++++++++++++++++++--- gst/rtsp-server/rtsp-session-pool.h | 11 ++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index a58be9da43..968d241795 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -23,6 +23,7 @@ static void gst_rtsp_session_pool_finalize (GObject * object); +static gchar * create_session_id (GstRTSPSessionPool *pool); G_DEFINE_TYPE (GstRTSPSessionPool, gst_rtsp_session_pool, G_TYPE_OBJECT); @@ -34,6 +35,8 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gst_rtsp_session_pool_finalize; + + klass->create_session_id = create_session_id; } static void @@ -59,6 +62,8 @@ gst_rtsp_session_pool_finalize (GObject * object) * gst_rtsp_session_pool_new: * * Create a new #GstRTSPSessionPool instance. + * + * Returns: A new #GstRTSPSessionPool. g_object_unref() after usage. */ GstRTSPSessionPool * gst_rtsp_session_pool_new (void) @@ -98,7 +103,7 @@ gst_rtsp_session_pool_find (GstRTSPSessionPool *pool, const gchar *sessionid) } static gchar * -create_session_id (void) +create_session_id (GstRTSPSessionPool *pool) { gchar id[16]; gint i; @@ -122,14 +127,23 @@ GstRTSPSession * gst_rtsp_session_pool_create (GstRTSPSessionPool *pool) { GstRTSPSession *result = NULL; - gchar *id; + GstRTSPSessionPoolClass *klass; + gchar *id = NULL; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL); + klass = GST_RTSP_SESSION_POOL_GET_CLASS (pool); + do { /* start by creating a new random session id, we assume that this is random * enough to not cause a collision, which we will check later */ - id = create_session_id (); + if (klass->create_session_id) + id = klass->create_session_id (pool); + else + goto no_function; + + if (id == NULL) + goto no_session; g_mutex_lock (pool->lock); /* check if the sessionid existed */ @@ -151,6 +165,18 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool *pool) } while (result == NULL); return result; + + /* ERRORS */ +no_function: + { + g_warning ("no create_session_id vmethod in GstRTSPSessionPool %p", pool); + return NULL; + } +no_session: + { + g_warning ("can't create session id with GstRTSPSessionPool %p", pool); + return NULL; + } } /** diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 9336647d4d..fafe606e9f 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -41,6 +41,9 @@ typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; /** * GstRTSPSessionPool: * + * @lock: locking the session hashtable + * @session: hashtable of sessions indexed by the session id. + * * An object that keeps track of the active sessions. */ struct _GstRTSPSessionPool { @@ -50,8 +53,16 @@ struct _GstRTSPSessionPool { GHashTable *sessions; }; +/** + * GstRTSPSessionPoolClass: + * + * @create_session_id: create a new random session id. Subclasses should not + * check if the session exists. + */ struct _GstRTSPSessionPoolClass { GObjectClass parent_class; + + gchar * (*create_session_id) (GstRTSPSessionPool *pool); }; GType gst_rtsp_session_pool_get_type (void); From 852cc3973c0dbca3963f63ba6e75e674db8d0b89 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Jan 2009 19:43:47 +0100 Subject: [PATCH 0030/1776] Add comments. Remove unused field --- gst/rtsp-server/rtsp-media.c | 3 --- gst/rtsp-server/rtsp-media.h | 19 ++++++++++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c02173416f..13425d03f9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -110,9 +110,6 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) } /** - * - * STREAMING CONFIGURATION - * * gst_rtsp_media_prepare: * @media: a #GstRTSPMedia * @bin: the parent bin to create the elements in. diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index bf4bede1ad..f96ab1f041 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -38,11 +38,22 @@ typedef struct _GstRTSPMedia GstRTSPMedia; typedef struct _GstRTSPMediaStream GstRTSPMediaStream; typedef struct _GstRTSPMediaClass GstRTSPMediaClass; +/** + * GstRTSPMediaStream: + * + * @idx: the stream index + * @element: the toplevel element + * @srcpad: the srcpad of the stream + * @payloader: the payloader of the formattt + * @caps_sig: the signal id for detecting caps + * @caps: the caps of the stream + * + * The definition of a media stream. The streams are identified by @id. + */ struct _GstRTSPMediaStream { GstRTSPMedia *media; guint idx; - gchar *name; GstElement *element; GstPad *srcpad; @@ -51,6 +62,12 @@ struct _GstRTSPMediaStream { GstCaps *caps; }; +/** + * GstRTSPMedia: + * + * The definition and logic for constructing the pipeline for a media. The media + * can contain multiple streams like audio and video. + */ struct _GstRTSPMedia { GObject parent; From 63ee9e050fd0c8cafa20f67f1d831d7163744c4e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Jan 2009 19:44:45 +0100 Subject: [PATCH 0031/1776] Add media factory to map urls to media pipeline objects. --- gst/rtsp-server/rtsp-media-factory.c | 97 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 75 +++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 gst/rtsp-server/rtsp-media-factory.c create mode 100644 gst/rtsp-server/rtsp-media-factory.h diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c new file mode 100644 index 0000000000..d402bad189 --- /dev/null +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -0,0 +1,97 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "rtsp-media-factory.h" + +G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT); + +static void gst_rtsp_media_factory_finalize (GObject * obj); + +static GstRTSPMedia * create_media (GstRTSPMediaFactory *factory, const gchar *url); + +static void +gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gst_rtsp_media_factory_finalize; + + klass->create_media = create_media; +} + +static void +gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) +{ +} + +static void +gst_rtsp_media_factory_finalize (GObject * obj) +{ + G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj); +} + +GstRTSPMediaFactory * +gst_rtsp_media_factory_new (void) +{ + GstRTSPMediaFactory *result; + + result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY, NULL); + + return result; +} + +static GstRTSPMedia * +create_media (GstRTSPMediaFactory *factory, const gchar *url) +{ + GstRTSPMedia *result; + + result = gst_rtsp_media_new (url); + + return result; +} + +GstRTSPMedia * +gst_rtsp_media_factory_create (GstRTSPMediaFactory *factory, const gchar *url) +{ + GstRTSPMedia *result = NULL; + GstRTSPMediaFactoryClass *klass; + + klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); + + if (klass->create_media) + result = klass->create_media (factory, url); + + return result; +} + +void +gst_rtsp_media_factory_add (GstRTSPMediaFactory *factory, const gchar *path, + GType type) +{ + g_warning ("gst_rtsp_media_factory_add: not implemented"); +} +void +gst_rtsp_media_factory_remove (GstRTSPMediaFactory *factory, const gchar *path, + GType type) +{ + g_warning ("gst_rtsp_media_factory_remove: not implemented"); +} + diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h new file mode 100644 index 0000000000..1399649bfa --- /dev/null +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -0,0 +1,75 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + +#include "rtsp-media.h" + +#ifndef __GST_RTSP_MEDIA_FACTORY_H__ +#define __GST_RTSP_MEDIA_FACTORY_H__ + +G_BEGIN_DECLS + +#define GST_TYPE_RTSP_MEDIA_FACTORY (gst_rtsp_media_get_type ()) +#define GST_IS_RTSP_MEDIA_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY)) +#define GST_IS_RTSP_MEDIA_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA_FACTORY)) +#define GST_RTSP_MEDIA_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA_FACTORY, GstRTSPMediaFactoryClass)) +#define GST_RTSP_MEDIA_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA_FACTORY, GstRTSPMediaFactory)) +#define GST_RTSP_MEDIA_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA_FACTORY, GstRTSPMediaFactoryClass)) +#define GST_RTSP_MEDIA_FACTORY_CAST(obj) ((GstRTSPMediaFactory*)(obj)) +#define GST_RTSP_MEDIA_FACTORY_CLASS_CAST(klass) ((GstRTSPMediaFactoryClass*)(klass)) + +typedef struct _GstRTSPMediaFactory GstRTSPMediaFactory; +typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; + +/** + * GstRTSPMediaFactory: + * + * Creates a #GstRTSPMedia object for a given url. + */ +struct _GstRTSPMediaFactory { + GObject parent; +}; + +struct _GstRTSPMediaFactoryClass { + GObjectClass parent_class; + + GstRTSPMedia * (*create_media) (GstRTSPMediaFactory *factory, const gchar *url); +}; + +GType gst_rtsp_media_factory_get_type (void); + +/* creating a factory */ +GstRTSPMediaFactory * gst_rtsp_media_factory_new (void); + +/* creating a media */ +GstRTSPMedia * gst_rtsp_media_factory_create (GstRTSPMediaFactory *factory, const gchar *url); + + +/* managing media GTypes to a path */ +void gst_rtsp_media_factory_add (GstRTSPMediaFactory *factory, const gchar *path, + GType type); +void gst_rtsp_media_factory_remove (GstRTSPMediaFactory *factory, const gchar *path, + GType type); + +G_END_DECLS + +#endif /* __GST_RTSP_MEDIA_FACTORY_H__ */ From f38c390736088c0d75861dbd7bdacf005c48aef7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Jan 2009 19:45:28 +0100 Subject: [PATCH 0032/1776] Add Makefile entry for the media factory --- gst/rtsp-server/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index f073cde767..873619bd8f 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -2,6 +2,7 @@ public_headers = \ rtsp-server.h \ rtsp-client.h \ rtsp-media.h \ + rtsp-media-factory.h \ rtsp-session-pool.h \ rtsp-session.h @@ -9,6 +10,7 @@ c_sources = \ rtsp-server.c \ rtsp-client.c \ rtsp-media.c \ + rtsp-media-factory.c \ rtsp-session-pool.c \ rtsp-session.c From 94d60a8611a7e5fb6f863206ab53a5059612a975 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Jan 2009 19:46:21 +0100 Subject: [PATCH 0033/1776] Allow setting a custom media factory for a client. --- gst/rtsp-server/rtsp-client.c | 43 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-client.h | 26 +++++++++++++-------- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 5249b4d952..b8849416da 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -803,6 +803,49 @@ gst_rtsp_client_get_session_pool (GstRTSPClient *client) return result; } +/** + * gst_rtsp_client_set_media_factory: + * @client: a #GstRTSPClient + * @factory: a #GstRTSPMediaFactory + * + * Set @factory as the media factory for @client which it will use to map urls + * to media streams. + */ +void +gst_rtsp_client_set_media_factory (GstRTSPClient *client, GstRTSPMediaFactory *factory) +{ + GstRTSPMediaFactory *old; + + old = client->factory; + + if (old != factory) { + if (factory) + g_object_ref (factory); + client->factory = factory; + if (old) + g_object_unref (old); + } +} + +/** + * gst_rtsp_client_get_media_factory: + * @client: a #GstRTSPClient + * + * Get the #GstRTSPMediaFactory object that @client uses to manage its sessions. + * + * Returns: a #GstRTSPMediaFactory, unref after usage. + */ +GstRTSPMediaFactory * +gst_rtsp_client_get_media_factory (GstRTSPClient *client) +{ + GstRTSPMediaFactory *result; + + if ((result = client->factory)) + g_object_ref (result); + + return result; +} + /** * gst_rtsp_client_attach: diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 1f80480d6e..5dff20c642 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -38,6 +38,7 @@ #define __GST_RTSP_CLIENT_H__ #include "rtsp-media.h" +#include "rtsp-media-factory.h" #include "rtsp-session-pool.h" G_BEGIN_DECLS @@ -70,28 +71,33 @@ struct _GstRTSPClient { GstRTSPConnection *connection; struct sockaddr_in address; - - GstRTSPMedia *media; + GThread *thread; GstRTSPSessionPool *pool; - GThread *thread; + GstRTSPMedia *media; + GstRTSPMediaFactory *factory; + }; struct _GstRTSPClientClass { GObjectClass parent_class; }; -GType gst_rtsp_client_get_type (void); +GType gst_rtsp_client_get_type (void); -GstRTSPClient * gst_rtsp_client_new (void); +GstRTSPClient * gst_rtsp_client_new (void); -void gst_rtsp_client_set_session_pool (GstRTSPClient *client, - GstRTSPSessionPool *pool); -GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client); +void gst_rtsp_client_set_session_pool (GstRTSPClient *client, + GstRTSPSessionPool *pool); +GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client); -gboolean gst_rtsp_client_accept (GstRTSPClient *client, - GIOChannel *channel); +void gst_rtsp_client_set_media_factory (GstRTSPClient *client, + GstRTSPMediaFactory *factory); +GstRTSPMediaFactory * gst_rtsp_client_get_media_factory (GstRTSPClient *client); + +gboolean gst_rtsp_client_accept (GstRTSPClient *client, + GIOChannel *channel); G_END_DECLS From ddf17f338b3c8702e8f9da7b786407af40383686 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Jan 2009 19:47:07 +0100 Subject: [PATCH 0034/1776] Allow setting a custom media factory for a server --- gst/rtsp-server/rtsp-server.c | 69 ++++++++++++++++++++++++++++++++++- gst/rtsp-server/rtsp-server.h | 31 ++++++++++------ 2 files changed, 87 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index fce3aa5f3b..cea1bf0455 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -31,6 +31,7 @@ enum PROP_BACKLOG, PROP_PORT, PROP_POOL, + PROP_FACTORY, PROP_LAST }; @@ -86,6 +87,15 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) g_object_class_install_property (gobject_class, PROP_POOL, g_param_spec_object ("pool", "Pool", "The session pool to use for client session", GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPServer::factory + * + * The media factory to use for this server. By default the server has no + * media factories and thus cannot map urls to media streams. + */ + g_object_class_install_property (gobject_class, PROP_POOL, + g_param_spec_object ("factory", "Factory", "The media factory to use for client session", + GST_TYPE_RTSP_MEDIA_FACTORY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); klass->accept_client = gst_rtsp_server_accept_client; } @@ -197,7 +207,7 @@ gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *poo if (server->pool) g_object_unref (server->pool); if (pool) - pool = g_object_ref (pool); + g_object_ref (pool); server->pool = pool; } @@ -224,6 +234,54 @@ gst_rtsp_server_get_session_pool (GstRTSPServer *server) return result; } +/** + * gst_rtsp_server_set_media_factory: + * @server: a #GstRTSPServer + * @factory: a #GstRTSPMediaFactory + * + * configure @factory to be used as the media factory of @server. + */ +void +gst_rtsp_server_set_media_factory (GstRTSPServer *server, GstRTSPMediaFactory *factory) +{ + GstRTSPMediaFactory *old; + + g_return_if_fail (GST_IS_RTSP_SERVER (server)); + + old = server->factory; + + if (old != factory) { + if (factory) + g_object_ref (factory); + server->factory = factory; + if (old) + g_object_unref (old); + } +} + + +/** + * gst_rtsp_server_get_media_factory: + * @server: a #GstRTSPServer + * + * Get the #GstRTSPMediaFactory used as the media factory of @server. + * + * Returns: the #GstRTSPMediaFactory of @server. g_object_unref() after + * usage. + */ +GstRTSPMediaFactory * +gst_rtsp_server_get_media_factory (GstRTSPServer *server) +{ + GstRTSPMediaFactory *result; + + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + + if ((result = server->factory)) + g_object_ref (result); + + return result; +} + static void gst_rtsp_server_get_property (GObject *object, guint propid, GValue *value, GParamSpec *pspec) @@ -240,6 +298,9 @@ gst_rtsp_server_get_property (GObject *object, guint propid, case PROP_POOL: g_value_take_object (value, gst_rtsp_server_get_session_pool (server)); break; + case PROP_FACTORY: + g_value_take_object (value, gst_rtsp_server_get_media_factory (server)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -261,6 +322,9 @@ gst_rtsp_server_set_property (GObject *object, guint propid, case PROP_POOL: gst_rtsp_server_set_session_pool (server, g_value_get_object (value)); break; + case PROP_FACTORY: + gst_rtsp_server_set_media_factory (server, g_value_get_object (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -375,6 +439,9 @@ gst_rtsp_server_accept_client (GstRTSPServer *server, GIOChannel *channel) /* set the session pool that this client should use */ gst_rtsp_client_set_session_pool (client, server->pool); + /* set the session pool that this client should use */ + gst_rtsp_client_set_media_factory (client, server->factory); + /* accept connections for that client, this function returns after accepting * the connection and will run the remainder of the communication with the * client asyncronously. */ diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index a7d7b5c422..5dd5629b63 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -34,6 +34,7 @@ #include #include "rtsp-session-pool.h" +#include "rtsp-media-factory.h" #include "rtsp-client.h" #ifndef __GST_RTSP_SERVER_H__ @@ -70,6 +71,9 @@ struct _GstRTSPServer { /* sessions on this server */ GstRTSPSessionPool *pool; + + /* media factory for this server */ + GstRTSPMediaFactory *factory; }; /** @@ -86,25 +90,28 @@ struct _GstRTSPServerClass { GstRTSPClient * (*accept_client) (GstRTSPServer *server, GIOChannel *channel); }; -GType gst_rtsp_server_get_type (void); +GType gst_rtsp_server_get_type (void); -GstRTSPServer * gst_rtsp_server_new (void); +GstRTSPServer * gst_rtsp_server_new (void); -void gst_rtsp_server_set_port (GstRTSPServer *server, gint port); -gint gst_rtsp_server_get_port (GstRTSPServer *server); +void gst_rtsp_server_set_port (GstRTSPServer *server, gint port); +gint gst_rtsp_server_get_port (GstRTSPServer *server); -void gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog); -gint gst_rtsp_server_get_backlog (GstRTSPServer *server); +void gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog); +gint gst_rtsp_server_get_backlog (GstRTSPServer *server); -void gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool); -GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *server); +void gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool); +GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *server); -gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, +void gst_rtsp_server_set_media_factory (GstRTSPServer *server, GstRTSPMediaFactory *factory); +GstRTSPMediaFactory * gst_rtsp_server_get_media_factory (GstRTSPServer *server); + +gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, GstRTSPServer *server); -GIOChannel * gst_rtsp_server_get_io_channel (GstRTSPServer *server); -GSource * gst_rtsp_server_create_watch (GstRTSPServer *server); -guint gst_rtsp_server_attach (GstRTSPServer *server, +GIOChannel * gst_rtsp_server_get_io_channel (GstRTSPServer *server); +GSource * gst_rtsp_server_create_watch (GstRTSPServer *server); +guint gst_rtsp_server_attach (GstRTSPServer *server, GMainContext *context); G_END_DECLS From 4b1c190a5fa5dc0b633072da5c9182b90afb300f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 22 Jan 2009 15:33:29 +0100 Subject: [PATCH 0035/1776] Make the server handle arbitrary pipelines Make GstMediaFactory an object that can instantiate GstMediaBin objects. The GstMediaBin object has a handle to a bin with elements and to a list of GstMediaStream objects that this bin produces. Add GstMediaMapper that can map url mountpoints to GstMediaFactory objects along with methods to register and remove those mappings. Add methods and a property to GstRTSPServer to manage the GstMediaMapper object used by the server instance. Modify the example application so that it shows how to create custom pipelines attached to a specific mount point. Various misc cleanps. --- examples/main.c | 34 ++++ gst/rtsp-server/Makefile.am | 4 +- gst/rtsp-server/rtsp-client.c | 190 +++++++++++++------- gst/rtsp-server/rtsp-client.h | 13 +- gst/rtsp-server/rtsp-media-factory.c | 252 ++++++++++++++++++++++++--- gst/rtsp-server/rtsp-media-factory.h | 34 ++-- gst/rtsp-server/rtsp-media-mapping.c | 146 ++++++++++++++++ gst/rtsp-server/rtsp-media-mapping.h | 76 ++++++++ gst/rtsp-server/rtsp-media.c | 211 +++------------------- gst/rtsp-server/rtsp-media.h | 50 +++--- gst/rtsp-server/rtsp-server.c | 75 ++++---- gst/rtsp-server/rtsp-server.h | 10 +- gst/rtsp-server/rtsp-session.c | 30 ++-- gst/rtsp-server/rtsp-session.h | 13 +- 14 files changed, 758 insertions(+), 380 deletions(-) create mode 100644 gst/rtsp-server/rtsp-media-mapping.c create mode 100644 gst/rtsp-server/rtsp-media-mapping.h diff --git a/examples/main.c b/examples/main.c index 41a1cb91ad..07b28cdd2a 100644 --- a/examples/main.c +++ b/examples/main.c @@ -26,6 +26,8 @@ main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; + GstRTSPMediaMapping *mapping; + GstRTSPMediaFactory *factory; gst_init (&argc, &argv); @@ -34,9 +36,41 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); + /* get the mapping for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mapping = gst_rtsp_server_get_media_mapping (server); + + /* make a media factory for a webcam. The default media factory can use + * gst-launch syntax to create pipelines. */ + factory = gst_rtsp_media_factory_new (); +#if 0 + gst_rtsp_media_factory_set_launch (factory, "( " + "v4l2src ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " + "queue ! videorate ! ffmpegcolorspace ! " + "x264enc bitrate=300 ! rtph264pay name=pay0 pt=96 " + "alsasrc ! audio/x-raw-int,rate=8000 ! queue ! " + "amrnbenc ! rtpamrpay name=pay1 pt=97 " + ")"); +#endif + /* any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + gst_rtsp_media_factory_set_launch (factory, "( " + "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " + "x264enc bitrate=300 ! rtph264pay name=pay0 pt=96 " + "audiotestsrc ! audio/x-raw-int,rate=8000 ! " + "alawenc ! rtppcmapay name=pay1 pt=97 " + ")"); + + /* attach the factory to the /camera url */ + gst_rtsp_media_mapping_add_factory (mapping, "/camera", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mapping); + /* attach the server to the default maincontext */ gst_rtsp_server_attach (server, NULL); + /* start serving */ g_main_loop_run (loop); return 0; diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 873619bd8f..54ba251e56 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -3,6 +3,7 @@ public_headers = \ rtsp-client.h \ rtsp-media.h \ rtsp-media-factory.h \ + rtsp-media-mapping.h \ rtsp-session-pool.h \ rtsp-session.h @@ -10,7 +11,8 @@ c_sources = \ rtsp-server.c \ rtsp-client.c \ rtsp-media.c \ - rtsp-media-factory.c \ + rtsp-media-factory.c \ + rtsp-media-mapping.c \ rtsp-session-pool.c \ rtsp-session.c diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b8849416da..a3372da5a7 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -25,6 +25,8 @@ #undef DEBUG +static void gst_rtsp_client_finalize (GObject * obj); + G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); static void @@ -33,6 +35,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gst_rtsp_client_finalize; } static void @@ -40,6 +44,12 @@ gst_rtsp_client_init (GstRTSPClient * client) { } +static void +gst_rtsp_client_finalize (GObject * obj) +{ + G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj); +} + /** * gst_rtsp_client_new: * @@ -87,7 +97,7 @@ handle_teardown_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag goto service_unavailable; /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, client->media); + media = gst_rtsp_session_get_media (session, uri, client->factory); if (!media) goto not_found; @@ -116,6 +126,7 @@ session_not_found: } service_unavailable: { + handle_generic_response (client, GST_RTSP_STS_OK, request); return FALSE; } not_found: @@ -145,7 +156,7 @@ handle_pause_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage * goto service_unavailable; /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, client->media); + media = gst_rtsp_session_get_media (session, uri, client->factory); if (!media) goto not_found; @@ -201,7 +212,7 @@ handle_play_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *r goto service_unavailable; /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, client->media); + media = gst_rtsp_session_get_media (session, uri, client->factory); if (!media) goto not_found; @@ -222,11 +233,11 @@ handle_play_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *r /* grab RTPInfo from the payloaders now */ rtpinfo = g_string_new (""); - n_streams = gst_rtsp_media_n_streams (client->media); + n_streams = gst_rtsp_media_bin_n_streams (media->mediabin); for (i = 0; i < n_streams; i++) { GstRTSPMediaStream *stream; - stream = gst_rtsp_media_get_stream (client->media, i); + stream = gst_rtsp_media_bin_get_stream (media->mediabin, i); g_object_get (G_OBJECT (stream->payloader), "seqnum", &seqnum, NULL); g_object_get (G_OBJECT (stream->payloader), "timestamp", ×tamp, NULL); @@ -271,7 +282,7 @@ not_found: } static gboolean -handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request) +handle_setup_response (GstRTSPClient *client, const gchar *location, GstRTSPMessage *request) { GstRTSPResult res; gchar *sessid; @@ -279,6 +290,7 @@ handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage * gchar **transports; gboolean have_transport; GstRTSPTransport *ct, *st; + GstRTSPUrl *uri; GstRTSPSession *session; gint i; GstRTSPLowerTrans supported; @@ -290,9 +302,28 @@ handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage * GstRTSPSessionMedia *media; gboolean need_session; + /* the uri contains the stream number we added in the SDP config, which is + * always /stream=%d so we need to strip that off */ + if ((res = gst_rtsp_url_parse (location, &uri)) != GST_RTSP_OK) + goto bad_url; + + /* parse the stream we need to configure, look for the stream in the abspath + * first and then in the query. */ + if (!(pos = strstr (uri->abspath, "/stream="))) { + if (!(pos = strstr (uri->query, "/stream="))) + goto bad_request; + } + + /* we can mofify the parse uri in place */ + *pos = '\0'; + + pos += strlen ("/stream="); + if (sscanf (pos, "%u", &streamid) != 1) + goto bad_request; + /* find the media associated with the uri */ - if (client->media == NULL) { - if ((client->media = gst_rtsp_media_new (uri)) == NULL) + if (client->factory == NULL) { + if ((client->factory = gst_rtsp_media_mapping_find_factory (client->mapping, uri)) == NULL) goto not_found; } @@ -351,20 +382,12 @@ handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage * } /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, client->media); + media = gst_rtsp_session_get_media (session, uri->abspath, client->factory); if (!media) goto not_found; - /* parse the stream we need to configure */ - if (!(pos = strstr (uri, "stream="))) - goto bad_request; - - pos += strlen ("stream="); - if (sscanf (pos, "%u", &streamid) != 1) - goto bad_request; - /* get a handle to the stream in the media */ - stream = gst_rtsp_session_get_stream (media, streamid); + stream = gst_rtsp_session_media_get_stream (media, streamid); /* setup the server transport from the client transport */ st = gst_rtsp_session_stream_set_transport (stream, inet_ntoa (client->address.sin_addr), ct); @@ -387,9 +410,9 @@ handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage * return TRUE; /* ERRORS */ -not_found: +bad_url: { - handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); return FALSE; } bad_request: @@ -397,6 +420,11 @@ bad_request: handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); return FALSE; } +not_found: + { + handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + return FALSE; + } session_not_found: { handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); @@ -414,46 +442,58 @@ service_unavailable: } } +/* for the describe we must generate an SDP */ static gboolean -handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request) +handle_describe_response (GstRTSPClient *client, const gchar *location, GstRTSPMessage *request) { GstRTSPMessage response = { 0 }; + GstRTSPResult res; GstSDPMessage *sdp; + GstRTSPUrl *uri; guint n_streams, i; gchar *sdptext; - GstRTSPMedia *media; - GstElement *pipeline = NULL; + GstRTSPMediaFactory *factory; + GstRTSPMediaBin *mediabin; + GstElement *pipeline; + + /* the uri contains the stream number we added in the SDP config, which is + * always /stream=%d so we need to strip that off */ + if ((res = gst_rtsp_url_parse (location, &uri)) != GST_RTSP_OK) + goto bad_url; + + /* find the factory for the uri first */ + if (!(factory = gst_rtsp_media_mapping_find_factory (client->mapping, uri))) + goto no_factory; /* check what kind of format is accepted */ + /* create a pipeline to preroll the media */ + pipeline = gst_pipeline_new ("client-describe-pipeline"); - /* for the describe we must generate an SDP */ - if (!(media = gst_rtsp_media_new (uri))) - goto no_media; - - /* create a pipeline if we have to */ - if (pipeline == NULL) { - pipeline = gst_pipeline_new ("client-pipeline"); - } - - /* prepare the media into the pipeline */ - if (!gst_rtsp_media_prepare (media, GST_BIN (pipeline))) - goto no_media; + /* prepare the media and add it to the pipeline */ + if (!(mediabin = gst_rtsp_media_factory_construct (factory, uri->abspath))) + goto no_media_bin; + + gst_bin_add (GST_BIN_CAST (pipeline), mediabin->element); /* link fakesink to all stream pads and set the pipeline to PLAYING */ - n_streams = gst_rtsp_media_n_streams (media); + n_streams = gst_rtsp_media_bin_n_streams (mediabin); for (i = 0; i < n_streams; i++) { GstRTSPMediaStream *stream; GstElement *sink; GstPad *sinkpad; + GstPadLinkReturn lret; - stream = gst_rtsp_media_get_stream (media, i); + stream = gst_rtsp_media_bin_get_stream (mediabin, i); sink = gst_element_factory_make ("fakesink", NULL); gst_bin_add (GST_BIN (pipeline), sink); sinkpad = gst_element_get_static_pad (sink, "sink"); - gst_pad_link (stream->srcpad, sinkpad); + lret = gst_pad_link (stream->srcpad, sinkpad); + if (lret != GST_PAD_LINK_OK) { + g_warning ("failed to link pad to sink: %d", lret); + } gst_object_unref (sinkpad); } @@ -487,7 +527,7 @@ handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag gboolean first; GString *fmtp; - stream = gst_rtsp_media_get_stream (media, i); + stream = gst_rtsp_media_bin_get_stream (mediabin, i); gst_sdp_media_new (&smedia); s = gst_caps_get_structure (stream->caps, 0); @@ -572,7 +612,7 @@ handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag /* go back to NULL */ gst_element_set_state (pipeline, GST_STATE_NULL); - g_object_unref (media); + g_object_unref (factory); gst_object_unref (pipeline); pipeline = NULL; @@ -590,11 +630,22 @@ handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag return TRUE; /* ERRORS */ -no_media: +bad_url: + { + handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); + return FALSE; + } +no_factory: { handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); return FALSE; } +no_media_bin: + { + handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + g_object_unref (factory); + return FALSE; + } } static void @@ -713,7 +764,8 @@ handle_client (GstRTSPClient *client) /* ERRORS */ receive_failed: { - g_print ("receive failed, disconnect client %p\n", client); + g_message ("receive failed %d (%s), disconnect client %p", res, + gst_rtsp_strresult (res), client); gst_rtsp_connection_close (client->connection); g_object_unref (client); return NULL; @@ -747,7 +799,7 @@ client_accept (GstRTSPClient *client, GIOChannel *channel) * connections */ gst_poll_add_fd (conn->fdset, &conn->fd); - g_print ("added new client %p ip %s with fd %d\n", client, + g_message ("added new client %p ip %s with fd %d", client, inet_ntoa (client->address.sin_addr), conn->fd.fd); client->connection = conn; @@ -769,7 +821,8 @@ accept_failed: * @pool: a #GstRTSPSessionPool * * Set @pool as the sessionpool for @client which it will use to find - * or allocate sessions. + * or allocate sessions. the sessionpool is usually inherited from the server + * that created the client but can be overridden later. */ void gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool) @@ -777,11 +830,13 @@ gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *poo GstRTSPSessionPool *old; old = client->pool; - if (pool) - g_object_ref (pool); - client->pool = pool; - if (old) - g_object_unref (old); + if (old != pool) { + if (pool) + g_object_ref (pool); + client->pool = pool; + if (old) + g_object_unref (old); + } } /** @@ -804,43 +859,44 @@ gst_rtsp_client_get_session_pool (GstRTSPClient *client) } /** - * gst_rtsp_client_set_media_factory: + * gst_rtsp_client_set_media_mapping: * @client: a #GstRTSPClient - * @factory: a #GstRTSPMediaFactory + * @mapping: a #GstRTSPMediaMapping * - * Set @factory as the media factory for @client which it will use to map urls - * to media streams. + * Set @mapping as the media mapping for @client which it will use to map urls + * to media streams. These mapping is usually inherited from the server that + * created the client but can be overriden later. */ void -gst_rtsp_client_set_media_factory (GstRTSPClient *client, GstRTSPMediaFactory *factory) +gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *mapping) { - GstRTSPMediaFactory *old; + GstRTSPMediaMapping *old; - old = client->factory; + old = client->mapping; - if (old != factory) { - if (factory) - g_object_ref (factory); - client->factory = factory; + if (old != mapping) { + if (mapping) + g_object_ref (mapping); + client->mapping = mapping; if (old) g_object_unref (old); } } /** - * gst_rtsp_client_get_media_factory: + * gst_rtsp_client_get_media_mapping: * @client: a #GstRTSPClient * - * Get the #GstRTSPMediaFactory object that @client uses to manage its sessions. + * Get the #GstRTSPMediaMapping object that @client uses to manage its sessions. * - * Returns: a #GstRTSPMediaFactory, unref after usage. + * Returns: a #GstRTSPMediaMapping, unref after usage. */ -GstRTSPMediaFactory * -gst_rtsp_client_get_media_factory (GstRTSPClient *client) +GstRTSPMediaMapping * +gst_rtsp_client_get_media_mapping (GstRTSPClient *client) { - GstRTSPMediaFactory *result; + GstRTSPMediaMapping *result; - if ((result = client->factory)) + if ((result = client->mapping)) g_object_ref (result); return result; diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 5dff20c642..11a375c0d5 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -38,7 +38,7 @@ #define __GST_RTSP_CLIENT_H__ #include "rtsp-media.h" -#include "rtsp-media-factory.h" +#include "rtsp-media-mapping.h" #include "rtsp-session-pool.h" G_BEGIN_DECLS @@ -75,9 +75,8 @@ struct _GstRTSPClient { GstRTSPSessionPool *pool; - GstRTSPMedia *media; - GstRTSPMediaFactory *factory; - + GstRTSPMediaFactory *factory; + GstRTSPMediaMapping *mapping; }; struct _GstRTSPClientClass { @@ -92,9 +91,9 @@ void gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool); GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client); -void gst_rtsp_client_set_media_factory (GstRTSPClient *client, - GstRTSPMediaFactory *factory); -GstRTSPMediaFactory * gst_rtsp_client_get_media_factory (GstRTSPClient *client); +void gst_rtsp_client_set_media_mapping (GstRTSPClient *client, + GstRTSPMediaMapping *mapping); +GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client); gboolean gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel); diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index d402bad189..1412d6a9c7 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -19,11 +19,24 @@ #include "rtsp-media-factory.h" -G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT); +#define DEFAULT_LAUNCH NULL +enum +{ + PROP_0, + PROP_LAUNCH, + PROP_LAST +}; + +static void gst_rtsp_media_factory_get_property (GObject *object, guint propid, + GValue *value, GParamSpec *pspec); +static void gst_rtsp_media_factory_set_property (GObject *object, guint propid, + const GValue *value, GParamSpec *pspec); static void gst_rtsp_media_factory_finalize (GObject * obj); -static GstRTSPMedia * create_media (GstRTSPMediaFactory *factory, const gchar *url); +static GstRTSPMediaBin * default_construct (GstRTSPMediaFactory *factory, const gchar *location); + +G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT); static void gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) @@ -32,9 +45,28 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) gobject_class = G_OBJECT_CLASS (klass); + gobject_class->get_property = gst_rtsp_media_factory_get_property; + gobject_class->set_property = gst_rtsp_media_factory_set_property; gobject_class->finalize = gst_rtsp_media_factory_finalize; - klass->create_media = create_media; + /** + * GstRTSPMediaFactory::launch + * + * The gst_parse_launch() line to use for constructing the pipeline in the + * default prepare vmethod. + * + * The pipeline description should return a GstBin as the toplevel element + * which can be accomplished by enclosing the dscription with brackets '(' + * ')'. + * + * The description should return a pipeline with payloaders named pay0, pay1, + * etc.. Each of the payloaders will result in a stream. + */ + g_object_class_install_property (gobject_class, PROP_LAUNCH, + g_param_spec_string ("launch", "Launch", "A launch description of the pipeline", + DEFAULT_LAUNCH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + klass->construct = default_construct; } static void @@ -45,9 +77,51 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) static void gst_rtsp_media_factory_finalize (GObject * obj) { + GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj); + + g_free (factory->launch); + G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj); } +static void +gst_rtsp_media_factory_get_property (GObject *object, guint propid, + GValue *value, GParamSpec *pspec) +{ + GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object); + + switch (propid) { + case PROP_LAUNCH: + g_value_take_string (value, gst_rtsp_media_factory_get_launch (factory)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static void +gst_rtsp_media_factory_set_property (GObject *object, guint propid, + const GValue *value, GParamSpec *pspec) +{ + GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object); + + switch (propid) { + case PROP_LAUNCH: + gst_rtsp_media_factory_set_launch (factory, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +/** + * gst_rtsp_media_factory_new: + * + * Create a new #GstRTSPMediaFactory instance. + * + * Returns: a new #GstRTSPMediaFactory object or %NULL when location did not contain a + * valid or understood URL. + */ GstRTSPMediaFactory * gst_rtsp_media_factory_new (void) { @@ -58,40 +132,172 @@ gst_rtsp_media_factory_new (void) return result; } -static GstRTSPMedia * -create_media (GstRTSPMediaFactory *factory, const gchar *url) +/** + * gst_rtsp_media_factory_set_launch: + * @factory: a #GstRTSPMediaFactory + * @launch: the launch description + * + * + * The gst_parse_launch() line to use for constructing the pipeline in the + * default prepare vmethod. + * + * The pipeline description should return a GstBin as the toplevel element + * which can be accomplished by enclosing the dscription with brackets '(' + * ')'. + * + * The description should return a pipeline with payloaders named pay0, pay1, + * etc.. Each of the payloaders will result in a stream. + */ +void +gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, const gchar *launch) { - GstRTSPMedia *result; + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + g_return_if_fail (launch != NULL); - result = gst_rtsp_media_new (url); + factory->launch = g_strdup (launch); +} + +/** + * gst_rtsp_media_factory_get_launch: + * @factory: a #GstRTSPMediaFactory + * + * Get the gst_parse_launch() pipeline description that will be used in the + * default prepare vmethod. + * + * Returns: the configured launch description. g_free() after usage. + */ +gchar * +gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory) +{ + gchar *result; + + result = g_strdup (factory->launch); return result; } -GstRTSPMedia * -gst_rtsp_media_factory_create (GstRTSPMediaFactory *factory, const gchar *url) +/** + * gst_rtsp_media_factory_construct: + * @factory: a #GstRTSPMediaFactory + * @location: the url used + * + * Prepare the media bin object and create its streams. Implementations + * should create the needed gstreamer elements and add them to the result + * object. No state changes should be performed on them yet. + * + * One or more GstRTSPMediaStream objects should be added to the result with + * the srcpad member set to a source pad that produces buffer of type + * application/x-rtp. + * + * Returns: a new #GstRTSPMediaBin if the media could be prepared. + */ +GstRTSPMediaBin * +gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const gchar *location) { - GstRTSPMedia *result = NULL; + GstRTSPMediaBin *res; GstRTSPMediaFactoryClass *klass; klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); - if (klass->create_media) - result = klass->create_media (factory, url); + if (klass->construct) + res = klass->construct (factory, location); + else + res = NULL; - return result; + g_message ("constructed mediabin %p for location %s", res, location); + + return res; } -void -gst_rtsp_media_factory_add (GstRTSPMediaFactory *factory, const gchar *path, - GType type) +static void +caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) { - g_warning ("gst_rtsp_media_factory_add: not implemented"); -} -void -gst_rtsp_media_factory_remove (GstRTSPMediaFactory *factory, const gchar *path, - GType type) -{ - g_warning ("gst_rtsp_media_factory_remove: not implemented"); + if (stream->caps) + gst_caps_unref (stream->caps); + if ((stream->caps = GST_PAD_CAPS (pad))) + gst_caps_ref (stream->caps); } +static GstRTSPMediaBin * +default_construct (GstRTSPMediaFactory *factory, const gchar *location) +{ + GstRTSPMediaBin *bin; + GstRTSPMediaStream *stream; + GstElement *pay, *element; + GstPad * pad; + gint i; + GError *error = NULL; + + /* we need a parse syntax */ + if (factory->launch == NULL) + goto no_launch; + + /* parse the user provided launch line */ + element = gst_parse_launch (factory->launch, &error); + if (element == NULL) + goto parse_error; + + if (error != NULL) { + /* a recoverable error was encountered */ + g_warning ("recoverable parsing error: %s", error->message); + g_error_free (error); + } + + bin = g_object_new (GST_TYPE_RTSP_MEDIA_BIN, NULL); + bin->element = element; + + /* try to find all the payloader elements, they should be named 'pay%d'. for + * each of the payloaders we will create a stream, collect the source pad and + * add a notify::caps on the pad. */ + for (i = 0; ; i++) { + gchar *name; + + name = g_strdup_printf ("pay%d", i); + + if (!(pay = gst_bin_get_by_name (GST_BIN (element), name))) { + /* no more payloaders found, we have found all the streams and we can + * end the loop */ + g_free (name); + break; + } + + /* create the stream */ + stream = g_new0 (GstRTSPMediaStream, 1); + stream->mediabin = bin; + stream->element = element; + stream->payloader = pay; + stream->idx = bin->streams->len; + + pad = gst_element_get_static_pad (pay, "src"); + + /* ghost the pad of the payloader to the element */ + stream->srcpad = gst_ghost_pad_new (name, pad); + gst_element_add_pad (stream->element, stream->srcpad); + + stream->caps_sig = g_signal_connect (pad, "notify::caps", (GCallback) caps_notify, stream); + gst_object_unref (pad); + + /* add stream now */ + g_array_append_val (bin->streams, stream); + gst_object_unref (pay); + + g_free (name); + } + + return bin; + + /* ERRORS */ +no_launch: + { + g_critical ("no launch line specified"); + return NULL; + } +parse_error: + { + g_critical ("could not parse launch syntax (%s): %s", factory->launch, + (error ? error->message : "unknown reason")); + if (error) + g_error_free (error); + return NULL; + } +} diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 1399649bfa..5a98a96c91 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -18,7 +18,6 @@ */ #include - #include #include "rtsp-media.h" @@ -28,7 +27,8 @@ G_BEGIN_DECLS -#define GST_TYPE_RTSP_MEDIA_FACTORY (gst_rtsp_media_get_type ()) +/* types for the media factory */ +#define GST_TYPE_RTSP_MEDIA_FACTORY (gst_rtsp_media_factory_get_type ()) #define GST_IS_RTSP_MEDIA_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY)) #define GST_IS_RTSP_MEDIA_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA_FACTORY)) #define GST_RTSP_MEDIA_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA_FACTORY, GstRTSPMediaFactoryClass)) @@ -42,33 +42,41 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; /** * GstRTSPMediaFactory: + * @launch: the launch description + * @streams: the array of #GstRTSPMediaStream objects for this media. * - * Creates a #GstRTSPMedia object for a given url. + * The definition and logic for constructing the pipeline for a media. The media + * can contain multiple streams like audio and video. */ struct _GstRTSPMediaFactory { GObject parent; + + gchar *launch; }; +/** + * GstRTSPMediaFactoryClass: + * @construct: the vmethod that will be called when the factory has to create the + * #GstRTSPMediaBin for @location. + * + * the #GstRTSPMediaFactory class structure. + */ struct _GstRTSPMediaFactoryClass { GObjectClass parent_class; - GstRTSPMedia * (*create_media) (GstRTSPMediaFactory *factory, const gchar *url); + GstRTSPMediaBin * (*construct) (GstRTSPMediaFactory *factory, const gchar *location); }; GType gst_rtsp_media_factory_get_type (void); -/* creating a factory */ +/* configuring the factory */ GstRTSPMediaFactory * gst_rtsp_media_factory_new (void); -/* creating a media */ -GstRTSPMedia * gst_rtsp_media_factory_create (GstRTSPMediaFactory *factory, const gchar *url); +void gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, const gchar *launch); +gchar * gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory); - -/* managing media GTypes to a path */ -void gst_rtsp_media_factory_add (GstRTSPMediaFactory *factory, const gchar *path, - GType type); -void gst_rtsp_media_factory_remove (GstRTSPMediaFactory *factory, const gchar *path, - GType type); +/* creating the media bin from the factory */ +GstRTSPMediaBin * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const gchar *location); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c new file mode 100644 index 0000000000..2471be793f --- /dev/null +++ b/gst/rtsp-server/rtsp-media-mapping.c @@ -0,0 +1,146 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "rtsp-media-mapping.h" + +G_DEFINE_TYPE (GstRTSPMediaMapping, gst_rtsp_media_mapping, G_TYPE_OBJECT); + +static void gst_rtsp_media_mapping_finalize (GObject * obj); + +static GstRTSPMediaFactory * find_media (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url); + +static void +gst_rtsp_media_mapping_class_init (GstRTSPMediaMappingClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gst_rtsp_media_mapping_finalize; + + klass->find_media = find_media; +} + +static void +gst_rtsp_media_mapping_init (GstRTSPMediaMapping * mapping) +{ + mapping->mappings = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); +} + +static void +gst_rtsp_media_mapping_finalize (GObject * obj) +{ + GstRTSPMediaMapping *mapping = GST_RTSP_MEDIA_MAPPING (obj); + + g_hash_table_unref (mapping->mappings); + + G_OBJECT_CLASS (gst_rtsp_media_mapping_parent_class)->finalize (obj); +} + +GstRTSPMediaMapping * +gst_rtsp_media_mapping_new (void) +{ + GstRTSPMediaMapping *result; + + result = g_object_new (GST_TYPE_RTSP_MEDIA_MAPPING, NULL); + + return result; +} + +static GstRTSPMediaFactory * +find_media (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url) +{ + GstRTSPMediaFactory *result; + + /* find the location of the media in the hashtable */ + result = g_hash_table_lookup (mapping->mappings, url->abspath); + if (result) + g_object_ref (result); + + g_message ("found media %p for url abspath %s", result, url->abspath); + + return result; +} + +/** + * gst_rtsp_media_mapping_find_factory: + * @mapping: a #GstRTSPMediaMapping + * @url: a url + * + * Find the #GstRTSPMediaFactory for @url from the mappings registered in @mapping. + * + * Returns: the #GstRTSPMediaFactory for @url. g_object_unref() after usage. + */ +GstRTSPMediaFactory * +gst_rtsp_media_mapping_find_factory (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url) +{ + GstRTSPMediaFactory *result; + GstRTSPMediaMappingClass *klass; + + klass = GST_RTSP_MEDIA_MAPPING_GET_CLASS (mapping); + + if (klass->find_media) + result = klass->find_media (mapping, url); + else + result = NULL; + + return result; +} + +/** + * gst_rtsp_media_mapping_add_factory: + * @mapping: a #GstRTSPMediaMapping + * @path: a mount point + * @factory: a #GstRTSPMediaFactory + * + * Attach @factory to the mount point @path in @mapping. + * + * @path is of the form (/node)+. Any previous mapping will be freed. + * + * Ownership is taken of the reference on @factory so that @factory should not be + * used after calling this function. + */ +void +gst_rtsp_media_mapping_add_factory (GstRTSPMediaMapping *mapping, const gchar *path, + GstRTSPMediaFactory *factory) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA_MAPPING (mapping)); + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + g_return_if_fail (path != NULL); + + g_hash_table_insert (mapping->mappings, g_strdup (path), factory); +} + +/** + * gst_rtsp_media_mapping_remove_factory: + * @mapping: a #GstRTSPMediaMapping + * @path: a mount point + * + * Remove the #GstRTSPMediaFactory associated with @path in @mapping. + */ +void +gst_rtsp_media_mapping_remove_factory (GstRTSPMediaMapping *mapping, const gchar *path) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA_MAPPING (mapping)); + g_return_if_fail (path != NULL); + + g_hash_table_remove (mapping->mappings, path); +} + diff --git a/gst/rtsp-server/rtsp-media-mapping.h b/gst/rtsp-server/rtsp-media-mapping.h new file mode 100644 index 0000000000..65442465f6 --- /dev/null +++ b/gst/rtsp-server/rtsp-media-mapping.h @@ -0,0 +1,76 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + +#include "rtsp-media-factory.h" + +#ifndef __GST_RTSP_MEDIA_MAPPING_H__ +#define __GST_RTSP_MEDIA_MAPPING_H__ + +G_BEGIN_DECLS + +#define GST_TYPE_RTSP_MEDIA_MAPPING (gst_rtsp_media_mapping_get_type ()) +#define GST_IS_RTSP_MEDIA_MAPPING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA_MAPPING)) +#define GST_IS_RTSP_MEDIA_MAPPING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA_MAPPING)) +#define GST_RTSP_MEDIA_MAPPING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA_MAPPING, GstRTSPMediaMappingClass)) +#define GST_RTSP_MEDIA_MAPPING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA_MAPPING, GstRTSPMediaMapping)) +#define GST_RTSP_MEDIA_MAPPING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA_MAPPING, GstRTSPMediaMappingClass)) +#define GST_RTSP_MEDIA_MAPPING_CAST(obj) ((GstRTSPMediaMapping*)(obj)) +#define GST_RTSP_MEDIA_MAPPING_CLASS_CAST(klass) ((GstRTSPMediaMappingClass*)(klass)) + +typedef struct _GstRTSPMediaMapping GstRTSPMediaMapping; +typedef struct _GstRTSPMediaMappingClass GstRTSPMediaMappingClass; + +/** + * GstRTSPMediaMapping: + * @mappings: the mountpoint to media mappings + * + * Creates a #GstRTSPMedia object for a given url. + */ +struct _GstRTSPMediaMapping { + GObject parent; + + GHashTable *mappings; +}; + +struct _GstRTSPMediaMappingClass { + GObjectClass parent_class; + + GstRTSPMediaFactory * (*find_media) (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url); +}; + +GType gst_rtsp_media_mapping_get_type (void); + +/* creating a mapping */ +GstRTSPMediaMapping * gst_rtsp_media_mapping_new (void); + +/* finding a media factory */ +GstRTSPMediaFactory * gst_rtsp_media_mapping_find_factory (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url); + +/* managing media to a path */ +void gst_rtsp_media_mapping_add_factory (GstRTSPMediaMapping *mapping, const gchar *path, + GstRTSPMediaFactory *factory); +void gst_rtsp_media_mapping_remove_factory (GstRTSPMediaMapping *mapping, const gchar *path); + +G_END_DECLS + +#endif /* __GST_RTSP_MEDIA_MAPPING_H__ */ diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 13425d03f9..036d09fbc9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -19,24 +19,24 @@ #include "rtsp-media.h" -G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); +static void gst_rtsp_media_bin_finalize (GObject * obj); -static void gst_rtsp_media_finalize (GObject * obj); +G_DEFINE_TYPE (GstRTSPMediaBin, gst_rtsp_media_bin, G_TYPE_OBJECT); static void -gst_rtsp_media_class_init (GstRTSPMediaClass * klass) +gst_rtsp_media_bin_class_init (GstRTSPMediaBinClass * klass) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); - gobject_class->finalize = gst_rtsp_media_finalize; + gobject_class->finalize = gst_rtsp_media_bin_finalize; } static void -gst_rtsp_media_init (GstRTSPMedia * media) +gst_rtsp_media_bin_init (GstRTSPMediaBin * bin) { - media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); + bin->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); } static void @@ -45,218 +45,59 @@ gst_rtsp_media_stream_free (GstRTSPMediaStream *stream) } static void -gst_rtsp_media_finalize (GObject * obj) +gst_rtsp_media_bin_finalize (GObject * obj) { - GstRTSPMedia *media; + GstRTSPMediaBin *bin; guint i; - media = GST_RTSP_MEDIA (obj); + bin = GST_RTSP_MEDIA_BIN (obj); - g_free (media->location); - gst_rtsp_url_free (media->url); - - for (i = 0; i < media->streams->len; i++) { + for (i = 0; i < bin->streams->len; i++) { GstRTSPMediaStream *stream; - stream = g_array_index (media->streams, GstRTSPMediaStream *, i); + stream = g_array_index (bin->streams, GstRTSPMediaStream *, i); gst_rtsp_media_stream_free (stream); } - g_array_free (media->streams, TRUE); + g_array_free (bin->streams, TRUE); - G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); + G_OBJECT_CLASS (gst_rtsp_media_bin_parent_class)->finalize (obj); } /** - * gst_rtsp_media_new: - * @location: the URL of the media + * gst_rtsp_media_bin_n_streams: + * @media: a #GstRTSPMediaBin * - * Create a new #GstRTSPMedia instance. - * - * Returns: a new #GstRTSPMedia object or %NULL when location did not contain a - * valid or understood URL. - */ -GstRTSPMedia * -gst_rtsp_media_new (const gchar *location) -{ - GstRTSPMedia *result; - GstRTSPUrl *url; - - url = NULL; - - if (gst_rtsp_url_parse (location, &url) != GST_RTSP_OK) - goto invalid_url; - - result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL); - result->location = g_strdup (location); - result->url = url; - - return result; - - /* ERRORS */ -invalid_url: - { - return NULL; - } -} - -static void -caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) -{ - if (stream->caps) - gst_caps_unref (stream->caps); - if ((stream->caps = GST_PAD_CAPS (pad))) - gst_caps_ref (stream->caps); -} - -/** - * gst_rtsp_media_prepare: - * @media: a #GstRTSPMedia - * @bin: the parent bin to create the elements in. - * - * Prepare the media object so that it creates its streams. Implementations - * should crate the needed gstreamer elements and add them to @bin. No state - * changes should be performed on them yet. - * - * One or more GstRTSPMediaStream objects should be added to @media with the - * srcpad member set to a source pad that produces buffer of type - * application/x-rtp. - * - * Returns: %TRUE if the media could be prepared. - */ -gboolean -gst_rtsp_media_prepare (GstRTSPMedia *media, GstBin *bin) -{ - GstRTSPMediaStream *stream; - GstElement *pay, *element; - GstPad * pad; - gint i; - - /* if we're already prepared we must exit */ - g_return_val_if_fail (media->prepared == FALSE, FALSE); - - g_print ("%s\n", media->url->abspath); - - if (g_str_has_prefix (media->url->abspath, "/camera")) { - /* live */ - element = gst_parse_launch ("( " - "v4l2src ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " - "queue ! videorate ! ffmpegcolorspace ! " - "x264enc bitrate=300 ! rtph264pay name=pay0 pt=96 " - "alsasrc ! audio/x-raw-int,rate=8000 ! queue ! " - "amrnbenc ! rtpamrpay name=pay1 pt=97 " - ")", NULL); - } - else if (g_str_has_prefix (media->url->abspath, "/h264")) { - /* transcode h264 */ - element = gst_parse_launch ("( uridecodebin " - "uri=file:///home/cschalle/Videos/mi2.avi ! " - "x264enc bitrate=300 ! rtph264pay name=pay0 )", NULL); - } - else if (g_str_has_prefix (media->url->abspath, "/theora")) { - /* transcode theora */ - element = gst_parse_launch ("( uridecodebin " - "uri=file:///home/wim/data/mi2.avi ! " - "theoraenc ! rtptheorapay name=pay0 )", NULL); - } - else if (g_str_has_prefix (media->url->abspath, "/macpclinux")) { - /* theora/vorbis */ - element = gst_parse_launch ("( filesrc " - "location=/home/cschalle/Videos/mac_pc_linux_2.ogg ! oggdemux name=d ! " - "queue ! theoraparse ! rtptheorapay name=pay0 " - "d. ! queue ! vorbisparse ! rtpvorbispay name=pay1 )", NULL); - } - else if (g_str_has_prefix (media->url->abspath, "/rtspproxy")) { - /* proxy RTSP transcode */ - element = gst_parse_launch ("( uridecodebin " - "uri=rtsp://ia300135.us.archive.org:554/0/items/uncovered_interviews/uncovered_interviews_3_256kb.mp4 ! " - "x264enc bitrate=1800 ! rtph264pay name=pay0 )", NULL); - } - else if (g_str_has_prefix (media->url->abspath, "/httpproxy")) { - /* proxy HTTP transcode */ - element = gst_parse_launch ("( uridecodebin " - "uri=http://movies.apple.com/movies/fox/maxpayne/maxpayne-tlre_h480.mov name=d " - "d. ! queue ! x264enc bitrate=1800 ! rtph264pay name=pay0 pt=96 " - "d. ! queue ! faac ! rtpmp4gpay name=pay1 pt=97 )", NULL); - } - else - return FALSE; - - gst_bin_add (bin, element); - - for (i = 0; ; i++) { - gchar *name; - - name = g_strdup_printf ("pay%d", i); - - if (!(pay = gst_bin_get_by_name (GST_BIN (element), name))) { - g_free (name); - break; - } - - /* create the stream */ - stream = g_new0 (GstRTSPMediaStream, 1); - stream->media = media; - stream->element = element; - stream->payloader = pay; - stream->idx = media->streams->len; - - pad = gst_element_get_static_pad (pay, "src"); - - stream->srcpad = gst_ghost_pad_new (name, pad); - gst_element_add_pad (stream->element, stream->srcpad); - - stream->caps_sig = g_signal_connect (pad, "notify::caps", (GCallback) caps_notify, stream); - gst_object_unref (pad); - - /* add stream now */ - g_array_append_val (media->streams, stream); - gst_object_unref (pay); - - g_free (name); - } - - media->prepared = TRUE; - - return TRUE; -} - -/** - * gst_rtsp_media_n_streams: - * @media: a #GstRTSPMedia - * - * Get the number of streams in this media. + * Get the number of streams in this mediabin. * * Returns: The number of streams. */ guint -gst_rtsp_media_n_streams (GstRTSPMedia *media) +gst_rtsp_media_bin_n_streams (GstRTSPMediaBin *bin) { - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0); - g_return_val_if_fail (media->prepared, 0); + g_return_val_if_fail (GST_IS_RTSP_MEDIA_BIN (bin), 0); - return media->streams->len; + return bin->streams->len; } /** - * gst_rtsp_media_get_stream: - * @media: a #GstRTSPMedia + * gst_rtsp_media_bin_get_stream: + * @bin: a #GstRTSPMediaBin * @idx: the stream index * - * Retrieve the stream with index @idx from @media. + * Retrieve the stream with index @idx from @bin. * * Returns: the #GstRTSPMediaStream at index @idx. */ GstRTSPMediaStream * -gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx) +gst_rtsp_media_bin_get_stream (GstRTSPMediaBin *bin, guint idx) { GstRTSPMediaStream *res; - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - g_return_val_if_fail (media->prepared, 0); - g_return_val_if_fail (idx < media->streams->len, NULL); + g_return_val_if_fail (GST_IS_RTSP_MEDIA_BIN (bin), NULL); + g_return_val_if_fail (idx < bin->streams->len, NULL); - res = g_array_index (media->streams, GstRTSPMediaStream *, idx); + res = g_array_index (bin->streams, GstRTSPMediaStream *, idx); return res; } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index f96ab1f041..8c6e64dcc8 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -25,18 +25,19 @@ G_BEGIN_DECLS -#define GST_TYPE_RTSP_MEDIA (gst_rtsp_media_get_type ()) -#define GST_IS_RTSP_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA)) -#define GST_IS_RTSP_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA)) -#define GST_RTSP_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMediaClass)) -#define GST_RTSP_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMedia)) -#define GST_RTSP_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA, GstRTSPMediaClass)) -#define GST_RTSP_MEDIA_CAST(obj) ((GstRTSPMedia*)(obj)) -#define GST_RTSP_MEDIA_CLASS_CAST(klass) ((GstRTSPMediaClass*)(klass)) +/* types for the media bin */ +#define GST_TYPE_RTSP_MEDIA_BIN (gst_rtsp_media_bin_get_type ()) +#define GST_IS_RTSP_MEDIA_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA_BIN)) +#define GST_IS_RTSP_MEDIA_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA_BIN)) +#define GST_RTSP_MEDIA_BIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA_BIN, GstRTSPMediaBinClass)) +#define GST_RTSP_MEDIA_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA_BIN, GstRTSPMediaBin)) +#define GST_RTSP_MEDIA_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA_BIN, GstRTSPMediaBinClass)) +#define GST_RTSP_MEDIA_BIN_CAST(obj) ((GstRTSPMediaBin*)(obj)) +#define GST_RTSP_MEDIA_BIN_CLASS_CAST(klass) ((GstRTSPMediaBinClass*)(klass)) -typedef struct _GstRTSPMedia GstRTSPMedia; typedef struct _GstRTSPMediaStream GstRTSPMediaStream; -typedef struct _GstRTSPMediaClass GstRTSPMediaClass; +typedef struct _GstRTSPMediaBin GstRTSPMediaBin; +typedef struct _GstRTSPMediaBinClass GstRTSPMediaBinClass; /** * GstRTSPMediaStream: @@ -51,7 +52,7 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass; * The definition of a media stream. The streams are identified by @id. */ struct _GstRTSPMediaStream { - GstRTSPMedia *media; + GstRTSPMediaBin *mediabin; guint idx; @@ -63,33 +64,28 @@ struct _GstRTSPMediaStream { }; /** - * GstRTSPMedia: + * GstRTSPMediaBin: + * @media: the owner #GstRTSPMedia * - * The definition and logic for constructing the pipeline for a media. The media - * can contain multiple streams like audio and video. + * A class that contains the elements to handle the media + * provided by @media. */ -struct _GstRTSPMedia { +struct _GstRTSPMediaBin { GObject parent; - gchar *location; - GstRTSPUrl *url; - - gboolean prepared; + GstElement *element; GArray *streams; }; -struct _GstRTSPMediaClass { +struct _GstRTSPMediaBinClass { GObjectClass parent_class; }; -GType gst_rtsp_media_get_type (void); +GType gst_rtsp_media_bin_get_type (void); -GstRTSPMedia * gst_rtsp_media_new (const gchar *name); - -gboolean gst_rtsp_media_prepare (GstRTSPMedia *media, GstBin *bin); - -guint gst_rtsp_media_n_streams (GstRTSPMedia *media); -GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); +/* dealing with the media bin */ +guint gst_rtsp_media_bin_n_streams (GstRTSPMediaBin *bin); +GstRTSPMediaStream * gst_rtsp_media_bin_get_stream (GstRTSPMediaBin *bin, guint idx); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index cea1bf0455..b34bc80a32 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -31,7 +31,7 @@ enum PROP_BACKLOG, PROP_PORT, PROP_POOL, - PROP_FACTORY, + PROP_MAPPING, PROP_LAST }; @@ -88,14 +88,14 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) g_param_spec_object ("pool", "Pool", "The session pool to use for client session", GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRTSPServer::factory + * GstRTSPServer::mapping * - * The media factory to use for this server. By default the server has no - * media factories and thus cannot map urls to media streams. + * The media mapping to use for this server. By default the server has no + * media mapping and thus cannot map urls to media streams. */ - g_object_class_install_property (gobject_class, PROP_POOL, - g_param_spec_object ("factory", "Factory", "The media factory to use for client session", - GST_TYPE_RTSP_MEDIA_FACTORY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MAPPING, + g_param_spec_object ("mapping", "Mapping", "The media mapping to use for client session", + GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); klass->accept_client = gst_rtsp_server_accept_client; } @@ -106,6 +106,7 @@ gst_rtsp_server_init (GstRTSPServer * server) server->server_port = DEFAULT_PORT; server->backlog = DEFAULT_BACKLOG; server->pool = gst_rtsp_session_pool_new (); + server->mapping = gst_rtsp_media_mapping_new (); } /** @@ -202,13 +203,19 @@ gst_rtsp_server_get_backlog (GstRTSPServer *server) void gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool) { + GstRTSPSessionPool *old; + g_return_if_fail (GST_IS_RTSP_SERVER (server)); - if (server->pool) - g_object_unref (server->pool); - if (pool) - g_object_ref (pool); - server->pool = pool; + old = server->pool; + + if (old != pool) { + if (pool) + g_object_ref (pool); + server->pool = pool; + if (old) + g_object_unref (old); + } } @@ -235,25 +242,25 @@ gst_rtsp_server_get_session_pool (GstRTSPServer *server) } /** - * gst_rtsp_server_set_media_factory: + * gst_rtsp_server_set_media_mapping: * @server: a #GstRTSPServer - * @factory: a #GstRTSPMediaFactory + * @mapping: a #GstRTSPMediaMapping * - * configure @factory to be used as the media factory of @server. + * configure @mapping to be used as the media mapping of @server. */ void -gst_rtsp_server_set_media_factory (GstRTSPServer *server, GstRTSPMediaFactory *factory) +gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *mapping) { - GstRTSPMediaFactory *old; + GstRTSPMediaMapping *old; g_return_if_fail (GST_IS_RTSP_SERVER (server)); - old = server->factory; + old = server->mapping; - if (old != factory) { - if (factory) - g_object_ref (factory); - server->factory = factory; + if (old != mapping) { + if (mapping) + g_object_ref (mapping); + server->mapping = mapping; if (old) g_object_unref (old); } @@ -261,22 +268,22 @@ gst_rtsp_server_set_media_factory (GstRTSPServer *server, GstRTSPMediaFactory *f /** - * gst_rtsp_server_get_media_factory: + * gst_rtsp_server_get_media_mapping: * @server: a #GstRTSPServer * - * Get the #GstRTSPMediaFactory used as the media factory of @server. + * Get the #GstRTSPMediaMapping used as the media mapping of @server. * - * Returns: the #GstRTSPMediaFactory of @server. g_object_unref() after + * Returns: the #GstRTSPMediaMapping of @server. g_object_unref() after * usage. */ -GstRTSPMediaFactory * -gst_rtsp_server_get_media_factory (GstRTSPServer *server) +GstRTSPMediaMapping * +gst_rtsp_server_get_media_mapping (GstRTSPServer *server) { - GstRTSPMediaFactory *result; + GstRTSPMediaMapping *result; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - if ((result = server->factory)) + if ((result = server->mapping)) g_object_ref (result); return result; @@ -298,8 +305,8 @@ gst_rtsp_server_get_property (GObject *object, guint propid, case PROP_POOL: g_value_take_object (value, gst_rtsp_server_get_session_pool (server)); break; - case PROP_FACTORY: - g_value_take_object (value, gst_rtsp_server_get_media_factory (server)); + case PROP_MAPPING: + g_value_take_object (value, gst_rtsp_server_get_media_mapping (server)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -322,8 +329,8 @@ gst_rtsp_server_set_property (GObject *object, guint propid, case PROP_POOL: gst_rtsp_server_set_session_pool (server, g_value_get_object (value)); break; - case PROP_FACTORY: - gst_rtsp_server_set_media_factory (server, g_value_get_object (value)); + case PROP_MAPPING: + gst_rtsp_server_set_media_mapping (server, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -440,7 +447,7 @@ gst_rtsp_server_accept_client (GstRTSPServer *server, GIOChannel *channel) gst_rtsp_client_set_session_pool (client, server->pool); /* set the session pool that this client should use */ - gst_rtsp_client_set_media_factory (client, server->factory); + gst_rtsp_client_set_media_mapping (client, server->mapping); /* accept connections for that client, this function returns after accepting * the connection and will run the remainder of the communication with the diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 5dd5629b63..277b8419d1 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -34,7 +34,7 @@ #include #include "rtsp-session-pool.h" -#include "rtsp-media-factory.h" +#include "rtsp-media-mapping.h" #include "rtsp-client.h" #ifndef __GST_RTSP_SERVER_H__ @@ -72,8 +72,8 @@ struct _GstRTSPServer { /* sessions on this server */ GstRTSPSessionPool *pool; - /* media factory for this server */ - GstRTSPMediaFactory *factory; + /* media mapper for this server */ + GstRTSPMediaMapping *mapping; }; /** @@ -103,8 +103,8 @@ gint gst_rtsp_server_get_backlog (GstRTSPServer *serve void gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool); GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *server); -void gst_rtsp_server_set_media_factory (GstRTSPServer *server, GstRTSPMediaFactory *factory); -GstRTSPMediaFactory * gst_rtsp_server_get_media_factory (GstRTSPServer *server); +void gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *mapping); +GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *server); gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, GstRTSPServer *server); diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 6eddd12272..dd608c7675 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -62,8 +62,8 @@ gst_rtsp_session_free_media (GstRTSPSessionMedia *media) gst_element_set_state (media->pipeline, GST_STATE_NULL); - if (media->media) - g_object_unref (media->media); + if (media->factory) + g_object_unref (media->factory); for (walk = media->streams; walk; walk = g_list_next (walk)) { GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data; @@ -98,14 +98,15 @@ gst_rtsp_session_finalize (GObject * obj) /** * gst_rtsp_session_get_media: * @sess: a #GstRTSPSession - * @media: a #GstRTSPSessionMedia + * @location: the url for the media + * @factory: a #GstRTSPMediaFactory * - * Get or create the session information for @media. + * Get or create the session information for @factory. * - * Returns: the configuration for @media in @sess. + * Returns: the configuration for @factory in @sess. */ GstRTSPSessionMedia * -gst_rtsp_session_get_media (GstRTSPSession *sess, GstRTSPMedia *media) +gst_rtsp_session_get_media (GstRTSPSession *sess, const gchar *location, GstRTSPMediaFactory *factory) { GstRTSPSessionMedia *result; GList *walk; @@ -115,19 +116,22 @@ gst_rtsp_session_get_media (GstRTSPSession *sess, GstRTSPMedia *media) for (walk = sess->medias; walk; walk = g_list_next (walk)) { result = (GstRTSPSessionMedia *) walk->data; - if (result->media == media) + if (result->factory == factory) break; result = NULL; } if (result == NULL) { result = g_new0 (GstRTSPSessionMedia, 1); - result->media = media; + result->factory = factory; result->pipeline = gst_pipeline_new ("pipeline"); - /* prepare media into the pipeline */ - if (!gst_rtsp_media_prepare (media, GST_BIN (result->pipeline))) + /* construct media and add to the pipeline */ + result->mediabin = gst_rtsp_media_factory_construct (factory, location); + if (result->mediabin == NULL) goto no_media; + + gst_bin_add (GST_BIN_CAST (result->pipeline), result->mediabin->element); result->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin"); @@ -149,7 +153,7 @@ no_media: } /** - * gst_rtsp_session_get_stream: + * gst_rtsp_session_media_get_stream: * @media: a #GstRTSPSessionMedia * @idx: the stream index * @@ -159,7 +163,7 @@ no_media: * is unreffed. */ GstRTSPSessionStream * -gst_rtsp_session_get_stream (GstRTSPSessionMedia *media, guint idx) +gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, guint idx) { GstRTSPSessionStream *result; GList *walk; @@ -178,7 +182,7 @@ gst_rtsp_session_get_stream (GstRTSPSessionMedia *media, guint idx) result = g_new0 (GstRTSPSessionStream, 1); result->idx = idx; result->media = media; - result->media_stream = gst_rtsp_media_get_stream (media->media, idx); + result->media_stream = gst_rtsp_media_bin_get_stream (media->mediabin, idx); media->streams = g_list_prepend (media->streams, result); } diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index c87a1396d1..5db5ba834b 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -22,6 +22,7 @@ #include #include "rtsp-media.h" +#include "rtsp-media-factory.h" #ifndef __GST_RTSP_SESSION_H__ #define __GST_RTSP_SESSION_H__ @@ -87,10 +88,11 @@ struct _GstRTSPSessionMedia GstRTSPSession *session; /* the media we are handling */ - GstRTSPMedia *media; + GstRTSPMediaFactory *factory; /* the pipeline for the media */ GstElement *pipeline; + GstRTSPMediaBin *mediabin; /* RTP session manager */ GstElement *rtpbin; @@ -125,15 +127,16 @@ GType gst_rtsp_session_get_type (void); GstRTSPSession * gst_rtsp_session_new (const gchar *sessionid); -GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, - GstRTSPMedia *media); -GstRTSPSessionStream * gst_rtsp_session_get_stream (GstRTSPSessionMedia *media, - guint idx); +GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, const gchar *location, + GstRTSPMediaFactory *factory); GstStateChangeReturn gst_rtsp_session_media_play (GstRTSPSessionMedia *media); GstStateChangeReturn gst_rtsp_session_media_pause (GstRTSPSessionMedia *media); GstStateChangeReturn gst_rtsp_session_media_stop (GstRTSPSessionMedia *media); +GstRTSPSessionStream * gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, + guint idx); + GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, const gchar *destination, GstRTSPTransport *ct); From 28b65778f6d4f323ae30da89133be36297b3e31f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 22 Jan 2009 16:51:08 +0100 Subject: [PATCH 0036/1776] Make element creation more extendible Add get_element vmethod to the default MediaFactory so that subclasses can just override that method and still use the default logic for making a MediaBin from that. --- gst/rtsp-server/rtsp-media-factory.c | 60 ++++++++++++++++++++-------- gst/rtsp-server/rtsp-media-factory.h | 11 ++++- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 1412d6a9c7..eb9c459295 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -35,6 +35,7 @@ static void gst_rtsp_media_factory_set_property (GObject *object, guint propid, static void gst_rtsp_media_factory_finalize (GObject * obj); static GstRTSPMediaBin * default_construct (GstRTSPMediaFactory *factory, const gchar *location); +static GstElement * default_get_element (GstRTSPMediaFactory *factory, const gchar *location); G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT); @@ -67,6 +68,7 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) DEFAULT_LAUNCH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); klass->construct = default_construct; + klass->get_element = default_get_element; } static void @@ -218,14 +220,10 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) gst_caps_ref (stream->caps); } -static GstRTSPMediaBin * -default_construct (GstRTSPMediaFactory *factory, const gchar *location) +static GstElement * +default_get_element (GstRTSPMediaFactory *factory, const gchar *location) { - GstRTSPMediaBin *bin; - GstRTSPMediaStream *stream; - GstElement *pay, *element; - GstPad * pad; - gint i; + GstElement *element; GError *error = NULL; /* we need a parse syntax */ @@ -242,6 +240,42 @@ default_construct (GstRTSPMediaFactory *factory, const gchar *location) g_warning ("recoverable parsing error: %s", error->message); g_error_free (error); } + return element; + + /* ERRORS */ +no_launch: + { + g_critical ("no launch line specified"); + return NULL; + } +parse_error: + { + g_critical ("could not parse launch syntax (%s): %s", factory->launch, + (error ? error->message : "unknown reason")); + if (error) + g_error_free (error); + return NULL; + } +} + +static GstRTSPMediaBin * +default_construct (GstRTSPMediaFactory *factory, const gchar *location) +{ + GstRTSPMediaBin *bin; + GstRTSPMediaStream *stream; + GstElement *pay, *element; + GstPad * pad; + gint i; + GstRTSPMediaFactoryClass *klass; + + klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); + + if (klass->get_element) + element = klass->get_element (factory, location); + else + element = NULL; + if (element == NULL) + goto no_element; bin = g_object_new (GST_TYPE_RTSP_MEDIA_BIN, NULL); bin->element = element; @@ -287,17 +321,9 @@ default_construct (GstRTSPMediaFactory *factory, const gchar *location) return bin; /* ERRORS */ -no_launch: +no_element: { - g_critical ("no launch line specified"); - return NULL; - } -parse_error: - { - g_critical ("could not parse launch syntax (%s): %s", factory->launch, - (error ? error->message : "unknown reason")); - if (error) - g_error_free (error); + g_critical ("could not create element"); return NULL; } } diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 5a98a96c91..b624eb13ad 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -56,15 +56,22 @@ struct _GstRTSPMediaFactory { /** * GstRTSPMediaFactoryClass: + * @get_element: Construct an return a #GstElement thast is a #GstBin containing + * the pipeline to use for the media. The bin should contain elements + * pay%d for each stream. The default implementation of this functions + * returns the bin created from the launch parameter. * @construct: the vmethod that will be called when the factory has to create the - * #GstRTSPMediaBin for @location. + * #GstRTSPMediaBin for @location. The default implementation of this + * function calls get_element to retrieve an element and then looks for + * pay%d to create the streams. * * the #GstRTSPMediaFactory class structure. */ struct _GstRTSPMediaFactoryClass { GObjectClass parent_class; - GstRTSPMediaBin * (*construct) (GstRTSPMediaFactory *factory, const gchar *location); + GstElement * (*get_element) (GstRTSPMediaFactory *factory, const gchar *location); + GstRTSPMediaBin * (*construct) (GstRTSPMediaFactory *factory, const gchar *location); }; GType gst_rtsp_media_factory_get_type (void); From 6f9b659b1de7e00c92fe16d5bfc76eecd0a20a0d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 22 Jan 2009 16:53:16 +0100 Subject: [PATCH 0037/1776] Handle state change failures better Handle state change failures better when changing the state of the pipeline to determine the SDP. --- gst/rtsp-server/rtsp-client.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a3372da5a7..9f0884d2b2 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -455,6 +455,7 @@ handle_describe_response (GstRTSPClient *client, const gchar *location, GstRTSPM GstRTSPMediaFactory *factory; GstRTSPMediaBin *mediabin; GstElement *pipeline; + GstStateChangeReturn ret; /* the uri contains the stream number we added in the SDP config, which is * always /stream=%d so we need to strip that off */ @@ -499,7 +500,9 @@ handle_describe_response (GstRTSPClient *client, const gchar *location, GstRTSPM /* now play and wait till we get the pads blocked. At that time the pipeline * is prerolled and we have the caps on the streams too. */ - gst_element_set_state (pipeline, GST_STATE_PLAYING); + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) + goto cant_play; /* wait for state change to complete */ gst_element_get_state (pipeline, NULL, NULL, -1); @@ -646,6 +649,13 @@ no_media_bin: g_object_unref (factory); return FALSE; } +cant_play: + { + handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + gst_object_unref (pipeline); + g_object_unref (factory); + return FALSE; + } } static void From 83cf4d8ee014aa4f1f30667dd5717ce20512a9a0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 22 Jan 2009 16:54:07 +0100 Subject: [PATCH 0038/1776] Update example Add some more docs and remove some old code from the example. --- examples/main.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/examples/main.c b/examples/main.c index 07b28cdd2a..3e00d41f0e 100644 --- a/examples/main.c +++ b/examples/main.c @@ -40,29 +40,19 @@ main (int argc, char *argv[]) * that be used to map uri mount points to media factories */ mapping = gst_rtsp_server_get_media_mapping (server); - /* make a media factory for a webcam. The default media factory can use - * gst-launch syntax to create pipelines. */ - factory = gst_rtsp_media_factory_new (); -#if 0 - gst_rtsp_media_factory_set_launch (factory, "( " - "v4l2src ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " - "queue ! videorate ! ffmpegcolorspace ! " - "x264enc bitrate=300 ! rtph264pay name=pay0 pt=96 " - "alsasrc ! audio/x-raw-int,rate=8000 ! queue ! " - "amrnbenc ! rtpamrpay name=pay1 pt=97 " - ")"); -#endif - /* any launch line works as long as it contains elements named pay%d. Each + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, "( " "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " "x264enc bitrate=300 ! rtph264pay name=pay0 pt=96 " "audiotestsrc ! audio/x-raw-int,rate=8000 ! " "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); - - /* attach the factory to the /camera url */ - gst_rtsp_media_mapping_add_factory (mapping, "/camera", factory); + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); /* don't need the ref to the mapper anymore */ g_object_unref (mapping); From cf18709634eb7e1c588c7b63b0f935bd8eb1a9fe Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 22 Jan 2009 17:58:19 +0100 Subject: [PATCH 0039/1776] More improvements Rename GstRTSPMediaBin to GstRTSPMedia Parse the request url into a GstRTSPUri object and pass this object to the various handlers and methods that require the uri. --- gst/rtsp-server/rtsp-client.c | 91 +++++++++++++++------------- gst/rtsp-server/rtsp-media-factory.c | 45 +++++++------- gst/rtsp-server/rtsp-media-factory.h | 19 ++++-- gst/rtsp-server/rtsp-media.c | 52 ++++++++-------- gst/rtsp-server/rtsp-media.h | 40 ++++++------ gst/rtsp-server/rtsp-session.c | 13 ++-- gst/rtsp-server/rtsp-session.h | 4 +- 7 files changed, 137 insertions(+), 127 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 9f0884d2b2..a45f618c60 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -78,7 +78,7 @@ handle_generic_response (GstRTSPClient *client, GstRTSPStatusCode code, } static gboolean -handle_teardown_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request) +handle_teardown_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPResult res; GstRTSPSessionMedia *media; @@ -137,7 +137,7 @@ not_found: } static gboolean -handle_pause_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request) +handle_pause_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPResult res; GstRTSPSessionMedia *media; @@ -189,7 +189,7 @@ not_found: } static gboolean -handle_play_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request) +handle_play_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPResult res; GstRTSPSessionMedia *media; @@ -233,18 +233,22 @@ handle_play_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *r /* grab RTPInfo from the payloaders now */ rtpinfo = g_string_new (""); - n_streams = gst_rtsp_media_bin_n_streams (media->mediabin); + n_streams = gst_rtsp_media_n_streams (media->media); for (i = 0; i < n_streams; i++) { GstRTSPMediaStream *stream; + gchar *uristr; - stream = gst_rtsp_media_bin_get_stream (media->mediabin, i); + stream = gst_rtsp_media_get_stream (media->media, i); g_object_get (G_OBJECT (stream->payloader), "seqnum", &seqnum, NULL); g_object_get (G_OBJECT (stream->payloader), "timestamp", ×tamp, NULL); if (i > 0) g_string_append (rtpinfo, ", "); - g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", uri, i, seqnum, timestamp); + + uristr = gst_rtsp_url_get_request_uri (uri); + g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", uristr, i, seqnum, timestamp); + g_free (uristr); } /* construct the response now */ @@ -282,7 +286,7 @@ not_found: } static gboolean -handle_setup_response (GstRTSPClient *client, const gchar *location, GstRTSPMessage *request) +handle_setup_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPResult res; gchar *sessid; @@ -290,7 +294,6 @@ handle_setup_response (GstRTSPClient *client, const gchar *location, GstRTSPMess gchar **transports; gboolean have_transport; GstRTSPTransport *ct, *st; - GstRTSPUrl *uri; GstRTSPSession *session; gint i; GstRTSPLowerTrans supported; @@ -303,11 +306,8 @@ handle_setup_response (GstRTSPClient *client, const gchar *location, GstRTSPMess gboolean need_session; /* the uri contains the stream number we added in the SDP config, which is - * always /stream=%d so we need to strip that off */ - if ((res = gst_rtsp_url_parse (location, &uri)) != GST_RTSP_OK) - goto bad_url; - - /* parse the stream we need to configure, look for the stream in the abspath + * always /stream=%d so we need to strip that off + * parse the stream we need to configure, look for the stream in the abspath * first and then in the query. */ if (!(pos = strstr (uri->abspath, "/stream="))) { if (!(pos = strstr (uri->query, "/stream="))) @@ -382,7 +382,7 @@ handle_setup_response (GstRTSPClient *client, const gchar *location, GstRTSPMess } /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, uri->abspath, client->factory); + media = gst_rtsp_session_get_media (session, uri, client->factory); if (!media) goto not_found; @@ -410,11 +410,6 @@ handle_setup_response (GstRTSPClient *client, const gchar *location, GstRTSPMess return TRUE; /* ERRORS */ -bad_url: - { - handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); - return FALSE; - } bad_request: { handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); @@ -444,48 +439,53 @@ service_unavailable: /* for the describe we must generate an SDP */ static gboolean -handle_describe_response (GstRTSPClient *client, const gchar *location, GstRTSPMessage *request) +handle_describe_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPMessage response = { 0 }; GstRTSPResult res; GstSDPMessage *sdp; - GstRTSPUrl *uri; guint n_streams, i; gchar *sdptext; GstRTSPMediaFactory *factory; - GstRTSPMediaBin *mediabin; + GstRTSPMedia *media; GstElement *pipeline; GstStateChangeReturn ret; - /* the uri contains the stream number we added in the SDP config, which is - * always /stream=%d so we need to strip that off */ - if ((res = gst_rtsp_url_parse (location, &uri)) != GST_RTSP_OK) - goto bad_url; - /* find the factory for the uri first */ if (!(factory = gst_rtsp_media_mapping_find_factory (client->mapping, uri))) goto no_factory; - /* check what kind of format is accepted */ + /* check what kind of format is accepted, we don't really do anything with it + * and always return SDP for now. */ + for (i = 0; i++; ) { + gchar *accept; + + res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_ACCEPT, &accept, i); + if (res == GST_RTSP_ENOTIMPL) + break; + + if (g_ascii_strcasecmp (accept, "application/sdp") == 0) + break; + } /* create a pipeline to preroll the media */ pipeline = gst_pipeline_new ("client-describe-pipeline"); /* prepare the media and add it to the pipeline */ - if (!(mediabin = gst_rtsp_media_factory_construct (factory, uri->abspath))) - goto no_media_bin; + if (!(media = gst_rtsp_media_factory_construct (factory, uri))) + goto no_media; - gst_bin_add (GST_BIN_CAST (pipeline), mediabin->element); + gst_bin_add (GST_BIN_CAST (pipeline), media->element); /* link fakesink to all stream pads and set the pipeline to PLAYING */ - n_streams = gst_rtsp_media_bin_n_streams (mediabin); + n_streams = gst_rtsp_media_n_streams (media); for (i = 0; i < n_streams; i++) { GstRTSPMediaStream *stream; GstElement *sink; GstPad *sinkpad; GstPadLinkReturn lret; - stream = gst_rtsp_media_bin_get_stream (mediabin, i); + stream = gst_rtsp_media_get_stream (media, i); sink = gst_element_factory_make ("fakesink", NULL); gst_bin_add (GST_BIN (pipeline), sink); @@ -530,7 +530,7 @@ handle_describe_response (GstRTSPClient *client, const gchar *location, GstRTSPM gboolean first; GString *fmtp; - stream = gst_rtsp_media_bin_get_stream (mediabin, i); + stream = gst_rtsp_media_get_stream (media, i); gst_sdp_media_new (&smedia); s = gst_caps_get_structure (stream->caps, 0); @@ -623,6 +623,8 @@ handle_describe_response (GstRTSPClient *client, const gchar *location, GstRTSPM gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE, "application/sdp"); + /* add SDP to the response body */ sdptext = gst_sdp_message_as_text (sdp); gst_rtsp_message_take_body (&response, (guint8 *)sdptext, strlen (sdptext)); @@ -633,17 +635,12 @@ handle_describe_response (GstRTSPClient *client, const gchar *location, GstRTSPM return TRUE; /* ERRORS */ -bad_url: - { - handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); - return FALSE; - } no_factory: { handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); return FALSE; } -no_media_bin: +no_media: { handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); g_object_unref (factory); @@ -659,7 +656,7 @@ cant_play: } static void -handle_options_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request) +handle_options_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPMessage response = { 0 }; GstRTSPMethod options; @@ -714,7 +711,8 @@ handle_client (GstRTSPClient *client) GstRTSPMessage request = { 0 }; GstRTSPResult res; GstRTSPMethod method; - const gchar *uri; + const gchar *uristr; + GstRTSPUrl *uri; GstRTSPVersion version; while (TRUE) { @@ -727,7 +725,7 @@ handle_client (GstRTSPClient *client) gst_rtsp_message_dump (&request); #endif - gst_rtsp_message_parse_request (&request, &method, &uri, &version); + gst_rtsp_message_parse_request (&request, &method, &uristr, &version); if (version != GST_RTSP_VERSION_1_0) { /* we can only handle 1.0 requests */ @@ -735,6 +733,12 @@ handle_client (GstRTSPClient *client) continue; } + /* we always try to parse the url first */ + if ((res = gst_rtsp_url_parse (uristr, &uri)) != GST_RTSP_OK) { + handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &request); + continue; + } + /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: @@ -767,6 +771,7 @@ handle_client (GstRTSPClient *client) handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &request); break; } + gst_rtsp_url_free (uri); } g_object_unref (client); return NULL; diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index eb9c459295..f9df9019c1 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -34,8 +34,8 @@ static void gst_rtsp_media_factory_set_property (GObject *object, guint propid, const GValue *value, GParamSpec *pspec); static void gst_rtsp_media_factory_finalize (GObject * obj); -static GstRTSPMediaBin * default_construct (GstRTSPMediaFactory *factory, const gchar *location); -static GstElement * default_get_element (GstRTSPMediaFactory *factory, const gchar *location); +static GstRTSPMedia * default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); +static GstElement * default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT); @@ -121,8 +121,7 @@ gst_rtsp_media_factory_set_property (GObject *object, guint propid, * * Create a new #GstRTSPMediaFactory instance. * - * Returns: a new #GstRTSPMediaFactory object or %NULL when location did not contain a - * valid or understood URL. + * Returns: a new #GstRTSPMediaFactory object. */ GstRTSPMediaFactory * gst_rtsp_media_factory_new (void) @@ -181,9 +180,9 @@ gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory) /** * gst_rtsp_media_factory_construct: * @factory: a #GstRTSPMediaFactory - * @location: the url used + * @url: the url used * - * Prepare the media bin object and create its streams. Implementations + * Prepare the media object and create its streams. Implementations * should create the needed gstreamer elements and add them to the result * object. No state changes should be performed on them yet. * @@ -191,22 +190,22 @@ gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory) * the srcpad member set to a source pad that produces buffer of type * application/x-rtp. * - * Returns: a new #GstRTSPMediaBin if the media could be prepared. + * Returns: a new #GstRTSPMedia if the media could be prepared. */ -GstRTSPMediaBin * -gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const gchar *location) +GstRTSPMedia * +gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) { - GstRTSPMediaBin *res; + GstRTSPMedia *res; GstRTSPMediaFactoryClass *klass; klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); if (klass->construct) - res = klass->construct (factory, location); + res = klass->construct (factory, url); else res = NULL; - g_message ("constructed mediabin %p for location %s", res, location); + g_message ("constructed media %p for url %s", res, url->abspath); return res; } @@ -221,7 +220,7 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) } static GstElement * -default_get_element (GstRTSPMediaFactory *factory, const gchar *location) +default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) { GstElement *element; GError *error = NULL; @@ -258,10 +257,10 @@ parse_error: } } -static GstRTSPMediaBin * -default_construct (GstRTSPMediaFactory *factory, const gchar *location) +static GstRTSPMedia * +default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) { - GstRTSPMediaBin *bin; + GstRTSPMedia *media; GstRTSPMediaStream *stream; GstElement *pay, *element; GstPad * pad; @@ -271,14 +270,14 @@ default_construct (GstRTSPMediaFactory *factory, const gchar *location) klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); if (klass->get_element) - element = klass->get_element (factory, location); + element = klass->get_element (factory, url); else element = NULL; if (element == NULL) goto no_element; - bin = g_object_new (GST_TYPE_RTSP_MEDIA_BIN, NULL); - bin->element = element; + media = g_object_new (GST_TYPE_RTSP_MEDIA, NULL); + media->element = element; /* try to find all the payloader elements, they should be named 'pay%d'. for * each of the payloaders we will create a stream, collect the source pad and @@ -297,10 +296,10 @@ default_construct (GstRTSPMediaFactory *factory, const gchar *location) /* create the stream */ stream = g_new0 (GstRTSPMediaStream, 1); - stream->mediabin = bin; + stream->media = media; stream->element = element; stream->payloader = pay; - stream->idx = bin->streams->len; + stream->idx = media->streams->len; pad = gst_element_get_static_pad (pay, "src"); @@ -312,13 +311,13 @@ default_construct (GstRTSPMediaFactory *factory, const gchar *location) gst_object_unref (pad); /* add stream now */ - g_array_append_val (bin->streams, stream); + g_array_append_val (media->streams, stream); gst_object_unref (pay); g_free (name); } - return bin; + return media; /* ERRORS */ no_element: diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index b624eb13ad..4c90ac75f1 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -61,17 +61,17 @@ struct _GstRTSPMediaFactory { * pay%d for each stream. The default implementation of this functions * returns the bin created from the launch parameter. * @construct: the vmethod that will be called when the factory has to create the - * #GstRTSPMediaBin for @location. The default implementation of this + * #GstRTSPMedia for @url. The default implementation of this * function calls get_element to retrieve an element and then looks for * pay%d to create the streams. - * + * the #GstRTSPMediaFactory class structure. */ struct _GstRTSPMediaFactoryClass { GObjectClass parent_class; - GstElement * (*get_element) (GstRTSPMediaFactory *factory, const gchar *location); - GstRTSPMediaBin * (*construct) (GstRTSPMediaFactory *factory, const gchar *location); + GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); }; GType gst_rtsp_media_factory_get_type (void); @@ -79,11 +79,18 @@ GType gst_rtsp_media_factory_get_type (void); /* configuring the factory */ GstRTSPMediaFactory * gst_rtsp_media_factory_new (void); -void gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, const gchar *launch); +void gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, + const gchar *launch); gchar * gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory, + gboolean shared); +gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory); + + /* creating the media bin from the factory */ -GstRTSPMediaBin * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const gchar *location); +GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, + const GstRTSPUrl *url); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 036d09fbc9..9447675267 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -19,24 +19,24 @@ #include "rtsp-media.h" -static void gst_rtsp_media_bin_finalize (GObject * obj); +static void gst_rtsp_media_finalize (GObject * obj); -G_DEFINE_TYPE (GstRTSPMediaBin, gst_rtsp_media_bin, G_TYPE_OBJECT); +G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); static void -gst_rtsp_media_bin_class_init (GstRTSPMediaBinClass * klass) +gst_rtsp_media_class_init (GstRTSPMediaClass * klass) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); - gobject_class->finalize = gst_rtsp_media_bin_finalize; + gobject_class->finalize = gst_rtsp_media_finalize; } static void -gst_rtsp_media_bin_init (GstRTSPMediaBin * bin) +gst_rtsp_media_init (GstRTSPMedia * media) { - bin->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); + media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); } static void @@ -45,59 +45,59 @@ gst_rtsp_media_stream_free (GstRTSPMediaStream *stream) } static void -gst_rtsp_media_bin_finalize (GObject * obj) +gst_rtsp_media_finalize (GObject * obj) { - GstRTSPMediaBin *bin; + GstRTSPMedia *media; guint i; - bin = GST_RTSP_MEDIA_BIN (obj); + media = GST_RTSP_MEDIA (obj); - for (i = 0; i < bin->streams->len; i++) { + for (i = 0; i < media->streams->len; i++) { GstRTSPMediaStream *stream; - stream = g_array_index (bin->streams, GstRTSPMediaStream *, i); + stream = g_array_index (media->streams, GstRTSPMediaStream *, i); gst_rtsp_media_stream_free (stream); } - g_array_free (bin->streams, TRUE); + g_array_free (media->streams, TRUE); - G_OBJECT_CLASS (gst_rtsp_media_bin_parent_class)->finalize (obj); + G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); } /** - * gst_rtsp_media_bin_n_streams: - * @media: a #GstRTSPMediaBin + * gst_rtsp_media_n_streams: + * @media: a #GstRTSPMedia * - * Get the number of streams in this mediabin. + * Get the number of streams in this media. * * Returns: The number of streams. */ guint -gst_rtsp_media_bin_n_streams (GstRTSPMediaBin *bin) +gst_rtsp_media_n_streams (GstRTSPMedia *media) { - g_return_val_if_fail (GST_IS_RTSP_MEDIA_BIN (bin), 0); + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0); - return bin->streams->len; + return media->streams->len; } /** - * gst_rtsp_media_bin_get_stream: - * @bin: a #GstRTSPMediaBin + * gst_rtsp_media_get_stream: + * @media: a #GstRTSPMedia * @idx: the stream index * - * Retrieve the stream with index @idx from @bin. + * Retrieve the stream with index @idx from @media. * * Returns: the #GstRTSPMediaStream at index @idx. */ GstRTSPMediaStream * -gst_rtsp_media_bin_get_stream (GstRTSPMediaBin *bin, guint idx) +gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx) { GstRTSPMediaStream *res; - g_return_val_if_fail (GST_IS_RTSP_MEDIA_BIN (bin), NULL); - g_return_val_if_fail (idx < bin->streams->len, NULL); + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + g_return_val_if_fail (idx < media->streams->len, NULL); - res = g_array_index (bin->streams, GstRTSPMediaStream *, idx); + res = g_array_index (media->streams, GstRTSPMediaStream *, idx); return res; } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 8c6e64dcc8..4bd3556eb0 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -25,19 +25,19 @@ G_BEGIN_DECLS -/* types for the media bin */ -#define GST_TYPE_RTSP_MEDIA_BIN (gst_rtsp_media_bin_get_type ()) -#define GST_IS_RTSP_MEDIA_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA_BIN)) -#define GST_IS_RTSP_MEDIA_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA_BIN)) -#define GST_RTSP_MEDIA_BIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA_BIN, GstRTSPMediaBinClass)) -#define GST_RTSP_MEDIA_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA_BIN, GstRTSPMediaBin)) -#define GST_RTSP_MEDIA_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA_BIN, GstRTSPMediaBinClass)) -#define GST_RTSP_MEDIA_BIN_CAST(obj) ((GstRTSPMediaBin*)(obj)) -#define GST_RTSP_MEDIA_BIN_CLASS_CAST(klass) ((GstRTSPMediaBinClass*)(klass)) +/* types for the media */ +#define GST_TYPE_RTSP_MEDIA (gst_rtsp_media_get_type ()) +#define GST_IS_RTSP_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA)) +#define GST_IS_RTSP_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA)) +#define GST_RTSP_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMediaClass)) +#define GST_RTSP_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMedia)) +#define GST_RTSP_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA, GstRTSPMediaClass)) +#define GST_RTSP_MEDIA_CAST(obj) ((GstRTSPMedia*)(obj)) +#define GST_RTSP_MEDIA_CLASS_CAST(klass) ((GstRTSPMediaClass*)(klass)) typedef struct _GstRTSPMediaStream GstRTSPMediaStream; -typedef struct _GstRTSPMediaBin GstRTSPMediaBin; -typedef struct _GstRTSPMediaBinClass GstRTSPMediaBinClass; +typedef struct _GstRTSPMedia GstRTSPMedia; +typedef struct _GstRTSPMediaClass GstRTSPMediaClass; /** * GstRTSPMediaStream: @@ -45,14 +45,14 @@ typedef struct _GstRTSPMediaBinClass GstRTSPMediaBinClass; * @idx: the stream index * @element: the toplevel element * @srcpad: the srcpad of the stream - * @payloader: the payloader of the formattt + * @payloader: the payloader of the format * @caps_sig: the signal id for detecting caps * @caps: the caps of the stream * * The definition of a media stream. The streams are identified by @id. */ struct _GstRTSPMediaStream { - GstRTSPMediaBin *mediabin; + GstRTSPMedia *media; guint idx; @@ -64,28 +64,28 @@ struct _GstRTSPMediaStream { }; /** - * GstRTSPMediaBin: + * GstRTSPMedia: * @media: the owner #GstRTSPMedia * * A class that contains the elements to handle the media * provided by @media. */ -struct _GstRTSPMediaBin { +struct _GstRTSPMedia { GObject parent; GstElement *element; GArray *streams; }; -struct _GstRTSPMediaBinClass { +struct _GstRTSPMediaClass { GObjectClass parent_class; }; -GType gst_rtsp_media_bin_get_type (void); +GType gst_rtsp_media_get_type (void); -/* dealing with the media bin */ -guint gst_rtsp_media_bin_n_streams (GstRTSPMediaBin *bin); -GstRTSPMediaStream * gst_rtsp_media_bin_get_stream (GstRTSPMediaBin *bin, guint idx); +/* dealing with the media */ +guint gst_rtsp_media_n_streams (GstRTSPMedia *media); +GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index dd608c7675..b59dee07d4 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -98,7 +98,7 @@ gst_rtsp_session_finalize (GObject * obj) /** * gst_rtsp_session_get_media: * @sess: a #GstRTSPSession - * @location: the url for the media + * @url: the url for the media * @factory: a #GstRTSPMediaFactory * * Get or create the session information for @factory. @@ -106,7 +106,7 @@ gst_rtsp_session_finalize (GObject * obj) * Returns: the configuration for @factory in @sess. */ GstRTSPSessionMedia * -gst_rtsp_session_get_media (GstRTSPSession *sess, const gchar *location, GstRTSPMediaFactory *factory) +gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *url, GstRTSPMediaFactory *factory) { GstRTSPSessionMedia *result; GList *walk; @@ -127,11 +127,11 @@ gst_rtsp_session_get_media (GstRTSPSession *sess, const gchar *location, GstRTSP result->pipeline = gst_pipeline_new ("pipeline"); /* construct media and add to the pipeline */ - result->mediabin = gst_rtsp_media_factory_construct (factory, location); - if (result->mediabin == NULL) + result->media = gst_rtsp_media_factory_construct (factory, url); + if (result->media == NULL) goto no_media; - gst_bin_add (GST_BIN_CAST (result->pipeline), result->mediabin->element); + gst_bin_add (GST_BIN_CAST (result->pipeline), result->media->element); result->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin"); @@ -182,7 +182,7 @@ gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, guint idx) result = g_new0 (GstRTSPSessionStream, 1); result->idx = idx; result->media = media; - result->media_stream = gst_rtsp_media_bin_get_stream (media->mediabin, idx); + result->media_stream = gst_rtsp_media_get_stream (media->media, idx); media->streams = g_list_prepend (media->streams, result); } @@ -508,4 +508,3 @@ gst_rtsp_session_media_stop (GstRTSPSessionMedia *media) return ret; } - diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 5db5ba834b..6055197ccc 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -92,7 +92,7 @@ struct _GstRTSPSessionMedia /* the pipeline for the media */ GstElement *pipeline; - GstRTSPMediaBin *mediabin; + GstRTSPMedia *media; /* RTP session manager */ GstElement *rtpbin; @@ -127,7 +127,7 @@ GType gst_rtsp_session_get_type (void); GstRTSPSession * gst_rtsp_session_new (const gchar *sessionid); -GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, const gchar *location, +GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *url, GstRTSPMediaFactory *factory); GstStateChangeReturn gst_rtsp_session_media_play (GstRTSPSessionMedia *media); From b0fcbfd290126ad1bbe8787336bd0980ea939859 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 22 Jan 2009 18:35:17 +0100 Subject: [PATCH 0040/1776] Cleanups and doc updates Add some more documentation and do some minor cleanups here and there. --- gst/rtsp-server/rtsp-client.c | 17 +++++++++-------- gst/rtsp-server/rtsp-media-mapping.c | 7 +++++-- gst/rtsp-server/rtsp-media-mapping.h | 10 +++++++++- gst/rtsp-server/rtsp-media.h | 6 ++++-- gst/rtsp-server/rtsp-session-pool.h | 8 ++++---- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a45f618c60..4d518fe9b0 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -451,9 +451,6 @@ handle_describe_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage GstElement *pipeline; GstStateChangeReturn ret; - /* find the factory for the uri first */ - if (!(factory = gst_rtsp_media_mapping_find_factory (client->mapping, uri))) - goto no_factory; /* check what kind of format is accepted, we don't really do anything with it * and always return SDP for now. */ @@ -468,12 +465,16 @@ handle_describe_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage break; } - /* create a pipeline to preroll the media */ - pipeline = gst_pipeline_new ("client-describe-pipeline"); + /* find the factory for the uri first */ + if (!(factory = gst_rtsp_media_mapping_find_factory (client->mapping, uri))) + goto no_factory; /* prepare the media and add it to the pipeline */ if (!(media = gst_rtsp_media_factory_construct (factory, uri))) goto no_media; + + /* create a pipeline to preroll the media */ + pipeline = gst_pipeline_new ("client-describe-pipeline"); gst_bin_add (GST_BIN_CAST (pipeline), media->element); @@ -662,9 +663,6 @@ handle_options_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage GstRTSPMethod options; GString *str; - gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, - gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); - options = GST_RTSP_DESCRIBE | GST_RTSP_OPTIONS | // GST_RTSP_PAUSE | @@ -696,6 +694,9 @@ handle_options_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage if (options & GST_RTSP_TEARDOWN) g_string_append (str, ", TEARDOWN"); + gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, + gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str->str); g_string_free (str, TRUE); diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c index 2471be793f..52490cd329 100644 --- a/gst/rtsp-server/rtsp-media-mapping.c +++ b/gst/rtsp-server/rtsp-media-mapping.c @@ -69,7 +69,9 @@ find_media (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url) { GstRTSPMediaFactory *result; - /* find the location of the media in the hashtable */ + /* find the location of the media in the hashtable we only use the absolute + * path of the uri to find a mapping. If the mapping depends on other + * properties found in the url, this method should be overridden. */ result = g_hash_table_lookup (mapping->mappings, url->abspath); if (result) g_object_ref (result); @@ -84,7 +86,8 @@ find_media (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url) * @mapping: a #GstRTSPMediaMapping * @url: a url * - * Find the #GstRTSPMediaFactory for @url from the mappings registered in @mapping. + * Find the #GstRTSPMediaFactory for @url. The default implementation of this object + * will use the mappings added with gst_rtsp_media_mapping_add_factory (). * * Returns: the #GstRTSPMediaFactory for @url. g_object_unref() after usage. */ diff --git a/gst/rtsp-server/rtsp-media-mapping.h b/gst/rtsp-server/rtsp-media-mapping.h index 65442465f6..07d4efa8b9 100644 --- a/gst/rtsp-server/rtsp-media-mapping.h +++ b/gst/rtsp-server/rtsp-media-mapping.h @@ -44,7 +44,7 @@ typedef struct _GstRTSPMediaMappingClass GstRTSPMediaMappingClass; * GstRTSPMediaMapping: * @mappings: the mountpoint to media mappings * - * Creates a #GstRTSPMedia object for a given url. + * Creates a #GstRTSPMediaFactory object for a given url. */ struct _GstRTSPMediaMapping { GObject parent; @@ -52,6 +52,14 @@ struct _GstRTSPMediaMapping { GHashTable *mappings; }; +/** + * GstRTSPMediaMappingClass: + * @find_media: Create or return a previously cached #GstRTSPMediaFactory object + * for the given url. the default implementation will use the mappings + * added with gst_rtsp_media_mapping_add_factory (). + * + * The class for the media mapping object. + */ struct _GstRTSPMediaMappingClass { GObjectClass parent_class; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 4bd3556eb0..17fa4eeef1 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -67,8 +67,10 @@ struct _GstRTSPMediaStream { * GstRTSPMedia: * @media: the owner #GstRTSPMedia * - * A class that contains the elements to handle the media - * provided by @media. + * A class that contains the GStreamer element along with a list of + * #GstRTSPediaStream objects that can produce data. + * + * This object is usually created from a #GstRTSPMediaFactory. */ struct _GstRTSPMedia { GObject parent; diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index fafe606e9f..9f65f41e3e 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -44,7 +44,8 @@ typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; * @lock: locking the session hashtable * @session: hashtable of sessions indexed by the session id. * - * An object that keeps track of the active sessions. + * An object that keeps track of the active sessions. This object is usually + * attached to a #GstRTSPServer object to manage the sessions in that server. */ struct _GstRTSPSessionPool { GObject parent; @@ -55,9 +56,8 @@ struct _GstRTSPSessionPool { /** * GstRTSPSessionPoolClass: - * - * @create_session_id: create a new random session id. Subclasses should not - * check if the session exists. + * @create_session_id: create a new random session id. Subclasses can create + * custom session ids and should not check if the session exists. */ struct _GstRTSPSessionPoolClass { GObjectClass parent_class; From ef9c3dc92105813a8e4278ba68fae05c36514af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Fri, 23 Jan 2009 20:31:11 +0100 Subject: [PATCH 0041/1776] Updated Vala bindings --- bindings/vala/gst-rtsp-server-0.10.vapi | 92 +++++-- .../packages/gst-rtsp-server-0.10.excludes | 1 - .../vala/packages/gst-rtsp-server-0.10.gi | 246 +++++++++++++++--- .../packages/gst-rtsp-server-0.10.metadata | 26 +- 4 files changed, 293 insertions(+), 72 deletions(-) delete mode 100644 bindings/vala/packages/gst-rtsp-server-0.10.excludes diff --git a/bindings/vala/gst-rtsp-server-0.10.vapi b/bindings/vala/gst-rtsp-server-0.10.vapi index c9652c5561..38cba5a5cb 100644 --- a/bindings/vala/gst-rtsp-server-0.10.vapi +++ b/bindings/vala/gst-rtsp-server-0.10.vapi @@ -6,29 +6,48 @@ namespace Gst { public class RTSPClient : GLib.Object { public void* address; public weak Gst.RTSPConnection connection; - public weak Gst.RTSPMedia media; + public weak Gst.RTSPMediaFactory factory; + public weak Gst.RTSPMediaMapping mapping; public weak Gst.RTSPSessionPool pool; public weak GLib.Thread thread; - public bool accept (GLib.IOChannel source); - public weak Gst.RTSPSessionPool get_session_pool (); + public bool accept (GLib.IOChannel channel); + public Gst.RTSPMediaMapping get_media_mapping (); + public Gst.RTSPSessionPool get_session_pool (); [CCode (has_construct_function = false)] - public RTSPClient (Gst.RTSPServer server); + public RTSPClient (); + public void set_media_mapping (Gst.RTSPMediaMapping mapping); public void set_session_pool (Gst.RTSPSessionPool pool); - [NoAccessorMethod] - public Gst.RTSPServer server { get; construct; } } [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] public class RTSPMedia : GLib.Object { - public bool prepared; + public weak Gst.Element element; public weak GLib.Array streams; - public weak Gst.RTSPMediaStream get_stream (uint idx); + public unowned Gst.RTSPMediaStream get_stream (uint idx); public uint n_streams (); + } + [CCode (cheader_filename = "gst/rtsp-server/rtsp-media-factory.h")] + public class RTSPMediaFactory : GLib.Object { + public virtual Gst.RTSPMedia @construct (Gst.RTSPUrl url); + [NoWrapper] + public virtual Gst.Element get_element (Gst.RTSPUrl url); + public string get_launch (); + public bool is_shared (); [CCode (has_construct_function = false)] - public RTSPMedia (string name); - [NoAccessorMethod] - public string location { get; construct; } - [NoAccessorMethod] - public Gst.RTSPUrl url { get; construct; } + public RTSPMediaFactory (); + public void set_launch (string launch); + public void set_shared (bool shared); + public string launch { get; set; } + } + [CCode (cheader_filename = "gst/rtsp-server/rtsp-media-mapping.h")] + public class RTSPMediaMapping : GLib.Object { + public weak GLib.HashTable mappings; + public void add_factory (string path, Gst.RTSPMediaFactory factory); + public Gst.RTSPMediaFactory find_factory (Gst.RTSPUrl url); + [NoWrapper] + public virtual Gst.RTSPMediaFactory find_media (Gst.RTSPUrl url); + [CCode (has_construct_function = false)] + public RTSPMediaMapping (); + public void remove_factory (string path); } [Compact] [CCode (cheader_filename = "gst/rtsp-server/rstp-media.h")] @@ -38,58 +57,77 @@ namespace Gst { public weak Gst.Element element; public uint idx; public weak Gst.RTSPMedia media; - public weak string name; public weak Gst.Element payloader; public weak Gst.Pad srcpad; } [CCode (cheader_filename = "gst/rtsp-server/rtsp-server.h")] - public class RTSPServer : Gst.Object { + public class RTSPServer : GLib.Object { public weak string host; public weak GLib.IOChannel io_channel; public weak GLib.TimeoutSource io_watch; - public weak Gst.RTSPSessionPool pool; public int server_port; public void* server_sin; public weak Gst.PollFD server_sock; + [NoWrapper] + public virtual Gst.RTSPClient accept_client (GLib.IOChannel channel); public uint attach (GLib.MainContext context); - public virtual weak Gst.Element prepare_media (Gst.RTSPMedia media, Gst.Bin bin); + public GLib.TimeoutSource create_watch (); + public int get_backlog (); + public GLib.IOChannel get_io_channel (); + public Gst.RTSPMediaMapping get_media_mapping (); + public int get_port (); + public Gst.RTSPSessionPool get_session_pool (); + public static bool io_func (GLib.IOChannel channel, GLib.IOCondition condition, Gst.RTSPServer server); + [CCode (has_construct_function = false)] + public RTSPServer (); + public void set_backlog (int backlog); + public void set_media_mapping (Gst.RTSPMediaMapping mapping); + public void set_port (int port); + public void set_session_pool (Gst.RTSPSessionPool pool); + public int backlog { get; set; } [NoAccessorMethod] - public int port { get; construct; } + public Gst.RTSPMediaMapping mapping { owned get; set; } + [NoAccessorMethod] + public Gst.RTSPSessionPool pool { owned get; set; } + public int port { get; set; } } [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] public class RTSPSession : GLib.Object { public weak GLib.List medias; public weak string sessionid; - public weak Gst.RTSPSessionMedia get_media (Gst.RTSPMedia media); - public static weak Gst.RTSPSessionStream get_stream (Gst.RTSPSessionMedia media, uint idx); + public unowned Gst.RTSPSessionMedia get_media (Gst.RTSPUrl url, Gst.RTSPMediaFactory factory); [CCode (has_construct_function = false)] public RTSPSession (string sessionid); } [Compact] [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] public class RTSPSessionMedia { + public weak Gst.RTSPMediaFactory factory; public weak Gst.Element fdsink; public weak Gst.RTSPMedia media; public weak Gst.Element pipeline; public weak Gst.Element rtpbin; public weak Gst.RTSPSession session; public weak GLib.List streams; + public unowned Gst.RTSPSessionStream get_stream (uint idx); public Gst.StateChangeReturn pause (); public Gst.StateChangeReturn play (); public Gst.StateChangeReturn stop (); } - [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-session-pool.h")] public class RTSPSessionPool : GLib.Object { public weak GLib.Mutex @lock; public weak GLib.HashTable sessions; - public weak Gst.RTSPSession create (); - public weak Gst.RTSPSession find (string sessionid); + public Gst.RTSPSession create (); + [NoWrapper] + public virtual string create_session_id (); + public Gst.RTSPSession find (string sessionid); [CCode (has_construct_function = false)] public RTSPSessionPool (); public void remove (Gst.RTSPSession sess); } [Compact] - [CCode (cheader_filename = "gst/rtsp-server/rtsp-session-pool.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] public class RTSPSessionStream { public weak Gst.RTSPTransport client_trans; public weak string destination; @@ -101,10 +139,10 @@ namespace Gst { public weak Gst.Pad send_rtp_sink; public weak Gst.Pad send_rtp_src; public weak Gst.RTSPTransport server_trans; - [NoArrayLength] + [CCode (array_length = false)] public weak Gst.Element[] udpsink; - [NoArrayLength] + [CCode (array_length = false)] public weak Gst.Element[] udpsrc; - public weak Gst.RTSPTransport set_transport (string destination, Gst.RTSPTransport ct); + public Gst.RTSPTransport set_transport (string destination, Gst.RTSPTransport ct); } } diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.excludes b/bindings/vala/packages/gst-rtsp-server-0.10.excludes deleted file mode 100644 index 4d93f3b112..0000000000 --- a/bindings/vala/packages/gst-rtsp-server-0.10.excludes +++ /dev/null @@ -1 +0,0 @@ -rtsp-url-compat.h diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.gi b/bindings/vala/packages/gst-rtsp-server-0.10.gi index b9257179a0..b71ad358b7 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.gi +++ b/bindings/vala/packages/gst-rtsp-server-0.10.gi @@ -4,7 +4,6 @@ - @@ -12,6 +11,13 @@ + + + + + + + @@ -31,8 +37,9 @@ - + + @@ -64,7 +71,13 @@ - + + + + + + + @@ -75,10 +88,14 @@ - - - + + + + + + + @@ -86,13 +103,12 @@ - - - - + + + @@ -108,20 +124,99 @@ - - - - - - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -129,44 +224,109 @@ - - + + - - - - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + - - - - - - - - + + @@ -202,6 +362,12 @@ + + + + + + diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.metadata b/bindings/vala/packages/gst-rtsp-server-0.10.metadata index adcd1e70c7..9de31628c7 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.metadata +++ b/bindings/vala/packages/gst-rtsp-server-0.10.metadata @@ -1,9 +1,27 @@ Gst cprefix="Gst" lower_case_cprefix="gst_" cheader_filename="gst/gst.h" -GstRTSPMediaStream cheader_filename="gst/rtsp-server/rstp-media.h" -GstRTSPMedia cheader_filename="gst/rtsp-server/rtsp-media.h" GstRTSPClient cheader_filename="gst/rtsp-server/rtsp-client.h" +GstRTSPMedia cheader_filename="gst/rtsp-server/rtsp-media.h" +GstRTSPMediaFactory cheader_filename="gst/rtsp-server/rtsp-media-factory.h" +GstRTSPMediaMapping cheader_filename="gst/rtsp-server/rtsp-media-mapping.h" +GstRTSPMediaStream cheader_filename="gst/rtsp-server/rstp-media.h" GstRTSPServer cheader_filename="gst/rtsp-server/rtsp-server.h" GstRTSPSession cheader_filename="gst/rtsp-server/rtsp-session.h" GstRTSPSessionMedia cheader_filename="gst/rtsp-server/rtsp-session.h" -GstRTSPSessionPool cheader_filename="gst/rtsp-server/rtsp-session.h" -GstRTSPSessionStream cheader_filename="gst/rtsp-server/rtsp-session-pool.h" +GstRTSPSessionPool cheader_filename="gst/rtsp-server/rtsp-session-pool.h" +GstRTSPSessionStream cheader_filename="gst/rtsp-server/rtsp-session.h" +gst_rtsp_client_get_media_mapping transfer_ownership="1" +gst_rtsp_client_get_session_pool transfer_ownership="1" +gst_rtsp_media_factory_get_launch transfer_ownership="1" +gst_rtsp_media_factory_construct transfer_ownership="1" +gst_rtsp_media_factory_get_element transfer_ownership="1" +gst_rtsp_media_mapping_find_factory transfer_ownership="1" +gst_rtsp_media_mapping_find_media transfer_ownership="1" +gst_rtsp_server_accept_client transfer_ownership="1" +gst_rtsp_server_create_watch transfer_ownership="1" +gst_rtsp_server_get_io_channel transfer_ownership="1" +gst_rtsp_server_get_media_mapping transfer_ownership="1" +gst_rtsp_server_get_session_pool transfer_ownership="1" +gst_rtsp_session_pool_create transfer_ownership="1" +gst_rtsp_session_pool_create_session_id transfer_ownership="1" +gst_rtsp_session_pool_find transfer_ownership="1" +gst_rtsp_session_stream_set_transport transfer_ownership="1" From 02711871d0e42479126454b23070c28f3f913ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Fri, 23 Jan 2009 21:03:53 +0100 Subject: [PATCH 0042/1776] Marked values as nullable accordingly --- bindings/vala/gst-rtsp-server-0.10.vapi | 18 +++++++++--------- .../packages/gst-rtsp-server-0.10.metadata | 17 +++++++++-------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/bindings/vala/gst-rtsp-server-0.10.vapi b/bindings/vala/gst-rtsp-server-0.10.vapi index 38cba5a5cb..af5804c7d7 100644 --- a/bindings/vala/gst-rtsp-server-0.10.vapi +++ b/bindings/vala/gst-rtsp-server-0.10.vapi @@ -27,9 +27,9 @@ namespace Gst { } [CCode (cheader_filename = "gst/rtsp-server/rtsp-media-factory.h")] public class RTSPMediaFactory : GLib.Object { - public virtual Gst.RTSPMedia @construct (Gst.RTSPUrl url); + public virtual Gst.RTSPMedia? @construct (Gst.RTSPUrl url); [NoWrapper] - public virtual Gst.Element get_element (Gst.RTSPUrl url); + public virtual Gst.Element? get_element (Gst.RTSPUrl url); public string get_launch (); public bool is_shared (); [CCode (has_construct_function = false)] @@ -42,9 +42,9 @@ namespace Gst { public class RTSPMediaMapping : GLib.Object { public weak GLib.HashTable mappings; public void add_factory (string path, Gst.RTSPMediaFactory factory); - public Gst.RTSPMediaFactory find_factory (Gst.RTSPUrl url); + public Gst.RTSPMediaFactory? find_factory (Gst.RTSPUrl url); [NoWrapper] - public virtual Gst.RTSPMediaFactory find_media (Gst.RTSPUrl url); + public virtual Gst.RTSPMediaFactory? find_media (Gst.RTSPUrl url); [CCode (has_construct_function = false)] public RTSPMediaMapping (); public void remove_factory (string path); @@ -69,11 +69,11 @@ namespace Gst { public void* server_sin; public weak Gst.PollFD server_sock; [NoWrapper] - public virtual Gst.RTSPClient accept_client (GLib.IOChannel channel); - public uint attach (GLib.MainContext context); - public GLib.TimeoutSource create_watch (); + public virtual Gst.RTSPClient? accept_client (GLib.IOChannel channel); + public uint attach (GLib.MainContext? context); + public GLib.TimeoutSource? create_watch (); public int get_backlog (); - public GLib.IOChannel get_io_channel (); + public GLib.IOChannel? get_io_channel (); public Gst.RTSPMediaMapping get_media_mapping (); public int get_port (); public Gst.RTSPSessionPool get_session_pool (); @@ -121,7 +121,7 @@ namespace Gst { public Gst.RTSPSession create (); [NoWrapper] public virtual string create_session_id (); - public Gst.RTSPSession find (string sessionid); + public Gst.RTSPSession? find (string sessionid); [CCode (has_construct_function = false)] public RTSPSessionPool (); public void remove (Gst.RTSPSession sess); diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.metadata b/bindings/vala/packages/gst-rtsp-server-0.10.metadata index 9de31628c7..bf7ed85e63 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.metadata +++ b/bindings/vala/packages/gst-rtsp-server-0.10.metadata @@ -12,16 +12,17 @@ GstRTSPSessionStream cheader_filename="gst/rtsp-server/rtsp-session.h" gst_rtsp_client_get_media_mapping transfer_ownership="1" gst_rtsp_client_get_session_pool transfer_ownership="1" gst_rtsp_media_factory_get_launch transfer_ownership="1" -gst_rtsp_media_factory_construct transfer_ownership="1" -gst_rtsp_media_factory_get_element transfer_ownership="1" -gst_rtsp_media_mapping_find_factory transfer_ownership="1" -gst_rtsp_media_mapping_find_media transfer_ownership="1" -gst_rtsp_server_accept_client transfer_ownership="1" -gst_rtsp_server_create_watch transfer_ownership="1" -gst_rtsp_server_get_io_channel transfer_ownership="1" +gst_rtsp_media_factory_construct transfer_ownership="1" nullable="1" +gst_rtsp_media_factory_get_element transfer_ownership="1" nullable="1" +gst_rtsp_media_mapping_find_factory transfer_ownership="1" nullable="1" +gst_rtsp_media_mapping_find_media transfer_ownership="1" nullable="1" +gst_rtsp_server_accept_client transfer_ownership="1" nullable="1" +gst_rtsp_server_create_watch transfer_ownership="1" nullable="1" +gst_rtsp_server_get_io_channel transfer_ownership="1" nullable="1" gst_rtsp_server_get_media_mapping transfer_ownership="1" gst_rtsp_server_get_session_pool transfer_ownership="1" +gst_rtsp_server_attach.context nullable="1" gst_rtsp_session_pool_create transfer_ownership="1" gst_rtsp_session_pool_create_session_id transfer_ownership="1" -gst_rtsp_session_pool_find transfer_ownership="1" +gst_rtsp_session_pool_find transfer_ownership="1" nullable="1" gst_rtsp_session_stream_set_transport transfer_ownership="1" From 5f2db2f2391190940ce14e6510234d41eba49bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Sat, 24 Jan 2009 14:34:35 +0100 Subject: [PATCH 0043/1776] Fixed compile error of python bindings --- bindings/python/Makefile.am | 4 ++-- bindings/python/rtspserver.override | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am index 76dcf7ab9f..03f8479c4c 100644 --- a/bindings/python/Makefile.am +++ b/bindings/python/Makefile.am @@ -14,13 +14,13 @@ defs_DATA = $(DEFS) defsdir = $(pkgdatadir)/$(GST_MAJORMINOR)/defs OVERRIDES = rtspserver.override -INCLUDES = $(PYTHON_INCLUDES) +INCLUDES = -I$(top_srcdir) -I$(srcdir) $(PYTHON_INCLUDES) rtspserver_la_CFLAGS = -I$(top_srcdir)/src \ $(PYGOBJECT_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) rtspserver_la_LDFLAGS = -export-symbols-regex "^(initrtspserver|_PyGObject_API).*" \ -module -avoid-version $(GST_PLUGIN_LDFLAGS) -rtspserver_la_LIBADD = $(top_builddir)/src/libgst-rtsp-server.a \ +rtspserver_la_LIBADD = $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_MAJORMINOR@.la \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ -lgstsdp-@GST_MAJORMINOR@ $(GST_LIBS) $(LIBM) diff --git a/bindings/python/rtspserver.override b/bindings/python/rtspserver.override index ca705edd04..3cab9d6635 100644 --- a/bindings/python/rtspserver.override +++ b/bindings/python/rtspserver.override @@ -14,7 +14,7 @@ headers #define Py_ssize_t int #endif -#include "rtsp-server.h" +#include typedef struct { PyObject_HEAD From 3cba21129c5f9ddf94a8abce03de44b7295dd497 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Jan 2009 15:19:01 +0100 Subject: [PATCH 0044/1776] Fix make dist Add more directories and files to the dist. --- bindings/vala/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bindings/vala/Makefile.am b/bindings/vala/Makefile.am index cd80cd4211..706cf19a33 100644 --- a/bindings/vala/Makefile.am +++ b/bindings/vala/Makefile.am @@ -7,3 +7,6 @@ gst-rtsp-server-0.10.deps: vapidir = $(VAPIDIR) vapi_DATA = $(VAPI_FILES) $(DEPS_FILES) + +EXTRA_DIST = packages $(DEPS_FILES) + From 0601746ccd26a6a93433ef39c8ef1b89cf658f9f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Jan 2009 11:20:18 +0100 Subject: [PATCH 0045/1776] Make 0.10.1 release Release 0.10.1 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index cfbbc2ec75..75c168975f 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.0.1, +AC_INIT(Gst-RTSP, 0.10.1.0, http://gstreamer.net/, gst-rtsp) From 82a684e1b90576be5954659d9aad197fcfda8938 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Jan 2009 11:23:57 +0100 Subject: [PATCH 0046/1776] Back to development Back to 0.10.1.1 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 75c168975f..9fdd1a1eee 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.1.0, +AC_INIT(Gst-RTSP, 0.10.1.1, http://gstreamer.net/, gst-rtsp) From 41dd6399a6afdb4db9c2f299fee60bc813b6dd7e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Jan 2009 13:31:27 +0100 Subject: [PATCH 0047/1776] Reorganize things, prepare for media sharing Added various other test server examples Move the SDP message generation to a separate helper. Refactor common code for finding the session. Add content-base for realplayer compatibility Clean up request uris before processing for better vlc compatibility. Move prerolling and pipeline construction to the RTSPMedia object. Use multiudpsink for future pipeline reuse. --- examples/Makefile.am | 10 +- examples/test-mp4.c | 77 +++++ examples/test-ogg.c | 77 +++++ examples/{main.c => test-video.c} | 3 +- gst/rtsp-server/Makefile.am | 2 + gst/rtsp-server/rtsp-client.c | 481 +++++++++++---------------- gst/rtsp-server/rtsp-client.h | 6 +- gst/rtsp-server/rtsp-media-factory.c | 27 +- gst/rtsp-server/rtsp-media-factory.h | 19 +- gst/rtsp-server/rtsp-media.c | 435 ++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 68 +++- gst/rtsp-server/rtsp-sdp.c | 145 ++++++++ gst/rtsp-server/rtsp-sdp.h | 35 ++ gst/rtsp-server/rtsp-server.c | 46 +-- gst/rtsp-server/rtsp-server.h | 21 +- gst/rtsp-server/rtsp-session.c | 315 +++--------------- gst/rtsp-server/rtsp-session.h | 40 +-- 17 files changed, 1140 insertions(+), 667 deletions(-) create mode 100644 examples/test-mp4.c create mode 100644 examples/test-ogg.c rename examples/{main.c => test-video.c} (97%) create mode 100644 gst/rtsp-server/rtsp-sdp.c create mode 100644 gst/rtsp-server/rtsp-sdp.h diff --git a/examples/Makefile.am b/examples/Makefile.am index 062f595579..1241eda2af 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,13 +1,9 @@ - -noinst_PROGRAMS = gst-rtsp-server +noinst_PROGRAMS = test-video test-ogg test-mp4 INCLUDES = -I$(top_srcdir) -I$(srcdir) -gst_rtsp_server_SOURCES = \ - main.c - -gst_rtsp_server_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) -gst_rtsp_server_LDFLAGS = \ +AM_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +AM_LDFLAGS = \ $(GST_LIBS) \ $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_MAJORMINOR@.la diff --git a/examples/test-mp4.c b/examples/test-mp4.c new file mode 100644 index 0000000000..a7756e23bb --- /dev/null +++ b/examples/test-mp4.c @@ -0,0 +1,77 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMediaMapping *mapping; + GstRTSPMediaFactory *factory; + gchar *str; + + gst_init (&argc, &argv); + + if (argc < 2) { + g_message ("usage: %s ", argv[0]); + return -1; + } + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mapping for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mapping = gst_rtsp_server_get_media_mapping (server); + + str = g_strdup_printf ( + "( " + "filesrc location=%s ! qtdemux name=d " + "d. ! queue ! rtph264pay pt=96 name=pay0 " + "d. ! queue ! rtpmp4apay pt=97 name=pay1 " + ")", argv[1]); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, str); + g_free (str); + + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mapping); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + /* start serving */ + g_main_loop_run (loop); + + return 0; +} diff --git a/examples/test-ogg.c b/examples/test-ogg.c new file mode 100644 index 0000000000..0e39f01462 --- /dev/null +++ b/examples/test-ogg.c @@ -0,0 +1,77 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMediaMapping *mapping; + GstRTSPMediaFactory *factory; + gchar *str; + + gst_init (&argc, &argv); + + if (argc < 2) { + g_message ("usage: %s ", argv[0]); + return -1; + } + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mapping for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mapping = gst_rtsp_server_get_media_mapping (server); + + str = g_strdup_printf ( + "( " + "filesrc location=%s ! oggdemux name=d " + "d. ! queue ! theoraparse ! rtptheorapay name=pay0 " + "d. ! queue ! vorbisparse ! rtpvorbispay name=pay1 " + ")", argv[1]); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, str); + g_free (str); + + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mapping); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + /* start serving */ + g_main_loop_run (loop); + + return 0; +} diff --git a/examples/main.c b/examples/test-video.c similarity index 97% rename from examples/main.c rename to examples/test-video.c index 3e00d41f0e..b03bc6ca3d 100644 --- a/examples/main.c +++ b/examples/test-video.c @@ -47,10 +47,11 @@ main (int argc, char *argv[]) factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, "( " "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " - "x264enc bitrate=300 ! rtph264pay name=pay0 pt=96 " + "ffenc_h263 ! rtph263pay name=pay0 pt=96 " "audiotestsrc ! audio/x-raw-int,rate=8000 ! " "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); + /* attach the test factory to the /test url */ gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 54ba251e56..68fa7fa662 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -4,6 +4,7 @@ public_headers = \ rtsp-media.h \ rtsp-media-factory.h \ rtsp-media-mapping.h \ + rtsp-sdp.h \ rtsp-session-pool.h \ rtsp-session.h @@ -13,6 +14,7 @@ c_sources = \ rtsp-media.c \ rtsp-media-factory.c \ rtsp-media-mapping.c \ + rtsp-sdp.c \ rtsp-session-pool.c \ rtsp-session.c diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4d518fe9b0..56d9320181 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -19,9 +19,8 @@ #include -#include - #include "rtsp-client.h" +#include "rtsp-sdp.h" #undef DEBUG @@ -65,6 +64,16 @@ gst_rtsp_client_new (void) return result; } +static void +handle_response (GstRTSPClient *client, GstRTSPMessage *response) +{ +#ifdef DEBUG + gst_rtsp_message_dump (response); +#endif + + gst_rtsp_connection_send (client->connection, response, NULL); +} + static void handle_generic_response (GstRTSPClient *client, GstRTSPStatusCode code, GstRTSPMessage *request) @@ -74,36 +83,101 @@ handle_generic_response (GstRTSPClient *client, GstRTSPStatusCode code, gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); - gst_rtsp_connection_send (client->connection, &response, NULL); + handle_response (client, &response); } -static gboolean -handle_teardown_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +static GstRTSPMedia * +find_media (GstRTSPClient *client, const GstRTSPUrl *uri, GstRTSPMessage *request) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + + /* find the factory for the uri first */ + if (!(factory = gst_rtsp_media_mapping_find_factory (client->media_mapping, uri))) + goto no_factory; + + /* prepare the media and add it to the pipeline */ + if (!(media = gst_rtsp_media_factory_construct (factory, uri))) + goto no_media; + + /* prepare the media */ + if (!(gst_rtsp_media_prepare (media))) + goto no_prepare; + + return media; + + /* ERRORS */ +no_factory: + { + handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + return NULL; + } +no_media: + { + handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + g_object_unref (factory); + return NULL; + } +no_prepare: + { + handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + g_object_unref (media); + g_object_unref (factory); + return NULL; + } +} + +/* Get the session or NULL when there was no session */ +static GstRTSPSession * +ensure_session (GstRTSPClient *client, GstRTSPMessage *request) { GstRTSPResult res; - GstRTSPSessionMedia *media; GstRTSPSession *session; gchar *sessid; - GstRTSPMessage response = { 0 }; - GstRTSPStatusCode code; res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); if (res == GST_RTSP_OK) { /* we had a session in the request, find it again */ - if (!(session = gst_rtsp_session_pool_find (client->pool, sessid))) + if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid))) goto session_not_found; } else goto service_unavailable; + return session; + + /* ERRORS */ +session_not_found: + { + handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + return NULL; + } +service_unavailable: + { + handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + return NULL; + } +} + +static gboolean +handle_teardown_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +{ + GstRTSPSessionMedia *media; + GstRTSPSession *session; + GstRTSPMessage response = { 0 }; + GstRTSPStatusCode code; + + if (!(session = ensure_session (client, request))) + goto no_session; + /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, uri, client->factory); + media = gst_rtsp_session_get_media (session, uri); if (!media) goto not_found; gst_rtsp_session_media_stop (media); - gst_rtsp_session_pool_remove (client->pool, session); + gst_rtsp_session_pool_remove (client->session_pool, session); g_object_unref (session); /* remove the session id from the request, which will also remove it from the @@ -114,19 +188,14 @@ handle_teardown_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); - gst_rtsp_connection_send (client->connection, &response, NULL); + handle_response (client, &response); return FALSE; /* ERRORS */ -session_not_found: +no_session: { - handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); - return FALSE; - } -service_unavailable: - { - handle_generic_response (client, GST_RTSP_STS_OK, request); + /* error was sent already */ return FALSE; } not_found: @@ -139,24 +208,16 @@ not_found: static gboolean handle_pause_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { - GstRTSPResult res; GstRTSPSessionMedia *media; GstRTSPSession *session; - gchar *sessid; GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; - res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); - if (res == GST_RTSP_OK) { - /* we had a session in the request, find it again */ - if (!(session = gst_rtsp_session_pool_find (client->pool, sessid))) - goto session_not_found; - } - else - goto service_unavailable; + if (!(session = ensure_session (client, request))) + goto no_session; /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, uri, client->factory); + media = gst_rtsp_session_get_media (session, uri); if (!media) goto not_found; @@ -167,17 +228,12 @@ handle_pause_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *r code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); - gst_rtsp_connection_send (client->connection, &response, NULL); + handle_response (client, &response); return FALSE; /* ERRORS */ -session_not_found: - { - handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); - return FALSE; - } -service_unavailable: +no_session: { return FALSE; } @@ -191,48 +247,25 @@ not_found: static gboolean handle_play_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { - GstRTSPResult res; GstRTSPSessionMedia *media; GstRTSPSession *session; - gchar *sessid; GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; - GstStateChangeReturn ret; GString *rtpinfo; guint n_streams, i; guint timestamp, seqnum; - res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); - if (res == GST_RTSP_OK) { - /* we had a session in the request, find it again */ - if (!(session = gst_rtsp_session_pool_find (client->pool, sessid))) - goto session_not_found; - } - else - goto service_unavailable; + if (!(session = ensure_session (client, request))) + goto no_session; /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, uri, client->factory); + media = gst_rtsp_session_get_media (session, uri); if (!media) goto not_found; - /* wait for paused to get the caps */ - ret = gst_rtsp_session_media_pause (media); - switch (ret) { - case GST_STATE_CHANGE_NO_PREROLL: - break; - case GST_STATE_CHANGE_SUCCESS: - break; - case GST_STATE_CHANGE_FAILURE: - goto service_unavailable; - case GST_STATE_CHANGE_ASYNC: - /* wait for paused state change to complete */ - ret = gst_element_get_state (media->pipeline, NULL, NULL, -1); - break; - } - /* grab RTPInfo from the payloaders now */ rtpinfo = g_string_new (""); + n_streams = gst_rtsp_media_n_streams (media->media); for (i = 0; i < n_streams; i++) { GstRTSPMediaStream *stream; @@ -259,7 +292,7 @@ handle_play_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re gst_rtsp_message_add_header (&response, GST_RTSP_HDR_RTP_INFO, rtpinfo->str); g_string_free (rtpinfo, TRUE); - gst_rtsp_connection_send (client->connection, &response, NULL); + handle_response (client, &response); /* start playing after sending the request */ gst_rtsp_session_media_play (media); @@ -268,14 +301,9 @@ handle_play_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re return FALSE; /* ERRORS */ -session_not_found: +no_session: { - handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); - return FALSE; - } -service_unavailable: - { - handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + /* error was sent */ return FALSE; } not_found: @@ -321,16 +349,10 @@ handle_setup_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *r if (sscanf (pos, "%u", &streamid) != 1) goto bad_request; - /* find the media associated with the uri */ - if (client->factory == NULL) { - if ((client->factory = gst_rtsp_media_mapping_find_factory (client->mapping, uri)) == NULL) - goto not_found; - } - /* parse the transport */ res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_TRANSPORT, &transport, 0); if (res != GST_RTSP_OK) - goto unsupported_transports; + goto no_transport; transports = g_strsplit (transport, ",", 0); gst_rtsp_transport_new (&ct); @@ -348,9 +370,11 @@ handle_setup_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *r } g_strfreev (transports); + g_free (ct->destination); + ct->destination = g_strdup (inet_ntoa (client->address.sin_addr)); + /* we have not found anything usable, error out */ if (!have_transport) { - gst_rtsp_transport_free (ct); goto unsupported_transports; } @@ -369,28 +393,36 @@ handle_setup_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *r res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); if (res == GST_RTSP_OK) { /* we had a session in the request, find it again */ - if (!(session = gst_rtsp_session_pool_find (client->pool, sessid))) + if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid))) goto session_not_found; need_session = FALSE; } else { /* create a session if this fails we probably reached our session limit or * something. */ - if (!(session = gst_rtsp_session_pool_create (client->pool))) + if (!(session = gst_rtsp_session_pool_create (client->session_pool))) goto service_unavailable; need_session = TRUE; } + if (need_session) { + GstRTSPMedia *m; + + /* get a handle to the configuration of the media in the session */ + if ((m = find_media (client, uri, request))) { + media = gst_rtsp_session_manage_media (session, uri, m); + } + } /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, uri, client->factory); - if (!media) + if (!(media = gst_rtsp_session_get_media (session, uri))) goto not_found; /* get a handle to the stream in the media */ - stream = gst_rtsp_session_media_get_stream (media, streamid); + if (!(stream = gst_rtsp_session_media_get_stream (media, streamid))) + goto no_stream; /* setup the server transport from the client transport */ - st = gst_rtsp_session_stream_set_transport (stream, inet_ntoa (client->address.sin_addr), ct); + st = gst_rtsp_session_stream_set_transport (stream, ct); /* serialize the server transport */ trans_str = gst_rtsp_transport_as_text (st); @@ -401,11 +433,12 @@ handle_setup_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *r if (need_session) gst_rtsp_message_add_header (&response, GST_RTSP_HDR_SESSION, session->sessionid); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str); g_free (trans_str); g_object_unref (session); - gst_rtsp_connection_send (client->connection, &response, NULL); + handle_response (client, &response); return TRUE; @@ -420,14 +453,25 @@ not_found: handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); return FALSE; } +no_stream: + { + handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + return FALSE; + } session_not_found: { handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); return FALSE; } +no_transport: + { + handle_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request); + return FALSE; + } unsupported_transports: { handle_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request); + gst_rtsp_transport_free (ct); return FALSE; } service_unavailable: @@ -444,13 +488,9 @@ handle_describe_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage GstRTSPMessage response = { 0 }; GstRTSPResult res; GstSDPMessage *sdp; - guint n_streams, i; - gchar *sdptext; - GstRTSPMediaFactory *factory; + guint i; + gchar *str; GstRTSPMedia *media; - GstElement *pipeline; - GstStateChangeReturn ret; - /* check what kind of format is accepted, we don't really do anything with it * and always return SDP for now. */ @@ -465,193 +505,42 @@ handle_describe_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage break; } - /* find the factory for the uri first */ - if (!(factory = gst_rtsp_media_mapping_find_factory (client->mapping, uri))) - goto no_factory; - - /* prepare the media and add it to the pipeline */ - if (!(media = gst_rtsp_media_factory_construct (factory, uri))) + /* find the media object for the uri */ + if (!(media = find_media (client, uri, request))) goto no_media; - /* create a pipeline to preroll the media */ - pipeline = gst_pipeline_new ("client-describe-pipeline"); - - gst_bin_add (GST_BIN_CAST (pipeline), media->element); - - /* link fakesink to all stream pads and set the pipeline to PLAYING */ - n_streams = gst_rtsp_media_n_streams (media); - for (i = 0; i < n_streams; i++) { - GstRTSPMediaStream *stream; - GstElement *sink; - GstPad *sinkpad; - GstPadLinkReturn lret; - - stream = gst_rtsp_media_get_stream (media, i); - - sink = gst_element_factory_make ("fakesink", NULL); - gst_bin_add (GST_BIN (pipeline), sink); - - sinkpad = gst_element_get_static_pad (sink, "sink"); - lret = gst_pad_link (stream->srcpad, sinkpad); - if (lret != GST_PAD_LINK_OK) { - g_warning ("failed to link pad to sink: %d", lret); - } - gst_object_unref (sinkpad); - } - - /* now play and wait till we get the pads blocked. At that time the pipeline - * is prerolled and we have the caps on the streams too. */ - ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); - if (ret == GST_STATE_CHANGE_FAILURE) - goto cant_play; - - /* wait for state change to complete */ - gst_element_get_state (pipeline, NULL, NULL, -1); - - /* we should now be able to construct the SDP message */ - gst_sdp_message_new (&sdp); - - /* some standard things first */ - gst_sdp_message_set_version (sdp, "0"); - gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", "IP4", "127.0.0.1"); - gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer"); - gst_sdp_message_set_information (sdp, "rtsp-server"); - gst_sdp_message_add_time (sdp, "0", "0", NULL); - gst_sdp_message_add_attribute (sdp, "tool", "GStreamer"); - gst_sdp_message_add_attribute (sdp, "type", "broadcast"); - - for (i = 0; i < n_streams; i++) { - GstRTSPMediaStream *stream; - GstSDPMedia *smedia; - GstStructure *s; - const gchar *caps_str, *caps_enc, *caps_params; - gchar *tmp; - gint caps_pt, caps_rate; - guint n_fields, j; - gboolean first; - GString *fmtp; - - stream = gst_rtsp_media_get_stream (media, i); - gst_sdp_media_new (&smedia); - - s = gst_caps_get_structure (stream->caps, 0); - - /* get media type and payload for the m= line */ - caps_str = gst_structure_get_string (s, "media"); - gst_sdp_media_set_media (smedia, caps_str); - - gst_structure_get_int (s, "payload", &caps_pt); - tmp = g_strdup_printf ("%d", caps_pt); - gst_sdp_media_add_format (smedia, tmp); - g_free (tmp); - - gst_sdp_media_set_port_info (smedia, 0, 1); - gst_sdp_media_set_proto (smedia, "RTP/AVP"); - - /* for the c= line */ - gst_sdp_media_add_connection (smedia, "IN", "IP4", "127.0.0.1", 0, 0); - - /* get clock-rate, media type and params for the rtpmap attribute */ - gst_structure_get_int (s, "clock-rate", &caps_rate); - caps_enc = gst_structure_get_string (s, "encoding-name"); - caps_params = gst_structure_get_string (s, "encoding-params"); - - if (caps_params) - tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate, - caps_params); - else - tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate); - - gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); - g_free (tmp); - - /* the config uri */ - tmp = g_strdup_printf ("stream=%d", i); - gst_sdp_media_add_attribute (smedia, "control", tmp); - g_free (tmp); - - /* collect all other properties and add them to fmtp */ - fmtp = g_string_new (""); - g_string_append_printf (fmtp, "%d ", caps_pt); - first = TRUE; - n_fields = gst_structure_n_fields (s); - for (j = 0; j < n_fields; j++) { - const gchar *fname, *fval; - - fname = gst_structure_nth_field_name (s, j); - - /* filter out standard properties */ - if (!strcmp (fname, "media")) - continue; - if (!strcmp (fname, "payload")) - continue; - if (!strcmp (fname, "clock-rate")) - continue; - if (!strcmp (fname, "encoding-name")) - continue; - if (!strcmp (fname, "encoding-params")) - continue; - if (!strcmp (fname, "ssrc")) - continue; - if (!strcmp (fname, "clock-base")) - continue; - if (!strcmp (fname, "seqnum-base")) - continue; - - if ((fval = gst_structure_get_string (s, fname))) { - g_string_append_printf (fmtp, "%s%s=%s", first ? "":";", fname, fval); - first = FALSE; - } - } - if (!first) { - tmp = g_string_free (fmtp, FALSE); - gst_sdp_media_add_attribute (smedia, "fmtp", tmp); - g_free (tmp); - } - else { - g_string_free (fmtp, TRUE); - } - gst_sdp_message_add_media (sdp, smedia); - } - /* go back to NULL */ - gst_element_set_state (pipeline, GST_STATE_NULL); - - g_object_unref (factory); - - gst_object_unref (pipeline); - pipeline = NULL; + /* create an SDP for the media object */ + if (!(sdp = gst_rtsp_sdp_from_media (media))) + goto no_sdp; gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE, "application/sdp"); + str = g_strdup_printf ("rtsp://%s:%u%s/", uri->host, uri->port, uri->abspath); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_BASE, str); + g_free (str); + /* add SDP to the response body */ - sdptext = gst_sdp_message_as_text (sdp); - gst_rtsp_message_take_body (&response, (guint8 *)sdptext, strlen (sdptext)); + str = gst_sdp_message_as_text (sdp); + gst_rtsp_message_take_body (&response, (guint8 *)str, strlen (str)); gst_sdp_message_free (sdp); - gst_rtsp_connection_send (client->connection, &response, NULL); + handle_response (client, &response); return TRUE; /* ERRORS */ -no_factory: - { - handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); - return FALSE; - } no_media: { - handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); - g_object_unref (factory); + /* error reply is already sent */ return FALSE; } -cant_play: +no_sdp: { handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); - gst_object_unref (pipeline); - g_object_unref (factory); + g_object_unref (media); return FALSE; } } @@ -661,7 +550,7 @@ handle_options_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage { GstRTSPMessage response = { 0 }; GstRTSPMethod options; - GString *str; + gchar *str; options = GST_RTSP_DESCRIBE | GST_RTSP_OPTIONS | @@ -670,38 +559,42 @@ handle_options_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage GST_RTSP_SETUP | GST_RTSP_TEARDOWN; - /* always return options.. */ - str = g_string_new ("OPTIONS"); - - if (options & GST_RTSP_DESCRIBE) - g_string_append (str, ", DESCRIBE"); - if (options & GST_RTSP_ANNOUNCE) - g_string_append (str, ", ANNOUNCE"); - if (options & GST_RTSP_GET_PARAMETER) - g_string_append (str, ", GET_PARAMETER"); - if (options & GST_RTSP_PAUSE) - g_string_append (str, ", PAUSE"); - if (options & GST_RTSP_PLAY) - g_string_append (str, ", PLAY"); - if (options & GST_RTSP_RECORD) - g_string_append (str, ", RECORD"); - if (options & GST_RTSP_REDIRECT) - g_string_append (str, ", REDIRECT"); - if (options & GST_RTSP_SETUP) - g_string_append (str, ", SETUP"); - if (options & GST_RTSP_SET_PARAMETER) - g_string_append (str, ", SET_PARAMETER"); - if (options & GST_RTSP_TEARDOWN) - g_string_append (str, ", TEARDOWN"); + str = gst_rtsp_options_as_text (options); gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str->str); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str); + g_free (str); - g_string_free (str, TRUE); + handle_response (client, &response); +} - gst_rtsp_connection_send (client->connection, &response, NULL); +/* remove duplicate and trailing '/' */ +static void +santize_uri (GstRTSPUrl *uri) +{ + gint i, len; + gchar *s, *d; + gboolean have_slash, prev_slash; + + s = d = uri->abspath; + len = strlen (uri->abspath); + + prev_slash = FALSE; + + for (i = 0; i < len; i++) { + have_slash = s[i] == '/'; + *d = s[i]; + if (!have_slash || !prev_slash) + d++; + prev_slash = have_slash; + } + len = d - uri->abspath; + /* don't remove the first slash if that's the only thing left */ + if (len > 1 && *(d-1) == '/') + d--; + *d = '\0'; } /* this function runs in a client specific thread and handles all rtsp messages @@ -740,6 +633,9 @@ handle_client (GstRTSPClient *client) continue; } + /* sanitize the uri */ + santize_uri (uri); + /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: @@ -845,11 +741,11 @@ gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *poo { GstRTSPSessionPool *old; - old = client->pool; + old = client->session_pool; if (old != pool) { if (pool) g_object_ref (pool); - client->pool = pool; + client->session_pool = pool; if (old) g_object_unref (old); } @@ -868,7 +764,7 @@ gst_rtsp_client_get_session_pool (GstRTSPClient *client) { GstRTSPSessionPool *result; - if ((result = client->pool)) + if ((result = client->session_pool)) g_object_ref (result); return result; @@ -888,12 +784,12 @@ gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *m { GstRTSPMediaMapping *old; - old = client->mapping; + old = client->media_mapping; if (old != mapping) { if (mapping) g_object_ref (mapping); - client->mapping = mapping; + client->media_mapping = mapping; if (old) g_object_unref (old); } @@ -912,13 +808,12 @@ gst_rtsp_client_get_media_mapping (GstRTSPClient *client) { GstRTSPMediaMapping *result; - if ((result = client->mapping)) + if ((result = client->media_mapping)) g_object_ref (result); return result; } - /** * gst_rtsp_client_attach: * @client: a #GstRTSPClient diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 11a375c0d5..504fd1da89 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -73,10 +73,8 @@ struct _GstRTSPClient { struct sockaddr_in address; GThread *thread; - GstRTSPSessionPool *pool; - - GstRTSPMediaFactory *factory; - GstRTSPMediaMapping *mapping; + GstRTSPSessionPool *session_pool; + GstRTSPMediaMapping *media_mapping; }; struct _GstRTSPClientClass { diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index f9df9019c1..c927175749 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -210,15 +210,6 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl return res; } -static void -caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) -{ - if (stream->caps) - gst_caps_unref (stream->caps); - if ((stream->caps = GST_PAD_CAPS (pad))) - gst_caps_ref (stream->caps); -} - static GstElement * default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) { @@ -276,12 +267,13 @@ default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) if (element == NULL) goto no_element; - media = g_object_new (GST_TYPE_RTSP_MEDIA, NULL); + /* create a new empty media */ + media = gst_rtsp_media_new (); media->element = element; /* try to find all the payloader elements, they should be named 'pay%d'. for - * each of the payloaders we will create a stream, collect the source pad and - * add a notify::caps on the pad. */ + * each of the payloaders we will create a stream and collect the source pad. + */ for (i = 0; ; i++) { gchar *name; @@ -297,7 +289,6 @@ default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) /* create the stream */ stream = g_new0 (GstRTSPMediaStream, 1); stream->media = media; - stream->element = element; stream->payloader = pay; stream->idx = media->streams->len; @@ -305,16 +296,12 @@ default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) /* ghost the pad of the payloader to the element */ stream->srcpad = gst_ghost_pad_new (name, pad); - gst_element_add_pad (stream->element, stream->srcpad); - - stream->caps_sig = g_signal_connect (pad, "notify::caps", (GCallback) caps_notify, stream); - gst_object_unref (pad); + gst_element_add_pad (media->element, stream->srcpad); + gst_object_unref (pay); + g_free (name); /* add stream now */ g_array_append_val (media->streams, stream); - gst_object_unref (pay); - - g_free (name); } return media; diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 4c90ac75f1..472d325585 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -56,22 +56,27 @@ struct _GstRTSPMediaFactory { /** * GstRTSPMediaFactoryClass: - * @get_element: Construct an return a #GstElement thast is a #GstBin containing - * the pipeline to use for the media. The bin should contain elements - * pay%d for each stream. The default implementation of this functions - * returns the bin created from the launch parameter. * @construct: the vmethod that will be called when the factory has to create the * #GstRTSPMedia for @url. The default implementation of this * function calls get_element to retrieve an element and then looks for * pay%d to create the streams. - + * @handle_message: Handle a bus message for @media created from @factory. + * @get_element: Construct an return a #GstElement thast is a #GstBin containing + * the pipeline to use for the media. The bin should contain elements + * pay%d for each stream. The default implementation of this functions + * returns the bin created from the launch parameter. + * * the #GstRTSPMediaFactory class structure. */ struct _GstRTSPMediaFactoryClass { GObjectClass parent_class; - GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); - GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + void (*handle_message) (GstRTSPMediaFactory *factory, GstRTSPMedia *media, + GstMessage *message); + + GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + }; GType gst_rtsp_media_factory_get_type (void); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 9447675267..2dc2c8c645 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -64,6 +64,26 @@ gst_rtsp_media_finalize (GObject * obj) G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); } +/** + * gst_rtsp_media_new: + * + * Create a new #GstRTSPMedia instance. The #GstRTSPMedia object contains the + * element to produde RTP data for one or more related (audio/video/..) + * streams. + * + * Returns: a new #GstRTSPMedia object. + */ +GstRTSPMedia * +gst_rtsp_media_new (void) +{ + GstRTSPMedia *result; + + result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL); + + return result; +} + + /** * gst_rtsp_media_n_streams: * @media: a #GstRTSPMedia @@ -102,3 +122,418 @@ gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx) return res; } +/* Allocate the udp ports and sockets */ +static gboolean +alloc_udp_ports (GstRTSPMediaStream * stream) +{ + GstStateChangeReturn ret; + GstElement *udpsrc0, *udpsrc1; + GstElement *udpsink0, *udpsink1; + gint tmp_rtp, tmp_rtcp; + guint count; + gint rtpport, rtcpport, sockfd; + + udpsrc0 = NULL; + udpsrc1 = NULL; + udpsink0 = NULL; + udpsink1 = NULL; + count = 0; + + /* Start with random port */ + tmp_rtp = 0; + + /* try to allocate 2 UDP ports, the RTP port should be an even + * number and the RTCP port should be the next (uneven) port */ +again: + udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL); + if (udpsrc0 == NULL) + goto no_udp_protocol; + g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL); + + ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED); + if (ret == GST_STATE_CHANGE_FAILURE) { + if (tmp_rtp != 0) { + tmp_rtp += 2; + if (++count > 20) + goto no_ports; + + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + + goto again; + } + goto no_udp_protocol; + } + + g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); + + /* check if port is even */ + if ((tmp_rtp & 1) != 0) { + /* port not even, close and allocate another */ + if (++count > 20) + goto no_ports; + + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + + tmp_rtp++; + goto again; + } + + /* allocate port+1 for RTCP now */ + udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL); + if (udpsrc1 == NULL) + goto no_udp_rtcp_protocol; + + /* set port */ + tmp_rtcp = tmp_rtp + 1; + g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL); + + ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED); + /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */ + if (ret == GST_STATE_CHANGE_FAILURE) { + + if (++count > 20) + goto no_ports; + + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + + gst_element_set_state (udpsrc1, GST_STATE_NULL); + gst_object_unref (udpsrc1); + + tmp_rtp += 2; + goto again; + } + + /* all fine, do port check */ + g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL); + g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL); + + /* this should not happen... */ + if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) + goto port_error; + + udpsink0 = gst_element_factory_make ("multiudpsink", NULL); + if (!udpsink0) + goto no_udp_protocol; + + g_object_get (G_OBJECT (udpsrc0), "sock", &sockfd, NULL); + g_object_set (G_OBJECT (udpsink0), "sockfd", sockfd, NULL); + g_object_set (G_OBJECT (udpsink0), "closefd", FALSE, NULL); + + udpsink1 = gst_element_factory_make ("multiudpsink", NULL); + if (!udpsink1) + goto no_udp_protocol; + + g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL); + g_object_set (G_OBJECT (udpsink1), "sockfd", sockfd, NULL); + g_object_set (G_OBJECT (udpsink1), "closefd", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); + + /* we keep these elements, we configure all in configure_transport when the + * server told us to really use the UDP ports. */ + stream->udpsrc[0] = gst_object_ref (udpsrc0); + stream->udpsrc[1] = gst_object_ref (udpsrc1); + stream->udpsink[0] = gst_object_ref (udpsink0); + stream->udpsink[1] = gst_object_ref (udpsink1); + stream->server_port.min = rtpport; + stream->server_port.max = rtcpport; + + /* they are ours now */ + gst_object_sink (udpsrc0); + gst_object_sink (udpsrc1); + gst_object_sink (udpsink0); + gst_object_sink (udpsink1); + + return TRUE; + + /* ERRORS */ +no_udp_protocol: + { + goto cleanup; + } +no_ports: + { + goto cleanup; + } +no_udp_rtcp_protocol: + { + goto cleanup; + } +port_error: + { + goto cleanup; + } +cleanup: + { + if (udpsrc0) { + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + } + if (udpsrc1) { + gst_element_set_state (udpsrc1, GST_STATE_NULL); + gst_object_unref (udpsrc1); + } + if (udpsink0) { + gst_element_set_state (udpsink0, GST_STATE_NULL); + gst_object_unref (udpsink0); + } + if (udpsink1) { + gst_element_set_state (udpsink1, GST_STATE_NULL); + gst_object_unref (udpsink1); + } + return FALSE; + } +} + +static void +caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) +{ + gchar *capsstr; + + if (stream->caps) + gst_caps_unref (stream->caps); + if ((stream->caps = GST_PAD_CAPS (pad))) + gst_caps_ref (stream->caps); + + capsstr = gst_caps_to_string (stream->caps); + g_message ("stream %p received caps %s", stream, capsstr); + g_free (capsstr); +} + +/* prepare the pipeline objects to handle @stream in @media */ +static gboolean +setup_stream (GstRTSPMediaStream *stream, GstRTSPMedia *media) +{ + gchar *name; + GstPad *pad; + + alloc_udp_ports (stream); + + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsink[0]); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsink[1]); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsrc[1]); + + /* hook up the stream to the RTP session elements. */ + name = g_strdup_printf ("send_rtp_sink_%d", stream->idx); + stream->send_rtp_sink = gst_element_get_request_pad (media->rtpbin, name); + g_free (name); + name = g_strdup_printf ("send_rtp_src_%d", stream->idx); + stream->send_rtp_src = gst_element_get_static_pad (media->rtpbin, name); + g_free (name); + name = g_strdup_printf ("send_rtcp_src_%d", stream->idx); + stream->send_rtcp_src = gst_element_get_request_pad (media->rtpbin, name); + g_free (name); + name = g_strdup_printf ("recv_rtcp_sink_%d", stream->idx); + stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name); + g_free (name); + + /* link the RTP pad to the session manager */ + gst_pad_link (stream->srcpad, stream->send_rtp_sink); + + /* link udp elements */ + pad = gst_element_get_static_pad (stream->udpsink[0], "sink"); + gst_pad_link (stream->send_rtp_src, pad); + gst_object_unref (pad); + pad = gst_element_get_static_pad (stream->udpsink[1], "sink"); + gst_pad_link (stream->send_rtcp_src, pad); + gst_object_unref (pad); + pad = gst_element_get_static_pad (stream->udpsrc[1], "src"); + gst_pad_link (pad, stream->recv_rtcp_sink); + gst_object_unref (pad); + + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values */ + gst_element_set_state (stream->udpsrc[0], GST_STATE_PLAYING); + gst_element_set_state (stream->udpsrc[1], GST_STATE_PLAYING); + gst_element_set_locked_state (stream->udpsrc[0], TRUE); + gst_element_set_locked_state (stream->udpsrc[1], TRUE); + + /* be notified of caps changes */ + stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps", + (GCallback) caps_notify, stream); + + stream->prepared = TRUE; + + return TRUE; +} + + +/** + * gst_rtsp_media_prepare: + * @obj: a #GstRTSPMedia + * + * Prepare @media for streaming. This function will create the pipeline and + * other objects to manage the streaming. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_media_prepare (GstRTSPMedia *media) +{ + GstStateChangeReturn ret; + guint i, n_streams; + + if (media->prepared) + goto was_prepared; + + media->pipeline = gst_pipeline_new ("media-pipeline"); + + gst_bin_add (GST_BIN_CAST (media->pipeline), media->element); + + media->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin"); + + /* add stuf to the bin */ + gst_bin_add (GST_BIN (media->pipeline), media->rtpbin); + + ret = gst_element_set_state (media->pipeline, GST_STATE_READY); + + n_streams = gst_rtsp_media_n_streams (media); + for (i = 0; i < n_streams; i++) { + GstRTSPMediaStream *stream; + + stream = gst_rtsp_media_get_stream (media, i); + + setup_stream (stream, media); + } + + /* first go to PAUSED */ + ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); + + switch (ret) { + case GST_STATE_CHANGE_SUCCESS: + break; + case GST_STATE_CHANGE_ASYNC: + break; + case GST_STATE_CHANGE_NO_PREROLL: + /* we need to go to PLAYING */ + g_message ("live media %p", media); + ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); + break; + case GST_STATE_CHANGE_FAILURE: + goto state_failed; + } + + /* no wait for all pads to be prerolled */ + ret = gst_element_get_state (media->pipeline, NULL, NULL, -1); + + /* and back to PAUSED for live pipelines */ + ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); + + g_message ("object %p is prerolled", media); + media->prepared = TRUE; + + return TRUE; + + /* OK */ +was_prepared: + { + return TRUE; + } + /* ERRORS */ +state_failed: + { + g_message ("state change failed for media %p", media); + return FALSE; + } +} + +gboolean +gst_rtsp_media_stream_add (GstRTSPMediaStream *stream, GstRTSPTransport *ct) +{ + g_return_val_if_fail (stream != NULL, FALSE); + g_return_val_if_fail (ct != NULL, FALSE); + g_return_val_if_fail (stream->prepared, FALSE); + + g_message ("adding %s:%d", ct->destination, ct->client_port.min); + + g_signal_emit_by_name (stream->udpsink[0], "add", ct->destination, ct->client_port.min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "add", ct->destination, ct->client_port.max, NULL); + + return TRUE; +} + +gboolean +gst_rtsp_media_stream_remove (GstRTSPMediaStream *stream, GstRTSPTransport *ct) +{ + g_return_val_if_fail (stream != NULL, FALSE); + g_return_val_if_fail (ct != NULL, FALSE); + g_return_val_if_fail (stream->prepared, FALSE); + + g_message ("removing %s:%d", ct->destination, ct->client_port.min); + + g_signal_emit_by_name (stream->udpsink[0], "remove", ct->destination, ct->client_port.min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "remove", ct->destination, ct->client_port.max, NULL); + + return TRUE; +} + +/** + * gst_rtsp_media_play: + * @media: a #GstRTSPMedia + * + * Tell the @media to start playing and streaming to the client. + * + * Returns: a #GstStateChangeReturn + */ +GstStateChangeReturn +gst_rtsp_media_play (GstRTSPMedia *media) +{ + GstStateChangeReturn ret; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_STATE_CHANGE_FAILURE); + g_return_val_if_fail (media->prepared, GST_STATE_CHANGE_FAILURE); + + g_message ("playing"); + ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); + + return ret; +} + +/** + * gst_rtsp_media_pause: + * @media: a #GstRTSPMedia + * + * Tell the @media to pause. + * + * Returns: a #GstStateChangeReturn + */ +GstStateChangeReturn +gst_rtsp_media_pause (GstRTSPMedia *media) +{ + GstStateChangeReturn ret; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_STATE_CHANGE_FAILURE); + g_return_val_if_fail (media->prepared, GST_STATE_CHANGE_FAILURE); + + g_message ("paused"); + ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); + + return ret; +} + +/** + * gst_rtsp_media_stop: + * @media: a #GstRTSPMedia + * + * Tell the @media to stop playing. After this call the media + * cannot be played or paused anymore + * + * Returns: a #GstStateChangeReturn + */ +GstStateChangeReturn +gst_rtsp_media_stop (GstRTSPMedia *media) +{ + GstStateChangeReturn ret; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_STATE_CHANGE_FAILURE); + g_return_val_if_fail (media->prepared, GST_STATE_CHANGE_FAILURE); + + g_message ("stop"); + ret = gst_element_set_state (media->pipeline, GST_STATE_NULL); + + return ret; +} + diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 17fa4eeef1..6fc0dc1460 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -42,10 +42,18 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass; /** * GstRTSPMediaStream: * + * @media: the owner #GstRTSPMedia * @idx: the stream index - * @element: the toplevel element * @srcpad: the srcpad of the stream * @payloader: the payloader of the format + * @prepared: if the stream is prepared for streaming + * @server_port: the server udp ports + * @recv_rtp_sink: sinkpad for RTP buffers + * @recv_rtcp_sink: sinkpad for RTCP buffers + * @recv_rtp_src: srcpad for RTP buffers + * @recv_rtcp_src: srcpad for RTCP buffers + * @udpsrc: the udp source elements for RTP/RTCP + * @udpsink: the udp sink elements for RTP/RTCP * @caps_sig: the signal id for detecting caps * @caps: the caps of the stream * @@ -54,18 +62,38 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass; struct _GstRTSPMediaStream { GstRTSPMedia *media; - guint idx; + guint idx; - GstElement *element; - GstPad *srcpad; - GstElement *payloader; - gulong caps_sig; - GstCaps *caps; + GstPad *srcpad; + GstElement *payloader; + gboolean prepared; + + GstRTSPRange server_port; + + /* pads on the rtpbin */ + GstPad *recv_rtcp_sink; + GstPad *send_rtp_sink; + GstPad *send_rtp_src; + GstPad *send_rtcp_src; + + /* sinks used for sending and receiving RTP and RTCP, they share + * sockets */ + GstElement *udpsrc[2]; + GstElement *udpsink[2]; + + /* the caps of the stream */ + gulong caps_sig; + GstCaps *caps; }; /** * GstRTSPMedia: - * @media: the owner #GstRTSPMedia + * @element: the data providing element + * @stream: the different streams provided by @element + * @prepared: if the media is prepared for streaming + * @pipeline: the toplevel pipeline + * @rtpbin: the rtpbin + * @multifdsink: multifdsink element for TCP transport * * A class that contains the GStreamer element along with a list of * #GstRTSPediaStream objects that can produce data. @@ -77,6 +105,16 @@ struct _GstRTSPMedia { GstElement *element; GArray *streams; + gboolean prepared; + + /* the pipeline for the media */ + GstElement *pipeline; + + /* RTP session manager */ + GstElement *rtpbin; + + /* for TCP transport */ + GstElement *multifdsink; }; struct _GstRTSPMediaClass { @@ -85,10 +123,24 @@ struct _GstRTSPMediaClass { GType gst_rtsp_media_get_type (void); +/* creating the media */ +GstRTSPMedia * gst_rtsp_media_new (void); + /* dealing with the media */ guint gst_rtsp_media_n_streams (GstRTSPMedia *media); GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); +/* prepare the media for playback */ +gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); + +/* add destinations to a stream */ +gboolean gst_rtsp_media_stream_add (GstRTSPMediaStream *stream, GstRTSPTransport *ct); +gboolean gst_rtsp_media_stream_remove (GstRTSPMediaStream *stream, GstRTSPTransport *ct); + +GstStateChangeReturn gst_rtsp_media_play (GstRTSPMedia *media); +GstStateChangeReturn gst_rtsp_media_pause (GstRTSPMedia *media); +GstStateChangeReturn gst_rtsp_media_stop (GstRTSPMedia *media); + G_END_DECLS #endif /* __GST_RTSP_MEDIA_H__ */ diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c new file mode 100644 index 0000000000..4a53b65769 --- /dev/null +++ b/gst/rtsp-server/rtsp-sdp.c @@ -0,0 +1,145 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include + +#include "rtsp-sdp.h" + +/** + * gst_rtsp_sdp_from_media: + * @media: a #GstRTSPMedia + * + * Create a new sdp message for @media. + * + * Returns: a new sdp message for @media. gst_sdp_message_free() after usage. + */ +GstSDPMessage * +gst_rtsp_sdp_from_media (GstRTSPMedia *media) +{ + GstSDPMessage *sdp; + guint i, n_streams; + + n_streams = gst_rtsp_media_n_streams (media); + + gst_sdp_message_new (&sdp); + + /* some standard things first */ + gst_sdp_message_set_version (sdp, "0"); + gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", "IP4", "127.0.0.1"); + gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer"); + gst_sdp_message_set_information (sdp, "rtsp-server"); + gst_sdp_message_add_time (sdp, "0", "0", NULL); + gst_sdp_message_add_attribute (sdp, "tool", "GStreamer"); + gst_sdp_message_add_attribute (sdp, "type", "broadcast"); + + for (i = 0; i < n_streams; i++) { + GstRTSPMediaStream *stream; + GstSDPMedia *smedia; + GstStructure *s; + const gchar *caps_str, *caps_enc, *caps_params; + gchar *tmp; + gint caps_pt, caps_rate; + guint n_fields, j; + gboolean first; + GString *fmtp; + + stream = gst_rtsp_media_get_stream (media, i); + gst_sdp_media_new (&smedia); + + s = gst_caps_get_structure (stream->caps, 0); + + /* get media type and payload for the m= line */ + caps_str = gst_structure_get_string (s, "media"); + gst_sdp_media_set_media (smedia, caps_str); + + gst_structure_get_int (s, "payload", &caps_pt); + tmp = g_strdup_printf ("%d", caps_pt); + gst_sdp_media_add_format (smedia, tmp); + g_free (tmp); + + gst_sdp_media_set_port_info (smedia, 0, 1); + gst_sdp_media_set_proto (smedia, "RTP/AVP"); + + /* for the c= line */ + gst_sdp_media_add_connection (smedia, "IN", "IP4", "127.0.0.1", 0, 0); + + /* get clock-rate, media type and params for the rtpmap attribute */ + gst_structure_get_int (s, "clock-rate", &caps_rate); + caps_enc = gst_structure_get_string (s, "encoding-name"); + caps_params = gst_structure_get_string (s, "encoding-params"); + + if (caps_params) + tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate, + caps_params); + else + tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate); + + gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); + g_free (tmp); + + /* the config uri */ + tmp = g_strdup_printf ("stream=%d", i); + gst_sdp_media_add_attribute (smedia, "control", tmp); + g_free (tmp); + + /* collect all other properties and add them to fmtp */ + fmtp = g_string_new (""); + g_string_append_printf (fmtp, "%d ", caps_pt); + first = TRUE; + n_fields = gst_structure_n_fields (s); + for (j = 0; j < n_fields; j++) { + const gchar *fname, *fval; + + fname = gst_structure_nth_field_name (s, j); + + /* filter out standard properties */ + if (!strcmp (fname, "media")) + continue; + if (!strcmp (fname, "payload")) + continue; + if (!strcmp (fname, "clock-rate")) + continue; + if (!strcmp (fname, "encoding-name")) + continue; + if (!strcmp (fname, "encoding-params")) + continue; + if (!strcmp (fname, "ssrc")) + continue; + if (!strcmp (fname, "clock-base")) + continue; + if (!strcmp (fname, "seqnum-base")) + continue; + + if ((fval = gst_structure_get_string (s, fname))) { + g_string_append_printf (fmtp, "%s%s=%s", first ? "":";", fname, fval); + first = FALSE; + } + } + if (!first) { + tmp = g_string_free (fmtp, FALSE); + gst_sdp_media_add_attribute (smedia, "fmtp", tmp); + g_free (tmp); + } + else { + g_string_free (fmtp, TRUE); + } + gst_sdp_message_add_media (sdp, smedia); + } + + return sdp; +} diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h new file mode 100644 index 0000000000..4016eda37c --- /dev/null +++ b/gst/rtsp-server/rtsp-sdp.h @@ -0,0 +1,35 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include "rtsp-media.h" + +#ifndef __GST_RTSP_SDP_H__ +#define __GST_RTSP_SDP_H__ + +G_BEGIN_DECLS + +/* creating SDP */ +GstSDPMessage * gst_rtsp_sdp_from_media (GstRTSPMedia *media); + +G_END_DECLS + +#endif /* __GST_RTSP_SDP_H__ */ diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index b34bc80a32..afbfe9243f 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -30,8 +30,8 @@ enum PROP_0, PROP_BACKLOG, PROP_PORT, - PROP_POOL, - PROP_MAPPING, + PROP_SESSION_POOL, + PROP_MEDIA_MAPPING, PROP_LAST }; @@ -78,23 +78,25 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) g_param_spec_int ("port", "Port", "The port the server uses to listen on", 1, 65535, DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRTSPServer::pool + * GstRTSPServer::session-pool * * The session pool of the server. By default each server has a separate * session pool but sessions can be shared between servers by setting the same * session pool on multiple servers. */ - g_object_class_install_property (gobject_class, PROP_POOL, - g_param_spec_object ("pool", "Pool", "The session pool to use for client session", + g_object_class_install_property (gobject_class, PROP_SESSION_POOL, + g_param_spec_object ("session-pool", "Session Pool", + "The session pool to use for client session", GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRTSPServer::mapping + * GstRTSPServer::media-mapping * * The media mapping to use for this server. By default the server has no * media mapping and thus cannot map urls to media streams. */ - g_object_class_install_property (gobject_class, PROP_MAPPING, - g_param_spec_object ("mapping", "Mapping", "The media mapping to use for client session", + g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING, + g_param_spec_object ("media-mapping", "Media Mapping", + "The media mapping to use for client session", GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); klass->accept_client = gst_rtsp_server_accept_client; @@ -105,8 +107,8 @@ gst_rtsp_server_init (GstRTSPServer * server) { server->server_port = DEFAULT_PORT; server->backlog = DEFAULT_BACKLOG; - server->pool = gst_rtsp_session_pool_new (); - server->mapping = gst_rtsp_media_mapping_new (); + server->session_pool = gst_rtsp_session_pool_new (); + server->media_mapping = gst_rtsp_media_mapping_new (); } /** @@ -207,12 +209,12 @@ gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *poo g_return_if_fail (GST_IS_RTSP_SERVER (server)); - old = server->pool; + old = server->session_pool; if (old != pool) { if (pool) g_object_ref (pool); - server->pool = pool; + server->session_pool = pool; if (old) g_object_unref (old); } @@ -235,7 +237,7 @@ gst_rtsp_server_get_session_pool (GstRTSPServer *server) g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - if ((result = server->pool)) + if ((result = server->session_pool)) g_object_ref (result); return result; @@ -255,12 +257,12 @@ gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *m g_return_if_fail (GST_IS_RTSP_SERVER (server)); - old = server->mapping; + old = server->media_mapping; if (old != mapping) { if (mapping) g_object_ref (mapping); - server->mapping = mapping; + server->media_mapping = mapping; if (old) g_object_unref (old); } @@ -283,7 +285,7 @@ gst_rtsp_server_get_media_mapping (GstRTSPServer *server) g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - if ((result = server->mapping)) + if ((result = server->media_mapping)) g_object_ref (result); return result; @@ -302,10 +304,10 @@ gst_rtsp_server_get_property (GObject *object, guint propid, case PROP_BACKLOG: g_value_set_int (value, gst_rtsp_server_get_backlog (server)); break; - case PROP_POOL: + case PROP_SESSION_POOL: g_value_take_object (value, gst_rtsp_server_get_session_pool (server)); break; - case PROP_MAPPING: + case PROP_MEDIA_MAPPING: g_value_take_object (value, gst_rtsp_server_get_media_mapping (server)); break; default: @@ -326,10 +328,10 @@ gst_rtsp_server_set_property (GObject *object, guint propid, case PROP_BACKLOG: gst_rtsp_server_set_backlog (server, g_value_get_int (value)); break; - case PROP_POOL: + case PROP_SESSION_POOL: gst_rtsp_server_set_session_pool (server, g_value_get_object (value)); break; - case PROP_MAPPING: + case PROP_MEDIA_MAPPING: gst_rtsp_server_set_media_mapping (server, g_value_get_object (value)); break; default: @@ -444,10 +446,10 @@ gst_rtsp_server_accept_client (GstRTSPServer *server, GIOChannel *channel) client = gst_rtsp_client_new (); /* set the session pool that this client should use */ - gst_rtsp_client_set_session_pool (client, server->pool); + gst_rtsp_client_set_session_pool (client, server->session_pool); /* set the session pool that this client should use */ - gst_rtsp_client_set_media_mapping (client, server->mapping); + gst_rtsp_client_set_media_mapping (client, server->media_mapping); /* accept connections for that client, this function returns after accepting * the connection and will run the remainder of the communication with the diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 277b8419d1..e719873a96 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -58,22 +58,21 @@ struct _GstRTSPServer { GObject parent; /* server information */ - gint server_port; - gint backlog; - gchar *host; - struct sockaddr_in server_sin; + gint server_port; + gint backlog; + gchar *host; + struct sockaddr_in server_sin; - /* socket */ - GstPollFD server_sock; - - GIOChannel *io_channel; - GSource *io_watch; + /* socket and channels */ + GstPollFD server_sock; + GIOChannel *io_channel; + GSource *io_watch; /* sessions on this server */ - GstRTSPSessionPool *pool; + GstRTSPSessionPool *session_pool; /* media mapper for this server */ - GstRTSPMediaMapping *mapping; + GstRTSPMediaMapping *media_mapping; }; /** diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index b59dee07d4..a5efc79235 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -16,6 +16,7 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ +#include #include "rtsp-session.h" @@ -45,12 +46,6 @@ gst_rtsp_session_free_stream (GstRTSPSessionStream *stream) { if (stream->client_trans) gst_rtsp_transport_free (stream->client_trans); - g_free (stream->destination); - if (stream->server_trans) - gst_rtsp_transport_free (stream->server_trans); - - if (stream->udpsrc[0]) - gst_object_unref (stream->udpsrc[0]); g_free (stream); } @@ -60,18 +55,11 @@ gst_rtsp_session_free_media (GstRTSPSessionMedia *media) { GList *walk; - gst_element_set_state (media->pipeline, GST_STATE_NULL); - - if (media->factory) - g_object_unref (media->factory); - for (walk = media->streams; walk; walk = g_list_next (walk)) { GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data; gst_rtsp_session_free_stream (stream); } - if (media->pipeline) - gst_object_unref (media->pipeline); g_list_free (media->streams); } @@ -95,61 +83,63 @@ gst_rtsp_session_finalize (GObject * obj) G_OBJECT_CLASS (gst_rtsp_session_parent_class)->finalize (obj); } +/** + * gst_rtsp_session_manage_media: + * @sess: a #GstRTSPSession + * @url: the url for the media + * @obj: a #GstRTSPMediaObject + * + * Manage the media object @obj in @sess. @url will be used to retrieve this + * media object from the session with gst_rtsp_session_get_media(). + * + * Returns: a new @GstRTSPSessionMedia object. + */ +GstRTSPSessionMedia * +gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, + GstRTSPMedia *media) +{ + GstRTSPSessionMedia *result; + + result = g_new0 (GstRTSPSessionMedia, 1); + result->media = media; + result->url = gst_rtsp_url_copy ((GstRTSPUrl *)uri); + + sess->medias = g_list_prepend (sess->medias, result); + + g_message ("manage new media %p in session %p", media, sess); + + return result; +} + /** * gst_rtsp_session_get_media: * @sess: a #GstRTSPSession * @url: the url for the media - * @factory: a #GstRTSPMediaFactory * - * Get or create the session information for @factory. + * Get the session media of the @url. * - * Returns: the configuration for @factory in @sess. + * Returns: the configuration for @url in @sess. */ GstRTSPSessionMedia * -gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *url, GstRTSPMediaFactory *factory) +gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *url) { GstRTSPSessionMedia *result; GList *walk; + g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); + g_return_val_if_fail (url != NULL, NULL); + result = NULL; for (walk = sess->medias; walk; walk = g_list_next (walk)) { result = (GstRTSPSessionMedia *) walk->data; - if (result->factory == factory) + if (strcmp (result->url->abspath, url->abspath) == 0) break; result = NULL; } - if (result == NULL) { - result = g_new0 (GstRTSPSessionMedia, 1); - result->factory = factory; - result->pipeline = gst_pipeline_new ("pipeline"); - - /* construct media and add to the pipeline */ - result->media = gst_rtsp_media_factory_construct (factory, url); - if (result->media == NULL) - goto no_media; - - gst_bin_add (GST_BIN_CAST (result->pipeline), result->media->element); - - result->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin"); - - /* add stuf to the bin */ - gst_bin_add (GST_BIN (result->pipeline), result->rtpbin); - - gst_element_set_state (result->pipeline, GST_STATE_READY); - - sess->medias = g_list_prepend (sess->medias, result); - } return result; - - /* ERRORS */ -no_media: - { - gst_rtsp_session_free_media (result); - return NULL; - } } /** @@ -205,198 +195,21 @@ gst_rtsp_session_new (const gchar *sessionid) return result; } -static gboolean -alloc_udp_ports (GstRTSPSessionStream * stream) -{ - GstStateChangeReturn ret; - GstElement *udpsrc0, *udpsrc1; - GstElement *udpsink0, *udpsink1; - gint tmp_rtp, tmp_rtcp; - guint count; - gint rtpport, rtcpport, sockfd; - gchar *name; - - udpsrc0 = NULL; - udpsrc1 = NULL; - udpsink0 = NULL; - udpsink1 = NULL; - count = 0; - - /* Start with random port */ - tmp_rtp = 0; - - /* try to allocate 2 UDP ports, the RTP port should be an even - * number and the RTCP port should be the next (uneven) port */ -again: - udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL); - if (udpsrc0 == NULL) - goto no_udp_protocol; - g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL); - - ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED); - if (ret == GST_STATE_CHANGE_FAILURE) { - if (tmp_rtp != 0) { - tmp_rtp += 2; - if (++count > 20) - goto no_ports; - - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - - goto again; - } - goto no_udp_protocol; - } - - g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); - - /* check if port is even */ - if ((tmp_rtp & 1) != 0) { - /* port not even, close and allocate another */ - if (++count > 20) - goto no_ports; - - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - - tmp_rtp++; - goto again; - } - - /* allocate port+1 for RTCP now */ - udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL); - if (udpsrc1 == NULL) - goto no_udp_rtcp_protocol; - - /* set port */ - tmp_rtcp = tmp_rtp + 1; - g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL); - - ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED); - /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */ - if (ret == GST_STATE_CHANGE_FAILURE) { - - if (++count > 20) - goto no_ports; - - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - - gst_element_set_state (udpsrc1, GST_STATE_NULL); - gst_object_unref (udpsrc1); - - tmp_rtp += 2; - goto again; - } - - /* all fine, do port check */ - g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL); - g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL); - - /* this should not happen... */ - if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) - goto port_error; - - name = g_strdup_printf ("udp://%s:%d", stream->destination, stream->client_trans->client_port.min); - udpsink0 = gst_element_make_from_uri (GST_URI_SINK, name, NULL); - g_free (name); - - if (!udpsink0) - goto no_udp_protocol; - - g_object_get (G_OBJECT (udpsrc0), "sock", &sockfd, NULL); - g_object_set (G_OBJECT (udpsink0), "sockfd", sockfd, NULL); - g_object_set (G_OBJECT (udpsink0), "closefd", FALSE, NULL); - - name = g_strdup_printf ("udp://%s:%d", stream->destination, stream->client_trans->client_port.max); - udpsink1 = gst_element_make_from_uri (GST_URI_SINK, name, NULL); - g_free (name); - - if (!udpsink1) - goto no_udp_protocol; - - g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL); - g_object_set (G_OBJECT (udpsink1), "sockfd", sockfd, NULL); - g_object_set (G_OBJECT (udpsink1), "closefd", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); - - - /* we keep these elements, we configure all in configure_transport when the - * server told us to really use the UDP ports. */ - stream->udpsrc[0] = gst_object_ref (udpsrc0); - stream->udpsrc[1] = gst_object_ref (udpsrc1); - stream->udpsink[0] = gst_object_ref (udpsink0); - stream->udpsink[1] = gst_object_ref (udpsink1); - stream->server_trans->server_port.min = rtpport; - stream->server_trans->server_port.max = rtcpport; - - /* they are ours now */ - gst_object_sink (udpsrc0); - gst_object_sink (udpsrc1); - gst_object_sink (udpsink0); - gst_object_sink (udpsink1); - - return TRUE; - - /* ERRORS */ -no_udp_protocol: - { - goto cleanup; - } -no_ports: - { - goto cleanup; - } -no_udp_rtcp_protocol: - { - goto cleanup; - } -port_error: - { - goto cleanup; - } -cleanup: - { - if (udpsrc0) { - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - } - if (udpsrc1) { - gst_element_set_state (udpsrc1, GST_STATE_NULL); - gst_object_unref (udpsrc1); - } - if (udpsink0) { - gst_element_set_state (udpsink0, GST_STATE_NULL); - gst_object_unref (udpsink0); - } - if (udpsink1) { - gst_element_set_state (udpsink1, GST_STATE_NULL); - gst_object_unref (udpsink1); - } - return FALSE; - } -} - - /** * gst_rtsp_session_stream_init_udp: * @stream: a #GstRTSPSessionStream * @ct: a client #GstRTSPTransport * * Set @ct as the client transport and create and return a matching server - * transport. After this call the needed ports and elements will be created and - * initialized. + * transport. * * Returns: a server transport or NULL if something went wrong. */ GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, - const gchar *destination, GstRTSPTransport *ct) + GstRTSPTransport *ct) { GstRTSPTransport *st; - GstPad *pad; - gchar *name; GstRTSPSessionMedia *media; media = stream->media; @@ -410,49 +223,18 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, st->client_port = ct->client_port; /* keep track of the transports */ - g_free (stream->destination); - stream->destination = g_strdup (destination); if (stream->client_trans) gst_rtsp_transport_free (stream->client_trans); stream->client_trans = ct; - if (stream->server_trans) - gst_rtsp_transport_free (stream->server_trans); + + st->server_port.min = stream->media_stream->server_port.min; + st->server_port.max = stream->media_stream->server_port.max; stream->server_trans = st; - alloc_udp_ports (stream); - - gst_bin_add (GST_BIN (media->pipeline), stream->udpsink[0]); - gst_bin_add (GST_BIN (media->pipeline), stream->udpsink[1]); - gst_bin_add (GST_BIN (media->pipeline), stream->udpsrc[1]); - - /* hook up the stream to the RTP session elements. */ - name = g_strdup_printf ("send_rtp_sink_%d", stream->idx); - stream->send_rtp_sink = gst_element_get_request_pad (media->rtpbin, name); - g_free (name); - name = g_strdup_printf ("send_rtp_src_%d", stream->idx); - stream->send_rtp_src = gst_element_get_static_pad (media->rtpbin, name); - g_free (name); - name = g_strdup_printf ("send_rtcp_src_%d", stream->idx); - stream->send_rtcp_src = gst_element_get_request_pad (media->rtpbin, name); - g_free (name); - name = g_strdup_printf ("recv_rtcp_sink_%d", stream->idx); - stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name); - g_free (name); - - gst_pad_link (stream->media_stream->srcpad, stream->send_rtp_sink); - pad = gst_element_get_static_pad (stream->udpsink[0], "sink"); - gst_pad_link (stream->send_rtp_src, pad); - gst_object_unref (pad); - pad = gst_element_get_static_pad (stream->udpsink[1], "sink"); - gst_pad_link (stream->send_rtcp_src, pad); - gst_object_unref (pad); - pad = gst_element_get_static_pad (stream->udpsrc[1], "src"); - gst_pad_link (pad, stream->recv_rtcp_sink); - gst_object_unref (pad); - return st; } + /** * gst_rtsp_session_media_play: * @media: a #GstRTSPSessionMedia @@ -465,8 +247,15 @@ GstStateChangeReturn gst_rtsp_session_media_play (GstRTSPSessionMedia *media) { GstStateChangeReturn ret; + GstRTSPSessionStream *stream; + GList *walk; - ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); + for (walk = media->streams; walk; walk = g_list_next (walk)) { + stream = (GstRTSPSessionStream *) walk->data; + + gst_rtsp_media_stream_add (stream->media_stream, stream->client_trans); + } + ret = gst_rtsp_media_play (media->media); return ret; } @@ -484,7 +273,7 @@ gst_rtsp_session_media_pause (GstRTSPSessionMedia *media) { GstStateChangeReturn ret; - ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); + ret = gst_rtsp_media_pause (media->media); return ret; } @@ -503,7 +292,7 @@ gst_rtsp_session_media_stop (GstRTSPSessionMedia *media) { GstStateChangeReturn ret; - ret = gst_element_set_state (media->pipeline, GST_STATE_NULL); + ret = gst_rtsp_media_stop (media->media); return ret; } diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 6055197ccc..9905753ef0 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -22,7 +22,6 @@ #include #include "rtsp-media.h" -#include "rtsp-media-factory.h" #ifndef __GST_RTSP_SESSION_H__ #define __GST_RTSP_SESSION_H__ @@ -60,46 +59,23 @@ struct _GstRTSPSessionStream GstRTSPMediaStream *media_stream; /* client and server transports */ - gchar *destination; GstRTSPTransport *client_trans; GstRTSPTransport *server_trans; - - /* pads on the rtpbin */ - GstPad *recv_rtcp_sink; - GstPad *send_rtp_sink; - GstPad *send_rtp_src; - GstPad *send_rtcp_src; - - /* sinks used for sending and receiving RTP and RTCP, they share sockets */ - GstElement *udpsrc[2]; - GstElement *udpsink[2]; }; /** * GstRTSPSessionMedia: * - * State of a client session regarding a specific media. The media is identified - * with the media factory. The media is typically composed of multiple streams, - * such as an audio and video stream. + * State of a client session regarding a specific media. */ struct _GstRTSPSessionMedia { - /* the owner session */ - GstRTSPSession *session; - - /* the media we are handling */ - GstRTSPMediaFactory *factory; + /* the url of the media */ + GstRTSPUrl *url; /* the pipeline for the media */ - GstElement *pipeline; GstRTSPMedia *media; - /* RTP session manager */ - GstElement *rtpbin; - - /* for TCP transport */ - GstElement *fdsink; - /* configuration for the different streams */ GList *streams; }; @@ -109,7 +85,7 @@ struct _GstRTSPSessionMedia * * Session information kept by the server for a specific client. * One client session, identified with a session id, can handle multiple medias - * identified with the media factory. + * identified with the media object. */ struct _GstRTSPSession { GObject parent; @@ -127,8 +103,11 @@ GType gst_rtsp_session_get_type (void); GstRTSPSession * gst_rtsp_session_new (const gchar *sessionid); -GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *url, - GstRTSPMediaFactory *factory); +GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess, + const GstRTSPUrl *uri, + GstRTSPMedia *media); +GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, + const GstRTSPUrl *uri); GstStateChangeReturn gst_rtsp_session_media_play (GstRTSPSessionMedia *media); GstStateChangeReturn gst_rtsp_session_media_pause (GstRTSPSessionMedia *media); @@ -138,7 +117,6 @@ GstRTSPSessionStream * gst_rtsp_session_media_get_stream (GstRTSPSessionMedi guint idx); GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, - const gchar *destination, GstRTSPTransport *ct); G_END_DECLS From 082099005dc21c0efcac40bd57ad71407d9aeedc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Jan 2009 17:19:21 +0100 Subject: [PATCH 0048/1776] Add a little comment Add some comment about the content-base header. --- gst/rtsp-server/rtsp-client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 56d9320181..679c34ff8a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -518,6 +518,7 @@ handle_describe_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE, "application/sdp"); + /* content base for some clients that might screw up creating the setup uri */ str = g_strdup_printf ("rtsp://%s:%u%s/", uri->host, uri->port, uri->abspath); gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_BASE, str); g_free (str); From 998cf7d5c7caa75729480be413b5ee4ee0c7c5cf Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Jan 2009 17:20:27 +0100 Subject: [PATCH 0049/1776] Add shared properties to media and factory Add the shared property to media. Implement some simple caching in the factory depending on if the media is shared or not. --- gst/rtsp-server/rtsp-media-factory.c | 157 +++++++++++++++++++++++++-- gst/rtsp-server/rtsp-media-factory.h | 33 ++++-- gst/rtsp-server/rtsp-media.c | 89 ++++++++++++++- gst/rtsp-server/rtsp-media.h | 12 +- 4 files changed, 267 insertions(+), 24 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index c927175749..1a5954c5b0 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -20,11 +20,13 @@ #include "rtsp-media-factory.h" #define DEFAULT_LAUNCH NULL +#define DEFAULT_SHARED FALSE enum { PROP_0, PROP_LAUNCH, + PROP_SHARED, PROP_LAST }; @@ -34,8 +36,10 @@ static void gst_rtsp_media_factory_set_property (GObject *object, guint propid, const GValue *value, GParamSpec *pspec); static void gst_rtsp_media_factory_finalize (GObject * obj); -static GstRTSPMedia * default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); +static gchar * default_gen_key (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); static GstElement * default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); +static GstRTSPMedia * default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); +static void default_configure (GstRTSPMediaFactory *factory, GstRTSPMedia *media); G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT); @@ -67,13 +71,26 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) g_param_spec_string ("launch", "Launch", "A launch description of the pipeline", DEFAULT_LAUNCH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - klass->construct = default_construct; + g_object_class_install_property (gobject_class, PROP_SHARED, + g_param_spec_boolean ("shared", "Shared", "If media from this factory is shared", + DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + klass->gen_key = default_gen_key; klass->get_element = default_get_element; + klass->construct = default_construct; + klass->configure = default_configure; } static void gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) { + factory->launch = g_strdup (DEFAULT_LAUNCH); + factory->shared = DEFAULT_SHARED; + + factory->lock = g_mutex_new (); + factory->medias_lock = g_mutex_new (); + factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); } static void @@ -81,7 +98,10 @@ gst_rtsp_media_factory_finalize (GObject * obj) { GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj); + g_hash_table_unref (factory->medias); + g_mutex_free (factory->medias_lock); g_free (factory->launch); + g_mutex_free (factory->lock); G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj); } @@ -96,6 +116,9 @@ gst_rtsp_media_factory_get_property (GObject *object, guint propid, case PROP_LAUNCH: g_value_take_string (value, gst_rtsp_media_factory_get_launch (factory)); break; + case PROP_SHARED: + g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -111,6 +134,9 @@ gst_rtsp_media_factory_set_property (GObject *object, guint propid, case PROP_LAUNCH: gst_rtsp_media_factory_set_launch (factory, g_value_get_string (value)); break; + case PROP_SHARED: + gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -155,7 +181,10 @@ gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, const gchar *la g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); g_return_if_fail (launch != NULL); + g_mutex_lock (factory->lock); + g_free (factory->launch); factory->launch = g_strdup (launch); + g_mutex_unlock (factory->lock); } /** @@ -172,7 +201,51 @@ gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory) { gchar *result; + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + + g_mutex_lock (factory->lock); result = g_strdup (factory->launch); + g_mutex_unlock (factory->lock); + + return result; +} + +/** + * gst_rtsp_media_factory_set_shared: + * @factory: a #GstRTSPMediaFactory + * @shared: the new value + * + * Configure if media created from this factory can be shared between clients. + */ +void +gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory, + gboolean shared) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + g_mutex_lock (factory->lock); + factory->shared = shared; + g_mutex_unlock (factory->lock); +} + +/** + * gst_rtsp_media_factory_is_shared: + * @factory: a #GstRTSPMediaFactory + * + * Get if media created from this factory can be shared between clients. + * + * Returns: %TRUE if the media will be shared between clients. + */ +gboolean +gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory) +{ + gboolean result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); + + g_mutex_lock (factory->lock); + result = factory->shared; + g_mutex_unlock (factory->lock); return result; } @@ -195,19 +268,68 @@ gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory) GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) { - GstRTSPMedia *res; + gchar *key; + GstRTSPMedia *media; GstRTSPMediaFactoryClass *klass; klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); - if (klass->construct) - res = klass->construct (factory, url); + /* convert the url to a key for the hashtable. NULL return or a NULL function + * will not cache anything for this factory. */ + if (klass->gen_key) + key = klass->gen_key (factory, url); else - res = NULL; + key = NULL; - g_message ("constructed media %p for url %s", res, url->abspath); + g_mutex_lock (factory->medias_lock); + if (key) { + /* we have a key, see if we find a cached media */ + media = g_hash_table_lookup (factory->medias, key); + if (media) + g_object_ref (media); + } + else + media = NULL; - return res; + if (media == NULL) { + /* nothing cached found, try to create one */ + if (klass->construct) + media = klass->construct (factory, url); + else + media = NULL; + + if (media) { + /* configure the media */ + if (klass->configure) + klass->configure (factory, media); + + /* check if we can cache this media */ + if (gst_rtsp_media_is_shared (media)) { + /* insert in the hashtable, takes ownership of the key */ + g_object_ref (media); + g_hash_table_insert (factory->medias, key, media); + key = NULL; + } + } + } + g_mutex_unlock (factory->medias_lock); + + if (key) + g_free (key); + + g_message ("constructed media %p for url %s", media, url->abspath); + + return media; +} + +static gchar * +default_gen_key (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) +{ + gchar *result; + + result = gst_rtsp_url_get_request_uri (url); + + return result; } static GstElement * @@ -216,6 +338,7 @@ default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) GstElement *element; GError *error = NULL; + g_mutex_lock (factory->lock); /* we need a parse syntax */ if (factory->launch == NULL) goto no_launch; @@ -225,6 +348,8 @@ default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) if (element == NULL) goto parse_error; + g_mutex_unlock (factory->lock); + if (error != NULL) { /* a recoverable error was encountered */ g_warning ("recoverable parsing error: %s", error->message); @@ -235,11 +360,13 @@ default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) /* ERRORS */ no_launch: { + g_mutex_unlock (factory->lock); g_critical ("no launch line specified"); return NULL; } parse_error: { + g_mutex_unlock (factory->lock); g_critical ("could not parse launch syntax (%s): %s", factory->launch, (error ? error->message : "unknown reason")); if (error) @@ -248,6 +375,7 @@ parse_error: } } + static GstRTSPMedia * default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) { @@ -313,3 +441,16 @@ no_element: return NULL; } } + +static void +default_configure (GstRTSPMediaFactory *factory, GstRTSPMedia *media) +{ + gboolean shared; + + /* configure the sharedness */ + g_mutex_lock (factory->lock); + shared = factory->shared; + g_mutex_unlock (factory->lock); + + gst_rtsp_media_set_shared (media, shared); +} diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 472d325585..6eafdd0a98 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -42,8 +42,11 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; /** * GstRTSPMediaFactory: + * @lock: mutex protecting the datastructure. * @launch: the launch description - * @streams: the array of #GstRTSPMediaStream objects for this media. + * @shared: if media from this factory can be shared between clients + * @media_lock: mutex protecting the medias. + * @media: hashtable of shared media * * The definition and logic for constructing the pipeline for a media. The media * can contain multiple streams like audio and video. @@ -51,39 +54,52 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; struct _GstRTSPMediaFactory { GObject parent; + GMutex *lock; gchar *launch; + gboolean shared; + + GMutex *medias_lock; + GHashTable *medias; }; /** * GstRTSPMediaFactoryClass: + * @gen_key: convert @url to a key for caching media + * @get_element: Construct an return a #GstElement thast is a #GstBin containing + * the elements to use for the media. The bin should contain payloaders + * pay%d for each stream. The default implementation of this functions + * returns the bin created from the launch parameter. * @construct: the vmethod that will be called when the factory has to create the * #GstRTSPMedia for @url. The default implementation of this * function calls get_element to retrieve an element and then looks for * pay%d to create the streams. + * @configure: configure the media created with @construct. The default + * implementation will configure the 'shared' property of the media. * @handle_message: Handle a bus message for @media created from @factory. - * @get_element: Construct an return a #GstElement thast is a #GstBin containing - * the pipeline to use for the media. The bin should contain elements - * pay%d for each stream. The default implementation of this functions - * returns the bin created from the launch parameter. * * the #GstRTSPMediaFactory class structure. */ struct _GstRTSPMediaFactoryClass { GObjectClass parent_class; + gchar * (*gen_key) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + + GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); + void (*handle_message) (GstRTSPMediaFactory *factory, GstRTSPMedia *media, GstMessage *message); - GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); }; GType gst_rtsp_media_factory_get_type (void); -/* configuring the factory */ +/* creating the factory */ GstRTSPMediaFactory * gst_rtsp_media_factory_new (void); +/* configuring the factory */ void gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, const gchar *launch); gchar * gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory); @@ -92,8 +108,7 @@ void gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * gboolean shared); gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory); - -/* creating the media bin from the factory */ +/* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 2dc2c8c645..430978d730 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -19,6 +19,19 @@ #include "rtsp-media.h" +#define DEFAULT_SHARED FALSE + +enum +{ + PROP_0, + PROP_SHARED, + PROP_LAST +}; + +static void gst_rtsp_media_get_property (GObject *object, guint propid, + GValue *value, GParamSpec *pspec); +static void gst_rtsp_media_set_property (GObject *object, guint propid, + const GValue *value, GParamSpec *pspec); static void gst_rtsp_media_finalize (GObject * obj); G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); @@ -30,7 +43,13 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) gobject_class = G_OBJECT_CLASS (klass); + gobject_class->get_property = gst_rtsp_media_get_property; + gobject_class->set_property = gst_rtsp_media_set_property; gobject_class->finalize = gst_rtsp_media_finalize; + + g_object_class_install_property (gobject_class, PROP_SHARED, + g_param_spec_boolean ("shared", "Shared", "If this media pipeline can be shared", + DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void @@ -64,6 +83,36 @@ gst_rtsp_media_finalize (GObject * obj) G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); } +static void +gst_rtsp_media_get_property (GObject *object, guint propid, + GValue *value, GParamSpec *pspec) +{ + GstRTSPMedia *media = GST_RTSP_MEDIA (object); + + switch (propid) { + case PROP_SHARED: + g_value_set_boolean (value, gst_rtsp_media_is_shared (media)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static void +gst_rtsp_media_set_property (GObject *object, guint propid, + const GValue *value, GParamSpec *pspec) +{ + GstRTSPMedia *media = GST_RTSP_MEDIA (object); + + switch (propid) { + case PROP_SHARED: + gst_rtsp_media_set_shared (media, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + /** * gst_rtsp_media_new: * @@ -83,6 +132,38 @@ gst_rtsp_media_new (void) return result; } +/** + * gst_rtsp_media_set_shared: + * @media: a #GstRTSPMedia + * @shared: the new value + * + * Set or unset if the pipeline for @media can be shared will multiple clients. + * When @shared is %TRUE, client requests for this media will share the media + * pipeline. + */ +void +gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + media->shared = shared; +} + +/** + * gst_rtsp_media_is_shared: + * @media: a #GstRTSPMedia + * + * Check if the pipeline for @media can be shared between multiple clients. + * + * Returns: %TRUE if the media can be shared between clients. + */ +gboolean +gst_rtsp_media_is_shared (GstRTSPMedia *media) +{ + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + return media->shared; +} /** * gst_rtsp_media_n_streams: @@ -360,7 +441,6 @@ setup_stream (GstRTSPMediaStream *stream, GstRTSPMedia *media) return TRUE; } - /** * gst_rtsp_media_prepare: * @obj: a #GstRTSPMedia @@ -379,6 +459,8 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) if (media->prepared) goto was_prepared; + g_message ("preparing media %p", media); + media->pipeline = gst_pipeline_new ("media-pipeline"); gst_bin_add (GST_BIN_CAST (media->pipeline), media->element); @@ -388,8 +470,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) /* add stuf to the bin */ gst_bin_add (GST_BIN (media->pipeline), media->rtpbin); - ret = gst_element_set_state (media->pipeline, GST_STATE_READY); - + /* link streams we already have */ n_streams = gst_rtsp_media_n_streams (media); for (i = 0; i < n_streams; i++) { GstRTSPMediaStream *stream; @@ -416,7 +497,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) goto state_failed; } - /* no wait for all pads to be prerolled */ + /* now wait for all pads to be prerolled */ ret = gst_element_get_state (media->pipeline, NULL, NULL, -1); /* and back to PAUSED for live pipelines */ diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 6fc0dc1460..1fb685f105 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -88,6 +88,7 @@ struct _GstRTSPMediaStream { /** * GstRTSPMedia: + * @shared: if this media can be shared between clients * @element: the data providing element * @stream: the different streams provided by @element * @prepared: if the media is prepared for streaming @@ -103,6 +104,8 @@ struct _GstRTSPMediaStream { struct _GstRTSPMedia { GObject parent; + gboolean shared; + GstElement *element; GArray *streams; gboolean prepared; @@ -126,13 +129,16 @@ GType gst_rtsp_media_get_type (void); /* creating the media */ GstRTSPMedia * gst_rtsp_media_new (void); -/* dealing with the media */ -guint gst_rtsp_media_n_streams (GstRTSPMedia *media); -GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); +void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared); +gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media); /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); +/* dealing with the media */ +guint gst_rtsp_media_n_streams (GstRTSPMedia *media); +GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); + /* add destinations to a stream */ gboolean gst_rtsp_media_stream_add (GstRTSPMediaStream *stream, GstRTSPTransport *ct); gboolean gst_rtsp_media_stream_remove (GstRTSPMediaStream *stream, GstRTSPTransport *ct); From b19b1fbe6beee24abad165a79a7a28eddc30395c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Jan 2009 18:51:02 +0100 Subject: [PATCH 0050/1776] Cleanups and reuse media from DESCRIBE Handle thread create errors. Rename some internal methods to better match what they actually do. Handle misconfiguration of session_pool and media_mapping gracefully. Cache the DESCRIBE media and uri in the client connection and reuse them when we receive a SETUP request in the same connection for the same uri. Cleanup the client connection object. --- gst/rtsp-server/rtsp-client.c | 193 ++++++++++++++++++++++++---------- gst/rtsp-server/rtsp-client.h | 3 + 2 files changed, 143 insertions(+), 53 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 679c34ff8a..bd4303dbae 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -43,9 +43,23 @@ gst_rtsp_client_init (GstRTSPClient * client) { } +/* A client is finalized when the connection is broken */ static void gst_rtsp_client_finalize (GObject * obj) { + GstRTSPClient *client = GST_RTSP_CLIENT (obj); + + gst_rtsp_connection_free (client->connection); + if (client->session_pool) + g_object_unref (client->session_pool); + if (client->media_mapping) + g_object_unref (client->media_mapping); + + if (client->uri) + gst_rtsp_url_free (client->uri); + if (client->media) + g_object_unref (client->media); + G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj); } @@ -65,17 +79,17 @@ gst_rtsp_client_new (void) } static void -handle_response (GstRTSPClient *client, GstRTSPMessage *response) +send_response (GstRTSPClient *client, GstRTSPMessage *response) { #ifdef DEBUG - gst_rtsp_message_dump (response); + gst_rtsp_message_dump (response); #endif gst_rtsp_connection_send (client->connection, response, NULL); } static void -handle_generic_response (GstRTSPClient *client, GstRTSPStatusCode code, +send_generic_response (GstRTSPClient *client, GstRTSPStatusCode code, GstRTSPMessage *request) { GstRTSPMessage response = { 0 }; @@ -83,44 +97,87 @@ handle_generic_response (GstRTSPClient *client, GstRTSPStatusCode code, gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); - handle_response (client, &response); + send_response (client, &response); } +static gboolean +compare_uri (const GstRTSPUrl *uri1, const GstRTSPUrl *uri2) +{ + if (uri1 == NULL || uri2 == NULL) + return FALSE; + + if (strcmp (uri1->abspath, uri2->abspath)) + return FALSE; + + return TRUE; +} + +/* this function is called to initially find the media for the DESCRIBE request + * but is cached for when the same client (without breaking the connection) is + * doing a setup for the exact same url. */ static GstRTSPMedia * find_media (GstRTSPClient *client, const GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPMediaFactory *factory; GstRTSPMedia *media; - /* find the factory for the uri first */ - if (!(factory = gst_rtsp_media_mapping_find_factory (client->media_mapping, uri))) - goto no_factory; + if (!compare_uri (client->uri, uri)) { + /* remove any previously cached values before we try to construct a new + * media for uri */ + if (client->uri) + gst_rtsp_url_free (client->uri); + client->uri = NULL; + if (client->media) + g_object_unref (client->media); + client->media = NULL; - /* prepare the media and add it to the pipeline */ - if (!(media = gst_rtsp_media_factory_construct (factory, uri))) - goto no_media; + if (!client->media_mapping) + goto no_mapping; - /* prepare the media */ - if (!(gst_rtsp_media_prepare (media))) - goto no_prepare; + /* find the factory for the uri first */ + if (!(factory = gst_rtsp_media_mapping_find_factory (client->media_mapping, uri))) + goto no_factory; + + /* prepare the media and add it to the pipeline */ + if (!(media = gst_rtsp_media_factory_construct (factory, uri))) + goto no_media; + + /* prepare the media */ + if (!(gst_rtsp_media_prepare (media))) + goto no_prepare; + + /* now keep track of the uri and the media */ + client->uri = gst_rtsp_url_copy (uri); + client->media = g_object_ref (media); + } + else { + /* we have seen this uri before, used cached media */ + media = g_object_ref (client->media); + g_message ("reusing cached media %p", media); + } return media; /* ERRORS */ +no_mapping: + { + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + return NULL; + } no_factory: { - handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); return NULL; } no_media: { - handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); g_object_unref (factory); return NULL; } no_prepare: { - handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); g_object_unref (media); g_object_unref (factory); return NULL; @@ -137,6 +194,9 @@ ensure_session (GstRTSPClient *client, GstRTSPMessage *request) res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); if (res == GST_RTSP_OK) { + if (client->session_pool == NULL) + goto no_pool; + /* we had a session in the request, find it again */ if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid))) goto session_not_found; @@ -147,20 +207,25 @@ ensure_session (GstRTSPClient *client, GstRTSPMessage *request) return session; /* ERRORS */ +no_pool: + { + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + return NULL; + } session_not_found: { - handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); return NULL; } service_unavailable: { - handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); return NULL; } } static gboolean -handle_teardown_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPSessionMedia *media; GstRTSPSession *session; @@ -188,7 +253,7 @@ handle_teardown_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); - handle_response (client, &response); + send_response (client, &response); return FALSE; @@ -200,13 +265,13 @@ no_session: } not_found: { - handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); return FALSE; } } static gboolean -handle_pause_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPSessionMedia *media; GstRTSPSession *session; @@ -228,7 +293,7 @@ handle_pause_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *r code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); - handle_response (client, &response); + send_response (client, &response); return FALSE; @@ -239,13 +304,13 @@ no_session: } not_found: { - handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); return FALSE; } } static gboolean -handle_play_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPSessionMedia *media; GstRTSPSession *session; @@ -292,7 +357,7 @@ handle_play_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re gst_rtsp_message_add_header (&response, GST_RTSP_HDR_RTP_INFO, rtpinfo->str); g_string_free (rtpinfo, TRUE); - handle_response (client, &response); + send_response (client, &response); /* start playing after sending the request */ gst_rtsp_session_media_play (media); @@ -308,13 +373,13 @@ no_session: } not_found: { - handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); return FALSE; } } static gboolean -handle_setup_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPResult res; gchar *sessid; @@ -388,6 +453,9 @@ handle_setup_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *r if (!(ct->lower_transport & supported)) goto unsupported_transports; + if (client->session_pool == NULL) + goto no_pool; + /* a setup request creates a session for a client, check if the client already * sent a session id to us */ res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); @@ -438,52 +506,57 @@ handle_setup_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *r g_free (trans_str); g_object_unref (session); - handle_response (client, &response); + send_response (client, &response); return TRUE; /* ERRORS */ bad_request: { - handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); return FALSE; } not_found: { - handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); return FALSE; } no_stream: { - handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); return FALSE; } session_not_found: { - handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); return FALSE; } no_transport: { - handle_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request); + send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request); return FALSE; } unsupported_transports: { - handle_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request); + send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request); gst_rtsp_transport_free (ct); return FALSE; } +no_pool: + { + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + return FALSE; + } service_unavailable: { - handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); return FALSE; } } /* for the describe we must generate an SDP */ static gboolean -handle_describe_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPMessage response = { 0 }; GstRTSPResult res; @@ -528,7 +601,7 @@ handle_describe_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage gst_rtsp_message_take_body (&response, (guint8 *)str, strlen (str)); gst_sdp_message_free (sdp); - handle_response (client, &response); + send_response (client, &response); return TRUE; @@ -540,14 +613,14 @@ no_media: } no_sdp: { - handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); g_object_unref (media); return FALSE; } } static void -handle_options_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +handle_options_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPMessage response = { 0 }; GstRTSPMethod options; @@ -568,7 +641,7 @@ handle_options_response (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str); g_free (str); - handle_response (client, &response); + send_response (client, &response); } /* remove duplicate and trailing '/' */ @@ -624,13 +697,13 @@ handle_client (GstRTSPClient *client) if (version != GST_RTSP_VERSION_1_0) { /* we can only handle 1.0 requests */ - handle_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, &request); + send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, &request); continue; } /* we always try to parse the url first */ if ((res = gst_rtsp_url_parse (uristr, &uri)) != GST_RTSP_OK) { - handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &request); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &request); continue; } @@ -640,33 +713,33 @@ handle_client (GstRTSPClient *client) /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: - handle_options_response (client, uri, &request); + handle_options_request (client, uri, &request); break; case GST_RTSP_DESCRIBE: - handle_describe_response (client, uri, &request); + handle_describe_request (client, uri, &request); break; case GST_RTSP_SETUP: - handle_setup_response (client, uri, &request); + handle_setup_request (client, uri, &request); break; case GST_RTSP_PLAY: - handle_play_response (client, uri, &request); + handle_play_request (client, uri, &request); break; case GST_RTSP_PAUSE: - handle_pause_response (client, uri, &request); + handle_pause_request (client, uri, &request); break; case GST_RTSP_TEARDOWN: - handle_teardown_response (client, uri, &request); + handle_teardown_request (client, uri, &request); break; case GST_RTSP_ANNOUNCE: case GST_RTSP_GET_PARAMETER: case GST_RTSP_RECORD: case GST_RTSP_REDIRECT: case GST_RTSP_SET_PARAMETER: - handle_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &request); + send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &request); break; case GST_RTSP_INVALID: default: - handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &request); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &request); break; } gst_rtsp_url_free (uri); @@ -830,12 +903,17 @@ gst_rtsp_client_get_media_mapping (GstRTSPClient *client) gboolean gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel) { + GError *error = NULL; + if (!client_accept (client, channel)) goto accept_failed; - /* client accepted, spawn a thread for the client */ + /* client accepted, spawn a thread for the client, we don't need to join the + * thread */ g_object_ref (client); - client->thread = g_thread_create ((GThreadFunc)handle_client, client, TRUE, NULL); + client->thread = g_thread_create ((GThreadFunc)handle_client, client, FALSE, &error); + if (client->thread == NULL) + goto no_thread; return TRUE; @@ -844,4 +922,13 @@ accept_failed: { return FALSE; } +no_thread: + { + if (error) { + g_warning ("could not create thread for client %p: %s", client, error->message); + g_error_free (error); + } + g_object_unref (client); + return FALSE; + } } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 504fd1da89..637bedf33f 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -75,6 +75,9 @@ struct _GstRTSPClient { GstRTSPSessionPool *session_pool; GstRTSPMediaMapping *media_mapping; + + GstRTSPUrl *uri; + GstRTSPMedia *media; }; struct _GstRTSPClientClass { From 704720f306d2025282b3789fce89bfaa8ecadf51 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Jan 2009 18:55:22 +0100 Subject: [PATCH 0051/1776] Cleanups to the session object Remove some unneeded variables in the session state of a stream such as the owner media and the server transport. Get the configuration of a media stream in a session based on the media_stream in the original object instead of our cached index. Free more data in the finalize method. --- gst/rtsp-server/rtsp-session.c | 60 +++++++++++++++++++--------------- gst/rtsp-server/rtsp-session.h | 9 ++--- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index a5efc79235..cd5fd85eea 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -42,7 +42,7 @@ gst_rtsp_session_init (GstRTSPSession * session) } static void -gst_rtsp_session_free_stream (GstRTSPSessionStream *stream) +gst_rtsp_session_free_stream (GstRTSPSessionStream *stream, GstRTSPSessionMedia *media) { if (stream->client_trans) gst_rtsp_transport_free (stream->client_trans); @@ -51,35 +51,36 @@ gst_rtsp_session_free_stream (GstRTSPSessionStream *stream) } static void -gst_rtsp_session_free_media (GstRTSPSessionMedia *media) +gst_rtsp_session_free_media (GstRTSPSessionMedia *media, GstRTSPSession *session) { - GList *walk; - - for (walk = media->streams; walk; walk = g_list_next (walk)) { - GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data; - - gst_rtsp_session_free_stream (stream); - } + g_list_foreach (media->streams, (GFunc) gst_rtsp_session_free_stream, + media); g_list_free (media->streams); + + if (media->url) + gst_rtsp_url_free (media->url); + + if (media->media) + g_object_unref (media->media); + + g_free (media); } static void gst_rtsp_session_finalize (GObject * obj) { GstRTSPSession *session; - GList *walk; session = GST_RTSP_SESSION (obj); - g_free (session->sessionid); - - for (walk = session->medias; walk; walk = g_list_next (walk)) { - GstRTSPSessionMedia *media = (GstRTSPSessionMedia *) walk->data; - - gst_rtsp_session_free_media (media); - } + /* free all media */ + g_list_foreach (session->medias, (GFunc) gst_rtsp_session_free_media, + session); g_list_free (session->medias); + /* free session id */ + g_free (session->sessionid); + G_OBJECT_CLASS (gst_rtsp_session_parent_class)->finalize (obj); } @@ -156,27 +157,38 @@ GstRTSPSessionStream * gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, guint idx) { GstRTSPSessionStream *result; + GstRTSPMediaStream *media_stream; GList *walk; - result = NULL; + g_return_val_if_fail (media != NULL, NULL); + g_return_val_if_fail (media->media != NULL, NULL); + media_stream = gst_rtsp_media_get_stream (media->media, idx); + if (media_stream == NULL) + goto no_media; + + result = NULL; for (walk = media->streams; walk; walk = g_list_next (walk)) { result = (GstRTSPSessionStream *) walk->data; - if (result->idx == idx) + if (result->media_stream == media_stream) break; result = NULL; } if (result == NULL) { result = g_new0 (GstRTSPSessionStream, 1); - result->idx = idx; - result->media = media; - result->media_stream = gst_rtsp_media_get_stream (media->media, idx); + result->media_stream = media_stream; media->streams = g_list_prepend (media->streams, result); } return result; + + /* ERRORS */ +no_media: + { + return NULL; + } } /** @@ -210,9 +222,6 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, GstRTSPTransport *ct) { GstRTSPTransport *st; - GstRTSPSessionMedia *media; - - media = stream->media; /* prepare the server transport */ gst_rtsp_transport_new (&st); @@ -229,7 +238,6 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, st->server_port.min = stream->media_stream->server_port.min; st->server_port.max = stream->media_stream->server_port.max; - stream->server_trans = st; return st; } diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 9905753ef0..3ff5ba05f4 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -51,22 +51,17 @@ typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia; */ struct _GstRTSPSessionStream { - guint idx; - - /* the owner media */ - GstRTSPSessionMedia *media; - + /* the stream of the media */ GstRTSPMediaStream *media_stream; /* client and server transports */ GstRTSPTransport *client_trans; - GstRTSPTransport *server_trans; }; /** * GstRTSPSessionMedia: * - * State of a client session regarding a specific media. + * State of a client session regarding a specific media identified by uri. */ struct _GstRTSPSessionMedia { From edd2175695355733a1432b31987d615f9e1d0bc5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Jan 2009 11:06:31 +0100 Subject: [PATCH 0052/1776] Fix some leaks and change default port Fix some memory leaks by setting the udpsrc elements to the unlocked state after we finished the initial preroll. If we keep them locked, setting the pipeline to NULL will not stop and clean up the sources correctly. Change the default RTSP port to 8554 aka the official alternative RTSP port. --- gst/rtsp-server/rtsp-media.c | 11 +++++++++++ gst/rtsp-server/rtsp-server.c | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 430978d730..023a153266 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -395,6 +395,7 @@ setup_stream (GstRTSPMediaStream *stream, GstRTSPMedia *media) gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsink[0]); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsink[1]); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsrc[0]); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsrc[1]); /* hook up the stream to the RTP session elements. */ @@ -503,6 +504,16 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) /* and back to PAUSED for live pipelines */ ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); + n_streams = gst_rtsp_media_n_streams (media); + for (i = 0; i < n_streams; i++) { + GstRTSPMediaStream *stream; + + stream = gst_rtsp_media_get_stream (media, i); + + gst_element_set_locked_state (stream->udpsrc[0], FALSE); + gst_element_set_locked_state (stream->udpsrc[1], FALSE); + } + g_message ("object %p is prerolled", media); media->prepared = TRUE; diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index afbfe9243f..873ca37b01 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -23,7 +23,7 @@ #include "rtsp-client.h" #define DEFAULT_BACKLOG 5 -#define DEFAULT_PORT 1554 +#define DEFAULT_PORT 8554 enum { From 031791ddd2aef4135fba3e965eb233317084103d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Jan 2009 13:24:04 +0100 Subject: [PATCH 0053/1776] Add a README and more example code Add a README file that contains a small introduction on how to use the server along with the example code explained in the readme. --- docs/README | 175 +++++++++++++++++++++++++++++++++++++++++ examples/Makefile.am | 2 +- examples/test-readme.c | 64 +++++++++++++++ 3 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 docs/README create mode 100644 examples/test-readme.c diff --git a/docs/README b/docs/README new file mode 100644 index 0000000000..06a28c746a --- /dev/null +++ b/docs/README @@ -0,0 +1,175 @@ +README +------ + +(Last updated on Fri 30 jan 2009, version 0.10.1.1) + +This HOWTO describes the basic usage of the GStreamer RTSP libraries and how you +can build simple server applications with it. + +* General + + The server relies heavily on the RTSP infrastructure of GStreamer. This includes + all of the media acquisition, decoding, encoding, payloading and UDP/TCP + streaming. We use the gstrtpbin element for all the session management. Most of + the RTSP message parsing and construction in the server is done using the RTSP + library that comes with gst-plugins-base. + + The result is that the server is rather small (a few 1000 lines of code) and easy + to understand and extend. In its current state of development, things change + fast, API and ABI are unstable. We encourage people to use it for their various + use cases and participate by suggesting changes/features. + + Most of the server is built as a library containing a bunch of GObject objects + that provide reasonable default functionality but has a fair amount of hooks + to override the default behaviour. + + The server currently integrates with the glib mainloop nicely. It is also a + heavy user of multiple threads. It's currently not meant to be used in + high-load scenarios and you should probably not put it on a public IP address. + +* Initialisation + + You need to initialize GStreamer before using any of the RTSP server functions. + + #include + + int + main (int argc, char *argv[]) + { + gst_init (&argc, &argv); + + ... + } + + The server itself currently does not have any specific initialisation function + but that might change in the future. + + +* Creating the server + + The first thing you want to do is create a new GstRTSPServer object. This object + will handle all the new client connections to your server once it is added to a + GMainLoop. You can create a new server object like this: + + #include + + GstRTSPServer *server; + + server = gst_rtsp_server_new (); + + The server will by default listen on port 8554 for new connections. This can be + changed by calling gst_rtsp_server_set_port() or with the 'port' GObject + property. This makes it possible to run multiple server instances listening on + multiple ports on one machine. + + We can make the server start listening on its default port by attaching it to a + mainloop. The following example shows how this is done and will start a server + on the default 8554 port. For any request we make, we will get a NOT_FOUND + error code because we need to configure more things before the server becomes + useful. + + #include + #include + + int + main (int argc, char *argv[]) + { + GstRTSPServer *server; + GMainLoop *loop; + + gst_init (&argc, &argv); + + server = gst_rtsp_server_new (); + + /* make a mainloop for the default context */ + loop = g_main_loop_new (NULL, FALSE); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + /* start serving */ + g_main_loop_run (loop); + } + + The server manages two other objects: GstRTSPSessionPool and + GstRTSPMediaMapping. + + The GstRTSPSessionPool is an object that keeps track of all the active sessions + in the server. A session will usually be kept for each client that performed a + SETUP request for a certain media stream. It contains the configuration that + the client negotiated with the server to receive the particular stream, ie. the + transport used and port pairs for UDP along with the state of the streaming. + The default implementation of the session pool is usually sufficient but + alternative implementation can be used by the server. + + The GstRTSPMediaMapping object is more interesting and needs more configuration + before the server object is useful. This object manages to mapping from a + request URL to a specific stream and its configuration. We explain in the next + topic how to configure this object. + +* Making url mappings + + Next we need to define what media is attached to a particular URL. What we want + to achieve is that when the user asks our server for a specific URL, say /test, + that we create (or reuse) a GStreamer pipeline that produces one or more RTP + streams. + + The object that can create such pipeline is called a GstRTSPMediaFactory object. + The default implementation of GstRTSPMediaFactory allows you to easily create + GStreamer pipelines using the gst-launch syntax. It possible to create a + GstRTSPMediaFactory subclass that uses different methods for constructing + pipelines. + + The default GstRTSPMediaFactory can be configured with a gst-launch line that + produces a toplevel bin (use '(' and ')' around the pipeline description to + force a toplevel GstBin instead of the default GstPipeline toplevel element). + The pipeline description should contain elements named payN, one for each + stream (ex. pay0, pay1, ...). Also, for increased compatibility each stream + should have a different payload type which can be configured on the payloader. + + The following code snippet illustrates how to create a media factory that + creates an RTP feed of an H264 encoded test video signal. + + GstRTSPMediaFactory *factory; + + factory = gst_rtsp_media_factory_new (); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! x264enc ! rtph264pay pt=96 name=pay0 )"); + + Now that we have the media factory, we can attach it to a specific url. To do + this we get the default GstRTSPMediaMapping from our server and add the url to + factory mapping to it like this: + + GstRTSPMediaMapping *mapping; + + ...create server..create factory.. + + /* get the default mapping from the server */ + mapping = gst_rtsp_server_get_media_mapping (server); + + /* attach the video test signal to the "/test" URL */ + gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + g_object_unref (mapping); + + When starting the server now and directing an RTP client to the URL (like with + vlc, mplayer or gstreamer): + + rtsp://localhost:8554/test + + a test signal will be streamed to the client. The full example code can be + found in the examples/test-readme.c file. + + + + + + + + + + + + + + diff --git a/examples/Makefile.am b/examples/Makefile.am index 1241eda2af..c8196d1095 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,4 +1,4 @@ -noinst_PROGRAMS = test-video test-ogg test-mp4 +noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/examples/test-readme.c b/examples/test-readme.c new file mode 100644 index 0000000000..880b6d2102 --- /dev/null +++ b/examples/test-readme.c @@ -0,0 +1,64 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMediaMapping *mapping; + GstRTSPMediaFactory *factory; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mapping for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mapping = gst_rtsp_server_get_media_mapping (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )"); + + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mapping); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + /* start serving */ + g_main_loop_run (loop); + + return 0; +} From 1b9225078b807fe4a191988c43984b732d5552d7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Jan 2009 14:53:28 +0100 Subject: [PATCH 0054/1776] More docs and small cleanups Add some more docs and update the README Cleanup some method names. Remove an unneeded idx field in the GstRTSPMediaStream --- docs/README | 97 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.c | 1 - gst/rtsp-server/rtsp-media-factory.h | 16 ++--- gst/rtsp-server/rtsp-media.c | 12 ++-- gst/rtsp-server/rtsp-media.h | 3 - gst/rtsp-server/rtsp-server.c | 6 +- gst/rtsp-server/rtsp-server.h | 4 +- 7 files changed, 116 insertions(+), 23 deletions(-) diff --git a/docs/README b/docs/README index 06a28c746a..76d4ab9807 100644 --- a/docs/README +++ b/docs/README @@ -107,6 +107,7 @@ can build simple server applications with it. request URL to a specific stream and its configuration. We explain in the next topic how to configure this object. + * Making url mappings Next we need to define what media is attached to a particular URL. What we want @@ -161,6 +162,102 @@ can build simple server applications with it. found in the examples/test-readme.c file. +* more on GstRTSPMediaFactory + + The GstRTSPMediaFactory is responsible for creating and caching GstRTSPMedia + objects. + + A freshly created GstRTSPMedia object from the factory initialy only contains a + GstElement containing the elements to produce the RTP streams for the media and + a GArray of GstRTSPMediaStream objects describing the payloader and its source + pad. The media is unprepared in this state. + + Usually the url will determine what kind of pipeline should be created. You can + for example use query parameters to configure certain parts of the pipeline or + select encoders and payloaders based on some url pattern. + + When dealing with a live stream from, for example, a webcam, it can be + interesting to share the pipeline with multiple clients. This must be done when + only one instance of the video capture element can be used at a time. In this + case, the shared property of GstRTSPMedia must be used to instruct the default + GstRTSPMediaFactory implementation to cache the media. + + When all objects created from a factory can be shared, you can set the shared + property directly on the factory. + +* more on GstRTSPMedia + + After creating the GstRTSPMedia object from the factory, it can be prepared + with gst_rtsp_media_prepare(). This method will put those objects in a + GstPipeline and will construct and link the streaming elements and the + gstrtpbin session manager object. + + The _prepare() method will then preroll the pipeline in order to figure out the + caps on the payloaders. After the GstRTSPMedia prerolled it will be in the + prepared state and can be used for creating SDP files or for streaming to + clients. + + The prepare method will also create 2 UDP ports for each stream that can be + used for sending and receiving RTP/RTCP from clients. These port numbers will + have to be negotiated with the client in the SETUP requests. + + When preparing a GstRTSPMedia, a multifdsink is also constructed for streaming + the stream over TCP^when requested. + + +* the GstRTSPClient object + + When a server detects a new client connection on its port, it will call its + accept_client vmethod. The default implementation of this function will create + a new GstRTCPClient object, will configure the session pool and media mapper + objects in it and will then call the accept function of the client. + + The default GstRTSPClient will accept the connection and will start a new + GThread to handle the connection. In RTSP it is usual to keep the connection + open between multiple RTSP requests. The client thread will simply block for a + new GstRTSPMessage, will dispatch it and will send a response. + + We will briefly describe how it deals with some common requests. + + - DESCRIBE: + + locates the GstRTSPMedia for the url, prepares it and asks the sdp helper + function to construct an SDP from the caps of the prepared media pipeline. + It will also cache the url+media object so that it can be reused later. + + - SETUP + + A new GstRTSPSession object will be created from the GstRTSPSessionPool + object configured in the GstRTSPClient. This session will contain the + configuration of the client regarding the media it is streaming and the + ports/transport it negotiated with the server. + + The sessionid is set in the response header. The client will add the + sessionid to any further SETUP/PLAY/PAUSE/TEARDOWN request so that we can + always find the session again. + + The session configuration for a sessionid will have a link to the prepared + GstRTSPMedia object of the stream. The port and transport of the client is + stored in the session configuration. + + - PLAY + + The session configuration is retrieved with the sessionid and the client + ports are configured in the UDP sinks, then the streaming to the client + is started. + + - PAUSE + + The session configuration is retrieved with the sessionid and the client + ports are removed from the UDP sinks, the streaming to the client + pauses. + + - TEARDOWN + + The session configuration is released along with its link to the + GstRTSPMedia object. When no more clients are refering to the GstRTSPMedia + object, it can be released as well. + diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 1a5954c5b0..7dd1419902 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -418,7 +418,6 @@ default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) stream = g_new0 (GstRTSPMediaStream, 1); stream->media = media; stream->payloader = pay; - stream->idx = media->streams->len; pad = gst_element_get_static_pad (pay, "src"); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 6eafdd0a98..f44192c590 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -64,11 +64,13 @@ struct _GstRTSPMediaFactory { /** * GstRTSPMediaFactoryClass: - * @gen_key: convert @url to a key for caching media - * @get_element: Construct an return a #GstElement thast is a #GstBin containing - * the elements to use for the media. The bin should contain payloaders - * pay%d for each stream. The default implementation of this functions - * returns the bin created from the launch parameter. + * @gen_key: convert @url to a key for caching shared #GstRTSPMedia objects. + * The default implementation of this function will use the complete URL + * including the query parameters to return a key. + * @get_element: Construct and return a #GstElement that is a #GstBin containing + * the elements to use for streaming the media. The bin should contain + * payloaders pay%d for each stream. The default implementation of this + * function returns the bin created from the launch parameter. * @construct: the vmethod that will be called when the factory has to create the * #GstRTSPMedia for @url. The default implementation of this * function calls get_element to retrieve an element and then looks for @@ -77,7 +79,7 @@ struct _GstRTSPMediaFactory { * implementation will configure the 'shared' property of the media. * @handle_message: Handle a bus message for @media created from @factory. * - * the #GstRTSPMediaFactory class structure. + * The #GstRTSPMediaFactory class structure. */ struct _GstRTSPMediaFactoryClass { GObjectClass parent_class; @@ -90,8 +92,6 @@ struct _GstRTSPMediaFactoryClass { void (*handle_message) (GstRTSPMediaFactory *factory, GstRTSPMedia *media, GstMessage *message); - - }; GType gst_rtsp_media_factory_get_type (void); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 023a153266..f619f02225 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -386,7 +386,7 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) /* prepare the pipeline objects to handle @stream in @media */ static gboolean -setup_stream (GstRTSPMediaStream *stream, GstRTSPMedia *media) +setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) { gchar *name; GstPad *pad; @@ -399,16 +399,16 @@ setup_stream (GstRTSPMediaStream *stream, GstRTSPMedia *media) gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsrc[1]); /* hook up the stream to the RTP session elements. */ - name = g_strdup_printf ("send_rtp_sink_%d", stream->idx); + name = g_strdup_printf ("send_rtp_sink_%d", idx); stream->send_rtp_sink = gst_element_get_request_pad (media->rtpbin, name); g_free (name); - name = g_strdup_printf ("send_rtp_src_%d", stream->idx); + name = g_strdup_printf ("send_rtp_src_%d", idx); stream->send_rtp_src = gst_element_get_static_pad (media->rtpbin, name); g_free (name); - name = g_strdup_printf ("send_rtcp_src_%d", stream->idx); + name = g_strdup_printf ("send_rtcp_src_%d", idx); stream->send_rtcp_src = gst_element_get_request_pad (media->rtpbin, name); g_free (name); - name = g_strdup_printf ("recv_rtcp_sink_%d", stream->idx); + name = g_strdup_printf ("recv_rtcp_sink_%d", idx); stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name); g_free (name); @@ -478,7 +478,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) stream = gst_rtsp_media_get_stream (media, i); - setup_stream (stream, media); + setup_stream (stream, i, media); } /* first go to PAUSED */ diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 1fb685f105..94cb097efd 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -43,7 +43,6 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass; * GstRTSPMediaStream: * * @media: the owner #GstRTSPMedia - * @idx: the stream index * @srcpad: the srcpad of the stream * @payloader: the payloader of the format * @prepared: if the stream is prepared for streaming @@ -62,8 +61,6 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass; struct _GstRTSPMediaStream { GstRTSPMedia *media; - guint idx; - GstPad *srcpad; GstElement *payloader; gboolean prepared; diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 873ca37b01..c77fcea7e0 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -42,7 +42,7 @@ static void gst_rtsp_server_get_property (GObject *object, guint propid, static void gst_rtsp_server_set_property (GObject *object, guint propid, const GValue *value, GParamSpec *pspec); -static GstRTSPClient * gst_rtsp_server_accept_client (GstRTSPServer *server, +static GstRTSPClient * default_accept_client (GstRTSPServer *server, GIOChannel *channel); static void @@ -99,7 +99,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) "The media mapping to use for client session", GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - klass->accept_client = gst_rtsp_server_accept_client; + klass->accept_client = default_accept_client; } static void @@ -438,7 +438,7 @@ bind_failed: /* default method for creating a new client object in the server to accept and * handle a client connection on this server */ static GstRTSPClient * -gst_rtsp_server_accept_client (GstRTSPServer *server, GIOChannel *channel) +default_accept_client (GstRTSPServer *server, GIOChannel *channel) { GstRTSPClient *client; diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index e719873a96..73c5b131a5 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -106,12 +106,12 @@ void gst_rtsp_server_set_media_mapping (GstRTSPServer *serve GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *server); gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, - GstRTSPServer *server); + GstRTSPServer *server); GIOChannel * gst_rtsp_server_get_io_channel (GstRTSPServer *server); GSource * gst_rtsp_server_create_watch (GstRTSPServer *server); guint gst_rtsp_server_attach (GstRTSPServer *server, - GMainContext *context); + GMainContext *context); G_END_DECLS From 27f069b43c743aa369f01f51c247328ed6b30e8b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Jan 2009 16:24:10 +0100 Subject: [PATCH 0055/1776] More cleanups Don't keep a reference to the GstRTSPMedia in the stream. Free more things when freeing the GstRTSPMedia. --- gst/rtsp-server/rtsp-client.c | 12 ++++++----- gst/rtsp-server/rtsp-media-factory.c | 1 - gst/rtsp-server/rtsp-media.c | 31 ++++++++++++++++------------ gst/rtsp-server/rtsp-media.h | 8 +++---- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index bd4303dbae..3973cd5db8 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -435,19 +435,16 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re } g_strfreev (transports); - g_free (ct->destination); - ct->destination = g_strdup (inet_ntoa (client->address.sin_addr)); - /* we have not found anything usable, error out */ - if (!have_transport) { + if (!have_transport) goto unsupported_transports; - } /* we have a valid transport, check if we can handle it */ if (ct->trans != GST_RTSP_TRANS_RTP) goto unsupported_transports; if (ct->profile != GST_RTSP_PROFILE_AVP) goto unsupported_transports; + supported = GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP; if (!(ct->lower_transport & supported)) @@ -456,6 +453,10 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re if (client->session_pool == NULL) goto no_pool; + /* we have a valid transport now, set the destination of the client. */ + g_free (ct->destination); + ct->destination = g_strdup (inet_ntoa (client->address.sin_addr)); + /* a setup request creates a session for a client, check if the client already * sent a session id to us */ res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); @@ -478,6 +479,7 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re /* get a handle to the configuration of the media in the session */ if ((m = find_media (client, uri, request))) { + /* manage the media in our session now */ media = gst_rtsp_session_manage_media (session, uri, m); } } diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 7dd1419902..84ac2fe5fb 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -416,7 +416,6 @@ default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) /* create the stream */ stream = g_new0 (GstRTSPMediaStream, 1); - stream->media = media; stream->payloader = pay; pad = gst_element_get_static_pad (pay, "src"); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index f619f02225..fcb2fa8002 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -56,11 +56,16 @@ static void gst_rtsp_media_init (GstRTSPMedia * media) { media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); + media->complete = FALSE; } static void gst_rtsp_media_stream_free (GstRTSPMediaStream *stream) { + if (stream->caps) + gst_caps_unref (stream->caps); + + g_free (stream); } static void @@ -80,6 +85,8 @@ gst_rtsp_media_finalize (GObject * obj) } g_array_free (media->streams, TRUE); + gst_object_unref (media->pipeline); + G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); } @@ -188,7 +195,8 @@ gst_rtsp_media_n_streams (GstRTSPMedia *media) * * Retrieve the stream with index @idx from @media. * - * Returns: the #GstRTSPMediaStream at index @idx. + * Returns: the #GstRTSPMediaStream at index @idx or %NULL when a stream with + * that index did not exist. */ GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx) @@ -196,9 +204,11 @@ gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx) GstRTSPMediaStream *res; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - g_return_val_if_fail (idx < media->streams->len, NULL); - res = g_array_index (media->streams, GstRTSPMediaStream *, idx); + if (idx < media->streams->len) + res = g_array_index (media->streams, GstRTSPMediaStream *, idx); + else + res = NULL; return res; } @@ -315,19 +325,13 @@ again: /* we keep these elements, we configure all in configure_transport when the * server told us to really use the UDP ports. */ - stream->udpsrc[0] = gst_object_ref (udpsrc0); - stream->udpsrc[1] = gst_object_ref (udpsrc1); - stream->udpsink[0] = gst_object_ref (udpsink0); - stream->udpsink[1] = gst_object_ref (udpsink1); + stream->udpsrc[0] = udpsrc0; + stream->udpsrc[1] = udpsrc1; + stream->udpsink[0] = udpsink0; + stream->udpsink[1] = udpsink1; stream->server_port.min = rtpport; stream->server_port.max = rtcpport; - /* they are ours now */ - gst_object_sink (udpsrc0); - gst_object_sink (udpsrc1); - gst_object_sink (udpsink0); - gst_object_sink (udpsink1); - return TRUE; /* ERRORS */ @@ -504,6 +508,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) /* and back to PAUSED for live pipelines */ ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); + /* unlock the udp src elements */ n_streams = gst_rtsp_media_n_streams (media); for (i = 0; i < n_streams; i++) { GstRTSPMediaStream *stream; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 94cb097efd..cf744fad37 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -59,14 +59,10 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass; * The definition of a media stream. The streams are identified by @id. */ struct _GstRTSPMediaStream { - GstRTSPMedia *media; - GstPad *srcpad; GstElement *payloader; gboolean prepared; - GstRTSPRange server_port; - /* pads on the rtpbin */ GstPad *recv_rtcp_sink; GstPad *send_rtp_sink; @@ -78,6 +74,9 @@ struct _GstRTSPMediaStream { GstElement *udpsrc[2]; GstElement *udpsink[2]; + /* server ports for sending/receiving */ + GstRTSPRange server_port; + /* the caps of the stream */ gulong caps_sig; GstCaps *caps; @@ -102,6 +101,7 @@ struct _GstRTSPMedia { GObject parent; gboolean shared; + gboolean complete; GstElement *element; GArray *streams; From ae2521096aebf5d05a1c889cf082d36855583965 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Jan 2009 17:06:26 +0100 Subject: [PATCH 0056/1776] Fix various leaks Fix some leaks. --- gst/rtsp-server/rtsp-client.c | 8 +++++++- gst/rtsp-server/rtsp-media.c | 3 ++- gst/rtsp-server/rtsp-sdp.c | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3973cd5db8..610428a1a7 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -86,6 +86,7 @@ send_response (GstRTSPClient *client, GstRTSPMessage *response) #endif gst_rtsp_connection_send (client->connection, response, NULL); + gst_rtsp_message_unset (response); } static void @@ -496,6 +497,7 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re /* serialize the server transport */ trans_str = gst_rtsp_transport_as_text (st); + gst_rtsp_transport_free (st); /* construct the response now */ code = GST_RTSP_STS_OK; @@ -752,8 +754,12 @@ handle_client (GstRTSPClient *client) /* ERRORS */ receive_failed: { + gchar *str; + str = gst_rtsp_strresult (res); g_message ("receive failed %d (%s), disconnect client %p", res, - gst_rtsp_strresult (res), client); + str, client); + g_free (str); + gst_rtsp_message_unset (&request); gst_rtsp_connection_close (client->connection); g_object_unref (client); return NULL; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index fcb2fa8002..6178e2167b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -85,7 +85,8 @@ gst_rtsp_media_finalize (GObject * obj) } g_array_free (media->streams, TRUE); - gst_object_unref (media->pipeline); + if (media->pipeline) + gst_object_unref (media->pipeline); G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); } diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 4a53b65769..52acf6e078 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -139,6 +139,7 @@ gst_rtsp_sdp_from_media (GstRTSPMedia *media) g_string_free (fmtp, TRUE); } gst_sdp_message_add_media (sdp, smedia); + gst_sdp_media_free (smedia); } return sdp; From f303eef9bb41bf87039042aa2e96cb607a7eac4a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 31 Jan 2009 19:50:33 +0100 Subject: [PATCH 0057/1776] Drop const from functions dealing with urls Drop const from GstRTSPUrl stuff because the .h files in gst-plugins-base don't have the right const in them. --- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-media-factory.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 610428a1a7..465b2ec624 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -117,7 +117,7 @@ compare_uri (const GstRTSPUrl *uri1, const GstRTSPUrl *uri2) * but is cached for when the same client (without breaking the connection) is * doing a setup for the exact same url. */ static GstRTSPMedia * -find_media (GstRTSPClient *client, const GstRTSPUrl *uri, GstRTSPMessage *request) +find_media (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) { GstRTSPMediaFactory *factory; GstRTSPMedia *media; diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 84ac2fe5fb..02614e65de 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -327,7 +327,7 @@ default_gen_key (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) { gchar *result; - result = gst_rtsp_url_get_request_uri (url); + result = gst_rtsp_url_get_request_uri ((GstRTSPUrl *)url); return result; } From d5a00f1f23744e6fa6f7e8c767c8f4d03e72646d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 3 Feb 2009 19:32:38 +0100 Subject: [PATCH 0058/1776] Rework the way we handle transports for streams Make the media accept an array of transports for the streams that we have configured for the play/pause requests. Implement server states for a client and its media. Require 0.10.22.1 (git HEAD) of gstreamer. --- configure.ac | 4 +- gst/rtsp-server/rtsp-client.c | 42 ++++++++++- gst/rtsp-server/rtsp-media.c | 133 ++++++++++++++++++++------------- gst/rtsp-server/rtsp-media.h | 24 ++++-- gst/rtsp-server/rtsp-session.c | 96 +++++++++++++----------- gst/rtsp-server/rtsp-session.h | 24 ++++-- 6 files changed, 208 insertions(+), 115 deletions(-) diff --git a/configure.ac b/configure.ac index 9fdd1a1eee..a5eb5249fb 100644 --- a/configure.ac +++ b/configure.ac @@ -37,8 +37,8 @@ AC_SUBST(GST_MAJORMINOR) AM_PROG_LIBTOOL dnl *** required versions of GStreamer stuff *** -GST_REQ=0.10.20 -GSTPB_REQ=0.10.20 +GST_REQ=0.10.22.1 +GSTPB_REQ=0.10.22.1 dnl export for .pc files AC_SUBST([GST_REQ]) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 465b2ec624..99c92fa5b6 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -287,8 +287,12 @@ handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re if (!media) goto not_found; + /* the session state must be playing or recording */ + if (media->state != GST_RTSP_STATE_PLAYING && + media->state != GST_RTSP_STATE_RECORDING) + goto invalid_state; + gst_rtsp_session_media_pause (media); - g_object_unref (session); /* construct the response now */ code = GST_RTSP_STS_OK; @@ -296,6 +300,10 @@ handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re send_response (client, &response); + /* the state is now READY */ + media->state = GST_RTSP_STATE_READY; + g_object_unref (session); + return FALSE; /* ERRORS */ @@ -308,6 +316,11 @@ not_found: send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); return FALSE; } +invalid_state: + { + send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request); + return FALSE; + } } static gboolean @@ -329,6 +342,11 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *req if (!media) goto not_found; + /* the session state must be playing or ready */ + if (media->state != GST_RTSP_STATE_PLAYING && + media->state != GST_RTSP_STATE_READY) + goto invalid_state; + /* grab RTPInfo from the payloaders now */ rtpinfo = g_string_new (""); @@ -362,6 +380,8 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *req /* start playing after sending the request */ gst_rtsp_session_media_play (media); + + media->state = GST_RTSP_STATE_PLAYING; g_object_unref (session); return FALSE; @@ -377,6 +397,11 @@ not_found: send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); return FALSE; } +invalid_state: + { + send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request); + return FALSE; + } } static gboolean @@ -508,10 +533,23 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str); g_free (trans_str); - g_object_unref (session); send_response (client, &response); + /* update the state */ + switch (media->state) { + case GST_RTSP_STATE_PLAYING: + case GST_RTSP_STATE_RECORDING: + case GST_RTSP_STATE_READY: + /* no state change */ + break; + default: + media->state = GST_RTSP_STATE_READY; + break; + } + + g_object_unref (session); + return TRUE; /* ERRORS */ diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 6178e2167b..b2e4cd6569 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -538,100 +538,125 @@ state_failed: } } -gboolean -gst_rtsp_media_stream_add (GstRTSPMediaStream *stream, GstRTSPTransport *ct) -{ - g_return_val_if_fail (stream != NULL, FALSE); - g_return_val_if_fail (ct != NULL, FALSE); - g_return_val_if_fail (stream->prepared, FALSE); - - g_message ("adding %s:%d", ct->destination, ct->client_port.min); - - g_signal_emit_by_name (stream->udpsink[0], "add", ct->destination, ct->client_port.min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "add", ct->destination, ct->client_port.max, NULL); - - return TRUE; -} - -gboolean -gst_rtsp_media_stream_remove (GstRTSPMediaStream *stream, GstRTSPTransport *ct) -{ - g_return_val_if_fail (stream != NULL, FALSE); - g_return_val_if_fail (ct != NULL, FALSE); - g_return_val_if_fail (stream->prepared, FALSE); - - g_message ("removing %s:%d", ct->destination, ct->client_port.min); - - g_signal_emit_by_name (stream->udpsink[0], "remove", ct->destination, ct->client_port.min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "remove", ct->destination, ct->client_port.max, NULL); - - return TRUE; -} - /** * gst_rtsp_media_play: * @media: a #GstRTSPMedia + * @transports: a GArray of #GstRTSPMediaTrans pointers * - * Tell the @media to start playing and streaming to the client. + * Start playing @media for to the transports in @transports. * - * Returns: a #GstStateChangeReturn + * Returns: %TRUE on success. */ -GstStateChangeReturn -gst_rtsp_media_play (GstRTSPMedia *media) +gboolean +gst_rtsp_media_play (GstRTSPMedia *media, GArray *transports) { + gint i; GstStateChangeReturn ret; - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_STATE_CHANGE_FAILURE); - g_return_val_if_fail (media->prepared, GST_STATE_CHANGE_FAILURE); + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + g_return_val_if_fail (transports != NULL, FALSE); + g_return_val_if_fail (media->prepared, FALSE); + + for (i = 0; i < transports->len; i++) { + GstRTSPMediaTrans *tr; + GstRTSPMediaStream *stream; + GstRTSPTransport *trans; + + /* we need a non-NULL entry in the array */ + tr = g_array_index (transports, GstRTSPMediaTrans *, i); + if (tr == NULL) + continue; + + /* we need a transport */ + if (!(trans = tr->transport)) + continue; + + /* get the stream and add the destinations */ + stream = gst_rtsp_media_get_stream (media, tr->idx); + + g_message ("adding %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); + + g_signal_emit_by_name (stream->udpsink[0], "add", trans->destination, trans->client_port.min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "add", trans->destination, trans->client_port.max, NULL); + } g_message ("playing"); ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); - return ret; + return TRUE; } /** * gst_rtsp_media_pause: * @media: a #GstRTSPMedia + * @transports: a array of #GstRTSPTransport pointers * - * Tell the @media to pause. + * Pause playing @media for to the transports in @transports. * - * Returns: a #GstStateChangeReturn + * Returns: %TRUE on success. */ -GstStateChangeReturn -gst_rtsp_media_pause (GstRTSPMedia *media) +gboolean +gst_rtsp_media_pause (GstRTSPMedia *media, GArray *transports) { + gint i; GstStateChangeReturn ret; - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_STATE_CHANGE_FAILURE); - g_return_val_if_fail (media->prepared, GST_STATE_CHANGE_FAILURE); + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + g_return_val_if_fail (transports != NULL, FALSE); + g_return_val_if_fail (media->prepared, FALSE); - g_message ("paused"); + for (i = 0; i < transports->len; i++) { + GstRTSPMediaTrans *tr; + GstRTSPMediaStream *stream; + GstRTSPTransport *trans; + + /* we need a non-NULL entry in the array */ + tr = g_array_index (transports, GstRTSPMediaTrans *, i); + if (tr == NULL) + continue; + + /* we need a transport */ + if (!(trans = tr->transport)) + continue; + + /* get the stream and add the destinations */ + stream = gst_rtsp_media_get_stream (media, tr->idx); + + g_message ("removing %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); + + g_signal_emit_by_name (stream->udpsink[0], "remove", trans->destination, trans->client_port.min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "remove", trans->destination, trans->client_port.max, NULL); + } + + g_message ("pause"); ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); - return ret; + return TRUE; } /** - * gst_rtsp_media_stop: + * gst_rtsp_media_stream_stop: * @media: a #GstRTSPMedia + * @transports: a GArray of #GstRTSPMediaTrans pointers * - * Tell the @media to stop playing. After this call the media - * cannot be played or paused anymore + * Stop playing @media for to the transports in @transports. * - * Returns: a #GstStateChangeReturn + * Returns: %TRUE on success. */ -GstStateChangeReturn -gst_rtsp_media_stop (GstRTSPMedia *media) +gboolean +gst_rtsp_media_stop (GstRTSPMedia *media, GArray *transports) { GstStateChangeReturn ret; - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_STATE_CHANGE_FAILURE); - g_return_val_if_fail (media->prepared, GST_STATE_CHANGE_FAILURE); + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + g_return_val_if_fail (transports != NULL, FALSE); + g_return_val_if_fail (media->prepared, FALSE); + + gst_rtsp_media_pause (media, transports); g_message ("stop"); ret = gst_element_set_state (media->pipeline, GST_STATE_NULL); - return ret; + return TRUE; } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index cf744fad37..dfb6e89c13 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -38,6 +38,20 @@ G_BEGIN_DECLS typedef struct _GstRTSPMediaStream GstRTSPMediaStream; typedef struct _GstRTSPMedia GstRTSPMedia; typedef struct _GstRTSPMediaClass GstRTSPMediaClass; +typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans; + +/** + * GstRTSPMediaTrans: + * @idx: a stream index + * @transport: a transport description + * + * A Transport description for stream @idx + */ +struct _GstRTSPMediaTrans { + guint idx; + + GstRTSPTransport *transport; +}; /** * GstRTSPMediaStream: @@ -136,13 +150,9 @@ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); guint gst_rtsp_media_n_streams (GstRTSPMedia *media); GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); -/* add destinations to a stream */ -gboolean gst_rtsp_media_stream_add (GstRTSPMediaStream *stream, GstRTSPTransport *ct); -gboolean gst_rtsp_media_stream_remove (GstRTSPMediaStream *stream, GstRTSPTransport *ct); - -GstStateChangeReturn gst_rtsp_media_play (GstRTSPMedia *media); -GstStateChangeReturn gst_rtsp_media_pause (GstRTSPMedia *media); -GstStateChangeReturn gst_rtsp_media_stop (GstRTSPMedia *media); +gboolean gst_rtsp_media_play (GstRTSPMedia *media, GArray *trans); +gboolean gst_rtsp_media_pause (GstRTSPMedia *media, GArray *trans); +gboolean gst_rtsp_media_stop (GstRTSPMedia *media, GArray *trans); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index cd5fd85eea..8ccd7331e0 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -42,10 +42,10 @@ gst_rtsp_session_init (GstRTSPSession * session) } static void -gst_rtsp_session_free_stream (GstRTSPSessionStream *stream, GstRTSPSessionMedia *media) +gst_rtsp_session_free_stream (GstRTSPSessionStream *stream) { - if (stream->client_trans) - gst_rtsp_transport_free (stream->client_trans); + if (stream->trans.transport) + gst_rtsp_transport_free (stream->trans.transport); g_free (stream); } @@ -53,9 +53,19 @@ gst_rtsp_session_free_stream (GstRTSPSessionStream *stream, GstRTSPSessionMedia static void gst_rtsp_session_free_media (GstRTSPSessionMedia *media, GstRTSPSession *session) { - g_list_foreach (media->streams, (GFunc) gst_rtsp_session_free_stream, - media); - g_list_free (media->streams); + guint size, i; + + size = media->streams->len; + + for (i = 0; i < size; i++) { + GstRTSPSessionStream *stream; + + stream = g_array_index (media->streams, GstRTSPSessionStream *, i); + + if (stream) + gst_rtsp_session_free_stream (stream); + } + g_array_free (media->streams, TRUE); if (media->url) gst_rtsp_url_free (media->url); @@ -100,10 +110,22 @@ gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, GstRTSPMedia *media) { GstRTSPSessionMedia *result; + guint n_streams; + + g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); + g_return_val_if_fail (uri != NULL, NULL); + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + g_return_val_if_fail (media->prepared, NULL); result = g_new0 (GstRTSPSessionMedia, 1); result->media = media; result->url = gst_rtsp_url_copy ((GstRTSPUrl *)uri); + result->state = GST_RTSP_STATE_INIT; + + /* prealloc the streams now, filled with NULL */ + n_streams = gst_rtsp_media_n_streams (media); + result->streams = g_array_sized_new (FALSE, TRUE, sizeof (GstRTSPSessionStream *), n_streams); + g_array_set_size (result->streams, n_streams); sess->medias = g_list_prepend (sess->medias, result); @@ -158,29 +180,25 @@ gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, guint idx) { GstRTSPSessionStream *result; GstRTSPMediaStream *media_stream; - GList *walk; g_return_val_if_fail (media != NULL, NULL); g_return_val_if_fail (media->media != NULL, NULL); - media_stream = gst_rtsp_media_get_stream (media->media, idx); - if (media_stream == NULL) - goto no_media; + if (idx >= media->streams->len) + return NULL; - result = NULL; - for (walk = media->streams; walk; walk = g_list_next (walk)) { - result = (GstRTSPSessionStream *) walk->data; - - if (result->media_stream == media_stream) - break; - - result = NULL; - } + result = g_array_index (media->streams, GstRTSPSessionStream *, idx); if (result == NULL) { + media_stream = gst_rtsp_media_get_stream (media->media, idx); + if (media_stream == NULL) + goto no_media; + result = g_new0 (GstRTSPSessionStream, 1); + result->trans.idx = idx; + result->trans.transport = NULL; result->media_stream = media_stream; - media->streams = g_list_prepend (media->streams, result); + g_array_insert_val (media->streams, idx, result); } return result; @@ -232,9 +250,9 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, st->client_port = ct->client_port; /* keep track of the transports */ - if (stream->client_trans) - gst_rtsp_transport_free (stream->client_trans); - stream->client_trans = ct; + if (stream->trans.transport) + gst_rtsp_transport_free (stream->trans.transport); + stream->trans.transport = ct; st->server_port.min = stream->media_stream->server_port.min; st->server_port.max = stream->media_stream->server_port.max; @@ -242,28 +260,20 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, return st; } - /** * gst_rtsp_session_media_play: * @media: a #GstRTSPSessionMedia * * Tell the media object @media to start playing and streaming to the client. * - * Returns: a #GstStateChangeReturn + * Returns: %TRUE on success. */ -GstStateChangeReturn +gboolean gst_rtsp_session_media_play (GstRTSPSessionMedia *media) { - GstStateChangeReturn ret; - GstRTSPSessionStream *stream; - GList *walk; + gboolean ret; - for (walk = media->streams; walk; walk = g_list_next (walk)) { - stream = (GstRTSPSessionStream *) walk->data; - - gst_rtsp_media_stream_add (stream->media_stream, stream->client_trans); - } - ret = gst_rtsp_media_play (media->media); + ret = gst_rtsp_media_play (media->media, media->streams); return ret; } @@ -274,14 +284,14 @@ gst_rtsp_session_media_play (GstRTSPSessionMedia *media) * * Tell the media object @media to pause. * - * Returns: a #GstStateChangeReturn + * Returns: %TRUE on success. */ -GstStateChangeReturn +gboolean gst_rtsp_session_media_pause (GstRTSPSessionMedia *media) { - GstStateChangeReturn ret; + gboolean ret; - ret = gst_rtsp_media_pause (media->media); + ret = gst_rtsp_media_pause (media->media, media->streams); return ret; } @@ -293,14 +303,14 @@ gst_rtsp_session_media_pause (GstRTSPSessionMedia *media) * Tell the media object @media to stop playing. After this call the media * cannot be played or paused anymore * - * Returns: a #GstStateChangeReturn + * Returns: %TRUE on success. */ -GstStateChangeReturn +gboolean gst_rtsp_session_media_stop (GstRTSPSessionMedia *media) { - GstStateChangeReturn ret; + gboolean ret; - ret = gst_rtsp_media_stop (media->media); + ret = gst_rtsp_media_stop (media->media, media->streams); return ret; } diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 3ff5ba05f4..150434ac88 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -45,17 +45,18 @@ typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia; /** * GstRTSPSessionStream: + * @trans: the media transport + * @media_stream: the controlled media stream * * Configuration of a stream. A stream is an audio or video stream related to a * media. */ struct _GstRTSPSessionStream { + GstRTSPMediaTrans trans; + /* the stream of the media */ GstRTSPMediaStream *media_stream; - - /* client and server transports */ - GstRTSPTransport *client_trans; }; /** @@ -71,8 +72,11 @@ struct _GstRTSPSessionMedia /* the pipeline for the media */ GstRTSPMedia *media; + /* the server state */ + GstRTSPState state; + /* configuration for the different streams */ - GList *streams; + GArray *streams; }; /** @@ -96,21 +100,27 @@ struct _GstRTSPSessionClass { GType gst_rtsp_session_get_type (void); +/* create a new session */ GstRTSPSession * gst_rtsp_session_new (const gchar *sessionid); +/* handle media in a session */ GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, GstRTSPMedia *media); +/* get media in a session */ GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *uri); -GstStateChangeReturn gst_rtsp_session_media_play (GstRTSPSessionMedia *media); -GstStateChangeReturn gst_rtsp_session_media_pause (GstRTSPSessionMedia *media); -GstStateChangeReturn gst_rtsp_session_media_stop (GstRTSPSessionMedia *media); +/* control media */ +gboolean gst_rtsp_session_media_play (GstRTSPSessionMedia *media); +gboolean gst_rtsp_session_media_pause (GstRTSPSessionMedia *media); +gboolean gst_rtsp_session_media_stop (GstRTSPSessionMedia *media); +/* get stream config */ GstRTSPSessionStream * gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, guint idx); +/* configure transport */ GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, GstRTSPTransport *ct); From 077a31b8dfb9d95ba41f840d7736d6bcd4c5f0a4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 4 Feb 2009 09:57:55 +0100 Subject: [PATCH 0059/1776] Rename a variable Rename the 'server_port' variable to simply 'port'. --- gst/rtsp-server/rtsp-server.c | 10 ++++++---- gst/rtsp-server/rtsp-server.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index c77fcea7e0..b860563358 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -105,7 +105,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) static void gst_rtsp_server_init (GstRTSPServer * server) { - server->server_port = DEFAULT_PORT; + server->port = DEFAULT_PORT; server->backlog = DEFAULT_BACKLOG; server->session_pool = gst_rtsp_session_pool_new (); server->media_mapping = gst_rtsp_media_mapping_new (); @@ -142,7 +142,7 @@ gst_rtsp_server_set_port (GstRTSPServer *server, gint port) g_return_if_fail (GST_IS_RTSP_SERVER (server)); g_return_if_fail (port >= 1 && port <= 65535); - server->server_port = port; + server->port = port; } /** @@ -158,7 +158,7 @@ gst_rtsp_server_get_port (GstRTSPServer *server) { g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1); - return server->server_port; + return server->port; } /** @@ -367,7 +367,7 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) /* name the socket */ memset (&server->server_sin, 0, sizeof (server->server_sin)); server->server_sin.sin_family = AF_INET; /* network socket */ - server->server_sin.sin_port = htons (server->server_port); /* on port */ + server->server_sin.sin_port = htons (server->port); /* on port */ server->server_sin.sin_addr.s_addr = htonl (INADDR_ANY); /* for hosts */ /* bind it */ @@ -389,6 +389,8 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) "listened on server socket %d, returning from connection setup", server->server_sock.fd); + g_message ("listening on port %d", server->port); + return TRUE; /* ERRORS */ diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 73c5b131a5..9e455ac908 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -58,7 +58,7 @@ struct _GstRTSPServer { GObject parent; /* server information */ - gint server_port; + gint port; gint backlog; gchar *host; struct sockaddr_in server_sin; From e789a8fdf31aeae4234a2fb7a7e4b251b47edfa5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 4 Feb 2009 17:00:42 +0100 Subject: [PATCH 0060/1776] Cleanup of sessions and more Fix the refcounting of media and sessions in the client. Properly clean up the session data when the client performs a teardown. Add Server header to responses. Allow for multiple uri setups in one session. Add Range header to the PLAY response and add the range attribute to the SDP message. Fix the session pool remove method, it used the wrong key in the hashtable. Also give the ownership of the sessionid to the session object. --- gst/rtsp-server/rtsp-client.c | 60 +++++++++++++++++++++++------ gst/rtsp-server/rtsp-media.c | 30 +++++++++++++++ gst/rtsp-server/rtsp-media.h | 4 ++ gst/rtsp-server/rtsp-sdp.c | 4 ++ gst/rtsp-server/rtsp-session-pool.c | 4 +- gst/rtsp-server/rtsp-session.c | 51 ++++++++++++++++++++++-- gst/rtsp-server/rtsp-session.h | 3 +- 7 files changed, 137 insertions(+), 19 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 99c92fa5b6..0f18d2119b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -49,6 +49,8 @@ gst_rtsp_client_finalize (GObject * obj) { GstRTSPClient *client = GST_RTSP_CLIENT (obj); + g_message ("finalize client %p", client); + gst_rtsp_connection_free (client->connection); if (client->session_pool) g_object_unref (client->session_pool); @@ -81,6 +83,8 @@ gst_rtsp_client_new (void) static void send_response (GstRTSPClient *client, GstRTSPMessage *response) { + gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER, "GStreamer RTSP server"); + #ifdef DEBUG gst_rtsp_message_dump (response); #endif @@ -149,14 +153,17 @@ find_media (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) /* now keep track of the uri and the media */ client->uri = gst_rtsp_url_copy (uri); - client->media = g_object_ref (media); + client->media = media; } else { /* we have seen this uri before, used cached media */ - media = g_object_ref (client->media); + media = client->media; g_message ("reusing cached media %p", media); } + if (media) + g_object_ref (media); + return media; /* ERRORS */ @@ -243,12 +250,17 @@ handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage gst_rtsp_session_media_stop (media); - gst_rtsp_session_pool_remove (client->session_pool, session); - g_object_unref (session); + /* unmanage the media in the session, returns false if all media session + * are torn down. */ + if (!gst_rtsp_session_release_media (session, media)) { + /* remove the session */ + gst_rtsp_session_pool_remove (client->session_pool, session); - /* remove the session id from the request, which will also remove it from the - * response */ - gst_rtsp_message_remove_header (request, GST_RTSP_HDR_SESSION, -1); + /* remove the session id from the request, which will also remove it from the + * response */ + gst_rtsp_message_remove_header (request, GST_RTSP_HDR_SESSION, -1); + } + g_object_unref (session); /* construct the response now */ code = GST_RTSP_STS_OK; @@ -314,11 +326,13 @@ no_session: not_found: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + g_object_unref (session); return FALSE; } invalid_state: { send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request); + g_object_unref (session); return FALSE; } } @@ -333,6 +347,7 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *req GString *rtpinfo; guint n_streams, i; guint timestamp, seqnum; + gchar *str; if (!(session = ensure_session (client, request))) goto no_session; @@ -373,8 +388,12 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *req gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); /* add the RTP-Info header */ - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_RTP_INFO, rtpinfo->str); - g_string_free (rtpinfo, TRUE); + str = g_string_free (rtpinfo, FALSE); + gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RTP_INFO, str); + + /* add the range */ + str = gst_rtsp_range_to_string (&media->media->range); + gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RANGE, str); send_response (client, &response); @@ -395,11 +414,13 @@ no_session: not_found: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + g_object_unref (session); return FALSE; } invalid_state: { send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request); + g_object_unref (session); return FALSE; } } @@ -490,6 +511,11 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re /* we had a session in the request, find it again */ if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid))) goto session_not_found; + + /* get a handle to the configuration of the media in the session, this can + * return NULL if this is a new url to manage in this session. */ + media = gst_rtsp_session_get_media (session, uri); + need_session = FALSE; } else { @@ -497,10 +523,15 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re * something. */ if (!(session = gst_rtsp_session_pool_create (client->session_pool))) goto service_unavailable; + + /* we need a new media configuration in this session */ + media = NULL; + need_session = TRUE; } - if (need_session) { + /* we have no media, find one and manage it */ + if (media == NULL) { GstRTSPMedia *m; /* get a handle to the configuration of the media in the session */ @@ -509,8 +540,9 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re media = gst_rtsp_session_manage_media (session, uri, m); } } - /* get a handle to the configuration of the media in the session */ - if (!(media = gst_rtsp_session_get_media (session, uri))) + + /* if we stil have no media, error */ + if (media == NULL) goto not_found; /* get a handle to the stream in the media */ @@ -528,6 +560,7 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); + /* add the new session header for new session ids */ if (need_session) gst_rtsp_message_add_header (&response, GST_RTSP_HDR_SESSION, session->sessionid); @@ -566,6 +599,7 @@ not_found: no_stream: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + g_object_unref (media); return FALSE; } session_not_found: @@ -628,6 +662,8 @@ handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage if (!(sdp = gst_rtsp_sdp_from_media (media))) goto no_sdp; + g_object_unref (media); + gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b2e4cd6569..d0f8ba0397 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -76,6 +76,8 @@ gst_rtsp_media_finalize (GObject * obj) media = GST_RTSP_MEDIA (obj); + g_message ("finalize media %p", media); + for (i = 0; i < media->streams->len; i++) { GstRTSPMediaStream *stream; @@ -447,6 +449,31 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) return TRUE; } +static void +collect_media_stats (GstRTSPMedia *media) +{ + GstFormat format; + gint64 duration; + + media->range.unit = GST_RTSP_RANGE_NPT; + media->range.min.type = GST_RTSP_TIME_SECONDS; + media->range.min.seconds = 0.0; + + /* get the duration */ + format = GST_FORMAT_TIME; + if (!gst_element_query_duration (media->pipeline, &format, &duration)) + duration = -1; + + if (duration == -1) { + media->range.max.type = GST_RTSP_TIME_END; + media->range.max.seconds = -1; + } + else { + media->range.max.type = GST_RTSP_TIME_SECONDS; + media->range.max.seconds = ((gdouble)duration) / GST_SECOND; + } +} + /** * gst_rtsp_media_prepare: * @obj: a #GstRTSPMedia @@ -509,6 +536,9 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) /* and back to PAUSED for live pipelines */ ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); + /* collect stats about the media */ + collect_media_stats (media); + /* unlock the udp src elements */ n_streams = gst_rtsp_media_n_streams (media); for (i = 0; i < n_streams; i++) { diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index dfb6e89c13..c00b165476 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -18,6 +18,7 @@ */ #include +#include #include #ifndef __GST_RTSP_MEDIA_H__ @@ -129,6 +130,9 @@ struct _GstRTSPMedia { /* for TCP transport */ GstElement *multifdsink; + + /* the range of media */ + GstRTSPTimeRange range; }; struct _GstRTSPMediaClass { diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 52acf6e078..74baa109ab 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -33,6 +33,7 @@ gst_rtsp_sdp_from_media (GstRTSPMedia *media) { GstSDPMessage *sdp; guint i, n_streams; + gchar *rangestr; n_streams = gst_rtsp_media_n_streams (media); @@ -46,6 +47,9 @@ gst_rtsp_sdp_from_media (GstRTSPMedia *media) gst_sdp_message_add_time (sdp, "0", "0", NULL); gst_sdp_message_add_attribute (sdp, "tool", "GStreamer"); gst_sdp_message_add_attribute (sdp, "type", "broadcast"); + rangestr = gst_rtsp_range_to_string (&media->range); + gst_sdp_message_add_attribute (sdp, "range", rangestr); + g_free (rangestr); for (i = 0; i < n_streams; i++) { GstRTSPMediaStream *stream; diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 968d241795..426049856c 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -44,7 +44,7 @@ gst_rtsp_session_pool_init (GstRTSPSessionPool * pool) { pool->lock = g_mutex_new (); pool->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); + NULL, g_object_unref); } static void @@ -197,7 +197,7 @@ gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, GstRTSPSession *sess) g_return_if_fail (GST_IS_RTSP_SESSION (sess)); g_mutex_lock (pool->lock); - found = g_hash_table_remove (pool->sessions, sess); + found = g_hash_table_remove (pool->sessions, sess->sessionid); g_mutex_unlock (pool->lock); } diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 8ccd7331e0..8596ea78ef 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -44,6 +44,8 @@ gst_rtsp_session_init (GstRTSPSession * session) static void gst_rtsp_session_free_stream (GstRTSPSessionStream *stream) { + g_message ("free session stream %p", stream); + if (stream->trans.transport) gst_rtsp_transport_free (stream->trans.transport); @@ -57,6 +59,8 @@ gst_rtsp_session_free_media (GstRTSPSessionMedia *media, GstRTSPSession *session size = media->streams->len; + g_message ("free session media %p", media); + for (i = 0; i < size; i++) { GstRTSPSessionStream *stream; @@ -83,6 +87,8 @@ gst_rtsp_session_finalize (GObject * obj) session = GST_RTSP_SESSION (obj); + g_message ("finalize session %p", session); + /* free all media */ g_list_foreach (session->medias, (GFunc) gst_rtsp_session_free_media, session); @@ -98,10 +104,12 @@ gst_rtsp_session_finalize (GObject * obj) * gst_rtsp_session_manage_media: * @sess: a #GstRTSPSession * @url: the url for the media - * @obj: a #GstRTSPMediaObject + * @media: a #GstRTSPMediaObject * * Manage the media object @obj in @sess. @url will be used to retrieve this - * media object from the session with gst_rtsp_session_get_media(). + * media from the session with gst_rtsp_session_get_media(). + * + * Ownership is taken from @media. * * Returns: a new @GstRTSPSessionMedia object. */ @@ -129,11 +137,46 @@ gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, sess->medias = g_list_prepend (sess->medias, result); - g_message ("manage new media %p in session %p", media, sess); + g_message ("manage new media %p in session %p", media, result); return result; } +/** + * gst_rtsp_session_release_media: + * @sess: a #GstRTSPSession + * @media: a #GstRTSPMediaObject + * + * Release the managed @media in @sess, freeing the memory allocated by it. + * + * Returns: %TRUE if there are more media session left in @sess. + */ +gboolean +gst_rtsp_session_release_media (GstRTSPSession *sess, + GstRTSPSessionMedia *media) +{ + GList *walk, *next; + + g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), FALSE); + g_return_val_if_fail (media != NULL, FALSE); + + for (walk = sess->medias; walk;) { + GstRTSPSessionMedia *find; + + find = (GstRTSPSessionMedia *) walk->data; + next = g_list_next (walk); + + if (find == media) { + sess->medias = g_list_delete_link (sess->medias, walk); + + gst_rtsp_session_free_media (find, sess); + break; + } + walk = next; + } + return (sess->medias != NULL); +} + /** * gst_rtsp_session_get_media: * @sess: a #GstRTSPSession @@ -141,7 +184,7 @@ gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, * * Get the session media of the @url. * - * Returns: the configuration for @url in @sess. + * Returns: the configuration for @url in @sess. */ GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *url) diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 150434ac88..08104f15b8 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -107,10 +107,11 @@ GstRTSPSession * gst_rtsp_session_new (const gchar *sessi GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, GstRTSPMedia *media); +gboolean gst_rtsp_session_release_media (GstRTSPSession *sess, + GstRTSPSessionMedia *media); /* get media in a session */ GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *uri); - /* control media */ gboolean gst_rtsp_session_media_play (GstRTSPSessionMedia *media); gboolean gst_rtsp_session_media_pause (GstRTSPSessionMedia *media); From aedd4652f386747efc65c6d230600e7422c8cc4a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 4 Feb 2009 19:52:50 +0100 Subject: [PATCH 0061/1776] Add beginnings of session timeouts and limits Add the timeout value to the Session header for unusual timeout values. Allow us to configure a limit to the amount of active sessions in a pool. Set a limit on the amount of retry we do after a sessionid collision. Add properties to the sessionid and the timeout of a session. Keep track of creation time and last access time for sessions. --- gst/rtsp-server/rtsp-client.c | 12 +- gst/rtsp-server/rtsp-session-pool.c | 167 ++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-session-pool.h | 18 ++- gst/rtsp-server/rtsp-session.c | 142 ++++++++++++++++++++++- gst/rtsp-server/rtsp-session.h | 19 +++- 5 files changed, 341 insertions(+), 17 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 0f18d2119b..8405d22a51 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -561,8 +561,16 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); /* add the new session header for new session ids */ - if (need_session) - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_SESSION, session->sessionid); + if (need_session) { + gchar *str; + + if (session->timeout != 60) + str = g_strdup_printf ("%s; timeout=%d", session->sessionid, session->timeout); + else + str = g_strdup (session->sessionid); + + gst_rtsp_message_take_header (&response, GST_RTSP_HDR_SESSION, str); + } gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str); g_free (trans_str); diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 426049856c..8ce18efbf9 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -21,6 +21,19 @@ #undef DEBUG +#define DEFAULT_MAX_SESSIONS 0 + +enum +{ + PROP_0, + PROP_MAX_SESSIONS, + PROP_LAST +}; + +static void gst_rtsp_session_pool_get_property (GObject *object, guint propid, + GValue *value, GParamSpec *pspec); +static void gst_rtsp_session_pool_set_property (GObject *object, guint propid, + const GValue *value, GParamSpec *pspec); static void gst_rtsp_session_pool_finalize (GObject * object); static gchar * create_session_id (GstRTSPSessionPool *pool); @@ -34,8 +47,16 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) gobject_class = G_OBJECT_CLASS (klass); + gobject_class->get_property = gst_rtsp_session_pool_get_property; + gobject_class->set_property = gst_rtsp_session_pool_set_property; gobject_class->finalize = gst_rtsp_session_pool_finalize; + g_object_class_install_property (gobject_class, PROP_MAX_SESSIONS, + g_param_spec_uint ("max-sessions", "Max Sessions", + "the maximum amount of sessions (0 = unlimited)", + 0, G_MAXUINT, DEFAULT_MAX_SESSIONS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + klass->create_session_id = create_session_id; } @@ -45,6 +66,7 @@ gst_rtsp_session_pool_init (GstRTSPSessionPool * pool) pool->lock = g_mutex_new (); pool->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + pool->max_sessions = DEFAULT_MAX_SESSIONS; } static void @@ -58,6 +80,42 @@ gst_rtsp_session_pool_finalize (GObject * object) G_OBJECT_CLASS (gst_rtsp_session_pool_parent_class)->finalize (object); } +static void +gst_rtsp_session_pool_get_property (GObject *object, guint propid, + GValue *value, GParamSpec *pspec) +{ + GstRTSPSessionPool *pool = GST_RTSP_SESSION_POOL (object); + + switch (propid) { + case PROP_MAX_SESSIONS: + g_mutex_lock (pool->lock); + g_value_set_uint (value, pool->max_sessions); + g_mutex_unlock (pool->lock); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + break; + } +} + +static void +gst_rtsp_session_pool_set_property (GObject *object, guint propid, + const GValue *value, GParamSpec *pspec) +{ + GstRTSPSessionPool *pool = GST_RTSP_SESSION_POOL (object); + + switch (propid) { + case PROP_MAX_SESSIONS: + g_mutex_lock (pool->lock); + pool->max_sessions = g_value_get_uint (value); + g_mutex_unlock (pool->lock); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + break; + } +} + /** * gst_rtsp_session_pool_new: * @@ -75,12 +133,76 @@ gst_rtsp_session_pool_new (void) return result; } +/** + * gst_rtsp_session_pool_set_max_sessions: + * @pool: a #GstRTSPSessionPool + * @max: the maximum number of sessions + * + * Configure the maximum allowed number of sessions in @pool to @max. + * A value of 0 means an unlimited amount of sessions. + */ +void +gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool *pool, guint max) +{ + g_return_if_fail (GST_IS_RTSP_SESSION_POOL (pool)); + + g_mutex_lock (pool->lock); + pool->max_sessions = max; + g_mutex_unlock (pool->lock); +} + +/** + * gst_rtsp_session_pool_get_max_sessions: + * @pool: a #GstRTSPSessionPool + * + * Get the maximum allowed number of sessions in @pool. 0 means an unlimited + * amount of sessions. + * + * Returns: the maximum allowed number of sessions. + */ +guint +gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool *pool) +{ + guint result; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0); + + g_mutex_lock (pool->lock); + result = pool->max_sessions; + g_mutex_unlock (pool->lock); + + return result; +} + +/** + * gst_rtsp_session_pool_get_n_sessions: + * @pool: a #GstRTSPSessionPool + * + * Get the amount of active sessions in @pool. + * + * Returns: the amount of active sessions in @pool. + */ +guint +gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool *pool) +{ + guint result; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0); + + g_mutex_lock (pool->lock); + result = g_hash_table_size (pool->sessions); + g_mutex_unlock (pool->lock); + + return result; +} + /** * gst_rtsp_session_pool_find: * @pool: the pool to search * @sessionid: the session id * - * Find the session with @sessionid in @pool. + * Find the session with @sessionid in @pool. The access time of the session + * will be updated with gst_rtsp_session_touch(). * * Returns: the #GstRTSPSession with @sessionid or %NULL when the session did * not exist. g_object_unref() after usage. @@ -95,10 +217,13 @@ gst_rtsp_session_pool_find (GstRTSPSessionPool *pool, const gchar *sessionid) g_mutex_lock (pool->lock); result = g_hash_table_lookup (pool->sessions, sessionid); - if (result) + if (result) g_object_ref (result); g_mutex_unlock (pool->lock); + if (result) + gst_rtsp_session_touch (result); + return result; } @@ -129,11 +254,13 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool *pool) GstRTSPSession *result = NULL; GstRTSPSessionPoolClass *klass; gchar *id = NULL; + guint retry; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL); klass = GST_RTSP_SESSION_POOL_GET_CLASS (pool); + retry = 0; do { /* start by creating a new random session id, we assume that this is random * enough to not cause a collision, which we will check later */ @@ -146,11 +273,19 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool *pool) goto no_session; g_mutex_lock (pool->lock); + /* check session limit */ + if (pool->max_sessions > 0) { + if (g_hash_table_size (pool->sessions) >= pool->max_sessions) + goto too_many_sessions; + } /* check if the sessionid existed */ result = g_hash_table_lookup (pool->sessions, id); if (result) { - /* found, retry with a different session id*/ + /* found, retry with a different session id */ result = NULL; + retry++; + if (retry > 100) + goto collision; } else { /* not found, create session and insert it in the pool */ @@ -177,6 +312,20 @@ no_session: g_warning ("can't create session id with GstRTSPSessionPool %p", pool); return NULL; } +collision: + { + g_warning ("can't find unique sessionid for GstRTSPSessionPool %p", pool); + g_mutex_unlock (pool->lock); + g_free (id); + return NULL; + } +too_many_sessions: + { + g_warning ("session pool reached max sessions of %d", pool->max_sessions); + g_mutex_unlock (pool->lock); + g_free (id); + return NULL; + } } /** @@ -184,20 +333,22 @@ no_session: * @pool: a #GstRTSPSessionPool * @sess: a #GstRTSPSession * - * Remove @sess from @pool and Clean it up. + * Remove @sess from @pool, releasing the ref that the pool has on @sess. * - * Returns: a new #GstRTSPSession. + * Returns: %TRUE if the session was found and removed. */ -void +gboolean gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, GstRTSPSession *sess) { gboolean found; - g_return_if_fail (GST_IS_RTSP_SESSION_POOL (pool)); - g_return_if_fail (GST_IS_RTSP_SESSION (sess)); + g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), FALSE); + g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), FALSE); g_mutex_lock (pool->lock); found = g_hash_table_remove (pool->sessions, sess->sessionid); g_mutex_unlock (pool->lock); + + return found; } diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 9f65f41e3e..30df9bd264 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -40,7 +40,7 @@ typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; /** * GstRTSPSessionPool: - * + * @max_sessions: the maximum number of sessions. * @lock: locking the session hashtable * @session: hashtable of sessions indexed by the session id. * @@ -50,6 +50,8 @@ typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; struct _GstRTSPSessionPool { GObject parent; + guint max_sessions; + GMutex *lock; GHashTable *sessions; }; @@ -57,7 +59,7 @@ struct _GstRTSPSessionPool { /** * GstRTSPSessionPoolClass: * @create_session_id: create a new random session id. Subclasses can create - * custom session ids and should not check if the session exists. + * custom session ids and should not check if the session exists. */ struct _GstRTSPSessionPoolClass { GObjectClass parent_class; @@ -67,12 +69,20 @@ struct _GstRTSPSessionPoolClass { GType gst_rtsp_session_pool_get_type (void); +/* creating a session pool */ GstRTSPSessionPool * gst_rtsp_session_pool_new (void); +/* counting sessionss */ +void gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool *pool, guint max); +guint gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool *pool); + +guint gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool *pool); + +/* managing sessions */ +GstRTSPSession * gst_rtsp_session_pool_create (GstRTSPSessionPool *pool); GstRTSPSession * gst_rtsp_session_pool_find (GstRTSPSessionPool *pool, const gchar *sessionid); -GstRTSPSession * gst_rtsp_session_pool_create (GstRTSPSessionPool *pool); -void gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, +gboolean gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, GstRTSPSession *sess); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 8596ea78ef..3c538b4b62 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -22,6 +22,20 @@ #undef DEBUG +#define DEFAULT_TIMEOUT 60 + +enum +{ + PROP_0, + PROP_SESSIONID, + PROP_TIMEOUT, + PROP_LAST +}; + +static void gst_rtsp_session_get_property (GObject *object, guint propid, + GValue *value, GParamSpec *pspec); +static void gst_rtsp_session_set_property (GObject *object, guint propid, + const GValue *value, GParamSpec *pspec); static void gst_rtsp_session_finalize (GObject * obj); G_DEFINE_TYPE (GstRTSPSession, gst_rtsp_session, G_TYPE_OBJECT); @@ -33,12 +47,26 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass) gobject_class = G_OBJECT_CLASS (klass); + gobject_class->get_property = gst_rtsp_session_get_property; + gobject_class->set_property = gst_rtsp_session_set_property; gobject_class->finalize = gst_rtsp_session_finalize; + + g_object_class_install_property (gobject_class, PROP_SESSIONID, + g_param_spec_string ("sessionid", "Sessionid", "the session id", + NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_TIMEOUT, + g_param_spec_uint ("timeout", "timeout", "the timeout of the session (0 = never)", + 0, G_MAXUINT, DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void gst_rtsp_session_init (GstRTSPSession * session) { + session->timeout = DEFAULT_TIMEOUT; + g_get_current_time (&session->create_time); + gst_rtsp_session_touch (session); } static void @@ -100,6 +128,43 @@ gst_rtsp_session_finalize (GObject * obj) G_OBJECT_CLASS (gst_rtsp_session_parent_class)->finalize (obj); } +static void +gst_rtsp_session_get_property (GObject *object, guint propid, + GValue *value, GParamSpec *pspec) +{ + GstRTSPSession *session = GST_RTSP_SESSION (object); + + switch (propid) { + case PROP_SESSIONID: + g_value_set_string (value, session->sessionid); + break; + case PROP_TIMEOUT: + g_value_set_uint (value, gst_rtsp_session_get_timeout (session)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static void +gst_rtsp_session_set_property (GObject *object, guint propid, + const GValue *value, GParamSpec *pspec) +{ + GstRTSPSession *session = GST_RTSP_SESSION (object); + + switch (propid) { + case PROP_SESSIONID: + g_free (session->sessionid); + session->sessionid = g_value_dup_string (value); + break; + case PROP_TIMEOUT: + gst_rtsp_session_set_timeout (session, g_value_get_uint (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + /** * gst_rtsp_session_manage_media: * @sess: a #GstRTSPSession @@ -262,12 +327,76 @@ gst_rtsp_session_new (const gchar *sessionid) { GstRTSPSession *result; - result = g_object_new (GST_TYPE_RTSP_SESSION, NULL); - result->sessionid = g_strdup (sessionid); + g_return_val_if_fail (sessionid != NULL, NULL); + + result = g_object_new (GST_TYPE_RTSP_SESSION, "sessionid", sessionid, NULL); return result; } +/** + * gst_rtsp_session_get_sessionid: + * @session: a #GstRTSPSession + * + * Get the sessionid of @session. + * + * Returns: the sessionid of @session. The value remains valid as long as + * @session is alive. + */ +const gchar * +gst_rtsp_session_get_sessionid (GstRTSPSession *session) +{ + g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL); + + return session->sessionid; +} + +/** + * gst_rtsp_session_set_timeout: + * @session: a #GstRTSPSession + * @timeout: the new timeout + * + * Configure @session for a timeout of @timeout seconds. The session will be + * cleaned up when there is no activity for @timeout seconds. + */ +void +gst_rtsp_session_set_timeout (GstRTSPSession *session, guint timeout) +{ + g_return_if_fail (GST_IS_RTSP_SESSION (session)); + + session->timeout = timeout; +} + +/** + * gst_rtsp_session_get_timeout: + * @session: a #GstRTSPSession + * + * Get the timeout value of @session. + * + * Returns: the timeout of @session in seconds. + */ +guint +gst_rtsp_session_get_timeout (GstRTSPSession *session) +{ + g_return_val_if_fail (GST_IS_RTSP_SESSION (session), 0); + + return session->timeout; +} + +/** + * gst_rtsp_session_touch: + * @session: a #GstRTSPSession + * + * Update the last_access time of the session to the current time. + */ +void +gst_rtsp_session_touch (GstRTSPSession *session) +{ + g_return_if_fail (GST_IS_RTSP_SESSION (session)); + + g_get_current_time (&session->last_access); +} + /** * gst_rtsp_session_stream_init_udp: * @stream: a #GstRTSPSessionStream @@ -284,6 +413,9 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, { GstRTSPTransport *st; + g_return_val_if_fail (stream != NULL, NULL); + g_return_val_if_fail (ct != NULL, NULL); + /* prepare the server transport */ gst_rtsp_transport_new (&st); @@ -316,6 +448,8 @@ gst_rtsp_session_media_play (GstRTSPSessionMedia *media) { gboolean ret; + g_return_val_if_fail (media != NULL, FALSE); + ret = gst_rtsp_media_play (media->media, media->streams); return ret; @@ -334,6 +468,8 @@ gst_rtsp_session_media_pause (GstRTSPSessionMedia *media) { gboolean ret; + g_return_val_if_fail (media != NULL, FALSE); + ret = gst_rtsp_media_pause (media->media, media->streams); return ret; @@ -353,6 +489,8 @@ gst_rtsp_session_media_stop (GstRTSPSessionMedia *media) { gboolean ret; + g_return_val_if_fail (media != NULL, FALSE); + ret = gst_rtsp_media_stop (media->media, media->streams); return ret; diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 08104f15b8..d87922bd66 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -81,16 +81,25 @@ struct _GstRTSPSessionMedia /** * GstRTSPSession: + * @sessionid: the session id of the session + * @timeout: the timeout of the session + * @create_time: the time when the session was created + * @last_access: the time the session was last accessed + * @media: a list of #GstRTSPSessionMedia managed in this session * * Session information kept by the server for a specific client. * One client session, identified with a session id, can handle multiple medias - * identified with the media object. + * identified with the url of a media. */ struct _GstRTSPSession { GObject parent; gchar *sessionid; + guint timeout; + GTimeVal create_time; + GTimeVal last_access; + GList *medias; }; @@ -103,6 +112,14 @@ GType gst_rtsp_session_get_type (void); /* create a new session */ GstRTSPSession * gst_rtsp_session_new (const gchar *sessionid); +const gchar * gst_rtsp_session_get_sessionid (GstRTSPSession *session); + +void gst_rtsp_session_set_timeout (GstRTSPSession *session, guint timeout); +guint gst_rtsp_session_get_timeout (GstRTSPSession *session); + +/* touch the session, update last_access */ +void gst_rtsp_session_touch (GstRTSPSession *session); + /* handle media in a session */ GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, From ae9da4c5b088b67a2d9a4c188e4965a3dd63993e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 4 Feb 2009 20:10:39 +0100 Subject: [PATCH 0062/1776] Add more timeout stuff Add method to check if a session is expired. Add method to perform cleanup on a session pool. --- gst/rtsp-server/rtsp-session-pool.c | 28 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-session-pool.h | 3 +++ gst/rtsp-server/rtsp-session.c | 29 +++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-session.h | 3 ++- 4 files changed, 62 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 8ce18efbf9..43a5887baf 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -352,3 +352,31 @@ gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, GstRTSPSession *sess) return found; } +static gboolean +cleanup_func (gchar *sessionid, GstRTSPSession *sess, GstRTSPSessionPool *pool) +{ + return gst_rtsp_session_is_expired (sess); +} + +/** + * gst_rtsp_session_pool_cleanup: + * @pool: a #GstRTSPSessionPool + * + * Inspect all the sessions in @pool and remove the sessions that are inactive + * for more than their timeout. + * + * Returns: the amount of sessions that got removed. + */ +guint +gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool) +{ + guint result; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0); + + g_mutex_lock (pool->lock); + result = g_hash_table_foreach_remove (pool->sessions, (GHRFunc) cleanup_func, pool); + g_mutex_unlock (pool->lock); + + return result; +} diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 30df9bd264..dba8b764f6 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -85,6 +85,9 @@ GstRTSPSession * gst_rtsp_session_pool_find (GstRTSPSessionPoo gboolean gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, GstRTSPSession *sess); +/* perform session maintenance */ +guint gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool); + G_END_DECLS #endif /* __GST_RTSP_SESSION_POOL_H__ */ diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 3c538b4b62..8e8ae0eef0 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -397,6 +397,35 @@ gst_rtsp_session_touch (GstRTSPSession *session) g_get_current_time (&session->last_access); } +/** + * gst_rtsp_session_is_expired: + * @session: a #GstRTSPSession + * + * Check if @session timeout out. + * + * Returns: %TRUE if @session timed out + */ +gboolean +gst_rtsp_session_is_expired (GstRTSPSession *session) +{ + gboolean res; + GstClockTime last_access, now_ns; + GTimeVal now; + + g_return_val_if_fail (GST_IS_RTSP_SESSION (session), FALSE); + + last_access = GST_TIMEVAL_TO_TIME (session->last_access); + /* add timeout */ + last_access += session->timeout * GST_SECOND; + + g_get_current_time (&now); + now_ns = GST_TIMEVAL_TO_TIME (now); + + res = now_ns > last_access; + + return res; +} + /** * gst_rtsp_session_stream_init_udp: * @stream: a #GstRTSPSessionStream diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index d87922bd66..bcda0887d5 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -117,8 +117,9 @@ const gchar * gst_rtsp_session_get_sessionid (GstRTSPSession *se void gst_rtsp_session_set_timeout (GstRTSPSession *session, guint timeout); guint gst_rtsp_session_get_timeout (GstRTSPSession *session); -/* touch the session, update last_access */ +/* session timeout stuff */ void gst_rtsp_session_touch (GstRTSPSession *session); +gboolean gst_rtsp_session_is_expired (GstRTSPSession *session); /* handle media in a session */ GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess, From c5b06ab5f801321fc9ed9abe486c5f89b3cea030 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 10 Feb 2009 16:21:17 +0100 Subject: [PATCH 0063/1776] Use getters and setters in property code Use the getters and setters for the timeout property instead of locking ourselves. --- gst/rtsp-server/rtsp-session-pool.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 43a5887baf..94c157b648 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -88,9 +88,7 @@ gst_rtsp_session_pool_get_property (GObject *object, guint propid, switch (propid) { case PROP_MAX_SESSIONS: - g_mutex_lock (pool->lock); - g_value_set_uint (value, pool->max_sessions); - g_mutex_unlock (pool->lock); + g_value_set_uint (value, gst_rtsp_session_pool_get_max_sessions (pool)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -106,9 +104,7 @@ gst_rtsp_session_pool_set_property (GObject *object, guint propid, switch (propid) { case PROP_MAX_SESSIONS: - g_mutex_lock (pool->lock); - pool->max_sessions = g_value_get_uint (value); - g_mutex_unlock (pool->lock); + gst_rtsp_session_pool_set_max_sessions (pool, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); From 34152ec84085f475934236341e8f01840ea74a0b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 10 Feb 2009 16:24:13 +0100 Subject: [PATCH 0064/1776] Add timeout property Add a timeout property ot the client and make the other properties into GObject properties. --- gst/rtsp-server/rtsp-client.c | 116 +++++++++++++++++++++++++++++++++- gst/rtsp-server/rtsp-client.h | 4 ++ 2 files changed, 118 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8405d22a51..062b371c58 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -24,6 +24,21 @@ #undef DEBUG +#define DEFAULT_TIMEOUT 60 + +enum +{ + PROP_0, + PROP_TIMEOUT, + PROP_SESSION_POOL, + PROP_MEDIA_MAPPING, + PROP_LAST +}; + +static void gst_rtsp_client_get_property (GObject *object, guint propid, + GValue *value, GParamSpec *pspec); +static void gst_rtsp_client_set_property (GObject *object, guint propid, + const GValue *value, GParamSpec *pspec); static void gst_rtsp_client_finalize (GObject * obj); G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); @@ -35,12 +50,29 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gobject_class = G_OBJECT_CLASS (klass); + gobject_class->get_property = gst_rtsp_client_get_property; + gobject_class->set_property = gst_rtsp_client_set_property; gobject_class->finalize = gst_rtsp_client_finalize; + + g_object_class_install_property (gobject_class, PROP_SESSION_POOL, + g_param_spec_uint ("timeout", "Timeout", "The client timeout", + 0, G_MAXUINT, DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_SESSION_POOL, + g_param_spec_object ("session-pool", "Session Pool", + "The session pool to use for client session", + GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING, + g_param_spec_object ("media-mapping", "Media Mapping", + "The media mapping to use for client session", + GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void gst_rtsp_client_init (GstRTSPClient * client) { + client->timeout = DEFAULT_TIMEOUT; } /* A client is finalized when the connection is broken */ @@ -65,6 +97,48 @@ gst_rtsp_client_finalize (GObject * obj) G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj); } +static void +gst_rtsp_client_get_property (GObject *object, guint propid, + GValue *value, GParamSpec *pspec) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (object); + + switch (propid) { + case PROP_TIMEOUT: + g_value_set_uint (value, gst_rtsp_client_get_timeout (client)); + break; + case PROP_SESSION_POOL: + g_value_take_object (value, gst_rtsp_client_get_session_pool (client)); + break; + case PROP_MEDIA_MAPPING: + g_value_take_object (value, gst_rtsp_client_get_media_mapping (client)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static void +gst_rtsp_client_set_property (GObject *object, guint propid, + const GValue *value, GParamSpec *pspec) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (object); + + switch (propid) { + case PROP_TIMEOUT: + gst_rtsp_client_set_timeout (client, g_value_get_uint (value)); + break; + case PROP_SESSION_POOL: + gst_rtsp_client_set_session_pool (client, g_value_get_object (value)); + break; + case PROP_MEDIA_MAPPING: + gst_rtsp_client_set_media_mapping (client, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + /** * gst_rtsp_client_new: * @@ -83,13 +157,18 @@ gst_rtsp_client_new (void) static void send_response (GstRTSPClient *client, GstRTSPMessage *response) { + GTimeVal timeout; + gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER, "GStreamer RTSP server"); #ifdef DEBUG gst_rtsp_message_dump (response); #endif - gst_rtsp_connection_send (client->connection, response, NULL); + timeout.tv_sec = client->timeout; + timeout.tv_usec = 0; + + gst_rtsp_connection_send (client->connection, response, &timeout); gst_rtsp_message_unset (response); } @@ -208,6 +287,8 @@ ensure_session (GstRTSPClient *client, GstRTSPMessage *request) /* we had a session in the request, find it again */ if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid))) goto session_not_found; + + client->timeout = gst_rtsp_session_get_timeout (session); } else goto service_unavailable; @@ -770,8 +851,12 @@ handle_client (GstRTSPClient *client) GstRTSPVersion version; while (TRUE) { + GTimeVal timeout; + + timeout.tv_sec = client->timeout; + /* start by waiting for a message from the client */ - res = gst_rtsp_connection_receive (client->connection, &request, NULL); + res = gst_rtsp_connection_receive (client->connection, &request, &timeout); if (res < 0) goto receive_failed; @@ -891,6 +976,33 @@ accept_failed: } } +/** + * gst_rtsp_client_set_timeout: + * @client: a #GstRTSPClient + * @timeout: a timeout in seconds + * + * Set the connection timeout to @timeout seconds for @client. + */ +void +gst_rtsp_client_set_timeout (GstRTSPClient *client, guint timeout) +{ + client->timeout = timeout; +} + +/** + * gst_rtsp_client_get_timeout: + * @client: a #GstRTSPClient + * + * Get the connection timeout @client. + * + * Returns: the connection timeout for @client in seconds. + */ +guint +gst_rtsp_client_get_timeout (GstRTSPClient *client) +{ + return client->timeout; +} + /** * gst_rtsp_client_set_session_pool: * @client: a #GstRTSPClient diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 637bedf33f..694361f4dc 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -73,6 +73,7 @@ struct _GstRTSPClient { struct sockaddr_in address; GThread *thread; + guint timeout; GstRTSPSessionPool *session_pool; GstRTSPMediaMapping *media_mapping; @@ -96,6 +97,9 @@ void gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *mapping); GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client); +void gst_rtsp_client_set_timeout (GstRTSPClient *client, guint timeout); +guint gst_rtsp_client_get_timeout (GstRTSPClient *client); + gboolean gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel); From e1154c92d6eaab316a656e64e261529fbf54e1ea Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 13 Feb 2009 12:57:45 +0100 Subject: [PATCH 0065/1776] Some more session timeout handling Move the session header setting code to a central place so that we always add the timeout parameter too. Handle timeouts by running the session cleanup code. Stop media before cleaning up. --- gst/rtsp-server/rtsp-client.c | 70 ++++++++++++++++++----------- gst/rtsp-server/rtsp-session-pool.c | 3 +- gst/rtsp-server/rtsp-session.c | 2 + 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 062b371c58..ed19555000 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -155,7 +155,7 @@ gst_rtsp_client_new (void) } static void -send_response (GstRTSPClient *client, GstRTSPMessage *response) +send_response (GstRTSPClient *client, GstRTSPSession *session, GstRTSPMessage *response) { GTimeVal timeout; @@ -168,6 +168,22 @@ send_response (GstRTSPClient *client, GstRTSPMessage *response) timeout.tv_sec = client->timeout; timeout.tv_usec = 0; + /* add the new session header for new session ids */ + if (session) { + gchar *str; + + if (session->timeout != 60) + str = g_strdup_printf ("%s; timeout=%d", session->sessionid, session->timeout); + else + str = g_strdup (session->sessionid); + + gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION, str); + } + else { + /* remove the session id from the response */ + gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1); + } + gst_rtsp_connection_send (client->connection, response, &timeout); gst_rtsp_message_unset (response); } @@ -181,7 +197,7 @@ send_generic_response (GstRTSPClient *client, GstRTSPStatusCode code, gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); - send_response (client, &response); + send_response (client, NULL, &response); } static gboolean @@ -336,18 +352,14 @@ handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage if (!gst_rtsp_session_release_media (session, media)) { /* remove the session */ gst_rtsp_session_pool_remove (client->session_pool, session); - - /* remove the session id from the request, which will also remove it from the - * response */ - gst_rtsp_message_remove_header (request, GST_RTSP_HDR_SESSION, -1); } - g_object_unref (session); - /* construct the response now */ code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); - send_response (client, &response); + send_response (client, session, &response); + + g_object_unref (session); return FALSE; @@ -391,7 +403,7 @@ handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); - send_response (client, &response); + send_response (client, session, &response); /* the state is now READY */ media->state = GST_RTSP_STATE_READY; @@ -476,7 +488,7 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *req str = gst_rtsp_range_to_string (&media->media->range); gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RANGE, str); - send_response (client, &response); + send_response (client, session, &response); /* start playing after sending the request */ gst_rtsp_session_media_play (media); @@ -641,22 +653,10 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); - /* add the new session header for new session ids */ - if (need_session) { - gchar *str; - - if (session->timeout != 60) - str = g_strdup_printf ("%s; timeout=%d", session->sessionid, session->timeout); - else - str = g_strdup (session->sessionid); - - gst_rtsp_message_take_header (&response, GST_RTSP_HDR_SESSION, str); - } - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str); g_free (trans_str); - send_response (client, &response); + send_response (client, session, &response); /* update the state */ switch (media->state) { @@ -768,7 +768,7 @@ handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage gst_rtsp_message_take_body (&response, (guint8 *)str, strlen (str)); gst_sdp_message_free (sdp); - send_response (client, &response); + send_response (client, NULL, &response); return TRUE; @@ -808,7 +808,7 @@ handle_options_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage * gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str); g_free (str); - send_response (client, &response); + send_response (client, NULL, &response); } /* remove duplicate and trailing '/' */ @@ -854,11 +854,16 @@ handle_client (GstRTSPClient *client) GTimeVal timeout; timeout.tv_sec = client->timeout; + timeout.tv_usec = 0; /* start by waiting for a message from the client */ res = gst_rtsp_connection_receive (client->connection, &request, &timeout); - if (res < 0) + if (res < 0) { + if (res == GST_RTSP_ETIMEOUT) + goto timeout; + goto receive_failed; + } #ifdef DEBUG gst_rtsp_message_dump (&request); @@ -919,6 +924,13 @@ handle_client (GstRTSPClient *client) return NULL; /* ERRORS */ +timeout: + { + g_message ("client timed out"); + if (client->session_pool) + gst_rtsp_session_pool_cleanup (client->session_pool); + goto cleanup; + } receive_failed: { gchar *str; @@ -926,6 +938,10 @@ receive_failed: g_message ("receive failed %d (%s), disconnect client %p", res, str, client); g_free (str); + goto cleanup; + } +cleanup: + { gst_rtsp_message_unset (&request); gst_rtsp_connection_close (client->connection); g_object_unref (client); diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 94c157b648..d32b43fd42 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -217,8 +217,9 @@ gst_rtsp_session_pool_find (GstRTSPSessionPool *pool, const gchar *sessionid) g_object_ref (result); g_mutex_unlock (pool->lock); - if (result) + if (result) { gst_rtsp_session_touch (result); + } return result; } diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 8e8ae0eef0..d8faa61723 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -89,6 +89,8 @@ gst_rtsp_session_free_media (GstRTSPSessionMedia *media, GstRTSPSession *session g_message ("free session media %p", media); + gst_rtsp_session_media_stop (media); + for (i = 0; i < size; i++) { GstRTSPSessionStream *stream; From cd29e2a454945205144338b6c5dfcc61052e53bf Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 13 Feb 2009 16:39:36 +0100 Subject: [PATCH 0066/1776] Handle media bus messages Handle media bus messages in a custom mainloop and dispatch them to the RTSPMedia objects. Let the default implementation handle some common messages. --- gst/rtsp-server/rtsp-media-factory.h | 4 - gst/rtsp-server/rtsp-media.c | 190 +++++++++++++++++++++++++-- gst/rtsp-server/rtsp-media.h | 22 ++++ 3 files changed, 202 insertions(+), 14 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index f44192c590..ef3f6e8103 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -77,7 +77,6 @@ struct _GstRTSPMediaFactory { * pay%d to create the streams. * @configure: configure the media created with @construct. The default * implementation will configure the 'shared' property of the media. - * @handle_message: Handle a bus message for @media created from @factory. * * The #GstRTSPMediaFactory class structure. */ @@ -89,9 +88,6 @@ struct _GstRTSPMediaFactoryClass { GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); - - void (*handle_message) (GstRTSPMediaFactory *factory, GstRTSPMedia *media, - GstMessage *message); }; GType gst_rtsp_media_factory_get_type (void); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d0f8ba0397..2768a808a9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -34,12 +34,16 @@ static void gst_rtsp_media_set_property (GObject *object, guint propid, const GValue *value, GParamSpec *pspec); static void gst_rtsp_media_finalize (GObject * obj); +static gpointer do_loop (GstRTSPMediaClass *klass); +static gboolean default_handle_message (GstRTSPMedia *media, GstMessage *message); + G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); static void gst_rtsp_media_class_init (GstRTSPMediaClass * klass) { GObjectClass *gobject_class; + GError *error = NULL; gobject_class = G_OBJECT_CLASS (klass); @@ -50,6 +54,15 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) g_object_class_install_property (gobject_class, PROP_SHARED, g_param_spec_boolean ("shared", "Shared", "If this media pipeline can be shared", DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + klass->context = g_main_context_new (); + klass->loop = g_main_loop_new (klass->context, TRUE); + + klass->thread = g_thread_create ((GThreadFunc) do_loop, klass, TRUE, &error); + if (error != NULL) { + g_critical ("could not start bus thread: %s", error->message); + } + klass->handle_message = default_handle_message; } static void @@ -57,6 +70,8 @@ gst_rtsp_media_init (GstRTSPMedia * media) { media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); media->complete = FALSE; + media->is_live = FALSE; + media->buffering = FALSE; } static void @@ -87,6 +102,11 @@ gst_rtsp_media_finalize (GObject * obj) } g_array_free (media->streams, TRUE); + if (media->source) { + g_source_destroy (media->source); + g_source_unref (media->source); + } + if (media->pipeline) gst_object_unref (media->pipeline); @@ -123,6 +143,16 @@ gst_rtsp_media_set_property (GObject *object, guint propid, } } +static gpointer +do_loop (GstRTSPMediaClass *klass) +{ + g_message ("enter mainloop"); + g_main_loop_run (klass->loop); + g_message ("exit mainloop"); + + return NULL; +} + /** * gst_rtsp_media_new: * @@ -449,6 +479,23 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) return TRUE; } +static void +unlock_streams (GstRTSPMedia *media) +{ + guint i, n_streams; + + /* unlock the udp src elements */ + n_streams = gst_rtsp_media_n_streams (media); + for (i = 0; i < n_streams; i++) { + GstRTSPMediaStream *stream; + + stream = gst_rtsp_media_get_stream (media, i); + + gst_element_set_locked_state (stream->udpsrc[0], FALSE); + gst_element_set_locked_state (stream->udpsrc[1], FALSE); + } +} + static void collect_media_stats (GstRTSPMedia *media) { @@ -474,6 +521,92 @@ collect_media_stats (GstRTSPMedia *media) } } +static gboolean +default_handle_message (GstRTSPMedia *media, GstMessage *message) +{ + GstMessageType type; + + type = GST_MESSAGE_TYPE (message); + + switch (type) { + case GST_MESSAGE_STATE_CHANGED: + break; + case GST_MESSAGE_BUFFERING: + { + gint percent; + + gst_message_parse_buffering (message, &percent); + + /* no state management needed for live pipelines */ + if (media->is_live) + break; + + if (percent == 100) { + /* a 100% message means buffering is done */ + media->buffering = FALSE; + /* if the desired state is playing, go back */ + if (media->target_state == GST_STATE_PLAYING) { + g_message ("Buffering done, setting pipeline to PLAYING"); + gst_element_set_state (media->pipeline, GST_STATE_PLAYING); + } + else { + g_message ("Buffering done"); + } + } else { + /* buffering busy */ + if (media->buffering == FALSE) { + if (media->target_state == GST_STATE_PLAYING) { + /* we were not buffering but PLAYING, PAUSE the pipeline. */ + g_message ("Buffering, setting pipeline to PAUSED ..."); + gst_element_set_state (media->pipeline, GST_STATE_PAUSED); + } + else { + g_message ("Buffering ..."); + } + } + media->buffering = TRUE; + } + break; + } + case GST_MESSAGE_LATENCY: + { + gst_bin_recalculate_latency (GST_BIN_CAST (media->pipeline)); + break; + } + case GST_MESSAGE_ERROR: + { + GError *gerror; + gchar *debug; + + gst_message_parse_error (message, &gerror, &debug); + g_warning ("%p: got error %s (%s)", media, gerror->message, debug); + g_error_free (gerror); + g_free (debug); + break; + } + default: + g_message ("%p: got message type %s", media, gst_message_type_get_name (type)); + break; + } + return TRUE; +} + +static gboolean +bus_message (GstBus *bus, GstMessage *message, GstRTSPMedia *media) +{ + GstRTSPMediaClass *klass; + gboolean ret; + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + + if (klass->handle_message) + ret = klass->handle_message (media, message); + else + ret = FALSE; + + return ret; +} + /** * gst_rtsp_media_prepare: * @obj: a #GstRTSPMedia @@ -488,6 +621,8 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) { GstStateChangeReturn ret; guint i, n_streams; + GstRTSPMediaClass *klass; + GstBus *bus; if (media->prepared) goto was_prepared; @@ -495,6 +630,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) g_message ("preparing media %p", media); media->pipeline = gst_pipeline_new ("media-pipeline"); + bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline)); gst_bin_add (GST_BIN_CAST (media->pipeline), media->element); @@ -515,6 +651,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) /* first go to PAUSED */ ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); + media->target_state = GST_STATE_PAUSED; switch (ret) { case GST_STATE_CHANGE_SUCCESS: @@ -524,6 +661,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) case GST_STATE_CHANGE_NO_PREROLL: /* we need to go to PLAYING */ g_message ("live media %p", media); + media->is_live = TRUE; ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); break; case GST_STATE_CHANGE_FAILURE: @@ -539,18 +677,21 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) /* collect stats about the media */ collect_media_stats (media); - /* unlock the udp src elements */ - n_streams = gst_rtsp_media_n_streams (media); - for (i = 0; i < n_streams; i++) { - GstRTSPMediaStream *stream; - - stream = gst_rtsp_media_get_stream (media, i); - - gst_element_set_locked_state (stream->udpsrc[0], FALSE); - gst_element_set_locked_state (stream->udpsrc[1], FALSE); - } + /* unlock the streams so that they follow the state changes from now on */ + unlock_streams (media); g_message ("object %p is prerolled", media); + + /* add the pipeline bus to our custom mainloop */ + bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline)); + media->source = gst_bus_create_watch (bus); + gst_object_unref (bus); + + g_source_set_callback (media->source, (GSourceFunc) bus_message, media, NULL); + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + media->id = g_source_attach (media->source, klass->context); + media->prepared = TRUE; return TRUE; @@ -563,7 +704,33 @@ was_prepared: /* ERRORS */ state_failed: { + GstMessage *message; + g_message ("state change failed for media %p", media); + while ((message = gst_bus_pop (bus))) { + GstMessageType type; + + type = GST_MESSAGE_TYPE (message); + switch (type) { + case GST_MESSAGE_ERROR: + { + GError *gerror; + gchar *debug; + + gst_message_parse_error (message, &gerror, &debug); + g_warning ("%p: got error %s (%s)", media, gerror->message, debug); + g_error_free (gerror); + g_free (debug); + break; + } + default: + break; + } + gst_message_unref (message); + } + unlock_streams (media); + gst_element_set_state (media->pipeline, GST_STATE_NULL); + gst_object_unref (bus); return FALSE; } } @@ -611,6 +778,7 @@ gst_rtsp_media_play (GstRTSPMedia *media, GArray *transports) } g_message ("playing"); + media->target_state = GST_STATE_PLAYING; ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); return TRUE; @@ -659,6 +827,7 @@ gst_rtsp_media_pause (GstRTSPMedia *media, GArray *transports) } g_message ("pause"); + media->target_state = GST_STATE_PAUSED; ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); return TRUE; @@ -685,6 +854,7 @@ gst_rtsp_media_stop (GstRTSPMedia *media, GArray *transports) gst_rtsp_media_pause (media, transports); g_message ("stop"); + media->target_state = GST_STATE_NULL; ret = gst_element_set_state (media->pipeline, GST_STATE_NULL); return TRUE; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index c00b165476..798ceef486 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -124,6 +124,12 @@ struct _GstRTSPMedia { /* the pipeline for the media */ GstElement *pipeline; + GSource *source; + guint id; + + gboolean is_live; + gboolean buffering; + GstState target_state; /* RTP session manager */ GstElement *rtpbin; @@ -135,8 +141,24 @@ struct _GstRTSPMedia { GstRTSPTimeRange range; }; +/** + * GstRTSPMediaClass: + * @context: the main context for dispatching messages + * @loop: the mainloop for message. + * @thread: the thread dispatching messages. + * @handle_message: handle a message + * + * The RTSP media class + */ struct _GstRTSPMediaClass { GObjectClass parent_class; + + /* thread for the mainloop */ + GMainContext *context; + GMainLoop *loop; + GThread *thread; + + gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message); }; GType gst_rtsp_media_get_type (void); From 308ad6f6d00ad98999fa1b5ceb8fc99a3c6b85af Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 13 Feb 2009 19:52:05 +0100 Subject: [PATCH 0067/1776] Add support for session keepalive Get and update the session timeout for all requests. get the session as early as possible. --- gst/rtsp-server/rtsp-client.c | 75 +++++++++++++---------------------- 1 file changed, 28 insertions(+), 47 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index ed19555000..f0c0eb7848 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -289,7 +289,7 @@ no_prepare: /* Get the session or NULL when there was no session */ static GstRTSPSession * -ensure_session (GstRTSPClient *client, GstRTSPMessage *request) +find_session (GstRTSPClient *client, GstRTSPMessage *request) { GstRTSPResult res; GstRTSPSession *session; @@ -314,30 +314,26 @@ ensure_session (GstRTSPClient *client, GstRTSPMessage *request) /* ERRORS */ no_pool: { - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); return NULL; } session_not_found: { - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); return NULL; } service_unavailable: { - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); return NULL; } } static gboolean -handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) { GstRTSPSessionMedia *media; - GstRTSPSession *session; GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; - if (!(session = ensure_session (client, request))) + if (!session) goto no_session; /* get a handle to the configuration of the media in the session */ @@ -359,14 +355,12 @@ handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage send_response (client, session, &response); - g_object_unref (session); - return FALSE; /* ERRORS */ no_session: { - /* error was sent already */ + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); return FALSE; } not_found: @@ -377,14 +371,13 @@ not_found: } static gboolean -handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) { GstRTSPSessionMedia *media; - GstRTSPSession *session; GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; - if (!(session = ensure_session (client, request))) + if (!session) goto no_session; /* get a handle to the configuration of the media in the session */ @@ -407,34 +400,31 @@ handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re /* the state is now READY */ media->state = GST_RTSP_STATE_READY; - g_object_unref (session); return FALSE; /* ERRORS */ no_session: { + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); return FALSE; } not_found: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); - g_object_unref (session); return FALSE; } invalid_state: { send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request); - g_object_unref (session); return FALSE; } } static gboolean -handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) { GstRTSPSessionMedia *media; - GstRTSPSession *session; GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; GString *rtpinfo; @@ -442,7 +432,7 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *req guint timestamp, seqnum; gchar *str; - if (!(session = ensure_session (client, request))) + if (!session) goto no_session; /* get a handle to the configuration of the media in the session */ @@ -494,7 +484,6 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *req gst_rtsp_session_media_play (media); media->state = GST_RTSP_STATE_PLAYING; - g_object_unref (session); return FALSE; @@ -507,27 +496,23 @@ no_session: not_found: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); - g_object_unref (session); return FALSE; } invalid_state: { send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request); - g_object_unref (session); return FALSE; } } static gboolean -handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) { GstRTSPResult res; - gchar *sessid; gchar *transport; gchar **transports; gboolean have_transport; GstRTSPTransport *ct, *st; - GstRTSPSession *session; gint i; GstRTSPLowerTrans supported; GstRTSPMessage response = { 0 }; @@ -597,14 +582,8 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re g_free (ct->destination); ct->destination = g_strdup (inet_ntoa (client->address.sin_addr)); - /* a setup request creates a session for a client, check if the client already - * sent a session id to us */ - res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); - if (res == GST_RTSP_OK) { - /* we had a session in the request, find it again */ - if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid))) - goto session_not_found; - + if (session) { + g_object_ref (session); /* get a handle to the configuration of the media in the session, this can * return NULL if this is a new url to manage in this session. */ media = gst_rtsp_session_get_media (session, uri); @@ -669,7 +648,6 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re media->state = GST_RTSP_STATE_READY; break; } - g_object_unref (session); return TRUE; @@ -683,17 +661,14 @@ bad_request: not_found: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + g_object_unref (session); return FALSE; } no_stream: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); g_object_unref (media); - return FALSE; - } -session_not_found: - { - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + g_object_unref (session); return FALSE; } no_transport: @@ -721,7 +696,7 @@ service_unavailable: /* for the describe we must generate an SDP */ static gboolean -handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) { GstRTSPMessage response = { 0 }; GstRTSPResult res; @@ -787,7 +762,7 @@ no_sdp: } static void -handle_options_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +handle_options_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) { GstRTSPMessage response = { 0 }; GstRTSPMethod options; @@ -852,6 +827,7 @@ handle_client (GstRTSPClient *client) while (TRUE) { GTimeVal timeout; + GstRTSPSession *session; timeout.tv_sec = client->timeout; timeout.tv_usec = 0; @@ -886,25 +862,28 @@ handle_client (GstRTSPClient *client) /* sanitize the uri */ santize_uri (uri); + /* get the session if there is any */ + session = find_session (client, &request); + /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: - handle_options_request (client, uri, &request); + handle_options_request (client, uri, session, &request); break; case GST_RTSP_DESCRIBE: - handle_describe_request (client, uri, &request); + handle_describe_request (client, uri, session, &request); break; case GST_RTSP_SETUP: - handle_setup_request (client, uri, &request); + handle_setup_request (client, uri, session, &request); break; case GST_RTSP_PLAY: - handle_play_request (client, uri, &request); + handle_play_request (client, uri, session, &request); break; case GST_RTSP_PAUSE: - handle_pause_request (client, uri, &request); + handle_pause_request (client, uri, session, &request); break; case GST_RTSP_TEARDOWN: - handle_teardown_request (client, uri, &request); + handle_teardown_request (client, uri, session, &request); break; case GST_RTSP_ANNOUNCE: case GST_RTSP_GET_PARAMETER: @@ -918,6 +897,8 @@ handle_client (GstRTSPClient *client) send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &request); break; } + if (session) + g_object_unref (session); gst_rtsp_url_free (uri); } g_object_unref (client); From f0c047ef948ecb55378060ecfece683590be37da Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 13 Feb 2009 19:54:18 +0100 Subject: [PATCH 0068/1776] Add suport for RTP manager monitoring Add the first stage in monitoring the rtp manager. Make sure we don't update the state to something we don't want. --- gst/rtsp-server/rtsp-media.c | 61 +++++++++++++++++++++++++++++++++++- gst/rtsp-server/rtsp-media.h | 3 ++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 2768a808a9..0aa34ac236 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -77,6 +77,9 @@ gst_rtsp_media_init (GstRTSPMedia * media) static void gst_rtsp_media_stream_free (GstRTSPMediaStream *stream) { + if (stream->session) + g_object_unref (stream->session); + if (stream->caps) gst_caps_unref (stream->caps); @@ -421,6 +424,36 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) g_free (capsstr); } +static void +on_new_ssrc (GObject *session, GObject *source, GstRTSPMedia *media) +{ + g_message ("%p: new source %p", media, source); +} + +static void +on_ssrc_active (GObject *session, GObject *source, GstRTSPMedia *media) +{ + g_message ("%p: source %p is active", media, source); +} + +static void +on_bye_ssrc (GObject *session, GObject *source, GstRTSPMedia *media) +{ + g_message ("%p: source %p bye", media, source); +} + +static void +on_bye_timeout (GObject *session, GObject *source, GstRTSPMedia *media) +{ + g_message ("%p: source %p bye timeout", media, source); +} + +static void +on_timeout (GObject *session, GObject *source, GstRTSPMedia *media) +{ + g_message ("%p: source %p timeout", media, source); +} + /* prepare the pipeline objects to handle @stream in @media */ static gboolean setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) @@ -449,6 +482,21 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name); g_free (name); + /* get the session */ + g_signal_emit_by_name (media->rtpbin, "get-internal-session", idx, + &stream->session); + + g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc, + media); + g_signal_connect (stream->session, "on-ssrc-active", (GCallback) on_ssrc_active, + media); + g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, + media); + g_signal_connect (stream->session, "on-bye-timeout", (GCallback) on_bye_timeout, + media); + g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout, + media); + /* link the RTP pad to the session manager */ gst_pad_link (stream->srcpad, stream->send_rtp_sink); @@ -665,7 +713,10 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); break; case GST_STATE_CHANGE_FAILURE: + { + unlock_streams (media); goto state_failed; + } } /* now wait for all pads to be prerolled */ @@ -728,7 +779,6 @@ state_failed: } gst_message_unref (message); } - unlock_streams (media); gst_element_set_state (media->pipeline, GST_STATE_NULL); gst_object_unref (bus); return FALSE; @@ -754,6 +804,9 @@ gst_rtsp_media_play (GstRTSPMedia *media, GArray *transports) g_return_val_if_fail (transports != NULL, FALSE); g_return_val_if_fail (media->prepared, FALSE); + if (media->target_state == GST_STATE_PLAYING) + return TRUE; + for (i = 0; i < transports->len; i++) { GstRTSPMediaTrans *tr; GstRTSPMediaStream *stream; @@ -803,6 +856,9 @@ gst_rtsp_media_pause (GstRTSPMedia *media, GArray *transports) g_return_val_if_fail (transports != NULL, FALSE); g_return_val_if_fail (media->prepared, FALSE); + if (media->target_state == GST_STATE_PAUSED) + return TRUE; + for (i = 0; i < transports->len; i++) { GstRTSPMediaTrans *tr; GstRTSPMediaStream *stream; @@ -851,6 +907,9 @@ gst_rtsp_media_stop (GstRTSPMedia *media, GArray *transports) g_return_val_if_fail (transports != NULL, FALSE); g_return_val_if_fail (media->prepared, FALSE); + if (media->target_state == GST_STATE_NULL) + return TRUE; + gst_rtsp_media_pause (media, transports); g_message ("stop"); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 798ceef486..e613925fbc 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -84,6 +84,9 @@ struct _GstRTSPMediaStream { GstPad *send_rtp_src; GstPad *send_rtcp_src; + /* the RTPSession object */ + GObject *session; + /* sinks used for sending and receiving RTP and RTCP, they share * sockets */ GstElement *udpsrc[2]; From bc785b0a47a3586bee00df84811b7abd0b9bd201 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 13 Feb 2009 19:56:01 +0100 Subject: [PATCH 0069/1776] Add better support for session timeouts Add a method to request the number of milliseconds when a session will timeout. --- gst/rtsp-server/rtsp-session.c | 48 +++++++++++++++++++++++++--------- gst/rtsp-server/rtsp-session.h | 3 ++- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index d8faa61723..a80e28022a 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -399,31 +399,53 @@ gst_rtsp_session_touch (GstRTSPSession *session) g_get_current_time (&session->last_access); } +/** + * gst_rtsp_session_next_timeout: + * @session: a #GstRTSPSession + * @now: the current system time + * + * Get the amount of milliseconds till the session will expire. + * + * Returns: the amount of milliseconds since the session will time out. + */ +gint +gst_rtsp_session_next_timeout (GstRTSPSession *session, GTimeVal *now) +{ + gint res; + GstClockTime last_access, now_ns; + + g_return_val_if_fail (GST_IS_RTSP_SESSION (session), -1); + g_return_val_if_fail (now != NULL, -1); + + last_access = GST_TIMEVAL_TO_TIME (session->last_access); + /* add timeout */ + last_access += session->timeout * GST_SECOND; + + now_ns = GST_TIMEVAL_TO_TIME (*now); + + if (last_access > now_ns) + res = GST_TIME_AS_MSECONDS (last_access - now_ns); + else + res = 0; + + return res; +} + /** * gst_rtsp_session_is_expired: * @session: a #GstRTSPSession + * @now: the current system time * * Check if @session timeout out. * * Returns: %TRUE if @session timed out */ gboolean -gst_rtsp_session_is_expired (GstRTSPSession *session) +gst_rtsp_session_is_expired (GstRTSPSession *session, GTimeVal *now) { gboolean res; - GstClockTime last_access, now_ns; - GTimeVal now; - g_return_val_if_fail (GST_IS_RTSP_SESSION (session), FALSE); - - last_access = GST_TIMEVAL_TO_TIME (session->last_access); - /* add timeout */ - last_access += session->timeout * GST_SECOND; - - g_get_current_time (&now); - now_ns = GST_TIMEVAL_TO_TIME (now); - - res = now_ns > last_access; + res = (gst_rtsp_session_next_timeout (session, now) == 0); return res; } diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index bcda0887d5..b3797b13ce 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -119,7 +119,8 @@ guint gst_rtsp_session_get_timeout (GstRTSPSession *se /* session timeout stuff */ void gst_rtsp_session_touch (GstRTSPSession *session); -gboolean gst_rtsp_session_is_expired (GstRTSPSession *session); +gint gst_rtsp_session_next_timeout (GstRTSPSession *session, GTimeVal *now); +gboolean gst_rtsp_session_is_expired (GstRTSPSession *session, GTimeVal *now); /* handle media in a session */ GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess, From b86451dc76abfc5a22703de0e51635416c02200d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 13 Feb 2009 19:58:17 +0100 Subject: [PATCH 0070/1776] Pass GTimeVal around for performance reasons Get the current time only once and pass it around so that sessions don't have to get the current time anymore. Add experimental support for a GSource that dispatches when the session needs to be cleaned up. --- gst/rtsp-server/rtsp-session-pool.c | 119 +++++++++++++++++++++++++++- gst/rtsp-server/rtsp-session-pool.h | 16 ++++ 2 files changed, 132 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index d32b43fd42..44d749b605 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -58,6 +58,7 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); klass->create_session_id = create_session_id; + } static void @@ -350,9 +351,9 @@ gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, GstRTSPSession *sess) } static gboolean -cleanup_func (gchar *sessionid, GstRTSPSession *sess, GstRTSPSessionPool *pool) +cleanup_func (gchar *sessionid, GstRTSPSession *sess, GTimeVal *now) { - return gst_rtsp_session_is_expired (sess); + return gst_rtsp_session_is_expired (sess, now); } /** @@ -368,12 +369,124 @@ guint gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool) { guint result; + GTimeVal now; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0); + g_get_current_time (&now); + g_mutex_lock (pool->lock); - result = g_hash_table_foreach_remove (pool->sessions, (GHRFunc) cleanup_func, pool); + result = g_hash_table_foreach_remove (pool->sessions, (GHRFunc) cleanup_func, &now); g_mutex_unlock (pool->lock); return result; } + +typedef struct +{ + GSource source; + GstRTSPSessionPool *pool; + gint timeout; +} GstPoolSource; + +static void +collect_timeout (gchar *sessionid, GstRTSPSession *sess, GstPoolSource *psrc) +{ + gint timeout; + GTimeVal now; + + g_source_get_current_time ((GSource*)psrc, &now); + + timeout = gst_rtsp_session_next_timeout (sess, &now); + g_message ("%p: next timeout: %d", sess, timeout); + if (psrc->timeout == -1 || timeout < psrc->timeout) + psrc->timeout = timeout; +} + +static gboolean +gst_pool_source_prepare (GSource * source, gint * timeout) +{ + GstPoolSource *psrc; + gboolean result; + + psrc = (GstPoolSource *) source; + psrc->timeout = -1; + + g_mutex_lock (psrc->pool->lock); + g_hash_table_foreach (psrc->pool->sessions, (GHFunc) collect_timeout, psrc); + g_mutex_unlock (psrc->pool->lock); + + if (timeout) + *timeout = psrc->timeout; + + result = psrc->timeout == 0; + + g_message ("prepare %d, %d", psrc->timeout, result); + + return result; +} + +static gboolean +gst_pool_source_check (GSource * source) +{ + g_message ("check"); + + return gst_pool_source_prepare (source, NULL); +} + +static gboolean +gst_pool_source_dispatch (GSource * source, GSourceFunc callback, + gpointer user_data) +{ + gboolean res; + GstPoolSource *psrc = (GstPoolSource *) source; + GstRTSPSessionPoolFunc func = (GstRTSPSessionPoolFunc) callback; + + g_message ("dispatch"); + + if (func) + res = func (psrc->pool, user_data); + else + res = FALSE; + + return res; +} + +static void +gst_pool_source_finalize (GSource * source) +{ + GstPoolSource *psrc = (GstPoolSource *) source; + + g_message ("finalize %p", psrc); + + g_object_unref (psrc->pool); + psrc->pool = NULL; +} + +static GSourceFuncs gst_pool_source_funcs = { + gst_pool_source_prepare, + gst_pool_source_check, + gst_pool_source_dispatch, + gst_pool_source_finalize +}; + +/** + * gst_rtsp_session_pool_create_watch: + * @pool: a #GstRTSPSessionPool + * + * A GSource that will be dispatched when the session should be cleaned up. + */ +GSource * +gst_rtsp_session_pool_create_watch (GstRTSPSessionPool *pool) +{ + GstPoolSource *source; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL); + + source = (GstPoolSource *) g_source_new (&gst_pool_source_funcs, + sizeof (GstPoolSource)); + source->pool = g_object_ref (pool); + + return (GSource *) source; +} + diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index dba8b764f6..7c387cd36e 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -67,6 +67,21 @@ struct _GstRTSPSessionPoolClass { gchar * (*create_session_id) (GstRTSPSessionPool *pool); }; +/** + * GstRTSPSessionPoolFunc: + * @pool: a #GstRTSPSessionPool object + * @user_data: user data that has been given when registering the handler + * + * The function that will be called from the GSource watch on the session pool. + * + * The function will be called when the pool must be cleaned up because one or + * more sessions timed out. + * + * Returns: %FALSe if the source should be removed. + */ +typedef gboolean (*GstRTSPSessionPoolFunc) (GstRTSPSessionPool *pool, gpointer user_data); + + GType gst_rtsp_session_pool_get_type (void); /* creating a session pool */ @@ -87,6 +102,7 @@ gboolean gst_rtsp_session_pool_remove (GstRTSPSessionPoo /* perform session maintenance */ guint gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool); +GSource * gst_rtsp_session_pool_create_watch (GstRTSPSessionPool *pool); G_END_DECLS From da0ef4a01414f5b5b3daa85d6695a409b97e741d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 13 Feb 2009 20:00:34 +0100 Subject: [PATCH 0071/1776] Time out sessions Add support for session timeouts in the example. --- examples/test-video.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/examples/test-video.c b/examples/test-video.c index b03bc6ca3d..5ed8b1da85 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -21,6 +21,19 @@ #include + +static gboolean +timeout (GstRTSPServer *server, gboolean ignored) +{ + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_cleanup (pool); + g_object_unref (pool); + + return TRUE; +} + int main (int argc, char *argv[]) { @@ -61,6 +74,8 @@ main (int argc, char *argv[]) /* attach the server to the default maincontext */ gst_rtsp_server_attach (server, NULL); + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + /* start serving */ g_main_loop_run (loop); From b70a6c9d83f861d46f746ad836698628e26cf6a3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 18 Feb 2009 17:49:03 +0100 Subject: [PATCH 0072/1776] Add better debug info Add some better debug info. --- gst/rtsp-server/rtsp-media.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 0aa34ac236..bfe56097c6 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -830,7 +830,7 @@ gst_rtsp_media_play (GstRTSPMedia *media, GArray *transports) g_signal_emit_by_name (stream->udpsink[1], "add", trans->destination, trans->client_port.max, NULL); } - g_message ("playing"); + g_message ("playing media %p", media); media->target_state = GST_STATE_PLAYING; ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); @@ -882,7 +882,7 @@ gst_rtsp_media_pause (GstRTSPMedia *media, GArray *transports) g_signal_emit_by_name (stream->udpsink[1], "remove", trans->destination, trans->client_port.max, NULL); } - g_message ("pause"); + g_message ("pause media %p", media); media->target_state = GST_STATE_PAUSED; ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); @@ -912,7 +912,7 @@ gst_rtsp_media_stop (GstRTSPMedia *media, GArray *transports) gst_rtsp_media_pause (media, transports); - g_message ("stop"); + g_message ("stop media %p", media); media->target_state = GST_STATE_NULL; ret = gst_element_set_state (media->pipeline, GST_STATE_NULL); From 39c2e31e6548448d9cd208af63764d5c5920195f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 18 Feb 2009 18:57:31 +0100 Subject: [PATCH 0073/1776] Use ASYNC RTSP io Use the async RTSP channels instead of spawning a new thread for each client. If a sessionid is specified in a request, fail if we don't have the session. --- gst/rtsp-server/rtsp-client.c | 369 ++++++++++++++++------------------ gst/rtsp-server/rtsp-client.h | 2 +- 2 files changed, 170 insertions(+), 201 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f0c0eb7848..c615f852d2 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -184,7 +184,10 @@ send_response (GstRTSPClient *client, GstRTSPSession *session, GstRTSPMessage *r gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1); } +#if 0 gst_rtsp_connection_send (client->connection, response, &timeout); +#endif + gst_rtsp_channel_queue_message (client->channel, response); gst_rtsp_message_unset (response); } @@ -287,45 +290,6 @@ no_prepare: } } -/* Get the session or NULL when there was no session */ -static GstRTSPSession * -find_session (GstRTSPClient *client, GstRTSPMessage *request) -{ - GstRTSPResult res; - GstRTSPSession *session; - gchar *sessid; - - res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); - if (res == GST_RTSP_OK) { - if (client->session_pool == NULL) - goto no_pool; - - /* we had a session in the request, find it again */ - if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid))) - goto session_not_found; - - client->timeout = gst_rtsp_session_get_timeout (session); - } - else - goto service_unavailable; - - return session; - - /* ERRORS */ -no_pool: - { - return NULL; - } -session_not_found: - { - return NULL; - } -service_unavailable: - { - return NULL; - } -} - static gboolean handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) { @@ -490,7 +454,7 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses /* ERRORS */ no_session: { - /* error was sent */ + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); return FALSE; } not_found: @@ -580,7 +544,7 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se /* we have a valid transport now, set the destination of the client. */ g_free (ct->destination); - ct->destination = g_strdup (inet_ntoa (client->address.sin_addr)); + ct->destination = g_strdup (client->connection->url->host); if (session) { g_object_ref (session); @@ -813,163 +777,101 @@ santize_uri (GstRTSPUrl *uri) *d = '\0'; } -/* this function runs in a client specific thread and handles all rtsp messages - * with the client */ -static gpointer -handle_client (GstRTSPClient *client) +static void +handle_request (GstRTSPClient *client, GstRTSPMessage *request) { - GstRTSPMessage request = { 0 }; - GstRTSPResult res; GstRTSPMethod method; const gchar *uristr; GstRTSPUrl *uri; GstRTSPVersion version; - - while (TRUE) { - GTimeVal timeout; - GstRTSPSession *session; - - timeout.tv_sec = client->timeout; - timeout.tv_usec = 0; - - /* start by waiting for a message from the client */ - res = gst_rtsp_connection_receive (client->connection, &request, &timeout); - if (res < 0) { - if (res == GST_RTSP_ETIMEOUT) - goto timeout; - - goto receive_failed; - } + GstRTSPResult res; + GstRTSPSession *session; + gchar *sessid; #ifdef DEBUG - gst_rtsp_message_dump (&request); + gst_rtsp_message_dump (request); #endif - gst_rtsp_message_parse_request (&request, &method, &uristr, &version); + gst_rtsp_message_parse_request (request, &method, &uristr, &version); - if (version != GST_RTSP_VERSION_1_0) { - /* we can only handle 1.0 requests */ - send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, &request); - continue; - } - - /* we always try to parse the url first */ - if ((res = gst_rtsp_url_parse (uristr, &uri)) != GST_RTSP_OK) { - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &request); - continue; - } - - /* sanitize the uri */ - santize_uri (uri); - - /* get the session if there is any */ - session = find_session (client, &request); - - /* now see what is asked and dispatch to a dedicated handler */ - switch (method) { - case GST_RTSP_OPTIONS: - handle_options_request (client, uri, session, &request); - break; - case GST_RTSP_DESCRIBE: - handle_describe_request (client, uri, session, &request); - break; - case GST_RTSP_SETUP: - handle_setup_request (client, uri, session, &request); - break; - case GST_RTSP_PLAY: - handle_play_request (client, uri, session, &request); - break; - case GST_RTSP_PAUSE: - handle_pause_request (client, uri, session, &request); - break; - case GST_RTSP_TEARDOWN: - handle_teardown_request (client, uri, session, &request); - break; - case GST_RTSP_ANNOUNCE: - case GST_RTSP_GET_PARAMETER: - case GST_RTSP_RECORD: - case GST_RTSP_REDIRECT: - case GST_RTSP_SET_PARAMETER: - send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &request); - break; - case GST_RTSP_INVALID: - default: - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &request); - break; - } - if (session) - g_object_unref (session); - gst_rtsp_url_free (uri); + if (version != GST_RTSP_VERSION_1_0) { + /* we can only handle 1.0 requests */ + send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, request); + return; } - g_object_unref (client); - return NULL; + + /* we always try to parse the url first */ + if ((res = gst_rtsp_url_parse (uristr, &uri)) != GST_RTSP_OK) { + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); + return; + } + + /* sanitize the uri */ + santize_uri (uri); + + /* get the session if there is any */ + res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); + if (res == GST_RTSP_OK) { + if (client->session_pool == NULL) + goto no_pool; + + /* we had a session in the request, find it again */ + if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid))) + goto session_not_found; + + client->timeout = gst_rtsp_session_get_timeout (session); + } + else + session = NULL; + + /* now see what is asked and dispatch to a dedicated handler */ + switch (method) { + case GST_RTSP_OPTIONS: + handle_options_request (client, uri, session, request); + break; + case GST_RTSP_DESCRIBE: + handle_describe_request (client, uri, session, request); + break; + case GST_RTSP_SETUP: + handle_setup_request (client, uri, session, request); + break; + case GST_RTSP_PLAY: + handle_play_request (client, uri, session, request); + break; + case GST_RTSP_PAUSE: + handle_pause_request (client, uri, session, request); + break; + case GST_RTSP_TEARDOWN: + handle_teardown_request (client, uri, session, request); + break; + case GST_RTSP_ANNOUNCE: + case GST_RTSP_GET_PARAMETER: + case GST_RTSP_RECORD: + case GST_RTSP_REDIRECT: + case GST_RTSP_SET_PARAMETER: + send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, request); + break; + case GST_RTSP_INVALID: + default: + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); + break; + } + if (session) + g_object_unref (session); + + gst_rtsp_url_free (uri); + return; /* ERRORS */ -timeout: +no_pool: { - g_message ("client timed out"); - if (client->session_pool) - gst_rtsp_session_pool_cleanup (client->session_pool); - goto cleanup; + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + return; } -receive_failed: +session_not_found: { - gchar *str; - str = gst_rtsp_strresult (res); - g_message ("receive failed %d (%s), disconnect client %p", res, - str, client); - g_free (str); - goto cleanup; - } -cleanup: - { - gst_rtsp_message_unset (&request); - gst_rtsp_connection_close (client->connection); - g_object_unref (client); - return NULL; - } -} - -/* called when we need to accept a new request from a client */ -static gboolean -client_accept (GstRTSPClient *client, GIOChannel *channel) -{ - /* a new client connected. */ - int server_sock_fd, fd; - unsigned int address_len; - GstRTSPConnection *conn; - - server_sock_fd = g_io_channel_unix_get_fd (channel); - - address_len = sizeof (client->address); - memset (&client->address, 0, address_len); - - fd = accept (server_sock_fd, (struct sockaddr *) &client->address, - &address_len); - if (fd == -1) - goto accept_failed; - - /* now create the connection object */ - gst_rtsp_connection_create (NULL, &conn); - conn->fd.fd = fd; - - /* FIXME some hackery, we need to have a connection method to accept server - * connections */ - gst_poll_add_fd (conn->fdset, &conn->fd); - - g_message ("added new client %p ip %s with fd %d", client, - inet_ntoa (client->address.sin_addr), conn->fd.fd); - - client->connection = conn; - - return TRUE; - - /* ERRORS */ -accept_failed: - { - g_error ("Could not accept client on server socket %d: %s (%d)", - server_sock_fd, g_strerror (errno), errno); - return FALSE; + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + return; } } @@ -1087,6 +989,58 @@ gst_rtsp_client_get_media_mapping (GstRTSPClient *client) return result; } +static GstRTSPResult +message_received (GstRTSPChannel *channel, GstRTSPMessage *message, gpointer user_data) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + + g_message ("client %p: received a message", client); + + handle_request (client, message); + + return GST_RTSP_OK; +} + +static GstRTSPResult +message_sent (GstRTSPChannel *channel, guint cseq, gpointer user_data) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + + g_message ("client %p: sent a message with cseq %d", client, cseq); + + return GST_RTSP_OK; +} + +static GstRTSPResult +closed (GstRTSPChannel *channel, gpointer user_data) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + + g_message ("client %p: connection closed", client); + + return GST_RTSP_OK; +} + +static GstRTSPResult +error (GstRTSPChannel *channel, GstRTSPResult result, gpointer user_data) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + gchar *str; + + str = gst_rtsp_strresult (result); + g_message ("client %p: received an error %s", client, str); + g_free (str); + + return GST_RTSP_OK; +} + +static GstRTSPChannelFuncs channel_funcs = { + message_received, + message_sent, + closed, + error +}; + /** * gst_rtsp_client_attach: * @client: a #GstRTSPClient @@ -1102,32 +1056,47 @@ gst_rtsp_client_get_media_mapping (GstRTSPClient *client) gboolean gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel) { - GError *error = NULL; + int sock; + GstRTSPConnection *conn; + GstRTSPResult res; + GSource *source; + GMainContext *context; - if (!client_accept (client, channel)) - goto accept_failed; + /* a new client connected. */ + sock = g_io_channel_unix_get_fd (channel); - /* client accepted, spawn a thread for the client, we don't need to join the - * thread */ - g_object_ref (client); - client->thread = g_thread_create ((GThreadFunc)handle_client, client, FALSE, &error); - if (client->thread == NULL) - goto no_thread; + GST_RTSP_CHECK (gst_rtsp_connection_accept (sock, &conn), accept_failed); + + g_message ("added new client %p ip %s:%d with fd %d", client, + conn->url->host, conn->url->port, conn->fd.fd); + + client->connection = conn; + + /* create channel for the connection and attach */ + client->channel = gst_rtsp_channel_new (client->connection, &channel_funcs, + g_object_ref (client), g_object_unref); + + /* find the context to add the channel */ + if ((source = g_main_current_source ())) + context = g_source_get_context (source); + else + context = NULL; + + g_message ("attaching to context %p", context); + + gst_rtsp_channel_attach (client->channel, context); + gst_rtsp_channel_unref (client->channel); return TRUE; /* ERRORS */ accept_failed: { - return FALSE; - } -no_thread: - { - if (error) { - g_warning ("could not create thread for client %p: %s", client, error->message); - g_error_free (error); - } - g_object_unref (client); + gchar *str = gst_rtsp_strresult (res); + + g_error ("Could not accept client on server socket %d: %s", + sock, str); + g_free (str); return FALSE; } } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 694361f4dc..4746d1c7e4 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -70,7 +70,7 @@ struct _GstRTSPClient { GObject parent; GstRTSPConnection *connection; - struct sockaddr_in address; + GstRTSPChannel *channel; GThread *thread; guint timeout; From daf27d27042d25ce19612f5587456152b6d1e9d9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 19 Feb 2009 15:53:50 +0100 Subject: [PATCH 0074/1776] Fix for channel -> watch rename in gstreamer Rename the RTSPChannel to RTSPWatch and remove an unused variable. --- gst/rtsp-server/rtsp-client.c | 22 +++++++++++----------- gst/rtsp-server/rtsp-client.h | 3 +-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c615f852d2..fe757ef787 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -187,7 +187,7 @@ send_response (GstRTSPClient *client, GstRTSPSession *session, GstRTSPMessage *r #if 0 gst_rtsp_connection_send (client->connection, response, &timeout); #endif - gst_rtsp_channel_queue_message (client->channel, response); + gst_rtsp_watch_queue_message (client->watch, response); gst_rtsp_message_unset (response); } @@ -990,7 +990,7 @@ gst_rtsp_client_get_media_mapping (GstRTSPClient *client) } static GstRTSPResult -message_received (GstRTSPChannel *channel, GstRTSPMessage *message, gpointer user_data) +message_received (GstRTSPWatch *watch, GstRTSPMessage *message, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); @@ -1002,7 +1002,7 @@ message_received (GstRTSPChannel *channel, GstRTSPMessage *message, gpointer use } static GstRTSPResult -message_sent (GstRTSPChannel *channel, guint cseq, gpointer user_data) +message_sent (GstRTSPWatch *watch, guint cseq, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); @@ -1012,7 +1012,7 @@ message_sent (GstRTSPChannel *channel, guint cseq, gpointer user_data) } static GstRTSPResult -closed (GstRTSPChannel *channel, gpointer user_data) +closed (GstRTSPWatch *watch, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); @@ -1022,7 +1022,7 @@ closed (GstRTSPChannel *channel, gpointer user_data) } static GstRTSPResult -error (GstRTSPChannel *channel, GstRTSPResult result, gpointer user_data) +error (GstRTSPWatch *watch, GstRTSPResult result, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); gchar *str; @@ -1034,7 +1034,7 @@ error (GstRTSPChannel *channel, GstRTSPResult result, gpointer user_data) return GST_RTSP_OK; } -static GstRTSPChannelFuncs channel_funcs = { +static GstRTSPWatchFuncs watch_funcs = { message_received, message_sent, closed, @@ -1072,11 +1072,11 @@ gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel) client->connection = conn; - /* create channel for the connection and attach */ - client->channel = gst_rtsp_channel_new (client->connection, &channel_funcs, + /* create watch for the connection and attach */ + client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs, g_object_ref (client), g_object_unref); - /* find the context to add the channel */ + /* find the context to add the watch */ if ((source = g_main_current_source ())) context = g_source_get_context (source); else @@ -1084,8 +1084,8 @@ gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel) g_message ("attaching to context %p", context); - gst_rtsp_channel_attach (client->channel, context); - gst_rtsp_channel_unref (client->channel); + gst_rtsp_watch_attach (client->watch, context); + gst_rtsp_watch_unref (client->watch); return TRUE; diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 4746d1c7e4..53e4f2f22d 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -70,8 +70,7 @@ struct _GstRTSPClient { GObject parent; GstRTSPConnection *connection; - GstRTSPChannel *channel; - GThread *thread; + GstRTSPWatch *watch; guint timeout; GstRTSPSessionPool *session_pool; From 2f8025dbddc14d418b22e90ead97235825b11c82 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 4 Mar 2009 12:44:01 +0100 Subject: [PATCH 0075/1776] rtsp-server: Add support for tunneling Add support for tunneling over HTTP. Use new connection methods to retrieve the url. Dispatch messages based on the message type instead of blindly assuming it's always a request. Keep track of the watch id so that we can remove it later. Set the media pipeline to NULL before unreffing the pipeline. --- gst/rtsp-server/rtsp-client.c | 120 +++++++++++++++++++++++++++++++--- gst/rtsp-server/rtsp-client.h | 1 + gst/rtsp-server/rtsp-media.c | 4 +- 3 files changed, 116 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index fe757ef787..1ba0678e2a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -26,6 +26,9 @@ #define DEFAULT_TIMEOUT 60 +static GMutex *tunnels_lock; +static GHashTable *tunnels; + enum { PROP_0, @@ -67,6 +70,9 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_param_spec_object ("media-mapping", "Media Mapping", "The media mapping to use for client session", GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + tunnels_lock = g_mutex_new (); } static void @@ -486,6 +492,7 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se guint streamid; GstRTSPSessionMedia *media; gboolean need_session; + GstRTSPUrl *url; /* the uri contains the stream number we added in the SDP config, which is * always /stream=%d so we need to strip that off @@ -535,7 +542,7 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se goto unsupported_transports; supported = GST_RTSP_LOWER_TRANS_UDP | - GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP; + GST_RTSP_LOWER_TRANS_UDP_MCAST; if (!(ct->lower_transport & supported)) goto unsupported_transports; @@ -544,7 +551,8 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se /* we have a valid transport now, set the destination of the client. */ g_free (ct->destination); - ct->destination = g_strdup (client->connection->url->host); + url = gst_rtsp_connection_get_url (client->connection); + ct->destination = g_strdup (url->host); if (session) { g_object_ref (session); @@ -996,8 +1004,17 @@ message_received (GstRTSPWatch *watch, GstRTSPMessage *message, gpointer user_da g_message ("client %p: received a message", client); - handle_request (client, message); - + switch (message->type) { + case GST_RTSP_MESSAGE_REQUEST: + handle_request (client, message); + break; + case GST_RTSP_MESSAGE_RESPONSE: + break; + case GST_RTSP_MESSAGE_DATA: + break; + default: + break; + } return GST_RTSP_OK; } @@ -1015,9 +1032,15 @@ static GstRTSPResult closed (GstRTSPWatch *watch, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + const gchar *tunnelid; g_message ("client %p: connection closed", client); + tunnelid = gst_rtsp_connection_get_tunnelid (client->connection); + g_mutex_lock (tunnels_lock); + g_hash_table_remove (tunnels, tunnelid); + g_mutex_unlock (tunnels_lock); + return GST_RTSP_OK; } @@ -1034,11 +1057,90 @@ error (GstRTSPWatch *watch, GstRTSPResult result, gpointer user_data) return GST_RTSP_OK; } +static GstRTSPStatusCode +tunnel_start (GstRTSPWatch *watch, gpointer user_data) +{ + GstRTSPClient *client; + const gchar *tunnelid; + + client = GST_RTSP_CLIENT (user_data); + + g_message ("client %p: tunnel start", client); + + /* store client in the pending tunnels */ + tunnelid = gst_rtsp_connection_get_tunnelid (client->connection); + + g_message ("client %p: inserting %s", client, tunnelid); + + /* we can't have two clients connecting with the same tunnelid */ + g_mutex_lock (tunnels_lock); + if (g_hash_table_lookup (tunnels, tunnelid)) + goto tunnel_existed; + + g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client)); + g_mutex_unlock (tunnels_lock); + + return GST_RTSP_STS_OK; + + /* ERRORS */ +tunnel_existed: + { + g_mutex_unlock (tunnels_lock); + g_message ("client %p: tunnel session %s existed", client, tunnelid); + return GST_RTSP_STS_SERVICE_UNAVAILABLE; + } +} + +static GstRTSPResult +tunnel_complete (GstRTSPWatch *watch, gpointer user_data) +{ + const gchar *tunnelid; + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + GstRTSPClient *oclient; + + g_message ("client %p: tunnel complete", client); + + /* find previous tunnel */ + tunnelid = gst_rtsp_connection_get_tunnelid (client->connection); + + g_mutex_lock (tunnels_lock); + if (!(oclient = g_hash_table_lookup (tunnels, tunnelid))) + goto no_tunnel; + + /* remove the old client from the table. ref before because removing it will + * remove the ref to it. */ + g_object_ref (oclient); + g_hash_table_remove (tunnels, tunnelid); + g_mutex_unlock (tunnels_lock); + + g_message ("client %p: found tunnel %p", client, oclient); + + /* merge the tunnels into the first client */ + gst_rtsp_connection_do_tunnel (oclient->connection, client->connection); + gst_rtsp_watch_reset (oclient->watch); + g_object_unref (oclient); + + /* we don't need this watch anymore */ + g_source_remove (client->watchid); + + return GST_RTSP_OK; + + /* ERRORS */ +no_tunnel: + { + g_mutex_unlock (tunnels_lock); + g_message ("client %p: tunnel session %s not found", client, tunnelid); + return GST_RTSP_OK; + } +} + static GstRTSPWatchFuncs watch_funcs = { message_received, message_sent, closed, - error + error, + tunnel_start, + tunnel_complete }; /** @@ -1061,14 +1163,16 @@ gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel) GstRTSPResult res; GSource *source; GMainContext *context; + GstRTSPUrl *url; /* a new client connected. */ sock = g_io_channel_unix_get_fd (channel); GST_RTSP_CHECK (gst_rtsp_connection_accept (sock, &conn), accept_failed); - g_message ("added new client %p ip %s:%d with fd %d", client, - conn->url->host, conn->url->port, conn->fd.fd); + url = gst_rtsp_connection_get_url (conn); + g_message ("added new client %p ip %s:%d", client, + url->host, url->port); client->connection = conn; @@ -1084,7 +1188,7 @@ gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel) g_message ("attaching to context %p", context); - gst_rtsp_watch_attach (client->watch, context); + client->watchid = gst_rtsp_watch_attach (client->watch, context); gst_rtsp_watch_unref (client->watch); return TRUE; diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 53e4f2f22d..9949f1a1cd 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -71,6 +71,7 @@ struct _GstRTSPClient { GstRTSPConnection *connection; GstRTSPWatch *watch; + guint watchid; guint timeout; GstRTSPSessionPool *session_pool; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index bfe56097c6..e590ae0ee5 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -110,8 +110,10 @@ gst_rtsp_media_finalize (GObject * obj) g_source_unref (media->source); } - if (media->pipeline) + if (media->pipeline) { + gst_element_set_state (media->pipeline, GST_STATE_NULL); gst_object_unref (media->pipeline); + } G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); } From d85b34f1b143ba071c8b83430fc083aa4811c608 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 4 Mar 2009 16:33:21 +0100 Subject: [PATCH 0076/1776] Only free the pending tunnel if there is one -- --- gst/rtsp-server/rtsp-client.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1ba0678e2a..585b5d83c8 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1036,10 +1036,11 @@ closed (GstRTSPWatch *watch, gpointer user_data) g_message ("client %p: connection closed", client); - tunnelid = gst_rtsp_connection_get_tunnelid (client->connection); - g_mutex_lock (tunnels_lock); - g_hash_table_remove (tunnels, tunnelid); - g_mutex_unlock (tunnels_lock); + if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) { + g_mutex_lock (tunnels_lock); + g_hash_table_remove (tunnels, tunnelid); + g_mutex_unlock (tunnels_lock); + } return GST_RTSP_OK; } From cd3ed91553c9d778f0fcffdce8db877a407bfa82 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 4 Mar 2009 16:33:59 +0100 Subject: [PATCH 0077/1776] Free the pipeline before other things --- --- gst/rtsp-server/rtsp-media.c | 54 ++++++++++-------------------------- 1 file changed, 14 insertions(+), 40 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e590ae0ee5..3b3d241d20 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -96,6 +96,11 @@ gst_rtsp_media_finalize (GObject * obj) g_message ("finalize media %p", media); + if (media->pipeline) { + gst_element_set_state (media->pipeline, GST_STATE_NULL); + gst_object_unref (media->pipeline); + } + for (i = 0; i < media->streams->len; i++) { GstRTSPMediaStream *stream; @@ -110,11 +115,6 @@ gst_rtsp_media_finalize (GObject * obj) g_source_unref (media->source); } - if (media->pipeline) { - gst_element_set_state (media->pipeline, GST_STATE_NULL); - gst_object_unref (media->pipeline); - } - G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); } @@ -682,6 +682,15 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) media->pipeline = gst_pipeline_new ("media-pipeline"); bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline)); + /* add the pipeline bus to our custom mainloop */ + media->source = gst_bus_create_watch (bus); + gst_object_unref (bus); + + g_source_set_callback (media->source, (GSourceFunc) bus_message, media, NULL); + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + media->id = g_source_attach (media->source, klass->context); + gst_bin_add (GST_BIN_CAST (media->pipeline), media->element); media->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin"); @@ -735,16 +744,6 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) g_message ("object %p is prerolled", media); - /* add the pipeline bus to our custom mainloop */ - bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline)); - media->source = gst_bus_create_watch (bus); - gst_object_unref (bus); - - g_source_set_callback (media->source, (GSourceFunc) bus_message, media, NULL); - - klass = GST_RTSP_MEDIA_GET_CLASS (media); - media->id = g_source_attach (media->source, klass->context); - media->prepared = TRUE; return TRUE; @@ -757,32 +756,7 @@ was_prepared: /* ERRORS */ state_failed: { - GstMessage *message; - - g_message ("state change failed for media %p", media); - while ((message = gst_bus_pop (bus))) { - GstMessageType type; - - type = GST_MESSAGE_TYPE (message); - switch (type) { - case GST_MESSAGE_ERROR: - { - GError *gerror; - gchar *debug; - - gst_message_parse_error (message, &gerror, &debug); - g_warning ("%p: got error %s (%s)", media, gerror->message, debug); - g_error_free (gerror); - g_free (debug); - break; - } - default: - break; - } - gst_message_unref (message); - } gst_element_set_state (media->pipeline, GST_STATE_NULL); - gst_object_unref (bus); return FALSE; } } From de1ebbc21be20ab1ac6a6888e9830e084264e4d5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 6 Mar 2009 19:34:14 +0100 Subject: [PATCH 0078/1776] Add support for live streams Add support for live streams and ranges Start on handling TCP data transfer. --- examples/test-readme.c | 2 +- gst/rtsp-server/rtsp-client.c | 8 +++- gst/rtsp-server/rtsp-media.c | 80 +++++++++++++++++++++++++---------- gst/rtsp-server/rtsp-media.h | 1 + 4 files changed, 66 insertions(+), 25 deletions(-) diff --git a/examples/test-readme.c b/examples/test-readme.c index 880b6d2102..e23c55ae76 100644 --- a/examples/test-readme.c +++ b/examples/test-readme.c @@ -46,7 +46,7 @@ main (int argc, char *argv[]) * element with pay%d names will be a stream */ factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, - "( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )"); + "( videotestsrc is-live=1 ! x264enc ! rtph264pay name=pay0 pt=96 )"); /* attach the test factory to the /test url */ gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 585b5d83c8..811ae032e3 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -542,7 +542,8 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se goto unsupported_transports; supported = GST_RTSP_LOWER_TRANS_UDP | - GST_RTSP_LOWER_TRANS_UDP_MCAST; + GST_RTSP_LOWER_TRANS_UDP_MCAST | + GST_RTSP_LOWER_TRANS_TCP; if (!(ct->lower_transport & supported)) goto unsupported_transports; @@ -594,6 +595,11 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se goto no_stream; /* setup the server transport from the client transport */ + if (ct->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { + ct->port.min = gst_rtsp_connection_get_readfd (client->connection); + ct->port.max = gst_rtsp_connection_get_writefd (client->connection); + } + st = gst_rtsp_session_stream_set_transport (stream, ct); /* serialize the server transport */ diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 3b3d241d20..6284612d74 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -415,13 +415,18 @@ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) { gchar *capsstr; + GstCaps *newcaps, *oldcaps; - if (stream->caps) - gst_caps_unref (stream->caps); - if ((stream->caps = GST_PAD_CAPS (pad))) - gst_caps_ref (stream->caps); + if ((newcaps = GST_PAD_CAPS (pad))) + gst_caps_ref (newcaps); - capsstr = gst_caps_to_string (stream->caps); + oldcaps = stream->caps; + stream->caps = newcaps; + + if (oldcaps) + gst_caps_unref (oldcaps); + + capsstr = gst_caps_to_string (newcaps); g_message ("stream %p received caps %s", stream, capsstr); g_free (capsstr); } @@ -553,21 +558,30 @@ collect_media_stats (GstRTSPMedia *media) gint64 duration; media->range.unit = GST_RTSP_RANGE_NPT; - media->range.min.type = GST_RTSP_TIME_SECONDS; - media->range.min.seconds = 0.0; - /* get the duration */ - format = GST_FORMAT_TIME; - if (!gst_element_query_duration (media->pipeline, &format, &duration)) - duration = -1; - - if (duration == -1) { + if (media->is_live) { + media->range.min.type = GST_RTSP_TIME_NOW; + media->range.min.seconds = -1; media->range.max.type = GST_RTSP_TIME_END; media->range.max.seconds = -1; } else { - media->range.max.type = GST_RTSP_TIME_SECONDS; - media->range.max.seconds = ((gdouble)duration) / GST_SECOND; + media->range.min.type = GST_RTSP_TIME_SECONDS; + media->range.min.seconds = 0.0; + + /* get the duration */ + format = GST_FORMAT_TIME; + if (!gst_element_query_duration (media->pipeline, &format, &duration)) + duration = -1; + + if (duration == -1) { + media->range.max.type = GST_RTSP_TIME_END; + media->range.max.seconds = -1; + } + else { + media->range.max.type = GST_RTSP_TIME_SECONDS; + media->range.max.seconds = ((gdouble)duration) / GST_SECOND; + } } } @@ -799,11 +813,21 @@ gst_rtsp_media_play (GstRTSPMedia *media, GArray *transports) /* get the stream and add the destinations */ stream = gst_rtsp_media_get_stream (media, tr->idx); + switch (trans->lower_transport) { + case GST_RTSP_LOWER_TRANS_UDP: + case GST_RTSP_LOWER_TRANS_UDP_MCAST: + g_message ("adding %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); - g_message ("adding %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); - - g_signal_emit_by_name (stream->udpsink[0], "add", trans->destination, trans->client_port.min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "add", trans->destination, trans->client_port.max, NULL); + g_signal_emit_by_name (stream->udpsink[0], "add", trans->destination, trans->client_port.min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "add", trans->destination, trans->client_port.max, NULL); + break; + case GST_RTSP_LOWER_TRANS_TCP: + g_message ("TCP transport not yet implemented"); + break; + default: + g_message ("Unknown transport %d", trans->lower_transport); + break; + } } g_message ("playing media %p", media); @@ -852,12 +876,22 @@ gst_rtsp_media_pause (GstRTSPMedia *media, GArray *transports) /* get the stream and add the destinations */ stream = gst_rtsp_media_get_stream (media, tr->idx); - g_message ("removing %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); + switch (trans->lower_transport) { + case GST_RTSP_LOWER_TRANS_UDP: + case GST_RTSP_LOWER_TRANS_UDP_MCAST: + g_message ("removing %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); - g_signal_emit_by_name (stream->udpsink[0], "remove", trans->destination, trans->client_port.min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "remove", trans->destination, trans->client_port.max, NULL); + g_signal_emit_by_name (stream->udpsink[0], "remove", trans->destination, trans->client_port.min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "remove", trans->destination, trans->client_port.max, NULL); + break; + case GST_RTSP_LOWER_TRANS_TCP: + g_message ("TCP transport not yet implemented"); + break; + default: + g_message ("Unknown transport %d", trans->lower_transport); + break; + } } - g_message ("pause media %p", media); media->target_state = GST_STATE_PAUSED; ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index e613925fbc..f746be6e43 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -91,6 +91,7 @@ struct _GstRTSPMediaStream { * sockets */ GstElement *udpsrc[2]; GstElement *udpsink[2]; + GstElement *appsrc[2]; /* server ports for sending/receiving */ GstRTSPRange server_port; From da6f337745fb62703d47f385913206b35f8c5578 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 11 Mar 2009 16:39:20 +0100 Subject: [PATCH 0079/1776] Add example server that takes launch lines Add an example server that streams any -launch line. --- examples/Makefile.am | 2 +- examples/test-launch.c | 70 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 examples/test-launch.c diff --git a/examples/Makefile.am b/examples/Makefile.am index c8196d1095..a7f9986a57 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,4 +1,4 @@ -noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme +noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/examples/test-launch.c b/examples/test-launch.c new file mode 100644 index 0000000000..fb863ecc3f --- /dev/null +++ b/examples/test-launch.c @@ -0,0 +1,70 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMediaMapping *mapping; + GstRTSPMediaFactory *factory; + + gst_init (&argc, &argv); + + if (argc < 2) { + g_print ("usage: %s \n" + "example: %s \"( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )\"\n", + argv[0], argv[0]); + return -1; + } + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mapping for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mapping = gst_rtsp_server_get_media_mapping (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, argv[1]); + + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mapping); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + /* start serving */ + g_main_loop_run (loop); + + return 0; +} From ebc28a47dad000f8344ab803a43fc981d1fca339 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 11 Mar 2009 16:45:12 +0100 Subject: [PATCH 0080/1776] Add TCP transports Use appsrc and appsink to send and receive RTP/RTCP packets in the TCP connection. --- gst/rtsp-server/rtsp-client.c | 168 ++++++++++++++-- gst/rtsp-server/rtsp-client.h | 14 +- gst/rtsp-server/rtsp-media.c | 345 +++++++++++++++++++++------------ gst/rtsp-server/rtsp-media.h | 41 +++- gst/rtsp-server/rtsp-server.c | 1 - gst/rtsp-server/rtsp-session.c | 72 +++---- gst/rtsp-server/rtsp-session.h | 9 +- 7 files changed, 454 insertions(+), 196 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 811ae032e3..70b0e23935 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -190,9 +190,6 @@ send_response (GstRTSPClient *client, GstRTSPSession *session, GstRTSPMessage *r gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1); } -#if 0 - gst_rtsp_connection_send (client->connection, response, &timeout); -#endif gst_rtsp_watch_queue_message (client->watch, response); gst_rtsp_message_unset (response); } @@ -296,6 +293,81 @@ no_prepare: } } +static gboolean +do_send_data (GstBuffer *buffer, guint8 channel, GstRTSPClient *client) +{ + GstRTSPMessage message = { 0 }; + guint8 *data; + guint size; + + gst_rtsp_message_init_data (&message, channel); + + data = GST_BUFFER_DATA (buffer); + size = GST_BUFFER_SIZE (buffer); + gst_rtsp_message_take_body (&message, data, size); + + gst_rtsp_watch_queue_message (client->watch, &message); + + gst_rtsp_message_steal_body (&message, &data, &size); + gst_rtsp_message_unset (&message); + + return TRUE; +} + +static void +link_stream (GstRTSPClient *client, GstRTSPSessionStream *stream) +{ + gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data, + (GstRTSPSendFunc) do_send_data, client, NULL); + client->streams = g_list_prepend (client->streams, stream); +} + +static void +unlink_stream (GstRTSPClient *client, GstRTSPSessionStream *stream) +{ + gst_rtsp_session_stream_set_callbacks (stream, NULL, + NULL, client, g_object_unref); + client->streams = g_list_remove (client->streams, stream); +} + +static void +unlink_streams (GstRTSPClient *client) +{ + GList *walk; + + for (walk = client->streams; walk; walk = g_list_next (walk)) { + GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data; + + gst_rtsp_session_stream_set_callbacks (stream, NULL, + NULL, NULL, NULL); + } + g_list_free (client->streams); + client->streams = NULL; +} + +static void +unlink_session_streams (GstRTSPClient *client, GstRTSPSessionMedia *media) +{ + guint n_streams, i; + + n_streams = gst_rtsp_media_n_streams (media->media); + for (i = 0; i < n_streams; i++) { + GstRTSPSessionStream *sstream; + GstRTSPTransport *tr; + + /* get the stream as configured in the session */ + sstream = gst_rtsp_session_media_get_stream (media, i); + /* get the transport, if there is no transport configured, skip this stream */ + if (!(tr = sstream->trans.transport)) + continue; + + if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { + /* for TCP, unlink the stream from the TCP connection of the client */ + unlink_stream (client, sstream); + } + } +} + static gboolean handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) { @@ -311,7 +383,10 @@ handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession if (!media) goto not_found; - gst_rtsp_session_media_stop (media); + /* unlink the all TCP callbacks */ + unlink_session_streams (client, media); + + gst_rtsp_session_media_set_state (media, GST_STATE_NULL); /* unmanage the media in the session, returns false if all media session * are torn down. */ @@ -360,7 +435,11 @@ handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se media->state != GST_RTSP_STATE_RECORDING) goto invalid_state; - gst_rtsp_session_media_pause (media); + /* unlink the all TCP callbacks */ + unlink_session_streams (client, media); + + /* then pause sending */ + gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED); /* construct the response now */ code = GST_RTSP_STS_OK; @@ -420,10 +499,23 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses n_streams = gst_rtsp_media_n_streams (media->media); for (i = 0; i < n_streams; i++) { + GstRTSPSessionStream *sstream; GstRTSPMediaStream *stream; + GstRTSPTransport *tr; gchar *uristr; - stream = gst_rtsp_media_get_stream (media->media, i); + /* get the stream as configured in the session */ + sstream = gst_rtsp_session_media_get_stream (media, i); + /* get the transport, if there is no transport configured, skip this stream */ + if (!(tr = sstream->trans.transport)) + continue; + + if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { + /* for TCP, link the stream to the TCP connection of the client */ + link_stream (client, sstream); + } + + stream = sstream->media_stream; g_object_get (G_OBJECT (stream->payloader), "seqnum", &seqnum, NULL); g_object_get (G_OBJECT (stream->payloader), "timestamp", ×tamp, NULL); @@ -451,7 +543,7 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses send_response (client, session, &response); /* start playing after sending the request */ - gst_rtsp_session_media_play (media); + gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING); media->state = GST_RTSP_STATE_PLAYING; @@ -594,12 +686,6 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se if (!(stream = gst_rtsp_session_media_get_stream (media, streamid))) goto no_stream; - /* setup the server transport from the client transport */ - if (ct->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { - ct->port.min = gst_rtsp_connection_get_readfd (client->connection); - ct->port.max = gst_rtsp_connection_get_writefd (client->connection); - } - st = gst_rtsp_session_stream_set_transport (stream, ct); /* serialize the server transport */ @@ -806,6 +892,8 @@ handle_request (GstRTSPClient *client, GstRTSPMessage *request) gst_rtsp_message_dump (request); #endif + g_message ("client %p: received a request", client); + gst_rtsp_message_parse_request (request, &method, &uristr, &version); if (version != GST_RTSP_VERSION_1_0) { @@ -889,6 +977,54 @@ session_not_found: } } +static void +handle_data (GstRTSPClient *client, GstRTSPMessage *message) +{ + GstRTSPResult res; + guint8 channel; + GList *walk; + guint8 *data; + guint size; + GstBuffer *buffer; + + /* find the stream for this message */ + res = gst_rtsp_message_parse_data (message, &channel); + if (res != GST_RTSP_OK) + return; + + gst_rtsp_message_steal_body (message, &data, &size); + + buffer = gst_buffer_new (); + GST_BUFFER_DATA (buffer) = data; + GST_BUFFER_MALLOCDATA (buffer) = data; + GST_BUFFER_SIZE (buffer) = size; + + for (walk = client->streams; walk; walk = g_list_next (walk)) { + GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data; + GstRTSPMediaStream *mstream; + GstRTSPTransport *tr; + + /* get the transport, if there is no transport configured, skip this stream */ + if (!(tr = stream->trans.transport)) + continue; + + /* we also need a media stream */ + if (!(mstream = stream->media_stream)) + continue; + + /* check for TCP transport */ + if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { + /* dispatch to the stream based on the channel number */ + if (tr->interleaved.min == channel) { + gst_rtsp_media_stream_rtp (mstream, buffer); + } else if (tr->interleaved.max == channel) { + gst_rtsp_media_stream_rtcp (mstream, buffer); + } + } + } + gst_buffer_unref (buffer); +} + /** * gst_rtsp_client_set_timeout: * @client: a #GstRTSPClient @@ -1008,8 +1144,6 @@ message_received (GstRTSPWatch *watch, GstRTSPMessage *message, gpointer user_da { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); - g_message ("client %p: received a message", client); - switch (message->type) { case GST_RTSP_MESSAGE_REQUEST: handle_request (client, message); @@ -1017,6 +1151,7 @@ message_received (GstRTSPWatch *watch, GstRTSPMessage *message, gpointer user_da case GST_RTSP_MESSAGE_RESPONSE: break; case GST_RTSP_MESSAGE_DATA: + handle_data (client, message); break; default: break; @@ -1048,6 +1183,9 @@ closed (GstRTSPWatch *watch, gpointer user_data) g_mutex_unlock (tunnels_lock); } + /* remove all streams that are streaming over this client connection */ + unlink_streams (client); + return GST_RTSP_OK; } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 9949f1a1cd..07b81d9180 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -59,10 +59,14 @@ typedef struct _GstRTSPClientClass GstRTSPClientClass; * GstRTSPClient: * * @connection: the connection object handling the client request. - * @address: the address of the connection - * @media: handle to the media handled by the client. - * @pool: handle to the session pool used by the client. - * @thread: thread to handle the client connection + * @watch: watch for the connection + * @watchid: id of the watch + * @timeout: the session timeout + * @session_pool: handle to the session pool used by the client. + * @media_mapping: handle to the media mapping used by the client. + * @uri: cached uri + * @media: cached media + * @streams: a list of streams using @connection. * * The client structure. */ @@ -79,6 +83,8 @@ struct _GstRTSPClient { GstRTSPUrl *uri; GstRTSPMedia *media; + + GList *streams; }; struct _GstRTSPClientClass { diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 6284612d74..b75d3863ca 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -69,7 +69,6 @@ static void gst_rtsp_media_init (GstRTSPMedia * media) { media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); - media->complete = FALSE; media->is_live = FALSE; media->buffering = FALSE; } @@ -251,6 +250,46 @@ gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx) return res; } +/** + * gst_rtsp_media_stream_rtp: + * @stream: a #GstRTSPMediaStream + * @buffer: a #GstBuffer + * + * Handle an RTP buffer for the stream. This method is usually called when a + * message has been received from a client using the TCP transport. + * + * Returns: a GstFlowReturn. + */ +GstFlowReturn +gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer) +{ + GstFlowReturn ret; + + g_signal_emit_by_name (stream->appsrc[0], "push-buffer", buffer, &ret); + + return ret; +} + +/** + * gst_rtsp_media_stream_rtcp: + * @stream: a #GstRTSPMediaStream + * @buffer: a #GstBuffer + * + * Handle an RTCP buffer for the stream. This method is usually called when a + * message has been received from a client using the TCP transport. + * + * Returns: a GstFlowReturn. + */ +GstFlowReturn +gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer) +{ + GstFlowReturn ret; + + g_signal_emit_by_name (stream->appsrc[1], "push-buffer", buffer, &ret); + + return GST_FLOW_ERROR; +} + /* Allocate the udp ports and sockets */ static gboolean alloc_udp_ports (GstRTSPMediaStream * stream) @@ -461,19 +500,67 @@ on_timeout (GObject *session, GObject *source, GstRTSPMedia *media) g_message ("%p: source %p timeout", media, source); } +static void +handle_new_buffer (GstElement *sink, GstRTSPMediaStream *stream) +{ + GList *walk; + GstBuffer *buffer; + + g_signal_emit_by_name (sink, "pull-buffer", &buffer); + if (!buffer) + return; + + for (walk = stream->transports; walk; walk = g_list_next (walk)) { + GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data; + + if (sink == stream->appsink[0]) { + if (tr->send_rtp) + tr->send_rtp (buffer, tr->transport->interleaved.min, tr->user_data); + } + else { + if (tr->send_rtcp) + tr->send_rtcp (buffer, tr->transport->interleaved.max, tr->user_data); + } + } + gst_buffer_unref (buffer); +} + /* prepare the pipeline objects to handle @stream in @media */ static gboolean setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) { gchar *name; - GstPad *pad; + GstPad *pad, *teepad, *selpad; + GstPadLinkReturn ret; + gint i; + GstElement *tee, *selector; - alloc_udp_ports (stream); + /* allocate udp ports, we will have 4 of them, 2 for receiving RTP/RTCP and 2 + * for sending RTP/RTCP. The sender and receiver ports are shared between the + * elements */ + if (!alloc_udp_ports (stream)) + return FALSE; - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsink[0]); - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsink[1]); - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsrc[0]); - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsrc[1]); + /* add the ports to the pipeline */ + for (i = 0; i < 2; i++) { + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsink[i]); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsrc[i]); + } + + /* create elements for the TCP transfer */ + for (i = 0; i < 2; i++) { + stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL); + stream->appsink[i] = gst_element_factory_make ("appsink", NULL); + g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL); + g_object_set (stream->appsink[i], "emit-signals", TRUE, NULL); + g_object_set (stream->appsink[i], "preroll-queue-len", 1, NULL); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsink[i]); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsrc[i]); + } + g_signal_connect (stream->appsink[0], "new-buffer", + (GCallback) handle_new_buffer, stream); + g_signal_connect (stream->appsink[1], "new-buffer", + (GCallback) handle_new_buffer, stream); /* hook up the stream to the RTP session elements. */ name = g_strdup_printf ("send_rtp_sink_%d", idx); @@ -505,19 +592,73 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) media); /* link the RTP pad to the session manager */ - gst_pad_link (stream->srcpad, stream->send_rtp_sink); + ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink); + if (ret != GST_PAD_LINK_OK) + goto link_failed; - /* link udp elements */ - pad = gst_element_get_static_pad (stream->udpsink[0], "sink"); + /* make tee for RTP and link to stream */ + tee = gst_element_factory_make ("tee", NULL); + gst_bin_add (GST_BIN_CAST (media->pipeline), tee); + + pad = gst_element_get_static_pad (tee, "sink"); gst_pad_link (stream->send_rtp_src, pad); gst_object_unref (pad); - pad = gst_element_get_static_pad (stream->udpsink[1], "sink"); + + /* link RTP sink, we're pretty sure this will work. */ + teepad = gst_element_get_request_pad (tee, "src%d"); + pad = gst_element_get_static_pad (stream->udpsink[0], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); + + teepad = gst_element_get_request_pad (tee, "src%d"); + pad = gst_element_get_static_pad (stream->appsink[0], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); + + /* make tee for RTCP */ + tee = gst_element_factory_make ("tee", NULL); + gst_bin_add (GST_BIN_CAST (media->pipeline), tee); + + pad = gst_element_get_static_pad (tee, "sink"); gst_pad_link (stream->send_rtcp_src, pad); gst_object_unref (pad); - pad = gst_element_get_static_pad (stream->udpsrc[1], "src"); + + /* link RTCP elements */ + teepad = gst_element_get_request_pad (tee, "src%d"); + pad = gst_element_get_static_pad (stream->udpsink[1], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); + + teepad = gst_element_get_request_pad (tee, "src%d"); + pad = gst_element_get_static_pad (stream->appsink[1], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); + + /* make selector for the RTCP receivers */ + selector = gst_element_factory_make ("input-selector", NULL); + g_object_set (selector, "select-all", TRUE, NULL); + gst_bin_add (GST_BIN_CAST (media->pipeline), selector); + + pad = gst_element_get_static_pad (selector, "src"); gst_pad_link (pad, stream->recv_rtcp_sink); gst_object_unref (pad); + selpad = gst_element_get_request_pad (selector, "sink%d"); + pad = gst_element_get_static_pad (stream->udpsrc[1], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + + selpad = gst_element_get_request_pad (selector, "sink%d"); + pad = gst_element_get_static_pad (stream->appsrc[1], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + /* we set and keep these to playing so that they don't cause NO_PREROLL return * values */ gst_element_set_state (stream->udpsrc[0], GST_STATE_PLAYING); @@ -532,6 +673,13 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) stream->prepared = TRUE; return TRUE; + + /* ERRORS */ +link_failed: + { + g_warning ("failed to link stream %d", idx); + return FALSE; + } } static void @@ -648,6 +796,17 @@ default_handle_message (GstRTSPMedia *media, GstMessage *message) g_free (debug); break; } + case GST_MESSAGE_WARNING: + { + GError *gerror; + gchar *debug; + + gst_message_parse_warning (message, &gerror, &debug); + g_warning ("%p: got warning %s (%s)", media, gerror->message, debug); + g_error_free (gerror); + g_free (debug); + break; + } default: g_message ("%p: got message type %s", media, gst_message_type_get_name (type)); break; @@ -678,6 +837,9 @@ bus_message (GstBus *bus, GstMessage *message, GstRTSPMedia *media) * Prepare @media for streaming. This function will create the pipeline and * other objects to manage the streaming. * + * It will preroll the pipeline and collect vital information about the streams + * such as the duration. + * * Returns: %TRUE on success. */ gboolean @@ -736,19 +898,22 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) g_message ("live media %p", media); media->is_live = TRUE; ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) + goto state_failed; break; case GST_STATE_CHANGE_FAILURE: - { - unlock_streams (media); goto state_failed; - } } /* now wait for all pads to be prerolled */ ret = gst_element_get_state (media->pipeline, NULL, NULL, -1); + if (ret == GST_STATE_CHANGE_FAILURE) + goto state_failed; /* and back to PAUSED for live pipelines */ ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); + if (ret == GST_STATE_CHANGE_FAILURE) + goto state_failed; /* collect stats about the media */ collect_media_stats (media); @@ -770,33 +935,58 @@ was_prepared: /* ERRORS */ state_failed: { + g_warning ("failed to preroll pipeline"); + unlock_streams (media); gst_element_set_state (media->pipeline, GST_STATE_NULL); return FALSE; } } /** - * gst_rtsp_media_play: + * gst_rtsp_media_set_state: * @media: a #GstRTSPMedia + * @state: the target state of the media * @transports: a GArray of #GstRTSPMediaTrans pointers * - * Start playing @media for to the transports in @transports. + * Set the state of @media to @state and for the transports in @transports. * * Returns: %TRUE on success. */ gboolean -gst_rtsp_media_play (GstRTSPMedia *media, GArray *transports) +gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transports) { gint i; GstStateChangeReturn ret; + gboolean add, remove; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (transports != NULL, FALSE); g_return_val_if_fail (media->prepared, FALSE); - if (media->target_state == GST_STATE_PLAYING) + /* NULL and READY are the same */ + if (state == GST_STATE_READY) + state = GST_STATE_NULL; + + if (media->target_state == state) return TRUE; + add = remove = FALSE; + + switch (state) { + case GST_STATE_NULL: + case GST_STATE_PAUSED: + /* we're going from PLAYING to READY or NULL, remove */ + if (media->target_state == GST_STATE_PLAYING) + remove = TRUE; + break; + case GST_STATE_PLAYING: + /* we're going to PLAYING, add */ + add = TRUE; + break; + default: + break; + } + for (i = 0; i < transports->len; i++) { GstRTSPMediaTrans *tr; GstRTSPMediaStream *stream; @@ -816,13 +1006,22 @@ gst_rtsp_media_play (GstRTSPMedia *media, GArray *transports) switch (trans->lower_transport) { case GST_RTSP_LOWER_TRANS_UDP: case GST_RTSP_LOWER_TRANS_UDP_MCAST: - g_message ("adding %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); - - g_signal_emit_by_name (stream->udpsink[0], "add", trans->destination, trans->client_port.min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "add", trans->destination, trans->client_port.max, NULL); + if (add) { + g_message ("adding %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); + g_signal_emit_by_name (stream->udpsink[0], "add", trans->destination, trans->client_port.min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "add", trans->destination, trans->client_port.max, NULL); + } else if (remove) { + g_message ("removing %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); + g_signal_emit_by_name (stream->udpsink[0], "remove", trans->destination, trans->client_port.min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "remove", trans->destination, trans->client_port.max, NULL); + } break; case GST_RTSP_LOWER_TRANS_TCP: - g_message ("TCP transport not yet implemented"); + if (add) { + stream->transports = g_list_prepend (stream->transports, tr); + } else if (remove) { + stream->transports = g_list_remove (stream->transports, tr); + } break; default: g_message ("Unknown transport %d", trans->lower_transport); @@ -830,101 +1029,9 @@ gst_rtsp_media_play (GstRTSPMedia *media, GArray *transports) } } - g_message ("playing media %p", media); - media->target_state = GST_STATE_PLAYING; - ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); - - return TRUE; -} - -/** - * gst_rtsp_media_pause: - * @media: a #GstRTSPMedia - * @transports: a array of #GstRTSPTransport pointers - * - * Pause playing @media for to the transports in @transports. - * - * Returns: %TRUE on success. - */ -gboolean -gst_rtsp_media_pause (GstRTSPMedia *media, GArray *transports) -{ - gint i; - GstStateChangeReturn ret; - - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - g_return_val_if_fail (transports != NULL, FALSE); - g_return_val_if_fail (media->prepared, FALSE); - - if (media->target_state == GST_STATE_PAUSED) - return TRUE; - - for (i = 0; i < transports->len; i++) { - GstRTSPMediaTrans *tr; - GstRTSPMediaStream *stream; - GstRTSPTransport *trans; - - /* we need a non-NULL entry in the array */ - tr = g_array_index (transports, GstRTSPMediaTrans *, i); - if (tr == NULL) - continue; - - /* we need a transport */ - if (!(trans = tr->transport)) - continue; - - /* get the stream and add the destinations */ - stream = gst_rtsp_media_get_stream (media, tr->idx); - - switch (trans->lower_transport) { - case GST_RTSP_LOWER_TRANS_UDP: - case GST_RTSP_LOWER_TRANS_UDP_MCAST: - g_message ("removing %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); - - g_signal_emit_by_name (stream->udpsink[0], "remove", trans->destination, trans->client_port.min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "remove", trans->destination, trans->client_port.max, NULL); - break; - case GST_RTSP_LOWER_TRANS_TCP: - g_message ("TCP transport not yet implemented"); - break; - default: - g_message ("Unknown transport %d", trans->lower_transport); - break; - } - } - g_message ("pause media %p", media); - media->target_state = GST_STATE_PAUSED; - ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); - - return TRUE; -} - -/** - * gst_rtsp_media_stream_stop: - * @media: a #GstRTSPMedia - * @transports: a GArray of #GstRTSPMediaTrans pointers - * - * Stop playing @media for to the transports in @transports. - * - * Returns: %TRUE on success. - */ -gboolean -gst_rtsp_media_stop (GstRTSPMedia *media, GArray *transports) -{ - GstStateChangeReturn ret; - - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - g_return_val_if_fail (transports != NULL, FALSE); - g_return_val_if_fail (media->prepared, FALSE); - - if (media->target_state == GST_STATE_NULL) - return TRUE; - - gst_rtsp_media_pause (media, transports); - - g_message ("stop media %p", media); - media->target_state = GST_STATE_NULL; - ret = gst_element_set_state (media->pipeline, GST_STATE_NULL); + g_message ("state %s media %p", gst_element_state_get_name (state), media); + media->target_state = state; + ret = gst_element_set_state (media->pipeline, state); return TRUE; } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index f746be6e43..4aaaa1debb 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -41,9 +41,15 @@ typedef struct _GstRTSPMedia GstRTSPMedia; typedef struct _GstRTSPMediaClass GstRTSPMediaClass; typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans; +typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); + /** * GstRTSPMediaTrans: * @idx: a stream index + * @send_rtp: callback for sending RTP messages + * @send_rtcp: callback for sending RTCP messages + * @user_data: user data passed in the callbacks + * @notify: free function for the user_data. * @transport: a transport description * * A Transport description for stream @idx @@ -51,13 +57,17 @@ typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans; struct _GstRTSPMediaTrans { guint idx; + GstRTSPSendFunc send_rtp; + GstRTSPSendFunc send_rtcp; + gpointer user_data; + GDestroyNotify notify; + GstRTSPTransport *transport; }; /** * GstRTSPMediaStream: * - * @media: the owner #GstRTSPMedia * @srcpad: the srcpad of the stream * @payloader: the payloader of the format * @prepared: if the stream is prepared for streaming @@ -68,8 +78,12 @@ struct _GstRTSPMediaTrans { * @recv_rtcp_src: srcpad for RTCP buffers * @udpsrc: the udp source elements for RTP/RTCP * @udpsink: the udp sink elements for RTP/RTCP + * @appsrc: the app source elements for RTP/RTCP + * @appsink: the app sink elements for RTP/RTCP + * @server_port: the server ports for this stream * @caps_sig: the signal id for detecting caps * @caps: the caps of the stream + * @tranports: the current transports being streamed * * The definition of a media stream. The streams are identified by @id. */ @@ -91,7 +105,9 @@ struct _GstRTSPMediaStream { * sockets */ GstElement *udpsrc[2]; GstElement *udpsink[2]; + /* for TCP transport */ GstElement *appsrc[2]; + GstElement *appsink[2]; /* server ports for sending/receiving */ GstRTSPRange server_port; @@ -99,17 +115,25 @@ struct _GstRTSPMediaStream { /* the caps of the stream */ gulong caps_sig; GstCaps *caps; + + /* transports we stream to */ + GList *transports; }; /** * GstRTSPMedia: * @shared: if this media can be shared between clients * @element: the data providing element - * @stream: the different streams provided by @element + * @streams: the different streams provided by @element * @prepared: if the media is prepared for streaming * @pipeline: the toplevel pipeline + * @source: the bus watch for pipeline messages. + * @id: the id of the watch + * @is_live: if the pipeline is live + * @buffering: if the pipeline is buffering + * @target_state: the desired target state of the pipeline * @rtpbin: the rtpbin - * @multifdsink: multifdsink element for TCP transport + * @range: the range of the media being streamed * * A class that contains the GStreamer element along with a list of * #GstRTSPediaStream objects that can produce data. @@ -120,7 +144,6 @@ struct _GstRTSPMedia { GObject parent; gboolean shared; - gboolean complete; GstElement *element; GArray *streams; @@ -138,9 +161,6 @@ struct _GstRTSPMedia { /* RTP session manager */ GstElement *rtpbin; - /* for TCP transport */ - GstElement *multifdsink; - /* the range of media */ GstRTSPTimeRange range; }; @@ -180,9 +200,10 @@ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); guint gst_rtsp_media_n_streams (GstRTSPMedia *media); GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); -gboolean gst_rtsp_media_play (GstRTSPMedia *media, GArray *trans); -gboolean gst_rtsp_media_pause (GstRTSPMedia *media, GArray *trans); -gboolean gst_rtsp_media_stop (GstRTSPMedia *media, GArray *trans); +GstFlowReturn gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer); +GstFlowReturn gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer); + +gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *trans); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index b860563358..e9c965edb1 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -220,7 +220,6 @@ gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *poo } } - /** * gst_rtsp_server_get_session_pool: * @server: a #GstRTSPServer diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index a80e28022a..b590146c66 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -89,7 +89,7 @@ gst_rtsp_session_free_media (GstRTSPSessionMedia *media, GstRTSPSession *session g_message ("free session media %p", media); - gst_rtsp_session_media_stop (media); + gst_rtsp_session_media_set_state (media, GST_STATE_NULL); for (i = 0; i < size; i++) { GstRTSPSessionStream *stream; @@ -476,75 +476,59 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, st->profile = ct->profile; st->lower_transport = ct->lower_transport; st->client_port = ct->client_port; + st->interleaved = ct->interleaved; + st->server_port.min = stream->media_stream->server_port.min; + st->server_port.max = stream->media_stream->server_port.max; - /* keep track of the transports */ + /* keep track of the transports in the stream. */ if (stream->trans.transport) gst_rtsp_transport_free (stream->trans.transport); stream->trans.transport = ct; - st->server_port.min = stream->media_stream->server_port.min; - st->server_port.max = stream->media_stream->server_port.max; - return st; } /** - * gst_rtsp_session_media_play: - * @media: a #GstRTSPSessionMedia + * gst_rtsp_session_stream_set_callbacks: + * @stream: a #GstRTSPSessionStream + * @send_rtp: a callback called when RTP should be send + * @send_rtcp: a callback called when RTCP should be send + * @user_data: user data passed to callbacks + * @notify: called with the user_data when no longer needed. * - * Tell the media object @media to start playing and streaming to the client. - * - * Returns: %TRUE on success. + * Install callbacks that will be called when data for a stream should be sent + * to a client. This is usually used when sending RTP/RTCP over TCP. */ -gboolean -gst_rtsp_session_media_play (GstRTSPSessionMedia *media) +void +gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream *stream, + GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, gpointer user_data, + GDestroyNotify notify) { - gboolean ret; - - g_return_val_if_fail (media != NULL, FALSE); - - ret = gst_rtsp_media_play (media->media, media->streams); - - return ret; + stream->trans.send_rtp = send_rtp; + stream->trans.send_rtcp = send_rtcp; + if (stream->trans.notify) + stream->trans.notify (stream->trans.user_data); + stream->trans.user_data = user_data; + stream->trans.notify = notify; } /** - * gst_rtsp_session_media_pause: + * gst_rtsp_session_media_set_state: * @media: a #GstRTSPSessionMedia + * @state: the new state * - * Tell the media object @media to pause. + * Tell the media object @media to change to @state. * * Returns: %TRUE on success. */ gboolean -gst_rtsp_session_media_pause (GstRTSPSessionMedia *media) +gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media, GstState state) { gboolean ret; g_return_val_if_fail (media != NULL, FALSE); - ret = gst_rtsp_media_pause (media->media, media->streams); - - return ret; -} - -/** - * gst_rtsp_session_media_stop: - * @media: a #GstRTSPSessionMedia - * - * Tell the media object @media to stop playing. After this call the media - * cannot be played or paused anymore - * - * Returns: %TRUE on success. - */ -gboolean -gst_rtsp_session_media_stop (GstRTSPSessionMedia *media) -{ - gboolean ret; - - g_return_val_if_fail (media != NULL, FALSE); - - ret = gst_rtsp_media_stop (media->media, media->streams); + ret = gst_rtsp_media_set_state (media->media, state, media->streams); return ret; } diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index b3797b13ce..495bc75989 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -132,9 +132,7 @@ gboolean gst_rtsp_session_release_media (GstRTSPSession *se GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *uri); /* control media */ -gboolean gst_rtsp_session_media_play (GstRTSPSessionMedia *media); -gboolean gst_rtsp_session_media_pause (GstRTSPSessionMedia *media); -gboolean gst_rtsp_session_media_stop (GstRTSPSessionMedia *media); +gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media, GstState state); /* get stream config */ GstRTSPSessionStream * gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, @@ -143,6 +141,11 @@ GstRTSPSessionStream * gst_rtsp_session_media_get_stream (GstRTSPSessionMedi /* configure transport */ GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, GstRTSPTransport *ct); +void gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream *stream, + GstRTSPSendFunc send_rtp, + GstRTSPSendFunc send_rtcp, + gpointer user_data, + GDestroyNotify notify); G_END_DECLS From 1be35624dad16502835a4de6300cc6a735030c05 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 11 Mar 2009 19:38:06 +0100 Subject: [PATCH 0081/1776] Do some more session cleanup Make session timeout kill the TCP connection that currently watches the session. Remove the client timeout property. --- gst/rtsp-server/rtsp-client.c | 105 +++++++++++++--------------- gst/rtsp-server/rtsp-client.h | 7 +- gst/rtsp-server/rtsp-session-pool.c | 6 +- 3 files changed, 52 insertions(+), 66 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 70b0e23935..2476db7a9b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -22,9 +22,7 @@ #include "rtsp-client.h" #include "rtsp-sdp.h" -#undef DEBUG - -#define DEFAULT_TIMEOUT 60 +#define DEBUG static GMutex *tunnels_lock; static GHashTable *tunnels; @@ -32,7 +30,6 @@ static GHashTable *tunnels; enum { PROP_0, - PROP_TIMEOUT, PROP_SESSION_POOL, PROP_MEDIA_MAPPING, PROP_LAST @@ -44,6 +41,8 @@ static void gst_rtsp_client_set_property (GObject *object, guint propid, const GValue *value, GParamSpec *pspec); static void gst_rtsp_client_finalize (GObject * obj); +static void client_session_finalized (GstRTSPClient *client, GstRTSPSession *session); + G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); static void @@ -57,10 +56,6 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gobject_class->set_property = gst_rtsp_client_set_property; gobject_class->finalize = gst_rtsp_client_finalize; - g_object_class_install_property (gobject_class, PROP_SESSION_POOL, - g_param_spec_uint ("timeout", "Timeout", "The client timeout", - 0, G_MAXUINT, DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_SESSION_POOL, g_param_spec_object ("session-pool", "Session Pool", "The session pool to use for client session", @@ -78,7 +73,6 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) static void gst_rtsp_client_init (GstRTSPClient * client) { - client->timeout = DEFAULT_TIMEOUT; } /* A client is finalized when the connection is broken */ @@ -86,9 +80,14 @@ static void gst_rtsp_client_finalize (GObject * obj) { GstRTSPClient *client = GST_RTSP_CLIENT (obj); + GList *walk; g_message ("finalize client %p", client); + for (walk = client->sessions; walk; walk = g_list_next (walk)) + g_object_weak_unref (G_OBJECT (walk->data), (GWeakNotify) client_session_finalized, client); + g_list_free (client->sessions); + gst_rtsp_connection_free (client->connection); if (client->session_pool) g_object_unref (client->session_pool); @@ -110,9 +109,6 @@ gst_rtsp_client_get_property (GObject *object, guint propid, GstRTSPClient *client = GST_RTSP_CLIENT (object); switch (propid) { - case PROP_TIMEOUT: - g_value_set_uint (value, gst_rtsp_client_get_timeout (client)); - break; case PROP_SESSION_POOL: g_value_take_object (value, gst_rtsp_client_get_session_pool (client)); break; @@ -131,9 +127,6 @@ gst_rtsp_client_set_property (GObject *object, guint propid, GstRTSPClient *client = GST_RTSP_CLIENT (object); switch (propid) { - case PROP_TIMEOUT: - gst_rtsp_client_set_timeout (client, g_value_get_uint (value)); - break; case PROP_SESSION_POOL: gst_rtsp_client_set_session_pool (client, g_value_get_object (value)); break; @@ -163,16 +156,10 @@ gst_rtsp_client_new (void) static void send_response (GstRTSPClient *client, GstRTSPSession *session, GstRTSPMessage *response) { - GTimeVal timeout; - gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER, "GStreamer RTSP server"); -#ifdef DEBUG - gst_rtsp_message_dump (response); -#endif - - timeout.tv_sec = client->timeout; - timeout.tv_usec = 0; + /* remove any previous header */ + gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1); /* add the new session header for new session ids */ if (session) { @@ -185,10 +172,10 @@ send_response (GstRTSPClient *client, GstRTSPSession *session, GstRTSPMessage *r gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION, str); } - else { - /* remove the session id from the response */ - gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1); - } + +#ifdef DEBUG + gst_rtsp_message_dump (response); +#endif gst_rtsp_watch_queue_message (client->watch, response); gst_rtsp_message_unset (response); @@ -807,7 +794,7 @@ handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession gst_rtsp_message_take_body (&response, (guint8 *)str, strlen (str)); gst_sdp_message_free (sdp); - send_response (client, NULL, &response); + send_response (client, session, &response); return TRUE; @@ -847,7 +834,7 @@ handle_options_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession * gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str); g_free (str); - send_response (client, NULL, &response); + send_response (client, session, &response); } /* remove duplicate and trailing '/' */ @@ -877,6 +864,37 @@ santize_uri (GstRTSPUrl *uri) *d = '\0'; } +static void +client_session_finalized (GstRTSPClient *client, GstRTSPSession *session) +{ + g_message ("session %p finalized", session); + + client->sessions = g_list_remove (client->sessions, session); + if (client->sessions == NULL) { + g_message ("all sessions finalized"); + g_source_destroy ((GSource*)client->watch); + } +} + +static void +client_watch_session (GstRTSPClient *client, GstRTSPSession *session) +{ + GList *walk; + + for (walk = client->sessions; walk; walk = g_list_next (walk)) { + GstRTSPSession *msession = (GstRTSPSession *) walk->data; + + /* we already know about this session */ + if (msession == session) + return; + } + + g_message ("watching session %p", session); + + g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client); + client->sessions = g_list_prepend (client->sessions, session); +} + static void handle_request (GstRTSPClient *client, GstRTSPMessage *request) { @@ -921,7 +939,7 @@ handle_request (GstRTSPClient *client, GstRTSPMessage *request) if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid))) goto session_not_found; - client->timeout = gst_rtsp_session_get_timeout (session); + client_watch_session (client, session); } else session = NULL; @@ -1025,33 +1043,6 @@ handle_data (GstRTSPClient *client, GstRTSPMessage *message) gst_buffer_unref (buffer); } -/** - * gst_rtsp_client_set_timeout: - * @client: a #GstRTSPClient - * @timeout: a timeout in seconds - * - * Set the connection timeout to @timeout seconds for @client. - */ -void -gst_rtsp_client_set_timeout (GstRTSPClient *client, guint timeout) -{ - client->timeout = timeout; -} - -/** - * gst_rtsp_client_get_timeout: - * @client: a #GstRTSPClient - * - * Get the connection timeout @client. - * - * Returns: the connection timeout for @client in seconds. - */ -guint -gst_rtsp_client_get_timeout (GstRTSPClient *client) -{ - return client->timeout; -} - /** * gst_rtsp_client_set_session_pool: * @client: a #GstRTSPClient diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 07b81d9180..ab124c0670 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -61,12 +61,12 @@ typedef struct _GstRTSPClientClass GstRTSPClientClass; * @connection: the connection object handling the client request. * @watch: watch for the connection * @watchid: id of the watch - * @timeout: the session timeout * @session_pool: handle to the session pool used by the client. * @media_mapping: handle to the media mapping used by the client. * @uri: cached uri * @media: cached media * @streams: a list of streams using @connection. + * @sessions: a list of sessions managed by @connection. * * The client structure. */ @@ -77,7 +77,6 @@ struct _GstRTSPClient { GstRTSPWatch *watch; guint watchid; - guint timeout; GstRTSPSessionPool *session_pool; GstRTSPMediaMapping *media_mapping; @@ -85,6 +84,7 @@ struct _GstRTSPClient { GstRTSPMedia *media; GList *streams; + GList *sessions; }; struct _GstRTSPClientClass { @@ -103,9 +103,6 @@ void gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *mapping); GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client); -void gst_rtsp_client_set_timeout (GstRTSPClient *client, guint timeout); -guint gst_rtsp_client_get_timeout (GstRTSPClient *client); - gboolean gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel); diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 44d749b605..d8702a9b23 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -214,13 +214,11 @@ gst_rtsp_session_pool_find (GstRTSPSessionPool *pool, const gchar *sessionid) g_mutex_lock (pool->lock); result = g_hash_table_lookup (pool->sessions, sessionid); - if (result) - g_object_ref (result); - g_mutex_unlock (pool->lock); - if (result) { + g_object_ref (result); gst_rtsp_session_touch (result); } + g_mutex_unlock (pool->lock); return result; } From d3c404f32f6a039770bbdbdd9a1dc84d66b6ee70 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 11 Mar 2009 20:03:06 +0100 Subject: [PATCH 0082/1776] Remove weak ref on the session in teardown We need to remove our weakref from the session when we do a teardown because else we close the TCP connection prematurely. --- gst/rtsp-server/rtsp-client.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 2476db7a9b..49f5696248 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -373,6 +373,10 @@ handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession /* unlink the all TCP callbacks */ unlink_session_streams (client, media); + /* remove the session from the watched sessions */ + g_object_weak_unref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client); + client->sessions = g_list_remove (client->sessions, session); + gst_rtsp_session_media_set_state (media, GST_STATE_NULL); /* unmanage the media in the session, returns false if all media session @@ -867,11 +871,8 @@ santize_uri (GstRTSPUrl *uri) static void client_session_finalized (GstRTSPClient *client, GstRTSPSession *session) { - g_message ("session %p finalized", session); - - client->sessions = g_list_remove (client->sessions, session); - if (client->sessions == NULL) { - g_message ("all sessions finalized"); + if (!(client->sessions = g_list_remove (client->sessions, session))) { + g_message ("all sessions finalized, close the connection"); g_source_destroy ((GSource*)client->watch); } } @@ -939,6 +940,9 @@ handle_request (GstRTSPClient *client, GstRTSPMessage *request) if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid))) goto session_not_found; + /* we add the session to the client list of watched sessions. When a session + * disappears because it times out, we will be notified. If all sessions are + * gone, we will close the connection */ client_watch_session (client, session); } else From 0ae095e825ae27a7069388e20d27dc7c3592b818 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 12 Mar 2009 20:31:22 +0100 Subject: [PATCH 0083/1776] allow pause requests for now. -- --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 49f5696248..b3abb7ade6 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -825,7 +825,7 @@ handle_options_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession * options = GST_RTSP_DESCRIBE | GST_RTSP_OPTIONS | - // GST_RTSP_PAUSE | + GST_RTSP_PAUSE | GST_RTSP_PLAY | GST_RTSP_SETUP | GST_RTSP_TEARDOWN; From 525d639cde5b3e616d84fa15486669f22ea665b8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 12 Mar 2009 20:32:14 +0100 Subject: [PATCH 0084/1776] Add beginnings of seeking. Parse the Range header and perform a seek on the pipeline for the requested position. It's disabled currently until I figure out what's going wrong. --- gst/rtsp-server/rtsp-client.c | 12 +++ gst/rtsp-server/rtsp-media.c | 169 +++++++++++++++++++++++++++------- gst/rtsp-server/rtsp-media.h | 2 + 3 files changed, 149 insertions(+), 34 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b3abb7ade6..5711a992f9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -471,6 +471,8 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses guint n_streams, i; guint timestamp, seqnum; gchar *str; + GstRTSPTimeRange *range; + GstRTSPResult res; if (!session) goto no_session; @@ -485,6 +487,16 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses media->state != GST_RTSP_STATE_READY) goto invalid_state; + /* parse the range header if we have one */ + res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_RANGE, &str, 0); + if (res == GST_RTSP_OK) { + if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) { + /* we have a range, seek to the position */ + gst_rtsp_media_seek (media->media, range); + gst_rtsp_range_free (range); + } + } + /* grab RTPInfo from the payloaders now */ rtpinfo = g_string_new (""); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b75d3863ca..6a24af0475 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -157,6 +157,50 @@ do_loop (GstRTSPMediaClass *klass) return NULL; } +static void +collect_media_stats (GstRTSPMedia *media) +{ + GstFormat format; + gint64 position, duration; + + media->range.unit = GST_RTSP_RANGE_NPT; + + if (media->is_live) { + media->range.min.type = GST_RTSP_TIME_NOW; + media->range.min.seconds = -1; + media->range.max.type = GST_RTSP_TIME_END; + media->range.max.seconds = -1; + } + else { + /* get the position */ + format = GST_FORMAT_TIME; + if (!gst_element_query_position (media->pipeline, &format, &position)) + position = 0; + + /* get the duration */ + format = GST_FORMAT_TIME; + if (!gst_element_query_duration (media->pipeline, &format, &duration)) + duration = -1; + + if (position == -1) { + media->range.min.type = GST_RTSP_TIME_NOW; + media->range.min.seconds = -1; + } + else { + media->range.min.type = GST_RTSP_TIME_SECONDS; + media->range.min.seconds = ((gdouble)position) / GST_SECOND; + } + if (duration == -1) { + media->range.max.type = GST_RTSP_TIME_END; + media->range.max.seconds = -1; + } + else { + media->range.max.type = GST_RTSP_TIME_SECONDS; + media->range.max.seconds = ((gdouble)duration) / GST_SECOND; + } + } +} + /** * gst_rtsp_media_new: * @@ -250,6 +294,97 @@ gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx) return res; } +/** + * gst_rtsp_media_seek: + * @stream: a #GstRTSPMediaStream + * @range: a #GstRTSPTimeRange + * + * Seek the pipeline to @range. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range) +{ + GstSeekFlags flags; + gboolean res; + gint64 start, stop; + GstSeekType start_type, stop_type; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + g_return_val_if_fail (range != NULL, FALSE); + + if (range->unit != GST_RTSP_RANGE_NPT) + goto not_supported; + + /* depends on the current playing state of the pipeline. We might need to + * queue this until we get EOS. */ + flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE; + + start_type = stop_type = GST_SEEK_TYPE_NONE; + + switch (range->min.type) { + case GST_RTSP_TIME_NOW: + start = -1; + break; + case GST_RTSP_TIME_SECONDS: + start = range->min.seconds * GST_SECOND; + start_type = GST_SEEK_TYPE_SET; + break; + case GST_RTSP_TIME_END: + default: + goto weird_type; + } + switch (range->max.type) { + case GST_RTSP_TIME_SECONDS: + stop = range->max.seconds * GST_SECOND; + stop_type = GST_SEEK_TYPE_SET; + break; + case GST_RTSP_TIME_END: + stop = -1; + stop_type = GST_SEEK_TYPE_SET; + break; + case GST_RTSP_TIME_NOW: + default: + goto weird_type; + } + + if (start != -1 || stop != -1) { + g_message ("seeking to %"GST_TIME_FORMAT" - %"GST_TIME_FORMAT, + GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); + +#if 0 + res = gst_element_seek (media->pipeline, 1.0, GST_FORMAT_TIME, + flags, start_type, start, stop_type, stop); +#endif + res = TRUE; + + /* and block for the seek to complete */ + gst_element_get_state (media->pipeline, NULL, NULL, -1); + g_message ("done seeking %d", res); + + collect_media_stats (media); + } + else { + g_message ("no seek needed"); + res = TRUE; + } + + return res; + + /* ERRORS */ +not_supported: + { + g_warning ("seek unit %d not supported", range->unit); + return FALSE; + } +weird_type: + { + g_warning ("weird range type %d not supported", range->min.type); + return FALSE; + } +} + /** * gst_rtsp_media_stream_rtp: * @stream: a #GstRTSPMediaStream @@ -699,40 +834,6 @@ unlock_streams (GstRTSPMedia *media) } } -static void -collect_media_stats (GstRTSPMedia *media) -{ - GstFormat format; - gint64 duration; - - media->range.unit = GST_RTSP_RANGE_NPT; - - if (media->is_live) { - media->range.min.type = GST_RTSP_TIME_NOW; - media->range.min.seconds = -1; - media->range.max.type = GST_RTSP_TIME_END; - media->range.max.seconds = -1; - } - else { - media->range.min.type = GST_RTSP_TIME_SECONDS; - media->range.min.seconds = 0.0; - - /* get the duration */ - format = GST_FORMAT_TIME; - if (!gst_element_query_duration (media->pipeline, &format, &duration)) - duration = -1; - - if (duration == -1) { - media->range.max.type = GST_RTSP_TIME_END; - media->range.max.seconds = -1; - } - else { - media->range.max.type = GST_RTSP_TIME_SECONDS; - media->range.max.seconds = ((gdouble)duration) / GST_SECOND; - } - } -} - static gboolean default_handle_message (GstRTSPMedia *media, GstMessage *message) { diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 4aaaa1debb..e2c840589f 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -200,6 +200,8 @@ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); guint gst_rtsp_media_n_streams (GstRTSPMedia *media); GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); +gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range); + GstFlowReturn gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer); GstFlowReturn gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer); From 8f914515558db7150af7dd828325a68289f08532 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 13 Mar 2009 15:57:42 +0100 Subject: [PATCH 0085/1776] More seeking fixes. Keep the udp sources in playing even if we go to paused. unlock the sources when we shut down. Add some more debug info. Only seek when we need to. Keep track of the position when we go to paused. --- gst/rtsp-server/rtsp-media.c | 46 ++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 6a24af0475..82f11718fa 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -36,6 +36,7 @@ static void gst_rtsp_media_finalize (GObject * obj); static gpointer do_loop (GstRTSPMediaClass *klass); static gboolean default_handle_message (GstRTSPMedia *media, GstMessage *message); +static void unlock_streams (GstRTSPMedia *media); G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); @@ -96,6 +97,7 @@ gst_rtsp_media_finalize (GObject * obj) g_message ("finalize media %p", media); if (media->pipeline) { + unlock_streams (media); gst_element_set_state (media->pipeline, GST_STATE_NULL); gst_object_unref (media->pipeline); } @@ -174,13 +176,20 @@ collect_media_stats (GstRTSPMedia *media) else { /* get the position */ format = GST_FORMAT_TIME; - if (!gst_element_query_position (media->pipeline, &format, &position)) + if (!gst_element_query_position (media->pipeline, &format, &position)) { + g_message ("position query failed"); position = 0; + } /* get the duration */ format = GST_FORMAT_TIME; - if (!gst_element_query_duration (media->pipeline, &format, &duration)) + if (!gst_element_query_duration (media->pipeline, &format, &duration)) { + g_message ("duration query failed"); duration = -1; + } + + g_message ("stats: position %"GST_TIME_FORMAT", duration %"GST_TIME_FORMAT, + GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); if (position == -1) { media->range.min.type = GST_RTSP_TIME_NOW; @@ -328,8 +337,13 @@ gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range) start = -1; break; case GST_RTSP_TIME_SECONDS: - start = range->min.seconds * GST_SECOND; - start_type = GST_SEEK_TYPE_SET; + /* only seek when something changed */ + if (media->range.min.seconds == range->min.seconds) { + start = -1; + } else { + start = range->min.seconds * GST_SECOND; + start_type = GST_SEEK_TYPE_SET; + } break; case GST_RTSP_TIME_END: default: @@ -337,8 +351,13 @@ gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range) } switch (range->max.type) { case GST_RTSP_TIME_SECONDS: - stop = range->max.seconds * GST_SECOND; - stop_type = GST_SEEK_TYPE_SET; + /* only seek when something changed */ + if (media->range.max.seconds == range->max.seconds) { + stop = -1; + } else { + stop = range->max.seconds * GST_SECOND; + stop_type = GST_SEEK_TYPE_SET; + } break; case GST_RTSP_TIME_END: stop = -1; @@ -353,15 +372,13 @@ gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range) g_message ("seeking to %"GST_TIME_FORMAT" - %"GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); -#if 0 res = gst_element_seek (media->pipeline, 1.0, GST_FORMAT_TIME, flags, start_type, start, stop_type, stop); -#endif - res = TRUE; /* and block for the seek to complete */ - gst_element_get_state (media->pipeline, NULL, NULL, -1); g_message ("done seeking %d", res); + gst_element_get_state (media->pipeline, NULL, NULL, -1); + g_message ("prerolled again"); collect_media_stats (media); } @@ -1019,9 +1036,6 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) /* collect stats about the media */ collect_media_stats (media); - /* unlock the streams so that they follow the state changes from now on */ - unlock_streams (media); - g_message ("object %p is prerolled", media); media->prepared = TRUE; @@ -1075,6 +1089,8 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport switch (state) { case GST_STATE_NULL: + /* unlock the streams so that they follow the state changes from now on */ + unlock_streams (media); case GST_STATE_PAUSED: /* we're going from PLAYING to READY or NULL, remove */ if (media->target_state == GST_STATE_PLAYING) @@ -1134,6 +1150,10 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport media->target_state = state; ret = gst_element_set_state (media->pipeline, state); + /* remember where we are */ + if (state == GST_STATE_PAUSED) + collect_media_stats (media); + return TRUE; } From 8f16b1504e0f8077e6f702e967868dd2ddf9b4ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 1 Apr 2009 00:45:17 +0100 Subject: [PATCH 0086/1776] docs: fix typo in API docs --- gst/rtsp-server/rtsp-session.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index b590146c66..fc13098329 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -491,8 +491,8 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, /** * gst_rtsp_session_stream_set_callbacks: * @stream: a #GstRTSPSessionStream - * @send_rtp: a callback called when RTP should be send - * @send_rtcp: a callback called when RTCP should be send + * @send_rtp: a callback called when RTP should be sent + * @send_rtcp: a callback called when RTCP should be sent * @user_data: user data passed to callbacks * @notify: called with the user_data when no longer needed. * From 0b8ffbbb5c4fc9756fba8dc06dd2e5856bbc0e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 1 Apr 2009 01:01:46 +0100 Subject: [PATCH 0087/1776] Fix rtsp client refcount management in TCP mode. Don't unref a client ref we never had. Fixes an unref of an already-free client object after a client teardown request for me. --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 5711a992f9..49665e70b6 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -313,7 +313,7 @@ static void unlink_stream (GstRTSPClient *client, GstRTSPSessionStream *stream) { gst_rtsp_session_stream_set_callbacks (stream, NULL, - NULL, client, g_object_unref); + NULL, NULL, NULL); client->streams = g_list_remove (client->streams, stream); } From 47c822bdf3c07d92844b3bf5478076515f0ee303 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 3 Apr 2009 09:03:59 +0200 Subject: [PATCH 0088/1776] client: fix refcounting crasher Don't need to remove the weak refs in the finalize methods, they are already removed in the dispose. Don't register the callback with a DestroyNofity. --- gst/rtsp-server/rtsp-client.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 49665e70b6..c6c5749c70 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -80,12 +80,9 @@ static void gst_rtsp_client_finalize (GObject * obj) { GstRTSPClient *client = GST_RTSP_CLIENT (obj); - GList *walk; g_message ("finalize client %p", client); - for (walk = client->sessions; walk; walk = g_list_next (walk)) - g_object_weak_unref (G_OBJECT (walk->data), (GWeakNotify) client_session_finalized, client); g_list_free (client->sessions); gst_rtsp_connection_free (client->connection); From c6e1aef8819db415c69c6c4af902814e8afad7b1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 3 Apr 2009 19:44:37 +0200 Subject: [PATCH 0089/1776] client: support shared media Always perform the state actions even if the target state of the pipeline is already correct, we still want to add/remove the transports when we are dealing with shared media. Keep a counter of the number of active transports for a media so that we can use this to perform a state change when needed. Perform a state change of the pipeline only when the first transport was added or when there are no active transports. --- gst/rtsp-server/rtsp-media.c | 27 ++++++++++++++++++++------- gst/rtsp-server/rtsp-media.h | 1 + 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 82f11718fa..fef38d5943 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1072,7 +1072,7 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport { gint i; GstStateChangeReturn ret; - gboolean add, remove; + gboolean add, remove, do_state; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (transports != NULL, FALSE); @@ -1082,15 +1082,13 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport if (state == GST_STATE_READY) state = GST_STATE_NULL; - if (media->target_state == state) - return TRUE; - add = remove = FALSE; switch (state) { case GST_STATE_NULL: /* unlock the streams so that they follow the state changes from now on */ unlock_streams (media); + break; case GST_STATE_PAUSED: /* we're going from PLAYING to READY or NULL, remove */ if (media->target_state == GST_STATE_PLAYING) @@ -1127,10 +1125,12 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport g_message ("adding %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); g_signal_emit_by_name (stream->udpsink[0], "add", trans->destination, trans->client_port.min, NULL); g_signal_emit_by_name (stream->udpsink[1], "add", trans->destination, trans->client_port.max, NULL); + media->active++; } else if (remove) { g_message ("removing %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); g_signal_emit_by_name (stream->udpsink[0], "remove", trans->destination, trans->client_port.min, NULL); g_signal_emit_by_name (stream->udpsink[1], "remove", trans->destination, trans->client_port.max, NULL); + media->active--; } break; case GST_RTSP_LOWER_TRANS_TCP: @@ -1146,9 +1146,22 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport } } - g_message ("state %s media %p", gst_element_state_get_name (state), media); - media->target_state = state; - ret = gst_element_set_state (media->pipeline, state); + /* we just added the first media, do the playing state change */ + if (media->active == 1 && add) + do_state = TRUE; + /* if we have no more active media, do the downward state changes */ + else if (media->active == 0) + do_state = TRUE; + else + do_state = FALSE; + + g_message ("active %d media %p", media->active, media); + + if (do_state) { + g_message ("state %s media %p", gst_element_state_get_name (state), media); + media->target_state = state; + ret = gst_element_set_state (media->pipeline, state); + } /* remember where we are */ if (state == GST_STATE_PAUSED) diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index e2c840589f..921c7b55bc 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -148,6 +148,7 @@ struct _GstRTSPMedia { GstElement *element; GArray *streams; gboolean prepared; + gint active; /* the pipeline for the media */ GstElement *pipeline; From 660006b04f97b8de1e7208dadfda824b766c955a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 3 Apr 2009 19:47:38 +0200 Subject: [PATCH 0090/1776] examples: mark the example as shared for testing --- examples/test-readme.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/test-readme.c b/examples/test-readme.c index e23c55ae76..977fcb080e 100644 --- a/examples/test-readme.c +++ b/examples/test-readme.c @@ -48,6 +48,8 @@ main (int argc, char *argv[]) gst_rtsp_media_factory_set_launch (factory, "( videotestsrc is-live=1 ! x264enc ! rtph264pay name=pay0 pt=96 )"); + gst_rtsp_media_factory_set_shared (factory, TRUE); + /* attach the test factory to the /test url */ gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); From 5dab222089fc7321b7ca074ee969c0bdcb7fe150 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 3 Apr 2009 22:22:30 +0200 Subject: [PATCH 0091/1776] media: more work on making the media shared Add a reusable flag to medias, indicating that they can be reused after a state change to NULL. Small cleanups. --- gst/rtsp-server/rtsp-media.c | 119 +++++++++++++++++++++++++++++++---- gst/rtsp-server/rtsp-media.h | 8 +++ 2 files changed, 114 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index fef38d5943..57cf15b09f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -20,11 +20,13 @@ #include "rtsp-media.h" #define DEFAULT_SHARED FALSE +#define DEFAULT_REUSABLE FALSE enum { PROP_0, PROP_SHARED, + PROP_REUSABLE, PROP_LAST }; @@ -56,6 +58,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) g_param_spec_boolean ("shared", "Shared", "If this media pipeline can be shared", DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_REUSABLE, + g_param_spec_boolean ("reusable", "Reusable", + "If this media pipeline can be reused after an unprepare", + DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + klass->context = g_main_context_new (); klass->loop = g_main_loop_new (klass->context, TRUE); @@ -129,6 +136,9 @@ gst_rtsp_media_get_property (GObject *object, guint propid, case PROP_SHARED: g_value_set_boolean (value, gst_rtsp_media_is_shared (media)); break; + case PROP_REUSABLE: + g_value_set_boolean (value, gst_rtsp_media_is_reusable (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -144,6 +154,9 @@ gst_rtsp_media_set_property (GObject *object, guint propid, case PROP_SHARED: gst_rtsp_media_set_shared (media, g_value_get_boolean (value)); break; + case PROP_REUSABLE: + gst_rtsp_media_set_reusable (media, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -262,6 +275,38 @@ gst_rtsp_media_is_shared (GstRTSPMedia *media) return media->shared; } +/** + * gst_rtsp_media_set_reusable: + * @media: a #GstRTSPMedia + * @reusable: the new value + * + * Set or unset if the pipeline for @media can be reused after the pipeline has + * been unprepared. + */ +void +gst_rtsp_media_set_reusable (GstRTSPMedia *media, gboolean reusable) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + media->reusable = reusable; +} + +/** + * gst_rtsp_media_is_reusable: + * @media: a #GstRTSPMedia + * + * Check if the pipeline for @media can be reused after an unprepare. + * + * Returns: %TRUE if the media can be reused + */ +gboolean +gst_rtsp_media_is_reusable (GstRTSPMedia *media) +{ + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + return media->reusable; +} + /** * gst_rtsp_media_n_streams: * @media: a #GstRTSPMedia @@ -971,6 +1016,9 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) if (media->prepared) goto was_prepared; + if (!media->reusable && media->reused) + goto is_reused; + g_message ("preparing media %p", media); media->pipeline = gst_pipeline_new ("media-pipeline"); @@ -1055,6 +1103,37 @@ state_failed: gst_element_set_state (media->pipeline, GST_STATE_NULL); return FALSE; } +is_reused: + { + g_warning ("can not reused media %p", media); + return FALSE; + } +} + +/** + * gst_rtsp_media_unprepare: + * @obj: a #GstRTSPMedia + * + * Unprepare @media. After this call, the media should be prepared again before + * it can be used again. If the media is set to be non-reusable, a new instance + * must be created. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_media_unprepare (GstRTSPMedia *media) +{ + if (!media->prepared) + return TRUE; + + if (media->reusable) { + g_message ("unprepare media %p", media); + media->target_state = GST_STATE_NULL; + gst_element_set_state (media->pipeline, GST_STATE_NULL); + media->prepared = FALSE; + media->reused = TRUE; + } + return TRUE; } /** @@ -1073,10 +1152,10 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport gint i; GstStateChangeReturn ret; gboolean add, remove, do_state; + gint old_active; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (transports != NULL, FALSE); - g_return_val_if_fail (media->prepared, FALSE); /* NULL and READY are the same */ if (state == GST_STATE_READY) @@ -1090,7 +1169,7 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport unlock_streams (media); break; case GST_STATE_PAUSED: - /* we're going from PLAYING to READY or NULL, remove */ + /* we're going from PLAYING to PAUSED, READY or NULL, remove */ if (media->target_state == GST_STATE_PLAYING) remove = TRUE; break; @@ -1101,6 +1180,7 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport default: break; } + old_active = media->active; for (i = 0; i < transports->len; i++) { GstRTSPMediaTrans *tr; @@ -1121,18 +1201,27 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport switch (trans->lower_transport) { case GST_RTSP_LOWER_TRANS_UDP: case GST_RTSP_LOWER_TRANS_UDP_MCAST: + { + gchar *dest; + gint min, max; + + dest = trans->destination; + min = trans->client_port.min; + max = trans->client_port.max; + if (add) { - g_message ("adding %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); - g_signal_emit_by_name (stream->udpsink[0], "add", trans->destination, trans->client_port.min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "add", trans->destination, trans->client_port.max, NULL); + g_message ("adding %s:%d-%d", dest, min, max); + g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); media->active++; } else if (remove) { - g_message ("removing %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max); - g_signal_emit_by_name (stream->udpsink[0], "remove", trans->destination, trans->client_port.min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "remove", trans->destination, trans->client_port.max, NULL); + g_message ("removing %s:%d-%d", dest, min, max); + g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); media->active--; } break; + } case GST_RTSP_LOWER_TRANS_TCP: if (add) { stream->transports = g_list_prepend (stream->transports, tr); @@ -1147,7 +1236,7 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport } /* we just added the first media, do the playing state change */ - if (media->active == 1 && add) + if (old_active == 0 && add) do_state = TRUE; /* if we have no more active media, do the downward state changes */ else if (media->active == 0) @@ -1157,10 +1246,14 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport g_message ("active %d media %p", media->active, media); - if (do_state) { - g_message ("state %s media %p", gst_element_state_get_name (state), media); - media->target_state = state; - ret = gst_element_set_state (media->pipeline, state); + if (do_state && media->target_state != state) { + if (state == GST_STATE_NULL) { + gst_rtsp_media_unprepare (media); + } else { + g_message ("state %s media %p", gst_element_state_get_name (state), media); + media->target_state = state; + ret = gst_element_set_state (media->pipeline, state); + } } /* remember where we are */ diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 921c7b55bc..e4eafaa1ac 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -123,6 +123,7 @@ struct _GstRTSPMediaStream { /** * GstRTSPMedia: * @shared: if this media can be shared between clients + * @reusable: if this media can be reused after an unprepare * @element: the data providing element * @streams: the different streams provided by @element * @prepared: if the media is prepared for streaming @@ -144,6 +145,8 @@ struct _GstRTSPMedia { GObject parent; gboolean shared; + gboolean reusable; + gboolean reused; GstElement *element; GArray *streams; @@ -194,8 +197,13 @@ GstRTSPMedia * gst_rtsp_media_new (void); void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared); gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media); +void gst_rtsp_media_set_reusable (GstRTSPMedia *media, gboolean reusable); +gboolean gst_rtsp_media_is_reusable (GstRTSPMedia *media); + /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); +gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media); +gboolean gst_rtsp_media_unprepare (GstRTSPMedia *media); /* dealing with the media */ guint gst_rtsp_media_n_streams (GstRTSPMedia *media); From 0c1df5e02372abb26c94719edd0cb610e4fbaa88 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 3 Apr 2009 22:45:57 +0200 Subject: [PATCH 0092/1776] media: add signal to notify of unprepare --- gst/rtsp-server/rtsp-media.c | 13 +++++++++++++ gst/rtsp-server/rtsp-media.h | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 57cf15b09f..b75662b0f4 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -30,6 +30,12 @@ enum PROP_LAST }; +enum +{ + SIGNAL_UNPREPARED, + SIGNAL_LAST +}; + static void gst_rtsp_media_get_property (GObject *object, guint propid, GValue *value, GParamSpec *pspec); static void gst_rtsp_media_set_property (GObject *object, guint propid, @@ -40,6 +46,8 @@ static gpointer do_loop (GstRTSPMediaClass *klass); static gboolean default_handle_message (GstRTSPMedia *media, GstMessage *message); static void unlock_streams (GstRTSPMedia *media); +static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; + G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); static void @@ -63,6 +71,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "If this media pipeline can be reused after an unprepare", DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_UNPREPARED] = + g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + klass->context = g_main_context_new (); klass->loop = g_main_loop_new (klass->context, TRUE); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index e4eafaa1ac..3273f532cf 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -186,7 +186,11 @@ struct _GstRTSPMediaClass { GMainLoop *loop; GThread *thread; + /* vmethods */ gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message); + + /* signals */ + gboolean (*unprepared) (GstRTSPMedia *media); }; GType gst_rtsp_media_get_type (void); From 35a5a709d35be34d411d1a5ac8aa0dd15585980e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 3 Apr 2009 22:46:22 +0200 Subject: [PATCH 0093/1776] factory: connect to the unprepare signal Connect to the unprepare signal for non-reusable media so that we can remove them from the cache. --- gst/rtsp-server/rtsp-media-factory.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 02614e65de..6eb834817b 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -250,6 +250,21 @@ gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory) return result; } +static gboolean +compare_media (gpointer key, GstRTSPMedia *media1, GstRTSPMedia *media2) +{ + return (media1 == media2); +} + +static void +media_unprepared (GstRTSPMedia *media, GstRTSPMediaFactory *factory) +{ + g_mutex_lock (factory->medias_lock); + g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, + media); + g_mutex_unlock (factory->medias_lock); +} + /** * gst_rtsp_media_factory_construct: * @factory: a #GstRTSPMediaFactory @@ -310,6 +325,12 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl g_hash_table_insert (factory->medias, key, media); key = NULL; } + if (!gst_rtsp_media_is_reusable (media)) { + /* when not reusable, connect to the unprepare signal to remove the item + * from our cache when it gets unprepared */ + g_signal_connect (media, "unprepared", (GCallback) media_unprepared, + factory); + } } } g_mutex_unlock (factory->medias_lock); From 5a074c81dd1a26da6129d4d802094e61c6db393f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 14 Apr 2009 23:38:15 +0200 Subject: [PATCH 0094/1776] tests: set the payload type correctly --- examples/test-ogg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/test-ogg.c b/examples/test-ogg.c index 0e39f01462..5847b85dbb 100644 --- a/examples/test-ogg.c +++ b/examples/test-ogg.c @@ -49,8 +49,8 @@ main (int argc, char *argv[]) str = g_strdup_printf ( "( " "filesrc location=%s ! oggdemux name=d " - "d. ! queue ! theoraparse ! rtptheorapay name=pay0 " - "d. ! queue ! vorbisparse ! rtpvorbispay name=pay1 " + "d. ! queue ! theoraparse ! rtptheorapay name=pay0 pt=96 " + "d. ! queue ! vorbisparse ! rtpvorbispay name=pay1 pt=97 " ")", argv[1]); /* make a media factory for a test stream. The default media factory can use From 3f1f38f479d0e3de8ab503d9616109d6040722cd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 14 Apr 2009 23:38:58 +0200 Subject: [PATCH 0095/1776] server: use appsink and appsrc with the API Use the appsink/appsrc API instead of the signals for higher performance. --- gst/rtsp-server/Makefile.am | 4 +++- gst/rtsp-server/rtsp-client.c | 9 +++++++- gst/rtsp-server/rtsp-media.c | 42 ++++++++++++++++++++++++----------- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 68fa7fa662..eced5819d9 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -29,7 +29,9 @@ libgstrtspserver_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstrtspserver_@GST_MAJORMINOR@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ - -lgstsdp-@GST_MAJORMINOR@ $(GST_LIBS) $(LIBM) + -lgstsdp-@GST_MAJORMINOR@ \ + -lgstapp-@GST_MAJORMINOR@ \ + $(GST_LIBS) $(LIBM) libgstrtspserver_@GST_MAJORMINOR@_la_LIBTOOLFLAGS = --tag=disable-static libgstrtspserver_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/rtsp-server diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c6c5749c70..27adf05d74 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1017,6 +1017,7 @@ handle_data (GstRTSPClient *client, GstRTSPMessage *message) guint8 *data; guint size; GstBuffer *buffer; + gboolean handled; /* find the stream for this message */ res = gst_rtsp_message_parse_data (message, &channel); @@ -1030,6 +1031,7 @@ handle_data (GstRTSPClient *client, GstRTSPMessage *message) GST_BUFFER_MALLOCDATA (buffer) = data; GST_BUFFER_SIZE (buffer) = size; + handled = FALSE; for (walk = client->streams; walk; walk = g_list_next (walk)) { GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data; GstRTSPMediaStream *mstream; @@ -1048,12 +1050,17 @@ handle_data (GstRTSPClient *client, GstRTSPMessage *message) /* dispatch to the stream based on the channel number */ if (tr->interleaved.min == channel) { gst_rtsp_media_stream_rtp (mstream, buffer); + handled = TRUE; + break; } else if (tr->interleaved.max == channel) { gst_rtsp_media_stream_rtcp (mstream, buffer); + handled = TRUE; + break; } } } - gst_buffer_unref (buffer); + if (!handled) + gst_buffer_unref (buffer); } /** diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b75662b0f4..4ae4153a16 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -17,6 +17,9 @@ * Boston, MA 02111-1307, USA. */ +#include +#include + #include "rtsp-media.h" #define DEFAULT_SHARED FALSE @@ -468,6 +471,8 @@ weird_type: * Handle an RTP buffer for the stream. This method is usually called when a * message has been received from a client using the TCP transport. * + * This function takes ownership of @buffer. + * * Returns: a GstFlowReturn. */ GstFlowReturn @@ -475,7 +480,7 @@ gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer) { GstFlowReturn ret; - g_signal_emit_by_name (stream->appsrc[0], "push-buffer", buffer, &ret); + ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[0]), buffer); return ret; } @@ -488,6 +493,8 @@ gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer) * Handle an RTCP buffer for the stream. This method is usually called when a * message has been received from a client using the TCP transport. * + * This function takes ownership of @buffer. + * * Returns: a GstFlowReturn. */ GstFlowReturn @@ -495,9 +502,9 @@ gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer) { GstFlowReturn ret; - g_signal_emit_by_name (stream->appsrc[1], "push-buffer", buffer, &ret); + ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[1]), buffer); - return GST_FLOW_ERROR; + return ret; } /* Allocate the udp ports and sockets */ @@ -710,20 +717,23 @@ on_timeout (GObject *session, GObject *source, GstRTSPMedia *media) g_message ("%p: source %p timeout", media, source); } -static void -handle_new_buffer (GstElement *sink, GstRTSPMediaStream *stream) +static GstFlowReturn +handle_new_buffer (GstAppSink *sink, gpointer user_data) { GList *walk; GstBuffer *buffer; + GstRTSPMediaStream *stream; - g_signal_emit_by_name (sink, "pull-buffer", &buffer); + buffer = gst_app_sink_pull_buffer (sink); if (!buffer) - return; + return GST_FLOW_OK; + + stream = (GstRTSPMediaStream *) user_data; for (walk = stream->transports; walk; walk = g_list_next (walk)) { GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data; - if (sink == stream->appsink[0]) { + if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) { if (tr->send_rtp) tr->send_rtp (buffer, tr->transport->interleaved.min, tr->user_data); } @@ -733,8 +743,16 @@ handle_new_buffer (GstElement *sink, GstRTSPMediaStream *stream) } } gst_buffer_unref (buffer); + + return GST_FLOW_OK; } +static GstAppSinkCallbacks sink_cb = { + NULL, /* not interested in EOS */ + NULL, /* not interested in preroll buffers */ + handle_new_buffer +}; + /* prepare the pipeline objects to handle @stream in @media */ static gboolean setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) @@ -762,15 +780,13 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL); stream->appsink[i] = gst_element_factory_make ("appsink", NULL); g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL); - g_object_set (stream->appsink[i], "emit-signals", TRUE, NULL); + g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL); g_object_set (stream->appsink[i], "preroll-queue-len", 1, NULL); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsink[i]); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsrc[i]); + gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]), + &sink_cb, stream, NULL); } - g_signal_connect (stream->appsink[0], "new-buffer", - (GCallback) handle_new_buffer, stream); - g_signal_connect (stream->appsink[1], "new-buffer", - (GCallback) handle_new_buffer, stream); /* hook up the stream to the RTP session elements. */ name = g_strdup_printf ("send_rtp_sink_%d", idx); From d4f26b411f06d7f7de66b1e6b6c1d758d7680c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Fri, 17 Apr 2009 21:13:07 +0200 Subject: [PATCH 0096/1776] Updated vala bindings --- bindings/vala/gst-rtsp-server-0.10.vapi | 148 ++++++-- .../vala/packages/gst-rtsp-server-0.10.gi | 338 +++++++++++++++--- .../packages/gst-rtsp-server-0.10.metadata | 4 + 3 files changed, 403 insertions(+), 87 deletions(-) diff --git a/bindings/vala/gst-rtsp-server-0.10.vapi b/bindings/vala/gst-rtsp-server-0.10.vapi index af5804c7d7..fd4bc9a488 100644 --- a/bindings/vala/gst-rtsp-server-0.10.vapi +++ b/bindings/vala/gst-rtsp-server-0.10.vapi @@ -4,12 +4,13 @@ namespace Gst { [CCode (cheader_filename = "gst/rtsp-server/rtsp-client.h")] public class RTSPClient : GLib.Object { - public void* address; public weak Gst.RTSPConnection connection; - public weak Gst.RTSPMediaFactory factory; - public weak Gst.RTSPMediaMapping mapping; - public weak Gst.RTSPSessionPool pool; - public weak GLib.Thread thread; + public weak Gst.RTSPMedia media; + public weak GLib.List sessions; + public weak GLib.List streams; + public weak Gst.RTSPUrl uri; + public weak Gst.RTSPWatch watch; + public uint watchid; public bool accept (GLib.IOChannel channel); public Gst.RTSPMediaMapping get_media_mapping (); public Gst.RTSPSessionPool get_session_pool (); @@ -17,18 +18,56 @@ namespace Gst { public RTSPClient (); public void set_media_mapping (Gst.RTSPMediaMapping mapping); public void set_session_pool (Gst.RTSPSessionPool pool); + public Gst.RTSPMediaMapping media_mapping { get; set; } + public Gst.RTSPSessionPool session_pool { get; set; } } [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] public class RTSPMedia : GLib.Object { + public int active; + public bool buffering; public weak Gst.Element element; + public uint id; + public bool is_live; + public weak Gst.Element pipeline; + public bool prepared; + public weak Gst.RTSPTimeRange range; + public bool reused; + public weak Gst.Element rtpbin; + public weak GLib.TimeoutSource source; public weak GLib.Array streams; + public Gst.State target_state; public unowned Gst.RTSPMediaStream get_stream (uint idx); + [NoWrapper] + public virtual bool handle_message (Gst.Message message); + public bool is_prepared (); + public bool is_reusable (); + public bool is_shared (); public uint n_streams (); + [CCode (has_construct_function = false)] + public RTSPMedia (); + public bool prepare (); + public bool seek (Gst.RTSPTimeRange range); + public void set_reusable (bool reusable); + public void set_shared (bool shared); + public bool set_state (Gst.State state, GLib.Array trans); + public bool unprepare (); + [NoAccessorMethod] + public bool reusable { get; set; } + [NoAccessorMethod] + public bool shared { get; set; } + public virtual signal void unprepared (); } [CCode (cheader_filename = "gst/rtsp-server/rtsp-media-factory.h")] public class RTSPMediaFactory : GLib.Object { + public weak GLib.Mutex @lock; + public weak GLib.HashTable medias; + public weak GLib.Mutex medias_lock; + [NoWrapper] + public virtual void configure (Gst.RTSPMedia media); public virtual Gst.RTSPMedia? @construct (Gst.RTSPUrl url); [NoWrapper] + public virtual string gen_key (Gst.RTSPUrl url); + [NoWrapper] public virtual Gst.Element? get_element (Gst.RTSPUrl url); public string get_launch (); public bool is_shared (); @@ -37,6 +76,8 @@ namespace Gst { public void set_launch (string launch); public void set_shared (bool shared); public string launch { get; set; } + [NoAccessorMethod] + public bool shared { get; set; } } [CCode (cheader_filename = "gst/rtsp-server/rtsp-media-mapping.h")] public class RTSPMediaMapping : GLib.Object { @@ -52,20 +93,44 @@ namespace Gst { [Compact] [CCode (cheader_filename = "gst/rtsp-server/rstp-media.h")] public class RTSPMediaStream { + [CCode (array_length = false)] + public weak Gst.Element[] appsink; + [CCode (array_length = false)] + public weak Gst.Element[] appsrc; public weak Gst.Caps caps; public ulong caps_sig; - public weak Gst.Element element; - public uint idx; - public weak Gst.RTSPMedia media; public weak Gst.Element payloader; + public bool prepared; + public weak Gst.Pad recv_rtcp_sink; + public weak Gst.Pad send_rtcp_src; + public weak Gst.Pad send_rtp_sink; + public weak Gst.Pad send_rtp_src; + public weak Gst.RTSPRange server_port; + public weak GLib.Object session; public weak Gst.Pad srcpad; + public weak GLib.List transports; + [CCode (array_length = false)] + public weak Gst.Element[] udpsink; + [CCode (array_length = false)] + public weak Gst.Element[] udpsrc; + public Gst.FlowReturn rtcp (Gst.Buffer buffer); + public Gst.FlowReturn rtp (Gst.Buffer buffer); + } + [Compact] + [CCode (cheader_filename = "gst/gst.h")] + public class RTSPMediaTrans { + public uint idx; + public weak GLib.DestroyNotify notify; + public weak Gst.RTSPSendFunc send_rtcp; + public weak Gst.RTSPSendFunc send_rtp; + public weak Gst.RTSPTransport transport; + public void* user_data; } [CCode (cheader_filename = "gst/rtsp-server/rtsp-server.h")] public class RTSPServer : GLib.Object { public weak string host; public weak GLib.IOChannel io_channel; public weak GLib.TimeoutSource io_watch; - public int server_port; public void* server_sin; public weak Gst.PollFD server_sock; [NoWrapper] @@ -85,64 +150,69 @@ namespace Gst { public void set_port (int port); public void set_session_pool (Gst.RTSPSessionPool pool); public int backlog { get; set; } - [NoAccessorMethod] - public Gst.RTSPMediaMapping mapping { owned get; set; } - [NoAccessorMethod] - public Gst.RTSPSessionPool pool { owned get; set; } + public Gst.RTSPMediaMapping media_mapping { get; set; } public int port { get; set; } + public Gst.RTSPSessionPool session_pool { get; set; } } [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] public class RTSPSession : GLib.Object { + public GLib.TimeVal create_time; + public GLib.TimeVal last_access; public weak GLib.List medias; - public weak string sessionid; - public unowned Gst.RTSPSessionMedia get_media (Gst.RTSPUrl url, Gst.RTSPMediaFactory factory); + public unowned Gst.RTSPSessionMedia get_media (Gst.RTSPUrl uri); + public unowned string get_sessionid (); + public uint get_timeout (); + public bool is_expired (GLib.TimeVal now); + public unowned Gst.RTSPSessionMedia manage_media (Gst.RTSPUrl uri, owned Gst.RTSPMedia media); [CCode (has_construct_function = false)] public RTSPSession (string sessionid); + public int next_timeout (GLib.TimeVal now); + public bool release_media (Gst.RTSPSessionMedia media); + public void set_timeout (uint timeout); + public void touch (); + public string sessionid { get; construct; } + public uint timeout { get; set; } } [Compact] [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] public class RTSPSessionMedia { - public weak Gst.RTSPMediaFactory factory; - public weak Gst.Element fdsink; public weak Gst.RTSPMedia media; - public weak Gst.Element pipeline; - public weak Gst.Element rtpbin; - public weak Gst.RTSPSession session; - public weak GLib.List streams; + public Gst.RTSPState state; + public weak GLib.Array streams; + public weak Gst.RTSPUrl url; public unowned Gst.RTSPSessionStream get_stream (uint idx); - public Gst.StateChangeReturn pause (); - public Gst.StateChangeReturn play (); - public Gst.StateChangeReturn stop (); + public bool set_state (Gst.State state); } [CCode (cheader_filename = "gst/rtsp-server/rtsp-session-pool.h")] public class RTSPSessionPool : GLib.Object { public weak GLib.Mutex @lock; public weak GLib.HashTable sessions; + public uint cleanup (); public Gst.RTSPSession create (); [NoWrapper] public virtual string create_session_id (); + public GLib.TimeoutSource create_watch (); public Gst.RTSPSession? find (string sessionid); + public uint get_max_sessions (); + public uint get_n_sessions (); [CCode (has_construct_function = false)] public RTSPSessionPool (); - public void remove (Gst.RTSPSession sess); + public bool remove (Gst.RTSPSession sess); + public void set_max_sessions (uint max); + public uint max_sessions { get; set; } } [Compact] [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] public class RTSPSessionStream { - public weak Gst.RTSPTransport client_trans; - public weak string destination; - public uint idx; - public weak Gst.RTSPSessionMedia media; public weak Gst.RTSPMediaStream media_stream; - public weak Gst.Pad recv_rtcp_sink; - public weak Gst.Pad send_rtcp_src; - public weak Gst.Pad send_rtp_sink; - public weak Gst.Pad send_rtp_src; - public weak Gst.RTSPTransport server_trans; - [CCode (array_length = false)] - public weak Gst.Element[] udpsink; - [CCode (array_length = false)] - public weak Gst.Element[] udpsrc; - public Gst.RTSPTransport set_transport (string destination, Gst.RTSPTransport ct); + public weak Gst.RTSPMediaTrans trans; + public void set_callbacks (Gst.RTSPSendFunc send_rtp, Gst.RTSPSendFunc send_rtcp, GLib.DestroyNotify notify); + public Gst.RTSPTransport set_transport (Gst.RTSPTransport ct); } + [CCode (cheader_filename = "gst/gst.h")] + public delegate bool RTSPSendFunc (Gst.Buffer buffer, uchar channel); + [CCode (cheader_filename = "gst/gst.h")] + public delegate bool RTSPSessionPoolFunc (Gst.RTSPSessionPool pool); + [CCode (cheader_filename = "gst/gst.h")] + public static Gst.SDPMessage rtsp_sdp_from_media (Gst.RTSPMedia media); } diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.gi b/bindings/vala/packages/gst-rtsp-server-0.10.gi index b71ad358b7..8a89bf0acc 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.gi +++ b/bindings/vala/packages/gst-rtsp-server-0.10.gi @@ -1,14 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -18,53 +70,38 @@ - - + + + - - - - - - - - - - - - - - - + - - - + + + + + + + + + + + + - - - + - - - - - - - - - @@ -103,12 +140,17 @@ + + - - - - - + + + + + + + + @@ -118,14 +160,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -165,6 +297,14 @@ + + + + + + + + @@ -172,6 +312,13 @@ + + + + + + + @@ -179,7 +326,11 @@ + + + + @@ -300,9 +451,9 @@ - - + + @@ -310,23 +461,49 @@ - + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -335,16 +512,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -352,22 +573,43 @@ + + + + + + + + + + + + - + + + + + + + + + + diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.metadata b/bindings/vala/packages/gst-rtsp-server-0.10.metadata index bf7ed85e63..ba417e58c9 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.metadata +++ b/bindings/vala/packages/gst-rtsp-server-0.10.metadata @@ -13,16 +13,20 @@ gst_rtsp_client_get_media_mapping transfer_ownership="1" gst_rtsp_client_get_session_pool transfer_ownership="1" gst_rtsp_media_factory_get_launch transfer_ownership="1" gst_rtsp_media_factory_construct transfer_ownership="1" nullable="1" +gst_rtsp_media_factory_gen_key transfer_ownership="1" gst_rtsp_media_factory_get_element transfer_ownership="1" nullable="1" gst_rtsp_media_mapping_find_factory transfer_ownership="1" nullable="1" gst_rtsp_media_mapping_find_media transfer_ownership="1" nullable="1" +gst_rtsp_sdp_from_media transfer_ownership="1" gst_rtsp_server_accept_client transfer_ownership="1" nullable="1" gst_rtsp_server_create_watch transfer_ownership="1" nullable="1" gst_rtsp_server_get_io_channel transfer_ownership="1" nullable="1" gst_rtsp_server_get_media_mapping transfer_ownership="1" gst_rtsp_server_get_session_pool transfer_ownership="1" gst_rtsp_server_attach.context nullable="1" +gst_rtsp_session_manage_media.media takes_ownership="1" gst_rtsp_session_pool_create transfer_ownership="1" gst_rtsp_session_pool_create_session_id transfer_ownership="1" +gst_rtsp_session_pool_create_watch transfer_ownership="1" gst_rtsp_session_pool_find transfer_ownership="1" nullable="1" gst_rtsp_session_stream_set_transport transfer_ownership="1" From 9b7cb2a4effd0ef664692d1d9c19c3a0a2124cb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Sat, 18 Apr 2009 16:10:59 +0200 Subject: [PATCH 0097/1776] Added finalize function to GstRTPSPServer to unref session pool and media mapping --- gst/rtsp-server/rtsp-server.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index e9c965edb1..0d1353d89b 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -41,6 +41,7 @@ static void gst_rtsp_server_get_property (GObject *object, guint propid, GValue *value, GParamSpec *pspec); static void gst_rtsp_server_set_property (GObject *object, guint propid, const GValue *value, GParamSpec *pspec); +static void gst_rtsp_server_finalize (GObject *object); static GstRTSPClient * default_accept_client (GstRTSPServer *server, GIOChannel *channel); @@ -54,6 +55,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) gobject_class->get_property = gst_rtsp_server_get_property; gobject_class->set_property = gst_rtsp_server_set_property; + gobject_class->finalize = gst_rtsp_server_finalize; /** * GstRTSPServer::backlog @@ -111,6 +113,15 @@ gst_rtsp_server_init (GstRTSPServer * server) server->media_mapping = gst_rtsp_media_mapping_new (); } +static void +gst_rtsp_server_finalize (GObject *object) +{ + GstRTSPServer *server = GST_RTSP_SERVER (object); + + g_object_unref (server->session_pool); + g_object_unref (server->media_mapping); +} + /** * gst_rtsp_server_new: * From 708c8daaec48a17c29f6e5aff075b8912a15cc14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Tue, 21 Apr 2009 22:23:54 +0200 Subject: [PATCH 0098/1776] Set pipeline's state to NULL no matter if the media is reusable and emit unprepared signal in gst_rtsp_media_unprepare --- gst/rtsp-server/rtsp-media.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4ae4153a16..482aaf1472 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1155,13 +1155,13 @@ gst_rtsp_media_unprepare (GstRTSPMedia *media) if (!media->prepared) return TRUE; - if (media->reusable) { - g_message ("unprepare media %p", media); - media->target_state = GST_STATE_NULL; - gst_element_set_state (media->pipeline, GST_STATE_NULL); - media->prepared = FALSE; - media->reused = TRUE; - } + g_message ("unprepare media %p", media); + media->target_state = GST_STATE_NULL; + gst_element_set_state (media->pipeline, GST_STATE_NULL); + media->prepared = FALSE; + media->reused = FALSE; + g_signal_emit_by_name (media, "unprepared", NULL); + return TRUE; } From 6ffd7432a5f4c69aad182f183d442b05ea51b295 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 21 Apr 2009 22:44:05 +0200 Subject: [PATCH 0099/1776] media: emit the unprepared signal by id Emit the unprepared signal by id instead of name and set the media as reused. --- gst/rtsp-server/rtsp-media.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 482aaf1472..e8bdaf24f7 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1158,9 +1158,13 @@ gst_rtsp_media_unprepare (GstRTSPMedia *media) g_message ("unprepare media %p", media); media->target_state = GST_STATE_NULL; gst_element_set_state (media->pipeline, GST_STATE_NULL); + media->prepared = FALSE; - media->reused = FALSE; - g_signal_emit_by_name (media, "unprepared", NULL); + media->reused = TRUE; + + /* when the media is not reusable, this will effectively unref the media and + * recreate it */ + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL); return TRUE; } From 5f19d4b09ee94402428fca2fd7f1a6c838664310 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 29 Apr 2009 17:24:46 +0200 Subject: [PATCH 0100/1776] media: seek to key frames --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e8bdaf24f7..f95848ea6f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -389,7 +389,7 @@ gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range) /* depends on the current playing state of the pipeline. We might need to * queue this until we get EOS. */ - flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE; + flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT; start_type = stop_type = GST_SEEK_TYPE_NONE; From 8d20ec3574fe5a75d1de20d4bb0668f89eda57a8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 11 May 2009 10:38:44 +0200 Subject: [PATCH 0101/1776] add some .gitignore files --- .gitignore | 3 +++ common/m4/.gitignore | 5 +++++ examples/.gitignore | 5 +++++ pkgconfig/.gitignore | 2 ++ 4 files changed, 15 insertions(+) create mode 100644 common/m4/.gitignore create mode 100644 examples/.gitignore create mode 100644 pkgconfig/.gitignore diff --git a/.gitignore b/.gitignore index cb3b21fe51..120bc47885 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ Makefile Makefile.in aclocal.m4 autom4te.cache +autoregen.sh compile config.guess config.h @@ -31,3 +32,5 @@ missing stamp-h1 bindings/python/rtspserver.c tags +gst-rtsp.spec +stamp-h.in diff --git a/common/m4/.gitignore b/common/m4/.gitignore new file mode 100644 index 0000000000..38066ddf7c --- /dev/null +++ b/common/m4/.gitignore @@ -0,0 +1,5 @@ +libtool.m4 +ltoptions.m4 +ltsugar.m4 +ltversion.m4 +lt~obsolete.m4 diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000000..d254cb2385 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,5 @@ +test-launch +test-mp4 +test-ogg +test-readme +test-video diff --git a/pkgconfig/.gitignore b/pkgconfig/.gitignore new file mode 100644 index 0000000000..bee7f7ad98 --- /dev/null +++ b/pkgconfig/.gitignore @@ -0,0 +1,2 @@ +gst-rtsp-server-0.10.pc +gst-rtsp-server.pc From 9645acef9fc342e175c0d4dfd8e3981e47ea38bf Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 11 May 2009 10:50:31 +0200 Subject: [PATCH 0102/1776] release 0.10.2 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a5eb5249fb..e1ea73fdbc 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.1.1, +AC_INIT(Gst-RTSP, 0.10.2, http://gstreamer.net/, gst-rtsp) From 0d88e13e31ae128990bfaec8fd72c2aad2680543 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 11 May 2009 10:51:47 +0200 Subject: [PATCH 0103/1776] back to development --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index e1ea73fdbc..bfbec185e1 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.2, +AC_INIT(Gst-RTSP, 0.10.2.1, http://gstreamer.net/, gst-rtsp) From 1f20cb68b40f8b2e1f8d3dd3de7f7552290a4f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Fri, 15 May 2009 17:10:44 +0200 Subject: [PATCH 0104/1776] Don't use hard-coded version number in pkg-config file --- pkgconfig/gst-rtsp-server.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgconfig/gst-rtsp-server.pc.in b/pkgconfig/gst-rtsp-server.pc.in index ada1a15f8b..52e33c5a42 100644 --- a/pkgconfig/gst-rtsp-server.pc.in +++ b/pkgconfig/gst-rtsp-server.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@/gstreamer-@GST_MAJORMINOR@ Name: gst-rtsp-server Description: GStreamer based RTSP server -Version: 0.10.1 +Version: @VERSION@ Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@ Libs: -L${libdir} -lgstrtspserver-@GST_MAJORMINOR@ Cflags: -I${includedir} From b83f54f1591fdef8347fceef9ab0ca8c70f7ef74 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 15 May 2009 17:58:44 +0200 Subject: [PATCH 0105/1776] media: link the RTP udpsrc to the session manager Link the RTP udpsrc and the appsrc to the session manager so that they don't shut down when the client sends a packet to open firewalls. --- gst/rtsp-server/rtsp-media.c | 40 ++++++++++++++++++++++++++++-------- gst/rtsp-server/rtsp-media.h | 3 +++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index f95848ea6f..0e5fec62fe 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -761,7 +761,7 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) GstPad *pad, *teepad, *selpad; GstPadLinkReturn ret; gint i; - GstElement *tee, *selector; + GstElement *tee; /* allocate udp ports, we will have 4 of them, 2 for receiving RTP/RTCP and 2 * for sending RTP/RTCP. The sender and receiver ports are shared between the @@ -801,6 +801,9 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) name = g_strdup_printf ("recv_rtcp_sink_%d", idx); stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name); g_free (name); + name = g_strdup_printf ("recv_rtp_sink_%d", idx); + stream->recv_rtp_sink = gst_element_get_request_pad (media->rtpbin, name); + g_free (name); /* get the session */ g_signal_emit_by_name (media->rtpbin, "get-internal-session", idx, @@ -864,22 +867,43 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) gst_object_unref (pad); gst_object_unref (teepad); - /* make selector for the RTCP receivers */ - selector = gst_element_factory_make ("input-selector", NULL); - g_object_set (selector, "select-all", TRUE, NULL); - gst_bin_add (GST_BIN_CAST (media->pipeline), selector); + /* make selector for the RTP receivers */ + stream->selector[0] = gst_element_factory_make ("input-selector", NULL); + g_object_set (stream->selector[0], "select-all", TRUE, NULL); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]); - pad = gst_element_get_static_pad (selector, "src"); + pad = gst_element_get_static_pad (stream->selector[0], "src"); + gst_pad_link (pad, stream->recv_rtp_sink); + gst_object_unref (pad); + + selpad = gst_element_get_request_pad (stream->selector[0], "sink%d"); + pad = gst_element_get_static_pad (stream->udpsrc[0], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + + selpad = gst_element_get_request_pad (stream->selector[0], "sink%d"); + pad = gst_element_get_static_pad (stream->appsrc[0], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + + /* make selector for the RTCP receivers */ + stream->selector[1] = gst_element_factory_make ("input-selector", NULL); + g_object_set (stream->selector[1], "select-all", TRUE, NULL); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]); + + pad = gst_element_get_static_pad (stream->selector[1], "src"); gst_pad_link (pad, stream->recv_rtcp_sink); gst_object_unref (pad); - selpad = gst_element_get_request_pad (selector, "sink%d"); + selpad = gst_element_get_request_pad (stream->selector[1], "sink%d"); pad = gst_element_get_static_pad (stream->udpsrc[1], "src"); gst_pad_link (pad, selpad); gst_object_unref (pad); gst_object_unref (selpad); - selpad = gst_element_get_request_pad (selector, "sink%d"); + selpad = gst_element_get_request_pad (stream->selector[1], "sink%d"); pad = gst_element_get_static_pad (stream->appsrc[1], "src"); gst_pad_link (pad, selpad); gst_object_unref (pad); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 3273f532cf..a7e9a1c25a 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -94,6 +94,7 @@ struct _GstRTSPMediaStream { /* pads on the rtpbin */ GstPad *recv_rtcp_sink; + GstPad *recv_rtp_sink; GstPad *send_rtp_sink; GstPad *send_rtp_src; GstPad *send_rtcp_src; @@ -109,6 +110,8 @@ struct _GstRTSPMediaStream { GstElement *appsrc[2]; GstElement *appsink[2]; + GstElement *selector[2]; + /* server ports for sending/receiving */ GstRTSPRange server_port; From aa0daff56167676c2419126ff27a1fb3d97976dd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 17 May 2009 13:59:10 +0200 Subject: [PATCH 0106/1776] release: 0.10.3 - Fixes a bug where it put the wrong verion in pkgconfig - Link RTP and RTCP sources --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index bfbec185e1..c666ab84b6 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.2.1, +AC_INIT(Gst-RTSP, 0.10.3, http://gstreamer.net/, gst-rtsp) From bace3b601b50335af9b62de1c04148f28f6c86ad Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 17 May 2009 14:04:31 +0200 Subject: [PATCH 0107/1776] back to development --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c666ab84b6..e26938e2f3 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.3, +AC_INIT(Gst-RTSP, 0.10.3.1, http://gstreamer.net/, gst-rtsp) From 8fcbe501dcecb2ebc18de9691eeb2f67e0ebad4c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 23 May 2009 16:17:02 +0200 Subject: [PATCH 0108/1776] client: only add RTP-Info when we have the info Only add RTP-Info for a stream when we can get the seqnum and timestamp from the depayloader. --- gst/rtsp-server/rtsp-client.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 27adf05d74..8138ceff54 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -465,7 +465,7 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; GString *rtpinfo; - guint n_streams, i; + guint n_streams, i, infocount; guint timestamp, seqnum; gchar *str; GstRTSPTimeRange *range; @@ -498,10 +498,11 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses rtpinfo = g_string_new (""); n_streams = gst_rtsp_media_n_streams (media->media); - for (i = 0; i < n_streams; i++) { + for (i = 0, infocount = 0; i < n_streams; i++) { GstRTSPSessionStream *sstream; GstRTSPMediaStream *stream; GstRTSPTransport *tr; + GObjectClass *payobjclass; gchar *uristr; /* get the stream as configured in the session */ @@ -517,15 +518,26 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses stream = sstream->media_stream; - g_object_get (G_OBJECT (stream->payloader), "seqnum", &seqnum, NULL); - g_object_get (G_OBJECT (stream->payloader), "timestamp", ×tamp, NULL); + payobjclass = G_OBJECT_GET_CLASS (stream->payloader); - if (i > 0) - g_string_append (rtpinfo, ", "); + if (g_object_class_find_property (payobjclass, "seqnum") && + g_object_class_find_property (payobjclass, "timestamp")) { + GObject *payobj; - uristr = gst_rtsp_url_get_request_uri (uri); - g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", uristr, i, seqnum, timestamp); - g_free (uristr); + payobj = G_OBJECT (stream->payloader); + + /* only add RTP-Info for streams with seqnum and timestamp */ + g_object_get (payobj, "seqnum", &seqnum, "timestamp", ×tamp, NULL); + + if (infocount > 0) + g_string_append (rtpinfo, ", "); + + uristr = gst_rtsp_url_get_request_uri (uri); + g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", uristr, i, seqnum, timestamp); + g_free (uristr); + + infocount++; + } } /* construct the response now */ From e5dc7c3719a2892094ebaf808e861971677dbb00 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 23 May 2009 16:18:04 +0200 Subject: [PATCH 0109/1776] factory: factor out the stream construction --- gst/rtsp-server/rtsp-media-factory.c | 77 ++++++++++++++++------------ 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 6eb834817b..69991aeaf9 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -396,15 +396,53 @@ parse_error: } } +/* try to find all the payloader elements, they should be named 'pay%d'. for + * each of the payloaders we will create a stream and collect the source pad. */ +static void +collect_streams (GstRTSPMediaFactory *factory, const GstRTSPUrl *url, + GstRTSPMedia *media) +{ + GstElement *element, *pay; + GstPad * pad; + gint i; + GstRTSPMediaStream *stream; + + element = media->element; + + for (i = 0; ; i++) { + gchar *name; + + name = g_strdup_printf ("pay%d", i); + if (!(pay = gst_bin_get_by_name (GST_BIN (element), name))) { + /* no more payloaders found, we have found all the streams and we can + * end the loop */ + g_free (name); + break; + } + /* create the stream */ + stream = g_new0 (GstRTSPMediaStream, 1); + stream->payloader = pay; + + g_message ("found stream %d with payloader %p", i, pay); + + pad = gst_element_get_static_pad (pay, "src"); + + /* ghost the pad of the payloader to the element */ + stream->srcpad = gst_ghost_pad_new (name, pad); + gst_element_add_pad (media->element, stream->srcpad); + gst_object_unref (pay); + g_free (name); + + /* add stream now */ + g_array_append_val (media->streams, stream); + } +} static GstRTSPMedia * default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) { GstRTSPMedia *media; - GstRTSPMediaStream *stream; - GstElement *pay, *element; - GstPad * pad; - gint i; + GstElement *element; GstRTSPMediaFactoryClass *klass; klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); @@ -420,36 +458,7 @@ default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) media = gst_rtsp_media_new (); media->element = element; - /* try to find all the payloader elements, they should be named 'pay%d'. for - * each of the payloaders we will create a stream and collect the source pad. - */ - for (i = 0; ; i++) { - gchar *name; - - name = g_strdup_printf ("pay%d", i); - - if (!(pay = gst_bin_get_by_name (GST_BIN (element), name))) { - /* no more payloaders found, we have found all the streams and we can - * end the loop */ - g_free (name); - break; - } - - /* create the stream */ - stream = g_new0 (GstRTSPMediaStream, 1); - stream->payloader = pay; - - pad = gst_element_get_static_pad (pay, "src"); - - /* ghost the pad of the payloader to the element */ - stream->srcpad = gst_ghost_pad_new (name, pad); - gst_element_add_pad (media->element, stream->srcpad); - gst_object_unref (pay); - g_free (name); - - /* add stream now */ - g_array_append_val (media->streams, stream); - } + collect_streams (factory, url, media); return media; From 740d71bd50bdcfc3c63dbcf8a0d007f994c7e5ba Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 23 May 2009 16:30:55 +0200 Subject: [PATCH 0110/1776] client: warn when we can't do RTP-Info --- gst/rtsp-server/rtsp-client.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8138ceff54..b47f81fe99 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -538,6 +538,9 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses infocount++; } + else { + g_warning ("RTP-Info cannot be determined for stream %d", i); + } } /* construct the response now */ @@ -545,8 +548,13 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); /* add the RTP-Info header */ - str = g_string_free (rtpinfo, FALSE); - gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RTP_INFO, str); + if (infocount > 0) { + str = g_string_free (rtpinfo, FALSE); + gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RTP_INFO, str); + } + else { + g_string_free (rtpinfo, TRUE); + } /* add the range */ str = gst_rtsp_range_to_string (&media->media->range); From 415e5e674b1053e3c59f3c53975232bafdc0d7f4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 24 May 2009 19:33:22 +0200 Subject: [PATCH 0111/1776] sdp: don't add encoding name when absent in caps --- gst/rtsp-server/rtsp-sdp.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 74baa109ab..3e6c27136e 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -87,14 +87,16 @@ gst_rtsp_sdp_from_media (GstRTSPMedia *media) caps_enc = gst_structure_get_string (s, "encoding-name"); caps_params = gst_structure_get_string (s, "encoding-params"); - if (caps_params) - tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate, + if (caps_enc) { + if (caps_params) + tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate, caps_params); - else - tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate); + else + tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate); - gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); - g_free (tmp); + gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); + g_free (tmp); + } /* the config uri */ tmp = g_strdup_printf ("stream=%d", i); From fab65082da699260f216073b1f74d9d7855a9b46 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 24 May 2009 19:34:52 +0200 Subject: [PATCH 0112/1776] rtsp: add support for dynamic elements Add support for dynamic elements. Don't set live pipelines back to paused. --- gst/rtsp-server/rtsp-media-factory.c | 55 ++++++++++------ gst/rtsp-server/rtsp-media.c | 99 ++++++++++++++++++++++------ gst/rtsp-server/rtsp-media.h | 3 + 3 files changed, 117 insertions(+), 40 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 69991aeaf9..2a5833d8ff 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -402,39 +402,52 @@ static void collect_streams (GstRTSPMediaFactory *factory, const GstRTSPUrl *url, GstRTSPMedia *media) { - GstElement *element, *pay; + GstElement *element, *elem; GstPad * pad; gint i; GstRTSPMediaStream *stream; + gboolean have_elem; element = media->element; - for (i = 0; ; i++) { + have_elem = TRUE; + for (i = 0; have_elem ; i++) { gchar *name; + have_elem = FALSE; + name = g_strdup_printf ("pay%d", i); - if (!(pay = gst_bin_get_by_name (GST_BIN (element), name))) { - /* no more payloaders found, we have found all the streams and we can - * end the loop */ - g_free (name); - break; + if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { + /* create the stream */ + stream = g_new0 (GstRTSPMediaStream, 1); + stream->payloader = elem; + + g_message ("found stream %d with payloader %p", i, elem); + + pad = gst_element_get_static_pad (elem, "src"); + + /* ghost the pad of the payloader to the element */ + stream->srcpad = gst_ghost_pad_new (name, pad); + gst_element_add_pad (media->element, stream->srcpad); + gst_object_unref (elem); + + /* add stream now */ + g_array_append_val (media->streams, stream); + have_elem = TRUE; } - /* create the stream */ - stream = g_new0 (GstRTSPMediaStream, 1); - stream->payloader = pay; - - g_message ("found stream %d with payloader %p", i, pay); - - pad = gst_element_get_static_pad (pay, "src"); - - /* ghost the pad of the payloader to the element */ - stream->srcpad = gst_ghost_pad_new (name, pad); - gst_element_add_pad (media->element, stream->srcpad); - gst_object_unref (pay); g_free (name); - /* add stream now */ - g_array_append_val (media->streams, stream); + name = g_strdup_printf ("dynpay%d", i); + if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { + /* a stream that will dynamically create pads to provide RTP packets */ + + g_message ("found dynamic element %d, %p", i, elem); + + media->dynamic = g_list_prepend (media->dynamic, elem); + + have_elem = TRUE; + } + g_free (name); } } diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 0e5fec62fe..b5e0c59f64 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -134,6 +134,9 @@ gst_rtsp_media_finalize (GObject * obj) } g_array_free (media->streams, TRUE); + g_list_foreach (media->dynamic, (GFunc) gst_object_unref, NULL); + g_list_free (media->dynamic); + if (media->source) { g_source_destroy (media->source); g_source_unref (media->source); @@ -761,7 +764,6 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) GstPad *pad, *teepad, *selpad; GstPadLinkReturn ret; gint i; - GstElement *tee; /* allocate udp ports, we will have 4 of them, 2 for receiving RTP/RTCP and 2 * for sending RTP/RTCP. The sender and receiver ports are shared between the @@ -826,42 +828,42 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) goto link_failed; /* make tee for RTP and link to stream */ - tee = gst_element_factory_make ("tee", NULL); - gst_bin_add (GST_BIN_CAST (media->pipeline), tee); + stream->tee[0] = gst_element_factory_make ("tee", NULL); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[0]); - pad = gst_element_get_static_pad (tee, "sink"); + pad = gst_element_get_static_pad (stream->tee[0], "sink"); gst_pad_link (stream->send_rtp_src, pad); gst_object_unref (pad); /* link RTP sink, we're pretty sure this will work. */ - teepad = gst_element_get_request_pad (tee, "src%d"); + teepad = gst_element_get_request_pad (stream->tee[0], "src%d"); pad = gst_element_get_static_pad (stream->udpsink[0], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); - teepad = gst_element_get_request_pad (tee, "src%d"); + teepad = gst_element_get_request_pad (stream->tee[0], "src%d"); pad = gst_element_get_static_pad (stream->appsink[0], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); /* make tee for RTCP */ - tee = gst_element_factory_make ("tee", NULL); - gst_bin_add (GST_BIN_CAST (media->pipeline), tee); + stream->tee[1] = gst_element_factory_make ("tee", NULL); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[1]); - pad = gst_element_get_static_pad (tee, "sink"); + pad = gst_element_get_static_pad (stream->tee[1], "sink"); gst_pad_link (stream->send_rtcp_src, pad); gst_object_unref (pad); /* link RTCP elements */ - teepad = gst_element_get_request_pad (tee, "src%d"); + teepad = gst_element_get_request_pad (stream->tee[1], "src%d"); pad = gst_element_get_static_pad (stream->udpsink[1], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); - teepad = gst_element_get_request_pad (tee, "src%d"); + teepad = gst_element_get_request_pad (stream->tee[1], "src%d"); pad = gst_element_get_static_pad (stream->appsink[1], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); @@ -1046,6 +1048,56 @@ bus_message (GstBus *bus, GstMessage *message, GstRTSPMedia *media) return ret; } +static void +pad_added_cb (GstElement *element, GstPad *pad, GstRTSPMedia *media) +{ + GstRTSPMediaStream *stream; + gchar *name; + gint i; + + i = media->streams->len + 1; + + g_message ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), i); + + stream = g_new0 (GstRTSPMediaStream, 1); + stream->payloader = element; + + name = g_strdup_printf ("dynpay%d", i); + + /* ghost the pad of the payloader to the element */ + stream->srcpad = gst_ghost_pad_new (name, pad); + gst_pad_set_active (stream->srcpad, TRUE); + gst_element_add_pad (media->element, stream->srcpad); + g_free (name); + + /* add stream now */ + g_array_append_val (media->streams, stream); + + setup_stream (stream, i, media); + + for (i = 0; i < 2; i++) { + gst_element_set_state (stream->udpsink[i], GST_STATE_PAUSED); + gst_element_set_state (stream->appsink[i], GST_STATE_PAUSED); + gst_element_set_state (stream->tee[i], GST_STATE_PAUSED); + gst_element_set_state (stream->selector[i], GST_STATE_PAUSED); + gst_element_set_state (stream->appsrc[i], GST_STATE_PAUSED); + } +} + +static void +no_more_pads_cb (GstElement *element, GstRTSPMedia *media) +{ + g_message ("no more pads"); + if (media->fakesink) { + gst_object_ref (media->fakesink); + gst_bin_remove (GST_BIN (media->pipeline), media->fakesink); + gst_element_set_state (media->fakesink, GST_STATE_NULL); + gst_object_unref (media->fakesink); + media->fakesink = NULL; + g_message ("removed fakesink"); + } +} + /** * gst_rtsp_media_prepare: * @obj: a #GstRTSPMedia @@ -1065,6 +1117,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) guint i, n_streams; GstRTSPMediaClass *klass; GstBus *bus; + GList *walk; if (media->prepared) goto was_prepared; @@ -1090,10 +1143,11 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) media->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin"); - /* add stuf to the bin */ + /* add stuff to the bin */ gst_bin_add (GST_BIN (media->pipeline), media->rtpbin); - /* link streams we already have */ + /* link streams we already have, other streams might appear when we have + * dynamic elements */ n_streams = gst_rtsp_media_n_streams (media); for (i = 0; i < n_streams; i++) { GstRTSPMediaStream *stream; @@ -1103,6 +1157,16 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) setup_stream (stream, i, media); } + for (walk = media->dynamic; walk; walk = g_list_next (walk)) { + GstElement *elem = walk->data; + + g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media); + g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media); + + media->fakesink = gst_element_factory_make ("fakesink", "fakesink"); + gst_bin_add (GST_BIN (media->pipeline), media->fakesink); + } + /* first go to PAUSED */ ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); media->target_state = GST_STATE_PAUSED; @@ -1129,11 +1193,6 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; - /* and back to PAUSED for live pipelines */ - ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); - if (ret == GST_STATE_CHANGE_FAILURE) - goto state_failed; - /* collect stats about the media */ collect_media_stats (media); @@ -1158,7 +1217,7 @@ state_failed: } is_reused: { - g_warning ("can not reused media %p", media); + g_warning ("can not reuse media %p", media); return FALSE; } } @@ -1281,8 +1340,10 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport } case GST_RTSP_LOWER_TRANS_TCP: if (add) { + g_message ("adding TCP %s", trans->destination); stream->transports = g_list_prepend (stream->transports, tr); } else if (remove) { + g_message ("removing TCP %s", trans->destination); stream->transports = g_list_remove (stream->transports, tr); } break; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index a7e9a1c25a..29e9989a3a 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -110,6 +110,7 @@ struct _GstRTSPMediaStream { GstElement *appsrc[2]; GstElement *appsink[2]; + GstElement *tee[2]; GstElement *selector[2]; /* server ports for sending/receiving */ @@ -153,11 +154,13 @@ struct _GstRTSPMedia { GstElement *element; GArray *streams; + GList *dynamic; gboolean prepared; gint active; /* the pipeline for the media */ GstElement *pipeline; + GstElement *fakesink; GSource *source; guint id; From 7a8b931a83d103773d7ef7991b60e4d839f5a366 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 24 May 2009 19:56:45 +0200 Subject: [PATCH 0113/1776] media: also count active TCP connections --- gst/rtsp-server/rtsp-media.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b5e0c59f64..d1f737ef58 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1342,9 +1342,11 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport if (add) { g_message ("adding TCP %s", trans->destination); stream->transports = g_list_prepend (stream->transports, tr); + media->active++; } else if (remove) { g_message ("removing TCP %s", trans->destination); stream->transports = g_list_remove (stream->transports, tr); + media->active--; } break; default: From b0beb1c8d133df21c1cebecdfadb9fdbb4fb5232 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 24 May 2009 20:00:19 +0200 Subject: [PATCH 0114/1776] example: add SDP relay example --- examples/.gitignore | 1 + examples/Makefile.am | 2 +- examples/test-sdp.c | 88 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 examples/test-sdp.c diff --git a/examples/.gitignore b/examples/.gitignore index d254cb2385..653f26db6a 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -2,4 +2,5 @@ test-launch test-mp4 test-ogg test-readme +test-sdp test-video diff --git a/examples/Makefile.am b/examples/Makefile.am index a7f9986a57..5af7696a63 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,4 +1,4 @@ -noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch +noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/examples/test-sdp.c b/examples/test-sdp.c new file mode 100644 index 0000000000..64113c5fbe --- /dev/null +++ b/examples/test-sdp.c @@ -0,0 +1,88 @@ +/* GStreamer + * Copyright (C) 2009 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + + +static gboolean +timeout (GstRTSPServer *server, gboolean ignored) +{ + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_cleanup (pool); + g_object_unref (pool); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMediaMapping *mapping; + GstRTSPMediaFactory *factory; + gchar *str; + + gst_init (&argc, &argv); + + if (argc < 2) { + g_message ("usage: %s ", argv[0]); + return -1; + } + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mapping for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mapping = gst_rtsp_server_get_media_mapping (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + + str = g_strdup_printf ( "( filesrc location=%s ! sdpdemux name=dynpay0 )", argv[1]); + gst_rtsp_media_factory_set_launch (factory, str); + gst_rtsp_media_factory_set_shared (factory, TRUE); + g_free (str); + + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mapping); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + + /* start serving */ + g_main_loop_run (loop); + + return 0; +} From 5955fc7d12cb0c168a9c6088c5be96173b9e2a00 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 26 May 2009 11:42:41 +0200 Subject: [PATCH 0115/1776] media: keep track of active transports Keep track of which transport is active to avoid closing the connection too soon. Remove the destination transport also when going to NULL. Print some stats about the SDES and other RTCP messages we receive from the clients. --- gst/rtsp-server/rtsp-media.c | 46 ++++++++++++++++++++++++++++++++---- gst/rtsp-server/rtsp-media.h | 1 + 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d1f737ef58..d07b380112 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -690,16 +690,40 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) g_free (capsstr); } +static void +dump_structure (const GstStructure *s) +{ + gchar *sstr; + + sstr = gst_structure_to_string (s); + g_message ("structure: %s", sstr); + g_free (sstr); +} + static void on_new_ssrc (GObject *session, GObject *source, GstRTSPMedia *media) { g_message ("%p: new source %p", media, source); } +static void +on_ssrc_sdes (GObject *session, GObject *source, GstRTSPMedia *media) +{ + GstStructure *sdes; + + g_message ("%p: new SDES %p", media, source); + g_object_get (source, "sdes", &sdes, NULL); + dump_structure (sdes); +} + static void on_ssrc_active (GObject *session, GObject *source, GstRTSPMedia *media) { + GstStructure *stats; + g_message ("%p: source %p is active", media, source); + g_object_get (source, "stats", &stats, NULL); + dump_structure (stats); } static void @@ -813,6 +837,8 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc, media); + g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes, + media); g_signal_connect (stream->session, "on-ssrc-active", (GCallback) on_ssrc_active, media); g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, @@ -1025,6 +1051,10 @@ default_handle_message (GstRTSPMedia *media, GstMessage *message) g_free (debug); break; } + case GST_MESSAGE_ELEMENT: + { + break; + } default: g_message ("%p: got message type %s", media, gst_message_type_get_name (type)); break; @@ -1279,11 +1309,13 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport add = remove = FALSE; + g_message ("going to state %s media %p", gst_element_state_get_name (state), media); + switch (state) { case GST_STATE_NULL: /* unlock the streams so that they follow the state changes from now on */ unlock_streams (media); - break; + /* fallthrough */ case GST_STATE_PAUSED: /* we're going from PLAYING to PAUSED, READY or NULL, remove */ if (media->target_state == GST_STATE_PLAYING) @@ -1325,27 +1357,31 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport min = trans->client_port.min; max = trans->client_port.max; - if (add) { + if (add && !tr->active) { g_message ("adding %s:%d-%d", dest, min, max); g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); + tr->active = TRUE; media->active++; - } else if (remove) { + } else if (remove && tr->active) { g_message ("removing %s:%d-%d", dest, min, max); g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); + tr->active = FALSE; media->active--; } break; } case GST_RTSP_LOWER_TRANS_TCP: - if (add) { + if (add && !tr->active) { g_message ("adding TCP %s", trans->destination); stream->transports = g_list_prepend (stream->transports, tr); + tr->active = TRUE; media->active++; - } else if (remove) { + } else if (remove && tr->active) { g_message ("removing TCP %s", trans->destination); stream->transports = g_list_remove (stream->transports, tr); + tr->active = FALSE; media->active--; } break; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 29e9989a3a..d41075fd7c 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -61,6 +61,7 @@ struct _GstRTSPMediaTrans { GstRTSPSendFunc send_rtcp; gpointer user_data; GDestroyNotify notify; + gboolean active; GstRTSPTransport *transport; }; From 461169537bff5bee289674bd7d48a77e07aecb3a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 26 May 2009 17:25:59 +0200 Subject: [PATCH 0116/1776] client: replay OK to GET/SET_PARAMETER Some clients (vlc) use GET/SET_PARAMETER to keep the TCP session open. Make it so that we return OK for those requests. --- gst/rtsp-server/rtsp-client.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b47f81fe99..b7ac1d01df 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -857,6 +857,8 @@ handle_options_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession * GST_RTSP_PAUSE | GST_RTSP_PLAY | GST_RTSP_SETUP | + GST_RTSP_GET_PARAMETER | + GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN; str = gst_rtsp_options_as_text (options); @@ -997,11 +999,13 @@ handle_request (GstRTSPClient *client, GstRTSPMessage *request) case GST_RTSP_TEARDOWN: handle_teardown_request (client, uri, session, request); break; - case GST_RTSP_ANNOUNCE: + case GST_RTSP_SET_PARAMETER: case GST_RTSP_GET_PARAMETER: + send_generic_response (client, GST_RTSP_STS_OK, request); + break; + case GST_RTSP_ANNOUNCE: case GST_RTSP_RECORD: case GST_RTSP_REDIRECT: - case GST_RTSP_SET_PARAMETER: send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, request); break; case GST_RTSP_INVALID: From 7bbdf7bf9754a894557c2d057bcf3b408d232178 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 26 May 2009 17:27:07 +0200 Subject: [PATCH 0117/1776] session: add 5sec to the real session timeout Allow the session to live 5sec longer before really timing out. This should give clients some extra time to keep the session active. --- gst/rtsp-server/rtsp-session.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index fc13098329..54a3700448 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -418,8 +418,8 @@ gst_rtsp_session_next_timeout (GstRTSPSession *session, GTimeVal *now) g_return_val_if_fail (now != NULL, -1); last_access = GST_TIMEVAL_TO_TIME (session->last_access); - /* add timeout */ - last_access += session->timeout * GST_SECOND; + /* add timeout allow for 5 seconds of extra time */ + last_access += session->timeout * GST_SECOND + (5 * GST_SECOND); now_ns = GST_TIMEVAL_TO_TIME (*now); From 9bed89c3b7f05bc0cb8f7fd1cad49ca6e05c414e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 26 May 2009 19:01:10 +0200 Subject: [PATCH 0118/1776] rtsp: use RTCP to keep the session alive Use the RTCP rtcp-from stats field to find the associated session and use this to keep the session alive. --- gst/rtsp-server/rtsp-client.c | 256 ++++++++++++++++++--------------- gst/rtsp-server/rtsp-media.c | 112 ++++++++++++--- gst/rtsp-server/rtsp-media.h | 28 +++- gst/rtsp-server/rtsp-session.c | 27 +++- gst/rtsp-server/rtsp-session.h | 4 + 5 files changed, 288 insertions(+), 139 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b7ac1d01df..aeaf52aa26 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -35,13 +35,14 @@ enum PROP_LAST }; -static void gst_rtsp_client_get_property (GObject *object, guint propid, - GValue *value, GParamSpec *pspec); -static void gst_rtsp_client_set_property (GObject *object, guint propid, - const GValue *value, GParamSpec *pspec); +static void gst_rtsp_client_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec); +static void gst_rtsp_client_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec); static void gst_rtsp_client_finalize (GObject * obj); -static void client_session_finalized (GstRTSPClient *client, GstRTSPSession *session); +static void client_session_finalized (GstRTSPClient * client, + GstRTSPSession * session); G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); @@ -59,14 +60,17 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_object_class_install_property (gobject_class, PROP_SESSION_POOL, g_param_spec_object ("session-pool", "Session Pool", "The session pool to use for client session", - GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_TYPE_RTSP_SESSION_POOL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING, g_param_spec_object ("media-mapping", "Media Mapping", "The media mapping to use for client session", - GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_TYPE_RTSP_MEDIA_MAPPING, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + tunnels = + g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); tunnels_lock = g_mutex_new (); } @@ -100,8 +104,8 @@ gst_rtsp_client_finalize (GObject * obj) } static void -gst_rtsp_client_get_property (GObject *object, guint propid, - GValue *value, GParamSpec *pspec) +gst_rtsp_client_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec) { GstRTSPClient *client = GST_RTSP_CLIENT (object); @@ -118,8 +122,8 @@ gst_rtsp_client_get_property (GObject *object, guint propid, } static void -gst_rtsp_client_set_property (GObject *object, guint propid, - const GValue *value, GParamSpec *pspec) +gst_rtsp_client_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec) { GstRTSPClient *client = GST_RTSP_CLIENT (object); @@ -151,9 +155,11 @@ gst_rtsp_client_new (void) } static void -send_response (GstRTSPClient *client, GstRTSPSession *session, GstRTSPMessage *response) +send_response (GstRTSPClient * client, GstRTSPSession * session, + GstRTSPMessage * response) { - gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER, "GStreamer RTSP server"); + gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER, + "GStreamer RTSP server"); /* remove any previous header */ gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1); @@ -163,13 +169,14 @@ send_response (GstRTSPClient *client, GstRTSPSession *session, GstRTSPMessage *r gchar *str; if (session->timeout != 60) - str = g_strdup_printf ("%s; timeout=%d", session->sessionid, session->timeout); + str = + g_strdup_printf ("%s; timeout=%d", session->sessionid, + session->timeout); else str = g_strdup (session->sessionid); gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION, str); } - #ifdef DEBUG gst_rtsp_message_dump (response); #endif @@ -179,19 +186,19 @@ send_response (GstRTSPClient *client, GstRTSPSession *session, GstRTSPMessage *r } static void -send_generic_response (GstRTSPClient *client, GstRTSPStatusCode code, - GstRTSPMessage *request) +send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, + GstRTSPMessage * request) { GstRTSPMessage response = { 0 }; - gst_rtsp_message_init_response (&response, code, - gst_rtsp_status_as_text (code), request); + gst_rtsp_message_init_response (&response, code, + gst_rtsp_status_as_text (code), request); send_response (client, NULL, &response); } static gboolean -compare_uri (const GstRTSPUrl *uri1, const GstRTSPUrl *uri2) +compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2) { if (uri1 == NULL || uri2 == NULL) return FALSE; @@ -206,7 +213,7 @@ compare_uri (const GstRTSPUrl *uri1, const GstRTSPUrl *uri2) * but is cached for when the same client (without breaking the connection) is * doing a setup for the exact same url. */ static GstRTSPMedia * -find_media (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) +find_media (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPMessage * request) { GstRTSPMediaFactory *factory; GstRTSPMedia *media; @@ -225,7 +232,8 @@ find_media (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) goto no_mapping; /* find the factory for the uri first */ - if (!(factory = gst_rtsp_media_mapping_find_factory (client->media_mapping, uri))) + if (!(factory = + gst_rtsp_media_mapping_find_factory (client->media_mapping, uri))) goto no_factory; /* prepare the media and add it to the pipeline */ @@ -239,11 +247,10 @@ find_media (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request) /* now keep track of the uri and the media */ client->uri = gst_rtsp_url_copy (uri); client->media = media; - } - else { + } else { /* we have seen this uri before, used cached media */ media = client->media; - g_message ("reusing cached media %p", media); + g_message ("reusing cached media %p", media); } if (media) @@ -278,7 +285,7 @@ no_prepare: } static gboolean -do_send_data (GstBuffer *buffer, guint8 channel, GstRTSPClient *client) +do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) { GstRTSPMessage message = { 0 }; guint8 *data; @@ -299,38 +306,36 @@ do_send_data (GstBuffer *buffer, guint8 channel, GstRTSPClient *client) } static void -link_stream (GstRTSPClient *client, GstRTSPSessionStream *stream) +link_stream (GstRTSPClient * client, GstRTSPSessionStream * stream) { gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data, - (GstRTSPSendFunc) do_send_data, client, NULL); + (GstRTSPSendFunc) do_send_data, client, NULL); client->streams = g_list_prepend (client->streams, stream); } static void -unlink_stream (GstRTSPClient *client, GstRTSPSessionStream *stream) +unlink_stream (GstRTSPClient * client, GstRTSPSessionStream * stream) { - gst_rtsp_session_stream_set_callbacks (stream, NULL, - NULL, NULL, NULL); + gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); client->streams = g_list_remove (client->streams, stream); } static void -unlink_streams (GstRTSPClient *client) +unlink_streams (GstRTSPClient * client) { GList *walk; for (walk = client->streams; walk; walk = g_list_next (walk)) { GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data; - gst_rtsp_session_stream_set_callbacks (stream, NULL, - NULL, NULL, NULL); + gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); } g_list_free (client->streams); client->streams = NULL; } static void -unlink_session_streams (GstRTSPClient *client, GstRTSPSessionMedia *media) +unlink_session_streams (GstRTSPClient * client, GstRTSPSessionMedia * media) { guint n_streams, i; @@ -353,7 +358,8 @@ unlink_session_streams (GstRTSPClient *client, GstRTSPSessionMedia *media) } static gboolean -handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) +handle_teardown_request (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request) { GstRTSPSessionMedia *media; GstRTSPMessage response = { 0 }; @@ -371,7 +377,8 @@ handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession unlink_session_streams (client, media); /* remove the session from the watched sessions */ - g_object_weak_unref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client); + g_object_weak_unref (G_OBJECT (session), + (GWeakNotify) client_session_finalized, client); client->sessions = g_list_remove (client->sessions, session); gst_rtsp_session_media_set_state (media, GST_STATE_NULL); @@ -384,7 +391,8 @@ handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession } /* construct the response now */ code = GST_RTSP_STS_OK; - gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); + gst_rtsp_message_init_response (&response, code, + gst_rtsp_status_as_text (code), request); send_response (client, session, &response); @@ -404,7 +412,8 @@ not_found: } static gboolean -handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) +handle_pause_request (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request) { GstRTSPSessionMedia *media; GstRTSPMessage response = { 0 }; @@ -431,7 +440,8 @@ handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se /* construct the response now */ code = GST_RTSP_STS_OK; - gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); + gst_rtsp_message_init_response (&response, code, + gst_rtsp_status_as_text (code), request); send_response (client, session, &response); @@ -453,13 +463,15 @@ not_found: } invalid_state: { - send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request); + send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, + request); return FALSE; } } static gboolean -handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) +handle_play_request (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request) { GstRTSPSessionMedia *media; GstRTSPMessage response = { 0 }; @@ -508,8 +520,10 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses /* get the stream as configured in the session */ sstream = gst_rtsp_session_media_get_stream (media, i); /* get the transport, if there is no transport configured, skip this stream */ - if (!(tr = sstream->trans.transport)) + if (!(tr = sstream->trans.transport)) { + g_message ("stream %d is not configured", i); continue; + } if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { /* for TCP, link the stream to the TCP connection of the client */ @@ -521,7 +535,7 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses payobjclass = G_OBJECT_GET_CLASS (stream->payloader); if (g_object_class_find_property (payobjclass, "seqnum") && - g_object_class_find_property (payobjclass, "timestamp")) { + g_object_class_find_property (payobjclass, "timestamp")) { GObject *payobj; payobj = G_OBJECT (stream->payloader); @@ -533,26 +547,26 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *ses g_string_append (rtpinfo, ", "); uristr = gst_rtsp_url_get_request_uri (uri); - g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", uristr, i, seqnum, timestamp); + g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", + uristr, i, seqnum, timestamp); g_free (uristr); infocount++; - } - else { + } else { g_warning ("RTP-Info cannot be determined for stream %d", i); } } /* construct the response now */ code = GST_RTSP_STS_OK; - gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); + gst_rtsp_message_init_response (&response, code, + gst_rtsp_status_as_text (code), request); /* add the RTP-Info header */ if (infocount > 0) { str = g_string_free (rtpinfo, FALSE); gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RTP_INFO, str); - } - else { + } else { g_string_free (rtpinfo, TRUE); } @@ -582,13 +596,22 @@ not_found: } invalid_state: { - send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request); + send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, + request); return FALSE; } } +static void +do_keepalive (GstRTSPSession * session) +{ + g_message ("keep session %p alive", session); + gst_rtsp_session_touch (session); +} + static gboolean -handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) +handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request) { GstRTSPResult res; gchar *transport; @@ -623,18 +646,20 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se goto bad_request; /* parse the transport */ - res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_TRANSPORT, &transport, 0); + res = + gst_rtsp_message_get_header (request, GST_RTSP_HDR_TRANSPORT, &transport, + 0); if (res != GST_RTSP_OK) goto no_transport; transports = g_strsplit (transport, ",", 0); - gst_rtsp_transport_new (&ct); + gst_rtsp_transport_new (&ct); /* loop through the transports, try to parse */ have_transport = FALSE; for (i = 0; transports[i]; i++) { - gst_rtsp_transport_init (ct); + gst_rtsp_transport_init (ct); res = gst_rtsp_transport_parse (transports[i], ct); if (res == GST_RTSP_OK) { have_transport = TRUE; @@ -644,7 +669,7 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se g_strfreev (transports); /* we have not found anything usable, error out */ - if (!have_transport) + if (!have_transport) goto unsupported_transports; /* we have a valid transport, check if we can handle it */ @@ -654,8 +679,7 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se goto unsupported_transports; supported = GST_RTSP_LOWER_TRANS_UDP | - GST_RTSP_LOWER_TRANS_UDP_MCAST | - GST_RTSP_LOWER_TRANS_TCP; + GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP; if (!(ct->lower_transport & supported)) goto unsupported_transports; @@ -674,8 +698,7 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se media = gst_rtsp_session_get_media (session, uri); need_session = FALSE; - } - else { + } else { /* create a session if this fails we probably reached our session limit or * something. */ if (!(session = gst_rtsp_session_pool_create (client->session_pool))) @@ -708,13 +731,18 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *se st = gst_rtsp_session_stream_set_transport (stream, ct); + /* configure keepalive for this transport */ + gst_rtsp_session_stream_set_keepalive (stream, + (GstRTSPKeepAliveFunc) do_keepalive, session, NULL); + /* serialize the server transport */ trans_str = gst_rtsp_transport_as_text (st); gst_rtsp_transport_free (st); /* construct the response now */ code = GST_RTSP_STS_OK; - gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); + gst_rtsp_message_init_response (&response, code, + gst_rtsp_status_as_text (code), request); gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str); g_free (trans_str); @@ -763,7 +791,7 @@ no_transport: unsupported_transports: { send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request); - gst_rtsp_transport_free (ct); + gst_rtsp_transport_free (ct); return FALSE; } no_pool: @@ -780,7 +808,8 @@ service_unavailable: /* for the describe we must generate an SDP */ static gboolean -handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) +handle_describe_request (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request) { GstRTSPMessage response = { 0 }; GstRTSPResult res; @@ -791,10 +820,11 @@ handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession /* check what kind of format is accepted, we don't really do anything with it * and always return SDP for now. */ - for (i = 0; i++; ) { + for (i = 0; i++;) { gchar *accept; - res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_ACCEPT, &accept, i); + res = + gst_rtsp_message_get_header (request, GST_RTSP_HDR_ACCEPT, &accept, i); if (res == GST_RTSP_ENOTIMPL) break; @@ -812,10 +842,11 @@ handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession g_object_unref (media); - gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, - gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); + gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, + gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE, "application/sdp"); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE, + "application/sdp"); /* content base for some clients that might screw up creating the setup uri */ str = g_strdup_printf ("rtsp://%s:%u%s/", uri->host, uri->port, uri->abspath); @@ -824,7 +855,7 @@ handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession /* add SDP to the response body */ str = gst_sdp_message_as_text (sdp); - gst_rtsp_message_take_body (&response, (guint8 *)str, strlen (str)); + gst_rtsp_message_take_body (&response, (guint8 *) str, strlen (str)); gst_sdp_message_free (sdp); send_response (client, session, &response); @@ -846,25 +877,24 @@ no_sdp: } static void -handle_options_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request) +handle_options_request (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request) { GstRTSPMessage response = { 0 }; GstRTSPMethod options; gchar *str; options = GST_RTSP_DESCRIBE | - GST_RTSP_OPTIONS | - GST_RTSP_PAUSE | - GST_RTSP_PLAY | - GST_RTSP_SETUP | - GST_RTSP_GET_PARAMETER | - GST_RTSP_SET_PARAMETER | - GST_RTSP_TEARDOWN; + GST_RTSP_OPTIONS | + GST_RTSP_PAUSE | + GST_RTSP_PLAY | + GST_RTSP_SETUP | + GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN; str = gst_rtsp_options_as_text (options); - gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, - gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); + gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, + gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str); g_free (str); @@ -874,7 +904,7 @@ handle_options_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession * /* remove duplicate and trailing '/' */ static void -santize_uri (GstRTSPUrl *uri) +santize_uri (GstRTSPUrl * uri) { gint i, len; gchar *s, *d; @@ -894,22 +924,22 @@ santize_uri (GstRTSPUrl *uri) } len = d - uri->abspath; /* don't remove the first slash if that's the only thing left */ - if (len > 1 && *(d-1) == '/') + if (len > 1 && *(d - 1) == '/') d--; *d = '\0'; } static void -client_session_finalized (GstRTSPClient *client, GstRTSPSession *session) +client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) { if (!(client->sessions = g_list_remove (client->sessions, session))) { g_message ("all sessions finalized, close the connection"); - g_source_destroy ((GSource*)client->watch); + g_source_destroy ((GSource *) client->watch); } } static void -client_watch_session (GstRTSPClient *client, GstRTSPSession *session) +client_watch_session (GstRTSPClient * client, GstRTSPSession * session) { GList *walk; @@ -923,12 +953,13 @@ client_watch_session (GstRTSPClient *client, GstRTSPSession *session) g_message ("watching session %p", session); - g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client); + g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, + client); client->sessions = g_list_prepend (client->sessions, session); } static void -handle_request (GstRTSPClient *client, GstRTSPMessage *request) +handle_request (GstRTSPClient * client, GstRTSPMessage * request) { GstRTSPMethod method; const gchar *uristr; @@ -948,7 +979,8 @@ handle_request (GstRTSPClient *client, GstRTSPMessage *request) if (version != GST_RTSP_VERSION_1_0) { /* we can only handle 1.0 requests */ - send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, request); + send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, + request); return; } @@ -975,8 +1007,7 @@ handle_request (GstRTSPClient *client, GstRTSPMessage *request) * disappears because it times out, we will be notified. If all sessions are * gone, we will close the connection */ client_watch_session (client, session); - } - else + } else session = NULL; /* now see what is asked and dispatch to a dedicated handler */ @@ -1033,7 +1064,7 @@ session_not_found: } static void -handle_data (GstRTSPClient *client, GstRTSPMessage *message) +handle_data (GstRTSPClient * client, GstRTSPMessage * message) { GstRTSPResult res; guint8 channel; @@ -1043,7 +1074,7 @@ handle_data (GstRTSPClient *client, GstRTSPMessage *message) GstBuffer *buffer; gboolean handled; - /* find the stream for this message */ + /* find the stream for this message */ res = gst_rtsp_message_parse_data (message, &channel); if (res != GST_RTSP_OK) return; @@ -1073,12 +1104,12 @@ handle_data (GstRTSPClient *client, GstRTSPMessage *message) if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { /* dispatch to the stream based on the channel number */ if (tr->interleaved.min == channel) { - gst_rtsp_media_stream_rtp (mstream, buffer); - handled = TRUE; + gst_rtsp_media_stream_rtp (mstream, buffer); + handled = TRUE; break; } else if (tr->interleaved.max == channel) { - gst_rtsp_media_stream_rtcp (mstream, buffer); - handled = TRUE; + gst_rtsp_media_stream_rtcp (mstream, buffer); + handled = TRUE; break; } } @@ -1097,7 +1128,8 @@ handle_data (GstRTSPClient *client, GstRTSPMessage *message) * that created the client but can be overridden later. */ void -gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool) +gst_rtsp_client_set_session_pool (GstRTSPClient * client, + GstRTSPSessionPool * pool) { GstRTSPSessionPool *old; @@ -1120,7 +1152,7 @@ gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *poo * Returns: a #GstRTSPSessionPool, unref after usage. */ GstRTSPSessionPool * -gst_rtsp_client_get_session_pool (GstRTSPClient *client) +gst_rtsp_client_get_session_pool (GstRTSPClient * client) { GstRTSPSessionPool *result; @@ -1140,7 +1172,8 @@ gst_rtsp_client_get_session_pool (GstRTSPClient *client) * created the client but can be overriden later. */ void -gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *mapping) +gst_rtsp_client_set_media_mapping (GstRTSPClient * client, + GstRTSPMediaMapping * mapping) { GstRTSPMediaMapping *old; @@ -1164,7 +1197,7 @@ gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *m * Returns: a #GstRTSPMediaMapping, unref after usage. */ GstRTSPMediaMapping * -gst_rtsp_client_get_media_mapping (GstRTSPClient *client) +gst_rtsp_client_get_media_mapping (GstRTSPClient * client) { GstRTSPMediaMapping *result; @@ -1175,7 +1208,8 @@ gst_rtsp_client_get_media_mapping (GstRTSPClient *client) } static GstRTSPResult -message_received (GstRTSPWatch *watch, GstRTSPMessage *message, gpointer user_data) +message_received (GstRTSPWatch * watch, GstRTSPMessage * message, + gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); @@ -1195,7 +1229,7 @@ message_received (GstRTSPWatch *watch, GstRTSPMessage *message, gpointer user_da } static GstRTSPResult -message_sent (GstRTSPWatch *watch, guint cseq, gpointer user_data) +message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); @@ -1205,7 +1239,7 @@ message_sent (GstRTSPWatch *watch, guint cseq, gpointer user_data) } static GstRTSPResult -closed (GstRTSPWatch *watch, gpointer user_data) +closed (GstRTSPWatch * watch, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); const gchar *tunnelid; @@ -1225,7 +1259,7 @@ closed (GstRTSPWatch *watch, gpointer user_data) } static GstRTSPResult -error (GstRTSPWatch *watch, GstRTSPResult result, gpointer user_data) +error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); gchar *str; @@ -1238,7 +1272,7 @@ error (GstRTSPWatch *watch, GstRTSPResult result, gpointer user_data) } static GstRTSPStatusCode -tunnel_start (GstRTSPWatch *watch, gpointer user_data) +tunnel_start (GstRTSPWatch * watch, gpointer user_data) { GstRTSPClient *client; const gchar *tunnelid; @@ -1272,7 +1306,7 @@ tunnel_existed: } static GstRTSPResult -tunnel_complete (GstRTSPWatch *watch, gpointer user_data) +tunnel_complete (GstRTSPWatch * watch, gpointer user_data) { const gchar *tunnelid; GstRTSPClient *client = GST_RTSP_CLIENT (user_data); @@ -1336,7 +1370,7 @@ static GstRTSPWatchFuncs watch_funcs = { * Returns: %TRUE if the client could be accepted. */ gboolean -gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel) +gst_rtsp_client_accept (GstRTSPClient * client, GIOChannel * channel) { int sock; GstRTSPConnection *conn; @@ -1351,14 +1385,13 @@ gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel) GST_RTSP_CHECK (gst_rtsp_connection_accept (sock, &conn), accept_failed); url = gst_rtsp_connection_get_url (conn); - g_message ("added new client %p ip %s:%d", client, - url->host, url->port); + g_message ("added new client %p ip %s:%d", client, url->host, url->port); client->connection = conn; /* create watch for the connection and attach */ client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs, - g_object_ref (client), g_object_unref); + g_object_ref (client), g_object_unref); /* find the context to add the watch */ if ((source = g_main_current_source ())) @@ -1378,8 +1411,7 @@ accept_failed: { gchar *str = gst_rtsp_strresult (res); - g_error ("Could not accept client on server socket %d: %s", - sock, str); + g_error ("Could not accept client on server socket %d: %s", sock, str); g_free (str); return FALSE; } diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d07b380112..fe322bc562 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -17,6 +17,8 @@ * Boston, MA 02111-1307, USA. */ +#include + #include #include @@ -39,6 +41,8 @@ enum SIGNAL_LAST }; +static GQuark ssrc_stream_map_key; + static void gst_rtsp_media_get_property (GObject *object, guint propid, GValue *value, GParamSpec *pspec); static void gst_rtsp_media_set_property (GObject *object, guint propid, @@ -87,6 +91,8 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) g_critical ("could not start bus thread: %s", error->message); } klass->handle_message = default_handle_message; + + ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); } static void @@ -106,6 +112,8 @@ gst_rtsp_media_stream_free (GstRTSPMediaStream *stream) if (stream->caps) gst_caps_unref (stream->caps); + g_list_free (stream->transports); + g_free (stream); } @@ -700,48 +708,112 @@ dump_structure (const GstStructure *s) g_free (sstr); } -static void -on_new_ssrc (GObject *session, GObject *source, GstRTSPMedia *media) +static GstRTSPMediaTrans * +find_transport (GstRTSPMediaStream *stream, const gchar *rtcp_from) { - g_message ("%p: new source %p", media, source); + GList *walk; + GstRTSPMediaTrans *result = NULL; + const gchar *dest; + guint port; + + if (rtcp_from == NULL) + return NULL; + + dest = g_strrstr (rtcp_from, ":"); + if (dest == NULL) + return NULL; + + port = atoi (dest + 1); + dest = g_strndup (rtcp_from, dest - rtcp_from); + + g_message ("finding %s:%d", dest, port); + + for (walk = stream->transports; walk; walk = g_list_next (walk)) { + GstRTSPMediaTrans *trans = walk->data; + gint min, max; + + min = trans->transport->client_port.min; + max = trans->transport->client_port.max; + + if ((strcmp (trans->transport->destination, dest) == 0) && (min == port || max == port)) { + result = trans; + break; + } + } + return result; } static void -on_ssrc_sdes (GObject *session, GObject *source, GstRTSPMedia *media) +on_new_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) +{ + GstStructure *stats; + GstRTSPMediaTrans *trans; + + g_message ("%p: new source %p", stream, source); + + /* see if we have a stream to match with the origin of the RTCP packet */ + trans = g_object_get_qdata (source, ssrc_stream_map_key); + if (trans == NULL) { + g_object_get (source, "stats", &stats, NULL); + if (stats) { + const gchar *rtcp_from; + + rtcp_from = gst_structure_get_string (stats, "rtcp-from"); + if ((trans = find_transport (stream, rtcp_from))) { + g_message ("%p: found transport %p for source %p", stream, trans, source); + g_object_set_qdata (source, ssrc_stream_map_key, trans); + } + } + } else { + g_message ("%p: source %p for transport %p", stream, source, trans); + } +} + +static void +on_ssrc_sdes (GObject *session, GObject *source, GstRTSPMediaStream *stream) { GstStructure *sdes; - g_message ("%p: new SDES %p", media, source); + g_message ("%p: new SDES %p", stream, source); g_object_get (source, "sdes", &sdes, NULL); dump_structure (sdes); } static void -on_ssrc_active (GObject *session, GObject *source, GstRTSPMedia *media) +on_ssrc_active (GObject *session, GObject *source, GstRTSPMediaStream *stream) { GstStructure *stats; + GstRTSPMediaTrans *trans; + + trans = g_object_get_qdata (source, ssrc_stream_map_key); + + g_message ("%p: source %p in transport %p is active", stream, trans, source); + + if (trans && trans->keep_alive) { + trans->keep_alive (trans->ka_user_data); + } - g_message ("%p: source %p is active", media, source); g_object_get (source, "stats", &stats, NULL); dump_structure (stats); + gst_structure_free (stats); } static void -on_bye_ssrc (GObject *session, GObject *source, GstRTSPMedia *media) +on_bye_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) { - g_message ("%p: source %p bye", media, source); + g_message ("%p: source %p bye", stream, source); } static void -on_bye_timeout (GObject *session, GObject *source, GstRTSPMedia *media) +on_bye_timeout (GObject *session, GObject *source, GstRTSPMediaStream *stream) { - g_message ("%p: source %p bye timeout", media, source); + g_message ("%p: source %p bye timeout", stream, source); } static void -on_timeout (GObject *session, GObject *source, GstRTSPMedia *media) +on_timeout (GObject *session, GObject *source, GstRTSPMediaStream *stream) { - g_message ("%p: source %p timeout", media, source); + g_message ("%p: source %p timeout", stream, source); } static GstFlowReturn @@ -836,17 +908,17 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) &stream->session); g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc, - media); + stream); g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes, - media); + stream); g_signal_connect (stream->session, "on-ssrc-active", (GCallback) on_ssrc_active, - media); + stream); g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, - media); + stream); g_signal_connect (stream->session, "on-bye-timeout", (GCallback) on_bye_timeout, - media); + stream); g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout, - media); + stream); /* link the RTP pad to the session manager */ ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink); @@ -1361,12 +1433,14 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport g_message ("adding %s:%d-%d", dest, min, max); g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); + stream->transports = g_list_prepend (stream->transports, tr); tr->active = TRUE; media->active++; } else if (remove && tr->active) { g_message ("removing %s:%d-%d", dest, min, max); g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); + stream->transports = g_list_remove (stream->transports, tr); tr->active = FALSE; media->active--; } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index d41075fd7c..eb513e3183 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -41,7 +41,8 @@ typedef struct _GstRTSPMedia GstRTSPMedia; typedef struct _GstRTSPMediaClass GstRTSPMediaClass; typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans; -typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); +typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); +typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); /** * GstRTSPMediaTrans: @@ -50,20 +51,33 @@ typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer * @send_rtcp: callback for sending RTCP messages * @user_data: user data passed in the callbacks * @notify: free function for the user_data. + * @keep_alive: keep alive callback + * @ka_user_data: data passed to @keep_alive + * @ka_notify: called when @ka_user_data is freed + * @active: if we are actively sending + * @timeout: if we timed out * @transport: a transport description + * @rtpsource: the receiver rtp source object * * A Transport description for stream @idx */ struct _GstRTSPMediaTrans { guint idx; - GstRTSPSendFunc send_rtp; - GstRTSPSendFunc send_rtcp; - gpointer user_data; - GDestroyNotify notify; - gboolean active; + GstRTSPSendFunc send_rtp; + GstRTSPSendFunc send_rtcp; + gpointer user_data; + GDestroyNotify notify; - GstRTSPTransport *transport; + GstRTSPKeepAliveFunc keep_alive; + gpointer ka_user_data; + GDestroyNotify ka_notify; + gboolean active; + gboolean timeout; + + GstRTSPTransport *transport; + + GObject *rtpsource; }; /** diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 54a3700448..3afd7886fc 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -74,6 +74,10 @@ gst_rtsp_session_free_stream (GstRTSPSessionStream *stream) { g_message ("free session stream %p", stream); + /* remove callbacks now */ + gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); + gst_rtsp_session_stream_set_keepalive (stream, NULL, NULL, NULL); + if (stream->trans.transport) gst_rtsp_transport_free (stream->trans.transport); @@ -308,7 +312,7 @@ gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, guint idx) result->trans.transport = NULL; result->media_stream = media_stream; - g_array_insert_val (media->streams, idx, result); + g_array_index (media->streams, GstRTSPSessionStream *, idx) = result; } return result; @@ -512,6 +516,27 @@ gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream *stream, stream->trans.notify = notify; } +/** + * gst_rtsp_session_stream_set_keepalive: + * @stream: a #GstRTSPSessionStream + * @keep_alive: a callback called when the receiver is active + * @user_data: user data passed to callback + * @notify: called with the user_data when no longer needed. + * + * Install callbacks that will be called when RTCP packets are received from the + * receiver of @stream. + */ +void +gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream *stream, + GstRTSPKeepAliveFunc keep_alive, gpointer user_data, GDestroyNotify notify) +{ + stream->trans.keep_alive = keep_alive; + if (stream->trans.ka_notify) + stream->trans.ka_notify (stream->trans.ka_user_data); + stream->trans.ka_user_data = user_data; + stream->trans.ka_notify = notify; +} + /** * gst_rtsp_session_media_set_state: * @media: a #GstRTSPSessionMedia diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 495bc75989..0074b559ef 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -146,6 +146,10 @@ void gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStre GstRTSPSendFunc send_rtcp, gpointer user_data, GDestroyNotify notify); +void gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream *stream, + GstRTSPKeepAliveFunc keep_alive, + gpointer user_data, + GDestroyNotify notify); G_END_DECLS From 1340e21239237dfeab8cb19b5dab678d41a13eab Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 26 May 2009 19:05:07 +0200 Subject: [PATCH 0119/1776] media: don't leak the destination address --- gst/rtsp-server/rtsp-media.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index fe322bc562..82a5fd82fa 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -713,18 +713,19 @@ find_transport (GstRTSPMediaStream *stream, const gchar *rtcp_from) { GList *walk; GstRTSPMediaTrans *result = NULL; - const gchar *dest; + const gchar *tmp; + gchar *dest; guint port; if (rtcp_from == NULL) return NULL; - dest = g_strrstr (rtcp_from, ":"); - if (dest == NULL) + tmp = g_strrstr (rtcp_from, ":"); + if (tmp == NULL) return NULL; - port = atoi (dest + 1); - dest = g_strndup (rtcp_from, dest - rtcp_from); + port = atoi (tmp + 1); + dest = g_strndup (rtcp_from, tmp - rtcp_from); g_message ("finding %s:%d", dest, port); @@ -740,6 +741,8 @@ find_transport (GstRTSPMediaStream *stream, const gchar *rtcp_from) break; } } + g_free (dest); + return result; } From 3fc143996506a02355d313486ad4cf7857f590ff Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 26 May 2009 19:20:07 +0200 Subject: [PATCH 0120/1776] media: be less verbose and leak less --- gst/rtsp-server/rtsp-media.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 82a5fd82fa..db6f23f613 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -761,11 +761,18 @@ on_new_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) if (stats) { const gchar *rtcp_from; + dump_structure (stats); + rtcp_from = gst_structure_get_string (stats, "rtcp-from"); if ((trans = find_transport (stream, rtcp_from))) { g_message ("%p: found transport %p for source %p", stream, trans, source); + + /* keep ref to the source */ + trans->rtpsource = source; + g_object_set_qdata (source, ssrc_stream_map_key, trans); } + gst_structure_free (stats); } } else { g_message ("%p: source %p for transport %p", stream, source, trans); @@ -775,30 +782,20 @@ on_new_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) static void on_ssrc_sdes (GObject *session, GObject *source, GstRTSPMediaStream *stream) { - GstStructure *sdes; - g_message ("%p: new SDES %p", stream, source); - g_object_get (source, "sdes", &sdes, NULL); - dump_structure (sdes); } static void on_ssrc_active (GObject *session, GObject *source, GstRTSPMediaStream *stream) { - GstStructure *stats; GstRTSPMediaTrans *trans; trans = g_object_get_qdata (source, ssrc_stream_map_key); g_message ("%p: source %p in transport %p is active", stream, trans, source); - if (trans && trans->keep_alive) { + if (trans && trans->keep_alive) trans->keep_alive (trans->ka_user_data); - } - - g_object_get (source, "stats", &stats, NULL); - dump_structure (stats); - gst_structure_free (stats); } static void @@ -810,13 +807,27 @@ on_bye_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) static void on_bye_timeout (GObject *session, GObject *source, GstRTSPMediaStream *stream) { + GstRTSPMediaTrans *trans; + g_message ("%p: source %p bye timeout", stream, source); + + if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) { + trans->rtpsource = NULL; + trans->timeout = TRUE; + } } static void on_timeout (GObject *session, GObject *source, GstRTSPMediaStream *stream) { + GstRTSPMediaTrans *trans; + g_message ("%p: source %p timeout", stream, source); + + if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) { + trans->rtpsource = NULL; + trans->timeout = TRUE; + } } static GstFlowReturn From 03ae66062ba936ac8e83a3ab5fa906c221639212 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 27 May 2009 11:15:22 +0200 Subject: [PATCH 0121/1776] media: fix message Fix a debug message Make dumping RTCP stats configurable --- gst/rtsp-server/rtsp-media.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index db6f23f613..3328b2752e 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -27,6 +27,9 @@ #define DEFAULT_SHARED FALSE #define DEFAULT_REUSABLE FALSE +/* define to dump received RTCP packets */ +#undef DUMP_STATS + enum { PROP_0, @@ -792,10 +795,21 @@ on_ssrc_active (GObject *session, GObject *source, GstRTSPMediaStream *stream) trans = g_object_get_qdata (source, ssrc_stream_map_key); - g_message ("%p: source %p in transport %p is active", stream, trans, source); + g_message ("%p: source %p in transport %p is active", stream, source, trans); if (trans && trans->keep_alive) trans->keep_alive (trans->ka_user_data); + +#ifdef DUMP_STATS + { + GstStructure *stats; + g_object_get (source, "stats", &stats, NULL); + if (stats) { + dump_structure (stats); + gst_structure_free (stats); + } + } +#endif } static void From 0ea3214326e967a641c4eed8a7eed3abcdab278e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Sat, 30 May 2009 14:38:34 +0200 Subject: [PATCH 0122/1776] vala: Fixed typo in header file of RTSPMediaStream --- bindings/vala/gst-rtsp-server-0.10.vapi | 2 +- bindings/vala/packages/gst-rtsp-server-0.10.metadata | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/vala/gst-rtsp-server-0.10.vapi b/bindings/vala/gst-rtsp-server-0.10.vapi index fd4bc9a488..df2e3a1d68 100644 --- a/bindings/vala/gst-rtsp-server-0.10.vapi +++ b/bindings/vala/gst-rtsp-server-0.10.vapi @@ -91,7 +91,7 @@ namespace Gst { public void remove_factory (string path); } [Compact] - [CCode (cheader_filename = "gst/rtsp-server/rstp-media.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] public class RTSPMediaStream { [CCode (array_length = false)] public weak Gst.Element[] appsink; diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.metadata b/bindings/vala/packages/gst-rtsp-server-0.10.metadata index ba417e58c9..ba1409d1aa 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.metadata +++ b/bindings/vala/packages/gst-rtsp-server-0.10.metadata @@ -3,7 +3,7 @@ GstRTSPClient cheader_filename="gst/rtsp-server/rtsp-client.h" GstRTSPMedia cheader_filename="gst/rtsp-server/rtsp-media.h" GstRTSPMediaFactory cheader_filename="gst/rtsp-server/rtsp-media-factory.h" GstRTSPMediaMapping cheader_filename="gst/rtsp-server/rtsp-media-mapping.h" -GstRTSPMediaStream cheader_filename="gst/rtsp-server/rstp-media.h" +GstRTSPMediaStream cheader_filename="gst/rtsp-server/rtsp-media.h" GstRTSPServer cheader_filename="gst/rtsp-server/rtsp-server.h" GstRTSPSession cheader_filename="gst/rtsp-server/rtsp-session.h" GstRTSPSessionMedia cheader_filename="gst/rtsp-server/rtsp-session.h" From e1765dec134d35bd67cfeaab9b1f4479b208b880 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 3 Jun 2009 12:13:21 +0200 Subject: [PATCH 0123/1776] sdp: warn and skip streams without media --- gst/rtsp-server/rtsp-sdp.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 3e6c27136e..264168a922 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -63,9 +63,19 @@ gst_rtsp_sdp_from_media (GstRTSPMedia *media) GString *fmtp; stream = gst_rtsp_media_get_stream (media, i); - gst_sdp_media_new (&smedia); + + if (stream->caps == NULL) { + g_warning ("ignoring stream %d without media type", i); + continue; + } s = gst_caps_get_structure (stream->caps, 0); + if (s == NULL) { + g_warning ("ignoring stream %d without media type", i); + continue; + } + + gst_sdp_media_new (&smedia); /* get media type and payload for the m= line */ caps_str = gst_structure_get_string (s, "media"); From 9a38f95417d98fb27e512b257802c1a9d6be0a6f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 4 Jun 2009 18:32:15 +0200 Subject: [PATCH 0124/1776] media: clean up the messages a bit --- gst/rtsp-server/rtsp-media.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 3328b2752e..129c1f3297 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -697,7 +697,7 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) gst_caps_unref (oldcaps); capsstr = gst_caps_to_string (newcaps); - g_message ("stream %p received caps %s", stream, capsstr); + g_message ("stream %p received caps %p, %s", stream, newcaps, capsstr); g_free (capsstr); } @@ -1152,9 +1152,9 @@ default_handle_message (GstRTSPMedia *media, GstMessage *message) break; } case GST_MESSAGE_ELEMENT: - { break; - } + case GST_MESSAGE_STREAM_STATUS: + break; default: g_message ("%p: got message type %s", media, gst_message_type_get_name (type)); break; From 94b6da045ae61a1e90a07b31390587acff8138ee Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 4 Jun 2009 19:20:26 +0200 Subject: [PATCH 0125/1776] media: don't leak session pads --- gst/rtsp-server/rtsp-media.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 129c1f3297..49e3bca8f5 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -115,6 +115,17 @@ gst_rtsp_media_stream_free (GstRTSPMediaStream *stream) if (stream->caps) gst_caps_unref (stream->caps); + if (stream->send_rtp_sink) + gst_object_unref (stream->send_rtp_sink); + if (stream->send_rtp_src) + gst_object_unref (stream->send_rtp_src); + if (stream->send_rtcp_src) + gst_object_unref (stream->send_rtcp_src); + if (stream->recv_rtcp_sink) + gst_object_unref (stream->recv_rtcp_sink); + if (stream->recv_rtp_sink) + gst_object_unref (stream->recv_rtp_sink); + g_list_free (stream->transports); g_free (stream); From 5e4757eff68aa42b354b62a513f367c635812c21 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Jun 2009 00:01:07 +0200 Subject: [PATCH 0126/1776] rtsp: prepare for handling GET/SET_PARAMETER Add helper functions to handle GET/SET_PARAMETER. Reply with an error when there is a body now. Fix return codes of handlers. --- gst/rtsp-server/Makefile.am | 2 + gst/rtsp-server/rtsp-client.c | 86 +++++++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-params.c | 55 ++++++++++++++++++++++ gst/rtsp-server/rtsp-params.h | 43 ++++++++++++++++++ 4 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 gst/rtsp-server/rtsp-params.c create mode 100644 gst/rtsp-server/rtsp-params.h diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index eced5819d9..1b33fc3b9b 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -4,6 +4,7 @@ public_headers = \ rtsp-media.h \ rtsp-media-factory.h \ rtsp-media-mapping.h \ + rtsp-params.h \ rtsp-sdp.h \ rtsp-session-pool.h \ rtsp-session.h @@ -14,6 +15,7 @@ c_sources = \ rtsp-media.c \ rtsp-media-factory.c \ rtsp-media-mapping.c \ + rtsp-params.c \ rtsp-sdp.c \ rtsp-session-pool.c \ rtsp-session.c diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index aeaf52aa26..4d245b72e4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -21,6 +21,7 @@ #include "rtsp-client.h" #include "rtsp-sdp.h" +#include "rtsp-params.h" #define DEBUG @@ -396,7 +397,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPUrl * uri, send_response (client, session, &response); - return FALSE; + return TRUE; /* ERRORS */ no_session: @@ -411,6 +412,77 @@ not_found: } } +static gboolean +handle_get_param_request (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request) +{ + GstRTSPResult res; + guint8 *data; + guint size; + + res = gst_rtsp_message_get_body (request, &data, &size); + if (res != GST_RTSP_OK) + goto bad_request; + + if (size == 0) { + /* no body, keep-alive request */ + send_generic_response (client, GST_RTSP_STS_OK, request); + } else { + /* there is a body */ + GstRTSPMessage response = { 0 }; + + /* there is a body, handle the params */ + res = gst_rtsp_params_get (client, uri, session, request, &response); + if (res != GST_RTSP_OK) + goto bad_request; + + send_response (client, session, &response); + } + return TRUE; + + /* ERRORS */ +bad_request: + { + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); + return FALSE; + } +} + +static gboolean +handle_set_param_request (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request) +{ + GstRTSPResult res; + guint8 *data; + guint size; + + res = gst_rtsp_message_get_body (request, &data, &size); + if (res != GST_RTSP_OK) + goto bad_request; + + if (size == 0) { + /* no body, keep-alive request */ + send_generic_response (client, GST_RTSP_STS_OK, request); + } else { + GstRTSPMessage response = { 0 }; + + /* there is a body, handle the params */ + res = gst_rtsp_params_set (client, uri, session, request, &response); + if (res != GST_RTSP_OK) + goto bad_request; + + send_response (client, session, &response); + } + return TRUE; + + /* ERRORS */ +bad_request: + { + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); + return FALSE; + } +} + static gboolean handle_pause_request (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request) @@ -448,7 +520,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPUrl * uri, /* the state is now READY */ media->state = GST_RTSP_STATE_READY; - return FALSE; + return TRUE; /* ERRORS */ no_session: @@ -581,7 +653,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPUrl * uri, media->state = GST_RTSP_STATE_PLAYING; - return FALSE; + return TRUE; /* ERRORS */ no_session: @@ -876,7 +948,7 @@ no_sdp: } } -static void +static gboolean handle_options_request (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request) { @@ -900,6 +972,8 @@ handle_options_request (GstRTSPClient * client, GstRTSPUrl * uri, g_free (str); send_response (client, session, &response); + + return TRUE; } /* remove duplicate and trailing '/' */ @@ -1031,8 +1105,10 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) handle_teardown_request (client, uri, session, request); break; case GST_RTSP_SET_PARAMETER: + handle_set_param_request (client, uri, session, request); + break; case GST_RTSP_GET_PARAMETER: - send_generic_response (client, GST_RTSP_STS_OK, request); + handle_get_param_request (client, uri, session, request); break; case GST_RTSP_ANNOUNCE: case GST_RTSP_RECORD: diff --git a/gst/rtsp-server/rtsp-params.c b/gst/rtsp-server/rtsp-params.c new file mode 100644 index 0000000000..079f714095 --- /dev/null +++ b/gst/rtsp-server/rtsp-params.c @@ -0,0 +1,55 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include + +#include "rtsp-params.h" + +GstRTSPResult +gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request, + GstRTSPMessage * response) +{ + GstRTSPStatusCode code; + + /* FIXME, actually parse the request based on the mime type and try to repond + * with a list of the parameters */ + code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD; + + gst_rtsp_message_init_response (response, code, + gst_rtsp_status_as_text (code), request); + + return GST_RTSP_OK; +} + +GstRTSPResult +gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request, + GstRTSPMessage * response) +{ + GstRTSPStatusCode code; + + /* FIXME, actually parse the request based on the mime type and try to repond + * with a list of the parameters */ + code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD; + + gst_rtsp_message_init_response (response, code, + gst_rtsp_status_as_text (code), request); + + return GST_RTSP_OK; +} diff --git a/gst/rtsp-server/rtsp-params.h b/gst/rtsp-server/rtsp-params.h new file mode 100644 index 0000000000..46903831a3 --- /dev/null +++ b/gst/rtsp-server/rtsp-params.h @@ -0,0 +1,43 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include +#include + +#ifndef __GST_RTSP_PARAMS_H__ +#define __GST_RTSP_PARAMS_H__ + +#include "rtsp-client.h" +#include "rtsp-session.h" + +G_BEGIN_DECLS + +GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request, + GstRTSPMessage * response); + +GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request, + GstRTSPMessage * response); + +G_END_DECLS + +#endif /* __GST_RTSP_PARAMS_H__ */ From a697d16c75ffc24077f0f8e9f05847011c852cf7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 11 Jun 2009 11:27:47 +0200 Subject: [PATCH 0127/1776] client: use g_source_destroy() We need to use g_source_destroy() because we might have added the source to a different main context than the default one. --- gst/rtsp-server/rtsp-client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4d245b72e4..e12d425603 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1411,7 +1411,8 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) g_object_unref (oclient); /* we don't need this watch anymore */ - g_source_remove (client->watchid); + g_source_destroy ((GSource *) client->watch); + client->watchid = 0; return GST_RTSP_OK; From e417d83dceea9db2cafbdfc788300ff3bf7106d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Fri, 12 Jun 2009 17:45:29 +0200 Subject: [PATCH 0128/1776] Added vmethod create_pipeline to GstRTSPMediaFactory The pipeline is created in this method and the GstRTSPMedia's element is added to it --- gst/rtsp-server/rtsp-media-factory.c | 22 ++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 3 +++ gst/rtsp-server/rtsp-media.c | 3 --- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 2a5833d8ff..fea0690ad3 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -40,6 +40,7 @@ static gchar * default_gen_key (GstRTSPMediaFactory *factory, const GstRTSPUrl * static GstElement * default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); static GstRTSPMedia * default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); static void default_configure (GstRTSPMediaFactory *factory, GstRTSPMedia *media); +static GstElement* default_create_pipeline (GstRTSPMediaFactory *factory, GstRTSPMedia *media); G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT); @@ -79,6 +80,7 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) klass->get_element = default_get_element; klass->construct = default_construct; klass->configure = default_configure; + klass->create_pipeline = default_create_pipeline; } static void @@ -471,6 +473,11 @@ default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) media = gst_rtsp_media_new (); media->element = element; + if (!klass->create_pipeline) + goto no_pipeline; + + media->pipeline = klass->create_pipeline (factory, media); + collect_streams (factory, url, media); return media; @@ -481,6 +488,21 @@ no_element: g_critical ("could not create element"); return NULL; } +no_pipeline: + { + g_critical ("could not create pipeline"); + return FALSE; + } +} + +static GstElement* +default_create_pipeline (GstRTSPMediaFactory *factory, GstRTSPMedia *media) { + GstElement *pipeline; + + pipeline = gst_pipeline_new ("media-pipeline"); + gst_bin_add (GST_BIN_CAST (pipeline), media->element); + + return pipeline; } static void diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index ef3f6e8103..9ba51eb8f8 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -77,6 +77,8 @@ struct _GstRTSPMediaFactory { * pay%d to create the streams. * @configure: configure the media created with @construct. The default * implementation will configure the 'shared' property of the media. + * @create_pipeline: create a new pipeline or re-use an existing one and + * add the #GstRTSPMedia's element created by @construct to the pipeline. * * The #GstRTSPMediaFactory class structure. */ @@ -88,6 +90,7 @@ struct _GstRTSPMediaFactoryClass { GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); + GstElement * (*create_pipeline)(GstRTSPMediaFactory *factory, GstRTSPMedia *media); }; GType gst_rtsp_media_factory_get_type (void); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 49e3bca8f5..cbd4e8b53b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1268,7 +1268,6 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) g_message ("preparing media %p", media); - media->pipeline = gst_pipeline_new ("media-pipeline"); bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline)); /* add the pipeline bus to our custom mainloop */ @@ -1280,8 +1279,6 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) klass = GST_RTSP_MEDIA_GET_CLASS (media); media->id = g_source_attach (media->source, klass->context); - gst_bin_add (GST_BIN_CAST (media->pipeline), media->element); - media->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin"); /* add stuff to the bin */ From 045875ecbe07498eafad6c9d5e2599c931989559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Fri, 12 Jun 2009 17:51:44 +0200 Subject: [PATCH 0129/1776] Made collect_streams function public --- gst/rtsp-server/rtsp-media-factory.c | 6 +++--- gst/rtsp-server/rtsp-media-factory.h | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index fea0690ad3..2110ea953a 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -400,8 +400,8 @@ parse_error: /* try to find all the payloader elements, they should be named 'pay%d'. for * each of the payloaders we will create a stream and collect the source pad. */ -static void -collect_streams (GstRTSPMediaFactory *factory, const GstRTSPUrl *url, +void +gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory *factory, const GstRTSPUrl *url, GstRTSPMedia *media) { GstElement *element, *elem; @@ -478,7 +478,7 @@ default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) media->pipeline = klass->create_pipeline (factory, media); - collect_streams (factory, url, media); + gst_rtsp_media_factory_collect_streams (factory, url, media); return media; diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 9ba51eb8f8..3d1ac9b7e7 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -111,6 +111,10 @@ gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); +void gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory *factory, + const GstRTSPUrl *url, + GstRTSPMedia *media); + G_END_DECLS #endif /* __GST_RTSP_MEDIA_FACTORY_H__ */ From 749765b9211d1a97e73af5924ceafb8d400246b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Fri, 12 Jun 2009 18:05:30 +0200 Subject: [PATCH 0130/1776] Added vmethod unprepare to GstRTSPMedia The default implementation sets the state of the pipeline to GST_STATE_NULL --- gst/rtsp-server/rtsp-media.c | 18 +++++++++++++++++- gst/rtsp-server/rtsp-media.h | 3 +++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index cbd4e8b53b..fdf4a7bee9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -54,6 +54,7 @@ static void gst_rtsp_media_finalize (GObject * obj); static gpointer do_loop (GstRTSPMediaClass *klass); static gboolean default_handle_message (GstRTSPMedia *media, GstMessage *message); +static gboolean default_unprepare (GstRTSPMedia *media); static void unlock_streams (GstRTSPMedia *media); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; @@ -94,6 +95,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) g_critical ("could not start bus thread: %s", error->message); } klass->handle_message = default_handle_message; + klass->unprepare = default_unprepare; ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); } @@ -1373,12 +1375,20 @@ is_reused: gboolean gst_rtsp_media_unprepare (GstRTSPMedia *media) { + GstRTSPMediaClass *klass; + gboolean success; + if (!media->prepared) return TRUE; g_message ("unprepare media %p", media); media->target_state = GST_STATE_NULL; - gst_element_set_state (media->pipeline, GST_STATE_NULL); + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + if (klass->unprepare) + success = klass->unprepare (media); + else + success = TRUE; media->prepared = FALSE; media->reused = TRUE; @@ -1387,6 +1397,12 @@ gst_rtsp_media_unprepare (GstRTSPMedia *media) * recreate it */ g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL); + return success; +} + +static gboolean +default_unprepare (GstRTSPMedia *media) { + gst_element_set_state (media->pipeline, GST_STATE_NULL); return TRUE; } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index eb513e3183..b8b7b19dec 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -196,6 +196,8 @@ struct _GstRTSPMedia { * @loop: the mainloop for message. * @thread: the thread dispatching messages. * @handle_message: handle a message + * @unprepare: the default implementation sets the pipeline's state + * to GST_STATE_NULL. * * The RTSP media class */ @@ -209,6 +211,7 @@ struct _GstRTSPMediaClass { /* vmethods */ gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message); + gboolean (*unprepare) (GstRTSPMedia *media); /* signals */ gboolean (*unprepared) (GstRTSPMedia *media); From 833a3d467c7bfea9a8a3ff5b7742b588f82471ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Fri, 12 Jun 2009 19:28:04 +0200 Subject: [PATCH 0131/1776] Updated Vala bindings --- bindings/vala/gst-rtsp-server-0.10.vapi | 33 +++++++-- .../vala/packages/gst-rtsp-server-0.10.gi | 67 +++++++++++++++++++ .../packages/gst-rtsp-server-0.10.metadata | 6 ++ 3 files changed, 101 insertions(+), 5 deletions(-) diff --git a/bindings/vala/gst-rtsp-server-0.10.vapi b/bindings/vala/gst-rtsp-server-0.10.vapi index df2e3a1d68..fff8c6a25b 100644 --- a/bindings/vala/gst-rtsp-server-0.10.vapi +++ b/bindings/vala/gst-rtsp-server-0.10.vapi @@ -25,7 +25,9 @@ namespace Gst { public class RTSPMedia : GLib.Object { public int active; public bool buffering; + public weak GLib.List @dynamic; public weak Gst.Element element; + public weak Gst.Element fakesink; public uint id; public bool is_live; public weak Gst.Element pipeline; @@ -50,7 +52,7 @@ namespace Gst { public void set_reusable (bool reusable); public void set_shared (bool shared); public bool set_state (Gst.State state, GLib.Array trans); - public bool unprepare (); + public virtual bool unprepare (); [NoAccessorMethod] public bool reusable { get; set; } [NoAccessorMethod] @@ -62,10 +64,13 @@ namespace Gst { public weak GLib.Mutex @lock; public weak GLib.HashTable medias; public weak GLib.Mutex medias_lock; + public void collect_streams (Gst.RTSPUrl url, Gst.RTSPMedia media); [NoWrapper] public virtual void configure (Gst.RTSPMedia media); public virtual Gst.RTSPMedia? @construct (Gst.RTSPUrl url); [NoWrapper] + public virtual Gst.Element create_pipeline (Gst.RTSPMedia media); + [NoWrapper] public virtual string gen_key (Gst.RTSPUrl url); [NoWrapper] public virtual Gst.Element? get_element (Gst.RTSPUrl url); @@ -102,12 +107,17 @@ namespace Gst { public weak Gst.Element payloader; public bool prepared; public weak Gst.Pad recv_rtcp_sink; + public weak Gst.Pad recv_rtp_sink; + [CCode (array_length = false)] + public weak Gst.Element[] selector; public weak Gst.Pad send_rtcp_src; public weak Gst.Pad send_rtp_sink; public weak Gst.Pad send_rtp_src; public weak Gst.RTSPRange server_port; public weak GLib.Object session; public weak Gst.Pad srcpad; + [CCode (array_length = false)] + public weak Gst.Element[] tee; public weak GLib.List transports; [CCode (array_length = false)] public weak Gst.Element[] udpsink; @@ -117,12 +127,18 @@ namespace Gst { public Gst.FlowReturn rtp (Gst.Buffer buffer); } [Compact] - [CCode (cheader_filename = "gst/gst.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] public class RTSPMediaTrans { + public bool active; public uint idx; + public weak GLib.DestroyNotify ka_notify; + public void* ka_user_data; + public weak Gst.RTSPKeepAliveFunc keep_alive; public weak GLib.DestroyNotify notify; + public weak GLib.Object rtpsource; public weak Gst.RTSPSendFunc send_rtcp; public weak Gst.RTSPSendFunc send_rtp; + public bool timeout; public weak Gst.RTSPTransport transport; public void* user_data; } @@ -207,12 +223,19 @@ namespace Gst { public weak Gst.RTSPMediaStream media_stream; public weak Gst.RTSPMediaTrans trans; public void set_callbacks (Gst.RTSPSendFunc send_rtp, Gst.RTSPSendFunc send_rtcp, GLib.DestroyNotify notify); + public void set_keepalive (Gst.RTSPKeepAliveFunc keep_alive, GLib.DestroyNotify notify); public Gst.RTSPTransport set_transport (Gst.RTSPTransport ct); } - [CCode (cheader_filename = "gst/gst.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] + public delegate void RTSPKeepAliveFunc (); + [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] public delegate bool RTSPSendFunc (Gst.Buffer buffer, uchar channel); - [CCode (cheader_filename = "gst/gst.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-session-pool.h")] public delegate bool RTSPSessionPoolFunc (Gst.RTSPSessionPool pool); [CCode (cheader_filename = "gst/gst.h")] - public static Gst.SDPMessage rtsp_sdp_from_media (Gst.RTSPMedia media); + public static Gst.RTSPResult rtsp_params_get (Gst.RTSPClient client, Gst.RTSPUrl uri, Gst.RTSPSession session, Gst.RTSPMessage request, Gst.RTSPMessage response); + [CCode (cheader_filename = "gst/gst.h")] + public static Gst.RTSPResult rtsp_params_set (Gst.RTSPClient client, Gst.RTSPUrl uri, Gst.RTSPSession session, Gst.RTSPMessage request, Gst.RTSPMessage response); + [CCode (cheader_filename = "gst/rtsp-server/rtsp-sdp.h")] + public static unowned Gst.SDPMessage rtsp_sdp_from_media (Gst.RTSPMedia media); } diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.gi b/bindings/vala/packages/gst-rtsp-server-0.10.gi index 8a89bf0acc..3bac5531d2 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.gi +++ b/bindings/vala/packages/gst-rtsp-server-0.10.gi @@ -1,12 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -41,6 +67,7 @@ + @@ -49,6 +76,8 @@ + + @@ -60,7 +89,13 @@ + + + + + + @@ -93,6 +128,15 @@ + + + + + + + + + @@ -243,14 +287,22 @@ + + + + + + + + @@ -260,6 +312,14 @@ + + + + + + + + @@ -312,6 +372,13 @@ + + + + + + + diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.metadata b/bindings/vala/packages/gst-rtsp-server-0.10.metadata index ba1409d1aa..ed7fffe237 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.metadata +++ b/bindings/vala/packages/gst-rtsp-server-0.10.metadata @@ -1,6 +1,7 @@ Gst cprefix="Gst" lower_case_cprefix="gst_" cheader_filename="gst/gst.h" GstRTSPClient cheader_filename="gst/rtsp-server/rtsp-client.h" GstRTSPMedia cheader_filename="gst/rtsp-server/rtsp-media.h" +GstRTSPMediaTrans cheader_filename="gst/rtsp-server/rtsp-media.h" GstRTSPMediaFactory cheader_filename="gst/rtsp-server/rtsp-media-factory.h" GstRTSPMediaMapping cheader_filename="gst/rtsp-server/rtsp-media-mapping.h" GstRTSPMediaStream cheader_filename="gst/rtsp-server/rtsp-media.h" @@ -15,6 +16,7 @@ gst_rtsp_media_factory_get_launch transfer_ownership="1" gst_rtsp_media_factory_construct transfer_ownership="1" nullable="1" gst_rtsp_media_factory_gen_key transfer_ownership="1" gst_rtsp_media_factory_get_element transfer_ownership="1" nullable="1" +gst_rtsp_media_factory_create_pipeline transfer_ownership="1" gst_rtsp_media_mapping_find_factory transfer_ownership="1" nullable="1" gst_rtsp_media_mapping_find_media transfer_ownership="1" nullable="1" gst_rtsp_sdp_from_media transfer_ownership="1" @@ -30,3 +32,7 @@ gst_rtsp_session_pool_create_session_id transfer_ownership="1" gst_rtsp_session_pool_create_watch transfer_ownership="1" gst_rtsp_session_pool_find transfer_ownership="1" nullable="1" gst_rtsp_session_stream_set_transport transfer_ownership="1" +GstRTSPKeepAliveFunc cheader_filename="gst/rtsp-server/rtsp-media.h" +GstRTSPSendFunc cheader_filename="gst/rtsp-server/rtsp-media.h" +GstRTSPSessionPoolFunc cheader_filename="gst/rtsp-server/rtsp-session-pool.h" +gst_rtsp_sdp_from_media cheader_filename="gst/rtsp-server/rtsp-sdp.h" From 1a3e5b369ccb27635d152ee0ba6d5140a67c79de Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 12 Jun 2009 22:22:40 +0200 Subject: [PATCH 0132/1776] Don't use name for gstrtpbin so we can add multiple instances to the pipeline --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index fdf4a7bee9..3ee45b383d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1281,7 +1281,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) klass = GST_RTSP_MEDIA_GET_CLASS (media); media->id = g_source_attach (media->source, klass->context); - media->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin"); + media->rtpbin = gst_element_factory_make ("gstrtpbin", NULL); /* add stuff to the bin */ gst_bin_add (GST_BIN (media->pipeline), media->rtpbin); From 3bd2d36b1b1786595d37eb536aa14a9a5e5f4e7d Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 13 Jun 2009 14:38:20 +0200 Subject: [PATCH 0133/1776] Added gst_rtsp_media_remove_elements function --- gst/rtsp-server/rtsp-media.c | 54 ++++++++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-media.h | 2 ++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 3ee45b383d..3d0ef33438 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -142,13 +142,13 @@ gst_rtsp_media_finalize (GObject * obj) media = GST_RTSP_MEDIA (obj); g_message ("finalize media %p", media); - +/* if (media->pipeline) { unlock_streams (media); gst_element_set_state (media->pipeline, GST_STATE_NULL); gst_object_unref (media->pipeline); } - +*/ for (i = 0; i < media->streams->len; i++) { GstRTSPMediaStream *stream; @@ -1545,3 +1545,53 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport return TRUE; } +void +gst_rtsp_media_remove_elements (GstRTSPMedia *media) +{ + gint i; + + unlock_streams (media); + + for (i = 0; i < media->streams->len; i++) { + GstRTSPMediaStream *stream; + + g_message ("Removing elements of stream %d from pipeline", i); + + stream = g_array_index (media->streams, GstRTSPMediaStream *, i); + + gst_pad_unlink (stream->srcpad, stream->send_rtp_sink); + + gst_element_set_state (stream->udpsrc[0], GST_STATE_NULL); + gst_element_set_state (stream->udpsrc[1], GST_STATE_NULL); + gst_element_set_state (stream->udpsink[0], GST_STATE_NULL); + gst_element_set_state (stream->udpsink[1], GST_STATE_NULL); + gst_element_set_state (stream->appsrc[0], GST_STATE_NULL); + gst_element_set_state (stream->appsrc[1], GST_STATE_NULL); + gst_element_set_state (stream->appsink[0], GST_STATE_NULL); + gst_element_set_state (stream->appsink[1], GST_STATE_NULL); + gst_element_set_state (stream->tee[0], GST_STATE_NULL); + gst_element_set_state (stream->tee[1], GST_STATE_NULL); + gst_element_set_state (stream->selector[0], GST_STATE_NULL); + gst_element_set_state (stream->selector[1], GST_STATE_NULL); + + gst_bin_remove (GST_BIN (media->pipeline), stream->udpsrc[0]); + gst_bin_remove (GST_BIN (media->pipeline), stream->udpsrc[1]); + gst_bin_remove (GST_BIN (media->pipeline), stream->udpsink[0]); + gst_bin_remove (GST_BIN (media->pipeline), stream->udpsink[1]); + gst_bin_remove (GST_BIN (media->pipeline), stream->appsrc[0]); + gst_bin_remove (GST_BIN (media->pipeline), stream->appsrc[1]); + gst_bin_remove (GST_BIN (media->pipeline), stream->appsink[0]); + gst_bin_remove (GST_BIN (media->pipeline), stream->appsink[1]); + gst_bin_remove (GST_BIN (media->pipeline), stream->tee[0]); + gst_bin_remove (GST_BIN (media->pipeline), stream->tee[1]); + gst_bin_remove (GST_BIN (media->pipeline), stream->selector[0]); + gst_bin_remove (GST_BIN (media->pipeline), stream->selector[1]); + + gst_rtsp_media_stream_free (stream); + } + g_array_remove_range (media->streams, 0, media->streams->len); + + gst_element_set_state (media->rtpbin, GST_STATE_NULL); + gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin); +} + diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index b8b7b19dec..aa58aef970 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -244,6 +244,8 @@ GstFlowReturn gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *strea gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *trans); +void gst_rtsp_media_remove_elements (GstRTSPMedia *media); + G_END_DECLS #endif /* __GST_RTSP_MEDIA_H__ */ From 018563fdcc2bcd04aba18a01f6275d43148942c6 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 13 Jun 2009 14:38:39 +0200 Subject: [PATCH 0134/1776] Added gst_rtsp_media_remove_elements function to Vala bindings --- bindings/vala/gst-rtsp-server-0.10.vapi | 3 ++- bindings/vala/packages/gst-rtsp-server-0.10.gi | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bindings/vala/gst-rtsp-server-0.10.vapi b/bindings/vala/gst-rtsp-server-0.10.vapi index fff8c6a25b..bcc53a1915 100644 --- a/bindings/vala/gst-rtsp-server-0.10.vapi +++ b/bindings/vala/gst-rtsp-server-0.10.vapi @@ -30,7 +30,7 @@ namespace Gst { public weak Gst.Element fakesink; public uint id; public bool is_live; - public weak Gst.Element pipeline; + public Gst.Element pipeline; public bool prepared; public weak Gst.RTSPTimeRange range; public bool reused; @@ -48,6 +48,7 @@ namespace Gst { [CCode (has_construct_function = false)] public RTSPMedia (); public bool prepare (); + public void remove_elements (); public bool seek (Gst.RTSPTimeRange range); public void set_reusable (bool reusable); public void set_shared (bool shared); diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.gi b/bindings/vala/packages/gst-rtsp-server-0.10.gi index 3bac5531d2..7088f45891 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.gi +++ b/bindings/vala/packages/gst-rtsp-server-0.10.gi @@ -237,6 +237,12 @@ + + + + + + From 036550bf60d956f593d08acf810882c329cc08e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Sat, 13 Jun 2009 16:05:02 +0200 Subject: [PATCH 0135/1776] set state and remove elements of media in for loop --- gst/rtsp-server/rtsp-media.c | 41 +++++++++++++----------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 3d0ef33438..502e478db5 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1548,7 +1548,7 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport void gst_rtsp_media_remove_elements (GstRTSPMedia *media) { - gint i; + gint i, j; unlock_streams (media); @@ -1561,32 +1561,21 @@ gst_rtsp_media_remove_elements (GstRTSPMedia *media) gst_pad_unlink (stream->srcpad, stream->send_rtp_sink); - gst_element_set_state (stream->udpsrc[0], GST_STATE_NULL); - gst_element_set_state (stream->udpsrc[1], GST_STATE_NULL); - gst_element_set_state (stream->udpsink[0], GST_STATE_NULL); - gst_element_set_state (stream->udpsink[1], GST_STATE_NULL); - gst_element_set_state (stream->appsrc[0], GST_STATE_NULL); - gst_element_set_state (stream->appsrc[1], GST_STATE_NULL); - gst_element_set_state (stream->appsink[0], GST_STATE_NULL); - gst_element_set_state (stream->appsink[1], GST_STATE_NULL); - gst_element_set_state (stream->tee[0], GST_STATE_NULL); - gst_element_set_state (stream->tee[1], GST_STATE_NULL); - gst_element_set_state (stream->selector[0], GST_STATE_NULL); - gst_element_set_state (stream->selector[1], GST_STATE_NULL); + for (j = 0; j < 2; j++) { + gst_element_set_state (stream->udpsrc[j], GST_STATE_NULL); + gst_element_set_state (stream->udpsink[j], GST_STATE_NULL); + gst_element_set_state (stream->appsrc[j], GST_STATE_NULL); + gst_element_set_state (stream->appsink[j], GST_STATE_NULL); + gst_element_set_state (stream->tee[j], GST_STATE_NULL); + gst_element_set_state (stream->selector[j], GST_STATE_NULL); - gst_bin_remove (GST_BIN (media->pipeline), stream->udpsrc[0]); - gst_bin_remove (GST_BIN (media->pipeline), stream->udpsrc[1]); - gst_bin_remove (GST_BIN (media->pipeline), stream->udpsink[0]); - gst_bin_remove (GST_BIN (media->pipeline), stream->udpsink[1]); - gst_bin_remove (GST_BIN (media->pipeline), stream->appsrc[0]); - gst_bin_remove (GST_BIN (media->pipeline), stream->appsrc[1]); - gst_bin_remove (GST_BIN (media->pipeline), stream->appsink[0]); - gst_bin_remove (GST_BIN (media->pipeline), stream->appsink[1]); - gst_bin_remove (GST_BIN (media->pipeline), stream->tee[0]); - gst_bin_remove (GST_BIN (media->pipeline), stream->tee[1]); - gst_bin_remove (GST_BIN (media->pipeline), stream->selector[0]); - gst_bin_remove (GST_BIN (media->pipeline), stream->selector[1]); - + gst_bin_remove (GST_BIN (media->pipeline), stream->udpsrc[j]); + gst_bin_remove (GST_BIN (media->pipeline), stream->udpsink[j]); + gst_bin_remove (GST_BIN (media->pipeline), stream->appsrc[j]); + gst_bin_remove (GST_BIN (media->pipeline), stream->appsink[j]); + gst_bin_remove (GST_BIN (media->pipeline), stream->tee[j]); + gst_bin_remove (GST_BIN (media->pipeline), stream->selector[j]); + } gst_rtsp_media_stream_free (stream); } g_array_remove_range (media->streams, 0, media->streams->len); From f384231ca30c939ab8a83c8aa291c011672eff7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Sun, 14 Jun 2009 23:12:13 +0200 Subject: [PATCH 0136/1776] Unref pipeline and set it to NULL. Set stream's caps to NULL, otherwise we unref it too often. --- gst/rtsp-server/rtsp-media.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 502e478db5..fe54253702 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -142,13 +142,13 @@ gst_rtsp_media_finalize (GObject * obj) media = GST_RTSP_MEDIA (obj); g_message ("finalize media %p", media); -/* + if (media->pipeline) { unlock_streams (media); gst_element_set_state (media->pipeline, GST_STATE_NULL); gst_object_unref (media->pipeline); } -*/ + for (i = 0; i < media->streams->len; i++) { GstRTSPMediaStream *stream; @@ -1576,11 +1576,15 @@ gst_rtsp_media_remove_elements (GstRTSPMedia *media) gst_bin_remove (GST_BIN (media->pipeline), stream->tee[j]); gst_bin_remove (GST_BIN (media->pipeline), stream->selector[j]); } + stream->caps = NULL; gst_rtsp_media_stream_free (stream); } g_array_remove_range (media->streams, 0, media->streams->len); gst_element_set_state (media->rtpbin, GST_STATE_NULL); gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin); + + gst_object_unref (media->pipeline); + media->pipeline = NULL; } From 5d4c0e20c02b58369a13142483999e1ff6a88244 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 18 Jun 2009 16:05:18 +0200 Subject: [PATCH 0137/1776] media: fix indentation --- gst/rtsp-server/rtsp-media.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index fe54253702..8ec799fb40 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1401,8 +1401,10 @@ gst_rtsp_media_unprepare (GstRTSPMedia *media) } static gboolean -default_unprepare (GstRTSPMedia *media) { +default_unprepare (GstRTSPMedia *media) +{ gst_element_set_state (media->pipeline, GST_STATE_NULL); + return TRUE; } From a403469a0352576fdfc9d1f8d4ccc4ecfaf72272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 22 Jun 2009 18:57:25 +0100 Subject: [PATCH 0138/1776] configure: bump core/base requirements to release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index e26938e2f3..325bf21456 100644 --- a/configure.ac +++ b/configure.ac @@ -37,8 +37,8 @@ AC_SUBST(GST_MAJORMINOR) AM_PROG_LIBTOOL dnl *** required versions of GStreamer stuff *** -GST_REQ=0.10.22.1 -GSTPB_REQ=0.10.22.1 +GST_REQ=0.10.23 +GSTPB_REQ=0.10.23 dnl export for .pc files AC_SUBST([GST_REQ]) From a4c90c28c77aa0619872701f5042e3c7f4a52222 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 30 Jun 2009 21:27:53 +0200 Subject: [PATCH 0139/1776] sessionpool: add function to filter sessions Add generic function to retrieve/remove sessions. --- gst/rtsp-server/rtsp-session-pool.c | 68 +++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-session-pool.h | 42 ++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index d8702a9b23..7c68da1396 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -380,6 +380,74 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool) return result; } +typedef struct +{ + GstRTSPSessionPool *pool; + GstRTSPSessionFilterFunc func; + gpointer user_data; + GList *list; +} FilterData; + +static gboolean +filter_func (gchar *sessionid, GstRTSPSession *sess, FilterData *data) +{ + switch (data->func (data->pool, sess, data->user_data)) { + case GST_RTSP_FILTER_REMOVE: + return TRUE; + case GST_RTSP_FILTER_REF: + /* keep ref */ + data->list = g_list_prepend (data->list, g_object_ref (sess)); + /* fallthrough */ + default: + case GST_RTSP_FILTER_KEEP: + return FALSE; + } +} + +/** + * gst_rtsp_session_pool_filter: + * @pool: a #GstRTSPSessionPool + * @func: a callback + * @user_data: user data passed to @func + * + * Call @func for each session in @pool. The result value of @func determines + * what happens to the session. @func will be called with the session pool + * locked so no further actions on @pool can be performed from @func. + * + * If @func returns #GST_RTSP_FILTER_REMOVE, the session will be removed from + * @pool. + * + * If @func returns #GST_RTSP_FILTER_KEEP, the session will remain in @pool. + * + * If @func returns #GST_RTSP_FILTER_REF, the session will remain in @pool but + * will also be added with an additional ref to the result GList of this + * function.. + * + * Returns: a GList with all sessions for which @func returned + * #GST_RTSP_FILTER_REF. After usage, each element in the GList should be unreffed + * before the list is freed. + */ +GList * +gst_rtsp_session_pool_filter (GstRTSPSessionPool *pool, + GstRTSPSessionFilterFunc func, gpointer user_data) +{ + FilterData data; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL); + g_return_val_if_fail (func != NULL, NULL); + + data.pool = pool; + data.func = func; + data.user_data = user_data; + data.list = NULL; + + g_mutex_lock (pool->lock); + g_hash_table_foreach_remove (pool->sessions, (GHRFunc) filter_func, &data); + g_mutex_unlock (pool->lock); + + return data.list; +} + typedef struct { GSource source; diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 7c387cd36e..475628c4e2 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -81,6 +81,45 @@ struct _GstRTSPSessionPoolClass { */ typedef gboolean (*GstRTSPSessionPoolFunc) (GstRTSPSessionPool *pool, gpointer user_data); +/** + * GstRTSPFilterResult: + * @GST_RTSP_FILTER_REMOVE: Remove session + * @GST_RTSP_FILTER_KEEP: Keep session in the pool + * @GST_RTSP_FILTER_REF: Ref session in the result list + * + * Possible return values for gst_rtsp_session_pool_filter(). + */ +typedef enum +{ + GST_RTSP_FILTER_REMOVE, + GST_RTSP_FILTER_KEEP, + GST_RTSP_FILTER_REF, +} GstRTSPFilterResult; + +/** + * GstRTSPSessionFilterFunc: + * @pool: a #GstRTSPSessionPool object + * @session: a #GstRTSPSession in @pool + * @user_data: user data that has been given to gst_rtsp_session_pool_filter() + * + * This function will be called by the gst_rtsp_session_pool_filter(). An + * implementation should return a value of #GstRTSPFilterResult. + * + * When this function returns #GST_RTSP_FILTER_REMOVE, @session will be removed + * from @pool. + * + * A return value of #GST_RTSP_FILTER_KEEP will leave @session untouched in + * @pool. + * + * A value of GST_RTSP_FILTER_REF will add @session to the result #GList of + * gst_rtsp_session_pool_filter(). + * + * Returns: a #GstRTSPFilterResult. + */ +typedef GstRTSPFilterResult (*GstRTSPSessionFilterFunc) (GstRTSPSessionPool *pool, + GstRTSPSession *session, + gpointer user_data); + GType gst_rtsp_session_pool_get_type (void); @@ -101,6 +140,9 @@ gboolean gst_rtsp_session_pool_remove (GstRTSPSessionPoo GstRTSPSession *sess); /* perform session maintenance */ +GList * gst_rtsp_session_pool_filter (GstRTSPSessionPool *pool, + GstRTSPSessionFilterFunc func, + gpointer user_data); guint gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool); GSource * gst_rtsp_session_pool_create_watch (GstRTSPSessionPool *pool); From 748290b8882219404be4d4e056bb047c82fe055d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Mon, 13 Jul 2009 11:31:23 +0200 Subject: [PATCH 0140/1776] bindings: update vala bindings with new method --- bindings/vala/gst-rtsp-server-0.10.vapi | 9 ++++++++ .../vala/packages/gst-rtsp-server-0.10.gi | 21 +++++++++++++++++++ .../packages/gst-rtsp-server-0.10.metadata | 2 ++ 3 files changed, 32 insertions(+) diff --git a/bindings/vala/gst-rtsp-server-0.10.vapi b/bindings/vala/gst-rtsp-server-0.10.vapi index bcc53a1915..46a8ed4a87 100644 --- a/bindings/vala/gst-rtsp-server-0.10.vapi +++ b/bindings/vala/gst-rtsp-server-0.10.vapi @@ -209,6 +209,7 @@ namespace Gst { [NoWrapper] public virtual string create_session_id (); public GLib.TimeoutSource create_watch (); + public GLib.List filter (Gst.RTSPSessionFilterFunc func); public Gst.RTSPSession? find (string sessionid); public uint get_max_sessions (); public uint get_n_sessions (); @@ -227,11 +228,19 @@ namespace Gst { public void set_keepalive (Gst.RTSPKeepAliveFunc keep_alive, GLib.DestroyNotify notify); public Gst.RTSPTransport set_transport (Gst.RTSPTransport ct); } + [CCode (cprefix = "GST_RTSP_FILTER_", has_type_id = "0", cheader_filename = "gst/gst.h")] + public enum RTSPFilterResult { + REMOVE, + KEEP, + REF + } [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] public delegate void RTSPKeepAliveFunc (); [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] public delegate bool RTSPSendFunc (Gst.Buffer buffer, uchar channel); [CCode (cheader_filename = "gst/rtsp-server/rtsp-session-pool.h")] + public delegate Gst.RTSPFilterResult RTSPSessionFilterFunc (Gst.RTSPSessionPool pool, Gst.RTSPSession session); + [CCode (cheader_filename = "gst/rtsp-server/rtsp-session-pool.h")] public delegate bool RTSPSessionPoolFunc (Gst.RTSPSessionPool pool); [CCode (cheader_filename = "gst/gst.h")] public static Gst.RTSPResult rtsp_params_get (Gst.RTSPClient client, Gst.RTSPUrl uri, Gst.RTSPSession session, Gst.RTSPMessage request, Gst.RTSPMessage response); diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.gi b/bindings/vala/packages/gst-rtsp-server-0.10.gi index 7088f45891..76671d9f5d 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.gi +++ b/bindings/vala/packages/gst-rtsp-server-0.10.gi @@ -41,6 +41,14 @@ + + + + + + + + @@ -147,6 +155,11 @@ + + + + + @@ -639,6 +652,14 @@ + + + + + + + + diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.metadata b/bindings/vala/packages/gst-rtsp-server-0.10.metadata index ed7fffe237..861e11e8d4 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.metadata +++ b/bindings/vala/packages/gst-rtsp-server-0.10.metadata @@ -10,6 +10,7 @@ GstRTSPSession cheader_filename="gst/rtsp-server/rtsp-session.h" GstRTSPSessionMedia cheader_filename="gst/rtsp-server/rtsp-session.h" GstRTSPSessionPool cheader_filename="gst/rtsp-server/rtsp-session-pool.h" GstRTSPSessionStream cheader_filename="gst/rtsp-server/rtsp-session.h" +GstRTSPSessionFilterFunc cheader_filename="gst/rtsp-server/rtsp-session-pool.h" gst_rtsp_client_get_media_mapping transfer_ownership="1" gst_rtsp_client_get_session_pool transfer_ownership="1" gst_rtsp_media_factory_get_launch transfer_ownership="1" @@ -31,6 +32,7 @@ gst_rtsp_session_pool_create transfer_ownership="1" gst_rtsp_session_pool_create_session_id transfer_ownership="1" gst_rtsp_session_pool_create_watch transfer_ownership="1" gst_rtsp_session_pool_find transfer_ownership="1" nullable="1" +gst_rtsp_session_pool_filter transfer_ownership="1" type_arguments="RTSPSession" gst_rtsp_session_stream_set_transport transfer_ownership="1" GstRTSPKeepAliveFunc cheader_filename="gst/rtsp-server/rtsp-media.h" GstRTSPSendFunc cheader_filename="gst/rtsp-server/rtsp-media.h" From daccf6bc99760e0653c1945ee4e85a96c1f149c1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 24 Jul 2009 12:49:41 +0200 Subject: [PATCH 0141/1776] client: don't crash when tunnelid is missing When a clients tries to open an HTTP tunnel but fails to provide a tunnelid, don't crash but return an error response to the client. Fixes #589489 --- gst/rtsp-server/rtsp-client.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e12d425603..65217b9d95 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1359,6 +1359,8 @@ tunnel_start (GstRTSPWatch * watch, gpointer user_data) /* store client in the pending tunnels */ tunnelid = gst_rtsp_connection_get_tunnelid (client->connection); + if (tunnelid == NULL) + goto no_tunnelid; g_message ("client %p: inserting %s", client, tunnelid); @@ -1373,6 +1375,11 @@ tunnel_start (GstRTSPWatch * watch, gpointer user_data) return GST_RTSP_STS_OK; /* ERRORS */ +no_tunnelid: + { + g_message ("client %p: no tunnelid provided", client); + return GST_RTSP_STS_SERVICE_UNAVAILABLE; + } tunnel_existed: { g_mutex_unlock (tunnels_lock); @@ -1392,6 +1399,8 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) /* find previous tunnel */ tunnelid = gst_rtsp_connection_get_tunnelid (client->connection); + if (tunnelid == NULL) + goto no_tunnelid; g_mutex_lock (tunnels_lock); if (!(oclient = g_hash_table_lookup (tunnels, tunnelid))) @@ -1417,11 +1426,16 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) return GST_RTSP_OK; /* ERRORS */ +no_tunnelid: + { + g_message ("client %p: no tunnelid provided", client); + return GST_RTSP_STS_SERVICE_UNAVAILABLE; + } no_tunnel: { g_mutex_unlock (tunnels_lock); g_message ("client %p: tunnel session %s not found", client, tunnelid); - return GST_RTSP_OK; + return GST_RTSP_STS_SERVICE_UNAVAILABLE; } } From 7338ab81e1ffb5ddf600fa15ff06bc8a7736057b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 27 Jul 2009 19:42:44 +0200 Subject: [PATCH 0142/1776] rtsp: allocate channels in TCP mode When the client does not provide us with channels in TCP mode, allocate channels ourselves. --- gst/rtsp-server/rtsp-client.c | 14 ++++++++++++-- gst/rtsp-server/rtsp-session.c | 12 ++++++++++-- gst/rtsp-server/rtsp-session.h | 6 ++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 65217b9d95..c2986d4955 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -797,6 +797,14 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, if (media == NULL) goto not_found; + /* fix the transports */ + if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) { + /* check if the client selected channels for TCP */ + if (ct->interleaved.min == -1 || ct->interleaved.max == -1) { + gst_rtsp_session_media_alloc_channels (media, &ct->interleaved); + } + } + /* get a handle to the stream in the media */ if (!(stream = gst_rtsp_session_media_get_stream (media, streamid))) goto no_stream; @@ -1307,9 +1315,11 @@ message_received (GstRTSPWatch * watch, GstRTSPMessage * message, static GstRTSPResult message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) { - GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + GstRTSPClient *client; + + client = GST_RTSP_CLIENT (user_data); - g_message ("client %p: sent a message with cseq %d", client, cseq); + /* g_message ("client %p: sent a message with cseq %d", client, cseq); */ return GST_RTSP_OK; } diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 3afd7886fc..7525036445 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -323,6 +323,15 @@ no_media: } } +gboolean +gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia *media, GstRTSPRange *range) +{ + range->min = media->counter++; + range->max = media->counter++; + + return TRUE; +} + /** * gst_rtsp_session_new: * @@ -481,8 +490,7 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, st->lower_transport = ct->lower_transport; st->client_port = ct->client_port; st->interleaved = ct->interleaved; - st->server_port.min = stream->media_stream->server_port.min; - st->server_port.max = stream->media_stream->server_port.max; + st->server_port = stream->media_stream->server_port; /* keep track of the transports in the stream. */ if (stream->trans.transport) diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 0074b559ef..56816679c3 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -75,6 +75,9 @@ struct _GstRTSPSessionMedia /* the server state */ GstRTSPState state; + /* counter for channels */ + guint counter; + /* configuration for the different streams */ GArray *streams; }; @@ -138,6 +141,9 @@ gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMedi GstRTSPSessionStream * gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, guint idx); +gboolean gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia *media, + GstRTSPRange *range); + /* configure transport */ GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, GstRTSPTransport *ct); From 5ec236326cd7ca960f277ae082da0cfb1a34926f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 5 Aug 2009 11:44:49 +0200 Subject: [PATCH 0143/1776] Release 0.10.4 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 325bf21456..063edd5e68 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.3.1, +AC_INIT(Gst-RTSP, 0.10.4, http://gstreamer.net/, gst-rtsp) From 02c60f3529310c3592ab5d9788e26ebf29d42092 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 5 Aug 2009 11:53:56 +0200 Subject: [PATCH 0144/1776] back to development --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 063edd5e68..86d1e3889c 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.4, +AC_INIT(Gst-RTSP, 0.10.4.1, http://gstreamer.net/, gst-rtsp) From 309f53a12bbe442dc6da628d073458618edb167f Mon Sep 17 00:00:00 2001 From: Peter Kjellerstedt Date: Mon, 24 Aug 2009 13:27:00 +0200 Subject: [PATCH 0145/1776] rtsp: Use gst_rtsp_watch_send_message(). Use gst_rtsp_watch_send_message() since the old API which used gst_rtsp_watch_queue_message() has been deprecated. --- gst/rtsp-server/rtsp-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c2986d4955..6dec049672 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -182,7 +182,7 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, gst_rtsp_message_dump (response); #endif - gst_rtsp_watch_queue_message (client->watch, response); + gst_rtsp_watch_send_message (client->watch, response, NULL); gst_rtsp_message_unset (response); } @@ -298,7 +298,7 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) size = GST_BUFFER_SIZE (buffer); gst_rtsp_message_take_body (&message, data, size); - gst_rtsp_watch_queue_message (client->watch, &message); + gst_rtsp_watch_send_message (client->watch, &message, NULL); gst_rtsp_message_steal_body (&message, &data, &size); gst_rtsp_message_unset (&message); From 297b6a755aa2a1574d4a5e1049077a963b270566 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 11 Sep 2009 13:52:27 +0200 Subject: [PATCH 0146/1776] media: add some docs --- gst/rtsp-server/rtsp-media.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 8ec799fb40..046e3d5f48 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1547,6 +1547,12 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport return TRUE; } +/** + * gst_rtsp_media_remove_elements: + * @media: a #GstRTSPMedia + * + * Remove all elements and the pipeline controlled by @media. + */ void gst_rtsp_media_remove_elements (GstRTSPMedia *media) { From 7d38b37ae6fec20fdc441aaea0920089c0497e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Fri, 9 Oct 2009 16:26:30 +0200 Subject: [PATCH 0147/1776] Added pkg-config file to use gst-rtsp-server uninstalled --- configure.ac | 1 + pkgconfig/.gitignore | 3 +-- pkgconfig/Makefile.am | 13 ++++++++++--- pkgconfig/gst-rtsp-server-uninstalled.pc.in | 12 ++++++++++++ 4 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 pkgconfig/gst-rtsp-server-uninstalled.pc.in diff --git a/configure.ac b/configure.ac index 86d1e3889c..47b611ccf0 100644 --- a/configure.ac +++ b/configure.ac @@ -277,6 +277,7 @@ bindings/python/codegen/Makefile bindings/vala/Makefile pkgconfig/Makefile pkgconfig/gst-rtsp-server.pc +pkgconfig/gst-rtsp-server-uninstalled.pc ]) AC_OUTPUT diff --git a/pkgconfig/.gitignore b/pkgconfig/.gitignore index bee7f7ad98..6fd0ef029e 100644 --- a/pkgconfig/.gitignore +++ b/pkgconfig/.gitignore @@ -1,2 +1 @@ -gst-rtsp-server-0.10.pc -gst-rtsp-server.pc +*.pc diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am index 310dc8a3d2..8d38e35bb3 100644 --- a/pkgconfig/Makefile.am +++ b/pkgconfig/Makefile.am @@ -1,14 +1,21 @@ pcfiles = \ gst-rtsp-server-@GST_MAJORMINOR@.pc -all-local: $(pcfiles) +pcfiles_uninstalled = \ + gst-rtsp-server-@GST_MAJORMINOR@-uninstalled.pc + +all-local: $(pcfiles) $(pcfiles_uninstalled) ### how to generate pc files %-@GST_MAJORMINOR@.pc: %.pc cp $< $@ +%-@GST_MAJORMINOR@-uninstalled.pc: %-uninstalled.pc + cp $< $@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pcfiles) -EXTRA_DIST = gst-rtsp-server.pc.in -CLEANFILES = $(pcfiles) +EXTRA_DIST = \ + gst-rtsp-server.pc.in \ + gst-rtsp-server-uninstalled.pc.in +CLEANFILES = $(pcfiles) $(pcfiles_uninstalled) diff --git a/pkgconfig/gst-rtsp-server-uninstalled.pc.in b/pkgconfig/gst-rtsp-server-uninstalled.pc.in new file mode 100644 index 0000000000..cd591be913 --- /dev/null +++ b/pkgconfig/gst-rtsp-server-uninstalled.pc.in @@ -0,0 +1,12 @@ +# the standard variables don't make sense for an uninstalled copy +prefix= +exec_prefix= +libdir=${pcfiledir}/../gst/rtsp-server +includedir=${pcfiledir}/.. + +Name: gst-rtsp-server +Description: GStreamer based RTSP server +Version: @VERSION@ +Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-plugins-base-@GST_MAJORMINOR@ +Libs: ${libdir}/libgstrtspserver-@GST_MAJORMINOR@.la +Cflags: -I${includedir} -I@srcdir@/.. From f8630c6c816007de43c6c0d701aabbb657c76877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Fri, 9 Oct 2009 23:08:18 +0200 Subject: [PATCH 0148/1776] media: Fixed crasher where caps got unref'ed too often --- gst/rtsp-server/rtsp-media.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 046e3d5f48..fe79296b60 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1569,6 +1569,8 @@ gst_rtsp_media_remove_elements (GstRTSPMedia *media) gst_pad_unlink (stream->srcpad, stream->send_rtp_sink); + g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig); + for (j = 0; j < 2; j++) { gst_element_set_state (stream->udpsrc[j], GST_STATE_NULL); gst_element_set_state (stream->udpsink[j], GST_STATE_NULL); @@ -1584,11 +1586,13 @@ gst_rtsp_media_remove_elements (GstRTSPMedia *media) gst_bin_remove (GST_BIN (media->pipeline), stream->tee[j]); gst_bin_remove (GST_BIN (media->pipeline), stream->selector[j]); } + if (stream->caps) + gst_caps_unref (stream->caps); stream->caps = NULL; gst_rtsp_media_stream_free (stream); } g_array_remove_range (media->streams, 0, media->streams->len); - + gst_element_set_state (media->rtpbin, GST_STATE_NULL); gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin); From 745900dd48bb6701faef960d5e7e52478f18027e Mon Sep 17 00:00:00 2001 From: Luca Ognibene Date: Sun, 11 Oct 2009 13:57:54 +0200 Subject: [PATCH 0149/1776] client: call weak-unref on client->sessions from finalize Fixes bug #596305 --- gst/rtsp-server/rtsp-client.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6dec049672..050969df4d 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -85,9 +85,17 @@ static void gst_rtsp_client_finalize (GObject * obj) { GstRTSPClient *client = GST_RTSP_CLIENT (obj); + GList *walk; g_message ("finalize client %p", client); + /* remove weak-ref from sessions */ + for (walk = client->sessions; walk; walk = g_list_next (walk)) { + GstRTSPSession *msession = (GstRTSPSession *) walk->data; + g_object_weak_unref (G_OBJECT (msession), + (GWeakNotify) client_session_finalized, client); + } + g_list_free (client->sessions); gst_rtsp_connection_free (client->connection); From 07f6c4de5a041f38a19dcdad5243fa0229bd7728 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 14 Oct 2009 12:11:31 +0200 Subject: [PATCH 0150/1776] configure: bump required versions --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 47b611ccf0..dd48fd75b0 100644 --- a/configure.ac +++ b/configure.ac @@ -37,8 +37,8 @@ AC_SUBST(GST_MAJORMINOR) AM_PROG_LIBTOOL dnl *** required versions of GStreamer stuff *** -GST_REQ=0.10.23 -GSTPB_REQ=0.10.23 +GST_REQ=0.10.25 +GSTPB_REQ=0.10.25 dnl export for .pc files AC_SUBST([GST_REQ]) From 95797040eb860ebb8f33b8d92e93f20b60e5215f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 5 Nov 2009 11:20:45 +0100 Subject: [PATCH 0151/1776] release 0.10.5 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index dd48fd75b0..ca7053d69a 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.4.1, +AC_INIT(Gst-RTSP, 0.10.5, http://gstreamer.net/, gst-rtsp) From f8604a6bc7623170c8a6cb2ac0c11c080992b749 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 5 Nov 2009 11:22:44 +0100 Subject: [PATCH 0152/1776] back to development --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index ca7053d69a..5529ede359 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.5, +AC_INIT(Gst-RTSP, 0.10.5.1, http://gstreamer.net/, gst-rtsp) From 87fbfa54a0d15e2ba29e2a360b5e456da52a721f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Sat, 21 Nov 2009 01:00:39 +0100 Subject: [PATCH 0153/1776] server: Set ghost pad active in gst_rtsp_media_factory_collect_streams --- gst/rtsp-server/rtsp-media-factory.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 2110ea953a..31823ce8fd 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -430,6 +430,7 @@ gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory *factory, const GstR /* ghost the pad of the payloader to the element */ stream->srcpad = gst_ghost_pad_new (name, pad); + gst_pad_set_active (stream->srcpad, TRUE); gst_element_add_pad (media->element, stream->srcpad); gst_object_unref (elem); From 6d227be7a9143ab41d0c56bb6c85f7edb4ed7e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Sat, 21 Nov 2009 19:20:23 +0100 Subject: [PATCH 0154/1776] Use GStreamer's debugging subsystem --- gst/rtsp-server/rtsp-client.c | 49 +++++++------ gst/rtsp-server/rtsp-media-factory.c | 13 ++-- gst/rtsp-server/rtsp-media-mapping.c | 5 +- gst/rtsp-server/rtsp-media.c | 101 ++++++++++++++------------- gst/rtsp-server/rtsp-server.c | 11 ++- gst/rtsp-server/rtsp-session-pool.c | 22 +++--- gst/rtsp-server/rtsp-session.c | 11 +-- 7 files changed, 120 insertions(+), 92 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 050969df4d..22477b28e9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -36,6 +36,9 @@ enum PROP_LAST }; +GST_DEBUG_CATEGORY_STATIC (rtsp_client_debug); +#define GST_CAT_DEFAULT rtsp_client_debug + static void gst_rtsp_client_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec); static void gst_rtsp_client_set_property (GObject * object, guint propid, @@ -73,6 +76,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); tunnels_lock = g_mutex_new (); + + GST_DEBUG_CATEGORY_INIT (rtsp_client_debug, "rtspclient", 0, "GstRTSPClient"); } static void @@ -87,7 +92,7 @@ gst_rtsp_client_finalize (GObject * obj) GstRTSPClient *client = GST_RTSP_CLIENT (obj); GList *walk; - g_message ("finalize client %p", client); + GST_INFO ("finalize client %p", client); /* remove weak-ref from sessions */ for (walk = client->sessions; walk; walk = g_list_next (walk)) { @@ -259,7 +264,7 @@ find_media (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPMessage * request) } else { /* we have seen this uri before, used cached media */ media = client->media; - g_message ("reusing cached media %p", media); + GST_INFO ("reusing cached media %p", media); } if (media) @@ -601,7 +606,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPUrl * uri, sstream = gst_rtsp_session_media_get_stream (media, i); /* get the transport, if there is no transport configured, skip this stream */ if (!(tr = sstream->trans.transport)) { - g_message ("stream %d is not configured", i); + GST_INFO ("stream %d is not configured", i); continue; } @@ -633,7 +638,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPUrl * uri, infocount++; } else { - g_warning ("RTP-Info cannot be determined for stream %d", i); + GST_WARNING ("RTP-Info cannot be determined for stream %d", i); } } @@ -685,7 +690,7 @@ invalid_state: static void do_keepalive (GstRTSPSession * session) { - g_message ("keep session %p alive", session); + GST_INFO ("keep session %p alive", session); gst_rtsp_session_touch (session); } @@ -1023,7 +1028,7 @@ static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) { if (!(client->sessions = g_list_remove (client->sessions, session))) { - g_message ("all sessions finalized, close the connection"); + GST_INFO ("all sessions finalized, close the connection"); g_source_destroy ((GSource *) client->watch); } } @@ -1041,7 +1046,7 @@ client_watch_session (GstRTSPClient * client, GstRTSPSession * session) return; } - g_message ("watching session %p", session); + GST_INFO ("watching session %p", session); g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client); @@ -1063,7 +1068,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) gst_rtsp_message_dump (request); #endif - g_message ("client %p: received a request", client); + GST_INFO ("client %p: received a request", client); gst_rtsp_message_parse_request (request, &method, &uristr, &version); @@ -1327,7 +1332,7 @@ message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) client = GST_RTSP_CLIENT (user_data); - /* g_message ("client %p: sent a message with cseq %d", client, cseq); */ + /* GST_INFO ("client %p: sent a message with cseq %d", client, cseq); */ return GST_RTSP_OK; } @@ -1338,7 +1343,7 @@ closed (GstRTSPWatch * watch, gpointer user_data) GstRTSPClient *client = GST_RTSP_CLIENT (user_data); const gchar *tunnelid; - g_message ("client %p: connection closed", client); + GST_INFO ("client %p: connection closed", client); if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) { g_mutex_lock (tunnels_lock); @@ -1359,7 +1364,7 @@ error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data) gchar *str; str = gst_rtsp_strresult (result); - g_message ("client %p: received an error %s", client, str); + GST_INFO ("client %p: received an error %s", client, str); g_free (str); return GST_RTSP_OK; @@ -1373,14 +1378,14 @@ tunnel_start (GstRTSPWatch * watch, gpointer user_data) client = GST_RTSP_CLIENT (user_data); - g_message ("client %p: tunnel start", client); + GST_INFO ("client %p: tunnel start", client); /* store client in the pending tunnels */ tunnelid = gst_rtsp_connection_get_tunnelid (client->connection); if (tunnelid == NULL) goto no_tunnelid; - g_message ("client %p: inserting %s", client, tunnelid); + GST_INFO ("client %p: inserting %s", client, tunnelid); /* we can't have two clients connecting with the same tunnelid */ g_mutex_lock (tunnels_lock); @@ -1395,13 +1400,13 @@ tunnel_start (GstRTSPWatch * watch, gpointer user_data) /* ERRORS */ no_tunnelid: { - g_message ("client %p: no tunnelid provided", client); + GST_INFO ("client %p: no tunnelid provided", client); return GST_RTSP_STS_SERVICE_UNAVAILABLE; } tunnel_existed: { g_mutex_unlock (tunnels_lock); - g_message ("client %p: tunnel session %s existed", client, tunnelid); + GST_INFO ("client %p: tunnel session %s existed", client, tunnelid); return GST_RTSP_STS_SERVICE_UNAVAILABLE; } } @@ -1413,7 +1418,7 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) GstRTSPClient *client = GST_RTSP_CLIENT (user_data); GstRTSPClient *oclient; - g_message ("client %p: tunnel complete", client); + GST_INFO ("client %p: tunnel complete", client); /* find previous tunnel */ tunnelid = gst_rtsp_connection_get_tunnelid (client->connection); @@ -1430,7 +1435,7 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) g_hash_table_remove (tunnels, tunnelid); g_mutex_unlock (tunnels_lock); - g_message ("client %p: found tunnel %p", client, oclient); + GST_INFO ("client %p: found tunnel %p", client, oclient); /* merge the tunnels into the first client */ gst_rtsp_connection_do_tunnel (oclient->connection, client->connection); @@ -1446,13 +1451,13 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) /* ERRORS */ no_tunnelid: { - g_message ("client %p: no tunnelid provided", client); + GST_INFO ("client %p: no tunnelid provided", client); return GST_RTSP_STS_SERVICE_UNAVAILABLE; } no_tunnel: { g_mutex_unlock (tunnels_lock); - g_message ("client %p: tunnel session %s not found", client, tunnelid); + GST_INFO ("client %p: tunnel session %s not found", client, tunnelid); return GST_RTSP_STS_SERVICE_UNAVAILABLE; } } @@ -1494,7 +1499,7 @@ gst_rtsp_client_accept (GstRTSPClient * client, GIOChannel * channel) GST_RTSP_CHECK (gst_rtsp_connection_accept (sock, &conn), accept_failed); url = gst_rtsp_connection_get_url (conn); - g_message ("added new client %p ip %s:%d", client, url->host, url->port); + GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port); client->connection = conn; @@ -1508,7 +1513,7 @@ gst_rtsp_client_accept (GstRTSPClient * client, GIOChannel * channel) else context = NULL; - g_message ("attaching to context %p", context); + GST_INFO ("attaching to context %p", context); client->watchid = gst_rtsp_watch_attach (client->watch, context); gst_rtsp_watch_unref (client->watch); @@ -1520,7 +1525,7 @@ accept_failed: { gchar *str = gst_rtsp_strresult (res); - g_error ("Could not accept client on server socket %d: %s", sock, str); + GST_ERROR ("Could not accept client on server socket %d: %s", sock, str); g_free (str); return FALSE; } diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 31823ce8fd..52f94714b8 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -30,6 +30,9 @@ enum PROP_LAST }; +GST_DEBUG_CATEGORY (rtsp_media_debug); +#define GST_CAT_DEFAULT rtsp_media_debug + static void gst_rtsp_media_factory_get_property (GObject *object, guint propid, GValue *value, GParamSpec *pspec); static void gst_rtsp_media_factory_set_property (GObject *object, guint propid, @@ -81,6 +84,8 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) klass->construct = default_construct; klass->configure = default_configure; klass->create_pipeline = default_create_pipeline; + + GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); } static void @@ -340,7 +345,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl if (key) g_free (key); - g_message ("constructed media %p for url %s", media, url->abspath); + GST_INFO ("constructed media %p for url %s", media, url->abspath); return media; } @@ -375,7 +380,7 @@ default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) if (error != NULL) { /* a recoverable error was encountered */ - g_warning ("recoverable parsing error: %s", error->message); + GST_WARNING ("recoverable parsing error: %s", error->message); g_error_free (error); } return element; @@ -424,7 +429,7 @@ gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory *factory, const GstR stream = g_new0 (GstRTSPMediaStream, 1); stream->payloader = elem; - g_message ("found stream %d with payloader %p", i, elem); + GST_INFO ("found stream %d with payloader %p", i, elem); pad = gst_element_get_static_pad (elem, "src"); @@ -444,7 +449,7 @@ gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory *factory, const GstR if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { /* a stream that will dynamically create pads to provide RTP packets */ - g_message ("found dynamic element %d, %p", i, elem); + GST_INFO ("found dynamic element %d, %p", i, elem); media->dynamic = g_list_prepend (media->dynamic, elem); diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c index 52490cd329..b0020fd62a 100644 --- a/gst/rtsp-server/rtsp-media-mapping.c +++ b/gst/rtsp-server/rtsp-media-mapping.c @@ -21,6 +21,9 @@ G_DEFINE_TYPE (GstRTSPMediaMapping, gst_rtsp_media_mapping, G_TYPE_OBJECT); +GST_DEBUG_CATEGORY_EXTERN (rtsp_media_debug); +#define GST_CAT_DEFAULT rtsp_media_debug + static void gst_rtsp_media_mapping_finalize (GObject * obj); static GstRTSPMediaFactory * find_media (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url); @@ -76,7 +79,7 @@ find_media (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url) if (result) g_object_ref (result); - g_message ("found media %p for url abspath %s", result, url->abspath); + GST_INFO ("found media %p for url abspath %s", result, url->abspath); return result; } diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index fe79296b60..70de6fd652 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -44,6 +44,9 @@ enum SIGNAL_LAST }; +GST_DEBUG_CATEGORY_EXTERN (rtsp_media_debug); +#define GST_CAT_DEFAULT rtsp_media_debug + static GQuark ssrc_stream_map_key; static void gst_rtsp_media_get_property (GObject *object, guint propid, @@ -141,7 +144,7 @@ gst_rtsp_media_finalize (GObject * obj) media = GST_RTSP_MEDIA (obj); - g_message ("finalize media %p", media); + GST_INFO ("finalize media %p", media); if (media->pipeline) { unlock_streams (media); @@ -208,9 +211,9 @@ gst_rtsp_media_set_property (GObject *object, guint propid, static gpointer do_loop (GstRTSPMediaClass *klass) { - g_message ("enter mainloop"); + GST_INFO ("enter mainloop"); g_main_loop_run (klass->loop); - g_message ("exit mainloop"); + GST_INFO ("exit mainloop"); return NULL; } @@ -233,18 +236,18 @@ collect_media_stats (GstRTSPMedia *media) /* get the position */ format = GST_FORMAT_TIME; if (!gst_element_query_position (media->pipeline, &format, &position)) { - g_message ("position query failed"); + GST_INFO ("position query failed"); position = 0; } /* get the duration */ format = GST_FORMAT_TIME; if (!gst_element_query_duration (media->pipeline, &format, &duration)) { - g_message ("duration query failed"); + GST_INFO ("duration query failed"); duration = -1; } - g_message ("stats: position %"GST_TIME_FORMAT", duration %"GST_TIME_FORMAT, + GST_INFO ("stats: position %"GST_TIME_FORMAT", duration %"GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); if (position == -1) { @@ -457,21 +460,21 @@ gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range) } if (start != -1 || stop != -1) { - g_message ("seeking to %"GST_TIME_FORMAT" - %"GST_TIME_FORMAT, + GST_INFO ("seeking to %"GST_TIME_FORMAT" - %"GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); res = gst_element_seek (media->pipeline, 1.0, GST_FORMAT_TIME, flags, start_type, start, stop_type, stop); /* and block for the seek to complete */ - g_message ("done seeking %d", res); + GST_INFO ("done seeking %d", res); gst_element_get_state (media->pipeline, NULL, NULL, -1); - g_message ("prerolled again"); + GST_INFO ("prerolled again"); collect_media_stats (media); } else { - g_message ("no seek needed"); + GST_INFO ("no seek needed"); res = TRUE; } @@ -480,12 +483,12 @@ gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range) /* ERRORS */ not_supported: { - g_warning ("seek unit %d not supported", range->unit); + GST_WARNING ("seek unit %d not supported", range->unit); return FALSE; } weird_type: { - g_warning ("weird range type %d not supported", range->min.type); + GST_WARNING ("weird range type %d not supported", range->min.type); return FALSE; } } @@ -710,7 +713,7 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) gst_caps_unref (oldcaps); capsstr = gst_caps_to_string (newcaps); - g_message ("stream %p received caps %p, %s", stream, newcaps, capsstr); + GST_INFO ("stream %p received caps %p, %s", stream, newcaps, capsstr); g_free (capsstr); } @@ -720,7 +723,7 @@ dump_structure (const GstStructure *s) gchar *sstr; sstr = gst_structure_to_string (s); - g_message ("structure: %s", sstr); + GST_INFO ("structure: %s", sstr); g_free (sstr); } @@ -743,7 +746,7 @@ find_transport (GstRTSPMediaStream *stream, const gchar *rtcp_from) port = atoi (tmp + 1); dest = g_strndup (rtcp_from, tmp - rtcp_from); - g_message ("finding %s:%d", dest, port); + GST_INFO ("finding %s:%d", dest, port); for (walk = stream->transports; walk; walk = g_list_next (walk)) { GstRTSPMediaTrans *trans = walk->data; @@ -768,7 +771,7 @@ on_new_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) GstStructure *stats; GstRTSPMediaTrans *trans; - g_message ("%p: new source %p", stream, source); + GST_INFO ("%p: new source %p", stream, source); /* see if we have a stream to match with the origin of the RTCP packet */ trans = g_object_get_qdata (source, ssrc_stream_map_key); @@ -781,7 +784,7 @@ on_new_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) rtcp_from = gst_structure_get_string (stats, "rtcp-from"); if ((trans = find_transport (stream, rtcp_from))) { - g_message ("%p: found transport %p for source %p", stream, trans, source); + GST_INFO ("%p: found transport %p for source %p", stream, trans, source); /* keep ref to the source */ trans->rtpsource = source; @@ -791,14 +794,14 @@ on_new_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) gst_structure_free (stats); } } else { - g_message ("%p: source %p for transport %p", stream, source, trans); + GST_INFO ("%p: source %p for transport %p", stream, source, trans); } } static void on_ssrc_sdes (GObject *session, GObject *source, GstRTSPMediaStream *stream) { - g_message ("%p: new SDES %p", stream, source); + GST_INFO ("%p: new SDES %p", stream, source); } static void @@ -808,7 +811,7 @@ on_ssrc_active (GObject *session, GObject *source, GstRTSPMediaStream *stream) trans = g_object_get_qdata (source, ssrc_stream_map_key); - g_message ("%p: source %p in transport %p is active", stream, source, trans); + GST_INFO ("%p: source %p in transport %p is active", stream, source, trans); if (trans && trans->keep_alive) trans->keep_alive (trans->ka_user_data); @@ -828,7 +831,7 @@ on_ssrc_active (GObject *session, GObject *source, GstRTSPMediaStream *stream) static void on_bye_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) { - g_message ("%p: source %p bye", stream, source); + GST_INFO ("%p: source %p bye", stream, source); } static void @@ -836,7 +839,7 @@ on_bye_timeout (GObject *session, GObject *source, GstRTSPMediaStream *stream) { GstRTSPMediaTrans *trans; - g_message ("%p: source %p bye timeout", stream, source); + GST_INFO ("%p: source %p bye timeout", stream, source); if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) { trans->rtpsource = NULL; @@ -849,7 +852,7 @@ on_timeout (GObject *session, GObject *source, GstRTSPMediaStream *stream) { GstRTSPMediaTrans *trans; - g_message ("%p: source %p timeout", stream, source); + GST_INFO ("%p: source %p timeout", stream, source); if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) { trans->rtpsource = NULL; @@ -1068,7 +1071,7 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) /* ERRORS */ link_failed: { - g_warning ("failed to link stream %d", idx); + GST_WARNING ("failed to link stream %d", idx); return FALSE; } } @@ -1115,22 +1118,22 @@ default_handle_message (GstRTSPMedia *media, GstMessage *message) media->buffering = FALSE; /* if the desired state is playing, go back */ if (media->target_state == GST_STATE_PLAYING) { - g_message ("Buffering done, setting pipeline to PLAYING"); + GST_INFO ("Buffering done, setting pipeline to PLAYING"); gst_element_set_state (media->pipeline, GST_STATE_PLAYING); } else { - g_message ("Buffering done"); + GST_INFO ("Buffering done"); } } else { /* buffering busy */ if (media->buffering == FALSE) { if (media->target_state == GST_STATE_PLAYING) { /* we were not buffering but PLAYING, PAUSE the pipeline. */ - g_message ("Buffering, setting pipeline to PAUSED ..."); + GST_INFO ("Buffering, setting pipeline to PAUSED ..."); gst_element_set_state (media->pipeline, GST_STATE_PAUSED); } else { - g_message ("Buffering ..."); + GST_INFO ("Buffering ..."); } } media->buffering = TRUE; @@ -1148,7 +1151,7 @@ default_handle_message (GstRTSPMedia *media, GstMessage *message) gchar *debug; gst_message_parse_error (message, &gerror, &debug); - g_warning ("%p: got error %s (%s)", media, gerror->message, debug); + GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug); g_error_free (gerror); g_free (debug); break; @@ -1159,7 +1162,7 @@ default_handle_message (GstRTSPMedia *media, GstMessage *message) gchar *debug; gst_message_parse_warning (message, &gerror, &debug); - g_warning ("%p: got warning %s (%s)", media, gerror->message, debug); + GST_WARNING ("%p: got warning %s (%s)", media, gerror->message, debug); g_error_free (gerror); g_free (debug); break; @@ -1169,7 +1172,7 @@ default_handle_message (GstRTSPMedia *media, GstMessage *message) case GST_MESSAGE_STREAM_STATUS: break; default: - g_message ("%p: got message type %s", media, gst_message_type_get_name (type)); + GST_INFO ("%p: got message type %s", media, gst_message_type_get_name (type)); break; } return TRUE; @@ -1200,7 +1203,7 @@ pad_added_cb (GstElement *element, GstPad *pad, GstRTSPMedia *media) i = media->streams->len + 1; - g_message ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), i); + GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), i); stream = g_new0 (GstRTSPMediaStream, 1); stream->payloader = element; @@ -1230,14 +1233,14 @@ pad_added_cb (GstElement *element, GstPad *pad, GstRTSPMedia *media) static void no_more_pads_cb (GstElement *element, GstRTSPMedia *media) { - g_message ("no more pads"); + GST_INFO ("no more pads"); if (media->fakesink) { gst_object_ref (media->fakesink); gst_bin_remove (GST_BIN (media->pipeline), media->fakesink); gst_element_set_state (media->fakesink, GST_STATE_NULL); gst_object_unref (media->fakesink); media->fakesink = NULL; - g_message ("removed fakesink"); + GST_INFO ("removed fakesink"); } } @@ -1268,7 +1271,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) if (!media->reusable && media->reused) goto is_reused; - g_message ("preparing media %p", media); + GST_INFO ("preparing media %p", media); bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline)); @@ -1318,7 +1321,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) break; case GST_STATE_CHANGE_NO_PREROLL: /* we need to go to PLAYING */ - g_message ("live media %p", media); + GST_INFO ("live media %p", media); media->is_live = TRUE; ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) @@ -1336,7 +1339,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) /* collect stats about the media */ collect_media_stats (media); - g_message ("object %p is prerolled", media); + GST_INFO ("object %p is prerolled", media); media->prepared = TRUE; @@ -1350,14 +1353,14 @@ was_prepared: /* ERRORS */ state_failed: { - g_warning ("failed to preroll pipeline"); + GST_WARNING ("failed to preroll pipeline"); unlock_streams (media); gst_element_set_state (media->pipeline, GST_STATE_NULL); return FALSE; } is_reused: { - g_warning ("can not reuse media %p", media); + GST_WARNING ("can not reuse media %p", media); return FALSE; } } @@ -1381,7 +1384,7 @@ gst_rtsp_media_unprepare (GstRTSPMedia *media) if (!media->prepared) return TRUE; - g_message ("unprepare media %p", media); + GST_INFO ("unprepare media %p", media); media->target_state = GST_STATE_NULL; klass = GST_RTSP_MEDIA_GET_CLASS (media); @@ -1435,7 +1438,7 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport add = remove = FALSE; - g_message ("going to state %s media %p", gst_element_state_get_name (state), media); + GST_INFO ("going to state %s media %p", gst_element_state_get_name (state), media); switch (state) { case GST_STATE_NULL: @@ -1484,14 +1487,14 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport max = trans->client_port.max; if (add && !tr->active) { - g_message ("adding %s:%d-%d", dest, min, max); + GST_INFO ("adding %s:%d-%d", dest, min, max); g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); stream->transports = g_list_prepend (stream->transports, tr); tr->active = TRUE; media->active++; } else if (remove && tr->active) { - g_message ("removing %s:%d-%d", dest, min, max); + GST_INFO ("removing %s:%d-%d", dest, min, max); g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); stream->transports = g_list_remove (stream->transports, tr); @@ -1502,19 +1505,19 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport } case GST_RTSP_LOWER_TRANS_TCP: if (add && !tr->active) { - g_message ("adding TCP %s", trans->destination); + GST_INFO ("adding TCP %s", trans->destination); stream->transports = g_list_prepend (stream->transports, tr); tr->active = TRUE; media->active++; } else if (remove && tr->active) { - g_message ("removing TCP %s", trans->destination); + GST_INFO ("removing TCP %s", trans->destination); stream->transports = g_list_remove (stream->transports, tr); tr->active = FALSE; media->active--; } break; default: - g_message ("Unknown transport %d", trans->lower_transport); + GST_INFO ("Unknown transport %d", trans->lower_transport); break; } } @@ -1528,13 +1531,13 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport else do_state = FALSE; - g_message ("active %d media %p", media->active, media); + GST_INFO ("active %d media %p", media->active, media); if (do_state && media->target_state != state) { if (state == GST_STATE_NULL) { gst_rtsp_media_unprepare (media); } else { - g_message ("state %s media %p", gst_element_state_get_name (state), media); + GST_INFO ("state %s media %p", gst_element_state_get_name (state), media); media->target_state = state; ret = gst_element_set_state (media->pipeline, state); } @@ -1563,7 +1566,7 @@ gst_rtsp_media_remove_elements (GstRTSPMedia *media) for (i = 0; i < media->streams->len; i++) { GstRTSPMediaStream *stream; - g_message ("Removing elements of stream %d from pipeline", i); + GST_INFO ("Removing elements of stream %d from pipeline", i); stream = g_array_index (media->streams, GstRTSPMediaStream *, i); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 0d1353d89b..3d690f8d53 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -37,6 +37,9 @@ enum G_DEFINE_TYPE (GstRTSPServer, gst_rtsp_server, G_TYPE_OBJECT); +GST_DEBUG_CATEGORY_STATIC (rtsp_server_debug); +#define GST_CAT_DEFAULT rtsp_server_debug + static void gst_rtsp_server_get_property (GObject *object, guint propid, GValue *value, GParamSpec *pspec); static void gst_rtsp_server_set_property (GObject *object, guint propid, @@ -102,6 +105,8 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); klass->accept_client = default_accept_client; + + GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer"); } static void @@ -399,7 +404,7 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) "listened on server socket %d, returning from connection setup", server->server_sock.fd); - g_message ("listening on port %d", server->port); + GST_INFO_OBJECT (server, "listening on port %d", server->port); return TRUE; @@ -474,7 +479,7 @@ default_accept_client (GstRTSPServer *server, GIOChannel *channel) /* ERRORS */ accept_failed: { - g_error ("Could not accept client on server socket %d: %s (%d)", + GST_ERROR_OBJECT (server, "Could not accept client on server socket %d: %s (%d)", server->server_sock.fd, g_strerror (errno), errno); gst_object_unref (client); return NULL; @@ -511,7 +516,7 @@ gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, GstRTSPSer gst_object_unref (client); } else { - g_print ("received unknown event %08x", condition); + GST_WARNING_OBJECT (server, "received unknown event %08x", condition); } return TRUE; diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 7c68da1396..8fec319697 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -30,6 +30,9 @@ enum PROP_LAST }; +GST_DEBUG_CATEGORY (rtsp_session_debug); +#define GST_CAT_DEFAULT rtsp_session_debug + static void gst_rtsp_session_pool_get_property (GObject *object, guint propid, GValue *value, GParamSpec *pspec); static void gst_rtsp_session_pool_set_property (GObject *object, guint propid, @@ -59,6 +62,7 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) klass->create_session_id = create_session_id; + GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0, "GstRTSPSession"); } static void @@ -300,24 +304,24 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool *pool) /* ERRORS */ no_function: { - g_warning ("no create_session_id vmethod in GstRTSPSessionPool %p", pool); + GST_WARNING ("no create_session_id vmethod in GstRTSPSessionPool %p", pool); return NULL; } no_session: { - g_warning ("can't create session id with GstRTSPSessionPool %p", pool); + GST_WARNING ("can't create session id with GstRTSPSessionPool %p", pool); return NULL; } collision: { - g_warning ("can't find unique sessionid for GstRTSPSessionPool %p", pool); + GST_WARNING ("can't find unique sessionid for GstRTSPSessionPool %p", pool); g_mutex_unlock (pool->lock); g_free (id); return NULL; } too_many_sessions: { - g_warning ("session pool reached max sessions of %d", pool->max_sessions); + GST_WARNING ("session pool reached max sessions of %d", pool->max_sessions); g_mutex_unlock (pool->lock); g_free (id); return NULL; @@ -464,7 +468,7 @@ collect_timeout (gchar *sessionid, GstRTSPSession *sess, GstPoolSource *psrc) g_source_get_current_time ((GSource*)psrc, &now); timeout = gst_rtsp_session_next_timeout (sess, &now); - g_message ("%p: next timeout: %d", sess, timeout); + GST_INFO ("%p: next timeout: %d", sess, timeout); if (psrc->timeout == -1 || timeout < psrc->timeout) psrc->timeout = timeout; } @@ -487,7 +491,7 @@ gst_pool_source_prepare (GSource * source, gint * timeout) result = psrc->timeout == 0; - g_message ("prepare %d, %d", psrc->timeout, result); + GST_INFO ("prepare %d, %d", psrc->timeout, result); return result; } @@ -495,7 +499,7 @@ gst_pool_source_prepare (GSource * source, gint * timeout) static gboolean gst_pool_source_check (GSource * source) { - g_message ("check"); + GST_INFO ("check"); return gst_pool_source_prepare (source, NULL); } @@ -508,7 +512,7 @@ gst_pool_source_dispatch (GSource * source, GSourceFunc callback, GstPoolSource *psrc = (GstPoolSource *) source; GstRTSPSessionPoolFunc func = (GstRTSPSessionPoolFunc) callback; - g_message ("dispatch"); + GST_INFO ("dispatch"); if (func) res = func (psrc->pool, user_data); @@ -523,7 +527,7 @@ gst_pool_source_finalize (GSource * source) { GstPoolSource *psrc = (GstPoolSource *) source; - g_message ("finalize %p", psrc); + GST_INFO ("finalize %p", psrc); g_object_unref (psrc->pool); psrc->pool = NULL; diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 7525036445..ea33fa05bb 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -32,6 +32,9 @@ enum PROP_LAST }; +GST_DEBUG_CATEGORY_EXTERN (rtsp_session_debug); +#define GST_CAT_DEFAULT rtsp_session_debug + static void gst_rtsp_session_get_property (GObject *object, guint propid, GValue *value, GParamSpec *pspec); static void gst_rtsp_session_set_property (GObject *object, guint propid, @@ -72,7 +75,7 @@ gst_rtsp_session_init (GstRTSPSession * session) static void gst_rtsp_session_free_stream (GstRTSPSessionStream *stream) { - g_message ("free session stream %p", stream); + GST_INFO ("free session stream %p", stream); /* remove callbacks now */ gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); @@ -91,7 +94,7 @@ gst_rtsp_session_free_media (GstRTSPSessionMedia *media, GstRTSPSession *session size = media->streams->len; - g_message ("free session media %p", media); + GST_INFO ("free session media %p", media); gst_rtsp_session_media_set_state (media, GST_STATE_NULL); @@ -121,7 +124,7 @@ gst_rtsp_session_finalize (GObject * obj) session = GST_RTSP_SESSION (obj); - g_message ("finalize session %p", session); + GST_INFO ("finalize session %p", session); /* free all media */ g_list_foreach (session->medias, (GFunc) gst_rtsp_session_free_media, @@ -208,7 +211,7 @@ gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, sess->medias = g_list_prepend (sess->medias, result); - g_message ("manage new media %p in session %p", media, result); + GST_INFO ("manage new media %p in session %p", media, result); return result; } From 3d7610b03303efcf241b458c34d647eb60d8c849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Sat, 21 Nov 2009 01:17:25 +0100 Subject: [PATCH 0155/1776] client: dump rtsp message only if debug threshold is higher than GST_LEVEL_LOG --- gst/rtsp-server/rtsp-client.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 22477b28e9..c8f75dc74f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -23,8 +23,6 @@ #include "rtsp-sdp.h" #include "rtsp-params.h" -#define DEBUG - static GMutex *tunnels_lock; static GHashTable *tunnels; @@ -191,9 +189,10 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION, str); } -#ifdef DEBUG - gst_rtsp_message_dump (response); -#endif + + if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) { + gst_rtsp_message_dump (response); + } gst_rtsp_watch_send_message (client->watch, response, NULL); gst_rtsp_message_unset (response); @@ -1064,9 +1063,9 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) GstRTSPSession *session; gchar *sessid; -#ifdef DEBUG - gst_rtsp_message_dump (request); -#endif + if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) { + gst_rtsp_message_dump (request); + } GST_INFO ("client %p: received a request", client); From 92eb244215911399d487fd97dcdbb363bfc7c431 Mon Sep 17 00:00:00 2001 From: Nikolay Ivanov Date: Fri, 25 Dec 2009 15:22:23 +0100 Subject: [PATCH 0156/1776] sdp: make server work better when behind a proxy --- gst/rtsp-server/rtsp-sdp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 264168a922..2a284c3dff 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -47,6 +47,7 @@ gst_rtsp_sdp_from_media (GstRTSPMedia *media) gst_sdp_message_add_time (sdp, "0", "0", NULL); gst_sdp_message_add_attribute (sdp, "tool", "GStreamer"); gst_sdp_message_add_attribute (sdp, "type", "broadcast"); + gst_sdp_message_add_attribute (sdp, "control", "*"); rangestr = gst_rtsp_range_to_string (&media->range); gst_sdp_message_add_attribute (sdp, "range", rangestr); g_free (rangestr); From 996112db95b0e931a67a34b1fa236d36a16e4c4e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 25 Dec 2009 18:24:10 +0100 Subject: [PATCH 0157/1776] docs: update docs and comments --- docs/README | 174 +++++++++++++++++++++++++--------- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-server.c | 3 +- 3 files changed, 130 insertions(+), 49 deletions(-) diff --git a/docs/README b/docs/README index 76d4ab9807..50ad82f4ff 100644 --- a/docs/README +++ b/docs/README @@ -103,7 +103,7 @@ can build simple server applications with it. alternative implementation can be used by the server. The GstRTSPMediaMapping object is more interesting and needs more configuration - before the server object is useful. This object manages to mapping from a + before the server object is useful. This object manages the mapping from a request URL to a specific stream and its configuration. We explain in the next topic how to configure this object. @@ -202,7 +202,7 @@ can build simple server applications with it. have to be negotiated with the client in the SETUP requests. When preparing a GstRTSPMedia, a multifdsink is also constructed for streaming - the stream over TCP^when requested. + the stream over TCP when requested. * the GstRTSPClient object @@ -212,61 +212,143 @@ can build simple server applications with it. a new GstRTCPClient object, will configure the session pool and media mapper objects in it and will then call the accept function of the client. - The default GstRTSPClient will accept the connection and will start a new - GThread to handle the connection. In RTSP it is usual to keep the connection - open between multiple RTSP requests. The client thread will simply block for a - new GstRTSPMessage, will dispatch it and will send a response. + The default GstRTSPClient will accept the connection and will attach a watch to + the server mainloop. In RTSP it is usual to keep the connection + open between multiple RTSP requests. The client watch will be dispatched by the + server mainloop when a new GstRTSPMessage is received, which will then be + handled and a response will be sent. + + The GstRTSPClient object remains alive for as long as a client has a TCP + connection open with the server. Since is possible for a client to open and close + the TCP connection between requests, we cannot store the state related + to the configured RTSP session in the GstRTSPClient object. This server state + is instead stored in the GstRTSPSession object. + + +* GstRTSPSession + + This object contains state about a specific RTSP session identified with a + session id. This state contains the configured streams and their associated + transports. - We will briefly describe how it deals with some common requests. + When a GstRTSPClient performs a SETUP request, the server will allocate a new + GstRTSPSession with a unique session id from the GstRTSPSessionPool. The pool + maintains a list of all existing sessions and makes sure that no session id is + used multiple times. The session id is sent to the client so that the client + can refer to its previously configured state by sending the session id in + further requests. - - DESCRIBE: + A client will then use the session id to configure one or more streams, + identified by their url. This information is kept in a GstRTSPSessionMedia + structure that is refered to from the GstRTSPSession. - locates the GstRTSPMedia for the url, prepares it and asks the sdp helper - function to construct an SDP from the caps of the prepared media pipeline. - It will also cache the url+media object so that it can be reused later. + +* GstRTSPSessionMedia and GstRTSPSessionStream + + A GstRTSPSessionMedia is identified by a URL and is referenced by a + GstRTSPSession. It is created as soon as a client performs a SETUP operation on + a particular URL. It will contain a link to the GstRTSPMedia object associated + with the URL along with the state of the media and the configured transports + for each of the streams in the media. + + Each SETUP request performed by the client will configure a + GstRTSPSessionStream object linked to by the GstRTSPSessionMedia structure. + It will contain the transport information needed to send this stream to the + client. The GstRTSPSessionStream also contains a link to the GstRTSPMediaStream + object that generates the actual data to be streamed to the client. + + Note how GstRTSPMedia and GstRTSPMediaStream (the providers of the data to + stream) are decoupled from GstRTSPSessionMedia and GstRTSPSessionStream (the + configuration of how to send this stream to a client) in order to be able to + send the data of one GstRTSPMedia to multiple clients. + + +* media control + + After a client has configured the transports for a GstRTSPMedia and its + GstRTSPMediaStreams, the client can play/pause/stop the stream. + + The GstRTSPMedia object was prepared in the DESCRIBE call (or during SETUP when + the client skipped the DESCRIBE request). As seen earlier, this configures a + couple of multiudpsink and udpsrc elements to respectively send and receive the + media to clients. + + When a client performs a PLAY request, its configured destination UDP ports are + added to the GstRTSPMediaStream target destinations, at which point data will + be sent to the client. The corresponding GstRTSPMedia object will be set to the + PLAYING state if it was not allready in order to send the data to the + destination. + + The server needs to prepare an RTP-Info header field in the PLAY response, + which consists of the sequence number and the RTP timestamp of the next RTP + packet. In order to achive this, the server queries the payloaders for this + information when it prerolled the pipeline. + + When a client performs a PAUSE request, the destination UDP ports are removed + from the GstRTSPMediaStream object and the GstRTSPMedia object is set to PAUSED + if no other destinations are configured anymore. + + +* seeking + + A seek is performed when a client sends a Range header in the PLAY request. + This only works when not dealing with shared (live) streams. + + The server performs a GStreamer flushing seek on the media, waits for the + pipeline to preroll again and then responds to the client after collecting the + new RTP sequence number and timestamp from the payloaders. + + +* session management + + The server has to react to clients that suddenly disappear because of network + problems or otherwise. It needs to make sure that it can reasonable free the + resources that are used by the various objects in use for streaming when the + client appears to be gone. + + Each of the GstRTSPSession objects managed by a GstRTSPSessionPool has + therefore a last_access field that contains the timestamp of when activity from + a client was last recorded. - - SETUP - - A new GstRTSPSession object will be created from the GstRTSPSessionPool - object configured in the GstRTSPClient. This session will contain the - configuration of the client regarding the media it is streaming and the - ports/transport it negotiated with the server. - - The sessionid is set in the response header. The client will add the - sessionid to any further SETUP/PLAY/PAUSE/TEARDOWN request so that we can - always find the session again. - - The session configuration for a sessionid will have a link to the prepared - GstRTSPMedia object of the stream. The port and transport of the client is - stored in the session configuration. - - - PLAY - - The session configuration is retrieved with the sessionid and the client - ports are configured in the UDP sinks, then the streaming to the client - is started. - - - PAUSE - - The session configuration is retrieved with the sessionid and the client - ports are removed from the UDP sinks, the streaming to the client - pauses. - - - TEARDOWN - - The session configuration is released along with its link to the - GstRTSPMedia object. When no more clients are refering to the GstRTSPMedia - object, it can be released as well. - - - + Various ways exist to detect activity from a client: + - RTSP keepalive requests. When a client is receiving RTP data, the RTSP TCP + connection is largely unused. It is the client responsability to + periodically send keep-alive requests over the TCP channel. + Whenever a keep-alive request is received by the server (any request that + contains a session id, usually an OPTION or GET_PARAMETER request) the + last_access of the session is updated. + - Since it is not required for a client to keep the RTSP TCP connection open + while streaming, gst-rtsp-server also detects activity from clients by + looking at the RTCP messages it receives. + When an RTCP message is received from a client, the server looks in its list + of active ports if this message originates from a known host/port pair that + is currently active in a GstRTSPSession. If this is the case, the session is + kept alive. + Since the server does not know anything about the port number that will be + used by the client to send RTCP, this method does not always work. Later + RTSP RFCs will include support for negotiating this port number with the + server. Most clients however use the same port number for sending and + receiving RTCP exactly for this reason. + If there was no activity in a particular session for a long time (by default 60 + seconds), the sessionpool will destroy the session along with all related + objects and media as if a TEARDOWN happened from the client. +* TEARDOWN + + A TEARDOWN request will first location the GstRTSPSessionMedia of the URL. It + will then remove all transports from the streams, making sure that streaming + stops to the client. It will then remove the GstRTSPSessionMedia and + GstRTSPSessionStream structures. Finally the GstRTSPSession is released back + into the pool. + + When there are no more references to the GstRTSPMedia, the media pipeline is + shut down and destroyed. diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c8f75dc74f..ee76abc9f4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1475,7 +1475,7 @@ static GstRTSPWatchFuncs watch_funcs = { * @client: a #GstRTSPClient * @channel: a #GIOChannel * - * Accept a new connection for @client on the socket in @source. + * Accept a new connection for @client on the socket in @channel. * * This function should be called when the client properties and urls are fully * configured and the client is ready to start. diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 3d690f8d53..489224f395 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -464,8 +464,7 @@ default_accept_client (GstRTSPServer *server, GIOChannel *channel) /* set the session pool that this client should use */ gst_rtsp_client_set_session_pool (client, server->session_pool); - - /* set the session pool that this client should use */ + /* set the media mapping that this client should use */ gst_rtsp_client_set_media_mapping (client, server->media_mapping); /* accept connections for that client, this function returns after accepting From ce6724f788ceac7b95a523d379f27b2d863ed605 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 27 Jan 2010 18:38:27 +0100 Subject: [PATCH 0158/1776] rtsp-client: implement error_full Implement error_full to avoid some segfaults when the rtspconnection calls it. See #608245 --- gst/rtsp-server/rtsp-client.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index ee76abc9f4..1de0bacce0 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1369,6 +1369,21 @@ error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data) return GST_RTSP_OK; } +static GstRTSPResult +error_full (GstRTSPWatch *watch, GstRTSPResult result, + GstRTSPMessage *message, guint id, gpointer user_data) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + gchar *str; + + str = gst_rtsp_strresult (result); + GST_INFO ("client %p: received an error %s when handling message %p with id %d", + client, str, message, id); + g_free (str); + + return GST_RTSP_OK; +} + static GstRTSPStatusCode tunnel_start (GstRTSPWatch * watch, gpointer user_data) { @@ -1467,7 +1482,8 @@ static GstRTSPWatchFuncs watch_funcs = { closed, error, tunnel_start, - tunnel_complete + tunnel_complete, + error_full }; /** From 63addbc278c653c120c85a0fd16be7811a79559e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Mar 2010 13:27:18 +0100 Subject: [PATCH 0159/1776] session: handle transport setup correctly Handle UDP, MCAST and TCP transport negotiation more correctly. Store the server session SSRC in the transport. --- gst/rtsp-server/rtsp-session.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index ea33fa05bb..b45530b875 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -491,9 +491,24 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, st->trans = ct->trans; st->profile = ct->profile; st->lower_transport = ct->lower_transport; - st->client_port = ct->client_port; - st->interleaved = ct->interleaved; - st->server_port = stream->media_stream->server_port; + + switch (st->lower_transport) { + case GST_RTSP_LOWER_TRANS_UDP: + st->client_port = ct->client_port; + st->server_port = stream->media_stream->server_port; + break; + case GST_RTSP_LOWER_TRANS_UDP_MCAST: + ct->port = st->port = stream->media_stream->server_port; + st->destination = g_strdup (ct->destination); + break; + case GST_RTSP_LOWER_TRANS_TCP: + st->interleaved = ct->interleaved; + default: + break; + } + + if (stream->media_stream->session) + g_object_get (stream->media_stream->session, "internal-ssrc", &st->ssrc, NULL); /* keep track of the transports in the stream. */ if (stream->trans.transport) From 53f8350b364a6164c0f37f605170d07778719630 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Mar 2010 13:28:58 +0100 Subject: [PATCH 0160/1776] media: set multicast sink parameters Disable loop and automatic multicast join on the udpsink elements. Add some more debug info. Reset some state variables in the right place. Use the right port numbers for multicast. --- gst/rtsp-server/rtsp-media.c | 97 +++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 40 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 70de6fd652..71dd1d4a56 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -107,8 +107,6 @@ static void gst_rtsp_media_init (GstRTSPMedia * media) { media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); - media->is_live = FALSE; - media->buffering = FALSE; } static void @@ -248,7 +246,7 @@ collect_media_stats (GstRTSPMedia *media) } GST_INFO ("stats: position %"GST_TIME_FORMAT", duration %"GST_TIME_FORMAT, - GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); + GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); if (position == -1) { media->range.min.type = GST_RTSP_TIME_NOW; @@ -461,10 +459,10 @@ gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range) if (start != -1 || stop != -1) { GST_INFO ("seeking to %"GST_TIME_FORMAT" - %"GST_TIME_FORMAT, - GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); + GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); res = gst_element_seek (media->pipeline, 1.0, GST_FORMAT_TIME, - flags, start_type, start, stop_type, stop); + flags, start_type, start, stop_type, stop); /* and block for the seek to complete */ GST_INFO ("done seeking %d", res); @@ -647,6 +645,11 @@ again: g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); + g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL); + g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "auto-multicast", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL); + /* we keep these elements, we configure all in configure_transport when the * server told us to really use the UDP ports. */ stream->udpsrc[0] = udpsrc0; @@ -786,8 +789,8 @@ on_new_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) if ((trans = find_transport (stream, rtcp_from))) { GST_INFO ("%p: found transport %p for source %p", stream, trans, source); - /* keep ref to the source */ - trans->rtpsource = source; + /* keep ref to the source */ + trans->rtpsource = source; g_object_set_qdata (source, ssrc_stream_map_key, trans); } @@ -927,7 +930,7 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsink[i]); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsrc[i]); gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]), - &sink_cb, stream, NULL); + &sink_cb, stream, NULL); } /* hook up the stream to the RTP session elements. */ @@ -949,7 +952,7 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) /* get the session */ g_signal_emit_by_name (media->rtpbin, "get-internal-session", idx, - &stream->session); + &stream->session); g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc, stream); @@ -1121,20 +1124,20 @@ default_handle_message (GstRTSPMedia *media, GstMessage *message) GST_INFO ("Buffering done, setting pipeline to PLAYING"); gst_element_set_state (media->pipeline, GST_STATE_PLAYING); } - else { + else { GST_INFO ("Buffering done"); - } + } } else { /* buffering busy */ if (media->buffering == FALSE) { - if (media->target_state == GST_STATE_PLAYING) { + if (media->target_state == GST_STATE_PLAYING) { /* we were not buffering but PLAYING, PAUSE the pipeline. */ GST_INFO ("Buffering, setting pipeline to PAUSED ..."); gst_element_set_state (media->pipeline, GST_STATE_PAUSED); - } - else { + } + else { GST_INFO ("Buffering ..."); - } + } } media->buffering = TRUE; } @@ -1273,6 +1276,10 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) GST_INFO ("preparing media %p", media); + /* reset some variables */ + media->is_live = FALSE; + media->buffering = FALSE; + bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline)); /* add the pipeline bus to our custom mainloop */ @@ -1306,22 +1313,27 @@ gst_rtsp_media_prepare (GstRTSPMedia *media) g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media); g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media); + /* we add a fakesink here in order to make the state change async. We remove + * the fakesink again in the no-more-pads callback. */ media->fakesink = gst_element_factory_make ("fakesink", "fakesink"); gst_bin_add (GST_BIN (media->pipeline), media->fakesink); } + GST_INFO ("setting pipeline to PAUSED for media %p", media); /* first go to PAUSED */ ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); media->target_state = GST_STATE_PAUSED; switch (ret) { case GST_STATE_CHANGE_SUCCESS: + GST_INFO ("SUCCESS state change for media %p", media); break; case GST_STATE_CHANGE_ASYNC: + GST_INFO ("ASYNC state change for media %p", media); break; case GST_STATE_CHANGE_NO_PREROLL: /* we need to go to PLAYING */ - GST_INFO ("live media %p", media); + GST_INFO ("NO_PREROLL state change: live media %p", media); media->is_live = TRUE; ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) @@ -1448,7 +1460,7 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport case GST_STATE_PAUSED: /* we're going from PLAYING to PAUSED, READY or NULL, remove */ if (media->target_state == GST_STATE_PLAYING) - remove = TRUE; + remove = TRUE; break; case GST_STATE_PLAYING: /* we're going to PLAYING, add */ @@ -1479,42 +1491,47 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport case GST_RTSP_LOWER_TRANS_UDP: case GST_RTSP_LOWER_TRANS_UDP_MCAST: { - gchar *dest; - gint min, max; + gchar *dest; + gint min, max; - dest = trans->destination; - min = trans->client_port.min; - max = trans->client_port.max; + dest = trans->destination; + if (trans->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + min = trans->port.min; + max = trans->port.max; + } else { + min = trans->client_port.min; + max = trans->client_port.max; + } - if (add && !tr->active) { + if (add && !tr->active) { GST_INFO ("adding %s:%d-%d", dest, min, max); g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); - stream->transports = g_list_prepend (stream->transports, tr); - tr->active = TRUE; - media->active++; - } else if (remove && tr->active) { + stream->transports = g_list_prepend (stream->transports, tr); + tr->active = TRUE; + media->active++; + } else if (remove && tr->active) { GST_INFO ("removing %s:%d-%d", dest, min, max); g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); - stream->transports = g_list_remove (stream->transports, tr); - tr->active = FALSE; - media->active--; - } + stream->transports = g_list_remove (stream->transports, tr); + tr->active = FALSE; + media->active--; + } break; } case GST_RTSP_LOWER_TRANS_TCP: - if (add && !tr->active) { + if (add && !tr->active) { GST_INFO ("adding TCP %s", trans->destination); - stream->transports = g_list_prepend (stream->transports, tr); - tr->active = TRUE; - media->active++; - } else if (remove && tr->active) { + stream->transports = g_list_prepend (stream->transports, tr); + tr->active = TRUE; + media->active++; + } else if (remove && tr->active) { GST_INFO ("removing TCP %s", trans->destination); - stream->transports = g_list_remove (stream->transports, tr); - tr->active = FALSE; - media->active--; - } + stream->transports = g_list_remove (stream->transports, tr); + tr->active = FALSE; + media->active--; + } break; default: GST_INFO ("Unknown transport %d", trans->lower_transport); From 73e8d6c69abcb51f2dadb3335b91f3c38e192549 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Mar 2010 13:31:37 +0100 Subject: [PATCH 0161/1776] client: rework transport parsing Rework the transport parsing code so that we can ignore transports we don't support instead of just picking the first one we can parse. Configure a (for now hardcoded) destination for multicast transports. --- gst/rtsp-server/rtsp-client.c | 57 +++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1de0bacce0..67f00375ff 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -739,16 +739,42 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, transports = g_strsplit (transport, ",", 0); gst_rtsp_transport_new (&ct); - /* loop through the transports, try to parse */ + /* init transports */ have_transport = FALSE; - for (i = 0; transports[i]; i++) { + gst_rtsp_transport_init (ct); - gst_rtsp_transport_init (ct); + /* our supported transports */ + supported = GST_RTSP_LOWER_TRANS_UDP | + GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP; + + /* loop through the transports, try to parse */ + for (i = 0; transports[i]; i++) { res = gst_rtsp_transport_parse (transports[i], ct); - if (res == GST_RTSP_OK) { - have_transport = TRUE; - break; + if (res != GST_RTSP_OK) { + /* no valid transport, search some more */ + GST_WARNING ("could not parse transport %s", transports[i]); + goto next; } + + /* we have a transport, see if it's RTP/AVP */ + if (ct->trans != GST_RTSP_TRANS_RTP || + ct->profile != GST_RTSP_PROFILE_AVP) { + GST_WARNING ("invalid transport %s", transports[i]); + goto next; + } + + if (!(ct->lower_transport & supported)) { + GST_WARNING ("unsupported transport %s", transports[i]); + goto next; + } + + /* we have a valid transport */ + GST_INFO ("found valid transport %s", transports[i]); + have_transport = TRUE; + break; + +next: + gst_rtsp_transport_init (ct); } g_strfreev (transports); @@ -756,24 +782,17 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, if (!have_transport) goto unsupported_transports; - /* we have a valid transport, check if we can handle it */ - if (ct->trans != GST_RTSP_TRANS_RTP) - goto unsupported_transports; - if (ct->profile != GST_RTSP_PROFILE_AVP) - goto unsupported_transports; - - supported = GST_RTSP_LOWER_TRANS_UDP | - GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP; - if (!(ct->lower_transport & supported)) - goto unsupported_transports; - if (client->session_pool == NULL) goto no_pool; /* we have a valid transport now, set the destination of the client. */ g_free (ct->destination); - url = gst_rtsp_connection_get_url (client->connection); - ct->destination = g_strdup (url->host); + if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + ct->destination = g_strdup ("224.2.0.1"); + } else { + url = gst_rtsp_connection_get_url (client->connection); + ct->destination = g_strdup (url->host); + } if (session) { g_object_ref (session); From 851e8aa744d2743e13c2a2fac76805f152c5dbf6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Mar 2010 13:34:15 +0100 Subject: [PATCH 0162/1776] media-factory: better error handling Improve the error handling a bit. --- gst/rtsp-server/rtsp-media-factory.c | 34 +++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 52f94714b8..44d80989cf 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -70,6 +70,9 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) * * The description should return a pipeline with payloaders named pay0, pay1, * etc.. Each of the payloaders will result in a stream. + * + * Support for dynamic payloaders can be accomplished by adding payloaders + * named dynpay0, dynpay1, etc.. */ g_object_class_install_property (gobject_class, PROP_LAUNCH, g_param_spec_string ("launch", "Launch", "A launch description of the pipeline", @@ -468,6 +471,9 @@ default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); + if (!klass->create_pipeline) + goto no_create; + if (klass->get_element) element = klass->get_element (factory, url); else @@ -479,16 +485,20 @@ default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) media = gst_rtsp_media_new (); media->element = element; - if (!klass->create_pipeline) - goto no_pipeline; - media->pipeline = klass->create_pipeline (factory, media); + if (media->pipeline == NULL) + goto no_pipeline; gst_rtsp_media_factory_collect_streams (factory, url, media); return media; /* ERRORS */ +no_create: + { + g_critical ("no create_pipeline function"); + return NULL; + } no_element: { g_critical ("could not create element"); @@ -496,19 +506,31 @@ no_element: } no_pipeline: { - g_critical ("could not create pipeline"); - return FALSE; + g_critical ("can't create pipeline"); + g_object_unref (media); + return NULL; } } static GstElement* -default_create_pipeline (GstRTSPMediaFactory *factory, GstRTSPMedia *media) { +default_create_pipeline (GstRTSPMediaFactory *factory, GstRTSPMedia *media) +{ GstElement *pipeline; + if (media->element == NULL) + goto no_element; + pipeline = gst_pipeline_new ("media-pipeline"); gst_bin_add (GST_BIN_CAST (pipeline), media->element); return pipeline; + + /* ERRORS */ +no_element: + { + g_critical ("no element"); + return NULL; + } } static void From d45eae2eddf71daba5f5377daf481bde052b2b45 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Mar 2010 16:20:08 +0100 Subject: [PATCH 0163/1776] media: reindent --- gst/rtsp-server/rtsp-media.c | 183 ++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 91 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 71dd1d4a56..986e6d7f76 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -49,16 +49,17 @@ GST_DEBUG_CATEGORY_EXTERN (rtsp_media_debug); static GQuark ssrc_stream_map_key; -static void gst_rtsp_media_get_property (GObject *object, guint propid, - GValue *value, GParamSpec *pspec); -static void gst_rtsp_media_set_property (GObject *object, guint propid, - const GValue *value, GParamSpec *pspec); +static void gst_rtsp_media_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec); +static void gst_rtsp_media_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec); static void gst_rtsp_media_finalize (GObject * obj); -static gpointer do_loop (GstRTSPMediaClass *klass); -static gboolean default_handle_message (GstRTSPMedia *media, GstMessage *message); -static gboolean default_unprepare (GstRTSPMedia *media); -static void unlock_streams (GstRTSPMedia *media); +static gpointer do_loop (GstRTSPMediaClass * klass); +static gboolean default_handle_message (GstRTSPMedia * media, + GstMessage * message); +static gboolean default_unprepare (GstRTSPMedia * media); +static void unlock_streams (GstRTSPMedia * media); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; @@ -77,8 +78,9 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) gobject_class->finalize = gst_rtsp_media_finalize; g_object_class_install_property (gobject_class, PROP_SHARED, - g_param_spec_boolean ("shared", "Shared", "If this media pipeline can be shared", - DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_boolean ("shared", "Shared", + "If this media pipeline can be shared", DEFAULT_SHARED, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_REUSABLE, g_param_spec_boolean ("reusable", "Reusable", @@ -110,7 +112,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) } static void -gst_rtsp_media_stream_free (GstRTSPMediaStream *stream) +gst_rtsp_media_stream_free (GstRTSPMediaStream * stream) { if (stream->session) g_object_unref (stream->session); @@ -171,8 +173,8 @@ gst_rtsp_media_finalize (GObject * obj) } static void -gst_rtsp_media_get_property (GObject *object, guint propid, - GValue *value, GParamSpec *pspec) +gst_rtsp_media_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec) { GstRTSPMedia *media = GST_RTSP_MEDIA (object); @@ -189,8 +191,8 @@ gst_rtsp_media_get_property (GObject *object, guint propid, } static void -gst_rtsp_media_set_property (GObject *object, guint propid, - const GValue *value, GParamSpec *pspec) +gst_rtsp_media_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec) { GstRTSPMedia *media = GST_RTSP_MEDIA (object); @@ -207,7 +209,7 @@ gst_rtsp_media_set_property (GObject *object, guint propid, } static gpointer -do_loop (GstRTSPMediaClass *klass) +do_loop (GstRTSPMediaClass * klass) { GST_INFO ("enter mainloop"); g_main_loop_run (klass->loop); @@ -217,7 +219,7 @@ do_loop (GstRTSPMediaClass *klass) } static void -collect_media_stats (GstRTSPMedia *media) +collect_media_stats (GstRTSPMedia * media) { GstFormat format; gint64 position, duration; @@ -229,8 +231,7 @@ collect_media_stats (GstRTSPMedia *media) media->range.min.seconds = -1; media->range.max.type = GST_RTSP_TIME_END; media->range.max.seconds = -1; - } - else { + } else { /* get the position */ format = GST_FORMAT_TIME; if (!gst_element_query_position (media->pipeline, &format, &position)) { @@ -245,24 +246,22 @@ collect_media_stats (GstRTSPMedia *media) duration = -1; } - GST_INFO ("stats: position %"GST_TIME_FORMAT", duration %"GST_TIME_FORMAT, - GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); + GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %" + GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); if (position == -1) { media->range.min.type = GST_RTSP_TIME_NOW; media->range.min.seconds = -1; - } - else { + } else { media->range.min.type = GST_RTSP_TIME_SECONDS; - media->range.min.seconds = ((gdouble)position) / GST_SECOND; + media->range.min.seconds = ((gdouble) position) / GST_SECOND; } if (duration == -1) { media->range.max.type = GST_RTSP_TIME_END; media->range.max.seconds = -1; - } - else { + } else { media->range.max.type = GST_RTSP_TIME_SECONDS; - media->range.max.seconds = ((gdouble)duration) / GST_SECOND; + media->range.max.seconds = ((gdouble) duration) / GST_SECOND; } } } @@ -296,7 +295,7 @@ gst_rtsp_media_new (void) * pipeline. */ void -gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared) +gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared) { g_return_if_fail (GST_IS_RTSP_MEDIA (media)); @@ -312,7 +311,7 @@ gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared) * Returns: %TRUE if the media can be shared between clients. */ gboolean -gst_rtsp_media_is_shared (GstRTSPMedia *media) +gst_rtsp_media_is_shared (GstRTSPMedia * media) { g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); @@ -328,7 +327,7 @@ gst_rtsp_media_is_shared (GstRTSPMedia *media) * been unprepared. */ void -gst_rtsp_media_set_reusable (GstRTSPMedia *media, gboolean reusable) +gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable) { g_return_if_fail (GST_IS_RTSP_MEDIA (media)); @@ -344,7 +343,7 @@ gst_rtsp_media_set_reusable (GstRTSPMedia *media, gboolean reusable) * Returns: %TRUE if the media can be reused */ gboolean -gst_rtsp_media_is_reusable (GstRTSPMedia *media) +gst_rtsp_media_is_reusable (GstRTSPMedia * media) { g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); @@ -360,7 +359,7 @@ gst_rtsp_media_is_reusable (GstRTSPMedia *media) * Returns: The number of streams. */ guint -gst_rtsp_media_n_streams (GstRTSPMedia *media) +gst_rtsp_media_n_streams (GstRTSPMedia * media) { g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0); @@ -378,10 +377,10 @@ gst_rtsp_media_n_streams (GstRTSPMedia *media) * that index did not exist. */ GstRTSPMediaStream * -gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx) +gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) { GstRTSPMediaStream *res; - + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); if (idx < media->streams->len) @@ -402,7 +401,7 @@ gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx) * Returns: %TRUE on success. */ gboolean -gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range) +gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) { GstSeekFlags flags; gboolean res; @@ -456,10 +455,10 @@ gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range) default: goto weird_type; } - + if (start != -1 || stop != -1) { - GST_INFO ("seeking to %"GST_TIME_FORMAT" - %"GST_TIME_FORMAT, - GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); + GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, + GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); res = gst_element_seek (media->pipeline, 1.0, GST_FORMAT_TIME, flags, start_type, start, stop_type, stop); @@ -470,8 +469,7 @@ gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range) GST_INFO ("prerolled again"); collect_media_stats (media); - } - else { + } else { GST_INFO ("no seek needed"); res = TRUE; } @@ -504,7 +502,7 @@ weird_type: * Returns: a GstFlowReturn. */ GstFlowReturn -gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer) +gst_rtsp_media_stream_rtp (GstRTSPMediaStream * stream, GstBuffer * buffer) { GstFlowReturn ret; @@ -526,7 +524,7 @@ gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer) * Returns: a GstFlowReturn. */ GstFlowReturn -gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer) +gst_rtsp_media_stream_rtcp (GstRTSPMediaStream * stream, GstBuffer * buffer) { GstFlowReturn ret; @@ -721,7 +719,7 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) } static void -dump_structure (const GstStructure *s) +dump_structure (const GstStructure * s) { gchar *sstr; @@ -731,7 +729,7 @@ dump_structure (const GstStructure *s) } static GstRTSPMediaTrans * -find_transport (GstRTSPMediaStream *stream, const gchar *rtcp_from) +find_transport (GstRTSPMediaStream * stream, const gchar * rtcp_from) { GList *walk; GstRTSPMediaTrans *result = NULL; @@ -758,7 +756,8 @@ find_transport (GstRTSPMediaStream *stream, const gchar *rtcp_from) min = trans->transport->client_port.min; max = trans->transport->client_port.max; - if ((strcmp (trans->transport->destination, dest) == 0) && (min == port || max == port)) { + if ((strcmp (trans->transport->destination, dest) == 0) && (min == port + || max == port)) { result = trans; break; } @@ -769,7 +768,7 @@ find_transport (GstRTSPMediaStream *stream, const gchar *rtcp_from) } static void -on_new_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) +on_new_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream) { GstStructure *stats; GstRTSPMediaTrans *trans; @@ -787,7 +786,8 @@ on_new_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) rtcp_from = gst_structure_get_string (stats, "rtcp-from"); if ((trans = find_transport (stream, rtcp_from))) { - GST_INFO ("%p: found transport %p for source %p", stream, trans, source); + GST_INFO ("%p: found transport %p for source %p", stream, trans, + source); /* keep ref to the source */ trans->rtpsource = source; @@ -802,13 +802,14 @@ on_new_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) } static void -on_ssrc_sdes (GObject *session, GObject *source, GstRTSPMediaStream *stream) +on_ssrc_sdes (GObject * session, GObject * source, GstRTSPMediaStream * stream) { GST_INFO ("%p: new SDES %p", stream, source); } static void -on_ssrc_active (GObject *session, GObject *source, GstRTSPMediaStream *stream) +on_ssrc_active (GObject * session, GObject * source, + GstRTSPMediaStream * stream) { GstRTSPMediaTrans *trans; @@ -832,13 +833,14 @@ on_ssrc_active (GObject *session, GObject *source, GstRTSPMediaStream *stream) } static void -on_bye_ssrc (GObject *session, GObject *source, GstRTSPMediaStream *stream) +on_bye_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream) { GST_INFO ("%p: source %p bye", stream, source); } static void -on_bye_timeout (GObject *session, GObject *source, GstRTSPMediaStream *stream) +on_bye_timeout (GObject * session, GObject * source, + GstRTSPMediaStream * stream) { GstRTSPMediaTrans *trans; @@ -851,7 +853,7 @@ on_bye_timeout (GObject *session, GObject *source, GstRTSPMediaStream *stream) } static void -on_timeout (GObject *session, GObject *source, GstRTSPMediaStream *stream) +on_timeout (GObject * session, GObject * source, GstRTSPMediaStream * stream) { GstRTSPMediaTrans *trans; @@ -864,7 +866,7 @@ on_timeout (GObject *session, GObject *source, GstRTSPMediaStream *stream) } static GstFlowReturn -handle_new_buffer (GstAppSink *sink, gpointer user_data) +handle_new_buffer (GstAppSink * sink, gpointer user_data) { GList *walk; GstBuffer *buffer; @@ -880,11 +882,10 @@ handle_new_buffer (GstAppSink *sink, gpointer user_data) GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data; if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) { - if (tr->send_rtp) + if (tr->send_rtp) tr->send_rtp (buffer, tr->transport->interleaved.min, tr->user_data); - } - else { - if (tr->send_rtcp) + } else { + if (tr->send_rtcp) tr->send_rtcp (buffer, tr->transport->interleaved.max, tr->user_data); } } @@ -894,14 +895,14 @@ handle_new_buffer (GstAppSink *sink, gpointer user_data) } static GstAppSinkCallbacks sink_cb = { - NULL, /* not interested in EOS */ - NULL, /* not interested in preroll buffers */ + NULL, /* not interested in EOS */ + NULL, /* not interested in preroll buffers */ handle_new_buffer }; /* prepare the pipeline objects to handle @stream in @media */ static gboolean -setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) +setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) { gchar *name; GstPad *pad, *teepad, *selpad; @@ -930,7 +931,7 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsink[i]); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsrc[i]); gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]), - &sink_cb, stream, NULL); + &sink_cb, stream, NULL); } /* hook up the stream to the RTP session elements. */ @@ -952,18 +953,18 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) /* get the session */ g_signal_emit_by_name (media->rtpbin, "get-internal-session", idx, - &stream->session); + &stream->session); g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc, stream); g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes, stream); - g_signal_connect (stream->session, "on-ssrc-active", (GCallback) on_ssrc_active, - stream); + g_signal_connect (stream->session, "on-ssrc-active", + (GCallback) on_ssrc_active, stream); g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, stream); - g_signal_connect (stream->session, "on-bye-timeout", (GCallback) on_bye_timeout, - stream); + g_signal_connect (stream->session, "on-bye-timeout", + (GCallback) on_bye_timeout, stream); g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout, stream); @@ -1062,10 +1063,10 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media) gst_element_set_state (stream->udpsrc[1], GST_STATE_PLAYING); gst_element_set_locked_state (stream->udpsrc[0], TRUE); gst_element_set_locked_state (stream->udpsrc[1], TRUE); - + /* be notified of caps changes */ stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps", - (GCallback) caps_notify, stream); + (GCallback) caps_notify, stream); stream->prepared = TRUE; @@ -1080,7 +1081,7 @@ link_failed: } static void -unlock_streams (GstRTSPMedia *media) +unlock_streams (GstRTSPMedia * media) { guint i, n_streams; @@ -1097,7 +1098,7 @@ unlock_streams (GstRTSPMedia *media) } static gboolean -default_handle_message (GstRTSPMedia *media, GstMessage *message) +default_handle_message (GstRTSPMedia * media, GstMessage * message) { GstMessageType type; @@ -1123,8 +1124,7 @@ default_handle_message (GstRTSPMedia *media, GstMessage *message) if (media->target_state == GST_STATE_PLAYING) { GST_INFO ("Buffering done, setting pipeline to PLAYING"); gst_element_set_state (media->pipeline, GST_STATE_PLAYING); - } - else { + } else { GST_INFO ("Buffering done"); } } else { @@ -1134,8 +1134,7 @@ default_handle_message (GstRTSPMedia *media, GstMessage *message) /* we were not buffering but PLAYING, PAUSE the pipeline. */ GST_INFO ("Buffering, setting pipeline to PAUSED ..."); gst_element_set_state (media->pipeline, GST_STATE_PAUSED); - } - else { + } else { GST_INFO ("Buffering ..."); } } @@ -1175,18 +1174,19 @@ default_handle_message (GstRTSPMedia *media, GstMessage *message) case GST_MESSAGE_STREAM_STATUS: break; default: - GST_INFO ("%p: got message type %s", media, gst_message_type_get_name (type)); + GST_INFO ("%p: got message type %s", media, + gst_message_type_get_name (type)); break; } return TRUE; } static gboolean -bus_message (GstBus *bus, GstMessage *message, GstRTSPMedia *media) +bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media) { GstRTSPMediaClass *klass; gboolean ret; - + klass = GST_RTSP_MEDIA_GET_CLASS (media); if (klass->handle_message) @@ -1198,7 +1198,7 @@ bus_message (GstBus *bus, GstMessage *message, GstRTSPMedia *media) } static void -pad_added_cb (GstElement *element, GstPad *pad, GstRTSPMedia *media) +pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) { GstRTSPMediaStream *stream; gchar *name; @@ -1234,7 +1234,7 @@ pad_added_cb (GstElement *element, GstPad *pad, GstRTSPMedia *media) } static void -no_more_pads_cb (GstElement *element, GstRTSPMedia *media) +no_more_pads_cb (GstElement * element, GstRTSPMedia * media) { GST_INFO ("no more pads"); if (media->fakesink) { @@ -1260,7 +1260,7 @@ no_more_pads_cb (GstElement *element, GstRTSPMedia *media) * Returns: %TRUE on success. */ gboolean -gst_rtsp_media_prepare (GstRTSPMedia *media) +gst_rtsp_media_prepare (GstRTSPMedia * media) { GstStateChangeReturn ret; guint i, n_streams; @@ -1388,7 +1388,7 @@ is_reused: * Returns: %TRUE on success. */ gboolean -gst_rtsp_media_unprepare (GstRTSPMedia *media) +gst_rtsp_media_unprepare (GstRTSPMedia * media) { GstRTSPMediaClass *klass; gboolean success; @@ -1416,7 +1416,7 @@ gst_rtsp_media_unprepare (GstRTSPMedia *media) } static gboolean -default_unprepare (GstRTSPMedia *media) +default_unprepare (GstRTSPMedia * media) { gst_element_set_state (media->pipeline, GST_STATE_NULL); @@ -1434,7 +1434,8 @@ default_unprepare (GstRTSPMedia *media) * Returns: %TRUE on success. */ gboolean -gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transports) +gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, + GArray * transports) { gint i; GstStateChangeReturn ret; @@ -1450,7 +1451,8 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport add = remove = FALSE; - GST_INFO ("going to state %s media %p", gst_element_state_get_name (state), media); + GST_INFO ("going to state %s media %p", gst_element_state_get_name (state), + media); switch (state) { case GST_STATE_NULL: @@ -1574,21 +1576,21 @@ gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transport * Remove all elements and the pipeline controlled by @media. */ void -gst_rtsp_media_remove_elements (GstRTSPMedia *media) +gst_rtsp_media_remove_elements (GstRTSPMedia * media) { gint i, j; unlock_streams (media); - + for (i = 0; i < media->streams->len; i++) { GstRTSPMediaStream *stream; - + GST_INFO ("Removing elements of stream %d from pipeline", i); stream = g_array_index (media->streams, GstRTSPMediaStream *, i); - + gst_pad_unlink (stream->srcpad, stream->send_rtp_sink); - + g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig); for (j = 0; j < 2; j++) { @@ -1598,7 +1600,7 @@ gst_rtsp_media_remove_elements (GstRTSPMedia *media) gst_element_set_state (stream->appsink[j], GST_STATE_NULL); gst_element_set_state (stream->tee[j], GST_STATE_NULL); gst_element_set_state (stream->selector[j], GST_STATE_NULL); - + gst_bin_remove (GST_BIN (media->pipeline), stream->udpsrc[j]); gst_bin_remove (GST_BIN (media->pipeline), stream->udpsink[j]); gst_bin_remove (GST_BIN (media->pipeline), stream->appsrc[j]); @@ -1619,4 +1621,3 @@ gst_rtsp_media_remove_elements (GstRTSPMedia *media) gst_object_unref (media->pipeline); media->pipeline = NULL; } - From c7ca9b74eb18f1a27dfcd1b5f7bf1b174de89acb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Mar 2010 17:51:26 +0100 Subject: [PATCH 0164/1776] media: avoid doing _get_state() for state changes When preparing, use the ASYNC_DONE and ERROR messages in the bus handler to wait until the media is prerolled or in error. This avoids doing a blocking call of gst_element_get_state() that can cause lockups when there is an error. Fixes #611899 --- gst/rtsp-server/rtsp-media.c | 63 +++++++++++++++++++++++++++------- gst/rtsp-server/rtsp-media.h | 57 ++++++++++++++++++++---------- gst/rtsp-server/rtsp-session.c | 2 +- 3 files changed, 90 insertions(+), 32 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 986e6d7f76..a2fe5d3f5d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -109,6 +109,8 @@ static void gst_rtsp_media_init (GstRTSPMedia * media) { media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); + media->lock = g_mutex_new (); + media->cond = g_cond_new (); } static void @@ -168,6 +170,8 @@ gst_rtsp_media_finalize (GObject * obj) g_source_destroy (media->source); g_source_unref (media->source); } + g_mutex_free (media->lock); + g_cond_free (media->cond); G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); } @@ -467,8 +471,6 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GST_INFO ("done seeking %d", res); gst_element_get_state (media->pipeline, NULL, NULL, -1); GST_INFO ("prerolled again"); - - collect_media_stats (media); } else { GST_INFO ("no seek needed"); res = TRUE; @@ -1097,6 +1099,37 @@ unlock_streams (GstRTSPMedia * media) } } +static void +gst_rtsp_media_set_status (GstRTSPMedia *media, GstRTSPMediaStatus status) +{ + g_mutex_lock (media->lock); + /* never overwrite the error status */ + if (media->status != GST_RTSP_MEDIA_STATUS_ERROR) + media->status = status; + GST_DEBUG ("setting new status to %d", status); + g_cond_broadcast (media->cond); + g_mutex_unlock (media->lock); +} + +static GstRTSPMediaStatus +gst_rtsp_media_get_status (GstRTSPMedia *media) +{ + GstRTSPMediaStatus result; + + g_mutex_lock (media->lock); + /* while we are preparing, wait */ + while (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) { + GST_DEBUG ("waiting for status change"); + g_cond_wait (media->cond, media->lock); + } + /* could be success or error */ + result = media->status; + GST_DEBUG ("got status %d", result); + g_mutex_unlock (media->lock); + + return result; +} + static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message) { @@ -1156,6 +1189,8 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug); g_error_free (gerror); g_free (debug); + + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR); break; } case GST_MESSAGE_WARNING: @@ -1173,6 +1208,12 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) break; case GST_MESSAGE_STREAM_STATUS: break; + case GST_MESSAGE_ASYNC_DONE: + GST_INFO ("%p: got ASYNC_DONE", media); + collect_media_stats (media); + + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); + break; default: GST_INFO ("%p: got message type %s", media, gst_message_type_get_name (type)); @@ -1263,12 +1304,13 @@ gboolean gst_rtsp_media_prepare (GstRTSPMedia * media) { GstStateChangeReturn ret; + GstRTSPMediaStatus status; guint i, n_streams; GstRTSPMediaClass *klass; GstBus *bus; GList *walk; - if (media->prepared) + if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) goto was_prepared; if (!media->reusable && media->reused) @@ -1279,6 +1321,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) /* reset some variables */ media->is_live = FALSE; media->buffering = FALSE; + /* we're preparing now */ + media->status = GST_RTSP_MEDIA_STATUS_PREPARING; bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline)); @@ -1344,17 +1388,12 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) } /* now wait for all pads to be prerolled */ - ret = gst_element_get_state (media->pipeline, NULL, NULL, -1); - if (ret == GST_STATE_CHANGE_FAILURE) + status = gst_rtsp_media_get_status (media); + if (status == GST_RTSP_MEDIA_STATUS_ERROR) goto state_failed; - /* collect stats about the media */ - collect_media_stats (media); - GST_INFO ("object %p is prerolled", media); - media->prepared = TRUE; - return TRUE; /* OK */ @@ -1393,7 +1432,7 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) GstRTSPMediaClass *klass; gboolean success; - if (!media->prepared) + if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED) return TRUE; GST_INFO ("unprepare media %p", media); @@ -1405,7 +1444,7 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) else success = TRUE; - media->prepared = FALSE; + media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED; media->reused = TRUE; /* when the media is not reusable, this will effectively unref the media and diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index aa58aef970..b4c75cd980 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -139,13 +139,29 @@ struct _GstRTSPMediaStream { GList *transports; }; +/** + * GstRTSPMediaStatus: + * @GST_RTSP_MEDIA_STATUS_UNPREPARED: media pipeline not prerolled + * @GST_RTSP_MEDIA_STATUS_PREPARING: media pipeline is prerolling + * @GST_RTSP_MEDIA_STATUS_PREPARED: media pipeline is prerolled + * @GST_RTSP_MEDIA_STATUS_ERROR: media pipeline is in error + * + * The state of the media pipeline. + */ +typedef enum { + GST_RTSP_MEDIA_STATUS_UNPREPARED = 0, + GST_RTSP_MEDIA_STATUS_PREPARING = 1, + GST_RTSP_MEDIA_STATUS_PREPARED = 2, + GST_RTSP_MEDIA_STATUS_ERROR = 3 +} GstRTSPMediaStatus; + /** * GstRTSPMedia: * @shared: if this media can be shared between clients * @reusable: if this media can be reused after an unprepare * @element: the data providing element * @streams: the different streams provided by @element - * @prepared: if the media is prepared for streaming + * @status: the status of the media pipeline * @pipeline: the toplevel pipeline * @source: the bus watch for pipeline messages. * @id: the id of the watch @@ -161,33 +177,36 @@ struct _GstRTSPMediaStream { * This object is usually created from a #GstRTSPMediaFactory. */ struct _GstRTSPMedia { - GObject parent; + GObject parent; - gboolean shared; - gboolean reusable; - gboolean reused; + GMutex *lock; + GCond *cond; - GstElement *element; - GArray *streams; - GList *dynamic; - gboolean prepared; - gint active; + gboolean shared; + gboolean reusable; + gboolean reused; + + GstElement *element; + GArray *streams; + GList *dynamic; + GstRTSPMediaStatus status; + gint active; /* the pipeline for the media */ - GstElement *pipeline; - GstElement *fakesink; - GSource *source; - guint id; + GstElement *pipeline; + GstElement *fakesink; + GSource *source; + guint id; - gboolean is_live; - gboolean buffering; - GstState target_state; + gboolean is_live; + gboolean buffering; + GstState target_state; /* RTP session manager */ - GstElement *rtpbin; + GstElement *rtpbin; /* the range of media */ - GstRTSPTimeRange range; + GstRTSPTimeRange range; }; /** diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index b45530b875..31a371a39b 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -197,7 +197,7 @@ gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); g_return_val_if_fail (uri != NULL, NULL); g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - g_return_val_if_fail (media->prepared, NULL); + g_return_val_if_fail (media->status == GST_RTSP_MEDIA_STATUS_PREPARED, NULL); result = g_new0 (GstRTSPSessionMedia, 1); result->media = media; From f90c422e624333f849edfd5cefbe2837a6945143 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Mar 2010 17:57:08 +0100 Subject: [PATCH 0165/1776] sdp: reindent and check for prepared status --- gst/rtsp-server/rtsp-sdp.c | 39 ++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 2a284c3dff..7c1744b03b 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -29,19 +29,24 @@ * Returns: a new sdp message for @media. gst_sdp_message_free() after usage. */ GstSDPMessage * -gst_rtsp_sdp_from_media (GstRTSPMedia *media) +gst_rtsp_sdp_from_media (GstRTSPMedia * media) { GstSDPMessage *sdp; guint i, n_streams; gchar *rangestr; + if (media->status != GST_RTSP_MEDIA_STATUS_PREPARED) + goto not_prepared; + n_streams = gst_rtsp_media_n_streams (media); gst_sdp_message_new (&sdp); /* some standard things first */ gst_sdp_message_set_version (sdp, "0"); - gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", "IP4", "127.0.0.1"); + + gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", "IP4", + "127.0.0.1"); gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer"); gst_sdp_message_set_information (sdp, "rtsp-server"); gst_sdp_message_add_time (sdp, "0", "0", NULL); @@ -101,7 +106,7 @@ gst_rtsp_sdp_from_media (GstRTSPMedia *media) if (caps_enc) { if (caps_params) tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate, - caps_params); + caps_params); else tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate); @@ -125,25 +130,25 @@ gst_rtsp_sdp_from_media (GstRTSPMedia *media) fname = gst_structure_nth_field_name (s, j); /* filter out standard properties */ - if (!strcmp (fname, "media")) + if (!strcmp (fname, "media")) continue; - if (!strcmp (fname, "payload")) + if (!strcmp (fname, "payload")) continue; - if (!strcmp (fname, "clock-rate")) + if (!strcmp (fname, "clock-rate")) continue; - if (!strcmp (fname, "encoding-name")) + if (!strcmp (fname, "encoding-name")) continue; - if (!strcmp (fname, "encoding-params")) + if (!strcmp (fname, "encoding-params")) continue; - if (!strcmp (fname, "ssrc")) + if (!strcmp (fname, "ssrc")) continue; - if (!strcmp (fname, "clock-base")) + if (!strcmp (fname, "clock-base")) continue; - if (!strcmp (fname, "seqnum-base")) + if (!strcmp (fname, "seqnum-base")) continue; if ((fval = gst_structure_get_string (s, fname))) { - g_string_append_printf (fmtp, "%s%s=%s", first ? "":";", fname, fval); + g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval); first = FALSE; } } @@ -151,8 +156,7 @@ gst_rtsp_sdp_from_media (GstRTSPMedia *media) tmp = g_string_free (fmtp, FALSE); gst_sdp_media_add_attribute (smedia, "fmtp", tmp); g_free (tmp); - } - else { + } else { g_string_free (fmtp, TRUE); } gst_sdp_message_add_media (sdp, smedia); @@ -160,4 +164,11 @@ gst_rtsp_sdp_from_media (GstRTSPMedia *media) } return sdp; + + /* ERRORS */ +not_prepared: + { + GST_ERROR ("media %p is not prepared", media); + return NULL; + } } From 83ed2586841bb912ad1d6ba6cdf0da10b6c43f18 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Mar 2010 18:23:18 +0100 Subject: [PATCH 0166/1776] media: limit the time to wait to something huge Avoid waiting forever but limit the timeout to 20 seconds. --- gst/rtsp-server/rtsp-media.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index a2fe5d3f5d..116e806b83 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1115,12 +1115,18 @@ static GstRTSPMediaStatus gst_rtsp_media_get_status (GstRTSPMedia *media) { GstRTSPMediaStatus result; + GTimeVal timeout; g_mutex_lock (media->lock); + g_get_current_time (&timeout); + g_time_val_add (&timeout, 20 * G_USEC_PER_SEC); /* while we are preparing, wait */ while (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) { GST_DEBUG ("waiting for status change"); - g_cond_wait (media->cond, media->lock); + if (!g_cond_timed_wait (media->cond, media->lock, &timeout)) { + GST_DEBUG ("timeout, assuming error status"); + media->status = GST_RTSP_MEDIA_STATUS_ERROR; + } } /* could be success or error */ result = media->status; From e19c382bbb648068cd46bef1d39723f971aa8d53 Mon Sep 17 00:00:00 2001 From: Luca Ognibene Date: Fri, 5 Mar 2010 18:37:17 +0100 Subject: [PATCH 0167/1776] client: call unlink_streams in client finalize Fixes #599027 --- gst/rtsp-server/rtsp-client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 67f00375ff..b0e10e3aa8 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -46,6 +46,8 @@ static void gst_rtsp_client_finalize (GObject * obj); static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session); +static void unlink_streams (GstRTSPClient * client); + G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); static void @@ -99,6 +101,8 @@ gst_rtsp_client_finalize (GObject * obj) (GWeakNotify) client_session_finalized, client); } + unlink_streams (client); + g_list_free (client->sessions); gst_rtsp_connection_free (client->connection); From 2997806d438e38d290a99d0f677f9b7f1e9cb20f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Mar 2010 19:08:08 +0100 Subject: [PATCH 0168/1776] media: collect media position when seek completes --- gst/rtsp-server/rtsp-media.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 116e806b83..b77604559e 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -471,6 +471,8 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GST_INFO ("done seeking %d", res); gst_element_get_state (media->pipeline, NULL, NULL, -1); GST_INFO ("prerolled again"); + + collect_media_stats (media); } else { GST_INFO ("no seek needed"); res = TRUE; From 5f535ecf873fb4b0aafc1edd46a602ea3f521ff7 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Tue, 9 Mar 2010 10:27:38 +0100 Subject: [PATCH 0169/1776] rtspmedia: emit "unprepared" if _prepare fails. Emit the unprepared signal if gst_rtsp_media_prepare fails so that the media object is removed from its factory's cache. --- gst/rtsp-server/rtsp-media.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b77604559e..593b1d438c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1410,16 +1410,17 @@ was_prepared: return TRUE; } /* ERRORS */ +is_reused: + { + GST_WARNING ("can not reuse media %p", media); + return FALSE; + } state_failed: { GST_WARNING ("failed to preroll pipeline"); unlock_streams (media); gst_element_set_state (media->pipeline, GST_STATE_NULL); - return FALSE; - } -is_reused: - { - GST_WARNING ("can not reuse media %p", media); + gst_rtsp_media_unprepare (media); return FALSE; } } From 68804ff9840ccf9e55610e7445a895b1f0087526 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Mar 2010 13:41:33 +0100 Subject: [PATCH 0170/1776] test: catch server bind errors --- examples/test-video.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/test-video.c b/examples/test-video.c index 5ed8b1da85..0da6f1420f 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -60,7 +60,7 @@ main (int argc, char *argv[]) factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, "( " "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " - "ffenc_h263 ! rtph263pay name=pay0 pt=96 " + "x264enc ! rtph264pay name=pay0 pt=96 " "audiotestsrc ! audio/x-raw-int,rate=8000 ! " "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); @@ -72,7 +72,8 @@ main (int argc, char *argv[]) g_object_unref (mapping); /* attach the server to the default maincontext */ - gst_rtsp_server_attach (server, NULL); + if (gst_rtsp_server_attach (server, NULL) == 0) + goto failed; g_timeout_add_seconds (2, (GSourceFunc) timeout, server); @@ -80,4 +81,11 @@ main (int argc, char *argv[]) g_main_loop_run (loop); return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } } From 171e89c63a1c306c82e876e39f5094997c152b39 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Mar 2010 13:42:50 +0100 Subject: [PATCH 0171/1776] client: guard against invalid paths --- gst/rtsp-server/rtsp-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b0e10e3aa8..350291c0aa 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -721,8 +721,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, * always /stream=%d so we need to strip that off * parse the stream we need to configure, look for the stream in the abspath * first and then in the query. */ - if (!(pos = strstr (uri->abspath, "/stream="))) { - if (!(pos = strstr (uri->query, "/stream="))) + if (uri->abspath == NULL || !(pos = strstr (uri->abspath, "/stream="))) { + if (uri->query == NULL || !(pos = strstr (uri->query, "/stream="))) goto bad_request; } From b3814d4646fd2f205c37b75f12c93d0633c64999 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Mar 2010 13:43:29 +0100 Subject: [PATCH 0172/1776] client: make content-base better Use the URI formatting functions to make a content-base. Also make sure that there is a trailing / at the end. --- gst/rtsp-server/rtsp-client.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 350291c0aa..7065db9042 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -929,8 +929,8 @@ handle_describe_request (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPMessage response = { 0 }; GstRTSPResult res; GstSDPMessage *sdp; - guint i; - gchar *str; + guint i, str_len; + gchar *str, *content_base; GstRTSPMedia *media; /* check what kind of format is accepted, we don't really do anything with it @@ -964,9 +964,21 @@ handle_describe_request (GstRTSPClient * client, GstRTSPUrl * uri, "application/sdp"); /* content base for some clients that might screw up creating the setup uri */ - str = g_strdup_printf ("rtsp://%s:%u%s/", uri->host, uri->port, uri->abspath); - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_BASE, str); - g_free (str); + str = gst_rtsp_url_get_request_uri (uri); + str_len = strlen (str); + + /* check for trailing '/' and append one */ + if (str[str_len - 1] != '/') { + content_base = g_malloc (str_len + 1); + memcpy (content_base, str, str_len); + content_base[str_len] = '/'; + content_base[str_len+1] = '\0'; + g_free (str); + } else { + content_base = str; + } + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_BASE, content_base); + g_free (content_base); /* add SDP to the response body */ str = gst_sdp_message_as_text (sdp); From 1b0dc41534b5a2e6dfff55cc7d6d717f474ef222 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Mar 2010 13:44:20 +0100 Subject: [PATCH 0173/1776] media: update comments a little --- gst/rtsp-server/rtsp-media.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index b4c75cd980..e873c04569 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -157,12 +157,18 @@ typedef enum { /** * GstRTSPMedia: + * @lock: for protecting the object + * @cond: for signaling the object * @shared: if this media can be shared between clients * @reusable: if this media can be reused after an unprepare + * @reused: if this media has been reused * @element: the data providing element * @streams: the different streams provided by @element + * @dynamic: list of dynamic elements managed by @element * @status: the status of the media pipeline + * @active: the number of active connections * @pipeline: the toplevel pipeline + * @fakesink: for making state changes async * @source: the bus watch for pipeline messages. * @id: the id of the watch * @is_live: if the pipeline is live From 17bb89f1fc25f97f3c5b9443822acb9baab3b0ea Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Mar 2010 13:49:00 +0100 Subject: [PATCH 0174/1776] server: rework server part Allow setting a bind address, make sure we can deal with ipv6. Remove the port property and change with the service property. --- gst/rtsp-server/rtsp-server.c | 207 +++++++++++++++++++++++----------- gst/rtsp-server/rtsp-server.h | 16 ++- 2 files changed, 154 insertions(+), 69 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 489224f395..e51982f468 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -22,14 +22,18 @@ #include "rtsp-server.h" #include "rtsp-client.h" +#define DEFAULT_ADDRESS "0.0.0.0" +//#define DEFAULT_ADDRESS "::1" +#define DEFAULT_SERVICE "8554" #define DEFAULT_BACKLOG 5 -#define DEFAULT_PORT 8554 enum { PROP_0, + PROP_ADDRESS, + PROP_SERVICE, PROP_BACKLOG, - PROP_PORT, + PROP_SESSION_POOL, PROP_MEDIA_MAPPING, PROP_LAST @@ -51,15 +55,33 @@ static GstRTSPClient * default_accept_client (GstRTSPServer *server, static void gst_rtsp_server_class_init (GstRTSPServerClass * klass) -{ +{ GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); - + gobject_class->get_property = gst_rtsp_server_get_property; gobject_class->set_property = gst_rtsp_server_set_property; gobject_class->finalize = gst_rtsp_server_finalize; - + + /** + * GstRTSPServer::address + * + * The address of the server. This is the address where the server will + * listen on. + */ + g_object_class_install_property (gobject_class, PROP_ADDRESS, + g_param_spec_string ("address", "Address", "The address the server uses to listen on", + DEFAULT_ADDRESS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPServer::service + * + * The service of the server. This is either a string with the service name or + * a port number (as a string) the server will listen on. + */ + g_object_class_install_property (gobject_class, PROP_SERVICE, + g_param_spec_string ("service", "Service", "The service or port number the server uses to listen on", + DEFAULT_SERVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstRTSPServer::backlog * @@ -71,17 +93,8 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) */ g_object_class_install_property (gobject_class, PROP_BACKLOG, g_param_spec_int ("backlog", "Backlog", "The maximum length to which the queue " - "of pending connections may grow", + "of pending connections may grow", 0, G_MAXINT, DEFAULT_BACKLOG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - /** - * GstRTSPServer::port - * - * The session port of the server. This is the port where the server will - * listen on. - */ - g_object_class_install_property (gobject_class, PROP_PORT, - g_param_spec_int ("port", "Port", "The port the server uses to listen on", - 1, 65535, DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstRTSPServer::session-pool * @@ -91,7 +104,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) */ g_object_class_install_property (gobject_class, PROP_SESSION_POOL, g_param_spec_object ("session-pool", "Session Pool", - "The session pool to use for client session", + "The session pool to use for client session", GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstRTSPServer::media-mapping @@ -101,7 +114,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) */ g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING, g_param_spec_object ("media-mapping", "Media Mapping", - "The media mapping to use for client session", + "The media mapping to use for client session", GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); klass->accept_client = default_accept_client; @@ -112,7 +125,8 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) static void gst_rtsp_server_init (GstRTSPServer * server) { - server->port = DEFAULT_PORT; + server->address = g_strdup (DEFAULT_ADDRESS); + server->service = g_strdup (DEFAULT_SERVICE); server->backlog = DEFAULT_BACKLOG; server->session_pool = gst_rtsp_session_pool_new (); server->media_mapping = gst_rtsp_media_mapping_new (); @@ -123,6 +137,9 @@ gst_rtsp_server_finalize (GObject *object) { GstRTSPServer *server = GST_RTSP_SERVER (object); + g_free (server->address); + g_free (server->service); + g_object_unref (server->session_pool); g_object_unref (server->media_mapping); } @@ -143,38 +160,75 @@ gst_rtsp_server_new (void) } /** - * gst_rtsp_server_set_port: + * gst_rtsp_server_set_address: * @server: a #GstRTSPServer - * @port: the port + * @address: the address * - * Configure @server to accept connections on the given port. - * @port should be a port number between 1 and 65535. + * Configure @server to accept connections on the given address. * * This function must be called before the server is bound. */ void -gst_rtsp_server_set_port (GstRTSPServer *server, gint port) +gst_rtsp_server_set_address (GstRTSPServer *server, const gchar *address) { g_return_if_fail (GST_IS_RTSP_SERVER (server)); - g_return_if_fail (port >= 1 && port <= 65535); + g_return_if_fail (address != NULL); - server->port = port; + g_free (server->address); + server->address = g_strdup (address); } /** - * gst_rtsp_server_get_port: + * gst_rtsp_server_get_address: * @server: a #GstRTSPServer * - * Get the port number on which the server will accept connections. + * Get the address on which the server will accept connections. * - * Returns: the server port. + * Returns: the server address. g_free() after usage. */ -gint -gst_rtsp_server_get_port (GstRTSPServer *server) +gchar * +gst_rtsp_server_get_address (GstRTSPServer *server) { - g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1); + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - return server->port; + return g_strdup (server->address); +} + +/** + * gst_rtsp_server_set_service: + * @server: a #GstRTSPServer + * @service: the service + * + * Configure @server to accept connections on the given service. + * @service should be a string containing the service name (see services(5)) or + * a string containing a port number between 1 and 65535. + * + * This function must be called before the server is bound. + */ +void +gst_rtsp_server_set_service (GstRTSPServer *server, const gchar *service) +{ + g_return_if_fail (GST_IS_RTSP_SERVER (server)); + g_return_if_fail (service != NULL); + + g_free (server->service); + server->service = g_strdup (service); +} + +/** + * gst_rtsp_server_get_service: + * @server: a #GstRTSPServer + * + * Get the service on which the server will accept connections. + * + * Returns: the service. use g_free() after usage. + */ +gchar * +gst_rtsp_server_get_service (GstRTSPServer *server) +{ + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + + return g_strdup (server->service); } /** @@ -313,8 +367,11 @@ gst_rtsp_server_get_property (GObject *object, guint propid, GstRTSPServer *server = GST_RTSP_SERVER (object); switch (propid) { - case PROP_PORT: - g_value_set_int (value, gst_rtsp_server_get_port (server)); + case PROP_ADDRESS: + g_value_take_string (value, gst_rtsp_server_get_address (server)); + break; + case PROP_SERVICE: + g_value_take_string (value, gst_rtsp_server_get_service (server)); break; case PROP_BACKLOG: g_value_set_int (value, gst_rtsp_server_get_backlog (server)); @@ -337,8 +394,11 @@ gst_rtsp_server_set_property (GObject *object, guint propid, GstRTSPServer *server = GST_RTSP_SERVER (object); switch (propid) { - case PROP_PORT: - gst_rtsp_server_set_port (server, g_value_get_int (value)); + case PROP_ADDRESS: + gst_rtsp_server_set_address (server, g_value_get_string (value)); + break; + case PROP_SERVICE: + gst_rtsp_server_set_service (server, g_value_get_string (value)); break; case PROP_BACKLOG: gst_rtsp_server_set_backlog (server, g_value_get_int (value)); @@ -358,12 +418,47 @@ gst_rtsp_server_set_property (GObject *object, guint propid, static gboolean gst_rtsp_server_sink_init_send (GstRTSPServer * server) { - int ret; + int ret, sockfd; + struct addrinfo hints; + struct addrinfo *result, *rp; - /* create server socket */ - if ((server->server_sock.fd = socket (AF_INET, SOCK_STREAM, 0)) == -1) + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_STREAM; /* stream socket */ + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address, server->service); + + /* resolve the server IP address */ + if ((ret = getaddrinfo (server->address, server->service, &hints, &result)) != 0) + goto no_address; + + /* create server socket, we loop through all the addresses until we manage to + * create a socket and bind. */ + for (rp = result; rp; rp = rp->ai_next) { + sockfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sockfd == -1) { + GST_DEBUG_OBJECT (server, "failed to make socket (%s), try next", g_strerror (errno)); + continue; + } + + if (bind (sockfd, rp->ai_addr, rp->ai_addrlen) == 0) + break; + + GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next", g_strerror (errno)); + close (sockfd); + } + freeaddrinfo (result); + + if (rp == NULL) goto no_socket; + server->server_sock.fd = sockfd; + GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d", server->server_sock.fd); @@ -379,19 +474,6 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) (void *) &ret, sizeof (ret)) < 0) goto keepalive_failed; - /* name the socket */ - memset (&server->server_sin, 0, sizeof (server->server_sin)); - server->server_sin.sin_family = AF_INET; /* network socket */ - server->server_sin.sin_port = htons (server->port); /* on port */ - server->server_sin.sin_addr.s_addr = htonl (INADDR_ANY); /* for hosts */ - - /* bind it */ - GST_DEBUG_OBJECT (server, "binding server socket to address"); - ret = bind (server->server_sock.fd, (struct sockaddr *) &server->server_sin, - sizeof (server->server_sin)); - if (ret) - goto bind_failed; - /* set the server socket to nonblocking */ fcntl (server->server_sock.fd, F_SETFL, O_NONBLOCK); @@ -404,11 +486,16 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) "listened on server socket %d, returning from connection setup", server->server_sock.fd); - GST_INFO_OBJECT (server, "listening on port %d", server->port); + GST_INFO_OBJECT (server, "listening on service %s", server->service); return TRUE; /* ERRORS */ +no_address: + { + GST_ERROR_OBJECT (server, "failed to resolve address: %s", gai_strerror(ret)); + return FALSE; + } no_socket: { GST_ERROR_OBJECT (server, "failed to create socket: %s", g_strerror (errno)); @@ -441,15 +528,6 @@ listen_failed: GST_ERROR_OBJECT (server, "failed to listen on socket: %s", g_strerror (errno)); return FALSE; } -bind_failed: - { - if (server->server_sock.fd >= 0) { - close (server->server_sock.fd); - server->server_sock.fd = -1; - } - GST_ERROR_OBJECT (server, "failed to bind on socket: %s", g_strerror (errno)); - return FALSE; - } } /* default method for creating a new client object in the server to accept and @@ -551,6 +629,7 @@ gst_rtsp_server_get_io_channel (GstRTSPServer *server) init_failed: { + GST_ERROR_OBJECT (server, "failed to initialize server"); return NULL; } } @@ -578,7 +657,7 @@ gst_rtsp_server_create_watch (GstRTSPServer *server) /* create a watch for reads (new connections) and possible errors */ server->io_watch = g_io_create_watch (channel, G_IO_IN | - G_IO_ERR | G_IO_HUP | G_IO_NVAL); + G_IO_ERR | G_IO_HUP | G_IO_NVAL); /* configure the callback */ g_source_set_callback (server->io_watch, (GSourceFunc) gst_rtsp_server_io_func, server, NULL); @@ -587,6 +666,7 @@ gst_rtsp_server_create_watch (GstRTSPServer *server) no_channel: { + GST_ERROR_OBJECT (server, "failed to create IO channel"); return NULL; } } @@ -623,6 +703,7 @@ gst_rtsp_server_attach (GstRTSPServer *server, GMainContext *context) /* ERRORS */ no_source: { + GST_ERROR_OBJECT (server, "failed to create watch"); return 0; } } diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 9e455ac908..5bbb4f2d61 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -58,9 +58,10 @@ struct _GstRTSPServer { GObject parent; /* server information */ - gint port; - gint backlog; - gchar *host; + gchar *address; + gchar *service; + gint backlog; + struct sockaddr_in server_sin; /* socket and channels */ @@ -93,8 +94,11 @@ GType gst_rtsp_server_get_type (void); GstRTSPServer * gst_rtsp_server_new (void); -void gst_rtsp_server_set_port (GstRTSPServer *server, gint port); -gint gst_rtsp_server_get_port (GstRTSPServer *server); +void gst_rtsp_server_set_address (GstRTSPServer *server, const gchar *address); +gchar * gst_rtsp_server_get_address (GstRTSPServer *server); + +void gst_rtsp_server_set_service (GstRTSPServer *server, const gchar *service); +gchar * gst_rtsp_server_get_service (GstRTSPServer *server); void gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog); gint gst_rtsp_server_get_backlog (GstRTSPServer *server); @@ -110,7 +114,7 @@ gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOChannel * gst_rtsp_server_get_io_channel (GstRTSPServer *server); GSource * gst_rtsp_server_create_watch (GstRTSPServer *server); -guint gst_rtsp_server_attach (GstRTSPServer *server, +guint gst_rtsp_server_attach (GstRTSPServer *server, GMainContext *context); G_END_DECLS From 6afa5be799d7d758ee27da7bbce40159299eea90 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Mar 2010 11:45:06 +0100 Subject: [PATCH 0175/1776] media: allow for ipv6 sockets --- gst/rtsp-server/rtsp-media.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 593b1d438c..bee6dff129 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -539,7 +539,7 @@ gst_rtsp_media_stream_rtcp (GstRTSPMediaStream * stream, GstBuffer * buffer) /* Allocate the udp ports and sockets */ static gboolean -alloc_udp_ports (GstRTSPMediaStream * stream) +alloc_udp_ports (GstRTSPMediaStream * stream, gboolean is_ipv6) { GstStateChangeReturn ret; GstElement *udpsrc0, *udpsrc1; @@ -547,6 +547,7 @@ alloc_udp_ports (GstRTSPMediaStream * stream) gint tmp_rtp, tmp_rtcp; guint count; gint rtpport, rtcpport, sockfd; + const gchar *host; udpsrc0 = NULL; udpsrc1 = NULL; @@ -557,10 +558,15 @@ alloc_udp_ports (GstRTSPMediaStream * stream) /* Start with random port */ tmp_rtp = 0; + if (is_ipv6) + host = "udp://[::0]"; + else + host = "udp://0.0.0.0"; + /* try to allocate 2 UDP ports, the RTP port should be an even * number and the RTCP port should be the next (uneven) port */ again: - udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL); + udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL); if (udpsrc0 == NULL) goto no_udp_protocol; g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL); @@ -596,7 +602,7 @@ again: } /* allocate port+1 for RTCP now */ - udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL); + udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL); if (udpsrc1 == NULL) goto no_udp_rtcp_protocol; @@ -916,7 +922,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) /* allocate udp ports, we will have 4 of them, 2 for receiving RTP/RTCP and 2 * for sending RTP/RTCP. The sender and receiver ports are shared between the * elements */ - if (!alloc_udp_ports (stream)) + if (!alloc_udp_ports (stream, FALSE)) return FALSE; /* add the ports to the pipeline */ From 0509aa1cbf2ac71eb372202ca536489e307f148d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Mar 2010 11:45:30 +0100 Subject: [PATCH 0176/1776] server: comment ipv6 server listening address --- gst/rtsp-server/rtsp-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index e51982f468..1e302d5409 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -23,7 +23,7 @@ #include "rtsp-client.h" #define DEFAULT_ADDRESS "0.0.0.0" -//#define DEFAULT_ADDRESS "::1" +/* #define DEFAULT_ADDRESS "::0" */ #define DEFAULT_SERVICE "8554" #define DEFAULT_BACKLOG 5 From d749f1e7d58b19eb08a1932f23df79ebbf1c367b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Mar 2010 18:33:23 +0100 Subject: [PATCH 0177/1776] client: use right size for malloc --- gst/rtsp-server/rtsp-client.c | 118 +++++++++++++++++++++++++++++----- 1 file changed, 102 insertions(+), 16 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 7065db9042..11a3317538 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -98,7 +98,7 @@ gst_rtsp_client_finalize (GObject * obj) for (walk = client->sessions; walk; walk = g_list_next (walk)) { GstRTSPSession *msession = (GstRTSPSession *) walk->data; g_object_weak_unref (G_OBJECT (msession), - (GWeakNotify) client_session_finalized, client); + (GWeakNotify) client_session_finalized, client); } unlink_streams (client); @@ -116,6 +116,8 @@ gst_rtsp_client_finalize (GObject * obj) if (client->media) g_object_unref (client->media); + g_free (client->server_ip); + G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj); } @@ -257,6 +259,9 @@ find_media (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPMessage * request) if (!(media = gst_rtsp_media_factory_construct (factory, uri))) goto no_media; + /* set ipv6 on the media before preparing */ + media->is_ipv6 = client->is_ipv6; + /* prepare the media */ if (!(gst_rtsp_media_prepare (media))) goto no_prepare; @@ -749,7 +754,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, /* our supported transports */ supported = GST_RTSP_LOWER_TRANS_UDP | - GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP; + GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP; /* loop through the transports, try to parse */ for (i = 0; transports[i]; i++) { @@ -761,8 +766,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, } /* we have a transport, see if it's RTP/AVP */ - if (ct->trans != GST_RTSP_TRANS_RTP || - ct->profile != GST_RTSP_PROFILE_AVP) { + if (ct->trans != GST_RTSP_TRANS_RTP || ct->profile != GST_RTSP_PROFILE_AVP) { GST_WARNING ("invalid transport %s", transports[i]); goto next; } @@ -777,7 +781,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, have_transport = TRUE; break; -next: + next: gst_rtsp_transport_init (ct); } g_strfreev (transports); @@ -848,7 +852,7 @@ next: /* configure keepalive for this transport */ gst_rtsp_session_stream_set_keepalive (stream, - (GstRTSPKeepAliveFunc) do_keepalive, session, NULL); + (GstRTSPKeepAliveFunc) do_keepalive, session, NULL); /* serialize the server transport */ trans_str = gst_rtsp_transport_as_text (st); @@ -921,6 +925,50 @@ service_unavailable: } } +static GstSDPMessage * +create_sdp (GstRTSPClient * client, GstRTSPMedia * media) +{ + GstSDPMessage *sdp; + GstSDPInfo info; + const gchar *proto; + + gst_sdp_message_new (&sdp); + + /* some standard things first */ + gst_sdp_message_set_version (sdp, "0"); + + if (client->is_ipv6) + proto = "IP6"; + else + proto = "IP4"; + + gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", proto, + client->server_ip); + + gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer"); + gst_sdp_message_set_information (sdp, "rtsp-server"); + gst_sdp_message_add_time (sdp, "0", "0", NULL); + gst_sdp_message_add_attribute (sdp, "tool", "GStreamer"); + gst_sdp_message_add_attribute (sdp, "type", "broadcast"); + gst_sdp_message_add_attribute (sdp, "control", "*"); + + info.server_proto = proto; + info.server_ip = client->server_ip; + + /* create an SDP for the media object */ + if (!gst_rtsp_sdp_from_media (sdp, &info, media)) + goto no_sdp; + + return sdp; + + /* ERRORS */ +no_sdp: + { + gst_sdp_message_free (sdp); + return NULL; + } +} + /* for the describe we must generate an SDP */ static gboolean handle_describe_request (GstRTSPClient * client, GstRTSPUrl * uri, @@ -951,8 +999,8 @@ handle_describe_request (GstRTSPClient * client, GstRTSPUrl * uri, if (!(media = find_media (client, uri, request))) goto no_media; - /* create an SDP for the media object */ - if (!(sdp = gst_rtsp_sdp_from_media (media))) + /* create an SDP for the media object on this client */ + if (!(sdp = create_sdp (client, media))) goto no_sdp; g_object_unref (media); @@ -969,15 +1017,19 @@ handle_describe_request (GstRTSPClient * client, GstRTSPUrl * uri, /* check for trailing '/' and append one */ if (str[str_len - 1] != '/') { - content_base = g_malloc (str_len + 1); + content_base = g_malloc (str_len + 2); memcpy (content_base, str, str_len); content_base[str_len] = '/'; - content_base[str_len+1] = '\0'; + content_base[str_len + 1] = '\0'; g_free (str); } else { content_base = str; } - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_BASE, content_base); + + GST_INFO ("adding content-base: %s", content_base); + + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_BASE, + content_base); g_free (content_base); /* add SDP to the response body */ @@ -1363,7 +1415,7 @@ static GstRTSPResult message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) { GstRTSPClient *client; - + client = GST_RTSP_CLIENT (user_data); /* GST_INFO ("client %p: sent a message with cseq %d", client, cseq); */ @@ -1405,14 +1457,15 @@ error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data) } static GstRTSPResult -error_full (GstRTSPWatch *watch, GstRTSPResult result, - GstRTSPMessage *message, guint id, gpointer user_data) +error_full (GstRTSPWatch * watch, GstRTSPResult result, + GstRTSPMessage * message, guint id, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); gchar *str; str = gst_rtsp_strresult (result); - GST_INFO ("client %p: received an error %s when handling message %p with id %d", + GST_INFO + ("client %p: received an error %s when handling message %p with id %d", client, str, message, id); g_free (str); @@ -1536,18 +1589,41 @@ static GstRTSPWatchFuncs watch_funcs = { gboolean gst_rtsp_client_accept (GstRTSPClient * client, GIOChannel * channel) { - int sock; + int sock, fd; GstRTSPConnection *conn; GstRTSPResult res; GSource *source; GMainContext *context; GstRTSPUrl *url; + struct sockaddr_storage addr; + socklen_t addrlen; + gchar ip[INET6_ADDRSTRLEN]; /* a new client connected. */ sock = g_io_channel_unix_get_fd (channel); GST_RTSP_CHECK (gst_rtsp_connection_accept (sock, &conn), accept_failed); + fd = gst_rtsp_connection_get_readfd (conn); + + addrlen = sizeof (addr); + if (getsockname (fd, (struct sockaddr *) &addr, &addrlen) < 0) + goto getpeername_failed; + + client->is_ipv6 = addr.ss_family == AF_INET6; + + addrlen = sizeof (addr); + if (getnameinfo ((struct sockaddr *) &addr, addrlen, ip, sizeof (ip), NULL, 0, + NI_NUMERICHOST) != 0) + goto getnameinfo_failed; + + /* keep the original ip that the client connected to */ + g_free (client->server_ip); + client->server_ip = g_strndup (ip, sizeof (ip)); + + GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client, + client->server_ip, client->is_ipv6); + url = gst_rtsp_connection_get_url (conn); GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port); @@ -1579,4 +1655,14 @@ accept_failed: g_free (str); return FALSE; } +getpeername_failed: + { + GST_ERROR ("getpeername failed: %s", g_strerror (errno)); + return FALSE; + } +getnameinfo_failed: + { + GST_ERROR ("getnameinfo failed: %s", g_strerror (errno)); + return FALSE; + } } From 4eccdd9dd7b7484cffafc9f2b9df0d18e2cb7ef7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Mar 2010 18:34:43 +0100 Subject: [PATCH 0178/1776] session: indent --- gst/rtsp-server/rtsp-session.c | 99 ++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 31a371a39b..b62c886ec6 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -35,10 +35,10 @@ enum GST_DEBUG_CATEGORY_EXTERN (rtsp_session_debug); #define GST_CAT_DEFAULT rtsp_session_debug -static void gst_rtsp_session_get_property (GObject *object, guint propid, - GValue *value, GParamSpec *pspec); -static void gst_rtsp_session_set_property (GObject *object, guint propid, - const GValue *value, GParamSpec *pspec); +static void gst_rtsp_session_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec); +static void gst_rtsp_session_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec); static void gst_rtsp_session_finalize (GObject * obj); G_DEFINE_TYPE (GstRTSPSession, gst_rtsp_session, G_TYPE_OBJECT); @@ -57,11 +57,12 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass) g_object_class_install_property (gobject_class, PROP_SESSIONID, g_param_spec_string ("sessionid", "Sessionid", "the session id", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_TIMEOUT, - g_param_spec_uint ("timeout", "timeout", "the timeout of the session (0 = never)", - 0, G_MAXUINT, DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_uint ("timeout", "timeout", + "the timeout of the session (0 = never)", 0, G_MAXUINT, + DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void @@ -73,7 +74,7 @@ gst_rtsp_session_init (GstRTSPSession * session) } static void -gst_rtsp_session_free_stream (GstRTSPSessionStream *stream) +gst_rtsp_session_free_stream (GstRTSPSessionStream * stream) { GST_INFO ("free session stream %p", stream); @@ -88,7 +89,8 @@ gst_rtsp_session_free_stream (GstRTSPSessionStream *stream) } static void -gst_rtsp_session_free_media (GstRTSPSessionMedia *media, GstRTSPSession *session) +gst_rtsp_session_free_media (GstRTSPSessionMedia * media, + GstRTSPSession * session) { guint size, i; @@ -128,7 +130,7 @@ gst_rtsp_session_finalize (GObject * obj) /* free all media */ g_list_foreach (session->medias, (GFunc) gst_rtsp_session_free_media, - session); + session); g_list_free (session->medias); /* free session id */ @@ -138,8 +140,8 @@ gst_rtsp_session_finalize (GObject * obj) } static void -gst_rtsp_session_get_property (GObject *object, guint propid, - GValue *value, GParamSpec *pspec) +gst_rtsp_session_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec) { GstRTSPSession *session = GST_RTSP_SESSION (object); @@ -156,8 +158,8 @@ gst_rtsp_session_get_property (GObject *object, guint propid, } static void -gst_rtsp_session_set_property (GObject *object, guint propid, - const GValue *value, GParamSpec *pspec) +gst_rtsp_session_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec) { GstRTSPSession *session = GST_RTSP_SESSION (object); @@ -188,8 +190,8 @@ gst_rtsp_session_set_property (GObject *object, guint propid, * Returns: a new @GstRTSPSessionMedia object. */ GstRTSPSessionMedia * -gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, - GstRTSPMedia *media) +gst_rtsp_session_manage_media (GstRTSPSession * sess, const GstRTSPUrl * uri, + GstRTSPMedia * media) { GstRTSPSessionMedia *result; guint n_streams; @@ -201,12 +203,14 @@ gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, result = g_new0 (GstRTSPSessionMedia, 1); result->media = media; - result->url = gst_rtsp_url_copy ((GstRTSPUrl *)uri); + result->url = gst_rtsp_url_copy ((GstRTSPUrl *) uri); result->state = GST_RTSP_STATE_INIT; /* prealloc the streams now, filled with NULL */ n_streams = gst_rtsp_media_n_streams (media); - result->streams = g_array_sized_new (FALSE, TRUE, sizeof (GstRTSPSessionStream *), n_streams); + result->streams = + g_array_sized_new (FALSE, TRUE, sizeof (GstRTSPSessionStream *), + n_streams); g_array_set_size (result->streams, n_streams); sess->medias = g_list_prepend (sess->medias, result); @@ -226,8 +230,8 @@ gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, * Returns: %TRUE if there are more media session left in @sess. */ gboolean -gst_rtsp_session_release_media (GstRTSPSession *sess, - GstRTSPSessionMedia *media) +gst_rtsp_session_release_media (GstRTSPSession * sess, + GstRTSPSessionMedia * media) { GList *walk, *next; @@ -237,7 +241,7 @@ gst_rtsp_session_release_media (GstRTSPSession *sess, for (walk = sess->medias; walk;) { GstRTSPSessionMedia *find; - find = (GstRTSPSessionMedia *) walk->data; + find = (GstRTSPSessionMedia *) walk->data; next = g_list_next (walk); if (find == media) { @@ -258,10 +262,10 @@ gst_rtsp_session_release_media (GstRTSPSession *sess, * * Get the session media of the @url. * - * Returns: the configuration for @url in @sess. + * Returns: the configuration for @url in @sess. */ GstRTSPSessionMedia * -gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *url) +gst_rtsp_session_get_media (GstRTSPSession * sess, const GstRTSPUrl * url) { GstRTSPSessionMedia *result; GList *walk; @@ -272,7 +276,7 @@ gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *url) result = NULL; for (walk = sess->medias; walk; walk = g_list_next (walk)) { - result = (GstRTSPSessionMedia *) walk->data; + result = (GstRTSPSessionMedia *) walk->data; if (strcmp (result->url->abspath, url->abspath) == 0) break; @@ -293,7 +297,7 @@ gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *url) * is unreffed. */ GstRTSPSessionStream * -gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, guint idx) +gst_rtsp_session_media_get_stream (GstRTSPSessionMedia * media, guint idx) { GstRTSPSessionStream *result; GstRTSPMediaStream *media_stream; @@ -327,7 +331,8 @@ no_media: } gboolean -gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia *media, GstRTSPRange *range) +gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia * media, + GstRTSPRange * range) { range->min = media->counter++; range->max = media->counter++; @@ -341,7 +346,7 @@ gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia *media, GstRTSPRange * Create a new #GstRTSPSession instance. */ GstRTSPSession * -gst_rtsp_session_new (const gchar *sessionid) +gst_rtsp_session_new (const gchar * sessionid) { GstRTSPSession *result; @@ -362,7 +367,7 @@ gst_rtsp_session_new (const gchar *sessionid) * @session is alive. */ const gchar * -gst_rtsp_session_get_sessionid (GstRTSPSession *session) +gst_rtsp_session_get_sessionid (GstRTSPSession * session) { g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL); @@ -378,7 +383,7 @@ gst_rtsp_session_get_sessionid (GstRTSPSession *session) * cleaned up when there is no activity for @timeout seconds. */ void -gst_rtsp_session_set_timeout (GstRTSPSession *session, guint timeout) +gst_rtsp_session_set_timeout (GstRTSPSession * session, guint timeout) { g_return_if_fail (GST_IS_RTSP_SESSION (session)); @@ -394,7 +399,7 @@ gst_rtsp_session_set_timeout (GstRTSPSession *session, guint timeout) * Returns: the timeout of @session in seconds. */ guint -gst_rtsp_session_get_timeout (GstRTSPSession *session) +gst_rtsp_session_get_timeout (GstRTSPSession * session) { g_return_val_if_fail (GST_IS_RTSP_SESSION (session), 0); @@ -408,7 +413,7 @@ gst_rtsp_session_get_timeout (GstRTSPSession *session) * Update the last_access time of the session to the current time. */ void -gst_rtsp_session_touch (GstRTSPSession *session) +gst_rtsp_session_touch (GstRTSPSession * session) { g_return_if_fail (GST_IS_RTSP_SESSION (session)); @@ -425,7 +430,7 @@ gst_rtsp_session_touch (GstRTSPSession *session) * Returns: the amount of milliseconds since the session will time out. */ gint -gst_rtsp_session_next_timeout (GstRTSPSession *session, GTimeVal *now) +gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) { gint res; GstClockTime last_access, now_ns; @@ -439,10 +444,10 @@ gst_rtsp_session_next_timeout (GstRTSPSession *session, GTimeVal *now) now_ns = GST_TIMEVAL_TO_TIME (*now); - if (last_access > now_ns) - res = GST_TIME_AS_MSECONDS (last_access - now_ns); + if (last_access > now_ns) + res = GST_TIME_AS_MSECONDS (last_access - now_ns); else - res = 0; + res = 0; return res; } @@ -452,12 +457,12 @@ gst_rtsp_session_next_timeout (GstRTSPSession *session, GTimeVal *now) * @session: a #GstRTSPSession * @now: the current system time * - * Check if @session timeout out. + * Check if @session timeout out. * * Returns: %TRUE if @session timed out */ gboolean -gst_rtsp_session_is_expired (GstRTSPSession *session, GTimeVal *now) +gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) { gboolean res; @@ -473,12 +478,12 @@ gst_rtsp_session_is_expired (GstRTSPSession *session, GTimeVal *now) * * Set @ct as the client transport and create and return a matching server * transport. - * + * * Returns: a server transport or NULL if something went wrong. */ GstRTSPTransport * -gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, - GstRTSPTransport *ct) +gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream, + GstRTSPTransport * ct) { GstRTSPTransport *st; @@ -508,7 +513,8 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, } if (stream->media_stream->session) - g_object_get (stream->media_stream->session, "internal-ssrc", &st->ssrc, NULL); + g_object_get (stream->media_stream->session, "internal-ssrc", &st->ssrc, + NULL); /* keep track of the transports in the stream. */ if (stream->trans.transport) @@ -530,9 +536,9 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, * to a client. This is usually used when sending RTP/RTCP over TCP. */ void -gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream *stream, +gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream * stream, GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, gpointer user_data, - GDestroyNotify notify) + GDestroyNotify notify) { stream->trans.send_rtp = send_rtp; stream->trans.send_rtcp = send_rtcp; @@ -553,8 +559,8 @@ gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream *stream, * receiver of @stream. */ void -gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream *stream, - GstRTSPKeepAliveFunc keep_alive, gpointer user_data, GDestroyNotify notify) +gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream * stream, + GstRTSPKeepAliveFunc keep_alive, gpointer user_data, GDestroyNotify notify) { stream->trans.keep_alive = keep_alive; if (stream->trans.ka_notify) @@ -573,7 +579,7 @@ gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream *stream, * Returns: %TRUE on success. */ gboolean -gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media, GstState state) +gst_rtsp_session_media_set_state (GstRTSPSessionMedia * media, GstState state) { gboolean ret; @@ -583,4 +589,3 @@ gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media, GstState state) return ret; } - From e866345f15291f60ece13bca98e36373810541a4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Mar 2010 18:37:18 +0100 Subject: [PATCH 0179/1776] rtsp: keep track of server ip and ipv6 Keep track of how the client connected to the server and setup the udp ports with the same protocol. Copy the server ip address in the SDP so that clients can send RTCP back to us. --- gst/rtsp-server/rtsp-client.h | 3 +++ gst/rtsp-server/rtsp-media.c | 6 +++--- gst/rtsp-server/rtsp-media.h | 1 + gst/rtsp-server/rtsp-sdp.c | 31 ++++++++++--------------------- gst/rtsp-server/rtsp-sdp.h | 7 ++++++- gst/rtsp-server/rtsp-server.c | 10 ++++++---- 6 files changed, 29 insertions(+), 29 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index ab124c0670..b29e218593 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -61,6 +61,7 @@ typedef struct _GstRTSPClientClass GstRTSPClientClass; * @connection: the connection object handling the client request. * @watch: watch for the connection * @watchid: id of the watch + * @ip: ip address used by the client to connect to us * @session_pool: handle to the session pool used by the client. * @media_mapping: handle to the media mapping used by the client. * @uri: cached uri @@ -76,6 +77,8 @@ struct _GstRTSPClient { GstRTSPConnection *connection; GstRTSPWatch *watch; guint watchid; + gchar *server_ip; + gboolean is_ipv6; GstRTSPSessionPool *session_pool; GstRTSPMediaMapping *media_mapping; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index bee6dff129..c4f824bf40 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -539,7 +539,7 @@ gst_rtsp_media_stream_rtcp (GstRTSPMediaStream * stream, GstBuffer * buffer) /* Allocate the udp ports and sockets */ static gboolean -alloc_udp_ports (GstRTSPMediaStream * stream, gboolean is_ipv6) +alloc_udp_ports (GstRTSPMedia * media, GstRTSPMediaStream * stream) { GstStateChangeReturn ret; GstElement *udpsrc0, *udpsrc1; @@ -558,7 +558,7 @@ alloc_udp_ports (GstRTSPMediaStream * stream, gboolean is_ipv6) /* Start with random port */ tmp_rtp = 0; - if (is_ipv6) + if (media->is_ipv6) host = "udp://[::0]"; else host = "udp://0.0.0.0"; @@ -922,7 +922,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) /* allocate udp ports, we will have 4 of them, 2 for receiving RTP/RTCP and 2 * for sending RTP/RTCP. The sender and receiver ports are shared between the * elements */ - if (!alloc_udp_ports (stream, FALSE)) + if (!alloc_udp_ports (media, stream)) return FALSE; /* add the ports to the pipeline */ diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index e873c04569..8abf05fa44 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -191,6 +191,7 @@ struct _GstRTSPMedia { gboolean shared; gboolean reusable; gboolean reused; + gboolean is_ipv6; GstElement *element; GArray *streams; diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 7c1744b03b..56ca719b8e 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -22,16 +22,18 @@ /** * gst_rtsp_sdp_from_media: + * @sdp: a #GstSDPessage + * @info: info * @media: a #GstRTSPMedia * - * Create a new sdp message for @media. + * Add @media specific info to @sdp. @info is used to configure the connection + * information in the SDP. * - * Returns: a new sdp message for @media. gst_sdp_message_free() after usage. + * Returns: TRUE on success. */ -GstSDPMessage * -gst_rtsp_sdp_from_media (GstRTSPMedia * media) +gboolean +gst_rtsp_sdp_from_media (GstSDPMessage *sdp, GstSDPInfo *info, GstRTSPMedia * media) { - GstSDPMessage *sdp; guint i, n_streams; gchar *rangestr; @@ -40,19 +42,6 @@ gst_rtsp_sdp_from_media (GstRTSPMedia * media) n_streams = gst_rtsp_media_n_streams (media); - gst_sdp_message_new (&sdp); - - /* some standard things first */ - gst_sdp_message_set_version (sdp, "0"); - - gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", "IP4", - "127.0.0.1"); - gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer"); - gst_sdp_message_set_information (sdp, "rtsp-server"); - gst_sdp_message_add_time (sdp, "0", "0", NULL); - gst_sdp_message_add_attribute (sdp, "tool", "GStreamer"); - gst_sdp_message_add_attribute (sdp, "type", "broadcast"); - gst_sdp_message_add_attribute (sdp, "control", "*"); rangestr = gst_rtsp_range_to_string (&media->range); gst_sdp_message_add_attribute (sdp, "range", rangestr); g_free (rangestr); @@ -96,7 +85,7 @@ gst_rtsp_sdp_from_media (GstRTSPMedia * media) gst_sdp_media_set_proto (smedia, "RTP/AVP"); /* for the c= line */ - gst_sdp_media_add_connection (smedia, "IN", "IP4", "127.0.0.1", 0, 0); + gst_sdp_media_add_connection (smedia, "IN", info->server_proto, info->server_ip, 0, 0); /* get clock-rate, media type and params for the rtpmap attribute */ gst_structure_get_int (s, "clock-rate", &caps_rate); @@ -163,12 +152,12 @@ gst_rtsp_sdp_from_media (GstRTSPMedia * media) gst_sdp_media_free (smedia); } - return sdp; + return TRUE; /* ERRORS */ not_prepared: { GST_ERROR ("media %p is not prepared", media); - return NULL; + return FALSE; } } diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h index 4016eda37c..6c4c00549a 100644 --- a/gst/rtsp-server/rtsp-sdp.h +++ b/gst/rtsp-server/rtsp-sdp.h @@ -27,8 +27,13 @@ G_BEGIN_DECLS +typedef struct { + const gchar *server_proto; + const gchar *server_ip; +} GstSDPInfo; + /* creating SDP */ -GstSDPMessage * gst_rtsp_sdp_from_media (GstRTSPMedia *media); +gboolean gst_rtsp_sdp_from_media (GstSDPMessage *sdp, GstSDPInfo *info, GstRTSPMedia * media); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 1e302d5409..7f54798dba 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -425,7 +425,7 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_STREAM; /* stream socket */ - hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + hints.ai_flags = AI_PASSIVE | AI_CANONNAME; /* For wildcard IP address */ hints.ai_protocol = 0; /* Any protocol */ hints.ai_canonname = NULL; hints.ai_addr = NULL; @@ -446,8 +446,10 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) continue; } - if (bind (sockfd, rp->ai_addr, rp->ai_addrlen) == 0) + if (bind (sockfd, rp->ai_addr, rp->ai_addrlen) == 0) { + GST_DEBUG_OBJECT (server, "bind on %s", rp->ai_canonname); break; + } GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next", g_strerror (errno)); close (sockfd); @@ -654,7 +656,7 @@ gst_rtsp_server_create_watch (GstRTSPServer *server) channel = gst_rtsp_server_get_io_channel (server); if (channel == NULL) goto no_channel; - + /* create a watch for reads (new connections) and possible errors */ server->io_watch = g_io_create_watch (channel, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL); @@ -682,7 +684,7 @@ no_channel: * This function should be called when the server properties and urls are fully * configured and the server is ready to start. * - * Returns: the ID (greater than 0) for the source within the GMainContext. + * Returns: the ID (greater than 0) for the source within the GMainContext. */ guint gst_rtsp_server_attach (GstRTSPServer *server, GMainContext *context) From ac8343ea6267a94c63c41d169b99de1943eda898 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 19 Mar 2010 15:15:29 +0100 Subject: [PATCH 0180/1776] media: allow configuration of allowed lower transport --- configure.ac | 4 +-- gst/rtsp-server/rtsp-media.c | 48 ++++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 6 +++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 5529ede359..0218fd236a 100644 --- a/configure.ac +++ b/configure.ac @@ -37,8 +37,8 @@ AC_SUBST(GST_MAJORMINOR) AM_PROG_LIBTOOL dnl *** required versions of GStreamer stuff *** -GST_REQ=0.10.25 -GSTPB_REQ=0.10.25 +GST_REQ=0.10.28.1 +GSTPB_REQ=0.10.28.1 dnl export for .pc files AC_SUBST([GST_REQ]) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c4f824bf40..e4c11d7ab5 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -26,6 +26,7 @@ #define DEFAULT_SHARED FALSE #define DEFAULT_REUSABLE FALSE +#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -35,6 +36,7 @@ enum PROP_0, PROP_SHARED, PROP_REUSABLE, + PROP_PROTOCOLS, PROP_LAST }; @@ -87,6 +89,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "If this media pipeline can be reused after an unprepare", DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PROTOCOLS, + g_param_spec_flags ("protocols", "Protocols", + "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS, + DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_UNPREPARED] = g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL, @@ -111,6 +118,10 @@ gst_rtsp_media_init (GstRTSPMedia * media) media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); media->lock = g_mutex_new (); media->cond = g_cond_new (); + + media->shared = DEFAULT_SHARED; + media->reusable = DEFAULT_REUSABLE; + media->protocols = DEFAULT_PROTOCOLS; } static void @@ -189,6 +200,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_REUSABLE: g_value_set_boolean (value, gst_rtsp_media_is_reusable (media)); break; + case PROP_PROTOCOLS: + g_value_set_flags (value, gst_rtsp_media_get_protocols (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -207,6 +221,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_REUSABLE: gst_rtsp_media_set_reusable (media, g_value_get_boolean (value)); break; + case PROP_PROTOCOLS: + gst_rtsp_media_set_protocols (media, g_value_get_flags (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -354,6 +371,37 @@ gst_rtsp_media_is_reusable (GstRTSPMedia * media) return media->reusable; } +/** + * gst_rtsp_media_set_protocols: + * @media: a #GstRTSPMedia + * @protocols: the new flags + * + * Configure the allowed lower transport for @media. + */ +void +gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + media->protocols = protocols; +} + +/** + * gst_rtsp_media_get_protocols: + * @media: a #GstRTSPMedia + * + * Get the allowed protocols of @media. + * + * Returns: a #GstRTSPLowerTrans + */ +GstRTSPLowerTrans +gst_rtsp_media_get_protocols (GstRTSPMedia * media) +{ + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_RTSP_LOWER_TRANS_UNKNOWN); + + return media->protocols; +} + /** * gst_rtsp_media_n_streams: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 8abf05fa44..ec3e832f65 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -161,7 +161,9 @@ typedef enum { * @cond: for signaling the object * @shared: if this media can be shared between clients * @reusable: if this media can be reused after an unprepare + * @protocols: the allowed lower transport for this stream * @reused: if this media has been reused + * @is_ipv6: if this media is using ipv6 * @element: the data providing element * @streams: the different streams provided by @element * @dynamic: list of dynamic elements managed by @element @@ -190,6 +192,7 @@ struct _GstRTSPMedia { gboolean shared; gboolean reusable; + GstRTSPLowerTrans protocols; gboolean reused; gboolean is_ipv6; @@ -254,6 +257,9 @@ gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media); void gst_rtsp_media_set_reusable (GstRTSPMedia *media, gboolean reusable); gboolean gst_rtsp_media_is_reusable (GstRTSPMedia *media); +void gst_rtsp_media_set_protocols (GstRTSPMedia *media, GstRTSPLowerTrans protocols); +GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia *media); + /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media); From 09b97dd4ac0429412de941ce16466ab44606da33 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 19 Mar 2010 18:03:40 +0100 Subject: [PATCH 0181/1776] rtsp-server: add more support for multicast --- gst/rtsp-server/rtsp-client.c | 10 ++++++++-- gst/rtsp-server/rtsp-media.c | 1 + gst/rtsp-server/rtsp-sdp.c | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 11a3317538..a408bc4c96 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -23,6 +23,9 @@ #include "rtsp-sdp.h" #include "rtsp-params.h" +/* temporary multicast address until it's configurable somewhere */ +#define MCAST_ADDRESS "224.2.0.1" + static GMutex *tunnels_lock; static GHashTable *tunnels; @@ -796,7 +799,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, /* we have a valid transport now, set the destination of the client. */ g_free (ct->destination); if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - ct->destination = g_strdup ("224.2.0.1"); + ct->destination = g_strdup (MCAST_ADDRESS); } else { url = gst_rtsp_connection_get_url (client->connection); ct->destination = g_strdup (url->host); @@ -953,7 +956,10 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) gst_sdp_message_add_attribute (sdp, "control", "*"); info.server_proto = proto; - info.server_ip = client->server_ip; + if (media->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) + info.server_ip = MCAST_ADDRESS; + else + info.server_ip = client->server_ip; /* create an SDP for the media object */ if (!gst_rtsp_sdp_from_media (sdp, &info, media)) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e4c11d7ab5..89dc466b54 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -27,6 +27,7 @@ #define DEFAULT_SHARED FALSE #define DEFAULT_REUSABLE FALSE #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP +//#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST /* define to dump received RTCP packets */ #undef DUMP_STATS diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 56ca719b8e..82ed995082 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -85,7 +85,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage *sdp, GstSDPInfo *info, GstRTSPMedia * me gst_sdp_media_set_proto (smedia, "RTP/AVP"); /* for the c= line */ - gst_sdp_media_add_connection (smedia, "IN", info->server_proto, info->server_ip, 0, 0); + gst_sdp_media_add_connection (smedia, "IN", info->server_proto, info->server_ip, 16, 0); /* get clock-rate, media type and params for the rtpmap attribute */ gst_structure_get_int (s, "clock-rate", &caps_rate); From 30c31a65eb03873c00dc358a1a36bb67f881fb9b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 6 Apr 2010 11:13:51 +0200 Subject: [PATCH 0182/1776] client: handle lost_tunnel callbacks Handle lost_tunnel callbacks and use it to store the tunnelid back into the hashtable so that we can reuse it for when the client reopens the POST socket. Close the connection after a TEARDOWN. Make sure or watchid is cleared when the watch is removed. Fixes #612915 --- gst/rtsp-server/rtsp-client.c | 88 +++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a408bc4c96..4d6d66e499 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -322,6 +322,8 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) size = GST_BUFFER_SIZE (buffer); gst_rtsp_message_take_body (&message, data, size); + /* FIXME, client->watch could have been finalized here, we need to keep an + * extra refcount to the watch. */ gst_rtsp_watch_send_message (client->watch, &message, NULL); gst_rtsp_message_steal_body (&message, &data, &size); @@ -333,6 +335,7 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) static void link_stream (GstRTSPClient * client, GstRTSPSessionStream * stream) { + GST_DEBUG ("client %p: linking stream %p", client, stream); gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data, (GstRTSPSendFunc) do_send_data, client, NULL); client->streams = g_list_prepend (client->streams, stream); @@ -341,6 +344,7 @@ link_stream (GstRTSPClient * client, GstRTSPSessionStream * stream) static void unlink_stream (GstRTSPClient * client, GstRTSPSessionStream * stream) { + GST_DEBUG ("client %p: unlinking stream %p", client, stream); gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); client->streams = g_list_remove (client->streams, stream); } @@ -350,6 +354,7 @@ unlink_streams (GstRTSPClient * client) { GList *walk; + GST_DEBUG ("client %p: unlinking streams", client); for (walk = client->streams; walk; walk = g_list_next (walk)) { GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data; @@ -419,8 +424,17 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPUrl * uri, gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONNECTION, "close"); + send_response (client, session, &response); + GST_DEBUG ("client %p: closing connection", client); + if (client->watchid) { + g_source_destroy ((GSource *) client->watch); + client->watchid = 0; + } + gst_rtsp_connection_close (client->connection); + return TRUE; /* ERRORS */ @@ -1122,6 +1136,7 @@ client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) if (!(client->sessions = g_list_remove (client->sessions, session))) { GST_INFO ("all sessions finalized, close the connection"); g_source_destroy ((GSource *) client->watch); + client->watchid = 0; } } @@ -1439,6 +1454,7 @@ closed (GstRTSPWatch * watch, gpointer user_data) if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) { g_mutex_lock (tunnels_lock); + /* remove from tunnelids */ g_hash_table_remove (tunnels, tunnelid); g_mutex_unlock (tunnels_lock); } @@ -1478,22 +1494,17 @@ error_full (GstRTSPWatch * watch, GstRTSPResult result, return GST_RTSP_OK; } -static GstRTSPStatusCode -tunnel_start (GstRTSPWatch * watch, gpointer user_data) +static gboolean +remember_tunnel (GstRTSPClient * client) { - GstRTSPClient *client; const gchar *tunnelid; - client = GST_RTSP_CLIENT (user_data); - - GST_INFO ("client %p: tunnel start", client); - /* store client in the pending tunnels */ tunnelid = gst_rtsp_connection_get_tunnelid (client->connection); if (tunnelid == NULL) goto no_tunnelid; - GST_INFO ("client %p: inserting %s", client, tunnelid); + GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid); /* we can't have two clients connecting with the same tunnelid */ g_mutex_lock (tunnels_lock); @@ -1503,22 +1514,59 @@ tunnel_start (GstRTSPWatch * watch, gpointer user_data) g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client)); g_mutex_unlock (tunnels_lock); - return GST_RTSP_STS_OK; + return TRUE; /* ERRORS */ no_tunnelid: { - GST_INFO ("client %p: no tunnelid provided", client); - return GST_RTSP_STS_SERVICE_UNAVAILABLE; + GST_ERROR ("client %p: no tunnelid provided", client); + return FALSE; } tunnel_existed: { g_mutex_unlock (tunnels_lock); - GST_INFO ("client %p: tunnel session %s existed", client, tunnelid); + GST_ERROR ("client %p: tunnel session %s already existed", client, tunnelid); + return FALSE; + } +} + +static GstRTSPStatusCode +tunnel_start (GstRTSPWatch * watch, gpointer user_data) +{ + GstRTSPClient *client; + + client = GST_RTSP_CLIENT (user_data); + + GST_INFO ("client %p: tunnel start (connection %p)", client, client->connection); + + if (!remember_tunnel (client)) + goto tunnel_error; + + return GST_RTSP_STS_OK; + + /* ERRORS */ +tunnel_error: + { + GST_ERROR ("client %p: error starting tunnel", client); return GST_RTSP_STS_SERVICE_UNAVAILABLE; } } +static GstRTSPResult +tunnel_lost (GstRTSPWatch * watch, gpointer user_data) +{ + GstRTSPClient *client; + + client = GST_RTSP_CLIENT (user_data); + + GST_INFO ("client %p: tunnel lost (connection %p)", client, client->connection); + + /* ignore error, it'll only be a problem when the client does a POST again */ + remember_tunnel (client); + + return GST_RTSP_OK; +} + static GstRTSPResult tunnel_complete (GstRTSPWatch * watch, gpointer user_data) { @@ -1543,7 +1591,8 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) g_hash_table_remove (tunnels, tunnelid); g_mutex_unlock (tunnels_lock); - GST_INFO ("client %p: found tunnel %p", client, oclient); + GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient, + oclient->connection, client->connection); /* merge the tunnels into the first client */ gst_rtsp_connection_do_tunnel (oclient->connection, client->connection); @@ -1577,9 +1626,18 @@ static GstRTSPWatchFuncs watch_funcs = { error, tunnel_start, tunnel_complete, - error_full + error_full, + tunnel_lost }; +static void +client_watch_notify (GstRTSPClient * client) +{ + GST_INFO ("client %p: watch destroyed", client); + client->watchid = 0; + g_object_unref (client); +} + /** * gst_rtsp_client_attach: * @client: a #GstRTSPClient @@ -1637,7 +1695,7 @@ gst_rtsp_client_accept (GstRTSPClient * client, GIOChannel * channel) /* create watch for the connection and attach */ client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs, - g_object_ref (client), g_object_unref); + g_object_ref (client), (GDestroyNotify) client_watch_notify); /* find the context to add the watch */ if ((source = g_main_current_source ())) From 558c7fddd2849b4a2b065cc52440f09886aad42b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 6 Apr 2010 15:44:45 +0200 Subject: [PATCH 0183/1776] session: small cleanups --- gst/rtsp-server/rtsp-session.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index b62c886ec6..30e1f1d711 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -300,7 +300,6 @@ GstRTSPSessionStream * gst_rtsp_session_media_get_stream (GstRTSPSessionMedia * media, guint idx) { GstRTSPSessionStream *result; - GstRTSPMediaStream *media_stream; g_return_val_if_fail (media != NULL, NULL); g_return_val_if_fail (media->media != NULL, NULL); @@ -310,6 +309,8 @@ gst_rtsp_session_media_get_stream (GstRTSPSessionMedia * media, guint idx) result = g_array_index (media->streams, GstRTSPSessionStream *, idx); if (result == NULL) { + GstRTSPMediaStream *media_stream; + media_stream = gst_rtsp_media_get_stream (media->media, idx); if (media_stream == NULL) goto no_media; @@ -477,9 +478,10 @@ gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) * @ct: a client #GstRTSPTransport * * Set @ct as the client transport and create and return a matching server - * transport. + * transport. This function takes ownership of the passed @ct. * - * Returns: a server transport or NULL if something went wrong. + * Returns: a server transport or NULL if something went wrong. Use + * gst_rtsp_transport_free () after usage. */ GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream, From 48a54054e7976cc94f954a6e9ec427c1cdd604ca Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 6 Apr 2010 15:45:56 +0200 Subject: [PATCH 0184/1776] client: fix unlink on session timeouts When our session times out, make sure we unlink all streams in this session. Remove the tunnelid when closing the connection. --- gst/rtsp-server/rtsp-client.c | 77 +++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4d6d66e499..6c575dbcd7 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -49,8 +49,6 @@ static void gst_rtsp_client_finalize (GObject * obj); static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session); -static void unlink_streams (GstRTSPClient * client); - G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); static void @@ -104,8 +102,6 @@ gst_rtsp_client_finalize (GObject * obj) (GWeakNotify) client_session_finalized, client); } - unlink_streams (client); - g_list_free (client->sessions); gst_rtsp_connection_free (client->connection); @@ -349,21 +345,6 @@ unlink_stream (GstRTSPClient * client, GstRTSPSessionStream * stream) client->streams = g_list_remove (client->streams, stream); } -static void -unlink_streams (GstRTSPClient * client) -{ - GList *walk; - - GST_DEBUG ("client %p: unlinking streams", client); - for (walk = client->streams; walk; walk = g_list_next (walk)) { - GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data; - - gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); - } - g_list_free (client->streams); - client->streams = NULL; -} - static void unlink_session_streams (GstRTSPClient * client, GstRTSPSessionMedia * media) { @@ -387,6 +368,28 @@ unlink_session_streams (GstRTSPClient * client, GstRTSPSessionMedia * media) } } +static void +close_connection (GstRTSPClient * client) +{ + const gchar * tunnelid; + + GST_DEBUG ("client %p: closing connection", client); + + if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) { + g_mutex_lock (tunnels_lock); + /* remove from tunnelids */ + g_hash_table_remove (tunnels, tunnelid); + g_mutex_unlock (tunnels_lock); + } + + gst_rtsp_connection_close (client->connection); + if (client->watchid) { + g_source_destroy ((GSource *) client->watch); + client->watchid = 0; + client->watch = NULL; + } +} + static gboolean handle_teardown_request (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request) @@ -428,12 +431,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPUrl * uri, send_response (client, session, &response); - GST_DEBUG ("client %p: closing connection", client); - if (client->watchid) { - g_source_destroy ((GSource *) client->watch); - client->watchid = 0; - } - gst_rtsp_connection_close (client->connection); + close_connection (client); return TRUE; @@ -1133,10 +1131,18 @@ santize_uri (GstRTSPUrl * uri) static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) { + GList *medias; + + GST_INFO ("client %p: session %p finished", client, session); + + /* unlink all media managed in this session */ + for (medias = session->medias; medias; medias = g_list_next (medias)) { + unlink_session_streams (client, (GstRTSPSessionMedia *) medias->data); + } + if (!(client->sessions = g_list_remove (client->sessions, session))) { - GST_INFO ("all sessions finalized, close the connection"); - g_source_destroy ((GSource *) client->watch); - client->watchid = 0; + GST_INFO ("client %p: all sessions finalized, close the connection", client); + close_connection (client); } } @@ -1459,9 +1465,6 @@ closed (GstRTSPWatch * watch, gpointer user_data) g_mutex_unlock (tunnels_lock); } - /* remove all streams that are streaming over this client connection */ - unlink_streams (client); - return GST_RTSP_OK; } @@ -1589,6 +1592,9 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) * remove the ref to it. */ g_object_ref (oclient); g_hash_table_remove (tunnels, tunnelid); + + if (oclient->watch == NULL) + goto tunnel_closed; g_mutex_unlock (tunnels_lock); GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient, @@ -1602,6 +1608,7 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) /* we don't need this watch anymore */ g_source_destroy ((GSource *) client->watch); client->watchid = 0; + client->watch = NULL; return GST_RTSP_OK; @@ -1617,6 +1624,13 @@ no_tunnel: GST_INFO ("client %p: tunnel session %s not found", client, tunnelid); return GST_RTSP_STS_SERVICE_UNAVAILABLE; } +tunnel_closed: + { + g_mutex_unlock (tunnels_lock); + GST_INFO ("client %p: tunnel session %s was closed", client, tunnelid); + g_object_unref (oclient); + return GST_RTSP_STS_SERVICE_UNAVAILABLE; + } } static GstRTSPWatchFuncs watch_funcs = { @@ -1635,6 +1649,7 @@ client_watch_notify (GstRTSPClient * client) { GST_INFO ("client %p: watch destroyed", client); client->watchid = 0; + client->watch = NULL; g_object_unref (client); } From 4fdd2bf4d1b6796cc055b3d2ad42b3687a229fcd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 6 Apr 2010 17:07:27 +0200 Subject: [PATCH 0185/1776] session: add support for prevent session timeouts Add an atomix counter to prevent session timeouts when we are, for example, streaming over TCP. --- gst/rtsp-server/rtsp-session.c | 19 +++++++++++++++++++ gst/rtsp-server/rtsp-session.h | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 30e1f1d711..7df6c3726e 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -421,6 +421,20 @@ gst_rtsp_session_touch (GstRTSPSession * session) g_get_current_time (&session->last_access); } +void +gst_rtsp_session_prevent_expire (GstRTSPSession *session) +{ + g_return_if_fail (GST_IS_RTSP_SESSION (session)); + + g_atomic_int_add (&session->expire_count, 1); +} + +void +gst_rtsp_session_allow_expire (GstRTSPSession *session) +{ + g_atomic_int_add (&session->expire_count, -1); +} + /** * gst_rtsp_session_next_timeout: * @session: a #GstRTSPSession @@ -439,6 +453,11 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) g_return_val_if_fail (GST_IS_RTSP_SESSION (session), -1); g_return_val_if_fail (now != NULL, -1); + if (g_atomic_int_get (&session->expire_count) != 0) { + /* touch session when the expire count is not 0 */ + g_get_current_time (&session->last_access); + } + last_access = GST_TIMEVAL_TO_TIME (session->last_access); /* add timeout allow for 5 seconds of extra time */ last_access += session->timeout * GST_SECOND + (5 * GST_SECOND); diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 56816679c3..3eab592177 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -88,6 +88,7 @@ struct _GstRTSPSessionMedia * @timeout: the timeout of the session * @create_time: the time when the session was created * @last_access: the time the session was last accessed + * @expire_count: the expire prevention counter * @media: a list of #GstRTSPSessionMedia managed in this session * * Session information kept by the server for a specific client. @@ -102,6 +103,7 @@ struct _GstRTSPSession { guint timeout; GTimeVal create_time; GTimeVal last_access; + gint expire_count; GList *medias; }; @@ -122,6 +124,8 @@ guint gst_rtsp_session_get_timeout (GstRTSPSession *se /* session timeout stuff */ void gst_rtsp_session_touch (GstRTSPSession *session); +void gst_rtsp_session_prevent_expire (GstRTSPSession *session); +void gst_rtsp_session_allow_expire (GstRTSPSession *session); gint gst_rtsp_session_next_timeout (GstRTSPSession *session, GTimeVal *now); gboolean gst_rtsp_session_is_expired (GstRTSPSession *session, GTimeVal *now); From 336ffc0941308597105f4cd3bc8c1cb497b38108 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 6 Apr 2010 17:08:40 +0200 Subject: [PATCH 0186/1776] client: improve client cleanups Make sure the session does not timeout when using TCP. We need to do this because quicktime player does not send RTCP for some reason in tunneled mode. Refactor some cleanup code. Fixes #612915 --- gst/rtsp-server/rtsp-client.c | 64 +++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6c575dbcd7..b65b5e4ebd 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -48,6 +48,8 @@ static void gst_rtsp_client_finalize (GObject * obj); static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session); +static void unlink_session_streams (GstRTSPClient * client, + GstRTSPSession *session, GstRTSPSessionMedia * media); G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); @@ -86,23 +88,42 @@ gst_rtsp_client_init (GstRTSPClient * client) { } +static void +client_unlink_session (GstRTSPClient *client, GstRTSPSession *session) +{ + GList *medias; + + /* unlink all media managed in this session */ + for (medias = session->medias; medias; medias = g_list_next (medias)) { + unlink_session_streams (client, session, (GstRTSPSessionMedia *) medias->data); + } +} + +static void +client_cleanup_sessions (GstRTSPClient *client) +{ + GList *sessions; + + /* remove weak-ref from sessions */ + for (sessions = client->sessions; sessions; sessions = g_list_next (sessions)) { + GstRTSPSession *session = (GstRTSPSession *) sessions->data; + g_object_weak_unref (G_OBJECT (session), + (GWeakNotify) client_session_finalized, client); + client_unlink_session (client, session); + } + g_list_free (client->sessions); + client->sessions = NULL; +} + /* A client is finalized when the connection is broken */ static void gst_rtsp_client_finalize (GObject * obj) { GstRTSPClient *client = GST_RTSP_CLIENT (obj); - GList *walk; GST_INFO ("finalize client %p", client); - /* remove weak-ref from sessions */ - for (walk = client->sessions; walk; walk = g_list_next (walk)) { - GstRTSPSession *msession = (GstRTSPSession *) walk->data; - g_object_weak_unref (G_OBJECT (msession), - (GWeakNotify) client_session_finalized, client); - } - - g_list_free (client->sessions); + client_cleanup_sessions (client); gst_rtsp_connection_free (client->connection); if (client->session_pool) @@ -329,24 +350,28 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) } static void -link_stream (GstRTSPClient * client, GstRTSPSessionStream * stream) +link_stream (GstRTSPClient * client, GstRTSPSession *session, GstRTSPSessionStream * stream) { GST_DEBUG ("client %p: linking stream %p", client, stream); gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data, (GstRTSPSendFunc) do_send_data, client, NULL); client->streams = g_list_prepend (client->streams, stream); + /* make sure our session can't expire */ + gst_rtsp_session_prevent_expire (session); } static void -unlink_stream (GstRTSPClient * client, GstRTSPSessionStream * stream) +unlink_stream (GstRTSPClient * client, GstRTSPSession *session, GstRTSPSessionStream * stream) { GST_DEBUG ("client %p: unlinking stream %p", client, stream); gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); client->streams = g_list_remove (client->streams, stream); + /* our session can now expire */ + gst_rtsp_session_allow_expire (session); } static void -unlink_session_streams (GstRTSPClient * client, GstRTSPSessionMedia * media) +unlink_session_streams (GstRTSPClient * client, GstRTSPSession *session, GstRTSPSessionMedia * media) { guint n_streams, i; @@ -363,7 +388,7 @@ unlink_session_streams (GstRTSPClient * client, GstRTSPSessionMedia * media) if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { /* for TCP, unlink the stream from the TCP connection of the client */ - unlink_stream (client, sstream); + unlink_stream (client, session, sstream); } } } @@ -407,7 +432,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPUrl * uri, goto not_found; /* unlink the all TCP callbacks */ - unlink_session_streams (client, media); + unlink_session_streams (client, session, media); /* remove the session from the watched sessions */ g_object_weak_unref (G_OBJECT (session), @@ -541,7 +566,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPUrl * uri, goto invalid_state; /* unlink the all TCP callbacks */ - unlink_session_streams (client, media); + unlink_session_streams (client, session, media); /* then pause sending */ gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED); @@ -635,7 +660,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPUrl * uri, if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { /* for TCP, link the stream to the TCP connection of the client */ - link_stream (client, sstream); + link_stream (client, session, sstream); } stream = sstream->media_stream; @@ -1131,15 +1156,12 @@ santize_uri (GstRTSPUrl * uri) static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) { - GList *medias; - GST_INFO ("client %p: session %p finished", client, session); /* unlink all media managed in this session */ - for (medias = session->medias; medias; medias = g_list_next (medias)) { - unlink_session_streams (client, (GstRTSPSessionMedia *) medias->data); - } + client_unlink_session (client, session); + /* remove the session */ if (!(client->sessions = g_list_remove (client->sessions, session))) { GST_INFO ("client %p: all sessions finalized, close the connection", client); close_connection (client); From b0c6a9aa339856fe2522d6c158e21b9e6f661d9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 25 Apr 2010 16:35:30 +0100 Subject: [PATCH 0187/1776] configure: fail if GStreamer core/base requirements are not met --- configure.ac | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 0218fd236a..84446f9c07 100644 --- a/configure.ac +++ b/configure.ac @@ -40,10 +40,6 @@ dnl *** required versions of GStreamer stuff *** GST_REQ=0.10.28.1 GSTPB_REQ=0.10.28.1 -dnl export for .pc files -AC_SUBST([GST_REQ]) -AC_SUBST([GSTPB_REQ]) - dnl *** autotools stuff **** dnl allow for different autotools @@ -155,7 +151,7 @@ AG_GST_GLIB_CHECK([$GLIB_REQ]) dnl checks for gstreamer dnl uninstalled is selected preferentially -- see pkg-config(1) -AG_GST_CHECK_GST($GST_MAJORMINOR, [$GST_REQ]) +AG_GST_CHECK_GST($GST_MAJORMINOR, [$GST_REQ], [yes]) GST_TOOLS_DIR=`$PKG_CONFIG --variable=toolsdir gstreamer-$GST_MAJORMINOR` if test -z $GST_TOOLS_DIR; then @@ -167,9 +163,9 @@ GST_PLUGINS_DIR=`$PKG_CONFIG gstreamer-$GST_MAJORMINOR --variable pluginsdir` AC_SUBST(GST_PLUGINS_DIR) AC_MSG_NOTICE(Using GStreamer Core Plugins in $GST_PLUGINS_DIR) -AG_GST_CHECK_GST_BASE($GST_MAJORMINOR, [$GST_REQ]) +AG_GST_CHECK_GST_BASE($GST_MAJORMINOR, [$GST_REQ], [yes]) -AG_GST_CHECK_GST_PLUGINS_BASE($GST_MAJORMINOR, [$GSTPB_REQ]) +AG_GST_CHECK_GST_PLUGINS_BASE($GST_MAJORMINOR, [$GSTPB_REQ], [yes]) GSTPB_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-base-$GST_MAJORMINOR --variable pluginsdir` AC_SUBST(GSTPB_PLUGINS_DIR) AC_MSG_NOTICE(Using GStreamer Base Plugins in $GSTPB_PLUGINS_DIR) From 1c749adc56c43f5258ed59f2d6d5d64cf187c702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 20 May 2010 14:09:18 +0100 Subject: [PATCH 0188/1776] configure: bump core/base requirements to released version Makes things less confusing for people. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 84446f9c07..5ec1cc50e8 100644 --- a/configure.ac +++ b/configure.ac @@ -37,8 +37,8 @@ AC_SUBST(GST_MAJORMINOR) AM_PROG_LIBTOOL dnl *** required versions of GStreamer stuff *** -GST_REQ=0.10.28.1 -GSTPB_REQ=0.10.28.1 +GST_REQ=0.10.29 +GSTPB_REQ=0.10.29 dnl *** autotools stuff **** From b22c67d9d5728ade1ac58e9ee602ebdbc4b20ec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 20 May 2010 14:33:24 +0100 Subject: [PATCH 0189/1776] build: distcheck fixes Fix 'make distcheck', somewhat (it still fails because it tries to install files into /usr/share/vala/vapi/ irrespective of the configured prefix). --- bindings/python/Makefile.am | 2 +- bindings/vala/Makefile.am | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am index 03f8479c4c..9c1b36794e 100644 --- a/bindings/python/Makefile.am +++ b/bindings/python/Makefile.am @@ -9,7 +9,7 @@ pygstrtspserver_PYTHON = pygstrtspserverexecdir = $(pkgpyexecdir) pygstrtspserverexec_LTLIBRARIES = rtspserver.la -DEFS = rtspserver-types.defs rtspserver.defs +DEFS = $(srcdir)/rtspserver-types.defs $(srcdir)/rtspserver.defs defs_DATA = $(DEFS) defsdir = $(pkgdatadir)/$(GST_MAJORMINOR)/defs OVERRIDES = rtspserver.override diff --git a/bindings/vala/Makefile.am b/bindings/vala/Makefile.am index 706cf19a33..c1fd597a05 100644 --- a/bindings/vala/Makefile.am +++ b/bindings/vala/Makefile.am @@ -1,12 +1,12 @@ -VAPI_FILES = gst-rtsp-server-0.10.deps -DEPS_FILES = gst-rtsp-server-0.10.vapi +DEPS_FILES = gst-rtsp-server-0.10.deps +VAPI_FILES = gst-rtsp-server-0.10.vapi gst-rtsp-server-0.10.deps: - cp packages/gst-rtsp-server-0.10.deps $@ + cp $(srcdir)/packages/gst-rtsp-server-0.10.deps $@ vapidir = $(VAPIDIR) vapi_DATA = $(VAPI_FILES) $(DEPS_FILES) -EXTRA_DIST = packages $(DEPS_FILES) +EXTRA_DIST = packages $(VAPI_FILES) From 6a880e53df3a1e66ea8d591184a79817311eb4f6 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Mon, 9 Aug 2010 12:56:23 -0700 Subject: [PATCH 0190/1776] Add stdlib.h for atoi() --- gst/rtsp-server/rtsp-media.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 89dc466b54..08939c6a69 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -18,6 +18,7 @@ */ #include +#include #include #include From f2a2577f13cbba5b3089e55d60fefa53a9acd7cd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 16 Aug 2010 12:24:50 +0200 Subject: [PATCH 0191/1776] README: add blurb about shared media factories --- docs/README | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/README b/docs/README index 50ad82f4ff..5b223b6340 100644 --- a/docs/README +++ b/docs/README @@ -161,6 +161,10 @@ can build simple server applications with it. a test signal will be streamed to the client. The full example code can be found in the examples/test-readme.c file. + Note that by default the factory will create a new pipeline for each client. If + you want to share a pipeline between clients, use + gst_rtsp_media_factory_set_shared(). + * more on GstRTSPMediaFactory From 8f6fd320654f5390d72027ac289921f1f26e40b4 Mon Sep 17 00:00:00 2001 From: Robert Krakora Date: Mon, 16 Aug 2010 12:32:28 +0200 Subject: [PATCH 0192/1776] server: use SO_LINGER SO_LINGER on the socket will make sure that any pending data on the socket is flushed ASAP and that the socket connection is reset. This makes sure that the socket can be reused immediately. Fixes 622757 --- gst/rtsp-server/rtsp-server.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 7f54798dba..7b52ffa667 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -421,6 +421,7 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) int ret, sockfd; struct addrinfo hints; struct addrinfo *result, *rp; + struct linger linger; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ @@ -476,6 +477,14 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) (void *) &ret, sizeof (ret)) < 0) goto keepalive_failed; + /* make sure socket is reset immediately after close. This ensure that we can + * reuse the socket quickly. */ + linger.l_onoff = 1; + linger.l_linger = 0; + if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_LINGER, + (void *) &linger, sizeof (linger)) < 0) + goto linger_failed; + /* set the server socket to nonblocking */ fcntl (server->server_sock.fd, F_SETFL, O_NONBLOCK); @@ -505,29 +514,30 @@ no_socket: } reuse_failed: { - if (server->server_sock.fd >= 0) { - close (server->server_sock.fd); - server->server_sock.fd = -1; - } GST_ERROR_OBJECT (server, "failed to reuse socket: %s", g_strerror (errno)); - return FALSE; + goto close_error; } keepalive_failed: { - if (server->server_sock.fd >= 0) { - close (server->server_sock.fd); - server->server_sock.fd = -1; - } GST_ERROR_OBJECT (server, "failed to configure keepalive socket: %s", g_strerror (errno)); - return FALSE; + goto close_error; + } +linger_failed: + { + GST_ERROR_OBJECT (server, "failed to no linger socket: %s", g_strerror (errno)); + goto close_error; } listen_failed: + { + GST_ERROR_OBJECT (server, "failed to listen on socket: %s", g_strerror (errno)); + goto close_error; + } +close_error: { if (server->server_sock.fd >= 0) { close (server->server_sock.fd); server->server_sock.fd = -1; } - GST_ERROR_OBJECT (server, "failed to listen on socket: %s", g_strerror (errno)); return FALSE; } } From 2607ff079da6f01831cd809f83aaabab1a89a428 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 19 Aug 2010 18:52:47 +0200 Subject: [PATCH 0193/1776] server: use 5 second linger period in SO_LINGER Wait 5 seconds before clearing the send buffers and reseting the connection with the client when we do a close. This should be enough time to get the message to the client. See #622757 --- gst/rtsp-server/rtsp-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 7b52ffa667..cc0345601d 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -480,7 +480,7 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) /* make sure socket is reset immediately after close. This ensure that we can * reuse the socket quickly. */ linger.l_onoff = 1; - linger.l_linger = 0; + linger.l_linger = 5; if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof (linger)) < 0) goto linger_failed; From af732fa7492c592c6ce7fd8b6092354e64f4675b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 20 Aug 2010 10:18:34 +0200 Subject: [PATCH 0194/1776] server: disable use of SO_LINGER SO_LINGER cause the client to fail to receive a TEARDOWN message because the server close()s the connection. --- gst/rtsp-server/rtsp-server.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index cc0345601d..3399a66827 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -27,6 +27,11 @@ #define DEFAULT_SERVICE "8554" #define DEFAULT_BACKLOG 5 +/* Define to use the SO_LINGER option so that the server sockets can be resused + * sooner. Disabled for now because it is not very well implemented by various + * OSes and it causes clients to fail to read the TEARDOWN response. */ +#undef USE_SOLINGER + enum { PROP_0, @@ -421,7 +426,9 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) int ret, sockfd; struct addrinfo hints; struct addrinfo *result, *rp; +#ifdef USE_SOLINGER struct linger linger; +#endif memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ @@ -477,13 +484,16 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) (void *) &ret, sizeof (ret)) < 0) goto keepalive_failed; - /* make sure socket is reset immediately after close. This ensure that we can - * reuse the socket quickly. */ +#ifdef USE_SOLINGER + /* make sure socket is reset 5 seconds after close. This ensure that we can + * reuse the socket quickly while still having a chance to send data to the + * client. */ linger.l_onoff = 1; linger.l_linger = 5; if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof (linger)) < 0) goto linger_failed; +#endif /* set the server socket to nonblocking */ fcntl (server->server_sock.fd, F_SETFL, O_NONBLOCK); @@ -522,11 +532,13 @@ keepalive_failed: GST_ERROR_OBJECT (server, "failed to configure keepalive socket: %s", g_strerror (errno)); goto close_error; } +#ifdef USE_SOLINGER linger_failed: { GST_ERROR_OBJECT (server, "failed to no linger socket: %s", g_strerror (errno)); goto close_error; } +#endif listen_failed: { GST_ERROR_OBJECT (server, "failed to listen on socket: %s", g_strerror (errno)); From 7c0f8a77ecfaa1b49bc0195e7c914769cec7e9de Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 20 Aug 2010 13:09:12 +0200 Subject: [PATCH 0195/1776] media: don't add udp addresses multiple times Keep track of the udp addresses we added to udpsink and never add the same udp destination twice. This avoids duplicate packets when using multicast. --- gst/rtsp-server/rtsp-media.c | 91 +++++++++++++++++++++++++++++++++--- gst/rtsp-server/rtsp-media.h | 1 + 2 files changed, 86 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 08939c6a69..919622e163 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1527,6 +1527,89 @@ default_unprepare (GstRTSPMedia * media) return TRUE; } +typedef struct { + gint count; + gchar *dest; + gint min, max; +} RTSPDestination; + + +static gint +dest_compare (RTSPDestination * a, RTSPDestination * b) +{ + if ((a->min == b->min) && (a->max == b->max) && (strcmp (a->dest, b->dest) == 0)) + return 0; + + return 1; +} + +/* FIXME, udpsink should do this for us */ +static void +add_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, + gchar *dest, gint min, gint max) +{ + RTSPDestination fdest; + RTSPDestination *ndest; + GList *find; + + fdest.dest = dest; + fdest.min = min; + fdest.max = max; + + /* first see if we already added this destination */ + find = g_list_find_custom (stream->destinations, &fdest, (GCompareFunc) dest_compare); + if (find) { + ndest = (RTSPDestination *) find->data; + + GST_INFO ("already streaming to %s:%d-%d with %d clients", dest, min, max, ndest->count); + ndest->count++; + } else { + GST_INFO ("adding %s:%d-%d", dest, min, max); + + g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); + + ndest = g_slice_new (RTSPDestination); + ndest->count = 1; + ndest->dest = g_strdup (dest); + ndest->min = min; + ndest->max = max; + + stream->destinations = g_list_prepend (stream->destinations, ndest); + } +} + +static void +remove_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, + gchar *dest, gint min, gint max) +{ + RTSPDestination fdest; + RTSPDestination *ndest; + GList *find; + + fdest.dest = dest; + fdest.min = min; + fdest.max = max; + + /* first see if we already added this destination */ + find = g_list_find_custom (stream->destinations, &fdest, (GCompareFunc) dest_compare); + if (!find) + return; + + ndest = (RTSPDestination *) find->data; + if (--ndest->count == 0) { + GST_INFO ("removing %s:%d-%d", dest, min, max); + g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); + + stream->destinations = g_list_delete_link (stream->destinations, find); + g_free (ndest->dest); + g_slice_free (RTSPDestination, ndest); + } else { + GST_INFO ("still streaming to %s:%d-%d with %d clients", dest, min, max, ndest->count); + } +} + /** * gst_rtsp_media_set_state: * @media: a #GstRTSPMedia @@ -1610,16 +1693,12 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, } if (add && !tr->active) { - GST_INFO ("adding %s:%d-%d", dest, min, max); - g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); + add_udp_destination (media, stream, dest, min, max); stream->transports = g_list_prepend (stream->transports, tr); tr->active = TRUE; media->active++; } else if (remove && tr->active) { - GST_INFO ("removing %s:%d-%d", dest, min, max); - g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); + remove_udp_destination (media, stream, dest, min, max); stream->transports = g_list_remove (stream->transports, tr); tr->active = FALSE; media->active--; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index ec3e832f65..d3c94db69a 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -137,6 +137,7 @@ struct _GstRTSPMediaStream { /* transports we stream to */ GList *transports; + GList *destinations; }; /** From c89d17ca266e0ab1b8c85746590cbad289ec78c4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 20 Aug 2010 13:19:56 +0200 Subject: [PATCH 0196/1776] media: don't leak destinations Refactor and cleanup the destinations array when the stream is destroyed. --- gst/rtsp-server/rtsp-media.c | 67 ++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 919622e163..a9d1413a60 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -126,6 +126,43 @@ gst_rtsp_media_init (GstRTSPMedia * media) media->protocols = DEFAULT_PROTOCOLS; } +/* FIXME. this should be done in multiudpsink */ +typedef struct { + gint count; + gchar *dest; + gint min, max; +} RTSPDestination; + +static gint +dest_compare (RTSPDestination * a, RTSPDestination * b) +{ + if ((a->min == b->min) && (a->max == b->max) && (strcmp (a->dest, b->dest) == 0)) + return 0; + + return 1; +} + +static RTSPDestination * +create_destination (const gchar *dest, gint min, gint max) +{ + RTSPDestination *res; + + res = g_slice_new (RTSPDestination); + res->count = 1; + res->dest = g_strdup (dest); + res->min = min; + res->max = max; + + return res; +} + +static void +free_destination (RTSPDestination *dest) +{ + g_free (dest->dest); + g_slice_free (RTSPDestination, dest); +} + static void gst_rtsp_media_stream_free (GstRTSPMediaStream * stream) { @@ -148,6 +185,9 @@ gst_rtsp_media_stream_free (GstRTSPMediaStream * stream) g_list_free (stream->transports); + g_list_foreach (stream->destinations, (GFunc) free_destination, NULL); + g_list_free (stream->destinations); + g_free (stream); } @@ -1527,23 +1567,6 @@ default_unprepare (GstRTSPMedia * media) return TRUE; } -typedef struct { - gint count; - gchar *dest; - gint min, max; -} RTSPDestination; - - -static gint -dest_compare (RTSPDestination * a, RTSPDestination * b) -{ - if ((a->min == b->min) && (a->max == b->max) && (strcmp (a->dest, b->dest) == 0)) - return 0; - - return 1; -} - -/* FIXME, udpsink should do this for us */ static void add_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, gchar *dest, gint min, gint max) @@ -1569,12 +1592,7 @@ add_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); - ndest = g_slice_new (RTSPDestination); - ndest->count = 1; - ndest->dest = g_strdup (dest); - ndest->min = min; - ndest->max = max; - + ndest = create_destination (dest, min, max); stream->destinations = g_list_prepend (stream->destinations, ndest); } } @@ -1603,8 +1621,7 @@ remove_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); stream->destinations = g_list_delete_link (stream->destinations, find); - g_free (ndest->dest); - g_slice_free (RTSPDestination, ndest); + free_destination (ndest); } else { GST_INFO ("still streaming to %s:%d-%d with %d clients", dest, min, max, ndest->count); } From a900866570f18cb35716952e5b9e441c9851f351 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 20 Aug 2010 15:58:39 +0200 Subject: [PATCH 0197/1776] media: use multiudpsink send-duplicates when we can If we have a new enough multiudpsink with the send-duplicates property, use this instead of doing our own filtering. Our custom filtering code should eventually be removed when we can depend on a released -good. --- gst/rtsp-server/rtsp-media.c | 85 ++++++++++++++++++++++++------------ gst/rtsp-server/rtsp-media.h | 4 ++ 2 files changed, 60 insertions(+), 29 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index a9d1413a60..c2dc996a60 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -737,6 +737,16 @@ again: if (!udpsink1) goto no_udp_protocol; + if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), "send-duplicates")) { + g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); + stream->filter_duplicates = FALSE; + } + else { + GST_WARNING ("multiudpsink version found without send-duplicates property"); + stream->filter_duplicates = TRUE; + } + g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL); g_object_set (G_OBJECT (udpsink1), "sockfd", sockfd, NULL); g_object_set (G_OBJECT (udpsink1), "closefd", FALSE, NULL); @@ -1571,29 +1581,37 @@ static void add_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, gchar *dest, gint min, gint max) { - RTSPDestination fdest; + gboolean do_add = TRUE; RTSPDestination *ndest; - GList *find; - fdest.dest = dest; - fdest.min = min; - fdest.max = max; + if (stream->filter_duplicates) { + RTSPDestination fdest; + GList *find; - /* first see if we already added this destination */ - find = g_list_find_custom (stream->destinations, &fdest, (GCompareFunc) dest_compare); - if (find) { - ndest = (RTSPDestination *) find->data; + fdest.dest = dest; + fdest.min = min; + fdest.max = max; - GST_INFO ("already streaming to %s:%d-%d with %d clients", dest, min, max, ndest->count); - ndest->count++; - } else { + /* first see if we already added this destination */ + find = g_list_find_custom (stream->destinations, &fdest, (GCompareFunc) dest_compare); + if (find) { + ndest = (RTSPDestination *) find->data; + + GST_INFO ("already streaming to %s:%d-%d with %d clients", dest, min, max, ndest->count); + ndest->count++; + do_add = FALSE; + } + } + + if (do_add) { GST_INFO ("adding %s:%d-%d", dest, min, max); - g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); - ndest = create_destination (dest, min, max); - stream->destinations = g_list_prepend (stream->destinations, ndest); + if (stream->filter_duplicates) { + ndest = create_destination (dest, min, max); + stream->destinations = g_list_prepend (stream->destinations, ndest); + } } } @@ -1601,29 +1619,38 @@ static void remove_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, gchar *dest, gint min, gint max) { - RTSPDestination fdest; + gboolean do_remove = TRUE; RTSPDestination *ndest; GList *find; - fdest.dest = dest; - fdest.min = min; - fdest.max = max; + if (stream->filter_duplicates) { + RTSPDestination fdest; - /* first see if we already added this destination */ - find = g_list_find_custom (stream->destinations, &fdest, (GCompareFunc) dest_compare); - if (!find) - return; + fdest.dest = dest; + fdest.min = min; + fdest.max = max; - ndest = (RTSPDestination *) find->data; - if (--ndest->count == 0) { + /* first see if we already added this destination */ + find = g_list_find_custom (stream->destinations, &fdest, (GCompareFunc) dest_compare); + if (!find) + return; + + ndest = (RTSPDestination *) find->data; + if (--ndest->count > 0) { + do_remove = FALSE; + GST_INFO ("still streaming to %s:%d-%d with %d clients", dest, min, max, ndest->count); + } + } + + if (do_remove) { GST_INFO ("removing %s:%d-%d", dest, min, max); g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); - stream->destinations = g_list_delete_link (stream->destinations, find); - free_destination (ndest); - } else { - GST_INFO ("still streaming to %s:%d-%d with %d clients", dest, min, max, ndest->count); + if (stream->filter_duplicates) { + stream->destinations = g_list_delete_link (stream->destinations, find); + free_destination (ndest); + } } } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index d3c94db69a..0dea08abb0 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -137,6 +137,10 @@ struct _GstRTSPMediaStream { /* transports we stream to */ GList *transports; + + /* to filter out duplicate destinations in case multiudpsink is too old to do + * this for us */ + gboolean filter_duplicates; GList *destinations; }; From dc33070da3c28f81b083f20881234a712babe0fc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 20 Aug 2010 18:17:08 +0200 Subject: [PATCH 0198/1776] media-factory: add eos-shutdown property Add an eos-shutdown property that will send an EOS to the pipeline before shutting it down. This allows for nice cleanup in case of a muxer. Fixes #625597 --- gst/rtsp-server/rtsp-media-factory.c | 60 ++++++++++++++++++++++- gst/rtsp-server/rtsp-media-factory.h | 5 ++ gst/rtsp-server/rtsp-media.c | 71 +++++++++++++++++++++++++++- gst/rtsp-server/rtsp-media.h | 5 ++ 4 files changed, 138 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 44d80989cf..92591aa7be 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -21,12 +21,14 @@ #define DEFAULT_LAUNCH NULL #define DEFAULT_SHARED FALSE +#define DEFAULT_EOS_SHUTDOWN FALSE enum { PROP_0, PROP_LAUNCH, PROP_SHARED, + PROP_EOS_SHUTDOWN, PROP_LAST }; @@ -82,6 +84,11 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) g_param_spec_boolean ("shared", "Shared", "If media from this factory is shared", DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN, + g_param_spec_boolean ("eos-shutdown", "EOS Shutdown", + "Send EOS down the pipeline before shutting down", + DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + klass->gen_key = default_gen_key; klass->get_element = default_get_element; klass->construct = default_construct; @@ -96,6 +103,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) { factory->launch = g_strdup (DEFAULT_LAUNCH); factory->shared = DEFAULT_SHARED; + factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN; factory->lock = g_mutex_new (); factory->medias_lock = g_mutex_new (); @@ -129,6 +137,9 @@ gst_rtsp_media_factory_get_property (GObject *object, guint propid, case PROP_SHARED: g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory)); break; + case PROP_EOS_SHUTDOWN: + g_value_set_boolean (value, gst_rtsp_media_factory_is_eos_shutdown (factory)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -147,6 +158,9 @@ gst_rtsp_media_factory_set_property (GObject *object, guint propid, case PROP_SHARED: gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value)); break; + case PROP_EOS_SHUTDOWN: + gst_rtsp_media_factory_set_eos_shutdown (factory, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -260,6 +274,48 @@ gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory) return result; } +/** + * gst_rtsp_media_factory_set_eos_shutdown: + * @factory: a #GstRTSPMediaFactory + * @eos_shutdown: the new value + * + * Configure if media created from this factory will have an EOS sent to the + * pipeline before shutdown. + */ +void +gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory *factory, + gboolean eos_shutdown) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + g_mutex_lock (factory->lock); + factory->eos_shutdown = eos_shutdown; + g_mutex_unlock (factory->lock); +} + +/** + * gst_rtsp_media_factory_is_eos_shutdown: + * @factory: a #GstRTSPMediaFactory + * + * Get if media created from this factory will have an EOS event sent to the + * pipeline before shutdown. + * + * Returns: %TRUE if the media will receive EOS before shutdown. + */ +gboolean +gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory) +{ + gboolean result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); + + g_mutex_lock (factory->lock); + result = factory->eos_shutdown; + g_mutex_unlock (factory->lock); + + return result; +} + static gboolean compare_media (gpointer key, GstRTSPMedia *media1, GstRTSPMedia *media2) { @@ -536,12 +592,14 @@ no_element: static void default_configure (GstRTSPMediaFactory *factory, GstRTSPMedia *media) { - gboolean shared; + gboolean shared, eos_shutdown; /* configure the sharedness */ g_mutex_lock (factory->lock); shared = factory->shared; + eos_shutdown = factory->eos_shutdown; g_mutex_unlock (factory->lock); gst_rtsp_media_set_shared (media, shared); + gst_rtsp_media_set_eos_shutdown (media, eos_shutdown); } diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 3d1ac9b7e7..d462914755 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -57,6 +57,7 @@ struct _GstRTSPMediaFactory { GMutex *lock; gchar *launch; gboolean shared; + gboolean eos_shutdown; GMutex *medias_lock; GHashTable *medias; @@ -107,6 +108,10 @@ void gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * gboolean shared); gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory *factory, + gboolean eos_shutdown); +gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory); + /* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c2dc996a60..02a9317402 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -29,6 +29,7 @@ #define DEFAULT_REUSABLE FALSE #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST +#define DEFAULT_EOS_SHUTDOWN FALSE /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -39,6 +40,7 @@ enum PROP_SHARED, PROP_REUSABLE, PROP_PROTOCOLS, + PROP_EOS_SHUTDOWN, PROP_LAST }; @@ -96,6 +98,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS, DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN, + g_param_spec_boolean ("eos-shutdown", "EOS Shutdown", + "Send an EOS event to the pipeline before unpreparing", + DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_UNPREPARED] = g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL, @@ -124,6 +131,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) media->shared = DEFAULT_SHARED; media->reusable = DEFAULT_REUSABLE; media->protocols = DEFAULT_PROTOCOLS; + media->eos_shutdown = DEFAULT_EOS_SHUTDOWN; } /* FIXME. this should be done in multiudpsink */ @@ -245,6 +253,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_PROTOCOLS: g_value_set_flags (value, gst_rtsp_media_get_protocols (media)); break; + case PROP_EOS_SHUTDOWN: + g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -266,6 +277,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_PROTOCOLS: gst_rtsp_media_set_protocols (media, g_value_get_flags (value)); break; + case PROP_EOS_SHUTDOWN: + gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -444,6 +458,39 @@ gst_rtsp_media_get_protocols (GstRTSPMedia * media) return media->protocols; } +/** + * gst_rtsp_media_set_eos_shutdown: + * @media: a #GstRTSPMedia + * @eos_shutdown: the new value + * + * Set or unset if an EOS event will be sent to the pipeline for @media before + * it is unprepared. + */ +void +gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + media->eos_shutdown = eos_shutdown; +} + +/** + * gst_rtsp_media_is_eos_shutdown: + * @media: a #GstRTSPMedia + * + * Check if the pipeline for @media will send an EOS down the pipeline before + * unpreparing. + * + * Returns: %TRUE if the media will send EOS before unpreparing. + */ +gboolean +gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media) +{ + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + return media->eos_shutdown; +} + /** * gst_rtsp_media_n_streams: * @media: a #GstRTSPMedia @@ -1328,6 +1375,15 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); break; + case GST_MESSAGE_EOS: + GST_INFO ("%p: got EOS", media); + if (media->eos_pending) { + GST_DEBUG ("shutting down after EOS"); + gst_element_set_state (media->pipeline, GST_STATE_NULL); + media->eos_pending = FALSE; + g_object_unref (media); + } + break; default: GST_INFO ("%p: got message type %s", media, gst_message_type_get_name (type)); @@ -1572,8 +1628,19 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) static gboolean default_unprepare (GstRTSPMedia * media) { - gst_element_set_state (media->pipeline, GST_STATE_NULL); - + if (media->eos_shutdown) { + GST_DEBUG ("sending EOS for shutdown"); + /* ref so that we don't disappear */ + g_object_ref (media); + media->eos_pending = TRUE; + gst_element_send_event (media->pipeline, gst_event_new_eos()); + /* we need to go to playing again for the EOS to propagate, normally in this + * state, nothing is receiving data from us anymore so this is ok. */ + gst_element_set_state (media->pipeline, GST_STATE_PLAYING); + } else { + GST_DEBUG ("shutting down"); + gst_element_set_state (media->pipeline, GST_STATE_NULL); + } return TRUE; } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 0dea08abb0..9f620740b2 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -200,12 +200,14 @@ struct _GstRTSPMedia { GstRTSPLowerTrans protocols; gboolean reused; gboolean is_ipv6; + gboolean eos_shutdown; GstElement *element; GArray *streams; GList *dynamic; GstRTSPMediaStatus status; gint active; + gboolean eos_pending; /* the pipeline for the media */ GstElement *pipeline; @@ -265,6 +267,9 @@ gboolean gst_rtsp_media_is_reusable (GstRTSPMedia *media); void gst_rtsp_media_set_protocols (GstRTSPMedia *media, GstRTSPLowerTrans protocols); GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia *media); +void gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown); +gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media); + /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media); From 450b68252f4fe9d4c5aa5e566810a919611e0371 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 24 Aug 2010 16:47:30 +0200 Subject: [PATCH 0199/1776] media: cleanup media transport before freeing Cleanup the media transport data before freeing. In particular, remove the qdata from the rtpsource object. --- gst/rtsp-server/rtsp-media.c | 15 +++++++++++++++ gst/rtsp-server/rtsp-media.h | 2 ++ gst/rtsp-server/rtsp-session.c | 3 +-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 02a9317402..c6a45ac366 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -171,6 +171,19 @@ free_destination (RTSPDestination *dest) g_slice_free (RTSPDestination, dest); } +void +gst_rtsp_media_trans_cleanup (GstRTSPMediaTrans *trans) +{ + if (trans->transport) { + gst_rtsp_transport_free (trans->transport); + trans->transport = NULL; + } + if (trans->rtpsource) { + g_object_set_qdata (trans->rtpsource, ssrc_stream_map_key, NULL); + trans->rtpsource = NULL; + } +} + static void gst_rtsp_media_stream_free (GstRTSPMediaStream * stream) { @@ -855,6 +868,7 @@ cleanup: } } +/* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) { @@ -1408,6 +1422,7 @@ bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media) return ret; } +/* called from streaming threads */ static void pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) { diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 9f620740b2..211e2c04b1 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -288,6 +288,8 @@ gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstS void gst_rtsp_media_remove_elements (GstRTSPMedia *media); +void gst_rtsp_media_trans_cleanup (GstRTSPMediaTrans *trans); + G_END_DECLS #endif /* __GST_RTSP_MEDIA_H__ */ diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 7df6c3726e..f435446b8a 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -82,8 +82,7 @@ gst_rtsp_session_free_stream (GstRTSPSessionStream * stream) gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); gst_rtsp_session_stream_set_keepalive (stream, NULL, NULL, NULL); - if (stream->trans.transport) - gst_rtsp_transport_free (stream->trans.transport); + gst_rtsp_media_trans_cleanup (&stream->trans); g_free (stream); } From ed473f6f26b0df5b778e088279b2b9f6517c28e1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 22 Sep 2010 16:15:56 +0200 Subject: [PATCH 0200/1776] media: help the compiler a little --- gst/rtsp-server/rtsp-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c6a45ac366..af802e9d65 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1702,8 +1702,8 @@ remove_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, gchar *dest, gint min, gint max) { gboolean do_remove = TRUE; - RTSPDestination *ndest; - GList *find; + RTSPDestination *ndest = NULL; + GList *find = NULL; if (stream->filter_duplicates) { RTSPDestination fdest; From a61610c96861dd11840add94b38e750cf5cf39b7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 22 Sep 2010 16:22:49 +0200 Subject: [PATCH 0201/1776] configure: release 0.10.6 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5ec1cc50e8..f045f5a48f 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.5.1, +AC_INIT(Gst-RTSP, 0.10.6, http://gstreamer.net/, gst-rtsp) From 0e6e03fafb3a42c54b509d90aef4b9b7f960e940 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 22 Sep 2010 16:32:30 +0200 Subject: [PATCH 0202/1776] back to development --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f045f5a48f..63fe726287 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.6, +AC_INIT(Gst-RTSP, 0.10.6.1, http://gstreamer.net/, gst-rtsp) From 6b771d391d99871ce2a9d1207f1310f3c1610a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 22 Sep 2010 18:12:50 +0200 Subject: [PATCH 0203/1776] Fix configure checks and installation location for Vala bindings Fixes bug #628676. --- bindings/vala/Makefile.am | 2 +- configure.ac | 29 ++++++++++++----------------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/bindings/vala/Makefile.am b/bindings/vala/Makefile.am index c1fd597a05..06e8ee4b5c 100644 --- a/bindings/vala/Makefile.am +++ b/bindings/vala/Makefile.am @@ -5,7 +5,7 @@ VAPI_FILES = gst-rtsp-server-0.10.vapi gst-rtsp-server-0.10.deps: cp $(srcdir)/packages/gst-rtsp-server-0.10.deps $@ -vapidir = $(VAPIDIR) +vapidir = $(datadir)/vala/vapi vapi_DATA = $(VAPI_FILES) $(DEPS_FILES) EXTRA_DIST = packages $(VAPI_FILES) diff --git a/configure.ac b/configure.ac index 63fe726287..ceab687513 100644 --- a/configure.ac +++ b/configure.ac @@ -113,23 +113,18 @@ fi AM_CONDITIONAL(WITH_PYTHON, [test "x$HAVE_PYTHON_BINDINGS" = "xyes"]) -dnl Check for vala -PKG_CHECK_EXISTS([vala-1.0], [HAVE_VALA="yes"], [HAVE_VALA="no"]) +dnl Check for Vala +AC_ARG_ENABLE([vala], + AC_HELP_STRING([--enable-vala],[enable Vala bindings (default=yes)]), + [case "${enableval}" in + yes) enable_vala=yes ;; + no) enable_vala=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-vala) ;; + esac + ], + [enable_vala=yes]) dnl Default value +AM_CONDITIONAL(WITH_VALA, [test "x$enable_vala" = "xyes"]) -AM_CONDITIONAL(WITH_VALA, [test "x$HAVE_VALA" = "xyes"]) - -AC_ARG_WITH([vapidir], - AS_HELP_STRING([--with-vapidir], [Define where to install the VAPI files])) - -if test "x$HAVE_VALA" = "xyes"; then - if test "x$with_vapidir" = "x"; then - VAPIDIR="`pkg-config --variable vapidir vala-1.0`" - else - VAPIDIR="$with_vapidir" - fi -fi -AC_SUBST(VAPIDIR) - dnl *** checks for libraries *** dnl *** checks for header files *** @@ -284,7 +279,7 @@ Configuration Source code location : ${srcdir} Prefix : ${prefix} Compiler : ${CC} - Vala bindings : ${HAVE_VALA} + Vala bindings : ${enable_vala} Python bindings: : ${HAVE_PYTHON_BINDINGS} Gst-rtsp-server configured. Type 'make' to build. From 8f927de4c8c98a4dd8fd1795f107345c1d2fef9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 22 Sep 2010 18:24:12 +0200 Subject: [PATCH 0204/1776] Update Vala bindings --- bindings/vala/gst-rtsp-server-0.10.vapi | 86 ++++++++---- .../vala/packages/gst-rtsp-server-0.10.gi | 124 ++++++++++++++++-- .../packages/gst-rtsp-server-0.10.metadata | 4 +- 3 files changed, 181 insertions(+), 33 deletions(-) diff --git a/bindings/vala/gst-rtsp-server-0.10.vapi b/bindings/vala/gst-rtsp-server-0.10.vapi index 46a8ed4a87..45b0fb502c 100644 --- a/bindings/vala/gst-rtsp-server-0.10.vapi +++ b/bindings/vala/gst-rtsp-server-0.10.vapi @@ -5,17 +5,19 @@ namespace Gst { [CCode (cheader_filename = "gst/rtsp-server/rtsp-client.h")] public class RTSPClient : GLib.Object { public weak Gst.RTSPConnection connection; + public bool is_ipv6; public weak Gst.RTSPMedia media; + public weak string server_ip; public weak GLib.List sessions; public weak GLib.List streams; public weak Gst.RTSPUrl uri; public weak Gst.RTSPWatch watch; public uint watchid; + [CCode (has_construct_function = false)] + public RTSPClient (); public bool accept (GLib.IOChannel channel); public Gst.RTSPMediaMapping get_media_mapping (); public Gst.RTSPSessionPool get_session_pool (); - [CCode (has_construct_function = false)] - public RTSPClient (); public void set_media_mapping (Gst.RTSPMediaMapping mapping); public void set_session_pool (Gst.RTSPSessionPool pool); public Gst.RTSPMediaMapping media_mapping { get; set; } @@ -25,36 +27,47 @@ namespace Gst { public class RTSPMedia : GLib.Object { public int active; public bool buffering; + public weak GLib.Cond cond; public weak GLib.List @dynamic; public weak Gst.Element element; + public bool eos_pending; public weak Gst.Element fakesink; public uint id; + public bool is_ipv6; public bool is_live; - public Gst.Element pipeline; - public bool prepared; + public weak GLib.Mutex @lock; + public weak Gst.Element pipeline; public weak Gst.RTSPTimeRange range; public bool reused; public weak Gst.Element rtpbin; public weak GLib.TimeoutSource source; + public Gst.RTSPMediaStatus status; public weak GLib.Array streams; public Gst.State target_state; + [CCode (has_construct_function = false)] + public RTSPMedia (); + public Gst.RTSPLowerTrans get_protocols (); public unowned Gst.RTSPMediaStream get_stream (uint idx); [NoWrapper] public virtual bool handle_message (Gst.Message message); + public bool is_eos_shutdown (); public bool is_prepared (); public bool is_reusable (); public bool is_shared (); public uint n_streams (); - [CCode (has_construct_function = false)] - public RTSPMedia (); public bool prepare (); public void remove_elements (); public bool seek (Gst.RTSPTimeRange range); + public void set_eos_shutdown (bool eos_shutdown); + public void set_protocols (Gst.RTSPLowerTrans protocols); public void set_reusable (bool reusable); public void set_shared (bool shared); public bool set_state (Gst.State state, GLib.Array trans); public virtual bool unprepare (); [NoAccessorMethod] + public bool eos_shutdown { get; set; } + public Gst.RTSPLowerTrans protocols { get; set; } + [NoAccessorMethod] public bool reusable { get; set; } [NoAccessorMethod] public bool shared { get; set; } @@ -65,6 +78,8 @@ namespace Gst { public weak GLib.Mutex @lock; public weak GLib.HashTable medias; public weak GLib.Mutex medias_lock; + [CCode (has_construct_function = false)] + public RTSPMediaFactory (); public void collect_streams (Gst.RTSPUrl url, Gst.RTSPMedia media); [NoWrapper] public virtual void configure (Gst.RTSPMedia media); @@ -76,11 +91,13 @@ namespace Gst { [NoWrapper] public virtual Gst.Element? get_element (Gst.RTSPUrl url); public string get_launch (); + public bool is_eos_shutdown (); public bool is_shared (); - [CCode (has_construct_function = false)] - public RTSPMediaFactory (); + public void set_eos_shutdown (bool eos_shutdown); public void set_launch (string launch); public void set_shared (bool shared); + [NoAccessorMethod] + public bool eos_shutdown { get; set; } public string launch { get; set; } [NoAccessorMethod] public bool shared { get; set; } @@ -88,12 +105,12 @@ namespace Gst { [CCode (cheader_filename = "gst/rtsp-server/rtsp-media-mapping.h")] public class RTSPMediaMapping : GLib.Object { public weak GLib.HashTable mappings; + [CCode (has_construct_function = false)] + public RTSPMediaMapping (); public void add_factory (string path, Gst.RTSPMediaFactory factory); public Gst.RTSPMediaFactory? find_factory (Gst.RTSPUrl url); [NoWrapper] public virtual Gst.RTSPMediaFactory? find_media (Gst.RTSPUrl url); - [CCode (has_construct_function = false)] - public RTSPMediaMapping (); public void remove_factory (string path); } [Compact] @@ -105,6 +122,8 @@ namespace Gst { public weak Gst.Element[] appsrc; public weak Gst.Caps caps; public ulong caps_sig; + public weak GLib.List destinations; + public bool filter_duplicates; public weak Gst.Element payloader; public bool prepared; public weak Gst.Pad recv_rtcp_sink; @@ -142,48 +161,54 @@ namespace Gst { public bool timeout; public weak Gst.RTSPTransport transport; public void* user_data; + public void cleanup (); } [CCode (cheader_filename = "gst/rtsp-server/rtsp-server.h")] public class RTSPServer : GLib.Object { - public weak string host; public weak GLib.IOChannel io_channel; public weak GLib.TimeoutSource io_watch; public void* server_sin; - public weak Gst.PollFD server_sock; + public Gst.PollFD server_sock; + [CCode (has_construct_function = false)] + public RTSPServer (); [NoWrapper] public virtual Gst.RTSPClient? accept_client (GLib.IOChannel channel); public uint attach (GLib.MainContext? context); public GLib.TimeoutSource? create_watch (); + public string get_address (); public int get_backlog (); public GLib.IOChannel? get_io_channel (); public Gst.RTSPMediaMapping get_media_mapping (); - public int get_port (); + public string get_service (); public Gst.RTSPSessionPool get_session_pool (); public static bool io_func (GLib.IOChannel channel, GLib.IOCondition condition, Gst.RTSPServer server); - [CCode (has_construct_function = false)] - public RTSPServer (); + public void set_address (string address); public void set_backlog (int backlog); public void set_media_mapping (Gst.RTSPMediaMapping mapping); - public void set_port (int port); + public void set_service (string service); public void set_session_pool (Gst.RTSPSessionPool pool); + public string address { get; set; } public int backlog { get; set; } public Gst.RTSPMediaMapping media_mapping { get; set; } - public int port { get; set; } + public string service { get; set; } public Gst.RTSPSessionPool session_pool { get; set; } } [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] public class RTSPSession : GLib.Object { public GLib.TimeVal create_time; + public int expire_count; public GLib.TimeVal last_access; public weak GLib.List medias; + [CCode (has_construct_function = false)] + public RTSPSession (string sessionid); + public void allow_expire (); public unowned Gst.RTSPSessionMedia get_media (Gst.RTSPUrl uri); public unowned string get_sessionid (); public uint get_timeout (); public bool is_expired (GLib.TimeVal now); public unowned Gst.RTSPSessionMedia manage_media (Gst.RTSPUrl uri, owned Gst.RTSPMedia media); - [CCode (has_construct_function = false)] - public RTSPSession (string sessionid); public int next_timeout (GLib.TimeVal now); + public void prevent_expire (); public bool release_media (Gst.RTSPSessionMedia media); public void set_timeout (uint timeout); public void touch (); @@ -193,10 +218,12 @@ namespace Gst { [Compact] [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] public class RTSPSessionMedia { + public uint counter; public weak Gst.RTSPMedia media; public Gst.RTSPState state; public weak GLib.Array streams; public weak Gst.RTSPUrl url; + public bool alloc_channels (Gst.RTSPRange range); public unowned Gst.RTSPSessionStream get_stream (uint idx); public bool set_state (Gst.State state); } @@ -204,6 +231,8 @@ namespace Gst { public class RTSPSessionPool : GLib.Object { public weak GLib.Mutex @lock; public weak GLib.HashTable sessions; + [CCode (has_construct_function = false)] + public RTSPSessionPool (); public uint cleanup (); public Gst.RTSPSession create (); [NoWrapper] @@ -213,8 +242,6 @@ namespace Gst { public Gst.RTSPSession? find (string sessionid); public uint get_max_sessions (); public uint get_n_sessions (); - [CCode (has_construct_function = false)] - public RTSPSessionPool (); public bool remove (Gst.RTSPSession sess); public void set_max_sessions (uint max); public uint max_sessions { get; set; } @@ -228,12 +255,25 @@ namespace Gst { public void set_keepalive (Gst.RTSPKeepAliveFunc keep_alive, GLib.DestroyNotify notify); public Gst.RTSPTransport set_transport (Gst.RTSPTransport ct); } - [CCode (cprefix = "GST_RTSP_FILTER_", has_type_id = "0", cheader_filename = "gst/gst.h")] + [Compact] + [CCode (cheader_filename = "gst/gst.h")] + public class SDPInfo { + public weak string server_ip; + public weak string server_proto; + } + [CCode (cprefix = "GST_RTSP_FILTER_", has_type_id = false, cheader_filename = "gst/gst.h")] public enum RTSPFilterResult { REMOVE, KEEP, REF } + [CCode (cprefix = "GST_RTSP_MEDIA_STATUS_", has_type_id = false, cheader_filename = "gst/gst.h")] + public enum RTSPMediaStatus { + UNPREPARED, + PREPARING, + PREPARED, + ERROR + } [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] public delegate void RTSPKeepAliveFunc (); [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] @@ -247,5 +287,5 @@ namespace Gst { [CCode (cheader_filename = "gst/gst.h")] public static Gst.RTSPResult rtsp_params_set (Gst.RTSPClient client, Gst.RTSPUrl uri, Gst.RTSPSession session, Gst.RTSPMessage request, Gst.RTSPMessage response); [CCode (cheader_filename = "gst/rtsp-server/rtsp-sdp.h")] - public static unowned Gst.SDPMessage rtsp_sdp_from_media (Gst.RTSPMedia media); + public static bool rtsp_sdp_from_media (ref unowned Gst.SDPMessage sdp, Gst.SDPInfo info, Gst.RTSPMedia media); } diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.gi b/bindings/vala/packages/gst-rtsp-server-0.10.gi index 76671d9f5d..8933d3bae0 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.gi +++ b/bindings/vala/packages/gst-rtsp-server-0.10.gi @@ -22,8 +22,10 @@ - + + + @@ -90,8 +92,16 @@ + + + + + + + + @@ -106,6 +116,13 @@ + + + + + + + @@ -123,6 +140,7 @@ + @@ -155,11 +173,21 @@ + + + + + + + + + + @@ -202,6 +230,8 @@ + + @@ -210,6 +240,12 @@ + + + + + + @@ -217,6 +253,12 @@ + + + + + + @@ -263,6 +305,20 @@ + + + + + + + + + + + + + + @@ -291,6 +347,8 @@ + + @@ -312,14 +370,20 @@ + + + + + - + + @@ -352,6 +416,12 @@ + + + + + + @@ -361,6 +431,13 @@ + + + + + + + @@ -375,6 +452,7 @@ + @@ -415,6 +493,7 @@ + @@ -467,6 +546,12 @@ + + + + + + @@ -485,8 +570,8 @@ - - + + @@ -508,6 +593,13 @@ + + + + + + + @@ -522,11 +614,11 @@ - + - + @@ -536,9 +628,10 @@ + - + @@ -547,9 +640,9 @@ - + + - @@ -558,6 +651,12 @@ + + + + + + @@ -605,6 +704,12 @@ + + + + + + @@ -631,6 +736,7 @@ + diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.metadata b/bindings/vala/packages/gst-rtsp-server-0.10.metadata index 861e11e8d4..10c1592a09 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.metadata +++ b/bindings/vala/packages/gst-rtsp-server-0.10.metadata @@ -20,12 +20,14 @@ gst_rtsp_media_factory_get_element transfer_ownership="1" nullable="1" gst_rtsp_media_factory_create_pipeline transfer_ownership="1" gst_rtsp_media_mapping_find_factory transfer_ownership="1" nullable="1" gst_rtsp_media_mapping_find_media transfer_ownership="1" nullable="1" -gst_rtsp_sdp_from_media transfer_ownership="1" +gst_rtsp_sdp_from_media.sdp is_ref="1" gst_rtsp_server_accept_client transfer_ownership="1" nullable="1" gst_rtsp_server_create_watch transfer_ownership="1" nullable="1" +gst_rtsp_server_get_address transfer_ownership="1" gst_rtsp_server_get_io_channel transfer_ownership="1" nullable="1" gst_rtsp_server_get_media_mapping transfer_ownership="1" gst_rtsp_server_get_session_pool transfer_ownership="1" +gst_rtsp_server_get_service transfer_ownership="1" gst_rtsp_server_attach.context nullable="1" gst_rtsp_session_manage_media.media takes_ownership="1" gst_rtsp_session_pool_create transfer_ownership="1" From 3c283b2af8a1af06ea4a8cda3ddea34a307b2d2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 22 Sep 2010 21:16:03 +0100 Subject: [PATCH 0205/1776] build: fix distcheck --- bindings/vala/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/vala/Makefile.am b/bindings/vala/Makefile.am index 06e8ee4b5c..acdf20fcaa 100644 --- a/bindings/vala/Makefile.am +++ b/bindings/vala/Makefile.am @@ -10,3 +10,4 @@ vapi_DATA = $(VAPI_FILES) $(DEPS_FILES) EXTRA_DIST = packages $(VAPI_FILES) +CLEANFILES = $(DEPS_FILES) From c310f0032ccb12633e8894a531a2e0c096c5df0f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 23 Sep 2010 11:32:58 +0200 Subject: [PATCH 0206/1776] media-factory: don't use host for shared hash key When we generate the key to share made between connections, don't include the host used to connect so that we can share media even if between clients that connected with localhost and ones with the ip address. --- gst/rtsp-server/rtsp-media-factory.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 92591aa7be..9eaddb70f4 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -413,8 +413,13 @@ static gchar * default_gen_key (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) { gchar *result; + const gchar *pre_query; + const gchar *query; - result = gst_rtsp_url_get_request_uri ((GstRTSPUrl *)url); + pre_query = url->query ? "?" : ""; + query = url->query ? url->query : ""; + + result = g_strdup_printf ("%u%s%s%s", url->port, url->abspath, pre_query, query); return result; } From 347e10e1f95f5e86b91a3cae4f8612f5a65ffe59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Wed, 22 Sep 2010 23:13:37 +0200 Subject: [PATCH 0207/1776] Added initial gobject-introspection support --- common/m4/introspection.m4 | 88 +++++++++++++++++++++++++++++++++++++ configure.ac | 13 ++++-- gst/rtsp-server/Makefile.am | 50 ++++++++++++++++----- 3 files changed, 137 insertions(+), 14 deletions(-) create mode 100644 common/m4/introspection.m4 diff --git a/common/m4/introspection.m4 b/common/m4/introspection.m4 new file mode 100644 index 0000000000..f9ce49ce97 --- /dev/null +++ b/common/m4/introspection.m4 @@ -0,0 +1,88 @@ +dnl -*- mode: autoconf -*- +dnl Copyright 2009 Johan Dahlin +dnl +dnl This file is free software; the author(s) gives unlimited +dnl permission to copy and/or distribute it, with or without +dnl modifications, as long as this notice is preserved. +dnl + +# serial 1 + +m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL], +[ + AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([LT_INIT],[$0])dnl setup libtool first + + dnl enable/disable introspection + m4_if([$2], [require], + [dnl + enable_introspection=yes + ],[dnl + AC_ARG_ENABLE(introspection, + AS_HELP_STRING([--enable-introspection[=@<:@no/auto/yes@:>@]], + [Enable introspection for this build]),, + [enable_introspection=auto]) + ])dnl + + AC_MSG_CHECKING([for gobject-introspection]) + + dnl presence/version checking + AS_CASE([$enable_introspection], + [no], [dnl + found_introspection="no (disabled, use --enable-introspection to enable)" + ],dnl + [yes],[dnl + PKG_CHECK_EXISTS([gobject-introspection-1.0],, + AC_MSG_ERROR([gobject-introspection-1.0 is not installed])) + PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], + found_introspection=yes, + AC_MSG_ERROR([You need to have gobject-introspection >= $1 installed to build AC_PACKAGE_NAME])) + ],dnl + [auto],[dnl + PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], found_introspection=yes, found_introspection=no) + ],dnl + [dnl + AC_MSG_ERROR([invalid argument passed to --enable-introspection, should be one of @<:@no/auto/yes@:>@]) + ])dnl + + AC_MSG_RESULT([$found_introspection]) + + INTROSPECTION_SCANNER= + INTROSPECTION_COMPILER= + INTROSPECTION_GENERATE= + INTROSPECTION_GIRDIR= + INTROSPECTION_TYPELIBDIR= + if test "x$found_introspection" = "xyes"; then + INTROSPECTION_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` + INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0` + INTROSPECTION_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` + INTROSPECTION_GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0` + INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)" + fi + AC_SUBST(INTROSPECTION_SCANNER) + AC_SUBST(INTROSPECTION_COMPILER) + AC_SUBST(INTROSPECTION_GENERATE) + AC_SUBST(INTROSPECTION_GIRDIR) + AC_SUBST(INTROSPECTION_TYPELIBDIR) + + AM_CONDITIONAL(HAVE_INTROSPECTION, test "x$found_introspection" = "xyes") +]) + + +dnl Usage: +dnl GOBJECT_INTROSPECTION_CHECK([minimum-g-i-version]) + +AC_DEFUN([GOBJECT_INTROSPECTION_CHECK], +[ + _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1]) +]) + +dnl Usage: +dnl GOBJECT_INTROSPECTION_REQUIRE([minimum-g-i-version]) + + +AC_DEFUN([GOBJECT_INTROSPECTION_REQUIRE], +[ + _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1], [require]) +]) diff --git a/configure.ac b/configure.ac index ceab687513..380f6e94f1 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,4 @@ -AC_PREREQ(2.52) - +AC_PREREQ(2.60) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too @@ -8,7 +7,7 @@ AC_INIT(Gst-RTSP, 0.10.6.1, gst-rtsp) dnl initialize automake -AM_INIT_AUTOMAKE +AM_INIT_AUTOMAKE([-Wno-portability 1.10]) dnl define PACKAGE_VERSION_* variables AS_VERSION @@ -28,6 +27,11 @@ AM_MAINTAINER_MODE dnl sets host_* variables AC_CANONICAL_HOST +dnl use pretty build output with automake >= 1.11 +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])], + [AM_DEFAULT_VERBOSITY=1 + AC_SUBST(AM_DEFAULT_VERBOSITY)]) + dnl our libraries and install dirs use major.minor as a version GST_MAJORMINOR=$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR dnl we override it here if we need to for the release candidate of new series @@ -73,6 +77,9 @@ AM_CHECK_PYTHON_HEADERS([HAVE_PYTHON_HEADERS="yes"], [HAVE_PYTHON_HEADERS="no"]) AC_PATH_PROG(VALGRIND_PATH, valgrind, no) AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") +dnl check for gobject-introspection +GOBJECT_INTROSPECTION_CHECK([0.6.3]) + dnl check for documentation tools AG_GST_DOCBOOK_CHECK GTK_DOC_CHECK([1.3]) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 1b33fc3b9b..88a30d4c71 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -1,24 +1,24 @@ public_headers = \ - rtsp-server.h \ - rtsp-client.h \ + rtsp-params.h \ + rtsp-sdp.h \ rtsp-media.h \ rtsp-media-factory.h \ rtsp-media-mapping.h \ - rtsp-params.h \ - rtsp-sdp.h \ + rtsp-session.h \ rtsp-session-pool.h \ - rtsp-session.h + rtsp-client.h \ + rtsp-server.h c_sources = \ - rtsp-server.c \ - rtsp-client.c \ + rtsp-params.c \ + rtsp-sdp.c \ rtsp-media.c \ rtsp-media-factory.c \ - rtsp-media-mapping.c \ - rtsp-params.c \ - rtsp-sdp.c \ + rtsp-media-mapping.c \ + rtsp-session.c \ rtsp-session-pool.c \ - rtsp-session.c + rtsp-client.c \ + rtsp-server.c lib_LTLIBRARIES = \ libgstrtspserver-@GST_MAJORMINOR@.la @@ -38,3 +38,31 @@ libgstrtspserver_@GST_MAJORMINOR@_la_LIBTOOLFLAGS = --tag=disable-static libgstrtspserver_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/rtsp-server libgstrtspserver_@GST_MAJORMINOR@include_HEADERS = $(public_headers) + +CLEANFILES = + +-include $(INTROSPECTION_MAKEFILE) +INTROSPECTION_GIRS = +INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) --strip-prefix=Gst +INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) + +if HAVE_INTROSPECTION +introspection_sources = $(public_headers) $(c_sources) + +GstRtspServer-0.10.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@GST_MAJORMINOR@.la +GstRtspServer_0_10_gir_INCLUDES = Gst-@GST_MAJORMINOR@ GstRtsp-@GST_MAJORMINOR@ +GstRtspServer_0_10_gir_CFLAGS = $(INCLUDES) +GstRtspServer_0_10_gir_LIBS = libgstrtspserver-@GST_MAJORMINOR@.la +GstRtspServer_0_10_gir_FILES = $(introspection_sources) +GstRtspServer_0_10_gir_NAMESPACE = GstRtspServer +GstRtspServer_0_10_gir_VERSION = @GST_MAJORMINOR@ +INTROSPECTION_GIRS += GstRtspServer-0.10.gir + +girdir = $(datadir)/gir-1.0 +gir_DATA = $(INTROSPECTION_GIRS) + +typelibdir = $(libdir)/girepository-1.0 +typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) + +CLEANFILES += $(gir_DATA) $(typelib_DATA) +endif From 57982994870c09111746ca9ec712951562f32c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Thu, 23 Sep 2010 12:44:18 +0200 Subject: [PATCH 0208/1776] Updated Vala bindings --- bindings/vala/gst-rtsp-server-0.10.vapi | 8 ++++---- .../vala/packages/gst-rtsp-server-0.10.metadata | 13 +++++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/bindings/vala/gst-rtsp-server-0.10.vapi b/bindings/vala/gst-rtsp-server-0.10.vapi index 45b0fb502c..2126ce5d4b 100644 --- a/bindings/vala/gst-rtsp-server-0.10.vapi +++ b/bindings/vala/gst-rtsp-server-0.10.vapi @@ -36,7 +36,7 @@ namespace Gst { public bool is_ipv6; public bool is_live; public weak GLib.Mutex @lock; - public weak Gst.Element pipeline; + public Gst.Element pipeline; public weak Gst.RTSPTimeRange range; public bool reused; public weak Gst.Element rtpbin; @@ -256,18 +256,18 @@ namespace Gst { public Gst.RTSPTransport set_transport (Gst.RTSPTransport ct); } [Compact] - [CCode (cheader_filename = "gst/gst.h")] + [CCode (cheader_filename = "gst/rtsp-server/rtsp-sdp.h")] public class SDPInfo { public weak string server_ip; public weak string server_proto; } - [CCode (cprefix = "GST_RTSP_FILTER_", has_type_id = false, cheader_filename = "gst/gst.h")] + [CCode (cprefix = "GST_RTSP_FILTER_", has_type_id = false, cheader_filename = "gst/rtsp-server/rtsp-session-pool.h")] public enum RTSPFilterResult { REMOVE, KEEP, REF } - [CCode (cprefix = "GST_RTSP_MEDIA_STATUS_", has_type_id = false, cheader_filename = "gst/gst.h")] + [CCode (cprefix = "GST_RTSP_MEDIA_STATUS_", has_type_id = false, cheader_filename = "gst/rtsp-server/rtsp-media.h")] public enum RTSPMediaStatus { UNPREPARED, PREPARING, diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.metadata b/bindings/vala/packages/gst-rtsp-server-0.10.metadata index 10c1592a09..b944eb697f 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.metadata +++ b/bindings/vala/packages/gst-rtsp-server-0.10.metadata @@ -4,6 +4,7 @@ GstRTSPMedia cheader_filename="gst/rtsp-server/rtsp-media.h" GstRTSPMediaTrans cheader_filename="gst/rtsp-server/rtsp-media.h" GstRTSPMediaFactory cheader_filename="gst/rtsp-server/rtsp-media-factory.h" GstRTSPMediaMapping cheader_filename="gst/rtsp-server/rtsp-media-mapping.h" +GstRTSPMediaStatus cheader_filename="gst/rtsp-server/rtsp-media.h" GstRTSPMediaStream cheader_filename="gst/rtsp-server/rtsp-media.h" GstRTSPServer cheader_filename="gst/rtsp-server/rtsp-server.h" GstRTSPSession cheader_filename="gst/rtsp-server/rtsp-session.h" @@ -11,6 +12,12 @@ GstRTSPSessionMedia cheader_filename="gst/rtsp-server/rtsp-session.h" GstRTSPSessionPool cheader_filename="gst/rtsp-server/rtsp-session-pool.h" GstRTSPSessionStream cheader_filename="gst/rtsp-server/rtsp-session.h" GstRTSPSessionFilterFunc cheader_filename="gst/rtsp-server/rtsp-session-pool.h" +GstRTSPSessionPoolFunc cheader_filename="gst/rtsp-server/rtsp-session-pool.h" +GstSDPInfo cheader_filename="gst/rtsp-server/rtsp-sdp.h" +GstRTSPFilterResult cheader_filename="gst/rtsp-server/rtsp-session-pool.h" +GstRTSPKeepAliveFunc cheader_filename="gst/rtsp-server/rtsp-media.h" +GstRTSPSendFunc cheader_filename="gst/rtsp-server/rtsp-media.h" +gst_rtsp_sdp_from_media cheader_filename="gst/rtsp-server/rtsp-sdp.h" gst_rtsp_client_get_media_mapping transfer_ownership="1" gst_rtsp_client_get_session_pool transfer_ownership="1" gst_rtsp_media_factory_get_launch transfer_ownership="1" @@ -26,6 +33,7 @@ gst_rtsp_server_create_watch transfer_ownership="1" nullable="1" gst_rtsp_server_get_address transfer_ownership="1" gst_rtsp_server_get_io_channel transfer_ownership="1" nullable="1" gst_rtsp_server_get_media_mapping transfer_ownership="1" +gst_rtsp_server_get_service transfer_ownership="1" gst_rtsp_server_get_session_pool transfer_ownership="1" gst_rtsp_server_get_service transfer_ownership="1" gst_rtsp_server_attach.context nullable="1" @@ -36,7 +44,4 @@ gst_rtsp_session_pool_create_watch transfer_ownership="1" gst_rtsp_session_pool_find transfer_ownership="1" nullable="1" gst_rtsp_session_pool_filter transfer_ownership="1" type_arguments="RTSPSession" gst_rtsp_session_stream_set_transport transfer_ownership="1" -GstRTSPKeepAliveFunc cheader_filename="gst/rtsp-server/rtsp-media.h" -GstRTSPSendFunc cheader_filename="gst/rtsp-server/rtsp-media.h" -GstRTSPSessionPoolFunc cheader_filename="gst/rtsp-server/rtsp-session-pool.h" -gst_rtsp_sdp_from_media cheader_filename="gst/rtsp-server/rtsp-sdp.h" +GstRTSPMedia.pipeline weak="0" From 6b2c868b9706e2229f3bf0838e91953cd49bf58a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 4 Oct 2010 17:16:40 +0200 Subject: [PATCH 0209/1776] test-ogg: remove parsers Remove the parsers, they are not needed anymore as oggdemux now outputs normal buffers with timestamps. Using the parsers also seems to break things. --- examples/test-ogg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/test-ogg.c b/examples/test-ogg.c index 5847b85dbb..403144f011 100644 --- a/examples/test-ogg.c +++ b/examples/test-ogg.c @@ -49,8 +49,8 @@ main (int argc, char *argv[]) str = g_strdup_printf ( "( " "filesrc location=%s ! oggdemux name=d " - "d. ! queue ! theoraparse ! rtptheorapay name=pay0 pt=96 " - "d. ! queue ! vorbisparse ! rtpvorbispay name=pay1 pt=97 " + "d. ! queue ! rtptheorapay name=pay0 pt=96 " + "d. ! queue ! rtpvorbispay name=pay1 pt=97 " ")", argv[1]); /* make a media factory for a test stream. The default media factory can use From 4d9db9e2cff925de0a37754eee8c93da9252ced8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 11 Oct 2010 11:05:40 +0200 Subject: [PATCH 0210/1776] release 0.10.7 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 380f6e94f1..bf2049c8a0 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.60) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.6.1, +AC_INIT(Gst-RTSP, 0.10.7, http://gstreamer.net/, gst-rtsp) From 411371c90fb0c912c8e6d5d13cdfe331834c70e9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 11 Oct 2010 11:12:11 +0200 Subject: [PATCH 0211/1776] back to development --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index bf2049c8a0..fd09ff0add 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.60) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.7, +AC_INIT(Gst-RTSP, 0.10.7.1, http://gstreamer.net/, gst-rtsp) From 3bbd5bd96469cdb0d0ea132ef3960400d0e8f37b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 30 Oct 2010 13:26:12 +0200 Subject: [PATCH 0212/1776] README: update Remove old stuff from the README --- README | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/README b/README index a785c592c8..23737300f3 100644 --- a/README +++ b/README @@ -1,18 +1,4 @@ -GstRTSP is an RTSP server built on top of GStreamer (http://gstreamer.net). - -Currently there is no configuration tools for this server so any streamed -files need to be hardcoded into the file: -src/rtsp-media.c - -Edit in your sources after the examples found under the section headlines by -* STREAMING CONFIGURATION - -Once the server is started you should be able to view the streams at: -rtsp://localhost:1554/@name_of_stream@ - -The replacement for @name_of_stream@ is from the rtsp-media.c editing you did above. - -You should be able to get the http proxy link working without any editing of the rtsp-media.c file as it points to an online http file: - -rtsp://localhost:1554/rtphttpproxy +gst-rtsp-server is a library ion top of GStreamer for building an RTSP server +There are some examples in the examples/ directory and more comprehensive +documentation in docs/README. From 2e1054036d24496ebe7311ed5cd412df95e98343 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 8 Nov 2010 17:04:00 +0000 Subject: [PATCH 0213/1776] Update introspection.m4 to match usage --- common/m4/introspection.m4 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/common/m4/introspection.m4 b/common/m4/introspection.m4 index f9ce49ce97..589721c5a0 100644 --- a/common/m4/introspection.m4 +++ b/common/m4/introspection.m4 @@ -59,12 +59,18 @@ m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL], INTROSPECTION_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` INTROSPECTION_GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0` INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)" + INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0` + INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0` + INTROSPECTION_MAKEFILE=`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection fi AC_SUBST(INTROSPECTION_SCANNER) AC_SUBST(INTROSPECTION_COMPILER) AC_SUBST(INTROSPECTION_GENERATE) AC_SUBST(INTROSPECTION_GIRDIR) AC_SUBST(INTROSPECTION_TYPELIBDIR) + AC_SUBST(INTROSPECTION_CFLAGS) + AC_SUBST(INTROSPECTION_LIBS) + AC_SUBST(INTROSPECTION_MAKEFILE) AM_CONDITIONAL(HAVE_INTROSPECTION, test "x$found_introspection" = "xyes") ]) From 26c20746a871506430811163710fd32438024d25 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 1 Dec 2010 19:58:49 +0100 Subject: [PATCH 0214/1776] common: Remove static version --- common/ChangeLog | 1041 -------------- common/Makefile.am | 15 - common/c-to-xml.py | 34 - common/check.mak | 149 -- common/coverage/coverage-report-entry.pl | 70 - common/coverage/coverage-report.pl | 125 -- common/coverage/coverage-report.xsl | 235 --- common/coverage/lcov.mak | 29 - common/gettext.patch | 23 - common/glib-gen.mak | 42 - common/gst-autogen.sh | 308 ---- common/gst-xmlinspect.py | 168 --- common/gst.supp | 1660 ---------------------- common/gstdoc-scangobj | 1562 -------------------- common/gtk-doc-plugins.mak | 358 ----- common/gtk-doc.mak | 260 ---- common/m4/.gitignore | 5 - common/m4/Makefile.am | 28 - common/m4/README | 3 - common/m4/as-ac-expand.m4 | 43 - common/m4/as-auto-alt.m4 | 50 - common/m4/as-compiler-flag.m4 | 33 - common/m4/as-compiler.m4 | 44 - common/m4/as-docbook.m4 | 66 - common/m4/as-libtool-tags.m4 | 83 -- common/m4/as-libtool.m4 | 45 - common/m4/as-python.m4 | 152 -- common/m4/as-scrub-include.m4 | 36 - common/m4/as-version.m4 | 71 - common/m4/ax_create_stdint_h.m4 | 569 -------- common/m4/check.m4 | 181 --- common/m4/glib-gettext.m4 | 380 ----- common/m4/gst-arch.m4 | 123 -- common/m4/gst-args.m4 | 276 ---- common/m4/gst-check.m4 | 138 -- common/m4/gst-debuginfo.m4 | 46 - common/m4/gst-default.m4 | 45 - common/m4/gst-doc.m4 | 148 -- common/m4/gst-error.m4 | 71 - common/m4/gst-feature.m4 | 285 ---- common/m4/gst-function.m4 | 63 - common/m4/gst-gettext.m4 | 21 - common/m4/gst-glib2.m4 | 26 - common/m4/gst-libxml2.m4 | 43 - common/m4/gst-plugindir.m4 | 17 - common/m4/gst-valgrind.m4 | 35 - common/m4/gtk-doc.m4 | 53 - common/m4/introspection.m4 | 94 -- common/m4/pkg.m4 | 131 -- common/mangle-tmpl.py | 155 -- common/plugins.xsl | 200 --- common/po.mak | 4 - common/release.mak | 25 - common/scangobj-merge.py | 226 --- common/upload.mak | 33 - 55 files changed, 10126 deletions(-) delete mode 100644 common/ChangeLog delete mode 100644 common/Makefile.am delete mode 100644 common/c-to-xml.py delete mode 100644 common/check.mak delete mode 100644 common/coverage/coverage-report-entry.pl delete mode 100644 common/coverage/coverage-report.pl delete mode 100644 common/coverage/coverage-report.xsl delete mode 100644 common/coverage/lcov.mak delete mode 100644 common/gettext.patch delete mode 100644 common/glib-gen.mak delete mode 100644 common/gst-autogen.sh delete mode 100644 common/gst-xmlinspect.py delete mode 100644 common/gst.supp delete mode 100755 common/gstdoc-scangobj delete mode 100644 common/gtk-doc-plugins.mak delete mode 100644 common/gtk-doc.mak delete mode 100644 common/m4/.gitignore delete mode 100644 common/m4/Makefile.am delete mode 100644 common/m4/README delete mode 100644 common/m4/as-ac-expand.m4 delete mode 100644 common/m4/as-auto-alt.m4 delete mode 100644 common/m4/as-compiler-flag.m4 delete mode 100644 common/m4/as-compiler.m4 delete mode 100644 common/m4/as-docbook.m4 delete mode 100644 common/m4/as-libtool-tags.m4 delete mode 100644 common/m4/as-libtool.m4 delete mode 100644 common/m4/as-python.m4 delete mode 100644 common/m4/as-scrub-include.m4 delete mode 100644 common/m4/as-version.m4 delete mode 100644 common/m4/ax_create_stdint_h.m4 delete mode 100644 common/m4/check.m4 delete mode 100644 common/m4/glib-gettext.m4 delete mode 100644 common/m4/gst-arch.m4 delete mode 100644 common/m4/gst-args.m4 delete mode 100644 common/m4/gst-check.m4 delete mode 100644 common/m4/gst-debuginfo.m4 delete mode 100644 common/m4/gst-default.m4 delete mode 100644 common/m4/gst-doc.m4 delete mode 100644 common/m4/gst-error.m4 delete mode 100644 common/m4/gst-feature.m4 delete mode 100644 common/m4/gst-function.m4 delete mode 100644 common/m4/gst-gettext.m4 delete mode 100644 common/m4/gst-glib2.m4 delete mode 100644 common/m4/gst-libxml2.m4 delete mode 100644 common/m4/gst-plugindir.m4 delete mode 100644 common/m4/gst-valgrind.m4 delete mode 100644 common/m4/gtk-doc.m4 delete mode 100644 common/m4/introspection.m4 delete mode 100644 common/m4/pkg.m4 delete mode 100644 common/mangle-tmpl.py delete mode 100644 common/plugins.xsl delete mode 100644 common/po.mak delete mode 100644 common/release.mak delete mode 100755 common/scangobj-merge.py delete mode 100644 common/upload.mak diff --git a/common/ChangeLog b/common/ChangeLog deleted file mode 100644 index 8f8b8537fd..0000000000 --- a/common/ChangeLog +++ /dev/null @@ -1,1041 +0,0 @@ -2007-09-21 Sebastian Dröge - - * m4/gst-args.m4: - Let the AG_GST_ARG_ENABLE_EXPERIMENTAL macro default to disable - building of experimental plugins. Nobody uses it yet and the - --enable--experimental stuff from gst-plugins-good defaults to - disable too. - -2007-09-06 Tim-Philipp Müller - - * gtk-doc-plugins.mak: - Just use the normal 'check' target and avoid a circular - dependency. - -2007-09-06 Tim-Philipp Müller - - * gtk-doc-plugins.mak: - Add rule to error out if .hierarchy file contains tabs. - -2007-08-20 Tim-Philipp Müller - - * download-translations: - * po.mak: - If there are new languages, they need to be added to po/LINGUAS. - -2007-08-20 Tim-Philipp Müller - - * download-translations: - * po.mak: - Fix up 'download-po' a bit, so that we find new translations - for languages that aren't in our po/LINGUAS file yet too. - -2007-07-16 Jan Schmidt - - * gst.supp: - Add a suppression for GLib caching the tmp dir seen on an - Ubuntu Feisty system. - -2007-07-13 Jan Schmidt - - * m4/gst-feature.m4: - If we want to use 'echo -e', call /bin/echo instead of the shell's - since -e is a bash extension, and our /bin/sh might not be being - provided by bash. - -2007-07-01 Thomas Vander Stichele - - * po.mak: - Translation project has moved. Also, no idea how this used to - work given that we weren't downloading a .po file. - -2007-06-25 Stefan Kost - - * gst-xmlinspect.py: - * plugins.xsl: - Also extract element caps for plugin-docs. Fixes parts of #117692. - -2007-06-21 Tim-Philipp Müller - - Patch by: Andreas Schwab - - * m4/gst-feature.m4: - Fix quoting (#449493). - -2007-06-10 Sebastian Dröge - - * m4/gst-parser.m4: - Only generate the parser if bison >= 1.875 _and_ flex >= 2.5.31 is - installed and use pre-generated sources otherwise. Fixes bug #444820. - -2007-05-11 Michael Smith - - * gst.supp: - Suppression variant for our good friend the TLS leak, this time for - Ubuntu Feisty/x86. - -2007-05-09 Tim-Philipp Müller - - * gtk-doc-plugins.mak: - Fix make distcheck again; change some spaces to tabs in makefile. - -2007-04-29 Thomas Vander Stichele - - * gtk-doc-plugins.mak (-module): - Error out when the html build step gives warnings, so they get - fixed properly. - -2007-04-23 Stefan Kost - - * m4/gst-feature.m4: - Add macro AG_GST_PARSE_SUBSYSTEM_DISABLES that checks the defines in - the configuration header and AC_DEFINES the setings. - -2007-04-19 Sebastian Dröge - - Patch by: Vincent Torri - - * m4/gst-parser.m4: - Put the AC_MSG_RESULT output in brackets to get it properly written to - the terminal. - -2007-04-18 Sebastian Dröge - - * m4/gst-parser.m4: - Check for flex >= 2.5.31 and set GENERATE_PARSER if we have at least - that version. Otherwise use pre-generated parser sources as we can't - raise the required flex version. HAVE_MT_SAVE_FLEX is obsolete now - as we use a new enough flex version anyway. First part of #349180 - -2007-04-10 Thomas Vander Stichele - - * m4/gst-check.m4: - Allow pre-setting the GST(PB)_TOOLS/PLUGINS_DIR variables to help - builds against older GStreamer. - -2007-03-25 Sebastian Dröge - - * m4/gst-parser.m4: - Fix the flex version check. It ignored the micro version before. - -2007-03-09 Jan Schmidt - - * check.mak: - Use the same timeout when generating valgrind suppressions as - running the valgrind test. - - * gst.supp: - Add some more suppressions and stuff. - -2007-03-08 Jan Schmidt - - * check.mak: - Make sure GSlice is disabled when building suppressions too. - - * gst.supp: - Add around *850* lines of suppressions for one-time initialisations - inside libasound and gconf/bonobo/ORBit. I feel so dirty. - -2007-03-07 Jan Schmidt - - * gst.supp: - add a suppression for this GConf flup on the FC5 buildbot. - -2007-03-06 Jan Schmidt - - * gst.supp: - Make the suppression a little more generic, to catch the FC5 - backtrace too. - -2007-03-06 Jan Schmidt - - * gst.supp: - Add a suppression for libcdio 0.76. It leaks an internal struct - when the CD-ROM device is not accessible. - -2007-02-28 Thomas Vander Stichele - - * m4/gst-arch.m4: - Move a line that was in the wrong macro - -2007-02-28 Thomas Vander Stichele - - * m4/gst.m4: - Add - * m4/gst-arch.m4: - * m4/gst-args.m4: - * m4/gst-check.m4: - * m4/gst-debuginfo.m4: - * m4/gst-default.m4: - * m4/gst-doc.m4: - * m4/gst-error.m4: - * m4/gst-feature.m4: - * m4/gst-function.m4: - * m4/gst-gettext.m4: - * m4/gst-glib2.m4: - * m4/gst-libxml2.m4: - * m4/gst-parser.m4: - * m4/gst-plugin-docs.m4: - * m4/gst-plugindir.m4: - * m4/gst-valgrind.m4: - * m4/gst-x11.m4: - Convert all macros to use AG_GST style so we can properly warn - when they're missing if configure.ac calls AG_GST_INIT - Will require update in all GStreamer modules. - -2007-02-11 Stefan Kost - - * m4/gst-args.m4: - Remove 'enable' from configure switch description as this leads to - confusing lines like "disable enable builing ...". - * m4/gst-feature.m4: - Fix comment to sound less horrible. - -2007-02-07 Tim-Philipp Müller - - Patch by: Will Newton - - * m4/gst-check.m4: - Use $PKG_CONFIG rather than pkg-config directly, the one in our path - might not be the one we want, like when cross-compiling. Also, other - macros such as PKG_CHECK_MODULES use $PKG_CONFIG, so we should - probably too just for consistency. Fixes #405288. - -2007-01-08 Tim-Philipp Müller - - * m4/gst-parser.m4: - Need to use double square brackets again so m4 doesn't remove them - (fixes #378931). - - * m4/gst-args.m4: - Use double square brackets here as well, for the same reason. - -2007-01-05 Tim-Philipp Müller - - * m4/gst-parser.m4: - Use 'sed' rather than 'tr' to strip trailing letters from version - numbers, since 'tr' might not be available and we know sed is - (#378931). - -2006-10-21 Tim-Philipp Müller - - * check.mak: - Increase default timeout under valgrind, 60 is just too short and - some tests take a bit longer these days and not everyone has a - beefy machine. - -2006-09-29 Michael Smith - - * gst.supp: - More suppressions for edgy. - -2006-09-28 Jan Schmidt - - * m4/gst-glib2.m4: - Use gmodule-no-export-2.0.pc instead of gmodule-2.0.pc - we neither - want nor need --export-dynamic (which ends up making us export a bunch - of unneeded symbols) - -2006-09-14 Tim-Philipp Müller - - * gst.supp: - Some suppressions for the more recent ld.so in ubuntu edgy. - -2006-08-23 Tim-Philipp Müller - - * gst.supp: - Shorten function trail so the suppression works on - my ubuntu dapper system with core cvs as well. - -2006-07-28 Jan Schmidt - - * gst.supp: - Extra suppressions from my Ubuntu x86_64 machine - -2006-07-24 Tim-Philipp Müller - - Patch by: Frederic Peters - - * m4/gst-parser.m4: - Need to double square brackets in .m4 files. Should fix bison - version detection with version numbers like 1.23a (#348354). - -2006-07-24 Jan Schmidt - - * check.mak: - Valgrind fails to find tests written in tests/check/ directly (rather - than a subdir) - because valgrind gets run with a filename that - doesn't contain a relative path, it goes searching /usr/bin instead. - Run with ./.... to make things work either way. - - * gtk-doc-plugins.mak: - Add $(top_builddir)/src as a place to look for plugins - when building too, since that's where gst-template keeps things - -2006-07-23 Stefan Kost - - Patch by: Frederic Peters - - * m4/gst-parser.m4: - Fix bison detection (#348354) - -2006-07-21 Stefan Kost - - * m4/gst-parser.m4: - check for bison and flex - -2006-07-13 Thomas Vander Stichele - - * m4/gst-plugin-docs.m4: - remove the configure argument for enabling plugin doc build; - having gtk-doc enabled and pyxml present is enough of a trigger - -2006-07-03 Thomas Vander Stichele - - * coverage/lcov.mak: - fix up rules to work with gst-python as well - run "make lcov" to test and generate the reports - run "make lcov-reset" to redo it after that - -2006-07-02 Thomas Vander Stichele - - * Makefile.am: - * check.mak: - add an inspect target that inspects every element feature, - so we can have that added for coverage - * coverage/lcov.mak: - add support for lcov - -2006-07-02 Thomas Vander Stichele - - * m4/gst-args.m4: - when building with gcov, reset CFLAGS and friends to O0 - -2006-07-02 Thomas Vander Stichele - - * m4/gst-args.m4: - Find the gcov that matches the gcc version - Only allow gcov if we use gcc - -2006-07-02 Thomas Vander Stichele - - * Makefile.am: - * coverage/coverage-report-entry.pl: - * coverage/coverage-report.pl: - * coverage/coverage-report.xsl: - copy coverage reporting files from dbus - -2006-07-01 Thomas Vander Stichele - - * m4/gst-args.m4: - libtool strips gcov's -f flags, so libgcov does not get - linked in. Setting GCOV_LIBS with -lgcov fixes libtool's - stripping - also show what pkg-config-path we set - -2006-06-22 Tim-Philipp Müller - - Patch by: Peter Kjellerstedt - - * m4/gst-feature.m4: - Show list of plugins without external dependencies that - will not be built as well (#344136). - -2006-06-15 Tim-Philipp Müller - - * m4/gst-plugin-docs.m4: - add GST_PLUGIN_DOCS, which checks for everything needed - to build the plugin docs (namely gtk-doc and pyxml); also - adds a new --enable-plugin-docs configure switch; will - set ENABLE_PLUGIN_DOCS conditional for use in Makefile.am - files (see #344039). - -2006-06-11 Thomas Vander Stichele - - * m4/gst-check.m4: - add GST_PKG_CHECK_MODULES, which in the normal case of checking - for a dependency lib for a plug-in only needs two arguments - to do the right thing. - * m4/gst-feature.m4: - clean up output a little of feature checking; also deal with - non-plug-in feature checks - * m4/Makefile.am: - * m4/gst-gstreamer.m4: - remove this file; it's a useless check - -2006-06-06 Thomas Vander Stichele - - * m4/gst-arch.m4: - add PPC64 so we can have separate structure sizes for it - -2006-06-05 Edward Hervey - - * gtk-doc.mak: - Check for the proper .devhelp2 file to remove. - -2006-05-31 Thomas Vander Stichele - - * gtk-doc.mak: - allow a magic variable to suppress errors from docbuilding - -2006-05-30 Thomas Vander Stichele - - * gtk-doc.mak: - error out if gtkdoc-mktmpl finds unused declarations - -2006-05-28 Edward Hervey - - * gst.supp: - Reverting previous commit. That's good to know, Edward, but why ? - -2006-05-28 Edward Hervey - - * gst.supp: - Added suppresion for memleak in g_option_context_parse on fc5-64 - -2006-05-19 Thomas Vander Stichele - - * m4/gst-check.m4: - set GSTPB_PLUGINS_DIR just like GST_PLUGINS_DIR - -2006-05-18 Tim-Philipp Müller - - * check.mak: - Fix 'make help' in check directories, it should be - 'valgrind.gen-suppressions' not 'valgrind-gen-suppressions' - (not changing target to match help string on purpose to keep - scripts etc. functional). - -2006-05-18 Thomas Vander Stichele - - Patch by: Peter Kjellerstedt - - * m4/gst-arch.m4: - add support for CRIS and CRISv32. - -2006-05-17 Jan Schmidt - - * m4/gst-args.m4: - Fix the macros for command-line supplied package and origin names - so they don't end up being configure as "" (Fixes #341479) - -2006-05-14 Jan Schmidt - - * gtk-doc.mak: - Add uninstall rule to remove .devhelp2 files. - -2006-05-09 Edward Hervey - - * gst.supp: - Add suppression for GSlice version of - g_type_init calloc leak - -2006-04-05 Michael Smith - - * gst.supp: - Delete a bogus suppression for the registry code. - Generalise a suppression for a glib bug (see #337404) - -2006-04-04 Michael Smith - - * gst.supp: - Add a leak suppression: the existing glibc-doesn't-free-TLS one - wasn't triggering here. - -2006-04-04 Michael Smith - - * gst.supp: - Add some minimally-neccesary suppressions for my x86/dapper system. - -2006-04-01 Thomas Vander Stichele - - * plugins.xsl: - Do not display an origin link if origin does not start with http - See #323798 - -2006-04-01 Thomas Vander Stichele - - * m4/gst-args.m4: - * m4/gst-feature.m4: - add more macros - * m4/gst-x11.m4: - X11-related checks - -2006-04-01 Thomas Vander Stichele - - * m4/as-version.m4: - newer version - * m4/gst-args.m4: - * m4/gst-doc.m4: - update and add other macros to be shared across projects - -2006-03-24 Thomas Vander Stichele - - * gst.supp: - add a suppression for g_parse_debug_string - -2006-03-23 Stefan Kost - - * gstdoc-scangobj: - sync fully with gtkdoc-0.15 - -2006-03-23 Stefan Kost - - * gstdoc-scangobj: - * gtk-doc.mak: - sync a little with gtk-doc mainline - -2006-03-17 Wim Taymans - - * gst.supp: - add another clone suppression - change all glibc suppressions to match 2.3.* - -2006-03-09 Thomas Vander Stichele - - * m4/check.m4: - fix test so it actually works when the normal check is used - over debian's/ubuntu's - -2006-03-08 Jan Schmidt - - * check.mak: - Set G_SLICE=always-malloc when valgrinding tests - (closes #333272) - -2006-02-21 Jan Schmidt - - * m4/gst-glib2.m4: - Fix debug output when the GLib version prerequisite is not found - -2006-02-13 Andy Wingo - - * m4/check.m4: Hack around Debian/Ubuntu's broken installation of - the PIC version of check as libcheck_pic.a. Should work with - cross-compilation too. Grr. - -2006-02-06 Thomas Vander Stichele - - * m4/gst-default.m4: - switch to auto* sinks for defaults - -2006-02-02 Wim Taymans - - * check.mak: - add a .valgrind.gen-suppressions target to aid in generating - suppressions - * gst.supp: - add more repressions from my debian glibc as of today - -2006-02-02 Thomas Vander Stichele - - * gtk-doc-plugins.mak: - only add srcdir/gst if it exists - -2006-01-30 Thomas Vander Stichele - - * release.mak: - don't complain about disted enums in win32 - -2006-01-20 Thomas Vander Stichele - - * m4/gst-check.m4: - AC_SUBST CFLAGS and LIBS - do a non-command because something is stripping out our AC_SUBST - -2006-01-20 Thomas Vander Stichele - - * m4/gst-args.m4: - * m4/gst-valgrind.m4: - properly give a "no" result manually when providing a - not-found action to fix configure output - -2006-01-20 Thomas Vander Stichele - - * m4/pkg.m4: - update with a more recent version - -2006-01-07 Thomas Vander Stichele - - * gettext.patch: - make Makefile depend on LINGUAS, so rebuilds work when adding - a language - -2006-01-03 Michael Smith - - * check.mak: - Clarify error message from valgrind test runs. - -2005-12-16 Thomas Vander Stichele - - * m4/gst-arch.m4: - define HOST_CPU - -2005-11-29 Thomas Vander Stichele - - * check.mak: - add a valgrind-forever target for tests - -2005-11-28 Thomas Vander Stichele - - * check.mak: - when a "make test.check" run fails, make it rerun the test with - at least debug level 2 - -2005-11-14 Thomas Vander Stichele - - * m4/Makefile.am: - * m4/gst-check.m4: - fix check for base plugins - * m4/gst-default.m4: - add m4 to set default elements - -2005-10-18 Thomas Vander Stichele - - * m4/gst-check.m4: - check for tools correctly - -2005-10-18 Thomas Vander Stichele - - * gtk-doc.mak: - only enable breaking on new API when make distcheck passes, - not before - -2005-10-18 Thomas Vander Stichele - - * m4/gst-check.m4: - Resurrect Julien's dead body and wipe his mind clean - -2005-10-18 Thomas Vander Stichele - - * m4/gst-check.m4: - Kill Julien - -2005-10-17 Julien MOUTTE - - * m4/gst-check.m4: I know Thomas will kill me but this - ifelse statement seems incorrect as it is always setting - required to "yes". With this one it seems to work. Fixes - build of gst-plugins-base on my setup where gstreamer-check - is definitely not present/required. - -2005-10-18 Stefan Kost - - * gtk-doc.mak: - make build break on new api that has not been added to the - sections file - -2005-10-17 Thomas Vander Stichele - - * m4/gst-glib2.m4: - * m4/Makefile.am: - * m4/gst-check.m4: - add macro for easy checks for GStreamer libs - -2005-10-16 Thomas Vander Stichele - - * m4/gst-glib2.m4: - update, warn in error cases - -2005-10-16 Thomas Vander Stichele - - * m4/gst-error.m4: - add GST_SET_DEFAULT_LEVEL - -2005-10-16 Thomas Vander Stichele - - * m4/Makefile.am: - * m4/gst-gettext.m4: - remove the AM_GNU_GETTEXT* calls, they need to be in configure.ac - * m4/gst-glib2.m4: - clean up and re-use in core soon - * m4/gst-plugindir.m4: - macro to set up PLUGINDIR and plugindir define/var - -2005-10-15 Thomas Vander Stichele - - * m4/Makefile.am: - * m4/gst-gettext.m4: - add macro for setting up gettext - -2005-10-15 Thomas Vander Stichele - - * m4/gst-args.m4: - add some .m4's for argument checking that can be shared among modules - -2005-10-15 Thomas Vander Stichele - - * m4/as-libtool.m4: - set _LT_LDFLAGS - * m4/gst-libxml2.m4: - document - -2005-10-15 Thomas Vander Stichele - - * m4/gst-arch.m4: - indent a little - add AC_REQUIRE - * m4/gst-error.m4: - clean up - -2005-10-12 Thomas Vander Stichele - - * gst-autogen.sh: - update version detection expression to catch stuff like - Libtool (libtool15) 1.5.0 - -2005-10-11 Thomas Vander Stichele - - * gst.supp: - commit 6 new suppressions related to g_module_open; can these - really not be folded into one ? - -2005-10-11 Edward Hervey - - * gst.supp: - made the suppression more generic - Added pthread memleak suppresions - Added nss_parse_* memleak suppresion (used by g_option_context_parse) - -2005-10-11 Thomas Vander Stichele - - * check.mak: - be more strict, more leak resolution - * gst.supp: - clean up the g_type_init suppressions - -2005-10-07 Thomas Vander Stichele - - * m4/Makefile.am: - * m4/gst-valgrind.m4: - put the valgrind detection in an .m4 - -2005-09-29 Thomas Vander Stichele - - * check.mak: - add some more targets, like "help", but also more intensive tests - -2005-09-23 Thomas Vander Stichele - - * gtk-doc.mak: - make certain doc warnings fatal so people maintain docs again - -2005-09-23 Thomas Vander Stichele - - * Makefile.am: - * gtk-doc-plugins.mak: - * scangobj-merge.py: - merge additions from the .signals.new and .args.new file in - the original ones, only updating if necessary - -2005-09-23 Thomas Vander Stichele - - * gst-xmlinspect.py: - * gstdoc-scangobj: - * gtk-doc-plugins.mak: - fix properly for new API; make update in plugins dir now works - -2005-09-20 Thomas Vander Stichele - - * gst-xmlinspect.py: - * gstdoc-scangobj: - some fixes for new API - * gtk-doc-plugins.mak: - set environment properly - -2005-09-17 David Schleef - - * gtk-doc-plugins.mak: Use new environment variables. - -2005-09-16 Michael Smith - - * gstdoc-scangobj: - Make the scanobj code reflect registry/plugin API changes - -2005-09-15 Thomas Vander Stichele - - * gtk-doc-plugins.mak: - split out scanobj step (which will be run by doc maintainer) - from scan step (which will be run on every build) - clean up some of the commands for make distcheck - -2005-09-15 Thomas Vander Stichele - - * gtk-doc-plugins.mak: - * mangle-tmpl.py: - first stab at reorganizing the plugins build so we can maintain - element docs - -2005-09-14 David Schleef - - * as-libtool.mak: Remove - * m4/as-libtool.m4: The libtool bug that this worked around has - been fixed. - * m4/as-version.m4: Don't define GST_RELEASE, since it causes - config.h to be regenerated needlessly, and we don't use it. - -2005-09-14 Thomas Vander Stichele - - * gtk-doc-plugins.mak: - error out on inspect failure - -2005-09-14 Michael Smith - - * glib-gen.mak: - Don't call glib-mkenums with arguments that confuse/break MinGW, - fixes 316155. - -2005-09-03 Thomas Vander Stichele - - * gtk-doc-plugins.mak: - * gtk-doc.mak: - * m4/gst-doc.m4: - separate out gtk-doc and docbook stuff - have two separate --enable configure flags - -2005-08-26 Thomas Vander Stichele - - * check.mak: - add a .gdb target; rebuild registry for each target, otherwise - a code rebuild always triggers a reg rebuild, and it's just too - annoying - * gstdoc-scangobj: - -2005-08-21 Thomas Vander Stichele - - * check.mak: - separate out REGISTRY_ENVIRONMENT; we want to use that from - our valgrind runs, but we also want TESTS_ENVIRONMENT to contain - everything that the first test, gst-register, needs - -2005-08-21 Thomas Vander Stichele - - * check.mak: - parse output of valgrind and check for definitely lost, and error - out; somehow I was led to believe valgrind returns non-zero for - leaks, but I can't make it do that, so let's parse - -2005-08-20 Thomas Vander Stichele - - * check.mak: - for some weird reason valgrind does not report actual memleaks - if GST_PLUGIN_PATH is set to anything but the core gstreamer dir - while valgrind is running. Since the registry is going to go - anyway, I don't want to waste any more time on this; I just run - valgrind without GST_PLUGIN_PATH set. Since the registry loading - doesn't check if GST_PLUGIN_PATH got changed as a reason to rebuild - the registry, that's actually fine. - -2005-08-15 Thomas Vander Stichele - - * mangle-tmpl.py: - keep original Long_Description; only insert an include if it's - not already the first line in there - * plugins.xsl: - output more information for plugins, including an origin hyperlink - -2005-08-15 Thomas Vander Stichele - - * gst-xmlinspect.py: - a first stab at inspecting plugins and outputting an xml description - * gtk-doc-plugins.mak: - a gtk-doc using snippet for plugins documentation - * plugins.xsl: - a stylesheet to convert gst-xmlinspect.py output to docbook output - for inclusion in the gtk-doc stuff - -2005-07-20 Ronald S. Bultje - - * m4/gst-doc.m4: - s/pdf/eps/ in test for whether we output EPS images (#309379). - -2005-07-18 Andy Wingo - - * m4/as-libtool-tags.m4: Ooh, backported from libtool 1.6. Much - better. Thanks, Paolo Bonzini! - - * m4/Makefile.am (EXTRA_DIST): - * m4/as-libtool-tags.m4: New file, tries to disable some CXX and - fortran checks. - -2005-07-08 Thomas Vander Stichele - - * m4/gst-error.m4: - add macro to set ERROR_CFLAGS - -2005-06-30 Jan Schmidt - - * gst-autogen.sh: - Remove the old autoregen.sh if it exists before recreating it, - to prevent confusing any shell process that might be reading it - currently. - -2005-06-29 Thomas Vander Stichele - - * m4/gtk-doc.m4: - added - -2005-06-03 Stefan Kost - - * gst-autogen.sh: create autoregen.sh *before* shifting the options - -2005-05-17 Thomas Vander Stichele - - * gst-autogen.sh: only update autoregen.sh on actual runs - -2005-03-11 Thomas Vander Stichele - - * m4/check.m4: m4 from the check unit test suite - -2004-12-14 David Schleef - - * m4/gst-arch.m4: remove MMX stuff, since it doesn't work and - isn't needed anywhere - -2004-12-08 Thomas Vander Stichele - - * gst-autogen.sh: - allow failure command to be run so we can clean upfrom autopoint - -2004-09-03 Zeeshan Ali Khattak - * m4/gst-feature.m4: Trying to correct the GST_CHECK_CONFIGPROG macro - -2004-07-21 Benjamin Otte - - * m4/.cvsignore: exciting updates for libtool m4 files - -2004-07-12 David Schleef - - * m4/as-objc.m4: Add a macro to test for objective C - -2004-06-12 Thomas Vander Stichele - - * m4/gst-feature.m4: - not all of them support --plugin-libs, so redirect stderr - -2004-06-12 Thomas Vander Stichele - - * m4/as-scrub-include.m4: - sync with upstream to 0.1.4. Fixes #132440 - -2004-06-07 Benjamin Otte - - * m4/gst-feature.m4: - write a big marker into configure output when checking next plugin - to allow easier parsing of why plugins are(n't) built. - -2004-06-01 Thomas Vander Stichele - - * m4/as-compiler-flag.m4: - * m4/as-compiler.m4: - * m4/as-libtool.m4: - * m4/as-version.m4: - sync with upstream, change sticky options to -ko - -2004-05-24 Thomas Vander Stichele - - * m4/as-scrub-include.m4: synced with upstream - -2004-05-03 Thomas Vander Stichele - - * po.mak: - snippet for updating .po files - -2004-03-18 Thomas Vander Stichele - - * Makefile.am: - * m4/Makefile.am: - integrate these with the dist - -2004-03-17 Thomas Vander Stichele - - * release.mak: add a release target - -2004-03-09 Thomas Vander Stichele - - patch by: Stephane Loeuillet - - * m4/ax_create_stdint_h.m4: - use head -n instead of head - (#136500) - -2004-03-05 Thomas Vander Stichele - - * m4/gst-doc.m4: don't build PS without dvips binary - -2004-02-22 Julio M. Merino Vidal - - reviewed by: Benjamin Otte - - * m4/as-docbook.m4: - don't use == operator with test(1) (fixes #135115) - -2004-02-16 Thomas Vander Stichele - - * common/m4/gst-arch.m4: x86_64 is x86 too (clue from Fedora 2 test) - -2004-02-13 Thomas Vander Stichele - - * m4/gst-feature.m4: - remove AM_CONDITIONAL for the subsystem since automake 1.6.x - requires that call be in configure.ac - -2004-02-13 Thomas Vander Stichele - - * m4/gst-libxml2.m4: - take required version as argument, and default to 2.4.9 if not - specified - -2004-02-12 Thomas Vander Stichele - - * m4/gst-feature.m4: - rename and fix up GST_CHECK_DISABLE_SUBSYSTEM - -2004-02-11 Thomas Vander Stichele - - * common/m4/as-ac-expand.m4: - * common/m4/as-auto-alt.m4: - * common/m4/as-compiler-flag.m4: - * common/m4/as-compiler.m4: - * common/m4/as-docbook.m4: - * common/m4/as-libtool.m4: - * common/m4/as-scrub-include.m4: - * common/m4/as-version.m4: - * common/m4/glib-gettext.m4: - * common/m4/gst-arch.m4: - * common/m4/gst-debuginfo.m4: - * common/m4/gst-doc.m4: - * common/m4/gst-feature.m4: - * common/m4/gst-function.m4: - * common/m4/gst-glib2.m4: - * common/m4/gst-gstreamer.m4: - * common/m4/gst-libxml2.m4: - * common/m4/gst-makecontext.m4: - * common/m4/gst-mcsc.m4: - * common/m4/pkg.m4: - fix underquoted macros as reported by automake 1.8.x (#133800) - -2004-02-11 Johan Dahlin - - * gst-autogen.sh: Use A-Z instead of A-z in sed expression to - avoid a warning - -2004-02-05 Thomas Vander Stichele - - * m4/gst-doc.m4: - we use --output-format=xml and --ingnore-files options to - gtkdoc-mkdb, which got added between 0.9 and 1.0 - -2004-02-04 Thomas Vander Stichele - - * m4/as-libtool.m4: remove AM_PROG_LIBTOOL so it can move back - to configure.ac to shut up libtoolize - -2004-02-03 Thomas Vander Stichele - - * glib-gen.mak: added; used to generate enums and marshal code - -2004-01-13 Thomas Vander Stichele - - * gettext.patch: added; used by autogen.sh to make sure - GETTEXT_PACKAGE is understood from po/Makefile.in.in -> po/Makefile.in - diff --git a/common/Makefile.am b/common/Makefile.am deleted file mode 100644 index ca8c02916e..0000000000 --- a/common/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -SUBDIRS = m4 - -EXTRA_DIST = \ - ChangeLog \ - gettext.patch \ - glib-gen.mak gtk-doc.mak upload.mak release.mak \ - gst-autogen.sh \ - c-to-xml.py gst-xmlinspect.py mangle-tmpl.py scangobj-merge.py \ - gtk-doc-plugins.mak \ - plugins.xsl gstdoc-scangobj \ - gst.supp check.mak \ - coverage/lcov.mak \ - coverage/coverage-report.pl \ - coverage/coverage-report.xsl \ - coverage/coverage-report-entry.pl diff --git a/common/c-to-xml.py b/common/c-to-xml.py deleted file mode 100644 index 8448fd248d..0000000000 --- a/common/c-to-xml.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- Mode: Python -*- -# vi:si:et:sw=4:sts=4:ts=4 - -""" -Convert a C program to valid XML to be included in docbook -""" - -import sys -import os -from xml.sax import saxutils - -def main(): - if len(sys.argv) == 1: - sys.stderr.write("Please specify a source file to convert") - sys.exit(1) - source = sys.argv[1] - - if not os.path.exists(source): - sys.stderr.write("%s does not exist.\n" % source) - sys.exit(1) - - content = open(source, "r").read() - - # print header - print '' - print '' - print - print '' - - # print content - print saxutils.escape(content).encode('UTF-8') - print '' - -main() diff --git a/common/check.mak b/common/check.mak deleted file mode 100644 index 9ac509d901..0000000000 --- a/common/check.mak +++ /dev/null @@ -1,149 +0,0 @@ -clean-local-check: - for i in `find . -name ".libs" -type d`; do \ - rm -rf $$i; \ - done - -if HAVE_VALGRIND -# hangs spectacularly on some machines, so let's not do this by default yet -check-valgrind: - make valgrind -else -check-valgrind: - @true -endif - -LOOPS = 10 - -# run any given test by running make test.check -# if the test fails, run it again at at least debug level 2 -%.check: % - @$(TESTS_ENVIRONMENT) \ - CK_DEFAULT_TIMEOUT=20 \ - $* || \ - $(TESTS_ENVIRONMENT) \ - GST_DEBUG=$$GST_DEBUG,*:2 \ - CK_DEFAULT_TIMEOUT=20 \ - $* - -# run any given test in a loop -%.torture: % - @for i in `seq 1 $(LOOPS)`; do \ - $(TESTS_ENVIRONMENT) \ - CK_DEFAULT_TIMEOUT=20 \ - $*; done - -# run any given test in an infinite loop -%.forever: % - @while true; do \ - $(TESTS_ENVIRONMENT) \ - CK_DEFAULT_TIMEOUT=20 \ - $* || break; done - -# valgrind any given test by running make test.valgrind -%.valgrind: % - $(TESTS_ENVIRONMENT) \ - CK_DEFAULT_TIMEOUT=360 \ - G_SLICE=always-malloc \ - libtool --mode=execute \ - $(VALGRIND_PATH) -q \ - $(foreach s,$(SUPPRESSIONS),--suppressions=$(s)) \ - --tool=memcheck --leak-check=full --trace-children=yes \ - --leak-resolution=high --num-callers=20 \ - ./$* 2>&1 | tee valgrind.log - @if grep "==" valgrind.log > /dev/null 2>&1; then \ - rm valgrind.log; \ - exit 1; \ - fi - @rm valgrind.log - -# valgrind any given test and generate suppressions for it -%.valgrind.gen-suppressions: % - $(TESTS_ENVIRONMENT) \ - CK_DEFAULT_TIMEOUT=360 \ - G_SLICE=always-malloc \ - libtool --mode=execute \ - $(VALGRIND_PATH) -q \ - $(foreach s,$(SUPPRESSIONS),--suppressions=$(s)) \ - --tool=memcheck --leak-check=full --trace-children=yes \ - --leak-resolution=high --num-callers=20 \ - --gen-suppressions=all \ - ./$* 2>&1 | tee suppressions.log - -# valgrind any given test until failure by running make test.valgrind-forever -%.valgrind-forever: % - @while make $*.valgrind; do \ - true; done - -# gdb any given test by running make test.gdb -%.gdb: % - $(TESTS_ENVIRONMENT) \ - CK_FORK=no \ - libtool --mode=execute \ - gdb $* - -# torture tests -torture: $(TESTS) - -rm test-registry.xml - @echo "Torturing tests ..." - for i in `seq 1 $(LOOPS)`; do \ - make check || \ - (echo "Failure after $$i runs"; exit 1) || \ - exit 1; \ - done - @banner="All $(LOOPS) loops passed"; \ - dashes=`echo "$$banner" | sed s/./=/g`; \ - echo $$dashes; echo $$banner; echo $$dashes - -# forever tests -forever: $(TESTS) - -rm test-registry.xml - @echo "Forever tests ..." - while true; do \ - make check || \ - (echo "Failure"; exit 1) || \ - exit 1; \ - done - -# valgrind all tests -valgrind: $(TESTS) - @echo "Valgrinding tests ..." - @failed=0; \ - for t in $(filter-out $(VALGRIND_TESTS_DISABLE),$(TESTS)); do \ - make $$t.valgrind; \ - if test "$$?" -ne 0; then \ - echo "Valgrind error for test $$t"; \ - failed=`expr $$failed + 1`; \ - whicht="$$whicht $$t"; \ - fi; \ - done; \ - if test "$$failed" -ne 0; then \ - echo "$$failed tests had leaks or errors under valgrind:"; \ - echo "$$whicht"; \ - false; \ - fi - -# inspect every plugin feature -GST_INSPECT = $(GST_TOOLS_DIR)/gst-inspect-$(GST_MAJORMINOR) -inspect: - @echo "Inspecting features ..." - for e in `$(TESTS_ENVIRONMENT) $(GST_INSPECT) | head -n -2 \ - | cut -d: -f2`; \ - do echo Inspecting $$e; \ - $(GST_INSPECT) $$e > /dev/null 2>&1; done - -help: - @echo "make check -- run all checks" - @echo "make torture -- run all checks $(LOOPS) times" - @echo "make (dir)/(test).check -- run the given check once" - @echo "make (dir)/(test).forever -- run the given check forever" - @echo "make (dir)/(test).torture -- run the given check $(LOOPS) times" - @echo - @echo "make (dir)/(test).gdb -- start up gdb for the given test" - @echo - @echo "make valgrind -- valgrind all tests" - @echo "make (dir)/(test).valgrind -- valgrind the given test" - @echo "make (dir)/(test).valgrind-forever -- valgrind the given test forever" - @echo "make (dir)/(test).valgrind.gen-suppressions -- generate suppressions" - @echo " and save to suppressions.log" - @echo "make inspect -- inspect all plugin features" - diff --git a/common/coverage/coverage-report-entry.pl b/common/coverage/coverage-report-entry.pl deleted file mode 100644 index 8f653afe69..0000000000 --- a/common/coverage/coverage-report-entry.pl +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/perl -# -# Copyright (C) 2006 Daniel Berrange -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -print < - -Coverage report for $ARGV[0] - - - -

Coverage report for $ARGV[0]

- -
-EOF
-
-
-while (<>) {
-    s/&/&/g;
-    s//>/g;
-
-    if (/^\s*function (\S+) called (\d+) returned \d+% blocks executed \d+%/) {
-	my $class = $2 > 0 ? "perfect" : "terrible";
-	$_ = "$_";
-    } elsif (/^\s*branch\s+\d+\s+taken\s+(\d+)%\s+.*$/) {
-	my $class = $1 > 0 ? "perfect" : "terrible";
-	$_ = "$_";
-    } elsif (/^\s*branch\s+\d+\s+never executed.*$/) {
-	my $class = "terrible";
-	$_ = "$_";
-    } elsif (/^\s*call\s+\d+\s+never executed.*$/) {
-	my $class = "terrible";
-	$_ = "$_";
-    } elsif (/^\s*call\s+\d+\s+returned\s+(\d+)%.*$/) {
-	my $class = $1 > 0 ? "perfect" : "terrible";
-	$_ = "$_";
-    }
-    
-
-    print;
-}
-
-print <
-
-
-EOF
diff --git a/common/coverage/coverage-report.pl b/common/coverage/coverage-report.pl
deleted file mode 100644
index 046bc370c5..0000000000
--- a/common/coverage/coverage-report.pl
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/usr/bin/perl
-#
-# Copyright (C) 2006 Daniel Berrange
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-use warnings;
-use strict;
-
-my %coverage = ( functions => {}, files => {} );
-
-my %filemap;
-
-my $type;
-my $name;
-
-my @functions;
-
-while (<>) {
-    if (/^Function '(.*)'\s*$/) {
-	$type = "function";
-	$name = $1;
-	$coverage{$type}->{$name} = {};
-	push @functions, $name;
-    } elsif (/^File '(.*?)'\s*$/) {
-	$type = "file";
-	$name = $1;
-	$coverage{$type}->{$name} = {};
-	
-	foreach my $func (@functions) {
-	    $coverage{"function"}->{$func}->{file} = $name;
-	}
-	@functions = ();
-    } elsif (/^Lines executed:(.*)%\s*of\s*(\d+)\s*$/) {
-	$coverage{$type}->{$name}->{lines} = $2;
-	$coverage{$type}->{$name}->{linesCoverage} = $1;
-    } elsif (/^Branches executed:(.*)%\s*of\s*(\d+)\s*$/) {
-	$coverage{$type}->{$name}->{branches} = $2;
-	$coverage{$type}->{$name}->{branchesCoverage} = $1;
-    } elsif (/^Taken at least once:(.*)%\s*of\s*(\d+)\s*$/) {
-	$coverage{$type}->{$name}->{conds} = $2;
-	$coverage{$type}->{$name}->{condsCoverage} = $1;
-    } elsif (/^Calls executed:(.*)%\s*of\s*(\d+)\s*$/) {
-	$coverage{$type}->{$name}->{calls} = $2;
-	$coverage{$type}->{$name}->{callsCoverage} = $1;
-    } elsif (/^No branches$/) {
-	$coverage{$type}->{$name}->{branches} = 0;
-	$coverage{$type}->{$name}->{branchesCoverage} = "100.00";
-	$coverage{$type}->{$name}->{conds} = 0;
-	$coverage{$type}->{$name}->{condsCoverage} = "100.00";
-    } elsif (/^No calls$/) {
-	$coverage{$type}->{$name}->{calls} = 0;
-	$coverage{$type}->{$name}->{callsCoverage} = "100.00";
-    } elsif (/^\s*(.*):creating '(.*)'\s*$/) {
-	$filemap{$1} = $2;
-    } elsif (/^\s*$/) {
-	# nada
-    } else {
-	warn "Shit [$_]\n";
-    }
-}
-
-my %summary;
-foreach my $type ("function", "file") {
-    $summary{$type} = {};
-    foreach my $m ("lines", "branches", "conds", "calls") {
-	my $totalGot = 0;
-	my $totalMiss = 0;
-	my $count = 0;
-	foreach my $func (keys %{$coverage{function}}) {
-	    $count++;
-	    my $got = $coverage{function}->{$func}->{$m};
-	    $totalGot += $got;
-	    my $miss = $got * $coverage{function}->{$func}->{$m ."Coverage"} / 100;
-	    $totalMiss += $miss;
-	}
-	$summary{$type}->{$m} = sprintf("%d", $totalGot);
-	$summary{$type}->{$m . "Coverage"} = sprintf("%.2f", $totalMiss / $totalGot * 100);
-    }
-}
-
-
-
-print "\n";
-
-foreach my $type ("function", "file") {
-    printf "<%ss>\n", $type;
-    foreach my $name (sort { $a cmp $b } keys %{$coverage{$type}}) {
-	my $rec = $coverage{$type}->{$name};
-	printf "  \n", $name, ($type eq "file" ? $filemap{$name} : $filemap{$rec->{file}});
-	printf "    \n", $rec->{lines}, $rec->{linesCoverage};
-	if (exists $rec->{branches}) {
-	    printf "    \n", $rec->{branches}, $rec->{branchesCoverage};
-	}
-	if (exists $rec->{conds}) {
-	    printf "    \n", $rec->{conds}, $rec->{condsCoverage};
-	}
-	if (exists $rec->{calls}) {
-	    printf "    \n", $rec->{calls}, $rec->{callsCoverage};
-	}
-	print  "  \n";
-    }
-    
-    printf "  \n";
-    printf "    \n", $summary{$type}->{lines}, $summary{$type}->{linesCoverage};
-    printf "    \n", $summary{$type}->{branches}, $summary{$type}->{branchesCoverage};
-    printf "    \n", $summary{$type}->{conds}, $summary{$type}->{condsCoverage};
-    printf "    \n", $summary{$type}->{calls}, $summary{$type}->{callsCoverage};
-    printf  "  \n";
-    printf "\n", $type;
-}
-
-print "\n";
diff --git a/common/coverage/coverage-report.xsl b/common/coverage/coverage-report.xsl
deleted file mode 100644
index b19ebb638b..0000000000
--- a/common/coverage/coverage-report.xsl
+++ /dev/null
@@ -1,235 +0,0 @@
-
-
-
-
-  
-
-  
-    
-      
-        Coverage report
-        
-      
-      
-        

Coverage report

- - - -
- - -

Function coverage

- - - -
- - - -

File coverage

- - - -
- - - - - - - - - - - - - - - - - - - - - odd - - - even - - - - - - - - - - - - - - odd - - - even - - - - - - -
NameLinesBranchesConditionsCalls
-
- - - - - - - - - - - - - - Summary - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - perfect - - - excellant - - - good - - - poor - - - bad - - - terrible - - - - - % of - - -
diff --git a/common/coverage/lcov.mak b/common/coverage/lcov.mak deleted file mode 100644 index 6d848f5245..0000000000 --- a/common/coverage/lcov.mak +++ /dev/null @@ -1,29 +0,0 @@ -# run lcov from scratch, always -lcov-reset: - make lcov-run - make lcov-report - -# run lcov from scratch if the dir is not there -lcov: - make lcov-reset - -# reset run coverage tests -lcov-run: - @-rm -rf lcov - find . -name "*.gcda" -exec rm {} \; - if test -d tests/check; then make -C tests/check inspect; fi - make check - -# generate report based on current coverage data -lcov-report: - mkdir lcov - lcov --directory . --capture --output-file lcov/lcov.info - lcov -l lcov/lcov.info | grep -v "`cd $(top_srcdir) && pwd`" | cut -d: -f1 > lcov/remove - lcov -l lcov/lcov.info | grep "tests/check/" | cut -d: -f1 >> lcov/remove - lcov -r lcov/lcov.info `cat lcov/remove` > lcov/lcov.cleaned.info - rm lcov/remove - mv lcov/lcov.cleaned.info lcov/lcov.info - genhtml -t "$(PACKAGE_STRING)" -o lcov lcov/lcov.info - -lcov-upload: lcov - rsync -rvz -e ssh --delete lcov/* gstreamer.freedesktop.org:/srv/gstreamer.freedesktop.org/www/data/coverage/lcov/$(PACKAGE) diff --git a/common/gettext.patch b/common/gettext.patch deleted file mode 100644 index 659718e3af..0000000000 --- a/common/gettext.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- po/Makefile.in.in.orig 2006-01-07 12:03:45.000000000 +0100 -+++ po/Makefile.in.in 2006-01-07 12:04:23.000000000 +0100 -@@ -11,6 +11,9 @@ - PACKAGE = @PACKAGE@ - VERSION = @VERSION@ - -+# thomas: add GETTEXT_PACKAGE substitution as used in Makevars -+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ -+ - SHELL = /bin/sh - @SET_MAKE@ - -@@ -305,7 +308,9 @@ - update-gmo: Makefile $(GMOFILES) - @: - --Makefile: Makefile.in.in $(top_builddir)/config.status POTFILES.in -+# thomas: add LINGUAS as a dependency so that the Makefile gets rebuilt -+# properly when we add languages -+Makefile: Makefile.in.in $(top_builddir)/config.status POTFILES.in LINGUAS - cd $(top_builddir) \ - && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \ - $(SHELL) ./config.status diff --git a/common/glib-gen.mak b/common/glib-gen.mak deleted file mode 100644 index eff414714a..0000000000 --- a/common/glib-gen.mak +++ /dev/null @@ -1,42 +0,0 @@ -# these are the variables your Makefile.am should set -# the example is based on the colorbalance interface - -#glib_enum_headers=$(colorbalance_headers) -#glib_enum_define=GST_COLOR_BALANCE -#glib_enum_prefix=gst_color_balance - -# these are all the rules generating the relevant files -%-marshal.h: %-marshal.list - glib-genmarshal --header --prefix=$(glib_enum_prefix)_marshal $^ > $*-marshal.h.tmp - mv $*-marshal.h.tmp $*-marshal.h - -%-marshal.c: %-marshal.list - echo "#include \"$*-marshal.h\"" >> $*-marshal.c.tmp - glib-genmarshal --body --prefix=$(glib_enum_prefix)_marshal $^ >> $*-marshal.c.tmp - mv $*-marshal.c.tmp $*-marshal.c - -%-enumtypes.h: $(glib_enum_headers) - glib-mkenums \ - --fhead "#ifndef __$(glib_enum_define)_ENUM_TYPES_H__\n#define __$(glib_enum_define)_ENUM_TYPES_H__\n\n#include \n\nG_BEGIN_DECLS\n" \ - --fprod "\n/* enumerations from \"@filename@\" */\n" \ - --vhead "GType @enum_name@_get_type (void);\n#define GST_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \ - --ftail "G_END_DECLS\n\n#endif /* __$(glib_enum_define)_ENUM_TYPES_H__ */" \ - $^ > $@ - -%-enumtypes.c: $(glib_enum_headers) - @if test "x$(glib_enum_headers)" == "x"; then echo "ERROR: glib_enum_headers is empty, please fix Makefile"; exit 1; fi - glib-mkenums \ - --fhead "#include <$*.h>" \ - --fprod "\n/* enumerations from \"@filename@\" */" \ - --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \ - --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ - --vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \ - $^ > $@ - -# a hack rule to make sure .Plo files exist because they get include'd -# from Makefile's -.deps/%-marshal.Plo: - touch $@ - -.deps/%-enumtypes.Plo: - touch $@ diff --git a/common/gst-autogen.sh b/common/gst-autogen.sh deleted file mode 100644 index 7b312124b7..0000000000 --- a/common/gst-autogen.sh +++ /dev/null @@ -1,308 +0,0 @@ -# a silly hack that generates autoregen.sh but it's handy -# Remove the old autoregen.sh first to create a new file, -# as the current one may be being read by the shell executing -# this script. -if [ -f "autoregen.sh" ]; then - rm autoregen.sh -fi -echo "#!/bin/sh" > autoregen.sh -echo "./autogen.sh $@ \$@" >> autoregen.sh -chmod +x autoregen.sh - -# helper functions for autogen.sh - -debug () -# print out a debug message if DEBUG is a defined variable -{ - if test ! -z "$DEBUG" - then - echo "DEBUG: $1" - fi -} - -version_check () -# check the version of a package -# first argument : package name (executable) -# second argument : optional path where to look for it instead -# third argument : source download url -# rest of arguments : major, minor, micro version -# all consecutive ones : suggestions for binaries to use -# (if not specified in second argument) -{ - PACKAGE=$1 - PKG_PATH=$2 - URL=$3 - MAJOR=$4 - MINOR=$5 - MICRO=$6 - - # for backwards compatibility, we let PKG_PATH=PACKAGE when PKG_PATH null - if test -z "$PKG_PATH"; then PKG_PATH=$PACKAGE; fi - debug "major $MAJOR minor $MINOR micro $MICRO" - VERSION=$MAJOR - if test ! -z "$MINOR"; then VERSION=$VERSION.$MINOR; else MINOR=0; fi - if test ! -z "$MICRO"; then VERSION=$VERSION.$MICRO; else MICRO=0; fi - - debug "major $MAJOR minor $MINOR micro $MICRO" - - for SUGGESTION in $PKG_PATH; do - COMMAND="$SUGGESTION" - - # don't check if asked not to - test -z "$NOCHECK" && { - echo -n " checking for $COMMAND >= $VERSION ... " - } || { - # we set a var with the same name as the package, but stripped of - # unwanted chars - VAR=`echo $PACKAGE | sed 's/-//g'` - debug "setting $VAR" - eval $VAR="$COMMAND" - return 0 - } - - debug "checking version with $COMMAND" - ($COMMAND --version) < /dev/null > /dev/null 2>&1 || - { - echo "not found." - continue - } - # strip everything that's not a digit, then use cut to get the first field - pkg_version=`$COMMAND --version|head -n 1|sed 's/^.*)[^0-9]*//'|cut -d' ' -f1` - debug "pkg_version $pkg_version" - # remove any non-digit characters from the version numbers to permit numeric - # comparison - pkg_major=`echo $pkg_version | cut -d. -f1 | sed s/[a-zA-Z\-].*//g` - pkg_minor=`echo $pkg_version | cut -d. -f2 | sed s/[a-zA-Z\-].*//g` - pkg_micro=`echo $pkg_version | cut -d. -f3 | sed s/[a-zA-Z\-].*//g` - test -z "$pkg_major" && pkg_major=0 - test -z "$pkg_minor" && pkg_minor=0 - test -z "$pkg_micro" && pkg_micro=0 - debug "found major $pkg_major minor $pkg_minor micro $pkg_micro" - - #start checking the version - debug "version check" - - # reset check - WRONG= - - if [ ! "$pkg_major" -gt "$MAJOR" ]; then - debug "major: $pkg_major <= $MAJOR" - if [ "$pkg_major" -lt "$MAJOR" ]; then - debug "major: $pkg_major < $MAJOR" - WRONG=1 - elif [ ! "$pkg_minor" -gt "$MINOR" ]; then - debug "minor: $pkg_minor <= $MINOR" - if [ "$pkg_minor" -lt "$MINOR" ]; then - debug "minor: $pkg_minor < $MINOR" - WRONG=1 - elif [ "$pkg_micro" -lt "$MICRO" ]; then - debug "micro: $pkg_micro < $MICRO" - WRONG=1 - fi - fi - fi - - if test ! -z "$WRONG"; then - echo "found $pkg_version, not ok !" - continue - else - echo "found $pkg_version, ok." - # we set a var with the same name as the package, but stripped of - # unwanted chars - VAR=`echo $PACKAGE | sed 's/-//g'` - debug "setting $VAR" - eval $VAR="$COMMAND" - return 0 - fi - done - - echo "not found !" - echo "You must have $PACKAGE installed to compile $package." - echo "Download the appropriate package for your distribution," - echo "or get the source tarball at $URL" - return 1; -} - -aclocal_check () -{ - # normally aclocal is part of automake - # so we expect it to be in the same place as automake - # so if a different automake is supplied, we need to adapt as well - # so how's about replacing automake with aclocal in the set var, - # and saving that in $aclocal ? - # note, this will fail if the actual automake isn't called automake* - # or if part of the path before it contains it - if [ -z "$automake" ]; then - echo "Error: no automake variable set !" - return 1 - else - aclocal=`echo $automake | sed s/automake/aclocal/` - debug "aclocal: $aclocal" - if [ "$aclocal" != "aclocal" ]; - then - CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-aclocal=$aclocal" - fi - if [ ! -x `which $aclocal` ]; then - echo "Error: cannot execute $aclocal !" - return 1 - fi - fi -} - -autoheader_check () -{ - # same here - autoheader is part of autoconf - # use the same voodoo - if [ -z "$autoconf" ]; then - echo "Error: no autoconf variable set !" - return 1 - else - autoheader=`echo $autoconf | sed s/autoconf/autoheader/` - debug "autoheader: $autoheader" - if [ "$autoheader" != "autoheader" ]; - then - CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-autoheader=$autoheader" - fi - if [ ! -x `which $autoheader` ]; then - echo "Error: cannot execute $autoheader !" - return 1 - fi - fi - -} -autoconf_2_52d_check () -{ - # autoconf 2.52d has a weird issue involving a yes:no error - # so don't allow it's use - test -z "$NOCHECK" && { - ac_version=`$autoconf --version|head -n 1|sed 's/^[a-zA-Z\.\ ()]*//;s/ .*$//'` - if test "$ac_version" = "2.52d"; then - echo "autoconf 2.52d has an issue with our current build." - echo "We don't know who's to blame however. So until we do, get a" - echo "regular version. RPM's of a working version are on the gstreamer site." - exit 1 - fi - } - return 0 -} - -die_check () -{ - # call with $DIE - # if set to 1, we need to print something helpful then die - DIE=$1 - if test "x$DIE" = "x1"; - then - echo - echo "- Please get the right tools before proceeding." - echo "- Alternatively, if you're sure we're wrong, run with --nocheck." - exit 1 - fi -} - -autogen_options () -{ - if test "x$1" = "x"; then - return 0 - fi - - while test "x$1" != "x" ; do - optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` - case "$1" in - --noconfigure) - NOCONFIGURE=defined - AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --noconfigure" - echo "+ configure run disabled" - shift - ;; - --nocheck) - AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --nocheck" - NOCHECK=defined - echo "+ autotools version check disabled" - shift - ;; - --debug) - DEBUG=defined - AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --debug" - echo "+ debug output enabled" - shift - ;; - --prefix=*) - CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT --prefix=$optarg" - echo "+ passing --prefix=$optarg to configure" - shift - ;; - --prefix) - shift - echo "DEBUG: $1" - CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT --prefix=$1" - echo "+ passing --prefix=$1 to configure" - shift - ;; - - -h|--help) - echo "autogen.sh (autogen options) -- (configure options)" - echo "autogen.sh help options: " - echo " --noconfigure don't run the configure script" - echo " --nocheck don't do version checks" - echo " --debug debug the autogen process" - echo " --prefix will be passed on to configure" - echo - echo " --with-autoconf PATH use autoconf in PATH" - echo " --with-automake PATH use automake in PATH" - echo - echo "to pass options to configure, put them as arguments after -- " - exit 1 - ;; - --with-automake=*) - AUTOMAKE=$optarg - echo "+ using alternate automake in $optarg" - CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-automake=$AUTOMAKE" - shift - ;; - --with-autoconf=*) - AUTOCONF=$optarg - echo "+ using alternate autoconf in $optarg" - CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-autoconf=$AUTOCONF" - shift - ;; - --disable*|--enable*|--with*) - echo "+ passing option $1 to configure" - CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT $1" - shift - ;; - --) shift ; break ;; - *) echo "- ignoring unknown autogen.sh argument $1"; shift ;; - esac - done - - for arg do CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT $arg"; done - if test ! -z "$CONFIGURE_EXT_OPT" - then - echo "+ options passed to configure: $CONFIGURE_EXT_OPT" - fi -} - -toplevel_check () -{ - srcfile=$1 - test -f $srcfile || { - echo "You must run this script in the top-level $package directory" - exit 1 - } -} - - -tool_run () -{ - tool=$1 - options=$2 - run_if_fail=$3 - echo "+ running $tool $options..." - $tool $options || { - echo - echo $tool failed - eval $run_if_fail - exit 1 - } -} diff --git a/common/gst-xmlinspect.py b/common/gst-xmlinspect.py deleted file mode 100644 index 0d7f696122..0000000000 --- a/common/gst-xmlinspect.py +++ /dev/null @@ -1,168 +0,0 @@ -# -*- Mode: Python -*- -# vi:si:et:sw=4:sts=4:ts=4 - -""" -examine all plugins and elements and output xml documentation for them -used as part of the plugin documentation build -""" - -import sys -import os -import pygst -pygst.require('0.10') -import gst - -INDENT_SIZE = 2 - -# all templates - -PAD_TEMPLATE = """ - %(name)s - %(direction)s - %(presence)s -
%(details)s
-
""" - -ELEMENT_TEMPLATE = """ - %(name)s - %(longname)s - %(class)s - %(description)s - %(author)s - -%(pads)s - -""" - -PLUGIN_TEMPLATE = """ - %(name)s - %(description)s - %(filename)s - %(basename)s - %(version)s - %(license)s - %(source)s - %(package)s - %(origin)s - -%(elements)s - -""" - -def xmlencode(line): - """ - Replace &, <, and > - """ - line = "&".join(line.split("&")) - line = "<".join(line.split("<")) - line = ">".join(line.split(">")) - return line - -def get_offset(indent): - return " " * INDENT_SIZE * indent - -def output_pad_template(pt, indent=0): - print "PAD TEMPLATE", pt.name_template - paddir = ("unknown","source","sink") - padpres = ("always","sometimes","request") - - d = { - 'name': xmlencode(pt.name_template), - 'direction': xmlencode(paddir[pt.direction]), - 'presence': xmlencode(padpres[pt.presence]), - 'details': xmlencode(pt.static_caps.string), - } - block = PAD_TEMPLATE % d - - offset = get_offset(indent) - return offset + ("\n" + offset).join(block.split("\n")) - -def output_element_factory(elf, indent=0): - print "ELEMENT", elf.get_name() - - padsoutput = [] - padtemplates = elf.get_static_pad_templates() - for padtemplate in padtemplates: - padsoutput.append(output_pad_template(padtemplate, indent)) - - d = { - 'name': xmlencode(elf.get_name()), - 'longname': xmlencode(elf.get_longname()), - 'class': xmlencode(elf.get_klass()), - 'description': xmlencode(elf.get_description()), - 'author': xmlencode(elf.get_author()), - 'pads': "\n".join(padsoutput), - } - block = ELEMENT_TEMPLATE % d - - offset = get_offset(indent) - return offset + ("\n" + offset).join(block.split("\n")) - -def output_plugin(plugin, indent=0): - print "PLUGIN", plugin.get_name() - version = plugin.get_version() - - elements = {} - gst.debug('getting features for plugin %s' % plugin.get_name()) - registry = gst.registry_get_default() - features = registry.get_feature_list_by_plugin(plugin.get_name()) - gst.debug('plugin %s has %d features' % (plugin.get_name(), len(features))) - for feature in features: - if isinstance(feature, gst.ElementFactory): - elements[feature.get_name()] = feature - #gst.debug("got features") - - elementsoutput = [] - keys = elements.keys() - keys.sort() - for name in keys: - feature = elements[name] - elementsoutput.append(output_element_factory(feature, indent + 2)) - - filename = plugin.get_filename() - basename = filename - if basename: - basename = os.path.basename(basename) - d = { - 'name': xmlencode(plugin.get_name()), - 'description': xmlencode(plugin.get_description()), - 'filename': filename, - 'basename': basename, - 'version': version, - 'license': xmlencode(plugin.get_license()), - 'source': xmlencode(plugin.get_source()), - 'package': xmlencode(plugin.get_package()), - 'origin': xmlencode(plugin.get_origin()), - 'elements': "\n".join(elementsoutput), - } - block = PLUGIN_TEMPLATE % d - - offset = get_offset(indent) - return offset + ("\n" + offset).join(block.split("\n")) - -def main(): - if len(sys.argv) == 1: - sys.stderr.write("Please specify a source module to inspect") - sys.exit(1) - source = sys.argv[1] - - if len(sys.argv) > 2: - os.chdir(sys.argv[2]) - - registry = gst.registry_get_default() - all = registry.get_plugin_list() - for plugin in all: - gst.debug("inspecting plugin %s from source %s" % ( - plugin.get_name(), plugin.get_source())) - # this skips gstcoreelements, with bin and pipeline - if plugin.get_filename() is None: - continue - if plugin.get_source() != source: - continue - - filename = "plugin-%s.xml" % plugin.get_name() - handle = open(filename, "w") - handle.write(output_plugin(plugin)) - handle.close() - -main() diff --git a/common/gst.supp b/common/gst.supp deleted file mode 100644 index ce0daa2568..0000000000 --- a/common/gst.supp +++ /dev/null @@ -1,1660 +0,0 @@ -### this file contains suppressions for valgrind when running -### the gstreamer unit tests -### it might be useful for wider use as well - -### syscall suppressions - -{ - - Memcheck:Param - clone(parent_tidptr) - fun:clone - fun:clone -} - -{ - - Memcheck:Param - clone(child_tidptr) - fun:clone - fun:clone -} - -{ - - Memcheck:Param - clone(tlsinfo) - fun:clone - fun:clone -} - -### glibc suppressions - -{ - - Memcheck:Cond - obj:/lib/ld-2.3.*.so - fun:dl_open_worker - obj:/lib/ld-2.3.*.so - fun:_dl_open - fun:dlopen_doit - obj:/lib/ld-2.3.*.so - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open - fun:gst_plugin_load_file -} - -# glibc does not deallocate thread-local storage - -{ - - Memcheck:Leak - fun:calloc - fun:_dl_allocate_tls - fun:pthread_create@@* -} - -# I get an extra stack entry on x86/dapper -{ - - Memcheck:Leak - fun:calloc - obj:/lib/ld-2.3.*.so - fun:_dl_allocate_tls - fun:pthread_create@@* -} - - -{ - - Memcheck:Cond - fun:strstr - fun:__pthread_initialize_minimal - obj:/lib/libpthread-*.so - obj:/lib/libpthread-*.so - fun:call_init - fun:_dl_init - obj:/lib/ld-*.so -} - -# a thread-related free problem in glibc from Edgard -{ - __libc_freeres_rw_acess - Memcheck:Addr4 - obj:* - obj:* - obj:* - obj:* - obj:* - fun:__libc_freeres -} - -{ - - Memcheck:Cond - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so -} - -# g_module_open-related problems -{ - - Memcheck:Addr2 - fun:memcpy - fun:_dl_map_object_deps - fun:dl_open_worker - fun:_dl_catch_error - fun:_dl_open - fun:dlopen_doit - fun:_dl_catch_error - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open - fun:gst_plugin_load_file - fun:gst_registry_scan_path_level - fun:gst_registry_scan_path_level - fun:gst_registry_scan_path_level - fun:init_post - fun:g_option_context_parse - fun:gst_init_check - fun:gst_init - fun:gst_check_init - fun:main -} - -{ - - Memcheck:Addr4 - fun:memcpy - fun:_dl_map_object_deps - fun:dl_open_worker - fun:_dl_catch_error - fun:_dl_open - fun:dlopen_doit - fun:_dl_catch_error - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open - fun:gst_plugin_load_file - fun:gst_registry_scan_path_level - fun:gst_registry_scan_path_level - fun:gst_registry_scan_path_level - fun:init_post - fun:g_option_context_parse - fun:gst_init_check - fun:gst_init - fun:gst_check_init - fun:main -} - -{ - - Memcheck:Cond - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - fun:do_sym - fun:_dl_sym - fun:dlsym_doit - obj:/lib/ld-2.3.*.so - fun:_dlerror_run - fun:dlsym - fun:g_module_symbol - fun:g_module_open - fun:gst_plugin_load_file -} - -{ - - Memcheck:Cond - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - fun:dl_open_worker - obj:/lib/ld-2.3.*.so - fun:_dl_open - fun:dlopen_doit - obj:/lib/ld-2.3.*.so - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open - fun:gst_plugin_load_file -} -{ - - Memcheck:Cond - obj:/lib/ld-2.3.*.so - fun:dl_open_worker - obj:/lib/ld-2.3.*.so - fun:_dl_open - fun:dlopen_doit - obj:/lib/ld-2.3.*.so - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open - fun:gst_plugin_load_file - fun:gst_plugin_load_by_name - fun:gst_plugin_feature_load -} - -{ - - Memcheck:Leak - fun:malloc - obj:/lib/ld-2.3.*.so - fun:dl_open_worker - obj:/lib/ld-2.3.*.so - fun:_dl_open - fun:dlopen_doit - obj:/lib/ld-2.3.*.so - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open - fun:gst_plugin_load_file - fun:gst_plugin_load_by_name -} - -{ - - Memcheck:Addr4 - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - fun:dl_open_worker - obj:/lib/ld-2.3.*.so - fun:_dl_open - fun:dlopen_doit - obj:/lib/ld-2.3.*.so -} - -{ - - Memcheck:Addr4 - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - fun:dl_open_worker - obj:/lib/ld-2.3.*.so - fun:_dl_open - fun:dlopen_doit - obj:/lib/ld-2.3.*.so - fun:_dlerror_run -} - -{ - - Memcheck:Addr4 - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - fun:dl_open_worker - obj:/lib/ld-2.3.*.so - fun:_dl_open - fun:dlopen_doit - obj:/lib/ld-2.3.*.so - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open -} - -{ - - Memcheck:Addr4 - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - fun:dl_open_worker - obj:/lib/ld-2.3.*.so - fun:_dl_open - fun:dlopen_doit - obj:/lib/ld-2.3.*.so - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open -} - -{ - - Memcheck:Addr4 - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - fun:do_sym - fun:_dl_sym - fun:dlsym_doit - obj:/lib/ld-2.3.*.so - fun:_dlerror_run - fun:dlsym - fun:g_module_symbol - fun:g_module_open -} - -{ - - Memcheck:Param - futex(uaddr2) - fun:pthread_once - obj:/lib/libc-2.3.*.so - obj:/lib/libc-2.3.*.so - fun:mbsnrtowcs - fun:vfprintf - fun:vsprintf - fun:sprintf - obj:/lib/libc-2.3.*.so - fun:tmpfile - fun:setup_pipe - fun:setup_messaging_with_key - fun:setup_messaging -} - -# valgrind doesn't allow me to specify a suppression for Addr1, Addr2, Addr4 -# as Addr*, so 3 copies for that; and then 2 of each for that pesky memcpy -{ - - Memcheck:Addr1 - fun:_dl_signal_error - fun:_dl_map_object_deps - fun:dl_open_worker - fun:_dl_catch_error - fun:_dl_open - fun:dlopen_doit - fun:_dl_catch_error - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open -} - -{ - - Memcheck:Addr2 - fun:_dl_signal_error - fun:_dl_map_object_deps - fun:dl_open_worker - fun:_dl_catch_error - fun:_dl_open - fun:dlopen_doit - fun:_dl_catch_error - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open -} -{ - - Memcheck:Addr4 - fun:_dl_signal_error - fun:_dl_map_object_deps - fun:dl_open_worker - fun:_dl_catch_error - fun:_dl_open - fun:dlopen_doit - fun:_dl_catch_error - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open -} - -{ - - Memcheck:Addr1 - fun:memcpy - fun:_dl_signal_error - fun:_dl_map_object_deps - fun:dl_open_worker - fun:_dl_catch_error - fun:_dl_open - fun:dlopen_doit - fun:_dl_catch_error - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open -} - -{ - - Memcheck:Addr2 - fun:memcpy - fun:_dl_signal_error - fun:_dl_map_object_deps - fun:dl_open_worker - fun:_dl_catch_error - fun:_dl_open - fun:dlopen_doit - fun:_dl_catch_error - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open -} -{ - - Memcheck:Addr4 - fun:memcpy - fun:_dl_signal_error - fun:_dl_map_object_deps - fun:dl_open_worker - fun:_dl_catch_error - fun:_dl_open - fun:dlopen_doit - fun:_dl_catch_error - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 - fun:g_module_open -} - -{ - - Memcheck:Addr8 - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/libc-2.3.*.so - obj:/lib/ld-2.3.*.so - fun:_dl_open - obj:/lib/libdl-2.3.*.so - obj:/lib/ld-2.3.*.so -} - -{ - - Memcheck:Cond - obj:/lib/ld-2.3.*.so - obj:/lib/libc-2.3.*.so - obj:/lib/ld-2.3.*.so - fun:_dl_open - obj:/lib/libdl-2.3.*.so - obj:/lib/ld-2.3.*.so - obj:/lib/libdl-2.3.*.so - fun:dlopen - fun:g_module_open - fun:gst_plugin_load_file - fun:gst_plugin_load_by_name - fun:gst_plugin_feature_load -} - -{ - - Memcheck:Addr4 - obj:/lib/ld-2.3.6.so - obj:/lib/ld-2.3.6.so - obj:/lib/tls/i686/cmov/libc-2.3.6.so - obj:/lib/ld-2.3.6.so - fun:_dl_open - obj:/lib/tls/i686/cmov/libdl-2.3.6.so - obj:/lib/ld-2.3.6.so - obj:/lib/tls/i686/cmov/libdl-2.3.6.so - fun:dlopen -} - -{ - - Memcheck:Cond - obj:/lib/ld-2.3.6.so - obj:/lib/tls/i686/cmov/libc-2.3.6.so - obj:/lib/ld-2.3.6.so - fun:_dl_open - obj:/lib/tls/i686/cmov/libdl-2.3.6.so - obj:/lib/ld-2.3.6.so - obj:/lib/tls/i686/cmov/libdl-2.3.6.so - fun:dlopen -} - -{ - - Memcheck:Cond - obj:/lib/ld-2.3.6.so - obj:/lib/ld-2.3.6.so - obj:/lib/ld-2.3.6.so - obj:/lib/tls/i686/cmov/libc-2.3.6.so - obj:/lib/ld-2.3.6.so - fun:_dl_open - obj:/lib/tls/i686/cmov/libdl-2.3.6.so - obj:/lib/ld-2.3.6.so - obj:/lib/tls/i686/cmov/libdl-2.3.6.so - fun:dlopen -} - -### glib suppressions -{ - - Memcheck:Cond - fun:g_parse_debug_string - obj:/usr/lib*/libglib-2.0.so.* - fun:g_slice_alloc - fun:g_slice_alloc0 -} - -{ - - Memcheck:Leak - fun:malloc - fun:g_malloc - fun:g_strdup - fun:g_quark_from_string - obj:* - obj:* - fun:g_type_register_fundamental - obj:* - fun:g_type_init_with_debug_flags - fun:g_type_init - fun:init_pre -} - -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - obj:* - obj:* - fun:g_type_register_fundamental -} - -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - obj:* - obj:* - fun:g_type_init_with_debug_flags -} - -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:g_slice_alloc - obj:* - obj:* - fun:g_type_init_with_debug_flags -} - -#pthread memleaks - -{ - Thread creation leak - Memcheck:Leak - fun:calloc - fun:allocate_dtv - fun:_dl_allocate* - fun:_dl_allocate* - fun:__pthread_initialize_minimal -} - -{ - Thread management leak - Memcheck:Leak - fun:calloc - fun:allocate_dtv - fun:_dl_allocate* - fun:_dl_allocate* - fun:__pthread_* -} - -{ - Thread management leak 2 - Memcheck:Leak - fun:memalign - fun:_dl_allocate* - fun:_dl_allocate* - fun:__pthread_* -} - -{ - pthread_create Syscall param write(buf) points to uninitialised byte(s) - Memcheck:Param - write(buf) - fun:pthread_create@@GLIBC_2.2.5 - fun:g_thread_create* - -} - -# nss_parse_* memleak (used by g_option_context_parse) -{ - nss_parse_* memleak - Memcheck:Leak - fun:malloc - fun:nss_parse_service_list - fun:__nss_database_lookup -} - -# liboil suppressions -{ - - Memcheck:Value8 - obj:/usr/lib/liboil-0.3.so.0.1.0 - obj:/usr/lib/liboil-0.3.so.0.1.0 - obj:/usr/lib/liboil-0.3.so.0.1.0 - fun:oil_cpu_fault_check_try - fun:oil_test_check_impl - fun:oil_class_optimize - fun:oil_optimize_all - fun:oil_init -} - -{ - - Memcheck:Addr8 - obj:/lib/ld-2.3.6.so -} - -{ - - Memcheck:Param - futex(uaddr2) - fun:pthread_once - obj:/lib/libc-2.3.6.so - obj:/lib/libc-2.3.6.so - fun:setlocale - fun:init_pre - fun:g_option_context_parse - fun:gst_init_check - fun:gst_init - fun:gst_check_init - fun:main -} - -{ - - Memcheck:Cond - obj:/lib/ld-2.3.6.so - obj:/lib/ld-2.3.6.so - fun:_dl_open - obj:/lib/libdl-2.3.6.so - obj:/lib/ld-2.3.6.so - obj:/lib/libdl-2.3.6.so - fun:dlopen - fun:g_module_open - fun:gst_plugin_load_file -} -# this exists in a bunch of different variations, hence the short tail/trace -{ - - Memcheck:Addr4 - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so -} -{ - - Memcheck:Addr8 - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so -} - -# More edgy suppressions (Mike) -{ - - Memcheck:Cond - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - fun:dlopen_doit - obj:/lib/ld-2.4.so - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 -} - -{ - - Memcheck:Cond - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - fun:dlopen_doit - obj:/lib/ld-2.4.so - fun:_dlerror_run - fun:dlopen@@GLIBC_2.1 -} - -{ - - Memcheck:Cond - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - fun:do_sym - fun:_dl_sym -} - -# This one's overly general, but there's zero other information in the stack -# trace - just these five lines! -{ - - Memcheck:Cond - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so - obj:/lib/ld-2.4.so -} - -{ - - Memcheck:Leak - fun:calloc - obj:/lib/ld-2.4.so - fun:_dl_allocate_tls - fun:pthread_create@@GLIBC_2.1 -} - -# TLS leaks for feisty/x86 -{ - - Memcheck:Leak - fun:calloc - fun:allocate_dtv - fun:_dl_allocate_tls - fun:pthread_create@@GLIBC_2.1 -} - -{ - - Memcheck:Leak - fun:calloc - obj:/usr/lib/libcdio.so.6.0.1 - fun:cdio_open_am_linux - obj:/usr/lib/libcdio.so.6.0.1 - fun:cdio_open_am -} - -{ - - Memcheck:Addr8 - obj:/lib/ld-2.5.so -} - -{ - - Memcheck:Cond - fun:snd_pcm_direct_shm_create_or_connect - fun:snd_pcm_dsnoop_open - fun:_snd_pcm_dsnoop_open - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_pcm_open_slave - fun:_snd_pcm_plug_open - obj:/*lib/libasound.so.2.0.0 - fun:snd_pcm_open_slave - fun:_snd_pcm_asym_open - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 -} - -{ - - Memcheck:Cond - fun:snd_pcm_hw_param_set_near - fun:set_hwparams -} - -{ - - Memcheck:Cond - fun:_snd_pcm_hw_param_set_min - fun:snd_pcm_hw_param_set_min - fun:snd_pcm_hw_param_set_near - fun:set_hwparams -} - -{ - - Memcheck:Cond - fun:_snd_pcm_hw_param_set_min - fun:snd_pcm_hw_param_set_min - fun:snd_pcm_hw_param_set_near - fun:set_hwparams -} - -{ - - Memcheck:Cond - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_pcm_hw_param_set_near - fun:set_hwparams -} -{ - - Memcheck:Cond - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_pcm_close - obj:/*lib/libasound.so.2.0.0 -} -{ - - Memcheck:Cond - fun:snd_pcm_direct_shm_create_or_connect - fun:snd_pcm_dmix_open - fun:_snd_pcm_dmix_open - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_pcm_open_slave - fun:_snd_pcm_softvol_open - obj:/*lib/libasound.so.2.0.0 - fun:snd_pcm_open_slave - fun:_snd_pcm_plug_open - obj:/*lib/libasound.so.2.0.0 - fun:snd_pcm_open_slave - fun:_snd_pcm_asym_open - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 -} -{ - - Memcheck:Leak - fun:malloc - fun:strdup - fun:snd_dlobj_cache_add - obj:/*lib/libasound.so.2.0.0 - fun:snd_pcm_open_slave - fun:snd_pcm_dsnoop_open - fun:_snd_pcm_dsnoop_open - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_pcm_open_slave - fun:_snd_pcm_plug_open - obj:/*lib/libasound.so.2.0.0 - fun:snd_pcm_open_slave - fun:_snd_pcm_asym_open - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 -} -# Catch about 15 variations on inserting info into an ALSA -# internal cache -{ - - Memcheck:Leak - fun:malloc - fun:snd_dlobj_cache_add - obj:/*lib/libasound.so.2.0.0 -} -{ - - Memcheck:Leak - fun:malloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks -} -{ - - Memcheck:Leak - fun:malloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - fun:snd_config_hook_load_for_all_cards - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks - fun:snd_config_search_alias_hooks - fun:snd_config_search_definition -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - fun:snd_config_hook_load_for_all_cards - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks - fun:snd_config_search_alias_hooks - fun:snd_config_search_definition -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks - fun:snd_config_search_alias_hooks - fun:snd_config_search_definition -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_update_r - fun:snd_config_update -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_update_r - fun:snd_config_update -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_update_r - fun:snd_config_update -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_update_r - fun:snd_config_update -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_update_r - fun:snd_config_update -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_update_r - fun:snd_config_update -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_update_r - fun:snd_config_update -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_update_r - fun:snd_config_update -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_update_r - fun:snd_config_update -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_update_r - fun:snd_config_update -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks - fun:snd_config_search_alias_hooks - fun:snd_config_search_definition - obj:/*lib/libasound.so.2.0.0 -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks - fun:snd_config_search_alias_hooks - fun:snd_config_search_definition - obj:/*lib/libasound.so.2.0.0 -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - fun:snd_config_hook_load_for_all_cards - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks - fun:snd_config_search_alias_hooks - fun:snd_config_search_definition - obj:/*lib/libasound.so.2.0.0 -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - fun:snd_config_hook_load_for_all_cards - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks - fun:snd_config_search_alias_hooks - fun:snd_config_search_definition - obj:/*lib/libasound.so.2.0.0 -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - fun:snd_config_hook_load_for_all_cards - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks - fun:snd_config_search_alias_hooks - fun:snd_config_search_definition - obj:/*lib/libasound.so.2.0.0 -} -{ - - Memcheck:Leak - fun:calloc - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_hook_load - fun:snd_config_hook_load_for_all_cards - obj:/*lib/libasound.so.2.0.0 - fun:snd_config_searcha_hooks - fun:snd_config_search_alias_hooks - fun:snd_config_search_definition - obj:/*lib/libasound.so.2.0.0 -} -{ - - Memcheck:Leak - fun:malloc - obj:/lib/libc*.so - fun:__nss_database_lookup - obj:* - obj:* - fun:getgrnam_r - fun:getgrnam - fun:snd_pcm_direct_parse_open_conf -} - -{ - - Memcheck:Leak - fun:calloc - fun:_XCBInitDisplayLock - fun:XOpenDisplay -} - -# GConf internal initialisations related to getting the default client. -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc_tcval - obj:/usr/lib/libORBit-2.so.* - fun:ORBit_demarshal_IOR - fun:ORBit_demarshal_object - fun:CORBA_ORB_string_to_object - obj:/usr/lib/libgconf-2.so.* - fun:gconf_get_current_lock_holder - fun:gconf_activate_server - obj:/usr/lib/libgconf-2.so.* - obj:/usr/lib/libgconf-2.so.* - fun:gconf_engine_get_default -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc_tcval - obj:/usr/lib/libORBit-2.so.* - fun:PortableServer_POA_servant_to_reference - obj:/usr/lib/libgconf-2.so.* - obj:/usr/lib/libgconf-2.so.* - obj:/usr/lib/libgconf-2.so.* - fun:gconf_engine_get_default -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc_tcval - obj:/usr/lib/libORBit-2.so.* - fun:ORBit_demarshal_IOR - fun:ORBit_demarshal_object - fun:CORBA_ORB_string_to_object - obj:/usr/lib/libgconf-2.so.* - fun:gconf_get_current_lock_holder - fun:gconf_activate_server - obj:/usr/lib/libgconf-2.so.* - obj:/usr/lib/libgconf-2.so.* - fun:gconf_engine_get_default -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc* - obj:/usr/lib/libORBit-2.so.* - fun:ORBit_demarshal_IOR - fun:ORBit_demarshal_object - fun:ORBit_demarshal_value - obj:/usr/lib/libORBit-2.so.* - fun:ORBit_small_invoke_stub - fun:ConfigServer_get_default_database - obj:/usr/lib/libgconf-2.so.* - fun:gconf_engine_get_default -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc* - obj:/usr/lib/libORBit-2.so.* - fun:IOP_generate_profiles - fun:ORBit_marshal_object - fun:ORBit_marshal_value - obj:/usr/lib/libORBit-2.so.* - fun:ORBit_small_invoke_stub - fun:ConfigServer_add_client - obj:/usr/lib/libgconf-2.so.* - obj:/usr/lib/libgconf-2.so.* - fun:gconf_engine_get_default -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc_by_tc - obj:/usr/lib/libORBit-2.so.* - fun:PortableServer_POA_servant_to_reference - obj:/usr/lib/libgconf-2.so.* - obj:/usr/lib/libgconf-2.so.* - obj:/usr/lib/libgconf-2.so.* - fun:gconf_engine_get_default -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc_by_tc - obj:/usr/lib/libORBit-2.so.* - fun:ORBit_demarshal_IOR - fun:ORBit_demarshal_object - fun:CORBA_ORB_string_to_object - obj:/usr/lib/libgconf-2.so.* - fun:gconf_get_current_lock_holder - fun:gconf_activate_server - obj:/usr/lib/libgconf-2.so.* - obj:/usr/lib/libgconf-2.so.* - fun:gconf_engine_get_default -} - -# Some libORBit/bonobo initialisation stuff -{ - - Memcheck:Leak - fun:malloc - fun:g_malloc - fun:ORBit_alloc_string - fun:CORBA_string_dup - fun:Bonobo_ActivationEnvValue_set - fun:bonobo_activation_init_activation_env - fun:bonobo_activation_orb_init - fun:bonobo_activation_init -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc* - fun:ORBit_small_alloc* - obj:/usr/lib/libORBit-2.so* - fun:PortableServer_POA_servant_to_reference - obj:/usr/lib/libbonobo-2.so* -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc_tcval - fun:ORBit_small_allocbuf - fun:ORBit_adaptor_setup - obj:/usr/lib/libORBit-2.so* - fun:ORBit_POA_setup_root - fun:ORBit_init_internals - fun:CORBA_ORB_init -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc_tcval - fun:ORBit_adaptor_setup - obj:/usr/lib/libORBit-2.so* - fun:ORBit_POA_setup_root - fun:ORBit_init_internals - fun:CORBA_ORB_init -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc* - fun:ORBit_small_allocbuf - fun:bonobo_activation_init_activation_env - fun:bonobo_activation_orb_init - fun:bonobo_activation_init -} - -# More GConf stuff from the FC5 buildbot, mostly variations on the -# above stack traces -{ - - Memcheck:Param - writev(vector[...]) - fun:writev - obj:/usr/lib/libORBit-2.so* - fun:link_connection_writev - fun:giop_send_buffer_write - obj:/usr/lib/libORBit-2.so* - fun:ORBit_small_invoke_stub - fun:ORBit_small_invoke_stub_n - fun:ORBit_c_stub_invoke - fun:ConfigServer_ping - fun:gconf_activate_server - obj:/usr/lib/libgconf-2.so* - obj:/usr/lib/libgconf-2.so* - fun:gconf_engine_get_default -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc* - fun:ORBit_small_alloc* - obj:/usr/lib/libORBit-2.so* - fun:PortableServer_POA_servant_to_reference - obj:/usr/lib/libgconf-2.so* - obj:/usr/lib/libgconf-2.so* - obj:/usr/lib/libgconf-2.so* - fun:gconf_engine_get_default -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc* - fun:ORBit_small_alloc - obj:/usr/lib/libORBit-2.so* - fun:ORBit_demarshal_IOR - fun:ORBit_demarshal_object - fun:CORBA_ORB_string_to_object - obj:/usr/lib/libgconf-2.so* - fun:gconf_get_current_lock_holder - fun:gconf_activate_server - obj:/usr/lib/libgconf-2.so* - obj:/usr/lib/libgconf-2.so* - fun:gconf_engine_get_default -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc* - fun:ORBit_small_alloc* - obj:/usr/lib/libORBit-2.so* - fun:ORBit_demarshal_IOR - fun:ORBit_demarshal_object - fun:CORBA_ORB_string_to_object - obj:/usr/lib/libgconf-2.so* - fun:gconf_get_current_lock_holder - fun:gconf_activate_server - obj:/usr/lib/libgconf-2.so* - obj:/usr/lib/libgconf-2.so* - fun:gconf_engine_get_default -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc* - fun:ORBit_small_alloc* - obj:/usr/lib/libORBit-2.so* - fun:ORBit_demarshal_IOR - fun:ORBit_demarshal_object - fun:ORBit_demarshal_value - obj:/usr/lib/libORBit-2.so* - fun:ORBit_small_invoke_stub - fun:ORBit_small_invoke_stub_n - fun:ORBit_c_stub_invoke - fun:ConfigServer_get_default_database - obj:/usr/lib/libgconf-2.so* - fun:gconf_engine_get_default -} -{ - - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:ORBit_alloc* - fun:ORBit_small_alloc* - obj:/usr/lib/libORBit-2.so* - fun:ORBit_OAObject_object_to_objkey - fun:IOP_generate_profiles - fun:ORBit_marshal_object - fun:ORBit_marshal_value - obj:/usr/lib/libORBit-2.so* - fun:ORBit_small_invoke_stub - fun:ORBit_small_invoke_stub_n - fun:ORBit_c_stub_invoke - fun:ConfigServer_add_client - obj:/usr/lib/libgconf-2.so* - obj:/usr/lib/libgconf-2.so* - fun:gconf_engine_get_default -} -{ - - Memcheck:Leak - fun:malloc - obj:/lib/libc-*.so - fun:__nss_database_lookup - obj:* - obj:* - fun:getpwnam_r - fun:g_get_any_init_do - fun:g_get_home_dir -} -{ - - Memcheck:Leak - fun:malloc - obj:/lib/libc-*.so - fun:__nss_database_lookup - obj:* - obj:* - fun:getpwnam_r - fun:g_get_any_init_do - fun:g_get_user_name -} -{ - - Memcheck:Leak - fun:malloc - obj:/lib/libc-*.so - fun:__nss_database_lookup - obj:* - obj:* - fun:getpwnam_r - obj:/usr/lib*/libglib-2.0.so.* - fun:g_get_tmp_dir -} - - -## Some Fontconfig errors. -{ - - Memcheck:Leak - fun:malloc - fun:FcPatternObjectInsertElt - fun:FcPatternObjectAddWithBinding - fun:FcPatternAppend - fun:FcEndElement - obj:/usr/lib/libexpat.so.1.0.0 - obj:/usr/lib/libexpat.so.1.0.0 - obj:/usr/lib/libexpat.so.1.0.0 - obj:/usr/lib/libexpat.so.1.0.0 - fun:XML_ParseBuffer - fun:FcConfigParseAndLoad - fun:FcConfigParseAndLoad - fun:FcParseInclude - fun:FcEndElement - obj:/usr/lib/libexpat.so.1.0.0 - obj:/usr/lib/libexpat.so.1.0.0 - obj:/usr/lib/libexpat.so.1.0.0 - obj:/usr/lib/libexpat.so.1.0.0 - fun:XML_ParseBuffer - fun:FcConfigParseAndLoad -} -{ - - Memcheck:Leak - fun:malloc - fun:FcStrCopy - fun:FcEndElement - obj:/usr/lib/libexpat.so.1.0.0 - obj:/usr/lib/libexpat.so.1.0.0 - obj:/usr/lib/libexpat.so.1.0.0 - obj:/usr/lib/libexpat.so.1.0.0 - fun:XML_ParseBuffer - fun:FcConfigParseAndLoad - fun:FcConfigParseAndLoad - fun:FcParseInclude - fun:FcEndElement - obj:/usr/lib/libexpat.so.1.0.0 - obj:/usr/lib/libexpat.so.1.0.0 - obj:/usr/lib/libexpat.so.1.0.0 - obj:/usr/lib/libexpat.so.1.0.0 - fun:XML_ParseBuffer - fun:FcConfigParseAndLoad - fun:FcInitLoadConfig - fun:FcInitLoadConfigAndFonts -} - diff --git a/common/gstdoc-scangobj b/common/gstdoc-scangobj deleted file mode 100755 index 0ff1b54960..0000000000 --- a/common/gstdoc-scangobj +++ /dev/null @@ -1,1562 +0,0 @@ -#!/usr/bin/perl -w -# -*- cperl -*- -# -# gtk-doc - GTK DocBook documentation generator. -# Copyright (C) 1998 Damon Chaplin -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# - -# -# This gets information about object heirarchies and signals -# by compiling a small C program. CFLAGS and LDFLAGS must be -# set appropriately before running this script. -# -# NOTE: the lookup_signal_arg_names() function contains the argument names of -# standard GTK signal handlers. This may need to be updated for new -# GTK signals or Gnome widget signals. - -use Getopt::Long; - -unshift @INC, '/usr/share/gtk-doc/data'; -require "gtkdoc-common.pl"; - -# Options - -# name of documentation module -my $MODULE; -my $OUTPUT_DIR; -my $PRINT_VERSION; -my $PRINT_HELP; -my $TYPE_INIT_FUNC="g_type_init ()"; - -# --nogtkinit is deprecated, as it is the default now anyway. -%optctl = (module => \$MODULE, - source => \$SOURCE, - types => \$TYPES_FILE, - nogtkinit => \$NO_GTK_INIT, - 'type-init-func' => \$TYPE_INIT_FUNC, - 'output-dir' => \$OUTPUT_DIR, - 'version' => \$PRINT_VERSION, - 'help' => \$PRINT_HELP); - -GetOptions(\%optctl, "module=s", "source=s", "types:s", "output-dir:s", "nogtkinit", "type-init-func:s", "version", "help"); - -if ($NO_GTK_INIT) { - # Do nothing. This just avoids a warning. -} - -if ($PRINT_VERSION) { - print "1.5\n"; - exit 0; -} - -if (!$MODULE) { - $PRINT_HELP = 1; -} - -if ($PRINT_HELP) { - print "gstdoc-scangobj version 1.5\n"; - print "\n--module=MODULE_NAME Name of the doc module being parsed"; - print "\n--source=SOURCE_NAME Name of the source module for plugins"; - print "\n--types=FILE The name of the file to store the types in"; - print "\n--type-init-func=FUNC The init function to call instead of g_type_init ()"; - print "\n--output-dir=DIRNAME The directory where the results are stored"; - print "\n--version Print the version of this program"; - print "\n--help Print this help\n"; - exit 0; -} - -$OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : "."; - -# THOMAS: dynamic types; only use types file for headers - $TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types"; - -open (TYPES, $TYPES_FILE) || die "Cannot open $TYPES_FILE: $!\n"; -open (OUTPUT, ">$MODULE-scan.c") || die "Cannot open $MODULE-scan.c: $!\n"; - -my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals"; -my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new"; -my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy"; -my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new"; -my $old_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces"; -my $new_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces.new"; -my $old_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites"; -my $new_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites.new"; -my $old_args_filename = "$OUTPUT_DIR/$MODULE.args"; -my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new"; - -# write a C program to scan the types - -$includes = ""; -#@types = (); - -for () { - if (/^#include/) { - $includes .= $_; -# } elsif (/^%/) { -# next; -# } elsif (/^\s*$/) { -# next; -# } else { -# chomp; -# push @types, $_; - } -} - -#$ntypes = @types + 1; - -print OUTPUT < -#include -#include -#include - -$includes -#ifdef GTK_IS_WIDGET_CLASS -#include -#endif -GType *object_types = NULL; - -static GType * -get_object_types (void) -{ - GList *plugins = NULL; - GList *factories = NULL; - GList *l; - GstElementFactory *factory = NULL; - - gint i = 0; - - /* get a list of features from plugins in our source module */ - plugins = gst_registry_get_plugin_list (gst_registry_get_default()); - - while (plugins) { - GList *features; - GstPlugin *plugin; - const gchar *source; - - plugin = (GstPlugin *) (plugins->data); - plugins = g_list_next (plugins); - source = gst_plugin_get_source (plugin); - g_print ("source: %s\\n", source); - if (!source || strcmp (gst_plugin_get_source (plugin), "$SOURCE") != 0) { - continue; - } - - features = - gst_registry_get_feature_list_by_plugin (gst_registry_get_default (), - plugin->desc.name); - while (features) { - GstPluginFeature *feature; - feature = GST_PLUGIN_FEATURE (features->data); - feature = gst_plugin_feature_load (feature); - if (!feature) { - g_warning ("Could not load plugin feature %s", - gst_plugin_feature_get_name (feature)); - } - - if (GST_IS_ELEMENT_FACTORY (feature)) { - factory = GST_ELEMENT_FACTORY (feature); - factories = g_list_append (factories, factory); - } - features = g_list_next (features); - } - } - - g_message ("number of element factories: %d", g_list_length (factories)); - - /* allocate the object_types array to hold them */ - object_types = g_new0 (GType, g_list_length (factories)+1); - - l = factories; - i = 0; - - /* fill it */ - while (l) { - GType type; - factory = GST_ELEMENT_FACTORY (l->data); - g_message ("adding type for factory %s", gst_element_factory_get_longname (factory)); - type = gst_element_factory_get_element_type (factory); - g_message ("adding type %p", (void *) type); - object_types[i] = type; - i++; - l = g_list_next (l); - } - object_types[i] = 0; -EOT - -print OUTPUT <\\n%s::%s\\n%s\\n%s\\n%s\\n\\n", - object_name, query_info.signal_name, ret_type_buffer, flags, buffer); -} - - -/* Returns the type name to use for a signal argument or return value, given - the GtkType from the signal info. It also sets is_pointer to TRUE if the - argument needs a '*' since it is a pointer. */ -static const gchar * -get_type_name (GType type, gboolean * is_pointer) -{ - const gchar *type_name; - - *is_pointer = FALSE; - type_name = g_type_name (type); - - switch (type) { - case G_TYPE_NONE: - case G_TYPE_CHAR: - case G_TYPE_UCHAR: - case G_TYPE_BOOLEAN: - case G_TYPE_INT: - case G_TYPE_UINT: - case G_TYPE_LONG: - case G_TYPE_ULONG: - case G_TYPE_FLOAT: - case G_TYPE_DOUBLE: - case G_TYPE_POINTER: - /* These all have normal C type names so they are OK. */ - return type_name; - - case G_TYPE_STRING: - /* A GtkString is really a gchar*. */ - *is_pointer = TRUE; - return "gchar"; - - case G_TYPE_ENUM: - case G_TYPE_FLAGS: - /* We use a gint for both of these. Hopefully a subtype with a decent - name will be registered and used instead, as GTK+ does itself. */ - return "gint"; - - case G_TYPE_BOXED: - /* The boxed type shouldn't be used itself, only subtypes. Though we - return 'gpointer' just in case. */ - return "gpointer"; - - case G_TYPE_PARAM: - /* A GParam is really a GParamSpec*. */ - *is_pointer = TRUE; - return "GParamSpec"; - - default: - break; - } - - /* For all GObject subclasses we can use the class name with a "*", - e.g. 'GtkWidget *'. */ - if (g_type_is_a (type, G_TYPE_OBJECT)) - *is_pointer = TRUE; - - if (G_TYPE_IS_CLASSED (type)) - *is_pointer = TRUE; - - /* All boxed subtypes will be pointers as well. */ - if (g_type_is_a (type, G_TYPE_BOXED)) - *is_pointer = TRUE; - - /* All pointer subtypes will be pointers as well. */ - if (g_type_is_a (type, G_TYPE_POINTER)) - *is_pointer = TRUE; - - return type_name; -} - - -static const gchar * -get_gdk_event (const gchar * signal_name) -{ - static const gchar *GbGDKEvents[] = - { - "button_press_event", "GdkEventButton", - "button_release_event", "GdkEventButton", - "motion_notify_event", "GdkEventMotion", - "delete_event", "GdkEvent", - "destroy_event", "GdkEvent", - "expose_event", "GdkEventExpose", - "key_press_event", "GdkEventKey", - "key_release_event", "GdkEventKey", - "enter_notify_event", "GdkEventCrossing", - "leave_notify_event", "GdkEventCrossing", - "configure_event", "GdkEventConfigure", - "focus_in_event", "GdkEventFocus", - "focus_out_event", "GdkEventFocus", - "map_event", "GdkEvent", - "unmap_event", "GdkEvent", - "property_notify_event", "GdkEventProperty", - "selection_clear_event", "GdkEventSelection", - "selection_request_event", "GdkEventSelection", - "selection_notify_event", "GdkEventSelection", - "proximity_in_event", "GdkEventProximity", - "proximity_out_event", "GdkEventProximity", - "drag_begin_event", "GdkEventDragBegin", - "drag_request_event", "GdkEventDragRequest", - "drag_end_event", "GdkEventDragRequest", - "drop_enter_event", "GdkEventDropEnter", - "drop_leave_event", "GdkEventDropLeave", - "drop_data_available_event", "GdkEventDropDataAvailable", - "other_event", "GdkEventOther", - "client_event", "GdkEventClient", - "no_expose_event", "GdkEventNoExpose", - "visibility_notify_event", "GdkEventVisibility", - "window_state_event", "GdkEventWindowState", - "scroll_event", "GdkEventScroll", - NULL - }; - - gint i; - - for (i = 0; GbGDKEvents[i]; i += 2) - { - if (!strcmp (signal_name, GbGDKEvents[i])) - return GbGDKEvents[i + 1]; - } - return "GdkEvent"; -} - - -/* This returns argument names to use for some known GTK signals. - It is passed a widget name, e.g. 'GtkCList' and a signal name, e.g. - 'select_row' and it returns a pointer to an array of argument types and - names. */ -static const gchar ** -lookup_signal_arg_names (const gchar * type, const gchar * signal_name) -{ - /* Each arg array starts with the object type name and the signal name, - and then signal arguments follow. */ - static const gchar *GbArgTable[][16] = - { - {"GtkCList", "select_row", - "gint row", - "gint column", - "GdkEventButton *event"}, - {"GtkCList", "unselect_row", - "gint row", - "gint column", - "GdkEventButton *event"}, - {"GtkCList", "click_column", - "gint column"}, - - {"GtkCList", "resize_column", - "gint column", - "gint width"}, - - {"GtkCList", "extend_selection", - "GtkScrollType scroll_type", - "gfloat position", - "gboolean auto_start_selection"}, - {"GtkCList", "scroll_vertical", - "GtkScrollType scroll_type", - "gfloat position"}, - {"GtkCList", "scroll_horizontal", - "GtkScrollType scroll_type", - "gfloat position"}, - - {"GtkCTree", "tree_select_row", - "GtkCTreeNode *node", - "gint column"}, - {"GtkCTree", "tree_unselect_row", - "GtkCTreeNode *node", - "gint column"}, - {"GtkCTree", "tree_expand", - "GtkCTreeNode *node"}, - {"GtkCTree", "tree_collapse", - "GtkCTreeNode *node"}, - {"GtkCTree", "tree_move", - "GtkCTreeNode *node", - "GtkCTreeNode *new_parent", - "GtkCTreeNode *new_sibling"}, - {"GtkCTree", "change_focus_row_expansion", - "GtkCTreeExpansionType expansion"}, - - {"GtkEditable", "insert_text", - "gchar *new_text", - "gint new_text_length", - "gint *position"}, - {"GtkEditable", "delete_text", - "gint start_pos", - "gint end_pos"}, - {"GtkEditable", "set_editable", - "gboolean is_editable"}, - {"GtkEditable", "move_cursor", - "gint x", - "gint y"}, - {"GtkEditable", "move_word", - "gint num_words"}, - {"GtkEditable", "move_page", - "gint x", - "gint y"}, - {"GtkEditable", "move_to_row", - "gint row"}, - {"GtkEditable", "move_to_column", - "gint column"}, - - {"GtkEditable", "kill_char", - "gint direction"}, - {"GtkEditable", "kill_word", - "gint direction"}, - {"GtkEditable", "kill_line", - "gint direction"}, - - - {"GtkInputDialog", "enable_device", - "GdkDevice *deviceid"}, - {"GtkInputDialog", "disable_device", - "GdkDevice *deviceid"}, - - {"GtkListItem", "extend_selection", - "GtkScrollType scroll_type", - "gfloat position", - "gboolean auto_start_selection"}, - {"GtkListItem", "scroll_vertical", - "GtkScrollType scroll_type", - "gfloat position"}, - {"GtkListItem", "scroll_horizontal", - "GtkScrollType scroll_type", - "gfloat position"}, - - {"GtkMenuShell", "move_current", - "GtkMenuDirectionType direction"}, - {"GtkMenuShell", "activate_current", - "gboolean force_hide"}, - - - {"GtkNotebook", "switch_page", - "GtkNotebookPage *page", - "guint page_num"}, - {"GtkStatusbar", "text_pushed", - "guint context_id", - "gchar *text"}, - {"GtkStatusbar", "text_popped", - "guint context_id", - "gchar *text"}, - {"GtkTipsQuery", "widget_entered", - "GtkWidget *widget", - "gchar *tip_text", - "gchar *tip_private"}, - {"GtkTipsQuery", "widget_selected", - "GtkWidget *widget", - "gchar *tip_text", - "gchar *tip_private", - "GdkEventButton *event"}, - {"GtkToolbar", "orientation_changed", - "GtkOrientation orientation"}, - {"GtkToolbar", "style_changed", - "GtkToolbarStyle style"}, - {"GtkWidget", "draw", - "GdkRectangle *area"}, - {"GtkWidget", "size_request", - "GtkRequisition *requisition"}, - {"GtkWidget", "size_allocate", - "GtkAllocation *allocation"}, - {"GtkWidget", "state_changed", - "GtkStateType state"}, - {"GtkWidget", "style_set", - "GtkStyle *previous_style"}, - - {"GtkWidget", "install_accelerator", - "gchar *signal_name", - "gchar key", - "gint modifiers"}, - - {"GtkWidget", "add_accelerator", - "guint accel_signal_id", - "GtkAccelGroup *accel_group", - "guint accel_key", - "GdkModifierType accel_mods", - "GtkAccelFlags accel_flags"}, - - {"GtkWidget", "parent_set", - "GtkObject *old_parent"}, - - {"GtkWidget", "remove_accelerator", - "GtkAccelGroup *accel_group", - "guint accel_key", - "GdkModifierType accel_mods"}, - {"GtkWidget", "debug_msg", - "gchar *message"}, - {"GtkWindow", "move_resize", - "gint *x", - "gint *y", - "gint width", - "gint height"}, - {"GtkWindow", "set_focus", - "GtkWidget *widget"}, - - {"GtkWidget", "selection_get", - "GtkSelectionData *data", - "guint info", - "guint time"}, - {"GtkWidget", "selection_received", - "GtkSelectionData *data", - "guint time"}, - - {"GtkWidget", "drag_begin", - "GdkDragContext *drag_context"}, - {"GtkWidget", "drag_end", - "GdkDragContext *drag_context"}, - {"GtkWidget", "drag_data_delete", - "GdkDragContext *drag_context"}, - {"GtkWidget", "drag_leave", - "GdkDragContext *drag_context", - "guint time"}, - {"GtkWidget", "drag_motion", - "GdkDragContext *drag_context", - "gint x", - "gint y", - "guint time"}, - {"GtkWidget", "drag_drop", - "GdkDragContext *drag_context", - "gint x", - "gint y", - "guint time"}, - {"GtkWidget", "drag_data_get", - "GdkDragContext *drag_context", - "GtkSelectionData *data", - "guint info", - "guint time"}, - {"GtkWidget", "drag_data_received", - "GdkDragContext *drag_context", - "gint x", - "gint y", - "GtkSelectionData *data", - "guint info", - "guint time"}, - - {NULL} - }; - - gint i; - - for (i = 0; GbArgTable[i][0]; i++) - { -#if 1 - if (!strcmp (type, GbArgTable[i][0]) - && !strcmp (signal_name, GbArgTable[i][1])) - return &GbArgTable[i][2]; -#endif - } - return NULL; -} - -/* This outputs the hierarchy of all objects which have been initialized, - i.e. by calling their XXX_get_type() initialization function. */ -static void -output_object_hierarchy (void) -{ - FILE *fp; - gint i; - - fp = fopen (hierarchy_filename, "w"); - if (fp == NULL) - { - g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, strerror(errno)); - return; - } - output_hierarchy (fp, G_TYPE_OBJECT, 0); - output_hierarchy (fp, G_TYPE_INTERFACE, 0); - - for (i=0; object_types[i]; i++) { - if (!g_type_parent (object_types[i]) && - (object_types[i] != G_TYPE_OBJECT) && - (object_types[i] != G_TYPE_INTERFACE) - ) { - output_hierarchy (fp, object_types[i], 0); - } - } - - fclose (fp); -} - -/* This is called recursively to output the hierarchy of a widget. */ -static void -output_hierarchy (FILE *fp, - GType type, - guint level) -{ - guint i; - GType *children; - guint n_children; - - if (!type) - return; - - for (i = 0; i < level; i++) - fprintf (fp, " "); - fprintf (fp, g_type_name (type)); - fprintf (fp, "\\n"); - - children = g_type_children (type, &n_children); - - for (i=0; i < n_children; i++) - output_hierarchy (fp, children[i], level + 1); - - g_free (children); -} - -static void output_object_interfaces (void) -{ - FILE *fp; - - fp = fopen (interfaces_filename, "w"); - if (fp == NULL) - { - g_warning ("Couldn't open output file: %s : %s", interfaces_filename, strerror(errno)); - return; - } - output_interfaces (fp, G_TYPE_OBJECT); - fclose (fp); -} - -static void -output_interfaces (FILE *fp, - GType type) -{ - guint i; - GType *children, *interfaces; - guint n_children, n_interfaces; - - if (!type) - return; - - interfaces = g_type_interfaces (type, &n_interfaces); - - if (n_interfaces > 0) - { - fprintf (fp, g_type_name (type)); - for (i=0; i < n_interfaces; i++) - fprintf (fp, " %s", g_type_name (interfaces[i])); - fprintf (fp, "\\n"); - } - g_free (interfaces); - - children = g_type_children (type, &n_children); - - for (i=0; i < n_children; i++) - output_interfaces (fp, children[i]); - - g_free (children); -} - -static void output_interface_prerequisites (void) -{ - FILE *fp; - - fp = fopen (prerequisites_filename, "w"); - if (fp == NULL) - { - g_warning ("Couldn't open output file: %s : %s", prerequisites_filename, strerror(errno)); - return; - } - output_prerequisites (fp, G_TYPE_INTERFACE); - fclose (fp); -} - -static void -output_prerequisites (FILE *fp, - GType type) -{ -#if GLIB_CHECK_VERSION(2,1,0) - guint i; - GType *children, *prerequisites; - guint n_children, n_prerequisites; - - if (!type) - return; - - prerequisites = g_type_interface_prerequisites (type, &n_prerequisites); - - if (n_prerequisites > 0) - { - fprintf (fp, g_type_name (type)); - for (i=0; i < n_prerequisites; i++) - fprintf (fp, " %s", g_type_name (prerequisites[i])); - fprintf (fp, "\\n"); - } - g_free (prerequisites); - - children = g_type_children (type, &n_children); - - for (i=0; i < n_children; i++) - output_prerequisites (fp, children[i]); - - g_free (children); -#endif -} - -static void -output_args (void) -{ - FILE *fp; - gint i; - - fp = fopen (args_filename, "w"); - if (fp == NULL) - { - g_warning ("Couldn't open output file: %s : %s", args_filename, strerror(errno)); - return; - } - - for (i = 0; object_types[i]; i++) { - output_object_args (fp, object_types[i]); - } - - fclose (fp); -} - -static gint -compare_param_specs (const void *a, const void *b) -{ - GParamSpec *spec_a = *(GParamSpec **)a; - GParamSpec *spec_b = *(GParamSpec **)b; - - return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b)); -} - -/* Its common to have unsigned properties restricted - * to the signed range. Therefore we make this look - * a bit nicer by spelling out the max constants. - */ - -/* Don't use "==" with floats, it might trigger a gcc warning. */ -#define GTKDOC_COMPARE_FLOAT(x, y) (x <= y && x >= y) - -static gchar* -describe_double_constant (gdouble value) -{ - gchar *desc; - - if (GTKDOC_COMPARE_FLOAT (value, G_MAXDOUBLE)) - desc = g_strdup ("G_MAXDOUBLE"); - else if (GTKDOC_COMPARE_FLOAT (value, G_MINDOUBLE)) - desc = g_strdup ("G_MINDOUBLE"); - else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXDOUBLE)) - desc = g_strdup ("-G_MAXDOUBLE"); - else if (GTKDOC_COMPARE_FLOAT (value, G_MAXFLOAT)) - desc = g_strdup ("G_MAXFLOAT"); - else if (GTKDOC_COMPARE_FLOAT (value, G_MINFLOAT)) - desc = g_strdup ("G_MINFLOAT"); - else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXFLOAT)) - desc = g_strdup ("-G_MAXFLOAT"); - else - desc = g_strdup_printf ("%lg", value); - - return desc; -} - -static gchar* -describe_signed_constant (gint64 value) -{ - gchar *desc; - - if (value == G_MAXINT) - desc = g_strdup ("G_MAXINT"); - else if (value == G_MININT) - desc = g_strdup ("G_MININT"); - else if (value == G_MAXUINT) - desc = g_strdup ("G_MAXUINT"); - else if (value == G_MAXLONG) - desc = g_strdup ("G_MAXLONG"); - else if (value == G_MINLONG) - desc = g_strdup ("G_MINLONG"); - else if (value == G_MAXULONG) - desc = g_strdup ("G_MAXULONG"); - else if (value == G_MAXINT64) - desc = g_strdup ("G_MAXINT64"); - else if (value == G_MININT64) - desc = g_strdup ("G_MININT64"); - else - desc = g_strdup_printf ("%" G_GINT64_FORMAT, value); - - return desc; -} - -static gchar* -describe_unsigned_constant (guint64 value) -{ - gchar *desc; - - if (value == G_MAXINT) - desc = g_strdup ("G_MAXINT"); - else if (value == G_MININT) - desc = g_strdup ("G_MININT"); - else if (value == G_MAXUINT) - desc = g_strdup ("G_MAXUINT"); - else if (value == G_MAXLONG) - desc = g_strdup ("G_MAXLONG"); - else if (value == G_MINLONG) - desc = g_strdup ("G_MINLONG"); - else if (value == G_MAXULONG) - desc = g_strdup ("G_MAXULONG"); - else if (value == G_MAXINT64) - desc = g_strdup ("G_MAXINT64"); - else if (value == G_MININT64) - desc = g_strdup ("G_MININT64"); - else if (value == G_MAXUINT64) - desc = g_strdup ("G_MAXUINT64"); - else - desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value); - - return desc; -} - -static gchar* -describe_type (GParamSpec *spec) -{ - gchar *desc; - gchar *lower; - gchar *upper; - - if (G_IS_PARAM_SPEC_CHAR (spec)) - { - GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec); - - lower = describe_signed_constant (pspec->minimum); - upper = describe_signed_constant (pspec->maximum); - if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8) - desc = g_strdup (""); - else if (pspec->minimum == G_MININT8) - desc = g_strdup_printf ("<= %s", upper); - else if (pspec->maximum == G_MAXINT8) - desc = g_strdup_printf (">= %s", lower); - else - desc = g_strdup_printf ("[%s,%s]", lower, upper); - g_free (lower); - g_free (upper); - } - else if (G_IS_PARAM_SPEC_UCHAR (spec)) - { - GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec); - - lower = describe_unsigned_constant (pspec->minimum); - upper = describe_unsigned_constant (pspec->maximum); - if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8) - desc = g_strdup (""); - else if (pspec->minimum == 0) - desc = g_strdup_printf ("<= %s", upper); - else if (pspec->maximum == G_MAXUINT8) - desc = g_strdup_printf (">= %s", lower); - else - desc = g_strdup_printf ("[%s,%s]", lower, upper); - g_free (lower); - g_free (upper); - } - else if (G_IS_PARAM_SPEC_INT (spec)) - { - GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec); - - lower = describe_signed_constant (pspec->minimum); - upper = describe_signed_constant (pspec->maximum); - if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT) - desc = g_strdup (""); - else if (pspec->minimum == G_MININT) - desc = g_strdup_printf ("<= %s", upper); - else if (pspec->maximum == G_MAXINT) - desc = g_strdup_printf (">= %s", lower); - else - desc = g_strdup_printf ("[%s,%s]", lower, upper); - g_free (lower); - g_free (upper); - } - else if (G_IS_PARAM_SPEC_UINT (spec)) - { - GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec); - - lower = describe_unsigned_constant (pspec->minimum); - upper = describe_unsigned_constant (pspec->maximum); - if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT) - desc = g_strdup (""); - else if (pspec->minimum == 0) - desc = g_strdup_printf ("<= %s", upper); - else if (pspec->maximum == G_MAXUINT) - desc = g_strdup_printf (">= %s", lower); - else - desc = g_strdup_printf ("[%s,%s]", lower, upper); - g_free (lower); - g_free (upper); - } - else if (G_IS_PARAM_SPEC_LONG (spec)) - { - GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec); - - lower = describe_signed_constant (pspec->minimum); - upper = describe_signed_constant (pspec->maximum); - if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG) - desc = g_strdup (""); - else if (pspec->minimum == G_MINLONG) - desc = g_strdup_printf ("<= %s", upper); - else if (pspec->maximum == G_MAXLONG) - desc = g_strdup_printf (">= %s", lower); - else - desc = g_strdup_printf ("[%s,%s]", lower, upper); - g_free (lower); - g_free (upper); - } - else if (G_IS_PARAM_SPEC_ULONG (spec)) - { - GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec); - gchar *upper; - - lower = describe_unsigned_constant (pspec->minimum); - upper = describe_unsigned_constant (pspec->maximum); - if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG) - desc = g_strdup (""); - else if (pspec->minimum == 0) - desc = g_strdup_printf ("<= %s", upper); - else if (pspec->maximum == G_MAXULONG) - desc = g_strdup_printf (">= %s", lower); - else - desc = g_strdup_printf ("[%s,%s]", lower, upper); - g_free (lower); - g_free (upper); - } - else if (G_IS_PARAM_SPEC_INT64 (spec)) - { - GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec); - - lower = describe_signed_constant (pspec->minimum); - upper = describe_signed_constant (pspec->maximum); - if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64) - desc = g_strdup (""); - else if (pspec->minimum == G_MININT64) - desc = g_strdup_printf ("<= %s", upper); - else if (pspec->maximum == G_MAXINT64) - desc = g_strdup_printf (">= %s", lower); - else - desc = g_strdup_printf ("[%s,%s]", lower, upper); - g_free (lower); - g_free (upper); - } - else if (G_IS_PARAM_SPEC_UINT64 (spec)) - { - GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec); - - lower = describe_unsigned_constant (pspec->minimum); - upper = describe_unsigned_constant (pspec->maximum); - if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64) - desc = g_strdup (""); - else if (pspec->minimum == 0) - desc = g_strdup_printf ("<= %s", upper); - else if (pspec->maximum == G_MAXUINT64) - desc = g_strdup_printf (">= %s", lower); - else - desc = g_strdup_printf ("[%s,%s]", lower, upper); - g_free (lower); - g_free (upper); - } - else if (G_IS_PARAM_SPEC_FLOAT (spec)) - { - GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec); - - lower = describe_double_constant (pspec->minimum); - upper = describe_double_constant (pspec->maximum); - if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXFLOAT)) - { - if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT)) - desc = g_strdup (""); - else - desc = g_strdup_printf ("<= %s", upper); - } - else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT)) - desc = g_strdup_printf (">= %s", lower); - else - desc = g_strdup_printf ("[%s,%s]", lower, upper); - g_free (lower); - g_free (upper); - } - else if (G_IS_PARAM_SPEC_DOUBLE (spec)) - { - GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec); - - lower = describe_double_constant (pspec->minimum); - upper = describe_double_constant (pspec->maximum); - if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXDOUBLE)) - { - if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE)) - desc = g_strdup (""); - else - desc = g_strdup_printf ("<= %s", upper); - } - else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE)) - desc = g_strdup_printf (">= %s", lower); - else - desc = g_strdup_printf ("[%s,%s]", lower, upper); - g_free (lower); - g_free (upper); - } - else - { - desc = g_strdup (""); - } - - return desc; -} - -static gchar* -describe_default (GParamSpec *spec) -{ - gchar *desc; - - if (G_IS_PARAM_SPEC_CHAR (spec)) - { - GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec); - - desc = g_strdup_printf ("%d", pspec->default_value); - } - else if (G_IS_PARAM_SPEC_UCHAR (spec)) - { - GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec); - - desc = g_strdup_printf ("%u", pspec->default_value); - } - else if (G_IS_PARAM_SPEC_BOOLEAN (spec)) - { - GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec); - - desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE"); - } - else if (G_IS_PARAM_SPEC_INT (spec)) - { - GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec); - - desc = g_strdup_printf ("%d", pspec->default_value); - } - else if (G_IS_PARAM_SPEC_UINT (spec)) - { - GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec); - - desc = g_strdup_printf ("%u", pspec->default_value); - } - else if (G_IS_PARAM_SPEC_LONG (spec)) - { - GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec); - - desc = g_strdup_printf ("%ld", pspec->default_value); - } - else if (G_IS_PARAM_SPEC_LONG (spec)) - { - GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec); - - desc = g_strdup_printf ("%lu", pspec->default_value); - } - else if (G_IS_PARAM_SPEC_INT64 (spec)) - { - GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec); - - desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value); - } - else if (G_IS_PARAM_SPEC_UINT64 (spec)) - { - GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec); - - desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value); - } - else if (G_IS_PARAM_SPEC_UNICHAR (spec)) - { - GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec); - - if (g_unichar_isprint (pspec->default_value)) - desc = g_strdup_printf ("'%c'", pspec->default_value); - else - desc = g_strdup_printf ("%u", pspec->default_value); - } - else if (G_IS_PARAM_SPEC_ENUM (spec)) - { - GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec); - - GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value); - if (value) - desc = g_strdup_printf ("%s", value->value_name); - else - desc = g_strdup_printf ("%d", pspec->default_value); - } - else if (G_IS_PARAM_SPEC_FLAGS (spec)) - { - GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec); - guint default_value; - GString *acc; - - default_value = pspec->default_value; - acc = g_string_new (""); - - while (default_value) - { - GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value); - - if (!value) - break; - - if (acc->len > 0) - g_string_append (acc, "|"); - g_string_append (acc, value->value_name); - - default_value &= ~value->value; - } - - if (default_value == 0) - desc = g_string_free (acc, FALSE); - else - { - desc = g_strdup_printf ("%d", pspec->default_value); - g_string_free (acc, TRUE); - } - } - else if (G_IS_PARAM_SPEC_FLOAT (spec)) - { - GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec); - - desc = g_strdup_printf ("%g", pspec->default_value); - } - else if (G_IS_PARAM_SPEC_DOUBLE (spec)) - { - GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec); - - desc = g_strdup_printf ("%lg", pspec->default_value); - } - else if (G_IS_PARAM_SPEC_STRING (spec)) - { - GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec); - - if (pspec->default_value) - { - gchar *esc = g_strescape (pspec->default_value, NULL); - - desc = g_strdup_printf ("\\"%s\\"", esc); - - g_free (esc); - } - else - desc = g_strdup_printf ("NULL"); - } - else - { - desc = g_strdup (""); - } - - return desc; -} - - -static void -output_object_args (FILE *fp, GType object_type) -{ - gpointer class; - const gchar *object_class_name; - guint arg; - gchar flags[16], *pos; - GParamSpec **properties; - guint n_properties; - gboolean child_prop; - gboolean style_prop; - gchar *type_desc; - gchar *default_value; - - if (G_TYPE_IS_CLASSED (object_type)) - { - class = g_type_class_peek (object_type); - if (!class) - return; - - properties = g_object_class_list_properties (class, &n_properties); - } -#if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3) - else if (G_TYPE_IS_INTERFACE (object_type)) - { - class = g_type_default_interface_ref (object_type); - - if (!class) - return; - - properties = g_object_interface_list_properties (class, &n_properties); - } -#endif - else - return; - - object_class_name = g_type_name (object_type); - - child_prop = FALSE; - style_prop = FALSE; - - while (TRUE) { - qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs); - for (arg = 0; arg < n_properties; arg++) - { - GParamSpec *spec = properties[arg]; - const gchar *nick, *blurb, *dot; - - if (spec->owner_type != object_type) - continue; - - pos = flags; - /* We use one-character flags for simplicity. */ - if (child_prop && !style_prop) - *pos++ = 'c'; - if (style_prop) - *pos++ = 's'; - if (spec->flags & G_PARAM_READABLE) - *pos++ = 'r'; - if (spec->flags & G_PARAM_WRITABLE) - *pos++ = 'w'; - if (spec->flags & G_PARAM_CONSTRUCT) - *pos++ = 'x'; - if (spec->flags & G_PARAM_CONSTRUCT_ONLY) - *pos++ = 'X'; - *pos = 0; - - nick = g_param_spec_get_nick (spec); - blurb = g_param_spec_get_blurb (spec); - - dot = ""; - if (blurb) { - int str_len = strlen (blurb); - if (str_len > 0 && blurb[str_len - 1] != '.') - dot = "."; - } - - type_desc = describe_type (spec); - default_value = describe_default (spec); - fprintf (fp, "\\n%s::%s\\n%s\\n%s\\n%s\\n%s\\n%s%s\\n%s\\n\\n\\n", - object_class_name, g_param_spec_get_name (spec), g_type_name (spec->value_type), type_desc, flags, nick ? nick : "(null)", blurb ? blurb : "(null)", dot, default_value); - g_free (type_desc); - g_free (default_value); - } - - g_free (properties); - -#ifdef GTK_IS_CONTAINER_CLASS - if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) { - properties = gtk_container_class_list_child_properties (class, &n_properties); - child_prop = TRUE; - continue; - } -#endif - -#ifdef GTK_IS_WIDGET_CLASS -#if GTK_CHECK_VERSION(2,1,0) - if (!style_prop && GTK_IS_WIDGET_CLASS (class)) { - properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties); - style_prop = TRUE; - continue; - } -#endif -#endif - - break; - } -} -EOT - -close OUTPUT; - -# Compile and run our file - -$CC = $ENV{CC} ? $ENV{CC} : "gcc"; -$LD = $ENV{LD} ? $ENV{LD} : $CC; -$CFLAGS = $ENV{CFLAGS} ? "$ENV{CFLAGS} -Wall -g" : "-Wall -g"; -$LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : ""; - -my $o_file; -if ($CC =~ /libtool/) { - $o_file = "$MODULE-scan.lo" -} else { - $o_file = "$MODULE-scan.o" -} - -print "gtk-doc: Compiling scanner\n"; -$command = "$CC $CFLAGS -c -o $o_file $MODULE-scan.c"; -system($command) == 0 or die "Compilation of scanner failed: $!\n"; - -print "gtk-doc: Linking scanner\n"; -$command = "$LD -o $MODULE-scan $o_file $LDFLAGS"; -system($command) == 0 or die "Linking of scanner failed: $!\n"; - -print "gtk-doc: Running scanner $MODULE-scan\n"; -system("sh -c ./$MODULE-scan") == 0 or die "Scan failed: $!\n"; - -unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan"; - -#&UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0); -#&UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0); -#&UpdateFileIfChanged ($old_interfaces_filename, $new_interfaces_filename, 0); -#&UpdateFileIfChanged ($old_prerequisites_filename, $new_prerequisites_filename, 0); -#&UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0); - - diff --git a/common/gtk-doc-plugins.mak b/common/gtk-doc-plugins.mak deleted file mode 100644 index 4bb57a4566..0000000000 --- a/common/gtk-doc-plugins.mak +++ /dev/null @@ -1,358 +0,0 @@ -# This is an include file specifically tuned for building documentation -# for GStreamer plug-ins - -help: - @echo "If you are a doc maintainer, run 'make update' to update" - @echo "the documentation files maintained in CVS" - -# update the stuff maintained by doc maintainers -update: - make inspect-update - make scanobj-update - -# We set GPATH here; this gives us semantics for GNU make -# which are more like other make's VPATH, when it comes to -# whether a source that is a target of one rule is then -# searched for in VPATH/GPATH. -# -GPATH = $(srcdir) - -# thomas: make docs parallel installable -TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@ - -EXTRA_DIST = \ - scanobj-build.stamp \ - $(srcdir)/inspect/*.xml \ - inspect.stamp \ - inspect-build.stamp \ - $(SCANOBJ_FILES) \ - $(content_files) \ - $(extra_files) \ - $(HTML_IMAGES) \ - $(DOC_MAIN_SGML_FILE) \ - $(DOC_MODULE).types \ - $(DOC_OVERRIDES) \ - $(DOC_MODULE)-sections.txt - -MAINTAINER_DOC_STAMPS = \ - scanobj-build.stamp \ - inspect-build.stamp \ - inspect.stamp - -# we don't add inspect-build.stamp and scanobj-build.stamp here since they are -# built manually by docs maintainers and result is commited to CVS -DOC_STAMPS = \ - scan-build.stamp \ - tmpl-build.stamp \ - sgml-build.stamp \ - html-build.stamp \ - scan.stamp \ - tmpl.stamp \ - sgml.stamp \ - html.stamp - -# files generated/updated by gtkdoc-scangobj -SCANOBJ_FILES = \ - $(DOC_MODULE).signals \ - $(DOC_MODULE).hierarchy \ - $(DOC_MODULE).interfaces \ - $(DOC_MODULE).prerequisites \ - $(DOC_MODULE).args - -SCANOBJ_FILES_O = \ - .libs/$(DOC_MODULE)-scan.o - -# files generated/updated by gtkdoc-scan -SCAN_FILES = \ - $(DOC_MODULE)-sections.txt \ - $(DOC_MODULE)-overrides.txt \ - $(DOC_MODULE)-undocumented.txt \ - $(DOC_MODULE)-decl.txt \ - $(DOC_MODULE)-decl-list.txt - -if ENABLE_GTK_DOC -all-local: html-build.stamp - -#### scan gobjects; done by documentation maintainer #### -scanobj-update: - -rm scanobj-build.stamp - make scanobj-build.stamp - -# in the case of non-srcdir builds, the built gst directory gets added -# to gtk-doc scanning; but only then, to avoid duplicates -# FIXME: since we don't have the scan step as part of the build anymore, -# we could remove that -# TODO: finish elite script that updates the output files of this step -# instead of rewriting them, so that multiple maintainers can generate -# a collective set of args and signals -scanobj-build.stamp: $(SCANOBJ_DEPS) $(basefiles) - @echo '*** Scanning GObjects ***' - if test x"$(srcdir)" != x. ; then \ - for f in $(SCANOBJ_FILES); \ - do \ - cp $(srcdir)/$$f . ; \ - done; \ - else \ - $(INSPECT_ENVIRONMENT) \ - CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" \ - CFLAGS="-g $(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" \ - $(GST_DOC_SCANOBJ) --type-init-func="gst_init(NULL,NULL)" \ - --module=$(DOC_MODULE) --source=$(PACKAGE) && \ - $(PYTHON) \ - $(top_srcdir)/common/scangobj-merge.py $(DOC_MODULE); \ - fi - touch scanobj-build.stamp - -$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(SCANOBJ_FILES_O): scan-build.stamp - @true - -### inspect GStreamer plug-ins; done by documentation maintainer ### - -# only look at the plugins in this module when building inspect .xml stuff -INSPECT_REGISTRY=$(top_builddir)/docs/plugins/inspect-registry.xml -INSPECT_ENVIRONMENT=\ - GST_PLUGIN_SYSTEM_PATH= \ - GST_PLUGIN_PATH=$(top_builddir)/gst:$(top_builddir)/sys:$(top_builddir)/ext:$(top_builddir)/plugins:$(top_builddir)/src \ - GST_REGISTRY=$(INSPECT_REGISTRY) - -# update the element and plugin XML descriptions; store in inspect/ -inspect: - mkdir inspect - -inspect-update: inspect - -rm $(INSPECT_REGISTRY) - -rm inspect-build.stamp - make inspect-build.stamp - -# FIXME: inspect.stamp should be written to by gst-xmlinspect.py -# IFF the output changed; see gtkdoc-mktmpl -inspect-build.stamp: - @echo '*** Rebuilding plugin inspection files ***' - if test x"$(srcdir)" != x. ; then \ - cp $(srcdir)/inspect.stamp . ; \ - cp $(srcdir)/inspect-build.stamp . ; \ - else \ - $(INSPECT_ENVIRONMENT) $(PYTHON) \ - $(top_srcdir)/common/gst-xmlinspect.py $(PACKAGE) inspect && \ - echo -n "timestamp" > inspect.stamp && \ - touch inspect-build.stamp; \ - fi - -### scan headers; done on every build ### -scan-build.stamp: $(HFILE_GLOB) $(EXTRA_HFILES) $(basefiles) scanobj-build.stamp inspect-build.stamp - if test "x$(top_srcdir)" != "x$(top_builddir)" && \ - test -d "$(top_builddir)/gst"; \ - then \ - export BUILT_OPTIONS="--source-dir=$(top_builddir)/gst"; \ - fi; \ - gtkdoc-scan \ - $(SCAN_OPTIONS) $(EXTRA_HFILES) \ - --module=$(DOC_MODULE) \ - $$BUILT_OPTIONS \ - --ignore-headers="$(IGNORE_HFILES)"; \ - touch scan-build.stamp - -#### update templates; done on every build #### - -### FIXME: make this error out again when docs are fixed for 0.9 -# in a non-srcdir build, we need to copy files from the previous step -# and the files from previous runs of this step -tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_OVERRIDES) - @echo '*** Rebuilding template files ***' - if test x"$(srcdir)" != x. ; then \ - for f in $(SCANOBJ_FILES) $(SCAN_FILES); \ - do \ - if test -e $(srcdir)/$$f; then cp $(srcdir)/$$f . ; fi; \ - done; \ - fi - gtkdoc-mktmpl --module=$(DOC_MODULE) | tee tmpl-build.log - $(PYTHON) \ - $(top_srcdir)/common/mangle-tmpl.py $(srcdir)/inspect tmpl - @cat $(DOC_MODULE)-unused.txt - rm -f tmpl-build.log - touch tmpl-build.stamp - -tmpl.stamp: tmpl-build.stamp - @true - -#### build xml; done on every build #### - -### FIXME: make this error out again when docs are fixed for 0.9 -sgml-build.stamp: tmpl.stamp inspect.stamp $(CFILE_GLOB) $(top_srcdir)/common/plugins.xsl - @echo '*** Building XML ***' - @-mkdir -p xml - @for a in $(srcdir)/inspect/*.xml; do \ - xsltproc --stringparam module $(MODULE) \ - $(top_srcdir)/common/plugins.xsl $$a > xml/`basename $$a`; done - @for f in $(EXAMPLE_CFILES); do \ - $(PYTHON) $(top_srcdir)/common/c-to-xml.py $$f > xml/element-`basename $$f .c`.xml; done - gtkdoc-mkdb \ - --module=$(DOC_MODULE) \ - --source-dir=$(DOC_SOURCE_DIR) \ - --main-sgml-file=$(srcdir)/$(DOC_MAIN_SGML_FILE) \ - --output-format=xml \ - --ignore-files="$(IGNORE_HFILES) $(IGNORE_CFILES)" \ - $(MKDB_OPTIONS) \ - | tee sgml-build.log - @if grep "WARNING:" sgml-build.log > /dev/null; then true; fi # exit 1; fi - cp ../version.entities xml - rm sgml-build.log - touch sgml-build.stamp - -sgml.stamp: sgml-build.stamp - @true - -#### build html; done on every step #### - -html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) - @echo '*** Building HTML ***' - if test -d html; then rm -rf html; fi - mkdir html - cp $(srcdir)/$(DOC_MAIN_SGML_FILE) html - @for f in $(content_files); do cp $(srcdir)/$$f html; done - cp -pr xml html - cp ../version.entities html - cd html && gtkdoc-mkhtml $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) \ - 2>&1 | tee ../html-build.log - @if grep "warning:" html-build.log > /dev/null; then \ - echo "ERROR"; grep "warning:" html-build.log; exit 1; fi - @rm html-build.log - rm -f html/$(DOC_MAIN_SGML_FILE) - rm -rf html/xml - rm -f html/version.entities - test "x$(HTML_IMAGES)" = "x" || for i in "" $(HTML_IMAGES) ; do \ - if test "$$i" != ""; then cp $(srcdir)/$$i html ; fi; done - @echo '-- Fixing Crossreferences' - gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) - touch html-build.stamp -else -all-local: -endif - -# FC3 seems to need -scan.c to be part of CLEANFILES for distcheck -# no idea why FC4 can do without -CLEANFILES = \ - $(SCANOBJ_FILES_O) \ - $(DOC_MODULE)-scan.c \ - $(DOC_MODULE)-unused.txt \ - $(DOC_STAMPS) \ - inspect-registry.xml - -# FIXME: these rules need a little cleaning up -clean-local: - rm -f *~ *.bak - rm -rf .libs -# clean files generated for tmpl build - -rm -rf tmpl -# clean files copied/generated for nonsrcdir tmpl build - if test x"$(srcdir)" != x. ; then \ - rm -rf $(SCANOBJ_FILES) $(SCAN_FILES); \ - fi -# clean files generated for xml build - -rm -rf xml -# clean files generate for html build - -rm -rf html - -distclean-local: clean - rm -rf tmpl/*.sgml.bak - rm -f *.stamp || true - rm -rf *.o - -# thomas: make docs parallel installable; devhelp requires majorminor too -install-data-local: - $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR) - (installfiles=`echo ./html/*.html`; \ - if test "$$installfiles" = './html/*.html'; \ - then echo '-- Nothing to install' ; \ - else \ - for i in $$installfiles; do \ - echo '-- Installing '$$i ; \ - $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ - done; \ - pngfiles=`echo ./html/*.png`; \ - if test "$$pngfiles" != './html/*.png'; then \ - for i in $$pngfiles; do \ - echo '-- Installing '$$i ; \ - $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ - done; \ - fi; \ - echo '-- Installing $(srcdir)/html/$(DOC_MODULE).devhelp' ; \ - $(INSTALL_DATA) $(srcdir)/html/$(DOC_MODULE).devhelp \ - $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ - echo '-- Installing $(srcdir)/html/index.sgml' ; \ - $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR); \ - if test -e $(srcdir)/html/style.css; then \ - echo '-- Installing $(srcdir)/html/style.css' ; \ - $(INSTALL_DATA) $(srcdir)/html/style.css $(DESTDIR)$(TARGET_DIR); \ - fi; \ - fi) -uninstall-local: - (installfiles=`echo ./html/*.html`; \ - if test "$$installfiles" = './html/*.html'; \ - then echo '-- Nothing to uninstall' ; \ - else \ - for i in $$installfiles; do \ - rmfile=`basename $$i` ; \ - echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ - rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ - done; \ - pngfiles=`echo ./html/*.png`; \ - if test "$$pngfiles" != './html/*.png'; then \ - for i in $$pngfiles; do \ - rmfile=`basename $$i` ; \ - echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ - rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ - done; \ - fi; \ - echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE).devhelp' ; \ - rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ - echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/index.sgml' ; \ - rm -f $(DESTDIR)$(TARGET_DIR)/index.sgml; \ - if test -e $(DESTDIR)$(TARGET_DIR)/style.css; then \ - echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/style.css' ; \ - rm -f $(DESTDIR)$(TARGET_DIR)/style.css; \ - fi; \ - fi) - if test -d $(DESTDIR)$(TARGET_DIR); then rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(TARGET_DIR) 2>/dev/null; fi; true - -# -# Checks -# -check-hierarchy: $(DOC_MODULE).hierarchy - @if grep ' ' $(DOC_MODULE).hierarchy; then \ - echo "$(DOC_MODULE).hierarchy contains tabs, please fix"; \ - /bin/false; \ - fi - -check: check-hierarchy - - -# -# Require gtk-doc when making dist -# -if ENABLE_GTK_DOC -dist-check-gtkdoc: -else -dist-check-gtkdoc: - @echo "*** gtk-doc must be installed and enabled in order to make dist" - @false -endif - -# FIXME: decide whether we want to dist generated html or not -dist-hook: dist-check-gtkdoc dist-hook-local - mkdir $(distdir)/tmpl - mkdir $(distdir)/xml - mkdir $(distdir)/html - -cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl - -cp $(srcdir)/sgml/*.xml $(distdir)/xml - -cp $(srcdir)/html/index.sgml $(distdir)/html - -cp $(srcdir)/html/*.html $(srcdir)/html/*.css $(distdir)/html - -cp $(srcdir)/html/$(DOC_MODULE).devhelp $(distdir)/html - - images=$(HTML_IMAGES) ; \ - for i in "" $$images ; do \ - if test "$$i" != ""; then cp $(srcdir)/$$i $(distdir)/html ; fi; \ - done - -.PHONY : dist-hook-local - diff --git a/common/gtk-doc.mak b/common/gtk-doc.mak deleted file mode 100644 index ea203d8745..0000000000 --- a/common/gtk-doc.mak +++ /dev/null @@ -1,260 +0,0 @@ -########################################################################### -# Everything below here is generic and you shouldn't need to change it. -########################################################################### -# thomas: except of course that we did - -# thomas: copied from glib-2 -# We set GPATH here; this gives us semantics for GNU make -# which are more like other make's VPATH, when it comes to -# whether a source that is a target of one rule is then -# searched for in VPATH/GPATH. -# -GPATH = $(srcdir) - -# thomas: make docs parallel installable -TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@ - -EXTRA_DIST = \ - $(content_files) \ - $(extra_files) \ - $(HTML_IMAGES) \ - $(DOC_MAIN_SGML_FILE) \ - $(DOC_MODULE).types \ - $(DOC_OVERRIDES) \ - $(DOC_MODULE)-sections.txt - -DOC_STAMPS = \ - scan-build.stamp \ - tmpl-build.stamp \ - sgml-build.stamp \ - html-build.stamp \ - $(srcdir)/tmpl.stamp \ - $(srcdir)/sgml.stamp \ - $(srcdir)/html.stamp - -SCANOBJ_FILES = \ - $(DOC_MODULE).args \ - $(DOC_MODULE).hierarchy \ - $(DOC_MODULE).interfaces \ - $(DOC_MODULE).prerequisites \ - .libs/$(DOC_MODULE)-scan.o \ - $(DOC_MODULE).signals - -CLEANFILES = $(SCANOBJ_FILES) $(DOC_MODULE)-unused.txt $(DOC_STAMPS) - -if ENABLE_GTK_DOC -all-local: html-build.stamp - -#### scan #### - -# in the case of non-srcdir builds, the built gst directory gets added -# to gtk-doc scanning; but only then, to avoid duplicates -scan-build.stamp: $(HFILE_GLOB) $(SCANOBJ_DEPS) $(basefiles) - @echo '*** Scanning header files ***' - if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null; \ - then \ - if test x"$(srcdir)" != x. ; then \ - cp $(srcdir)/$(DOC_MODULE).types . ; \ - chmod u+w $(DOC_MODULE).types ; \ - fi ; \ - GST_PLUGIN_SYSTEM_PATH=`cd $(top_builddir) && pwd` \ - GST_PLUGIN_PATH= \ - CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" \ - CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" \ - gtkdoc-scangobj --type-init-func="gst_init(NULL,NULL)" \ - --module=$(DOC_MODULE) ; \ - else \ - cd $(srcdir) ; \ - for i in $(SCANOBJ_FILES) ; do \ - test -f $$i || touch $$i ; \ - done \ - fi - if test "x$(top_srcdir)" != "x$(top_builddir)"; \ - then \ - export BUILT_OPTIONS="--source-dir=$(DOC_BUILD_DIR)"; \ - fi; \ - gtkdoc-scan \ - $(SCAN_OPTIONS) $(EXTRA_HFILES) \ - --module=$(DOC_MODULE) \ - --source-dir=$(DOC_SOURCE_DIR) \ - $$BUILT_OPTIONS \ - --ignore-headers="$(IGNORE_HFILES)" - touch scan-build.stamp - -$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES): scan-build.stamp - @true - -#### templates #### - -tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_OVERRIDES) - @echo '*** Rebuilding template files ***' - if test x"$(srcdir)" != x. ; then \ - cp $(srcdir)/$(DOC_MODULE)-sections.txt . ; \ - touch $(DOC_MODULE)-decl.txt ; \ - fi - gtkdoc-mktmpl --module=$(DOC_MODULE) | tee tmpl-build.log - @if test -s $(DOC_MODULE)-unused.txt; then \ - exit $(if $(DOCS_ARE_INCOMPLETE_PLEASE_FIXME),0,1); fi - rm -f tmpl-build.log - touch tmpl-build.stamp - -tmpl.stamp: tmpl-build.stamp - @true - -#### xml #### - -### FIXME: make this error out again when docs are fixed for 0.9 -sgml-build.stamp: tmpl.stamp $(CFILE_GLOB) - @echo '*** Building XML ***' - gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --main-sgml-file=$(srcdir)/$(DOC_MAIN_SGML_FILE) --output-format=xml $(MKDB_OPTIONS) | tee sgml-build.log - @if grep "WARNING:" sgml-build.log > /dev/null; then true; fi # exit 1; fi - rm sgml-build.log - touch sgml-build.stamp - -sgml.stamp: sgml-build.stamp - @true - -#### html #### - -html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) - @echo '*** Building HTML ***' - if test -d html; then rm -rf html; fi - mkdir html - cp $(srcdir)/$(DOC_MAIN_SGML_FILE) html - @for f in $(content_files); do cp $(srcdir)/$$f html; done - cp -pr xml html - cp ../version.entities html - cd html && gtkdoc-mkhtml $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) - rm -f html/$(DOC_MAIN_SGML_FILE) - rm -rf html/xml - rm -f html/version.entities - test "x$(HTML_IMAGES)" = "x" || for i in "" $(HTML_IMAGES) ; do \ - if test "$$i" != ""; then cp $(srcdir)/$$i html ; fi; done - @echo '-- Fixing Crossreferences' - gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) - touch html-build.stamp -else -all-local: -endif - -clean-local: - rm -f *~ *.bak - rm -rf xml html - rm -rf .libs - -maintainer-clean-local: clean - cd $(srcdir) && rm -rf xml html $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt - -# company: don't delete .sgml and -sections.txt as they're in CVS -# FIXME : thomas added all sgml files and some other things to make -# make distcheck work -distclean-local: clean - rm -f $(DOC_MODULE)-decl-list.txt - rm -f $(DOC_MODULE)-decl.txt - rm -f $(DOC_MODULE)-undocumented.txt - rm -f $(DOC_MODULE)-unused.txt - rm -rf tmpl/*.sgml.bak - rm -f $(DOC_MODULE).hierarchy - rm -f *.stamp || true - if test x"$(srcdir)" != x. ; then \ - rm -f $(DOC_MODULE)-docs.sgml ; \ - rm -f $(DOC_MODULE).types ; \ - rm -f $(DOC_MODULE).interfaces ; \ - rm -f $(DOC_MODULE)-overrides.txt ; \ - rm -f $(DOC_MODULE).prerequisites ; \ - rm -f $(DOC_MODULE)-sections.txt ; \ - rm -rf tmpl/*.sgml ; \ - fi - rm -rf *.o - -# thomas: make docs parallel installable; devhelp requires majorminor too -install-data-local: - $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR) - (installfiles=`echo ./html/*.html`; \ - if test "$$installfiles" = './html/*.html'; \ - then echo '-- Nothing to install' ; \ - else \ - for i in $$installfiles; do \ - echo '-- Installing '$$i ; \ - $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ - done; \ - pngfiles=`echo ./html/*.png`; \ - if test "$$pngfiles" != './html/*.png'; then \ - for i in $$pngfiles; do \ - echo '-- Installing '$$i ; \ - $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ - done; \ - fi; \ - echo '-- Installing $(srcdir)/html/$(DOC_MODULE).devhelp' ; \ - $(INSTALL_DATA) $(srcdir)/html/$(DOC_MODULE).devhelp \ - $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ - if test -e $(srcdir)/html/$(DOC_MODULE).devhelp2; then \ - $(INSTALL_DATA) $(srcdir)/html/$(DOC_MODULE).devhelp2 \ - $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; \ - fi; \ - echo '-- Installing $(srcdir)/html/index.sgml' ; \ - $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR); \ - if test -e $(srcdir)/html/style.css; then \ - echo '-- Installing $(srcdir)/html/style.css' ; \ - $(INSTALL_DATA) $(srcdir)/html/style.css $(DESTDIR)$(TARGET_DIR); \ - fi; \ - fi) -uninstall-local: - (installfiles=`echo ./html/*.html`; \ - if test "$$installfiles" = './html/*.html'; \ - then echo '-- Nothing to uninstall' ; \ - else \ - for i in $$installfiles; do \ - rmfile=`basename $$i` ; \ - echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ - rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ - done; \ - pngfiles=`echo ./html/*.png`; \ - if test "$$pngfiles" != './html/*.png'; then \ - for i in $$pngfiles; do \ - rmfile=`basename $$i` ; \ - echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ - rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ - done; \ - fi; \ - echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE).devhelp' ; \ - rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ - if test -e $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; then \ - rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; \ - fi; \ - echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/index.sgml' ; \ - rm -f $(DESTDIR)$(TARGET_DIR)/index.sgml; \ - if test -e $(DESTDIR)$(TARGET_DIR)/style.css; then \ - echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/style.css' ; \ - rm -f $(DESTDIR)$(TARGET_DIR)/style.css; \ - fi; \ - fi) - if test -d $(DESTDIR)$(TARGET_DIR); then rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(TARGET_DIR) 2>/dev/null; fi; true - -# -# Require gtk-doc when making dist -# -if ENABLE_GTK_DOC -dist-check-gtkdoc: -else -dist-check-gtkdoc: - @echo "*** gtk-doc must be installed and enabled in order to make dist" - @false -endif - -dist-hook: dist-check-gtkdoc dist-hook-local - mkdir $(distdir)/tmpl - mkdir $(distdir)/xml - mkdir $(distdir)/html - -cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl - -cp $(srcdir)/sgml/*.xml $(distdir)/xml - -cp $(srcdir)/html/index.sgml $(distdir)/html - -cp $(srcdir)/html/*.html $(srcdir)/html/*.css $(distdir)/html - -cp $(srcdir)/html/$(DOC_MODULE).devhelp* $(distdir)/html - - images=$(HTML_IMAGES) ; \ - for i in "" $$images ; do \ - if test "$$i" != ""; then cp $(srcdir)/$$i $(distdir)/html ; fi; \ - done - -.PHONY : dist-hook-local diff --git a/common/m4/.gitignore b/common/m4/.gitignore deleted file mode 100644 index 38066ddf7c..0000000000 --- a/common/m4/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -libtool.m4 -ltoptions.m4 -ltsugar.m4 -ltversion.m4 -lt~obsolete.m4 diff --git a/common/m4/Makefile.am b/common/m4/Makefile.am deleted file mode 100644 index 3bbf0e96bc..0000000000 --- a/common/m4/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -EXTRA_DIST = \ - README \ - as-ac-expand.m4 \ - as-auto-alt.m4 \ - as-compiler-flag.m4 \ - as-compiler.m4 \ - as-docbook.m4 \ - as-libtool.m4 \ - as-libtool-tags.m4 \ - as-python.m4 \ - as-scrub-include.m4 \ - as-version.m4 \ - ax_create_stdint_h.m4 \ - glib-gettext.m4 \ - gst-arch.m4 \ - gst-args.m4 \ - gst-check.m4 \ - gst-debuginfo.m4 \ - gst-default.m4 \ - gst-doc.m4 \ - gst-feature.m4 \ - gst-function.m4 \ - gst-gettext.m4 \ - gst-glib2.m4 \ - gst-libxml2.m4 \ - gst-plugindir.m4 \ - gst-valgrind.m4 \ - pkg.m4 diff --git a/common/m4/README b/common/m4/README deleted file mode 100644 index f044598500..0000000000 --- a/common/m4/README +++ /dev/null @@ -1,3 +0,0 @@ -All aclocal .m4 files we need are put here and cat'd to acinclude.m4 in -the source root. Official ones (taken from the relevant devel packages) -are named as-is, unofficial ones (or changed ones) get a gst-prefix. diff --git a/common/m4/as-ac-expand.m4 b/common/m4/as-ac-expand.m4 deleted file mode 100644 index d6c9e33060..0000000000 --- a/common/m4/as-ac-expand.m4 +++ /dev/null @@ -1,43 +0,0 @@ -dnl as-ac-expand.m4 0.2.0 -dnl autostars m4 macro for expanding directories using configure's prefix -dnl thomas@apestaart.org - -dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR) -dnl example -dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir) -dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local - -AC_DEFUN([AS_AC_EXPAND], -[ - EXP_VAR=[$1] - FROM_VAR=[$2] - - dnl first expand prefix and exec_prefix if necessary - prefix_save=$prefix - exec_prefix_save=$exec_prefix - - dnl if no prefix given, then use /usr/local, the default prefix - if test "x$prefix" = "xNONE"; then - prefix="$ac_default_prefix" - fi - dnl if no exec_prefix given, then use prefix - if test "x$exec_prefix" = "xNONE"; then - exec_prefix=$prefix - fi - - full_var="$FROM_VAR" - dnl loop until it doesn't change anymore - while true; do - new_full_var="`eval echo $full_var`" - if test "x$new_full_var" = "x$full_var"; then break; fi - full_var=$new_full_var - done - - dnl clean up - full_var=$new_full_var - AC_SUBST([$1], "$full_var") - - dnl restore prefix and exec_prefix - prefix=$prefix_save - exec_prefix=$exec_prefix_save -]) diff --git a/common/m4/as-auto-alt.m4 b/common/m4/as-auto-alt.m4 deleted file mode 100644 index 3f7920dd23..0000000000 --- a/common/m4/as-auto-alt.m4 +++ /dev/null @@ -1,50 +0,0 @@ -dnl as-auto-alt.m4 0.0.2 -dnl autostars m4 macro for supplying alternate autotools versions to configure -dnl thomas@apestaart.org -dnl -dnl AS_AUTOTOOLS_ALTERNATE() -dnl -dnl supplies --with arguments for autoconf, autoheader, automake, aclocal - -AC_DEFUN([AS_AUTOTOOLS_ALTERNATE], -[ - dnl allow for different autoconf version - AC_ARG_WITH(autoconf, - AC_HELP_STRING([--with-autoconf], - [use a different autoconf for regeneration of Makefiles]), - [ - unset AUTOCONF - AM_MISSING_PROG(AUTOCONF, ${withval}) - AC_MSG_NOTICE([Using $AUTOCONF as autoconf]) - ]) - - dnl allow for different autoheader version - AC_ARG_WITH(autoheader, - AC_HELP_STRING([--with-autoheader], - [use a different autoheader for regeneration of Makefiles]), - [ - unset AUTOHEADER - AM_MISSING_PROG(AUTOHEADER, ${withval}) - AC_MSG_NOTICE([Using $AUTOHEADER as autoheader]) - ]) - - dnl allow for different automake version - AC_ARG_WITH(automake, - AC_HELP_STRING([--with-automake], - [use a different automake for regeneration of Makefiles]), - [ - unset AUTOMAKE - AM_MISSING_PROG(AUTOMAKE, ${withval}) - AC_MSG_NOTICE([Using $AUTOMAKE as automake]) - ]) - - dnl allow for different aclocal version - AC_ARG_WITH(aclocal, - AC_HELP_STRING([--with-aclocal], - [use a different aclocal for regeneration of Makefiles]), - [ - unset ACLOCAL - AM_MISSING_PROG(ACLOCAL, ${withval}) - AC_MSG_NOTICE([Using $ACLOCAL as aclocal]) - ]) -]) diff --git a/common/m4/as-compiler-flag.m4 b/common/m4/as-compiler-flag.m4 deleted file mode 100644 index aba31b1c9d..0000000000 --- a/common/m4/as-compiler-flag.m4 +++ /dev/null @@ -1,33 +0,0 @@ -dnl as-compiler-flag.m4 0.1.0 - -dnl autostars m4 macro for detection of compiler flags - -dnl David Schleef - -dnl $Id: as-compiler-flag.m4,v 1.1 2004/06/01 09:33:45 thomasvs Exp $ - -dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) -dnl Tries to compile with the given CFLAGS. -dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, -dnl and ACTION-IF-NOT-ACCEPTED otherwise. - -AC_DEFUN([AS_COMPILER_FLAG], -[ - AC_MSG_CHECKING([to see if compiler understands $1]) - - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $1" - - AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) - CFLAGS="$save_CFLAGS" - - if test "X$flag_ok" = Xyes ; then - $2 - true - else - $3 - true - fi - AC_MSG_RESULT([$flag_ok]) -]) - diff --git a/common/m4/as-compiler.m4 b/common/m4/as-compiler.m4 deleted file mode 100644 index 233a719d44..0000000000 --- a/common/m4/as-compiler.m4 +++ /dev/null @@ -1,44 +0,0 @@ -dnl as-compiler.m4 0.1.0 - -dnl autostars m4 macro for detection of compiler flavor - -dnl Thomas Vander Stichele - -dnl $Id: as-compiler.m4,v 1.4 2004/06/01 09:33:45 thomasvs Exp $ - -dnl AS_COMPILER(COMPILER) -dnl will set variable COMPILER to -dnl - gcc -dnl - forte -dnl - (empty) if no guess could be made - -AC_DEFUN([AS_COMPILER], -[ - as_compiler= - AC_MSG_CHECKING(for compiler flavour) - - dnl is it gcc ? - if test "x$GCC" = "xyes"; then - as_compiler="gcc" - fi - - dnl is it forte ? - AC_TRY_RUN([ -int main -(int argc, char *argv[]) -{ -#ifdef __sun - return 0; -#else - return 1; -#endif -} - ], as_compiler="forte", ,) - - if test "x$as_compiler" = "x"; then - AC_MSG_RESULT([unknown !]) - else - AC_MSG_RESULT($as_compiler) - fi - [$1]=$as_compiler -]) diff --git a/common/m4/as-docbook.m4 b/common/m4/as-docbook.m4 deleted file mode 100644 index 6a2aa458d8..0000000000 --- a/common/m4/as-docbook.m4 +++ /dev/null @@ -1,66 +0,0 @@ -dnl AS_DOCBOOK([, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) -dnl checks if xsltproc can build docbook documentation -dnl (which is possible if the catalog is set up properly -dnl I also tried checking for a specific version and type of docbook -dnl but xsltproc seemed to happily run anyway, so we can't check for that -dnl and version -dnl this macro takes inspiration from -dnl http://www.movement.uklinux.net/docs/docbook-autotools/configure.html -AC_DEFUN([AS_DOCBOOK], -[ - XSLTPROC_FLAGS=--nonet - DOCBOOK_ROOT= - TYPE_LC=xml - TYPE_UC=XML - DOCBOOK_VERSION=4.1.2 - - if test ! -f /etc/xml/catalog; then - for i in /usr/share/sgml/docbook/stylesheet/xsl/nwalsh /usr/share/sgml/docbook/xsl-stylesheets/; - do - if test -d "$i"; then - DOCBOOK_ROOT=$i - fi - done - else - XML_CATALOG=/etc/xml/catalog - CAT_ENTRY_START='' - fi - - dnl We need xsltproc to process the test - AC_CHECK_PROG(XSLTPROC,xsltproc,xsltproc,) - XSLTPROC_WORKS=no - if test -n "$XSLTPROC"; then - AC_MSG_CHECKING([whether xsltproc docbook processing works]) - - if test -n "$XML_CATALOG"; then - DB_FILE="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl" - else - DB_FILE="$DOCBOOK_ROOT/docbook.xsl" - fi - $XSLTPROC $XSLTPROC_FLAGS $DB_FILE >/dev/null 2>&1 << END - - - - -END - if test "$?" = 0; then - XSLTPROC_WORKS=yes - fi - AC_MSG_RESULT($XSLTPROC_WORKS) - fi - - if test "x$XSLTPROC_WORKS" = "xyes"; then - dnl execute ACTION-IF-FOUND - ifelse([$1], , :, [$1]) - else - dnl execute ACTION-IF-NOT-FOUND - ifelse([$2], , :, [$2]) - fi - - AC_SUBST(XML_CATALOG) - AC_SUBST(XSLTPROC_FLAGS) - AC_SUBST(DOCBOOK_ROOT) - AC_SUBST(CAT_ENTRY_START) - AC_SUBST(CAT_ENTRY_END) -]) diff --git a/common/m4/as-libtool-tags.m4 b/common/m4/as-libtool-tags.m4 deleted file mode 100644 index 69f775e7da..0000000000 --- a/common/m4/as-libtool-tags.m4 +++ /dev/null @@ -1,83 +0,0 @@ -dnl as-libtool-tags.m4 0.1.4 - -dnl autostars m4 macro for selecting libtool "tags" (languages) - -dnl Andy Wingo does not claim credit for this macro -dnl backported from libtool 1.6 by Paolo Bonzini -dnl see http://lists.gnu.org/archive/html/libtool/2003-12/msg00007.html - -dnl $Id: as-libtool-tags.m4,v 1.3 2006/04/01 15:30:56 thomasvs Exp $ - -dnl AS_LIBTOOL_TAGS([tags...]) - -dnl example -dnl AS_LIBTOOL_TAGS([]) for only C (no fortran, etc) - -dnl When AC_LIBTOOL_TAGS is used, I redefine _LT_AC_TAGCONFIG -dnl to be more similar to the libtool 1.6 implementation, which -dnl uses an m4 loop and m4 case instead of a shell loop. This -dnl way the CXX/GCJ/F77/RC tests are not always expanded. - -dnl AS_LIBTOOL_TAGS -dnl --------------- -dnl tags to enable -AC_DEFUN([AS_LIBTOOL_TAGS], -[m4_define([_LT_TAGS],[$1]) -m4_define([_LT_AC_TAGCONFIG], [ - # redefined LT AC TAGCONFIG - if test -f "$ltmain"; then - if test ! -f "${ofile}"; then - AC_MSG_WARN([output file `$ofile' does not exist]) - fi - - if test -z "$LTCC"; then - eval "`$SHELL ${ofile} --config | grep '^LTCC='`" - if test -z "$LTCC"; then - AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) - else - AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) - fi - fi - - AC_FOREACH([_LT_TAG], _LT_TAGS, - echo THOMAS: tag _LT_TAG - [m4_case(_LT_TAG, - [CXX], [ - if test -n "$CXX" && test "X$CXX" != "Xno"; then - echo "THOMAS: YAY CXX" - AC_LIBTOOL_LANG_CXX_CONFIG - available_tags="$available_tags _LT_TAG" - fi], - [F77], [ - if test -n "$F77" && test "X$F77" != "Xno"; then - AC_LIBTOOL_LANG_F77_CONFIG - available_tags="$available_tags _LT_TAG" - fi], - [GCJ], [ - if test -n "$GCJ" && test "X$GCJ" != "Xno"; then - AC_LIBTOOL_LANG_GCJ_CONFIG - available_tags="$available_tags _LT_TAG" - fi], - [RC], [ - if test -n "$RC" && test "X$RC" != "Xno"; then - AC_LIBTOOL_LANG_RC_CONFIG - available_tags="$available_tags _LT_TAG" - fi], - [m4_errprintn(m4_location[: error: invalid tag name: ]"_LT_TAG") - m4_exit(1)]) - ]) - echo THOMAS: available tags: $available_tags - fi - # Now substitute the updated list of available tags. - if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then - mv "${ofile}T" "$ofile" - chmod +x "$ofile" - AC_MSG_NOTICE([updated available libtool tags with $available_tags.]) - else - rm -f "${ofile}T" - AC_MSG_ERROR([unable to update list of available tagged configurations.]) - - fi - -])dnl _LT_AC_TAG_CONFIG -]) diff --git a/common/m4/as-libtool.m4 b/common/m4/as-libtool.m4 deleted file mode 100644 index 73dec1f408..0000000000 --- a/common/m4/as-libtool.m4 +++ /dev/null @@ -1,45 +0,0 @@ -dnl as-libtool.m4 0.1.4 - -dnl autostars m4 macro for libtool versioning - -dnl Thomas Vander Stichele - -dnl $Id: as-libtool.m4,v 1.6 2004/06/01 10:04:44 thomasvs Exp $ - -dnl AS_LIBTOOL(PREFIX, CURRENT, REVISION, AGE, [RELEASE]) - -dnl example -dnl AS_LIBTOOL(GST, 2, 0, 0) - -dnl this macro -dnl - defines [$PREFIX]_CURRENT, REVISION and AGE -dnl - defines [$PREFIX]_LIBVERSION -dnl - defines [$PREFIX]_LT_LDFLAGS to set versioning -dnl - AC_SUBST's them all - -dnl if RELEASE is given, then add a -release option to the LDFLAGS -dnl with the given release version -dnl then use [$PREFIX]_LT_LDFLAGS in the relevant Makefile.am's - -dnl call AM_PROG_LIBTOOL after this call - -AC_DEFUN([AS_LIBTOOL], -[ - [$1]_CURRENT=[$2] - [$1]_REVISION=[$3] - [$1]_AGE=[$4] - [$1]_LIBVERSION=[$2]:[$3]:[$4] - AC_SUBST([$1]_CURRENT) - AC_SUBST([$1]_REVISION) - AC_SUBST([$1]_AGE) - AC_SUBST([$1]_LIBVERSION) - - [$1]_LT_LDFLAGS="$[$1]_LT_LDFLAGS -version-info $[$1]_LIBVERSION" - if test ! -z "[$5]" - then - [$1]_LT_LDFLAGS="$[$1]_LT_LDFLAGS -release [$5]" - fi - AC_SUBST([$1]_LT_LDFLAGS) - - AC_LIBTOOL_DLOPEN -]) diff --git a/common/m4/as-python.m4 b/common/m4/as-python.m4 deleted file mode 100644 index eb9b1754de..0000000000 --- a/common/m4/as-python.m4 +++ /dev/null @@ -1,152 +0,0 @@ -## ------------------------ -## Python file handling -## From Andrew Dalke -## Updated by James Henstridge -## Updated by Andy Wingo to loop through possible pythons -## ------------------------ - -# AS_PATH_PYTHON([MINIMUM-VERSION]) - -# Adds support for distributing Python modules and packages. To -# install modules, copy them to $(pythondir), using the python_PYTHON -# automake variable. To install a package with the same name as the -# automake package, install to $(pkgpythondir), or use the -# pkgpython_PYTHON automake variable. - -# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as -# locations to install python extension modules (shared libraries). -# Another macro is required to find the appropriate flags to compile -# extension modules. - -# If your package is configured with a different prefix to python, -# users will have to add the install directory to the PYTHONPATH -# environment variable, or create a .pth file (see the python -# documentation for details). - -# If the MINIMUM-VERSION argument is passed, AS_PATH_PYTHON will -# cause an error if the version of python installed on the system -# doesn't meet the requirement. MINIMUM-VERSION should consist of -# numbers and dots only. - -# Updated to loop over all possible python binaries by Andy Wingo -# -# Updated to only warn and unset PYTHON if no good one is found - -AC_DEFUN([AS_PATH_PYTHON], - [ - dnl Find a version of Python. I could check for python versions 1.4 - dnl or earlier, but the default installation locations changed from - dnl $prefix/lib/site-python in 1.4 to $prefix/lib/python1.5/site-packages - dnl in 1.5, and I don't want to maintain that logic. - - dnl should we do the version check? - PYTHON_CANDIDATES="python python2.2 python2.1 python2.0 python2 \ - python1.6 python1.5" - ifelse([$1],[], - [AC_PATH_PROG(PYTHON, $PYTHON_CANDIDATES)], - [ - AC_MSG_NOTICE(Looking for Python version >= $1) - changequote(<<, >>)dnl - prog=" -import sys, string -minver = '$1' -# split string by '.' and convert to numeric -minver_info = map(string.atoi, string.split(minver, '.')) -# we can now do comparisons on the two lists: -if sys.version_info >= tuple(minver_info): - sys.exit(0) -else: - sys.exit(1)" - changequote([, ])dnl - - python_good=false - for python_candidate in $PYTHON_CANDIDATES; do - unset PYTHON - AC_PATH_PROG(PYTHON, $python_candidate) 1> /dev/null 2> /dev/null - - if test "x$PYTHON" = "x"; then continue; fi - - if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC; then - AC_MSG_CHECKING(["$PYTHON":]) - AC_MSG_RESULT([okay]) - python_good=true - break; - else - dnl clear the cache val - unset ac_cv_path_PYTHON - fi - done - ]) - - if test "$python_good" != "true"; then - AC_MSG_WARN([No suitable version of python found]) - PYTHON= - else - - AC_MSG_CHECKING([local Python configuration]) - - dnl Query Python for its version number. Getting [:3] seems to be - dnl the best way to do this; it's what "site.py" does in the standard - dnl library. Need to change quote character because of [:3] - - AC_SUBST(PYTHON_VERSION) - changequote(<<, >>)dnl - PYTHON_VERSION=`$PYTHON -c "import sys; print sys.version[:3]"` - changequote([, ])dnl - - - dnl Use the values of $prefix and $exec_prefix for the corresponding - dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made - dnl distinct variables so they can be overridden if need be. However, - dnl general consensus is that you shouldn't need this ability. - - AC_SUBST(PYTHON_PREFIX) - PYTHON_PREFIX='${prefix}' - - AC_SUBST(PYTHON_EXEC_PREFIX) - PYTHON_EXEC_PREFIX='${exec_prefix}' - - dnl At times (like when building shared libraries) you may want - dnl to know which OS platform Python thinks this is. - - AC_SUBST(PYTHON_PLATFORM) - PYTHON_PLATFORM=`$PYTHON -c "import sys; print sys.platform"` - - - dnl Set up 4 directories: - - dnl pythondir -- where to install python scripts. This is the - dnl site-packages directory, not the python standard library - dnl directory like in previous automake betas. This behaviour - dnl is more consistent with lispdir.m4 for example. - dnl - dnl Also, if the package prefix isn't the same as python's prefix, - dnl then the old $(pythondir) was pretty useless. - - AC_SUBST(pythondir) - pythondir=$PYTHON_PREFIX"/lib/python"$PYTHON_VERSION/site-packages - - dnl pkgpythondir -- $PACKAGE directory under pythondir. Was - dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is - dnl more consistent with the rest of automake. - dnl Maybe this should be put in python.am? - - AC_SUBST(pkgpythondir) - pkgpythondir=\${pythondir}/$PACKAGE - - dnl pyexecdir -- directory for installing python extension modules - dnl (shared libraries) Was PYTHON_SITE_EXEC in previous betas. - - AC_SUBST(pyexecdir) - pyexecdir=$PYTHON_EXEC_PREFIX"/lib/python"$PYTHON_VERSION/site-packages - - dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) - dnl Maybe this should be put in python.am? - - AC_SUBST(pkgpyexecdir) - pkgpyexecdir=\${pyexecdir}/$PACKAGE - - AC_MSG_RESULT([looks good]) - - fi -]) diff --git a/common/m4/as-scrub-include.m4 b/common/m4/as-scrub-include.m4 deleted file mode 100644 index 96dfb8f088..0000000000 --- a/common/m4/as-scrub-include.m4 +++ /dev/null @@ -1,36 +0,0 @@ -dnl as-scrub-include.m4 0.0.4 - -dnl autostars m4 macro for scrubbing CFLAGS of system include dirs -dnl because gcc 3.x complains about including system including dirs - -dnl Thomas Vander Stichele - -dnl $Id: as-scrub-include.m4,v 1.5 2004/06/12 08:19:09 thomasvs Exp $ - -dnl This macro uses output of cpp -v and expects it to contain text that -dnl looks a little bit like this: -dnl #include <...> search starts here: -dnl /usr/local/include -dnl /usr/lib/gcc-lib/i386-redhat-linux/3.2/include -dnl /usr/include -dnl End of search list. - -dnl AS_SCRUB_INCLUDE(VAR) -dnl example -dnl AS_SCRUB_INCLUDE(CFLAGS) -dnl will remove all system include dirs from the given CFLAGS - -AC_DEFUN([AS_SCRUB_INCLUDE], -[ - GIVEN_CFLAGS=$[$1] - INCLUDE_DIRS=`echo | cpp -v 2>&1` - - dnl remove everything from this output between the "starts here" and "End of" - dnl line - INCLUDE_DIRS=`echo $INCLUDE_DIRS | sed -e 's/.*<...> search starts here://' | sed -e 's/End of search list.*//'` - for dir in $INCLUDE_DIRS; do - dnl use "" as the sed script so $dir gets expanded - GIVEN_CFLAGS=`echo $GIVEN_CFLAGS | sed -e "s#-I$dir ##"` - done - [$1]=$GIVEN_CFLAGS -]) diff --git a/common/m4/as-version.m4 b/common/m4/as-version.m4 deleted file mode 100644 index a5b439903e..0000000000 --- a/common/m4/as-version.m4 +++ /dev/null @@ -1,71 +0,0 @@ -dnl as-version.m4 0.2.0 - -dnl autostars m4 macro for versioning - -dnl Thomas Vander Stichele - -dnl $Id: as-version.m4,v 1.4 2004/06/01 09:40:05 thomasvs Exp $ - -dnl AS_VERSION - -dnl example -dnl AS_VERSION - -dnl this macro -dnl - AC_SUBST's PACKAGE_VERSION_MAJOR, _MINOR, _MICRO -dnl - AC_SUBST's PACKAGE_VERSION_RELEASE, -dnl which can be used for rpm release fields -dnl - doesn't call AM_INIT_AUTOMAKE anymore because it prevents -dnl maintainer mode from running correctly -dnl -dnl don't forget to put #undef PACKAGE_VERSION_RELEASE in acconfig.h -dnl if you use acconfig.h - -AC_DEFUN([AS_VERSION], -[ - PACKAGE_VERSION_MAJOR=$(echo AC_PACKAGE_VERSION | cut -d'.' -f1) - PACKAGE_VERSION_MINOR=$(echo AC_PACKAGE_VERSION | cut -d'.' -f2) - PACKAGE_VERSION_MICRO=$(echo AC_PACKAGE_VERSION | cut -d'.' -f3) - - AC_SUBST(PACKAGE_VERSION_MAJOR) - AC_SUBST(PACKAGE_VERSION_MINOR) - AC_SUBST(PACKAGE_VERSION_MICRO) -]) - -dnl AS_NANO(ACTION-IF-NO-NANO, [ACTION-IF-NANO]) - -dnl requires AC_INIT to be called before -dnl For projects using a fourth or nano number in your versioning to indicate -dnl development or prerelease snapshots, this macro allows the build to be -dnl set up differently accordingly. - -dnl this macro: -dnl - parses AC_PACKAGE_VERSION, set by AC_INIT, and extracts the nano number -dnl - sets the variable PACKAGE_VERSION_NANO -dnl - sets the variable PACKAGE_VERSION_RELEASE, which can be used -dnl for rpm release fields -dnl - executes ACTION-IF-NO-NANO or ACTION-IF-NANO - -dnl example: -dnl AS_NANO(RELEASE="yes", RELEASE="no") - -AC_DEFUN([AS_NANO], -[ - AC_MSG_CHECKING(nano version) - - NANO=$(echo AC_PACKAGE_VERSION | cut -d'.' -f4) - - if test x"$NANO" = x || test "x$NANO" = "x0" ; then - AC_MSG_RESULT([0 (release)]) - NANO=0 - PACKAGE_VERSION_RELEASE=1 - ifelse([$1], , :, [$1]) - else - AC_MSG_RESULT($NANO) - PACKAGE_VERSION_RELEASE=0.`date +%Y%m%d.%H%M%S` - ifelse([$2], , :, [$2]) - fi - PACKAGE_VERSION_NANO=$NANO - AC_SUBST(PACKAGE_VERSION_NANO) - AC_SUBST(PACKAGE_VERSION_RELEASE) -]) diff --git a/common/m4/ax_create_stdint_h.m4 b/common/m4/ax_create_stdint_h.m4 deleted file mode 100644 index 061619fb1f..0000000000 --- a/common/m4/ax_create_stdint_h.m4 +++ /dev/null @@ -1,569 +0,0 @@ -dnl @synopsis AX_CREATE_STDINT_H [( HEADER-TO-GENERATE [, HEDERS-TO-CHECK])] -dnl -dnl the "ISO C9X: 7.18 Integer types " section requires the -dnl existence of an include file that defines a set of -dnl typedefs, especially uint8_t,int32_t,uintptr_t. -dnl Many older installations will not provide this file, but some will -dnl have the very same definitions in . In other enviroments -dnl we can use the inet-types in which would define the -dnl typedefs int8_t and u_int8_t respectivly. -dnl -dnl This macros will create a local "_stdint.h" or the headerfile given as -dnl an argument. In many cases that file will just "#include " -dnl or "#include ", while in other environments it will provide -dnl the set of basic 'stdint's definitions/typedefs: -dnl int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,intptr_t,uintptr_t -dnl int_least32_t.. int_fast32_t.. intmax_t -dnl which may or may not rely on the definitions of other files, -dnl or using the AC_CHECK_SIZEOF macro to determine the actual -dnl sizeof each type. -dnl -dnl if your header files require the stdint-types you will want to create an -dnl installable file mylib-int.h that all your other installable header -dnl may include. So if you have a library package named "mylib", just use -dnl AX_CREATE_STDINT_H(mylib-int.h) -dnl in configure.ac and go to install that very header file in Makefile.am -dnl along with the other headers (mylib.h) - and the mylib-specific headers -dnl can simply use "#include " to obtain the stdint-types. -dnl -dnl Remember, if the system already had a valid , the generated -dnl file will include it directly. No need for fuzzy HAVE_STDINT_H things... -dnl -dnl @, (status: used on new platforms) (see http://ac-archive.sf.net/gstdint/) -dnl @version $Id: ax_create_stdint_h.m4,v 1.2 2004/03/09 14:57:53 thomasvs Exp $ -dnl @author Guido Draheim - -AC_DEFUN([AX_CREATE_STDINT_H], -[# ------ AX CREATE STDINT H ------------------------------------- -AC_MSG_CHECKING([for stdint types]) -ac_stdint_h=`echo ifelse($1, , _stdint.h, $1)` -# try to shortcircuit - if the default include path of the compiler -# can find a "stdint.h" header then we assume that all compilers can. -AC_CACHE_VAL([ac_cv_header_stdint_t],[ -old_CXXFLAGS="$CXXFLAGS" ; CXXFLAGS="" -old_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS="" -old_CFLAGS="$CFLAGS" ; CFLAGS="" -AC_TRY_COMPILE([#include ],[int_least32_t v = 0;], -[ac_cv_stdint_result="(assuming C99 compatible system)" - ac_cv_header_stdint_t="stdint.h"; ], -[ac_cv_header_stdint_t=""]) -CXXFLAGS="$old_CXXFLAGS" -CPPFLAGS="$old_CPPFLAGS" -CFLAGS="$old_CFLAGS" ]) - -v="... $ac_cv_header_stdint_h" -if test "$ac_stdint_h" = "stdint.h" ; then - AC_MSG_RESULT([(are you sure you want them in ./stdint.h?)]) -elif test "$ac_stdint_h" = "inttypes.h" ; then - AC_MSG_RESULT([(are you sure you want them in ./inttypes.h?)]) -elif test "_$ac_cv_header_stdint_t" = "_" ; then - AC_MSG_RESULT([(putting them into $ac_stdint_h)$v]) -else - ac_cv_header_stdint="$ac_cv_header_stdint_t" - AC_MSG_RESULT([$ac_cv_header_stdint (shortcircuit)]) -fi - -if test "_$ac_cv_header_stdint_t" = "_" ; then # can not shortcircuit.. - -dnl .....intro message done, now do a few system checks..... -dnl btw, all CHECK_TYPE macros do automatically "DEFINE" a type, therefore -dnl we use the autoconf implementation detail _AC CHECK_TYPE_NEW instead - -inttype_headers=`echo $2 | sed -e 's/,/ /g'` - -ac_cv_stdint_result="(no helpful system typedefs seen)" -AC_CACHE_CHECK([for stdint uintptr_t], [ac_cv_header_stdint_x],[ - ac_cv_header_stdint_x="" # the 1997 typedefs (inttypes.h) - AC_MSG_RESULT([(..)]) - for i in stdint.h inttypes.h sys/inttypes.h $inttype_headers ; do - unset ac_cv_type_uintptr_t - unset ac_cv_type_uint64_t - _AC_CHECK_TYPE_NEW(uintptr_t,[ac_cv_header_stdint_x=$i],dnl - continue,[#include <$i>]) - AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) - ac_cv_stdint_result="(seen uintptr_t$and64 in $i)" - break; - done - AC_MSG_CHECKING([for stdint uintptr_t]) - ]) - -if test "_$ac_cv_header_stdint_x" = "_" ; then -AC_CACHE_CHECK([for stdint uint32_t], [ac_cv_header_stdint_o],[ - ac_cv_header_stdint_o="" # the 1995 typedefs (sys/inttypes.h) - AC_MSG_RESULT([(..)]) - for i in inttypes.h sys/inttypes.h stdint.h $inttype_headers ; do - unset ac_cv_type_uint32_t - unset ac_cv_type_uint64_t - AC_CHECK_TYPE(uint32_t,[ac_cv_header_stdint_o=$i],dnl - continue,[#include <$i>]) - AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) - ac_cv_stdint_result="(seen uint32_t$and64 in $i)" - break; - done - AC_MSG_CHECKING([for stdint uint32_t]) - ]) -fi - -if test "_$ac_cv_header_stdint_x" = "_" ; then -if test "_$ac_cv_header_stdint_o" = "_" ; then -AC_CACHE_CHECK([for stdint u_int32_t], [ac_cv_header_stdint_u],[ - ac_cv_header_stdint_u="" # the BSD typedefs (sys/types.h) - AC_MSG_RESULT([(..)]) - for i in sys/types.h inttypes.h sys/inttypes.h $inttype_headers ; do - unset ac_cv_type_u_int32_t - unset ac_cv_type_u_int64_t - AC_CHECK_TYPE(u_int32_t,[ac_cv_header_stdint_u=$i],dnl - continue,[#include <$i>]) - AC_CHECK_TYPE(u_int64_t,[and64="/u_int64_t"],[and64=""],[#include<$i>]) - ac_cv_stdint_result="(seen u_int32_t$and64 in $i)" - break; - done - AC_MSG_CHECKING([for stdint u_int32_t]) - ]) -fi fi - -dnl if there was no good C99 header file, do some typedef checks... -if test "_$ac_cv_header_stdint_x" = "_" ; then - AC_MSG_CHECKING([for stdint datatype model]) - AC_MSG_RESULT([(..)]) - AC_CHECK_SIZEOF(char) - AC_CHECK_SIZEOF(short) - AC_CHECK_SIZEOF(int) - AC_CHECK_SIZEOF(long) - AC_CHECK_SIZEOF(void*) - ac_cv_stdint_char_model="" - ac_cv_stdint_char_model="$ac_cv_stdint_char_model$ac_cv_sizeof_char" - ac_cv_stdint_char_model="$ac_cv_stdint_char_model$ac_cv_sizeof_short" - ac_cv_stdint_char_model="$ac_cv_stdint_char_model$ac_cv_sizeof_int" - ac_cv_stdint_long_model="" - ac_cv_stdint_long_model="$ac_cv_stdint_long_model$ac_cv_sizeof_int" - ac_cv_stdint_long_model="$ac_cv_stdint_long_model$ac_cv_sizeof_long" - ac_cv_stdint_long_model="$ac_cv_stdint_long_model$ac_cv_sizeof_voidp" - name="$ac_cv_stdint_long_model" - case "$ac_cv_stdint_char_model/$ac_cv_stdint_long_model" in - 122/242) name="$name, IP16 (standard 16bit machine)" ;; - 122/244) name="$name, LP32 (standard 32bit mac/win)" ;; - 122/*) name="$name (unusual int16 model)" ;; - 124/444) name="$name, ILP32 (standard 32bit unixish)" ;; - 124/488) name="$name, LP64 (standard 64bit unixish)" ;; - 124/448) name="$name, LLP64 (unusual 64bit unixish)" ;; - 124/*) name="$name (unusual int32 model)" ;; - 128/888) name="$name, ILP64 (unusual 64bit numeric)" ;; - 128/*) name="$name (unusual int64 model)" ;; - 222/*|444/*) name="$name (unusual dsptype)" ;; - *) name="$name (very unusal model)" ;; - esac - AC_MSG_RESULT([combined for stdint datatype model... $name]) -fi - -if test "_$ac_cv_header_stdint_x" != "_" ; then - ac_cv_header_stdint="$ac_cv_header_stdint_x" -elif test "_$ac_cv_header_stdint_o" != "_" ; then - ac_cv_header_stdint="$ac_cv_header_stdint_o" -elif test "_$ac_cv_header_stdint_u" != "_" ; then - ac_cv_header_stdint="$ac_cv_header_stdint_u" -else - ac_cv_header_stdint="stddef.h" -fi - -AC_MSG_CHECKING([for extra inttypes in chosen header]) -AC_MSG_RESULT([($ac_cv_header_stdint)]) -dnl see if int_least and int_fast types are present in _this_ header. -unset ac_cv_type_int_least32_t -unset ac_cv_type_int_fast32_t -AC_CHECK_TYPE(int_least32_t,,,[#include <$ac_cv_header_stdint>]) -AC_CHECK_TYPE(int_fast32_t,,,[#include<$ac_cv_header_stdint>]) -AC_CHECK_TYPE(intmax_t,,,[#include <$ac_cv_header_stdint>]) - -fi # shortcircut to system "stdint.h" -# ------------------ PREPARE VARIABLES ------------------------------ -if test "$GCC" = "yes" ; then -ac_cv_stdint_message="using gnu compiler "`$CC --version | head -n 1` -else -ac_cv_stdint_message="using $CC" -fi - -AC_MSG_RESULT([make use of $ac_cv_header_stdint in $ac_stdint_h dnl -$ac_cv_stdint_result]) - -# ----------------- DONE inttypes.h checks START header ------------- -AC_CONFIG_COMMANDS([$ac_stdint_h],[ -AC_MSG_NOTICE(creating $ac_stdint_h : $_ac_stdint_h) -ac_stdint=$tmp/_stdint.h - -echo "#ifndef" $_ac_stdint_h >$ac_stdint -echo "#define" $_ac_stdint_h "1" >>$ac_stdint -echo "#ifndef" _GENERATED_STDINT_H >>$ac_stdint -echo "#define" _GENERATED_STDINT_H '"'$PACKAGE $VERSION'"' >>$ac_stdint -echo "/* generated $ac_cv_stdint_message */" >>$ac_stdint -if test "_$ac_cv_header_stdint_t" != "_" ; then -echo "#define _STDINT_HAVE_STDINT_H" "1" >>$ac_stdint -fi - -cat >>$ac_stdint < -#else -#include - -/* .................... configured part ............................ */ - -STDINT_EOF - -echo "/* whether we have a C99 compatible stdint header file */" >>$ac_stdint -if test "_$ac_cv_header_stdint_x" != "_" ; then - ac_header="$ac_cv_header_stdint_x" - echo "#define _STDINT_HEADER_INTPTR" '"'"$ac_header"'"' >>$ac_stdint -else - echo "/* #undef _STDINT_HEADER_INTPTR */" >>$ac_stdint -fi - -echo "/* whether we have a C96 compatible inttypes header file */" >>$ac_stdint -if test "_$ac_cv_header_stdint_o" != "_" ; then - ac_header="$ac_cv_header_stdint_o" - echo "#define _STDINT_HEADER_UINT32" '"'"$ac_header"'"' >>$ac_stdint -else - echo "/* #undef _STDINT_HEADER_UINT32 */" >>$ac_stdint -fi - -echo "/* whether we have a BSD compatible inet types header */" >>$ac_stdint -if test "_$ac_cv_header_stdint_u" != "_" ; then - ac_header="$ac_cv_header_stdint_u" - echo "#define _STDINT_HEADER_U_INT32" '"'"$ac_header"'"' >>$ac_stdint -else - echo "/* #undef _STDINT_HEADER_U_INT32 */" >>$ac_stdint -fi - -echo "" >>$ac_stdint - -if test "_$ac_header" != "_" ; then if test "$ac_header" != "stddef.h" ; then - echo "#include <$ac_header>" >>$ac_stdint - echo "" >>$ac_stdint -fi fi - -echo "/* which 64bit typedef has been found */" >>$ac_stdint -if test "$ac_cv_type_uint64_t" = "yes" ; then -echo "#define _STDINT_HAVE_UINT64_T" "1" >>$ac_stdint -else -echo "/* #undef _STDINT_HAVE_UINT64_T */" >>$ac_stdint -fi -if test "$ac_cv_type_u_int64_t" = "yes" ; then -echo "#define _STDINT_HAVE_U_INT64_T" "1" >>$ac_stdint -else -echo "/* #undef _STDINT_HAVE_U_INT64_T */" >>$ac_stdint -fi -echo "" >>$ac_stdint - -echo "/* which type model has been detected */" >>$ac_stdint -if test "_$ac_cv_stdint_char_model" != "_" ; then -echo "#define _STDINT_CHAR_MODEL" "$ac_cv_stdint_char_model" >>$ac_stdint -echo "#define _STDINT_LONG_MODEL" "$ac_cv_stdint_long_model" >>$ac_stdint -else -echo "/* #undef _STDINT_CHAR_MODEL // skipped */" >>$ac_stdint -echo "/* #undef _STDINT_LONG_MODEL // skipped */" >>$ac_stdint -fi -echo "" >>$ac_stdint - -echo "/* whether int_least types were detected */" >>$ac_stdint -if test "$ac_cv_type_int_least32_t" = "yes"; then -echo "#define _STDINT_HAVE_INT_LEAST32_T" "1" >>$ac_stdint -else -echo "/* #undef _STDINT_HAVE_INT_LEAST32_T */" >>$ac_stdint -fi -echo "/* whether int_fast types were detected */" >>$ac_stdint -if test "$ac_cv_type_int_fast32_t" = "yes"; then -echo "#define _STDINT_HAVE_INT_FAST32_T" "1" >>$ac_stdint -else -echo "/* #undef _STDINT_HAVE_INT_FAST32_T */" >>$ac_stdint -fi -echo "/* whether intmax_t type was detected */" >>$ac_stdint -if test "$ac_cv_type_intmax_t" = "yes"; then -echo "#define _STDINT_HAVE_INTMAX_T" "1" >>$ac_stdint -else -echo "/* #undef _STDINT_HAVE_INTMAX_T */" >>$ac_stdint -fi -echo "" >>$ac_stdint - - cat >>$ac_stdint <= 199901L -#define _HAVE_UINT64_T -typedef long long int64_t; -typedef unsigned long long uint64_t; - -#elif !defined __STRICT_ANSI__ -#if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ -#define _HAVE_UINT64_T -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; - -#elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__ -/* note: all ELF-systems seem to have loff-support which needs 64-bit */ -#if !defined _NO_LONGLONG -#define _HAVE_UINT64_T -typedef long long int64_t; -typedef unsigned long long uint64_t; -#endif - -#elif defined __alpha || (defined __mips && defined _ABIN32) -#if !defined _NO_LONGLONG -typedef long int64_t; -typedef unsigned long uint64_t; -#endif - /* compiler/cpu type to define int64_t */ -#endif -#endif -#endif - -#if defined _STDINT_HAVE_U_INT_TYPES -/* int8_t int16_t int32_t defined by inet code, redeclare the u_intXX types */ -typedef u_int8_t uint8_t; -typedef u_int16_t uint16_t; -typedef u_int32_t uint32_t; - -/* glibc compatibility */ -#ifndef __int8_t_defined -#define __int8_t_defined -#endif -#endif - -#ifdef _STDINT_NEED_INT_MODEL_T -/* we must guess all the basic types. Apart from byte-adressable system, */ -/* there a few 32-bit-only dsp-systems that we guard with BYTE_MODEL 8-} */ -/* (btw, those nibble-addressable systems are way off, or so we assume) */ - -dnl /* have a look at "64bit and data size neutrality" at */ -dnl /* http://unix.org/version2/whatsnew/login_64bit.html */ -dnl /* (the shorthand "ILP" types always have a "P" part) */ - -#if defined _STDINT_BYTE_MODEL -#if _STDINT_LONG_MODEL+0 == 242 -/* 2:4:2 = IP16 = a normal 16-bit system */ -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned long uint32_t; -#ifndef __int8_t_defined -#define __int8_t_defined -typedef char int8_t; -typedef short int16_t; -typedef long int32_t; -#endif -#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL == 444 -/* 2:4:4 = LP32 = a 32-bit system derived from a 16-bit */ -/* 4:4:4 = ILP32 = a normal 32-bit system */ -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -#ifndef __int8_t_defined -#define __int8_t_defined -typedef char int8_t; -typedef short int16_t; -typedef int int32_t; -#endif -#elif _STDINT_LONG_MODEL+0 == 484 || _STDINT_LONG_MODEL+0 == 488 -/* 4:8:4 = IP32 = a 32-bit system prepared for 64-bit */ -/* 4:8:8 = LP64 = a normal 64-bit system */ -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -#ifndef __int8_t_defined -#define __int8_t_defined -typedef char int8_t; -typedef short int16_t; -typedef int int32_t; -#endif -/* this system has a "long" of 64bit */ -#ifndef _HAVE_UINT64_T -#define _HAVE_UINT64_T -typedef unsigned long uint64_t; -typedef long int64_t; -#endif -#elif _STDINT_LONG_MODEL+0 == 448 -/* LLP64 a 64-bit system derived from a 32-bit system */ -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -#ifndef __int8_t_defined -#define __int8_t_defined -typedef char int8_t; -typedef short int16_t; -typedef int int32_t; -#endif -/* assuming the system has a "long long" */ -#ifndef _HAVE_UINT64_T -#define _HAVE_UINT64_T -typedef unsigned long long uint64_t; -typedef long long int64_t; -#endif -#else -#define _STDINT_NO_INT32_T -#endif -#else -#define _STDINT_NO_INT8_T -#define _STDINT_NO_INT32_T -#endif -#endif - -/* - * quote from SunOS-5.8 sys/inttypes.h: - * Use at your own risk. As of February 1996, the committee is squarely - * behind the fixed sized types; the "least" and "fast" types are still being - * discussed. The probability that the "fast" types may be removed before - * the standard is finalized is high enough that they are not currently - * implemented. - */ - -#if defined _STDINT_NEED_INT_LEAST_T -typedef int8_t int_least8_t; -typedef int16_t int_least16_t; -typedef int32_t int_least32_t; -#ifdef _HAVE_UINT64_T -typedef int64_t int_least64_t; -#endif - -typedef uint8_t uint_least8_t; -typedef uint16_t uint_least16_t; -typedef uint32_t uint_least32_t; -#ifdef _HAVE_UINT64_T -typedef uint64_t uint_least64_t; -#endif - /* least types */ -#endif - -#if defined _STDINT_NEED_INT_FAST_T -typedef int8_t int_fast8_t; -typedef int int_fast16_t; -typedef int32_t int_fast32_t; -#ifdef _HAVE_UINT64_T -typedef int64_t int_fast64_t; -#endif - -typedef uint8_t uint_fast8_t; -typedef unsigned uint_fast16_t; -typedef uint32_t uint_fast32_t; -#ifdef _HAVE_UINT64_T -typedef uint64_t uint_fast64_t; -#endif - /* fast types */ -#endif - -#ifdef _STDINT_NEED_INTMAX_T -#ifdef _HAVE_UINT64_T -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; -#else -typedef long intmax_t; -typedef unsigned long uintmax_t; -#endif -#endif - -#ifdef _STDINT_NEED_INTPTR_T -#ifndef __intptr_t_defined -#define __intptr_t_defined -/* we encourage using "long" to store pointer values, never use "int" ! */ -#if _STDINT_LONG_MODEL+0 == 242 || _STDINT_LONG_MODEL+0 == 484 -typedef unsinged int uintptr_t; -typedef int intptr_t; -#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL+0 == 444 -typedef unsigned long uintptr_t; -typedef long intptr_t; -#elif _STDINT_LONG_MODEL+0 == 448 && defined _HAVE_UINT64_T -typedef uint64_t uintptr_t; -typedef int64_t intptr_t; -#else /* matches typical system types ILP32 and LP64 - but not IP16 or LLP64 */ -typedef unsigned long uintptr_t; -typedef long intptr_t; -#endif -#endif -#endif - - /* shortcircuit*/ -#endif - /* once */ -#endif -#endif -STDINT_EOF - if cmp -s $ac_stdint_h $ac_stdint 2>/dev/null; then - AC_MSG_NOTICE([$ac_stdint_h is unchanged]) - else - ac_dir=`AS_DIRNAME(["$ac_stdint_h"])` - AS_MKDIR_P(["$ac_dir"]) - rm -f $ac_stdint_h - mv $ac_stdint $ac_stdint_h - fi -],[# variables for create stdint.h replacement -PACKAGE="$PACKAGE" -VERSION="$VERSION" -ac_stdint_h="$ac_stdint_h" -_ac_stdint_h=AS_TR_CPP(_$PACKAGE-$ac_stdint_h) -ac_cv_stdint_message="$ac_cv_stdint_message" -ac_cv_header_stdint_t="$ac_cv_header_stdint_t" -ac_cv_header_stdint_x="$ac_cv_header_stdint_x" -ac_cv_header_stdint_o="$ac_cv_header_stdint_o" -ac_cv_header_stdint_u="$ac_cv_header_stdint_u" -ac_cv_type_uint64_t="$ac_cv_type_uint64_t" -ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t" -ac_cv_stdint_char_model="$ac_cv_stdint_char_model" -ac_cv_stdint_long_model="$ac_cv_stdint_long_model" -ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t" -ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t" -ac_cv_type_intmax_t="$ac_cv_type_intmax_t" -]) -]) diff --git a/common/m4/check.m4 b/common/m4/check.m4 deleted file mode 100644 index 19784ae01f..0000000000 --- a/common/m4/check.m4 +++ /dev/null @@ -1,181 +0,0 @@ -dnl _AM_TRY_CHECK(MINIMUM-VERSION, EXTRA-CFLAGS, EXTRA-LIBS, CHECK-LIB-NAME -dnl [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) -dnl Test for check, and define CHECK_CFLAGS and CHECK_LIBS -dnl Done this way because of the brokenness that is -dnl https://launchpad.net/distros/ubuntu/+source/check/+bug/5840 -dnl - -AC_DEFUN([_AM_TRY_CHECK], -[ - min_check_version=$1 - extra_cflags=$2 - extra_libs=$3 - check_lib_name=$4 - - CHECK_CFLAGS="$extra_cflags" - CHECK_LIBS="$extra_libs -l$check_lib_name" - - ac_save_CFLAGS="$CFLAGS" - ac_save_LIBS="$LIBS" - - CFLAGS="$CFLAGS $CHECK_CFLAGS" - LIBS="$CHECK_LIBS $LIBS" - - AC_MSG_CHECKING(for check named $check_lib_name - version >= $min_check_version) - - rm -f conf.check-test - dnl unset no_check, since in our second run it would have been set to yes - dnl before - no_check= - AC_TRY_RUN([ -#include -#include - -#include - -int main () -{ - int major, minor, micro; - char *tmp_version; - - system ("touch conf.check-test"); - - /* HP/UX 9 (%@#!) writes to sscanf strings */ - tmp_version = strdup("$min_check_version"); - if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { - printf("%s, bad version string\n", "$min_check_version"); - return 1; - } - - if ((CHECK_MAJOR_VERSION != check_major_version) || - (CHECK_MINOR_VERSION != check_minor_version) || - (CHECK_MICRO_VERSION != check_micro_version)) - { - printf("\n*** The check header file (version %d.%d.%d) does not match\n", - CHECK_MAJOR_VERSION, CHECK_MINOR_VERSION, CHECK_MICRO_VERSION); - printf("*** the check library (version %d.%d.%d).\n", - check_major_version, check_minor_version, check_micro_version); - return 1; - } - - if ((check_major_version > major) || - ((check_major_version == major) && (check_minor_version > minor)) || - ((check_major_version == major) && (check_minor_version == minor) && (check_micro_version >= micro))) - { - return 0; - } - else - { - printf("\n*** An old version of check (%d.%d.%d) was found.\n", - check_major_version, check_minor_version, check_micro_version); - printf("*** You need a version of check being at least %d.%d.%d.\n", major, minor, micro); - printf("***\n"); - printf("*** If you have already installed a sufficiently new version, this error\n"); - printf("*** probably means that the wrong copy of the check library and header\n"); - printf("*** file is being found. Rerun configure with the --with-check=PATH option\n"); - printf("*** to specify the prefix where the correct version was installed.\n"); - } - - return 1; -} -],, no_check=yes, [echo $ac_n "cross compiling; assumed OK... $ac_c"]) - - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - - if test "x$no_check" = x ; then - AC_MSG_RESULT(yes) - ifelse([$5], , :, [$5]) - else - AC_MSG_RESULT(no) - if test -f conf.check-test ; then - : - else - echo "*** Could not run check test program, checking why..." - CFLAGS="$CFLAGS $CHECK_CFLAGS" - LIBS="$CHECK_LIBS $LIBS" - AC_TRY_LINK([ -#include -#include - -#include -], , [ echo "*** The test program compiled, but did not run. This usually means" - echo "*** that the run-time linker is not finding check. You'll need to set your" - echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" - echo "*** to the installed location Also, make sure you have run ldconfig if that" - echo "*** is required on your system" - echo "***" - echo "*** If you have an old version installed, it is best to remove it, although" - echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], - [ echo "*** The test program failed to compile or link. See the file config.log for" - echo "*** the exact error that occured." ]) - - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - - CHECK_CFLAGS="" - CHECK_LIBS="" - - rm -f conf.check-test - ifelse([$6], , AC_MSG_ERROR([check not found]), [$6]) - fi -]) - - -dnl AM_PATH_CHECK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) -dnl Test for check, and define CHECK_CFLAGS and CHECK_LIBS -dnl - -AC_DEFUN([AM_PATH_CHECK], -[ - AC_ARG_WITH(check, - [ --with-check=PATH prefix where check is installed [default=auto]]) - - AC_ARG_WITH(checklibname, - AC_HELP_STRING([--with-check-lib-name=NAME], - [name of the PIC check library (default=check)])) - - min_check_version=ifelse([$1], ,0.8.2,$1) - - if test x$with_check = xno; then - AC_MSG_RESULT(disabled) - ifelse([$3], , AC_MSG_ERROR([disabling check is not supported]), [$3]) - else - if test "x$with_check" != x; then - CHECK_EXTRA_CFLAGS="-I$with_check/include" - CHECK_EXTRA_LIBS="-L$with_check/lib" - else - CHECK_EXTRA_CFLAGS="" - CHECK_EXTRA_LIBS="" - fi - - if test x$with_checklibname = x; then - _AM_TRY_CHECK($min_check_version, $CHECK_EXTRA_CFLAGS, $CHECK_EXTRA_LIBS, - check_pic, [have_check=true], [have_check=false]) - if test x$have_check = xtrue; then - ifelse([$2], , :, [$2]) - else - _AM_TRY_CHECK($min_check_version, $CHECK_EXTRA_CFLAGS, $CHECK_EXTRA_LIBS, - check, [have_check=true], [have_check=false]) - if test x$have_check = xtrue; then - ifelse([$2], , :, [$2]) - else - ifelse([$3], , AC_MSG_ERROR([check not found]), [$3]) - fi - fi - else - _AM_TRY_CHECK($min_check_version, $CHECK_EXTRA_CFLAGS, $CHECK_EXTRA_LIBS, - $with_checklibname, [have_check=true], [have_check=false]) - if test x$have_check = xtrue; then - ifelse([$2], , :, [$2]) - else - ifelse([$3], , AC_MSG_ERROR([check not found]), [$3]) - fi - fi - - AC_SUBST(CHECK_CFLAGS) - AC_SUBST(CHECK_LIBS) - rm -f conf.check-test - fi -]) diff --git a/common/m4/glib-gettext.m4 b/common/m4/glib-gettext.m4 deleted file mode 100644 index 5a4ef2814e..0000000000 --- a/common/m4/glib-gettext.m4 +++ /dev/null @@ -1,380 +0,0 @@ -# Copyright (C) 1995-2002 Free Software Foundation, Inc. -# Copyright (C) 2001-2003 Red Hat, Inc. -# -# This file is free software, distributed under the terms of the GNU -# General Public License. As a special exception to the GNU General -# Public License, this file may be distributed as part of a program -# that contains a configuration script generated by Autoconf, under -# the same distribution terms as the rest of that program. -# -# This file can be copied and used freely without restrictions. It can -# be used in projects which are not available under the GNU Public License -# but which still want to provide support for the GNU gettext functionality. -# -# Macro to add for using GNU gettext. -# Ulrich Drepper , 1995, 1996 -# -# Modified to never use included libintl. -# Owen Taylor , 12/15/1998 -# -# Major rework to remove unused code -# Owen Taylor , 12/11/2002 -# -# Added better handling of ALL_LINGUAS from GNU gettext version -# written by Bruno Haible, Owen Taylor 5/30/3002 - -# -# We need this here as well, since someone might use autoconf-2.5x -# to configure GLib then an older version to configure a package -# using AM_GLIB_GNU_GETTEXT -AC_PREREQ(2.53) - -dnl -dnl We go to great lengths to make sure that aclocal won't -dnl try to pull in the installed version of these macros -dnl when running aclocal in the glib directory. -dnl -m4_copy([AC_DEFUN],[glib_DEFUN]) -m4_copy([AC_REQUIRE],[glib_REQUIRE]) -dnl -dnl At the end, if we're not within glib, we'll define the public -dnl definitions in terms of our private definitions. -dnl - -# GLIB_LC_MESSAGES -#-------------------- -glib_DEFUN([GLIB_LC_MESSAGES], - [AC_CHECK_HEADERS([locale.h]) - if test $ac_cv_header_locale_h = yes; then - AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, - [AC_TRY_LINK([#include ], [return LC_MESSAGES], - am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) - if test $am_cv_val_LC_MESSAGES = yes; then - AC_DEFINE(HAVE_LC_MESSAGES, 1, - [Define if your file defines LC_MESSAGES.]) - fi - fi]) - -# GLIB_PATH_PROG_WITH_TEST -#---------------------------- -dnl GLIB_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, -dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) -glib_DEFUN([GLIB_PATH_PROG_WITH_TEST], -[# Extract the first word of "$2", so it can be a program name with args. -set dummy $2; ac_word=[$]2 -AC_MSG_CHECKING([for $ac_word]) -AC_CACHE_VAL(ac_cv_path_$1, -[case "[$]$1" in - /*) - ac_cv_path_$1="[$]$1" # Let the user override the test with a path. - ;; - *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in ifelse([$5], , $PATH, [$5]); do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - if [$3]; then - ac_cv_path_$1="$ac_dir/$ac_word" - break - fi - fi - done - IFS="$ac_save_ifs" -dnl If no 4th arg is given, leave the cache variable unset, -dnl so AC_PATH_PROGS will keep looking. -ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" -])dnl - ;; -esac])dnl -$1="$ac_cv_path_$1" -if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then - AC_MSG_RESULT([$]$1) -else - AC_MSG_RESULT(no) -fi -AC_SUBST($1)dnl -]) - -# GLIB_WITH_NLS -#----------------- -glib_DEFUN([GLIB_WITH_NLS], - dnl NLS is obligatory - [USE_NLS=yes - AC_SUBST(USE_NLS) - - gt_cv_have_gettext=no - - CATOBJEXT=NONE - XGETTEXT=: - INTLLIBS= - - AC_CHECK_HEADER(libintl.h, - [gt_cv_func_dgettext_libintl="no" - libintl_extra_libs="" - - # - # First check in libc - # - AC_CACHE_CHECK([for dgettext in libc], gt_cv_func_dgettext_libc, - [AC_TRY_LINK([ -#include -], - [return (int) dgettext ("","")], - gt_cv_func_dgettext_libc=yes, - gt_cv_func_dgettext_libc=no) - ]) - - if test "$gt_cv_func_dgettext_libc" = "yes" ; then - AC_CHECK_FUNCS(bind_textdomain_codeset) - fi - - # - # If we don't have everything we want, check in libintl - # - if test "$gt_cv_func_dgettext_libc" != "yes" \ - || test "$ac_cv_func_bind_textdomain_codeset" != "yes" ; then - - AC_CHECK_LIB(intl, bindtextdomain, - [AC_CHECK_LIB(intl, dgettext, - gt_cv_func_dgettext_libintl=yes)]) - - if test "$gt_cv_func_dgettext_libintl" != "yes" ; then - AC_MSG_CHECKING([if -liconv is needed to use gettext]) - AC_MSG_RESULT([]) - AC_CHECK_LIB(intl, dcgettext, - [gt_cv_func_dgettext_libintl=yes - libintl_extra_libs=-liconv], - :,-liconv) - fi - - # - # If we found libintl, then check in it for bind_textdomain_codeset(); - # we'll prefer libc if neither have bind_textdomain_codeset(), - # and both have dgettext - # - if test "$gt_cv_func_dgettext_libintl" = "yes" ; then - glib_save_LIBS="$LIBS" - LIBS="$LIBS -lintl $libintl_extra_libs" - unset ac_cv_func_bind_textdomain_codeset - AC_CHECK_FUNCS(bind_textdomain_codeset) - LIBS="$glib_save_LIBS" - - if test "$ac_cv_func_bind_textdomain_codeset" = "yes" ; then - gt_cv_func_dgettext_libc=no - else - if test "$gt_cv_func_dgettext_libc" = "yes"; then - gt_cv_func_dgettext_libintl=no - fi - fi - fi - fi - - if test "$gt_cv_func_dgettext_libc" = "yes" \ - || test "$gt_cv_func_dgettext_libintl" = "yes"; then - gt_cv_have_gettext=yes - fi - - if test "$gt_cv_func_dgettext_libintl" = "yes"; then - INTLLIBS="-lintl $libintl_extra_libs" - fi - - if test "$gt_cv_have_gettext" = "yes"; then - AC_DEFINE(HAVE_GETTEXT,1, - [Define if the GNU gettext() function is already present or preinstalled.]) - GLIB_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, - [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl - if test "$MSGFMT" != "no"; then - glib_save_LIBS="$LIBS" - LIBS="$LIBS $INTLLIBS" - AC_CHECK_FUNCS(dcgettext) - AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) - GLIB_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, - [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) - AC_TRY_LINK(, [extern int _nl_msg_cat_cntr; - return _nl_msg_cat_cntr], - [CATOBJEXT=.gmo - DATADIRNAME=share], - [case $host in - *-*-solaris*) - dnl On Solaris, if bind_textdomain_codeset is in libc, - dnl GNU format message catalog is always supported, - dnl since both are added to the libc all together. - dnl Hence, we'd like to go with DATADIRNAME=share and - dnl and CATOBJEXT=.gmo in this case. - AC_CHECK_FUNC(bind_textdomain_codeset, - [CATOBJEXT=.gmo - DATADIRNAME=share], - [CATOBJEXT=.mo - DATADIRNAME=lib]) - ;; - *) - CATOBJEXT=.mo - DATADIRNAME=lib - ;; - esac]) - LIBS="$glib_save_LIBS" - INSTOBJEXT=.mo - else - gt_cv_have_gettext=no - fi - fi - ]) - - if test "$gt_cv_have_gettext" = "yes" ; then - AC_DEFINE(ENABLE_NLS, 1, - [always defined to indicate that i18n is enabled]) - fi - - dnl Test whether we really found GNU xgettext. - if test "$XGETTEXT" != ":"; then - dnl If it is not GNU xgettext we define it as : so that the - dnl Makefiles still can work. - if $XGETTEXT --omit-header /dev/null 2> /dev/null; then - : ; - else - AC_MSG_RESULT( - [found xgettext program is not GNU xgettext; ignore it]) - XGETTEXT=":" - fi - fi - - # We need to process the po/ directory. - POSUB=po - - AC_OUTPUT_COMMANDS( - [case "$CONFIG_FILES" in *po/Makefile.in*) - sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile - esac]) - - dnl These rules are solely for the distribution goal. While doing this - dnl we only have to keep exactly one list of the available catalogs - dnl in configure.in. - for lang in $ALL_LINGUAS; do - GMOFILES="$GMOFILES $lang.gmo" - POFILES="$POFILES $lang.po" - done - - dnl Make all variables we use known to autoconf. - AC_SUBST(CATALOGS) - AC_SUBST(CATOBJEXT) - AC_SUBST(DATADIRNAME) - AC_SUBST(GMOFILES) - AC_SUBST(INSTOBJEXT) - AC_SUBST(INTLLIBS) - AC_SUBST(PO_IN_DATADIR_TRUE) - AC_SUBST(PO_IN_DATADIR_FALSE) - AC_SUBST(POFILES) - AC_SUBST(POSUB) - ]) - -# AM_GLIB_GNU_GETTEXT -# ------------------- -# Do checks necessary for use of gettext. If a suitable implementation -# of gettext is found in either in libintl or in the C library, -# it will set INTLLIBS to the libraries needed for use of gettext -# and AC_DEFINE() HAVE_GETTEXT and ENABLE_NLS. (The shell variable -# gt_cv_have_gettext will be set to "yes".) It will also call AC_SUBST() -# on various variables needed by the Makefile.in.in installed by -# glib-gettextize. -dnl -glib_DEFUN([GLIB_GNU_GETTEXT], - [AC_REQUIRE([AC_PROG_CC])dnl - AC_REQUIRE([AC_HEADER_STDC])dnl - - GLIB_LC_MESSAGES - GLIB_WITH_NLS - - if test "$gt_cv_have_gettext" = "yes"; then - if test "x$ALL_LINGUAS" = "x"; then - LINGUAS= - else - AC_MSG_CHECKING(for catalogs to be installed) - NEW_LINGUAS= - for presentlang in $ALL_LINGUAS; do - useit=no - if test "%UNSET%" != "${LINGUAS-%UNSET%}"; then - desiredlanguages="$LINGUAS" - else - desiredlanguages="$ALL_LINGUAS" - fi - for desiredlang in $desiredlanguages; do - # Use the presentlang catalog if desiredlang is - # a. equal to presentlang, or - # b. a variant of presentlang (because in this case, - # presentlang can be used as a fallback for messages - # which are not translated in the desiredlang catalog). - case "$desiredlang" in - "$presentlang"*) useit=yes;; - esac - done - if test $useit = yes; then - NEW_LINGUAS="$NEW_LINGUAS $presentlang" - fi - done - LINGUAS=$NEW_LINGUAS - AC_MSG_RESULT($LINGUAS) - fi - - dnl Construct list of names of catalog files to be constructed. - if test -n "$LINGUAS"; then - for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done - fi - fi - - dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly - dnl find the mkinstalldirs script in another subdir but ($top_srcdir). - dnl Try to locate is. - MKINSTALLDIRS= - if test -n "$ac_aux_dir"; then - MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" - fi - if test -z "$MKINSTALLDIRS"; then - MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" - fi - AC_SUBST(MKINSTALLDIRS) - - dnl Generate list of files to be processed by xgettext which will - dnl be included in po/Makefile. - test -d po || mkdir po - if test "x$srcdir" != "x."; then - if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then - posrcprefix="$srcdir/" - else - posrcprefix="../$srcdir/" - fi - else - posrcprefix="../" - fi - rm -f po/POTFILES - sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \ - < $srcdir/po/POTFILES.in > po/POTFILES - ]) - -# AM_GLIB_DEFINE_LOCALEDIR(VARIABLE) -# ------------------------------- -# Define VARIABLE to the location where catalog files will -# be installed by po/Makefile. -glib_DEFUN([GLIB_DEFINE_LOCALEDIR], -[glib_REQUIRE([GLIB_GNU_GETTEXT])dnl -glib_save_prefix="$prefix" -glib_save_exec_prefix="$exec_prefix" -test "x$prefix" = xNONE && prefix=$ac_default_prefix -test "x$exec_prefix" = xNONE && exec_prefix=$prefix -if test "x$CATOBJEXT" = "x.mo" ; then - localedir=`eval echo "${libdir}/locale"` -else - localedir=`eval echo "${datadir}/locale"` -fi -prefix="$glib_save_prefix" -exec_prefix="$glib_save_exec_prefix" -AC_DEFINE_UNQUOTED($1, "$localedir", - [Define the location where the catalogs will be installed]) -]) - -dnl -dnl Now the definitions that aclocal will find -dnl -ifdef(glib_configure_in,[],[ -AC_DEFUN([AM_GLIB_GNU_GETTEXT],[GLIB_GNU_GETTEXT($@)]) -AC_DEFUN([AM_GLIB_DEFINE_LOCALEDIR],[GLIB_DEFINE_LOCALEDIR($@)]) -])dnl diff --git a/common/m4/gst-arch.m4 b/common/m4/gst-arch.m4 deleted file mode 100644 index 8a32bd23b5..0000000000 --- a/common/m4/gst-arch.m4 +++ /dev/null @@ -1,123 +0,0 @@ -dnl AG_GST_ARCH -dnl sets up defines and automake conditionals for host architecture -dnl checks endianness -dnl defines HOST_CPU - -AC_DEFUN([AG_GST_ARCH], -[ - AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use host_ variables - - dnl Determine CPU - case "x${host_cpu}" in - xi?86 | xk? | xi?86_64) - HAVE_CPU_I386=yes - AC_DEFINE(HAVE_CPU_I386, 1, [Define if the host CPU is an x86]) - - dnl FIXME could use some better detection - dnl (ie CPUID) - case "x${host_cpu}" in - xi386 | xi486) ;; - *) - AC_DEFINE(HAVE_RDTSC, 1, [Define if RDTSC is available]) ;; - esac ;; - xpowerpc) - HAVE_CPU_PPC=yes - AC_DEFINE(HAVE_CPU_PPC, 1, [Define if the host CPU is a PowerPC]) ;; - xpowerpc64) - HAVE_CPU_PPC64=yes - AC_DEFINE(HAVE_CPU_PPC64, 1, [Define if the host CPU is a 64 bit PowerPC]) ;; - xalpha*) - HAVE_CPU_ALPHA=yes - AC_DEFINE(HAVE_CPU_ALPHA, 1, [Define if the host CPU is an Alpha]) ;; - xarm*) - HAVE_CPU_ARM=yes - AC_DEFINE(HAVE_CPU_ARM, 1, [Define if the host CPU is an ARM]) ;; - xsparc*) - HAVE_CPU_SPARC=yes - AC_DEFINE(HAVE_CPU_SPARC, 1, [Define if the host CPU is a SPARC]) ;; - xmips*) - HAVE_CPU_MIPS=yes - AC_DEFINE(HAVE_CPU_MIPS, 1, [Define if the host CPU is a MIPS]) ;; - xhppa*) - HAVE_CPU_HPPA=yes - AC_DEFINE(HAVE_CPU_HPPA, 1, [Define if the host CPU is a HPPA]) ;; - xs390*) - HAVE_CPU_S390=yes - AC_DEFINE(HAVE_CPU_S390, 1, [Define if the host CPU is a S390]) ;; - xia64*) - HAVE_CPU_IA64=yes - AC_DEFINE(HAVE_CPU_IA64, 1, [Define if the host CPU is a IA64]) ;; - xm68k*) - HAVE_CPU_M68K=yes - AC_DEFINE(HAVE_CPU_M68K, 1, [Define if the host CPU is a M68K]) ;; - xx86_64) - HAVE_CPU_X86_64=yes - AC_DEFINE(HAVE_CPU_X86_64, 1, [Define if the host CPU is a x86_64]) ;; - xcris) - HAVE_CPU_CRIS=yes - AC_DEFINE(HAVE_CPU_CRIS, 1, [Define if the host CPU is a CRIS]) ;; - xcrisv32) - HAVE_CPU_CRISV32=yes - AC_DEFINE(HAVE_CPU_CRISV32, 1, [Define if the host CPU is a CRISv32]) ;; - esac - - dnl Determine endianness - AC_C_BIGENDIAN - - AM_CONDITIONAL(HAVE_CPU_I386, test "x$HAVE_CPU_I386" = "xyes") - AM_CONDITIONAL(HAVE_CPU_PPC, test "x$HAVE_CPU_PPC" = "xyes") - AM_CONDITIONAL(HAVE_CPU_PPC64, test "x$HAVE_CPU_PPC64" = "xyes") - AM_CONDITIONAL(HAVE_CPU_ALPHA, test "x$HAVE_CPU_ALPHA" = "xyes") - AM_CONDITIONAL(HAVE_CPU_ARM, test "x$HAVE_CPU_ARM" = "xyes") - AM_CONDITIONAL(HAVE_CPU_SPARC, test "x$HAVE_CPU_SPARC" = "xyes") - AM_CONDITIONAL(HAVE_CPU_HPPA, test "x$HAVE_CPU_HPPA" = "xyes") - AM_CONDITIONAL(HAVE_CPU_MIPS, test "x$HAVE_CPU_MIPS" = "xyes") - AM_CONDITIONAL(HAVE_CPU_S390, test "x$HAVE_CPU_S390" = "xyes") - AM_CONDITIONAL(HAVE_CPU_IA64, test "x$HAVE_CPU_IA64" = "xyes") - AM_CONDITIONAL(HAVE_CPU_M68K, test "x$HAVE_CPU_M68K" = "xyes") - AM_CONDITIONAL(HAVE_CPU_X86_64, test "x$HAVE_CPU_X86_64" = "xyes") - AM_CONDITIONAL(HAVE_CPU_CRIS, test "x$HAVE_CPU_CRIS" = "xyes") - AM_CONDITIONAL(HAVE_CPU_CRISV32, test "x$HAVE_CPU_CRISV32" = "xyes") - - AC_DEFINE_UNQUOTED(HOST_CPU, "$host_cpu", [the host CPU]) -]) - -dnl check if unaligned memory access works correctly -AC_DEFUN([AG_GST_UNALIGNED_ACCESS], [ - AC_MSG_CHECKING([if unaligned memory access works correctly]) - if test x"$as_cv_unaligned_access" = x ; then - case $host in - alpha*|arm*|hp*|mips*|sh*|sparc*|ia64*) - _AS_ECHO_N([(blacklisted) ]) - as_cv_unaligned_access=no - ;; - i?86*|powerpc*|m68k*|cris*) - _AS_ECHO_N([(whitelisted) ]) - as_cv_unaligned_access=yes - ;; - esac - else - _AS_ECHO_N([(cached) ]) - fi - if test x"$as_cv_unaligned_access" = x ; then - AC_TRY_RUN([ -int main(int argc, char **argv) -{ - char array[] = "ABCDEFGH"; - unsigned int iarray[2]; - memcpy(iarray,array,8); -#define GET(x) (*(unsigned int *)((char *)iarray + (x))) - if(GET(0) != 0x41424344 && GET(0) != 0x44434241) return 1; - if(GET(1) != 0x42434445 && GET(1) != 0x45444342) return 1; - if(GET(2) != 0x43444546 && GET(2) != 0x46454443) return 1; - if(GET(3) != 0x44454647 && GET(3) != 0x47464544) return 1; - return 0; -} - ], as_cv_unaligned_access="yes", as_cv_unaligned_access="no") - fi - AC_MSG_RESULT($as_cv_unaligned_access) - if test "$as_cv_unaligned_access" = "yes"; then - AC_DEFINE_UNQUOTED(HAVE_UNALIGNED_ACCESS, 1, - [defined if unaligned memory access works correctly]) - fi -]) diff --git a/common/m4/gst-args.m4 b/common/m4/gst-args.m4 deleted file mode 100644 index a326f96f2b..0000000000 --- a/common/m4/gst-args.m4 +++ /dev/null @@ -1,276 +0,0 @@ -dnl configure-time options shared among gstreamer modules - -dnl AG_GST_ARG_DEBUG -dnl AG_GST_ARG_PROFILING -dnl AG_GST_ARG_VALGRIND -dnl AG_GST_ARG_GCOV - -dnl AG_GST_ARG_EXAMPLES - -dnl AG_GST_ARG_WITH_PKG_CONFIG_PATH -dnl AG_GST_ARG_WITH_PACKAGE_NAME -dnl AG_GST_ARG_WITH_PACKAGE_ORIGIN - -dnl AG_GST_ARG_WITH_PLUGINS - -dnl AG_GST_ARG_ENABLE_EXTERNAL -dnl AG_GST_ARG_ENABLE_EXPERIMENTAL -dnl AG_GST_ARG_ENABLE_BROKEN - -AC_DEFUN([AG_GST_ARG_DEBUG], -[ - dnl debugging stuff - AC_ARG_ENABLE(debug, - AC_HELP_STRING([--disable-debug],[disable addition of -g debugging info]), - [ - case "${enableval}" in - yes) USE_DEBUG=yes ;; - no) USE_DEBUG=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; - esac - ], - [USE_DEBUG=yes]) dnl Default value -]) - -AC_DEFUN([AG_GST_ARG_PROFILING], -[ - AC_ARG_ENABLE(profiling, - AC_HELP_STRING([--enable-profiling], - [adds -pg to compiler commandline, for profiling]), - [ - case "${enableval}" in - yes) USE_PROFILING=yes ;; - no) USE_PROFILING=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-profiling) ;; - esac - ], - [USE_PROFILING=no]) dnl Default value -]) - -AC_DEFUN([AG_GST_ARG_VALGRIND], -[ - dnl valgrind inclusion - AC_ARG_ENABLE(valgrind, - AC_HELP_STRING([--disable-valgrind],[disable run-time valgrind detection]), - [ - case "${enableval}" in - yes) USE_VALGRIND="$USE_DEBUG" ;; - no) USE_VALGRIND=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-valgrind) ;; - esac - ], - [USE_VALGRIND="$USE_DEBUG"]) dnl Default value - VALGRIND_REQ="2.1" - if test "x$USE_VALGRIND" = xyes; then - PKG_CHECK_MODULES(VALGRIND, valgrind > $VALGRIND_REQ, - USE_VALGRIND="yes", - [ - USE_VALGRIND="no" - AC_MSG_RESULT([no]) - ]) - fi - if test "x$USE_VALGRIND" = xyes; then - AC_DEFINE(HAVE_VALGRIND, 1, [Define if valgrind should be used]) - AC_MSG_NOTICE(Using extra code paths for valgrind) - fi -]) - -AC_DEFUN([AG_GST_ARG_GCOV], -[ - AC_ARG_ENABLE(gcov, - AC_HELP_STRING([--enable-gcov], - [compile with coverage profiling instrumentation (gcc only)]), - enable_gcov=$enableval, - enable_gcov=no) - if test x$enable_gcov = xyes ; then - if test "x$GCC" != "xyes" - then - AC_MSG_ERROR([gcov only works if gcc is used]) - fi - - AS_COMPILER_FLAG(["-fprofile-arcs"], - [GCOV_CFLAGS="$GCOV_CFLAGS -fprofile-arcs"], - true) - AS_COMPILER_FLAG(["-ftest-coverage"], - [GCOV_CFLAGS="$GCOV_CFLAGS -ftest-coverage"], - true) - dnl remove any -O flags - FIXME: is this needed ? - GCOV_CFLAGS=`echo "$GCOV_CFLAGS" | sed -e 's/-O[[0-9]]*//g'` - dnl libtool 1.5.22 and lower strip -fprofile-arcs from the flags - dnl passed to the linker, which is a bug; -fprofile-arcs implicitly - dnl links in -lgcov, so we do it explicitly here for the same effect - GCOV_LIBS=-lgcov - AC_SUBST(GCOV_CFLAGS) - AC_SUBST(GCOV_LIBS) - GCOV=`echo $CC | sed s/gcc/gcov/g` - AC_SUBST(GCOV) - - GST_GCOV_ENABLED=yes - AC_DEFINE_UNQUOTED(GST_GCOV_ENABLED, 1, - [Defined if gcov is enabled to force a rebuild due to config.h changing]) - dnl if gcov is used, we do not want default -O2 CFLAGS - if test "x$GST_GCOV_ENABLED" = "xyes" - then - CFLAGS="-O0" - AC_SUBST(CFLAGS) - CXXFLAGS="-O0" - AC_SUBST(CXXFLAGS) - FFLAGS="-O0" - AC_SUBST(FFLAGS) - CCASFLAGS="-O0" - AC_SUBST(CCASFLAGS) - AC_MSG_NOTICE([gcov enabled, setting CFLAGS and friends to $CFLAGS]) - fi - fi - AM_CONDITIONAL(GST_GCOV_ENABLED, test x$enable_gcov = xyes) -]) - -AC_DEFUN([AG_GST_ARG_EXAMPLES], -[ - AC_ARG_ENABLE(examples, - AC_HELP_STRING([--disable-examples], [disable building examples]), - [ - case "${enableval}" in - yes) BUILD_EXAMPLES=yes ;; - no) BUILD_EXAMPLES=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --disable-examples) ;; - esac - ], - [BUILD_EXAMPLES=yes]) dnl Default value - AM_CONDITIONAL(BUILD_EXAMPLES, test "x$BUILD_EXAMPLES" = "xyes") -]) - -AC_DEFUN([AG_GST_ARG_WITH_PKG_CONFIG_PATH], -[ - dnl possibly modify pkg-config path - AC_ARG_WITH(pkg-config-path, - AC_HELP_STRING([--with-pkg-config-path], - [colon-separated list of pkg-config(1) dirs]), - [ - export PKG_CONFIG_PATH=${withval} - AC_MSG_NOTICE(Set PKG_CONFIG_PATH to $PKG_CONFIG_PATH) - ]) -]) - - -dnl This macro requires that GST_CVS is set to yes or no (release) -AC_DEFUN([AG_GST_ARG_WITH_PACKAGE_NAME], -[ - dnl package name in plugins - AC_ARG_WITH(package-name, - AC_HELP_STRING([--with-package-name], - [specify package name to use in plugins]), - [ - case "${withval}" in - yes) AC_MSG_ERROR(bad value ${withval} for --with-package-name) ;; - no) AC_MSG_ERROR(bad value ${withval} for --with-package-name) ;; - *) GST_PACKAGE_NAME="${withval}" ;; - esac - ], - [ - P=$1 - if test "x$P" = "x" - then - P=$PACKAGE_NAME - fi - - dnl default value - if test "x$GST_CVS" = "xyes" - then - dnl nano >= 1 - GST_PACKAGE_NAME="$P CVS/prerelease" - else - GST_PACKAGE_NAME="$P source release" - fi - ] - ) - AC_MSG_NOTICE(Using $GST_PACKAGE_NAME as package name) - AC_DEFINE_UNQUOTED(GST_PACKAGE_NAME, "$GST_PACKAGE_NAME", - [package name in plugins]) - AC_SUBST(GST_PACKAGE_NAME) -]) - -AC_DEFUN([AG_GST_ARG_WITH_PACKAGE_ORIGIN], -[ - dnl package origin URL - AC_ARG_WITH(package-origin, - AC_HELP_STRING([--with-package-origin], - [specify package origin URL to use in plugins]), - [ - case "${withval}" in - yes) AC_MSG_ERROR(bad value ${withval} for --with-package-origin) ;; - no) AC_MSG_ERROR(bad value ${withval} for --with-package-origin) ;; - *) GST_PACKAGE_ORIGIN="${withval}" ;; - esac - ], - [GST_PACKAGE_ORIGIN="[Unknown package origin]"] dnl Default value - ) - AC_MSG_NOTICE(Using $GST_PACKAGE_ORIGIN as package origin) - AC_DEFINE_UNQUOTED(GST_PACKAGE_ORIGIN, "$GST_PACKAGE_ORIGIN", - [package origin]) - AC_SUBST(GST_PACKAGE_ORIGIN) -]) - -dnl sets GST_PLUGINS_SELECTED to the list given as an argument, or to -dnl GST_PLUGINS_ALL -AC_DEFUN([AG_GST_ARG_WITH_PLUGINS], -[ - AC_ARG_WITH(plugins, - AC_HELP_STRING([--with-plugins], - [comma-separated list of dependencyless plug-ins to compile]), - [ - for i in `echo $withval | tr , ' '`; do - if echo $GST_PLUGINS_ALL | grep $i > /dev/null - then - GST_PLUGINS_SELECTED="$GST_PLUGINS_SELECTED $i" - else - echo "plug-in $i not recognized, ignoring..." - fi - done], - [GST_PLUGINS_SELECTED=$GST_PLUGINS_ALL]) -]) - -AC_DEFUN([AG_GST_ARG_ENABLE_EXTERNAL], -[ - AG_GST_CHECK_FEATURE(EXTERNAL, [enable building of plug-ins with external deps],, - HAVE_EXTERNAL=yes, enabled, - [ - AC_MSG_NOTICE(building external plug-ins) - BUILD_EXTERNAL="yes" - ],[ - AC_MSG_WARN(all plug-ins with external dependencies will not be built) - BUILD_EXTERNAL="no" - ]) - # make BUILD_EXTERNAL available to Makefile.am - AM_CONDITIONAL(BUILD_EXTERNAL, test "x$BUILD_EXTERNAL" = "xyes") -]) - -dnl experimental plug-ins; stuff that hasn't had the dust settle yet -dnl read 'builds, but might not work' -AC_DEFUN([AG_GST_ARG_ENABLE_EXPERIMENTAL], -[ - AG_GST_CHECK_FEATURE(EXPERIMENTAL, - [building of experimental plug-ins],, - HAVE_EXPERIMENTAL=yes, disabled, - [ - AC_MSG_WARN(building experimental plug-ins) - BUILD_EXPERIMENTAL="yes" - ],[ - AC_MSG_NOTICE(not building experimental plug-ins) - BUILD_EXPERIMENTAL="no" - ]) - # make BUILD_EXPERIMENTAL available to Makefile.am - AM_CONDITIONAL(BUILD_EXPERIMENTAL, test "x$BUILD_EXPERIMENTAL" = "xyes") -]) - -dnl broken plug-ins; stuff that doesn't seem to build at the moment -AC_DEFUN([AG_GST_ARG_ENABLE_BROKEN], -[ - AG_GST_CHECK_FEATURE(BROKEN, [enable building of broken plug-ins],, - HAVE_BROKEN=yes, disabled, - [ - AC_MSG_WARN([building broken plug-ins -- no bug reports on these, only patches ...]) - ],[ - AC_MSG_NOTICE([not building broken plug-ins]) - ]) -]) diff --git a/common/m4/gst-check.m4 b/common/m4/gst-check.m4 deleted file mode 100644 index 3f6b8ffd46..0000000000 --- a/common/m4/gst-check.m4 +++ /dev/null @@ -1,138 +0,0 @@ -dnl pkg-config-based checks for GStreamer modules and dependency modules - -dnl generic: -dnl AG_GST_PKG_CHECK_MODULES([PREFIX], [WHICH], [REQUIRED]) -dnl sets HAVE_[$PREFIX], [$PREFIX]_* -dnl AG_GST_CHECK_MODULES([PREFIX], [MODULE], [MINVER], [NAME], [REQUIRED]) -dnl sets HAVE_[$PREFIX], [$PREFIX]_* - -dnl specific: -dnl AG_GST_CHECK_GST([MAJMIN], [MINVER], [REQUIRED]) -dnl also sets/ACSUBSTs GST_TOOLS_DIR and GST_PLUGINS_DIR -dnl AG_GST_CHECK_GST_BASE([MAJMIN], [MINVER], [REQUIRED]) -dnl AG_GST_CHECK_GST_GDP([MAJMIN], [MINVER], [REQUIRED]) -dnl AG_GST_CHECK_GST_CONTROLLER([MAJMIN], [MINVER], [REQUIRED]) -dnl AG_GST_CHECK_GST_CHECK([MAJMIN], [MINVER], [REQUIRED]) -dnl AG_GST_CHECK_GST_PLUGINS_BASE([MAJMIN], [MINVER], [REQUIRED]) -dnl also sets/ACSUBSTs GSTPB_PLUGINS_DIR - -AC_DEFUN([AG_GST_PKG_CHECK_MODULES], -[ - which="[$2]" - dnl not required by default, since we use this mostly for plugin deps - required=ifelse([$3], , "no", [$3]) - - PKG_CHECK_MODULES([$1], $which, - [ - HAVE_[$1]="yes" - ], - [ - HAVE_[$1]="no" - AC_MSG_RESULT(no) - if test "x$required" = "xyes"; then - AC_MSG_ERROR($[$1]_PKG_ERRORS) - else - AC_MSG_NOTICE($[$1]_PKG_ERRORS) - fi - ]) - - dnl AC_SUBST of CFLAGS and LIBS was not done before automake 1.7 - dnl It gets done automatically in automake >= 1.7, which we now require -])) - -AC_DEFUN([AG_GST_CHECK_MODULES], -[ - module=[$2] - minver=[$3] - name="[$4]" - required=ifelse([$5], , "yes", [$5]) dnl required by default - - PKG_CHECK_MODULES([$1], $module >= $minver, - [ - HAVE_[$1]="yes" - ], - [ - HAVE_[$1]="no" - AC_MSG_RESULT(no) - AC_MSG_NOTICE($[$1]_PKG_ERRORS) - if test "x$required" = "xyes"; then - AC_MSG_ERROR([no $module >= $minver ($name) found]) - else - AC_MSG_NOTICE([no $module >= $minver ($name) found]) - fi - ]) - - dnl AC_SUBST of CFLAGS and LIBS was not done before automake 1.7 - dnl It gets done automatically in automake >= 1.7, which we now require -])) - -AC_DEFUN([AG_GST_CHECK_GST], -[ - AG_GST_CHECK_MODULES(GST, gstreamer-[$1], [$2], [GStreamer], [$3]) - dnl allow setting before calling this macro to override - if test -z $GST_TOOLS_DIR; then - GST_TOOLS_DIR=`$PKG_CONFIG --variable=toolsdir gstreamer-[$1]` - if test -z $GST_TOOLS_DIR; then - AC_MSG_ERROR( - [no tools dir set in GStreamer pkg-config file, core upgrade needed.]) - fi - fi - AC_MSG_NOTICE([using GStreamer tools in $GST_TOOLS_DIR]) - AC_SUBST(GST_TOOLS_DIR) - - dnl check for where core plug-ins got installed - dnl this is used for unit tests - dnl allow setting before calling this macro to override - if test -z $GST_PLUGINS_DIR; then - GST_PLUGINS_DIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-[$1]` - if test -z $GST_PLUGINS_DIR; then - AC_MSG_ERROR( - [no pluginsdir set in GStreamer pkg-config file, core upgrade needed.]) - fi - fi - AC_MSG_NOTICE([using GStreamer plug-ins in $GST_PLUGINS_DIR]) - AC_SUBST(GST_PLUGINS_DIR) -]) - -AC_DEFUN([AG_GST_CHECK_GST_BASE], -[ - AG_GST_CHECK_MODULES(GST_BASE, gstreamer-base-[$1], [$2], - [GStreamer Base Libraries], [$3]) -]) - -AC_DEFUN([AG_GST_CHECK_GST_GDP], -[ - AG_GST_CHECK_MODULES(GST_GDP, gstreamer-dataprotocol-[$1], [$2], - [GStreamer Data Protocol Library], [$3]) -]) - -AC_DEFUN([AG_GST_CHECK_GST_CONTROLLER], -[ - AG_GST_CHECK_MODULES(GST_CONTROLLER, gstreamer-controller-[$1], [$2], - [GStreamer Controller Library], [$3]) -]) - -AC_DEFUN([AG_GST_CHECK_GST_CHECK], -[ - AG_GST_CHECK_MODULES(GST_CHECK, gstreamer-check-[$1], [$2], - [GStreamer Check unittest Library], [$3]) -]) - -AC_DEFUN([AG_GST_CHECK_GST_PLUGINS_BASE], -[ - AG_GST_CHECK_MODULES(GST_PLUGINS_BASE, gstreamer-plugins-base-[$1], [$2], - [GStreamer Base Plug-ins Library], [$3]) - - dnl check for where base plug-ins got installed - dnl this is used for unit tests - dnl allow setting before calling this macro to override - if test -z $GSTPB_PLUGINS_DIR; then - GSTPB_PLUGINS_DIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-plugins-base-[$1]` - if test -z $GSTPB_PLUGINS_DIR; then - AC_MSG_ERROR( - [no pluginsdir set in GStreamer Base Plug-ins pkg-config file]) - fi - fi - AC_MSG_NOTICE([using GStreamer Base Plug-ins in $GSTPB_PLUGINS_DIR]) - AC_SUBST(GSTPB_PLUGINS_DIR) -]) diff --git a/common/m4/gst-debuginfo.m4 b/common/m4/gst-debuginfo.m4 deleted file mode 100644 index b48854d97a..0000000000 --- a/common/m4/gst-debuginfo.m4 +++ /dev/null @@ -1,46 +0,0 @@ -AC_DEFUN([AG_GST_DEBUGINFO], [ -AC_ARG_ENABLE(debug, -AC_HELP_STRING([--disable-debug],[disable addition of -g debugging info]), -[case "${enableval}" in - yes) USE_DEBUG=yes ;; - no) USE_DEBUG=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; -esac], -[USE_DEBUG=yes]) dnl Default value - -AC_ARG_ENABLE(DEBUG, -AC_HELP_STRING([--disable-DEBUG],[disables compilation of debugging messages]), -[case "${enableval}" in - yes) ENABLE_DEBUG=yes ;; - no) ENABLE_DEBUG=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-DEBUG) ;; -esac], -[ENABLE_DEBUG=yes]) dnl Default value -if test x$ENABLE_DEBUG = xyes; then - AC_DEFINE(GST_DEBUG_ENABLED, 1, [Define if DEBUG statements should be compiled in]) -fi - -AC_ARG_ENABLE(INFO, -AC_HELP_STRING([--disable-INFO],[disables compilation of informational messages]), -[case "${enableval}" in - yes) ENABLE_INFO=yes ;; - no) ENABLE_INFO=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-INFO) ;; -esac], -[ENABLE_INFO=yes]) dnl Default value -if test x$ENABLE_INFO = xyes; then - AC_DEFINE(GST_INFO_ENABLED, 1, [Define if INFO statements should be compiled in]) -fi - -AC_ARG_ENABLE(debug-color, -AC_HELP_STRING([--disable-debug-color],[disables color output of DEBUG and INFO output]), -[case "${enableval}" in - yes) ENABLE_DEBUG_COLOR=yes ;; - no) ENABLE_DEBUG_COLOR=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug-color) ;; -esac], -[ENABLE_DEBUG_COLOR=yes]) dnl Default value -if test "x$ENABLE_DEBUG_COLOR" = xyes; then - AC_DEFINE(GST_DEBUG_COLOR, 1, [Define if debugging messages should be colorized]) -fi -]) diff --git a/common/m4/gst-default.m4 b/common/m4/gst-default.m4 deleted file mode 100644 index da1a81c938..0000000000 --- a/common/m4/gst-default.m4 +++ /dev/null @@ -1,45 +0,0 @@ -dnl default elements used for tests and such - -dnl AG_GST_DEFAULT_ELEMENTS - -AC_DEFUN([AG_GST_DEFAULT_ELEMENTS], -[ - dnl decide on default elements - dnl FIXME: provide configure-time options for this - dnl FIXME: describe where exactly this gets used - dnl FIXME: decide if it's a problem that this could point to sinks from - dnl depending plugin modules - DEFAULT_AUDIOSINK="autoaudiosink" - DEFAULT_VIDEOSINK="autovideosink" - DEFAULT_AUDIOSRC="alsasrc" - DEFAULT_VIDEOSRC="v4lsrc" - DEFAULT_VISUALIZER="goom" - case "$host" in - *-sun-* | *pc-solaris* ) - DEFAULT_AUDIOSINK="sunaudiosink" - DEFAULT_VIDEOSINK="ximagesink" - DEFAULT_AUDIOSRC="sunaudiosrc" - ;; - *-darwin* ) - DEFAULT_AUDIOSINK="osxaudiosink" - DEFAULT_AUDIOSRC="osxaudiosrc" - DEFAULT_VIDEOSINK="osxvideosink" - ;; - esac - - AC_SUBST(DEFAULT_AUDIOSINK) - AC_DEFINE_UNQUOTED(DEFAULT_AUDIOSINK, "$DEFAULT_AUDIOSINK", - [Default audio sink]) - AC_SUBST(DEFAULT_AUDIOSRC) - AC_DEFINE_UNQUOTED(DEFAULT_AUDIOSRC, "$DEFAULT_AUDIOSRC", - [Default audio source]) - AC_SUBST(DEFAULT_VIDEOSINK) - AC_DEFINE_UNQUOTED(DEFAULT_VIDEOSINK, "$DEFAULT_VIDEOSINK", - [Default video sink]) - AC_SUBST(DEFAULT_VIDEOSRC) - AC_DEFINE_UNQUOTED(DEFAULT_VIDEOSRC, "$DEFAULT_VIDEOSRC", - [Default video source]) - AC_SUBST(DEFAULT_VISUALIZER) - AC_DEFINE_UNQUOTED(DEFAULT_VISUALIZER, "$DEFAULT_VISUALIZER", - [Default visualizer]) -]) diff --git a/common/m4/gst-doc.m4 b/common/m4/gst-doc.m4 deleted file mode 100644 index 7000c17ad1..0000000000 --- a/common/m4/gst-doc.m4 +++ /dev/null @@ -1,148 +0,0 @@ -AC_DEFUN([AG_GST_DOCBOOK_CHECK], -[ - dnl choose a location to install docbook docs in - if test "x$PACKAGE_TARNAME" = "x" - then - AC_MSG_ERROR([Internal error - PACKAGE_TARNAME not set]) - fi - docdir="\$(datadir)/doc/$PACKAGE_TARNAME-$GST_MAJORMINOR" - - dnl enable/disable docbook documentation building - AC_ARG_ENABLE(docbook, - AC_HELP_STRING([--enable-docbook], - [use docbook to build documentation [default=no]]),, - enable_docbook=no) - - have_docbook=no - - if test x$enable_docbook = xyes; then - dnl check if we actually have everything we need - - dnl check for docbook tools - AC_CHECK_PROG(HAVE_DOCBOOK2PS, docbook2ps, yes, no) - AC_CHECK_PROG(HAVE_DOCBOOK2HTML, docbook2html, yes, no) - AC_CHECK_PROG(HAVE_JADETEX, jadetex, yes, no) - AC_CHECK_PROG(HAVE_PS2PDF, ps2pdf, yes, no) - - # -V option appeared in 0.6.10 - docbook2html_min_version=0.6.10 - if test "x$HAVE_DOCBOOK2HTML" != "xno"; then - docbook2html_version=`docbook2html --version` - AC_MSG_CHECKING([docbook2html version ($docbook2html_version) >= $docbook2html_min_version]) - if perl -w < \$min_version_major) || - ((\$docbook2html_version_major == \$min_version_major) && - (\$docbook2html_version_minor >= \$min_version_minor)) || - ((\$docbook2html_version_major == \$min_version_major) && - (\$docbook2html_version_minor >= \$min_version_minor) && - (\$docbook2html_version_micro >= \$min_version_micro))) - ? 0 : 1); -EOF - then - AC_MSG_RESULT(yes) - else - AC_MSG_RESULT(no) - HAVE_DOCBOOK2HTML=no - fi - fi - - dnl check if we can process docbook stuff - AS_DOCBOOK(have_docbook=yes, have_docbook=no) - - dnl check for extra tools - AC_CHECK_PROG(HAVE_DVIPS, dvips, yes, no) - AC_CHECK_PROG(HAVE_XMLLINT, xmllint, yes, no) - - dnl check for image conversion tools - AC_CHECK_PROG(HAVE_FIG2DEV, fig2dev, yes, no) - if test "x$HAVE_FIG2DEV" = "xno" ; then - AC_MSG_WARN([Did not find fig2dev (from xfig), images will not be generated.]) - fi - - dnl The following is a hack: if fig2dev doesn't display an error message - dnl for the desired type, we assume it supports it. - HAVE_FIG2DEV_EPS=no - if test "x$HAVE_FIG2DEV" = "xyes" ; then - fig2dev_quiet=`fig2dev -L eps &1 >/dev/null` - if test "x$fig2dev_quiet" = "x" ; then - HAVE_FIG2DEV_EPS=yes - fi - fi - HAVE_FIG2DEV_PNG=no - if test "x$HAVE_FIG2DEV" = "xyes" ; then - fig2dev_quiet=`fig2dev -L png &1 >/dev/null` - if test "x$fig2dev_quiet" = "x" ; then - HAVE_FIG2DEV_PNG=yes - fi - fi - HAVE_FIG2DEV_PDF=no - if test "x$HAVE_FIG2DEV" = "xyes" ; then - fig2dev_quiet=`fig2dev -L pdf &1 >/dev/null` - if test "x$fig2dev_quiet" = "x" ; then - HAVE_FIG2DEV_PDF=yes - fi - fi - - AC_CHECK_PROG(HAVE_PNGTOPNM, pngtopnm, yes, no) - AC_CHECK_PROG(HAVE_PNMTOPS, pnmtops, yes, no) - AC_CHECK_PROG(HAVE_EPSTOPDF, epstopdf, yes, no) - - dnl check if we can generate HTML - if test "x$HAVE_DOCBOOK2HTML" = "xyes" && \ - test "x$enable_docbook" = "xyes" && \ - test "x$HAVE_XMLLINT" = "xyes" && \ - test "x$HAVE_FIG2DEV_PNG" = "xyes"; then - DOC_HTML=yes - AC_MSG_NOTICE(Will output HTML documentation) - else - DOC_HTML=no - AC_MSG_NOTICE(Will not output HTML documentation) - fi - - dnl check if we can generate PS - if test "x$HAVE_DOCBOOK2PS" = "xyes" && \ - test "x$enable_docbook" = "xyes" && \ - test "x$HAVE_XMLLINT" = "xyes" && \ - test "x$HAVE_JADETEX" = "xyes" && \ - test "x$HAVE_FIG2DEV_EPS" = "xyes" && \ - test "x$HAVE_DVIPS" = "xyes" && \ - test "x$HAVE_PNGTOPNM" = "xyes" && \ - test "x$HAVE_PNMTOPS" = "xyes"; then - DOC_PS=yes - AC_MSG_NOTICE(Will output PS documentation) - else - DOC_PS=no - AC_MSG_NOTICE(Will not output PS documentation) - fi - - dnl check if we can generate PDF - using only ps2pdf - if test "x$DOC_PS" = "xyes" && \ - test "x$enable_docbook" = "xyes" && \ - test "x$HAVE_XMLLINT" = "xyes" && \ - test "x$HAVE_PS2PDF" = "xyes"; then - DOC_PDF=yes - AC_MSG_NOTICE(Will output PDF documentation) - else - DOC_PDF=no - AC_MSG_NOTICE(Will not output PDF documentation) - fi - - dnl if we don't have everything, we should disable - if test "x$have_docbook" != "xyes"; then - enable_docbook=no - fi - fi - - dnl if we're going to install documentation, tell us where - if test "x$have_docbook" = "xyes"; then - AC_MSG_NOTICE(Installing documentation in $docdir) - AC_SUBST(docdir) - fi - - AM_CONDITIONAL(ENABLE_DOCBOOK, test x$enable_docbook = xyes) - AM_CONDITIONAL(DOC_HTML, test x$DOC_HTML = xyes) - AM_CONDITIONAL(DOC_PDF, test x$DOC_PDF = xyes) - AM_CONDITIONAL(DOC_PS, test x$DOC_PS = xyes) -]) diff --git a/common/m4/gst-error.m4 b/common/m4/gst-error.m4 deleted file mode 100644 index 4c3f12c4df..0000000000 --- a/common/m4/gst-error.m4 +++ /dev/null @@ -1,71 +0,0 @@ -dnl handle various error-related things - -dnl Thomas Vander Stichele - -dnl Last modification: 2005-10-16 - -dnl AG_GST_SET_ERROR_CFLAGS([ADD-WERROR]) -dnl AG_GST_SET_LEVEL_DEFAULT([IS-CVS-VERSION]) - - -dnl Sets ERROR_CFLAGS to something the compiler will accept. -dnl AC_SUBST them so they are available in Makefile - -dnl -Wall is added if it is supported -dnl -Werror is added if ADD-WERROR is not "no" - -dnl These flags can be overridden at make time: -dnl make ERROR_CFLAGS= -AC_DEFUN([AG_GST_SET_ERROR_CFLAGS], -[ - AC_REQUIRE([AC_PROG_CC]) - AC_REQUIRE([AS_COMPILER_FLAG]) - - - dnl if we support -Wall, set it unconditionally - AS_COMPILER_FLAG(-Wall, - ERROR_CFLAGS="-Wall", - ERROR_CFLAGS="") - - dnl if asked for, add -Werror if supported - if test "x$1" != "xno" - then - AS_COMPILER_FLAG(-Werror, ERROR_CFLAGS="$ERROR_CFLAGS -Werror") - - dnl if -Werror isn't suported - if test "x$ERROR_CFLAGS" == "x" - then - dnl try -errwarn=%all,no%E_EMPTY_DECLARATION,no%E_STATEMENT_NOT_REACHED (Sun Forte case) - dnl For Forte we need disable "empty declaration" warning produced by un-needed semicolon - dnl "statement not reached" disabled because there is g_assert_not_reached () in some places - AS_COMPILER_FLAG([-errwarn=%all,no%E_EMPTY_DECLARATION,no%E_STATEMENT_NOT_REACHED], - [ERROR_CFLAGS="-errwarn=%all,no%E_EMPTY_DECLARATION,no%E_STATEMENT_NOT_REACHED"]) - - dnl if this also isn't suported, try only for -errwarn=%all - if test "x$ERROR_CFLAGS" == "x" - then - AS_COMPILER_FLAG(-errwarn=%all, - ERROR_CFLAGS="-errwarn=%all") - fi - fi - fi - - AC_SUBST(ERROR_CFLAGS) - AC_MSG_NOTICE([set ERROR_CFLAGS to $ERROR_CFLAGS]) -]) - -dnl Sets the default error level for debugging messages -AC_DEFUN([AG_GST_SET_LEVEL_DEFAULT], -[ - dnl define correct errorlevel for debugging messages. We want to have - dnl GST_ERROR messages printed when running cvs builds - if test "x[$1]" = "xyes"; then - GST_LEVEL_DEFAULT=GST_LEVEL_ERROR - else - GST_LEVEL_DEFAULT=GST_LEVEL_NONE - fi - AC_DEFINE_UNQUOTED(GST_LEVEL_DEFAULT, $GST_LEVEL_DEFAULT, - [Default errorlevel to use]) - dnl AC_SUBST so we can use it for win32/common/config.h - AC_SUBST(GST_LEVEL_DEFAULT) -]) diff --git a/common/m4/gst-feature.m4 b/common/m4/gst-feature.m4 deleted file mode 100644 index 510d228d9a..0000000000 --- a/common/m4/gst-feature.m4 +++ /dev/null @@ -1,285 +0,0 @@ -dnl Perform a check for a feature for GStreamer -dnl Richard Boulton -dnl Thomas Vander Stichele added useful stuff -dnl Last modification: 25/06/2001 -dnl AG_GST_CHECK_FEATURE(FEATURE-NAME, FEATURE-DESCRIPTION, -dnl DEPENDENT-PLUGINS, TEST-FOR-FEATURE, -dnl DISABLE-BY-DEFAULT, ACTION-IF-USE, ACTION-IF-NOTUSE) -dnl -dnl This macro adds a command line argument to allow the user to enable -dnl or disable a feature, and if the feature is enabled, performs a supplied -dnl test to check if the feature is available. -dnl -dnl The test should define HAVE_ to "yes" or "no" depending -dnl on whether the feature is available. -dnl -dnl The macro will set USE_ to "yes" or "no" depending on -dnl whether the feature is to be used. -dnl Thomas changed this, so that when USE_ was already set -dnl to no, then it stays that way. -dnl -dnl The macro will call AM_CONDITIONAL(USE_<, ...) to allow -dnl the feature to control what is built in Makefile.ams. If you want -dnl additional actions resulting from the test, you can add them with the -dnl ACTION-IF-USE and ACTION-IF-NOTUSE parameters. -dnl -dnl FEATURE-NAME is the name of the feature, and should be in -dnl purely upper case characters. -dnl FEATURE-DESCRIPTION is used to describe the feature in help text for -dnl the command line argument. -dnl DEPENDENT-PLUGINS lists any plug-ins which depend on this feature. -dnl TEST-FOR-FEATURE is a test which sets HAVE_ to "yes" -dnl or "no" depending on whether the feature is -dnl available. -dnl DISABLE-BY-DEFAULT if "disabled", the feature is disabled by default, -dnl if any other value, the feature is enabled by default. -dnl ACTION-IF-USE any extra actions to perform if the feature is to be -dnl used. -dnl ACTION-IF-NOTUSE any extra actions to perform if the feature is not to -dnl be used. -dnl -dnl -dnl thomas : -dnl we also added a history. -dnl GST_PLUGINS_YES will contain all plugins to be built -dnl that were checked through AG_GST_CHECK_FEATURE -dnl GST_PLUGINS_NO will contain those that won't be built - -AC_DEFUN([AG_GST_CHECK_FEATURE], -[echo -AC_MSG_NOTICE(*** checking feature: [$2] ***) -if test "x[$3]" != "x" -then - AC_MSG_NOTICE(*** for plug-ins: [$3] ***) -fi -dnl -builtin(define, [gst_endisable], ifelse($5, [disabled], [enable], [disable]))dnl -dnl if it is set to NO, then don't even consider it for building -NOUSE= -if test "x$USE_[$1]" = "xno"; then - NOUSE="yes" -fi -AC_ARG_ENABLE(translit([$1], A-Z, a-z), - [ ]builtin(format, --%-26s gst_endisable %s, gst_endisable-translit([$1], A-Z, a-z), [$2]ifelse([$3],,,: [$3])), - [ case "${enableval}" in - yes) USE_[$1]=yes;; - no) USE_[$1]=no;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-translit([$1], A-Z, a-z)) ;; - esac], - [ USE_$1=]ifelse($5, [disabled], [no], [yes])) dnl DEFAULT - -dnl *** set it back to no if it was preset to no -if test "x$NOUSE" = "xyes"; then - USE_[$1]="no" - AC_MSG_WARN(*** $3 pre-configured not to be built) -fi -NOUSE= - -dnl *** If it's enabled - -if test x$USE_[$1] = xyes; then - dnl save compile variables before the test - - gst_check_save_LIBS=$LIBS - gst_check_save_LDFLAGS=$LDFLAGS - gst_check_save_CFLAGS=$CFLAGS - gst_check_save_CPPFLAGS=$CPPFLAGS - gst_check_save_CXXFLAGS=$CXXFLAGS - - HAVE_[$1]=no - dnl TEST_FOR_FEATURE - $4 - - LIBS=$gst_check_save_LIBS - LDFLAGS=$gst_check_save_LDFLAGS - CFLAGS=$gst_check_save_CFLAGS - CPPFLAGS=$gst_check_save_CPPFLAGS - CXXFLAGS=$gst_check_save_CXXFLAGS - - dnl If it isn't found, unset USE_[$1] - if test x$HAVE_[$1] = xno; then - USE_[$1]=no - else - ifelse([$3], , :, [AC_MSG_NOTICE(*** These plugins will be built: [$3])]) - fi -fi -dnl *** Warn if it's disabled or not found -if test x$USE_[$1] = xyes; then - ifelse([$6], , :, [$6]) - if test "x$3" != "x"; then - GST_PLUGINS_YES="\t[$3]\n$GST_PLUGINS_YES" - fi - AC_DEFINE(HAVE_[$1], , [support for features: $3]) -else - ifelse([$3], , :, [AC_MSG_NOTICE(*** These plugins will not be built: [$3])]) - if test "x$3" != "x"; then - GST_PLUGINS_NO="\t[$3]\n$GST_PLUGINS_NO" - fi - ifelse([$7], , :, [$7]) -fi -dnl *** Define the conditional as appropriate -AM_CONDITIONAL(USE_[$1], test x$USE_[$1] = xyes) -]) - -dnl Use a -config program which accepts --cflags and --libs parameters -dnl to set *_CFLAGS and *_LIBS and check existence of a feature. -dnl Richard Boulton -dnl Last modification: 26/06/2001 -dnl AG_GST_CHECK_CONFIGPROG(FEATURE-NAME, CONFIG-PROG-FILENAME, MODULES) -dnl -dnl This check was written for GStreamer: it should be renamed and checked -dnl for portability if you decide to use it elsewhere. -dnl -AC_DEFUN([AG_GST_CHECK_CONFIGPROG], -[ - AC_PATH_PROG([$1]_CONFIG, [$2], no) - if test x$[$1]_CONFIG = xno; then - [$1]_LIBS= - [$1]_CFLAGS= - HAVE_[$1]=no - else - if [$2] --plugin-libs [$3] &> /dev/null; then - [$1]_LIBS=`[$2] --plugin-libs [$3]` - else - [$1]_LIBS=`[$2] --libs [$3]` - fi - [$1]_CFLAGS=`[$2] --cflags [$3]` - HAVE_[$1]=yes - fi - AC_SUBST([$1]_LIBS) - AC_SUBST([$1]_CFLAGS) -]) - -dnl Use AC_CHECK_LIB and AC_CHECK_HEADER to do both tests at once -dnl sets HAVE_module if we have it -dnl Richard Boulton -dnl Last modification: 26/06/2001 -dnl AG_GST_CHECK_LIBHEADER(FEATURE-NAME, LIB NAME, LIB FUNCTION, EXTRA LD FLAGS, -dnl HEADER NAME, ACTION-IF-FOUND, ACTION-IF-NOT-FOUND) -dnl -dnl This check was written for GStreamer: it should be renamed and checked -dnl for portability if you decide to use it elsewhere. -dnl -AC_DEFUN([AG_GST_CHECK_LIBHEADER], -[ - AC_CHECK_LIB([$2], [$3], HAVE_[$1]=yes, HAVE_[$1]=no,[$4]) - if test "x$HAVE_[$1]" = "xyes"; then - AC_CHECK_HEADER([$5], :, HAVE_[$1]=no) - if test "x$HAVE_[$1]" = "xyes"; then - dnl execute what needs to be - ifelse([$6], , :, [$6]) - else - ifelse([$7], , :, [$7]) - fi - else - ifelse([$7], , :, [$7]) - fi - AC_SUBST(HAVE_[$1]) -] -) - -dnl 2004-02-14 Thomas - changed to get set properly and use proper output -dnl 2003-06-27 Benjamin Otte - changed to make this work with gstconfig.h -dnl -dnl Add a subsystem --disable flag and all the necessary symbols and substitions -dnl -dnl AG_GST_CHECK_SUBSYSTEM_DISABLE(SYSNAME, [subsystem name]) -dnl -AC_DEFUN([AG_GST_CHECK_SUBSYSTEM_DISABLE], -[ - dnl this define will replace each literal subsys_def occurrence with - dnl the lowercase hyphen-separated subsystem - dnl e.g. if $1 is GST_DEBUG then subsys_def will be a macro with gst-debug - define([subsys_def],translit([$1], _A-Z, -a-z)) - - AC_ARG_ENABLE(subsys_def, - AC_HELP_STRING(--disable-subsys_def, [disable $2]), - [ - case "${enableval}" in - yes) GST_DISABLE_[$1]=no ;; - no) GST_DISABLE_[$1]=yes ;; - *) AC_MSG_ERROR([bad value ${enableval} for --enable-subsys_def]) ;; - esac - ], - [GST_DISABLE_[$1]=no]) dnl Default value - - if test x$GST_DISABLE_[$1] = xyes; then - AC_MSG_NOTICE([disabled subsystem [$2]]) - GST_DISABLE_[$1]_DEFINE="#define GST_DISABLE_$1 1" - else - GST_DISABLE_[$1]_DEFINE="/* #undef GST_DISABLE_$1 */" - fi - AC_SUBST(GST_DISABLE_[$1]_DEFINE) - undefine([subsys_def]) -]) - - -dnl Parse gstconfig.h for feature and defines add the symbols and substitions -dnl -dnl AG_GST_PARSE_SUBSYSTEM_DISABLE(GST_CONFIGPATH, FEATURE) -dnl -AC_DEFUN([AG_GST_PARSE_SUBSYSTEM_DISABLE], -[ - grep >/dev/null "#undef GST_DISABLE_$2" $1 - if test $? = 0; then - GST_DISABLE_[$2]=0 - else - GST_DISABLE_[$2]=1 - fi - AC_SUBST(GST_DISABLE_[$2]) -]) - -dnl Parse gstconfig.h and defines add the symbols and substitions -dnl -dnl GST_CONFIGPATH=`$PKG_CONFIG --variable=includedir gstreamer-0.10`"/gst/gstconfig.h" -dnl AG_GST_PARSE_SUBSYSTEM_DISABLES(GST_CONFIGPATH) -dnl -AC_DEFUN([AG_GST_PARSE_SUBSYSTEM_DISABLES], -[ - AG_GST_PARSE_SUBSYSTEM_DISABLE($1,GST_DEBUG) - AG_GST_PARSE_SUBSYSTEM_DISABLE($1,LOADSAVE) - AG_GST_PARSE_SUBSYSTEM_DISABLE($1,PARSE) - AG_GST_PARSE_SUBSYSTEM_DISABLE($1,TRACE) - AG_GST_PARSE_SUBSYSTEM_DISABLE($1,ALLOC_TRACE) - AG_GST_PARSE_SUBSYSTEM_DISABLE($1,REGISTRY) - AG_GST_PARSE_SUBSYSTEM_DISABLE($1,ENUMTYPES) - AG_GST_PARSE_SUBSYSTEM_DISABLE($1,INDEX) - AG_GST_PARSE_SUBSYSTEM_DISABLE($1,PLUGIN) - AG_GST_PARSE_SUBSYSTEM_DISABLE($1,URI) - AG_GST_PARSE_SUBSYSTEM_DISABLE($1,XML) -]) - - - -dnl relies on GST_PLUGINS_ALL, GST_PLUGINS_SELECTED, GST_PLUGINS_YES, -dnl GST_PLUGINS_NO, and BUILD_EXTERNAL -AC_DEFUN([AG_GST_OUTPUT_PLUGINS], [ - -echo "configure: *** Plug-ins without external dependencies that will be built:" -( for i in $GST_PLUGINS_SELECTED; do /bin/echo -e '\t'$i; done ) | sort -echo - -echo "configure: *** Plug-ins without external dependencies that will NOT be built:" -( for i in $GST_PLUGINS_ALL; do - case $GST_PLUGINS_SELECTED in - *$i*) - ;; - *) - /bin/echo -e '\t'$i - ;; - esac - done ) | sort -echo - -if test "x$BUILD_EXTERNAL" = "xno"; then - echo "configure: *** No plug-ins with external dependencies will be built" -else - /bin/echo -n "configure: *** Plug-ins with dependencies that will be built:" - /bin/echo -e "$GST_PLUGINS_YES" | sort - /bin/echo - /bin/echo -n "configure: *** Plug-ins with dependencies that will NOT be built:" - /bin/echo -e "$GST_PLUGINS_NO" | sort - /bin/echo -fi -]) - diff --git a/common/m4/gst-function.m4 b/common/m4/gst-function.m4 deleted file mode 100644 index 12166214d5..0000000000 --- a/common/m4/gst-function.m4 +++ /dev/null @@ -1,63 +0,0 @@ -dnl -dnl Check for compiler mechanism to show functions in debugging -dnl copied from an Ali patch floating on the internet -dnl -AC_DEFUN([AG_GST_CHECK_FUNCTION],[ - dnl #1: __PRETTY_FUNCTION__ - AC_MSG_CHECKING(whether $CC implements __PRETTY_FUNCTION__) - AC_CACHE_VAL(have_pretty_function,[ - AC_TRY_LINK([#include ], - [printf("%s", __PRETTY_FUNCTION__);], - have_pretty_function=yes, - have_pretty_function=no) - ]) - AC_MSG_RESULT($have_pretty_function) - if test "$have_pretty_function" = yes; then - AC_DEFINE(HAVE_PRETTY_FUNCTION, 1, - [defined if the compiler implements __PRETTY_FUNCTION__]) - fi - -dnl #2: __FUNCTION__ - AC_MSG_CHECKING(whether $CC implements __FUNCTION__) - AC_CACHE_VAL(have_function,[ - AC_TRY_LINK([#include ], - [printf("%s", __FUNCTION__);], - have_function=yes, - have_function=no) - ]) - AC_MSG_RESULT($have_function) - if test "$have_function" = yes; then - AC_DEFINE(HAVE_FUNCTION, 1, - [defined if the compiler implements __FUNCTION__]) - fi - -dnl #3: __func__ - AC_MSG_CHECKING(whether $CC implements __func__) - AC_CACHE_VAL(have_func,[ - AC_TRY_LINK([#include ], - [printf("%s", __func__);], - have_func=yes, - have_func=no) - ]) - AC_MSG_RESULT($have_func) - if test "$have_func" = yes; then - AC_DEFINE(HAVE_FUNC, 1, - [defined if the compiler implements __func__]) - fi - -dnl now define FUNCTION to whatever works, and fallback to "" - if test "$have_pretty_function" = yes; then - function=__PRETTY_FUNCTION__ - else - if test "$have_function" = yes; then - function=__FUNCTION__ - else - if test "$have_func" = yes; then - function=__func__ - else - function=\"\" - fi - fi - fi - AC_DEFINE_UNQUOTED(GST_FUNCTION, $function, [macro to use to show function name]) -]) diff --git a/common/m4/gst-gettext.m4 b/common/m4/gst-gettext.m4 deleted file mode 100644 index a63651bf84..0000000000 --- a/common/m4/gst-gettext.m4 +++ /dev/null @@ -1,21 +0,0 @@ -dnl gettext setup - -dnl AG_GST_GETTEXT([gettext-package]) -dnl defines GETTEXT_PACKAGE and LOCALEDIR - -AC_DEFUN([AG_GST_GETTEXT], -[ - if test "$USE_NLS" = "yes"; then - GETTEXT_PACKAGE=[$1] - else - GETTEXT_PACKAGE=[NULL] - fi - AC_SUBST(GETTEXT_PACKAGE) - AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], "$GETTEXT_PACKAGE", - [gettext package name]) - - dnl define LOCALEDIR in config.h - AS_AC_EXPAND(LOCALEDIR, $datadir/locale) - AC_DEFINE_UNQUOTED([LOCALEDIR], "$LOCALEDIR", - [gettext locale dir]) -]) diff --git a/common/m4/gst-glib2.m4 b/common/m4/gst-glib2.m4 deleted file mode 100644 index 71e293b279..0000000000 --- a/common/m4/gst-glib2.m4 +++ /dev/null @@ -1,26 +0,0 @@ -dnl check for a minimum version of GLib - -dnl AG_GST_GLIB_CHECK([minimum-version-required]) - -AC_DEFUN([AG_GST_GLIB_CHECK], -[ - dnl Minimum required version of GLib - GLIB_REQ=[$1] - if test "x$GLIB_REQ" = "x" - then - AC_MSG_ERROR([Please specify a required version for GLib 2.0]) - fi - AC_SUBST(GLIB_REQ) - - dnl Check for glib with everything - PKG_CHECK_MODULES(GLIB, - glib-2.0 >= $GLIB_REQ gobject-2.0 gthread-2.0 gmodule-no-export-2.0, - HAVE_GLIB=yes,HAVE_GLIB=no) - - if test "x$HAVE_GLIB" = "xno"; then - AC_MSG_ERROR([This package requires GLib >= $GLIB_REQ to compile.]) - fi - - dnl for the poor souls who for example have glib in /usr/local - AS_SCRUB_INCLUDE(GLIB_CFLAGS) -]) diff --git a/common/m4/gst-libxml2.m4 b/common/m4/gst-libxml2.m4 deleted file mode 100644 index 001d67b827..0000000000 --- a/common/m4/gst-libxml2.m4 +++ /dev/null @@ -1,43 +0,0 @@ -dnl call this macro with the minimum required version as an argument -dnl this macro sets and AC_SUBSTs XML_CFLAGS and XML_LIBS -dnl it also sets LIBXML_PKG, used for the pkg-config file - -AC_DEFUN([AG_GST_LIBXML2_CHECK], -[ - dnl Minimum required version of libxml2 - dnl default to 2.4.9 if not specified - LIBXML2_REQ=ifelse([$1],,2.4.9,[$1]) - AC_SUBST(LIBXML2_REQ) - - dnl check for libxml2 - PKG_CHECK_MODULES(XML, libxml-2.0 >= $LIBXML2_REQ, - HAVE_LIBXML2=yes, HAVE_LIBXML2=no) - if test "x$HAVE_LIBXML2" = "xyes"; then - AC_DEFINE(HAVE_LIBXML2, 1, [Define if libxml2 is available]) - else - AC_MSG_ERROR([Need libxml2 for glib2 builds -- you should be able to do without it -- this needs fixing]) - fi - dnl this is for the .pc file - LIBXML_PKG=', libxml-2.0' - AC_SUBST(LIBXML_PKG) - AC_SUBST(XML_LIBS) - AC_SUBST(XML_CFLAGS) - - dnl XML_LIBS might pull in -lz without zlib actually being on the system, so - dnl try linking with these LIBS and CFLAGS - ac_save_CFLAGS=$CFLAGS - ac_save_LIBS=$LIBS - CFLAGS="$CFLAGS $XML_CFLAGS" - LIBS="$LIBS $XML_LIBS" - AC_TRY_LINK([ -#include -#include -],[ -/* function body */ -], - AC_MSG_NOTICE([Test xml2 program linked]), - AC_MSG_ERROR([Could not link libxml2 test program. Check if you have the necessary dependencies.]) - ) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" -]) diff --git a/common/m4/gst-plugindir.m4 b/common/m4/gst-plugindir.m4 deleted file mode 100644 index 09989d0742..0000000000 --- a/common/m4/gst-plugindir.m4 +++ /dev/null @@ -1,17 +0,0 @@ -dnl AG_GST_SET_PLUGINDIR - -dnl AC_DEFINE PLUGINDIR to the full location where plug-ins will be installed -dnl AC_SUBST plugindir, to be used in Makefile.am's - -AC_DEFUN([AG_GST_SET_PLUGINDIR], -[ - dnl define location of plugin directory - AS_AC_EXPAND(PLUGINDIR, ${libdir}/gstreamer-$GST_MAJORMINOR) - AC_DEFINE_UNQUOTED(PLUGINDIR, "$PLUGINDIR", - [directory where plugins are located]) - AC_MSG_NOTICE([Using $PLUGINDIR as the plugin install location]) - - dnl plugin directory configure-time variable for use in Makefile.am - plugindir="\$(libdir)/gstreamer-$GST_MAJORMINOR" - AC_SUBST(plugindir) -]) diff --git a/common/m4/gst-valgrind.m4 b/common/m4/gst-valgrind.m4 deleted file mode 100644 index 93c26357b9..0000000000 --- a/common/m4/gst-valgrind.m4 +++ /dev/null @@ -1,35 +0,0 @@ -AC_DEFUN([AG_GST_VALGRIND_CHECK], -[ - dnl valgrind inclusion - AC_ARG_ENABLE(valgrind, - AC_HELP_STRING([--disable-valgrind], [disable run-time valgrind detection]), - [ - case "${enableval}" in - yes) USE_VALGRIND="$USE_DEBUG" ;; - no) USE_VALGRIND=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-valgrind) ;; - esac], - [ - USE_VALGRIND="$USE_DEBUG" - ]) dnl Default value - - VALGRIND_REQ="2.1" - if test "x$USE_VALGRIND" = xyes; then - PKG_CHECK_MODULES(VALGRIND, valgrind > $VALGRIND_REQ, - USE_VALGRIND="yes", - [ - USE_VALGRIND="no" - AC_MSG_RESULT([no]) - ]) - fi - - if test "x$USE_VALGRIND" = xyes; then - AC_DEFINE(HAVE_VALGRIND, 1, [Define if valgrind should be used]) - AC_MSG_NOTICE(Using extra code paths for valgrind) - fi - AC_SUBST(VALGRIND_CFLAGS) - AC_SUBST(VALGRIND_LIBS) - - AC_PATH_PROG(VALGRIND_PATH, valgrind, no) - AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") -]) diff --git a/common/m4/gtk-doc.m4 b/common/m4/gtk-doc.m4 deleted file mode 100644 index af73800bf2..0000000000 --- a/common/m4/gtk-doc.m4 +++ /dev/null @@ -1,53 +0,0 @@ -dnl -*- mode: autoconf -*- - -# serial 1 - -dnl Usage: -dnl GTK_DOC_CHECK([minimum-gtk-doc-version]) -AC_DEFUN([GTK_DOC_CHECK], -[ - AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first - AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first - dnl for overriding the documentation installation directory - AC_ARG_WITH(html-dir, - AC_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),, - [with_html_dir='${datadir}/gtk-doc/html']) - HTML_DIR="$with_html_dir" - AC_SUBST(HTML_DIR) - - dnl enable/disable documentation building - AC_ARG_ENABLE(gtk-doc, - AC_HELP_STRING([--enable-gtk-doc], - [use gtk-doc to build documentation [default=no]]),, - enable_gtk_doc=no) - - have_gtk_doc=no - if test x$enable_gtk_doc = xyes; then - if test -z "$PKG_CONFIG"; then - AC_PATH_PROG(PKG_CONFIG, pkg-config, no) - fi - if test "$PKG_CONFIG" != "no" && $PKG_CONFIG --exists gtk-doc; then - have_gtk_doc=yes - fi - - dnl do we want to do a version check? -ifelse([$1],[],, - [gtk_doc_min_version=$1 - if test "$have_gtk_doc" = yes; then - AC_MSG_CHECKING([gtk-doc version >= $gtk_doc_min_version]) - if $PKG_CONFIG --atleast-version $gtk_doc_min_version gtk-doc; then - AC_MSG_RESULT(yes) - else - AC_MSG_RESULT(no) - have_gtk_doc=no - fi - fi -]) - if test "$have_gtk_doc" != yes; then - enable_gtk_doc=no - fi - fi - - AM_CONDITIONAL(ENABLE_GTK_DOC, test x$enable_gtk_doc = xyes) - AM_CONDITIONAL(GTK_DOC_USE_LIBTOOL, test -n "$LIBTOOL") -]) diff --git a/common/m4/introspection.m4 b/common/m4/introspection.m4 deleted file mode 100644 index 589721c5a0..0000000000 --- a/common/m4/introspection.m4 +++ /dev/null @@ -1,94 +0,0 @@ -dnl -*- mode: autoconf -*- -dnl Copyright 2009 Johan Dahlin -dnl -dnl This file is free software; the author(s) gives unlimited -dnl permission to copy and/or distribute it, with or without -dnl modifications, as long as this notice is preserved. -dnl - -# serial 1 - -m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL], -[ - AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first - AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first - AC_BEFORE([LT_INIT],[$0])dnl setup libtool first - - dnl enable/disable introspection - m4_if([$2], [require], - [dnl - enable_introspection=yes - ],[dnl - AC_ARG_ENABLE(introspection, - AS_HELP_STRING([--enable-introspection[=@<:@no/auto/yes@:>@]], - [Enable introspection for this build]),, - [enable_introspection=auto]) - ])dnl - - AC_MSG_CHECKING([for gobject-introspection]) - - dnl presence/version checking - AS_CASE([$enable_introspection], - [no], [dnl - found_introspection="no (disabled, use --enable-introspection to enable)" - ],dnl - [yes],[dnl - PKG_CHECK_EXISTS([gobject-introspection-1.0],, - AC_MSG_ERROR([gobject-introspection-1.0 is not installed])) - PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], - found_introspection=yes, - AC_MSG_ERROR([You need to have gobject-introspection >= $1 installed to build AC_PACKAGE_NAME])) - ],dnl - [auto],[dnl - PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], found_introspection=yes, found_introspection=no) - ],dnl - [dnl - AC_MSG_ERROR([invalid argument passed to --enable-introspection, should be one of @<:@no/auto/yes@:>@]) - ])dnl - - AC_MSG_RESULT([$found_introspection]) - - INTROSPECTION_SCANNER= - INTROSPECTION_COMPILER= - INTROSPECTION_GENERATE= - INTROSPECTION_GIRDIR= - INTROSPECTION_TYPELIBDIR= - if test "x$found_introspection" = "xyes"; then - INTROSPECTION_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` - INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0` - INTROSPECTION_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` - INTROSPECTION_GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0` - INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)" - INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0` - INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0` - INTROSPECTION_MAKEFILE=`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection - fi - AC_SUBST(INTROSPECTION_SCANNER) - AC_SUBST(INTROSPECTION_COMPILER) - AC_SUBST(INTROSPECTION_GENERATE) - AC_SUBST(INTROSPECTION_GIRDIR) - AC_SUBST(INTROSPECTION_TYPELIBDIR) - AC_SUBST(INTROSPECTION_CFLAGS) - AC_SUBST(INTROSPECTION_LIBS) - AC_SUBST(INTROSPECTION_MAKEFILE) - - AM_CONDITIONAL(HAVE_INTROSPECTION, test "x$found_introspection" = "xyes") -]) - - -dnl Usage: -dnl GOBJECT_INTROSPECTION_CHECK([minimum-g-i-version]) - -AC_DEFUN([GOBJECT_INTROSPECTION_CHECK], -[ - _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1]) -]) - -dnl Usage: -dnl GOBJECT_INTROSPECTION_REQUIRE([minimum-g-i-version]) - - -AC_DEFUN([GOBJECT_INTROSPECTION_REQUIRE], -[ - _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1], [require]) -]) diff --git a/common/m4/pkg.m4 b/common/m4/pkg.m4 deleted file mode 100644 index 6c35916f6b..0000000000 --- a/common/m4/pkg.m4 +++ /dev/null @@ -1,131 +0,0 @@ -# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- -# -# Copyright © 2004 Scott James Remnant . -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# PKG_PROG_PKG_CONFIG([MIN-VERSION]) -# ---------------------------------- -AC_DEFUN([PKG_PROG_PKG_CONFIG], -[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) -m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) -AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=m4_ifval([$1], [$1], [0.9.0]) - AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - PKG_CONFIG="" - fi - -fi[]dnl -])# PKG_PROG_PKG_CONFIG - -# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -# -# Check to see whether a particular set of modules exists. Similar -# to PKG_CHECK_MODULES(), but does not set variables or print errors. -# -# -# Similar to PKG_CHECK_MODULES, make sure that the first instance of -# this or PKG_CHECK_MODULES is called, or make sure to call -# PKG_CHECK_EXISTS manually -# -------------------------------------------------------------- -AC_DEFUN([PKG_CHECK_EXISTS], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -if test -n "$PKG_CONFIG" && \ - AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then - m4_ifval([$2], [$2], [:]) -m4_ifvaln([$3], [else - $3])dnl -fi]) - - -# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) -# --------------------------------------------- -m4_define([_PKG_CONFIG], -[if test -n "$PKG_CONFIG"; then - PKG_CHECK_EXISTS([$3], - [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], - [pkg_failed=yes]) -else - pkg_failed=untried -fi[]dnl -])# _PKG_CONFIG - -# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], -# [ACTION-IF-NOT-FOUND]) -# -# -# Note that if there is a possibility the first call to -# PKG_CHECK_MODULES might not happen, you should be sure to include an -# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac -# -# -# -------------------------------------------------------------- -AC_DEFUN([PKG_CHECK_MODULES], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl -AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl - -pkg_failed=no -AC_MSG_CHECKING([for $1]) - -_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) -_PKG_CONFIG([$1][_LIBS], [libs], [$2]) - -if test $pkg_failed = yes; then - $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` - # Put the nasty error message in config.log where it belongs - echo "$$1[]_PKG_ERRORS" 1>&AS_MESSAGE_LOG_FD - - ifelse([$4], , [AC_MSG_ERROR(dnl -[Package requirements ($2) were not met. -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -Alternatively you may set the $1_CFLAGS and $1_LIBS environment variables -to avoid the need to call pkg-config. See the pkg-config man page for -more details.])], - [$4]) -elif test $pkg_failed = untried; then - ifelse([$4], , [AC_MSG_FAILURE(dnl -[The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -Alternatively you may set the $1_CFLAGS and $1_LIBS environment variables -to avoid the need to call pkg-config. See the pkg-config man page for -more details. - -To get pkg-config, see .])], - [$4]) -else - $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS - $1[]_LIBS=$pkg_cv_[]$1[]_LIBS - AC_MSG_RESULT([yes]) - ifelse([$3], , :, [$3]) -fi[]dnl -])# PKG_CHECK_MODULES diff --git a/common/mangle-tmpl.py b/common/mangle-tmpl.py deleted file mode 100644 index d3190402b6..0000000000 --- a/common/mangle-tmpl.py +++ /dev/null @@ -1,155 +0,0 @@ -# -*- Mode: Python -*- -# vi:si:et:sw=4:sts=4:ts=4 - -""" -use the output from gst-xmlinspect.py to mangle tmpl/*.sgml and -insert/overwrite Short Description and Long Description -""" - -# FIXME: right now it uses pygst and scans on its own; -# we really should use inspect/*.xml instead since the result of -# gst-xmlinspect.py is commited by the docs maintainer, who can be -# expected to have pygst, but this step should be done for every docs build, -# so no pygst allowed - -# read in inspect/*.xml -# for every tmpl/element-(name).xml: mangle with details from element - -import glob -import re -import sys -import os - -class Tmpl: - def __init__(self, filename): - self.filename = filename - self._sectionids = [] - self._sections = {} - - def read(self): - """ - Read and parse the sections from the given file. - """ - lines = open(self.filename).readlines() - matcher = re.compile("\n") - id = None - - for line in lines: - match = matcher.search(line) - if match: - id = match.expand("\\1") - self._sectionids.append(id) - self._sections[id] = [] - else: - if not id: - sys.stderr.write( - "WARNING: line before a SECTION header: %s" % line) - else: - self._sections[id].append(line) - - def get_section(self, id): - """ - Get the content from the given section. - """ - return self._sections[id] - - def set_section(self, id, content): - """ - Replace the given section id with the given content. - """ - self._sections[id] = content - - def output(self): - """ - Return the output of the current template in the tmpl/*.sgml format. - """ - lines = [] - for id in self._sectionids: - lines.append("\n" % id) - for line in self._sections[id]: - lines.append(line) - - return "".join(lines) - - def write(self, backup=False): - """ - Write out the template file again, backing up the previous one. - """ - if backup: - target = self.filename + ".mangle.bak" - os.rename(self.filename, target) - - handle = open(self.filename, "w") - handle.write(self.output()) - handle.close() - -from xml.dom.ext.reader import Sax2 -from xml.dom.NodeFilter import NodeFilter - -def get_elements(file): - elements = {} - handle = open(file) - reader = Sax2.Reader() - doc = reader.fromStream(handle) - handle.close() - - walker = doc.createTreeWalker(doc.documentElement, - NodeFilter.SHOW_ELEMENT, None, 0) - while walker.currentNode and walker.currentNode.tagName != 'elements': - walker.nextNode() - - # we're at elements now - el = walker.firstChild() - while walker.currentNode: - element = walker.firstChild() - # loop over children of - name = None - description = None - while walker.currentNode: - if walker.currentNode.tagName == 'name': - name = walker.currentNode.firstChild.data.encode('UTF-8') - if walker.currentNode.tagName == 'description': - description = walker.currentNode.firstChild.data.encode('UTF-8') - if not walker.nextSibling(): break - # back up to - walker.parentNode() - elements[name] = {'description': description} - - if not walker.nextSibling(): break - - return elements - - -def main(): - if not len(sys.argv) == 3: - sys.stderr.write('Please specify the inspect/ dir and the tmpl/ dir') - sys.exit(1) - - inspectdir = sys.argv[1] - tmpldir = sys.argv[2] - - # parse all .xml files; build map of element name -> short desc - #for file in glob.glob("inspect/plugin-*.xml"): - elements = {} - for file in glob.glob("%s/plugin-*.xml" % inspectdir): - elements.update(get_elements(file)) - - for file in glob.glob("%s/element-*.sgml" % tmpldir): - base = os.path.basename(file) - element = base[len("element-"):-len(".sgml")] - tmpl = Tmpl(file) - tmpl.read() - if element in elements.keys(): - description = elements[element]['description'] - tmpl.set_section("Short_Description", "%s\n\n" % description) - - # put in an include if not yet there - line = '\n' - section = tmpl.get_section("Long_Description") - if not section[0] == line: - section.insert(0, line) - tmpl.set_section("Long_Description", section) - tmpl.write() - -main() diff --git a/common/plugins.xsl b/common/plugins.xsl deleted file mode 100644 index 150087f53d..0000000000 --- a/common/plugins.xsl +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - - - - - - - -plugins- - - - - - - - - - - - - - Element Information - - - - - plugin - - - - plugin- - - - - - - - - author - - - - - - - class - - - - - - - - Element Pads - - - - - name - - - - - - - direction - - - - - - - presence - - - - - - - details - - - - - - - - - - - - - - - - - - -plugins-plugin- - - - - - - 3 - FIXME Library - - - - - - plugin- - - - - - - - - - - - Plugin Information - - - - filename - - - - - - - version - - - - - - - run-time license - - - - - - - package - - - - - - - origin - - - - - - - - - - - - - - - - - - - - - - - Elements - - - - - - - - - - - - - - diff --git a/common/po.mak b/common/po.mak deleted file mode 100644 index e019fac121..0000000000 --- a/common/po.mak +++ /dev/null @@ -1,4 +0,0 @@ -# rule to download the latest .po files -download-po: $(top_srcdir)/common/download-translations - $(top_srcdir)/common/download-translations $(PACKAGE) - diff --git a/common/release.mak b/common/release.mak deleted file mode 100644 index 373146537a..0000000000 --- a/common/release.mak +++ /dev/null @@ -1,25 +0,0 @@ -# include this snippet to add a common release: target by using -# include $(top_srcdir)/common/release.mak - -# make bz2 as well -AUTOMAKE_OPTIONS = dist-bzip2 - -release: dist - make $(PACKAGE)-$(VERSION).tar.gz.md5 - make $(PACKAGE)-$(VERSION).tar.bz2.md5 - -# generate md5 sum files -%.md5: % - md5sum $< > $@ - -# check that no marshal or enumtypes files are included -# this in turn ensures that distcheck fails for missing .list files which is currently -# shadowed when the corresponding .c and .h files are included. -distcheck-hook: - @test "x" = "x`find $(distdir) -name \*-enumtypes.[ch] | grep -v win32`" && \ - test "x" = "x`find $(distdir) -name \*-marshal.[ch]`" || \ - ( $(ECHO) "*** Leftover enumtypes or marshal files in the tarball." && \ - $(ECHO) "*** Make sure the following files are not disted:" && \ - find $(distdir) -name \*-enumtypes.[ch] | grep -v win32 && \ - find $(distdir) -name \*-marshal.[ch] && \ - false ) diff --git a/common/scangobj-merge.py b/common/scangobj-merge.py deleted file mode 100755 index 4917255da5..0000000000 --- a/common/scangobj-merge.py +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/python -# -*- Mode: Python -*- -# vi:si:et:sw=4:sts=4:ts=4 - -""" -parse, update and write .signals and .args files -""" - -from twisted.python import util - -import sys -import os - -def debug(*args): - pass - -class Object: - def __init__(self, name): - self._signals = util.OrderedDict() - self._args = util.OrderedDict() - self.name = name - - def __repr__(self): - return "" % self.name - - def add_signal(self, signal, overwrite=True): - if not overwrite and self._signals.has_key(signal.name): - raise IndexError, "signal %s already in %r" % (signal.name, self) - self._signals[signal.name] = signal - - def add_arg(self, arg, overwrite=True): - if not overwrite and self._args.has_key(arg.name): - raise IndexError, "arg %s already in %r" % (arg.name, self) - self._args[arg.name] = arg - -class Docable: - def __init__(self, **kwargs): - for key in self.attrs: - setattr(self, key, kwargs[key]) - self.dict = kwargs - - def __repr__(self): - return "<%r %s>" % (str(self.__class__), self.name) - -class Signal(Docable): - attrs = ['name', 'returns', 'args'] - -class Arg(Docable): - attrs = ['name', 'type', 'range', 'flags', 'nick', 'blurb', 'default'] - -class GDoc: - def load_file(self, filename): - try: - lines = open(filename).readlines() - self.load_data("".join(lines)) - except IOError: - print "WARNING - could not read from %s" % filename - - def save_file(self, filename, backup=False): - """ - Save the signals information to the given .signals file if the - file content changed. - """ - olddata = None - try: - lines = open(filename).readlines() - olddata = "".join(lines) - except IOError: - print "WARNING - could not read from %s" % filename - newdata = self.get_data() - if olddata and olddata == newdata: - return - - if olddata: - if backup: - os.rename(filename, filename + '.bak') - - handle = open(filename, "w") - handle.write(newdata) - handle.close() - -class Signals(GDoc): - def __init__(self): - self._objects = util.OrderedDict() - - def load_data(self, data): - """ - Load the .signals lines, creating our list of objects and signals. - """ - import re - smatcher = re.compile( - '(?s)' # make . match \n - '\n(.*?)\n' - ) - nmatcher = re.compile( - '' - '(?P\S*)' # store object - '::' - '(?P\S*)' # store signal - '' - ) - rmatcher = re.compile( - '(?s)' # make . match \n - '(?P\S*)\n' # store returns - '(?P.*)' # store args - ) - for block in smatcher.findall(data): - nmatch = nmatcher.search(block) - if nmatch: - o = nmatch.group('object') - debug("Found object", o) - debug("Found signal", nmatch.group('signal')) - if not self._objects.has_key(o): - object = Object(o) - self._objects[o] = object - - rmatch = rmatcher.search(block) - if rmatch: - dict = rmatch.groupdict().copy() - dict['name'] = nmatch.group('signal') - signal = Signal(**dict) - self._objects[o].add_signal(signal) - - def get_data(self): - lines = [] - for o in self._objects.values(): - for s in o._signals.values(): - block = """ -%(object)s::%(name)s -%(returns)s -%(args)s -""" - d = s.dict.copy() - d['object'] = o.name - lines.append(block % d) - - return "\n".join(lines) + '\n' - -class Args(GDoc): - def __init__(self): - self._objects = util.OrderedDict() - - def load_data(self, data): - """ - Load the .args lines, creating our list of objects and args. - """ - import re - amatcher = re.compile( - '(?s)' # make . match \n - '\n(.*?)\n' - ) - nmatcher = re.compile( - '' - '(?P\S*)' # store object - '::' - '(?P\S*)' # store arg - '' - ) - rmatcher = re.compile( - '(?s)' # make . match \n - '(?P\S*)\n' # store type - '(?P.*?)\n' # store range - '(?P\S*)\n' # store flags - '(?P.*?)\n' # store nick - '(?P.*?)\n' # store blurb - '(?P.*?)\n' # store default - ) - for block in amatcher.findall(data): - nmatch = nmatcher.search(block) - if nmatch: - o = nmatch.group('object') - debug("Found object", o) - debug("Found arg", nmatch.group('arg')) - if not self._objects.has_key(o): - object = Object(o) - self._objects[o] = object - - rmatch = rmatcher.search(block) - if rmatch: - dict = rmatch.groupdict().copy() - dict['name'] = nmatch.group('arg') - arg = Arg(**dict) - self._objects[o].add_arg(arg) - else: - print "ERROR: could not match arg from block %s" % block - - def get_data(self): - lines = [] - for o in self._objects.values(): - for a in o._args.values(): - block = """ -%(object)s::%(name)s -%(type)s -%(range)s -%(flags)s -%(nick)s -%(blurb)s -%(default)s - -""" - d = a.dict.copy() - d['object'] = o.name - lines.append(block % d) - - return "\n".join(lines) + '\n' - -def main(argv): - modulename = None - try: - modulename = argv[1] - except IndexError: - sys.stderr.write('Pleae provide a documentation module name\n') - sys.exit(1) - - print "Merging scangobj output for %s" % modulename - signals = Signals() - signals.load_file(modulename + '.signals') - signals.load_file(modulename + '.signals.new') - signals.save_file(modulename + '.signals', backup=True) - - args = Args() - args.load_file(modulename + '.args') - args.load_file(modulename + '.args.new') - args.save_file(modulename + '.args', backup=True) - -main(sys.argv) diff --git a/common/upload.mak b/common/upload.mak deleted file mode 100644 index 60731e5783..0000000000 --- a/common/upload.mak +++ /dev/null @@ -1,33 +0,0 @@ -# this snippet is to be included by both our docbook manuals -# and gtk-doc API references - -# it adds an upload target to each of these dir's Makefiles - -# each Makefile.am should define the following variables: -# - DOC: the base name of the documentation -# (faq, manual, pwg, gstreamer, gstreamer-libs) -# - FORMATS: the formats in which DOC is output -# (html ps pdf) - -# if you want to use it, make sure your $HOME/.ssh/config file contains the -# correct User entry for the Host entry for the DOC_SERVER - -# these variables define the location of the online docs -DOC_SERVER = gstreamer.freedesktop.org -DOC_BASE = /srv/gstreamer.freedesktop.org/www/data/doc -DOC_URL = $(DOC_SERVER):$(DOC_BASE) - -upload: $(FORMATS) - @if test "x$(PACKAGE_VERSION_NANO)" = x0; then \ - export DOCVERSION=$(VERSION); \ - else export DOCVERSION=head; \ - fi; \ - export DIR=$(DOC_BASE)/gstreamer/$$DOCVERSION/$(DOC); \ - ssh $(DOC_SERVER) mkdir -p $$DIR; \ - if echo $(FORMATS) | grep html > /dev/null; then export SRC="$$SRC html"; fi; \ - if echo $(FORMATS) | grep ps > /dev/null; then export SRC="$$SRC $(DOC).ps"; fi; \ - if echo $(FORMATS) | grep pdf > /dev/null; then export SRC="$$SRC $(DOC).pdf"; fi; \ - echo Uploading $$SRC to $(DOC_SERVER):$$DIR; \ - rsync -rv -e ssh --delete $$SRC $(DOC_SERVER):$$DIR; \ - ssh $(DOC_SERVER) chmod -R g+w $$DIR; \ - echo Done From 99e07a21d4b23b143ebeb41dcf87eb0f8d79ef30 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 1 Dec 2010 20:00:22 +0100 Subject: [PATCH 0215/1776] Add common submodule --- .gitmodules | 3 +++ common | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 common diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..a6b1edac4c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "common"] + path = common + url = git://anongit.freedesktop.org/gstreamer/common diff --git a/common b/common new file mode 160000 index 0000000000..011bcc8a0f --- /dev/null +++ b/common @@ -0,0 +1 @@ +Subproject commit 011bcc8a0fc7f798ee874a7ba899123fb2470e22 From 3dcf9a3382cb121a5a55aa51ced07dec472c6c6d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 6 Dec 2010 12:40:30 +0100 Subject: [PATCH 0216/1776] configure: open 0.11 branch --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index fd09ff0add..c8b8ea4621 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.60) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.7.1, +AC_INIT(Gst-RTSP, 0.11.0.1, http://gstreamer.net/, gst-rtsp) @@ -35,14 +35,14 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])], dnl our libraries and install dirs use major.minor as a version GST_MAJORMINOR=$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR dnl we override it here if we need to for the release candidate of new series -GST_MAJORMINOR=0.10 +GST_MAJORMINOR=0.11 AC_SUBST(GST_MAJORMINOR) AM_PROG_LIBTOOL dnl *** required versions of GStreamer stuff *** -GST_REQ=0.10.29 -GSTPB_REQ=0.10.29 +GST_REQ=0.11.0 +GSTPB_REQ=0.11.0 dnl *** autotools stuff **** From 422fea478c87430f5a1733ba93d3e7d4960a6771 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 6 Dec 2010 19:29:53 +0100 Subject: [PATCH 0217/1776] media: warn and fail when gstrtpbin is not found --- gst/rtsp-server/rtsp-media.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index af802e9d65..8a218ec104 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1501,6 +1501,10 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) if (!media->reusable && media->reused) goto is_reused; + media->rtpbin = gst_element_factory_make ("gstrtpbin", NULL); + if (media->rtpbin == NULL) + goto no_gstrtpbin; + GST_INFO ("preparing media %p", media); /* reset some variables */ @@ -1520,8 +1524,6 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) klass = GST_RTSP_MEDIA_GET_CLASS (media); media->id = g_source_attach (media->source, klass->context); - media->rtpbin = gst_element_factory_make ("gstrtpbin", NULL); - /* add stuff to the bin */ gst_bin_add (GST_BIN (media->pipeline), media->rtpbin); @@ -1592,6 +1594,12 @@ is_reused: GST_WARNING ("can not reuse media %p", media); return FALSE; } +no_gstrtpbin: + { + GST_WARNING ("no gstrtpbin element"); + g_warning ("failed to create element 'gstrtpbin', check your installation"); + return FALSE; + } state_failed: { GST_WARNING ("failed to preroll pipeline"); From ca7b6551b5675e702b1db007c1fe6eb57a086662 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 7 Dec 2010 18:14:22 +0100 Subject: [PATCH 0218/1776] autogen/configure: Bring more in sync to standard gst module behaviour --- autogen.sh | 76 +++++++++++++++++++++++++++++----------------------- configure.ac | 33 ++++++++++++++++++----- 2 files changed, 69 insertions(+), 40 deletions(-) diff --git a/autogen.sh b/autogen.sh index 737032a07c..edb1dd1d85 100755 --- a/autogen.sh +++ b/autogen.sh @@ -5,16 +5,13 @@ DIE=0 package=gst-rtsp srcfile=gst/rtsp-server/rtsp-server.c -# a quick cvs co to ease the transition -if test ! -d common; +# Make sure we have common +if test ! -f common/gst-autogen.sh; then - echo "+ getting common/ from cvs" - if test -e CVS/Tag - then - TAG="-r `tail -c +2 CVS/Tag`" - fi - cvs co $TAG common + echo "+ Setting up common submodule" + git submodule init fi +git submodule update # source helper functions if test ! -f common/gst-autogen.sh; @@ -25,18 +22,25 @@ then fi . common/gst-autogen.sh +# install pre-commit hook for doing clean commits +if test ! \( -x .git/hooks/pre-commit -a -L .git/hooks/pre-commit \); +then + rm -f .git/hooks/pre-commit + ln -s ../../common/hooks/pre-commit.hook .git/hooks/pre-commit +fi + CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc' autogen_options $@ -echo -n "+ check for build tools" +printf "+ check for build tools" if test ! -z "$NOCHECK"; then echo ": skipped version checks"; else echo; fi -version_check "autoconf" "$AUTOCONF autoconf autoconf259 autoconf257 autoconf-2.54 autoconf-2.53 autoconf253 autoconf-2.52 autoconf252" \ - "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 52 || DIE=1 -version_check "automake" "$AUTOMAKE automake automake-1.9 automake19 automake-1.8 automake18 automake-1.7 automake17 automake-1.6 automake16" \ - "ftp://ftp.gnu.org/pub/gnu/automake/" 1 7 || DIE=1 +version_check "autoconf" "$AUTOCONF autoconf autoconf270 autoconf269 autoconf268 autoconf267 autoconf266 autoconf265 autoconf264 autoconf263 autoconf262 autoconf261 autoconf260" \ + "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 60 || DIE=1 +version_check "automake" "$AUTOMAKE automake automake-1.11 automake-1.10" \ + "ftp://ftp.gnu.org/pub/gnu/automake/" 1 10 || DIE=1 version_check "autopoint" "autopoint" \ - "ftp://ftp.gnu.org/pub/gnu/gettext/" 0 11 5 || DIE=1 + "ftp://ftp.gnu.org/pub/gnu/gettext/" 0 17 || DIE=1 version_check "libtoolize" "libtoolize libtoolize15 glibtoolize" \ "ftp://ftp.gnu.org/pub/gnu/libtool/" 1 5 0 || DIE=1 version_check "pkg-config" "" \ @@ -61,43 +65,47 @@ fi toplevel_check $srcfile -tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS" +# autopoint +# older autopoint (< 0.12) has a tendency to complain about mkinstalldirs +if test -x mkinstalldirs; then rm mkinstalldirs; fi +# first remove patch if necessary, then run autopoint, then reapply +if test -f po/Makefile.in.in; +then + patch -p0 -R --forward < common/gettext.patch +fi +tool_run "$autopoint" "--force" "patch -p0 < common/gettext.patch" +patch -p0 < common/gettext.patch + +# aclocal +# if test -f acinclude.m4; then rm acinclude.m4; fi + tool_run "$libtoolize" "--copy --force" +tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS" tool_run "$autoheader" # touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode -- wingo echo timestamp > stamp-h.in 2> /dev/null 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 +debug "automake: $automake" +tool_run "$automake" "--add-missing --copy" test -n "$NOCONFIGURE" && { - echo "+ skipping configure stage for package $package, as requested." - echo "+ autogen.sh done." + 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 $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT +./configure $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT || { echo " configure failed" exit 1 } + +echo "Now type 'make' to compile $package." + diff --git a/configure.ac b/configure.ac index fd09ff0add..27bfdaaafd 100644 --- a/configure.ac +++ b/configure.ac @@ -3,8 +3,9 @@ dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too AC_INIT(Gst-RTSP, 0.10.7.1, - http://gstreamer.net/, + http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-rtsp) +AG_GST_INIT dnl initialize automake AM_INIT_AUTOMAKE([-Wno-portability 1.10]) @@ -13,7 +14,7 @@ dnl define PACKAGE_VERSION_* variables AS_VERSION dnl check if this is a release version -AS_NANO(GST_CVS="no", GST_CVS="yes") +AS_NANO(GST_GIT="no", GST_GIT="yes") dnl can autoconf find the source ? AC_CONFIG_SRCDIR([gst/rtsp-server/rtsp-server.c]) @@ -52,6 +53,12 @@ AS_AUTOTOOLS_ALTERNATE dnl Add parameters for aclocal AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4") +dnl set up gettext +dnl the version check needs to stay here because autopoint greps for it +AM_GNU_GETTEXT_VERSION([0.17]) +AM_GNU_GETTEXT([external]) +AG_GST_GETTEXT([gstreamer-$GST_MAJORMINOR]) + dnl *** check for arguments to configure *** AG_GST_ARG_DEBUG @@ -71,8 +78,22 @@ AC_PROG_CC AM_PROG_CC_C_O dnl check for python -AM_PATH_PYTHON(2.3) -AM_CHECK_PYTHON_HEADERS([HAVE_PYTHON_HEADERS="yes"], [HAVE_PYTHON_HEADERS="no"]) +AM_PATH_PYTHON +AC_MSG_CHECKING(for python >= 2.3) +prog=" +import sys, string +minver = (2,3,0,'final',0) +if sys.version_info < minver: + sys.exit(1) +sys.exit(0)" + +if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC +then + AC_MSG_RESULT(okay) +else + AC_MSG_ERROR(too old) +fi +AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)]) AC_PATH_PROG(VALGRIND_PATH, valgrind, no) AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") @@ -190,10 +211,10 @@ dnl set location of plugin directory AG_GST_SET_PLUGINDIR dnl define an ERROR_CFLAGS Makefile variable -AG_GST_SET_ERROR_CFLAGS($GST_CVS) +AG_GST_SET_ERROR_CFLAGS($GST_GIT) dnl define correct level for debugging messages -AG_GST_SET_LEVEL_DEFAULT($GST_CVS) +AG_GST_SET_LEVEL_DEFAULT($GST_GIT) dnl used in examples AG_GST_DEFAULT_ELEMENTS From bdd477f2bf1ca4ac994ab2acb9811a353f02379d Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 7 Dec 2010 18:14:39 +0100 Subject: [PATCH 0219/1776] Makefile.am: Use standard GIR make behaviour --- gst/rtsp-server/Makefile.am | 59 ++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 88a30d4c71..1c61825231 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -8,7 +8,7 @@ public_headers = \ rtsp-session-pool.h \ rtsp-client.h \ rtsp-server.h - + c_sources = \ rtsp-params.c \ rtsp-sdp.c \ @@ -19,13 +19,13 @@ c_sources = \ rtsp-session-pool.c \ rtsp-client.c \ rtsp-server.c - + lib_LTLIBRARIES = \ libgstrtspserver-@GST_MAJORMINOR@.la libgstrtspserver_@GST_MAJORMINOR@_la_SOURCES = \ $(c_sources) - + libgstrtspserver_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) libgstrtspserver_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstrtspserver_@GST_MAJORMINOR@_la_LIBADD = \ @@ -41,28 +41,45 @@ libgstrtspserver_@GST_MAJORMINOR@include_HEADERS = $(public_headers) CLEANFILES = --include $(INTROSPECTION_MAKEFILE) -INTROSPECTION_GIRS = -INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) --strip-prefix=Gst -INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) - if HAVE_INTROSPECTION -introspection_sources = $(public_headers) $(c_sources) +BUILT_GIRSOURCES = GstRtspServer-@GST_MAJORMINOR@.gir -GstRtspServer-0.10.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@GST_MAJORMINOR@.la -GstRtspServer_0_10_gir_INCLUDES = Gst-@GST_MAJORMINOR@ GstRtsp-@GST_MAJORMINOR@ -GstRtspServer_0_10_gir_CFLAGS = $(INCLUDES) -GstRtspServer_0_10_gir_LIBS = libgstrtspserver-@GST_MAJORMINOR@.la -GstRtspServer_0_10_gir_FILES = $(introspection_sources) -GstRtspServer_0_10_gir_NAMESPACE = GstRtspServer -GstRtspServer_0_10_gir_VERSION = @GST_MAJORMINOR@ -INTROSPECTION_GIRS += GstRtspServer-0.10.gir +gir_headers=$(patsubst %,$(srcdir)/%, $(libgstrtspserver_@GST_MAJORMINOR@include_HEADERS)) +gir_sources=$(patsubst %,$(srcdir)/%, $(libgstrtspserver_@GST_MAJORMINOR@_la_SOURCES)) +gir_cincludes=$(patsubst %,--c-include='gst/rtsp-server/%',$(libgstrtspinclude_HEADERS)) +GstRtspServer-@GST_MAJORMINOR@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@GST_MAJORMINOR@.la + $(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \ + $(INTROSPECTION_SCANNER) -v --namespace GstRtspServer \ + --nsversion=@GST_MAJORMINOR@ \ + --strip-prefix=Gst \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + -DIN_GOBJECT_INTROSPECTION=1 \ + --c-include='gst/gst.h' \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \ + --library=libgstrtspserver-0.10.la \ + --include=Gst-0.10 \ + --include=GstRtsp-0.10 \ + --libtool="$(top_builddir)/libtool" \ + --pkg gstreamer-0.10 \ + --pkg gstreamer-rtsp-0.10 \ + --pkg-export gstreamer-rtsp-server-0.10 \ + --output $@ \ + $(gir_headers) \ + $(gir_sources) + +# INTROSPECTION_GIRDIR/INTROSPECTION_TYPELIBDIR aren't the right place to +# install anything - we need to install inside our prefix. girdir = $(datadir)/gir-1.0 -gir_DATA = $(INTROSPECTION_GIRS) +gir_DATA = $(BUILT_GIRSOURCES) -typelibdir = $(libdir)/girepository-1.0 -typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) +typelibsdir = $(libdir)/girepository-1.0/ -CLEANFILES += $(gir_DATA) $(typelib_DATA) +typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) + +%.typelib: %.gir $(INTROSPECTION_COMPILER) + $(AM_V_GEN)$(INTROSPECTION_COMPILER) --includedir=$(srcdir) --includedir=$(builddir) $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) + +CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA) endif From a2680c6c57a507e3337b52b8dda0039b492c6d8e Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 7 Dec 2010 18:52:15 +0100 Subject: [PATCH 0220/1776] docs: Add gtk-doc build system --- Makefile.am | 1 + configure.ac | 3 + docs/Makefile.am | 11 ++ docs/libs/Makefile.am | 105 ++++++++++++ docs/libs/gst-rtsp-server-docs.sgml | 88 ++++++++++ docs/libs/gst-rtsp-server-sections.txt | 223 +++++++++++++++++++++++++ docs/libs/gst-rtsp-server.types | 8 + docs/version.entities.in | 1 + 8 files changed, 440 insertions(+) create mode 100644 docs/Makefile.am create mode 100644 docs/libs/Makefile.am create mode 100644 docs/libs/gst-rtsp-server-docs.sgml create mode 100644 docs/libs/gst-rtsp-server-sections.txt create mode 100644 docs/libs/gst-rtsp-server.types create mode 100644 docs/version.entities.in diff --git a/Makefile.am b/Makefile.am index 6936b37fec..cd0de82863 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,6 +6,7 @@ SUBDIRS = \ m4 \ common \ pkgconfig \ + docs \ examples DIST_SUBDIRS = $(SUBDIRS) diff --git a/configure.ac b/configure.ac index 27bfdaaafd..3c225d027b 100644 --- a/configure.ac +++ b/configure.ac @@ -297,6 +297,9 @@ bindings/vala/Makefile pkgconfig/Makefile pkgconfig/gst-rtsp-server.pc pkgconfig/gst-rtsp-server-uninstalled.pc +docs/Makefile +docs/version.entities +docs/libs/Makefile ]) AC_OUTPUT diff --git a/docs/Makefile.am b/docs/Makefile.am new file mode 100644 index 0000000000..f782512c1a --- /dev/null +++ b/docs/Makefile.am @@ -0,0 +1,11 @@ +if ENABLE_GTK_DOC +DOCS_SUBDIRS = libs +else +DOCS_SUBDIRS = +endif + +SUBDIRS = $(DOCS_SUBDIRS) +DIST_SUBDIRS = libs + +EXTRA_DIST = \ + version.entities.in diff --git a/docs/libs/Makefile.am b/docs/libs/Makefile.am new file mode 100644 index 0000000000..71ac2e0e60 --- /dev/null +++ b/docs/libs/Makefile.am @@ -0,0 +1,105 @@ +GST_DOC_SCANOBJ = $(top_srcdir)/common/gstdoc-scangobj + +## Process this file with automake to produce Makefile.in + +# The name of the module, e.g. 'glib'. +MODULE=gst-rtsp-server +DOC_MODULE=$(MODULE) + +# for upload-doc.mak +DOC=$(MODULE) +FORMATS=html ps pdf +html: html-build.stamp +include $(top_srcdir)/common/upload-doc.mak + +# generated basefiles +#basefiles = \ +## $(DOC_MODULE).types \ +# $(DOC_MODULE)-sections.txt \ +# $(DOC_MODULE)-docs.sgml + +# ugly hack to make -unused.sgml work +#unused-build.stamp: +# BUILDDIR=`pwd` && \ +# cd $(srcdir)/tmpl && \ +# ln -sf gstreamer-libs-unused.sgml \ +# $$BUILDDIR/tmpl/gstreamer-libs-@GST_MAJORMINOR@-unused.sgml +# touch unused-build.stamp + +# these rules are added to create parallel docs using GST_MAJORMINOR +#$(basefiles): gstreamer-libs-@GST_MAJORMINOR@%: gstreamer-libs% +# cp $< $@ + +#CLEANFILES = $(basefiles) + +# The top-level SGML file. Change it if you want. +DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml + +# The directory containing the source code. Relative to $(top_srcdir). +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting functions and macros. +DOC_SOURCE_DIR = $(top_srcdir)/gst/rtsp-server/ +DOC_BUILD_DIR=$(top_builddir)/gst/rtsp-server/ + +SCAN_OPTIONS= + +# FIXME : +# there's something wrong with gstreamer-sections.txt not being in the dist +# maybe it doesn't resolve; we're adding it below for now +#EXTRA_DIST = gstreamer.types.in gstreamer.hierarchy $(DOC_MODULE)-sections.txt gstreamer-sections.txt $(DOC_MAIN_SGML_FILE) + +# Extra options to supply to gtkdoc-mkdb. +MKDB_OPTIONS=--sgml-mode --source-suffixes=c,h,cc,m + +# Extra options to supply to gtkdoc-fixref. +FIXXREF_OPTIONS=--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html \ + --extra-dir=$(GST_PREFIX)/share/gtk-doc/html \ + --extra-dir=$(GSTPB_PREFIX)/share/gtk-doc/html + +# Used for dependencies. +HFILE_GLOB=$(DOC_SOURCE_DIR)/*.h +CFILE_GLOB=$(DOC_SOURCE_DIR)/*.c + +SCANOBJ_DEPS = \ + $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_MAJORMINOR@.la + +# Extra options to supply to gtkdoc-scan. +SCANOBJ_OPTIONS=--type-init-func="g_type_init();gst_init(&argc,&argv)" + +# Header files to ignore when scanning. +IGNORE_HFILES = +IGNORE_CFILES = + +# we add all .h files of elements that have signals/args we want +# sadly this also pulls in the private methods - maybe we should +# move those around in the source ? +# also, we should add some stuff here conditionally based on whether +# or not the plugin will actually build +# but I'm not sure about that - it might be this Just Works given that +# the registry won't have the element + +EXTRA_HFILES = + +# Images to copy into HTML directory. +HTML_IMAGES = + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +content_files = + +# Other files to distribute. +extra_files = + +# CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib +# contains GtkObjects/GObjects and you want to document signals and properties. +GTKDOC_CFLAGS = -I$(top_srcdir) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GST_PBUTILS_CFLAGS) +GTKDOC_LIBS = $(SCANOBJ_DEPS) $(GST_BASE_LIBS) $(GST_LIBS) + +GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC) +GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) + +# If you need to override some of the declarations, place them in this file +# and uncomment this line. +#DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt +DOC_OVERRIDES = + +include $(top_srcdir)/common/gtk-doc.mak diff --git a/docs/libs/gst-rtsp-server-docs.sgml b/docs/libs/gst-rtsp-server-docs.sgml new file mode 100644 index 0000000000..7412dbc143 --- /dev/null +++ b/docs/libs/gst-rtsp-server-docs.sgml @@ -0,0 +1,88 @@ + + +%version-entities; +]> + + + + GStreamer RTSP Server Reference Manual + + for GStreamer RTSP Server &GST_MAJORMINOR; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Object Hierarchy + + + + + API Index + + + diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt new file mode 100644 index 0000000000..a86beac253 --- /dev/null +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -0,0 +1,223 @@ +
+rtsp-media-mapping +GstRTSPMediaMapping +GstRTSPMediaMapping +GstRTSPMediaMappingClass +gst_rtsp_media_mapping_new +gst_rtsp_media_mapping_find_factory +gst_rtsp_media_mapping_add_factory +gst_rtsp_media_mapping_remove_factory + +GST_RTSP_MEDIA_MAPPING_CLASS +GST_RTSP_MEDIA_MAPPING_CAST +GST_RTSP_MEDIA_MAPPING_CLASS_CAST +GST_RTSP_MEDIA_MAPPING +GST_IS_RTSP_MEDIA_MAPPING +GST_TYPE_RTSP_MEDIA_MAPPING +gst_rtsp_media_mapping_get_type +GST_IS_RTSP_MEDIA_MAPPING_CLASS +GST_RTSP_MEDIA_MAPPING_GET_CLASS +
+ +
+rtsp-media-factory +GstRTSPMediaFactory +GstRTSPMediaFactory +GstRTSPMediaFactoryClass +gst_rtsp_media_factory_new +gst_rtsp_media_factory_set_launch +gst_rtsp_media_factory_get_launch +gst_rtsp_media_factory_set_shared +gst_rtsp_media_factory_is_shared +gst_rtsp_media_factory_set_eos_shutdown +gst_rtsp_media_factory_is_eos_shutdown +gst_rtsp_media_factory_construct +gst_rtsp_media_factory_collect_streams + +GST_RTSP_MEDIA_FACTORY_CLASS +GST_RTSP_MEDIA_FACTORY_CAST +GST_RTSP_MEDIA_FACTORY_CLASS_CAST +GST_RTSP_MEDIA_FACTORY +GST_IS_RTSP_MEDIA_FACTORY +GST_TYPE_RTSP_MEDIA_FACTORY +gst_rtsp_media_factory_get_type +GST_IS_RTSP_MEDIA_FACTORY_CLASS +GST_RTSP_MEDIA_FACTORY_GET_CLASS +
+ +
+rtsp-media +GstRTSPMedia +GstRTSPMediaStream +GstRTSPMedia +GstRTSPMediaClass +GstRTSPMediaTrans +GstRTSPSendFunc +GstRTSPKeepAliveFunc +GstRTSPMediaStatus +gst_rtsp_media_new +gst_rtsp_media_set_shared +gst_rtsp_media_is_shared +gst_rtsp_media_set_reusable +gst_rtsp_media_is_reusable +gst_rtsp_media_set_protocols +gst_rtsp_media_get_protocols +gst_rtsp_media_set_eos_shutdown +gst_rtsp_media_is_eos_shutdown +gst_rtsp_media_prepare +gst_rtsp_media_is_prepared +gst_rtsp_media_unprepare +gst_rtsp_media_n_streams +gst_rtsp_media_get_stream +gst_rtsp_media_seek +gst_rtsp_media_stream_rtp +gst_rtsp_media_stream_rtcp +gst_rtsp_media_set_state +gst_rtsp_media_remove_elements +gst_rtsp_media_trans_cleanup + +GST_RTSP_MEDIA_CLASS +GST_RTSP_MEDIA_CAST +GST_RTSP_MEDIA_CLASS_CAST +GST_RTSP_MEDIA +GST_IS_RTSP_MEDIA +GST_TYPE_RTSP_MEDIA +gst_rtsp_media_get_type +GST_IS_RTSP_MEDIA_CLASS +GST_RTSP_MEDIA_GET_CLASS +
+ +
+rtsp-server +GstRTSPServer +GstRTSPServer +GstRTSPServerClass +gst_rtsp_server_new +gst_rtsp_server_set_address +gst_rtsp_server_get_address +gst_rtsp_server_set_service +gst_rtsp_server_get_service +gst_rtsp_server_set_backlog +gst_rtsp_server_get_backlog +gst_rtsp_server_set_session_pool +gst_rtsp_server_get_session_pool +gst_rtsp_server_set_media_mapping +gst_rtsp_server_get_media_mapping +gst_rtsp_server_io_func +gst_rtsp_server_get_io_channel +gst_rtsp_server_create_watch +gst_rtsp_server_attach + +GST_RTSP_SERVER_CLASS +GST_RTSP_SERVER_CAST +GST_RTSP_SERVER_CLASS_CAST +GST_RTSP_SERVER +GST_IS_RTSP_SERVER +GST_TYPE_RTSP_SERVER +gst_rtsp_server_get_type +GST_IS_RTSP_SERVER_CLASS +GST_RTSP_SERVER_GET_CLASS +
+ +
+rtsp-session-pool +GstRTSPSessionPool +GstRTSPSessionPool +GstRTSPSessionPoolClass +GstRTSPSessionPoolFunc +GstRTSPFilterResult +GstRTSPSessionFilterFunc +gst_rtsp_session_pool_new +gst_rtsp_session_pool_set_max_sessions +gst_rtsp_session_pool_get_max_sessions +gst_rtsp_session_pool_get_n_sessions +gst_rtsp_session_pool_create +gst_rtsp_session_pool_find +gst_rtsp_session_pool_remove +gst_rtsp_session_pool_filter +gst_rtsp_session_pool_cleanup +gst_rtsp_session_pool_create_watch + +GST_RTSP_SESSION_POOL_CLASS +GST_RTSP_SESSION_POOL_CAST +GST_RTSP_SESSION_POOL_CLASS_CAST +GST_RTSP_SESSION_POOL +GST_IS_RTSP_SESSION_POOL +GST_TYPE_RTSP_SESSION_POOL +gst_rtsp_session_pool_get_type +GST_IS_RTSP_SESSION_POOL_CLASS +GST_RTSP_SESSION_POOL_GET_CLASS +
+ +
+rtsp-session +GstRTSPSession +GstRTSPSession +GstRTSPSessionClass +GstRTSPSessionStream +GstRTSPSessionMedia +gst_rtsp_session_new +gst_rtsp_session_get_sessionid +gst_rtsp_session_set_timeout +gst_rtsp_session_get_timeout +gst_rtsp_session_touch +gst_rtsp_session_prevent_expire +gst_rtsp_session_allow_expire +gst_rtsp_session_next_timeout +gst_rtsp_session_is_expired +gst_rtsp_session_manage_media +gst_rtsp_session_release_media +gst_rtsp_session_get_media +gst_rtsp_session_media_set_state +gst_rtsp_session_media_get_stream +gst_rtsp_session_media_alloc_channels +gst_rtsp_session_stream_set_transport +gst_rtsp_session_stream_set_callbacks +gst_rtsp_session_stream_set_keepalive + +GST_RTSP_SESSION_CLASS +GST_RTSP_SESSION_CAST +GST_RTSP_SESSION_CLASS_CAST +GST_RTSP_SESSION +GST_IS_RTSP_SESSION +GST_TYPE_RTSP_SESSION +gst_rtsp_session_get_type +GST_IS_RTSP_SESSION_CLASS +GST_RTSP_SESSION_GET_CLASS +
+ +
+rtsp-client +GstRTSPClient +GstRTSPClient +GstRTSPClientClass +gst_rtsp_client_new +gst_rtsp_client_set_session_pool +gst_rtsp_client_get_session_pool +gst_rtsp_client_set_media_mapping +gst_rtsp_client_get_media_mapping +gst_rtsp_client_accept + +GST_RTSP_CLIENT_CLASS +GST_RTSP_CLIENT_CAST +GST_RTSP_CLIENT_CLASS_CAST +GST_RTSP_CLIENT +GST_IS_RTSP_CLIENT +GST_TYPE_RTSP_CLIENT +gst_rtsp_client_get_type +GST_IS_RTSP_CLIENT_CLASS +GST_RTSP_CLIENT_GET_CLASS +
+ +
+rtsp-params +gst_rtsp_params_set +gst_rtsp_params_get +
+ +
+rtsp-sdp +GstSDPInfo +gst_rtsp_sdp_from_media +
+ diff --git a/docs/libs/gst-rtsp-server.types b/docs/libs/gst-rtsp-server.types new file mode 100644 index 0000000000..e87c42564a --- /dev/null +++ b/docs/libs/gst-rtsp-server.types @@ -0,0 +1,8 @@ +#include +gst_rtsp_media_mapping_get_type +gst_rtsp_media_factory_get_type +gst_rtsp_media_get_type +gst_rtsp_server_get_type +gst_rtsp_session_pool_get_type +gst_rtsp_session_get_type +gst_rtsp_client_get_type diff --git a/docs/version.entities.in b/docs/version.entities.in new file mode 100644 index 0000000000..34dc4bca4d --- /dev/null +++ b/docs/version.entities.in @@ -0,0 +1 @@ + From d9a36aa1b73397321c1eda491e1a261907e7afcb Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 7 Dec 2010 18:56:03 +0100 Subject: [PATCH 0221/1776] Makefile: Add cruft-cleaning support --- Makefile.am | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Makefile.am b/Makefile.am index cd0de82863..802e23ab33 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,3 +34,11 @@ check-torture: true endif +# cruft: plugins that have been merged or moved or renamed +CRUFT_FILES = \ + $(top_builddir)/common/shave \ + $(top_builddir)/common/shave-libtool + +include $(top_srcdir)/common/cruft.mak + +all-local: check-cruft \ No newline at end of file From b95165fcff29919eeaf4c5babd1e3d3c82ac99a9 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 11 Dec 2010 10:48:25 +0100 Subject: [PATCH 0222/1776] rtsp-server: Some more doc fixups --- gst/rtsp-server/rtsp-media-mapping.h | 2 +- gst/rtsp-server/rtsp-media.c | 8 ++++---- gst/rtsp-server/rtsp-media.h | 5 ++--- gst/rtsp-server/rtsp-sdp.c | 2 +- gst/rtsp-server/rtsp-session-pool.h | 2 +- gst/rtsp-server/rtsp-session.c | 8 ++++---- gst/rtsp-server/rtsp-session.h | 2 +- 7 files changed, 14 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-mapping.h b/gst/rtsp-server/rtsp-media-mapping.h index 07d4efa8b9..5c3e46f2df 100644 --- a/gst/rtsp-server/rtsp-media-mapping.h +++ b/gst/rtsp-server/rtsp-media-mapping.h @@ -56,7 +56,7 @@ struct _GstRTSPMediaMapping { * GstRTSPMediaMappingClass: * @find_media: Create or return a previously cached #GstRTSPMediaFactory object * for the given url. the default implementation will use the mappings - * added with gst_rtsp_media_mapping_add_factory (). + * added with gst_rtsp_media_mapping_add_factory(). * * The class for the media mapping object. */ diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index af802e9d65..0d93394f46 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -547,7 +547,7 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) /** * gst_rtsp_media_seek: - * @stream: a #GstRTSPMediaStream + * @media: a #GstRTSPMedia * @range: a #GstRTSPTimeRange * * Seek the pipeline to @range. @@ -1475,7 +1475,7 @@ no_more_pads_cb (GstElement * element, GstRTSPMedia * media) /** * gst_rtsp_media_prepare: - * @obj: a #GstRTSPMedia + * @media: a #GstRTSPMedia * * Prepare @media for streaming. This function will create the pipeline and * other objects to manage the streaming. @@ -1604,7 +1604,7 @@ state_failed: /** * gst_rtsp_media_unprepare: - * @obj: a #GstRTSPMedia + * @media: a #GstRTSPMedia * * Unprepare @media. After this call, the media should be prepared again before * it can be used again. If the media is set to be non-reusable, a new instance @@ -1740,7 +1740,7 @@ remove_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, * gst_rtsp_media_set_state: * @media: a #GstRTSPMedia * @state: the target state of the media - * @transports: a GArray of #GstRTSPMediaTrans pointers + * @transports: a #GArray of #GstRTSPMediaTrans pointers * * Set the state of @media to @state and for the transports in @transports. * diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 211e2c04b1..06c299dab2 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -82,7 +82,6 @@ struct _GstRTSPMediaTrans { /** * GstRTSPMediaStream: - * * @srcpad: the srcpad of the stream * @payloader: the payloader of the format * @prepared: if the stream is prepared for streaming @@ -185,7 +184,7 @@ typedef enum { * @range: the range of the media being streamed * * A class that contains the GStreamer element along with a list of - * #GstRTSPediaStream objects that can produce data. + * #GstRTSPMediaStream objects that can produce data. * * This object is usually created from a #GstRTSPMediaFactory. */ @@ -284,7 +283,7 @@ gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstR GstFlowReturn gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer); GstFlowReturn gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer); -gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *trans); +gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transports); void gst_rtsp_media_remove_elements (GstRTSPMedia *media); diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 82ed995082..7f400e29f0 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -22,7 +22,7 @@ /** * gst_rtsp_sdp_from_media: - * @sdp: a #GstSDPessage + * @sdp: a #GstSDPMessage * @info: info * @media: a #GstRTSPMedia * diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 475628c4e2..865b16baee 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -77,7 +77,7 @@ struct _GstRTSPSessionPoolClass { * The function will be called when the pool must be cleaned up because one or * more sessions timed out. * - * Returns: %FALSe if the source should be removed. + * Returns: %FALSE if the source should be removed. */ typedef gboolean (*GstRTSPSessionPoolFunc) (GstRTSPSessionPool *pool, gpointer user_data); diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index f435446b8a..7e25888901 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -178,10 +178,10 @@ gst_rtsp_session_set_property (GObject * object, guint propid, /** * gst_rtsp_session_manage_media: * @sess: a #GstRTSPSession - * @url: the url for the media - * @media: a #GstRTSPMediaObject + * @uri: the uri for the media + * @media: a #GstRTSPMedia * - * Manage the media object @obj in @sess. @url will be used to retrieve this + * Manage the media object @obj in @sess. @uri will be used to retrieve this * media from the session with gst_rtsp_session_get_media(). * * Ownership is taken from @media. @@ -222,7 +222,7 @@ gst_rtsp_session_manage_media (GstRTSPSession * sess, const GstRTSPUrl * uri, /** * gst_rtsp_session_release_media: * @sess: a #GstRTSPSession - * @media: a #GstRTSPMediaObject + * @media: a #GstRTSPMedia * * Release the managed @media in @sess, freeing the memory allocated by it. * diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 3eab592177..cfd75c60c1 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -137,7 +137,7 @@ gboolean gst_rtsp_session_release_media (GstRTSPSession *se GstRTSPSessionMedia *media); /* get media in a session */ GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, - const GstRTSPUrl *uri); + const GstRTSPUrl *url); /* control media */ gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media, GstState state); From eb83fc631866dcc84a5483acda7fa7b902406920 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 11 Dec 2010 10:48:42 +0100 Subject: [PATCH 0223/1776] rtsp-server: Run gst-indent Since it wasn't using the upstream common previously, there was no indentation check before commiting. --- gst/rtsp-server/rtsp-client.c | 32 ++++--- gst/rtsp-server/rtsp-media-factory.c | 112 ++++++++++++----------- gst/rtsp-server/rtsp-media-mapping.c | 20 +++-- gst/rtsp-server/rtsp-media.c | 53 ++++++----- gst/rtsp-server/rtsp-params.c | 4 +- gst/rtsp-server/rtsp-sdp.c | 6 +- gst/rtsp-server/rtsp-server.c | 128 +++++++++++++++------------ gst/rtsp-server/rtsp-session-pool.c | 69 ++++++++------- gst/rtsp-server/rtsp-session.c | 4 +- 9 files changed, 239 insertions(+), 189 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b65b5e4ebd..8207fcca4a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -49,7 +49,7 @@ static void gst_rtsp_client_finalize (GObject * obj); static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session); static void unlink_session_streams (GstRTSPClient * client, - GstRTSPSession *session, GstRTSPSessionMedia * media); + GstRTSPSession * session, GstRTSPSessionMedia * media); G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); @@ -89,18 +89,19 @@ gst_rtsp_client_init (GstRTSPClient * client) } static void -client_unlink_session (GstRTSPClient *client, GstRTSPSession *session) +client_unlink_session (GstRTSPClient * client, GstRTSPSession * session) { GList *medias; /* unlink all media managed in this session */ for (medias = session->medias; medias; medias = g_list_next (medias)) { - unlink_session_streams (client, session, (GstRTSPSessionMedia *) medias->data); + unlink_session_streams (client, session, + (GstRTSPSessionMedia *) medias->data); } } static void -client_cleanup_sessions (GstRTSPClient *client) +client_cleanup_sessions (GstRTSPClient * client) { GList *sessions; @@ -350,7 +351,8 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) } static void -link_stream (GstRTSPClient * client, GstRTSPSession *session, GstRTSPSessionStream * stream) +link_stream (GstRTSPClient * client, GstRTSPSession * session, + GstRTSPSessionStream * stream) { GST_DEBUG ("client %p: linking stream %p", client, stream); gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data, @@ -361,7 +363,8 @@ link_stream (GstRTSPClient * client, GstRTSPSession *session, GstRTSPSessionStre } static void -unlink_stream (GstRTSPClient * client, GstRTSPSession *session, GstRTSPSessionStream * stream) +unlink_stream (GstRTSPClient * client, GstRTSPSession * session, + GstRTSPSessionStream * stream) { GST_DEBUG ("client %p: unlinking stream %p", client, stream); gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); @@ -371,7 +374,8 @@ unlink_stream (GstRTSPClient * client, GstRTSPSession *session, GstRTSPSessionSt } static void -unlink_session_streams (GstRTSPClient * client, GstRTSPSession *session, GstRTSPSessionMedia * media) +unlink_session_streams (GstRTSPClient * client, GstRTSPSession * session, + GstRTSPSessionMedia * media) { guint n_streams, i; @@ -396,7 +400,7 @@ unlink_session_streams (GstRTSPClient * client, GstRTSPSession *session, GstRTSP static void close_connection (GstRTSPClient * client) { - const gchar * tunnelid; + const gchar *tunnelid; GST_DEBUG ("client %p: closing connection", client); @@ -1163,7 +1167,8 @@ client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) /* remove the session */ if (!(client->sessions = g_list_remove (client->sessions, session))) { - GST_INFO ("client %p: all sessions finalized, close the connection", client); + GST_INFO ("client %p: all sessions finalized, close the connection", + client); close_connection (client); } } @@ -1550,7 +1555,8 @@ no_tunnelid: tunnel_existed: { g_mutex_unlock (tunnels_lock); - GST_ERROR ("client %p: tunnel session %s already existed", client, tunnelid); + GST_ERROR ("client %p: tunnel session %s already existed", client, + tunnelid); return FALSE; } } @@ -1562,7 +1568,8 @@ tunnel_start (GstRTSPWatch * watch, gpointer user_data) client = GST_RTSP_CLIENT (user_data); - GST_INFO ("client %p: tunnel start (connection %p)", client, client->connection); + GST_INFO ("client %p: tunnel start (connection %p)", client, + client->connection); if (!remember_tunnel (client)) goto tunnel_error; @@ -1584,7 +1591,8 @@ tunnel_lost (GstRTSPWatch * watch, gpointer user_data) client = GST_RTSP_CLIENT (user_data); - GST_INFO ("client %p: tunnel lost (connection %p)", client, client->connection); + GST_INFO ("client %p: tunnel lost (connection %p)", client, + client->connection); /* ignore error, it'll only be a problem when the client does a POST again */ remember_tunnel (client); diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 9eaddb70f4..f8dfe3359c 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -35,17 +35,22 @@ enum GST_DEBUG_CATEGORY (rtsp_media_debug); #define GST_CAT_DEFAULT rtsp_media_debug -static void gst_rtsp_media_factory_get_property (GObject *object, guint propid, - GValue *value, GParamSpec *pspec); -static void gst_rtsp_media_factory_set_property (GObject *object, guint propid, - const GValue *value, GParamSpec *pspec); +static void gst_rtsp_media_factory_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec); +static void gst_rtsp_media_factory_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec); static void gst_rtsp_media_factory_finalize (GObject * obj); -static gchar * default_gen_key (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); -static GstElement * default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); -static GstRTSPMedia * default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); -static void default_configure (GstRTSPMediaFactory *factory, GstRTSPMedia *media); -static GstElement* default_create_pipeline (GstRTSPMediaFactory *factory, GstRTSPMedia *media); +static gchar *default_gen_key (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url); +static GstElement *default_get_element (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url); +static GstRTSPMedia *default_construct (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url); +static void default_configure (GstRTSPMediaFactory * factory, + GstRTSPMedia * media); +static GstElement *default_create_pipeline (GstRTSPMediaFactory * factory, + GstRTSPMedia * media); G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT); @@ -77,16 +82,18 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) * named dynpay0, dynpay1, etc.. */ g_object_class_install_property (gobject_class, PROP_LAUNCH, - g_param_spec_string ("launch", "Launch", "A launch description of the pipeline", - DEFAULT_LAUNCH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_string ("launch", "Launch", + "A launch description of the pipeline", DEFAULT_LAUNCH, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_SHARED, - g_param_spec_boolean ("shared", "Shared", "If media from this factory is shared", - DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_boolean ("shared", "Shared", + "If media from this factory is shared", DEFAULT_SHARED, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN, g_param_spec_boolean ("eos-shutdown", "EOS Shutdown", - "Send EOS down the pipeline before shutting down", + "Send EOS down the pipeline before shutting down", DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); klass->gen_key = default_gen_key; @@ -108,7 +115,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) factory->lock = g_mutex_new (); factory->medias_lock = g_mutex_new (); factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); + g_free, g_object_unref); } static void @@ -125,8 +132,8 @@ gst_rtsp_media_factory_finalize (GObject * obj) } static void -gst_rtsp_media_factory_get_property (GObject *object, guint propid, - GValue *value, GParamSpec *pspec) +gst_rtsp_media_factory_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec) { GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object); @@ -138,7 +145,8 @@ gst_rtsp_media_factory_get_property (GObject *object, guint propid, g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory)); break; case PROP_EOS_SHUTDOWN: - g_value_set_boolean (value, gst_rtsp_media_factory_is_eos_shutdown (factory)); + g_value_set_boolean (value, + gst_rtsp_media_factory_is_eos_shutdown (factory)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -146,8 +154,8 @@ gst_rtsp_media_factory_get_property (GObject *object, guint propid, } static void -gst_rtsp_media_factory_set_property (GObject *object, guint propid, - const GValue *value, GParamSpec *pspec) +gst_rtsp_media_factory_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec) { GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object); @@ -159,7 +167,8 @@ gst_rtsp_media_factory_set_property (GObject *object, guint propid, gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value)); break; case PROP_EOS_SHUTDOWN: - gst_rtsp_media_factory_set_eos_shutdown (factory, g_value_get_boolean (value)); + gst_rtsp_media_factory_set_eos_shutdown (factory, + g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -200,7 +209,8 @@ gst_rtsp_media_factory_new (void) * etc.. Each of the payloaders will result in a stream. */ void -gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, const gchar *launch) +gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory, + const gchar * launch) { g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); g_return_if_fail (launch != NULL); @@ -221,7 +231,7 @@ gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, const gchar *la * Returns: the configured launch description. g_free() after usage. */ gchar * -gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory) +gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory) { gchar *result; @@ -242,7 +252,7 @@ gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory) * Configure if media created from this factory can be shared between clients. */ void -gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory, +gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory, gboolean shared) { g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); @@ -261,7 +271,7 @@ gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory, * Returns: %TRUE if the media will be shared between clients. */ gboolean -gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory) +gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * factory) { gboolean result; @@ -283,7 +293,7 @@ gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory) * pipeline before shutdown. */ void -gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory *factory, +gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory, gboolean eos_shutdown) { g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); @@ -303,7 +313,7 @@ gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory *factory, * Returns: %TRUE if the media will receive EOS before shutdown. */ gboolean -gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory) +gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory) { gboolean result; @@ -317,17 +327,16 @@ gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory) } static gboolean -compare_media (gpointer key, GstRTSPMedia *media1, GstRTSPMedia *media2) +compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) { return (media1 == media2); } static void -media_unprepared (GstRTSPMedia *media, GstRTSPMediaFactory *factory) +media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory) { g_mutex_lock (factory->medias_lock); - g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, - media); + g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, media); g_mutex_unlock (factory->medias_lock); } @@ -347,7 +356,8 @@ media_unprepared (GstRTSPMedia *media, GstRTSPMediaFactory *factory) * Returns: a new #GstRTSPMedia if the media could be prepared. */ GstRTSPMedia * -gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) +gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url) { gchar *key; GstRTSPMedia *media; @@ -368,8 +378,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl media = g_hash_table_lookup (factory->medias, key); if (media) g_object_ref (media); - } - else + } else media = NULL; if (media == NULL) { @@ -392,10 +401,10 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl key = NULL; } if (!gst_rtsp_media_is_reusable (media)) { - /* when not reusable, connect to the unprepare signal to remove the item - * from our cache when it gets unprepared */ - g_signal_connect (media, "unprepared", (GCallback) media_unprepared, - factory); + /* when not reusable, connect to the unprepare signal to remove the item + * from our cache when it gets unprepared */ + g_signal_connect (media, "unprepared", (GCallback) media_unprepared, + factory); } } } @@ -410,7 +419,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl } static gchar * -default_gen_key (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) +default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { gchar *result; const gchar *pre_query; @@ -419,13 +428,14 @@ default_gen_key (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) pre_query = url->query ? "?" : ""; query = url->query ? url->query : ""; - result = g_strdup_printf ("%u%s%s%s", url->port, url->abspath, pre_query, query); + result = + g_strdup_printf ("%u%s%s%s", url->port, url->abspath, pre_query, query); return result; } static GstElement * -default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) +default_get_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { GstElement *element; GError *error = NULL; @@ -459,8 +469,8 @@ no_launch: parse_error: { g_mutex_unlock (factory->lock); - g_critical ("could not parse launch syntax (%s): %s", factory->launch, - (error ? error->message : "unknown reason")); + g_critical ("could not parse launch syntax (%s): %s", factory->launch, + (error ? error->message : "unknown reason")); if (error) g_error_free (error); return NULL; @@ -470,11 +480,11 @@ parse_error: /* try to find all the payloader elements, they should be named 'pay%d'. for * each of the payloaders we will create a stream and collect the source pad. */ void -gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory *factory, const GstRTSPUrl *url, - GstRTSPMedia *media) +gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url, GstRTSPMedia * media) { GstElement *element, *elem; - GstPad * pad; + GstPad *pad; gint i; GstRTSPMediaStream *stream; gboolean have_elem; @@ -482,7 +492,7 @@ gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory *factory, const GstR element = media->element; have_elem = TRUE; - for (i = 0; have_elem ; i++) { + for (i = 0; have_elem; i++) { gchar *name; have_elem = FALSE; @@ -524,7 +534,7 @@ gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory *factory, const GstR } static GstRTSPMedia * -default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url) +default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { GstRTSPMedia *media; GstElement *element; @@ -573,8 +583,8 @@ no_pipeline: } } -static GstElement* -default_create_pipeline (GstRTSPMediaFactory *factory, GstRTSPMedia *media) +static GstElement * +default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media) { GstElement *pipeline; @@ -595,7 +605,7 @@ no_element: } static void -default_configure (GstRTSPMediaFactory *factory, GstRTSPMedia *media) +default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) { gboolean shared, eos_shutdown; diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c index b0020fd62a..d65f41cbb5 100644 --- a/gst/rtsp-server/rtsp-media-mapping.c +++ b/gst/rtsp-server/rtsp-media-mapping.c @@ -26,7 +26,8 @@ GST_DEBUG_CATEGORY_EXTERN (rtsp_media_debug); static void gst_rtsp_media_mapping_finalize (GObject * obj); -static GstRTSPMediaFactory * find_media (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url); +static GstRTSPMediaFactory *find_media (GstRTSPMediaMapping * mapping, + const GstRTSPUrl * url); static void gst_rtsp_media_mapping_class_init (GstRTSPMediaMappingClass * klass) @@ -44,7 +45,7 @@ static void gst_rtsp_media_mapping_init (GstRTSPMediaMapping * mapping) { mapping->mappings = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); + g_free, g_object_unref); } static void @@ -68,7 +69,7 @@ gst_rtsp_media_mapping_new (void) } static GstRTSPMediaFactory * -find_media (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url) +find_media (GstRTSPMediaMapping * mapping, const GstRTSPUrl * url) { GstRTSPMediaFactory *result; @@ -76,7 +77,7 @@ find_media (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url) * path of the uri to find a mapping. If the mapping depends on other * properties found in the url, this method should be overridden. */ result = g_hash_table_lookup (mapping->mappings, url->abspath); - if (result) + if (result) g_object_ref (result); GST_INFO ("found media %p for url abspath %s", result, url->abspath); @@ -95,7 +96,8 @@ find_media (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url) * Returns: the #GstRTSPMediaFactory for @url. g_object_unref() after usage. */ GstRTSPMediaFactory * -gst_rtsp_media_mapping_find_factory (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url) +gst_rtsp_media_mapping_find_factory (GstRTSPMediaMapping * mapping, + const GstRTSPUrl * url) { GstRTSPMediaFactory *result; GstRTSPMediaMappingClass *klass; @@ -124,8 +126,8 @@ gst_rtsp_media_mapping_find_factory (GstRTSPMediaMapping *mapping, const GstRTSP * used after calling this function. */ void -gst_rtsp_media_mapping_add_factory (GstRTSPMediaMapping *mapping, const gchar *path, - GstRTSPMediaFactory *factory) +gst_rtsp_media_mapping_add_factory (GstRTSPMediaMapping * mapping, + const gchar * path, GstRTSPMediaFactory * factory) { g_return_if_fail (GST_IS_RTSP_MEDIA_MAPPING (mapping)); g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); @@ -142,11 +144,11 @@ gst_rtsp_media_mapping_add_factory (GstRTSPMediaMapping *mapping, const gchar *p * Remove the #GstRTSPMediaFactory associated with @path in @mapping. */ void -gst_rtsp_media_mapping_remove_factory (GstRTSPMediaMapping *mapping, const gchar *path) +gst_rtsp_media_mapping_remove_factory (GstRTSPMediaMapping * mapping, + const gchar * path) { g_return_if_fail (GST_IS_RTSP_MEDIA_MAPPING (mapping)); g_return_if_fail (path != NULL); g_hash_table_remove (mapping->mappings, path); } - diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 0d93394f46..1e02c009f9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -135,7 +135,8 @@ gst_rtsp_media_init (GstRTSPMedia * media) } /* FIXME. this should be done in multiudpsink */ -typedef struct { +typedef struct +{ gint count; gchar *dest; gint min, max; @@ -144,14 +145,15 @@ typedef struct { static gint dest_compare (RTSPDestination * a, RTSPDestination * b) { - if ((a->min == b->min) && (a->max == b->max) && (strcmp (a->dest, b->dest) == 0)) + if ((a->min == b->min) && (a->max == b->max) + && (strcmp (a->dest, b->dest) == 0)) return 0; return 1; } static RTSPDestination * -create_destination (const gchar *dest, gint min, gint max) +create_destination (const gchar * dest, gint min, gint max) { RTSPDestination *res; @@ -165,14 +167,14 @@ create_destination (const gchar *dest, gint min, gint max) } static void -free_destination (RTSPDestination *dest) +free_destination (RTSPDestination * dest) { g_free (dest->dest); g_slice_free (RTSPDestination, dest); } void -gst_rtsp_media_trans_cleanup (GstRTSPMediaTrans *trans) +gst_rtsp_media_trans_cleanup (GstRTSPMediaTrans * trans) { if (trans->transport) { gst_rtsp_transport_free (trans->transport); @@ -466,7 +468,8 @@ gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols) GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia * media) { - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_RTSP_LOWER_TRANS_UNKNOWN); + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), + GST_RTSP_LOWER_TRANS_UNKNOWN); return media->protocols; } @@ -480,7 +483,7 @@ gst_rtsp_media_get_protocols (GstRTSPMedia * media) * it is unprepared. */ void -gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown) +gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown) { g_return_if_fail (GST_IS_RTSP_MEDIA (media)); @@ -497,7 +500,7 @@ gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown) * Returns: %TRUE if the media will send EOS before unpreparing. */ gboolean -gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media) +gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media) { g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); @@ -797,12 +800,12 @@ again: if (!udpsink1) goto no_udp_protocol; - if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), "send-duplicates")) { + if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), + "send-duplicates")) { g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); stream->filter_duplicates = FALSE; - } - else { + } else { GST_WARNING ("multiudpsink version found without send-duplicates property"); stream->filter_duplicates = TRUE; } @@ -1269,7 +1272,7 @@ unlock_streams (GstRTSPMedia * media) } static void -gst_rtsp_media_set_status (GstRTSPMedia *media, GstRTSPMediaStatus status) +gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status) { g_mutex_lock (media->lock); /* never overwrite the error status */ @@ -1281,7 +1284,7 @@ gst_rtsp_media_set_status (GstRTSPMedia *media, GstRTSPMediaStatus status) } static GstRTSPMediaStatus -gst_rtsp_media_get_status (GstRTSPMedia *media) +gst_rtsp_media_get_status (GstRTSPMedia * media) { GstRTSPMediaStatus result; GTimeVal timeout; @@ -1648,7 +1651,7 @@ default_unprepare (GstRTSPMedia * media) /* ref so that we don't disappear */ g_object_ref (media); media->eos_pending = TRUE; - gst_element_send_event (media->pipeline, gst_event_new_eos()); + gst_element_send_event (media->pipeline, gst_event_new_eos ()); /* we need to go to playing again for the EOS to propagate, normally in this * state, nothing is receiving data from us anymore so this is ok. */ gst_element_set_state (media->pipeline, GST_STATE_PLAYING); @@ -1660,8 +1663,8 @@ default_unprepare (GstRTSPMedia * media) } static void -add_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, - gchar *dest, gint min, gint max) +add_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream, + gchar * dest, gint min, gint max) { gboolean do_add = TRUE; RTSPDestination *ndest; @@ -1675,11 +1678,14 @@ add_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, fdest.max = max; /* first see if we already added this destination */ - find = g_list_find_custom (stream->destinations, &fdest, (GCompareFunc) dest_compare); + find = + g_list_find_custom (stream->destinations, &fdest, + (GCompareFunc) dest_compare); if (find) { ndest = (RTSPDestination *) find->data; - GST_INFO ("already streaming to %s:%d-%d with %d clients", dest, min, max, ndest->count); + GST_INFO ("already streaming to %s:%d-%d with %d clients", dest, min, max, + ndest->count); ndest->count++; do_add = FALSE; } @@ -1698,8 +1704,8 @@ add_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, } static void -remove_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, - gchar *dest, gint min, gint max) +remove_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream, + gchar * dest, gint min, gint max) { gboolean do_remove = TRUE; RTSPDestination *ndest = NULL; @@ -1713,14 +1719,17 @@ remove_udp_destination (GstRTSPMedia *media, GstRTSPMediaStream *stream, fdest.max = max; /* first see if we already added this destination */ - find = g_list_find_custom (stream->destinations, &fdest, (GCompareFunc) dest_compare); + find = + g_list_find_custom (stream->destinations, &fdest, + (GCompareFunc) dest_compare); if (!find) return; ndest = (RTSPDestination *) find->data; if (--ndest->count > 0) { do_remove = FALSE; - GST_INFO ("still streaming to %s:%d-%d with %d clients", dest, min, max, ndest->count); + GST_INFO ("still streaming to %s:%d-%d with %d clients", dest, min, max, + ndest->count); } } diff --git a/gst/rtsp-server/rtsp-params.c b/gst/rtsp-server/rtsp-params.c index 079f714095..7f32350e72 100644 --- a/gst/rtsp-server/rtsp-params.c +++ b/gst/rtsp-server/rtsp-params.c @@ -32,7 +32,7 @@ gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri, code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD; gst_rtsp_message_init_response (response, code, - gst_rtsp_status_as_text (code), request); + gst_rtsp_status_as_text (code), request); return GST_RTSP_OK; } @@ -49,7 +49,7 @@ gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri, code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD; gst_rtsp_message_init_response (response, code, - gst_rtsp_status_as_text (code), request); + gst_rtsp_status_as_text (code), request); return GST_RTSP_OK; } diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 7f400e29f0..2db7e6f9a1 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -32,7 +32,8 @@ * Returns: TRUE on success. */ gboolean -gst_rtsp_sdp_from_media (GstSDPMessage *sdp, GstSDPInfo *info, GstRTSPMedia * media) +gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, + GstRTSPMedia * media) { guint i, n_streams; gchar *rangestr; @@ -85,7 +86,8 @@ gst_rtsp_sdp_from_media (GstSDPMessage *sdp, GstSDPInfo *info, GstRTSPMedia * me gst_sdp_media_set_proto (smedia, "RTP/AVP"); /* for the c= line */ - gst_sdp_media_add_connection (smedia, "IN", info->server_proto, info->server_ip, 16, 0); + gst_sdp_media_add_connection (smedia, "IN", info->server_proto, + info->server_ip, 16, 0); /* get clock-rate, media type and params for the rtpmap attribute */ gst_structure_get_int (s, "clock-rate", &caps_rate); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 3399a66827..b4ce7b290d 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -49,14 +49,14 @@ G_DEFINE_TYPE (GstRTSPServer, gst_rtsp_server, G_TYPE_OBJECT); GST_DEBUG_CATEGORY_STATIC (rtsp_server_debug); #define GST_CAT_DEFAULT rtsp_server_debug -static void gst_rtsp_server_get_property (GObject *object, guint propid, - GValue *value, GParamSpec *pspec); -static void gst_rtsp_server_set_property (GObject *object, guint propid, - const GValue *value, GParamSpec *pspec); -static void gst_rtsp_server_finalize (GObject *object); +static void gst_rtsp_server_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec); +static void gst_rtsp_server_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec); +static void gst_rtsp_server_finalize (GObject * object); -static GstRTSPClient * default_accept_client (GstRTSPServer *server, - GIOChannel *channel); +static GstRTSPClient *default_accept_client (GstRTSPServer * server, + GIOChannel * channel); static void gst_rtsp_server_class_init (GstRTSPServerClass * klass) @@ -76,8 +76,9 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) * listen on. */ g_object_class_install_property (gobject_class, PROP_ADDRESS, - g_param_spec_string ("address", "Address", "The address the server uses to listen on", - DEFAULT_ADDRESS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_string ("address", "Address", + "The address the server uses to listen on", DEFAULT_ADDRESS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstRTSPServer::service * @@ -85,7 +86,8 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) * a port number (as a string) the server will listen on. */ g_object_class_install_property (gobject_class, PROP_SERVICE, - g_param_spec_string ("service", "Service", "The service or port number the server uses to listen on", + g_param_spec_string ("service", "Service", + "The service or port number the server uses to listen on", DEFAULT_SERVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstRTSPServer::backlog @@ -97,9 +99,10 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) * request may be ignored so that a later reattempt at connection succeeds. */ g_object_class_install_property (gobject_class, PROP_BACKLOG, - g_param_spec_int ("backlog", "Backlog", "The maximum length to which the queue " - "of pending connections may grow", - 0, G_MAXINT, DEFAULT_BACKLOG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_int ("backlog", "Backlog", + "The maximum length to which the queue " + "of pending connections may grow", 0, G_MAXINT, DEFAULT_BACKLOG, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstRTSPServer::session-pool * @@ -110,7 +113,8 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) g_object_class_install_property (gobject_class, PROP_SESSION_POOL, g_param_spec_object ("session-pool", "Session Pool", "The session pool to use for client session", - GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_TYPE_RTSP_SESSION_POOL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstRTSPServer::media-mapping * @@ -120,7 +124,8 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING, g_param_spec_object ("media-mapping", "Media Mapping", "The media mapping to use for client session", - GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_TYPE_RTSP_MEDIA_MAPPING, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); klass->accept_client = default_accept_client; @@ -138,7 +143,7 @@ gst_rtsp_server_init (GstRTSPServer * server) } static void -gst_rtsp_server_finalize (GObject *object) +gst_rtsp_server_finalize (GObject * object) { GstRTSPServer *server = GST_RTSP_SERVER (object); @@ -174,7 +179,7 @@ gst_rtsp_server_new (void) * This function must be called before the server is bound. */ void -gst_rtsp_server_set_address (GstRTSPServer *server, const gchar *address) +gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address) { g_return_if_fail (GST_IS_RTSP_SERVER (server)); g_return_if_fail (address != NULL); @@ -192,7 +197,7 @@ gst_rtsp_server_set_address (GstRTSPServer *server, const gchar *address) * Returns: the server address. g_free() after usage. */ gchar * -gst_rtsp_server_get_address (GstRTSPServer *server) +gst_rtsp_server_get_address (GstRTSPServer * server) { g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); @@ -211,7 +216,7 @@ gst_rtsp_server_get_address (GstRTSPServer *server) * This function must be called before the server is bound. */ void -gst_rtsp_server_set_service (GstRTSPServer *server, const gchar *service) +gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service) { g_return_if_fail (GST_IS_RTSP_SERVER (server)); g_return_if_fail (service != NULL); @@ -229,7 +234,7 @@ gst_rtsp_server_set_service (GstRTSPServer *server, const gchar *service) * Returns: the service. use g_free() after usage. */ gchar * -gst_rtsp_server_get_service (GstRTSPServer *server) +gst_rtsp_server_get_service (GstRTSPServer * server) { g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); @@ -247,7 +252,7 @@ gst_rtsp_server_get_service (GstRTSPServer *server) * This function must be called before the server is bound. */ void -gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog) +gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog) { g_return_if_fail (GST_IS_RTSP_SERVER (server)); @@ -263,7 +268,7 @@ gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog) * Returns: the server backlog. */ gint -gst_rtsp_server_get_backlog (GstRTSPServer *server) +gst_rtsp_server_get_backlog (GstRTSPServer * server) { g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1); @@ -278,7 +283,8 @@ gst_rtsp_server_get_backlog (GstRTSPServer *server) * configure @pool to be used as the session pool of @server. */ void -gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool) +gst_rtsp_server_set_session_pool (GstRTSPServer * server, + GstRTSPSessionPool * pool) { GstRTSPSessionPool *old; @@ -305,7 +311,7 @@ gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *poo * usage. */ GstRTSPSessionPool * -gst_rtsp_server_get_session_pool (GstRTSPServer *server) +gst_rtsp_server_get_session_pool (GstRTSPServer * server) { GstRTSPSessionPool *result; @@ -325,7 +331,8 @@ gst_rtsp_server_get_session_pool (GstRTSPServer *server) * configure @mapping to be used as the media mapping of @server. */ void -gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *mapping) +gst_rtsp_server_set_media_mapping (GstRTSPServer * server, + GstRTSPMediaMapping * mapping) { GstRTSPMediaMapping *old; @@ -353,7 +360,7 @@ gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *m * usage. */ GstRTSPMediaMapping * -gst_rtsp_server_get_media_mapping (GstRTSPServer *server) +gst_rtsp_server_get_media_mapping (GstRTSPServer * server) { GstRTSPMediaMapping *result; @@ -366,8 +373,8 @@ gst_rtsp_server_get_media_mapping (GstRTSPServer *server) } static void -gst_rtsp_server_get_property (GObject *object, guint propid, - GValue *value, GParamSpec *pspec) +gst_rtsp_server_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec) { GstRTSPServer *server = GST_RTSP_SERVER (object); @@ -393,8 +400,8 @@ gst_rtsp_server_get_property (GObject *object, guint propid, } static void -gst_rtsp_server_set_property (GObject *object, guint propid, - const GValue *value, GParamSpec *pspec) +gst_rtsp_server_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec) { GstRTSPServer *server = GST_RTSP_SERVER (object); @@ -430,19 +437,21 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) struct linger linger; #endif - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ - hints.ai_socktype = SOCK_STREAM; /* stream socket */ - hints.ai_flags = AI_PASSIVE | AI_CANONNAME; /* For wildcard IP address */ - hints.ai_protocol = 0; /* Any protocol */ + memset (&hints, 0, sizeof (struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_STREAM; /* stream socket */ + hints.ai_flags = AI_PASSIVE | AI_CANONNAME; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; - GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address, server->service); + GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address, + server->service); /* resolve the server IP address */ - if ((ret = getaddrinfo (server->address, server->service, &hints, &result)) != 0) + if ((ret = + getaddrinfo (server->address, server->service, &hints, &result)) != 0) goto no_address; /* create server socket, we loop through all the addresses until we manage to @@ -450,7 +459,8 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) for (rp = result; rp; rp = rp->ai_next) { sockfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sockfd == -1) { - GST_DEBUG_OBJECT (server, "failed to make socket (%s), try next", g_strerror (errno)); + GST_DEBUG_OBJECT (server, "failed to make socket (%s), try next", + g_strerror (errno)); continue; } @@ -459,7 +469,8 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) break; } - GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next", g_strerror (errno)); + GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next", + g_strerror (errno)); close (sockfd); } freeaddrinfo (result); @@ -514,12 +525,14 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) /* ERRORS */ no_address: { - GST_ERROR_OBJECT (server, "failed to resolve address: %s", gai_strerror(ret)); + GST_ERROR_OBJECT (server, "failed to resolve address: %s", + gai_strerror (ret)); return FALSE; } no_socket: { - GST_ERROR_OBJECT (server, "failed to create socket: %s", g_strerror (errno)); + GST_ERROR_OBJECT (server, "failed to create socket: %s", + g_strerror (errno)); return FALSE; } reuse_failed: @@ -529,19 +542,22 @@ reuse_failed: } keepalive_failed: { - GST_ERROR_OBJECT (server, "failed to configure keepalive socket: %s", g_strerror (errno)); + GST_ERROR_OBJECT (server, "failed to configure keepalive socket: %s", + g_strerror (errno)); goto close_error; } #ifdef USE_SOLINGER linger_failed: { - GST_ERROR_OBJECT (server, "failed to no linger socket: %s", g_strerror (errno)); + GST_ERROR_OBJECT (server, "failed to no linger socket: %s", + g_strerror (errno)); goto close_error; } #endif listen_failed: { - GST_ERROR_OBJECT (server, "failed to listen on socket: %s", g_strerror (errno)); + GST_ERROR_OBJECT (server, "failed to listen on socket: %s", + g_strerror (errno)); goto close_error; } close_error: @@ -557,7 +573,7 @@ close_error: /* default method for creating a new client object in the server to accept and * handle a client connection on this server */ static GstRTSPClient * -default_accept_client (GstRTSPServer *server, GIOChannel *channel) +default_accept_client (GstRTSPServer * server, GIOChannel * channel) { GstRTSPClient *client; @@ -580,8 +596,9 @@ default_accept_client (GstRTSPServer *server, GIOChannel *channel) /* ERRORS */ accept_failed: { - GST_ERROR_OBJECT (server, "Could not accept client on server socket %d: %s (%d)", - server->server_sock.fd, g_strerror (errno), errno); + GST_ERROR_OBJECT (server, + "Could not accept client on server socket %d: %s (%d)", + server->server_sock.fd, g_strerror (errno), errno); gst_object_unref (client); return NULL; } @@ -598,7 +615,8 @@ accept_failed: * Returns: TRUE if the source could be connected, FALSE if an error occured. */ gboolean -gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, GstRTSPServer *server) +gst_rtsp_server_io_func (GIOChannel * channel, GIOCondition condition, + GstRTSPServer * server) { GstRTSPClient *client = NULL; GstRTSPServerClass *klass; @@ -615,8 +633,7 @@ gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, GstRTSPSer /* can unref the client now, when the request is finished, it will be * unreffed async. */ gst_object_unref (client); - } - else { + } else { GST_WARNING_OBJECT (server, "received unknown event %08x", condition); } return TRUE; @@ -638,7 +655,7 @@ client_failed: * Returns: the GIOChannel for @server or NULL when an error occured. */ GIOChannel * -gst_rtsp_server_get_io_channel (GstRTSPServer *server) +gst_rtsp_server_get_io_channel (GstRTSPServer * server) { g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); @@ -668,7 +685,7 @@ init_failed: * Returns: the #GSource for @server or NULL when an error occured. */ GSource * -gst_rtsp_server_create_watch (GstRTSPServer *server) +gst_rtsp_server_create_watch (GstRTSPServer * server) { g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); @@ -681,10 +698,11 @@ gst_rtsp_server_create_watch (GstRTSPServer *server) /* create a watch for reads (new connections) and possible errors */ server->io_watch = g_io_create_watch (channel, G_IO_IN | - G_IO_ERR | G_IO_HUP | G_IO_NVAL); + G_IO_ERR | G_IO_HUP | G_IO_NVAL); /* configure the callback */ - g_source_set_callback (server->io_watch, (GSourceFunc) gst_rtsp_server_io_func, server, NULL); + g_source_set_callback (server->io_watch, + (GSourceFunc) gst_rtsp_server_io_func, server, NULL); } return server->io_watch; @@ -709,7 +727,7 @@ no_channel: * Returns: the ID (greater than 0) for the source within the GMainContext. */ guint -gst_rtsp_server_attach (GstRTSPServer *server, GMainContext *context) +gst_rtsp_server_attach (GstRTSPServer * server, GMainContext * context) { guint res; GSource *source; diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 8fec319697..cbaf71e4b1 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -33,13 +33,13 @@ enum GST_DEBUG_CATEGORY (rtsp_session_debug); #define GST_CAT_DEFAULT rtsp_session_debug -static void gst_rtsp_session_pool_get_property (GObject *object, guint propid, - GValue *value, GParamSpec *pspec); -static void gst_rtsp_session_pool_set_property (GObject *object, guint propid, - const GValue *value, GParamSpec *pspec); +static void gst_rtsp_session_pool_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec); +static void gst_rtsp_session_pool_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec); static void gst_rtsp_session_pool_finalize (GObject * object); -static gchar * create_session_id (GstRTSPSessionPool *pool); +static gchar *create_session_id (GstRTSPSessionPool * pool); G_DEFINE_TYPE (GstRTSPSessionPool, gst_rtsp_session_pool, G_TYPE_OBJECT); @@ -62,7 +62,8 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) klass->create_session_id = create_session_id; - GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0, "GstRTSPSession"); + GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0, + "GstRTSPSession"); } static void @@ -70,24 +71,24 @@ gst_rtsp_session_pool_init (GstRTSPSessionPool * pool) { pool->lock = g_mutex_new (); pool->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, g_object_unref); + NULL, g_object_unref); pool->max_sessions = DEFAULT_MAX_SESSIONS; } static void gst_rtsp_session_pool_finalize (GObject * object) { - GstRTSPSessionPool * pool = GST_RTSP_SESSION_POOL (object); + GstRTSPSessionPool *pool = GST_RTSP_SESSION_POOL (object); g_mutex_free (pool->lock); g_hash_table_unref (pool->sessions); - + G_OBJECT_CLASS (gst_rtsp_session_pool_parent_class)->finalize (object); } static void -gst_rtsp_session_pool_get_property (GObject *object, guint propid, - GValue *value, GParamSpec *pspec) +gst_rtsp_session_pool_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec) { GstRTSPSessionPool *pool = GST_RTSP_SESSION_POOL (object); @@ -102,8 +103,8 @@ gst_rtsp_session_pool_get_property (GObject *object, guint propid, } static void -gst_rtsp_session_pool_set_property (GObject *object, guint propid, - const GValue *value, GParamSpec *pspec) +gst_rtsp_session_pool_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec) { GstRTSPSessionPool *pool = GST_RTSP_SESSION_POOL (object); @@ -143,7 +144,7 @@ gst_rtsp_session_pool_new (void) * A value of 0 means an unlimited amount of sessions. */ void -gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool *pool, guint max) +gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool * pool, guint max) { g_return_if_fail (GST_IS_RTSP_SESSION_POOL (pool)); @@ -162,7 +163,7 @@ gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool *pool, guint max) * Returns: the maximum allowed number of sessions. */ guint -gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool *pool) +gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool * pool) { guint result; @@ -184,7 +185,7 @@ gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool *pool) * Returns: the amount of active sessions in @pool. */ guint -gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool *pool) +gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool * pool) { guint result; @@ -209,7 +210,7 @@ gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool *pool) * not exist. g_object_unref() after usage. */ GstRTSPSession * -gst_rtsp_session_pool_find (GstRTSPSessionPool *pool, const gchar *sessionid) +gst_rtsp_session_pool_find (GstRTSPSessionPool * pool, const gchar * sessionid) { GstRTSPSession *result; @@ -228,7 +229,7 @@ gst_rtsp_session_pool_find (GstRTSPSessionPool *pool, const gchar *sessionid) } static gchar * -create_session_id (GstRTSPSessionPool *pool) +create_session_id (GstRTSPSessionPool * pool) { gchar id[16]; gint i; @@ -249,7 +250,7 @@ create_session_id (GstRTSPSessionPool *pool) * Returns: a new #GstRTSPSession. */ GstRTSPSession * -gst_rtsp_session_pool_create (GstRTSPSessionPool *pool) +gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) { GstRTSPSession *result = NULL; GstRTSPSessionPoolClass *klass; @@ -276,7 +277,7 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool *pool) /* check session limit */ if (pool->max_sessions > 0) { if (g_hash_table_size (pool->sessions) >= pool->max_sessions) - goto too_many_sessions; + goto too_many_sessions; } /* check if the sessionid existed */ result = g_hash_table_lookup (pool->sessions, id); @@ -285,11 +286,10 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool *pool) result = NULL; retry++; if (retry > 100) - goto collision; - } - else { + goto collision; + } else { /* not found, create session and insert it in the pool */ - result = gst_rtsp_session_new (id); + result = gst_rtsp_session_new (id); /* take additional ref for the pool */ g_object_ref (result); g_hash_table_insert (pool->sessions, result->sessionid, result); @@ -338,7 +338,7 @@ too_many_sessions: * Returns: %TRUE if the session was found and removed. */ gboolean -gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, GstRTSPSession *sess) +gst_rtsp_session_pool_remove (GstRTSPSessionPool * pool, GstRTSPSession * sess) { gboolean found; @@ -353,7 +353,7 @@ gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, GstRTSPSession *sess) } static gboolean -cleanup_func (gchar *sessionid, GstRTSPSession *sess, GTimeVal *now) +cleanup_func (gchar * sessionid, GstRTSPSession * sess, GTimeVal * now) { return gst_rtsp_session_is_expired (sess, now); } @@ -368,7 +368,7 @@ cleanup_func (gchar *sessionid, GstRTSPSession *sess, GTimeVal *now) * Returns: the amount of sessions that got removed. */ guint -gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool) +gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool) { guint result; GTimeVal now; @@ -378,7 +378,9 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool) g_get_current_time (&now); g_mutex_lock (pool->lock); - result = g_hash_table_foreach_remove (pool->sessions, (GHRFunc) cleanup_func, &now); + result = + g_hash_table_foreach_remove (pool->sessions, (GHRFunc) cleanup_func, + &now); g_mutex_unlock (pool->lock); return result; @@ -393,7 +395,7 @@ typedef struct } FilterData; static gboolean -filter_func (gchar *sessionid, GstRTSPSession *sess, FilterData *data) +filter_func (gchar * sessionid, GstRTSPSession * sess, FilterData * data) { switch (data->func (data->pool, sess, data->user_data)) { case GST_RTSP_FILTER_REMOVE: @@ -432,7 +434,7 @@ filter_func (gchar *sessionid, GstRTSPSession *sess, FilterData *data) * before the list is freed. */ GList * -gst_rtsp_session_pool_filter (GstRTSPSessionPool *pool, +gst_rtsp_session_pool_filter (GstRTSPSessionPool * pool, GstRTSPSessionFilterFunc func, gpointer user_data) { FilterData data; @@ -460,12 +462,12 @@ typedef struct } GstPoolSource; static void -collect_timeout (gchar *sessionid, GstRTSPSession *sess, GstPoolSource *psrc) +collect_timeout (gchar * sessionid, GstRTSPSession * sess, GstPoolSource * psrc) { gint timeout; GTimeVal now; - g_source_get_current_time ((GSource*)psrc, &now); + g_source_get_current_time ((GSource *) psrc, &now); timeout = gst_rtsp_session_next_timeout (sess, &now); GST_INFO ("%p: next timeout: %d", sess, timeout); @@ -547,7 +549,7 @@ static GSourceFuncs gst_pool_source_funcs = { * A GSource that will be dispatched when the session should be cleaned up. */ GSource * -gst_rtsp_session_pool_create_watch (GstRTSPSessionPool *pool) +gst_rtsp_session_pool_create_watch (GstRTSPSessionPool * pool) { GstPoolSource *source; @@ -559,4 +561,3 @@ gst_rtsp_session_pool_create_watch (GstRTSPSessionPool *pool) return (GSource *) source; } - diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 7e25888901..e87f096743 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -421,7 +421,7 @@ gst_rtsp_session_touch (GstRTSPSession * session) } void -gst_rtsp_session_prevent_expire (GstRTSPSession *session) +gst_rtsp_session_prevent_expire (GstRTSPSession * session) { g_return_if_fail (GST_IS_RTSP_SESSION (session)); @@ -429,7 +429,7 @@ gst_rtsp_session_prevent_expire (GstRTSPSession *session) } void -gst_rtsp_session_allow_expire (GstRTSPSession *session) +gst_rtsp_session_allow_expire (GstRTSPSession * session) { g_atomic_int_add (&session->expire_count, -1); } From 150f64892fc0bbc91fee519494a6897d3323afaf Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 11 Dec 2010 10:49:30 +0100 Subject: [PATCH 0224/1776] examples: Run gst-indent --- examples/test-launch.c | 4 ++-- examples/test-mp4.c | 8 +++----- examples/test-ogg.c | 8 +++----- examples/test-readme.c | 4 ++-- examples/test-sdp.c | 8 +++++--- examples/test-video.c | 13 ++++++------- 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/examples/test-launch.c b/examples/test-launch.c index fb863ecc3f..8226485f8a 100644 --- a/examples/test-launch.c +++ b/examples/test-launch.c @@ -33,8 +33,8 @@ main (int argc, char *argv[]) if (argc < 2) { g_print ("usage: %s \n" - "example: %s \"( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )\"\n", - argv[0], argv[0]); + "example: %s \"( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )\"\n", + argv[0], argv[0]); return -1; } diff --git a/examples/test-mp4.c b/examples/test-mp4.c index a7756e23bb..ba31ca2ab0 100644 --- a/examples/test-mp4.c +++ b/examples/test-mp4.c @@ -46,12 +46,10 @@ main (int argc, char *argv[]) * that be used to map uri mount points to media factories */ mapping = gst_rtsp_server_get_media_mapping (server); - str = g_strdup_printf ( - "( " + str = g_strdup_printf ("( " "filesrc location=%s ! qtdemux name=d " - "d. ! queue ! rtph264pay pt=96 name=pay0 " - "d. ! queue ! rtpmp4apay pt=97 name=pay1 " - ")", argv[1]); + "d. ! queue ! rtph264pay pt=96 name=pay0 " + "d. ! queue ! rtpmp4apay pt=97 name=pay1 " ")", argv[1]); /* make a media factory for a test stream. The default media factory can use * gst-launch syntax to create pipelines. diff --git a/examples/test-ogg.c b/examples/test-ogg.c index 403144f011..555bc7fc7e 100644 --- a/examples/test-ogg.c +++ b/examples/test-ogg.c @@ -46,12 +46,10 @@ main (int argc, char *argv[]) * that be used to map uri mount points to media factories */ mapping = gst_rtsp_server_get_media_mapping (server); - str = g_strdup_printf ( - "( " + str = g_strdup_printf ("( " "filesrc location=%s ! oggdemux name=d " - "d. ! queue ! rtptheorapay name=pay0 pt=96 " - "d. ! queue ! rtpvorbispay name=pay1 pt=97 " - ")", argv[1]); + "d. ! queue ! rtptheorapay name=pay0 pt=96 " + "d. ! queue ! rtpvorbispay name=pay1 pt=97 " ")", argv[1]); /* make a media factory for a test stream. The default media factory can use * gst-launch syntax to create pipelines. diff --git a/examples/test-readme.c b/examples/test-readme.c index 977fcb080e..5464e04171 100644 --- a/examples/test-readme.c +++ b/examples/test-readme.c @@ -45,8 +45,8 @@ main (int argc, char *argv[]) * any launch line works as long as it contains elements named pay%d. Each * element with pay%d names will be a stream */ factory = gst_rtsp_media_factory_new (); - gst_rtsp_media_factory_set_launch (factory, - "( videotestsrc is-live=1 ! x264enc ! rtph264pay name=pay0 pt=96 )"); + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc is-live=1 ! x264enc ! rtph264pay name=pay0 pt=96 )"); gst_rtsp_media_factory_set_shared (factory, TRUE); diff --git a/examples/test-sdp.c b/examples/test-sdp.c index 64113c5fbe..416e9ac94c 100644 --- a/examples/test-sdp.c +++ b/examples/test-sdp.c @@ -23,7 +23,7 @@ static gboolean -timeout (GstRTSPServer *server, gboolean ignored) +timeout (GstRTSPServer * server, gboolean ignored) { GstRTSPSessionPool *pool; @@ -65,7 +65,9 @@ main (int argc, char *argv[]) * element with pay%d names will be a stream */ factory = gst_rtsp_media_factory_new (); - str = g_strdup_printf ( "( filesrc location=%s ! sdpdemux name=dynpay0 )", argv[1]); + str = + g_strdup_printf ("( filesrc location=%s ! sdpdemux name=dynpay0 )", + argv[1]); gst_rtsp_media_factory_set_launch (factory, str); gst_rtsp_media_factory_set_shared (factory, TRUE); g_free (str); @@ -79,7 +81,7 @@ main (int argc, char *argv[]) /* attach the server to the default maincontext */ gst_rtsp_server_attach (server, NULL); - g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); /* start serving */ g_main_loop_run (loop); diff --git a/examples/test-video.c b/examples/test-video.c index 0da6f1420f..c4eed533a1 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -23,7 +23,7 @@ static gboolean -timeout (GstRTSPServer *server, gboolean ignored) +timeout (GstRTSPServer * server, gboolean ignored) { GstRTSPSessionPool *pool; @@ -59,11 +59,10 @@ main (int argc, char *argv[]) * element with pay%d names will be a stream */ factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, "( " - "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " - "x264enc ! rtph264pay name=pay0 pt=96 " - "audiotestsrc ! audio/x-raw-int,rate=8000 ! " - "alawenc ! rtppcmapay name=pay1 pt=97 " - ")"); + "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " + "x264enc ! rtph264pay name=pay0 pt=96 " + "audiotestsrc ! audio/x-raw-int,rate=8000 ! " + "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); /* attach the test factory to the /test url */ gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); @@ -75,7 +74,7 @@ main (int argc, char *argv[]) if (gst_rtsp_server_attach (server, NULL) == 0) goto failed; - g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); /* start serving */ g_main_loop_run (loop); From a6556551e31671df9a1b872b7640b1962c5cdcb0 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 11 Dec 2010 10:53:28 +0100 Subject: [PATCH 0225/1776] rtsp-server: Remove unused variable and dead assignment --- gst/rtsp-server/rtsp-client.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8207fcca4a..16646b74d0 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -763,7 +763,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, gchar *trans_str, *pos; guint streamid; GstRTSPSessionMedia *media; - gboolean need_session; GstRTSPUrl *url; /* the uri contains the stream number we added in the SDP config, which is @@ -851,8 +850,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, /* get a handle to the configuration of the media in the session, this can * return NULL if this is a new url to manage in this session. */ media = gst_rtsp_session_get_media (session, uri); - - need_session = FALSE; } else { /* create a session if this fails we probably reached our session limit or * something. */ @@ -861,8 +858,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, /* we need a new media configuration in this session */ media = NULL; - - need_session = TRUE; } /* we have no media, find one and manage it */ @@ -1220,7 +1215,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) } /* we always try to parse the url first */ - if ((res = gst_rtsp_url_parse (uristr, &uri)) != GST_RTSP_OK) { + if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) { send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); return; } From 75a7cda97dfae07a7651da50f3d7b8cf20a4a3e2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 11 Dec 2010 13:41:24 +0100 Subject: [PATCH 0226/1776] media-factory: make lock macro --- gst/rtsp-server/rtsp-media-factory.c | 36 ++++++++++++++-------------- gst/rtsp-server/rtsp-media-factory.h | 4 ++++ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index f8dfe3359c..d5c63bc9c7 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -215,10 +215,10 @@ gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory, g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); g_return_if_fail (launch != NULL); - g_mutex_lock (factory->lock); + GST_RTSP_MEDIA_FACTORY_LOCK (factory); g_free (factory->launch); factory->launch = g_strdup (launch); - g_mutex_unlock (factory->lock); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); } /** @@ -237,9 +237,9 @@ gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory) g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); - g_mutex_lock (factory->lock); + GST_RTSP_MEDIA_FACTORY_LOCK (factory); result = g_strdup (factory->launch); - g_mutex_unlock (factory->lock); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); return result; } @@ -257,9 +257,9 @@ gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory, { g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); - g_mutex_lock (factory->lock); + GST_RTSP_MEDIA_FACTORY_LOCK (factory); factory->shared = shared; - g_mutex_unlock (factory->lock); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); } /** @@ -277,9 +277,9 @@ gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * factory) g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); - g_mutex_lock (factory->lock); + GST_RTSP_MEDIA_FACTORY_LOCK (factory); result = factory->shared; - g_mutex_unlock (factory->lock); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); return result; } @@ -298,9 +298,9 @@ gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory, { g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); - g_mutex_lock (factory->lock); + GST_RTSP_MEDIA_FACTORY_LOCK (factory); factory->eos_shutdown = eos_shutdown; - g_mutex_unlock (factory->lock); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); } /** @@ -319,9 +319,9 @@ gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory) g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); - g_mutex_lock (factory->lock); + GST_RTSP_MEDIA_FACTORY_LOCK (factory); result = factory->eos_shutdown; - g_mutex_unlock (factory->lock); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); return result; } @@ -440,7 +440,7 @@ default_get_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) GstElement *element; GError *error = NULL; - g_mutex_lock (factory->lock); + GST_RTSP_MEDIA_FACTORY_LOCK (factory); /* we need a parse syntax */ if (factory->launch == NULL) goto no_launch; @@ -450,7 +450,7 @@ default_get_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) if (element == NULL) goto parse_error; - g_mutex_unlock (factory->lock); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); if (error != NULL) { /* a recoverable error was encountered */ @@ -462,13 +462,13 @@ default_get_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) /* ERRORS */ no_launch: { - g_mutex_unlock (factory->lock); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); g_critical ("no launch line specified"); return NULL; } parse_error: { - g_mutex_unlock (factory->lock); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); g_critical ("could not parse launch syntax (%s): %s", factory->launch, (error ? error->message : "unknown reason")); if (error) @@ -610,10 +610,10 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gboolean shared, eos_shutdown; /* configure the sharedness */ - g_mutex_lock (factory->lock); + GST_RTSP_MEDIA_FACTORY_LOCK (factory); shared = factory->shared; eos_shutdown = factory->eos_shutdown; - g_mutex_unlock (factory->lock); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_shared (media, shared); gst_rtsp_media_set_eos_shutdown (media, eos_shutdown); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index d462914755..4d6487626e 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -40,6 +40,10 @@ G_BEGIN_DECLS typedef struct _GstRTSPMediaFactory GstRTSPMediaFactory; typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; +#define GST_RTSP_MEDIA_FACTORY_GET_LOCK(f) (GST_RTSP_MEDIA_FACTORY_CAST(f)->lock) +#define GST_RTSP_MEDIA_FACTORY_LOCK(f) (g_mutex_lock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f))) +#define GST_RTSP_MEDIA_FACTORY_UNLOCK(f) (g_mutex_unlock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f))) + /** * GstRTSPMediaFactory: * @lock: mutex protecting the datastructure. From 34f0973831d4c7908130840368bbf39db526855f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 11 Dec 2010 17:31:44 +0100 Subject: [PATCH 0227/1776] media: ignore spurious ASYNC_DONE messages When we are dynamically adding pads, the addition of the udpsrc elements will trigger an ASYNC_DONE. We have to ignore this because we only want to react to the real ASYNC_DONE when everything is prerolled. --- gst/rtsp-server/rtsp-media.c | 18 +++++++++++++++--- gst/rtsp-server/rtsp-media.h | 1 + 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1e02c009f9..9649472d70 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1387,10 +1387,17 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) case GST_MESSAGE_STREAM_STATUS: break; case GST_MESSAGE_ASYNC_DONE: - GST_INFO ("%p: got ASYNC_DONE", media); - collect_media_stats (media); + if (!media->adding) { + /* when we are dynamically adding pads, the addition of the udpsrc will + * temporarily produce ASYNC_DONE messages. We have to ignore them and + * wait for the final ASYNC_DONE after everything prerolled */ + GST_INFO ("%p: got ASYNC_DONE", media); + collect_media_stats (media); - gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); + } else { + GST_INFO ("%p: ignoring ASYNC_DONE", media); + } break; case GST_MESSAGE_EOS: GST_INFO ("%p: got EOS", media); @@ -1442,6 +1449,8 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) name = g_strdup_printf ("dynpay%d", i); + media->adding = TRUE; + /* ghost the pad of the payloader to the element */ stream->srcpad = gst_ghost_pad_new (name, pad); gst_pad_set_active (stream->srcpad, TRUE); @@ -1460,6 +1469,7 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) gst_element_set_state (stream->selector[i], GST_STATE_PAUSED); gst_element_set_state (stream->appsrc[i], GST_STATE_PAUSED); } + media->adding = FALSE; } static void @@ -1542,6 +1552,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) for (walk = media->dynamic; walk; walk = g_list_next (walk)) { GstElement *elem = walk->data; + GST_INFO ("adding callbacks for dynamic element %p", elem); + g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media); g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 06c299dab2..45fa22e719 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -207,6 +207,7 @@ struct _GstRTSPMedia { GstRTSPMediaStatus status; gint active; gboolean eos_pending; + gboolean adding; /* the pipeline for the media */ GstElement *pipeline; From 7ef0bf98da98af6077734443c519455365075bb4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 11 Dec 2010 18:01:53 +0100 Subject: [PATCH 0228/1776] factory-uri: add a factory to stream any URI Make a factory that uses uridecodebin to decode any uri and autoplug a payloader when we have one. --- gst/rtsp-server/Makefile.am | 2 + gst/rtsp-server/rtsp-media-factory-uri.c | 373 +++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory-uri.h | 76 +++++ gst/rtsp-server/rtsp-server.h | 1 + 4 files changed, 452 insertions(+) create mode 100644 gst/rtsp-server/rtsp-media-factory-uri.c create mode 100644 gst/rtsp-server/rtsp-media-factory-uri.h diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 1c61825231..8be1f593b5 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -3,6 +3,7 @@ public_headers = \ rtsp-sdp.h \ rtsp-media.h \ rtsp-media-factory.h \ + rtsp-media-factory-uri.h \ rtsp-media-mapping.h \ rtsp-session.h \ rtsp-session-pool.h \ @@ -14,6 +15,7 @@ c_sources = \ rtsp-sdp.c \ rtsp-media.c \ rtsp-media-factory.c \ + rtsp-media-factory-uri.c \ rtsp-media-mapping.c \ rtsp-session.c \ rtsp-session-pool.c \ diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c new file mode 100644 index 0000000000..d8eb8e6d27 --- /dev/null +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -0,0 +1,373 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "rtsp-media-factory-uri.h" + +#define DEFAULT_URI NULL + +enum +{ + PROP_0, + PROP_URI, + PROP_LAST +}; + +static const gchar *factory_key = "GstRTSPMediaFactoryURI"; + +GST_DEBUG_CATEGORY (rtsp_media_factory_uri_debug); +#define GST_CAT_DEFAULT rtsp_media_factory_uri_debug + +static void gst_rtsp_media_factory_uri_get_property (GObject * object, + guint propid, GValue * value, GParamSpec * pspec); +static void gst_rtsp_media_factory_uri_set_property (GObject * object, + guint propid, const GValue * value, GParamSpec * pspec); +static void gst_rtsp_media_factory_uri_finalize (GObject * obj); + +static GstElement *rtsp_media_factory_uri_get_element (GstRTSPMediaFactory * + factory, const GstRTSPUrl * url); + +G_DEFINE_TYPE (GstRTSPMediaFactoryURI, gst_rtsp_media_factory_uri, + GST_TYPE_RTSP_MEDIA_FACTORY); + +static void +gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass) +{ + GObjectClass *gobject_class; + GstRTSPMediaFactoryClass *mediafactory_class; + + gobject_class = G_OBJECT_CLASS (klass); + mediafactory_class = GST_RTSP_MEDIA_FACTORY_CLASS (klass); + + gobject_class->get_property = gst_rtsp_media_factory_uri_get_property; + gobject_class->set_property = gst_rtsp_media_factory_uri_set_property; + gobject_class->finalize = gst_rtsp_media_factory_uri_finalize; + + /** + * GstRTSPMediaFactoryURI::uri + * + * The uri of the resource that will be served by this factory. + */ + g_object_class_install_property (gobject_class, PROP_URI, + g_param_spec_string ("uri", "URI", + "The URI of the resource to stream", DEFAULT_URI, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + mediafactory_class->get_element = rtsp_media_factory_uri_get_element; + + GST_DEBUG_CATEGORY_INIT (rtsp_media_factory_uri_debug, "rtspmediafactoryuri", + 0, "GstRTSPMediaFactoryUri"); +} + +static void +gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory) +{ + factory->uri = g_strdup (DEFAULT_URI); + factory->factories = + gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PAYLOADER, + GST_RANK_NONE); +} + +static void +gst_rtsp_media_factory_uri_finalize (GObject * obj) +{ + GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (obj); + + g_free (factory->uri); + gst_plugin_feature_list_free (factory->factories); + + G_OBJECT_CLASS (gst_rtsp_media_factory_uri_parent_class)->finalize (obj); +} + +static void +gst_rtsp_media_factory_uri_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec) +{ + GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (object); + + switch (propid) { + case PROP_URI: + g_value_take_string (value, gst_rtsp_media_factory_uri_get_uri (factory)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static void +gst_rtsp_media_factory_uri_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec) +{ + GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (object); + + switch (propid) { + case PROP_URI: + gst_rtsp_media_factory_uri_set_uri (factory, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +/** + * gst_rtsp_media_factory_uri_new: + * + * Create a new #GstRTSPMediaFactoryURI instance. + * + * Returns: a new #GstRTSPMediaFactoryURI object. + */ +GstRTSPMediaFactoryURI * +gst_rtsp_media_factory_uri_new (void) +{ + GstRTSPMediaFactoryURI *result; + + result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY_URI, NULL); + + return result; +} + +/** + * gst_rtsp_media_factory_uri_set_uri: + * @factory: a #GstRTSPMediaFactory + * @uri: the uri the stream + * + * Set the URI of the resource that will be streamed by this factory. + */ +void +gst_rtsp_media_factory_uri_set_uri (GstRTSPMediaFactoryURI * factory, + const gchar * uri) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY_URI (factory)); + g_return_if_fail (uri != NULL); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + g_free (factory->uri); + factory->uri = g_strdup (uri); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_uri_get_uri: + * @factory: a #GstRTSPMediaFactory + * + * Get the URI that will provide media for this factory. + * + * Returns: the configured URI. g_free() after usage. + */ +gchar * +gst_rtsp_media_factory_uri_get_uri (GstRTSPMediaFactoryURI * factory) +{ + gchar *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY_URI (factory), NULL); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + result = g_strdup (factory->uri); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} + +static GstElementFactory * +find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps) +{ + GList *list, *tmp; + GstElementFactory *factory = NULL; + + /* find payloader that can link */ + list = gst_element_factory_list_filter (urifact->factories, caps, + GST_PAD_SINK, FALSE); + + for (tmp = list; tmp; tmp = g_list_next (tmp)) { + GstElementFactory *f = GST_ELEMENT_FACTORY_CAST (tmp->data); + const gchar *name; + + name = gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (f)); + if (strcmp (name, "gdppay") == 0) + continue; + + factory = f; + break; + } + if (factory) + g_object_ref (factory); + + gst_plugin_feature_list_free (list); + + return factory; +} + +static gboolean +autoplug_continue_cb (GstElement * uribin, GstPad * pad, GstCaps * caps, + GstElement * element) +{ + GList *list, *tmp; + GstRTSPMediaFactoryURI *urifact; + GstElementFactory *factory; + gboolean res; + + GST_DEBUG ("found pad %s:%s of caps %" GST_PTR_FORMAT, + GST_DEBUG_PAD_NAME (pad), caps); + + urifact = g_object_get_data (G_OBJECT (element), factory_key); + + if (!(factory = find_payloader (urifact, caps))) + goto no_factory; + + /* we found a payloader, stop autoplugging */ + GST_DEBUG ("found payloader factory %s", + gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory))); + gst_object_unref (factory); + + return FALSE; + + /* ERRORS */ +no_factory: + { + /* no payloader, continue autoplugging */ + GST_DEBUG ("no payloader found"); + return TRUE; + } +} + +static void +pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) +{ + GstRTSPMediaFactoryURI *urifact; + GstElementFactory *factory; + GstElement *payloader; + GstCaps *caps; + GstPad *sinkpad, *srcpad, *ghostpad; + + GST_DEBUG ("added pad %s:%s", GST_DEBUG_PAD_NAME (pad)); + + /* link the element now and expose the pad */ + urifact = g_object_get_data (G_OBJECT (element), factory_key); + + caps = gst_pad_get_caps (pad); + if (caps == NULL) + goto no_caps; + + if (!(factory = find_payloader (urifact, caps))) + goto no_factory; + + gst_caps_unref (caps); + + /* we have a payloader now */ + GST_DEBUG ("found payloader factory %s", + gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory))); + + payloader = gst_element_factory_create (factory, NULL); + if (payloader == NULL) + goto no_payloader; + + /* add the payloader to the pipeline */ + gst_bin_add (GST_BIN_CAST (element), payloader); + + gst_element_set_state (payloader, GST_STATE_PLAYING); + + /* link the pad to the sinkpad of the payloader */ + sinkpad = gst_element_get_static_pad (payloader, "sink"); + gst_pad_link (pad, sinkpad); + gst_object_unref (sinkpad); + + /* now expose the srcpad of the payloader as a ghostpad with the same name + * as the uridecodebin pad name. */ + srcpad = gst_element_get_static_pad (payloader, "src"); + ghostpad = gst_ghost_pad_new (GST_PAD_NAME (pad), srcpad); + gst_object_unref (srcpad); + + gst_pad_set_active (ghostpad, TRUE); + gst_element_add_pad (element, ghostpad); + + return; + + /* ERRORS */ +no_caps: + { + GST_WARNING ("could not get caps from pad"); + return; + } +no_factory: + { + GST_DEBUG ("no payloader found"); + gst_caps_unref (caps); + return; + } +no_payloader: + { + GST_ERROR ("could not create payloader from factory"); + gst_caps_unref (caps); + return; + } +} + +static void +no_more_pads_cb (GstElement * uribin, GstElement * element) +{ + GST_DEBUG ("no-more-pads"); + gst_element_no_more_pads (element); +} + +static GstElement * +rtsp_media_factory_uri_get_element (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url) +{ + GstElement *topbin, *element, *uribin; + GstRTSPMediaFactoryURI *urifact; + + urifact = GST_RTSP_MEDIA_FACTORY_URI_CAST (factory); + + GST_LOG ("creating element"); + + topbin = gst_bin_new ("GstRTSPMediaFactoryURI"); + g_assert (topbin != NULL); + + /* our bin will dynamically expose payloaded pads */ + element = gst_bin_new ("dynpay0"); + g_assert (element != NULL); + + uribin = gst_element_factory_make ("uridecodebin", "uribin"); + if (uribin == NULL) + goto no_uridecodebin; + + g_object_set (uribin, "uri", urifact->uri, NULL); + + /* keep factory around */ + g_object_set_data_full (G_OBJECT (element), factory_key, + g_object_ref (factory), g_object_unref); + + /* connect to the signals */ + g_signal_connect (uribin, "autoplug-continue", + (GCallback) autoplug_continue_cb, element); + g_signal_connect (uribin, "pad-added", (GCallback) pad_added_cb, element); + g_signal_connect (uribin, "no-more-pads", (GCallback) no_more_pads_cb, + element); + + gst_bin_add (GST_BIN_CAST (element), uribin); + gst_bin_add (GST_BIN_CAST (topbin), element); + + return topbin; + +no_uridecodebin: + { + g_critical ("can't create uridecodebin element"); + g_object_unref (element); + return NULL; + } +} diff --git a/gst/rtsp-server/rtsp-media-factory-uri.h b/gst/rtsp-server/rtsp-media-factory-uri.h new file mode 100644 index 0000000000..57427238d2 --- /dev/null +++ b/gst/rtsp-server/rtsp-media-factory-uri.h @@ -0,0 +1,76 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "rtsp-media-factory.h" + +#ifndef __GST_RTSP_MEDIA_FACTORY_URI_H__ +#define __GST_RTSP_MEDIA_FACTORY_URI_H__ + +G_BEGIN_DECLS + +/* types for the media factory */ +#define GST_TYPE_RTSP_MEDIA_FACTORY_URI (gst_rtsp_media_factory_uri_get_type ()) +#define GST_IS_RTSP_MEDIA_FACTORY_URI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY_URI)) +#define GST_IS_RTSP_MEDIA_FACTORY_URI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA_FACTORY_URI)) +#define GST_RTSP_MEDIA_FACTORY_URI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA_FACTORY_URI, GstRTSPMediaFactoryURIClass)) +#define GST_RTSP_MEDIA_FACTORY_URI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA_FACTORY_URI, GstRTSPMediaFactoryURI)) +#define GST_RTSP_MEDIA_FACTORY_URI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA_FACTORY_URI, GstRTSPMediaFactoryURIClass)) +#define GST_RTSP_MEDIA_FACTORY_URI_CAST(obj) ((GstRTSPMediaFactoryURI*)(obj)) +#define GST_RTSP_MEDIA_FACTORY_URI_CLASS_CAST(klass) ((GstRTSPMediaFactoryURIClass*)(klass)) + +typedef struct _GstRTSPMediaFactoryURI GstRTSPMediaFactoryURI; +typedef struct _GstRTSPMediaFactoryURIClass GstRTSPMediaFactoryURIClass; + +/** + * GstRTSPMediaFactoryURI: + * @uri: the uri + * + * A media factory that creates a pipeline to play and uri. + */ +struct _GstRTSPMediaFactoryURI { + GstRTSPMediaFactory parent; + + gchar *uri; + GList *factories; +}; + +/** + * GstRTSPMediaFactoryURIClass: + * + * The #GstRTSPMediaFactoryURI class structure. + */ +struct _GstRTSPMediaFactoryURIClass { + GstRTSPMediaFactoryClass parent_class; +}; + +GType gst_rtsp_media_factory_uri_get_type (void); + +/* creating the factory */ +GstRTSPMediaFactoryURI * gst_rtsp_media_factory_uri_new (void); + +/* configuring the factory */ +void gst_rtsp_media_factory_uri_set_uri (GstRTSPMediaFactoryURI *factory, + const gchar *uri); +gchar * gst_rtsp_media_factory_uri_get_uri (GstRTSPMediaFactoryURI *factory); + +G_END_DECLS + +#endif /* __GST_RTSP_MEDIA_FACTORY_URI_H__ */ diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 5bbb4f2d61..296e19a1f6 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -35,6 +35,7 @@ #include "rtsp-session-pool.h" #include "rtsp-media-mapping.h" +#include "rtsp-media-factory-uri.h" #include "rtsp-client.h" #ifndef __GST_RTSP_SERVER_H__ From 8585dda467f3cfbc5961ca2c1664e702e68a889e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 11 Dec 2010 18:06:26 +0100 Subject: [PATCH 0229/1776] example: add example of the uri factory --- examples/Makefile.am | 2 +- examples/test-uri.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 examples/test-uri.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 5af7696a63..1886511a77 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,4 +1,4 @@ -noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp +noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp test-uri INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/examples/test-uri.c b/examples/test-uri.c new file mode 100644 index 0000000000..bde0355435 --- /dev/null +++ b/examples/test-uri.c @@ -0,0 +1,89 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + + +static gboolean +timeout (GstRTSPServer * server, gboolean ignored) +{ + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_cleanup (pool); + g_object_unref (pool); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMediaMapping *mapping; + GstRTSPMediaFactoryURI *factory; + + gst_init (&argc, &argv); + + if (argc < 2) { + g_message ("usage: %s ", argv[0]); + return -1; + } + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mapping for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mapping = gst_rtsp_server_get_media_mapping (server); + + /* make a URI media factory for a test stream. */ + factory = gst_rtsp_media_factory_uri_new (); + gst_rtsp_media_factory_uri_set_uri (factory, argv[1]); + + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test", + GST_RTSP_MEDIA_FACTORY (factory)); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mapping); + + /* attach the server to the default maincontext */ + if (gst_rtsp_server_attach (server, NULL) == 0) + goto failed; + + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + + /* start serving */ + g_main_loop_run (loop); + + return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } +} From d99a448f79f0189beafd04c9ca3935af309f2a1e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 12 Dec 2010 04:06:41 +0100 Subject: [PATCH 0230/1776] factory-uri: add colorspace and fix pt Rework the way we pass data to the autoplugger. When we have raw caps, plug a converter element to make pluggin to raw payloaders more successful. Make sure all dynamically plugged payloaders have a unique payload types. --- gst/rtsp-server/rtsp-media-factory-uri.c | 105 ++++++++++++++++++++--- gst/rtsp-server/rtsp-media-factory-uri.h | 2 + 2 files changed, 97 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index d8eb8e6d27..d10ecd0868 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -28,6 +28,32 @@ enum PROP_LAST }; + +#define RAW_VIDEO_CAPS \ + "video/x-raw-yuv; " \ + "video/x-raw-rgb; " \ + "video/x-raw-gray" + +#define RAW_AUDIO_CAPS \ + "audio/x-raw-int; " \ + "audio/x-raw-float" + +static GstStaticCaps raw_video_caps = GST_STATIC_CAPS (RAW_VIDEO_CAPS); +static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS (RAW_AUDIO_CAPS); + +typedef struct +{ + GstRTSPMediaFactoryURI *factory; + guint pt; +} FactoryData; + +static void +free_data (FactoryData * data) +{ + g_object_unref (data->factory); + g_free (data); +} + static const gchar *factory_key = "GstRTSPMediaFactoryURI"; GST_DEBUG_CATEGORY (rtsp_media_factory_uri_debug); @@ -81,6 +107,8 @@ gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory) factory->factories = gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PAYLOADER, GST_RANK_NONE); + factory->raw_vcaps = gst_static_caps_get (&raw_video_caps); + factory->raw_acaps = gst_static_caps_get (&raw_audio_caps); } static void @@ -90,6 +118,8 @@ gst_rtsp_media_factory_uri_finalize (GObject * obj) g_free (factory->uri); gst_plugin_feature_list_free (factory->factories); + gst_caps_unref (factory->raw_vcaps); + gst_caps_unref (factory->raw_acaps); G_OBJECT_CLASS (gst_rtsp_media_factory_uri_parent_class)->finalize (obj); } @@ -217,16 +247,16 @@ autoplug_continue_cb (GstElement * uribin, GstPad * pad, GstCaps * caps, GstElement * element) { GList *list, *tmp; - GstRTSPMediaFactoryURI *urifact; + FactoryData *data; GstElementFactory *factory; gboolean res; GST_DEBUG ("found pad %s:%s of caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME (pad), caps); - urifact = g_object_get_data (G_OBJECT (element), factory_key); + data = g_object_get_data (G_OBJECT (element), factory_key); - if (!(factory = find_payloader (urifact, caps))) + if (!(factory = find_payloader (data->factory, caps))) goto no_factory; /* we found a payloader, stop autoplugging */ @@ -249,20 +279,60 @@ static void pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) { GstRTSPMediaFactoryURI *urifact; + FactoryData *data; GstElementFactory *factory; GstElement *payloader; GstCaps *caps; GstPad *sinkpad, *srcpad, *ghostpad; + GstElement *convert; + gchar *padname; GST_DEBUG ("added pad %s:%s", GST_DEBUG_PAD_NAME (pad)); /* link the element now and expose the pad */ - urifact = g_object_get_data (G_OBJECT (element), factory_key); + data = g_object_get_data (G_OBJECT (element), factory_key); + urifact = data->factory; - caps = gst_pad_get_caps (pad); - if (caps == NULL) + /* ref to make refcounting easier later */ + gst_object_ref (pad); + padname = gst_pad_get_name (pad); + + /* get pad caps first, then call get_caps, then fail */ + if ((caps = GST_PAD_CAPS (pad))) + gst_caps_ref (caps); + else if ((caps = gst_pad_get_caps (pad)) == NULL) goto no_caps; + /* check for raw caps */ + if (gst_caps_can_intersect (caps, urifact->raw_vcaps)) { + /* we have raw video caps, insert converter */ + convert = gst_element_factory_make ("ffmpegcolorspace", NULL); + } else if (gst_caps_can_intersect (caps, urifact->raw_acaps)) { + /* we have raw audio caps, insert converter */ + convert = gst_element_factory_make ("audioconvert", NULL); + } else { + convert = NULL; + } + + if (convert) { + gst_bin_add (GST_BIN_CAST (element), convert); + gst_element_set_state (convert, GST_STATE_PLAYING); + + sinkpad = gst_element_get_static_pad (convert, "sink"); + gst_pad_link (pad, sinkpad); + gst_object_unref (sinkpad); + + /* unref old pad, we reffed before */ + gst_object_unref (pad); + + /* continue with new pad and caps */ + pad = gst_element_get_static_pad (convert, "src"); + if ((caps = GST_PAD_CAPS (pad))) + gst_caps_ref (caps); + else if ((caps = gst_pad_get_caps (pad)) == NULL) + goto no_caps; + } + if (!(factory = find_payloader (urifact, caps))) goto no_factory; @@ -276,21 +346,25 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) if (payloader == NULL) goto no_payloader; + g_object_set (payloader, "pt", data->pt, NULL); + data->pt++; + /* add the payloader to the pipeline */ gst_bin_add (GST_BIN_CAST (element), payloader); - gst_element_set_state (payloader, GST_STATE_PLAYING); /* link the pad to the sinkpad of the payloader */ sinkpad = gst_element_get_static_pad (payloader, "sink"); gst_pad_link (pad, sinkpad); gst_object_unref (sinkpad); + gst_object_unref (pad); /* now expose the srcpad of the payloader as a ghostpad with the same name * as the uridecodebin pad name. */ srcpad = gst_element_get_static_pad (payloader, "src"); - ghostpad = gst_ghost_pad_new (GST_PAD_NAME (pad), srcpad); + ghostpad = gst_ghost_pad_new (padname, srcpad); gst_object_unref (srcpad); + g_free (padname); gst_pad_set_active (ghostpad, TRUE); gst_element_add_pad (element, ghostpad); @@ -301,18 +375,24 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) no_caps: { GST_WARNING ("could not get caps from pad"); + g_free (padname); + gst_object_unref (pad); return; } no_factory: { GST_DEBUG ("no payloader found"); + g_free (padname); gst_caps_unref (caps); + gst_object_unref (pad); return; } no_payloader: { GST_ERROR ("could not create payloader from factory"); + g_free (padname); gst_caps_unref (caps); + gst_object_unref (pad); return; } } @@ -330,6 +410,7 @@ rtsp_media_factory_uri_get_element (GstRTSPMediaFactory * factory, { GstElement *topbin, *element, *uribin; GstRTSPMediaFactoryURI *urifact; + FactoryData *data; urifact = GST_RTSP_MEDIA_FACTORY_URI_CAST (factory); @@ -348,9 +429,13 @@ rtsp_media_factory_uri_get_element (GstRTSPMediaFactory * factory, g_object_set (uribin, "uri", urifact->uri, NULL); - /* keep factory around */ + /* keep factory data around */ + data = g_new0 (FactoryData, 1); + data->factory = g_object_ref (factory); + data->pt = 96; + g_object_set_data_full (G_OBJECT (element), factory_key, - g_object_ref (factory), g_object_unref); + data, (GDestroyNotify) free_data); /* connect to the signals */ g_signal_connect (uribin, "autoplug-continue", diff --git a/gst/rtsp-server/rtsp-media-factory-uri.h b/gst/rtsp-server/rtsp-media-factory-uri.h index 57427238d2..f27c718192 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.h +++ b/gst/rtsp-server/rtsp-media-factory-uri.h @@ -49,6 +49,8 @@ struct _GstRTSPMediaFactoryURI { GstRTSPMediaFactory parent; gchar *uri; + GstCaps *raw_vcaps; + GstCaps *raw_acaps; GList *factories; }; From ca76a73ca0a25c87bca4ee339150ea4bf414d7aa Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 12 Dec 2010 15:48:47 +0100 Subject: [PATCH 0231/1776] media: update range when active clients changed When we changed the number of active clients, update the current range information because we want the second client connecting to a shared resource continue from where the stream currently. --- gst/rtsp-server/rtsp-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 9649472d70..6f03057cf7 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -341,7 +341,7 @@ collect_media_stats (GstRTSPMedia * media) GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); - if (position == -1) { + if (position == -1 || media->active > 0) { media->range.min.type = GST_RTSP_TIME_NOW; media->range.min.seconds = -1; } else { @@ -1893,7 +1893,7 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, } /* remember where we are */ - if (state == GST_STATE_PAUSED) + if (state == GST_STATE_PAUSED || old_active != media->active) collect_media_stats (media); return TRUE; From a7d6578a80bd748e743b14f7c9a30ec4161cbf3f Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Mon, 13 Dec 2010 16:38:09 +0100 Subject: [PATCH 0232/1776] python an optional dependency * configure.ac: Move up valgrind and g-i checks. Make the python dependency optional, as it was before. --- configure.ac | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/configure.ac b/configure.ac index 3c225d027b..f83f35d820 100644 --- a/configure.ac +++ b/configure.ac @@ -77,6 +77,16 @@ dnl find a compiler AC_PROG_CC AM_PROG_CC_C_O +AC_PATH_PROG(VALGRIND_PATH, valgrind, no) +AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") + +dnl check for gobject-introspection +GOBJECT_INTROSPECTION_CHECK([0.6.3]) + +dnl check for documentation tools +AG_GST_DOCBOOK_CHECK +GTK_DOC_CHECK([1.3]) + dnl check for python AM_PATH_PYTHON AC_MSG_CHECKING(for python >= 2.3) @@ -89,49 +99,33 @@ sys.exit(0)" if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC then + HAVE_PYTHON=yes AC_MSG_RESULT(okay) else - AC_MSG_ERROR(too old) + HAVE_PYTHON=no + AC_MSG_RESULT(no python) fi -AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)]) -AC_PATH_PROG(VALGRIND_PATH, valgrind, no) -AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") - -dnl check for gobject-introspection -GOBJECT_INTROSPECTION_CHECK([0.6.3]) - -dnl check for documentation tools -AG_GST_DOCBOOK_CHECK -GTK_DOC_CHECK([1.3]) - -AC_SUBST(PYGOBJECT_REQ, 2.11.2) +AM_CHECK_PYTHON_HEADERS([HAVE_PYTHON_HEADERS=yes],[HAVE_PYTHON_HEADERS=no]) dnl check for pygobject (optional, used in the bindings) PKG_CHECK_MODULES(PYGOBJECT, pygobject-2.0 >= $PYGOBJECT_REQ, - [ - HAVE_PYGOBJECT="yes" - ], - [ - HAVE_PYGOBJECT="no" - ]) + [HAVE_PYGOBJECT="yes"], [HAVE_PYGOBJECT="no"]) AC_SUBST(PYGOBJECT_CFLAGS) +AC_SUBST(PYGOBJECT_REQ, 2.11.2) dnl check for gst-python PKG_CHECK_MODULES(PYGST, gst-python-0.10, - [ - HAVE_PYGST="yes" - ], - [ - HAVE_PYGST="no" - ]) + [HAVE_PYGST="yes"], [HAVE_PYGST="no"]) if test "x$HAVE_PYGST" = "xyes"; then PYGST_DEFSDIR=`pkg-config gst-python-0.10 --variable=defsdir` fi AC_SUBST(PYGST_DEFSDIR, $PYGST_DEFSDIR) -if test "x$HAVE_PYTHON_HEADERS" = "xyes" -a \ +if test \ + "x$HAVE_PYTHON" = "xyes" -a \ + "x$HAVE_PYTHON_HEADERS" = "xyes" -a \ "x$HAVE_PYGOBJECT" = "xyes" -a \ "x$HAVE_PYGST" = "xyes"; then HAVE_PYTHON_BINDINGS="yes" From 7dfb91e2890b576bfc61471ec3e58b09f152c9f0 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 15 Dec 2010 14:58:00 +0200 Subject: [PATCH 0233/1776] Automatic update of common submodule From 011bcc8 to 169462a --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 011bcc8a0f..169462a62f 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 011bcc8a0fc7f798ee874a7ba899123fb2470e22 +Subproject commit 169462a62f8b3cb91d721092af13530a3f72a462 From 1ea450179eaf7069a90ac23db21dc08ed1c26557 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 Dec 2010 16:58:36 +0100 Subject: [PATCH 0234/1776] media: emit prepared signal when prepared Make a 'prepared' signal and emit it when we successfully prepared the element. This signal can be used to configure the media object after it has been prepared for streaming. --- gst/rtsp-server/rtsp-media.c | 8 ++++++++ gst/rtsp-server/rtsp-media.h | 1 + 2 files changed, 9 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 6f03057cf7..8f3b643a18 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -46,6 +46,7 @@ enum enum { + SIGNAL_PREPARED, SIGNAL_UNPREPARED, SIGNAL_LAST }; @@ -103,6 +104,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "Send an EOS event to the pipeline before unpreparing", DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_PREPARED] = + g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + gst_rtsp_media_signals[SIGNAL_UNPREPARED] = g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL, @@ -1592,6 +1598,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) if (status == GST_RTSP_MEDIA_STATUS_ERROR) goto state_failed; + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL); + GST_INFO ("object %p is prerolled", media); return TRUE; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 45fa22e719..6e35b20487 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -250,6 +250,7 @@ struct _GstRTSPMediaClass { gboolean (*unprepare) (GstRTSPMedia *media); /* signals */ + gboolean (*prepared) (GstRTSPMedia *media); gboolean (*unprepared) (GstRTSPMedia *media); }; From ad2e0edee5f6139e03bfc00440a68c1e43aa7539 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 18 Dec 2010 11:24:48 +0100 Subject: [PATCH 0235/1776] server: set SO_REUSEADDR before bind Set the SO_REUSEADDR _before_ bind() to make it actually work. --- gst/rtsp-server/rtsp-server.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index b4ce7b290d..70396aa62b 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -464,6 +464,15 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) continue; } + /* make address reusable */ + ret = 1; + if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, + (void *) &ret, sizeof (ret)) < 0) { + /* warn but try to bind anyway */ + GST_WARNING_OBJECT (server, "failed to reuse socker (%s)", + g_strerror (errno)); + } + if (bind (sockfd, rp->ai_addr, rp->ai_addrlen) == 0) { GST_DEBUG_OBJECT (server, "bind on %s", rp->ai_canonname); break; @@ -483,12 +492,6 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d", server->server_sock.fd); - /* make address reusable */ - ret = 1; - if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_REUSEADDR, - (void *) &ret, sizeof (ret)) < 0) - goto reuse_failed; - /* keep connection alive; avoids SIGPIPE during write */ ret = 1; if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_KEEPALIVE, @@ -535,11 +538,6 @@ no_socket: g_strerror (errno)); return FALSE; } -reuse_failed: - { - GST_ERROR_OBJECT (server, "failed to reuse socket: %s", g_strerror (errno)); - goto close_error; - } keepalive_failed: { GST_ERROR_OBJECT (server, "failed to configure keepalive socket: %s", From bc10b30e62f3c47bcc42fc56c9231291b3e600e3 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 20 Dec 2010 17:48:41 +0100 Subject: [PATCH 0236/1776] Automatic update of common submodule From 169462a to 46445ad --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 169462a62f..46445ad50f 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 169462a62f8b3cb91d721092af13530a3f72a462 +Subproject commit 46445ad50f184d2640dd205361e0446e9121ba5f From 105386011289e9c8d788bb92a2483c75a468e9d5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 21 Dec 2010 17:37:26 +0100 Subject: [PATCH 0237/1776] factory-uri: use better factory filter Make better payloader filter based on autoplug rank and RTP use case. --- gst/rtsp-server/rtsp-media-factory-uri.c | 37 +++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index d10ecd0868..df697ddab1 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -17,6 +17,8 @@ * Boston, MA 02111-1307, USA. */ +#include + #include "rtsp-media-factory-uri.h" #define DEFAULT_URI NULL @@ -100,13 +102,42 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass) 0, "GstRTSPMediaFactoryUri"); } +static gboolean +payloader_filter (GstPluginFeature * feature, gpointer data) +{ + gboolean res; + const gchar *klass; + + /* we only care about element factories */ + if (G_UNLIKELY (!GST_IS_ELEMENT_FACTORY (feature))) + return FALSE; + + if (gst_plugin_feature_get_rank (feature) < GST_RANK_MARGINAL) + return FALSE; + + klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY_CAST (feature)); + + if (strstr (klass, "Payloader") == NULL) + return FALSE; + + if (strstr (klass, "RTP") == NULL) + return FALSE; + + return TRUE; +} + static void gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory) { factory->uri = g_strdup (DEFAULT_URI); + /* get the feature list using the filter */ factory->factories = - gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PAYLOADER, - GST_RANK_NONE); + gst_default_registry_feature_filter ((GstPluginFeatureFilter) + payloader_filter, FALSE, NULL); + /* sort on rank and name */ + factory->factories = + g_list_sort (factory->factories, gst_plugin_feature_rank_compare_func); + factory->raw_vcaps = gst_static_caps_get (&raw_video_caps); factory->raw_acaps = gst_static_caps_get (&raw_audio_caps); } @@ -228,8 +259,6 @@ find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps) const gchar *name; name = gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (f)); - if (strcmp (name, "gdppay") == 0) - continue; factory = f; break; From 9ce4ea165bb529f876f72d174df7740a45825124 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 23 Dec 2010 15:58:14 +0100 Subject: [PATCH 0238/1776] factory-uri: rework the autoplugger. Rewrite the autoplugger a little so that it prefers to plug demuxers and parsers before payloaders. --- gst/rtsp-server/rtsp-media-factory-uri.c | 100 ++++++++++++++++------- gst/rtsp-server/rtsp-media-factory-uri.h | 4 +- 2 files changed, 73 insertions(+), 31 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index df697ddab1..91922b0c98 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -102,11 +102,20 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass) 0, "GstRTSPMediaFactoryUri"); } +typedef struct +{ + GList *demux; + GList *payload; + GList *decode; +} FilterData; + static gboolean -payloader_filter (GstPluginFeature * feature, gpointer data) +payloader_filter (GstPluginFeature * feature, FilterData * data) { gboolean res; const gchar *klass; + GstElementFactory *fact; + GList **list = NULL; /* we only care about element factories */ if (G_UNLIKELY (!GST_IS_ELEMENT_FACTORY (feature))) @@ -115,28 +124,43 @@ payloader_filter (GstPluginFeature * feature, gpointer data) if (gst_plugin_feature_get_rank (feature) < GST_RANK_MARGINAL) return FALSE; - klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY_CAST (feature)); + fact = GST_ELEMENT_FACTORY_CAST (feature); - if (strstr (klass, "Payloader") == NULL) - return FALSE; + klass = gst_element_factory_get_klass (fact); - if (strstr (klass, "RTP") == NULL) - return FALSE; + if (strstr (klass, "Decoder")) + list = &data->decode; + else if (strstr (klass, "Demux")) + list = &data->demux; + else if (strstr (klass, "Parser") && strstr (klass, "Codec")) + list = &data->demux; + else if (strstr (klass, "Payloader") && strstr (klass, "RTP")) + list = &data->payload; - return TRUE; + if (list) { + GST_DEBUG ("adding %s", GST_PLUGIN_FEATURE_NAME (fact)); + *list = g_list_prepend (*list, fact); + } + + return FALSE; } static void gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory) { + FilterData data = { NULL, NULL, NULL }; + factory->uri = g_strdup (DEFAULT_URI); /* get the feature list using the filter */ - factory->factories = - gst_default_registry_feature_filter ((GstPluginFeatureFilter) - payloader_filter, FALSE, NULL); - /* sort on rank and name */ - factory->factories = - g_list_sort (factory->factories, gst_plugin_feature_rank_compare_func); + gst_default_registry_feature_filter ((GstPluginFeatureFilter) + payloader_filter, FALSE, &data); + /* sort */ + factory->demuxers = + g_list_sort (data.demux, gst_plugin_feature_rank_compare_func); + factory->payloaders = + g_list_sort (data.payload, gst_plugin_feature_rank_compare_func); + factory->decoders = + g_list_sort (data.decode, gst_plugin_feature_rank_compare_func); factory->raw_vcaps = gst_static_caps_get (&raw_video_caps); factory->raw_acaps = gst_static_caps_get (&raw_audio_caps); @@ -148,7 +172,9 @@ gst_rtsp_media_factory_uri_finalize (GObject * obj) GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (obj); g_free (factory->uri); - gst_plugin_feature_list_free (factory->factories); + gst_plugin_feature_list_free (factory->demuxers); + gst_plugin_feature_list_free (factory->payloaders); + gst_plugin_feature_list_free (factory->decoders); gst_caps_unref (factory->raw_vcaps); gst_caps_unref (factory->raw_acaps); @@ -250,24 +276,37 @@ find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps) GList *list, *tmp; GstElementFactory *factory = NULL; - /* find payloader that can link */ - list = gst_element_factory_list_filter (urifact->factories, caps, + /* first find a demuxer that can link */ + list = gst_element_factory_list_filter (urifact->demuxers, caps, GST_PAD_SINK, FALSE); - for (tmp = list; tmp; tmp = g_list_next (tmp)) { - GstElementFactory *f = GST_ELEMENT_FACTORY_CAST (tmp->data); - const gchar *name; - - name = gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (f)); - - factory = f; - break; + if (list != NULL) { + /* we have a demuxer, try that one first */ + gst_plugin_feature_list_free (list); + return NULL; } - if (factory) + + /* no demuxer try a depayloader */ + list = gst_element_factory_list_filter (urifact->payloaders, caps, + GST_PAD_SINK, FALSE); + + if (list == NULL) { + /* no depayloader, try a decoder */ + list = gst_element_factory_list_filter (urifact->decoders, caps, + GST_PAD_SINK, FALSE); + + if (list != NULL) { + /* we have a decoder, try that one first */ + gst_plugin_feature_list_free (list); + return NULL; + } + } + + if (list != NULL) { + factory = GST_ELEMENT_FACTORY_CAST (list->data); g_object_ref (factory); - - gst_plugin_feature_list_free (list); - + gst_plugin_feature_list_free (list); + } return factory; } @@ -288,8 +327,9 @@ autoplug_continue_cb (GstElement * uribin, GstPad * pad, GstCaps * caps, if (!(factory = find_payloader (data->factory, caps))) goto no_factory; - /* we found a payloader, stop autoplugging */ - GST_DEBUG ("found payloader factory %s", + /* we found a payloader, stop autoplugging so we can plug the + * payloader. */ + GST_DEBUG ("found factory %s", gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory))); gst_object_unref (factory); diff --git a/gst/rtsp-server/rtsp-media-factory-uri.h b/gst/rtsp-server/rtsp-media-factory-uri.h index f27c718192..cf011ca34e 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.h +++ b/gst/rtsp-server/rtsp-media-factory-uri.h @@ -51,7 +51,9 @@ struct _GstRTSPMediaFactoryURI { gchar *uri; GstCaps *raw_vcaps; GstCaps *raw_acaps; - GList *factories; + GList *demuxers; + GList *payloaders; + GList *decoders; }; /** From 50a71b9d86fc6d89dd2f49d15037bcb8e930b683 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 23 Dec 2010 18:53:01 +0100 Subject: [PATCH 0239/1776] factory-uri: add support for gstpay Add an option to prefer gstpay over decoder + raw payloader. --- gst/rtsp-server/rtsp-media-factory-uri.c | 42 +++++++++++++++++++----- gst/rtsp-server/rtsp-media-factory-uri.h | 2 ++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 91922b0c98..3660905f63 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -21,12 +21,14 @@ #include "rtsp-media-factory-uri.h" -#define DEFAULT_URI NULL +#define DEFAULT_URI NULL +#define DEFAULT_USE_GSTPAY FALSE enum { PROP_0, PROP_URI, + PROP_USE_GSTPAY, PROP_LAST }; @@ -95,6 +97,16 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass) g_param_spec_string ("uri", "URI", "The URI of the resource to stream", DEFAULT_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPMediaFactoryURI::use-gstpay + * + * Allow the usage of gstpay in order to avoid decoding of compressed formats + * without a payloader. + */ + g_object_class_install_property (gobject_class, PROP_USE_GSTPAY, + g_param_spec_string ("use-gstpay", "Use gstpay", + "Use the gstpay payloader to avoid decoding", DEFAULT_USE_GSTPAY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); mediafactory_class->get_element = rtsp_media_factory_uri_get_element; @@ -151,6 +163,8 @@ gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory) FilterData data = { NULL, NULL, NULL }; factory->uri = g_strdup (DEFAULT_URI); + factory->use_gstpay = DEFAULT_USE_GSTPAY; + /* get the feature list using the filter */ gst_default_registry_feature_filter ((GstPluginFeatureFilter) payloader_filter, FALSE, &data); @@ -191,6 +205,9 @@ gst_rtsp_media_factory_uri_get_property (GObject * object, guint propid, case PROP_URI: g_value_take_string (value, gst_rtsp_media_factory_uri_get_uri (factory)); break; + case PROP_USE_GSTPAY: + g_value_set_boolean (value, factory->use_gstpay); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -206,6 +223,9 @@ gst_rtsp_media_factory_uri_set_property (GObject * object, guint propid, case PROP_URI: gst_rtsp_media_factory_uri_set_uri (factory, g_value_get_string (value)); break; + case PROP_USE_GSTPAY: + factory->use_gstpay = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -291,14 +311,20 @@ find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps) GST_PAD_SINK, FALSE); if (list == NULL) { - /* no depayloader, try a decoder */ - list = gst_element_factory_list_filter (urifact->decoders, caps, - GST_PAD_SINK, FALSE); + if (urifact->use_gstpay) { + /* no depayloader or parser/demuxer, use gstpay when allowed */ + factory = gst_element_factory_find ("rtpgstpay"); + } else { + /* no depayloader, try a decoder, we'll get to a payloader for a decoded + * video or audio format, worst case. */ + list = gst_element_factory_list_filter (urifact->decoders, caps, + GST_PAD_SINK, FALSE); - if (list != NULL) { - /* we have a decoder, try that one first */ - gst_plugin_feature_list_free (list); - return NULL; + if (list != NULL) { + /* we have a decoder, try that one first */ + gst_plugin_feature_list_free (list); + return NULL; + } } } diff --git a/gst/rtsp-server/rtsp-media-factory-uri.h b/gst/rtsp-server/rtsp-media-factory-uri.h index cf011ca34e..fcc2dd501d 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.h +++ b/gst/rtsp-server/rtsp-media-factory-uri.h @@ -49,6 +49,8 @@ struct _GstRTSPMediaFactoryURI { GstRTSPMediaFactory parent; gchar *uri; + gboolean use_gstpay; + GstCaps *raw_vcaps; GstCaps *raw_acaps; GList *demuxers; From 899f6248456445164e62b54debd915dc958f6b5d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 28 Dec 2010 12:18:41 +0100 Subject: [PATCH 0240/1776] client: fix typo --- gst/rtsp-server/rtsp-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 16646b74d0..229456480a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1127,7 +1127,7 @@ handle_options_request (GstRTSPClient * client, GstRTSPUrl * uri, /* remove duplicate and trailing '/' */ static void -santize_uri (GstRTSPUrl * uri) +sanitize_uri (GstRTSPUrl * uri) { gint i, len; gchar *s, *d; @@ -1221,7 +1221,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) } /* sanitize the uri */ - santize_uri (uri); + sanitize_uri (uri); /* get the session if there is any */ res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); From 43f4696f78839dcffb1efbbd64c5349a8701aa48 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 28 Dec 2010 18:31:26 +0100 Subject: [PATCH 0241/1776] client: cleanup headers --- gst/rtsp-server/rtsp-client.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index b29e218593..145fdf83ff 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -98,15 +98,15 @@ GType gst_rtsp_client_get_type (void); GstRTSPClient * gst_rtsp_client_new (void); -void gst_rtsp_client_set_session_pool (GstRTSPClient *client, +void gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool); GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client); -void gst_rtsp_client_set_media_mapping (GstRTSPClient *client, +void gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *mapping); GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client); -gboolean gst_rtsp_client_accept (GstRTSPClient *client, +gboolean gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel); G_END_DECLS From 915cd708ea8e974c730fe7c679105be1fd89b6c5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 28 Dec 2010 18:34:10 +0100 Subject: [PATCH 0242/1776] media: add signal to notify of state changes --- gst/rtsp-server/rtsp-media.c | 28 ++++++++++++++++++++-------- gst/rtsp-server/rtsp-media.h | 2 ++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 8f3b643a18..45843b4dd3 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -48,6 +48,7 @@ enum { SIGNAL_PREPARED, SIGNAL_UNPREPARED, + SIGNAL_NEW_STATE, SIGNAL_LAST }; @@ -114,6 +115,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + gst_rtsp_media_signals[SIGNAL_NEW_STATE] = + g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL, + g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 0, G_TYPE_INT); + klass->context = g_main_context_new (); klass->loop = g_main_loop_new (klass->context, TRUE); @@ -1888,16 +1894,22 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, else do_state = FALSE; - GST_INFO ("active %d media %p", media->active, media); + GST_INFO ("state %d active %d media %p do_state %d", state, media->active, + media, do_state); - if (do_state && media->target_state != state) { - if (state == GST_STATE_NULL) { - gst_rtsp_media_unprepare (media); - } else { - GST_INFO ("state %s media %p", gst_element_state_get_name (state), media); - media->target_state = state; - ret = gst_element_set_state (media->pipeline, state); + if (media->target_state != state) { + if (do_state) { + if (state == GST_STATE_NULL) { + gst_rtsp_media_unprepare (media); + } else { + GST_INFO ("state %s media %p", gst_element_state_get_name (state), + media); + media->target_state = state; + ret = gst_element_set_state (media->pipeline, state); + } } + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state, + NULL); } /* remember where we are */ diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 6e35b20487..fc4b15998a 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -252,6 +252,8 @@ struct _GstRTSPMediaClass { /* signals */ gboolean (*prepared) (GstRTSPMedia *media); gboolean (*unprepared) (GstRTSPMedia *media); + + gboolean (*new_state) (GstRTSPMedia *media, GstState state); }; GType gst_rtsp_media_get_type (void); From 4234d9631497fc05641cc176d2e479f62cf48656 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 28 Dec 2010 18:35:01 +0100 Subject: [PATCH 0243/1776] media: make method to retrieve the play range Make a method to retrieve the playback range so that we can conditionally create a different range for the SDP and the PLAY requests. --- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-media.c | 30 +++++++++++++++++++++++++++++- gst/rtsp-server/rtsp-media.h | 1 + gst/rtsp-server/rtsp-sdp.c | 2 +- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 229456480a..b352378a35 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -708,7 +708,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPUrl * uri, } /* add the range */ - str = gst_rtsp_range_to_string (&media->media->range); + str = gst_rtsp_media_get_range_string (media->media, TRUE); gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RANGE, str); send_response (client, session, &response); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 45843b4dd3..21dfa454bf 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -353,7 +353,7 @@ collect_media_stats (GstRTSPMedia * media) GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); - if (position == -1 || media->active > 0) { + if (position == -1) { media->range.min.type = GST_RTSP_TIME_NOW; media->range.min.seconds = -1; } else { @@ -560,6 +560,34 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) return res; } +/** + * gst_rtsp_media_get_range_string: + * @media: a #GstRTSPMedia + * @play: for the PLAY request + * + * Get the current range as a string. + * + * Returns: The range as a string, g_free() after usage. + */ +gchar * +gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play) +{ + gchar *result; + GstRTSPTimeRange range; + + /* make copy */ + range = media->range; + + if (!play && media->active > 0) { + range.min.type = GST_RTSP_TIME_NOW; + range.min.seconds = -1; + } + + result = gst_rtsp_range_to_string (&range); + + return result; +} + /** * gst_rtsp_media_seek: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index fc4b15998a..2c83f7602b 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -283,6 +283,7 @@ guint gst_rtsp_media_n_streams (GstRTSPMedia *media); GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range); +gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, gboolean play); GstFlowReturn gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer); GstFlowReturn gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer); diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 2db7e6f9a1..c6b379b830 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -43,7 +43,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, n_streams = gst_rtsp_media_n_streams (media); - rangestr = gst_rtsp_range_to_string (&media->range); + rangestr = gst_rtsp_media_get_range_string (media, FALSE); gst_sdp_message_add_attribute (sdp, "range", rangestr); g_free (rangestr); From 50b4c8de9822ca7ea3c9d6d28fb3c40861b4b745 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 29 Dec 2010 16:26:41 +0100 Subject: [PATCH 0244/1776] rtsp-server: add support for buffer lists Add support for sending bufferlists received from appsink. Fixes #635832 --- gst/rtsp-server/rtsp-client.c | 26 ++++++++++++++++++++++++-- gst/rtsp-server/rtsp-media.c | 34 +++++++++++++++++++++++++++++++++- gst/rtsp-server/rtsp-media.h | 3 +++ gst/rtsp-server/rtsp-session.c | 12 +++++++++--- gst/rtsp-server/rtsp-session.h | 2 ++ 5 files changed, 71 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b352378a35..2c168bd55b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -350,13 +350,34 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) return TRUE; } +static gboolean +do_send_data_list (GstBufferList * blist, guint8 channel, + GstRTSPClient * client) +{ + GstBufferListIterator *it; + + it = gst_buffer_list_iterate (blist); + while (gst_buffer_list_iterator_next_group (it)) { + GstBuffer *group = gst_buffer_list_iterator_merge_group (it); + + if (group == NULL) + continue; + + do_send_data (group, channel, client); + } + gst_buffer_list_iterator_free (it); + + return TRUE; +} + static void link_stream (GstRTSPClient * client, GstRTSPSession * session, GstRTSPSessionStream * stream) { GST_DEBUG ("client %p: linking stream %p", client, stream); gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data, - (GstRTSPSendFunc) do_send_data, client, NULL); + (GstRTSPSendFunc) do_send_data, (GstRTSPSendListFunc) do_send_data_list, + (GstRTSPSendListFunc) do_send_data_list, client, NULL); client->streams = g_list_prepend (client->streams, stream); /* make sure our session can't expire */ gst_rtsp_session_prevent_expire (session); @@ -367,7 +388,8 @@ unlink_stream (GstRTSPClient * client, GstRTSPSession * session, GstRTSPSessionStream * stream) { GST_DEBUG ("client %p: unlinking stream %p", client, stream); - gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); + gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL, NULL, + NULL); client->streams = g_list_remove (client->streams, stream); /* our session can now expire */ gst_rtsp_session_allow_expire (session); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 21dfa454bf..8922d42de2 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1108,10 +1108,42 @@ handle_new_buffer (GstAppSink * sink, gpointer user_data) return GST_FLOW_OK; } +static GstFlowReturn +handle_new_buffer_list (GstAppSink * sink, gpointer user_data) +{ + GList *walk; + GstBufferList *blist; + GstRTSPMediaStream *stream; + + blist = gst_app_sink_pull_buffer_list (sink); + if (!blist) + return GST_FLOW_OK; + + stream = (GstRTSPMediaStream *) user_data; + + for (walk = stream->transports; walk; walk = g_list_next (walk)) { + GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data; + + if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) { + if (tr->send_rtp_list) + tr->send_rtp_list (blist, tr->transport->interleaved.min, + tr->user_data); + } else { + if (tr->send_rtcp_list) + tr->send_rtcp_list (blist, tr->transport->interleaved.max, + tr->user_data); + } + } + gst_buffer_list_unref (blist); + + return GST_FLOW_OK; +} + static GstAppSinkCallbacks sink_cb = { NULL, /* not interested in EOS */ NULL, /* not interested in preroll buffers */ - handle_new_buffer + handle_new_buffer, + handle_new_buffer_list }; /* prepare the pipeline objects to handle @stream in @media */ diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 2c83f7602b..c5208e9df9 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -42,6 +42,7 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass; typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans; typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); +typedef gboolean (*GstRTSPSendListFunc) (GstBufferList *blist, guint8 channel, gpointer user_data); typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); /** @@ -66,6 +67,8 @@ struct _GstRTSPMediaTrans { GstRTSPSendFunc send_rtp; GstRTSPSendFunc send_rtcp; + GstRTSPSendListFunc send_rtp_list; + GstRTSPSendListFunc send_rtcp_list; gpointer user_data; GDestroyNotify notify; diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index e87f096743..8d507e5397 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -79,7 +79,8 @@ gst_rtsp_session_free_stream (GstRTSPSessionStream * stream) GST_INFO ("free session stream %p", stream); /* remove callbacks now */ - gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); + gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL, NULL, + NULL); gst_rtsp_session_stream_set_keepalive (stream, NULL, NULL, NULL); gst_rtsp_media_trans_cleanup (&stream->trans); @@ -549,6 +550,8 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream, * @stream: a #GstRTSPSessionStream * @send_rtp: a callback called when RTP should be sent * @send_rtcp: a callback called when RTCP should be sent + * @send_rtp_list: a callback called when RTP should be sent + * @send_rtcp_list: a callback called when RTCP should be sent * @user_data: user data passed to callbacks * @notify: called with the user_data when no longer needed. * @@ -557,11 +560,14 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream, */ void gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream * stream, - GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, gpointer user_data, - GDestroyNotify notify) + GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, + GstRTSPSendListFunc send_rtp_list, GstRTSPSendListFunc send_rtcp_list, + gpointer user_data, GDestroyNotify notify) { stream->trans.send_rtp = send_rtp; stream->trans.send_rtcp = send_rtcp; + stream->trans.send_rtp_list = send_rtp_list; + stream->trans.send_rtcp_list = send_rtcp_list; if (stream->trans.notify) stream->trans.notify (stream->trans.user_data); stream->trans.user_data = user_data; diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index cfd75c60c1..00bc3f3d64 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -154,6 +154,8 @@ GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStre void gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream *stream, GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, + GstRTSPSendListFunc send_rtp_list, + GstRTSPSendListFunc send_rtcp_list, gpointer user_data, GDestroyNotify notify); void gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream *stream, From 160fc25867f7dba7389834665f63a13c584fc1fc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 30 Dec 2010 12:41:31 +0100 Subject: [PATCH 0245/1776] docs: improve docs --- gst/rtsp-server/rtsp-client.c | 2 ++ gst/rtsp-server/rtsp-media.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 2c168bd55b..03a7d8ab6f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -182,6 +182,8 @@ gst_rtsp_client_set_property (GObject * object, guint propid, * gst_rtsp_client_new: * * Create a new #GstRTSPClient instance. + * + * Returns: a new #GstRTSPClient */ GstRTSPClient * gst_rtsp_client_new (void) diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index c5208e9df9..542455421f 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -50,6 +50,8 @@ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); * @idx: a stream index * @send_rtp: callback for sending RTP messages * @send_rtcp: callback for sending RTCP messages + * @send_rtp_list: callback for sending RTP messages + * @send_rtcp_list: callback for sending RTCP messages * @user_data: user data passed in the callbacks * @notify: free function for the user_data. * @keep_alive: keep alive callback From 220f9118514dd1075655f9f3ec9b9a05585c7318 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 30 Dec 2010 12:41:53 +0100 Subject: [PATCH 0246/1776] docs: add uri factory to the docs --- docs/libs/gst-rtsp-server-docs.sgml | 1 + docs/libs/gst-rtsp-server-sections.txt | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/docs/libs/gst-rtsp-server-docs.sgml b/docs/libs/gst-rtsp-server-docs.sgml index 7412dbc143..14d3e08472 100644 --- a/docs/libs/gst-rtsp-server-docs.sgml +++ b/docs/libs/gst-rtsp-server-docs.sgml @@ -16,6 +16,7 @@ + diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index a86beac253..cec65600e2 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -45,6 +45,30 @@ GST_IS_RTSP_MEDIA_FACTORY_CLASS GST_RTSP_MEDIA_FACTORY_GET_CLASS +
+rtsp-media-factory-uri +GstRTSPMediaFactoryURI +GST_RTSP_MEDIA_FACTORY_GET_LOCK +GST_RTSP_MEDIA_FACTORY_LOCK +GST_RTSP_MEDIA_FACTORY_UNLOCK +GstRTSPMediaFactoryURI +GstRTSPMediaFactoryURIClass +gst_rtsp_media_factory_uri_new +gst_rtsp_media_factory_uri_set_uri +gst_rtsp_media_factory_uri_get_uri + +GST_IS_RTSP_MEDIA_FACTORY_URI +GST_IS_RTSP_MEDIA_FACTORY_URI_CLASS +GST_RTSP_MEDIA_FACTORY_URI +GST_RTSP_MEDIA_FACTORY_URI_CAST +GST_RTSP_MEDIA_FACTORY_URI_CLASS +GST_RTSP_MEDIA_FACTORY_URI_CLASS_CAST +GST_RTSP_MEDIA_FACTORY_URI_GET_CLASS +GST_TYPE_RTSP_MEDIA_FACTORY_URI +gst_rtsp_media_factory_uri_get_type +
+ +
rtsp-media GstRTSPMedia @@ -53,6 +77,7 @@ GstRTSPMedia GstRTSPMediaClass GstRTSPMediaTrans GstRTSPSendFunc +GstRTSPSendListFunc GstRTSPKeepAliveFunc GstRTSPMediaStatus gst_rtsp_media_new @@ -70,6 +95,7 @@ gst_rtsp_media_unprepare gst_rtsp_media_n_streams gst_rtsp_media_get_stream gst_rtsp_media_seek +gst_rtsp_media_get_range_string gst_rtsp_media_stream_rtp gst_rtsp_media_stream_rtcp gst_rtsp_media_set_state From b5a1719e89576098809aea59f1a8ddd3cc0a09e8 Mon Sep 17 00:00:00 2001 From: Jonas Larsson Date: Wed, 5 Jan 2011 11:26:30 +0100 Subject: [PATCH 0247/1776] client: use the socket length from getsockname Use the length returned by getsockname to perform the getnameinfo call because the size can depend on the socket type and platform. Fixes #638723 --- gst/rtsp-server/rtsp-client.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 03a7d8ab6f..76450a20f1 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1740,7 +1740,6 @@ gst_rtsp_client_accept (GstRTSPClient * client, GIOChannel * channel) client->is_ipv6 = addr.ss_family == AF_INET6; - addrlen = sizeof (addr); if (getnameinfo ((struct sockaddr *) &addr, addrlen, ip, sizeof (ip), NULL, 0, NI_NUMERICHOST) != 0) goto getnameinfo_failed; From 790c06791909e2efd89b2a058328dcb6004fdddd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 5 Jan 2011 12:06:23 +0100 Subject: [PATCH 0248/1776] media: attempt to configure bigger UDP buffers Attempt to configure bigger udp kernel send buffers to avoid overflowing the send buffers with high bitrate streams. --- gst/rtsp-server/rtsp-media.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 8922d42de2..25decae8ac 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -850,6 +850,13 @@ again: stream->filter_duplicates = TRUE; } + if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), + "buffer-size")) { + g_object_set (G_OBJECT (udpsink0), "buffer-size", 0x80000, NULL); + } else { + GST_WARNING ("multiudpsink version found without buffer-size property"); + } + g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL); g_object_set (G_OBJECT (udpsink1), "sockfd", sockfd, NULL); g_object_set (G_OBJECT (udpsink1), "closefd", FALSE, NULL); From 257bac1bab2794919a6ae36b88a39e92b12598aa Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 5 Jan 2011 12:07:42 +0100 Subject: [PATCH 0249/1776] factory-uri: attempt to configure buffer-lists Attempt to configure buffer lists in the payloader for improved performance. --- gst/rtsp-server/rtsp-media-factory-uri.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 3660905f63..227c7947f9 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -444,6 +444,10 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) g_object_set (payloader, "pt", data->pt, NULL); data->pt++; + if (g_object_class_find_property (G_OBJECT_GET_CLASS (payloader), + "buffer-list")) + g_object_set (payloader, "buffer-list", TRUE, NULL); + /* add the payloader to the pipeline */ gst_bin_add (GST_BIN_CAST (element), payloader); gst_element_set_state (payloader, GST_STATE_PLAYING); From 186089ff1e67b025717b5bd82b3b4fca686aed5e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 7 Jan 2011 11:24:39 +0100 Subject: [PATCH 0250/1776] factory-uri: use right property type --- gst/rtsp-server/rtsp-media-factory-uri.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 227c7947f9..c0932b90c0 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -104,7 +104,7 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass) * without a payloader. */ g_object_class_install_property (gobject_class, PROP_USE_GSTPAY, - g_param_spec_string ("use-gstpay", "Use gstpay", + g_param_spec_boolean ("use-gstpay", "Use gstpay", "Use the gstpay payloader to avoid decoding", DEFAULT_USE_GSTPAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); From 5227832132747abae0c89b06ad989d3af3389e5c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 7 Jan 2011 11:27:57 +0100 Subject: [PATCH 0251/1776] examples: add some more options and comments --- examples/test-uri.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/test-uri.c b/examples/test-uri.c index bde0355435..61af721485 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -60,7 +60,13 @@ main (int argc, char *argv[]) /* make a URI media factory for a test stream. */ factory = gst_rtsp_media_factory_uri_new (); + /* when using GStreamer as a client, one can use the gst payloader, which is + * more efficient when there is no payloader for the compressed format */ + /* g_object_set (factory, "use-gstpay", TRUE, NULL); */ gst_rtsp_media_factory_uri_set_uri (factory, argv[1]); + /* if you want multiple clients to see the same video, set the shared property + * to TRUE */ + /* gst_rtsp_media_factory_set_shared ( GST_RTSP_MEDIA_FACTORY (factory), TRUE); */ /* attach the test factory to the /test url */ gst_rtsp_media_mapping_add_factory (mapping, "/test", From 8b1ec41d0858fe257d2aa5db1e450e4c726d00a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 8 Jan 2011 01:15:35 +0000 Subject: [PATCH 0252/1776] gobject-introspection: fix g-i build for uninstalled setup Requires gst-plugins-base git (> 0.10.31.2). --- configure.ac | 2 ++ gst/rtsp-server/Makefile.am | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f83f35d820..6cc68d7262 100644 --- a/configure.ac +++ b/configure.ac @@ -67,6 +67,8 @@ AG_GST_ARG_GCOV AG_GST_ARG_WITH_PACKAGE_NAME AG_GST_ARG_WITH_PACKAGE_ORIGIN +AG_GST_PKG_CONFIG_PATH + dnl *** checks for platform *** dnl * hardware/architecture * diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 8be1f593b5..02a0bd7787 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -60,6 +60,8 @@ GstRtspServer-@GST_MAJORMINOR@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@G -DIN_GOBJECT_INTROSPECTION=1 \ --c-include='gst/gst.h' \ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-0.10` \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-0.10` \ --library=libgstrtspserver-0.10.la \ --include=Gst-0.10 \ --include=GstRtsp-0.10 \ @@ -81,7 +83,13 @@ typelibsdir = $(libdir)/girepository-1.0/ typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) %.typelib: %.gir $(INTROSPECTION_COMPILER) - $(AM_V_GEN)$(INTROSPECTION_COMPILER) --includedir=$(srcdir) --includedir=$(builddir) $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) + $(AM_V_GEN)$(INTROSPECTION_COMPILER) \ + --includedir=$(srcdir) \ + --includedir=$(builddir) \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-0.10` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-0.10` \ + $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA) endif From 4faf186ea3d151ee68e1cc89bf6dc4ee1fbca8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 8 Jan 2011 01:55:06 +0000 Subject: [PATCH 0253/1776] build: make autotools put all .m4 cruft into m4/ rather than polluting common/m4 --- .gitignore | 2 ++ Makefile.am | 43 ++++++++++++++++++++++++++++++++++++++----- configure.ac | 2 +- m4/Makefile.am | 18 ------------------ m4/codeset.m4 | 23 ----------------------- 5 files changed, 41 insertions(+), 47 deletions(-) delete mode 100644 m4/Makefile.am delete mode 100644 m4/codeset.m4 diff --git a/.gitignore b/.gitignore index 120bc47885..16f8566d45 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ bindings/python/rtspserver.c tags gst-rtsp.spec stamp-h.in + +/m4/*m4 diff --git a/Makefile.am b/Makefile.am index 802e23ab33..441ac000a7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,7 +3,6 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc SUBDIRS = \ gst \ bindings \ - m4 \ common \ pkgconfig \ docs \ @@ -16,7 +15,7 @@ EXTRA_DIST = \ AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \ gst-rtsp.spec docs/design/gst-rtp-server-design -ACLOCAL_AMFLAGS = -I common/m4 -I m4 +ACLOCAL_AMFLAGS = -I m4 -I common/m4 DISTCLEANFILES = _stdint.h gst-rtsp.spec @@ -36,9 +35,43 @@ endif # cruft: plugins that have been merged or moved or renamed CRUFT_FILES = \ - $(top_builddir)/common/shave \ - $(top_builddir)/common/shave-libtool + $(top_builddir)/common/shave \ + $(top_builddir)/common/shave-libtool \ + $(top_builddir)/common/m4/codeset.m4 \ + $(top_builddir)/common/m4/gettext.m4 \ + $(top_builddir)/common/m4/glibc2.m4 \ + $(top_builddir)/common/m4/glibc21.m4 \ + $(top_builddir)/common/m4/iconv.m4 \ + $(top_builddir)/common/m4/intdiv0.m4 \ + $(top_builddir)/common/m4/intl.m4 \ + $(top_builddir)/common/m4/intldir.m4 \ + $(top_builddir)/common/m4/intlmacosx.m4 \ + $(top_builddir)/common/m4/intmax.m4 \ + $(top_builddir)/common/m4/inttypes-pri.m4 \ + $(top_builddir)/common/m4/inttypes_h.m4 \ + $(top_builddir)/common/m4/lcmessage.m4 \ + $(top_builddir)/common/m4/lib-ld.m4 \ + $(top_builddir)/common/m4/lib-link.m4 \ + $(top_builddir)/common/m4/lib-prefix.m4 \ + $(top_builddir)/common/m4/libtool.m4 \ + $(top_builddir)/common/m4/lock.m4 \ + $(top_builddir)/common/m4/longlong.m4 \ + $(top_builddir)/common/m4/ltoptions.m4 \ + $(top_builddir)/common/m4/ltsugar.m4 \ + $(top_builddir)/common/m4/ltversion.m4 \ + $(top_builddir)/common/m4/lt~obsolete.m4 \ + $(top_builddir)/common/m4/nls.m4 \ + $(top_builddir)/common/m4/po.m4 \ + $(top_builddir)/common/m4/printf-posix.m4 \ + $(top_builddir)/common/m4/progtest.m4 \ + $(top_builddir)/common/m4/size_max.m4 \ + $(top_builddir)/common/m4/stdint_h.m4 \ + $(top_builddir)/common/m4/uintmax_t.m4 \ + $(top_builddir)/common/m4/visibility.m4 \ + $(top_builddir)/common/m4/wchar_t.m4 \ + $(top_builddir)/common/m4/wint_t.m4 \ + $(top_builddir)/common/m4/xsize.m4 include $(top_srcdir)/common/cruft.mak -all-local: check-cruft \ No newline at end of file +all-local: check-cruft diff --git a/configure.ac b/configure.ac index 6cc68d7262..f007fc413f 100644 --- a/configure.ac +++ b/configure.ac @@ -52,6 +52,7 @@ AS_AUTOTOOLS_ALTERNATE dnl Add parameters for aclocal AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4") +AC_CONFIG_MACRO_DIR([m4]) dnl set up gettext dnl the version check needs to stay here because autopoint greps for it @@ -282,7 +283,6 @@ Makefile gst-rtsp.spec common/Makefile common/m4/Makefile -m4/Makefile gst/Makefile gst/rtsp-server/Makefile examples/Makefile diff --git a/m4/Makefile.am b/m4/Makefile.am deleted file mode 100644 index 226cc479db..0000000000 --- a/m4/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -EXTRA_DIST = \ - codeset.m4 - gettext.m4 - glibc21.m4 \ - iconv.m4 \ - intdiv0.m4 \ - inttypes-pri.m4 \ - nttypes.m4 \ - inttypes_h.m4 \ - isc-posix.m4 \ - lcmessage.m4 \ - lib-ld.m4 \ - lib-link.m4 \ - lib-prefix.m4 \ - progtest.m4 \ - stdint_h.m4 \ - uintmax_t.m4 \ - ulonglong.m4 diff --git a/m4/codeset.m4 b/m4/codeset.m4 deleted file mode 100644 index 59535ebcff..0000000000 --- a/m4/codeset.m4 +++ /dev/null @@ -1,23 +0,0 @@ -# codeset.m4 serial AM1 (gettext-0.10.40) -dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Bruno Haible. - -AC_DEFUN([AM_LANGINFO_CODESET], -[ - AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, - [AC_TRY_LINK([#include ], - [char* cs = nl_langinfo(CODESET);], - am_cv_langinfo_codeset=yes, - am_cv_langinfo_codeset=no) - ]) - if test $am_cv_langinfo_codeset = yes; then - AC_DEFINE(HAVE_LANGINFO_CODESET, 1, - [Define if you have and nl_langinfo(CODESET).]) - fi -]) From c19eb8fb4e08f02964b95443d9ac3e8db1281eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 8 Jan 2011 01:58:44 +0000 Subject: [PATCH 0254/1776] gobject-introspection: use PKG_CONFIG_PATH specified at configure time Use PKG_CONFIG_PATH specified at configure time (if any) as well for the g-ir-compiler, rather than just assuming the env var has been set. --- gst/rtsp-server/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 02a0bd7787..ac5624a0ac 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -83,7 +83,8 @@ typelibsdir = $(libdir)/girepository-1.0/ typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) %.typelib: %.gir $(INTROSPECTION_COMPILER) - $(AM_V_GEN)$(INTROSPECTION_COMPILER) \ + $(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \ + $(INTROSPECTION_COMPILER) \ --includedir=$(srcdir) \ --includedir=$(builddir) \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \ From 7b3cbfde1bb84297ccd405f2b9cb2837b270e148 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 10 Jan 2011 13:41:43 +0100 Subject: [PATCH 0255/1776] rtsp-media: add and use fsfunnel Add a copy of fsfunnel to the build because input-selector removed the (broken) select-all property that we need. --- gst/rtsp-server/Makefile.am | 2 + gst/rtsp-server/fs-funnel.c | 405 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/fs-funnel.h | 69 ++++++ gst/rtsp-server/rtsp-media.c | 9 +- 4 files changed, 481 insertions(+), 4 deletions(-) create mode 100644 gst/rtsp-server/fs-funnel.c create mode 100644 gst/rtsp-server/fs-funnel.h diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index ac5624a0ac..d3819b5cac 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -1,4 +1,5 @@ public_headers = \ + fs-funnel.h \ rtsp-params.h \ rtsp-sdp.h \ rtsp-media.h \ @@ -11,6 +12,7 @@ public_headers = \ rtsp-server.h c_sources = \ + fs-funnel.c \ rtsp-params.c \ rtsp-sdp.c \ rtsp-media.c \ diff --git a/gst/rtsp-server/fs-funnel.c b/gst/rtsp-server/fs-funnel.c new file mode 100644 index 0000000000..6c8ac7e890 --- /dev/null +++ b/gst/rtsp-server/fs-funnel.c @@ -0,0 +1,405 @@ +/* + * Farsight2 - Farsight Funnel element + * + * Copyright 2007 Collabora Ltd. + * @author: Olivier Crete + * Copyright 2007 Nokia Corp. + * + * fs-funnel.c: Simple Funnel element + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * SECTION:element-fsfunnel + * @short_description: N-to-1 simple funnel + * + * Takes packets from various input sinks into one output source + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "fs-funnel.h" + +GST_DEBUG_CATEGORY_STATIC (fs_funnel_debug); +#define GST_CAT_DEFAULT fs_funnel_debug + +static const GstElementDetails fs_funnel_details = +GST_ELEMENT_DETAILS ("Farsight Funnel pipe fitting", + "Generic", + "N-to-1 pipe fitting", + "Olivier Crete "); + +static GstStaticPadTemplate funnel_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink%d", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS_ANY); + +static GstStaticPadTemplate funnel_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + + +static void +_do_init (GType type) +{ + GST_DEBUG_CATEGORY_INIT (fs_funnel_debug, "fsfunnel", 0, "fsfunnel element"); +} + +GST_BOILERPLATE_FULL (FsFunnel, fs_funnel, GstElement, GST_TYPE_ELEMENT, + _do_init); + + + +static GstStateChangeReturn fs_funnel_change_state (GstElement * element, + GstStateChange transition); + +static GstPad *fs_funnel_request_new_pad (GstElement * element, + GstPadTemplate * templ, const gchar * name); +static void fs_funnel_release_pad (GstElement * element, GstPad * pad); + +static GstFlowReturn fs_funnel_chain (GstPad * pad, GstBuffer * buffer); +static gboolean fs_funnel_event (GstPad * pad, GstEvent * event); +static gboolean fs_funnel_src_event (GstPad * pad, GstEvent * event); +static GstCaps *fs_funnel_getcaps (GstPad * pad); + + +typedef struct +{ + GstSegment segment; +} FsFunnelPadPrivate; + +static void +fs_funnel_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details (gstelement_class, &fs_funnel_details); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&funnel_sink_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&funnel_src_template)); +} + + +static void +fs_funnel_dispose (GObject * object) +{ + GList *item; + +restart: + for (item = GST_ELEMENT_PADS (object); item; item = g_list_next (item)) { + GstPad *pad = GST_PAD (item->data); + + if (GST_PAD_IS_SINK (pad)) { + gst_element_release_request_pad (GST_ELEMENT (object), pad); + goto restart; + } + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +fs_funnel_class_init (FsFunnelClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + + gobject_class->dispose = GST_DEBUG_FUNCPTR (fs_funnel_dispose); + + gstelement_class->request_new_pad = + GST_DEBUG_FUNCPTR (fs_funnel_request_new_pad); + gstelement_class->release_pad = GST_DEBUG_FUNCPTR (fs_funnel_release_pad); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (fs_funnel_change_state); +} + +static void +fs_funnel_init (FsFunnel * funnel, FsFunnelClass * g_class) +{ + funnel->srcpad = gst_pad_new_from_static_template (&funnel_src_template, + "src"); + gst_pad_set_event_function (funnel->srcpad, fs_funnel_src_event); + gst_pad_use_fixed_caps (funnel->srcpad); + gst_element_add_pad (GST_ELEMENT (funnel), funnel->srcpad); +} + + +static GstPad * +fs_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ, + const gchar * name) +{ + GstPad *sinkpad; + FsFunnelPadPrivate *priv = g_slice_alloc0 (sizeof (FsFunnelPadPrivate)); + + GST_DEBUG_OBJECT (element, "requesting pad"); + + sinkpad = gst_pad_new_from_template (templ, name); + + gst_pad_set_chain_function (sinkpad, GST_DEBUG_FUNCPTR (fs_funnel_chain)); + gst_pad_set_event_function (sinkpad, GST_DEBUG_FUNCPTR (fs_funnel_event)); + gst_pad_set_getcaps_function (sinkpad, GST_DEBUG_FUNCPTR (fs_funnel_getcaps)); + + gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED); + gst_pad_set_element_private (sinkpad, priv); + + gst_pad_set_active (sinkpad, TRUE); + + gst_element_add_pad (element, sinkpad); + + return sinkpad; +} + +static void +fs_funnel_release_pad (GstElement * element, GstPad * pad) +{ + FsFunnel *funnel = FS_FUNNEL (element); + FsFunnelPadPrivate *priv = gst_pad_get_element_private (pad); + + GST_DEBUG_OBJECT (funnel, "releasing pad"); + + gst_pad_set_active (pad, FALSE); + + if (priv) + g_slice_free1 (sizeof (FsFunnelPadPrivate), priv); + + gst_element_remove_pad (GST_ELEMENT_CAST (funnel), pad); +} + +static GstCaps * +fs_funnel_getcaps (GstPad * pad) +{ + FsFunnel *funnel = FS_FUNNEL (gst_pad_get_parent (pad)); + GstCaps *caps; + + caps = gst_pad_peer_get_caps (funnel->srcpad); + if (caps == NULL) + caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); + + gst_object_unref (funnel); + + return caps; +} + +static GstFlowReturn +fs_funnel_chain (GstPad * pad, GstBuffer * buffer) +{ + GstFlowReturn res; + FsFunnel *funnel = FS_FUNNEL (gst_pad_get_parent (pad)); + FsFunnelPadPrivate *priv = gst_pad_get_element_private (pad); + GstEvent *event = NULL; + GstClockTime newts; + GstCaps *padcaps; + + GST_DEBUG_OBJECT (funnel, "received buffer %p", buffer); + + GST_OBJECT_LOCK (funnel); + if (priv->segment.format == GST_FORMAT_UNDEFINED) { + GST_WARNING_OBJECT (funnel, "Got buffer without segment," + " setting segment [0,inf["); + gst_segment_set_newsegment_full (&priv->segment, FALSE, 1.0, 1.0, + GST_FORMAT_TIME, 0, -1, 0); + } + + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) + gst_segment_set_last_stop (&priv->segment, priv->segment.format, + GST_BUFFER_TIMESTAMP (buffer)); + + newts = gst_segment_to_running_time (&priv->segment, + priv->segment.format, GST_BUFFER_TIMESTAMP (buffer)); + if (newts != GST_BUFFER_TIMESTAMP (buffer)) { + buffer = gst_buffer_make_metadata_writable (buffer); + GST_BUFFER_TIMESTAMP (buffer) = newts; + } + + if (!funnel->has_segment) { + event = gst_event_new_new_segment_full (FALSE, 1.0, 1.0, GST_FORMAT_TIME, + 0, -1, 0); + funnel->has_segment = TRUE; + } + GST_OBJECT_UNLOCK (funnel); + + if (event) { + if (!gst_pad_push_event (funnel->srcpad, event)) { + GST_WARNING_OBJECT (funnel, "Could not push out newsegment event"); + res = GST_FLOW_ERROR; + goto out; + } + } + + + GST_OBJECT_LOCK (pad); + padcaps = GST_PAD_CAPS (funnel->srcpad); + GST_OBJECT_UNLOCK (pad); + + if (GST_BUFFER_CAPS (buffer) && GST_BUFFER_CAPS (buffer) != padcaps) { + if (!gst_pad_set_caps (funnel->srcpad, GST_BUFFER_CAPS (buffer))) { + res = GST_FLOW_NOT_NEGOTIATED; + goto out; + } + } + + res = gst_pad_push (funnel->srcpad, buffer); + + GST_LOG_OBJECT (funnel, "handled buffer %s", gst_flow_get_name (res)); + +out: + gst_object_unref (funnel); + + return res; +} + +static gboolean +fs_funnel_event (GstPad * pad, GstEvent * event) +{ + FsFunnel *funnel = FS_FUNNEL (gst_pad_get_parent (pad)); + FsFunnelPadPrivate *priv = gst_pad_get_element_private (pad); + gboolean forward = TRUE; + gboolean res = TRUE; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + { + gboolean update; + gdouble rate, arate; + GstFormat format; + gint64 start; + gint64 stop; + gint64 time; + + gst_event_parse_new_segment_full (event, &update, &rate, &arate, + &format, &start, &stop, &time); + + + GST_OBJECT_LOCK (funnel); + gst_segment_set_newsegment_full (&priv->segment, update, rate, arate, + format, start, stop, time); + GST_OBJECT_UNLOCK (funnel); + + forward = FALSE; + gst_event_unref (event); + } + break; + case GST_EVENT_FLUSH_STOP: + { + GST_OBJECT_LOCK (funnel); + gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED); + GST_OBJECT_UNLOCK (funnel); + } + break; + default: + break; + } + + + if (forward) + res = gst_pad_push_event (funnel->srcpad, event); + + gst_object_unref (funnel); + + return res; +} + +static gboolean +fs_funnel_src_event (GstPad * pad, GstEvent * event) +{ + GstElement *funnel; + GstIterator *iter; + GstPad *sinkpad; + gboolean result = FALSE; + gboolean done = FALSE; + + funnel = gst_pad_get_parent_element (pad); + g_return_val_if_fail (funnel != NULL, FALSE); + + iter = gst_element_iterate_sink_pads (funnel); + + while (!done) { + switch (gst_iterator_next (iter, (gpointer) & sinkpad)) { + case GST_ITERATOR_OK: + gst_event_ref (event); + result |= gst_pad_push_event (sinkpad, event); + gst_object_unref (sinkpad); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + result = FALSE; + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (funnel, "Error iterating sinkpads"); + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iter); + gst_object_unref (funnel); + gst_event_unref (event); + + return result; +} + +static void +reset_pad (gpointer data, gpointer user_data) +{ + GstPad *pad = data; + FsFunnelPadPrivate *priv = gst_pad_get_element_private (pad); + + GST_OBJECT_LOCK (pad); + gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED); + GST_OBJECT_UNLOCK (pad); + gst_object_unref (pad); +} + +static GstStateChangeReturn +fs_funnel_change_state (GstElement * element, GstStateChange transition) +{ + FsFunnel *funnel = FS_FUNNEL (element); + GstStateChangeReturn ret; + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + { + GstIterator *iter = gst_element_iterate_sink_pads (element); + GstIteratorResult res; + + do { + res = gst_iterator_foreach (iter, reset_pad, NULL); + } while (res == GST_ITERATOR_RESYNC); + + gst_iterator_free (iter); + + if (res == GST_ITERATOR_ERROR) + return GST_STATE_CHANGE_FAILURE; + + GST_OBJECT_LOCK (funnel); + funnel->has_segment = FALSE; + GST_OBJECT_UNLOCK (funnel); + } + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + return ret; +} diff --git a/gst/rtsp-server/fs-funnel.h b/gst/rtsp-server/fs-funnel.h new file mode 100644 index 0000000000..c1d5094e46 --- /dev/null +++ b/gst/rtsp-server/fs-funnel.h @@ -0,0 +1,69 @@ +/* + * Farsight2 - Farsight Funnel element + * + * Copyright 2007 Collabora Ltd. + * @author: Olivier Crete + * Copyright 2007 Nokia Corp. + * + * fs-funnel.h: Simple Funnel element + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef __FS_FUNNEL_H__ +#define __FS_FUNNEL_H__ + +#include + +G_BEGIN_DECLS + +#define FS_TYPE_FUNNEL \ + (fs_funnel_get_type ()) +#define FS_FUNNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),FS_TYPE_FUNNEL,FsFunnel)) +#define FS_FUNNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),FS_TYPE_FUNNEL,FsFunnelClass)) +#define FS_IS_FUNNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),FS_TYPE_FUNNEL)) +#define FS_IS_FUNNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),FS_TYPE_FUNNEL)) + +typedef struct _FsFunnel FsFunnel; +typedef struct _FsFunnelClass FsFunnelClass; + +/** + * FsFunnel: + * + * Opaque #FsFunnel data structure. + */ +struct _FsFunnel { + GstElement element; + + /*< private >*/ + GstPad *srcpad; + + gboolean has_segment; +}; + +struct _FsFunnelClass { + GstElementClass parent_class; +}; + +GType fs_funnel_get_type (void); + +G_END_DECLS + +#endif /* __FS_FUNNEL_H__ */ diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 25decae8ac..4a2de22f2f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -23,6 +23,7 @@ #include #include +#include "fs-funnel.h" #include "rtsp-media.h" #define DEFAULT_SHARED FALSE @@ -131,6 +132,8 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->unprepare = default_unprepare; ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); + + gst_element_register (NULL, "fsfunnel", GST_RANK_NONE, FS_TYPE_FUNNEL); } static void @@ -1269,8 +1272,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) gst_object_unref (teepad); /* make selector for the RTP receivers */ - stream->selector[0] = gst_element_factory_make ("input-selector", NULL); - g_object_set (stream->selector[0], "select-all", TRUE, NULL); + stream->selector[0] = gst_element_factory_make ("fsfunnel", NULL); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]); pad = gst_element_get_static_pad (stream->selector[0], "src"); @@ -1290,8 +1292,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) gst_object_unref (selpad); /* make selector for the RTCP receivers */ - stream->selector[1] = gst_element_factory_make ("input-selector", NULL); - g_object_set (stream->selector[1], "select-all", TRUE, NULL); + stream->selector[1] = gst_element_factory_make ("fsfunnel", NULL); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]); pad = gst_element_get_static_pad (stream->selector[1], "src"); From e1787e07761d23f625d7814f5b0721ec9aaf979d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 10 Jan 2011 15:10:53 +0100 Subject: [PATCH 0256/1776] funnel: rename fsfunnel to rtspfunnel Rename the funnel to avoid conflicts with the farsight one. --- gst/rtsp-server/Makefile.am | 4 +- .../{fs-funnel.c => rtsp-funnel.c} | 96 ++++++++++--------- .../{fs-funnel.h => rtsp-funnel.h} | 42 ++++---- gst/rtsp-server/rtsp-media.c | 8 +- 4 files changed, 76 insertions(+), 74 deletions(-) rename gst/rtsp-server/{fs-funnel.c => rtsp-funnel.c} (74%) rename gst/rtsp-server/{fs-funnel.h => rtsp-funnel.h} (58%) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index d3819b5cac..50e2718c3a 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -1,5 +1,5 @@ public_headers = \ - fs-funnel.h \ + rtsp-funnel.h \ rtsp-params.h \ rtsp-sdp.h \ rtsp-media.h \ @@ -12,7 +12,7 @@ public_headers = \ rtsp-server.h c_sources = \ - fs-funnel.c \ + rtsp-funnel.c \ rtsp-params.c \ rtsp-sdp.c \ rtsp-media.c \ diff --git a/gst/rtsp-server/fs-funnel.c b/gst/rtsp-server/rtsp-funnel.c similarity index 74% rename from gst/rtsp-server/fs-funnel.c rename to gst/rtsp-server/rtsp-funnel.c index 6c8ac7e890..6f073c1d3a 100644 --- a/gst/rtsp-server/fs-funnel.c +++ b/gst/rtsp-server/rtsp-funnel.c @@ -5,7 +5,7 @@ * @author: Olivier Crete * Copyright 2007 Nokia Corp. * - * fs-funnel.c: Simple Funnel element + * rtsp-funnel.c: Simple Funnel element * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,7 +23,7 @@ */ /** - * SECTION:element-fsfunnel + * SECTION:element-rtspfunnel * @short_description: N-to-1 simple funnel * * Takes packets from various input sinks into one output source @@ -33,12 +33,12 @@ # include "config.h" #endif -#include "fs-funnel.h" +#include "rtsp-funnel.h" -GST_DEBUG_CATEGORY_STATIC (fs_funnel_debug); -#define GST_CAT_DEFAULT fs_funnel_debug +GST_DEBUG_CATEGORY_STATIC (rtsp_funnel_debug); +#define GST_CAT_DEFAULT rtsp_funnel_debug -static const GstElementDetails fs_funnel_details = +static const GstElementDetails rtsp_funnel_details = GST_ELEMENT_DETAILS ("Farsight Funnel pipe fitting", "Generic", "N-to-1 pipe fitting", @@ -60,38 +60,39 @@ GST_STATIC_PAD_TEMPLATE ("src", static void _do_init (GType type) { - GST_DEBUG_CATEGORY_INIT (fs_funnel_debug, "fsfunnel", 0, "fsfunnel element"); + GST_DEBUG_CATEGORY_INIT (rtsp_funnel_debug, "rtspfunnel", 0, + "rtsp funnel element"); } -GST_BOILERPLATE_FULL (FsFunnel, fs_funnel, GstElement, GST_TYPE_ELEMENT, +GST_BOILERPLATE_FULL (RTSPFunnel, rtsp_funnel, GstElement, GST_TYPE_ELEMENT, _do_init); -static GstStateChangeReturn fs_funnel_change_state (GstElement * element, +static GstStateChangeReturn rtsp_funnel_change_state (GstElement * element, GstStateChange transition); -static GstPad *fs_funnel_request_new_pad (GstElement * element, +static GstPad *rtsp_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * name); -static void fs_funnel_release_pad (GstElement * element, GstPad * pad); +static void rtsp_funnel_release_pad (GstElement * element, GstPad * pad); -static GstFlowReturn fs_funnel_chain (GstPad * pad, GstBuffer * buffer); -static gboolean fs_funnel_event (GstPad * pad, GstEvent * event); -static gboolean fs_funnel_src_event (GstPad * pad, GstEvent * event); -static GstCaps *fs_funnel_getcaps (GstPad * pad); +static GstFlowReturn rtsp_funnel_chain (GstPad * pad, GstBuffer * buffer); +static gboolean rtsp_funnel_event (GstPad * pad, GstEvent * event); +static gboolean rtsp_funnel_src_event (GstPad * pad, GstEvent * event); +static GstCaps *rtsp_funnel_getcaps (GstPad * pad); typedef struct { GstSegment segment; -} FsFunnelPadPrivate; +} RTSPFunnelPadPrivate; static void -fs_funnel_base_init (gpointer g_class) +rtsp_funnel_base_init (gpointer g_class) { GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); - gst_element_class_set_details (gstelement_class, &fs_funnel_details); + gst_element_class_set_details (gstelement_class, &rtsp_funnel_details); gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&funnel_sink_template)); @@ -101,7 +102,7 @@ fs_funnel_base_init (gpointer g_class) static void -fs_funnel_dispose (GObject * object) +rtsp_funnel_dispose (GObject * object) { GList *item; @@ -119,44 +120,45 @@ restart: } static void -fs_funnel_class_init (FsFunnelClass * klass) +rtsp_funnel_class_init (RTSPFunnelClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - gobject_class->dispose = GST_DEBUG_FUNCPTR (fs_funnel_dispose); + gobject_class->dispose = GST_DEBUG_FUNCPTR (rtsp_funnel_dispose); gstelement_class->request_new_pad = - GST_DEBUG_FUNCPTR (fs_funnel_request_new_pad); - gstelement_class->release_pad = GST_DEBUG_FUNCPTR (fs_funnel_release_pad); - gstelement_class->change_state = GST_DEBUG_FUNCPTR (fs_funnel_change_state); + GST_DEBUG_FUNCPTR (rtsp_funnel_request_new_pad); + gstelement_class->release_pad = GST_DEBUG_FUNCPTR (rtsp_funnel_release_pad); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (rtsp_funnel_change_state); } static void -fs_funnel_init (FsFunnel * funnel, FsFunnelClass * g_class) +rtsp_funnel_init (RTSPFunnel * funnel, RTSPFunnelClass * g_class) { funnel->srcpad = gst_pad_new_from_static_template (&funnel_src_template, "src"); - gst_pad_set_event_function (funnel->srcpad, fs_funnel_src_event); + gst_pad_set_event_function (funnel->srcpad, rtsp_funnel_src_event); gst_pad_use_fixed_caps (funnel->srcpad); gst_element_add_pad (GST_ELEMENT (funnel), funnel->srcpad); } static GstPad * -fs_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ, +rtsp_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * name) { GstPad *sinkpad; - FsFunnelPadPrivate *priv = g_slice_alloc0 (sizeof (FsFunnelPadPrivate)); + RTSPFunnelPadPrivate *priv = g_slice_alloc0 (sizeof (RTSPFunnelPadPrivate)); GST_DEBUG_OBJECT (element, "requesting pad"); sinkpad = gst_pad_new_from_template (templ, name); - gst_pad_set_chain_function (sinkpad, GST_DEBUG_FUNCPTR (fs_funnel_chain)); - gst_pad_set_event_function (sinkpad, GST_DEBUG_FUNCPTR (fs_funnel_event)); - gst_pad_set_getcaps_function (sinkpad, GST_DEBUG_FUNCPTR (fs_funnel_getcaps)); + gst_pad_set_chain_function (sinkpad, GST_DEBUG_FUNCPTR (rtsp_funnel_chain)); + gst_pad_set_event_function (sinkpad, GST_DEBUG_FUNCPTR (rtsp_funnel_event)); + gst_pad_set_getcaps_function (sinkpad, + GST_DEBUG_FUNCPTR (rtsp_funnel_getcaps)); gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED); gst_pad_set_element_private (sinkpad, priv); @@ -169,25 +171,25 @@ fs_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ, } static void -fs_funnel_release_pad (GstElement * element, GstPad * pad) +rtsp_funnel_release_pad (GstElement * element, GstPad * pad) { - FsFunnel *funnel = FS_FUNNEL (element); - FsFunnelPadPrivate *priv = gst_pad_get_element_private (pad); + RTSPFunnel *funnel = RTSP_FUNNEL (element); + RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad); GST_DEBUG_OBJECT (funnel, "releasing pad"); gst_pad_set_active (pad, FALSE); if (priv) - g_slice_free1 (sizeof (FsFunnelPadPrivate), priv); + g_slice_free1 (sizeof (RTSPFunnelPadPrivate), priv); gst_element_remove_pad (GST_ELEMENT_CAST (funnel), pad); } static GstCaps * -fs_funnel_getcaps (GstPad * pad) +rtsp_funnel_getcaps (GstPad * pad) { - FsFunnel *funnel = FS_FUNNEL (gst_pad_get_parent (pad)); + RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad)); GstCaps *caps; caps = gst_pad_peer_get_caps (funnel->srcpad); @@ -200,11 +202,11 @@ fs_funnel_getcaps (GstPad * pad) } static GstFlowReturn -fs_funnel_chain (GstPad * pad, GstBuffer * buffer) +rtsp_funnel_chain (GstPad * pad, GstBuffer * buffer) { GstFlowReturn res; - FsFunnel *funnel = FS_FUNNEL (gst_pad_get_parent (pad)); - FsFunnelPadPrivate *priv = gst_pad_get_element_private (pad); + RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad)); + RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad); GstEvent *event = NULL; GstClockTime newts; GstCaps *padcaps; @@ -268,10 +270,10 @@ out: } static gboolean -fs_funnel_event (GstPad * pad, GstEvent * event) +rtsp_funnel_event (GstPad * pad, GstEvent * event) { - FsFunnel *funnel = FS_FUNNEL (gst_pad_get_parent (pad)); - FsFunnelPadPrivate *priv = gst_pad_get_element_private (pad); + RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad)); + RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad); gboolean forward = TRUE; gboolean res = TRUE; @@ -319,7 +321,7 @@ fs_funnel_event (GstPad * pad, GstEvent * event) } static gboolean -fs_funnel_src_event (GstPad * pad, GstEvent * event) +rtsp_funnel_src_event (GstPad * pad, GstEvent * event) { GstElement *funnel; GstIterator *iter; @@ -361,7 +363,7 @@ static void reset_pad (gpointer data, gpointer user_data) { GstPad *pad = data; - FsFunnelPadPrivate *priv = gst_pad_get_element_private (pad); + RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad); GST_OBJECT_LOCK (pad); gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED); @@ -370,9 +372,9 @@ reset_pad (gpointer data, gpointer user_data) } static GstStateChangeReturn -fs_funnel_change_state (GstElement * element, GstStateChange transition) +rtsp_funnel_change_state (GstElement * element, GstStateChange transition) { - FsFunnel *funnel = FS_FUNNEL (element); + RTSPFunnel *funnel = RTSP_FUNNEL (element); GstStateChangeReturn ret; switch (transition) { diff --git a/gst/rtsp-server/fs-funnel.h b/gst/rtsp-server/rtsp-funnel.h similarity index 58% rename from gst/rtsp-server/fs-funnel.h rename to gst/rtsp-server/rtsp-funnel.h index c1d5094e46..f762d8161c 100644 --- a/gst/rtsp-server/fs-funnel.h +++ b/gst/rtsp-server/rtsp-funnel.h @@ -5,7 +5,7 @@ * @author: Olivier Crete * Copyright 2007 Nokia Corp. * - * fs-funnel.h: Simple Funnel element + * rtsp-funnel.h: Simple Funnel element * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,33 +23,33 @@ */ -#ifndef __FS_FUNNEL_H__ -#define __FS_FUNNEL_H__ +#ifndef __RTSP_FUNNEL_H__ +#define __RTSP_FUNNEL_H__ #include G_BEGIN_DECLS -#define FS_TYPE_FUNNEL \ - (fs_funnel_get_type ()) -#define FS_FUNNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),FS_TYPE_FUNNEL,FsFunnel)) -#define FS_FUNNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),FS_TYPE_FUNNEL,FsFunnelClass)) -#define FS_IS_FUNNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),FS_TYPE_FUNNEL)) -#define FS_IS_FUNNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),FS_TYPE_FUNNEL)) +#define RTSP_TYPE_FUNNEL \ + (rtsp_funnel_get_type ()) +#define RTSP_FUNNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),RTSP_TYPE_FUNNEL,RTSPFunnel)) +#define RTSP_FUNNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),RTSP_TYPE_FUNNEL,RTSPFunnelClass)) +#define RTSP_IS_FUNNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),RTSP_TYPE_FUNNEL)) +#define RTSP_IS_FUNNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),RTSP_TYPE_FUNNEL)) -typedef struct _FsFunnel FsFunnel; -typedef struct _FsFunnelClass FsFunnelClass; +typedef struct _RTSPFunnel RTSPFunnel; +typedef struct _RTSPFunnelClass RTSPFunnelClass; /** - * FsFunnel: + * RTSPFunnel: * - * Opaque #FsFunnel data structure. + * Opaque #RTSPFunnel data structure. */ -struct _FsFunnel { +struct _RTSPFunnel { GstElement element; /*< private >*/ @@ -58,12 +58,12 @@ struct _FsFunnel { gboolean has_segment; }; -struct _FsFunnelClass { +struct _RTSPFunnelClass { GstElementClass parent_class; }; -GType fs_funnel_get_type (void); +GType rtsp_funnel_get_type (void); G_END_DECLS -#endif /* __FS_FUNNEL_H__ */ +#endif /* __RTSP_FUNNEL_H__ */ diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4a2de22f2f..61d935207c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -23,7 +23,7 @@ #include #include -#include "fs-funnel.h" +#include "rtsp-funnel.h" #include "rtsp-media.h" #define DEFAULT_SHARED FALSE @@ -133,7 +133,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); - gst_element_register (NULL, "fsfunnel", GST_RANK_NONE, FS_TYPE_FUNNEL); + gst_element_register (NULL, "rtspfunnel", GST_RANK_NONE, RTSP_TYPE_FUNNEL); } static void @@ -1272,7 +1272,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) gst_object_unref (teepad); /* make selector for the RTP receivers */ - stream->selector[0] = gst_element_factory_make ("fsfunnel", NULL); + stream->selector[0] = gst_element_factory_make ("rtspfunnel", NULL); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]); pad = gst_element_get_static_pad (stream->selector[0], "src"); @@ -1292,7 +1292,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) gst_object_unref (selpad); /* make selector for the RTCP receivers */ - stream->selector[1] = gst_element_factory_make ("fsfunnel", NULL); + stream->selector[1] = gst_element_factory_make ("rtspfunnel", NULL); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]); pad = gst_element_get_static_pad (stream->selector[1], "src"); From 18b08c1eb640ecb0ea3c084bebe309ddb183a589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 10 Jan 2011 14:56:39 +0000 Subject: [PATCH 0257/1776] Automatic update of common submodule From 46445ad to ccbaa85 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 46445ad50f..ccbaa85fc5 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 46445ad50f184d2640dd205361e0446e9121ba5f +Subproject commit ccbaa85fc58099fb90f1b5a0fad4d92d45500d19 From a1d808e5ea90d18f29637b52df00472d81fb8774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 10 Jan 2011 16:39:36 +0000 Subject: [PATCH 0258/1776] Automatic update of common submodule From ccbaa85 to e572c87 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index ccbaa85fc5..e572c87c58 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit ccbaa85fc58099fb90f1b5a0fad4d92d45500d19 +Subproject commit e572c87c582166a6c65edf2a6a0fa73e31a3b04c From f2ed39c9e674cd6f535e0d1c97a550311dcda32c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 11 Jan 2011 12:58:39 +0100 Subject: [PATCH 0259/1776] docs: We don't build ps/pdf for API reference docs --- docs/libs/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/libs/Makefile.am b/docs/libs/Makefile.am index 71ac2e0e60..574e9e59e9 100644 --- a/docs/libs/Makefile.am +++ b/docs/libs/Makefile.am @@ -8,7 +8,7 @@ DOC_MODULE=$(MODULE) # for upload-doc.mak DOC=$(MODULE) -FORMATS=html ps pdf +FORMATS=html html: html-build.stamp include $(top_srcdir)/common/upload-doc.mak From 2cc9eee3e6f50e153595ace7857c2c71ddab8acf Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 11 Jan 2011 13:01:44 +0100 Subject: [PATCH 0260/1776] gitignore: updates --- .gitignore | 2 ++ docs/.gitignore | 1 + docs/libs/.gitignore | 22 ++++++++++++++++++++++ examples/.gitignore | 1 + gst/rtsp-server/.gitignore | 2 ++ 5 files changed, 28 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/libs/.gitignore create mode 100644 gst/rtsp-server/.gitignore diff --git a/.gitignore b/.gitignore index 16f8566d45..780c799642 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ *~ .deps .libs +ABOUT-NLS INSTALL Makefile Makefile.in @@ -21,6 +22,7 @@ config.guess config.h config.h.in config.log +config.rpath config.status config.sub configure diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000000..e5a7abe44d --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +version.entities diff --git a/docs/libs/.gitignore b/docs/libs/.gitignore new file mode 100644 index 0000000000..511b34c4e1 --- /dev/null +++ b/docs/libs/.gitignore @@ -0,0 +1,22 @@ +*.stamp +html +tmpl +xml +Makefile +Makefile.in +*-decl.txt +*-decl-list.txt +*-presed-scan.c +*-undeclared.txt +*-undocumented.txt +*-unused.txt +*-overrides.txt +*.args +*.hierarchy +*.interfaces +*.prerequisites +*.signals +doc-registry.xml + +*-unused.sgml +*.bak diff --git a/examples/.gitignore b/examples/.gitignore index 653f26db6a..b5dd6b203c 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -4,3 +4,4 @@ test-ogg test-readme test-sdp test-video +test-uri diff --git a/gst/rtsp-server/.gitignore b/gst/rtsp-server/.gitignore new file mode 100644 index 0000000000..f94bcca81a --- /dev/null +++ b/gst/rtsp-server/.gitignore @@ -0,0 +1,2 @@ +GstRtspServer-0.10.gir +GstRtspServer-0.10.typelib From e641e4ed1f78d3be71b89aa8950662f7088fb6a5 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Tue, 11 Jan 2011 15:52:44 +0200 Subject: [PATCH 0261/1776] Automatic update of common submodule From e572c87 to f94d739 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index e572c87c58..f94d739915 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit e572c87c582166a6c65edf2a6a0fa73e31a3b04c +Subproject commit f94d73991563ea2dcae2218b4847e32998f06816 From 28597c913da3acdd9a0dda8ad62977f9b77e282e Mon Sep 17 00:00:00 2001 From: Sreerenj Balachandran Date: Fri, 7 Jan 2011 23:45:32 +0200 Subject: [PATCH 0262/1776] rtsp-media.h: Minor corrections in comments. Fixes #638944 --- gst/rtsp-server/rtsp-media.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 542455421f..33db2f9219 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -90,11 +90,10 @@ struct _GstRTSPMediaTrans { * @srcpad: the srcpad of the stream * @payloader: the payloader of the format * @prepared: if the stream is prepared for streaming - * @server_port: the server udp ports * @recv_rtp_sink: sinkpad for RTP buffers * @recv_rtcp_sink: sinkpad for RTCP buffers - * @recv_rtp_src: srcpad for RTP buffers - * @recv_rtcp_src: srcpad for RTCP buffers + * @send_rtp_src: srcpad for RTP buffers + * @send_rtcp_src: srcpad for RTCP buffers * @udpsrc: the udp source elements for RTP/RTCP * @udpsink: the udp sink elements for RTP/RTCP * @appsrc: the app source elements for RTP/RTCP From da35feb1aa199417abce74f865ec0538a99a2dbc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 11 Jan 2011 22:41:12 +0100 Subject: [PATCH 0263/1776] rtsp: move network includes where they are needed --- gst/rtsp-server/rtsp-client.c | 13 +++++++++++++ gst/rtsp-server/rtsp-client.h | 14 -------------- gst/rtsp-server/rtsp-server.c | 13 +++++++++++++ gst/rtsp-server/rtsp-server.h | 14 -------------- 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 76450a20f1..be193def90 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -17,6 +17,19 @@ * Boston, MA 02111-1307, USA. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "rtsp-client.h" diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 145fdf83ff..59996d5df2 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -17,20 +17,6 @@ * Boston, MA 02111-1307, USA. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 70396aa62b..62547c7916 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -17,6 +17,19 @@ * Boston, MA 02111-1307, USA. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "rtsp-server.h" diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 296e19a1f6..7e36b7f5e7 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -17,20 +17,6 @@ * Boston, MA 02111-1307, USA. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include "rtsp-session-pool.h" From 61bee9985a228428f6cf9b14f4ae8d009bd1f153 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 00:20:36 +0100 Subject: [PATCH 0264/1776] server: move includes back the includes are needed for sockaddr_in. --- gst/rtsp-server/rtsp-server.c | 15 --------------- gst/rtsp-server/rtsp-server.h | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 62547c7916..36c6b52cb1 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -17,21 +17,6 @@ * Boston, MA 02111-1307, USA. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "rtsp-server.h" #include "rtsp-client.h" diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 7e36b7f5e7..296e19a1f6 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -17,6 +17,20 @@ * Boston, MA 02111-1307, USA. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include "rtsp-session-pool.h" From 5fb5f750208c7f35422a7fc3405fdb9b35b86fdc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 00:17:54 +0100 Subject: [PATCH 0265/1776] auth: add authentication object Add an object that can check the authorization of requests. Implement basic authentication. Add example authentication to test-video --- examples/test-video.c | 10 ++ gst/rtsp-server/Makefile.am | 2 + gst/rtsp-server/rtsp-auth.c | 220 ++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-auth.h | 79 ++++++++++++ gst/rtsp-server/rtsp-client.c | 75 ++++++++++++ gst/rtsp-server/rtsp-client.h | 7 ++ gst/rtsp-server/rtsp-server.c | 52 ++++++++ gst/rtsp-server/rtsp-server.h | 7 ++ 8 files changed, 452 insertions(+) create mode 100644 gst/rtsp-server/rtsp-auth.c create mode 100644 gst/rtsp-server/rtsp-auth.h diff --git a/examples/test-video.c b/examples/test-video.c index c4eed533a1..988c1621b4 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -41,6 +41,8 @@ main (int argc, char *argv[]) GstRTSPServer *server; GstRTSPMediaMapping *mapping; GstRTSPMediaFactory *factory; + GstRTSPAuth *auth; + gchar *basic; gst_init (&argc, &argv); @@ -53,6 +55,14 @@ main (int argc, char *argv[]) * that be used to map uri mount points to media factories */ mapping = gst_rtsp_server_get_media_mapping (server); + /* make a new authentication manager */ + auth = gst_rtsp_auth_new (); + basic = gst_rtsp_auth_make_basic ("user", "admin"); + gst_rtsp_auth_set_basic (auth, basic); + g_free (basic); + /* configure in the server */ + gst_rtsp_server_set_auth (server, auth); + /* make a media factory for a test stream. The default media factory can use * gst-launch syntax to create pipelines. * any launch line works as long as it contains elements named pay%d. Each diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 50e2718c3a..ca400c0a1c 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -1,5 +1,6 @@ public_headers = \ rtsp-funnel.h \ + rtsp-auth.h \ rtsp-params.h \ rtsp-sdp.h \ rtsp-media.h \ @@ -13,6 +14,7 @@ public_headers = \ c_sources = \ rtsp-funnel.c \ + rtsp-auth.c \ rtsp-params.c \ rtsp-sdp.c \ rtsp-media.c \ diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c new file mode 100644 index 0000000000..ff83c1be91 --- /dev/null +++ b/gst/rtsp-server/rtsp-auth.c @@ -0,0 +1,220 @@ +/* GStreamer + * Copyright (C) 2010 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "rtsp-auth.h" + +enum +{ + PROP_0, + PROP_LAST +}; + +GST_DEBUG_CATEGORY_STATIC (rtsp_auth_debug); +#define GST_CAT_DEFAULT rtsp_auth_debug + +static void gst_rtsp_auth_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec); +static void gst_rtsp_auth_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec); +static void gst_rtsp_auth_finalize (GObject * obj); + +static gboolean default_check_method (GstRTSPAuth * auth, GstRTSPMethod method, + GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, + GstRTSPMessage * request); + +G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT); + +static void +gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->get_property = gst_rtsp_auth_get_property; + gobject_class->set_property = gst_rtsp_auth_set_property; + gobject_class->finalize = gst_rtsp_auth_finalize; + + klass->check_method = default_check_method; + + GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth"); +} + +static void +gst_rtsp_auth_init (GstRTSPAuth * auth) +{ + /* bitwise or of all methods that need authentication */ + auth->methods = GST_RTSP_DESCRIBE | + GST_RTSP_ANNOUNCE | + GST_RTSP_GET_PARAMETER | + GST_RTSP_SET_PARAMETER | + GST_RTSP_PAUSE | + GST_RTSP_PLAY | GST_RTSP_RECORD | GST_RTSP_SETUP | GST_RTSP_TEARDOWN; +} + +static void +gst_rtsp_auth_finalize (GObject * obj) +{ + GstRTSPAuth *auth = GST_RTSP_AUTH (obj); + + GST_INFO ("finalize auth %p", auth); + + G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj); +} + +static void +gst_rtsp_auth_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec) +{ + GstRTSPAuth *auth = GST_RTSP_AUTH (object); + + switch (propid) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static void +gst_rtsp_auth_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec) +{ + GstRTSPAuth *auth = GST_RTSP_AUTH (object); + + switch (propid) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +/** + * gst_rtsp_auth_new: + * + * Create a new #GstRTSPAuth instance. + * + * Returns: a new #GstRTSPAuth + */ +GstRTSPAuth * +gst_rtsp_auth_new (void) +{ + GstRTSPAuth *result; + + result = g_object_new (GST_TYPE_RTSP_AUTH, NULL); + + return result; +} + +/** + * gst_rtsp_auth_set_basic: + * @auth: a #GstRTSPAuth + * @basic: the basic token + * + * Set the basic token for the default authentication algorithm. + */ +void +gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic) +{ + g_free (auth->basic); + auth->basic = g_strdup (basic); +} + +static gboolean +default_check_method (GstRTSPAuth * auth, GstRTSPMethod method, + GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, + GstRTSPMessage * request) +{ + gboolean result = TRUE; + GstRTSPResult res; + + if (method & auth->methods != 0) { + gchar *authorization; + + result = FALSE; + + res = + gst_rtsp_message_get_header (request, GST_RTSP_HDR_AUTHORIZATION, + &authorization, 0); + if (res < 0) + goto no_auth; + + /* parse type */ + if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) { + GST_DEBUG_OBJECT (auth, "check Basic auth"); + if (auth->basic && strcmp (&authorization[6], auth->basic) == 0) + result = TRUE; + } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) { + GST_DEBUG_OBJECT (auth, "check Digest auth"); + /* not implemented yet */ + result = FALSE; + } + } + return result; + +no_auth: + { + GST_DEBUG_OBJECT (auth, "no authorization header found"); + return FALSE; + } +} + +/** + * gst_rtsp_auth_check_method: + * @auth: a #GstRTSPAuth + * @method: method to check + * @client: the client + * @uri: the requested uri + * @session: the session + * @request: the request + * + * Check if @client is allowed to perform @method for the @uri in + * @session and with @request. + * + * Returns: FALSE if the method is not allowed. + */ +gboolean +gst_rtsp_auth_check_method (GstRTSPAuth * auth, GstRTSPMethod method, + GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, + GstRTSPMessage * request) +{ + gboolean result = FALSE; + GstRTSPAuthClass *klass; + + klass = GST_RTSP_AUTH_GET_CLASS (auth); + + GST_DEBUG_OBJECT (auth, "check method %d", method); + + if (klass->check_method) + result = klass->check_method (auth, method, client, uri, session, request); + + return result; +} + +gchar * +gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass) +{ + gchar *user_pass; + gchar *result; + + user_pass = g_strjoin (":", user, pass, NULL); + result = g_base64_encode ((guchar *) user_pass, strlen (user_pass)); + g_free (user_pass); + + return result; +} diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h new file mode 100644 index 0000000000..85ac733925 --- /dev/null +++ b/gst/rtsp-server/rtsp-auth.h @@ -0,0 +1,79 @@ +/* GStreamer + * Copyright (C) 2010 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#ifndef __GST_RTSP_AUTH_H__ +#define __GST_RTSP_AUTH_H__ + +typedef struct _GstRTSPAuth GstRTSPAuth; +typedef struct _GstRTSPAuthClass GstRTSPAuthClass; + +#include "rtsp-client.h" +#include "rtsp-media-mapping.h" +#include "rtsp-session-pool.h" + +G_BEGIN_DECLS + +#define GST_TYPE_RTSP_AUTH (gst_rtsp_auth_get_type ()) +#define GST_IS_RTSP_AUTH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_AUTH)) +#define GST_IS_RTSP_AUTH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_AUTH)) +#define GST_RTSP_AUTH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuthClass)) +#define GST_RTSP_AUTH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuth)) +#define GST_RTSP_AUTH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_AUTH, GstRTSPAuthClass)) +#define GST_RTSP_AUTH_CAST(obj) ((GstRTSPAuth*)(obj)) +#define GST_RTSP_AUTH_CLASS_CAST(klass) ((GstRTSPAuthClass*)(klass)) + +/** + * GstRTSPAuth: + * + * The authentication structure. + */ +struct _GstRTSPAuth { + GObject parent; + + /*< private >*/ + gchar *basic; + GstRTSPMethod methods; +}; + +struct _GstRTSPAuthClass { + GObjectClass parent_class; + + gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPMethod method, + GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request); +}; + +GType gst_rtsp_auth_get_type (void); + +GstRTSPAuth * gst_rtsp_auth_new (void); + +void gst_rtsp_auth_set_basic (GstRTSPAuth *auth, const gchar * basic); + +gboolean gst_rtsp_auth_check_method (GstRTSPAuth *auth, GstRTSPMethod method, + GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request); + +/* helpers */ +gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass); + +G_END_DECLS + +#endif /* __GST_RTSP_AUTH_H__ */ diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index be193def90..8465a97324 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -252,6 +252,22 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, send_response (client, NULL, &response); } +static gboolean +handle_unauthorized_request (GstRTSPClient * client, GstRTSPUrl * uri, + GstRTSPSession * session, GstRTSPMessage * request) +{ + GstRTSPMessage response = { 0 }; + + gst_rtsp_message_init_response (&response, GST_RTSP_STS_UNAUTHORIZED, + gst_rtsp_status_as_text (GST_RTSP_STS_UNAUTHORIZED), request); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_WWW_AUTHENTICATE, + "Basic "); + + send_response (client, session, &response); + return; +} + + static gboolean compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2) { @@ -1277,6 +1293,12 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) } else session = NULL; + if (client->auth) { + if (!gst_rtsp_auth_check_method (client->auth, method, client, uri, session, + request)) + goto not_authorized; + } + /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: @@ -1330,6 +1352,11 @@ session_not_found: send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); return; } +not_authorized: + { + handle_unauthorized_request (client, uri, session, request); + return; + } } static void @@ -1476,6 +1503,54 @@ gst_rtsp_client_get_media_mapping (GstRTSPClient * client) return result; } +/** + * gst_rtsp_client_set_auth: + * @client: a #GstRTSPClient + * @auth: a #GstRTSPAuth + * + * configure @auth to be used as the authentication manager of @client. + */ +void +gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth) +{ + GstRTSPAuth *old; + + g_return_if_fail (GST_IS_RTSP_CLIENT (client)); + + old = client->auth; + + if (old != auth) { + if (auth) + g_object_ref (auth); + client->auth = auth; + if (old) + g_object_unref (old); + } +} + + +/** + * gst_rtsp_client_get_auth: + * @client: a #GstRTSPClient + * + * Get the #GstRTSPAuth used as the authentication manager of @client. + * + * Returns: the #GstRTSPAuth of @client. g_object_unref() after + * usage. + */ +GstRTSPAuth * +gst_rtsp_client_get_auth (GstRTSPClient * client) +{ + GstRTSPAuth *result; + + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); + + if ((result = client->auth)) + g_object_ref (result); + + return result; +} + static GstRTSPResult message_received (GstRTSPWatch * watch, GstRTSPMessage * message, gpointer user_data) diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 59996d5df2..e6781059c7 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -41,6 +41,8 @@ G_BEGIN_DECLS typedef struct _GstRTSPClient GstRTSPClient; typedef struct _GstRTSPClientClass GstRTSPClientClass; +#include "rtsp-auth.h" + /** * GstRTSPClient: * @@ -68,6 +70,7 @@ struct _GstRTSPClient { GstRTSPSessionPool *session_pool; GstRTSPMediaMapping *media_mapping; + GstRTSPAuth *auth; GstRTSPUrl *uri; GstRTSPMedia *media; @@ -92,6 +95,10 @@ void gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *mapping); GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client); +void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth); +GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); + + gboolean gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 36c6b52cb1..d7a0d1cca3 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -17,6 +17,8 @@ * Boston, MA 02111-1307, USA. */ +#include + #include "rtsp-server.h" #include "rtsp-client.h" @@ -370,6 +372,54 @@ gst_rtsp_server_get_media_mapping (GstRTSPServer * server) return result; } +/** + * gst_rtsp_server_set_auth: + * @server: a #GstRTSPServer + * @auth: a #GstRTSPAuth + * + * configure @auth to be used as the authentication manager of @server. + */ +void +gst_rtsp_server_set_auth (GstRTSPServer * server, GstRTSPAuth * auth) +{ + GstRTSPAuth *old; + + g_return_if_fail (GST_IS_RTSP_SERVER (server)); + + old = server->auth; + + if (old != auth) { + if (auth) + g_object_ref (auth); + server->auth = auth; + if (old) + g_object_unref (old); + } +} + + +/** + * gst_rtsp_server_get_auth: + * @server: a #GstRTSPServer + * + * Get the #GstRTSPAuth used as the authentication manager of @server. + * + * Returns: the #GstRTSPAuth of @server. g_object_unref() after + * usage. + */ +GstRTSPAuth * +gst_rtsp_server_get_auth (GstRTSPServer * server) +{ + GstRTSPAuth *result; + + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + + if ((result = server->auth)) + g_object_ref (result); + + return result; +} + static void gst_rtsp_server_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec) @@ -580,6 +630,8 @@ default_accept_client (GstRTSPServer * server, GIOChannel * channel) gst_rtsp_client_set_session_pool (client, server->session_pool); /* set the media mapping that this client should use */ gst_rtsp_client_set_media_mapping (client, server->media_mapping); + /* set authentication manager */ + gst_rtsp_client_set_auth (client, server->auth); /* accept connections for that client, this function returns after accepting * the connection and will run the remainder of the communication with the diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 296e19a1f6..3354f8ce33 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -37,6 +37,7 @@ #include "rtsp-media-mapping.h" #include "rtsp-media-factory-uri.h" #include "rtsp-client.h" +#include "rtsp-auth.h" #ifndef __GST_RTSP_SERVER_H__ #define __GST_RTSP_SERVER_H__ @@ -75,6 +76,9 @@ struct _GstRTSPServer { /* media mapper for this server */ GstRTSPMediaMapping *media_mapping; + + /* authentication manager */ + GstRTSPAuth *auth; }; /** @@ -110,6 +114,9 @@ GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *serve void gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *mapping); GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *server); +void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); +GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server); + gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, GstRTSPServer *server); From c59d9e2970a9ca78f127e35e78dce808235c6cae Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 00:35:28 +0100 Subject: [PATCH 0266/1776] client: delegate setup of auth to the manager Delegate the configuration of the authentication tokens to the manager object when configured. --- gst/rtsp-server/rtsp-auth.c | 47 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-auth.h | 7 ++++++ gst/rtsp-server/rtsp-client.c | 11 +++++--- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index ff83c1be91..81855c2f83 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -36,6 +36,9 @@ static void gst_rtsp_auth_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_auth_finalize (GObject * obj); +static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, + GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request, + GstRTSPMessage * response); static gboolean default_check_method (GstRTSPAuth * auth, GstRTSPMethod method, GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request); @@ -53,6 +56,7 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) gobject_class->set_property = gst_rtsp_auth_set_property; gobject_class->finalize = gst_rtsp_auth_finalize; + klass->setup_auth = default_setup_auth; klass->check_method = default_check_method; GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth"); @@ -135,6 +139,49 @@ gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic) auth->basic = g_strdup (basic); } +static gboolean +default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, + GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request, + GstRTSPMessage * response) +{ + /* we only have Basic for now */ + gst_rtsp_message_add_header (response, GST_RTSP_HDR_WWW_AUTHENTICATE, + "Basic "); + + return TRUE; +} + +/** + * gst_rtsp_auth_setup_auth: + * @auth: a #GstRTSPAuth + * @client: the client + * @uri: the requested uri + * @session: the session + * @request: the request + * @response: the response + * + * Add authentication tokens to @response. + * + * Returns: FALSE if something is wrong. + */ +gboolean +gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, + GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request, + GstRTSPMessage * response) +{ + gboolean result = FALSE; + GstRTSPAuthClass *klass; + + klass = GST_RTSP_AUTH_GET_CLASS (auth); + + GST_DEBUG_OBJECT (auth, "setup auth"); + + if (klass->setup_auth) + result = klass->setup_auth (auth, client, uri, session, request, response); + + return result; +} + static gboolean default_check_method (GstRTSPAuth * auth, GstRTSPMethod method, GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 85ac733925..786d561e68 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -56,6 +56,10 @@ struct _GstRTSPAuth { struct _GstRTSPAuthClass { GObjectClass parent_class; + gboolean (*setup_auth) (GstRTSPAuth *auth, GstRTSPClient * client, + GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request, + GstRTSPMessage *response); + gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPMethod method, GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request); @@ -67,6 +71,9 @@ GstRTSPAuth * gst_rtsp_auth_new (void); void gst_rtsp_auth_set_basic (GstRTSPAuth *auth, const gchar * basic); +gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth *auth, GstRTSPClient * client, + GstRTSPUrl * uri, GstRTSPSession * session, + GstRTSPMessage * request, GstRTSPMessage *response); gboolean gst_rtsp_auth_check_method (GstRTSPAuth *auth, GstRTSPMethod method, GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request); diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8465a97324..757f08f141 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -252,7 +252,7 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, send_response (client, NULL, &response); } -static gboolean +static void handle_unauthorized_request (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request) { @@ -260,11 +260,14 @@ handle_unauthorized_request (GstRTSPClient * client, GstRTSPUrl * uri, gst_rtsp_message_init_response (&response, GST_RTSP_STS_UNAUTHORIZED, gst_rtsp_status_as_text (GST_RTSP_STS_UNAUTHORIZED), request); - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_WWW_AUTHENTICATE, - "Basic "); + + if (client->auth) { + /* and let the authentication manager setup the auth tokens */ + gst_rtsp_auth_setup_auth (client->auth, client, uri, session, request, + &response); + } send_response (client, session, &response); - return; } From 9f52f281babc9ad4f4de072e6ebf039b3169573a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 10:41:42 +0100 Subject: [PATCH 0267/1776] auth: fix memleak and add some docs Fix a memleak of the basic auth token. Add docs for the helper function --- gst/rtsp-server/rtsp-auth.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 81855c2f83..a113f56b11 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -80,6 +80,7 @@ gst_rtsp_auth_finalize (GObject * obj) GstRTSPAuth *auth = GST_RTSP_AUTH (obj); GST_INFO ("finalize auth %p", auth); + g_free (auth->basic); G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj); } @@ -253,6 +254,16 @@ gst_rtsp_auth_check_method (GstRTSPAuth * auth, GstRTSPMethod method, return result; } +/** + * gst_rtsp_auth_make_basic: + * @user: a userid + * @pass: a password + * + * Construct a Basic authorisation token from @user and @pass. + * + * Returns: the base64 encoding of the string @user:@pass. g_free() + * after usage. + */ gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass) { From 8ccebd90b40311080c4676be16ffbca123f3673c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 10:42:52 +0100 Subject: [PATCH 0268/1776] client: add support for setting the server. Add support for keeping a ref to the server that started this client connection. --- gst/rtsp-server/rtsp-client.c | 41 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-client.h | 17 ++++++++++----- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 757f08f141..3d35618bca 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1461,6 +1461,47 @@ gst_rtsp_client_get_session_pool (GstRTSPClient * client) return result; } +/** + * gst_rtsp_client_set_server: + * @client: a #GstRTSPClient + * @server: a #GstRTSPServer + * + * Set @server as the server that created @client. + */ +void +gst_rtsp_client_set_server (GstRTSPClient * client, GstRTSPServer * server) +{ + GstRTSPServer *old; + + old = client->server; + if (old != server) { + if (server) + g_object_ref (server); + client->server = server; + if (old) + g_object_unref (old); + } +} + +/** + * gst_rtsp_client_get_server: + * @client: a #GstRTSPClient + * + * Get the #GstRTSPServer object that @client was created from. + * + * Returns: a #GstRTSPServer, unref after usage. + */ +GstRTSPServer * +gst_rtsp_client_get_server (GstRTSPClient * client) +{ + GstRTSPServer *result; + + if ((result = client->server)) + g_object_ref (result); + + return result; +} + /** * gst_rtsp_client_set_media_mapping: * @client: a #GstRTSPClient diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index e6781059c7..d4011489af 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -23,11 +23,16 @@ #ifndef __GST_RTSP_CLIENT_H__ #define __GST_RTSP_CLIENT_H__ +G_BEGIN_DECLS + +typedef struct _GstRTSPClient GstRTSPClient; +typedef struct _GstRTSPClientClass GstRTSPClientClass; + +#include "rtsp-server.h" #include "rtsp-media.h" #include "rtsp-media-mapping.h" #include "rtsp-session-pool.h" - -G_BEGIN_DECLS +#include "rtsp-auth.h" #define GST_TYPE_RTSP_CLIENT (gst_rtsp_client_get_type ()) #define GST_IS_RTSP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_CLIENT)) @@ -38,10 +43,6 @@ G_BEGIN_DECLS #define GST_RTSP_CLIENT_CAST(obj) ((GstRTSPClient*)(obj)) #define GST_RTSP_CLIENT_CLASS_CAST(klass) ((GstRTSPClientClass*)(klass)) -typedef struct _GstRTSPClient GstRTSPClient; -typedef struct _GstRTSPClientClass GstRTSPClientClass; - -#include "rtsp-auth.h" /** * GstRTSPClient: @@ -68,6 +69,7 @@ struct _GstRTSPClient { gchar *server_ip; gboolean is_ipv6; + GstRTSPServer *server; GstRTSPSessionPool *session_pool; GstRTSPMediaMapping *media_mapping; GstRTSPAuth *auth; @@ -87,6 +89,9 @@ GType gst_rtsp_client_get_type (void); GstRTSPClient * gst_rtsp_client_new (void); +void gst_rtsp_client_set_server (GstRTSPClient * client, GstRTSPServer * server); +GstRTSPServer * gst_rtsp_client_get_server (GstRTSPClient * client); + void gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool); GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client); From 6d6ba1ee6145f96f21d2341deab4ac5f6f99b07a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 10:57:08 +0100 Subject: [PATCH 0269/1776] server: separate create and accept Create separate create and accept methods so that subclasses can create custom client object. Configure the server in the client object and prepare for keeping track of connected clients. --- gst/rtsp-server/rtsp-server.c | 61 +++++++++++++++++++++++++++-------- gst/rtsp-server/rtsp-server.h | 43 +++++++++++++++--------- 2 files changed, 75 insertions(+), 29 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index d7a0d1cca3..b9ac26c900 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -55,8 +55,9 @@ static void gst_rtsp_server_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_server_finalize (GObject * object); -static GstRTSPClient *default_accept_client (GstRTSPServer * server, - GIOChannel * channel); +static GstRTSPClient *default_create_client (GstRTSPServer * server); +static gboolean default_accept_client (GstRTSPServer * server, + GstRTSPClient * client, GIOChannel * channel); static void gst_rtsp_server_class_init (GstRTSPServerClass * klass) @@ -127,6 +128,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + klass->create_client = default_create_client; klass->accept_client = default_accept_client; GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer"); @@ -135,6 +137,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) static void gst_rtsp_server_init (GstRTSPServer * server) { + server->lock = g_mutex_new (); server->address = g_strdup (DEFAULT_ADDRESS); server->service = g_strdup (DEFAULT_SERVICE); server->backlog = DEFAULT_BACKLOG; @@ -147,6 +150,7 @@ gst_rtsp_server_finalize (GObject * object) { GstRTSPServer *server = GST_RTSP_SERVER (object); + g_mutex_free (server->lock); g_free (server->address); g_free (server->service); @@ -616,10 +620,20 @@ close_error: } } -/* default method for creating a new client object in the server to accept and - * handle a client connection on this server */ +/* add the client to the active list of clients, takes ownership of + * the client */ +static void +manage_client (GstRTSPServer * server, GstRTSPClient * client) +{ + gst_rtsp_client_set_server (client, server); + + /* can unref the client now, when the request is finished, it will be + * unreffed async. */ + gst_object_unref (client); +} + static GstRTSPClient * -default_accept_client (GstRTSPServer * server, GIOChannel * channel) +default_create_client (GstRTSPServer * server) { GstRTSPClient *client; @@ -633,13 +647,22 @@ default_accept_client (GstRTSPServer * server, GIOChannel * channel) /* set authentication manager */ gst_rtsp_client_set_auth (client, server->auth); + return client; +} + +/* default method for creating a new client object in the server to accept and + * handle a client connection on this server */ +static gboolean +default_accept_client (GstRTSPServer * server, GstRTSPClient * client, + GIOChannel * channel) +{ /* accept connections for that client, this function returns after accepting * the connection and will run the remainder of the communication with the * client asyncronously. */ if (!gst_rtsp_client_accept (client, channel)) goto accept_failed; - return client; + return TRUE; /* ERRORS */ accept_failed: @@ -647,8 +670,7 @@ accept_failed: GST_ERROR_OBJECT (server, "Could not accept client on server socket %d: %s (%d)", server->server_sock.fd, g_strerror (errno), errno); - gst_object_unref (client); - return NULL; + return FALSE; } } @@ -666,21 +688,26 @@ gboolean gst_rtsp_server_io_func (GIOChannel * channel, GIOCondition condition, GstRTSPServer * server) { + gboolean result; GstRTSPClient *client = NULL; GstRTSPServerClass *klass; if (condition & G_IO_IN) { klass = GST_RTSP_SERVER_GET_CLASS (server); - /* a new client connected, create a client object to handle the client. */ - if (klass->accept_client) - client = klass->accept_client (server, channel); + if (klass->create_client) + client = klass->create_client (server); if (client == NULL) goto client_failed; - /* can unref the client now, when the request is finished, it will be - * unreffed async. */ - gst_object_unref (client); + /* a new client connected, create a client object to handle the client. */ + if (klass->accept_client) + result = klass->accept_client (server, client, channel); + if (!result) + goto accept_failed; + + /* manage the client connection */ + manage_client (server, client); } else { GST_WARNING_OBJECT (server, "received unknown event %08x", condition); } @@ -692,6 +719,12 @@ client_failed: GST_ERROR_OBJECT (server, "failed to create a client"); return FALSE; } +accept_failed: + { + GST_ERROR_OBJECT (server, "failed to accept client"); + gst_object_unref (client); + return FALSE; + } } /** diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 3354f8ce33..472ca061cc 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -31,19 +31,22 @@ #include #include +#ifndef __GST_RTSP_SERVER_H__ +#define __GST_RTSP_SERVER_H__ + #include +G_BEGIN_DECLS + +typedef struct _GstRTSPServer GstRTSPServer; +typedef struct _GstRTSPServerClass GstRTSPServerClass; + #include "rtsp-session-pool.h" #include "rtsp-media-mapping.h" #include "rtsp-media-factory-uri.h" #include "rtsp-client.h" #include "rtsp-auth.h" -#ifndef __GST_RTSP_SERVER_H__ -#define __GST_RTSP_SERVER_H__ - -G_BEGIN_DECLS - #define GST_TYPE_RTSP_SERVER (gst_rtsp_server_get_type ()) #define GST_IS_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SERVER)) #define GST_IS_RTSP_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SERVER)) @@ -53,16 +56,21 @@ G_BEGIN_DECLS #define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj)) #define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass)) -typedef struct _GstRTSPServer GstRTSPServer; -typedef struct _GstRTSPServerClass GstRTSPServerClass; - +/** + * GstRTSPServer: + * + * This object listens on a port, creates and manages the clients connected to + * it. + */ struct _GstRTSPServer { - GObject parent; + GObject parent; + + GMutex *lock; /* server information */ - gchar *address; - gchar *service; - gint backlog; + gchar *address; + gchar *service; + gint backlog; struct sockaddr_in server_sin; @@ -79,20 +87,25 @@ struct _GstRTSPServer { /* authentication manager */ GstRTSPAuth *auth; + + /* the clients that are connected */ + GList *clients; }; /** * GstRTSPServerClass: * - * @accept_client: Create, configure, accept and return a new GstRTSPClient - * object that handles the new connection on @channel. + * @create_client: Create, configure a new GstRTSPClient + * object that handles the new connection on @channel. + * @accept_client: accept a new GstRTSPClient * * The RTSP server class structure */ struct _GstRTSPServerClass { GObjectClass parent_class; - GstRTSPClient * (*accept_client) (GstRTSPServer *server, GIOChannel *channel); + GstRTSPClient * (*create_client) (GstRTSPServer *server); + gboolean (*accept_client) (GstRTSPServer *server, GstRTSPClient *client, GIOChannel *channel); }; GType gst_rtsp_server_get_type (void); From 515aac7c9f83e9d6a3613a0afcec440715d07b62 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 11:07:26 +0100 Subject: [PATCH 0270/1776] docs: add more docs --- docs/libs/gst-rtsp-server-docs.sgml | 1 + docs/libs/gst-rtsp-server-sections.txt | 28 ++++++++++++++++++++++++++ docs/libs/gst-rtsp-server.types | 1 + 3 files changed, 30 insertions(+) diff --git a/docs/libs/gst-rtsp-server-docs.sgml b/docs/libs/gst-rtsp-server-docs.sgml index 14d3e08472..f78eca7283 100644 --- a/docs/libs/gst-rtsp-server-docs.sgml +++ b/docs/libs/gst-rtsp-server-docs.sgml @@ -19,6 +19,7 @@ + diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index cec65600e2..9ac66c1c30 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -129,6 +129,8 @@ gst_rtsp_server_set_session_pool gst_rtsp_server_get_session_pool gst_rtsp_server_set_media_mapping gst_rtsp_server_get_media_mapping +gst_rtsp_server_get_auth +gst_rtsp_server_set_auth gst_rtsp_server_io_func gst_rtsp_server_get_io_channel gst_rtsp_server_create_watch @@ -212,16 +214,42 @@ GST_IS_RTSP_SESSION_CLASS GST_RTSP_SESSION_GET_CLASS
+
+rtsp-auth +GstRTSPAuth +GstRTSPAuth +GstRTSPAuthClass +gst_rtsp_auth_new +gst_rtsp_auth_set_basic +gst_rtsp_auth_setup_auth +gst_rtsp_auth_check_method +gst_rtsp_auth_make_basic + +GST_IS_RTSP_AUTH +GST_IS_RTSP_AUTH_CLASS +GST_RTSP_AUTH +GST_RTSP_AUTH_CAST +GST_RTSP_AUTH_CLASS +GST_RTSP_AUTH_CLASS_CAST +GST_RTSP_AUTH_GET_CLASS +GST_TYPE_RTSP_AUTH +gst_rtsp_auth_get_type +
+
rtsp-client GstRTSPClient GstRTSPClient GstRTSPClientClass gst_rtsp_client_new +gst_rtsp_client_set_server +gst_rtsp_client_get_server gst_rtsp_client_set_session_pool gst_rtsp_client_get_session_pool gst_rtsp_client_set_media_mapping gst_rtsp_client_get_media_mapping +gst_rtsp_client_set_auth +gst_rtsp_client_get_auth gst_rtsp_client_accept GST_RTSP_CLIENT_CLASS diff --git a/docs/libs/gst-rtsp-server.types b/docs/libs/gst-rtsp-server.types index e87c42564a..37ae5ccfa7 100644 --- a/docs/libs/gst-rtsp-server.types +++ b/docs/libs/gst-rtsp-server.types @@ -1,4 +1,5 @@ #include +gst_rtsp_auth_get_type gst_rtsp_media_mapping_get_type gst_rtsp_media_factory_get_type gst_rtsp_media_get_type From 6915572695b6438b78bfc87abed245b72f951987 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 12:07:04 +0100 Subject: [PATCH 0271/1776] server: unref auth in finalize --- gst/rtsp-server/rtsp-server.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index b9ac26c900..b51569a97d 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -156,6 +156,9 @@ gst_rtsp_server_finalize (GObject * object) g_object_unref (server->session_pool); g_object_unref (server->media_mapping); + + if (server->auth) + g_object_unref (server->auth); } /** From 748d044b623d4d0a8e48e2159fd8f8b1e1383e90 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 12:07:20 +0100 Subject: [PATCH 0272/1776] client: unref auth in finalize --- gst/rtsp-server/rtsp-client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3d35618bca..356f2145d8 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -144,6 +144,8 @@ gst_rtsp_client_finalize (GObject * obj) g_object_unref (client->session_pool); if (client->media_mapping) g_object_unref (client->media_mapping); + if (client->auth) + g_object_unref (client->auth); if (client->uri) gst_rtsp_url_free (client->uri); From 9ea0346d97e6cc19c57783c1a55eb74094ca0084 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 12:07:40 +0100 Subject: [PATCH 0273/1776] media-factory: add methods to configure authorisation --- gst/rtsp-server/rtsp-media-factory.c | 52 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 6 ++++ 2 files changed, 58 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index d5c63bc9c7..dd0ef7987e 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -127,6 +127,8 @@ gst_rtsp_media_factory_finalize (GObject * obj) g_mutex_free (factory->medias_lock); g_free (factory->launch); g_mutex_free (factory->lock); + if (factory->auth) + g_object_unref (factory->auth); G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj); } @@ -326,6 +328,56 @@ gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_set_auth: + * @factory: a #GstRTSPMediaFactory + * @auth: a #GstRTSPAuth + * + * configure @auth to be used as the authentication manager of @factory. + */ +void +gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory, + GstRTSPAuth * auth) +{ + GstRTSPAuth *old; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + old = factory->auth; + + if (old != auth) { + if (auth) + g_object_ref (auth); + factory->auth = auth; + if (old) + g_object_unref (old); + } +} + + +/** + * gst_rtsp_media_factory_get_auth: + * @factory: a #GstRTSPMediaFactory + * + * Get the #GstRTSPAuth used as the authentication manager of @factory. + * + * Returns: the #GstRTSPAuth of @factory. g_object_unref() after + * usage. + */ +GstRTSPAuth * +gst_rtsp_factory_get_auth (GstRTSPMediaFactory * factory) +{ + GstRTSPAuth *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + + if ((result = factory->auth)) + g_object_ref (result); + + return result; +} + + static gboolean compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) { diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 4d6487626e..a06a48d94e 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -21,6 +21,7 @@ #include #include "rtsp-media.h" +#include "rtsp-auth.h" #ifndef __GST_RTSP_MEDIA_FACTORY_H__ #define __GST_RTSP_MEDIA_FACTORY_H__ @@ -62,6 +63,7 @@ struct _GstRTSPMediaFactory { gchar *launch; gboolean shared; gboolean eos_shutdown; + GstRTSPAuth *auth; GMutex *medias_lock; GHashTable *medias; @@ -116,6 +118,10 @@ void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFac gboolean eos_shutdown); gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory *factory, GstRTSPAuth *auth); +GstRTSPAuth * gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory *factory); + + /* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); From 5773df1d52fba53f891c725f666ad8dd903a2e3a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 13:16:08 +0100 Subject: [PATCH 0274/1776] rtsp-server: Pass ClientState structure arround Pass the collected information for the ongoing request in a GstRTSPClientState structure that we can then pass around to simplify the method arguments. This will also be handy when we implement logging functionality. --- gst/rtsp-server/rtsp-auth.c | 49 ++++---- gst/rtsp-server/rtsp-auth.h | 18 +-- gst/rtsp-server/rtsp-client.c | 226 +++++++++++++++++++--------------- gst/rtsp-server/rtsp-client.h | 24 ++++ gst/rtsp-server/rtsp-params.c | 16 +-- gst/rtsp-server/rtsp-params.h | 9 +- 6 files changed, 186 insertions(+), 156 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index a113f56b11..676537b26e 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -37,11 +37,9 @@ static void gst_rtsp_auth_set_property (GObject * object, guint propid, static void gst_rtsp_auth_finalize (GObject * obj); static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request, - GstRTSPMessage * response); -static gboolean default_check_method (GstRTSPAuth * auth, GstRTSPMethod method, - GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, - GstRTSPMessage * request); + GstRTSPClientState * state); +static gboolean default_check_method (GstRTSPAuth * auth, + GstRTSPClient * client, GstRTSPClientState * state); G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT); @@ -142,11 +140,13 @@ gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic) static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request, - GstRTSPMessage * response) + GstRTSPClientState * state) { + if (state->response == NULL) + return FALSE; + /* we only have Basic for now */ - gst_rtsp_message_add_header (response, GST_RTSP_HDR_WWW_AUTHENTICATE, + gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE, "Basic "); return TRUE; @@ -167,8 +167,7 @@ default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, */ gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request, - GstRTSPMessage * response) + GstRTSPClientState * state) { gboolean result = FALSE; GstRTSPAuthClass *klass; @@ -178,26 +177,25 @@ gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, GST_DEBUG_OBJECT (auth, "setup auth"); if (klass->setup_auth) - result = klass->setup_auth (auth, client, uri, session, request, response); + result = klass->setup_auth (auth, client, state); return result; } static gboolean -default_check_method (GstRTSPAuth * auth, GstRTSPMethod method, - GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, - GstRTSPMessage * request) +default_check_method (GstRTSPAuth * auth, GstRTSPClient * client, + GstRTSPClientState * state) { gboolean result = TRUE; GstRTSPResult res; - if (method & auth->methods != 0) { + if (state->method & auth->methods != 0) { gchar *authorization; result = FALSE; res = - gst_rtsp_message_get_header (request, GST_RTSP_HDR_AUTHORIZATION, + gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION, &authorization, 0); if (res < 0) goto no_auth; @@ -225,31 +223,26 @@ no_auth: /** * gst_rtsp_auth_check_method: * @auth: a #GstRTSPAuth - * @method: method to check * @client: the client - * @uri: the requested uri - * @session: the session - * @request: the request + * @state: client state * - * Check if @client is allowed to perform @method for the @uri in - * @session and with @request. + * Check if @client is allowed to perform the actions of @state. * - * Returns: FALSE if the method is not allowed. + * Returns: FALSE if the action is not allowed. */ gboolean -gst_rtsp_auth_check_method (GstRTSPAuth * auth, GstRTSPMethod method, - GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session, - GstRTSPMessage * request) +gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client, + GstRTSPClientState * state) { gboolean result = FALSE; GstRTSPAuthClass *klass; klass = GST_RTSP_AUTH_GET_CLASS (auth); - GST_DEBUG_OBJECT (auth, "check method %d", method); + GST_DEBUG_OBJECT (auth, "check state"); if (klass->check_method) - result = klass->check_method (auth, method, client, uri, session, request); + result = klass->check_method (auth, client, state); return result; } diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 786d561e68..4699dea2e5 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -56,13 +56,8 @@ struct _GstRTSPAuth { struct _GstRTSPAuthClass { GObjectClass parent_class; - gboolean (*setup_auth) (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPUrl * uri, GstRTSPSession * session, GstRTSPMessage * request, - GstRTSPMessage *response); - - gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPMethod method, - GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request); + gboolean (*setup_auth) (GstRTSPAuth *auth, GstRTSPClient * client, GstRTSPClientState *state); + gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPClient * client, GstRTSPClientState *state); }; GType gst_rtsp_auth_get_type (void); @@ -72,12 +67,9 @@ GstRTSPAuth * gst_rtsp_auth_new (void); void gst_rtsp_auth_set_basic (GstRTSPAuth *auth, const gchar * basic); gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPUrl * uri, GstRTSPSession * session, - GstRTSPMessage * request, GstRTSPMessage *response); -gboolean gst_rtsp_auth_check_method (GstRTSPAuth *auth, GstRTSPMethod method, - GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request); - + GstRTSPClientState *state); +gboolean gst_rtsp_auth_check_method (GstRTSPAuth *auth, GstRTSPClient * client, + GstRTSPClientState *state); /* helpers */ gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass); diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 356f2145d8..d73bb493c2 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -244,32 +244,32 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, static void send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, - GstRTSPMessage * request) + GstRTSPClientState * state) { GstRTSPMessage response = { 0 }; gst_rtsp_message_init_response (&response, code, - gst_rtsp_status_as_text (code), request); + gst_rtsp_status_as_text (code), state->request); send_response (client, NULL, &response); } static void -handle_unauthorized_request (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request) +handle_unauthorized_request (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPMessage response = { 0 }; gst_rtsp_message_init_response (&response, GST_RTSP_STS_UNAUTHORIZED, - gst_rtsp_status_as_text (GST_RTSP_STS_UNAUTHORIZED), request); + gst_rtsp_status_as_text (GST_RTSP_STS_UNAUTHORIZED), state->request); + + state->response = &response; if (client->auth) { /* and let the authentication manager setup the auth tokens */ - gst_rtsp_auth_setup_auth (client->auth, client, uri, session, request, - &response); + gst_rtsp_auth_setup_auth (client->auth, client, state); } - send_response (client, session, &response); + send_response (client, state->session, &response); } @@ -289,12 +289,12 @@ compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2) * but is cached for when the same client (without breaking the connection) is * doing a setup for the exact same url. */ static GstRTSPMedia * -find_media (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPMessage * request) +find_media (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPMediaFactory *factory; GstRTSPMedia *media; - if (!compare_uri (client->uri, uri)) { + if (!compare_uri (client->uri, state->uri)) { /* remove any previously cached values before we try to construct a new * media for uri */ if (client->uri) @@ -309,26 +309,31 @@ find_media (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPMessage * request) /* find the factory for the uri first */ if (!(factory = - gst_rtsp_media_mapping_find_factory (client->media_mapping, uri))) + gst_rtsp_media_mapping_find_factory (client->media_mapping, + state->uri))) goto no_factory; + state->factory = factory; + /* prepare the media and add it to the pipeline */ - if (!(media = gst_rtsp_media_factory_construct (factory, uri))) + if (!(media = gst_rtsp_media_factory_construct (factory, state->uri))) goto no_media; /* set ipv6 on the media before preparing */ media->is_ipv6 = client->is_ipv6; + state->media = media; /* prepare the media */ if (!(gst_rtsp_media_prepare (media))) goto no_prepare; /* now keep track of the uri and the media */ - client->uri = gst_rtsp_url_copy (uri); + client->uri = gst_rtsp_url_copy (state->uri); client->media = media; } else { /* we have seen this uri before, used cached media */ media = client->media; + state->media = media; GST_INFO ("reusing cached media %p", media); } @@ -340,23 +345,23 @@ find_media (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPMessage * request) /* ERRORS */ no_mapping: { - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return NULL; } no_factory: { - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return NULL; } no_media: { - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); g_object_unref (factory); return NULL; } no_prepare: { - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); g_object_unref (media); g_object_unref (factory); return NULL; @@ -478,21 +483,25 @@ close_connection (GstRTSPClient * client) } static gboolean -handle_teardown_request (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request) +handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) { + GstRTSPSession *session; GstRTSPSessionMedia *media; GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; - if (!session) + if (!state->session) goto no_session; + session = state->session; + /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, uri); + media = gst_rtsp_session_get_media (session, state->uri); if (!media) goto not_found; + state->sessmedia = media; + /* unlink the all TCP callbacks */ unlink_session_streams (client, session, media); @@ -512,7 +521,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPUrl * uri, /* construct the response now */ code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (&response, code, - gst_rtsp_status_as_text (code), request); + gst_rtsp_status_as_text (code), state->request); gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONNECTION, "close"); @@ -525,103 +534,107 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPUrl * uri, /* ERRORS */ no_session: { - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); return FALSE; } not_found: { - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return FALSE; } } static gboolean -handle_get_param_request (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request) +handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPResult res; guint8 *data; guint size; - res = gst_rtsp_message_get_body (request, &data, &size); + res = gst_rtsp_message_get_body (state->request, &data, &size); if (res != GST_RTSP_OK) goto bad_request; if (size == 0) { /* no body, keep-alive request */ - send_generic_response (client, GST_RTSP_STS_OK, request); + send_generic_response (client, GST_RTSP_STS_OK, state); } else { /* there is a body */ GstRTSPMessage response = { 0 }; + state->response = &response; + /* there is a body, handle the params */ - res = gst_rtsp_params_get (client, uri, session, request, &response); + res = gst_rtsp_params_get (client, state); if (res != GST_RTSP_OK) goto bad_request; - send_response (client, session, &response); + send_response (client, state->session, &response); } return TRUE; /* ERRORS */ bad_request: { - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); return FALSE; } } static gboolean -handle_set_param_request (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request) +handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPResult res; guint8 *data; guint size; - res = gst_rtsp_message_get_body (request, &data, &size); + res = gst_rtsp_message_get_body (state->request, &data, &size); if (res != GST_RTSP_OK) goto bad_request; if (size == 0) { /* no body, keep-alive request */ - send_generic_response (client, GST_RTSP_STS_OK, request); + send_generic_response (client, GST_RTSP_STS_OK, state); } else { GstRTSPMessage response = { 0 }; + state->response = &response; + /* there is a body, handle the params */ - res = gst_rtsp_params_set (client, uri, session, request, &response); + res = gst_rtsp_params_set (client, state); if (res != GST_RTSP_OK) goto bad_request; - send_response (client, session, &response); + send_response (client, state->session, &response); } return TRUE; /* ERRORS */ bad_request: { - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); return FALSE; } } static gboolean -handle_pause_request (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request) +handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) { + GstRTSPSession *session; GstRTSPSessionMedia *media; GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; - if (!session) + if (!(session = state->session)) goto no_session; /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, uri); + media = gst_rtsp_session_get_media (session, state->uri); if (!media) goto not_found; + state->sessmedia = media; + /* the session state must be playing or recording */ if (media->state != GST_RTSP_STATE_PLAYING && media->state != GST_RTSP_STATE_RECORDING) @@ -636,7 +649,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPUrl * uri, /* construct the response now */ code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (&response, code, - gst_rtsp_status_as_text (code), request); + gst_rtsp_status_as_text (code), state->request); send_response (client, session, &response); @@ -648,26 +661,26 @@ handle_pause_request (GstRTSPClient * client, GstRTSPUrl * uri, /* ERRORS */ no_session: { - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); return FALSE; } not_found: { - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return FALSE; } invalid_state: { send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, - request); + state); return FALSE; } } static gboolean -handle_play_request (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request) +handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) { + GstRTSPSession *session; GstRTSPSessionMedia *media; GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; @@ -678,21 +691,24 @@ handle_play_request (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPTimeRange *range; GstRTSPResult res; - if (!session) + if (!(session = state->session)) goto no_session; /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, uri); + media = gst_rtsp_session_get_media (session, state->uri); if (!media) goto not_found; + state->sessmedia = media; + /* the session state must be playing or ready */ if (media->state != GST_RTSP_STATE_PLAYING && media->state != GST_RTSP_STATE_READY) goto invalid_state; /* parse the range header if we have one */ - res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_RANGE, &str, 0); + res = + gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_RANGE, &str, 0); if (res == GST_RTSP_OK) { if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) { /* we have a range, seek to the position */ @@ -741,7 +757,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPUrl * uri, if (infocount > 0) g_string_append (rtpinfo, ", "); - uristr = gst_rtsp_url_get_request_uri (uri); + uristr = gst_rtsp_url_get_request_uri (state->uri); g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", uristr, i, seqnum, timestamp); g_free (uristr); @@ -755,7 +771,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPUrl * uri, /* construct the response now */ code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (&response, code, - gst_rtsp_status_as_text (code), request); + gst_rtsp_status_as_text (code), state->request); /* add the RTP-Info header */ if (infocount > 0) { @@ -781,18 +797,18 @@ handle_play_request (GstRTSPClient * client, GstRTSPUrl * uri, /* ERRORS */ no_session: { - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); return FALSE; } not_found: { - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return FALSE; } invalid_state: { send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, - request); + state); return FALSE; } } @@ -805,10 +821,10 @@ do_keepalive (GstRTSPSession * session) } static gboolean -handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request) +handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPResult res; + GstRTSPUrl *uri; gchar *transport; gchar **transports; gboolean have_transport; @@ -817,12 +833,15 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPLowerTrans supported; GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; + GstRTSPSession *session; GstRTSPSessionStream *stream; gchar *trans_str, *pos; guint streamid; GstRTSPSessionMedia *media; GstRTSPUrl *url; + uri = state->uri; + /* the uri contains the stream number we added in the SDP config, which is * always /stream=%d so we need to strip that off * parse the stream we need to configure, look for the stream in the abspath @@ -841,8 +860,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, /* parse the transport */ res = - gst_rtsp_message_get_header (request, GST_RTSP_HDR_TRANSPORT, &transport, - 0); + gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_TRANSPORT, + &transport, 0); if (res != GST_RTSP_OK) goto no_transport; @@ -903,6 +922,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, ct->destination = g_strdup (url->host); } + session = state->session; + if (session) { g_object_ref (session); /* get a handle to the configuration of the media in the session, this can @@ -914,6 +935,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, if (!(session = gst_rtsp_session_pool_create (client->session_pool))) goto service_unavailable; + state->session = session; + /* we need a new media configuration in this session */ media = NULL; } @@ -923,7 +946,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPMedia *m; /* get a handle to the configuration of the media in the session */ - if ((m = find_media (client, uri, request))) { + if ((m = find_media (client, state))) { /* manage the media in our session now */ media = gst_rtsp_session_manage_media (session, uri, m); } @@ -933,6 +956,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, if (media == NULL) goto not_found; + state->sessmedia = media; + /* fix the transports */ if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) { /* check if the client selected channels for TCP */ @@ -958,7 +983,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, /* construct the response now */ code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (&response, code, - gst_rtsp_status_as_text (code), request); + gst_rtsp_status_as_text (code), state->request); gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str); g_free (trans_str); @@ -983,41 +1008,41 @@ handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri, /* ERRORS */ bad_request: { - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); return FALSE; } not_found: { - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); g_object_unref (session); return FALSE; } no_stream: { - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); g_object_unref (media); g_object_unref (session); return FALSE; } no_transport: { - send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request); + send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); return FALSE; } unsupported_transports: { - send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request); + send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); gst_rtsp_transport_free (ct); return FALSE; } no_pool: { - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); return FALSE; } service_unavailable: { - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); return FALSE; } } @@ -1071,8 +1096,7 @@ no_sdp: /* for the describe we must generate an SDP */ static gboolean -handle_describe_request (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request) +handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPMessage response = { 0 }; GstRTSPResult res; @@ -1087,7 +1111,8 @@ handle_describe_request (GstRTSPClient * client, GstRTSPUrl * uri, gchar *accept; res = - gst_rtsp_message_get_header (request, GST_RTSP_HDR_ACCEPT, &accept, i); + gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_ACCEPT, + &accept, i); if (res == GST_RTSP_ENOTIMPL) break; @@ -1096,7 +1121,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPUrl * uri, } /* find the media object for the uri */ - if (!(media = find_media (client, uri, request))) + if (!(media = find_media (client, state))) goto no_media; /* create an SDP for the media object on this client */ @@ -1106,13 +1131,13 @@ handle_describe_request (GstRTSPClient * client, GstRTSPUrl * uri, g_object_unref (media); gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, - gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); + gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request); gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE, "application/sdp"); /* content base for some clients that might screw up creating the setup uri */ - str = gst_rtsp_url_get_request_uri (uri); + str = gst_rtsp_url_get_request_uri (state->uri); str_len = strlen (str); /* check for trailing '/' and append one */ @@ -1137,7 +1162,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPUrl * uri, gst_rtsp_message_take_body (&response, (guint8 *) str, strlen (str)); gst_sdp_message_free (sdp); - send_response (client, session, &response); + send_response (client, state->session, &response); return TRUE; @@ -1149,15 +1174,14 @@ no_media: } no_sdp: { - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); g_object_unref (media); return FALSE; } } static gboolean -handle_options_request (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request) +handle_options_request (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPMessage response = { 0 }; GstRTSPMethod options; @@ -1173,12 +1197,12 @@ handle_options_request (GstRTSPClient * client, GstRTSPUrl * uri, str = gst_rtsp_options_as_text (options); gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, - gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); + gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request); gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str); g_free (str); - send_response (client, session, &response); + send_response (client, state->session, &response); return TRUE; } @@ -1255,8 +1279,11 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) GstRTSPVersion version; GstRTSPResult res; GstRTSPSession *session; + GstRTSPClientState state = { NULL }; gchar *sessid; + state.request = request; + if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) { gst_rtsp_message_dump (request); } @@ -1268,18 +1295,20 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) if (version != GST_RTSP_VERSION_1_0) { /* we can only handle 1.0 requests */ send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, - request); + &state); return; } + state.method = method; /* we always try to parse the url first */ if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) { - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state); return; } /* sanitize the uri */ sanitize_uri (uri); + state.uri = uri; /* get the session if there is any */ res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); @@ -1298,46 +1327,47 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) } else session = NULL; + state.session = session; + if (client->auth) { - if (!gst_rtsp_auth_check_method (client->auth, method, client, uri, session, - request)) + if (!gst_rtsp_auth_check (client->auth, client, &state)) goto not_authorized; } /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: - handle_options_request (client, uri, session, request); + handle_options_request (client, &state); break; case GST_RTSP_DESCRIBE: - handle_describe_request (client, uri, session, request); + handle_describe_request (client, &state); break; case GST_RTSP_SETUP: - handle_setup_request (client, uri, session, request); + handle_setup_request (client, &state); break; case GST_RTSP_PLAY: - handle_play_request (client, uri, session, request); + handle_play_request (client, &state); break; case GST_RTSP_PAUSE: - handle_pause_request (client, uri, session, request); + handle_pause_request (client, &state); break; case GST_RTSP_TEARDOWN: - handle_teardown_request (client, uri, session, request); + handle_teardown_request (client, &state); break; case GST_RTSP_SET_PARAMETER: - handle_set_param_request (client, uri, session, request); + handle_set_param_request (client, &state); break; case GST_RTSP_GET_PARAMETER: - handle_get_param_request (client, uri, session, request); + handle_get_param_request (client, &state); break; case GST_RTSP_ANNOUNCE: case GST_RTSP_RECORD: case GST_RTSP_REDIRECT: - send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, request); + send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &state); break; case GST_RTSP_INVALID: default: - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state); break; } if (session) @@ -1349,17 +1379,17 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) /* ERRORS */ no_pool: { - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, &state); return; } session_not_found: { - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state); return; } not_authorized: { - handle_unauthorized_request (client, uri, session, request); + handle_unauthorized_request (client, &state); return; } } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index d4011489af..710a7b33f1 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -27,6 +27,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPClient GstRTSPClient; typedef struct _GstRTSPClientClass GstRTSPClientClass; +typedef struct _GstRTSPClientState GstRTSPClientState; #include "rtsp-server.h" #include "rtsp-media.h" @@ -43,6 +44,29 @@ typedef struct _GstRTSPClientClass GstRTSPClientClass; #define GST_RTSP_CLIENT_CAST(obj) ((GstRTSPClient*)(obj)) #define GST_RTSP_CLIENT_CLASS_CAST(klass) ((GstRTSPClientClass*)(klass)) +/** + * GstRTSPClientState: + * @request: the complete request + * @uri: the complete url parsed from @request + * @method: the parsed method of @uri + * @session: the session, can be NULL + * @sessmedia: the session media for the url can be NULL + * @factory: the media factory for the url, can be NULL. + * @media: the session media for the url can be NULL + * @response: the response + * + * Information passed around containing the client state of a request. + */ +struct _GstRTSPClientState{ + GstRTSPMessage *request; + GstRTSPUrl *uri; + GstRTSPMethod method; + GstRTSPSession *session; + GstRTSPSessionMedia *sessmedia; + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPMessage *response; +}; /** * GstRTSPClient: diff --git a/gst/rtsp-server/rtsp-params.c b/gst/rtsp-server/rtsp-params.c index 7f32350e72..95614fdce5 100644 --- a/gst/rtsp-server/rtsp-params.c +++ b/gst/rtsp-server/rtsp-params.c @@ -21,9 +21,7 @@ #include "rtsp-params.h" GstRTSPResult -gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request, - GstRTSPMessage * response) +gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPStatusCode code; @@ -31,16 +29,14 @@ gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri, * with a list of the parameters */ code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD; - gst_rtsp_message_init_response (response, code, - gst_rtsp_status_as_text (code), request); + gst_rtsp_message_init_response (state->response, code, + gst_rtsp_status_as_text (code), state->request); return GST_RTSP_OK; } GstRTSPResult -gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request, - GstRTSPMessage * response) +gst_rtsp_params_get (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPStatusCode code; @@ -48,8 +44,8 @@ gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri, * with a list of the parameters */ code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD; - gst_rtsp_message_init_response (response, code, - gst_rtsp_status_as_text (code), request); + gst_rtsp_message_init_response (state->response, code, + gst_rtsp_status_as_text (code), state->request); return GST_RTSP_OK; } diff --git a/gst/rtsp-server/rtsp-params.h b/gst/rtsp-server/rtsp-params.h index 46903831a3..3b0d001bc3 100644 --- a/gst/rtsp-server/rtsp-params.h +++ b/gst/rtsp-server/rtsp-params.h @@ -30,13 +30,8 @@ G_BEGIN_DECLS -GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request, - GstRTSPMessage * response); - -GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri, - GstRTSPSession * session, GstRTSPMessage * request, - GstRTSPMessage * response); +GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state); +GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPClientState * state); G_END_DECLS From 7797023fda21479a844ed18389c06dca3c7efede Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 13:57:09 +0100 Subject: [PATCH 0275/1776] media: enable per factory authorisations Allow for adding a GstRTSPAuth on the factory and media level and check permissions when accessing the factory. Add hints to the auth methods for future more fine grained authorisation. Add example application for per factory authentication. --- examples/.gitignore | 1 + examples/Makefile.am | 2 +- examples/test-auth.c | 115 +++++++++++++++++++++++++++ examples/test-video.c | 4 + gst/rtsp-server/rtsp-auth.c | 17 ++-- gst/rtsp-server/rtsp-auth.h | 10 ++- gst/rtsp-server/rtsp-client.c | 27 ++++++- gst/rtsp-server/rtsp-media-factory.c | 10 ++- gst/rtsp-server/rtsp-media.c | 48 +++++++++++ gst/rtsp-server/rtsp-media.h | 6 ++ gst/rtsp-server/rtsp-session-pool.h | 9 ++- gst/rtsp-server/rtsp-session.h | 4 +- 12 files changed, 227 insertions(+), 26 deletions(-) create mode 100644 examples/test-auth.c diff --git a/examples/.gitignore b/examples/.gitignore index b5dd6b203c..6912d88c0b 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -5,3 +5,4 @@ test-readme test-sdp test-video test-uri +test-auth diff --git a/examples/Makefile.am b/examples/Makefile.am index 1886511a77..92f6cf4ce8 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,4 +1,4 @@ -noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp test-uri +noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp test-uri test-auth INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/examples/test-auth.c b/examples/test-auth.c new file mode 100644 index 0000000000..915173aa21 --- /dev/null +++ b/examples/test-auth.c @@ -0,0 +1,115 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + + +static gboolean +timeout (GstRTSPServer * server, gboolean ignored) +{ + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_cleanup (pool); + g_object_unref (pool); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMediaMapping *mapping; + GstRTSPMediaFactory *factory; + GstRTSPAuth *auth; + gchar *basic; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mapping for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mapping = gst_rtsp_server_get_media_mapping (server); + + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, "( " + "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " + "x264enc ! rtph264pay name=pay0 pt=96 " + "audiotestsrc ! audio/x-raw-int,rate=8000 ! " + "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); + + /* make a new authentication manager */ + auth = gst_rtsp_auth_new (); + basic = gst_rtsp_auth_make_basic ("user", "admin"); + gst_rtsp_auth_set_basic (auth, basic); + g_free (basic); + gst_rtsp_media_factory_set_auth (factory, auth); + g_object_unref (auth); + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + + /* make another factory */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, "( " + "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=30/1 ! " + "x264enc ! rtph264pay name=pay0 pt=96 )"); + /* make a new authentication manager */ + auth = gst_rtsp_auth_new (); + basic = gst_rtsp_auth_make_basic ("user2", "admin2"); + gst_rtsp_auth_set_basic (auth, basic); + g_free (basic); + gst_rtsp_media_factory_set_auth (factory, auth); + g_object_unref (auth); + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test2", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mapping); + + /* attach the server to the default maincontext */ + if (gst_rtsp_server_attach (server, NULL) == 0) + goto failed; + + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + + /* start serving */ + g_main_loop_run (loop); + + return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } +} diff --git a/examples/test-video.c b/examples/test-video.c index 988c1621b4..41194a098e 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -41,8 +41,10 @@ main (int argc, char *argv[]) GstRTSPServer *server; GstRTSPMediaMapping *mapping; GstRTSPMediaFactory *factory; +#if 0 GstRTSPAuth *auth; gchar *basic; +#endif gst_init (&argc, &argv); @@ -55,6 +57,7 @@ main (int argc, char *argv[]) * that be used to map uri mount points to media factories */ mapping = gst_rtsp_server_get_media_mapping (server); +#if 0 /* make a new authentication manager */ auth = gst_rtsp_auth_new (); basic = gst_rtsp_auth_make_basic ("user", "admin"); @@ -62,6 +65,7 @@ main (int argc, char *argv[]) g_free (basic); /* configure in the server */ gst_rtsp_server_set_auth (server, auth); +#endif /* make a media factory for a test stream. The default media factory can use * gst-launch syntax to create pipelines. diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 676537b26e..84d5c546a9 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -37,9 +37,9 @@ static void gst_rtsp_auth_set_property (GObject * object, guint propid, static void gst_rtsp_auth_finalize (GObject * obj); static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state); + GQuark hint, GstRTSPClientState * state); static gboolean default_check_method (GstRTSPAuth * auth, - GstRTSPClient * client, GstRTSPClientState * state); + GstRTSPClient * client, GQuark hint, GstRTSPClientState * state); G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT); @@ -140,7 +140,7 @@ gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic) static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state) + GQuark hint, GstRTSPClientState * state) { if (state->response == NULL) return FALSE; @@ -167,7 +167,7 @@ default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, */ gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state) + GQuark hint, GstRTSPClientState * state) { gboolean result = FALSE; GstRTSPAuthClass *klass; @@ -177,14 +177,14 @@ gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, GST_DEBUG_OBJECT (auth, "setup auth"); if (klass->setup_auth) - result = klass->setup_auth (auth, client, state); + result = klass->setup_auth (auth, client, hint, state); return result; } static gboolean default_check_method (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state) + GQuark hint, GstRTSPClientState * state) { gboolean result = TRUE; GstRTSPResult res; @@ -224,6 +224,7 @@ no_auth: * gst_rtsp_auth_check_method: * @auth: a #GstRTSPAuth * @client: the client + * @hint: a hint * @state: client state * * Check if @client is allowed to perform the actions of @state. @@ -232,7 +233,7 @@ no_auth: */ gboolean gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state) + GQuark hint, GstRTSPClientState * state) { gboolean result = FALSE; GstRTSPAuthClass *klass; @@ -242,7 +243,7 @@ gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client, GST_DEBUG_OBJECT (auth, "check state"); if (klass->check_method) - result = klass->check_method (auth, client, state); + result = klass->check_method (auth, client, hint, state); return result; } diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 4699dea2e5..3aadeffd67 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -56,8 +56,10 @@ struct _GstRTSPAuth { struct _GstRTSPAuthClass { GObjectClass parent_class; - gboolean (*setup_auth) (GstRTSPAuth *auth, GstRTSPClient * client, GstRTSPClientState *state); - gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPClient * client, GstRTSPClientState *state); + gboolean (*setup_auth) (GstRTSPAuth *auth, GstRTSPClient * client, + GQuark hint, GstRTSPClientState *state); + gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPClient * client, + GQuark hint, GstRTSPClientState *state); }; GType gst_rtsp_auth_get_type (void); @@ -67,9 +69,9 @@ GstRTSPAuth * gst_rtsp_auth_new (void); void gst_rtsp_auth_set_basic (GstRTSPAuth *auth, const gchar * basic); gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPClientState *state); + GQuark hint, GstRTSPClientState *state); gboolean gst_rtsp_auth_check_method (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPClientState *state); + GQuark hint, GstRTSPClientState *state); /* helpers */ gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass); diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d73bb493c2..b829ffa315 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -255,7 +255,8 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, } static void -handle_unauthorized_request (GstRTSPClient * client, GstRTSPClientState * state) +handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth, + GstRTSPClientState * state) { GstRTSPMessage response = { 0 }; @@ -264,9 +265,9 @@ handle_unauthorized_request (GstRTSPClient * client, GstRTSPClientState * state) state->response = &response; - if (client->auth) { + if (auth) { /* and let the authentication manager setup the auth tokens */ - gst_rtsp_auth_setup_auth (client->auth, client, state); + gst_rtsp_auth_setup_auth (auth, client, 0, state); } send_response (client, state->session, &response); @@ -293,6 +294,7 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPMediaFactory *factory; GstRTSPMedia *media; + GstRTSPAuth *auth; if (!compare_uri (client->uri, state->uri)) { /* remove any previously cached values before we try to construct a new @@ -315,10 +317,20 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) state->factory = factory; + /* check if we have access to the factory */ + if ((auth = gst_rtsp_media_factory_get_auth (factory))) { + if (!gst_rtsp_auth_check (auth, client, 0, state)) + goto not_allowed; + + g_object_unref (auth); + } + /* prepare the media and add it to the pipeline */ if (!(media = gst_rtsp_media_factory_construct (factory, state->uri))) goto no_media; + g_object_unref (factory); + /* set ipv6 on the media before preparing */ media->is_ipv6 = client->is_ipv6; state->media = media; @@ -353,6 +365,13 @@ no_factory: send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return NULL; } +not_allowed: + { + handle_unauthorized_request (client, auth, state); + g_object_unref (factory); + g_object_unref (auth); + return NULL; + } no_media: { send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); @@ -1389,7 +1408,7 @@ session_not_found: } not_authorized: { - handle_unauthorized_request (client, &state); + handle_unauthorized_request (client, client->auth, &state); return; } } diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index dd0ef7987e..2fe309d320 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -354,7 +354,6 @@ gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory, } } - /** * gst_rtsp_media_factory_get_auth: * @factory: a #GstRTSPMediaFactory @@ -365,7 +364,7 @@ gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory, * usage. */ GstRTSPAuth * -gst_rtsp_factory_get_auth (GstRTSPMediaFactory * factory) +gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory) { GstRTSPAuth *result; @@ -377,7 +376,6 @@ gst_rtsp_factory_get_auth (GstRTSPMediaFactory * factory) return result; } - static gboolean compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) { @@ -660,6 +658,7 @@ static void default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) { gboolean shared, eos_shutdown; + GstRTSPAuth *auth; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -669,4 +668,9 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_shared (media, shared); gst_rtsp_media_set_eos_shutdown (media, eos_shutdown); + + if ((auth = gst_rtsp_media_factory_get_auth (factory))) { + gst_rtsp_media_set_auth (media, auth); + g_object_unref (auth); + } } diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 61d935207c..cd1e42ab71 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -522,6 +522,54 @@ gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media) return media->eos_shutdown; } +/** + * gst_rtsp_media_set_auth: + * @media: a #GstRTSPMedia + * @auth: a #GstRTSPAuth + * + * configure @auth to be used as the authentication manager of @media. + */ +void +gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth) +{ + GstRTSPAuth *old; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + old = media->auth; + + if (old != auth) { + if (auth) + g_object_ref (auth); + media->auth = auth; + if (old) + g_object_unref (old); + } +} + +/** + * gst_rtsp_media_get_auth: + * @media: a #GstRTSPMedia + * + * Get the #GstRTSPAuth used as the authentication manager of @media. + * + * Returns: the #GstRTSPAuth of @media. g_object_unref() after + * usage. + */ +GstRTSPAuth * +gst_rtsp_media_get_auth (GstRTSPMedia * media) +{ + GstRTSPAuth *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + + if ((result = media->auth)) + g_object_ref (result); + + return result; +} + + /** * gst_rtsp_media_n_streams: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 33db2f9219..a62390ae37 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -85,6 +85,8 @@ struct _GstRTSPMediaTrans { GObject *rtpsource; }; +#include "rtsp-auth.h" + /** * GstRTSPMediaStream: * @srcpad: the srcpad of the stream @@ -204,6 +206,7 @@ struct _GstRTSPMedia { gboolean reused; gboolean is_ipv6; gboolean eos_shutdown; + GstRTSPAuth *auth; GstElement *element; GArray *streams; @@ -277,6 +280,9 @@ GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia *media); void gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown); gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media); +void gst_rtsp_media_set_auth (GstRTSPMedia *media, GstRTSPAuth *auth); +GstRTSPAuth * gst_rtsp_media_get_auth (GstRTSPMedia *media); + /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media); diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 865b16baee..3cd56d4ef8 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -22,10 +22,14 @@ #ifndef __GST_RTSP_SESSION_POOL_H__ #define __GST_RTSP_SESSION_POOL_H__ -#include "rtsp-session.h" G_BEGIN_DECLS +typedef struct _GstRTSPSessionPool GstRTSPSessionPool; +typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; + +#include "rtsp-session.h" + #define GST_TYPE_RTSP_SESSION_POOL (gst_rtsp_session_pool_get_type ()) #define GST_IS_RTSP_SESSION_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SESSION_POOL)) #define GST_IS_RTSP_SESSION_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SESSION_POOL)) @@ -35,9 +39,6 @@ G_BEGIN_DECLS #define GST_RTSP_SESSION_POOL_CAST(obj) ((GstRTSPSessionPool*)(obj)) #define GST_RTSP_SESSION_POOL_CLASS_CAST(klass) ((GstRTSPSessionPoolClass*)(klass)) -typedef struct _GstRTSPSessionPool GstRTSPSessionPool; -typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; - /** * GstRTSPSessionPool: * @max_sessions: the maximum number of sessions. diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 00bc3f3d64..07efb1958d 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -21,8 +21,6 @@ #include -#include "rtsp-media.h" - #ifndef __GST_RTSP_SESSION_H__ #define __GST_RTSP_SESSION_H__ @@ -43,6 +41,8 @@ typedef struct _GstRTSPSessionClass GstRTSPSessionClass; typedef struct _GstRTSPSessionStream GstRTSPSessionStream; typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia; +#include "rtsp-media.h" + /** * GstRTSPSessionStream: * @trans: the media transport From 4a4a15077b67cc2374ab1df5b7e385949685cffb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 15:35:51 +0100 Subject: [PATCH 0276/1776] client: emit signal when closing --- gst/rtsp-server/rtsp-client.c | 14 ++++++++++++++ gst/rtsp-server/rtsp-client.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b829ffa315..8e9b026d72 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -50,9 +50,17 @@ enum PROP_LAST }; +enum +{ + SIGNAL_CLOSED, + SIGNAL_LAST +}; + GST_DEBUG_CATEGORY_STATIC (rtsp_client_debug); #define GST_CAT_DEFAULT rtsp_client_debug +static guint gst_rtsp_client_signals[SIGNAL_LAST] = { 0 }; + static void gst_rtsp_client_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec); static void gst_rtsp_client_set_property (GObject * object, guint propid, @@ -89,6 +97,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_client_signals[SIGNAL_CLOSED] = + g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); tunnels_lock = g_mutex_new (); @@ -1882,6 +1895,7 @@ client_watch_notify (GstRTSPClient * client) GST_INFO ("client %p: watch destroyed", client); client->watchid = 0; client->watch = NULL; + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL); g_object_unref (client); } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 710a7b33f1..dc2c79c088 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -107,6 +107,9 @@ struct _GstRTSPClient { struct _GstRTSPClientClass { GObjectClass parent_class; + + /* signals */ + void (*closed) (GstRTSPClient *client); }; GType gst_rtsp_client_get_type (void); From 318b3a1df4803933aed6a2872b3fe35578381a74 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 15:36:22 +0100 Subject: [PATCH 0277/1776] server: use signal to keep track of clients Keep track of all the clients that the server creates and remove them when they fire the 'closed' signal. --- gst/rtsp-server/rtsp-server.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index b51569a97d..0d5dc57200 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -623,16 +623,30 @@ close_error: } } +static void +unmanage_client (GstRTSPClient * client, GstRTSPServer * server) +{ + GST_DEBUG_OBJECT (server, "unmanage client %p", client); + + g_mutex_lock (server->lock); + server->clients = g_list_remove (server->clients, client); + g_mutex_unlock (server->lock); + + g_object_unref (client); +} + /* add the client to the active list of clients, takes ownership of * the client */ static void manage_client (GstRTSPServer * server, GstRTSPClient * client) { + GST_DEBUG_OBJECT (server, "manage client %p", client); gst_rtsp_client_set_server (client, server); - /* can unref the client now, when the request is finished, it will be - * unreffed async. */ - gst_object_unref (client); + g_mutex_lock (server->lock); + g_signal_connect (client, "closed", (GCallback) unmanage_client, server); + server->clients = g_list_prepend (server->clients, client); + g_mutex_unlock (server->lock); } static GstRTSPClient * From df0e2c28590899a30ddac7484cc63825c1290170 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 15:37:39 +0100 Subject: [PATCH 0278/1776] client: use the response from the clientstate Create the response object only once and store in the client state. Make all methods use the state response, --- gst/rtsp-server/rtsp-client.c | 77 ++++++++++++++--------------------- 1 file changed, 30 insertions(+), 47 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8e9b026d72..6ddcb57444 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -259,31 +259,25 @@ static void send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, GstRTSPClientState * state) { - GstRTSPMessage response = { 0 }; - - gst_rtsp_message_init_response (&response, code, + gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); - send_response (client, NULL, &response); + send_response (client, NULL, state->response); } static void handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth, GstRTSPClientState * state) { - GstRTSPMessage response = { 0 }; - - gst_rtsp_message_init_response (&response, GST_RTSP_STS_UNAUTHORIZED, + gst_rtsp_message_init_response (state->response, GST_RTSP_STS_UNAUTHORIZED, gst_rtsp_status_as_text (GST_RTSP_STS_UNAUTHORIZED), state->request); - state->response = &response; - if (auth) { /* and let the authentication manager setup the auth tokens */ gst_rtsp_auth_setup_auth (auth, client, 0, state); } - send_response (client, state->session, &response); + send_response (client, state->session, state->response); } @@ -519,7 +513,6 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPSession *session; GstRTSPSessionMedia *media; - GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; if (!state->session) @@ -552,12 +545,13 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) } /* construct the response now */ code = GST_RTSP_STS_OK; - gst_rtsp_message_init_response (&response, code, + gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONNECTION, "close"); + gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONNECTION, + "close"); - send_response (client, session, &response); + send_response (client, session, state->response); close_connection (client); @@ -591,17 +585,12 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state) /* no body, keep-alive request */ send_generic_response (client, GST_RTSP_STS_OK, state); } else { - /* there is a body */ - GstRTSPMessage response = { 0 }; - - state->response = &response; - /* there is a body, handle the params */ res = gst_rtsp_params_get (client, state); if (res != GST_RTSP_OK) goto bad_request; - send_response (client, state->session, &response); + send_response (client, state->session, state->response); } return TRUE; @@ -628,16 +617,12 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state) /* no body, keep-alive request */ send_generic_response (client, GST_RTSP_STS_OK, state); } else { - GstRTSPMessage response = { 0 }; - - state->response = &response; - /* there is a body, handle the params */ res = gst_rtsp_params_set (client, state); if (res != GST_RTSP_OK) goto bad_request; - send_response (client, state->session, &response); + send_response (client, state->session, state->response); } return TRUE; @@ -654,7 +639,6 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPSession *session; GstRTSPSessionMedia *media; - GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; if (!(session = state->session)) @@ -680,10 +664,10 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) /* construct the response now */ code = GST_RTSP_STS_OK; - gst_rtsp_message_init_response (&response, code, + gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); - send_response (client, session, &response); + send_response (client, session, state->response); /* the state is now READY */ media->state = GST_RTSP_STATE_READY; @@ -714,7 +698,6 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPSession *session; GstRTSPSessionMedia *media; - GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; GString *rtpinfo; guint n_streams, i, infocount; @@ -802,22 +785,22 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) /* construct the response now */ code = GST_RTSP_STS_OK; - gst_rtsp_message_init_response (&response, code, + gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); /* add the RTP-Info header */ if (infocount > 0) { str = g_string_free (rtpinfo, FALSE); - gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RTP_INFO, str); + gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RTP_INFO, str); } else { g_string_free (rtpinfo, TRUE); } /* add the range */ str = gst_rtsp_media_get_range_string (media->media, TRUE); - gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RANGE, str); + gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str); - send_response (client, session, &response); + send_response (client, session, state->response); /* start playing after sending the request */ gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING); @@ -863,7 +846,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPTransport *ct, *st; gint i; GstRTSPLowerTrans supported; - GstRTSPMessage response = { 0 }; GstRTSPStatusCode code; GstRTSPSession *session; GstRTSPSessionStream *stream; @@ -1014,13 +996,14 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) /* construct the response now */ code = GST_RTSP_STS_OK; - gst_rtsp_message_init_response (&response, code, + gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str); + gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_TRANSPORT, + trans_str); g_free (trans_str); - send_response (client, session, &response); + send_response (client, session, state->response); /* update the state */ switch (media->state) { @@ -1130,7 +1113,6 @@ no_sdp: static gboolean handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) { - GstRTSPMessage response = { 0 }; GstRTSPResult res; GstSDPMessage *sdp; guint i, str_len; @@ -1162,10 +1144,10 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) g_object_unref (media); - gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, + gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request); - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE, + gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_TYPE, "application/sdp"); /* content base for some clients that might screw up creating the setup uri */ @@ -1185,16 +1167,16 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) GST_INFO ("adding content-base: %s", content_base); - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_BASE, + gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_BASE, content_base); g_free (content_base); /* add SDP to the response body */ str = gst_sdp_message_as_text (sdp); - gst_rtsp_message_take_body (&response, (guint8 *) str, strlen (str)); + gst_rtsp_message_take_body (state->response, (guint8 *) str, strlen (str)); gst_sdp_message_free (sdp); - send_response (client, state->session, &response); + send_response (client, state->session, state->response); return TRUE; @@ -1215,7 +1197,6 @@ no_sdp: static gboolean handle_options_request (GstRTSPClient * client, GstRTSPClientState * state) { - GstRTSPMessage response = { 0 }; GstRTSPMethod options; gchar *str; @@ -1228,13 +1209,13 @@ handle_options_request (GstRTSPClient * client, GstRTSPClientState * state) str = gst_rtsp_options_as_text (options); - gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, + gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request); - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str); + gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_PUBLIC, str); g_free (str); - send_response (client, state->session, &response); + send_response (client, state->session, state->response); return TRUE; } @@ -1312,9 +1293,11 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) GstRTSPResult res; GstRTSPSession *session; GstRTSPClientState state = { NULL }; + GstRTSPMessage response = { 0 }; gchar *sessid; state.request = request; + state.response = &response; if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) { gst_rtsp_message_dump (request); From 165a2959ee8fa5137edf96f3c9f75937687f605a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Dieb=20Martins?= Date: Tue, 21 Sep 2010 17:04:02 -0300 Subject: [PATCH 0279/1776] gst-rtsp-server: update python bindings --- bindings/python/rtspserver-types.defs | 57 +++++ bindings/python/rtspserver.defs | 347 ++++++++++++++++++++++++++ bindings/python/rtspserver.override | 47 ++-- bindings/python/test.py | 130 ++++++++++ 4 files changed, 565 insertions(+), 16 deletions(-) create mode 100644 bindings/python/test.py diff --git a/bindings/python/rtspserver-types.defs b/bindings/python/rtspserver-types.defs index 133ed8ff87..04949afe48 100644 --- a/bindings/python/rtspserver-types.defs +++ b/bindings/python/rtspserver-types.defs @@ -1,6 +1,63 @@ +;; From gst/rtsp-server/rtsp-server.h + (define-object Server (in-module "Gst.RTSPServer") (parent "GObject") (c-name "GstRTSPServer") (gtype-id "GST_TYPE_RTSP_SERVER") ) + +;; From gst/rtsp-server/rtsp-media-mapping.h + +(define-object MediaMapping + (in-module "Gst.RTSPServer") + (parent "GObject") + (c-name "GstRTSPMediaMapping") + (gtype-id "GST_TYPE_RTSP_MEDIA_MAPPING") +) + +;; From gst/rtsp-server/rtsp-media-factory.h + +(define-object MediaFactory + (in-module "Gst.RTSPServer") + (parent "GObject") + (c-name "GstRTSPMediaFactory") + (gtype-id "GST_TYPE_RTSP_MEDIA_FACTORY") +) + +;; From gst/rtsp-server/rtsp-media.h + +(define-object Media + (in-module "Gst.RTSPServer") + (parent "GObject") + (c-name "GstRTSPMedia") + (gtype-id "GST_TYPE_RTSP_MEDIA") +) + +;; From gst/rtsp-server/rtsp-session-pool.h + +(define-object SessionPool + (in-module "Gst") + (parent "GObject") + (c-name "GstRTSPSessionPool") + (gtype-id "GST_TYPE_RTSP_SESSION_POOL") +) + +;; From gst/rtsp-server/rtsp-session.h + +(define-object Session + (in-module "Gst") + (parent "GObject") + (c-name "GstRTSPSession") + (gtype-id "GST_TYPE_RTSP_SESSION") +) + +;; From gst/rtsp-server/rtsp-client.h + +(define-object Client + (in-module "Gst") + (parent "GObject") + (c-name "GstRTSPClient") + (gtype-id "GST_TYPE_RTSP_CLIENT") +) + diff --git a/bindings/python/rtspserver.defs b/bindings/python/rtspserver.defs index 4442f9fcfb..25d190b520 100644 --- a/bindings/python/rtspserver.defs +++ b/bindings/python/rtspserver.defs @@ -1,11 +1,99 @@ (include "rtspserver-types.defs") +;; From gst/rtsp-server/rtsp-server.h + (define-function rtsp_server_new (c-name "gst_rtsp_server_new") (is-constructor-of "GstRTSPServer") (return-type "GstRTSPServer*") ) +(define-method set_address + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_set_address") + (parameters + '("const-gchar*" "address") + ) +) + +(define-method get_address + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_get_address") + (return-type "const-gchar*") +) + +(define-method set_service + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_set_service") + (parameters + '("const-gchar*" "service") + ) +) + +(define-method get_service + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_get_service") + (return-type "const-gchar*") +) + +(define-method set_backlog + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_set_backlog") + (parameters + '("gint" "backlog") + ) +) + +(define-method get_backlog + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_get_backlog") + (return-type "gint") +) + +(define-method set_session_pool + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_set_session_pool") + (parameters + '("GstRTSPSessionPool*" "pool") + ) +) + +(define-method get_session_pool + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_get_session_pool") + (return-type "GstRTSPSessionPool*") +) + +(define-method set_media_mapping + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_set_media_mapping") + (parameters + '("GstRTSPMediaMapping*" "mapping") + ) +) + +(define-method get_media_mapping + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_get_media_mapping") + (return-type "GstRTSPMediaMapping*") +) + +(define-function io_func + (c-name "gst_rtsp_server_io_func") + (return-type "gboolean") + (parameters + '("GIOChannel*" "channel") + '("GIOCondition" "condition") + '("GstRTSPServer*" "server") + ) +) + +(define-method get_io_channel + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_get_io_channel") + (return-type "GIOChannel*") +) + (define-method attach (of-object "GstRTSPServer") (c-name "gst_rtsp_server_attach") @@ -14,3 +102,262 @@ '("GMainContext*" "context") ) ) + +(define-method create_watch + (of-object "GstRTSPServer") + (c-name "gst_rtsp_server_create_watch") + (return-type "GSource*") +) + +;; From gst/rtsp-server/rtsp-media-mapping.h + +(define-function rtsp_media_mapping_new + (c-name "gst_rtsp_media_mapping_new") + (is-constructor-of "GstRTSPMediaMapping") + (return-type "GstRTSPMediaMapping*") +) + + +;; TODO define const-GstRTSPUrl* on arg-types.py +(define-method find_factory + (of-object "GstRTSPMediaMapping") + (c-name "gst_rtsp_media_mapping_find_factory") + (return-type "GstRTSPMediaFactory*") + (parameters + '("const-GstRTSPUrl*" "url") + ) +) + +(define-method add_factory + (of-object "GstRTSPMediaMapping") + (c-name "gst_rtsp_media_mapping_add_factory") + (parameters + '("const-gchar*" "path") + '("GstRTSPMediaFactory*" "factory") + ) +) + +(define-method remove_factory + (of-object "GstRTSPMediaMapping") + (c-name "gst_rtsp_media_mapping_remove_factory") + (parameters + '("const-gchar*" "path") + ) +) + +;; From gst/rtsp-server/rtsp-media-factory.h + +(define-function rtsp_media_factory_new + (c-name "gst_rtsp_media_factory_new") + (is-constructor-of "GstRTSMediaFactory") + (return-type "GstRTSPMediaFactory*") +) + +(define-method set_launch + (of-object "GstRTSPMediaFactory") + (c-name "gst_rtsp_media_factory_set_launch") + (parameters + '("gchar*" "launch") + ) +) + +(define-method get_launch + (of-object "GstRTSPMediaFactory") + (c-name "gst_rtsp_media_factory_get_launch") + (return-type "gchar*") +) + +(define-method set_shared + (of-object "GstRTSPMediaFactory") + (c-name "gst_rtsp_media_factory_set_shared") + (parameters + '("gboolean" "shared") + ) +) + +(define-method is_shared + (of-object "GstRTSPMediaFactory") + (c-name "gst_rtsp_media_factory_is_shared") + (return-type "gboolean") +) + +(define-method set_eos_shutdown + (of-object "GstRTSPMediaFactory") + (c-name "gst_rtsp_media_factory_set_eos_shutdown") + (parameters + '("gboolean" "eos_shutdown") + ) +) + +(define-method is_eos_shutdown + (of-object "GstRTSPMediaFactory") + (c-name "gst_rtsp_media_factory_is_eos_shutdown") + (return-type "gboolean") +) + +;; TODO define const-GstRTSPUrl* on arg-types.py +(define-method construct + (of-object "GstRTSPMediaFactory") + (c-name "gst_rtsp_media_factory_construct") + (return-type "GstRTSPMedia*") + (parameters + '("const-GstRTSPUrl*" "url") + ) +) + +(define-method collect_streams + (of-object "GstRTSPMediaFactory") + (c-name "gst_rtsp_media_factory_construct") + (parameters + '("const-GstRTSPUrl*" "url") + '("GstRTSPMedia*" "media") + ) +) + +;; From gst/rtsp-server/rtsp-session-pool.h + +(define-function gst_rtsp_session_pool_new + (c-name "gst_rtsp_session_pool_new") + (is-constructor-of "GstRTSPSessionPool") + (return-type "GstRTSPSessionPool*") +) + +(define-method set_max_sessions + (of-object "GstRTSPSessionPool") + (c-name "gst_rtsp_session_pool_set_max_sessions") + (return-type "none") + (parameters + '("guint" "max") + ) +) + +(define-method get_max_sessions + (of-object "GstRTSPSessionPool") + (c-name "gst_rtsp_session_pool_get_max_sessions") + (return-type "guint") +) + +(define-method get_n_sessions + (of-object "GstRTSPSessionPool") + (c-name "gst_rtsp_session_pool_get_n_sessions") + (return-type "guint") +) + +(define-method create + (of-object "GstRTSPSessionPool") + (c-name "gst_rtsp_session_pool_create") + (return-type "GstRTSPSession*") +) + +(define-method find + (of-object "GstRTSPSessionPool") + (c-name "gst_rtsp_session_pool_find") + (return-type "GstRTSPSession*") + (parameters + '("const-gchar*" "sessionid") + ) +) + +(define-method remove + (of-object "GstRTSPSessionPool") + (c-name "gst_rtsp_session_pool_remove") + (return-type "gboolean") + (parameters + '("GstRTSPSession*" "sess") + ) +) + +(define-method filter + (of-object "GstRTSPSessionPool") + (c-name "gst_rtsp_session_pool_filter") + (return-type "GList*") + (parameters + '("GstRTSPSessionFilterFunc" "func") + '("gpointer" "user_data") + ) +) + +(define-method cleanup + (of-object "GstRTSPSessionPool") + (c-name "gst_rtsp_session_pool_cleanup") + (return-type "guint") +) + +(define-method create_watch + (of-object "GstRTSPSessionPool") + (c-name "gst_rtsp_session_pool_create_watch") + (return-type "GSource*") +) + +;; From gst/rtsp-server/rtsp-client.h + +(define-function gst_rtsp_client_new + (c-name "gst_rtsp_client_new") + (is-constructor-of "GstRTSPClient") + (return-type "GstRTSPClient*") +) + +(define-method set_session_pool + (of-object "GstRTSPClient") + (c-name "gst_rtsp_client_set_session_pool") + (return-type "none") + (parameters + '("GstRTSPSessionPool*" "pool") + ) +) + +(define-method get_session_pool + (of-object "GstRTSPClient") + (c-name "gst_rtsp_client_get_session_pool") + (return-type "GstRTSPSessionPool*") +) + +(define-method set_media_mapping + (of-object "GstRTSPClient") + (c-name "gst_rtsp_client_set_media_mapping") + (return-type "none") + (parameters + '("GstRTSPMediaMapping*" "mapping") + ) +) + +(define-method get_media_mapping + (of-object "GstRTSPClient") + (c-name "gst_rtsp_client_get_media_mapping") + (return-type "GstRTSPMediaMapping*") +) + +(define-method accept + (of-object "GstRTSPClient") + (c-name "gst_rtsp_client_accept") + (return-type "gboolean") + (parameters + '("GIOChannel*" "channel") + ) +) + +;; From bindings/python/rtsp-params.h + +(define-function gst_rtsp_params_set + (c-name "gst_rtsp_params_set") + (return-type "GstRTSPResult") + (parameters + '("GstRTSPClient*" "client") + '("GstRTSPUrl*" "uri") + '("GstRTSPSession*" "session") + '("GstRTSPMessage*" "request") + '("GstRTSPMessage*" "response") + ) +) + +(define-function gst_rtsp_params_get + (c-name "gst_rtsp_params_get") + (return-type "GstRTSPResult") + (parameters + '("GstRTSPClient*" "client") + '("GstRTSPUrl*" "uri") + '("GstRTSPSession*" "session") + '("GstRTSPMessage*" "request") + '("GstRTSPMessage*" "response") + ) +) diff --git a/bindings/python/rtspserver.override b/bindings/python/rtspserver.override index 3cab9d6635..eda93e89ed 100644 --- a/bindings/python/rtspserver.override +++ b/bindings/python/rtspserver.override @@ -5,6 +5,11 @@ headers #define NO_IMPORT_PYGOBJECT #include +#include +#include + +#include + #ifdef HAVE_CONFIG_H # include #endif @@ -24,29 +29,39 @@ typedef struct { %% import gobject.GObject as PyGObject_Type import gobject.MainContext as PyGMainContext_Type - %% override gst_rtsp_server_attach kwargs static PyObject * _wrap_gst_rtsp_server_attach (PyGObject *self, - PyObject *args, PyObject *keywords) + PyObject *args, PyObject *keywords) { - static char *kwlist[] = {"context", NULL}; - PyGMainContext *py_context = NULL; - GMainContext *context = NULL; - guint res; + static char *kwlist[] = {"context", NULL}; + PyGMainContext *py_context = NULL; + GMainContext *context = NULL; + guint res; - if (!PyArg_ParseTupleAndKeywords (args, keywords, - "|O!:GstRTSPServer.__init__", kwlist, - &PyGMainContext_Type, &py_context)) - return NULL; + if (!PyArg_ParseTupleAndKeywords (args, keywords, + "|O!:GstRTSPServer.__init__", kwlist, + &PyGMainContext_Type, &py_context)) + return NULL; - if (py_context) - context = py_context->context; + if (py_context) + context = py_context->context; - pyg_begin_allow_threads; - res = gst_rtsp_server_attach (GST_RTSP_SERVER (self->obj), context); - pyg_end_allow_threads; + pyg_begin_allow_threads; + res = gst_rtsp_server_attach (GST_RTSP_SERVER (self->obj), context); + pyg_end_allow_threads; - return PyLong_FromLong (res); + return PyLong_FromLong (res); +} +%% +override gst_rtsp_server_create_watch kwargs +static PyObject * +_wrap_gst_rtsp_server_create_watch(PyGObject *self, PyObject *args, PyObject *keywords) +{ + GSource *ret; + pyg_begin_allow_threads; + ret = gst_rtsp_server_create_watch(GST_RTSP_SERVER(self->obj)); + pyg_end_allow_threads; + return pygobject_new((GObject *)ret); } diff --git a/bindings/python/test.py b/bindings/python/test.py new file mode 100644 index 0000000000..3278faa058 --- /dev/null +++ b/bindings/python/test.py @@ -0,0 +1,130 @@ +import unittest +import rtspserver + + +def pubdir(obj): + return [d for d in dir(obj) if not d.startswith('_')] + +#print 'Module listing:', pubdir(rtspserver) + +from rtspserver import Server, SessionPool, Session, MediaMapping, MediaFactory + +#print 'Server listing: ', pubdir(Server) +#print 'MediaMapping listing: ', pubdir(MediaMapping) +#print 'MediaFactory listing: ', pubdir(MediaFactory) +#print 'SessionPool listing: ', pubdir(SessionPool) +#print 'Session listing: ', pubdir(Session) + + +class ServerTestCase(unittest.TestCase): + + def setUp(self): + self.server = Server() + + def tearDown(self): + del self.server + + def test_address(self): + """ Server address set/get """ + addr = '1.2.3.4' + self.server.set_address(addr) + self.assertEquals(addr, self.server.get_address()) + + def test_service(self): + """ Server service set/get """ + service = '12345' + self.server.set_service(service) + self.assertEquals(service, self.server.get_service()) + + def test_backlog(self): + """ Server backlog set/get """ + backlog = 1234 + self.server.set_backlog(backlog) + self.assertEquals(backlog, self.server.get_backlog()) + + def test_session_pool(self): + """ Server session pool set/get """ + pool = SessionPool() + self.server.set_session_pool(pool) + self.assertEquals(pool, self.server.get_session_pool()) + + def test_media_mapping(self): + """ Server media mapping set/get """ + mmap = MediaMapping() + self.server.set_media_mapping(mmap) + self.assertEquals(mmap, self.server.get_media_mapping()) + + +class MediaMappingTestCase(unittest.TestCase): + + def setUp(self): + self.mmap = MediaMapping() + + def tearDown(self): + del self.mmap + + def test_factory(self): + """ MediaMapping factory add/remove """ + self.factory = MediaFactory() + self.mmap.add_factory("/test", self.factory) + self.mmap.remove_factory("/test") + + +class MediaFactoryTestCase(unittest.TestCase): + + def setUp(self): + self.factory = MediaFactory() + + def tearDown(self): + del self.factory + + def test_launch(self): + """ MediaFactory launch set/get """ + launch = "videotestsrc ! xvimagesink" + self.factory.set_launch(launch) + self.assertEquals(launch, self.factory.get_launch()) + + def test_shared(self): + """ MediaFactory shared set/is """ + self.factory.set_shared(True) + self.assert_(self.factory.is_shared()) + self.factory.set_shared(False) + self.assert_(not self.factory.is_shared()) + + def test_eos_shutdown(self): + """ MediaFactory eos_shutdown set/is """ + self.factory.set_eos_shutdown(True) + self.assert_(self.factory.is_eos_shutdown()) + self.factory.set_eos_shutdown(False) + self.assert_(not self.factory.is_eos_shutdown()) + + + +def alltests(): + tests = [] + + for p in dir(ServerTestCase): + try: + if 'test_' in p: + tests.append(ServerTestCase(p)) + except: + pass + + for p in dir(MediaMappingTestCase): + try: + if 'test_' in p: + tests.append(MediaMappingTestCase(p)) + except: + pass + + for p in dir(MediaFactoryTestCase): + try: + if 'test_' in p: + tests.append(MediaFactoryTestCase(p)) + except: + pass + + return unittest.TestSuite(tests) + + +unittest.TextTestRunner(verbosity=2).run(alltests()) From 0ef53a2d4f2db0ab6d5361971da53e39b0734dba Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 16:38:34 +0100 Subject: [PATCH 0280/1776] server: chain up to the parent finalize --- gst/rtsp-server/rtsp-server.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 0d5dc57200..b839ef500b 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -159,6 +159,8 @@ gst_rtsp_server_finalize (GObject * object) if (server->auth) g_object_unref (server->auth); + + G_OBJECT_CLASS (gst_rtsp_server_parent_class)->finalize (object); } /** From 9e97faf2db237bcfcd3172dcbacfaac7f9013837 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 18:14:48 +0100 Subject: [PATCH 0281/1776] server: improve debugging in various objects --- gst/rtsp-server/rtsp-media-factory-uri.c | 2 +- gst/rtsp-server/rtsp-media-factory.c | 5 +++-- gst/rtsp-server/rtsp-media-mapping.c | 9 ++++++++- gst/rtsp-server/rtsp-media.c | 4 +++- gst/rtsp-server/rtsp-session-pool.c | 6 +++--- gst/rtsp-server/rtsp-session.c | 5 ++++- 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index c0932b90c0..bb0d661dc9 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -60,7 +60,7 @@ free_data (FactoryData * data) static const gchar *factory_key = "GstRTSPMediaFactoryURI"; -GST_DEBUG_CATEGORY (rtsp_media_factory_uri_debug); +GST_DEBUG_CATEGORY_STATIC (rtsp_media_factory_uri_debug); #define GST_CAT_DEFAULT rtsp_media_factory_uri_debug static void gst_rtsp_media_factory_uri_get_property (GObject * object, diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 2fe309d320..f4045e886b 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -32,7 +32,7 @@ enum PROP_LAST }; -GST_DEBUG_CATEGORY (rtsp_media_debug); +GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug); #define GST_CAT_DEFAULT rtsp_media_debug static void gst_rtsp_media_factory_get_property (GObject * object, guint propid, @@ -102,7 +102,8 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) klass->configure = default_configure; klass->create_pipeline = default_create_pipeline; - GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); + GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediafactory", 0, + "GstRTSPMediaFactory"); } static void diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c index d65f41cbb5..5943c3032a 100644 --- a/gst/rtsp-server/rtsp-media-mapping.c +++ b/gst/rtsp-server/rtsp-media-mapping.c @@ -21,7 +21,7 @@ G_DEFINE_TYPE (GstRTSPMediaMapping, gst_rtsp_media_mapping, G_TYPE_OBJECT); -GST_DEBUG_CATEGORY_EXTERN (rtsp_media_debug); +GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug); #define GST_CAT_DEFAULT rtsp_media_debug static void gst_rtsp_media_mapping_finalize (GObject * obj); @@ -39,11 +39,16 @@ gst_rtsp_media_mapping_class_init (GstRTSPMediaMappingClass * klass) gobject_class->finalize = gst_rtsp_media_mapping_finalize; klass->find_media = find_media; + + GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediamapping", 0, + "GstRTSPMediaMapping"); } static void gst_rtsp_media_mapping_init (GstRTSPMediaMapping * mapping) { + GST_DEBUG_OBJECT (mapping, "created"); + mapping->mappings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } @@ -53,6 +58,8 @@ gst_rtsp_media_mapping_finalize (GObject * obj) { GstRTSPMediaMapping *mapping = GST_RTSP_MEDIA_MAPPING (obj); + GST_DEBUG_OBJECT (mapping, "finalized"); + g_hash_table_unref (mapping->mappings); G_OBJECT_CLASS (gst_rtsp_media_mapping_parent_class)->finalize (obj); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index cd1e42ab71..7d6c76c323 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -53,7 +53,7 @@ enum SIGNAL_LAST }; -GST_DEBUG_CATEGORY_EXTERN (rtsp_media_debug); +GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug); #define GST_CAT_DEFAULT rtsp_media_debug static GQuark ssrc_stream_map_key; @@ -134,6 +134,8 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); gst_element_register (NULL, "rtspfunnel", GST_RANK_NONE, RTSP_TYPE_FUNNEL); + + GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); } static void diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index cbaf71e4b1..36c0211970 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -30,7 +30,7 @@ enum PROP_LAST }; -GST_DEBUG_CATEGORY (rtsp_session_debug); +GST_DEBUG_CATEGORY_STATIC (rtsp_session_debug); #define GST_CAT_DEFAULT rtsp_session_debug static void gst_rtsp_session_pool_get_property (GObject * object, guint propid, @@ -62,8 +62,8 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) klass->create_session_id = create_session_id; - GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0, - "GstRTSPSession"); + GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsessionpool", 0, + "GstRTSPSessionPool"); } static void diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 8d507e5397..ce86d43f27 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -32,7 +32,7 @@ enum PROP_LAST }; -GST_DEBUG_CATEGORY_EXTERN (rtsp_session_debug); +GST_DEBUG_CATEGORY_STATIC (rtsp_session_debug); #define GST_CAT_DEFAULT rtsp_session_debug static void gst_rtsp_session_get_property (GObject * object, guint propid, @@ -63,6 +63,9 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass) g_param_spec_uint ("timeout", "timeout", "the timeout of the session (0 = never)", 0, G_MAXUINT, DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0, + "GstRTSPSession"); } static void From 2be30a92681641d73dcfea9c22fc810a6514fc97 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 18:16:46 +0100 Subject: [PATCH 0282/1776] tests: add tests directory and cleanup test --- tests/.gitignore | 1 + tests/Makefile.am | 9 ++++++ tests/test-cleanup.c | 68 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 tests/.gitignore create mode 100644 tests/Makefile.am create mode 100644 tests/test-cleanup.c diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000000..58b8c22377 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1 @@ +test-cleanup diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000000..a4a47d9704 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,9 @@ +noinst_PROGRAMS = test-cleanup + +INCLUDES = -I$(top_srcdir) -I$(srcdir) + +AM_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +AM_LDFLAGS = \ + $(GST_LIBS) \ + $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_MAJORMINOR@.la + diff --git a/tests/test-cleanup.c b/tests/test-cleanup.c new file mode 100644 index 0000000000..13dba5c77f --- /dev/null +++ b/tests/test-cleanup.c @@ -0,0 +1,68 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + +static gboolean +timeout (GMainLoop * loop, gboolean ignored) +{ + g_main_loop_quit (loop); + return FALSE; +} + + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + guint id; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* attach the server to the default maincontext */ + if ((id = gst_rtsp_server_attach (server, NULL)) == 0) + goto failed; + + g_timeout_add_seconds (2, (GSourceFunc) timeout, loop); + + /* start serving */ + g_main_loop_run (loop); + + /* cleanup */ + g_source_remove (id); + g_object_unref (server); + g_main_loop_unref (loop); + + return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } +} From 6b77f83921a869e5a470abff94ca66e9573f4cdd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 18:17:26 +0100 Subject: [PATCH 0283/1776] build tests --- Makefile.am | 3 ++- configure.ac | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 441ac000a7..b7f6b49f25 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,7 +6,8 @@ SUBDIRS = \ common \ pkgconfig \ docs \ - examples + examples \ + tests DIST_SUBDIRS = $(SUBDIRS) diff --git a/configure.ac b/configure.ac index f007fc413f..9933ad8dab 100644 --- a/configure.ac +++ b/configure.ac @@ -286,6 +286,7 @@ common/m4/Makefile gst/Makefile gst/rtsp-server/Makefile examples/Makefile +tests/Makefile bindings/Makefile bindings/python/Makefile bindings/python/codegen/Makefile From ba4d65a6736d017268cb6b8aa06f45d2d26e714b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 18:18:13 +0100 Subject: [PATCH 0284/1776] server: simplify management of channel and source We don't need to keep around the channel and source objects. Let the mainloop and the source manage the source and channel respectively. --- gst/rtsp-server/rtsp-server.c | 104 ++++++++++++++++++++-------------- gst/rtsp-server/rtsp-server.h | 21 ------- 2 files changed, 63 insertions(+), 62 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index b839ef500b..2abbf354b5 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -17,6 +17,19 @@ * Boston, MA 02111-1307, USA. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "rtsp-server.h" @@ -150,6 +163,8 @@ gst_rtsp_server_finalize (GObject * object) { GstRTSPServer *server = GST_RTSP_SERVER (object); + GST_DEBUG_OBJECT (server, "finalize server"); + g_mutex_free (server->lock); g_free (server->address); g_free (server->service); @@ -484,9 +499,10 @@ gst_rtsp_server_set_property (GObject * object, guint propid, } /* Prepare a server socket for @server and make it listen on the configured port */ -static gboolean +static GIOChannel * gst_rtsp_server_sink_init_send (GstRTSPServer * server) { + GIOChannel *channel; int ret, sockfd; struct addrinfo hints; struct addrinfo *result, *rp; @@ -544,14 +560,11 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) if (rp == NULL) goto no_socket; - server->server_sock.fd = sockfd; - - GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d", - server->server_sock.fd); + GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d", sockfd); /* keep connection alive; avoids SIGPIPE during write */ ret = 1; - if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_KEEPALIVE, + if (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *) &ret, sizeof (ret)) < 0) goto keepalive_failed; @@ -561,39 +574,42 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) * client. */ linger.l_onoff = 1; linger.l_linger = 5; - if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_LINGER, + if (setsockopt (sockfd, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof (linger)) < 0) goto linger_failed; #endif /* set the server socket to nonblocking */ - fcntl (server->server_sock.fd, F_SETFL, O_NONBLOCK); + fcntl (sockfd, F_SETFL, O_NONBLOCK); GST_DEBUG_OBJECT (server, "listening on server socket %d with queue of %d", - server->server_sock.fd, server->backlog); - if (listen (server->server_sock.fd, server->backlog) == -1) + sockfd, server->backlog); + if (listen (sockfd, server->backlog) == -1) goto listen_failed; GST_DEBUG_OBJECT (server, - "listened on server socket %d, returning from connection setup", - server->server_sock.fd); + "listened on server socket %d, returning from connection setup", sockfd); + + /* create IO channel for the socket */ + channel = g_io_channel_unix_new (sockfd); + g_io_channel_set_close_on_unref (channel, TRUE); GST_INFO_OBJECT (server, "listening on service %s", server->service); - return TRUE; + return channel; /* ERRORS */ no_address: { GST_ERROR_OBJECT (server, "failed to resolve address: %s", gai_strerror (ret)); - return FALSE; + return NULL; } no_socket: { GST_ERROR_OBJECT (server, "failed to create socket: %s", g_strerror (errno)); - return FALSE; + return NULL; } keepalive_failed: { @@ -617,11 +633,10 @@ listen_failed: } close_error: { - if (server->server_sock.fd >= 0) { - close (server->server_sock.fd); - server->server_sock.fd = -1; + if (sockfd >= 0) { + close (sockfd); } - return FALSE; + return NULL; } } @@ -687,8 +702,8 @@ default_accept_client (GstRTSPServer * server, GstRTSPClient * client, accept_failed: { GST_ERROR_OBJECT (server, - "Could not accept client on server socket %d: %s (%d)", - server->server_sock.fd, g_strerror (errno), errno); + "Could not accept client on server : %s (%d)", g_strerror (errno), + errno); return FALSE; } } @@ -757,16 +772,14 @@ accept_failed: GIOChannel * gst_rtsp_server_get_io_channel (GstRTSPServer * server) { + GIOChannel *channel; + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - if (server->io_channel == NULL) { - if (!gst_rtsp_server_sink_init_send (server)) - goto init_failed; + if (!(channel = gst_rtsp_server_sink_init_send (server))) + goto init_failed; - /* create IO channel for the socket */ - server->io_channel = g_io_channel_unix_new (server->server_sock.fd); - } - return server->io_channel; + return channel; init_failed: { @@ -775,6 +788,12 @@ init_failed: } } +static void +watch_destroyed (GstRTSPServer * server) +{ + GST_DEBUG_OBJECT (server, "source destroyed"); +} + /** * gst_rtsp_server_create_watch: * @server: a #GstRTSPServer @@ -787,24 +806,26 @@ init_failed: GSource * gst_rtsp_server_create_watch (GstRTSPServer * server) { + GIOChannel *channel; + GSource *source; + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - if (server->io_watch == NULL) { - GIOChannel *channel; + channel = gst_rtsp_server_get_io_channel (server); + if (channel == NULL) + goto no_channel; - channel = gst_rtsp_server_get_io_channel (server); - if (channel == NULL) - goto no_channel; + /* create a watch for reads (new connections) and possible errors */ + source = g_io_create_watch (channel, G_IO_IN | + G_IO_ERR | G_IO_HUP | G_IO_NVAL); + g_io_channel_unref (channel); - /* create a watch for reads (new connections) and possible errors */ - server->io_watch = g_io_create_watch (channel, G_IO_IN | - G_IO_ERR | G_IO_HUP | G_IO_NVAL); + /* configure the callback */ + g_source_set_callback (source, + (GSourceFunc) gst_rtsp_server_io_func, server, + (GDestroyNotify) watch_destroyed); - /* configure the callback */ - g_source_set_callback (server->io_watch, - (GSourceFunc) gst_rtsp_server_io_func, server, NULL); - } - return server->io_watch; + return source; no_channel: { @@ -839,6 +860,7 @@ gst_rtsp_server_attach (GstRTSPServer * server, GMainContext * context) goto no_source; res = g_source_attach (source, context); + g_source_unref (source); return res; diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 472ca061cc..0a63428b5d 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -17,20 +17,6 @@ * Boston, MA 02111-1307, USA. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #ifndef __GST_RTSP_SERVER_H__ #define __GST_RTSP_SERVER_H__ @@ -72,13 +58,6 @@ struct _GstRTSPServer { gchar *service; gint backlog; - struct sockaddr_in server_sin; - - /* socket and channels */ - GstPollFD server_sock; - GIOChannel *io_channel; - GSource *io_watch; - /* sessions on this server */ GstRTSPSessionPool *session_pool; From 3315031bf621ed2a1e2bb3eaca1627c608392911 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 18:24:44 +0100 Subject: [PATCH 0285/1776] server: simpify channel function --- gst/rtsp-server/rtsp-server.c | 43 +++++++++++------------------------ 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 2abbf354b5..0259b91813 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -498,9 +498,17 @@ gst_rtsp_server_set_property (GObject * object, guint propid, } } -/* Prepare a server socket for @server and make it listen on the configured port */ -static GIOChannel * -gst_rtsp_server_sink_init_send (GstRTSPServer * server) +/** + * gst_rtsp_server_get_io_channel: + * @server: a #GstRTSPServer + * + * Create a #GIOChannel for @server. The io channel will listen on the + * configured service. + * + * Returns: the GIOChannel for @server or NULL when an error occured. + */ +GIOChannel * +gst_rtsp_server_get_io_channel (GstRTSPServer * server) { GIOChannel *channel; int ret, sockfd; @@ -510,6 +518,8 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server) struct linger linger; #endif + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_STREAM; /* stream socket */ @@ -761,33 +771,6 @@ accept_failed: } } -/** - * gst_rtsp_server_get_io_channel: - * @server: a #GstRTSPServer - * - * Create a #GIOChannel for @server. - * - * Returns: the GIOChannel for @server or NULL when an error occured. - */ -GIOChannel * -gst_rtsp_server_get_io_channel (GstRTSPServer * server) -{ - GIOChannel *channel; - - g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - - if (!(channel = gst_rtsp_server_sink_init_send (server))) - goto init_failed; - - return channel; - -init_failed: - { - GST_ERROR_OBJECT (server, "failed to initialize server"); - return NULL; - } -} - static void watch_destroyed (GstRTSPServer * server) { From 94c99997153571f3065caadb50291b02d293f550 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 18:26:57 +0100 Subject: [PATCH 0286/1776] server: ensure the watch has a ref to the server --- gst/rtsp-server/rtsp-server.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 0259b91813..f97e12559b 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -775,6 +775,7 @@ static void watch_destroyed (GstRTSPServer * server) { GST_DEBUG_OBJECT (server, "source destroyed"); + g_object_unref (server); } /** @@ -805,7 +806,7 @@ gst_rtsp_server_create_watch (GstRTSPServer * server) /* configure the callback */ g_source_set_callback (source, - (GSourceFunc) gst_rtsp_server_io_func, server, + (GSourceFunc) gst_rtsp_server_io_func, g_object_ref (server), (GDestroyNotify) watch_destroyed); return source; From 459bc46e31c165e459f4b49ebcd1e048372daf8e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 18:33:49 +0100 Subject: [PATCH 0287/1776] example: improve example docs a little --- examples/test-video.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/test-video.c b/examples/test-video.c index 41194a098e..f1ca1c8551 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -21,7 +21,13 @@ #include +/* define this if you want the resource to only be available when using + * user/admin as the password */ +#undef WITH_AUTH +/* this timeout is periodically run to clean up the expired sessions from the + * pool. This needs to be run explicitly currently but might be done + * automatically as part of the mainloop. */ static gboolean timeout (GstRTSPServer * server, gboolean ignored) { @@ -41,7 +47,7 @@ main (int argc, char *argv[]) GstRTSPServer *server; GstRTSPMediaMapping *mapping; GstRTSPMediaFactory *factory; -#if 0 +#ifdef WITH_AUTH GstRTSPAuth *auth; gchar *basic; #endif @@ -57,8 +63,9 @@ main (int argc, char *argv[]) * that be used to map uri mount points to media factories */ mapping = gst_rtsp_server_get_media_mapping (server); -#if 0 - /* make a new authentication manager */ +#ifdef WITH_AUTH + /* make a new authentication manager. it can be added to control access to all + * the factories on the server or on individual factories. */ auth = gst_rtsp_auth_new (); basic = gst_rtsp_auth_make_basic ("user", "admin"); gst_rtsp_auth_set_basic (auth, basic); @@ -88,9 +95,10 @@ main (int argc, char *argv[]) if (gst_rtsp_server_attach (server, NULL) == 0) goto failed; + /* add a timeout for the session cleanup */ g_timeout_add_seconds (2, (GSourceFunc) timeout, server); - /* start serving */ + /* start serving, this never stops */ g_main_loop_run (loop); return 0; From b076933f5e9dce630a96f67345464264d48b1e84 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Jan 2011 18:57:41 +0100 Subject: [PATCH 0288/1776] server: add locking --- gst/rtsp-server/rtsp-server.c | 113 +++++++++++++++++++++++----------- gst/rtsp-server/rtsp-server.h | 4 ++ 2 files changed, 81 insertions(+), 36 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index f97e12559b..8d70d0b235 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -165,7 +165,6 @@ gst_rtsp_server_finalize (GObject * object) GST_DEBUG_OBJECT (server, "finalize server"); - g_mutex_free (server->lock); g_free (server->address); g_free (server->service); @@ -175,6 +174,8 @@ gst_rtsp_server_finalize (GObject * object) if (server->auth) g_object_unref (server->auth); + g_mutex_free (server->lock); + G_OBJECT_CLASS (gst_rtsp_server_parent_class)->finalize (object); } @@ -208,8 +209,10 @@ gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address) g_return_if_fail (GST_IS_RTSP_SERVER (server)); g_return_if_fail (address != NULL); + GST_RTSP_SERVER_LOCK (server); g_free (server->address); server->address = g_strdup (address); + GST_RTSP_SERVER_UNLOCK (server); } /** @@ -223,9 +226,14 @@ gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address) gchar * gst_rtsp_server_get_address (GstRTSPServer * server) { + gchar *result; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - return g_strdup (server->address); + GST_RTSP_SERVER_LOCK (server); + result = g_strdup (server->address); + GST_RTSP_SERVER_UNLOCK (server); + + return result; } /** @@ -245,8 +253,10 @@ gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service) g_return_if_fail (GST_IS_RTSP_SERVER (server)); g_return_if_fail (service != NULL); + GST_RTSP_SERVER_LOCK (server); g_free (server->service); server->service = g_strdup (service); + GST_RTSP_SERVER_UNLOCK (server); } /** @@ -260,9 +270,15 @@ gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service) gchar * gst_rtsp_server_get_service (GstRTSPServer * server) { + gchar *result; + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - return g_strdup (server->service); + GST_RTSP_SERVER_LOCK (server); + result = g_strdup (server->service); + GST_RTSP_SERVER_UNLOCK (server); + + return result; } /** @@ -280,7 +296,9 @@ gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog) { g_return_if_fail (GST_IS_RTSP_SERVER (server)); + GST_RTSP_SERVER_LOCK (server); server->backlog = backlog; + GST_RTSP_SERVER_UNLOCK (server); } /** @@ -294,9 +312,15 @@ gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog) gint gst_rtsp_server_get_backlog (GstRTSPServer * server) { + gint result; + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1); - return server->backlog; + GST_RTSP_SERVER_LOCK (server); + result = server->backlog; + GST_RTSP_SERVER_UNLOCK (server); + + return result; } /** @@ -314,15 +338,16 @@ gst_rtsp_server_set_session_pool (GstRTSPServer * server, g_return_if_fail (GST_IS_RTSP_SERVER (server)); - old = server->session_pool; + if (pool) + g_object_ref (pool); - if (old != pool) { - if (pool) - g_object_ref (pool); - server->session_pool = pool; - if (old) - g_object_unref (old); - } + GST_RTSP_SERVER_LOCK (server); + old = server->session_pool; + server->session_pool = pool; + GST_RTSP_SERVER_UNLOCK (server); + + if (old) + g_object_unref (old); } /** @@ -341,8 +366,10 @@ gst_rtsp_server_get_session_pool (GstRTSPServer * server) g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + GST_RTSP_SERVER_LOCK (server); if ((result = server->session_pool)) g_object_ref (result); + GST_RTSP_SERVER_UNLOCK (server); return result; } @@ -362,15 +389,16 @@ gst_rtsp_server_set_media_mapping (GstRTSPServer * server, g_return_if_fail (GST_IS_RTSP_SERVER (server)); - old = server->media_mapping; + if (mapping) + g_object_ref (mapping); - if (old != mapping) { - if (mapping) - g_object_ref (mapping); - server->media_mapping = mapping; - if (old) - g_object_unref (old); - } + GST_RTSP_SERVER_LOCK (server); + old = server->media_mapping; + server->media_mapping = mapping; + GST_RTSP_SERVER_UNLOCK (server); + + if (old) + g_object_unref (old); } @@ -390,8 +418,10 @@ gst_rtsp_server_get_media_mapping (GstRTSPServer * server) g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + GST_RTSP_SERVER_LOCK (server); if ((result = server->media_mapping)) g_object_ref (result); + GST_RTSP_SERVER_UNLOCK (server); return result; } @@ -410,15 +440,16 @@ gst_rtsp_server_set_auth (GstRTSPServer * server, GstRTSPAuth * auth) g_return_if_fail (GST_IS_RTSP_SERVER (server)); - old = server->auth; + if (auth) + g_object_ref (auth); - if (old != auth) { - if (auth) - g_object_ref (auth); - server->auth = auth; - if (old) - g_object_unref (old); - } + GST_RTSP_SERVER_LOCK (server); + old = server->auth; + server->auth = auth; + GST_RTSP_SERVER_UNLOCK (server); + + if (old) + g_object_unref (old); } @@ -438,8 +469,10 @@ gst_rtsp_server_get_auth (GstRTSPServer * server) g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + GST_RTSP_SERVER_LOCK (server); if ((result = server->auth)) g_object_ref (result); + GST_RTSP_SERVER_UNLOCK (server); return result; } @@ -511,7 +544,7 @@ GIOChannel * gst_rtsp_server_get_io_channel (GstRTSPServer * server) { GIOChannel *channel; - int ret, sockfd; + int ret, sockfd = -1; struct addrinfo hints; struct addrinfo *result, *rp; #ifdef USE_SOLINGER @@ -532,6 +565,7 @@ gst_rtsp_server_get_io_channel (GstRTSPServer * server) GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address, server->service); + GST_RTSP_SERVER_LOCK (server); /* resolve the server IP address */ if ((ret = getaddrinfo (server->address, server->service, &hints, &result)) != 0) @@ -564,10 +598,11 @@ gst_rtsp_server_get_io_channel (GstRTSPServer * server) GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next", g_strerror (errno)); close (sockfd); + sockfd = -1; } freeaddrinfo (result); - if (rp == NULL) + if (sockfd == -1) goto no_socket; GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d", sockfd); @@ -605,6 +640,7 @@ gst_rtsp_server_get_io_channel (GstRTSPServer * server) g_io_channel_set_close_on_unref (channel, TRUE); GST_INFO_OBJECT (server, "listening on service %s", server->service); + GST_RTSP_SERVER_UNLOCK (server); return channel; @@ -613,13 +649,13 @@ no_address: { GST_ERROR_OBJECT (server, "failed to resolve address: %s", gai_strerror (ret)); - return NULL; + goto close_error; } no_socket: { GST_ERROR_OBJECT (server, "failed to create socket: %s", g_strerror (errno)); - return NULL; + goto close_error; } keepalive_failed: { @@ -646,6 +682,7 @@ close_error: if (sockfd >= 0) { close (sockfd); } + GST_RTSP_SERVER_UNLOCK (server); return NULL; } } @@ -655,9 +692,11 @@ unmanage_client (GstRTSPClient * client, GstRTSPServer * server) { GST_DEBUG_OBJECT (server, "unmanage client %p", client); - g_mutex_lock (server->lock); + gst_rtsp_client_set_server (client, NULL); + + GST_RTSP_SERVER_LOCK (server); server->clients = g_list_remove (server->clients, client); - g_mutex_unlock (server->lock); + GST_RTSP_SERVER_UNLOCK (server); g_object_unref (client); } @@ -670,10 +709,10 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) GST_DEBUG_OBJECT (server, "manage client %p", client); gst_rtsp_client_set_server (client, server); - g_mutex_lock (server->lock); + GST_RTSP_SERVER_LOCK (server); g_signal_connect (client, "closed", (GCallback) unmanage_client, server); server->clients = g_list_prepend (server->clients, client); - g_mutex_unlock (server->lock); + GST_RTSP_SERVER_UNLOCK (server); } static GstRTSPClient * @@ -685,11 +724,13 @@ default_create_client (GstRTSPServer * server) client = gst_rtsp_client_new (); /* set the session pool that this client should use */ + GST_RTSP_SERVER_LOCK (server); gst_rtsp_client_set_session_pool (client, server->session_pool); /* set the media mapping that this client should use */ gst_rtsp_client_set_media_mapping (client, server->media_mapping); /* set authentication manager */ gst_rtsp_client_set_auth (client, server->auth); + GST_RTSP_SERVER_UNLOCK (server); return client; } diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 0a63428b5d..2169d8dda2 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -42,6 +42,10 @@ typedef struct _GstRTSPServerClass GstRTSPServerClass; #define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj)) #define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass)) +#define GST_RTSP_SERVER_GET_LOCK(server) (GST_RTSP_SERVER_CAST(server)->lock) +#define GST_RTSP_SERVER_LOCK(server) (g_mutex_lock(GST_RTSP_SERVER_GET_LOCK(server))) +#define GST_RTSP_SERVER_UNLOCK(server) (g_mutex_unlock(GST_RTSP_SERVER_GET_LOCK(server))) + /** * GstRTSPServer: * From cd8382674dbb50019650da6789daeaf93abf79ec Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 13 Jan 2011 18:40:48 +0100 Subject: [PATCH 0289/1776] auth: add realm to make it more spec compliant --- gst/rtsp-server/rtsp-auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 84d5c546a9..e01315ccdb 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -147,7 +147,7 @@ default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, /* we only have Basic for now */ gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE, - "Basic "); + "Basic realm=\"GStreamer RTSP Server\""); return TRUE; } From 44b418b3463e62e549505b31264eeb78c46c9a90 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 13 Jan 2011 18:57:15 +0100 Subject: [PATCH 0290/1776] media: init debug category before starting thread --- gst/rtsp-server/rtsp-media.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 7d6c76c323..ba0f45f09f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -124,6 +124,8 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->context = g_main_context_new (); klass->loop = g_main_loop_new (klass->context, TRUE); + GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); + klass->thread = g_thread_create ((GThreadFunc) do_loop, klass, TRUE, &error); if (error != NULL) { g_critical ("could not start bus thread: %s", error->message); @@ -135,7 +137,6 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) gst_element_register (NULL, "rtspfunnel", GST_RANK_NONE, RTSP_TYPE_FUNNEL); - GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); } static void From 325b2cf8a200cd870dfa17050e1655753434a4ec Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Jan 2011 15:29:55 +0100 Subject: [PATCH 0291/1776] rtsp-server: clarify docs a little --- gst/rtsp-server/rtsp-server.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 8d70d0b235..cf20f0ea44 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -865,7 +865,8 @@ no_channel: * @context: a #GMainContext * * Attaches @server to @context. When the mainloop for @context is run, the - * server will be dispatched. + * server will be dispatched. When @context is NULL, the default context will be + * used). * * This function should be called when the server properties and urls are fully * configured and the server is ready to start. From ed7bb93c2ff6c35229687604f6d6ae8c1ff3c4f2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 24 Jan 2011 11:57:12 +0100 Subject: [PATCH 0292/1776] release 0.10.8 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 9933ad8dab..b98b14f82a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.60) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.7.1, +AC_INIT(Gst-RTSP, 0.10.8, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-rtsp) AG_GST_INIT From 128ddf6318f4aaf96c6ee7b3ba00f24b900fbc57 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 24 Jan 2011 12:07:17 +0100 Subject: [PATCH 0293/1776] back to development --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b98b14f82a..3fe547b863 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.60) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.10.8, +AC_INIT(Gst-RTSP, 0.10.8.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-rtsp) AG_GST_INIT From aa312eec8dafa85924321316b88bf684a0f99ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 24 Jan 2011 11:53:17 +0000 Subject: [PATCH 0294/1776] docs: mention full version these docs are for, not just major-minor --- docs/libs/gst-rtsp-server-docs.sgml | 2 +- docs/version.entities.in | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/libs/gst-rtsp-server-docs.sgml b/docs/libs/gst-rtsp-server-docs.sgml index f78eca7283..2311bd36b2 100644 --- a/docs/libs/gst-rtsp-server-docs.sgml +++ b/docs/libs/gst-rtsp-server-docs.sgml @@ -9,7 +9,7 @@ GStreamer RTSP Server Reference Manual - for GStreamer RTSP Server &GST_MAJORMINOR; + for GStreamer RTSP Server &GST_VERSION; diff --git a/docs/version.entities.in b/docs/version.entities.in index 34dc4bca4d..79a68981d5 100644 --- a/docs/version.entities.in +++ b/docs/version.entities.in @@ -1 +1,2 @@ + From 1c300d92e012f7298fd2ef8e84a7a023eea2f318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 24 Jan 2011 11:59:22 +0000 Subject: [PATCH 0295/1776] docs: recursive into sub-directories on 'make upload' --- docs/Makefile.am | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/Makefile.am b/docs/Makefile.am index f782512c1a..9f9f150bb3 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -9,3 +9,12 @@ DIST_SUBDIRS = libs EXTRA_DIST = \ version.entities.in + +upload: + @if test "x$(SUBDIRS)" != x; then \ + for a in $(SUBDIRS); do \ + cd $$a; \ + make upload; \ + cd ..; \ + done; \ + fi From 68a828ee29a446e4ed6b54e953f1f90356816841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 26 Jan 2011 15:52:54 +0000 Subject: [PATCH 0296/1776] configure: set PYGOBJECT_REQ before using it https://bugzilla.gnome.org/show_bug.cgi?id=640641 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 3fe547b863..10b8407c46 100644 --- a/configure.ac +++ b/configure.ac @@ -112,10 +112,10 @@ fi AM_CHECK_PYTHON_HEADERS([HAVE_PYTHON_HEADERS=yes],[HAVE_PYTHON_HEADERS=no]) dnl check for pygobject (optional, used in the bindings) +PYGOBJECT_REQ=2.11.2 PKG_CHECK_MODULES(PYGOBJECT, pygobject-2.0 >= $PYGOBJECT_REQ, [HAVE_PYGOBJECT="yes"], [HAVE_PYGOBJECT="no"]) AC_SUBST(PYGOBJECT_CFLAGS) -AC_SUBST(PYGOBJECT_REQ, 2.11.2) dnl check for gst-python PKG_CHECK_MODULES(PYGST, gst-python-0.10, From 88b4c02dff0e27ed35a77f4b9acd57ce1517a4b6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 31 Jan 2011 17:28:22 +0100 Subject: [PATCH 0297/1776] media: add property to configure kernel buffer sizes Add a property to configure the kernel UDP buffer size. --- gst/rtsp-server/rtsp-media.c | 47 +++++++++++++++++++++++++++++++++++- gst/rtsp-server/rtsp-media.h | 4 +++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index ba0f45f09f..b7f2d47159 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -31,6 +31,7 @@ #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST #define DEFAULT_EOS_SHUTDOWN FALSE +#define DEFAULT_BUFFER_SIZE 0x800000 /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -42,6 +43,7 @@ enum PROP_REUSABLE, PROP_PROTOCOLS, PROP_EOS_SHUTDOWN, + PROP_BUFFER_SIZE, PROP_LAST }; @@ -106,6 +108,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "Send an EOS event to the pipeline before unpreparing", DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE, + g_param_spec_uint ("buffer-size", "Buffer Size", + "The kernel UDP buffer size to use", 0, G_MAXUINT, + DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_PREPARED] = g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL, @@ -150,6 +157,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) media->reusable = DEFAULT_REUSABLE; media->protocols = DEFAULT_PROTOCOLS; media->eos_shutdown = DEFAULT_EOS_SHUTDOWN; + media->buffer_size = DEFAULT_BUFFER_SIZE; } /* FIXME. this should be done in multiudpsink */ @@ -289,6 +297,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_EOS_SHUTDOWN: g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media)); break; + case PROP_BUFFER_SIZE: + g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -313,6 +324,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_EOS_SHUTDOWN: gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value)); break; + case PROP_BUFFER_SIZE: + gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -525,6 +539,37 @@ gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media) return media->eos_shutdown; } +/** + * gst_rtsp_media_set_buffer_size: + * @media: a #GstRTSPMedia + * @size: the new value + * + * Set the kernel UDP buffer size. + */ +void +gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + media->buffer_size = size; +} + +/** + * gst_rtsp_media_get_buffer_size: + * @media: a #GstRTSPMedia + * + * Get the kernel UDP buffer size. + * + * Returns: the kernel UDP buffer size. + */ +guint +gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) +{ + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + return media->buffer_size; +} + /** * gst_rtsp_media_set_auth: * @media: a #GstRTSPMedia @@ -906,7 +951,7 @@ again: if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), "buffer-size")) { - g_object_set (G_OBJECT (udpsink0), "buffer-size", 0x80000, NULL); + g_object_set (G_OBJECT (udpsink0), "buffer-size", media->buffer_size, NULL); } else { GST_WARNING ("multiudpsink version found without buffer-size property"); } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index a62390ae37..32c82269bc 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -206,6 +206,7 @@ struct _GstRTSPMedia { gboolean reused; gboolean is_ipv6; gboolean eos_shutdown; + guint buffer_size; GstRTSPAuth *auth; GstElement *element; @@ -283,6 +284,9 @@ gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media); void gst_rtsp_media_set_auth (GstRTSPMedia *media, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_media_get_auth (GstRTSPMedia *media); +void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size); +guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media); + /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media); From e86b7c4b15f91cf223401dda65c3b121dc2dcd7a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 31 Jan 2011 17:37:02 +0100 Subject: [PATCH 0298/1776] media-factory: add property to configure the buffer-size Add a property to configure the kernel UDP buffer size. --- gst/rtsp-server/rtsp-media-factory.c | 59 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 4 ++ 2 files changed, 63 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index f4045e886b..70e6c25aa3 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -22,6 +22,7 @@ #define DEFAULT_LAUNCH NULL #define DEFAULT_SHARED FALSE #define DEFAULT_EOS_SHUTDOWN FALSE +#define DEFAULT_BUFFER_SIZE 0x800000 enum { @@ -29,6 +30,7 @@ enum PROP_LAUNCH, PROP_SHARED, PROP_EOS_SHUTDOWN, + PROP_BUFFER_SIZE, PROP_LAST }; @@ -96,6 +98,11 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "Send EOS down the pipeline before shutting down", DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE, + g_param_spec_uint ("buffer-size", "Buffer Size", + "The kernel UDP buffer size to use", 0, G_MAXUINT, + DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + klass->gen_key = default_gen_key; klass->get_element = default_get_element; klass->construct = default_construct; @@ -112,6 +119,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) factory->launch = g_strdup (DEFAULT_LAUNCH); factory->shared = DEFAULT_SHARED; factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN; + factory->buffer_size = DEFAULT_BUFFER_SIZE; factory->lock = g_mutex_new (); factory->medias_lock = g_mutex_new (); @@ -151,6 +159,10 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_boolean (value, gst_rtsp_media_factory_is_eos_shutdown (factory)); break; + case PROP_BUFFER_SIZE: + g_value_set_uint (value, + gst_rtsp_media_factory_get_buffer_size (factory)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -173,6 +185,10 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_eos_shutdown (factory, g_value_get_boolean (value)); break; + case PROP_BUFFER_SIZE: + gst_rtsp_media_factory_set_buffer_size (factory, + g_value_get_uint (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -329,6 +345,46 @@ gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_set_buffer_size: + * @factory: a #GstRTSPMedia + * @size: the new value + * + * Set the kernel UDP buffer size. + */ +void +gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, + guint size) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + factory->buffer_size = size; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_buffer_size: + * @factory: a #GstRTSPMedia + * + * Get the kernel UDP buffer size. + * + * Returns: the kernel UDP buffer size. + */ +guint +gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory) +{ + guint result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + result = factory->buffer_size; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} + /** * gst_rtsp_media_factory_set_auth: * @factory: a #GstRTSPMediaFactory @@ -659,16 +715,19 @@ static void default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) { gboolean shared, eos_shutdown; + guint size; GstRTSPAuth *auth; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); shared = factory->shared; eos_shutdown = factory->eos_shutdown; + size = factory->buffer_size; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_shared (media, shared); gst_rtsp_media_set_eos_shutdown (media, eos_shutdown); + gst_rtsp_media_set_buffer_size (media, size); if ((auth = gst_rtsp_media_factory_get_auth (factory))) { gst_rtsp_media_set_auth (media, auth); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index a06a48d94e..9e8c23fa01 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -64,6 +64,7 @@ struct _GstRTSPMediaFactory { gboolean shared; gboolean eos_shutdown; GstRTSPAuth *auth; + guint buffer_size; GMutex *medias_lock; GHashTable *medias; @@ -121,6 +122,9 @@ gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFac void gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory *factory, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint size); +guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory); + /* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, From 8477fdbf43d442525c5bb5855cc55f55e5066f87 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 31 Jan 2011 17:38:47 +0100 Subject: [PATCH 0299/1776] media: fix default buffer size --- gst/rtsp-server/rtsp-media-factory.c | 2 +- gst/rtsp-server/rtsp-media.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 70e6c25aa3..082b8ebdd6 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -22,7 +22,7 @@ #define DEFAULT_LAUNCH NULL #define DEFAULT_SHARED FALSE #define DEFAULT_EOS_SHUTDOWN FALSE -#define DEFAULT_BUFFER_SIZE 0x800000 +#define DEFAULT_BUFFER_SIZE 0x80000 enum { diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b7f2d47159..d6a7f25d95 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -31,7 +31,7 @@ #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST #define DEFAULT_EOS_SHUTDOWN FALSE -#define DEFAULT_BUFFER_SIZE 0x800000 +#define DEFAULT_BUFFER_SIZE 0x80000 /* define to dump received RTCP packets */ #undef DUMP_STATS From ec2201a3a8adee4463ac2d52194c814f48b28f20 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 2 Feb 2011 15:30:45 +0100 Subject: [PATCH 0300/1776] media: remove duplicate filtering Remove the duplicate filtering code now that we have a released -good version. Give a warning instead. --- gst/rtsp-server/rtsp-media.c | 78 ++++-------------------------------- gst/rtsp-server/rtsp-media.h | 5 --- 2 files changed, 8 insertions(+), 75 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d6a7f25d95..38a37d710f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -234,9 +234,6 @@ gst_rtsp_media_stream_free (GstRTSPMediaStream * stream) g_list_free (stream->transports); - g_list_foreach (stream->destinations, (GFunc) free_destination, NULL); - g_list_free (stream->destinations); - g_free (stream); } @@ -943,10 +940,9 @@ again: "send-duplicates")) { g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); - stream->filter_duplicates = FALSE; } else { - GST_WARNING ("multiudpsink version found without send-duplicates property"); - stream->filter_duplicates = TRUE; + g_warning + ("old multiudpsink version found without send-duplicates property"); } if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), @@ -1859,38 +1855,9 @@ add_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream, gboolean do_add = TRUE; RTSPDestination *ndest; - if (stream->filter_duplicates) { - RTSPDestination fdest; - GList *find; - - fdest.dest = dest; - fdest.min = min; - fdest.max = max; - - /* first see if we already added this destination */ - find = - g_list_find_custom (stream->destinations, &fdest, - (GCompareFunc) dest_compare); - if (find) { - ndest = (RTSPDestination *) find->data; - - GST_INFO ("already streaming to %s:%d-%d with %d clients", dest, min, max, - ndest->count); - ndest->count++; - do_add = FALSE; - } - } - - if (do_add) { - GST_INFO ("adding %s:%d-%d", dest, min, max); - g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); - - if (stream->filter_duplicates) { - ndest = create_destination (dest, min, max); - stream->destinations = g_list_prepend (stream->destinations, ndest); - } - } + GST_INFO ("adding %s:%d-%d", dest, min, max); + g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); } static void @@ -1901,38 +1868,9 @@ remove_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream, RTSPDestination *ndest = NULL; GList *find = NULL; - if (stream->filter_duplicates) { - RTSPDestination fdest; - - fdest.dest = dest; - fdest.min = min; - fdest.max = max; - - /* first see if we already added this destination */ - find = - g_list_find_custom (stream->destinations, &fdest, - (GCompareFunc) dest_compare); - if (!find) - return; - - ndest = (RTSPDestination *) find->data; - if (--ndest->count > 0) { - do_remove = FALSE; - GST_INFO ("still streaming to %s:%d-%d with %d clients", dest, min, max, - ndest->count); - } - } - - if (do_remove) { - GST_INFO ("removing %s:%d-%d", dest, min, max); - g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); - - if (stream->filter_duplicates) { - stream->destinations = g_list_delete_link (stream->destinations, find); - free_destination (ndest); - } - } + GST_INFO ("removing %s:%d-%d", dest, min, max); + g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); } /** diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 32c82269bc..2f103af24a 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -142,11 +142,6 @@ struct _GstRTSPMediaStream { /* transports we stream to */ GList *transports; - - /* to filter out duplicate destinations in case multiudpsink is too old to do - * this for us */ - gboolean filter_duplicates; - GList *destinations; }; /** From a924e90c7944ec6b82202b5d3932636780c8d489 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 2 Feb 2011 15:37:03 +0100 Subject: [PATCH 0301/1776] media: remove more unused code --- gst/rtsp-server/rtsp-media.c | 46 ------------------------------------ 1 file changed, 46 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 38a37d710f..357027a8f8 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -160,45 +160,6 @@ gst_rtsp_media_init (GstRTSPMedia * media) media->buffer_size = DEFAULT_BUFFER_SIZE; } -/* FIXME. this should be done in multiudpsink */ -typedef struct -{ - gint count; - gchar *dest; - gint min, max; -} RTSPDestination; - -static gint -dest_compare (RTSPDestination * a, RTSPDestination * b) -{ - if ((a->min == b->min) && (a->max == b->max) - && (strcmp (a->dest, b->dest) == 0)) - return 0; - - return 1; -} - -static RTSPDestination * -create_destination (const gchar * dest, gint min, gint max) -{ - RTSPDestination *res; - - res = g_slice_new (RTSPDestination); - res->count = 1; - res->dest = g_strdup (dest); - res->min = min; - res->max = max; - - return res; -} - -static void -free_destination (RTSPDestination * dest) -{ - g_free (dest->dest); - g_slice_free (RTSPDestination, dest); -} - void gst_rtsp_media_trans_cleanup (GstRTSPMediaTrans * trans) { @@ -1852,9 +1813,6 @@ static void add_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream, gchar * dest, gint min, gint max) { - gboolean do_add = TRUE; - RTSPDestination *ndest; - GST_INFO ("adding %s:%d-%d", dest, min, max); g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); @@ -1864,10 +1822,6 @@ static void remove_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream, gchar * dest, gint min, gint max) { - gboolean do_remove = TRUE; - RTSPDestination *ndest = NULL; - GList *find = NULL; - GST_INFO ("removing %s:%d-%d", dest, min, max); g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); From 050ce233e089d353c385c2fee0b86b5e4546d67f Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Mon, 14 Feb 2011 12:56:29 +0200 Subject: [PATCH 0302/1776] Automatic update of common submodule From f94d739 to 1de7f6a --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index f94d739915..1de7f6ab2d 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit f94d73991563ea2dcae2218b4847e32998f06816 +Subproject commit 1de7f6ab2d4bc1af69f06079cf0f4e2cbbfdc178 From a67284c6c88e45ce0ae8fdc0cca3989a6e502c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 26 Feb 2011 19:58:02 +0000 Subject: [PATCH 0303/1776] configure: require core/base 0.10.31 Needed at least for gst_plugin_feature_rank_compare_func(). --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 10b8407c46..70ed5e1742 100644 --- a/configure.ac +++ b/configure.ac @@ -42,8 +42,8 @@ AC_SUBST(GST_MAJORMINOR) AM_PROG_LIBTOOL dnl *** required versions of GStreamer stuff *** -GST_REQ=0.10.29 -GSTPB_REQ=0.10.29 +GST_REQ=0.10.31 +GSTPB_REQ=0.10.31 dnl *** autotools stuff **** From 160e0ed11b5585fc00577d4103fa0601863d170d Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 28 Feb 2011 18:35:03 +0100 Subject: [PATCH 0304/1776] Automatic update of common submodule From 1de7f6a to 6aec6b9 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 1de7f6ab2d..6aec6b9716 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 1de7f6ab2d4bc1af69f06079cf0f4e2cbbfdc178 +Subproject commit 6aec6b9716c184c60c4bc6a5916a2471cfa8c8cd From 63744dfece975a09cbe9517071d1f7d58143674d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 7 Mar 2011 10:23:06 +0100 Subject: [PATCH 0305/1776] rtsp-server: Don't install the funnel header --- gst/rtsp-server/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index ca400c0a1c..06b0f3534e 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -1,5 +1,4 @@ public_headers = \ - rtsp-funnel.h \ rtsp-auth.h \ rtsp-params.h \ rtsp-sdp.h \ @@ -26,6 +25,8 @@ c_sources = \ rtsp-client.c \ rtsp-server.c +noinst_HEADERS = rtsp-funnel.h + lib_LTLIBRARIES = \ libgstrtspserver-@GST_MAJORMINOR@.la From 17ce0df09a22966fe4298dab3eec384df3792192 Mon Sep 17 00:00:00 2001 From: Miguel Angel Cabrera Moya Date: Thu, 3 Mar 2011 20:38:03 +0100 Subject: [PATCH 0306/1776] session: use full charset for RTSP session ID As specified in RFC 2326 section 3.4 use full valid charset to make guessing session ID more difficult. https://bugzilla.gnome.org/show_bug.cgi?id=643812 --- gst/rtsp-server/rtsp-session-pool.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 36c0211970..de9234edbe 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -30,6 +30,14 @@ enum PROP_LAST }; +static const gchar session_id_charset[] = + { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '$', '-', '_', '.', '+' +}; + GST_DEBUG_CATEGORY_STATIC (rtsp_session_debug); #define GST_CAT_DEFAULT rtsp_session_debug @@ -235,7 +243,9 @@ create_session_id (GstRTSPSessionPool * pool) gint i; for (i = 0; i < 16; i++) { - id[i] = g_random_int_range ('a', 'z'); + id[i] = + session_id_charset[g_random_int_range (0, + G_N_ELEMENTS (session_id_charset))]; } return g_strndup (id, 16); From 42728254c9adb56fc95c4a9a42dc34d6d0716ec0 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 18 Mar 2011 19:34:57 +0100 Subject: [PATCH 0307/1776] autogen: wingo signed comment --- autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index edb1dd1d85..5f1971433f 100755 --- a/autogen.sh +++ b/autogen.sh @@ -83,7 +83,7 @@ tool_run "$libtoolize" "--copy --force" tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS" tool_run "$autoheader" -# touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode -- wingo +# touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode echo timestamp > stamp-h.in 2> /dev/null tool_run "$autoconf" From 964225aaf92777f24bbb9686978bddecd9fd2711 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 24 Mar 2011 18:51:37 +0200 Subject: [PATCH 0308/1776] Automatic update of common submodule From 6aec6b9 to 6aaa286 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 6aec6b9716..6aaa286970 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 6aec6b9716c184c60c4bc6a5916a2471cfa8c8cd +Subproject commit 6aaa286970e59ed89bd69544f2ee10551f377cb6 From e1201dc044108ef5f1ba63cbde8eafa213053629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 25 Mar 2011 09:11:40 +0100 Subject: [PATCH 0309/1776] Automatic update of common submodule From 6aaa286 to d8814b6 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 6aaa286970..d8814b6c7f 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 6aaa286970e59ed89bd69544f2ee10551f377cb6 +Subproject commit d8814b6c7fb8e037bd19bff6a2698f55ddb2b311 From 36e5dc02073e307221755ce420c22768a02a35f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 25 Mar 2011 09:35:15 +0100 Subject: [PATCH 0310/1776] Automatic update of common submodule From d8814b6 to b77e2bf --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index d8814b6c7f..b77e2bfbb7 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit d8814b6c7fb8e037bd19bff6a2698f55ddb2b311 +Subproject commit b77e2bfbb78e1093d39b7714572ed364e46df53c From f3f10b0f8e94ad22436cb4eae48c630017b791c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 25 Mar 2011 10:04:57 +0100 Subject: [PATCH 0311/1776] build: Include lcov.mak to allow test coverage report generation --- Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.am b/Makefile.am index b7f6b49f25..e923327255 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,6 +23,8 @@ DISTCLEANFILES = _stdint.h gst-rtsp.spec include $(top_srcdir)/common/release.mak include $(top_srcdir)/common/po.mak +include $(top_srcdir)/common/coverage/lcov.mak + check-valgrind: cd tests/check && make check-valgrind From 69f659bd26121687efaba257af5641419cdaba2d Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Fri, 25 Mar 2011 14:58:34 +0200 Subject: [PATCH 0312/1776] Automatic update of common submodule From b77e2bf to 193b717 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index b77e2bfbb7..193b7176e6 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit b77e2bfbb78e1093d39b7714572ed364e46df53c +Subproject commit 193b7176e61160d78a967884f1b20af76d1c7379 From dc4a0c7176b7c22bb80f8e449f76ea4a33a6ca97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 25 Mar 2011 22:38:06 +0100 Subject: [PATCH 0313/1776] Automatic update of common submodule From 193b717 to 1ccbe09 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 193b7176e6..1ccbe098d6 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 193b7176e61160d78a967884f1b20af76d1c7379 +Subproject commit 1ccbe098d6379612fcef09f4000da23585af980a From b73f996b853d500d7fddfa5b73d9ff949d1b6731 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Mon, 4 Apr 2011 15:59:50 +0300 Subject: [PATCH 0314/1776] Automatic update of common submodule From 1ccbe09 to c3cafe1 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 1ccbe098d6..c3cafe123f 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 1ccbe098d6379612fcef09f4000da23585af980a +Subproject commit c3cafe123f3a363d337a29ad32fdd6d3631f52c0 From 61ae57cbdfd556235da61cd2616ca4f80ee10b79 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Wed, 20 Apr 2011 10:16:08 +0200 Subject: [PATCH 0315/1776] python bindings: fix the definition of MediaFactory.collect_stream --- bindings/python/rtspserver.defs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/rtspserver.defs b/bindings/python/rtspserver.defs index 25d190b520..8ed06e5b3f 100644 --- a/bindings/python/rtspserver.defs +++ b/bindings/python/rtspserver.defs @@ -207,7 +207,7 @@ (define-method collect_streams (of-object "GstRTSPMediaFactory") - (c-name "gst_rtsp_media_factory_construct") + (c-name "gst_rtsp_media_factory_collect_streams") (parameters '("const-GstRTSPUrl*" "url") '("GstRTSPMedia*" "media") From 8ab79b0f4be2bacae49a06f23bb967eb23285b6a Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Wed, 20 Apr 2011 10:17:07 +0200 Subject: [PATCH 0316/1776] python bindings: add arg type for GstRTSPUrl --- bindings/python/arg-types.py | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/bindings/python/arg-types.py b/bindings/python/arg-types.py index 1963b9935b..14ab4e3bcf 100644 --- a/bindings/python/arg-types.py +++ b/bindings/python/arg-types.py @@ -145,6 +145,54 @@ class GstIteratorArg(ArgType): info.varlist.add('GstIterator', '*ret') info.codeafter.append(' return pygst_iterator_new(ret);') +class GstRTSPUrlArg(ArgType): + """GstRTSPUrl node generator""" + + before = (' parse_result = gst_rtsp_url_parse (py_%(name)s, &%(name)s);\n' + ' if (parse_result != GST_RTSP_OK) {\n' + ' PyErr_SetString(PyExc_TypeError, "invalid url");\n' + ' return NULL;\n' + ' }') + beforenull = (' if (py_%(name)s == NULL)\n' + ' %(name)s = NULL;\n' + ' else\n' + ' ' + before) + after = (' if (%(name)s)\n' + ' gst_rtsp_url_free (%(name)s);\n') + + def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): + if ptype in ('const-GstRTSPUrl*', 'GstRTSPUrl*'): + self.write_normal_param(pname, pdflt, pnull, info) + else: + raise RuntimeError, "write_param not implemented for %s" % ptype + + def write_normal_param(self, pname, pdflt, pnull, info): + info.varlist.add('GstRTSPResult', 'parse_result') + if pdflt: + assert pdflt == 'NULL' + info.varlist.add('const char', '*py_' + pname + ' = NULL') + else: + info.varlist.add('const char', '*py_' + pname) + info.varlist.add('GstRTSPUrl', '*'+pname) + info.add_parselist('s', ['&py_'+pname], [pname]) + info.arglist.append(pname) + if pnull: + info.codebefore.append (self.beforenull % { 'name' : pname }) + else: + info.codebefore.append (self.before % { 'name' : pname }) + info.codeafter.append (self.after % { 'name' : pname }) + + def write_return(self, ptype, ownsreturn, info): + if ptype == 'GstRTSPUrl*': + info.varlist.add('GstRTSPUrl', '*ret') + copyval = 'FALSE' + elif ptype == 'const-GstRTSPUrl*': + info.varlist.add('const GstRTSPUrl', '*ret') + copyval = 'TRUE' + else: + raise RuntimeError, "write_return not implemented for %s" % ptype + info.codeafter.append(' return pyg_boxed_new (GST_TYPE_CAPS, ret, '+copyval+', TRUE);') + class GstMiniObjectParam(Parameter): def get_c_type(self): @@ -343,6 +391,8 @@ matcher.register('GstCaps', GstCapsArg()) #FIXME: does this work? matcher.register('GstCaps*', GstCapsArg()) #FIXME: does this work? matcher.register('const-GstCaps*', GstCapsArg()) matcher.register('GstIterator*', GstIteratorArg()) +matcher.register('const-GstRTSPUrl*', GstRTSPUrlArg()) +matcher.register('GstRTSPUrl*', GstRTSPUrlArg()) arg = PointerArg('gpointer', 'G_TYPE_POINTER') matcher.register('GstClockID', arg) From c5f41da5531c32a5bfa8e429801043c0a1094c7d Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Wed, 20 Apr 2011 10:19:46 +0200 Subject: [PATCH 0317/1776] python bindings: fix returning GstRTSPUrl types --- bindings/python/arg-types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/arg-types.py b/bindings/python/arg-types.py index 14ab4e3bcf..ec1d749e05 100644 --- a/bindings/python/arg-types.py +++ b/bindings/python/arg-types.py @@ -191,7 +191,7 @@ class GstRTSPUrlArg(ArgType): copyval = 'TRUE' else: raise RuntimeError, "write_return not implemented for %s" % ptype - info.codeafter.append(' return pyg_boxed_new (GST_TYPE_CAPS, ret, '+copyval+', TRUE);') + info.codeafter.append(' return pyg_boxed_new (GST_TYPE_RTSP_URL, ret, '+copyval+', TRUE);') class GstMiniObjectParam(Parameter): From 15e0e2d67cf8d52339402151f983429271430351 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Wed, 20 Apr 2011 11:13:56 +0200 Subject: [PATCH 0318/1776] python bindings: add GstRTSPUrlParam Needed to implement MediaFactory virtual proxies --- bindings/python/arg-types.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/bindings/python/arg-types.py b/bindings/python/arg-types.py index ec1d749e05..112fb301cc 100644 --- a/bindings/python/arg-types.py +++ b/bindings/python/arg-types.py @@ -213,6 +213,31 @@ class GstMiniObjectParam(Parameter): matcher.register_reverse('GstMiniObject*', GstMiniObjectParam) +class GstRTSPUrlParam(Parameter): + + def get_c_type(self): + c_type = self.props.get('c_type', None) + if c_type and c_type.startswith('const'): + return 'const GstRTSPUrl *' + return 'GstRTSPUrl *' + + def convert_c2py(self): + self.wrapper.add_declaration("char *%s_str = NULL;" % self.name) + self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name) + self.wrapper.write_code(code=("if (%(name)s) {\n" + " %(name)s_str = gst_rtsp_url_get_request_uri ((GstRTSPUrl*) %(name)s);\n" + " py_%(name)s = PyString_FromString (%(name)s_str);\n" + " g_free (%(name)s_str);\n" + "} else {\n" + " Py_INCREF(Py_None);\n" + " py_%(name)s = Py_None;\n" + "}" % {'name': self.name}), + cleanup=("Py_DECREF(py_%s);" % self.name)) + self.wrapper.add_pyargv_item("py_%s" % self.name) + +matcher.register_reverse('const-GstRTSPUrl*', GstRTSPUrlParam) +matcher.register_reverse('GstRTSPUrl*', GstRTSPUrlParam) + class GstMiniObjectReturn(ReturnType): def get_c_type(self): From ab9b00d439b300ae8c2541860e706037496bb2d0 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Wed, 20 Apr 2011 11:19:38 +0200 Subject: [PATCH 0319/1776] python bindings: wrap GstRTSPMediaFactoryClass vfuncs --- bindings/python/Makefile.am | 1 + bindings/python/rtspserver.defs | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am index 9c1b36794e..b9ba9c750a 100644 --- a/bindings/python/Makefile.am +++ b/bindings/python/Makefile.am @@ -37,6 +37,7 @@ rtspserver.c: $(DEFS) $(OVERRIDES) arg-types.py ($(PYTHON) $(srcdir)/codegen/codegen.py \ --load-types $(srcdir)/arg-types.py \ --register $(srcdir)/rtspserver-types.defs \ + --register $(PYGST_DEFSDIR)/gst-types.defs \ --override $(srcdir)/$*.override \ --extendpath $(top_builddir)/gst/ \ --extendpath $(srcdir)/ \ diff --git a/bindings/python/rtspserver.defs b/bindings/python/rtspserver.defs index 8ed06e5b3f..f000434cf6 100644 --- a/bindings/python/rtspserver.defs +++ b/bindings/python/rtspserver.defs @@ -214,6 +214,42 @@ ) ) +(define-virtual get_element + (of-object "GstRTSPMediaFactory") + (parameters + '("const-GstRTSPUrl*" "url") + ) + (return-type "GstElement*") +) + + +(define-virtual construct + (of-object "GstRTSPMediaFactory") + (parameters + '("const-GstRTSPUrl*" "url") + ) + (return-type "GstRTSPMedia*") +) + + +(define-virtual configure + (of-object "GstRTSPMediaFactory") + (parameters + '("GstRTSPMedia*" "media") + ) + (return-type "none") +) + + +(define-virtual create_pipeline + (of-object "GstRTSPMediaFactory") + (parameters + '("GstRTSPMedia*" "media") + ) + (return-type "GstElement*") +) + + ;; From gst/rtsp-server/rtsp-session-pool.h (define-function gst_rtsp_session_pool_new From de30ca60c40faa48e52a5e4c514cf13b355f2c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 24 Apr 2011 14:07:11 +0100 Subject: [PATCH 0320/1776] Automatic update of common submodule From c3cafe1 to 46dfcea --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index c3cafe123f..46dfcea233 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit c3cafe123f3a363d337a29ad32fdd6d3631f52c0 +Subproject commit 46dfcea233cf6df83e3771d8a8066e87d614f893 From 7c55d66d0762bf9145894706875e4c6bc38554d7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 26 Apr 2011 19:14:18 +0200 Subject: [PATCH 0321/1776] add common --- common | 1 + 1 file changed, 1 insertion(+) create mode 160000 common diff --git a/common b/common new file mode 160000 index 0000000000..46dfcea233 --- /dev/null +++ b/common @@ -0,0 +1 @@ +Subproject commit 46dfcea233cf6df83e3771d8a8066e87d614f893 From 914b481e4288e9d1220e1e83ac57bdd5957e32d7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 26 Apr 2011 19:22:50 +0200 Subject: [PATCH 0322/1776] rtsp-server: port to 0.11 --- gst/rtsp-server/Makefile.am | 3 +- gst/rtsp-server/rtsp-client.c | 29 ++- gst/rtsp-server/rtsp-funnel.c | 407 ---------------------------------- gst/rtsp-server/rtsp-funnel.h | 69 ------ gst/rtsp-server/rtsp-media.c | 8 +- 5 files changed, 17 insertions(+), 499 deletions(-) delete mode 100644 gst/rtsp-server/rtsp-funnel.c delete mode 100644 gst/rtsp-server/rtsp-funnel.h diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 06b0f3534e..eb751ecac1 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -12,7 +12,6 @@ public_headers = \ rtsp-server.h c_sources = \ - rtsp-funnel.c \ rtsp-auth.c \ rtsp-params.c \ rtsp-sdp.c \ @@ -25,7 +24,7 @@ c_sources = \ rtsp-client.c \ rtsp-server.c -noinst_HEADERS = rtsp-funnel.h +noinst_HEADERS = lib_LTLIBRARIES = \ libgstrtspserver-@GST_MAJORMINOR@.la diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6ddcb57444..62b2a997a7 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -399,19 +399,22 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) { GstRTSPMessage message = { 0 }; guint8 *data; - guint size; + guint usize; + gsize size; gst_rtsp_message_init_data (&message, channel); - data = GST_BUFFER_DATA (buffer); - size = GST_BUFFER_SIZE (buffer); - gst_rtsp_message_take_body (&message, data, size); + data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ); + usize = size; + gst_rtsp_message_take_body (&message, data, usize); /* FIXME, client->watch could have been finalized here, we need to keep an * extra refcount to the watch. */ gst_rtsp_watch_send_message (client->watch, &message, NULL); - gst_rtsp_message_steal_body (&message, &data, &size); + gst_rtsp_message_steal_body (&message, &data, &usize); + gst_buffer_unmap (buffer, data, size); + gst_rtsp_message_unset (&message); return TRUE; @@ -421,18 +424,15 @@ static gboolean do_send_data_list (GstBufferList * blist, guint8 channel, GstRTSPClient * client) { - GstBufferListIterator *it; + guint len, i; - it = gst_buffer_list_iterate (blist); - while (gst_buffer_list_iterator_next_group (it)) { - GstBuffer *group = gst_buffer_list_iterator_merge_group (it); + len = gst_buffer_list_len (blist); - if (group == NULL) - continue; + for (i = 0; i < len; i++) { + GstBuffer *group = gst_buffer_list_get (blist, i); do_send_data (group, channel, client); } - gst_buffer_list_iterator_free (it); return TRUE; } @@ -1428,9 +1428,8 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) gst_rtsp_message_steal_body (message, &data, &size); buffer = gst_buffer_new (); - GST_BUFFER_DATA (buffer) = data; - GST_BUFFER_MALLOCDATA (buffer) = data; - GST_BUFFER_SIZE (buffer) = size; + gst_buffer_take_memory (buffer, + gst_memory_new_wrapped (0, data, g_free, size, 0, size)); handled = FALSE; for (walk = client->streams; walk; walk = g_list_next (walk)) { diff --git a/gst/rtsp-server/rtsp-funnel.c b/gst/rtsp-server/rtsp-funnel.c deleted file mode 100644 index 6f073c1d3a..0000000000 --- a/gst/rtsp-server/rtsp-funnel.c +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Farsight2 - Farsight Funnel element - * - * Copyright 2007 Collabora Ltd. - * @author: Olivier Crete - * Copyright 2007 Nokia Corp. - * - * rtsp-funnel.c: Simple Funnel element - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * SECTION:element-rtspfunnel - * @short_description: N-to-1 simple funnel - * - * Takes packets from various input sinks into one output source - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "rtsp-funnel.h" - -GST_DEBUG_CATEGORY_STATIC (rtsp_funnel_debug); -#define GST_CAT_DEFAULT rtsp_funnel_debug - -static const GstElementDetails rtsp_funnel_details = -GST_ELEMENT_DETAILS ("Farsight Funnel pipe fitting", - "Generic", - "N-to-1 pipe fitting", - "Olivier Crete "); - -static GstStaticPadTemplate funnel_sink_template = -GST_STATIC_PAD_TEMPLATE ("sink%d", - GST_PAD_SINK, - GST_PAD_REQUEST, - GST_STATIC_CAPS_ANY); - -static GstStaticPadTemplate funnel_src_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - - -static void -_do_init (GType type) -{ - GST_DEBUG_CATEGORY_INIT (rtsp_funnel_debug, "rtspfunnel", 0, - "rtsp funnel element"); -} - -GST_BOILERPLATE_FULL (RTSPFunnel, rtsp_funnel, GstElement, GST_TYPE_ELEMENT, - _do_init); - - - -static GstStateChangeReturn rtsp_funnel_change_state (GstElement * element, - GstStateChange transition); - -static GstPad *rtsp_funnel_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * name); -static void rtsp_funnel_release_pad (GstElement * element, GstPad * pad); - -static GstFlowReturn rtsp_funnel_chain (GstPad * pad, GstBuffer * buffer); -static gboolean rtsp_funnel_event (GstPad * pad, GstEvent * event); -static gboolean rtsp_funnel_src_event (GstPad * pad, GstEvent * event); -static GstCaps *rtsp_funnel_getcaps (GstPad * pad); - - -typedef struct -{ - GstSegment segment; -} RTSPFunnelPadPrivate; - -static void -rtsp_funnel_base_init (gpointer g_class) -{ - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (gstelement_class, &rtsp_funnel_details); - - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&funnel_sink_template)); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&funnel_src_template)); -} - - -static void -rtsp_funnel_dispose (GObject * object) -{ - GList *item; - -restart: - for (item = GST_ELEMENT_PADS (object); item; item = g_list_next (item)) { - GstPad *pad = GST_PAD (item->data); - - if (GST_PAD_IS_SINK (pad)) { - gst_element_release_request_pad (GST_ELEMENT (object), pad); - goto restart; - } - } - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -rtsp_funnel_class_init (RTSPFunnelClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - - gobject_class->dispose = GST_DEBUG_FUNCPTR (rtsp_funnel_dispose); - - gstelement_class->request_new_pad = - GST_DEBUG_FUNCPTR (rtsp_funnel_request_new_pad); - gstelement_class->release_pad = GST_DEBUG_FUNCPTR (rtsp_funnel_release_pad); - gstelement_class->change_state = GST_DEBUG_FUNCPTR (rtsp_funnel_change_state); -} - -static void -rtsp_funnel_init (RTSPFunnel * funnel, RTSPFunnelClass * g_class) -{ - funnel->srcpad = gst_pad_new_from_static_template (&funnel_src_template, - "src"); - gst_pad_set_event_function (funnel->srcpad, rtsp_funnel_src_event); - gst_pad_use_fixed_caps (funnel->srcpad); - gst_element_add_pad (GST_ELEMENT (funnel), funnel->srcpad); -} - - -static GstPad * -rtsp_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ, - const gchar * name) -{ - GstPad *sinkpad; - RTSPFunnelPadPrivate *priv = g_slice_alloc0 (sizeof (RTSPFunnelPadPrivate)); - - GST_DEBUG_OBJECT (element, "requesting pad"); - - sinkpad = gst_pad_new_from_template (templ, name); - - gst_pad_set_chain_function (sinkpad, GST_DEBUG_FUNCPTR (rtsp_funnel_chain)); - gst_pad_set_event_function (sinkpad, GST_DEBUG_FUNCPTR (rtsp_funnel_event)); - gst_pad_set_getcaps_function (sinkpad, - GST_DEBUG_FUNCPTR (rtsp_funnel_getcaps)); - - gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED); - gst_pad_set_element_private (sinkpad, priv); - - gst_pad_set_active (sinkpad, TRUE); - - gst_element_add_pad (element, sinkpad); - - return sinkpad; -} - -static void -rtsp_funnel_release_pad (GstElement * element, GstPad * pad) -{ - RTSPFunnel *funnel = RTSP_FUNNEL (element); - RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad); - - GST_DEBUG_OBJECT (funnel, "releasing pad"); - - gst_pad_set_active (pad, FALSE); - - if (priv) - g_slice_free1 (sizeof (RTSPFunnelPadPrivate), priv); - - gst_element_remove_pad (GST_ELEMENT_CAST (funnel), pad); -} - -static GstCaps * -rtsp_funnel_getcaps (GstPad * pad) -{ - RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad)); - GstCaps *caps; - - caps = gst_pad_peer_get_caps (funnel->srcpad); - if (caps == NULL) - caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); - - gst_object_unref (funnel); - - return caps; -} - -static GstFlowReturn -rtsp_funnel_chain (GstPad * pad, GstBuffer * buffer) -{ - GstFlowReturn res; - RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad)); - RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad); - GstEvent *event = NULL; - GstClockTime newts; - GstCaps *padcaps; - - GST_DEBUG_OBJECT (funnel, "received buffer %p", buffer); - - GST_OBJECT_LOCK (funnel); - if (priv->segment.format == GST_FORMAT_UNDEFINED) { - GST_WARNING_OBJECT (funnel, "Got buffer without segment," - " setting segment [0,inf["); - gst_segment_set_newsegment_full (&priv->segment, FALSE, 1.0, 1.0, - GST_FORMAT_TIME, 0, -1, 0); - } - - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) - gst_segment_set_last_stop (&priv->segment, priv->segment.format, - GST_BUFFER_TIMESTAMP (buffer)); - - newts = gst_segment_to_running_time (&priv->segment, - priv->segment.format, GST_BUFFER_TIMESTAMP (buffer)); - if (newts != GST_BUFFER_TIMESTAMP (buffer)) { - buffer = gst_buffer_make_metadata_writable (buffer); - GST_BUFFER_TIMESTAMP (buffer) = newts; - } - - if (!funnel->has_segment) { - event = gst_event_new_new_segment_full (FALSE, 1.0, 1.0, GST_FORMAT_TIME, - 0, -1, 0); - funnel->has_segment = TRUE; - } - GST_OBJECT_UNLOCK (funnel); - - if (event) { - if (!gst_pad_push_event (funnel->srcpad, event)) { - GST_WARNING_OBJECT (funnel, "Could not push out newsegment event"); - res = GST_FLOW_ERROR; - goto out; - } - } - - - GST_OBJECT_LOCK (pad); - padcaps = GST_PAD_CAPS (funnel->srcpad); - GST_OBJECT_UNLOCK (pad); - - if (GST_BUFFER_CAPS (buffer) && GST_BUFFER_CAPS (buffer) != padcaps) { - if (!gst_pad_set_caps (funnel->srcpad, GST_BUFFER_CAPS (buffer))) { - res = GST_FLOW_NOT_NEGOTIATED; - goto out; - } - } - - res = gst_pad_push (funnel->srcpad, buffer); - - GST_LOG_OBJECT (funnel, "handled buffer %s", gst_flow_get_name (res)); - -out: - gst_object_unref (funnel); - - return res; -} - -static gboolean -rtsp_funnel_event (GstPad * pad, GstEvent * event) -{ - RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad)); - RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad); - gboolean forward = TRUE; - gboolean res = TRUE; - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - { - gboolean update; - gdouble rate, arate; - GstFormat format; - gint64 start; - gint64 stop; - gint64 time; - - gst_event_parse_new_segment_full (event, &update, &rate, &arate, - &format, &start, &stop, &time); - - - GST_OBJECT_LOCK (funnel); - gst_segment_set_newsegment_full (&priv->segment, update, rate, arate, - format, start, stop, time); - GST_OBJECT_UNLOCK (funnel); - - forward = FALSE; - gst_event_unref (event); - } - break; - case GST_EVENT_FLUSH_STOP: - { - GST_OBJECT_LOCK (funnel); - gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED); - GST_OBJECT_UNLOCK (funnel); - } - break; - default: - break; - } - - - if (forward) - res = gst_pad_push_event (funnel->srcpad, event); - - gst_object_unref (funnel); - - return res; -} - -static gboolean -rtsp_funnel_src_event (GstPad * pad, GstEvent * event) -{ - GstElement *funnel; - GstIterator *iter; - GstPad *sinkpad; - gboolean result = FALSE; - gboolean done = FALSE; - - funnel = gst_pad_get_parent_element (pad); - g_return_val_if_fail (funnel != NULL, FALSE); - - iter = gst_element_iterate_sink_pads (funnel); - - while (!done) { - switch (gst_iterator_next (iter, (gpointer) & sinkpad)) { - case GST_ITERATOR_OK: - gst_event_ref (event); - result |= gst_pad_push_event (sinkpad, event); - gst_object_unref (sinkpad); - break; - case GST_ITERATOR_RESYNC: - gst_iterator_resync (iter); - result = FALSE; - break; - case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (funnel, "Error iterating sinkpads"); - case GST_ITERATOR_DONE: - done = TRUE; - break; - } - } - gst_iterator_free (iter); - gst_object_unref (funnel); - gst_event_unref (event); - - return result; -} - -static void -reset_pad (gpointer data, gpointer user_data) -{ - GstPad *pad = data; - RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad); - - GST_OBJECT_LOCK (pad); - gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED); - GST_OBJECT_UNLOCK (pad); - gst_object_unref (pad); -} - -static GstStateChangeReturn -rtsp_funnel_change_state (GstElement * element, GstStateChange transition) -{ - RTSPFunnel *funnel = RTSP_FUNNEL (element); - GstStateChangeReturn ret; - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - { - GstIterator *iter = gst_element_iterate_sink_pads (element); - GstIteratorResult res; - - do { - res = gst_iterator_foreach (iter, reset_pad, NULL); - } while (res == GST_ITERATOR_RESYNC); - - gst_iterator_free (iter); - - if (res == GST_ITERATOR_ERROR) - return GST_STATE_CHANGE_FAILURE; - - GST_OBJECT_LOCK (funnel); - funnel->has_segment = FALSE; - GST_OBJECT_UNLOCK (funnel); - } - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - return ret; -} diff --git a/gst/rtsp-server/rtsp-funnel.h b/gst/rtsp-server/rtsp-funnel.h deleted file mode 100644 index f762d8161c..0000000000 --- a/gst/rtsp-server/rtsp-funnel.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Farsight2 - Farsight Funnel element - * - * Copyright 2007 Collabora Ltd. - * @author: Olivier Crete - * Copyright 2007 Nokia Corp. - * - * rtsp-funnel.h: Simple Funnel element - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#ifndef __RTSP_FUNNEL_H__ -#define __RTSP_FUNNEL_H__ - -#include - -G_BEGIN_DECLS - -#define RTSP_TYPE_FUNNEL \ - (rtsp_funnel_get_type ()) -#define RTSP_FUNNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),RTSP_TYPE_FUNNEL,RTSPFunnel)) -#define RTSP_FUNNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),RTSP_TYPE_FUNNEL,RTSPFunnelClass)) -#define RTSP_IS_FUNNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),RTSP_TYPE_FUNNEL)) -#define RTSP_IS_FUNNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),RTSP_TYPE_FUNNEL)) - -typedef struct _RTSPFunnel RTSPFunnel; -typedef struct _RTSPFunnelClass RTSPFunnelClass; - -/** - * RTSPFunnel: - * - * Opaque #RTSPFunnel data structure. - */ -struct _RTSPFunnel { - GstElement element; - - /*< private >*/ - GstPad *srcpad; - - gboolean has_segment; -}; - -struct _RTSPFunnelClass { - GstElementClass parent_class; -}; - -GType rtsp_funnel_get_type (void); - -G_END_DECLS - -#endif /* __RTSP_FUNNEL_H__ */ diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e3ba5cec40..143236c3e5 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -23,7 +23,6 @@ #include #include -#include "rtsp-funnel.h" #include "rtsp-media.h" #define DEFAULT_SHARED FALSE @@ -141,9 +140,6 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->unprepare = default_unprepare; ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); - - gst_element_register (NULL, "rtspfunnel", GST_RANK_NONE, RTSP_TYPE_FUNNEL); - } static void @@ -1325,7 +1321,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) gst_object_unref (teepad); /* make selector for the RTP receivers */ - stream->selector[0] = gst_element_factory_make ("rtspfunnel", NULL); + stream->selector[0] = gst_element_factory_make ("funnel", NULL); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]); pad = gst_element_get_static_pad (stream->selector[0], "src"); @@ -1345,7 +1341,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) gst_object_unref (selpad); /* make selector for the RTCP receivers */ - stream->selector[1] = gst_element_factory_make ("rtspfunnel", NULL); + stream->selector[1] = gst_element_factory_make ("funnel", NULL); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]); pad = gst_element_get_static_pad (stream->selector[1], "src"); From 6b862f0c0e6ab6c1a84f4f8701b4bffccefe3b54 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Sun, 8 May 2011 13:15:19 +0200 Subject: [PATCH 0323/1776] python: override gst_rtsp_media_mapping_add_factory to fix refcounting --- bindings/python/rtspserver.override | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/bindings/python/rtspserver.override b/bindings/python/rtspserver.override index eda93e89ed..2fd69a718a 100644 --- a/bindings/python/rtspserver.override +++ b/bindings/python/rtspserver.override @@ -65,3 +65,23 @@ _wrap_gst_rtsp_server_create_watch(PyGObject *self, PyObject *args, PyObject *ke pyg_end_allow_threads; return pygobject_new((GObject *)ret); } + +%% +override gst_rtsp_media_mapping_add_factory kwargs +static PyObject * +_wrap_gst_rtsp_media_mapping_add_factory(PyGObject *self, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "path", "factory", NULL }; + char *path; + PyGObject *factory; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs,"sO!:GstRTSPMediaMapping.add_factory", kwlist, &path, &PyGstRTSPMediaFactory_Type, &factory)) + return NULL; + pyg_begin_allow_threads; + gst_rtsp_media_mapping_add_factory(GST_RTSP_MEDIA_MAPPING(self->obj), path, + g_object_ref (GST_RTSP_MEDIA_FACTORY(factory->obj))); + pyg_end_allow_threads; + Py_INCREF(Py_None); + return Py_None; +} + From 6ef7c966aef6e6758a43ba417916af79385db825 Mon Sep 17 00:00:00 2001 From: Fabian Deutsch Date: Tue, 3 May 2011 16:24:28 +0200 Subject: [PATCH 0324/1776] Add a signal for newly connected clients. Signed-off-by: Fabian Deutsch --- gst/rtsp-server/rtsp-server.c | 17 +++++++++++++++++ gst/rtsp-server/rtsp-server.h | 7 +++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index cf20f0ea44..ac239d1bbf 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -57,11 +57,19 @@ enum PROP_LAST }; +enum +{ + SIGNAL_CLIENT_CONNECTED, + SIGNAL_LAST +}; + G_DEFINE_TYPE (GstRTSPServer, gst_rtsp_server, G_TYPE_OBJECT); GST_DEBUG_CATEGORY_STATIC (rtsp_server_debug); #define GST_CAT_DEFAULT rtsp_server_debug +static guint gst_rtsp_server_signals[SIGNAL_LAST] = { 0 }; + static void gst_rtsp_server_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec); static void gst_rtsp_server_set_property (GObject * object, guint propid, @@ -141,6 +149,12 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED] = + g_signal_new ("client-connected", G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPServerClass, client_connected), + NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, + gst_rtsp_client_get_type ()); + klass->create_client = default_create_client; klass->accept_client = default_accept_client; @@ -793,6 +807,9 @@ gst_rtsp_server_io_func (GIOChannel * channel, GIOCondition condition, /* manage the client connection */ manage_client (server, client); + + g_signal_emit (server, gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED], 0, + client); } else { GST_WARNING_OBJECT (server, "received unknown event %08x", condition); } diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 2169d8dda2..cfbfbd7a58 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -87,8 +87,11 @@ struct _GstRTSPServer { struct _GstRTSPServerClass { GObjectClass parent_class; - GstRTSPClient * (*create_client) (GstRTSPServer *server); - gboolean (*accept_client) (GstRTSPServer *server, GstRTSPClient *client, GIOChannel *channel); + GstRTSPClient * (*create_client) (GstRTSPServer *server); + gboolean (*accept_client) (GstRTSPServer *server, GstRTSPClient *client, GIOChannel *channel); + + /* signals */ + void (*client_connected) (GstRTSPServer *server, GstRTSPClient *client); }; GType gst_rtsp_server_get_type (void); From ae4a3a9f2928f6c8b8b80d43d4cab8600d206351 Mon Sep 17 00:00:00 2001 From: Fabian Deutsch Date: Tue, 3 May 2011 21:13:15 +0200 Subject: [PATCH 0325/1776] Updated Vala bindings. Signed-off-by: Fabian Deutsch --- bindings/vala/gst-rtsp-server-0.10.vapi | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/vala/gst-rtsp-server-0.10.vapi b/bindings/vala/gst-rtsp-server-0.10.vapi index 2126ce5d4b..d537a96926 100644 --- a/bindings/vala/gst-rtsp-server-0.10.vapi +++ b/bindings/vala/gst-rtsp-server-0.10.vapi @@ -165,6 +165,7 @@ namespace Gst { } [CCode (cheader_filename = "gst/rtsp-server/rtsp-server.h")] public class RTSPServer : GLib.Object { + public signal void client_connected (RTSPClient client); public weak GLib.IOChannel io_channel; public weak GLib.TimeoutSource io_watch; public void* server_sin; From 80e0b0b19a8439134c7a63f6f0f0de0e4f4a2abe Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 17 May 2011 09:48:13 +0200 Subject: [PATCH 0326/1776] media: port to new caps API --- gst/rtsp-server/rtsp-media-factory-uri.c | 14 ++++++-------- gst/rtsp-server/rtsp-media.c | 3 +-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index bb0d661dc9..dde816fb5f 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -393,10 +393,9 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) padname = gst_pad_get_name (pad); /* get pad caps first, then call get_caps, then fail */ - if ((caps = GST_PAD_CAPS (pad))) - gst_caps_ref (caps); - else if ((caps = gst_pad_get_caps (pad)) == NULL) - goto no_caps; + if ((caps = gst_pad_get_current_caps (pad)) == NULL) + if ((caps = gst_pad_get_caps (pad, NULL)) == NULL) + goto no_caps; /* check for raw caps */ if (gst_caps_can_intersect (caps, urifact->raw_vcaps)) { @@ -422,10 +421,9 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) /* continue with new pad and caps */ pad = gst_element_get_static_pad (convert, "src"); - if ((caps = GST_PAD_CAPS (pad))) - gst_caps_ref (caps); - else if ((caps = gst_pad_get_caps (pad)) == NULL) - goto no_caps; + if ((caps = gst_pad_get_current_caps (pad)) == NULL) + if ((caps = gst_pad_get_caps (pad, NULL)) == NULL) + goto no_caps; } if (!(factory = find_payloader (urifact, caps))) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 143236c3e5..a7c9810b93 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -977,8 +977,7 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) gchar *capsstr; GstCaps *newcaps, *oldcaps; - if ((newcaps = GST_PAD_CAPS (pad))) - gst_caps_ref (newcaps); + newcaps = gst_pad_get_current_caps (pad); oldcaps = stream->caps; stream->caps = newcaps; From f5ab822252f80f193c431d65d1f56bb174705976 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 18 May 2011 12:27:35 +0300 Subject: [PATCH 0327/1776] Automatic update of common submodule From 46dfcea to fd35073 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 46dfcea233..fd3507359e 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 46dfcea233cf6df83e3771d8a8066e87d614f893 +Subproject commit fd3507359e845119d199b348c7779b987cee1c45 From 44e2d0f8a6b30e623602cbc14810b4de0a4aaa51 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 18 May 2011 16:14:10 +0300 Subject: [PATCH 0328/1776] Automatic update of common submodule From fd35073 to 9e5bbd5 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index fd3507359e..9e5bbd5085 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit fd3507359e845119d199b348c7779b987cee1c45 +Subproject commit 9e5bbd508588961696e70c38e764492e0312ec4c From 9e9a1eeeacc4e91af09458fe2156824fcd7f4cd7 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 19 May 2011 23:00:52 +0300 Subject: [PATCH 0329/1776] Automatic update of common submodule From 9e5bbd5 to 69b981f --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 9e5bbd5085..69b981f10c 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 9e5bbd508588961696e70c38e764492e0312ec4c +Subproject commit 69b981f10caa234ad0ff639179d0fda8505bd94b From c94416d486b2158be5b24a1f732df94686e6a71c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 7 Jun 2011 10:54:26 +0200 Subject: [PATCH 0330/1776] Makefile.am: 0.10 => @GST_MAJORMINOR@ --- gst/rtsp-server/Makefile.am | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index eb751ecac1..eeac445206 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -63,16 +63,16 @@ GstRtspServer-@GST_MAJORMINOR@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@G -I$(top_builddir) \ -DIN_GOBJECT_INTROSPECTION=1 \ --c-include='gst/gst.h' \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-0.10` \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-0.10` \ - --library=libgstrtspserver-0.10.la \ - --include=Gst-0.10 \ - --include=GstRtsp-0.10 \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_MAJORMINOR@` \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_MAJORMINOR@` \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_MAJORMINOR@` \ + --library=libgstrtspserver-@GST_MAJORMINOR@.la \ + --include=Gst-@GST_MAJORMINOR@ \ + --include=GstRtsp-@GST_MAJORMINOR@ \ --libtool="$(top_builddir)/libtool" \ - --pkg gstreamer-0.10 \ - --pkg gstreamer-rtsp-0.10 \ - --pkg-export gstreamer-rtsp-server-0.10 \ + --pkg gstreamer-@GST_MAJORMINOR@ \ + --pkg gstreamer-rtsp-@GST_MAJORMINOR@ \ + --pkg-export gstreamer-rtsp-server-@GST_MAJORMINOR@ \ --output $@ \ $(gir_headers) \ $(gir_sources) @@ -91,9 +91,9 @@ typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) $(INTROSPECTION_COMPILER) \ --includedir=$(srcdir) \ --includedir=$(builddir) \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-0.10` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-0.10` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_MAJORMINOR@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_MAJORMINOR@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_MAJORMINOR@` \ $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA) From 14f8ed65b4572e3c4b80d5127a7741463c1aa40a Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 7 Jun 2011 10:59:03 +0200 Subject: [PATCH 0331/1776] .gitignore: 0.10 => 0.11 --- gst/rtsp-server/.gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/.gitignore b/gst/rtsp-server/.gitignore index f94bcca81a..6091a86a2e 100644 --- a/gst/rtsp-server/.gitignore +++ b/gst/rtsp-server/.gitignore @@ -1,2 +1,2 @@ -GstRtspServer-0.10.gir -GstRtspServer-0.10.typelib +GstRtspServer-0.11.gir +GstRtspServer-0.11.typelib From 597a99e9b9f5feee53f4596b19f141681a920c8d Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 7 Jun 2011 10:59:16 +0200 Subject: [PATCH 0332/1776] rtsp-media-factory-uri: GST_PLUGIN_FEATURE_NAME is no longer --- gst/rtsp-server/rtsp-media-factory-uri.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index dde816fb5f..2d38eea26e 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -150,7 +150,7 @@ payloader_filter (GstPluginFeature * feature, FilterData * data) list = &data->payload; if (list) { - GST_DEBUG ("adding %s", GST_PLUGIN_FEATURE_NAME (fact)); + GST_DEBUG ("adding %s", GST_OBJECT_NAME (fact)); *list = g_list_prepend (*list, fact); } From b93f046708097910deb87c8183f40c173987a2b3 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 7 Jun 2011 10:54:26 +0200 Subject: [PATCH 0333/1776] Makefile.am: 0.10 => @GST_MAJORMINOR@ --- gst/rtsp-server/Makefile.am | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 06b0f3534e..5f640d9b0e 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -64,16 +64,16 @@ GstRtspServer-@GST_MAJORMINOR@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@G -I$(top_builddir) \ -DIN_GOBJECT_INTROSPECTION=1 \ --c-include='gst/gst.h' \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-0.10` \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-0.10` \ - --library=libgstrtspserver-0.10.la \ - --include=Gst-0.10 \ - --include=GstRtsp-0.10 \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_MAJORMINOR@` \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_MAJORMINOR@` \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_MAJORMINOR@` \ + --library=libgstrtspserver-@GST_MAJORMINOR@.la \ + --include=Gst-@GST_MAJORMINOR@ \ + --include=GstRtsp-@GST_MAJORMINOR@ \ --libtool="$(top_builddir)/libtool" \ - --pkg gstreamer-0.10 \ - --pkg gstreamer-rtsp-0.10 \ - --pkg-export gstreamer-rtsp-server-0.10 \ + --pkg gstreamer-@GST_MAJORMINOR@ \ + --pkg gstreamer-rtsp-@GST_MAJORMINOR@ \ + --pkg-export gstreamer-rtsp-server-@GST_MAJORMINOR@ \ --output $@ \ $(gir_headers) \ $(gir_sources) @@ -92,9 +92,9 @@ typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) $(INTROSPECTION_COMPILER) \ --includedir=$(srcdir) \ --includedir=$(builddir) \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-0.10` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-0.10` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_MAJORMINOR@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_MAJORMINOR@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_MAJORMINOR@` \ $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA) From bd8eb8f3d9d9e20386a79dcd4de6d7e6b5e4aea3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 Jun 2011 19:05:57 +0200 Subject: [PATCH 0334/1776] client: update for buffer API change --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 62b2a997a7..a3be642bb4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1428,7 +1428,7 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) gst_rtsp_message_steal_body (message, &data, &size); buffer = gst_buffer_new (); - gst_buffer_take_memory (buffer, + gst_buffer_take_memory (buffer, -1, gst_memory_new_wrapped (0, data, g_free, size, 0, size)); handled = FALSE; From e5df7a89cc57387e5d49c2e55d5bb1fb3a7ee30e Mon Sep 17 00:00:00 2001 From: David Schleef Date: Thu, 23 Jun 2011 11:30:14 -0700 Subject: [PATCH 0335/1776] Automatic update of common submodule From 69b981f to 605cd9a --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 69b981f10c..605cd9a65e 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 69b981f10caa234ad0ff639179d0fda8505bd94b +Subproject commit 605cd9a65ed61505f24b840d3fe8e252be72b151 From 40c7bb6386617524627967ff5a7bdf9e59fcb262 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 19 Jul 2011 16:10:39 +0200 Subject: [PATCH 0336/1776] examples: tell rtsp uri when ready --- examples/test-launch.c | 1 + examples/test-readme.c | 1 + examples/test-uri.c | 1 + examples/test-video.c | 1 + 4 files changed, 4 insertions(+) diff --git a/examples/test-launch.c b/examples/test-launch.c index 8226485f8a..2a2242d22c 100644 --- a/examples/test-launch.c +++ b/examples/test-launch.c @@ -64,6 +64,7 @@ main (int argc, char *argv[]) gst_rtsp_server_attach (server, NULL); /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); g_main_loop_run (loop); return 0; diff --git a/examples/test-readme.c b/examples/test-readme.c index 5464e04171..bbe8b14488 100644 --- a/examples/test-readme.c +++ b/examples/test-readme.c @@ -60,6 +60,7 @@ main (int argc, char *argv[]) gst_rtsp_server_attach (server, NULL); /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); g_main_loop_run (loop); return 0; diff --git a/examples/test-uri.c b/examples/test-uri.c index 61af721485..db610dd42c 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -82,6 +82,7 @@ main (int argc, char *argv[]) g_timeout_add_seconds (2, (GSourceFunc) timeout, server); /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); g_main_loop_run (loop); return 0; diff --git a/examples/test-video.c b/examples/test-video.c index f1ca1c8551..c39c8b0828 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -99,6 +99,7 @@ main (int argc, char *argv[]) g_timeout_add_seconds (2, (GSourceFunc) timeout, server); /* start serving, this never stops */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); g_main_loop_run (loop); return 0; From 93fb73b46f6be57696ae559bcab341afb74eea6c Mon Sep 17 00:00:00 2001 From: Thijs Vermeir Date: Wed, 20 Jul 2011 17:16:42 +0200 Subject: [PATCH 0337/1776] fix compiler warnings about unused variables --- gst/rtsp-server/rtsp-client.c | 4 ++-- gst/rtsp-server/rtsp-media.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6ddcb57444..44a5c02641 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1666,9 +1666,9 @@ message_received (GstRTSPWatch * watch, GstRTSPMessage * message, static GstRTSPResult message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) { - GstRTSPClient *client; + /* GstRTSPClient *client; */ - client = GST_RTSP_CLIENT (user_data); + /* client = GST_RTSP_CLIENT (user_data); */ /* GST_INFO ("client %p: sent a message with cseq %d", client, cseq); */ diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 357027a8f8..65f831f588 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1842,7 +1842,6 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, GArray * transports) { gint i; - GstStateChangeReturn ret; gboolean add, remove, do_state; gint old_active; @@ -1961,7 +1960,7 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, GST_INFO ("state %s media %p", gst_element_state_get_name (state), media); media->target_state = state; - ret = gst_element_set_state (media->pipeline, state); + gst_element_set_state (media->pipeline, state); } } g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state, From aa128813fedf6075720275f672edf78039b5ad3f Mon Sep 17 00:00:00 2001 From: David Schleef Date: Mon, 27 Jun 2011 11:26:26 -0700 Subject: [PATCH 0338/1776] client: fix reference counting --- gst/rtsp-server/rtsp-client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 44a5c02641..6a5bc76654 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -337,6 +337,8 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) goto no_media; g_object_unref (factory); + factory = NULL; + state->factory = NULL; /* set ipv6 on the media before preparing */ media->is_ipv6 = client->is_ipv6; @@ -389,7 +391,6 @@ no_prepare: { send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); g_object_unref (media); - g_object_unref (factory); return NULL; } } From 6854a3c00fb7275b74d26909ec38189a76de18a3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 4 Aug 2011 08:58:58 +0200 Subject: [PATCH 0339/1776] configure: use unstable api --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 82319667b1..610d1e3846 100644 --- a/configure.ac +++ b/configure.ac @@ -242,7 +242,7 @@ AC_SUBST(GST_OPTION_CFLAGS) dnl FIXME: do we want to rename to GST_ALL_* ? dnl prefer internal headers to already installed ones dnl add GST_OPTION_CFLAGS, but overridable -GST_CFLAGS="$GST_CFLAGS \$(GST_OPTION_CFLAGS)" +GST_CFLAGS="$GST_CFLAGS -DGST_USE_UNSTABLE_API \$(GST_OPTION_CFLAGS)" AC_SUBST(GST_CFLAGS) AC_SUBST(GST_LIBS) From bbab01747d3702cc0041eff97ba2ea9736fdb47a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 4 Aug 2011 08:59:17 +0200 Subject: [PATCH 0340/1776] media: use new api --- gst/rtsp-server/rtsp-media.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index a7c9810b93..816622162b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -299,7 +299,6 @@ do_loop (GstRTSPMediaClass * klass) static void collect_media_stats (GstRTSPMedia * media) { - GstFormat format; gint64 position, duration; media->range.unit = GST_RTSP_RANGE_NPT; @@ -311,15 +310,15 @@ collect_media_stats (GstRTSPMedia * media) media->range.max.seconds = -1; } else { /* get the position */ - format = GST_FORMAT_TIME; - if (!gst_element_query_position (media->pipeline, &format, &position)) { + if (!gst_element_query_position (media->pipeline, GST_FORMAT_TIME, + &position)) { GST_INFO ("position query failed"); position = 0; } /* get the duration */ - format = GST_FORMAT_TIME; - if (!gst_element_query_duration (media->pipeline, &format, &duration)) { + if (!gst_element_query_duration (media->pipeline, GST_FORMAT_TIME, + &duration)) { GST_INFO ("duration query failed"); duration = -1; } From 041b62db8b73a00091b507f73d434a60263a7fb0 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Thu, 11 Aug 2011 18:07:08 -0700 Subject: [PATCH 0341/1776] rtsp-server: hold on to reference while using object --- gst/rtsp-server/rtsp-server.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index ac239d1bbf..4477d8d23b 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -706,11 +706,13 @@ unmanage_client (GstRTSPClient * client, GstRTSPServer * server) { GST_DEBUG_OBJECT (server, "unmanage client %p", client); + g_object_ref (server); gst_rtsp_client_set_server (client, NULL); GST_RTSP_SERVER_LOCK (server); server->clients = g_list_remove (server->clients, client); GST_RTSP_SERVER_UNLOCK (server); + g_object_unref (server); g_object_unref (client); } From 5dc9e76125466be7990187b78000b1df32704312 Mon Sep 17 00:00:00 2001 From: Emmanuel Pacaud Date: Thu, 30 Jun 2011 10:13:59 +0200 Subject: [PATCH 0342/1776] media-factory: add a "media-constructed" signal to GstRTSPMediaFactory For example, it can be used to retrieve source elements like appsrc, in a more convenient way than subclassing get_element. --- gst/rtsp-server/rtsp-media-factory.c | 22 ++++++++++++++++++++-- gst/rtsp-server/rtsp-media-factory.h | 13 ++++++++----- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 082b8ebdd6..1d86c704d5 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -34,9 +34,17 @@ enum PROP_LAST }; +enum +{ + SIGNAL_MEDIA_CONSTRUCTED, + SIGNAL_LAST +}; + GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug); #define GST_CAT_DEFAULT rtsp_media_debug +static guint gst_rtsp_media_factory_signals[SIGNAL_LAST] = { 0 }; + static void gst_rtsp_media_factory_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec); static void gst_rtsp_media_factory_set_property (GObject * object, guint propid, @@ -103,6 +111,12 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "The kernel UDP buffer size to use", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = + g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, + media_constructed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA); + klass->gen_key = default_gen_key; klass->get_element = default_get_element; klass->construct = default_construct; @@ -490,9 +504,13 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, if (media == NULL) { /* nothing cached found, try to create one */ - if (klass->construct) + if (klass->construct) { media = klass->construct (factory, url); - else + if (media) + g_signal_emit (factory, + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED], 0, media, + NULL); + } else media = NULL; if (media) { diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 9e8c23fa01..1c7bab9444 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -93,12 +93,15 @@ struct _GstRTSPMediaFactory { struct _GstRTSPMediaFactoryClass { GObjectClass parent_class; - gchar * (*gen_key) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + gchar * (*gen_key) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); - GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); - GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); - void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); - GstElement * (*create_pipeline)(GstRTSPMediaFactory *factory, GstRTSPMedia *media); + GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); + GstElement * (*create_pipeline) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); + + /* signals */ + void (*media_constructed)(GstRTSPMediaFactory *factory, GstRTSPMedia *media); }; GType gst_rtsp_media_factory_get_type (void); From f7223cfdab653409cd92d117c906de166b00623b Mon Sep 17 00:00:00 2001 From: Robert Krakora Date: Tue, 16 Aug 2011 12:09:48 +0200 Subject: [PATCH 0343/1776] client: destroy pipeline on client disconnect with no prior TEARDOWN. The problem occurs when the client abruptly closes the connection without issuing a TEARDOWN. The TEARDOWN handler in the rtsp-client.c file of the RTSP server is where the pipeline gets torn down. Since this handler is not called, the pipeline remains and is up and running. Subsequent clients get their own pipelines and if the do not issue TEARDOWNs then those pipelines will also remain up and running. This is a resource leak. --- gst/rtsp-server/rtsp-client.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6a5bc76654..ec9175229e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -121,8 +121,12 @@ client_unlink_session (GstRTSPClient * client, GstRTSPSession * session) /* unlink all media managed in this session */ for (medias = session->medias; medias; medias = g_list_next (medias)) { - unlink_session_streams (client, session, - (GstRTSPSessionMedia *) medias->data); + GstRTSPSessionMedia *media = medias->data; + + gst_rtsp_session_media_set_state (media, GST_STATE_NULL); + unlink_session_streams (client, session, media); + /* unmanage the media in the session. */ + gst_rtsp_session_release_media (session, media); } } From b0e22d6861ab751c917eff8d4379c02b05d12a9b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 12:51:44 +0200 Subject: [PATCH 0344/1776] client: do configuration of transport in one place Move the configuration of the transport destination address to where we also configure the other bits. --- gst/rtsp-server/rtsp-client.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4b106d2fdc..070a4694e4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -857,7 +857,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) gchar *trans_str, *pos; guint streamid; GstRTSPSessionMedia *media; - GstRTSPUrl *url; uri = state->uri; @@ -932,15 +931,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) if (client->session_pool == NULL) goto no_pool; - /* we have a valid transport now, set the destination of the client. */ - g_free (ct->destination); - if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - ct->destination = g_strdup (MCAST_ADDRESS); - } else { - url = gst_rtsp_connection_get_url (client->connection); - ct->destination = g_strdup (url->host); - } - session = state->session; if (session) { @@ -977,11 +967,21 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) state->sessmedia = media; - /* fix the transports */ - if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) { - /* check if the client selected channels for TCP */ - if (ct->interleaved.min == -1 || ct->interleaved.max == -1) { - gst_rtsp_session_media_alloc_channels (media, &ct->interleaved); + /* we have a valid transport now, set the destination of the client. */ + g_free (ct->destination); + if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + ct->destination = g_strdup (MCAST_ADDRESS); + } else { + GstRTSPUrl *url; + + url = gst_rtsp_connection_get_url (client->connection); + ct->destination = g_strdup (url->host); + + if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) { + /* check if the client selected channels for TCP */ + if (ct->interleaved.min == -1 || ct->interleaved.max == -1) { + gst_rtsp_session_media_alloc_channels (media, &ct->interleaved); + } } } From 1f8b97d940731d2869bd55cc846af2b97788f1b5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 13:13:36 +0200 Subject: [PATCH 0345/1776] media-factory: add property for multicast group Add a property to configure the multicast group in the media factory. Based on patches from Marc Leeman and Robert Krakora. --- gst/rtsp-server/rtsp-media-factory.c | 66 ++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-media-factory.h | 3 ++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 1d86c704d5..3dd6559d3e 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -19,10 +19,11 @@ #include "rtsp-media-factory.h" -#define DEFAULT_LAUNCH NULL -#define DEFAULT_SHARED FALSE -#define DEFAULT_EOS_SHUTDOWN FALSE -#define DEFAULT_BUFFER_SIZE 0x80000 +#define DEFAULT_LAUNCH NULL +#define DEFAULT_SHARED FALSE +#define DEFAULT_EOS_SHUTDOWN FALSE +#define DEFAULT_BUFFER_SIZE 0x80000 +#define DEFAULT_MULTICAST_GROUP "224.2.0.1" enum { @@ -31,6 +32,7 @@ enum PROP_SHARED, PROP_EOS_SHUTDOWN, PROP_BUFFER_SIZE, + PROP_MULTICAST_GROUP, PROP_LAST }; @@ -111,6 +113,11 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "The kernel UDP buffer size to use", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP, + g_param_spec_string ("multicast-group", "Multicast Group", + "The Multicast group to send media to", + DEFAULT_MULTICAST_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, @@ -134,6 +141,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) factory->shared = DEFAULT_SHARED; factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN; factory->buffer_size = DEFAULT_BUFFER_SIZE; + factory->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP); factory->lock = g_mutex_new (); factory->medias_lock = g_mutex_new (); @@ -149,6 +157,7 @@ gst_rtsp_media_factory_finalize (GObject * obj) g_hash_table_unref (factory->medias); g_mutex_free (factory->medias_lock); g_free (factory->launch); + g_free (factory->multicast_group); g_mutex_free (factory->lock); if (factory->auth) g_object_unref (factory->auth); @@ -177,6 +186,10 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_uint (value, gst_rtsp_media_factory_get_buffer_size (factory)); break; + case PROP_MULTICAST_GROUP: + g_value_take_string (value, + gst_rtsp_media_factory_get_multicast_group (factory)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -203,6 +216,10 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_buffer_size (factory, g_value_get_uint (value)); break; + case PROP_MULTICAST_GROUP: + gst_rtsp_media_factory_set_multicast_group (factory, + g_value_get_string (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -399,6 +416,47 @@ gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_set_multicast_group: + * @factory: a #GstRTSPMedia + * @mc: the new multicast group + * + * Set the multicast group that media from @factory will be streamed to. + */ +void +gst_rtsp_media_factory_set_multicast_group (GstRTSPMediaFactory * factory, + const gchar * mc) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + g_free (factory->multicast_group); + factory->multicast_group = g_strdup (mc); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_multicast_group: + * @factory: a #GstRTSPMedia + * + * Get the multicast group that media from @factory will be streamed to. + * + * Returns: the multicast group + */ +gchar * +gst_rtsp_media_factory_get_multicast_group (GstRTSPMediaFactory * factory) +{ + gchar *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + result = g_strdup (factory->multicast_group); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} + /** * gst_rtsp_media_factory_set_auth: * @factory: a #GstRTSPMediaFactory diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 1c7bab9444..d2b8ee9088 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -65,6 +65,7 @@ struct _GstRTSPMediaFactory { gboolean eos_shutdown; GstRTSPAuth *auth; guint buffer_size; + gchar *multicast_group; GMutex *medias_lock; GHashTable *medias; @@ -128,6 +129,8 @@ GstRTSPAuth * gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint size); guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory); +void gst_rtsp_media_factory_set_multicast_group (GstRTSPMediaFactory * factory, const gchar *mc); +gchar * gst_rtsp_media_factory_get_multicast_group (GstRTSPMediaFactory * factory); /* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, From 5b53335873fbca3285d31f4a3c355779fc12b88b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 13:25:16 +0200 Subject: [PATCH 0346/1776] media: add property for multicast group Add a property to configure the multicast group in the media. Based on patches from Marc Leeman and Robert Krakora. --- gst/rtsp-server/rtsp-media.c | 65 +++++++++++++++++++++++++++++++++--- gst/rtsp-server/rtsp-media.h | 5 +++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c4127f8ce9..70fe4740d6 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -25,12 +25,13 @@ #include "rtsp-media.h" -#define DEFAULT_SHARED FALSE -#define DEFAULT_REUSABLE FALSE -#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP +#define DEFAULT_SHARED FALSE +#define DEFAULT_REUSABLE FALSE +#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST -#define DEFAULT_EOS_SHUTDOWN FALSE -#define DEFAULT_BUFFER_SIZE 0x80000 +#define DEFAULT_EOS_SHUTDOWN FALSE +#define DEFAULT_BUFFER_SIZE 0x80000 +#define DEFAULT_MULTICAST_GROUP "224.2.0.1" /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -43,6 +44,7 @@ enum PROP_PROTOCOLS, PROP_EOS_SHUTDOWN, PROP_BUFFER_SIZE, + PROP_MULTICAST_GROUP, PROP_LAST }; @@ -112,6 +114,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "The kernel UDP buffer size to use", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP, + g_param_spec_string ("multicast-group", "Multicast Group", + "The Multicast group to send media to", + DEFAULT_MULTICAST_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_PREPARED] = g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL, @@ -154,6 +161,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) media->protocols = DEFAULT_PROTOCOLS; media->eos_shutdown = DEFAULT_EOS_SHUTDOWN; media->buffer_size = DEFAULT_BUFFER_SIZE; + media->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP); } void @@ -226,6 +234,7 @@ gst_rtsp_media_finalize (GObject * obj) g_source_destroy (media->source); g_source_unref (media->source); } + g_free (media->multicast_group); g_mutex_free (media->lock); g_cond_free (media->cond); @@ -254,6 +263,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_BUFFER_SIZE: g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media)); break; + case PROP_MULTICAST_GROUP: + g_value_take_string (value, gst_rtsp_media_get_multicast_group (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -281,6 +293,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_BUFFER_SIZE: gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value)); break; + case PROP_MULTICAST_GROUP: + gst_rtsp_media_set_multicast_group (media, g_value_get_string (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -523,6 +538,46 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) return media->buffer_size; } +/** + * gst_rtsp_media_set_multicast_group: + * @media: a #GstRTSPMedia + * @mc: the new multicast group + * + * Set the multicast group that media from @media will be streamed to. + */ +void +gst_rtsp_media_set_multicast_group (GstRTSPMedia * media, const gchar * mc) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + g_mutex_lock (media->lock); + g_free (media->multicast_group); + media->multicast_group = g_strdup (mc); + g_mutex_unlock (media->lock); +} + +/** + * gst_rtsp_media_get_multicast_group: + * @media: a #GstRTSPMedia + * + * Get the multicast group that media from @media will be streamed to. + * + * Returns: the multicast group + */ +gchar * +gst_rtsp_media_get_multicast_group (GstRTSPMedia * media) +{ + gchar *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + + g_mutex_lock (media->lock); + result = g_strdup (media->multicast_group); + g_mutex_unlock (media->lock); + + return result; +} + /** * gst_rtsp_media_set_auth: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 2f103af24a..09fe5248f1 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -203,6 +203,7 @@ struct _GstRTSPMedia { gboolean eos_shutdown; guint buffer_size; GstRTSPAuth *auth; + gchar *multicast_group; GstElement *element; GArray *streams; @@ -282,6 +283,10 @@ GstRTSPAuth * gst_rtsp_media_get_auth (GstRTSPMedia *media); void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size); guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media); +void gst_rtsp_media_set_multicast_group (GstRTSPMedia *media, const gchar * mc); +gchar * gst_rtsp_media_get_multicast_group (GstRTSPMedia *media); + + /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media); From ccfb99f8521a85622e9e231d816838ecedd276c1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 13:27:39 +0200 Subject: [PATCH 0347/1776] media-factory: configure multicast in media --- gst/rtsp-server/rtsp-media-factory.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 3dd6559d3e..4106e61a1d 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -793,6 +793,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gboolean shared, eos_shutdown; guint size; GstRTSPAuth *auth; + gchar *mc; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -809,4 +810,8 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_auth (media, auth); g_object_unref (auth); } + if ((mc = gst_rtsp_media_factory_get_multicast_group (factory))) { + gst_rtsp_media_set_multicast_group (media, mc); + g_free (mc); + } } From ae67971cde33785618dc7672880d708cdee71bdf Mon Sep 17 00:00:00 2001 From: Robert Krakora Date: Tue, 16 Aug 2011 13:31:52 +0200 Subject: [PATCH 0348/1776] sdp: copy and free the server ip address Copy and free the server ip address to make memory management easier later. --- gst/rtsp-server/rtsp-client.c | 7 +++++-- gst/rtsp-server/rtsp-sdp.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 070a4694e4..4698726fa8 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1096,19 +1096,22 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) info.server_proto = proto; if (media->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) - info.server_ip = MCAST_ADDRESS; + info.server_ip = g_strdup (MCAST_ADDRESS); else - info.server_ip = client->server_ip; + info.server_ip = g_strdup (client->server_ip); /* create an SDP for the media object */ if (!gst_rtsp_sdp_from_media (sdp, &info, media)) goto no_sdp; + g_free (info.server_ip); + return sdp; /* ERRORS */ no_sdp: { + g_free (info.server_ip); gst_sdp_message_free (sdp); return NULL; } diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h index 6c4c00549a..e6ac1b28cd 100644 --- a/gst/rtsp-server/rtsp-sdp.h +++ b/gst/rtsp-server/rtsp-sdp.h @@ -29,7 +29,7 @@ G_BEGIN_DECLS typedef struct { const gchar *server_proto; - const gchar *server_ip; + gchar *server_ip; } GstSDPInfo; /* creating SDP */ From 26c8898e79d0dd099df7757280eccc876d77c25e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 13:37:50 +0200 Subject: [PATCH 0349/1776] retab some .h --- gst/rtsp-server/rtsp-media-factory.h | 12 ++++++------ gst/rtsp-server/rtsp-server.h | 2 +- gst/rtsp-server/rtsp-session-pool.h | 2 +- gst/rtsp-server/rtsp-session.h | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index d2b8ee9088..4804a9de0b 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -94,15 +94,15 @@ struct _GstRTSPMediaFactory { struct _GstRTSPMediaFactoryClass { GObjectClass parent_class; - gchar * (*gen_key) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + gchar * (*gen_key) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); - GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); - GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); - void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); - GstElement * (*create_pipeline) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); + GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); + GstElement * (*create_pipeline) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); /* signals */ - void (*media_constructed)(GstRTSPMediaFactory *factory, GstRTSPMedia *media); + void (*media_constructed) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); }; GType gst_rtsp_media_factory_get_type (void); diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index cfbfbd7a58..98a3391dad 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -89,7 +89,7 @@ struct _GstRTSPServerClass { GstRTSPClient * (*create_client) (GstRTSPServer *server); gboolean (*accept_client) (GstRTSPServer *server, GstRTSPClient *client, GIOChannel *channel); - + /* signals */ void (*client_connected) (GstRTSPServer *server, GstRTSPClient *client); }; diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 3cd56d4ef8..f432208737 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -143,7 +143,7 @@ gboolean gst_rtsp_session_pool_remove (GstRTSPSessionPoo /* perform session maintenance */ GList * gst_rtsp_session_pool_filter (GstRTSPSessionPool *pool, GstRTSPSessionFilterFunc func, - gpointer user_data); + gpointer user_data); guint gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool); GSource * gst_rtsp_session_pool_create_watch (GstRTSPSessionPool *pool); diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 07efb1958d..4289ecba8f 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -132,7 +132,7 @@ gboolean gst_rtsp_session_is_expired (GstRTSPSession *se /* handle media in a session */ GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, - GstRTSPMedia *media); + GstRTSPMedia *media); gboolean gst_rtsp_session_release_media (GstRTSPSession *sess, GstRTSPSessionMedia *media); /* get media in a session */ From 9573058f5401cd18786f5e5d6660bb2f4aefa113 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 13:43:44 +0200 Subject: [PATCH 0350/1776] client: use media multicast group --- gst/rtsp-server/rtsp-client.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4698726fa8..9b8e6ce8aa 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -36,9 +36,6 @@ #include "rtsp-sdp.h" #include "rtsp-params.h" -/* temporary multicast address until it's configurable somewhere */ -#define MCAST_ADDRESS "224.2.0.1" - static GMutex *tunnels_lock; static GHashTable *tunnels; @@ -970,7 +967,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) /* we have a valid transport now, set the destination of the client. */ g_free (ct->destination); if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - ct->destination = g_strdup (MCAST_ADDRESS); + ct->destination = gst_rtsp_media_get_multicast_group (media->media); } else { GstRTSPUrl *url; @@ -1096,7 +1093,7 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) info.server_proto = proto; if (media->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) - info.server_ip = g_strdup (MCAST_ADDRESS); + info.server_ip = gst_rtsp_media_get_multicast_group (media); else info.server_ip = g_strdup (client->server_ip); From b881dc66690f81b5928f859e43c202440b85ab97 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 12:51:44 +0200 Subject: [PATCH 0351/1776] client: do configuration of transport in one place Move the configuration of the transport destination address to where we also configure the other bits. --- gst/rtsp-server/rtsp-client.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index ec9175229e..af944080a2 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -857,7 +857,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) gchar *trans_str, *pos; guint streamid; GstRTSPSessionMedia *media; - GstRTSPUrl *url; uri = state->uri; @@ -932,15 +931,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) if (client->session_pool == NULL) goto no_pool; - /* we have a valid transport now, set the destination of the client. */ - g_free (ct->destination); - if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - ct->destination = g_strdup (MCAST_ADDRESS); - } else { - url = gst_rtsp_connection_get_url (client->connection); - ct->destination = g_strdup (url->host); - } - session = state->session; if (session) { @@ -977,11 +967,21 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) state->sessmedia = media; - /* fix the transports */ - if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) { - /* check if the client selected channels for TCP */ - if (ct->interleaved.min == -1 || ct->interleaved.max == -1) { - gst_rtsp_session_media_alloc_channels (media, &ct->interleaved); + /* we have a valid transport now, set the destination of the client. */ + g_free (ct->destination); + if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + ct->destination = g_strdup (MCAST_ADDRESS); + } else { + GstRTSPUrl *url; + + url = gst_rtsp_connection_get_url (client->connection); + ct->destination = g_strdup (url->host); + + if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) { + /* check if the client selected channels for TCP */ + if (ct->interleaved.min == -1 || ct->interleaved.max == -1) { + gst_rtsp_session_media_alloc_channels (media, &ct->interleaved); + } } } From 514728864a34459b52a48e8bd805cde0dc2a3685 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 13:13:36 +0200 Subject: [PATCH 0352/1776] media-factory: add property for multicast group Add a property to configure the multicast group in the media factory. Based on patches from Marc Leeman and Robert Krakora. --- gst/rtsp-server/rtsp-media-factory.c | 66 ++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-media-factory.h | 3 ++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 1d86c704d5..3dd6559d3e 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -19,10 +19,11 @@ #include "rtsp-media-factory.h" -#define DEFAULT_LAUNCH NULL -#define DEFAULT_SHARED FALSE -#define DEFAULT_EOS_SHUTDOWN FALSE -#define DEFAULT_BUFFER_SIZE 0x80000 +#define DEFAULT_LAUNCH NULL +#define DEFAULT_SHARED FALSE +#define DEFAULT_EOS_SHUTDOWN FALSE +#define DEFAULT_BUFFER_SIZE 0x80000 +#define DEFAULT_MULTICAST_GROUP "224.2.0.1" enum { @@ -31,6 +32,7 @@ enum PROP_SHARED, PROP_EOS_SHUTDOWN, PROP_BUFFER_SIZE, + PROP_MULTICAST_GROUP, PROP_LAST }; @@ -111,6 +113,11 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "The kernel UDP buffer size to use", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP, + g_param_spec_string ("multicast-group", "Multicast Group", + "The Multicast group to send media to", + DEFAULT_MULTICAST_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, @@ -134,6 +141,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) factory->shared = DEFAULT_SHARED; factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN; factory->buffer_size = DEFAULT_BUFFER_SIZE; + factory->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP); factory->lock = g_mutex_new (); factory->medias_lock = g_mutex_new (); @@ -149,6 +157,7 @@ gst_rtsp_media_factory_finalize (GObject * obj) g_hash_table_unref (factory->medias); g_mutex_free (factory->medias_lock); g_free (factory->launch); + g_free (factory->multicast_group); g_mutex_free (factory->lock); if (factory->auth) g_object_unref (factory->auth); @@ -177,6 +186,10 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_uint (value, gst_rtsp_media_factory_get_buffer_size (factory)); break; + case PROP_MULTICAST_GROUP: + g_value_take_string (value, + gst_rtsp_media_factory_get_multicast_group (factory)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -203,6 +216,10 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_buffer_size (factory, g_value_get_uint (value)); break; + case PROP_MULTICAST_GROUP: + gst_rtsp_media_factory_set_multicast_group (factory, + g_value_get_string (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -399,6 +416,47 @@ gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_set_multicast_group: + * @factory: a #GstRTSPMedia + * @mc: the new multicast group + * + * Set the multicast group that media from @factory will be streamed to. + */ +void +gst_rtsp_media_factory_set_multicast_group (GstRTSPMediaFactory * factory, + const gchar * mc) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + g_free (factory->multicast_group); + factory->multicast_group = g_strdup (mc); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_multicast_group: + * @factory: a #GstRTSPMedia + * + * Get the multicast group that media from @factory will be streamed to. + * + * Returns: the multicast group + */ +gchar * +gst_rtsp_media_factory_get_multicast_group (GstRTSPMediaFactory * factory) +{ + gchar *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + result = g_strdup (factory->multicast_group); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} + /** * gst_rtsp_media_factory_set_auth: * @factory: a #GstRTSPMediaFactory diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 1c7bab9444..d2b8ee9088 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -65,6 +65,7 @@ struct _GstRTSPMediaFactory { gboolean eos_shutdown; GstRTSPAuth *auth; guint buffer_size; + gchar *multicast_group; GMutex *medias_lock; GHashTable *medias; @@ -128,6 +129,8 @@ GstRTSPAuth * gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint size); guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory); +void gst_rtsp_media_factory_set_multicast_group (GstRTSPMediaFactory * factory, const gchar *mc); +gchar * gst_rtsp_media_factory_get_multicast_group (GstRTSPMediaFactory * factory); /* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, From c0793251698f91982002c6e8d3f450e8c1270822 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 13:25:16 +0200 Subject: [PATCH 0353/1776] media: add property for multicast group Add a property to configure the multicast group in the media. Based on patches from Marc Leeman and Robert Krakora. --- gst/rtsp-server/rtsp-media.c | 65 +++++++++++++++++++++++++++++++++--- gst/rtsp-server/rtsp-media.h | 5 +++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 65f831f588..aaba0679ed 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -26,12 +26,13 @@ #include "rtsp-funnel.h" #include "rtsp-media.h" -#define DEFAULT_SHARED FALSE -#define DEFAULT_REUSABLE FALSE -#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP +#define DEFAULT_SHARED FALSE +#define DEFAULT_REUSABLE FALSE +#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST -#define DEFAULT_EOS_SHUTDOWN FALSE -#define DEFAULT_BUFFER_SIZE 0x80000 +#define DEFAULT_EOS_SHUTDOWN FALSE +#define DEFAULT_BUFFER_SIZE 0x80000 +#define DEFAULT_MULTICAST_GROUP "224.2.0.1" /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -44,6 +45,7 @@ enum PROP_PROTOCOLS, PROP_EOS_SHUTDOWN, PROP_BUFFER_SIZE, + PROP_MULTICAST_GROUP, PROP_LAST }; @@ -113,6 +115,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "The kernel UDP buffer size to use", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP, + g_param_spec_string ("multicast-group", "Multicast Group", + "The Multicast group to send media to", + DEFAULT_MULTICAST_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_PREPARED] = g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL, @@ -158,6 +165,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) media->protocols = DEFAULT_PROTOCOLS; media->eos_shutdown = DEFAULT_EOS_SHUTDOWN; media->buffer_size = DEFAULT_BUFFER_SIZE; + media->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP); } void @@ -230,6 +238,7 @@ gst_rtsp_media_finalize (GObject * obj) g_source_destroy (media->source); g_source_unref (media->source); } + g_free (media->multicast_group); g_mutex_free (media->lock); g_cond_free (media->cond); @@ -258,6 +267,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_BUFFER_SIZE: g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media)); break; + case PROP_MULTICAST_GROUP: + g_value_take_string (value, gst_rtsp_media_get_multicast_group (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -285,6 +297,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_BUFFER_SIZE: gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value)); break; + case PROP_MULTICAST_GROUP: + gst_rtsp_media_set_multicast_group (media, g_value_get_string (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -528,6 +543,46 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) return media->buffer_size; } +/** + * gst_rtsp_media_set_multicast_group: + * @media: a #GstRTSPMedia + * @mc: the new multicast group + * + * Set the multicast group that media from @media will be streamed to. + */ +void +gst_rtsp_media_set_multicast_group (GstRTSPMedia * media, const gchar * mc) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + g_mutex_lock (media->lock); + g_free (media->multicast_group); + media->multicast_group = g_strdup (mc); + g_mutex_unlock (media->lock); +} + +/** + * gst_rtsp_media_get_multicast_group: + * @media: a #GstRTSPMedia + * + * Get the multicast group that media from @media will be streamed to. + * + * Returns: the multicast group + */ +gchar * +gst_rtsp_media_get_multicast_group (GstRTSPMedia * media) +{ + gchar *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + + g_mutex_lock (media->lock); + result = g_strdup (media->multicast_group); + g_mutex_unlock (media->lock); + + return result; +} + /** * gst_rtsp_media_set_auth: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 2f103af24a..09fe5248f1 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -203,6 +203,7 @@ struct _GstRTSPMedia { gboolean eos_shutdown; guint buffer_size; GstRTSPAuth *auth; + gchar *multicast_group; GstElement *element; GArray *streams; @@ -282,6 +283,10 @@ GstRTSPAuth * gst_rtsp_media_get_auth (GstRTSPMedia *media); void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size); guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media); +void gst_rtsp_media_set_multicast_group (GstRTSPMedia *media, const gchar * mc); +gchar * gst_rtsp_media_get_multicast_group (GstRTSPMedia *media); + + /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media); From 647e8c7af8fed431f2904e1bd7c0d2612092b995 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 13:27:39 +0200 Subject: [PATCH 0354/1776] media-factory: configure multicast in media --- gst/rtsp-server/rtsp-media-factory.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 3dd6559d3e..4106e61a1d 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -793,6 +793,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gboolean shared, eos_shutdown; guint size; GstRTSPAuth *auth; + gchar *mc; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -809,4 +810,8 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_auth (media, auth); g_object_unref (auth); } + if ((mc = gst_rtsp_media_factory_get_multicast_group (factory))) { + gst_rtsp_media_set_multicast_group (media, mc); + g_free (mc); + } } From a5e028ba72a195aa35f220b8ba7d49398f5995e0 Mon Sep 17 00:00:00 2001 From: Robert Krakora Date: Tue, 16 Aug 2011 13:31:52 +0200 Subject: [PATCH 0355/1776] sdp: copy and free the server ip address Copy and free the server ip address to make memory management easier later. --- gst/rtsp-server/rtsp-client.c | 7 +++++-- gst/rtsp-server/rtsp-sdp.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index af944080a2..e6150d9f53 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1096,19 +1096,22 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) info.server_proto = proto; if (media->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) - info.server_ip = MCAST_ADDRESS; + info.server_ip = g_strdup (MCAST_ADDRESS); else - info.server_ip = client->server_ip; + info.server_ip = g_strdup (client->server_ip); /* create an SDP for the media object */ if (!gst_rtsp_sdp_from_media (sdp, &info, media)) goto no_sdp; + g_free (info.server_ip); + return sdp; /* ERRORS */ no_sdp: { + g_free (info.server_ip); gst_sdp_message_free (sdp); return NULL; } diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h index 6c4c00549a..e6ac1b28cd 100644 --- a/gst/rtsp-server/rtsp-sdp.h +++ b/gst/rtsp-server/rtsp-sdp.h @@ -29,7 +29,7 @@ G_BEGIN_DECLS typedef struct { const gchar *server_proto; - const gchar *server_ip; + gchar *server_ip; } GstSDPInfo; /* creating SDP */ From 2c9701bd73686be01143c73feb6b095ccd03eb20 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 13:37:50 +0200 Subject: [PATCH 0356/1776] retab some .h --- gst/rtsp-server/rtsp-media-factory.h | 12 ++++++------ gst/rtsp-server/rtsp-server.h | 2 +- gst/rtsp-server/rtsp-session-pool.h | 2 +- gst/rtsp-server/rtsp-session.h | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index d2b8ee9088..4804a9de0b 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -94,15 +94,15 @@ struct _GstRTSPMediaFactory { struct _GstRTSPMediaFactoryClass { GObjectClass parent_class; - gchar * (*gen_key) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + gchar * (*gen_key) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); - GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); - GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); - void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); - GstElement * (*create_pipeline) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); + GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); + GstElement * (*create_pipeline) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); /* signals */ - void (*media_constructed)(GstRTSPMediaFactory *factory, GstRTSPMedia *media); + void (*media_constructed) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); }; GType gst_rtsp_media_factory_get_type (void); diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index cfbfbd7a58..98a3391dad 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -89,7 +89,7 @@ struct _GstRTSPServerClass { GstRTSPClient * (*create_client) (GstRTSPServer *server); gboolean (*accept_client) (GstRTSPServer *server, GstRTSPClient *client, GIOChannel *channel); - + /* signals */ void (*client_connected) (GstRTSPServer *server, GstRTSPClient *client); }; diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 3cd56d4ef8..f432208737 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -143,7 +143,7 @@ gboolean gst_rtsp_session_pool_remove (GstRTSPSessionPoo /* perform session maintenance */ GList * gst_rtsp_session_pool_filter (GstRTSPSessionPool *pool, GstRTSPSessionFilterFunc func, - gpointer user_data); + gpointer user_data); guint gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool); GSource * gst_rtsp_session_pool_create_watch (GstRTSPSessionPool *pool); diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 07efb1958d..4289ecba8f 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -132,7 +132,7 @@ gboolean gst_rtsp_session_is_expired (GstRTSPSession *se /* handle media in a session */ GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri, - GstRTSPMedia *media); + GstRTSPMedia *media); gboolean gst_rtsp_session_release_media (GstRTSPSession *sess, GstRTSPSessionMedia *media); /* get media in a session */ From 56a16f9f5a67c05f74b8c2ebf386f598280d652e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 13:43:44 +0200 Subject: [PATCH 0357/1776] client: use media multicast group --- gst/rtsp-server/rtsp-client.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e6150d9f53..a166e132db 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -36,9 +36,6 @@ #include "rtsp-sdp.h" #include "rtsp-params.h" -/* temporary multicast address until it's configurable somewhere */ -#define MCAST_ADDRESS "224.2.0.1" - static GMutex *tunnels_lock; static GHashTable *tunnels; @@ -970,7 +967,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) /* we have a valid transport now, set the destination of the client. */ g_free (ct->destination); if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - ct->destination = g_strdup (MCAST_ADDRESS); + ct->destination = gst_rtsp_media_get_multicast_group (media->media); } else { GstRTSPUrl *url; @@ -1096,7 +1093,7 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) info.server_proto = proto; if (media->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) - info.server_ip = g_strdup (MCAST_ADDRESS); + info.server_ip = gst_rtsp_media_get_multicast_group (media); else info.server_ip = g_strdup (client->server_ip); From 8684fc5c692324a0c0f5dd76dceda7acc3f67f87 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 15:03:06 +0200 Subject: [PATCH 0358/1776] media-factory: add media-configure signal Add signal to allow the application to configure the media after it was created from the factory. --- gst/rtsp-server/rtsp-media-factory.c | 11 +++++++++++ gst/rtsp-server/rtsp-media-factory.h | 1 + 2 files changed, 12 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 4106e61a1d..e67b6ab082 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -39,6 +39,7 @@ enum enum { SIGNAL_MEDIA_CONSTRUCTED, + SIGNAL_MEDIA_CONFIGURE, SIGNAL_LAST }; @@ -124,6 +125,12 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) media_constructed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA); + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE] = + g_signal_new ("media-configure", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, + media_configure), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA); + klass->gen_key = default_gen_key; klass->get_element = default_get_element; klass->construct = default_construct; @@ -576,6 +583,10 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, if (klass->configure) klass->configure (factory, media); + g_signal_emit (factory, + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE], 0, media, + NULL); + /* check if we can cache this media */ if (gst_rtsp_media_is_shared (media)) { /* insert in the hashtable, takes ownership of the key */ diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 4804a9de0b..f1d55aa313 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -103,6 +103,7 @@ struct _GstRTSPMediaFactoryClass { /* signals */ void (*media_constructed) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); + void (*media_configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); }; GType gst_rtsp_media_factory_get_type (void); From 0e9ce1caf387795b4348b1c21abd1e820b3fd40a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 15:15:19 +0200 Subject: [PATCH 0359/1776] media-factory: add protocols property Add a property to configure the allowed protocols in the media created from the factory. --- gst/rtsp-server/rtsp-media-factory.c | 50 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 35 ++++++++++++------- 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index e67b6ab082..ca4527ef4c 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -22,6 +22,7 @@ #define DEFAULT_LAUNCH NULL #define DEFAULT_SHARED FALSE #define DEFAULT_EOS_SHUTDOWN FALSE +#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_MULTICAST_GROUP "224.2.0.1" @@ -31,6 +32,7 @@ enum PROP_LAUNCH, PROP_SHARED, PROP_EOS_SHUTDOWN, + PROP_PROTOCOLS, PROP_BUFFER_SIZE, PROP_MULTICAST_GROUP, PROP_LAST @@ -109,6 +111,11 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "Send EOS down the pipeline before shutting down", DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PROTOCOLS, + g_param_spec_flags ("protocols", "Protocols", + "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS, + DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE, g_param_spec_uint ("buffer-size", "Buffer Size", "The kernel UDP buffer size to use", 0, G_MAXUINT, @@ -147,6 +154,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) factory->launch = g_strdup (DEFAULT_LAUNCH); factory->shared = DEFAULT_SHARED; factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN; + factory->protocols = DEFAULT_PROTOCOLS; factory->buffer_size = DEFAULT_BUFFER_SIZE; factory->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP); @@ -189,6 +197,9 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_boolean (value, gst_rtsp_media_factory_is_eos_shutdown (factory)); break; + case PROP_PROTOCOLS: + g_value_set_flags (value, gst_rtsp_media_factory_get_protocols (factory)); + break; case PROP_BUFFER_SIZE: g_value_set_uint (value, gst_rtsp_media_factory_get_buffer_size (factory)); @@ -219,6 +230,9 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_eos_shutdown (factory, g_value_get_boolean (value)); break; + case PROP_PROTOCOLS: + gst_rtsp_media_factory_set_protocols (factory, g_value_get_flags (value)); + break; case PROP_BUFFER_SIZE: gst_rtsp_media_factory_set_buffer_size (factory, g_value_get_uint (value)); @@ -512,6 +526,39 @@ gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_set_protocols: + * @factory: a #GstRTSPMediaFactory + * @protocols: the new flags + * + * Configure the allowed lower transport for @factory. + */ +void +gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * factory, + GstRTSPLowerTrans protocols) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + factory->protocols = protocols; +} + +/** + * gst_rtsp_media_factory_get_protocols: + * @factory: a #GstRTSPMediaFactory + * + * Get the allowed protocols of @factory. + * + * Returns: a #GstRTSPLowerTrans + */ +GstRTSPLowerTrans +gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory) +{ + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), + GST_RTSP_LOWER_TRANS_UNKNOWN); + + return factory->protocols; +} + static gboolean compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) { @@ -804,6 +851,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gboolean shared, eos_shutdown; guint size; GstRTSPAuth *auth; + GstRTSPLowerTrans protocols; gchar *mc; /* configure the sharedness */ @@ -811,11 +859,13 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) shared = factory->shared; eos_shutdown = factory->eos_shutdown; size = factory->buffer_size; + protocols = factory->protocols; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_shared (media, shared); gst_rtsp_media_set_eos_shutdown (media, eos_shutdown); gst_rtsp_media_set_buffer_size (media, size); + gst_rtsp_media_set_protocols (media, protocols); if ((auth = gst_rtsp_media_factory_get_auth (factory))) { gst_rtsp_media_set_auth (media, auth); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index f1d55aa313..225d9b26d6 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -50,25 +50,31 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; * @lock: mutex protecting the datastructure. * @launch: the launch description * @shared: if media from this factory can be shared between clients - * @media_lock: mutex protecting the medias. - * @media: hashtable of shared media + * @eos_shutdown: if shutdown should first send EOS to the pipeline + * @protocols: allowed transport protocols + * @auth: the authentication manager + * @buffer_size: the kernel udp buffer size + * @multicast_group: the multicast group to send to + * @medias_lock: mutex protecting the medias. + * @medias: hashtable of shared media * * The definition and logic for constructing the pipeline for a media. The media * can contain multiple streams like audio and video. */ struct _GstRTSPMediaFactory { - GObject parent; + GObject parent; - GMutex *lock; - gchar *launch; - gboolean shared; - gboolean eos_shutdown; - GstRTSPAuth *auth; - guint buffer_size; - gchar *multicast_group; + GMutex *lock; + gchar *launch; + gboolean shared; + gboolean eos_shutdown; + GstRTSPLowerTrans protocols; + GstRTSPAuth *auth; + guint buffer_size; + gchar *multicast_group; - GMutex *medias_lock; - GHashTable *medias; + GMutex *medias_lock; + GHashTable *medias; }; /** @@ -88,6 +94,8 @@ struct _GstRTSPMediaFactory { * implementation will configure the 'shared' property of the media. * @create_pipeline: create a new pipeline or re-use an existing one and * add the #GstRTSPMedia's element created by @construct to the pipeline. + * @media_constructed: signal emited when a media was cunstructed + * @media_configure: signal emited when a media should be configured * * The #GstRTSPMediaFactory class structure. */ @@ -124,6 +132,9 @@ void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFac gboolean eos_shutdown); gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory *factory, GstRTSPLowerTrans protocols); +GstRTSPLowerTrans gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory *factory); + void gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory *factory, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory *factory); From 6fa73b255278edf0350b7860beca72abd5f97633 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 16:07:04 +0200 Subject: [PATCH 0360/1776] client: use method to access property --- gst/rtsp-server/rtsp-client.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 9b8e6ce8aa..3d4dd69126 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1070,6 +1070,7 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) GstSDPMessage *sdp; GstSDPInfo info; const gchar *proto; + GstRTSPLowerTrans protocols; gst_sdp_message_new (&sdp); @@ -1092,7 +1093,8 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) gst_sdp_message_add_attribute (sdp, "control", "*"); info.server_proto = proto; - if (media->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) + protocols = gst_rtsp_media_get_protocols (media); + if (protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) info.server_ip = gst_rtsp_media_get_multicast_group (media); else info.server_ip = g_strdup (client->server_ip); From 85e2013ca443bf69634771a7c9976f4ac2237cbe Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 15:03:06 +0200 Subject: [PATCH 0361/1776] media-factory: add media-configure signal Add signal to allow the application to configure the media after it was created from the factory. --- gst/rtsp-server/rtsp-media-factory.c | 11 +++++++++++ gst/rtsp-server/rtsp-media-factory.h | 1 + 2 files changed, 12 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 4106e61a1d..e67b6ab082 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -39,6 +39,7 @@ enum enum { SIGNAL_MEDIA_CONSTRUCTED, + SIGNAL_MEDIA_CONFIGURE, SIGNAL_LAST }; @@ -124,6 +125,12 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) media_constructed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA); + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE] = + g_signal_new ("media-configure", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, + media_configure), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA); + klass->gen_key = default_gen_key; klass->get_element = default_get_element; klass->construct = default_construct; @@ -576,6 +583,10 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, if (klass->configure) klass->configure (factory, media); + g_signal_emit (factory, + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE], 0, media, + NULL); + /* check if we can cache this media */ if (gst_rtsp_media_is_shared (media)) { /* insert in the hashtable, takes ownership of the key */ diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 4804a9de0b..f1d55aa313 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -103,6 +103,7 @@ struct _GstRTSPMediaFactoryClass { /* signals */ void (*media_constructed) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); + void (*media_configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); }; GType gst_rtsp_media_factory_get_type (void); From 4c8f3696d01016c0df74c7721e5900bc89fa5ff4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 15:15:19 +0200 Subject: [PATCH 0362/1776] media-factory: add protocols property Add a property to configure the allowed protocols in the media created from the factory. --- gst/rtsp-server/rtsp-media-factory.c | 50 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 35 ++++++++++++------- 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index e67b6ab082..ca4527ef4c 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -22,6 +22,7 @@ #define DEFAULT_LAUNCH NULL #define DEFAULT_SHARED FALSE #define DEFAULT_EOS_SHUTDOWN FALSE +#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_MULTICAST_GROUP "224.2.0.1" @@ -31,6 +32,7 @@ enum PROP_LAUNCH, PROP_SHARED, PROP_EOS_SHUTDOWN, + PROP_PROTOCOLS, PROP_BUFFER_SIZE, PROP_MULTICAST_GROUP, PROP_LAST @@ -109,6 +111,11 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "Send EOS down the pipeline before shutting down", DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PROTOCOLS, + g_param_spec_flags ("protocols", "Protocols", + "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS, + DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE, g_param_spec_uint ("buffer-size", "Buffer Size", "The kernel UDP buffer size to use", 0, G_MAXUINT, @@ -147,6 +154,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) factory->launch = g_strdup (DEFAULT_LAUNCH); factory->shared = DEFAULT_SHARED; factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN; + factory->protocols = DEFAULT_PROTOCOLS; factory->buffer_size = DEFAULT_BUFFER_SIZE; factory->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP); @@ -189,6 +197,9 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_boolean (value, gst_rtsp_media_factory_is_eos_shutdown (factory)); break; + case PROP_PROTOCOLS: + g_value_set_flags (value, gst_rtsp_media_factory_get_protocols (factory)); + break; case PROP_BUFFER_SIZE: g_value_set_uint (value, gst_rtsp_media_factory_get_buffer_size (factory)); @@ -219,6 +230,9 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_eos_shutdown (factory, g_value_get_boolean (value)); break; + case PROP_PROTOCOLS: + gst_rtsp_media_factory_set_protocols (factory, g_value_get_flags (value)); + break; case PROP_BUFFER_SIZE: gst_rtsp_media_factory_set_buffer_size (factory, g_value_get_uint (value)); @@ -512,6 +526,39 @@ gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_set_protocols: + * @factory: a #GstRTSPMediaFactory + * @protocols: the new flags + * + * Configure the allowed lower transport for @factory. + */ +void +gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * factory, + GstRTSPLowerTrans protocols) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + factory->protocols = protocols; +} + +/** + * gst_rtsp_media_factory_get_protocols: + * @factory: a #GstRTSPMediaFactory + * + * Get the allowed protocols of @factory. + * + * Returns: a #GstRTSPLowerTrans + */ +GstRTSPLowerTrans +gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory) +{ + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), + GST_RTSP_LOWER_TRANS_UNKNOWN); + + return factory->protocols; +} + static gboolean compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) { @@ -804,6 +851,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gboolean shared, eos_shutdown; guint size; GstRTSPAuth *auth; + GstRTSPLowerTrans protocols; gchar *mc; /* configure the sharedness */ @@ -811,11 +859,13 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) shared = factory->shared; eos_shutdown = factory->eos_shutdown; size = factory->buffer_size; + protocols = factory->protocols; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_shared (media, shared); gst_rtsp_media_set_eos_shutdown (media, eos_shutdown); gst_rtsp_media_set_buffer_size (media, size); + gst_rtsp_media_set_protocols (media, protocols); if ((auth = gst_rtsp_media_factory_get_auth (factory))) { gst_rtsp_media_set_auth (media, auth); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index f1d55aa313..225d9b26d6 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -50,25 +50,31 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; * @lock: mutex protecting the datastructure. * @launch: the launch description * @shared: if media from this factory can be shared between clients - * @media_lock: mutex protecting the medias. - * @media: hashtable of shared media + * @eos_shutdown: if shutdown should first send EOS to the pipeline + * @protocols: allowed transport protocols + * @auth: the authentication manager + * @buffer_size: the kernel udp buffer size + * @multicast_group: the multicast group to send to + * @medias_lock: mutex protecting the medias. + * @medias: hashtable of shared media * * The definition and logic for constructing the pipeline for a media. The media * can contain multiple streams like audio and video. */ struct _GstRTSPMediaFactory { - GObject parent; + GObject parent; - GMutex *lock; - gchar *launch; - gboolean shared; - gboolean eos_shutdown; - GstRTSPAuth *auth; - guint buffer_size; - gchar *multicast_group; + GMutex *lock; + gchar *launch; + gboolean shared; + gboolean eos_shutdown; + GstRTSPLowerTrans protocols; + GstRTSPAuth *auth; + guint buffer_size; + gchar *multicast_group; - GMutex *medias_lock; - GHashTable *medias; + GMutex *medias_lock; + GHashTable *medias; }; /** @@ -88,6 +94,8 @@ struct _GstRTSPMediaFactory { * implementation will configure the 'shared' property of the media. * @create_pipeline: create a new pipeline or re-use an existing one and * add the #GstRTSPMedia's element created by @construct to the pipeline. + * @media_constructed: signal emited when a media was cunstructed + * @media_configure: signal emited when a media should be configured * * The #GstRTSPMediaFactory class structure. */ @@ -124,6 +132,9 @@ void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFac gboolean eos_shutdown); gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory *factory, GstRTSPLowerTrans protocols); +GstRTSPLowerTrans gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory *factory); + void gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory *factory, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory *factory); From 6759a4b9b01c8472fb1854581a3d09c822a22954 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Aug 2011 16:07:04 +0200 Subject: [PATCH 0363/1776] client: use method to access property --- gst/rtsp-server/rtsp-client.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a166e132db..7e05ff9580 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1070,6 +1070,7 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) GstSDPMessage *sdp; GstSDPInfo info; const gchar *proto; + GstRTSPLowerTrans protocols; gst_sdp_message_new (&sdp); @@ -1092,7 +1093,8 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) gst_sdp_message_add_attribute (sdp, "control", "*"); info.server_proto = proto; - if (media->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) + protocols = gst_rtsp_media_get_protocols (media); + if (protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) info.server_ip = gst_rtsp_media_get_multicast_group (media); else info.server_ip = g_strdup (client->server_ip); From d2fda7986dadc3cb0059c8b5e3e88dbeb568f1a4 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 6 Sep 2011 16:07:18 +0200 Subject: [PATCH 0364/1776] Automatic update of common submodule From 605cd9a to a39eb83 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 605cd9a65e..a39eb835fb 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 605cd9a65ed61505f24b840d3fe8e252be72b151 +Subproject commit a39eb835fb3be2a4c5a6a89b5ca5cc064e79b2e2 From 6ad4b79c7ebc333f96cc0acb2b4881c402b92e5d Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 6 Sep 2011 21:53:46 +0200 Subject: [PATCH 0365/1776] Automatic update of common submodule From a39eb83 to 11f0cd5 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index a39eb835fb..11f0cd5a3f 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit a39eb835fb3be2a4c5a6a89b5ca5cc064e79b2e2 +Subproject commit 11f0cd5a3fba36f85cf3e434150bfe66b1bf08d4 From 20b6be38527123836c656570b1d503fc7967ca39 Mon Sep 17 00:00:00 2001 From: mat Date: Thu, 3 Nov 2011 10:48:40 +0100 Subject: [PATCH 0366/1776] #ifdef statements for windows socket creation were missing --- gst/rtsp-server/rtsp-server.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 4477d8d23b..f1f431ffe4 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -650,7 +650,11 @@ gst_rtsp_server_get_io_channel (GstRTSPServer * server) "listened on server socket %d, returning from connection setup", sockfd); /* create IO channel for the socket */ +#ifdef G_OS_WIN32 + channel = g_io_channel_win32_new_socket (sockfd); +#else channel = g_io_channel_unix_new (sockfd); +#endif g_io_channel_set_close_on_unref (channel, TRUE); GST_INFO_OBJECT (server, "listening on service %s", server->service); From 526bbb5a8fab7bf5a83f871819442bb2cc6dd26a Mon Sep 17 00:00:00 2001 From: Victor Gottardi Date: Fri, 16 Sep 2011 11:31:17 -0400 Subject: [PATCH 0367/1776] Disallow seek in live media --- gst/rtsp-server/rtsp-media.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index aaba0679ed..44d337641b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -720,6 +720,11 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (range != NULL, FALSE); + if (media->is_live) { + GST_INFO ("no seek in live media"); + return TRUE; + } + if (range->unit != GST_RTSP_RANGE_NPT) goto not_supported; From a701e8595e1fbf005be31cb5a01660e6acdb6818 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 3 Nov 2011 12:55:24 +0100 Subject: [PATCH 0368/1776] media: add a seekable boolean Maintain the seekable state with a new variable instead of reusing the is_live variable. --- gst/rtsp-server/rtsp-media.c | 10 ++++++++-- gst/rtsp-server/rtsp-media.h | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 44d337641b..96d039e8f4 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -720,8 +720,8 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (range != NULL, FALSE); - if (media->is_live) { - GST_INFO ("no seek in live media"); + if (media->seekable) { + GST_INFO ("pipeline is not seekable"); return TRUE; } @@ -1711,6 +1711,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) /* reset some variables */ media->is_live = FALSE; + media->seekable = FALSE; media->buffering = FALSE; /* we're preparing now */ media->status = GST_RTSP_MEDIA_STATUS_PREPARING; @@ -1764,13 +1765,18 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) switch (ret) { case GST_STATE_CHANGE_SUCCESS: GST_INFO ("SUCCESS state change for media %p", media); + media->seekable = TRUE; break; case GST_STATE_CHANGE_ASYNC: GST_INFO ("ASYNC state change for media %p", media); + media->seekable = TRUE; break; case GST_STATE_CHANGE_NO_PREROLL: /* we need to go to PLAYING */ GST_INFO ("NO_PREROLL state change: live media %p", media); + /* FIXME we disable seeking for live streams for now. We should perform a + * seeking query in preroll instead and do a seeking query. */ + media->seekable = FALSE; media->is_live = TRUE; ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 09fe5248f1..a7334edb90 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -179,6 +179,7 @@ typedef enum { * @source: the bus watch for pipeline messages. * @id: the id of the watch * @is_live: if the pipeline is live + * @seekable: if the pipeline can perform a seek * @buffering: if the pipeline is buffering * @target_state: the desired target state of the pipeline * @rtpbin: the rtpbin @@ -220,6 +221,7 @@ struct _GstRTSPMedia { guint id; gboolean is_live; + gboolean seekable; gboolean buffering; GstState target_state; From 7a91860832830c9740548a3bae85b144bbc42af6 Mon Sep 17 00:00:00 2001 From: Fabian Deutsch Date: Thu, 3 Nov 2011 16:06:23 +0100 Subject: [PATCH 0369/1776] bindings: Fix vala binding of gst_rtsp_media_mapping_add_factory to transfer ownership. Signed-off-by: Fabian Deutsch --- bindings/vala/packages/gst-rtsp-server-0.10.metadata | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.metadata b/bindings/vala/packages/gst-rtsp-server-0.10.metadata index b944eb697f..a69c2ed53e 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.metadata +++ b/bindings/vala/packages/gst-rtsp-server-0.10.metadata @@ -27,6 +27,7 @@ gst_rtsp_media_factory_get_element transfer_ownership="1" nullable="1" gst_rtsp_media_factory_create_pipeline transfer_ownership="1" gst_rtsp_media_mapping_find_factory transfer_ownership="1" nullable="1" gst_rtsp_media_mapping_find_media transfer_ownership="1" nullable="1" +gst_rtsp_media_mapping_add_factory transfer_ownership="1" gst_rtsp_sdp_from_media.sdp is_ref="1" gst_rtsp_server_accept_client transfer_ownership="1" nullable="1" gst_rtsp_server_create_watch transfer_ownership="1" nullable="1" From b28b3223fd0b909bb85f3f7edda121a1d38bc244 Mon Sep 17 00:00:00 2001 From: Fabian Deutsch Date: Thu, 3 Nov 2011 16:06:23 +0100 Subject: [PATCH 0370/1776] bindings: Fix vala binding of gst_rtsp_media_mapping_add_factory to transfer ownership. Signed-off-by: Fabian Deutsch --- bindings/vala/packages/gst-rtsp-server-0.10.metadata | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.metadata b/bindings/vala/packages/gst-rtsp-server-0.10.metadata index b944eb697f..a69c2ed53e 100644 --- a/bindings/vala/packages/gst-rtsp-server-0.10.metadata +++ b/bindings/vala/packages/gst-rtsp-server-0.10.metadata @@ -27,6 +27,7 @@ gst_rtsp_media_factory_get_element transfer_ownership="1" nullable="1" gst_rtsp_media_factory_create_pipeline transfer_ownership="1" gst_rtsp_media_mapping_find_factory transfer_ownership="1" nullable="1" gst_rtsp_media_mapping_find_media transfer_ownership="1" nullable="1" +gst_rtsp_media_mapping_add_factory transfer_ownership="1" gst_rtsp_sdp_from_media.sdp is_ref="1" gst_rtsp_server_accept_client transfer_ownership="1" nullable="1" gst_rtsp_server_create_watch transfer_ownership="1" nullable="1" From fde25cd9c3b01594310dc4a65f508f4fc4b91bb3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 9 Dec 2011 10:53:30 +0100 Subject: [PATCH 0371/1776] rtsp-server: port some more to 0.11 Fix caps. Remove bufferlist stuff Update for new API. Add queue before appsink now that preroll-queue-len is gone. Update for request pad changes. --- examples/test-video.c | 4 +- gst/rtsp-server/rtsp-client.c | 6 +- gst/rtsp-server/rtsp-media-factory-uri.c | 4 +- gst/rtsp-server/rtsp-media.c | 103 ++++++++++------------- gst/rtsp-server/rtsp-media.h | 4 +- gst/rtsp-server/rtsp-session.c | 6 +- gst/rtsp-server/rtsp-session.h | 2 - 7 files changed, 51 insertions(+), 78 deletions(-) diff --git a/examples/test-video.c b/examples/test-video.c index c39c8b0828..b2536cb725 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -80,9 +80,9 @@ main (int argc, char *argv[]) * element with pay%d names will be a stream */ factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, "( " - "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " + "videotestsrc ! video/x-raw,width=352,height=288,framerate=15/1 ! " "x264enc ! rtph264pay name=pay0 pt=96 " - "audiotestsrc ! audio/x-raw-int,rate=8000 ! " + "audiotestsrc ! audio/x-raw,rate=8000 ! " "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); /* attach the test factory to the /test url */ diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3d4dd69126..393884e546 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -445,8 +445,7 @@ link_stream (GstRTSPClient * client, GstRTSPSession * session, { GST_DEBUG ("client %p: linking stream %p", client, stream); gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data, - (GstRTSPSendFunc) do_send_data, (GstRTSPSendListFunc) do_send_data_list, - (GstRTSPSendListFunc) do_send_data_list, client, NULL); + (GstRTSPSendFunc) do_send_data, client, NULL); client->streams = g_list_prepend (client->streams, stream); /* make sure our session can't expire */ gst_rtsp_session_prevent_expire (session); @@ -457,8 +456,7 @@ unlink_stream (GstRTSPClient * client, GstRTSPSession * session, GstRTSPSessionStream * stream) { GST_DEBUG ("client %p: unlinking stream %p", client, stream); - gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL, NULL, - NULL); + gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); client->streams = g_list_remove (client->streams, stream); /* our session can now expire */ gst_rtsp_session_allow_expire (session); diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 2d38eea26e..2f32d2b418 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -394,7 +394,7 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) /* get pad caps first, then call get_caps, then fail */ if ((caps = gst_pad_get_current_caps (pad)) == NULL) - if ((caps = gst_pad_get_caps (pad, NULL)) == NULL) + if ((caps = gst_pad_query_caps (pad, NULL)) == NULL) goto no_caps; /* check for raw caps */ @@ -422,7 +422,7 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) /* continue with new pad and caps */ pad = gst_element_get_static_pad (convert, "src"); if ((caps = gst_pad_get_current_caps (pad)) == NULL) - if ((caps = gst_pad_get_caps (pad, NULL)) == NULL) + if ((caps = gst_pad_query_caps (pad, NULL)) == NULL) goto no_caps; } diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index ddf2d5bf45..028407e18d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1197,17 +1197,19 @@ on_timeout (GObject * session, GObject * source, GstRTSPMediaStream * stream) } static GstFlowReturn -handle_new_buffer (GstAppSink * sink, gpointer user_data) +handle_new_sample (GstAppSink * sink, gpointer user_data) { GList *walk; + GstSample *sample; GstBuffer *buffer; GstRTSPMediaStream *stream; - buffer = gst_app_sink_pull_buffer (sink); - if (!buffer) + sample = gst_app_sink_pull_sample (sink); + if (!sample) return GST_FLOW_OK; stream = (GstRTSPMediaStream *) user_data; + buffer = gst_sample_get_buffer (sample); for (walk = stream->transports; walk; walk = g_list_next (walk)) { GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data; @@ -1220,47 +1222,15 @@ handle_new_buffer (GstAppSink * sink, gpointer user_data) tr->send_rtcp (buffer, tr->transport->interleaved.max, tr->user_data); } } - gst_buffer_unref (buffer); - - return GST_FLOW_OK; -} - -static GstFlowReturn -handle_new_buffer_list (GstAppSink * sink, gpointer user_data) -{ - GList *walk; - GstBufferList *blist; - GstRTSPMediaStream *stream; - - blist = gst_app_sink_pull_buffer_list (sink); - if (!blist) - return GST_FLOW_OK; - - stream = (GstRTSPMediaStream *) user_data; - - for (walk = stream->transports; walk; walk = g_list_next (walk)) { - GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data; - - if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) { - if (tr->send_rtp_list) - tr->send_rtp_list (blist, tr->transport->interleaved.min, - tr->user_data); - } else { - if (tr->send_rtcp_list) - tr->send_rtcp_list (blist, tr->transport->interleaved.max, - tr->user_data); - } - } - gst_buffer_list_unref (blist); + gst_sample_unref (sample); return GST_FLOW_OK; } static GstAppSinkCallbacks sink_cb = { NULL, /* not interested in EOS */ - NULL, /* not interested in preroll buffers */ - handle_new_buffer, - handle_new_buffer_list + NULL, /* not interested in preroll samples */ + handle_new_sample, }; /* prepare the pipeline objects to handle @stream in @media */ @@ -1268,7 +1238,7 @@ static gboolean setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) { gchar *name; - GstPad *pad, *teepad, *selpad; + GstPad *pad, *teepad, *queuepad, *selpad; GstPadLinkReturn ret; gint i; @@ -1287,10 +1257,11 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) /* create elements for the TCP transfer */ for (i = 0; i < 2; i++) { stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL); + stream->appqueue[i] = gst_element_factory_make ("queue", NULL); stream->appsink[i] = gst_element_factory_make ("appsink", NULL); g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL); g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL); - g_object_set (stream->appsink[i], "preroll-queue-len", 1, NULL); + gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appqueue[i]); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsink[i]); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsrc[i]); gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]), @@ -1298,19 +1269,19 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) } /* hook up the stream to the RTP session elements. */ - name = g_strdup_printf ("send_rtp_sink_%d", idx); + name = g_strdup_printf ("send_rtp_sink_%u", idx); stream->send_rtp_sink = gst_element_get_request_pad (media->rtpbin, name); g_free (name); - name = g_strdup_printf ("send_rtp_src_%d", idx); + name = g_strdup_printf ("send_rtp_src_%u", idx); stream->send_rtp_src = gst_element_get_static_pad (media->rtpbin, name); g_free (name); - name = g_strdup_printf ("send_rtcp_src_%d", idx); + name = g_strdup_printf ("send_rtcp_src_%u", idx); stream->send_rtcp_src = gst_element_get_request_pad (media->rtpbin, name); g_free (name); - name = g_strdup_printf ("recv_rtcp_sink_%d", idx); + name = g_strdup_printf ("recv_rtcp_sink_%u", idx); stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name); g_free (name); - name = g_strdup_printf ("recv_rtp_sink_%d", idx); + name = g_strdup_printf ("recv_rtp_sink_%u", idx); stream->recv_rtp_sink = gst_element_get_request_pad (media->rtpbin, name); g_free (name); @@ -1345,18 +1316,24 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) gst_object_unref (pad); /* link RTP sink, we're pretty sure this will work. */ - teepad = gst_element_get_request_pad (stream->tee[0], "src%d"); + teepad = gst_element_get_request_pad (stream->tee[0], "src_%u"); pad = gst_element_get_static_pad (stream->udpsink[0], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); - teepad = gst_element_get_request_pad (stream->tee[0], "src%d"); - pad = gst_element_get_static_pad (stream->appsink[0], "sink"); + teepad = gst_element_get_request_pad (stream->tee[0], "src_%u"); + pad = gst_element_get_static_pad (stream->appqueue[0], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); + queuepad = gst_element_get_static_pad (stream->appqueue[0], "src"); + pad = gst_element_get_static_pad (stream->appsink[0], "sink"); + gst_pad_link (queuepad, pad); + gst_object_unref (pad); + gst_object_unref (queuepad); + /* make tee for RTCP */ stream->tee[1] = gst_element_factory_make ("tee", NULL); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[1]); @@ -1366,18 +1343,24 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) gst_object_unref (pad); /* link RTCP elements */ - teepad = gst_element_get_request_pad (stream->tee[1], "src%d"); + teepad = gst_element_get_request_pad (stream->tee[1], "src_%u"); pad = gst_element_get_static_pad (stream->udpsink[1], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); - teepad = gst_element_get_request_pad (stream->tee[1], "src%d"); - pad = gst_element_get_static_pad (stream->appsink[1], "sink"); + teepad = gst_element_get_request_pad (stream->tee[1], "src_%u"); + pad = gst_element_get_static_pad (stream->appqueue[1], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); + queuepad = gst_element_get_static_pad (stream->appqueue[1], "src"); + pad = gst_element_get_static_pad (stream->appsink[1], "sink"); + gst_pad_link (queuepad, pad); + gst_object_unref (pad); + gst_object_unref (queuepad); + /* make selector for the RTP receivers */ stream->selector[0] = gst_element_factory_make ("funnel", NULL); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]); @@ -1386,13 +1369,13 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) gst_pad_link (pad, stream->recv_rtp_sink); gst_object_unref (pad); - selpad = gst_element_get_request_pad (stream->selector[0], "sink%d"); + selpad = gst_element_get_request_pad (stream->selector[0], "sink_%u"); pad = gst_element_get_static_pad (stream->udpsrc[0], "src"); gst_pad_link (pad, selpad); gst_object_unref (pad); gst_object_unref (selpad); - selpad = gst_element_get_request_pad (stream->selector[0], "sink%d"); + selpad = gst_element_get_request_pad (stream->selector[0], "sink_%u"); pad = gst_element_get_static_pad (stream->appsrc[0], "src"); gst_pad_link (pad, selpad); gst_object_unref (pad); @@ -1406,13 +1389,13 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) gst_pad_link (pad, stream->recv_rtcp_sink); gst_object_unref (pad); - selpad = gst_element_get_request_pad (stream->selector[1], "sink%d"); + selpad = gst_element_get_request_pad (stream->selector[1], "sink_%u"); pad = gst_element_get_static_pad (stream->udpsrc[1], "src"); gst_pad_link (pad, selpad); gst_object_unref (pad); gst_object_unref (selpad); - selpad = gst_element_get_request_pad (stream->selector[1], "sink%d"); + selpad = gst_element_get_request_pad (stream->selector[1], "sink_%u"); pad = gst_element_get_static_pad (stream->appsrc[1], "src"); gst_pad_link (pad, selpad); gst_object_unref (pad); @@ -1701,9 +1684,9 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) if (!media->reusable && media->reused) goto is_reused; - media->rtpbin = gst_element_factory_make ("gstrtpbin", NULL); + media->rtpbin = gst_element_factory_make ("rtpbin", NULL); if (media->rtpbin == NULL) - goto no_gstrtpbin; + goto no_rtpbin; GST_INFO ("preparing media %p", media); @@ -1804,10 +1787,10 @@ is_reused: GST_WARNING ("can not reuse media %p", media); return FALSE; } -no_gstrtpbin: +no_rtpbin: { - GST_WARNING ("no gstrtpbin element"); - g_warning ("failed to create element 'gstrtpbin', check your installation"); + GST_WARNING ("no rtpbin element"); + g_warning ("failed to create element 'rtpbin', check your installation"); return FALSE; } state_failed: diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index a7334edb90..38f7c353b6 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -42,7 +42,6 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass; typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans; typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); -typedef gboolean (*GstRTSPSendListFunc) (GstBufferList *blist, guint8 channel, gpointer user_data); typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); /** @@ -69,8 +68,6 @@ struct _GstRTSPMediaTrans { GstRTSPSendFunc send_rtp; GstRTSPSendFunc send_rtcp; - GstRTSPSendListFunc send_rtp_list; - GstRTSPSendListFunc send_rtcp_list; gpointer user_data; GDestroyNotify notify; @@ -128,6 +125,7 @@ struct _GstRTSPMediaStream { GstElement *udpsink[2]; /* for TCP transport */ GstElement *appsrc[2]; + GstElement *appqueue[2]; GstElement *appsink[2]; GstElement *tee[2]; diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index ce86d43f27..de16415cb6 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -82,8 +82,7 @@ gst_rtsp_session_free_stream (GstRTSPSessionStream * stream) GST_INFO ("free session stream %p", stream); /* remove callbacks now */ - gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL, NULL, - NULL); + gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); gst_rtsp_session_stream_set_keepalive (stream, NULL, NULL, NULL); gst_rtsp_media_trans_cleanup (&stream->trans); @@ -564,13 +563,10 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream, void gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream * stream, GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, - GstRTSPSendListFunc send_rtp_list, GstRTSPSendListFunc send_rtcp_list, gpointer user_data, GDestroyNotify notify) { stream->trans.send_rtp = send_rtp; stream->trans.send_rtcp = send_rtcp; - stream->trans.send_rtp_list = send_rtp_list; - stream->trans.send_rtcp_list = send_rtcp_list; if (stream->trans.notify) stream->trans.notify (stream->trans.user_data); stream->trans.user_data = user_data; diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 4289ecba8f..973f196cf4 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -154,8 +154,6 @@ GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStre void gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream *stream, GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, - GstRTSPSendListFunc send_rtp_list, - GstRTSPSendListFunc send_rtcp_list, gpointer user_data, GDestroyNotify notify); void gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream *stream, From 57775e09995210e650ad555770e3f6fdbd3a2284 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 9 Dec 2011 11:00:46 +0100 Subject: [PATCH 0372/1776] example: update for new caps --- examples/test-auth.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/test-auth.c b/examples/test-auth.c index 915173aa21..5cba45bff9 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -62,9 +62,9 @@ main (int argc, char *argv[]) * element with pay%d names will be a stream */ factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, "( " - "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! " + "videotestsrc ! video/x-raw,width=352,height=288,framerate=15/1 ! " "x264enc ! rtph264pay name=pay0 pt=96 " - "audiotestsrc ! audio/x-raw-int,rate=8000 ! " + "audiotestsrc ! audio/x-raw,rate=8000 ! " "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); /* make a new authentication manager */ @@ -80,7 +80,7 @@ main (int argc, char *argv[]) /* make another factory */ factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, "( " - "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=30/1 ! " + "videotestsrc ! video/x-raw,width=352,height=288,framerate=30/1 ! " "x264enc ! rtph264pay name=pay0 pt=96 )"); /* make a new authentication manager */ auth = gst_rtsp_auth_new (); From 32cee2beaf4b5ce7db28c793cd22101504febe9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 4 Jan 2012 19:56:02 +0000 Subject: [PATCH 0373/1776] Automatic update of common submodule From 11f0cd5 to 0807187 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 11f0cd5a3f..08071872d3 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 11f0cd5a3fba36f85cf3e434150bfe66b1bf08d4 +Subproject commit 08071872d3d2aaf10a13170809b04e86fa5e87be From 054267e64259cf51099fdfcf2652d147a9ffebac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 18 Jan 2012 16:48:41 +0100 Subject: [PATCH 0374/1776] Automatic update of common submodule From 0807187 to 2a59016 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 08071872d3..2a59016f13 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 08071872d3d2aaf10a13170809b04e86fa5e87be +Subproject commit 2a59016f13316d1e7992fca4d3d8aab20c2ce512 From 8d5716f232d18f156f66fb37fca207ad0dc829fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 25 Jan 2012 11:40:59 +0100 Subject: [PATCH 0375/1776] Automatic update of common submodule From 2a59016 to c463bc0 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 2a59016f13..c463bc0b05 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 2a59016f13316d1e7992fca4d3d8aab20c2ce512 +Subproject commit c463bc0b05e14a0eec30558fd08bb109f789d7c8 From e8117344328f34e8338a6ea77dcdee272ad180a2 Mon Sep 17 00:00:00 2001 From: Thomas Vander Stichele Date: Wed, 25 Jan 2012 14:12:41 +0100 Subject: [PATCH 0376/1776] Automatic update of common submodule From c463bc0 to 7fda524 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index c463bc0b05..7fda5249ab 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit c463bc0b05e14a0eec30558fd08bb109f789d7c8 +Subproject commit 7fda5249ab56f0de09277df330780a3b90a2b306 From 2ea47851c061cd9c38e73a453155a746edfbf940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 13 Feb 2012 10:37:37 +0000 Subject: [PATCH 0377/1776] python: remove pygst-based python bindings pygi is the future, apparently. --- .gitignore | 1 - bindings/Makefile.am | 4 - bindings/python/Makefile.am | 46 - bindings/python/arg-types.py | 451 ------ bindings/python/codegen/Makefile.am | 15 - bindings/python/codegen/__init__.py | 15 - bindings/python/codegen/argtypes.py | 1075 ------------- bindings/python/codegen/code-coverage.py | 42 - bindings/python/codegen/codegen.py | 1572 ------------------- bindings/python/codegen/definitions.py | 607 ------- bindings/python/codegen/defsparser.py | 143 -- bindings/python/codegen/docextract.py | 185 --- bindings/python/codegen/docgen.py | 752 --------- bindings/python/codegen/fileprefix.override | 12 - bindings/python/codegen/fileprefixmodule.c | 31 - bindings/python/codegen/h2def.py | 536 ------- bindings/python/codegen/mergedefs.py | 26 - bindings/python/codegen/mkskel.py | 89 -- bindings/python/codegen/override.py | 288 ---- bindings/python/codegen/reversewrapper.py | 771 --------- bindings/python/codegen/scmexpr.py | 144 -- bindings/python/rtspserver-types.defs | 63 - bindings/python/rtspserver.defs | 399 ----- bindings/python/rtspserver.override | 87 - bindings/python/rtspservermodule.c | 31 - bindings/python/test.py | 130 -- configure.ac | 51 - 27 files changed, 7566 deletions(-) delete mode 100644 bindings/python/Makefile.am delete mode 100644 bindings/python/arg-types.py delete mode 100644 bindings/python/codegen/Makefile.am delete mode 100644 bindings/python/codegen/__init__.py delete mode 100644 bindings/python/codegen/argtypes.py delete mode 100755 bindings/python/codegen/code-coverage.py delete mode 100644 bindings/python/codegen/codegen.py delete mode 100644 bindings/python/codegen/definitions.py delete mode 100644 bindings/python/codegen/defsparser.py delete mode 100644 bindings/python/codegen/docextract.py delete mode 100644 bindings/python/codegen/docgen.py delete mode 100644 bindings/python/codegen/fileprefix.override delete mode 100644 bindings/python/codegen/fileprefixmodule.c delete mode 100755 bindings/python/codegen/h2def.py delete mode 100755 bindings/python/codegen/mergedefs.py delete mode 100755 bindings/python/codegen/mkskel.py delete mode 100644 bindings/python/codegen/override.py delete mode 100644 bindings/python/codegen/reversewrapper.py delete mode 100644 bindings/python/codegen/scmexpr.py delete mode 100644 bindings/python/rtspserver-types.defs delete mode 100644 bindings/python/rtspserver.defs delete mode 100644 bindings/python/rtspserver.override delete mode 100644 bindings/python/rtspservermodule.c delete mode 100644 bindings/python/test.py diff --git a/.gitignore b/.gitignore index 780c799642..c84ca4c3a4 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,6 @@ libtool ltmain.sh missing stamp-h1 -bindings/python/rtspserver.c tags gst-rtsp.spec stamp-h.in diff --git a/bindings/Makefile.am b/bindings/Makefile.am index b193731205..7a9ca5ad71 100644 --- a/bindings/Makefile.am +++ b/bindings/Makefile.am @@ -1,9 +1,5 @@ SUBDIRS = -if WITH_PYTHON - SUBDIRS += python -endif - if WITH_VALA SUBDIRS += vala endif diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am deleted file mode 100644 index b9ba9c750a..0000000000 --- a/bindings/python/Makefile.am +++ /dev/null @@ -1,46 +0,0 @@ -SUBDIRS = codegen -pkgpyexecdir = $(pyexecdir)/gst-$(GST_MAJORMINOR)/gst - -# we install everything in pyexecdir; otherwise you end up with a mess for -# multilib -pygstrtspserverdir = $(pkgpyexecdir) -pygstrtspserver_PYTHON = - -pygstrtspserverexecdir = $(pkgpyexecdir) -pygstrtspserverexec_LTLIBRARIES = rtspserver.la - -DEFS = $(srcdir)/rtspserver-types.defs $(srcdir)/rtspserver.defs -defs_DATA = $(DEFS) -defsdir = $(pkgdatadir)/$(GST_MAJORMINOR)/defs -OVERRIDES = rtspserver.override - -INCLUDES = -I$(top_srcdir) -I$(srcdir) $(PYTHON_INCLUDES) - -rtspserver_la_CFLAGS = -I$(top_srcdir)/src \ - $(PYGOBJECT_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) -rtspserver_la_LDFLAGS = -export-symbols-regex "^(initrtspserver|_PyGObject_API).*" \ - -module -avoid-version $(GST_PLUGIN_LDFLAGS) -rtspserver_la_LIBADD = $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_MAJORMINOR@.la \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ - -lgstsdp-@GST_MAJORMINOR@ $(GST_LIBS) $(LIBM) -rtspserver_la_SOURCES = rtspservermodule.c -nodist_rtspserver_la_SOURCES = rtspserver.c - -EXTRA_DIST = $(defs_DATA) $(OVERRIDES) arg-types.py - -CLEANFILES = rtspserver.c - -rtspserver.c: $(DEFS) $(OVERRIDES) arg-types.py - -.defs.c: - ($(PYTHON) $(srcdir)/codegen/codegen.py \ - --load-types $(srcdir)/arg-types.py \ - --register $(srcdir)/rtspserver-types.defs \ - --register $(PYGST_DEFSDIR)/gst-types.defs \ - --override $(srcdir)/$*.override \ - --extendpath $(top_builddir)/gst/ \ - --extendpath $(srcdir)/ \ - --prefix pygst_rtsp_server $<) > gen-$*.c \ - && cp gen-$*.c $*.c \ - && rm -f gen-$*.c diff --git a/bindings/python/arg-types.py b/bindings/python/arg-types.py deleted file mode 100644 index 112fb301cc..0000000000 --- a/bindings/python/arg-types.py +++ /dev/null @@ -1,451 +0,0 @@ -# -*- Mode: Python -*- -# vi:si:et:sw=4:sts=4:ts=4 -# -# gst-python -# Copyright (C) 2002 David I. Lehn -# 2004 Johan Dahlin -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Library General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library General Public -# License along with this library; if not, write to the -# Free Software Foundation, Inc., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. -# -# Author: David I. Lehn - -from argtypes import UInt64Arg, Int64Arg, PointerArg, ArgMatcher, ArgType, matcher -from reversewrapper import Parameter, ReturnType, GBoxedParam, GBoxedReturn, IntParam, IntReturn - -class XmlNodeArg(ArgType): - """libxml2 node generator""" - - names = {"xobj":"xmlNode", - "xptr":"xmlNodePtr", - "xwrap":"libxml_xmlNodePtrWrap"} - - parm = (' if(xml == NULL) return NULL;\n' - ' xobj = PyObject_GetAttrString(xml, "%(xobj)s");\n' - ' if(!PyObject_IsInstance(py%(name)s, xobj)) {\n' - ' PyErr_Clear();\n' - ' PyErr_SetString(PyExc_RuntimeError,"%(name)s is not a %(xobj)s instance");\n' - ' Py_DECREF(xobj);Py_DECREF(xml);\n' - ' return NULL;\n' - ' }\n' - ' o = PyObject_GetAttrString(py%(name)s, "_o");\n' - ' %(name)s = PyCObject_AsVoidPtr(o);\n') - parmp = (' Py_DECREF(o); Py_DECREF(xobj);Py_DECREF(xml);\n') - - ret = (' if(xml == NULL) return NULL;\n') - retp = (' xargs = PyTuple_New(1);\n' - ' xobj = PyObject_GetAttrString(xml, "%(xobj)s");\n' - ' o = %(xwrap)s(ret);\n' - ' PyTuple_SetItem(xargs, 0, o);\n' - ' return PyInstance_New(xobj, xargs, PyDict_New());\n') - - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - info.varlist.add('PyObject', '*xml = _gst_get_libxml2_module()') - info.varlist.add('PyObject', '*o') - info.varlist.add('PyObject', '*xobj') - info.varlist.add('PyObject', '*py' + pname) - info.varlist.add(self.names["xptr"], pname) - #if pnull: - info.add_parselist('O', ['&py'+pname], [pname]) - info.arglist.append(pname) - self.names["name"] = pname - info.codebefore.append(self.parm % self.names) - info.codeafter.append(self.parmp % self.names); - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('PyObject', '*xml = _gst_get_libxml2_module()') - info.varlist.add('PyObject', '*xargs') - info.varlist.add('PyObject', '*xobj') - info.varlist.add('PyObject', '*o') - info.varlist.add(self.names["xptr"], 'ret') - info.codebefore.append(self.ret % self.names) - info.codeafter.append(self.retp % self.names) - -class XmlDocArg(XmlNodeArg): - """libxml2 doc generator""" - names = {"xobj":"xmlDoc", - "xptr":"xmlDocPtr", - "xwrap":"libxml_xmlDocPtrWrap"} - -class GstCapsArg(ArgType): - """GstCaps node generator""" - - before = (' %(name)s = pygst_caps_from_pyobject (py_%(name)s, %(namecopy)s);\n' - ' if (PyErr_Occurred())\n' - ' return NULL;\n') - beforenull = (' if (py_%(name)s == Py_None || py_%(name)s == NULL)\n' - ' %(name)s = NULL;\n' - ' else\n' - ' ' + before) - after = (' if (%(name)s && %(name)s_is_copy)\n' - ' gst_caps_unref (%(name)s);\n') - - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if ptype == 'const-GstCaps*': - self.write_const_param(pname, pdflt, pnull, info) - elif ptype == 'GstCaps*': - self.write_normal_param(pname, pdflt, pnull, info) - else: - raise RuntimeError, "write_param not implemented for %s" % ptype - - def write_const_param(self, pname, pdflt, pnull, info): - if pdflt: - assert pdflt == 'NULL' - info.varlist.add('PyObject', '*py_' + pname + ' = NULL') - else: - info.varlist.add('PyObject', '*py_' + pname) - info.varlist.add('GstCaps', '*'+pname) - info.varlist.add('gboolean', pname+'_is_copy') - info.add_parselist('O', ['&py_'+pname], [pname]) - info.arglist.append(pname) - if pnull: - info.codebefore.append (self.beforenull % { 'name' : pname, 'namecopy' : '&'+pname+'_is_copy' }) - else: - info.codebefore.append (self.before % { 'name' : pname, 'namecopy' : '&'+pname+'_is_copy' }) - info.codeafter.append (self.after % { 'name' : pname, 'namecopy' : '&'+pname+'_is_copy' }) - - def write_normal_param(self, pname, pdflt, pnull, info): - if pdflt: - assert pdflt == 'NULL' - info.varlist.add('PyObject', '*py_' + pname + ' = NULL') - else: - info.varlist.add('PyObject', '*py_' + pname) - info.varlist.add('GstCaps', '*'+pname) - info.add_parselist('O', ['&py_'+pname], [pname]) - info.arglist.append(pname) - if pnull: - info.codebefore.append (self.beforenull % { 'name' : pname, 'namecopy' : 'NULL' }) - else: - info.codebefore.append (self.before % { 'name' : pname, 'namecopy' : 'NULL' }) - - def write_return(self, ptype, ownsreturn, info): - if ptype == 'GstCaps*': - info.varlist.add('GstCaps', '*ret') - copyval = 'FALSE' - elif ptype == 'const-GstCaps*': - info.varlist.add('const GstCaps', '*ret') - copyval = 'TRUE' - else: - raise RuntimeError, "write_return not implemented for %s" % ptype - info.codeafter.append(' return pyg_boxed_new (GST_TYPE_CAPS, ret, '+copyval+', TRUE);') - -class GstIteratorArg(ArgType): - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('GstIterator', '*ret') - info.codeafter.append(' return pygst_iterator_new(ret);') - -class GstRTSPUrlArg(ArgType): - """GstRTSPUrl node generator""" - - before = (' parse_result = gst_rtsp_url_parse (py_%(name)s, &%(name)s);\n' - ' if (parse_result != GST_RTSP_OK) {\n' - ' PyErr_SetString(PyExc_TypeError, "invalid url");\n' - ' return NULL;\n' - ' }') - beforenull = (' if (py_%(name)s == NULL)\n' - ' %(name)s = NULL;\n' - ' else\n' - ' ' + before) - after = (' if (%(name)s)\n' - ' gst_rtsp_url_free (%(name)s);\n') - - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if ptype in ('const-GstRTSPUrl*', 'GstRTSPUrl*'): - self.write_normal_param(pname, pdflt, pnull, info) - else: - raise RuntimeError, "write_param not implemented for %s" % ptype - - def write_normal_param(self, pname, pdflt, pnull, info): - info.varlist.add('GstRTSPResult', 'parse_result') - if pdflt: - assert pdflt == 'NULL' - info.varlist.add('const char', '*py_' + pname + ' = NULL') - else: - info.varlist.add('const char', '*py_' + pname) - info.varlist.add('GstRTSPUrl', '*'+pname) - info.add_parselist('s', ['&py_'+pname], [pname]) - info.arglist.append(pname) - if pnull: - info.codebefore.append (self.beforenull % { 'name' : pname }) - else: - info.codebefore.append (self.before % { 'name' : pname }) - info.codeafter.append (self.after % { 'name' : pname }) - - def write_return(self, ptype, ownsreturn, info): - if ptype == 'GstRTSPUrl*': - info.varlist.add('GstRTSPUrl', '*ret') - copyval = 'FALSE' - elif ptype == 'const-GstRTSPUrl*': - info.varlist.add('const GstRTSPUrl', '*ret') - copyval = 'TRUE' - else: - raise RuntimeError, "write_return not implemented for %s" % ptype - info.codeafter.append(' return pyg_boxed_new (GST_TYPE_RTSP_URL, ret, '+copyval+', TRUE);') - -class GstMiniObjectParam(Parameter): - - def get_c_type(self): - return self.props.get('c_type', 'GstMiniObject *') - - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name) - self.wrapper.write_code(code=("if (%s) {\n" - " py_%s = pygstminiobject_new((GstMiniObject *) %s);\n" - " gst_mini_object_unref ((GstMiniObject *) %s);\n" - "} else {\n" - " Py_INCREF(Py_None);\n" - " py_%s = Py_None;\n" - "}" - % (self.name, self.name, self.name, self.name, self.name)), - cleanup=("gst_mini_object_ref ((GstMiniObject *) %s);\nPy_DECREF(py_%s);" % (self.name, self.name))) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -matcher.register_reverse('GstMiniObject*', GstMiniObjectParam) - -class GstRTSPUrlParam(Parameter): - - def get_c_type(self): - c_type = self.props.get('c_type', None) - if c_type and c_type.startswith('const'): - return 'const GstRTSPUrl *' - return 'GstRTSPUrl *' - - def convert_c2py(self): - self.wrapper.add_declaration("char *%s_str = NULL;" % self.name) - self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name) - self.wrapper.write_code(code=("if (%(name)s) {\n" - " %(name)s_str = gst_rtsp_url_get_request_uri ((GstRTSPUrl*) %(name)s);\n" - " py_%(name)s = PyString_FromString (%(name)s_str);\n" - " g_free (%(name)s_str);\n" - "} else {\n" - " Py_INCREF(Py_None);\n" - " py_%(name)s = Py_None;\n" - "}" % {'name': self.name}), - cleanup=("Py_DECREF(py_%s);" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -matcher.register_reverse('const-GstRTSPUrl*', GstRTSPUrlParam) -matcher.register_reverse('GstRTSPUrl*', GstRTSPUrlParam) - -class GstMiniObjectReturn(ReturnType): - - def get_c_type(self): - return self.props.get('c_type', 'GstMiniObject *') - - def write_decl(self): - self.wrapper.add_declaration("%s retval;" % self.get_c_type()) - - def write_error_return(self): - self.wrapper.write_code("return NULL;") - - def write_conversion(self): - self.wrapper.write_code("retval = (%s) pygstminiobject_get(py_retval);" - % self.get_c_type()) - self.wrapper.write_code("gst_mini_object_ref((GstMiniObject *) retval);") - -matcher.register_reverse_ret('GstMiniObject*', GstMiniObjectReturn) - -class GstCapsParam(Parameter): - - def get_c_type(self): - return self.props.get('c_type', 'GstCaps *') - - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name) - self.wrapper.write_code(code=("if (%s)\n" - " py_%s = pyg_boxed_new (GST_TYPE_CAPS, %s, FALSE, TRUE);\n" - "else {\n" - " Py_INCREF(Py_None);\n" - " py_%s = Py_None;\n" - "}" - % (self.name, self.name, self.name, self.name)), - cleanup=("gst_caps_ref(%s);\nPy_DECREF(py_%s);" % (self.name, self.name))) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -matcher.register_reverse('GstCaps*', GstCapsParam) - -class GstCapsReturn(ReturnType): - - def get_c_type(self): - return self.props.get('c_type', 'GstCaps *') - - def write_decl(self): - self.wrapper.add_declaration("%s retval;" % self.get_c_type()) - - def write_error_return(self): - self.wrapper.write_code("return NULL;") - - def write_conversion(self): - self.wrapper.write_code("retval = (%s) pygst_caps_from_pyobject (py_retval, NULL);" - % self.get_c_type()) -## self.wrapper.write_code("gst_mini_object_ref((GstMiniObject *) retval);") - -matcher.register_reverse_ret('GstCaps*', GstCapsReturn) - - -class Int64Param(Parameter): - - def get_c_type(self): - return self.props.get('c_type', 'gint64') - - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = PyLong_FromLongLong(%s);" % - (self.name, self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -class Int64Return(ReturnType): - def get_c_type(self): - return self.props.get('c_type', 'gint64') - def write_decl(self): - self.wrapper.add_declaration("%s retval;" % self.get_c_type()) - def write_error_return(self): - self.wrapper.write_code("return -G_MAXINT;") - def write_conversion(self): - self.wrapper.write_code( - code=None, - failure_expression="!PyLong_Check(py_retval)", - failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be an long");') - self.wrapper.write_code("retval = PyLong_AsLongLong(py_retval);") - -class UInt64Param(Parameter): - - def get_c_type(self): - return self.props.get('c_type', 'guint64') - - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = PyLong_FromUnsignedLongLong(%s);" % - (self.name, self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -class UInt64Return(ReturnType): - def get_c_type(self): - return self.props.get('c_type', 'guint64') - def write_decl(self): - self.wrapper.add_declaration("%s retval;" % self.get_c_type()) - def write_error_return(self): - self.wrapper.write_code("return -G_MAXINT;") - def write_conversion(self): - self.wrapper.write_code( - code=None, - failure_expression="!PyLong_Check(py_retval)", - failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be an long");') - self.wrapper.write_code("retval = PyLong_AsUnsignedLongLongMask(py_retval);") - -class ULongParam(Parameter): - - def get_c_type(self): - return self.props.get('c_type', 'gulong') - - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = PyLong_FromUnsignedLong(%s);" % - (self.name, self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -class ULongReturn(ReturnType): - def get_c_type(self): - return self.props.get('c_type', 'gulong') - def write_decl(self): - self.wrapper.add_declaration("%s retval;" % self.get_c_type()) - def write_error_return(self): - self.wrapper.write_code("return -G_MAXINT;") - def write_conversion(self): - self.wrapper.write_code( - code=None, - failure_expression="!PyLong_Check(py_retval)", - failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be an long");') - self.wrapper.write_code("retval = PyLong_AsUnsignedLongMask(py_retval);") - -class ConstStringReturn(ReturnType): - - def get_c_type(self): - return "const gchar *" - - def write_decl(self): - self.wrapper.add_declaration("const gchar *retval;") - - def write_error_return(self): - self.wrapper.write_code("return NULL;") - - def write_conversion(self): - self.wrapper.write_code( - code=None, - failure_expression="!PyString_Check(py_retval)", - failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a string");') - self.wrapper.write_code("retval = g_strdup(PyString_AsString(py_retval));") - -class StringArrayArg(ArgType): - """Arg type for NULL-terminated string pointer arrays (GStrv, aka gchar**).""" - def write_return(self, ptype, ownsreturn, info): - if ownsreturn: - raise NotImplementedError () - else: - info.varlist.add("gchar", "**ret") - info.codeafter.append(" if (ret) {\n" - " guint size = g_strv_length(ret);\n" - " PyObject *py_ret = PyTuple_New(size);\n" - " gint i;\n" - " for (i = 0; i < size; i++)\n" - " PyTuple_SetItem(py_ret, i,\n" - " PyString_FromString(ret[i]));\n" - " return py_ret;\n" - " }\n" - " return PyTuple_New (0);\n") - -matcher.register('GstClockTime', UInt64Arg()) -matcher.register('GstClockTimeDiff', Int64Arg()) -matcher.register('xmlNodePtr', XmlNodeArg()) -matcher.register('xmlDocPtr', XmlDocArg()) -matcher.register('GstCaps', GstCapsArg()) #FIXME: does this work? -matcher.register('GstCaps*', GstCapsArg()) #FIXME: does this work? -matcher.register('const-GstCaps*', GstCapsArg()) -matcher.register('GstIterator*', GstIteratorArg()) -matcher.register('const-GstRTSPUrl*', GstRTSPUrlArg()) -matcher.register('GstRTSPUrl*', GstRTSPUrlArg()) - -arg = PointerArg('gpointer', 'G_TYPE_POINTER') -matcher.register('GstClockID', arg) - -for typename in ["GstPlugin", "GstStructure", "GstTagList", "GError", "GstDate", "GstSegment"]: - matcher.register_reverse(typename, GBoxedParam) - matcher.register_reverse_ret(typename, GBoxedReturn) - -for typename in ["GstBuffer*", "GstEvent*", "GstMessage*", "GstQuery*"]: - matcher.register_reverse(typename, GstMiniObjectParam) - matcher.register_reverse_ret(typename, GstMiniObjectReturn) - -for typename in ["gint64", "GstClockTimeDiff"]: - matcher.register_reverse(typename, Int64Param) - matcher.register_reverse_ret(typename, Int64Return) - -for typename in ["guint64", "GstClockTime"]: - matcher.register_reverse(typename, UInt64Param) - matcher.register_reverse_ret(typename, UInt64Return) - -matcher.register_reverse_ret("const-gchar*", ConstStringReturn) - -matcher.register_reverse("GType", IntParam) -matcher.register_reverse_ret("GType", IntReturn) - -matcher.register_reverse("gulong", ULongParam) -matcher.register_reverse_ret("gulong", ULongReturn) - -matcher.register("GStrv", StringArrayArg()) - -del arg diff --git a/bindings/python/codegen/Makefile.am b/bindings/python/codegen/Makefile.am deleted file mode 100644 index dd3eea0641..0000000000 --- a/bindings/python/codegen/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -EXTRA_DIST = \ - argtypes.py \ - code-coverage.py \ - codegen.py \ - definitions.py \ - defsparser.py \ - docextract.py \ - docgen.py \ - h2def.py \ - __init__.py \ - mergedefs.py \ - mkskel.py \ - override.py \ - reversewrapper.py \ - scmexpr.py diff --git a/bindings/python/codegen/__init__.py b/bindings/python/codegen/__init__.py deleted file mode 100644 index cfa896ee6a..0000000000 --- a/bindings/python/codegen/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- - -__all__ = [ - 'argtypes', - 'codegen', - 'definitions', - 'defsparser', - 'docextract', - 'docgen', - 'h2def', - 'mergedefs', - 'mkskel', - 'override', - 'scmexpr' -] diff --git a/bindings/python/codegen/argtypes.py b/bindings/python/codegen/argtypes.py deleted file mode 100644 index 948bae106c..0000000000 --- a/bindings/python/codegen/argtypes.py +++ /dev/null @@ -1,1075 +0,0 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- -import string -import keyword -import struct - -class VarList: - """Nicely format a C variable list""" - def __init__(self): - self.vars = {} - def add(self, ctype, name): - if self.vars.has_key(ctype): - self.vars[ctype] = self.vars[ctype] + (name,) - else: - self.vars[ctype] = (name,) - def __str__(self): - ret = [] - for type in self.vars.keys(): - ret.append(' ') - ret.append(type) - ret.append(' ') - ret.append(string.join(self.vars[type], ', ')) - ret.append(';\n') - if ret: - ret.append('\n') - return string.join(ret, '') - return '' - -class WrapperInfo: - """A class that holds information about variable defs, code - snippets, etcd for use in writing out the function/method - wrapper.""" - def __init__(self): - self.varlist = VarList() - self.parsestr = '' - self.parselist = ['', 'kwlist'] - self.codebefore = [] - self.codeafter = [] - self.arglist = [] - self.kwlist = [] - def get_parselist(self): - return string.join(self.parselist, ', ') - def get_codebefore(self): - return string.join(self.codebefore, '') - def get_codeafter(self): - return string.join(self.codeafter, '') - def get_arglist(self): - return string.join(self.arglist, ', ') - def get_varlist(self): - return str(self.varlist) - def get_kwlist(self): - ret = ' static char *kwlist[] = { %s };\n' % \ - string.join(self.kwlist + [ 'NULL' ], ', ') - if not self.get_varlist(): - ret = ret + '\n' - return ret - - def add_parselist(self, codes, parseargs, keywords): - self.parsestr = self.parsestr + codes - for arg in parseargs: - self.parselist.append(arg) - for kw in keywords: - if keyword.iskeyword(kw): - kw = kw + '_' - self.kwlist.append('"%s"' % kw) - -class ArgType: - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - """Add code to the WrapperInfo instance to handle - parameter.""" - raise RuntimeError, "write_param not implemented for %s" % \ - self.__class__.__name__ - def write_return(self, ptype, ownsreturn, info): - """Adds a variable named ret of the return type to - info.varlist, and add any required code to info.codeafter to - convert the return value to a python object.""" - raise RuntimeError, "write_return not implemented for %s" % \ - self.__class__.__name__ - -class NoneArg(ArgType): - def write_return(self, ptype, ownsreturn, info): - info.codeafter.append(' Py_INCREF(Py_None);\n' + - ' return Py_None;') - -class StringArg(ArgType): - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - if pdflt != 'NULL': pdflt = '"' + pdflt + '"' - info.varlist.add('char', '*' + pname + ' = ' + pdflt) - else: - info.varlist.add('char', '*' + pname) - info.arglist.append(pname) - if pnull: - info.add_parselist('z', ['&' + pname], [pname]) - else: - info.add_parselist('s', ['&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - if ownsreturn: - # have to free result ... - info.varlist.add('gchar', '*ret') - info.codeafter.append(' if (ret) {\n' + - ' PyObject *py_ret = PyString_FromString(ret);\n' + - ' g_free(ret);\n' + - ' return py_ret;\n' + - ' }\n' + - ' Py_INCREF(Py_None);\n' + - ' return Py_None;') - else: - info.varlist.add('const gchar', '*ret') - info.codeafter.append(' if (ret)\n' + - ' return PyString_FromString(ret);\n'+ - ' Py_INCREF(Py_None);\n' + - ' return Py_None;') - -class UCharArg(ArgType): - # allows strings with embedded NULLs. - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add('guchar', '*' + pname + ' = "' + pdflt + '"') - else: - info.varlist.add('guchar', '*' + pname) - info.varlist.add('int', pname + '_len') - info.arglist.append(pname) - if pnull: - info.add_parselist('z#', ['&' + pname, '&' + pname + '_len'], - [pname]) - else: - info.add_parselist('s#', ['&' + pname, '&' + pname + '_len'], - [pname]) - -class CharArg(ArgType): - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add('char', pname + " = '" + pdflt + "'") - else: - info.varlist.add('char', pname) - info.arglist.append(pname) - info.add_parselist('c', ['&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('gchar', 'ret') - info.codeafter.append(' return PyString_FromStringAndSize(&ret, 1);') -class GUniCharArg(ArgType): - ret_tmpl = ('#if !defined(Py_UNICODE_SIZE) || Py_UNICODE_SIZE == 2\n' - ' if (ret > 0xffff) {\n' - ' PyErr_SetString(PyExc_RuntimeError, "returned character can not be represented in 16-bit unicode");\n' - ' return NULL;\n' - ' }\n' - '#endif\n' - ' py_ret = (Py_UNICODE)ret;\n' - ' return PyUnicode_FromUnicode(&py_ret, 1);\n') - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add('gunichar', pname + " = '" + pdflt + "'") - else: - info.varlist.add('gunichar', pname) - info.arglist.append(pname) - info.add_parselist('O&', ['pyg_pyobj_to_unichar_conv', '&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('gunichar', 'ret') - info.varlist.add('Py_UNICODE', 'py_ret') - info.codeafter.append(self.ret_tmpl) - - -class IntArg(ArgType): - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add('int', pname + ' = ' + pdflt) - else: - info.varlist.add('int', pname) - info.arglist.append(pname) - info.add_parselist('i', ['&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('int', 'ret') - info.codeafter.append(' return PyInt_FromLong(ret);') - -class UIntArg(ArgType): - dflt = (' if (py_%(name)s) {\n' - ' if (PyLong_Check(py_%(name)s))\n' - ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n' - ' else if (PyInt_Check(py_%(name)s))\n' - ' %(name)s = PyInt_AsLong(py_%(name)s);\n' - ' else\n' - ' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n' - ' if (PyErr_Occurred())\n' - ' return NULL;\n' - ' }\n') - before = (' if (PyLong_Check(py_%(name)s))\n' - ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n' - ' else if (PyInt_Check(py_%(name)s))\n' - ' %(name)s = PyInt_AsLong(py_%(name)s);\n' - ' else\n' - ' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n' - ' if (PyErr_Occurred())\n' - ' return NULL;\n') - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if not pdflt: - pdflt = '0'; - - info.varlist.add(ptype, pname + ' = ' + pdflt) - info.codebefore.append(self.dflt % {'name':pname}) - info.varlist.add('PyObject', "*py_" + pname + ' = NULL') - info.arglist.append(pname) - info.add_parselist('O', ['&py_' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add(ptype, 'ret') - info.codeafter.append(' return PyLong_FromUnsignedLong(ret);') - -class SizeArg(ArgType): - - if struct.calcsize('P') <= struct.calcsize('l'): - llp64 = True - else: - llp64 = False - - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add(ptype, pname + ' = ' + pdflt) - else: - info.varlist.add(ptype, pname) - info.arglist.append(pname) - if self.llp64: - info.add_parselist('k', ['&' + pname], [pname]) - else: - info.add_parselist('K', ['&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add(ptype, 'ret') - if self.llp64: - info.codeafter.append(' return PyLong_FromUnsignedLongLong(ret);\n') - else: - info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n') - -class SSizeArg(ArgType): - - if struct.calcsize('P') <= struct.calcsize('l'): - llp64 = True - else: - llp64 = False - - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add(ptype, pname + ' = ' + pdflt) - else: - info.varlist.add(ptype, pname) - info.arglist.append(pname) - if self.llp64: - info.add_parselist('l', ['&' + pname], [pname]) - else: - info.add_parselist('L', ['&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add(ptype, 'ret') - if self.llp64: - info.codeafter.append(' return PyLong_FromLongLong(ret);\n') - else: - info.codeafter.append(' return PyLong_FromLong(ret);\n') - -class LongArg(ArgType): - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add(ptype, pname + ' = ' + pdflt) - else: - info.varlist.add(ptype, pname) - info.arglist.append(pname) - info.add_parselist('l', ['&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add(ptype, 'ret') - info.codeafter.append(' return PyInt_FromLong(ret);\n') - -class BoolArg(IntArg): - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('int', 'ret') - info.codeafter.append(' return PyBool_FromLong(ret);\n') - -class TimeTArg(ArgType): - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add('time_t', pname + ' = ' + pdflt) - else: - info.varlist.add('time_t', pname) - info.arglist.append(pname) - info.add_parselist('i', ['&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('time_t', 'ret') - info.codeafter.append(' return PyInt_FromLong(ret);') - -class ULongArg(ArgType): - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add('unsigned long', pname + ' = ' + pdflt) - else: - info.varlist.add('unsigned long', pname) - info.arglist.append(pname) - info.add_parselist('k', ['&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add(ptype, 'ret') - info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n') - -class UInt32Arg(ULongArg): - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - ULongArg.write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info) - ## if sizeof(unsigned long) > sizeof(unsigned int), we need to - ## check the value is within guint32 range - if struct.calcsize('L') > struct.calcsize('I'): - info.codebefore.append(( - ' if (%(pname)s > G_MAXUINT32) {\n' - ' PyErr_SetString(PyExc_ValueError,\n' - ' "Value out of range in conversion of"\n' - ' " %(pname)s parameter to unsigned 32 bit integer");\n' - ' return NULL;\n' - ' }\n') % vars()) - -class Int64Arg(ArgType): - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add('gint64', pname + ' = ' + pdflt) - else: - info.varlist.add('gint64', pname) - info.arglist.append(pname) - info.add_parselist('L', ['&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('gint64', 'ret') - info.codeafter.append(' return PyLong_FromLongLong(ret);') - -class UInt64Arg(ArgType): - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add('guint64', pname + ' = ' + pdflt) - else: - info.varlist.add('guint64', pname) - info.arglist.append(pname) - info.add_parselist('K', ['&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('guint64', 'ret') - info.codeafter.append(' return PyLong_FromUnsignedLongLong(ret);') - - -class DoubleArg(ArgType): - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add('double', pname + ' = ' + pdflt) - else: - info.varlist.add('double', pname) - info.arglist.append(pname) - info.add_parselist('d', ['&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('double', 'ret') - info.codeafter.append(' return PyFloat_FromDouble(ret);') - -class FileArg(ArgType): - nulldflt = (' if (py_%(name)s == Py_None)\n' - ' %(name)s = NULL;\n' - ' else if (py_%(name)s && PyFile_Check(py_%(name)s)\n' - ' %s = PyFile_AsFile(py_%(name)s);\n' - ' else if (py_%(name)s) {\n' - ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a file object or None");\n' - ' return NULL;\n' - ' }') - null = (' if (py_%(name)s && PyFile_Check(py_%(name)s)\n' - ' %(name)s = PyFile_AsFile(py_%(name)s);\n' - ' else if (py_%(name)s != Py_None) {\n' - ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a file object or None");\n' - ' return NULL;\n' - ' }\n') - dflt = (' if (py_%(name)s)\n' - ' %(name)s = PyFile_AsFile(py_%(name)s);\n') - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pnull: - if pdflt: - info.varlist.add('FILE', '*' + pname + ' = ' + pdflt) - info.varlist.add('PyObject', '*py_' + pname + ' = NULL') - info.codebefore.append(self.nulldflt % {'name':pname}) - else: - info.varlist.add('FILE', '*' + pname + ' = NULL') - info.varlist.add('PyObject', '*py_' + pname) - info.codebefore.append(self.null & {'name':pname}) - info.arglist.appned(pname) - info.add_parselist('O', ['&py_' + pname], [pname]) - else: - if pdflt: - info.varlist.add('FILE', '*' + pname + ' = ' + pdflt) - info.varlist.add('PyObject', '*py_' + pname + ' = NULL') - info.codebefore.append(self.dflt % {'name':pname}) - info.arglist.append(pname) - else: - info.varlist.add('PyObject', '*' + pname) - info.arglist.append('PyFile_AsFile(' + pname + ')') - info.add_parselist('O!', ['&PyFile_Type', '&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('FILE', '*ret') - info.codeafter.append(' if (ret)\n' + - ' return PyFile_FromFile(ret, "", "", fclose);\n' + - ' Py_INCREF(Py_None);\n' + - ' return Py_None;') - -class EnumArg(ArgType): - enum = (' if (pyg_enum_get_value(%(typecode)s, py_%(name)s, (gint *)&%(name)s))\n' - ' return NULL;\n') - def __init__(self, enumname, typecode): - self.enumname = enumname - self.typecode = typecode - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add(self.enumname, pname + ' = ' + pdflt) - else: - info.varlist.add(self.enumname, pname) - info.varlist.add('PyObject', '*py_' + pname + ' = NULL') - info.codebefore.append(self.enum % { 'typecode': self.typecode, - 'name': pname}) - info.arglist.append(pname) - info.add_parselist('O', ['&py_' + pname], [pname]); - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('gint', 'ret') - info.codeafter.append(' return pyg_enum_from_gtype(%s, ret);' % self.typecode) - -class FlagsArg(ArgType): - flag = (' if (%(default)spyg_flags_get_value(%(typecode)s, py_%(name)s, (gint *)&%(name)s))\n' - ' return NULL;\n') - def __init__(self, flagname, typecode): - self.flagname = flagname - self.typecode = typecode - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add(self.flagname, pname + ' = ' + pdflt) - default = "py_%s && " % (pname,) - else: - info.varlist.add(self.flagname, pname) - default = "" - info.varlist.add('PyObject', '*py_' + pname + ' = NULL') - info.codebefore.append(self.flag % {'default':default, - 'typecode':self.typecode, - 'name':pname}) - info.arglist.append(pname) - info.add_parselist('O', ['&py_' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('guint', 'ret') - info.codeafter.append(' return pyg_flags_from_gtype(%s, ret);' % self.typecode) - -class ObjectArg(ArgType): - # should change these checks to more typesafe versions that check - # a little further down in the class heirachy. - nulldflt = (' if ((PyObject *)py_%(name)s == Py_None)\n' - ' %(name)s = NULL;\n' - ' else if (py_%(name)s && pygobject_check(py_%(name)s, &Py%(type)s_Type))\n' - ' %(name)s = %(cast)s(py_%(name)s->obj);\n' - ' else if (py_%(name)s) {\n' - ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n' - ' return NULL;\n' - ' }\n') - null = (' if (py_%(name)s && pygobject_check(py_%(name)s, &Py%(type)s_Type))\n' - ' %(name)s = %(cast)s(py_%(name)s->obj);\n' - ' else if ((PyObject *)py_%(name)s != Py_None) {\n' - ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n' - ' return NULL;\n' - ' }\n') - dflt = ' if (py_%(name)s)\n' \ - ' %(name)s = %(cast)s(py_%(name)s->obj);\n' - def __init__(self, objname, parent, typecode): - self.objname = objname - self.cast = string.replace(typecode, '_TYPE_', '_', 1) - self.parent = parent - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pnull: - if pdflt: - info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt) - info.varlist.add('PyGObject', '*py_' + pname + ' = NULL') - info.codebefore.append(self.nulldflt % {'name':pname, - 'cast':self.cast, - 'type':self.objname}) - else: - info.varlist.add(self.objname, '*' + pname + ' = NULL') - info.varlist.add('PyGObject', '*py_' + pname) - info.codebefore.append(self.null % {'name':pname, - 'cast':self.cast, - 'type':self.objname}) - if ptype.endswith('*'): - typename = ptype[:-1] - try: - const, typename = typename.split('const-') - except ValueError: - const = '' - if typename != ptype: - info.arglist.append('(%s *) %s' % (ptype[:-1], pname)) - else: - info.arglist.append(pname) - - info.add_parselist('O', ['&py_' + pname], [pname]) - else: - if pdflt: - info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt) - info.varlist.add('PyGObject', '*py_' + pname + ' = NULL') - info.codebefore.append(self.dflt % {'name':pname, - 'cast':self.cast}) - info.arglist.append(pname) - info.add_parselist('O!', ['&Py%s_Type' % self.objname, - '&py_' + pname], [pname]) - else: - info.varlist.add('PyGObject', '*' + pname) - info.arglist.append('%s(%s->obj)' % (self.cast, pname)) - info.add_parselist('O!', ['&Py%s_Type' % self.objname, - '&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - if ptype.endswith('*'): - typename = ptype[:-1] - try: - const, typename = typename.split('const-') - except ValueError: - const = '' - info.varlist.add(typename, '*ret') - if ownsreturn: - info.varlist.add('PyObject', '*py_ret') - # < GLib 2.8: using our custom _new and _unref functions - # makes sure we update the proper GstObject refcount - info.codeafter.append(' py_ret = pygobject_new((GObject *)ret);\n' - ' if (ret != NULL)\n' - ' g_object_unref((GObject *)ret);\n' - ' return py_ret;') - else: - info.codeafter.append(' /* pygobject_new handles NULL checking */\n' + - ' return pygobject_new((GObject *)ret);') - -class MiniObjectArg(ArgType): - # should change these checks to more typesafe versions that check - # a little further down in the class heirachy. - nulldflt = (' if ((PyObject *)py_%(name)s == Py_None)\n' - ' %(name)s = NULL;\n' - ' else if (py_%(name)s) && pygstminiobject_check(py_%(name)s, &Py%(type)s_Type))\n' - ' %(name)s = %(cast)s(py_%(name)s->obj);\n' - ' else if (py_%(name)s) {\n' - ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n' - ' return NULL;\n' - ' }\n') - null = (' if (py_%(name)s && pygstminiobject_check(py_%(name)s, &Py%(type)s_Type))\n' - ' %(name)s = %(cast)s(py_%(name)s->obj);\n' - ' else if ((PyObject *)py_%(name)s != Py_None) {\n' - ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n' - ' return NULL;\n' - ' }\n') - dflt = ' if (py_%(name)s)\n' \ - ' %(name)s = %(cast)s(py_%(name)s->obj);\n' - def __init__(self, objname, parent, typecode): - self.objname = objname - self.cast = string.replace(typecode, '_TYPE_', '_', 1) - self.parent = parent - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pnull: - if pdflt: - info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt) - info.varlist.add('PyGstMiniObject', '*py_' + pname + ' = NULL') - info.codebefore.append(self.nulldflt % {'name':pname, - 'cast':self.cast, - 'type':self.objname}) - else: - info.varlist.add(self.objname, '*' + pname + ' = NULL') - info.varlist.add('PyGstMiniObject', '*py_' + pname) - info.codebefore.append(self.null % {'name':pname, - 'cast':self.cast, - 'type':self.objname}) - if ptype.endswith('*'): - typename = ptype[:-1] - try: - const, typename = typename.split('const-') - except ValueError: - const = '' - if typename != ptype: - info.arglist.append('(%s *) %s' % (ptype[:-1], pname)) - else: - info.arglist.append(pname) - - info.add_parselist('O', ['&py_' + pname], [pname]) - else: - if pdflt: - info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt) - info.varlist.add('PyGstMiniObject', '*py_' + pname + ' = NULL') - info.codebefore.append(self.dflt % {'name':pname, - 'cast':self.cast}) - info.arglist.append(pname) - info.add_parselist('O', ['&Py%s_Type' % self.objname, - '&py_' + pname], [pname]) - else: - info.varlist.add('PyGstMiniObject', '*' + pname) - info.arglist.append('%s(%s->obj)' % (self.cast, pname)) - info.add_parselist('O!', ['&Py%s_Type' % self.objname, - '&' + pname], [pname]) - if keeprefcount: - info.codebefore.append(' gst_mini_object_ref(GST_MINI_OBJECT(%s->obj));\n' % pname) - def write_return(self, ptype, ownsreturn, info): - if ptype.endswith('*'): - typename = ptype[:-1] - try: - const, typename = typename.split('const-') - except ValueError: - const = '' - info.varlist.add(typename, '*ret') - if ownsreturn: - info.varlist.add('PyObject', '*py_ret') - info.codeafter.append(' py_ret = pygstminiobject_new((GstMiniObject *)ret);\n' - ' if (ret != NULL)\n' - ' gst_mini_object_unref((GstMiniObject *)ret);\n' - ' return py_ret;') - else: - info.codeafter.append(' /* pygobject_new handles NULL checking */\n' + - ' return pygstminiobject_new((GstMiniObject *)ret);') - -class BoxedArg(ArgType): - # haven't done support for default args. Is it needed? - check = (' if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n' - ' %(name)s = pyg_boxed_get(py_%(name)s, %(typename)s);\n' - ' else {\n' - ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s");\n' - ' return NULL;\n' - ' }\n') - null = (' if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n' - ' %(name)s = pyg_boxed_get(py_%(name)s, %(typename)s);\n' - ' else if (py_%(name)s != Py_None) {\n' - ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s or None");\n' - ' return NULL;\n' - ' }\n') - def __init__(self, ptype, typecode): - self.typename = ptype - self.typecode = typecode - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pnull: - info.varlist.add(self.typename, '*' + pname + ' = NULL') - info.varlist.add('PyObject', '*py_' + pname + ' = Py_None') - info.codebefore.append(self.null % {'name': pname, - 'typename': self.typename, - 'typecode': self.typecode}) - else: - info.varlist.add(self.typename, '*' + pname + ' = NULL') - info.varlist.add('PyObject', '*py_' + pname) - info.codebefore.append(self.check % {'name': pname, - 'typename': self.typename, - 'typecode': self.typecode}) - if ptype[-1] == '*': - typename = ptype[:-1] - if typename[:6] == 'const-': typename = typename[6:] - if typename != self.typename: - info.arglist.append('(%s *)%s' % (ptype[:-1], pname)) - else: - info.arglist.append(pname) - else: - info.arglist.append(pname) - info.add_parselist('O', ['&py_' + pname], [pname]) - ret_tmpl = ' /* pyg_boxed_new handles NULL checking */\n' \ - ' return pyg_boxed_new(%(typecode)s, %(ret)s, %(copy)s, TRUE);' - def write_return(self, ptype, ownsreturn, info): - if ptype[-1] == '*': - info.varlist.add(self.typename, '*ret') - ret = 'ret' - else: - info.varlist.add(self.typename, 'ret') - ret = '&ret' - ownsreturn = 0 # of course it can't own a ref to a local var ... - info.codeafter.append(self.ret_tmpl % - { 'typecode': self.typecode, - 'ret': ret, - 'copy': ownsreturn and 'FALSE' or 'TRUE'}) - -class CustomBoxedArg(ArgType): - # haven't done support for default args. Is it needed? - null = (' if (%(check)s(py_%(name)s))\n' - ' %(name)s = %(get)s(py_%(name)s);\n' - ' else if (py_%(name)s != Py_None) {\n' - ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n' - ' return NULL;\n' - ' }\n') - def __init__(self, ptype, pytype, getter, new): - self.pytype = pytype - self.getter = getter - self.checker = 'Py' + ptype + '_Check' - self.new = new - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pnull: - info.varlist.add(ptype[:-1], '*' + pname + ' = NULL') - info.varlist.add('PyObject', '*py_' + pname + ' = Py_None') - info.codebefore.append(self.null % {'name': pname, - 'get': self.getter, - 'check': self.checker, - 'type': ptype[:-1]}) - info.arglist.append(pname) - info.add_parselist('O', ['&py_' + pname], [pname]) - else: - info.varlist.add('PyObject', '*' + pname) - info.arglist.append(self.getter + '(' + pname + ')') - info.add_parselist('O!', ['&' + self.pytype, '&' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add(ptype[:-1], '*ret') - info.codeafter.append(' if (ret)\n' + - ' return ' + self.new + '(ret);\n' + - ' Py_INCREF(Py_None);\n' + - ' return Py_None;') - -class PointerArg(ArgType): - # haven't done support for default args. Is it needed? - check = (' if (pyg_pointer_check(py_%(name)s, %(typecode)s))\n' - ' %(name)s = pyg_pointer_get(py_%(name)s, %(typename)s);\n' - ' else {\n' - ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s");\n' - ' return NULL;\n' - ' }\n') - null = (' if (pyg_pointer_check(py_%(name)s, %(typecode)s))\n' - ' %(name)s = pyg_pointer_get(py_%(name)s, %(typename)s);\n' - ' else if (py_%(name)s != Py_None) {\n' - ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s or None");\n' - ' return NULL;\n' - ' }\n') - def __init__(self, ptype, typecode): - self.typename = ptype - self.typecode = typecode - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pnull: - info.varlist.add(self.typename, '*' + pname + ' = NULL') - info.varlist.add('PyObject', '*py_' + pname + ' = Py_None') - info.codebefore.append(self.null % {'name': pname, - 'typename': self.typename, - 'typecode': self.typecode}) - else: - info.varlist.add(self.typename, '*' + pname + ' = NULL') - info.varlist.add('PyObject', '*py_' + pname) - info.codebefore.append(self.check % {'name': pname, - 'typename': self.typename, - 'typecode': self.typecode}) - info.arglist.append(pname) - info.add_parselist('O', ['&py_' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - if ptype[-1] == '*': - info.varlist.add(self.typename, '*ret') - info.codeafter.append(' /* pyg_pointer_new handles NULL checking */\n' + - ' return pyg_pointer_new(' + self.typecode + ', ret);') - else: - info.varlist.add(self.typename, 'ret') - info.codeafter.append(' /* pyg_pointer_new handles NULL checking */\n' + - ' return pyg_pointer_new(' + self.typecode + ', &ret);') - -class AtomArg(IntArg): - dflt = ' if (py_%(name)s) {\n' \ - ' %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n' \ - ' if (PyErr_Occurred())\n' \ - ' return NULL;\n' \ - ' }\n' - atom = (' %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n' - ' if (PyErr_Occurred())\n' - ' return NULL;\n') - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pdflt: - info.varlist.add('GdkAtom', pname + ' = ' + pdflt) - info.varlist.add('PyObject', '*py_' + pname + ' = NULL') - info.codebefore.append(self.dflt % {'name': pname}) - else: - info.varlist.add('GdkAtom', pname) - info.varlist.add('PyObject', '*py_' + pname + ' = NULL') - info.codebefore.append(self.atom % {'name': pname}) - info.arglist.append(pname) - info.add_parselist('O', ['&py_' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('GdkAtom', 'ret') - info.varlist.add('PyObject *', 'py_ret') - info.varlist.add('gchar *', 'name') - info.codeafter.append(' name = gdk_atom_name(ret);\n' - ' py_ret = PyString_FromString(name);\n' - ' g_free(name);\n' - ' return py_ret;') - -class GTypeArg(ArgType): - gtype = (' if ((%(name)s = pyg_type_from_object(py_%(name)s)) == 0)\n' - ' return NULL;\n') - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - info.varlist.add('GType', pname) - info.varlist.add('PyObject', '*py_' + pname + ' = NULL') - info.codebefore.append(self.gtype % {'name': pname}) - info.arglist.append(pname) - info.add_parselist('O', ['&py_' + pname], [pname]) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('GType', 'ret') - info.codeafter.append(' return pyg_type_wrapper_new(ret);') - -# simple GError handler. -class GErrorArg(ArgType): - handleerror = (' if (pyg_error_check(&%(name)s))\n' - ' return NULL;\n') - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - info.varlist.add('GError', '*' + pname + ' = NULL') - info.arglist.append('&' + pname) - info.codeafter.append(self.handleerror % { 'name': pname }) - -class GtkTreePathArg(ArgType): - # haven't done support for default args. Is it needed? - normal = (' %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n' - ' if (!%(name)s) {\n' - ' PyErr_SetString(PyExc_TypeError, "could not convert %(name)s to a GtkTreePath");\n' - ' return NULL;\n' - ' }\n') - null = (' if (py_%(name)s != Py_None) {\n' - ' %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n' - ' if (!%(name)s) {\n' - ' PyErr_SetString(PyExc_TypeError, "could not convert %(name)s to a GtkTreePath");\n' - ' return NULL;\n' - ' }\n' - ' }\n') - freepath = (' if (%(name)s)\n' - ' gtk_tree_path_free(%(name)s);\n') - def __init__(self): - pass - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pnull: - info.varlist.add('GtkTreePath', '*' + pname + ' = NULL') - info.varlist.add('PyObject', '*py_' + pname + ' = Py_None') - info.codebefore.append(self.null % {'name': pname}) - info.arglist.append(pname) - info.add_parselist('O', ['&py_' + pname], [pname]) - else: - info.varlist.add('GtkTreePath', '*' + pname) - info.varlist.add('PyObject', '*py_' + pname) - info.codebefore.append(self.normal % {'name': pname}) - info.arglist.append(pname) - info.add_parselist('O', ['&py_' + pname], [pname]) - info.codeafter.append(self.freepath % {'name': pname}) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('GtkTreePath', '*ret') - if ownsreturn: - info.codeafter.append(' if (ret) {\n' - ' PyObject *py_ret = pygtk_tree_path_to_pyobject(ret);\n' - ' gtk_tree_path_free(ret);\n' - ' return py_ret;\n' - ' }\n' - ' Py_INCREF(Py_None);\n' - ' return Py_None;') - else: - info.codeafter.append(' if (ret) {\n' - ' PyObject *py_ret = pygtk_tree_path_to_pyobject(ret);\n' - ' return py_ret;\n' - ' }\n' - ' Py_INCREF(Py_None);\n' - ' return Py_None;') - -class GdkRectanglePtrArg(ArgType): - normal = (' if (!pygdk_rectangle_from_pyobject(py_%(name)s, &%(name)s))\n' - ' return NULL;\n') - null = (' if (py_%(name)s == Py_None)\n' - ' %(name)s = NULL;\n' - ' else if (pygdk_rectangle_from_pyobject(py_%(name)s, &%(name)s_rect))\n' - ' %(name)s = &%(name)s_rect;\n' - ' else\n' - ' return NULL;\n') - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - if pnull: - info.varlist.add('GdkRectangle', pname + '_rect = { 0, 0, 0, 0 }') - info.varlist.add('GdkRectangle', '*' + pname) - info.varlist.add('PyObject', '*py_' + pname + ' = Py_None') - info.add_parselist('O', ['&py_' + pname], [pname]) - info.arglist.append(pname) - info.codebefore.append(self.null % {'name': pname}) - else: - info.varlist.add('GdkRectangle', pname + ' = { 0, 0, 0, 0 }') - info.varlist.add('PyObject', '*py_' + pname) - info.add_parselist('O', ['&py_' + pname], [pname]) - info.arglist.append('&' + pname) - info.codebefore.append(self.normal % {'name': pname}) - -class GdkRectangleArg(ArgType): - def write_return(self, ptype, ownsreturn, info): - info.varlist.add('GdkRectangle', 'ret') - info.codeafter.append(' return pyg_boxed_new(GDK_TYPE_RECTANGLE, &ret, TRUE, TRUE);') - -class PyObjectArg(ArgType): - def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info): - info.varlist.add('PyObject', '*' + pname) - info.add_parselist('O', ['&' + pname], [pname]) - info.arglist.append(pname) - def write_return(self, ptype, ownsreturn, info): - info.varlist.add("PyObject", "*ret") - if ownsreturn: - info.codeafter.append(' if (ret) {\n' - ' return ret;\n' - ' }\n' - ' Py_INCREF(Py_None);\n' - ' return Py_None;') - else: - info.codeafter.append(' if (!ret) ret = Py_None;\n' - ' Py_INCREF(ret);\n' - ' return ret;') - -class ArgMatcher: - def __init__(self): - self.argtypes = {} - self.reverse_argtypes = {} - self.reverse_rettypes = {} - - def register(self, ptype, handler): - self.argtypes[ptype] = handler - def register_reverse(self, ptype, handler): - self.reverse_argtypes[ptype] = handler - def register_reverse_ret(self, ptype, handler): - self.reverse_rettypes[ptype] = handler - - def register_enum(self, ptype, typecode): - if typecode is None: - typecode = "G_TYPE_NONE" - self.register(ptype, EnumArg(ptype, typecode)) - def register_flag(self, ptype, typecode): - if typecode is None: - typecode = "G_TYPE_NONE" - self.register(ptype, FlagsArg(ptype, typecode)) - def register_object(self, ptype, parent, typecode): - oa = ObjectArg(ptype, parent, typecode) - self.register(ptype, oa) # in case I forget the * in the .defs - self.register(ptype+'*', oa) - self.register('const-'+ptype+'*', oa) - if ptype == 'GdkPixmap': - # hack to handle GdkBitmap synonym. - self.register('GdkBitmap', oa) - self.register('GdkBitmap*', oa) - def register_miniobject(self, ptype, parent, typecode): - oa = MiniObjectArg(ptype, parent, typecode) - self.register(ptype, oa) # in case I forget the * in the .defs - self.register(ptype+'*', oa) - def register_boxed(self, ptype, typecode): - if self.argtypes.has_key(ptype): return - arg = BoxedArg(ptype, typecode) - self.register(ptype, arg) - self.register(ptype+'*', arg) - self.register('const-'+ptype+'*', arg) - def register_custom_boxed(self, ptype, pytype, getter, new): - arg = CustomBoxedArg(ptype, pytype, getter, new) - self.register(ptype+'*', arg) - self.register('const-'+ptype+'*', arg) - def register_pointer(self, ptype, typecode): - arg = PointerArg(ptype, typecode) - self.register(ptype, arg) - self.register(ptype+'*', arg) - self.register('const-'+ptype+'*', arg) - - def get(self, ptype): - try: - return self.argtypes[ptype] - except KeyError: - if ptype[:8] == 'GdkEvent' and ptype[-1] == '*': - return self.argtypes['GdkEvent*'] - raise - def _get_reverse_common(self, ptype, registry): - props = dict(c_type=ptype) - try: - return registry[ptype], props - except KeyError: - try: - handler = self.argtypes[ptype] - except KeyError: - if ptype.startswith('GdkEvent') and ptype.endswith('*'): - handler = self.argtypes['GdkEvent*'] - else: - raise - if isinstance(handler, ObjectArg): - return registry['GObject*'], props - elif isinstance(handler, EnumArg): - props['typecode'] = handler.typecode - props['enumname'] = handler.enumname - return registry['GEnum'], props - elif isinstance(handler, FlagsArg): - props['typecode'] = handler.typecode - props['flagname'] = handler.flagname - return registry['GFlags'], props - elif isinstance(handler, BoxedArg): - props['typecode'] = handler.typecode - props['typename'] = handler.typename - return registry['GBoxed'], props - else: - raise - def get_reverse(self, ptype): - return self._get_reverse_common(ptype, self.reverse_argtypes) - def get_reverse_ret(self, ptype): - return self._get_reverse_common(ptype, self.reverse_rettypes) - - def object_is_a(self, otype, parent): - if otype == None: return 0 - if otype == parent: return 1 - if not self.argtypes.has_key(otype): return 0 - return self.object_is_a(self.get(otype).parent, parent) - -matcher = ArgMatcher() - -arg = NoneArg() -matcher.register(None, arg) -matcher.register('none', arg) - -arg = StringArg() -matcher.register('char*', arg) -matcher.register('gchar*', arg) -matcher.register('const-char*', arg) -matcher.register('char-const*', arg) -matcher.register('const-gchar*', arg) -matcher.register('gchar-const*', arg) -matcher.register('string', arg) -matcher.register('static_string', arg) - -arg = UCharArg() -matcher.register('unsigned-char*', arg) -matcher.register('const-guchar*', arg) -matcher.register('guchar*', arg) - -arg = CharArg() -matcher.register('char', arg) -matcher.register('gchar', arg) -matcher.register('guchar', arg) - -arg = GUniCharArg() -matcher.register('gunichar', arg) - -arg = IntArg() -matcher.register('int', arg) -matcher.register('gint', arg) -matcher.register('short', arg) -matcher.register('gshort', arg) -matcher.register('gushort', arg) -matcher.register('gsize', SizeArg()) -matcher.register('gssize', SSizeArg()) -matcher.register('guint8', arg) -matcher.register('gint8', arg) -matcher.register('guint16', arg) -matcher.register('gint16', arg) -matcher.register('gint32', arg) -matcher.register('GTime', arg) - -arg = LongArg() -matcher.register('long', arg) -matcher.register('glong', arg) - -arg = UIntArg() -matcher.register('guint', arg) - -arg = BoolArg() -matcher.register('gboolean', arg) - -arg = TimeTArg() -matcher.register('time_t', arg) - -matcher.register('guint32', UInt32Arg()) - -arg = ULongArg() -matcher.register('gulong', arg) - -arg = Int64Arg() -matcher.register('gint64', arg) -matcher.register('long-long', arg) - -arg = UInt64Arg() -matcher.register('guint64', arg) -matcher.register('unsigned-long-long', arg) - -arg = DoubleArg() -matcher.register('double', arg) -matcher.register('gdouble', arg) -matcher.register('float', arg) -matcher.register('gfloat', arg) - -arg = FileArg() -matcher.register('FILE*', arg) - -# enums, flags, objects - -matcher.register('GdkAtom', AtomArg()) - -matcher.register('GType', GTypeArg()) -matcher.register('GtkType', GTypeArg()) - -matcher.register('GError**', GErrorArg()) -matcher.register('GtkTreePath*', GtkTreePathArg()) -matcher.register('GdkRectangle*', GdkRectanglePtrArg()) -matcher.register('GtkAllocation*', GdkRectanglePtrArg()) -matcher.register('GdkRectangle', GdkRectangleArg()) -matcher.register('PyObject*', PyObjectArg()) - -matcher.register('GdkNativeWindow', ULongArg()) - -matcher.register_object('GObject', None, 'G_TYPE_OBJECT') -matcher.register_miniobject('GstMiniObject', None, 'GST_TYPE_MINI_OBJECT') - -del arg diff --git a/bindings/python/codegen/code-coverage.py b/bindings/python/codegen/code-coverage.py deleted file mode 100755 index fd15034736..0000000000 --- a/bindings/python/codegen/code-coverage.py +++ /dev/null @@ -1,42 +0,0 @@ -from __future__ import generators -import sys, os - -def read_symbols(file, type=None, dynamic=0): - if dynamic: - cmd = 'nm -D %s' % file - else: - cmd = 'nm %s' % file - for line in os.popen(cmd, 'r'): - if line[0] != ' ': # has an address as first bit of line - while line[0] != ' ': - line = line[1:] - while line[0] == ' ': - line = line[1:] - # we should be up to "type symbolname" now - sym_type = line[0] - symbol = line[1:].strip() - - if not type or type == sym_type: - yield symbol - -def main(): - if len(sys.argv) != 3: - sys.stderr.write('usage: coverage-check library.so wrapper.so\n') - sys.exit(1) - library = sys.argv[1] - wrapper = sys.argv[2] - - # first create a dict with all referenced symbols in the wrapper - # should really be a set, but a dict will do ... - wrapper_symbols = {} - for symbol in read_symbols(wrapper, type='U', dynamic=1): - wrapper_symbols[symbol] = 1 - - # now go through the library looking for matches on the defined symbols: - for symbol in read_symbols(library, type='T', dynamic=1): - if symbol[0] == '_': continue - if symbol not in wrapper_symbols: - print symbol - -if __name__ == '__main__': - main() diff --git a/bindings/python/codegen/codegen.py b/bindings/python/codegen/codegen.py deleted file mode 100644 index 8f20bf7089..0000000000 --- a/bindings/python/codegen/codegen.py +++ /dev/null @@ -1,1572 +0,0 @@ -import getopt -import keyword -import os -import string -import sys - -import argtypes -import definitions -import defsparser -import override -import reversewrapper - -class Coverage(object): - def __init__(self, name): - self.name = name - self.wrapped = 0 - self.not_wrapped = 0 - - def declare_wrapped(self): - self.wrapped += 1 - - def declare_not_wrapped(self): - self.not_wrapped += 1 - - def printstats(self): - total = self.wrapped + self.not_wrapped - fd = sys.stderr - if total: - fd.write("***INFO*** The coverage of %s is %.2f%% (%i/%i)\n" % - (self.name, - float(self.wrapped*100)/total, - self.wrapped, - total)) - else: - fd.write("***INFO*** There are no declared %s." % self.name) - -functions_coverage = Coverage("global functions") -methods_coverage = Coverage("methods") -vproxies_coverage = Coverage("virtual proxies") -vaccessors_coverage = Coverage("virtual accessors") -iproxies_coverage = Coverage("interface proxies") - -def exc_info(): - #traceback.print_exc() - etype, value, tb = sys.exc_info() - ret = "" - try: - sval = str(value) - if etype == KeyError: - ret = "No ArgType for %s" % (sval,) - else: - ret = sval - finally: - del etype, value, tb - return ret - -def fixname(name): - if keyword.iskeyword(name): - return name + '_' - return name - -class FileOutput: - '''Simple wrapper for file object, that makes writing #line - statements easier.''' # " - def __init__(self, fp, filename=None): - self.fp = fp - self.lineno = 1 - if filename: - self.filename = filename - else: - self.filename = self.fp.name - # handle writing to the file, and keep track of the line number ... - def write(self, str): - self.fp.write(str) - self.lineno = self.lineno + string.count(str, '\n') - def writelines(self, sequence): - for line in sequence: - self.write(line) - def close(self): - self.fp.close() - def flush(self): - self.fp.flush() - - def setline(self, linenum, filename): - '''writes out a #line statement, for use by the C - preprocessor.''' # " - self.write('#line %d "%s"\n' % (linenum, filename)) - def resetline(self): - '''resets line numbering to the original file''' - self.setline(self.lineno + 1, self.filename) - -class Wrapper: - type_tmpl = ( - 'PyTypeObject Py%(typename)s_Type = {\n' - ' PyObject_HEAD_INIT(NULL)\n' - ' 0, /* ob_size */\n' - ' "%(classname)s", /* tp_name */\n' - ' sizeof(%(tp_basicsize)s), /* tp_basicsize */\n' - ' 0, /* tp_itemsize */\n' - ' /* methods */\n' - ' (destructor)%(tp_dealloc)s, /* tp_dealloc */\n' - ' (printfunc)0, /* tp_print */\n' - ' (getattrfunc)%(tp_getattr)s, /* tp_getattr */\n' - ' (setattrfunc)%(tp_setattr)s, /* tp_setattr */\n' - ' (cmpfunc)%(tp_compare)s, /* tp_compare */\n' - ' (reprfunc)%(tp_repr)s, /* tp_repr */\n' - ' (PyNumberMethods*)%(tp_as_number)s, /* tp_as_number */\n' - ' (PySequenceMethods*)%(tp_as_sequence)s, /* tp_as_sequence */\n' - ' (PyMappingMethods*)%(tp_as_mapping)s, /* tp_as_mapping */\n' - ' (hashfunc)%(tp_hash)s, /* tp_hash */\n' - ' (ternaryfunc)%(tp_call)s, /* tp_call */\n' - ' (reprfunc)%(tp_str)s, /* tp_str */\n' - ' (getattrofunc)%(tp_getattro)s, /* tp_getattro */\n' - ' (setattrofunc)%(tp_setattro)s, /* tp_setattro */\n' - ' (PyBufferProcs*)%(tp_as_buffer)s, /* tp_as_buffer */\n' - ' %(tp_flags)s, /* tp_flags */\n' - ' %(tp_doc)s, /* Documentation string */\n' - ' (traverseproc)%(tp_traverse)s, /* tp_traverse */\n' - ' (inquiry)%(tp_clear)s, /* tp_clear */\n' - ' (richcmpfunc)%(tp_richcompare)s, /* tp_richcompare */\n' - ' %(tp_weaklistoffset)s, /* tp_weaklistoffset */\n' - ' (getiterfunc)%(tp_iter)s, /* tp_iter */\n' - ' (iternextfunc)%(tp_iternext)s, /* tp_iternext */\n' - ' (struct PyMethodDef*)%(tp_methods)s, /* tp_methods */\n' - ' (struct PyMemberDef*)0, /* tp_members */\n' - ' (struct PyGetSetDef*)%(tp_getset)s, /* tp_getset */\n' - ' NULL, /* tp_base */\n' - ' NULL, /* tp_dict */\n' - ' (descrgetfunc)%(tp_descr_get)s, /* tp_descr_get */\n' - ' (descrsetfunc)%(tp_descr_set)s, /* tp_descr_set */\n' - ' %(tp_dictoffset)s, /* tp_dictoffset */\n' - ' (initproc)%(tp_init)s, /* tp_init */\n' - ' (allocfunc)%(tp_alloc)s, /* tp_alloc */\n' - ' (newfunc)%(tp_new)s, /* tp_new */\n' - ' (freefunc)%(tp_free)s, /* tp_free */\n' - ' (inquiry)%(tp_is_gc)s /* tp_is_gc */\n' - '};\n\n' - ) - - slots_list = [ - 'tp_getattr', 'tp_setattr', 'tp_getattro', 'tp_setattro', - 'tp_compare', 'tp_repr', - 'tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'tp_hash', - 'tp_call', 'tp_str', 'tp_as_buffer', 'tp_richcompare', 'tp_iter', - 'tp_iternext', 'tp_descr_get', 'tp_descr_set', 'tp_init', - 'tp_alloc', 'tp_new', 'tp_free', 'tp_is_gc', - 'tp_traverse', 'tp_clear', 'tp_dealloc', 'tp_flags', 'tp_doc' - ] - - getter_tmpl = ( - 'static PyObject *\n' - '%(funcname)s(PyObject *self, void *closure)\n' - '{\n' - '%(varlist)s' - ' ret = %(field)s;\n' - '%(codeafter)s\n' - '}\n\n' - ) - - parse_tmpl = ( - ' if (!PyArg_ParseTupleAndKeywords(args, kwargs,' - '"%(typecodes)s:%(name)s"%(parselist)s))\n' - ' return %(errorreturn)s;\n' - ) - - deprecated_tmpl = ( - ' if (PyErr_Warn(PyExc_DeprecationWarning, ' - '"%(deprecationmsg)s") < 0)\n' - ' return %(errorreturn)s;\n' - ) - - methdef_tmpl = ( - ' { "%(name)s", (PyCFunction)%(cname)s, %(flags)s,\n' - ' %(docstring)s },\n' - ) - - noconstructor = ( - 'static int\n' - 'pygobject_no_constructor(PyObject *self, PyObject *args, ' - 'PyObject *kwargs)\n' - '{\n' - ' gchar buf[512];\n' - '\n' - ' g_snprintf(buf, sizeof(buf), "%s is an abstract widget", ' - 'self->ob_type->tp_name);\n' - ' PyErr_SetString(PyExc_NotImplementedError, buf);\n' - ' return -1;\n' - '}\n\n' - ) - - function_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' %(begin_allow_threads)s\n' - ' %(setreturn)s%(cname)s(%(arglist)s);\n' - ' %(end_allow_threads)s\n' - '%(codeafter)s\n' - '}\n\n' - ) - - virtual_accessor_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n' - '{\n' - ' gpointer klass;\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' klass = g_type_class_ref(pyg_type_from_object(cls));\n' - ' if (%(class_cast_macro)s(klass)->%(virtual)s) {\n' - ' pyg_begin_allow_threads;\n' - ' %(setreturn)s%(class_cast_macro)s(klass)->' - '%(virtual)s(%(arglist)s);\n' - ' pyg_end_allow_threads;\n' - ' } else {\n' - ' PyErr_SetString(PyExc_NotImplementedError, ' - '"virtual method %(name)s not implemented");\n' - ' g_type_class_unref(klass);\n' - ' return NULL;\n' - ' }\n' - ' g_type_class_unref(klass);\n' - '%(codeafter)s\n' - '}\n\n' - ) - - # template for method calls - constructor_tmpl = None - method_tmpl = None - - def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)): - self.parser = parser - self.objinfo = objinfo - self.overrides = overrides - self.fp = fp - - def get_lower_name(self): - return string.lower(string.replace(self.objinfo.typecode, - '_TYPE_', '_', 1)) - - def get_field_accessor(self, fieldname): - raise NotImplementedError - - def get_initial_class_substdict(self): return {} - - def get_initial_constructor_substdict(self, constructor): - return { 'name': '%s.__init__' % self.objinfo.c_name, - 'errorreturn': '-1' } - def get_initial_method_substdict(self, method): - substdict = { 'name': '%s.%s' % (self.objinfo.c_name, method.name) } - substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;' - substdict['end_allow_threads'] = 'pyg_end_allow_threads;' - return substdict - - def write_class(self): - if self.overrides.is_type_ignored(self.objinfo.c_name): - return - self.fp.write('\n/* ----------- %s ----------- */\n\n' % - self.objinfo.c_name) - substdict = self.get_initial_class_substdict() - if not substdict.has_key('tp_flags'): - substdict['tp_flags'] = 'Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE' - substdict['typename'] = self.objinfo.c_name - if self.overrides.modulename: - substdict['classname'] = '%s.%s' % (self.overrides.modulename, - self.objinfo.name) - else: - substdict['classname'] = self.objinfo.name - substdict['tp_doc'] = self.objinfo.docstring - - # Maybe this could be done in a nicer way, but I'll leave it as it is - # for now: -- Johan - if not self.overrides.slot_is_overriden('%s.tp_init' % - self.objinfo.c_name): - substdict['tp_init'] = self.write_constructor() - substdict['tp_methods'] = self.write_methods() - substdict['tp_getset'] = self.write_getsets() - - # handle slots ... - for slot in self.slots_list: - - slotname = '%s.%s' % (self.objinfo.c_name, slot) - slotfunc = '_wrap_%s_%s' % (self.get_lower_name(), slot) - if slot[:6] == 'tp_as_': - slotfunc = '&' + slotfunc - if self.overrides.slot_is_overriden(slotname): - data = self.overrides.slot_override(slotname) - self.write_function(slotname, data) - substdict[slot] = slotfunc - else: - if not substdict.has_key(slot): - substdict[slot] = '0' - - self.fp.write(self.type_tmpl % substdict) - - self.write_virtuals() - - def write_function_wrapper(self, function_obj, template, - handle_return=0, is_method=0, kwargs_needed=0, - substdict=None): - '''This function is the guts of all functions that generate - wrappers for functions, methods and constructors.''' - if not substdict: substdict = {} - - info = argtypes.WrapperInfo() - - substdict.setdefault('errorreturn', 'NULL') - - # for methods, we want the leading comma - if is_method: - info.arglist.append('') - - if function_obj.varargs: - raise ValueError, "varargs functions not supported" - - for param in function_obj.params: - if param.pdflt and '|' not in info.parsestr: - info.add_parselist('|', [], []) - handler = argtypes.matcher.get(param.ptype) - handler.write_param(param.ptype, param.pname, param.pdflt, - param.pnull, param.keeprefcount, info) - - substdict['setreturn'] = '' - if handle_return: - if function_obj.ret not in ('none', None): - substdict['setreturn'] = 'ret = ' - handler = argtypes.matcher.get(function_obj.ret) - handler.write_return(function_obj.ret, - function_obj.caller_owns_return, info) - - if function_obj.deprecated != None: - deprecated = self.deprecated_tmpl % { - 'deprecationmsg': function_obj.deprecated, - 'errorreturn': substdict['errorreturn'] } - else: - deprecated = '' - - # if name isn't set, set it to function_obj.name - substdict.setdefault('name', function_obj.name) - - substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;' - substdict['end_allow_threads'] = 'pyg_end_allow_threads;' - - if self.objinfo: - substdict['typename'] = self.objinfo.c_name - substdict.setdefault('cname', function_obj.c_name) - substdict['varlist'] = info.get_varlist() - substdict['typecodes'] = info.parsestr - substdict['parselist'] = info.get_parselist() - substdict['arglist'] = info.get_arglist() - substdict['codebefore'] = deprecated + ( - string.replace(info.get_codebefore(), - 'return NULL', 'return ' + substdict['errorreturn']) - ) - substdict['codeafter'] = ( - string.replace(info.get_codeafter(), - 'return NULL', - 'return ' + substdict['errorreturn'])) - - if info.parsestr or kwargs_needed: - substdict['parseargs'] = self.parse_tmpl % substdict - substdict['extraparams'] = ', PyObject *args, PyObject *kwargs' - flags = 'METH_VARARGS|METH_KEYWORDS' - - # prepend the keyword list to the variable list - substdict['varlist'] = info.get_kwlist() + substdict['varlist'] - else: - substdict['parseargs'] = '' - substdict['extraparams'] = '' - flags = 'METH_NOARGS' - - return template % substdict, flags - - def write_constructor(self): - initfunc = '0' - constructor = self.parser.find_constructor(self.objinfo,self.overrides) - if not constructor: - return self.write_default_constructor() - - funcname = constructor.c_name - try: - if self.overrides.is_overriden(funcname): - data = self.overrides.override(funcname) - self.write_function(funcname, data) - self.objinfo.has_new_constructor_api = ( - self.objinfo.typecode in - self.overrides.newstyle_constructors) - else: - # ok, a hack to determine if we should use - # new-style constructores :P - property_based = getattr(self, - 'write_property_based_constructor', - None) - if property_based: - if (len(constructor.params) == 0 or - isinstance(constructor.params[0], - definitions.Property)): - # write_property_based_constructor is only - # implemented in GObjectWrapper - return self.write_property_based_constructor( - constructor) - else: - sys.stderr.write( - "Warning: generating old-style constructor for:" + - constructor.c_name + '\n') - - # write constructor from template ... - code = self.write_function_wrapper(constructor, - self.constructor_tmpl, - handle_return=0, is_method=0, kwargs_needed=1, - substdict=self.get_initial_constructor_substdict( - constructor))[0] - self.fp.write(code) - initfunc = '_wrap_' + funcname - except: - sys.stderr.write('Could not write constructor for %s: %s\n' - % (self.objinfo.c_name, exc_info())) - - initfunc = self.write_noconstructor() - return initfunc - - def write_noconstructor(self): - # this is a hack ... - if not hasattr(self.overrides, 'no_constructor_written'): - self.fp.write(self.noconstructor) - self.overrides.no_constructor_written = 1 - initfunc = 'pygobject_no_constructor' - return initfunc - - def write_default_constructor(self): - return self.write_noconstructor() - - def get_methflags(self, funcname): - if self.overrides.wants_kwargs(funcname): - flags = 'METH_VARARGS|METH_KEYWORDS' - elif self.overrides.wants_noargs(funcname): - flags = 'METH_NOARGS' - elif self.overrides.wants_onearg(funcname): - flags = 'METH_O' - else: - flags = 'METH_VARARGS' - if self.overrides.is_staticmethod(funcname): - flags += '|METH_STATIC' - elif self.overrides.is_classmethod(funcname): - flags += '|METH_CLASS' - return flags - - def write_function(self, funcname, data): - lineno, filename = self.overrides.getstartline(funcname) - self.fp.setline(lineno, filename) - self.fp.write(data) - self.fp.resetline() - self.fp.write('\n\n') - - def _get_class_virtual_substdict(self, meth, cname, parent): - substdict = self.get_initial_method_substdict(meth) - substdict['virtual'] = substdict['name'].split('.')[1] - substdict['cname'] = cname - substdict['class_cast_macro'] = parent.typecode.replace( - '_TYPE_', '_', 1) + "_CLASS" - substdict['typecode'] = self.objinfo.typecode - substdict['cast'] = string.replace(parent.typecode, '_TYPE_', '_', 1) - return substdict - - def write_methods(self): - methods = [] - klass = self.objinfo.c_name - # First, get methods from the defs files - for meth in self.parser.find_methods(self.objinfo): - method_name = meth.c_name - if self.overrides.is_ignored(method_name): - continue - try: - if self.overrides.is_overriden(method_name): - if not self.overrides.is_already_included(method_name): - data = self.overrides.override(method_name) - self.write_function(method_name, data) - - methflags = self.get_methflags(method_name) - else: - # write constructor from template ... - code, methflags = self.write_function_wrapper(meth, - self.method_tmpl, handle_return=1, is_method=1, - substdict=self.get_initial_method_substdict(meth)) - self.fp.write(code) - methods.append(self.methdef_tmpl % - { 'name': fixname(meth.name), - 'cname': '_wrap_' + method_name, - 'flags': methflags, - 'docstring': meth.docstring }) - methods_coverage.declare_wrapped() - except: - methods_coverage.declare_not_wrapped() - sys.stderr.write('Could not write method %s.%s: %s\n' - % (klass, meth.name, exc_info())) - - # Now try to see if there are any defined in the override - for method_name in self.overrides.get_defines_for(klass): - c_name = override.class2cname(klass, method_name) - if self.overrides.is_already_included(method_name): - continue - - try: - data = self.overrides.define(klass, method_name) - self.write_function(method_name, data) - methflags = self.get_methflags(method_name) - - methods.append(self.methdef_tmpl % - { 'name': method_name, - 'cname': '_wrap_' + c_name, - 'flags': methflags, - 'docstring': meth.docstring }) - methods_coverage.declare_wrapped() - except: - methods_coverage.declare_not_wrapped() - sys.stderr.write('Could not write method %s.%s: %s\n' - % (klass, meth.name, exc_info())) - - # Add GObject virtual method accessors, for chaining to parent - # virtuals from subclasses - methods += self.write_virtual_accessors() - - if methods: - methoddefs = '_Py%s_methods' % self.objinfo.c_name - # write the PyMethodDef structure - methods.append(' { NULL, NULL, 0, NULL }\n') - self.fp.write('static const PyMethodDef %s[] = {\n' % methoddefs) - self.fp.write(string.join(methods, '')) - self.fp.write('};\n\n') - else: - methoddefs = 'NULL' - return methoddefs - - def write_virtual_accessors(self): - klass = self.objinfo.c_name - methods = [] - for meth in self.parser.find_virtuals(self.objinfo): - method_name = self.objinfo.c_name + "__do_" + meth.name - if self.overrides.is_ignored(method_name): - continue - try: - if self.overrides.is_overriden(method_name): - if not self.overrides.is_already_included(method_name): - data = self.overrides.override(method_name) - self.write_function(method_name, data) - methflags = self.get_methflags(method_name) - else: - # temporarily add a 'self' parameter as first argument - meth.params.insert(0, definitions.Parameter( - ptype=(self.objinfo.c_name + '*'), - pname='self', pdflt=None, pnull=None)) - try: - # write method from template ... - code, methflags = self.write_function_wrapper( - meth, self.virtual_accessor_tmpl, - handle_return=True, is_method=False, - substdict=self._get_class_virtual_substdict( - meth, method_name, self.objinfo)) - self.fp.write(code) - finally: - del meth.params[0] - methods.append(self.methdef_tmpl % - { 'name': "do_" + fixname(meth.name), - 'cname': '_wrap_' + method_name, - 'flags': methflags + '|METH_CLASS', - 'docstring': 'NULL'}) - vaccessors_coverage.declare_wrapped() - except: - vaccessors_coverage.declare_not_wrapped() - sys.stderr.write( - 'Could not write virtual accessor method %s.%s: %s\n' - % (klass, meth.name, exc_info())) - return methods - - def write_virtuals(self): - ''' - Write _wrap_FooBar__proxy_do_zbr() reverse wrapers for - GObject virtuals - ''' - klass = self.objinfo.c_name - virtuals = [] - for meth in self.parser.find_virtuals(self.objinfo): - method_name = self.objinfo.c_name + "__proxy_do_" + meth.name - if self.overrides.is_ignored(method_name): - continue - try: - if self.overrides.is_overriden(method_name): - if not self.overrides.is_already_included(method_name): - data = self.overrides.override(method_name) - self.write_function(method_name, data) - else: - # write virtual proxy ... - ret, props = argtypes.matcher.get_reverse_ret(meth.ret) - wrapper = reversewrapper.ReverseWrapper( - '_wrap_' + method_name, is_static=True) - wrapper.set_return_type(ret(wrapper, **props)) - wrapper.add_parameter(reversewrapper.PyGObjectMethodParam( - wrapper, "self", method_name="do_" + meth.name, - c_type=(klass + ' *'))) - for param in meth.params: - handler, props = argtypes.matcher.get_reverse( - param.ptype) - props["direction"] = param.pdir - wrapper.add_parameter(handler(wrapper, - param.pname, **props)) - buf = reversewrapper.MemoryCodeSink() - wrapper.generate(buf) - self.fp.write(buf.flush()) - virtuals.append((fixname(meth.name), '_wrap_' + method_name)) - vproxies_coverage.declare_wrapped() - except (KeyError, ValueError): - vproxies_coverage.declare_not_wrapped() - virtuals.append((fixname(meth.name), None)) - sys.stderr.write('Could not write virtual proxy %s.%s: %s\n' - % (klass, meth.name, exc_info())) - if virtuals: - # Write a 'pygtk class init' function for this object, - # except when the object type is explicitly ignored (like - # GtkPlug and GtkSocket on win32). - if self.overrides.is_ignored(self.objinfo.typecode): - return - class_cast_macro = self.objinfo.typecode.replace( - '_TYPE_', '_', 1) + "_CLASS" - cast_macro = self.objinfo.typecode.replace('_TYPE_', '_', 1) - funcname = "__%s_class_init" % klass - self.objinfo.class_init_func = funcname - have_implemented_virtuals = not not [True - for name, cname in virtuals - if cname is not None] - self.fp.write( - ('\nstatic int\n' - '%(funcname)s(gpointer gclass, PyTypeObject *pyclass)\n' - '{\n') % vars()) - - if have_implemented_virtuals: - self.fp.write(' PyObject *o;\n') - self.fp.write( - ' %(klass)sClass *klass = ' - '%(class_cast_macro)s(gclass);\n' - ' PyObject *gsignals = ' - 'PyDict_GetItemString(pyclass->tp_dict, "__gsignals__");\n' - % vars()) - - for name, cname in virtuals: - do_name = 'do_' + name - if cname is None: - self.fp.write('\n /* overriding %(do_name)s ' - 'is currently not supported */\n' % vars()) - else: - self.fp.write(''' - o = PyObject_GetAttrString((PyObject *) pyclass, "%(do_name)s"); - if (o == NULL) - PyErr_Clear(); - else { - if (!PyObject_TypeCheck(o, &PyCFunction_Type) - && !(gsignals && PyDict_GetItemString(gsignals, "%(name)s"))) - klass->%(name)s = %(cname)s; - Py_DECREF(o); - } -''' % vars()) - self.fp.write(' return 0;\n}\n') - - def write_getsets(self): - lower_name = self.get_lower_name() - getsets_name = lower_name + '_getsets' - getterprefix = '_wrap_' + lower_name + '__get_' - setterprefix = '_wrap_' + lower_name + '__set_' - - # no overrides for the whole function. If no fields, - # don't write a func - if not self.objinfo.fields: - return '0' - getsets = [] - for ftype, cfname in self.objinfo.fields: - fname = cfname.replace('.', '_') - gettername = '0' - settername = '0' - attrname = self.objinfo.c_name + '.' + fname - if self.overrides.attr_is_overriden(attrname): - code = self.overrides.attr_override(attrname) - self.write_function(attrname, code) - if string.find(code, getterprefix + fname) >= 0: - gettername = getterprefix + fname - if string.find(code, setterprefix + fname) >= 0: - settername = setterprefix + fname - if gettername == '0': - try: - funcname = getterprefix + fname - info = argtypes.WrapperInfo() - handler = argtypes.matcher.get(ftype) - # for attributes, we don't own the "return value" - handler.write_return(ftype, 0, info) - self.fp.write(self.getter_tmpl % - { 'funcname': funcname, - 'varlist': info.varlist, - 'field': self.get_field_accessor(cfname), - 'codeafter': info.get_codeafter() }) - gettername = funcname - except: - sys.stderr.write( - "Could not write getter for %s.%s: %s\n" - % (self.objinfo.c_name, fname, exc_info())) - if gettername != '0' or settername != '0': - getsets.append(' { "%s", (getter)%s, (setter)%s },\n' % - (fixname(fname), gettername, settername)) - - if not getsets: - return '0' - self.fp.write('static const PyGetSetDef %s[] = {\n' % getsets_name) - for getset in getsets: - self.fp.write(getset) - self.fp.write(' { NULL, (getter)0, (setter)0 },\n') - self.fp.write('};\n\n') - - return getsets_name - - def write_functions(self, prefix): - self.fp.write('\n/* ----------- functions ----------- */\n\n') - functions = [] - - # First, get methods from the defs files - for func in self.parser.find_functions(): - funcname = func.c_name - if self.overrides.is_ignored(funcname): - continue - try: - if self.overrides.is_overriden(funcname): - data = self.overrides.override(funcname) - self.write_function(funcname, data) - - methflags = self.get_methflags(funcname) - else: - # write constructor from template ... - code, methflags = self.write_function_wrapper(func, - self.function_tmpl, handle_return=1, is_method=0) - self.fp.write(code) - functions.append(self.methdef_tmpl % - { 'name': func.name, - 'cname': '_wrap_' + funcname, - 'flags': methflags, - 'docstring': func.docstring }) - functions_coverage.declare_wrapped() - except: - functions_coverage.declare_not_wrapped() - sys.stderr.write('Could not write function %s: %s\n' - % (func.name, exc_info())) - - # Now try to see if there are any defined in the override - for funcname in self.overrides.get_functions(): - try: - data = self.overrides.function(funcname) - self.write_function(funcname, data) - methflags = self.get_methflags(funcname) - functions.append(self.methdef_tmpl % - { 'name': funcname, - 'cname': '_wrap_' + funcname, - 'flags': methflags, - 'docstring': 'NULL'}) - functions_coverage.declare_wrapped() - except: - functions_coverage.declare_not_wrapped() - sys.stderr.write('Could not write function %s: %s\n' - % (funcname, exc_info())) - - # write the PyMethodDef structure - functions.append(' { NULL, NULL, 0, NULL }\n') - - self.fp.write('const PyMethodDef ' + prefix + '_functions[] = {\n') - self.fp.write(string.join(functions, '')) - self.fp.write('};\n\n') - -class GObjectWrapper(Wrapper): - constructor_tmpl = ( - 'static int\n' - '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' self->obj = (GObject *)%(cname)s(%(arglist)s);\n' - '%(codeafter)s\n' - ' if (!self->obj) {\n' - ' PyErr_SetString(PyExc_RuntimeError, ' - '"could not create %(typename)s object");\n' - ' return -1;\n' - ' }\n' - '%(aftercreate)s' - ' pygobject_register_wrapper((PyObject *)self);\n' - ' return 0;\n' - '}\n\n' - ) - - method_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' %(begin_allow_threads)s\n' - ' %(setreturn)s%(cname)s(%(cast)s(self->obj)%(arglist)s);\n' - ' %(end_allow_threads)s\n' - '%(codeafter)s\n' - '}\n\n' - ) - def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)): - Wrapper.__init__(self, parser, objinfo, overrides, fp) - if self.objinfo: - self.castmacro = string.replace(self.objinfo.typecode, - '_TYPE_', '_', 1) - - def get_initial_class_substdict(self): - return { 'tp_basicsize' : 'PyGObject', - 'tp_weaklistoffset' : 'offsetof(PyGObject, weakreflist)', - 'tp_dictoffset' : 'offsetof(PyGObject, inst_dict)' } - - def get_field_accessor(self, fieldname): - castmacro = string.replace(self.objinfo.typecode, '_TYPE_', '_', 1) - return '%s(pygobject_get(self))->%s' % (castmacro, fieldname) - - def get_initial_constructor_substdict(self, constructor): - substdict = Wrapper.get_initial_constructor_substdict(self, - constructor) - if not constructor.caller_owns_return: - substdict['aftercreate'] = " g_object_ref(self->obj);\n" - else: - substdict['aftercreate'] = '' - return substdict - - def get_initial_method_substdict(self, method): - substdict = Wrapper.get_initial_method_substdict(self, method) - substdict['cast'] = string.replace(self.objinfo.typecode, - '_TYPE_', '_', 1) - return substdict - - def write_default_constructor(self): - try: - parent = self.parser.find_object(self.objinfo.parent) - except ValueError: - parent = None - if parent is not None: - ## just like the constructor is inheritted, we should - # inherit the new API compatibility flag - self.objinfo.has_new_constructor_api = ( - parent.has_new_constructor_api) - elif self.objinfo.parent == 'GObject': - self.objinfo.has_new_constructor_api = True - return '0' - - def write_property_based_constructor(self, constructor): - self.objinfo.has_new_constructor_api = True - out = self.fp - print >> out, "static int" - print >> out, '_wrap_%s(PyGObject *self, PyObject *args,' \ - ' PyObject *kwargs)\n{' % constructor.c_name - if constructor.params: - s = " GType obj_type = pyg_type_from_object((PyObject *) self);" - print >> out, s - - def py_str_list_to_c(arg): - if arg: - return "{" + ", ".join( - map(lambda s: '"' + s + '"', arg)) + ", NULL }" - else: - return "{ NULL }" - - classname = '%s.%s' % (self.overrides.modulename, - self.objinfo.name) - - if constructor.params: - mandatory_arguments = [param for param in constructor.params - if not param.optional] - optional_arguments = [param for param in constructor.params - if param.optional] - arg_names = py_str_list_to_c( - [param.argname - for param in mandatory_arguments + optional_arguments]) - - prop_names = py_str_list_to_c( - [param.pname - for param in mandatory_arguments + optional_arguments]) - - print >> out, " GParameter params[%i];" % \ - len(constructor.params) - print >> out, " PyObject *parsed_args[%i] = {NULL, };" % \ - len(constructor.params) - print >> out, " char *arg_names[] = %s;" % arg_names - print >> out, " char *prop_names[] = %s;" % prop_names - print >> out, " guint nparams, i;" - print >> out - if constructor.deprecated is not None: - out.write( - ' if (PyErr_Warn(PyExc_DeprecationWarning, ' - '"%s") < 0)\n' % - constructor.deprecated) - print >> out, ' return -1;' - print >> out - out.write(" if (!PyArg_ParseTupleAndKeywords(args, kwargs, ") - template = '"' - if mandatory_arguments: - template += "O"*len(mandatory_arguments) - if optional_arguments: - template += "|" + "O"*len(optional_arguments) - template += ':%s.__init__"' % classname - print >> out, template, ", arg_names", - for i in range(len(constructor.params)): - print >> out, ", &parsed_args[%i]" % i, - - out.write( - "))\n" - " return -1;\n" - "\n" - " memset(params, 0, sizeof(GParameter)*%i);\n" - " if (!pyg_parse_constructor_args(obj_type, arg_names,\n" - " prop_names, params, \n" - " &nparams, parsed_args))\n" - " return -1;\n" - " pygobject_constructv(self, nparams, params);\n" - " for (i = 0; i < nparams; ++i)\n" - " g_value_unset(¶ms[i].value);\n" - % len(constructor.params)) - else: - out.write( - " static char* kwlist[] = { NULL };\n" - "\n") - - if constructor.deprecated is not None: - out.write( - ' if (PyErr_Warn(PyExc_DeprecationWarning, "%s") < 0)\n' - ' return -1;\n' - '\n' % constructor.deprecated) - - out.write( - ' if (!PyArg_ParseTupleAndKeywords(args, kwargs,\n' - ' ":%s.__init__",\n' - ' kwlist))\n' - ' return -1;\n' - '\n' - ' pygobject_constructv(self, 0, NULL);\n' % classname) - out.write( - ' if (!self->obj) {\n' - ' PyErr_SetString(\n' - ' PyExc_RuntimeError, \n' - ' "could not create %s object");\n' - ' return -1;\n' - ' }\n' % classname) - - if not constructor.caller_owns_return: - print >> out, " g_object_ref(self->obj);\n" - - out.write( - ' return 0;\n' - '}\n\n') - - return "_wrap_%s" % constructor.c_name - - -## TODO : Add GstMiniObjectWrapper(Wrapper) -class GstMiniObjectWrapper(Wrapper): - constructor_tmpl = ( - 'static int\n' - '_wrap_%(cname)s(PyGstMiniObject *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' self->obj = (GstMiniObject *)%(cname)s(%(arglist)s);\n' - '%(codeafter)s\n' - ' if (!self->obj) {\n' - ' PyErr_SetString(PyExc_RuntimeError, ' - '"could not create %(typename)s miniobject");\n' - ' return -1;\n' - ' }\n' - '%(aftercreate)s' - ' pygstminiobject_register_wrapper((PyObject *)self);\n' - ' return 0;\n' - '}\n\n' - ) - method_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyGstMiniObject *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' %(begin_allow_threads)s\n' - ' %(setreturn)s%(cname)s(%(cast)s(self->obj)%(arglist)s);\n' - ' %(end_allow_threads)s\n' - '%(codeafter)s\n' - '}\n\n' - ) - def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)): - Wrapper.__init__(self, parser, objinfo, overrides, fp) - if self.objinfo: - self.castmacro = string.replace(self.objinfo.typecode, - '_TYPE_', '_', 1) - - def get_initial_class_substdict(self): - return { 'tp_basicsize' : 'PyGstMiniObject', - 'tp_weaklistoffset' : 'offsetof(PyGstMiniObject, weakreflist)', - 'tp_dictoffset' : 'offsetof(PyGstMiniObject, inst_dict)' } - - def get_field_accessor(self, fieldname): - castmacro = string.replace(self.objinfo.typecode, '_TYPE_', '_', 1) - return '%s(pygstminiobject_get(self))->%s' % (castmacro, fieldname) - - def get_initial_constructor_substdict(self, constructor): - substdict = Wrapper.get_initial_constructor_substdict(self, - constructor) - if not constructor.caller_owns_return: - substdict['aftercreate'] = " gst_mini_object_ref(self->obj);\n" - else: - substdict['aftercreate'] = '' - return substdict - - def get_initial_method_substdict(self, method): - substdict = Wrapper.get_initial_method_substdict(self, method) - substdict['cast'] = string.replace(self.objinfo.typecode, - '_TYPE_', '_', 1) - return substdict - - - -class GInterfaceWrapper(GObjectWrapper): - virtual_accessor_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n' - '{\n' - ' %(vtable)s *iface;\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' iface = g_type_interface_peek(' - 'g_type_class_peek(pyg_type_from_object(cls)), %(typecode)s);\n' - ' if (iface->%(virtual)s)\n' - ' %(setreturn)siface->%(virtual)s(%(arglist)s);\n' - ' else {\n' - ' PyErr_SetString(PyExc_NotImplementedError, ' - '"interface method %(name)s not implemented");\n' - ' return NULL;\n' - ' }\n' - '%(codeafter)s\n' - '}\n\n' - ) - - def get_initial_class_substdict(self): - return { 'tp_basicsize' : 'PyObject', - 'tp_weaklistoffset' : '0', - 'tp_dictoffset' : '0'} - - def write_constructor(self): - # interfaces have no constructors ... - return '0' - def write_getsets(self): - # interfaces have no fields ... - return '0' - - def _get_class_virtual_substdict(self, meth, cname, parent): - substdict = self.get_initial_method_substdict(meth) - substdict['virtual'] = substdict['name'].split('.')[1] - substdict['cname'] = cname - substdict['typecode'] = self.objinfo.typecode - substdict['vtable'] = self.objinfo.vtable - return substdict - - def write_virtuals(self): - ## Now write reverse method wrappers, which let python code - ## implement interface methods. - # First, get methods from the defs files - klass = self.objinfo.c_name - proxies = [] - for meth in self.parser.find_virtuals(self.objinfo): - method_name = self.objinfo.c_name + "__proxy_do_" + meth.name - if self.overrides.is_ignored(method_name): - continue - try: - if self.overrides.is_overriden(method_name): - if not self.overrides.is_already_included(method_name): - data = self.overrides.override(method_name) - self.write_function(method_name, data) - else: - # write proxy ... - ret, props = argtypes.matcher.get_reverse_ret(meth.ret) - wrapper = reversewrapper.ReverseWrapper( - '_wrap_' + method_name, is_static=True) - wrapper.set_return_type(ret(wrapper, **props)) - wrapper.add_parameter(reversewrapper.PyGObjectMethodParam( - wrapper, "self", method_name="do_" + meth.name, - c_type=(klass + ' *'))) - for param in meth.params: - handler, props = argtypes.matcher.get_reverse( - param.ptype) - props["direction"] = param.pdir - wrapper.add_parameter( - handler(wrapper, param.pname, **props)) - buf = reversewrapper.MemoryCodeSink() - wrapper.generate(buf) - self.fp.write(buf.flush()) - proxies.append((fixname(meth.name), '_wrap_' + method_name)) - iproxies_coverage.declare_wrapped() - except (KeyError, ValueError): - iproxies_coverage.declare_not_wrapped() - proxies.append((fixname(meth.name), None)) - sys.stderr.write('Could not write interface proxy %s.%s: %s\n' - % (klass, meth.name, exc_info())) - - if not proxies: - return - - # Make sure we have at least one proxy function - if not [cname for name,cname in proxies if not cname is None]: - return - - ## Write an interface init function for this object - funcname = "__%s__interface_init" % klass - vtable = self.objinfo.vtable - self.fp.write( - '\nstatic void\n' - '%(funcname)s(%(vtable)s *iface, PyTypeObject *pytype)\n' - '{\n' - ' %(vtable)s *parent_iface = ' - 'g_type_interface_peek_parent(iface);\n' - ' PyObject *py_method;\n' - '\n' - % vars()) - - for name, cname in proxies: - do_name = 'do_' + name - if cname is None: - continue - - self.fp.write(( - ' py_method = pytype? PyObject_GetAttrString(' - '(PyObject *) pytype, "%(do_name)s") : NULL;\n' - ' if (py_method && !PyObject_TypeCheck(py_method, ' - '&PyCFunction_Type)) {\n' - ' iface->%(name)s = %(cname)s;\n' - ' } else {\n' - ' PyErr_Clear();\n' - ' if (parent_iface) {\n' - ' iface->%(name)s = parent_iface->%(name)s;\n' - ' }\n' - ' Py_XDECREF(py_method);\n' - ' }\n' - ) % vars()) - self.fp.write('}\n\n') - interface_info = "__%s__iinfo" % klass - self.fp.write(''' -static const GInterfaceInfo %s = { - (GInterfaceInitFunc) %s, - NULL, - NULL -}; -''' % (interface_info, funcname)) - self.objinfo.interface_info = interface_info - -class GBoxedWrapper(Wrapper): - constructor_tmpl = ( - 'static int\n' - '_wrap_%(cname)s(PyGBoxed *self%(extraparams)s)\n' - '{\n' \ - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' self->gtype = %(typecode)s;\n' - ' self->free_on_dealloc = FALSE;\n' - ' self->boxed = %(cname)s(%(arglist)s);\n' - '%(codeafter)s\n' - ' if (!self->boxed) {\n' - ' PyErr_SetString(PyExc_RuntimeError, ' - '"could not create %(typename)s object");\n' - ' return -1;\n' - ' }\n' - ' self->free_on_dealloc = TRUE;\n' - ' return 0;\n' - '}\n\n' - ) - - method_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' %(begin_allow_threads)s\n' - ' %(setreturn)s%(cname)s(pyg_boxed_get(self, ' - '%(typename)s)%(arglist)s);\n' - ' %(end_allow_threads)s\n' - '%(codeafter)s\n' - '}\n\n' - ) - - def get_initial_class_substdict(self): - return { 'tp_basicsize' : 'PyGBoxed', - 'tp_weaklistoffset' : '0', - 'tp_dictoffset' : '0' } - - def get_field_accessor(self, fieldname): - return 'pyg_boxed_get(self, %s)->%s' % (self.objinfo.c_name, fieldname) - - def get_initial_constructor_substdict(self, constructor): - substdict = Wrapper.get_initial_constructor_substdict( - self, constructor) - substdict['typecode'] = self.objinfo.typecode - return substdict - -class GPointerWrapper(GBoxedWrapper): - constructor_tmpl = ( - 'static int\n' - '_wrap_%(cname)s(PyGPointer *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' self->gtype = %(typecode)s;\n' - ' self->pointer = %(cname)s(%(arglist)s);\n' - '%(codeafter)s\n' - ' if (!self->pointer) {\n' - ' PyErr_SetString(PyExc_RuntimeError, ' - '"could not create %(typename)s object");\n' - ' return -1;\n' - ' }\n' - ' return 0;\n' - '}\n\n' - ) - - method_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' %(setreturn)s%(cname)s(pyg_pointer_get(self, ' - '%(typename)s)%(arglist)s);\n' - '%(codeafter)s\n' - '}\n\n' - ) - - def get_initial_class_substdict(self): - return { 'tp_basicsize' : 'PyGPointer', - 'tp_weaklistoffset' : '0', - 'tp_dictoffset' : '0' } - - def get_field_accessor(self, fieldname): - return 'pyg_pointer_get(self, %s)->%s' % (self.objinfo.c_name, - fieldname) - - def get_initial_constructor_substdict(self, constructor): - substdict = Wrapper.get_initial_constructor_substdict( - self, constructor) - substdict['typecode'] = self.objinfo.typecode - return substdict - -def write_headers(data, fp): - fp.write('/* -- THIS FILE IS GENERATED - DO NOT EDIT */') - fp.write('/* -*- Mode: C; c-basic-offset: 4 -*- */\n\n') - fp.write('#include \n\n\n') - fp.write(data) - fp.resetline() - fp.write('\n\n') - -def write_body(data, fp): - fp.write(data) - fp.resetline() - fp.write('\n\n') - -def write_imports(overrides, fp): - fp.write('/* ---------- types from other modules ---------- */\n') - for module, pyname, cname in overrides.get_imports(): - fp.write('static PyTypeObject *_%s;\n' % cname) - fp.write('#define %s (*_%s)\n' % (cname, cname)) - fp.write('\n\n') - -def write_type_declarations(parser, fp): - fp.write('/* ---------- forward type declarations ---------- */\n') - for obj in parser.boxes: - fp.write('PyTypeObject Py' + obj.c_name + '_Type;\n') - for obj in parser.objects: - fp.write('PyTypeObject Py' + obj.c_name + '_Type;\n') - for obj in parser.miniobjects: - fp.write('PyTypeObject Py' + obj.c_name + '_Type;\n') - for interface in parser.interfaces: - fp.write('PyTypeObject Py' + interface.c_name + '_Type;\n') - fp.write('\n') - - -def sort_parent_children(objects): - objects = list(objects) - modified = True - while modified: - modified = False - parent_index = None - child_index = None - for i, obj in enumerate(objects): - if obj.parent == 'GObject': - continue - if obj.parent not in [info.c_name for info in objects[:i]]: - for j, info in enumerate(objects[i+1:]): - if info.c_name == obj.parent: - parent_index = i + 1 + j - child_index = i - break - else: - continue - break - if child_index is not None and parent_index is not None: - if child_index != parent_index: - objects.insert(child_index, objects.pop(parent_index)) - modified = True - return objects - -def write_classes(parser, overrides, fp): - ## Sort the objects, so that we generate code for the parent types - ## before their children. - objects = sort_parent_children(parser.objects) - for klass, items in ((GBoxedWrapper, parser.boxes), - (GPointerWrapper, parser.pointers), - (GObjectWrapper, objects), - (GstMiniObjectWrapper, parser.miniobjects), - (GInterfaceWrapper, parser.interfaces)): - for item in items: - instance = klass(parser, item, overrides, fp) - instance.write_class() - fp.write('\n') - -def write_enums(parser, overrides, prefix, fp=sys.stdout): - if not parser.enums: - return - fp.write('\n/* ----------- enums and flags ----------- */\n\n') - fp.write( - 'void\n' + prefix + - '_add_constants(PyObject *module, const gchar *strip_prefix)\n{\n') - - for enum in parser.enums: - if overrides.is_type_ignored(enum.c_name): - continue - if enum.typecode is None: - for nick, value in enum.values: - fp.write( - ' PyModule_AddIntConstant(module, ' - '(char *) pyg_constant_strip_prefix("%s", strip_prefix), %s);\n' - % (value, value)) - else: - if enum.deftype == 'enum': - fp.write(' pyg_enum_add(module, "%s", strip_prefix, %s);\n' - % (enum.name, enum.typecode)) - else: - fp.write(' pyg_flags_add(module, "%s", strip_prefix, %s);\n' - % (enum.name, enum.typecode)) - - fp.write('\n') - fp.write(' if (PyErr_Occurred())\n') - fp.write(' PyErr_Print();\n') - fp.write('}\n\n') - -def write_extension_init(overrides, prefix, fp): - fp.write('/* initialise stuff extension classes */\n') - fp.write('void\n' + prefix + '_register_classes(PyObject *d)\n{\n') - imports = overrides.get_imports()[:] - if imports: - bymod = {} - for module, pyname, cname in imports: - bymod.setdefault(module, []).append((pyname, cname)) - fp.write(' PyObject *module;\n\n') - for module in bymod: - fp.write( - ' if ((module = PyImport_ImportModule("%s")) != NULL) {\n' - % module) - fp.write( - ' PyObject *moddict = PyModule_GetDict(module);\n\n') - for pyname, cname in bymod[module]: - fp.write( - ' _%s = (PyTypeObject *)PyDict_GetItemString(' - 'moddict, "%s");\n' % (cname, pyname)) - fp.write(' if (_%s == NULL) {\n' % cname) - fp.write(' PyErr_SetString(PyExc_ImportError,\n') - fp.write(' "cannot import name %s from %s");\n' - % (pyname, module)) - fp.write(' return;\n') - fp.write(' }\n') - fp.write(' } else {\n') - fp.write(' PyErr_SetString(PyExc_ImportError,\n') - fp.write(' "could not import %s");\n' % module) - fp.write(' return;\n') - fp.write(' }\n') - fp.write('\n') - fp.write(overrides.get_init() + '\n') - fp.resetline() - -def write_registers(parser, overrides, fp): - for boxed in parser.boxes: - if overrides.is_type_ignored(boxed.c_name): - continue - fp.write(' pyg_register_boxed(d, "' + boxed.name + - '", ' + boxed.typecode + - ', &Py' + boxed.c_name + - '_Type);\n') - for pointer in parser.pointers: - if overrides.is_type_ignored(pointer.c_name): - continue - fp.write(' pyg_register_pointer(d, "' + pointer.name + - '", ' + pointer.typecode + - ', &Py' + pointer.c_name + '_Type);\n') - for interface in parser.interfaces: - if overrides.is_type_ignored(interface.c_name): - continue - fp.write(' pyg_register_interface(d, "' + interface.name + - '", '+ interface.typecode + ', &Py' + interface.c_name + - '_Type);\n') - if interface.interface_info is not None: - fp.write(' pyg_register_interface_info(%s, &%s);\n' % - (interface.typecode, interface.interface_info)) - - objects = parser.objects[:] - pos = 0 - while pos < len(objects): - parent = objects[pos].parent - for i in range(pos+1, len(objects)): - if objects[i].c_name == parent: - objects.insert(i+1, objects[pos]) - del objects[pos] - break - else: - pos = pos + 1 - for obj in objects: - if overrides.is_type_ignored(obj.c_name): - continue - bases = [] - if obj.parent != None: - bases.append(obj.parent) - bases = bases + obj.implements - if bases: - fp.write(' pygobject_register_class(d, "' + obj.c_name + - '", ' + obj.typecode + ', &Py' + obj.c_name + - '_Type, Py_BuildValue("(' + 'O' * len(bases) + ')", ' + - string.join(map(lambda s: '&Py'+s+'_Type', bases), ', ') + - '));\n') - else: - fp.write(' pygobject_register_class(d, "' + obj.c_name + - '", ' + obj.typecode + ', &Py' + obj.c_name + - '_Type, NULL);\n') - if obj.has_new_constructor_api: - fp.write(' pyg_set_object_has_new_constructor(%s);\n' % - obj.typecode) - else: - print >> sys.stderr, ( - "Warning: Constructor for %s needs to be updated to new API\n" - " See http://live.gnome.org/PyGTK_2fWhatsNew28" - "#update-constructors") % obj.c_name - if obj.class_init_func is not None: - fp.write(' pyg_register_class_init(%s, %s);\n' % - (obj.typecode, obj.class_init_func)) - #TODO: register mini-objects - miniobjects = parser.miniobjects[:] - for obj in miniobjects: - bases = [] - if obj.parent != None: - bases.append(obj.parent) - bases = bases + obj.implements - if bases: - fp.write(' pygstminiobject_register_class(d, "' + obj.c_name + - '", ' + obj.typecode + ', &Py' + obj.c_name + - '_Type, Py_BuildValue("(' + 'O' * len(bases) + ')", ' + - string.join(map(lambda s: '&Py'+s+'_Type', bases), ', ') + - '));\n') - else: - fp.write(' pygstminiobject_register_class(d, "' + obj.c_name + - '", ' + obj.typecode + ', &Py' + obj.c_name + - '_Type, NULL);\n') - - fp.write('}\n') - -def write_source(parser, overrides, prefix, fp=FileOutput(sys.stdout)): - write_headers(overrides.get_headers(), fp) - write_imports(overrides, fp) - write_type_declarations(parser, fp) - write_body(overrides.get_body(), fp) - write_classes(parser, overrides, fp) - - wrapper = Wrapper(parser, None, overrides, fp) - wrapper.write_functions(prefix) - - write_enums(parser, overrides, prefix, fp) - write_extension_init(overrides, prefix, fp) - write_registers(parser, overrides, fp) - -def register_types(parser): - for boxed in parser.boxes: - argtypes.matcher.register_boxed(boxed.c_name, boxed.typecode) - for pointer in parser.pointers: - argtypes.matcher.register_pointer(pointer.c_name, pointer.typecode) - for obj in parser.objects: - argtypes.matcher.register_object(obj.c_name, obj.parent, obj.typecode) - for obj in parser.miniobjects: - argtypes.matcher.register_miniobject(obj.c_name, obj.parent, obj.typecode) - for obj in parser.interfaces: - argtypes.matcher.register_object(obj.c_name, None, obj.typecode) - for enum in parser.enums: - if enum.deftype == 'flags': - argtypes.matcher.register_flag(enum.c_name, enum.typecode) - else: - argtypes.matcher.register_enum(enum.c_name, enum.typecode) - -usage = 'usage: codegen.py [-o overridesfile] [-p prefix] defsfile' -def main(argv): - o = override.Overrides() - prefix = 'pygtk' - outfilename = None - errorfilename = None - extendpath = [] - opts, args = getopt.getopt(argv[1:], "o:p:r:t:D:x", - ["override=", "prefix=", "register=", "outfilename=", - "load-types=", "errorfilename=", "extendpath="]) - defines = {} # -Dkey[=val] options - - for opt, arg in opts: - if opt in ('-x', '--extendpath'): - extendpath.append(arg) - extendpath.insert(0, os.getcwd()) - o = override.Overrides(path=extendpath) - - for opt, arg in opts: - if opt in ('-o', '--override'): - o = override.Overrides(arg, path=extendpath) - elif opt in ('-p', '--prefix'): - prefix = arg - elif opt in ('-r', '--register'): - # Warning: user has to make sure all -D options appear before -r - p = defsparser.DefsParser(arg, defines) - p.startParsing() - register_types(p) - del p - elif opt == '--outfilename': - outfilename = arg - elif opt == '--errorfilename': - errorfilename = arg - elif opt in ('-t', '--load-types'): - globals = {} - execfile(arg, globals) - elif opt == '-D': - nameval = arg.split('=') - try: - defines[nameval[0]] = nameval[1] - except IndexError: - defines[nameval[0]] = None - if len(args) < 1: - print >> sys.stderr, usage - return 1 - if errorfilename: - sys.stderr = open(errorfilename, "w") - p = defsparser.DefsParser(args[0], defines) - if not outfilename: - outfilename = os.path.splitext(args[0])[0] + '.c' - - p.startParsing() - - register_types(p) - write_source(p, o, prefix, FileOutput(sys.stdout, outfilename)) - - functions_coverage.printstats() - methods_coverage.printstats() - vproxies_coverage.printstats() - vaccessors_coverage.printstats() - iproxies_coverage.printstats() - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/bindings/python/codegen/definitions.py b/bindings/python/codegen/definitions.py deleted file mode 100644 index 911c8ddb4b..0000000000 --- a/bindings/python/codegen/definitions.py +++ /dev/null @@ -1,607 +0,0 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- -import copy -import sys - -def get_valid_scheme_definitions(defs): - return [x for x in defs if isinstance(x, tuple) and len(x) >= 2] - -def unescape(s): - s = s.replace('\r\n', '\\r\\n').replace('\t', '\\t') - return s.replace('\r', '\\r').replace('\n', '\\n') - -def make_docstring(lines): - return "(char *) " + '\n'.join(['"%s"' % unescape(s) for s in lines]) - -# New Parameter class, wich emulates a tuple for compatibility reasons -class Parameter(object): - def __init__(self, ptype, pname, pdflt, pnull, pdir=None, keeprefcount = False): - self.ptype = ptype - self.pname = pname - self.pdflt = pdflt - self.pnull = pnull - self.pdir = pdir - self.keeprefcount = keeprefcount - - def __len__(self): return 4 - def __getitem__(self, i): - return (self.ptype, self.pname, self.pdflt, self.pnull)[i] - - def merge(self, old): - if old.pdflt is not None: - self.pdflt = old.pdflt - if old.pnull is not None: - self.pnull = old.pnull - -# Parameter for property based constructors -class Property(object): - def __init__(self, pname, optional, argname): - self.pname = pname - self.optional = optional - self.argname = argname - - def merge(self, old): - if old.optional is not None: - self.optional = old.optional - if old.argname is not None: - self.argname = old.argname - - -class Definition: - docstring = "NULL" - def __init__(self, *args): - """Create a new defs object of this type. The arguments are the - components of the definition""" - raise RuntimeError, "this is an abstract class" - def merge(self, old): - """Merge in customisations from older version of definition""" - raise RuntimeError, "this is an abstract class" - def write_defs(self, fp=sys.stdout): - """write out this definition in defs file format""" - raise RuntimeError, "this is an abstract class" - - def guess_return_value_ownership(self): - "return 1 if caller owns return value" - if getattr(self, 'is_constructor_of', False): - self.caller_owns_return = True - elif self.ret in ('char*', 'gchar*', 'string'): - self.caller_owns_return = True - else: - self.caller_owns_return = False - - -class ObjectDef(Definition): - def __init__(self, name, *args): - self.name = name - self.module = None - self.parent = None - self.c_name = None - self.typecode = None - self.fields = [] - self.implements = [] - self.class_init_func = None - self.has_new_constructor_api = False - for arg in get_valid_scheme_definitions(args): - if arg[0] == 'in-module': - self.module = arg[1] - elif arg[0] == 'docstring': - self.docstring = make_docstring(arg[1:]) - elif arg[0] == 'parent': - self.parent = arg[1] - elif arg[0] == 'c-name': - self.c_name = arg[1] - elif arg[0] == 'gtype-id': - self.typecode = arg[1] - elif arg[0] == 'fields': - for parg in arg[1:]: - self.fields.append((parg[0], parg[1])) - elif arg[0] == 'implements': - self.implements.append(arg[1]) - def merge(self, old): - # currently the .h parser doesn't try to work out what fields of - # an object structure should be public, so we just copy the list - # from the old version ... - self.fields = old.fields - self.implements = old.implements - def write_defs(self, fp=sys.stdout): - fp.write('(define-object ' + self.name + '\n') - if self.module: - fp.write(' (in-module "' + self.module + '")\n') - if self.parent != (None, None): - fp.write(' (parent "' + self.parent + '")\n') - for interface in self.implements: - fp.write(' (implements "' + interface + '")\n') - if self.c_name: - fp.write(' (c-name "' + self.c_name + '")\n') - if self.typecode: - fp.write(' (gtype-id "' + self.typecode + '")\n') - if self.fields: - fp.write(' (fields\n') - for (ftype, fname) in self.fields: - fp.write(' \'("' + ftype + '" "' + fname + '")\n') - fp.write(' )\n') - fp.write(')\n\n') - -class MiniObjectDef(Definition): - def __init__(self, name, *args): - self.name = name - self.module = None - self.parent = None - self.c_name = None - self.typecode = None - self.fields = [] - self.implements = [] - for arg in args: - if type(arg) != type(()) or len(arg) < 2: - continue - if arg[0] == 'in-module': - self.module = arg[1] - elif arg[0] == 'parent': - self.parent = arg[1] - elif arg[0] == 'c-name': - self.c_name = arg[1] - elif arg[0] == 'gtype-id': - self.typecode = arg[1] - elif arg[0] == 'fields': - for parg in arg[1:]: - self.fields.append((parg[0], parg[1])) - elif arg[0] == 'implements': - self.implements.append(arg[1]) - def merge(self, old): - # currently the .h parser doesn't try to work out what fields of - # an object structure should be public, so we just copy the list - # from the old version ... - self.fields = old.fields - self.implements = old.implements - def write_defs(self, fp=sys.stdout): - fp.write('(define-object ' + self.name + '\n') - if self.module: - fp.write(' (in-module "' + self.module + '")\n') - if self.parent != (None, None): - fp.write(' (parent "' + self.parent + '")\n') - for interface in self.implements: - fp.write(' (implements "' + interface + '")\n') - if self.c_name: - fp.write(' (c-name "' + self.c_name + '")\n') - if self.typecode: - fp.write(' (gtype-id "' + self.typecode + '")\n') - if self.fields: - fp.write(' (fields\n') - for (ftype, fname) in self.fields: - fp.write(' \'("' + ftype + '" "' + fname + '")\n') - fp.write(' )\n') - fp.write(')\n\n') - - -class InterfaceDef(Definition): - def __init__(self, name, *args): - self.name = name - self.module = None - self.c_name = None - self.typecode = None - self.vtable = None - self.fields = [] - self.interface_info = None - for arg in get_valid_scheme_definitions(args): - if arg[0] == 'in-module': - self.module = arg[1] - elif arg[0] == 'docstring': - self.docstring = make_docstring(arg[1:]) - elif arg[0] == 'c-name': - self.c_name = arg[1] - elif arg[0] == 'gtype-id': - self.typecode = arg[1] - elif arg[0] == 'vtable': - self.vtable = arg[1] - if self.vtable is None: - self.vtable = self.c_name + "Iface" - def write_defs(self, fp=sys.stdout): - fp.write('(define-interface ' + self.name + '\n') - if self.module: - fp.write(' (in-module "' + self.module + '")\n') - if self.c_name: - fp.write(' (c-name "' + self.c_name + '")\n') - if self.typecode: - fp.write(' (gtype-id "' + self.typecode + '")\n') - fp.write(')\n\n') - -class EnumDef(Definition): - def __init__(self, name, *args): - self.deftype = 'enum' - self.name = name - self.in_module = None - self.c_name = None - self.typecode = None - self.values = [] - for arg in get_valid_scheme_definitions(args): - if arg[0] == 'in-module': - self.in_module = arg[1] - elif arg[0] == 'c-name': - self.c_name = arg[1] - elif arg[0] == 'gtype-id': - self.typecode = arg[1] - elif arg[0] == 'values': - for varg in arg[1:]: - self.values.append((varg[0], varg[1])) - def merge(self, old): - pass - def write_defs(self, fp=sys.stdout): - fp.write('(define-' + self.deftype + ' ' + self.name + '\n') - if self.in_module: - fp.write(' (in-module "' + self.in_module + '")\n') - fp.write(' (c-name "' + self.c_name + '")\n') - fp.write(' (gtype-id "' + self.typecode + '")\n') - if self.values: - fp.write(' (values\n') - for name, val in self.values: - fp.write(' \'("' + name + '" "' + val + '")\n') - fp.write(' )\n') - fp.write(')\n\n') - -class FlagsDef(EnumDef): - def __init__(self, *args): - apply(EnumDef.__init__, (self,) + args) - self.deftype = 'flags' - -class BoxedDef(Definition): - def __init__(self, name, *args): - self.name = name - self.module = None - self.c_name = None - self.typecode = None - self.copy = None - self.release = None - self.fields = [] - for arg in get_valid_scheme_definitions(args): - if arg[0] == 'in-module': - self.module = arg[1] - elif arg[0] == 'c-name': - self.c_name = arg[1] - elif arg[0] == 'gtype-id': - self.typecode = arg[1] - elif arg[0] == 'copy-func': - self.copy = arg[1] - elif arg[0] == 'release-func': - self.release = arg[1] - elif arg[0] == 'fields': - for parg in arg[1:]: - self.fields.append((parg[0], parg[1])) - def merge(self, old): - # currently the .h parser doesn't try to work out what fields of - # an object structure should be public, so we just copy the list - # from the old version ... - self.fields = old.fields - def write_defs(self, fp=sys.stdout): - fp.write('(define-boxed ' + self.name + '\n') - if self.module: - fp.write(' (in-module "' + self.module + '")\n') - if self.c_name: - fp.write(' (c-name "' + self.c_name + '")\n') - if self.typecode: - fp.write(' (gtype-id "' + self.typecode + '")\n') - if self.copy: - fp.write(' (copy-func "' + self.copy + '")\n') - if self.release: - fp.write(' (release-func "' + self.release + '")\n') - if self.fields: - fp.write(' (fields\n') - for (ftype, fname) in self.fields: - fp.write(' \'("' + ftype + '" "' + fname + '")\n') - fp.write(' )\n') - fp.write(')\n\n') - -class PointerDef(Definition): - def __init__(self, name, *args): - self.name = name - self.module = None - self.c_name = None - self.typecode = None - self.fields = [] - for arg in get_valid_scheme_definitions(args): - if arg[0] == 'in-module': - self.module = arg[1] - elif arg[0] == 'c-name': - self.c_name = arg[1] - elif arg[0] == 'gtype-id': - self.typecode = arg[1] - elif arg[0] == 'fields': - for parg in arg[1:]: - self.fields.append((parg[0], parg[1])) - def merge(self, old): - # currently the .h parser doesn't try to work out what fields of - # an object structure should be public, so we just copy the list - # from the old version ... - self.fields = old.fields - def write_defs(self, fp=sys.stdout): - fp.write('(define-pointer ' + self.name + '\n') - if self.module: - fp.write(' (in-module "' + self.module + '")\n') - if self.c_name: - fp.write(' (c-name "' + self.c_name + '")\n') - if self.typecode: - fp.write(' (gtype-id "' + self.typecode + '")\n') - if self.fields: - fp.write(' (fields\n') - for (ftype, fname) in self.fields: - fp.write(' \'("' + ftype + '" "' + fname + '")\n') - fp.write(' )\n') - fp.write(')\n\n') - -class MethodDefBase(Definition): - def __init__(self, name, *args): - dump = 0 - self.name = name - self.ret = None - self.caller_owns_return = None - self.unblock_threads = None - self.c_name = None - self.typecode = None - self.of_object = None - self.params = [] # of form (type, name, default, nullok) - self.varargs = 0 - self.deprecated = None - for arg in get_valid_scheme_definitions(args): - if arg[0] == 'of-object': - self.of_object = arg[1] - elif arg[0] == 'docstring': - self.docstring = make_docstring(arg[1:]) - elif arg[0] == 'c-name': - self.c_name = arg[1] - elif arg[0] == 'gtype-id': - self.typecode = arg[1] - elif arg[0] == 'return-type': - self.ret = arg[1] - elif arg[0] == 'caller-owns-return': - self.caller_owns_return = arg[1] in ('t', '#t') - elif arg[0] == 'unblock-threads': - self.unblock_threads = arg[1] in ('t', '#t') - elif arg[0] == 'parameters': - for parg in arg[1:]: - ptype = parg[0] - pname = parg[1] - pdflt = None - pnull = 0 - pdir = None - keeprefcount = False - for farg in parg[2:]: - assert isinstance(farg, tuple) - if farg[0] == 'default': - pdflt = farg[1] - elif farg[0] == 'null-ok': - pnull = 1 - elif farg[0] == 'direction': - pdir = farg[1] - elif farg[0] == 'keep-refcount': - keeprefcount = True - self.params.append(Parameter(ptype, pname, pdflt, pnull, pdir, - keeprefcount=keeprefcount)) - elif arg[0] == 'varargs': - self.varargs = arg[1] in ('t', '#t') - elif arg[0] == 'deprecated': - self.deprecated = arg[1] - else: - sys.stderr.write("Warning: %s argument unsupported.\n" - % (arg[0])) - dump = 1 - if dump: - self.write_defs(sys.stderr) - - if self.caller_owns_return is None and self.ret is not None: - self.guess_return_value_ownership() - - def merge(self, old, parmerge): - self.caller_owns_return = old.caller_owns_return - self.varargs = old.varargs - # here we merge extra parameter flags accross to the new object. - if not parmerge: - self.params = copy.deepcopy(old.params) - return - for i in range(len(self.params)): - ptype, pname, pdflt, pnull = self.params[i] - for p2 in old.params: - if p2[1] == pname: - self.params[i] = (ptype, pname, p2[2], p2[3]) - break - def _write_defs(self, fp=sys.stdout): - if self.of_object != (None, None): - fp.write(' (of-object "' + self.of_object + '")\n') - if self.c_name: - fp.write(' (c-name "' + self.c_name + '")\n') - if self.typecode: - fp.write(' (gtype-id "' + self.typecode + '")\n') - if self.caller_owns_return: - fp.write(' (caller-owns-return #t)\n') - if self.unblock_threads: - fp.write(' (unblock_threads #t)\n') - if self.ret: - fp.write(' (return-type "' + self.ret + '")\n') - if self.deprecated: - fp.write(' (deprecated "' + self.deprecated + '")\n') - if self.params: - fp.write(' (parameters\n') - for ptype, pname, pdflt, pnull in self.params: - fp.write(' \'("' + ptype + '" "' + pname +'"') - if pdflt: fp.write(' (default "' + pdflt + '")') - if pnull: fp.write(' (null-ok)') - fp.write(')\n') - fp.write(' )\n') - if self.varargs: - fp.write(' (varargs #t)\n') - fp.write(')\n\n') - - -class MethodDef(MethodDefBase): - def __init__(self, name, *args): - MethodDefBase.__init__(self, name, *args) - for item in ('c_name', 'of_object'): - if self.__dict__[item] == None: - self.write_defs(sys.stderr) - raise RuntimeError, "definition missing required %s" % (item,) - - def write_defs(self, fp=sys.stdout): - fp.write('(define-method ' + self.name + '\n') - self._write_defs(fp) - -class VirtualDef(MethodDefBase): - def write_defs(self, fp=sys.stdout): - fp.write('(define-virtual ' + self.name + '\n') - self._write_defs(fp) - -class FunctionDef(Definition): - def __init__(self, name, *args): - dump = 0 - self.name = name - self.in_module = None - self.is_constructor_of = None - self.ret = None - self.caller_owns_return = None - self.unblock_threads = None - self.c_name = None - self.typecode = None - self.params = [] # of form (type, name, default, nullok) - self.varargs = 0 - self.deprecated = None - for arg in get_valid_scheme_definitions(args): - if arg[0] == 'in-module': - self.in_module = arg[1] - elif arg[0] == 'docstring': - self.docstring = make_docstring(arg[1:]) - elif arg[0] == 'is-constructor-of': - self.is_constructor_of = arg[1] - elif arg[0] == 'c-name': - self.c_name = arg[1] - elif arg[0] == 'gtype-id': - self.typecode = arg[1] - elif arg[0] == 'return-type': - self.ret = arg[1] - elif arg[0] == 'caller-owns-return': - self.caller_owns_return = arg[1] in ('t', '#t') - elif arg[0] == 'unblock-threads': - self.unblock_threads = arg[1] in ('t', '#t') - elif arg[0] == 'parameters': - for parg in arg[1:]: - ptype = parg[0] - pname = parg[1] - pdflt = None - pnull = 0 - keeprefcount = False - for farg in parg[2:]: - if farg[0] == 'default': - pdflt = farg[1] - elif farg[0] == 'null-ok': - pnull = 1 - elif farg[0] == 'keep-refcount': - keeprefcount = True - self.params.append(Parameter(ptype, pname, pdflt, pnull, - keeprefcount = keeprefcount)) - elif arg[0] == 'properties': - if self.is_constructor_of is None: - print >> sys.stderr, "Warning: (properties ...) "\ - "is only valid for constructors" - for prop in arg[1:]: - pname = prop[0] - optional = False - argname = pname - for farg in prop[1:]: - if farg[0] == 'optional': - optional = True - elif farg[0] == 'argname': - argname = farg[1] - self.params.append(Property(pname, optional, argname)) - elif arg[0] == 'varargs': - self.varargs = arg[1] in ('t', '#t') - elif arg[0] == 'deprecated': - self.deprecated = arg[1] - else: - sys.stderr.write("Warning: %s argument unsupported\n" - % (arg[0],)) - dump = 1 - if dump: - self.write_defs(sys.stderr) - - if self.caller_owns_return is None and self.ret is not None: - self.guess_return_value_ownership() - for item in ('c_name',): - if self.__dict__[item] == None: - self.write_defs(sys.stderr) - raise RuntimeError, "definition missing required %s" % (item,) - - _method_write_defs = MethodDef.__dict__['write_defs'] - - def merge(self, old, parmerge): - self.caller_owns_return = old.caller_owns_return - self.varargs = old.varargs - if not parmerge: - self.params = copy.deepcopy(old.params) - return - # here we merge extra parameter flags accross to the new object. - def merge_param(param): - for old_param in old.params: - if old_param.pname == param.pname: - if isinstance(old_param, Property): - # h2def never scans Property's, therefore if - # we have one it was manually written, so we - # keep it. - return copy.deepcopy(old_param) - else: - param.merge(old_param) - return param - raise RuntimeError, "could not find %s in old_parameters %r" % ( - param.pname, [p.pname for p in old.params]) - try: - self.params = map(merge_param, self.params) - except RuntimeError: - # parameter names changed and we can't find a match; it's - # safer to keep the old parameter list untouched. - self.params = copy.deepcopy(old.params) - - if not self.is_constructor_of: - try: - self.is_constructor_of = old.is_constructor_of - except AttributeError: - pass - if isinstance(old, MethodDef): - self.name = old.name - # transmogrify from function into method ... - self.write_defs = self._method_write_defs - self.of_object = old.of_object - del self.params[0] - def write_defs(self, fp=sys.stdout): - fp.write('(define-function ' + self.name + '\n') - if self.in_module: - fp.write(' (in-module "' + self.in_module + '")\n') - if self.is_constructor_of: - fp.write(' (is-constructor-of "' + self.is_constructor_of +'")\n') - if self.c_name: - fp.write(' (c-name "' + self.c_name + '")\n') - if self.typecode: - fp.write(' (gtype-id "' + self.typecode + '")\n') - if self.caller_owns_return: - fp.write(' (caller-owns-return #t)\n') - if self.unblock_threads: - fp.write(' (unblock-threads #t)\n') - if self.ret: - fp.write(' (return-type "' + self.ret + '")\n') - if self.deprecated: - fp.write(' (deprecated "' + self.deprecated + '")\n') - if self.params: - if isinstance(self.params[0], Parameter): - fp.write(' (parameters\n') - for ptype, pname, pdflt, pnull in self.params: - fp.write(' \'("' + ptype + '" "' + pname +'"') - if pdflt: fp.write(' (default "' + pdflt + '")') - if pnull: fp.write(' (null-ok)') - fp.write(')\n') - fp.write(' )\n') - elif isinstance(self.params[0], Property): - fp.write(' (properties\n') - for prop in self.params: - fp.write(' \'("' + prop.pname +'"') - if prop.optional: fp.write(' (optional)') - fp.write(')\n') - fp.write(' )\n') - else: - assert False, "strange parameter list %r" % self.params[0] - if self.varargs: - fp.write(' (varargs #t)\n') - - fp.write(')\n\n') diff --git a/bindings/python/codegen/defsparser.py b/bindings/python/codegen/defsparser.py deleted file mode 100644 index e24a969674..0000000000 --- a/bindings/python/codegen/defsparser.py +++ /dev/null @@ -1,143 +0,0 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- -import os, sys -import scmexpr -from definitions import BoxedDef, EnumDef, FlagsDef, FunctionDef, \ - InterfaceDef, MethodDef, ObjectDef, MiniObjectDef, PointerDef, \ - VirtualDef - -class IncludeParser(scmexpr.Parser): - """A simple parser that follows include statements automatically""" - def include(self, filename): - if not os.path.isabs(filename): - filename = os.path.join(os.path.dirname(self.filename), filename) - - # set self.filename to the include name, to handle recursive includes - oldfile = self.filename - self.filename = filename - self.startParsing() - self.filename = oldfile - -class DefsParser(IncludeParser): - def __init__(self, arg, defines={}): - IncludeParser.__init__(self, arg) - self.objects = [] - self.miniobjects = [] - self.interfaces = [] - self.enums = [] # enums and flags - self.boxes = [] # boxed types - self.pointers = [] # pointer types - self.functions = [] # functions and methods - self.virtuals = [] # virtual methods - self.c_name = {} # hash of c names of functions - self.methods = {} # hash of methods of particular objects - self.defines = defines # -Dfoo=bar options, as dictionary - - def define_object(self, *args): - odef = apply(ObjectDef, args) - self.objects.append(odef) - self.c_name[odef.c_name] = odef - # TODO: define_mini_object - def define_miniobject(self, *args): - odef = apply(MiniObjectDef, args) - self.miniobjects.append(odef) - self.c_name[odef.c_name] = odef - def define_interface(self, *args): - idef = apply(InterfaceDef, args) - self.interfaces.append(idef) - self.c_name[idef.c_name] = idef - def define_enum(self, *args): - edef = apply(EnumDef, args) - self.enums.append(edef) - self.c_name[edef.c_name] = edef - def define_flags(self, *args): - fdef = apply(FlagsDef, args) - self.enums.append(fdef) - self.c_name[fdef.c_name] = fdef - def define_boxed(self, *args): - bdef = apply(BoxedDef, args) - self.boxes.append(bdef) - self.c_name[bdef.c_name] = bdef - def define_pointer(self, *args): - pdef = apply(PointerDef, args) - self.pointers.append(pdef) - self.c_name[pdef.c_name] = pdef - def define_function(self, *args): - fdef = apply(FunctionDef, args) - self.functions.append(fdef) - self.c_name[fdef.c_name] = fdef - def define_method(self, *args): - mdef = apply(MethodDef, args) - self.functions.append(mdef) - self.c_name[mdef.c_name] = mdef - def define_virtual(self, *args): - vdef = apply(VirtualDef, args) - self.virtuals.append(vdef) - def merge(self, old, parmerge): - for obj in self.objects: - if old.c_name.has_key(obj.c_name): - obj.merge(old.c_name[obj.c_name]) - for f in self.functions: - if old.c_name.has_key(f.c_name): - f.merge(old.c_name[f.c_name], parmerge) - - def printMissing(self, old): - for obj in self.objects: - if not old.c_name.has_key(obj.c_name): - obj.write_defs() - for f in self.functions: - if not old.c_name.has_key(f.c_name): - f.write_defs() - - def write_defs(self, fp=sys.stdout): - for obj in self.objects: - obj.write_defs(fp) - # TODO: Add miniobject - for obj in self.miniobjects: - obj.write_defs(fp) - for enum in self.enums: - enum.write_defs(fp) - for boxed in self.boxes: - boxed.write_defs(fp) - for pointer in self.pointers: - pointer.write_defs(fp) - for func in self.functions: - func.write_defs(fp) - - def find_object(self, c_name): - for obj in self.objects: - if obj.c_name == c_name: - return obj - else: - raise ValueError, 'object not found' - - def find_constructor(self, obj, overrides): - for func in self.functions: - if isinstance(func, FunctionDef) and \ - func.is_constructor_of == obj.c_name and \ - not overrides.is_ignored(func.c_name): - return func - - def find_methods(self, obj): - objname = obj.c_name - return filter(lambda func, on=objname: isinstance(func, MethodDef) and - func.of_object == on, self.functions) - - def find_virtuals(self, obj): - objname = obj.c_name - retval = filter(lambda func, on=objname: isinstance(func, VirtualDef) and - func.of_object == on, self.virtuals) - return retval - - def find_functions(self): - return filter(lambda func: isinstance(func, FunctionDef) and - not func.is_constructor_of, self.functions) - - def ifdef(self, *args): - if args[0] in self.defines: - for arg in args[1:]: - self.handle(arg) - - def ifndef(self, *args): - if args[0] not in self.defines: - for arg in args[1:]: - self.handle(arg) diff --git a/bindings/python/codegen/docextract.py b/bindings/python/codegen/docextract.py deleted file mode 100644 index e6c65053d6..0000000000 --- a/bindings/python/codegen/docextract.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- -'''Simple module for extracting GNOME style doc comments from C -sources, so I can use them for other purposes.''' - -import sys, os, string, re - -__all__ = ['extract'] - -class FunctionDoc: - def __init__(self): - self.name = None - self.params = [] - self.description = '' - self.ret = '' - def set_name(self, name): - self.name = name - def add_param(self, name, description): - if name == '...': - name = 'Varargs' - self.params.append((name, description)) - def append_to_last_param(self, extra): - self.params[-1] = (self.params[-1][0], self.params[-1][1] + extra) - def append_to_named_param(self, name, extra): - for i in range(len(self.params)): - if self.params[i][0] == name: - self.params[i] = (name, self.params[i][1] + extra) - return - # fall through to adding extra parameter ... - self.add_param(name, extra) - def append_description(self, extra): - self.description = self.description + extra - def append_return(self, extra): - self.ret = self.ret + extra - - def get_param_description(self, name): - for param, description in self.params: - if param == name: - return description - else: - return '' - -comment_start_pat = re.compile(r'^\s*/\*\*\s') -comment_end_pat = re.compile(r'^\s*\*+/') -comment_line_lead = re.compile(r'^\s*\*\s*') -funcname_pat = re.compile(r'^(\w+)\s*:?') -return_pat = re.compile(r'^(returns:|return\s+value:|returns\s*)(.*\n?)$', - re.IGNORECASE) -param_pat = re.compile(r'^@(\S+)\s*:(.*\n?)$') - -def parse_file(fp, doc_dict): - line = fp.readline() - in_comment_block = 0 - while line: - if not in_comment_block: - if comment_start_pat.match(line): - in_comment_block = 1 - cur_doc = FunctionDoc() - in_description = 0 - in_return = 0 - line = fp.readline() - continue - - # we are inside a comment block ... - if comment_end_pat.match(line): - if not cur_doc.name: - sys.stderr.write("no function name found in doc comment\n") - else: - doc_dict[cur_doc.name] = cur_doc - in_comment_block = 0 - line = fp.readline() - continue - - # inside a comment block, and not the end of the block ... - line = comment_line_lead.sub('', line) - if not line: line = '\n' - - if not cur_doc.name: - match = funcname_pat.match(line) - if match: - cur_doc.set_name(match.group(1)) - elif in_return: - match = return_pat.match(line) - if match: - # assume the last return statement was really part of the - # description - return_start = match.group(1) - cur_doc.ret = match.group(2) - cur_doc.description = cur_doc.description + return_start + \ - cur_doc.ret - else: - cur_doc.append_return(line) - elif in_description: - if line[:12] == 'Description:': - line = line[12:] - match = return_pat.match(line) - if match: - in_return = 1 - return_start = match.group(1) - cur_doc.append_return(match.group(2)) - else: - cur_doc.append_description(line) - elif line == '\n': - # end of parameters - in_description = 1 - else: - match = param_pat.match(line) - if match: - param = match.group(1) - desc = match.group(2) - if param == 'returns': - cur_doc.ret = desc - else: - cur_doc.add_param(param, desc) - else: - # must be continuation - try: - if param == 'returns': - cur_doc.append_return(line) - else: - cur_doc.append_to_last_param(line) - except: - sys.stderr.write('something weird while reading param\n') - line = fp.readline() - -def parse_dir(dir, doc_dict): - for file in os.listdir(dir): - if file in ('.', '..'): continue - path = os.path.join(dir, file) - if os.path.isdir(path): - parse_dir(path, doc_dict) - if len(file) > 2 and file[-2:] == '.c': - parse_file(open(path, 'r'), doc_dict) - -def extract(dirs, doc_dict=None): - if not doc_dict: doc_dict = {} - for dir in dirs: - parse_dir(dir, doc_dict) - return doc_dict - -tmpl_section_pat = re.compile(r'^$') -def parse_tmpl(fp, doc_dict): - cur_doc = None - - line = fp.readline() - while line: - match = tmpl_section_pat.match(line) - if match: - cur_doc = None # new input shouldn't affect the old doc dict - sect_type = match.group(1) - sect_name = match.group(2) - - if sect_type == 'FUNCTION': - cur_doc = doc_dict.get(sect_name) - if not cur_doc: - cur_doc = FunctionDoc() - cur_doc.set_name(sect_name) - doc_dict[sect_name] = cur_doc - elif line == '\n': - cur_doc = None # don't worry about unused params. - elif cur_doc: - if line[:10] == '@Returns: ': - if string.strip(line[10:]): - cur_doc.append_return(line[10:]) - elif line[0] == '@': - pos = string.find(line, ':') - if pos >= 0: - cur_doc.append_to_named_param(line[1:pos], line[pos+1:]) - else: - cur_doc.append_description(line) - else: - cur_doc.append_description(line) - - line = fp.readline() - -def extract_tmpl(dirs, doc_dict=None): - if not doc_dict: doc_dict = {} - for dir in dirs: - for file in os.listdir(dir): - if file in ('.', '..'): continue - path = os.path.join(dir, file) - if os.path.isdir(path): - continue - if len(file) > 2 and file[-2:] == '.sgml': - parse_tmpl(open(path, 'r'), doc_dict) - return doc_dict diff --git a/bindings/python/codegen/docgen.py b/bindings/python/codegen/docgen.py deleted file mode 100644 index 6905a14bf8..0000000000 --- a/bindings/python/codegen/docgen.py +++ /dev/null @@ -1,752 +0,0 @@ -#!/usr/bin/env python -# -*- Mode: Python; py-indent-offset: 4 -*- -import sys, os, string, re, getopt - -import defsparser -import definitions -import override -import docextract - -class Node: - def __init__(self, name, interfaces=[]): - self.name = name - self.interfaces = interfaces - self.subclasses = [] - def add_child(self, node): - self.subclasses.append(node) - -def build_object_tree(parser): - # reorder objects so that parent classes come first ... - objects = parser.objects[:] - pos = 0 - while pos < len(objects): - parent = objects[pos].parent - for i in range(pos+1, len(objects)): - if objects[i].c_name == parent: - objects.insert(i+1, objects[pos]) - del objects[pos] - break - else: - pos = pos + 1 - - root = Node(None) - nodes = { None: root } - for obj_def in objects: - print obj_def.name - parent_node = nodes[obj_def.parent] - node = Node(obj_def.c_name, obj_def.implements) - parent_node.add_child(node) - nodes[node.name] = node - - if parser.interfaces: - interfaces = Node('gobject.GInterface') - root.add_child(interfaces) - nodes[interfaces.name] = interfaces - for obj_def in parser.interfaces: - node = Node(obj_def.c_name) - interfaces.add_child(node) - nodes[node.name] = node - - if parser.boxes: - boxed = Node('gobject.GBoxed') - root.add_child(boxed) - nodes[boxed.name] = boxed - for obj_def in parser.boxes: - node = Node(obj_def.c_name) - boxed.add_child(node) - nodes[node.name] = node - - if parser.pointers: - pointers = Node('gobject.GPointer') - root.add_child(pointers) - nodes[pointers.name] = pointers - for obj_def in parser.pointers: - node = Node(obj_def.c_name) - pointers.add_child(node) - nodes[node.name] = node - - return root - -class DocWriter: - def __init__(self): - # parse the defs file - self.parser = defsparser.DefsParser(()) - self.overrides = override.Overrides() - self.classmap = {} - self.docs = {} - - def add_sourcedirs(self, source_dirs): - self.docs = docextract.extract(source_dirs, self.docs) - def add_tmpldirs(self, tmpl_dirs): - self.docs = docextract.extract_tmpl(tmpl_dirs, self.docs) - - def add_docs(self, defs_file, overrides_file, module_name): - '''parse information about a given defs file''' - self.parser.filename = defs_file - self.parser.startParsing(defs_file) - if overrides_file: - self.overrides.handle_file(overrides_file) - - for obj in self.parser.objects: - if not self.classmap.has_key(obj.c_name): - self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name) - for obj in self.parser.interfaces: - if not self.classmap.has_key(obj.c_name): - self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name) - for obj in self.parser.boxes: - if not self.classmap.has_key(obj.c_name): - self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name) - for obj in self.parser.pointers: - if not self.classmap.has_key(obj.c_name): - self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name) - - def pyname(self, name): - return self.classmap.get(name, name) - - def __compare(self, obja, objb): - return cmp(self.pyname(obja.c_name), self.pyname(objb.c_name)) - def output_docs(self, output_prefix): - files = [] - - # class hierarchy - hierarchy = build_object_tree(self.parser) - filename = self.create_filename('hierarchy', output_prefix) - fp = open(filename, 'w') - self.write_full_hierarchy(hierarchy, fp) - fp.close() - - obj_defs = self.parser.objects + self.parser.interfaces + \ - self.parser.boxes + self.parser.pointers - obj_defs.sort(self.__compare) - for obj_def in obj_defs: - filename = self.create_filename(obj_def.c_name, output_prefix) - fp = open(filename, 'w') - if isinstance(obj_def, definitions.ObjectDef): - self.output_object_docs(obj_def, fp) - elif isinstance(obj_def, definitions.InterfaceDef): - self.output_interface_docs(obj_def, fp) - elif isinstance(obj_def, definitions.BoxedDef): - self.output_boxed_docs(obj_def, fp) - elif isinstance(obj_def, definitions.PointerDef): - self.output_boxed_docs(obj_def, fp) - fp.close() - files.append((os.path.basename(filename), obj_def)) - - if files: - filename = self.create_toc_filename(output_prefix) - fp = open(filename, 'w') - self.output_toc(files, fp) - fp.close() - - def output_object_docs(self, obj_def, fp=sys.stdout): - self.write_class_header(obj_def.c_name, fp) - - self.write_heading('Synopsis', fp) - self.write_synopsis(obj_def, fp) - self.close_section(fp) - - # construct the inheritence hierarchy ... - ancestry = [ (obj_def.c_name, obj_def.implements) ] - try: - parent = obj_def.parent - while parent != None: - if parent == 'GObject': - ancestry.append(('GObject', [])) - parent = None - else: - parent_def = self.parser.find_object(parent) - ancestry.append((parent_def.c_name, parent_def.implements)) - parent = parent_def.parent - except ValueError: - pass - ancestry.reverse() - self.write_heading('Ancestry', fp) - self.write_hierarchy(obj_def.c_name, ancestry, fp) - self.close_section(fp) - - constructor = self.parser.find_constructor(obj_def, self.overrides) - if constructor: - self.write_heading('Constructor', fp) - self.write_constructor(constructor, - self.docs.get(constructor.c_name, None), - fp) - self.close_section(fp) - - methods = self.parser.find_methods(obj_def) - methods = filter(lambda meth, self=self: - not self.overrides.is_ignored(meth.c_name), methods) - if methods: - self.write_heading('Methods', fp) - for method in methods: - self.write_method(method, self.docs.get(method.c_name, None), fp) - self.close_section(fp) - - self.write_class_footer(obj_def.c_name, fp) - - def output_interface_docs(self, int_def, fp=sys.stdout): - self.write_class_header(int_def.c_name, fp) - - self.write_heading('Synopsis', fp) - self.write_synopsis(int_def, fp) - self.close_section(fp) - - methods = self.parser.find_methods(int_def) - methods = filter(lambda meth, self=self: - not self.overrides.is_ignored(meth.c_name), methods) - if methods: - self.write_heading('Methods', fp) - for method in methods: - self.write_method(method, self.docs.get(method.c_name, None), fp) - self.close_section(fp) - - self.write_class_footer(int_def.c_name, fp) - - def output_boxed_docs(self, box_def, fp=sys.stdout): - self.write_class_header(box_def.c_name, fp) - - self.write_heading('Synopsis', fp) - self.write_synopsis(box_def, fp) - self.close_section(fp) - - constructor = self.parser.find_constructor(box_def, self.overrides) - if constructor: - self.write_heading('Constructor', fp) - self.write_constructor(constructor, - self.docs.get(constructor.c_name, None), - fp) - self.close_section(fp) - - methods = self.parser.find_methods(box_def) - methods = filter(lambda meth, self=self: - not self.overrides.is_ignored(meth.c_name), methods) - if methods: - self.write_heading('Methods', fp) - for method in methods: - self.write_method(method, self.docs.get(method.c_name, None), fp) - self.close_section(fp) - - self.write_class_footer(box_def.c_name, fp) - - def output_toc(self, files, fp=sys.stdout): - fp.write('TOC\n\n') - for filename, obj_def in files: - fp.write(obj_def.c_name + ' - ' + filename + '\n') - - # override the following to create a more complex output format - def create_filename(self, obj_name, output_prefix): - '''Create output filename for this particular object''' - return output_prefix + '-' + string.lower(obj_name) + '.txt' - def create_toc_filename(self, output_prefix): - return self.create_filename(self, 'docs', output_prefix) - - def write_full_hierarchy(self, hierarchy, fp): - def handle_node(node, fp, indent=''): - for child in node.subclasses: - fp.write(indent + node.name) - if node.interfaces: - fp.write(' (implements ') - fp.write(string.join(node.interfaces, ', ')) - fp.write(')\n') - else: - fp.write('\n') - handle_node(child, fp, indent + ' ') - handle_node(hierarchy, fp) - - # these need to handle default args ... - def create_constructor_prototype(self, func_def): - return func_def.is_constructor_of + '(' + \ - string.join(map(lambda x: x[1], func_def.params), ', ') + \ - ')' - def create_function_prototype(self, func_def): - return func_def.name + '(' + \ - string.join(map(lambda x: x[1], func_def.params), ', ') + \ - ')' - def create_method_prototype(self, meth_def): - return meth_def.of_object + '.' + \ - meth_def.name + '(' + \ - string.join(map(lambda x: x[1], meth_def.params), ', ') + \ - ')' - - def write_class_header(self, obj_name, fp): - fp.write('Class %s\n' % obj_name) - fp.write('======%s\n\n' % ('=' * len(obj_name))) - def write_class_footer(self, obj_name, fp): - pass - def write_heading(self, text, fp): - fp.write('\n' + text + '\n' + ('-' * len(text)) + '\n') - def close_section(self, fp): - pass - def write_synopsis(self, obj_def, fp): - fp.write('class %s' % obj_def.c_name) - if isinstance(obj_def, definitions.ObjectDef): - bases = [] - if obj_def.parent: bases.append(obj_def.parent) - bases = bases = obj_def.implements - if bases: - fp.write('(%s)' % string.join(bases, ', ')) - fp.write(':\n') - - constructor = self.parser.find_constructor(obj_def, self.overrides) - if constructor: - prototype = self.create_constructor_prototype(constructor) - fp.write(' def %s\n' % prototype) - methods = self.parser.find_methods(obj_def) - methods = filter(lambda meth, self=self: - not self.overrides.is_ignored(meth.c_name), methods) - for meth in methods: - prototype = self.create_method_prototype(meth) - fp.write(' def %s\n' % prototype) - - def write_hierarchy(self, obj_name, ancestry, fp): - indent = '' - for name, interfaces in ancestry: - fp.write(indent + '+-- ' + name) - if interfaces: - fp.write(' (implements ') - fp.write(string.join(interfaces, ', ')) - fp.write(')\n') - else: - fp.write('\n') - indent = indent + ' ' - fp.write('\n') - def write_constructor(self, func_def, func_doc, fp): - prototype = self.create_constructor_prototype(func_def) - fp.write(prototype + '\n\n') - for type, name, dflt, null in func_def.params: - if func_doc: - descr = func_doc.get_param_description(name) - else: - descr = 'a ' + type - fp.write(' ' + name + ': ' + descr + '\n') - if func_def.ret and func_def.ret != 'none': - if func_doc and func_doc.ret: - descr = func_doc.ret - else: - descr = 'a ' + func_def.ret - fp.write(' Returns: ' + descr + '\n') - if func_doc and func_doc.description: - fp.write(func_doc.description) - fp.write('\n\n\n') - def write_method(self, meth_def, func_doc, fp): - prototype = self.create_method_prototype(meth_def) - fp.write(prototype + '\n\n') - for type, name, dflt, null in meth_def.params: - if func_doc: - descr = func_doc.get_param_description(name) - else: - descr = 'a ' + type - fp.write(' ' + name + ': ' + descr + '\n') - if meth_def.ret and meth_def.ret != 'none': - if func_doc and func_doc.ret: - descr = func_doc.ret - else: - descr = 'a ' + meth_def.ret - fp.write(' Returns: ' + descr + '\n') - if func_doc and func_doc.description: - fp.write('\n') - fp.write(func_doc.description) - fp.write('\n\n') - -class DocbookDocWriter(DocWriter): - def __init__(self, use_xml=0): - DocWriter.__init__(self) - self.use_xml = use_xml - - def create_filename(self, obj_name, output_prefix): - '''Create output filename for this particular object''' - stem = output_prefix + '-' + string.lower(obj_name) - if self.use_xml: - return stem + '.xml' - else: - return stem + '.sgml' - def create_toc_filename(self, output_prefix): - if self.use_xml: - return self.create_filename('classes', output_prefix) - else: - return self.create_filename('docs', output_prefix) - - # make string -> reference translation func - __transtable = [ '-' ] * 256 - for digit in '0123456789': - __transtable[ord(digit)] = digit - for letter in 'abcdefghijklmnopqrstuvwxyz': - __transtable[ord(letter)] = letter - __transtable[ord(string.upper(letter))] = letter - __transtable = string.join(__transtable, '') - - def make_class_ref(self, obj_name): - return 'class-' + string.translate(obj_name, self.__transtable) - def make_method_ref(self, meth_def): - return 'method-' + string.translate(meth_def.of_object, - self.__transtable) + \ - '--' + string.translate(meth_def.name, self.__transtable) - - __function_pat = re.compile(r'(\w+)\s*\(\)') - def __format_function(self, match): - info = self.parser.c_name.get(match.group(1), None) - if info: - if isinstance(info, defsparser.FunctionDef): - if info.is_constructor_of is not None: - # should have a link here - return '%s()' % \ - self.pyname(info.is_constructor_of) - else: - return '' + info.name + '()' - if isinstance(info, defsparser.MethodDef): - return '' + self.pyname(info.of_object) + '.' + \ - info.name + '()' - # fall through through - return '' + match.group(1) + '()' - __parameter_pat = re.compile(r'\@(\w+)') - def __format_param(self, match): - return '' + match.group(1) + '' - __constant_pat = re.compile(r'\%(-?\w+)') - def __format_const(self, match): - return '' + match.group(1) + '' - __symbol_pat = re.compile(r'#([\w-]+)') - def __format_symbol(self, match): - info = self.parser.c_name.get(match.group(1), None) - if info: - if isinstance(info, defsparser.FunctionDef): - if info.is_constructor_of is not None: - # should have a link here - return '' + self.pyname(info.is_constructor_of) + \ - '' - else: - return '' + info.name + '' - if isinstance(info, defsparser.MethodDef): - return '' + self.pyname(info.of_object) + '.' + \ - info.name + '' - if isinstance(info, defsparser.ObjectDef) or \ - isinstance(info, defsparser.InterfaceDef) or \ - isinstance(info, defsparser.BoxedDef) or \ - isinstance(info, defsparser.PointerDef): - return '' + self.pyname(info.c_name) + \ - '' - # fall through through - return '' + match.group(1) + '' - - def reformat_text(self, text, singleline=0): - # replace special strings ... - text = self.__function_pat.sub(self.__format_function, text) - text = self.__parameter_pat.sub(self.__format_param, text) - text = self.__constant_pat.sub(self.__format_const, text) - text = self.__symbol_pat.sub(self.__format_symbol, text) - - # don't bother with expansion for single line text. - if singleline: return text - - lines = string.split(string.strip(text), '\n') - for index in range(len(lines)): - if string.strip(lines[index]) == '': - lines[index] = '\n' - continue - lines.insert(0, '') - lines.append('') - return string.join(lines, '\n') - - # write out hierarchy - def write_full_hierarchy(self, hierarchy, fp): - def handle_node(node, fp, indent=''): - if node.name: - fp.write('%s%s' % - (indent, self.make_class_ref(node.name), - self.pyname(node.name))) - if node.interfaces: - fp.write(' (implements ') - for i in range(len(node.interfaces)): - fp.write('%s' % - (self.make_class_ref(node.interfaces[i]), - self.pyname(node.interfaces[i]))) - if i != len(node.interfaces) - 1: - fp.write(', ') - fp.write(')\n') - else: - fp.write('\n') - - indent = indent + ' ' - node.subclasses.sort(lambda a,b: - cmp(self.pyname(a.name), self.pyname(b.name))) - for child in node.subclasses: - handle_node(child, fp, indent) - if self.use_xml: - fp.write('\n') - fp.write('\n') - fp.write('') - handle_node(hierarchy, fp) - fp.write('\n') - - # these need to handle default args ... - def create_constructor_prototype(self, func_def): - sgml = [ '\n'] - sgml.append(' __init__\n') - for type, name, dflt, null in func_def.params: - sgml.append(' ') - sgml.append(name) - sgml.append('') - if dflt: - sgml.append('') - sgml.append(dflt) - sgml.append('') - sgml.append('\n') - if not func_def.params: - sgml.append(' ') - sgml.append(' ') - return string.join(sgml, '') - def create_function_prototype(self, func_def): - sgml = [ '\n \n'] - sgml.append(' ') - sgml.append(func_def.name) - sgml.append('\n') - for type, name, dflt, null in func_def.params: - sgml.append(' ') - sgml.append(name) - sgml.append('') - if dflt: - sgml.append('') - sgml.append(dflt) - sgml.append('') - sgml.append('\n') - if not func_def.params: - sgml.append(' \n ') - return string.join(sgml, '') - def create_method_prototype(self, meth_def, addlink=0): - sgml = [ '\n'] - sgml.append(' ') - if addlink: - sgml.append('' % self.make_method_ref(meth_def)) - sgml.append(self.pyname(meth_def.name)) - if addlink: - sgml.append('') - sgml.append('\n') - for type, name, dflt, null in meth_def.params: - sgml.append(' ') - sgml.append(name) - sgml.append('') - if dflt: - sgml.append('') - sgml.append(dflt) - sgml.append('') - sgml.append('\n') - if not meth_def.params: - sgml.append(' ') - sgml.append(' ') - return string.join(sgml, '') - - def write_class_header(self, obj_name, fp): - if self.use_xml: - fp.write('\n') - fp.write('\n') - fp.write('\n') - fp.write(' \n') - fp.write(' %s\n' - % self.pyname(obj_name)) - fp.write(' 3\n') - fp.write(' PyGTK Docs\n') - fp.write(' \n\n') - fp.write(' \n') - fp.write(' %s\n' - % self.pyname(obj_name)) - fp.write(' \n\n') - def write_class_footer(self, obj_name, fp): - fp.write('\n') - def write_heading(self, text, fp): - fp.write(' \n') - fp.write(' ' + text + '\n\n') - def close_section(self, fp): - fp.write(' \n') - - def write_synopsis(self, obj_def, fp): - fp.write('\n') - fp.write(' %s\n' - % self.pyname(obj_def.c_name)) - if isinstance(obj_def, definitions.ObjectDef): - if obj_def.parent: - fp.write(' %s' - '\n' - % (self.make_class_ref(obj_def.parent), - self.pyname(obj_def.parent))) - for base in obj_def.implements: - fp.write(' %s' - '\n' - % (self.make_class_ref(base), self.pyname(base))) - elif isinstance(obj_def, definitions.InterfaceDef): - fp.write(' gobject.GInterface' - '\n') - elif isinstance(obj_def, definitions.BoxedDef): - fp.write(' gobject.GBoxed' - '\n') - elif isinstance(obj_def, definitions.PointerDef): - fp.write(' gobject.GPointer' - '\n') - - constructor = self.parser.find_constructor(obj_def, self.overrides) - if constructor: - fp.write('%s\n' % self.create_constructor_prototype(constructor)) - methods = self.parser.find_methods(obj_def) - methods = filter(lambda meth, self=self: - not self.overrides.is_ignored(meth.c_name), methods) - for meth in methods: - fp.write('%s\n' % self.create_method_prototype(meth, addlink=1)) - fp.write('\n\n') - - def write_hierarchy(self, obj_name, ancestry, fp): - fp.write('') - indent = '' - for name, interfaces in ancestry: - fp.write(indent + '+-- '+ self.pyname(name) + '') - if interfaces: - fp.write(' (implements ') - for i in range(len(interfaces)): - fp.write('%s' % - (self.make_class_ref(interfaces[i]), - self.pyname(interfaces[i]))) - if i != len(interfaces) - 1: - fp.write(', ') - fp.write(')\n') - else: - fp.write('\n') - indent = indent + ' ' - fp.write('\n\n') - - def write_params(self, params, ret, func_doc, fp): - if not params and (not ret or ret == 'none'): - return - fp.write(' \n') - for type, name, dflt, null in params: - if func_doc: - descr = string.strip(func_doc.get_param_description(name)) - else: - descr = 'a ' + type - fp.write(' \n') - fp.write(' %s :\n' % name) - fp.write(' %s\n' % - self.reformat_text(descr, singleline=1)) - fp.write(' \n') - if ret and ret != 'none': - if func_doc and func_doc.ret: - descr = string.strip(func_doc.ret) - else: - descr = 'a ' + ret - fp.write(' \n') - fp.write(' Returns :\n') - fp.write(' %s\n' % - self.reformat_text(descr, singleline=1)) - fp.write(' \n') - fp.write(' \n') - - def write_constructor(self, func_def, func_doc, fp): - prototype = self.create_constructor_prototype(func_def) - fp.write('%s\n' % prototype) - self.write_params(func_def.params, func_def.ret, func_doc, fp) - - if func_doc and func_doc.description: - fp.write(self.reformat_text(func_doc.description)) - fp.write('\n\n\n') - - def write_method(self, meth_def, func_doc, fp): - fp.write(' \n') - fp.write(' ' + self.pyname(meth_def.of_object) + '.' + - meth_def.name + '\n\n') - prototype = self.create_method_prototype(meth_def) - fp.write('%s\n' % prototype) - self.write_params(meth_def.params, meth_def.ret, func_doc, fp) - if func_doc and func_doc.description: - fp.write(self.reformat_text(func_doc.description)) - fp.write(' \n\n\n') - - def output_toc(self, files, fp=sys.stdout): - if self.use_xml: - fp.write('\n') - fp.write('\n') - #for filename, obj_def in files: - # fp.write(' \n') - #fp.write(']>\n\n') - - #fp.write('\n') - #fp.write(' Class Documentation\n') - #for filename, obj_def in files: - # fp.write('&' + string.translate(obj_def.c_name, - # self.__transtable) + ';\n') - #fp.write('\n') - - fp.write('\n') - fp.write(' Class Reference\n') - for filename, obj_def in files: - fp.write(' \n' % filename) - fp.write('\n') - else: - fp.write('\n') - fp.write(']>\n\n') - - fp.write('\n\n') - fp.write(' \n') - fp.write(' PyGTK Docs\n') - fp.write(' \n') - fp.write(' \n') - fp.write(' James\n') - fp.write(' Henstridge\n') - fp.write(' \n') - fp.write(' \n') - fp.write(' \n\n') - - fp.write(' \n') - fp.write(' Class Hierarchy\n') - fp.write(' Not done yet\n') - fp.write(' \n\n') - - fp.write(' \n') - fp.write(' Class Documentation\n') - for filename, obj_def in files: - fp.write('&' + string.translate(obj_def.c_name, - self.__transtable) + ';\n') - - fp.write(' \n') - fp.write('\n') - -if __name__ == '__main__': - try: - opts, args = getopt.getopt(sys.argv[1:], "d:s:o:", - ["defs-file=", "override=", "source-dir=", - "output-prefix="]) - except getopt.error, e: - sys.stderr.write('docgen.py: %s\n' % e) - sys.stderr.write( - 'usage: docgen.py -d file.defs [-s /src/dir] [-o output-prefix]\n') - sys.exit(1) - defs_file = None - overrides_file = None - source_dirs = [] - output_prefix = 'docs' - for opt, arg in opts: - if opt in ('-d', '--defs-file'): - defs_file = arg - if opt in ('--override',): - overrides_file = arg - elif opt in ('-s', '--source-dir'): - source_dirs.append(arg) - elif opt in ('-o', '--output-prefix'): - output_prefix = arg - if len(args) != 0 or not defs_file: - sys.stderr.write( - 'usage: docgen.py -d file.defs [-s /src/dir] [-o output-prefix]\n') - sys.exit(1) - - d = DocbookDocWriter() - d.add_sourcedirs(source_dirs) - d.add_docs(defs_file, overrides_file, 'gtk') - d.output_docs(output_prefix) diff --git a/bindings/python/codegen/fileprefix.override b/bindings/python/codegen/fileprefix.override deleted file mode 100644 index 4e280c5e6c..0000000000 --- a/bindings/python/codegen/fileprefix.override +++ /dev/null @@ -1,12 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- */ -%% -headers -/* include any required headers here */ -%% -init - /* include any code here that needs to be executed before the - * extension classes get initialised */ -%% - -/* you should add appropriate ignore, ignore-glob and - * override sections here */ diff --git a/bindings/python/codegen/fileprefixmodule.c b/bindings/python/codegen/fileprefixmodule.c deleted file mode 100644 index 4361d6484d..0000000000 --- a/bindings/python/codegen/fileprefixmodule.c +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include -#include - -/* include any extra headers needed here */ - -void prefix_register_classes(PyObject *d); -extern PyMethodDef prefix_functions[]; - -DL_EXPORT(void) -initmodule(void) -{ - PyObject *m, *d; - - /* perform any initialisation required by the library here */ - - m = Py_InitModule("module", prefix_functions); - d = PyModule_GetDict(m); - - init_pygtk(); - - prefix_register_classes(d); - - /* add anything else to the module dictionary (such as constants) */ - - if (PyErr_Occurred()) - Py_FatalError("could not initialise module module"); -} diff --git a/bindings/python/codegen/h2def.py b/bindings/python/codegen/h2def.py deleted file mode 100755 index d4b21356c2..0000000000 --- a/bindings/python/codegen/h2def.py +++ /dev/null @@ -1,536 +0,0 @@ -#!/usr/bin/env python -# -*- Mode: Python; py-indent-offset: 4 -*- -# Search through a header file looking for function prototypes. -# For each prototype, generate a scheme style definition. -# GPL'ed -# Toby D. Reeves -# -# Modified by James Henstridge to output stuff in -# Havoc's new defs format. Info on this format can be seen at: -# http://www.gnome.org/mailing-lists/archives/gtk-devel-list/2000-January/0085.shtml -# Updated to be PEP-8 compatible and refactored to use OOP - -import getopt -import os -import re -import string -import sys - -import defsparser - -# ------------------ Create typecodes from typenames --------- - -_upperstr_pat1 = re.compile(r'([^A-Z])([A-Z])') -_upperstr_pat2 = re.compile(r'([A-Z][A-Z])([A-Z][0-9a-z])') -_upperstr_pat3 = re.compile(r'^([A-Z])([A-Z])') - -def to_upper_str(name): - """Converts a typename to the equivalent upercase and underscores - name. This is used to form the type conversion macros and enum/flag - name variables""" - name = _upperstr_pat1.sub(r'\1_\2', name) - name = _upperstr_pat2.sub(r'\1_\2', name) - name = _upperstr_pat3.sub(r'\1_\2', name, count=1) - return string.upper(name) - -def typecode(typename): - """create a typecode (eg. GTK_TYPE_WIDGET) from a typename""" - return string.replace(to_upper_str(typename), '_', '_TYPE_', 1) - - -# ------------------ Find object definitions ----------------- - -def strip_comments(buf): - parts = [] - lastpos = 0 - while 1: - pos = string.find(buf, '/*', lastpos) - if pos >= 0: - parts.append(buf[lastpos:pos]) - pos = string.find(buf, '*/', pos) - if pos >= 0: - lastpos = pos + 2 - else: - break - else: - parts.append(buf[lastpos:]) - break - return string.join(parts, '') - -obj_name_pat = "[A-Z][a-z]*[A-Z][A-Za-z0-9]*" - -split_prefix_pat = re.compile('([A-Z]+[a-z]*)([A-Za-z0-9]+)') - -def find_obj_defs(buf, objdefs=[]): - """ - Try to find object definitions in header files. - """ - - # filter out comments from buffer. - buf = strip_comments(buf) - - maybeobjdefs = [] # contains all possible objects from file - - # first find all structures that look like they may represent a GtkObject - pat = re.compile("struct _(" + obj_name_pat + ")\s*{\s*" + - "(" + obj_name_pat + ")\s+", re.MULTILINE) - pos = 0 - while pos < len(buf): - m = pat.search(buf, pos) - if not m: break - maybeobjdefs.append((m.group(1), m.group(2))) - pos = m.end() - - # handle typedef struct { ... } style struct defs. - pat = re.compile("typedef struct\s+[_\w]*\s*{\s*" + - "(" + obj_name_pat + ")\s+[^}]*}\s*" + - "(" + obj_name_pat + ")\s*;", re.MULTILINE) - pos = 0 - while pos < len(buf): - m = pat.search(buf, pos) - if not m: break - maybeobjdefs.append((m.group(2), m.group(2))) - pos = m.end() - - # now find all structures that look like they might represent a class: - pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" + - "(" + obj_name_pat + ")Class\s+", re.MULTILINE) - pos = 0 - while pos < len(buf): - m = pat.search(buf, pos) - if not m: break - t = (m.group(1), m.group(2)) - # if we find an object structure together with a corresponding - # class structure, then we have probably found a GtkObject subclass. - if t in maybeobjdefs: - objdefs.append(t) - pos = m.end() - - pat = re.compile("typedef struct\s+[_\w]*\s*{\s*" + - "(" + obj_name_pat + ")Class\s+[^}]*}\s*" + - "(" + obj_name_pat + ")Class\s*;", re.MULTILINE) - pos = 0 - while pos < len(buf): - m = pat.search(buf, pos) - if not m: break - t = (m.group(2), m.group(1)) - # if we find an object structure together with a corresponding - # class structure, then we have probably found a GtkObject subclass. - if t in maybeobjdefs: - objdefs.append(t) - pos = m.end() - - # now find all structures that look like they might represent - # a class inherited from GTypeInterface: - pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" + - "GTypeInterface\s+", re.MULTILINE) - pos = 0 - while pos < len(buf): - m = pat.search(buf, pos) - if not m: break - t = (m.group(1), '') - t2 = (m.group(1)+'Class', 'GTypeInterface') - # if we find an object structure together with a corresponding - # class structure, then we have probably found a GtkObject subclass. - if t2 in maybeobjdefs: - objdefs.append(t) - pos = m.end() - - # now find all structures that look like they might represent - # an Iface inherited from GTypeInterface: - pat = re.compile("struct _(" + obj_name_pat + ")Iface\s*{\s*" + - "GTypeInterface\s+", re.MULTILINE) - pos = 0 - while pos < len(buf): - m = pat.search(buf, pos) - if not m: break - t = (m.group(1), '') - t2 = (m.group(1)+'Iface', 'GTypeInterface') - # if we find an object structure together with a corresponding - # class structure, then we have probably found a GtkObject subclass. - if t2 in maybeobjdefs: - objdefs.append(t) - pos = m.end() - -def sort_obj_defs(objdefs): - objdefs.sort() # not strictly needed, but looks nice - pos = 0 - while pos < len(objdefs): - klass,parent = objdefs[pos] - for i in range(pos+1, len(objdefs)): - # parent below subclass ... reorder - if objdefs[i][0] == parent: - objdefs.insert(i+1, objdefs[pos]) - del objdefs[pos] - break - else: - pos = pos + 1 - return objdefs - -# ------------------ Find enum definitions ----------------- - -def find_enum_defs(buf, enums=[]): - # strip comments - # bulk comments - buf = strip_comments(buf) - - buf = re.sub('\n', ' ', buf) - - enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)') - splitter = re.compile(r'\s*,\s', re.MULTILINE) - pos = 0 - while pos < len(buf): - m = enum_pat.search(buf, pos) - if not m: break - - name = m.group(2) - vals = m.group(1) - isflags = string.find(vals, '<<') >= 0 - entries = [] - for val in splitter.split(vals): - if not string.strip(val): continue - entries.append(string.split(val)[0]) - if name != 'GdkCursorType': - enums.append((name, isflags, entries)) - - pos = m.end() - -# ------------------ Find function definitions ----------------- - -def clean_func(buf): - """ - Ideally would make buf have a single prototype on each line. - Actually just cuts out a good deal of junk, but leaves lines - where a regex can figure prototypes out. - """ - # bulk comments - buf = strip_comments(buf) - - # compact continued lines - pat = re.compile(r"""\\\n""", re.MULTILINE) - buf = pat.sub('', buf) - - # Preprocess directives - pat = re.compile(r"""^[#].*?$""", re.MULTILINE) - buf = pat.sub('', buf) - - #typedefs, stucts, and enums - pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""", - re.MULTILINE) - buf = pat.sub('', buf) - - #strip DECLS macros - pat = re.compile(r"""G_BEGIN_DECLS|BEGIN_LIBGTOP_DECLS""", re.MULTILINE) - buf = pat.sub('', buf) - - #extern "C" - pat = re.compile(r"""^\s*(extern)\s+\"C\"\s+{""", re.MULTILINE) - buf = pat.sub('', buf) - - #multiple whitespace - pat = re.compile(r"""\s+""", re.MULTILINE) - buf = pat.sub(' ', buf) - - #clean up line ends - pat = re.compile(r""";\s*""", re.MULTILINE) - buf = pat.sub('\n', buf) - buf = buf.lstrip() - - #associate *, &, and [] with type instead of variable - #pat = re.compile(r'\s+([*|&]+)\s*(\w+)') - pat = re.compile(r' \s* ([*|&]+) \s* (\w+)', re.VERBOSE) - buf = pat.sub(r'\1 \2', buf) - pat = re.compile(r'\s+ (\w+) \[ \s* \]', re.VERBOSE) - buf = pat.sub(r'[] \1', buf) - - # make return types that are const work. - buf = string.replace(buf, 'G_CONST_RETURN ', 'const-') - buf = string.replace(buf, 'const ', 'const-') - - return buf - -proto_pat=re.compile(r""" -(?P(-|\w|\&|\*)+\s*) # return type -\s+ # skip whitespace -(?P\w+)\s*[(] # match the function name until the opening ( -\s*(?P.*?)\s*[)] # group the function arguments -""", re.IGNORECASE|re.VERBOSE) -#""" -arg_split_pat = re.compile("\s*,\s*") - -get_type_pat = re.compile(r'(const-)?([A-Za-z0-9]+)\*?\s+') -pointer_pat = re.compile('.*\*$') -func_new_pat = re.compile('(\w+)_new$') - -class DefsWriter: - def __init__(self, fp=None, prefix=None, verbose=False, - defsfilter=None): - if not fp: - fp = sys.stdout - - self.fp = fp - self.prefix = prefix - self.verbose = verbose - - self._enums = {} - self._objects = {} - self._functions = {} - if defsfilter: - filter = defsparser.DefsParser(defsfilter) - filter.startParsing() - for func in filter.functions + filter.methods.values(): - self._functions[func.c_name] = func - for obj in filter.objects + filter.boxes + filter.interfaces: - self._objects[obj.c_name] = func - for obj in filter.enums: - self._enums[obj.c_name] = func - - def write_def(self, deffile): - buf = open(deffile).read() - - self.fp.write('\n;; From %s\n\n' % os.path.basename(deffile)) - self._define_func(buf) - self.fp.write('\n') - - def write_enum_defs(self, enums, fp=None): - if not fp: - fp = self.fp - - fp.write(';; Enumerations and flags ...\n\n') - trans = string.maketrans(string.uppercase + '_', - string.lowercase + '-') - filter = self._enums - for cname, isflags, entries in enums: - if filter: - if cname in filter: - continue - name = cname - module = None - m = split_prefix_pat.match(cname) - if m: - module = m.group(1) - name = m.group(2) - if isflags: - fp.write('(define-flags ' + name + '\n') - else: - fp.write('(define-enum ' + name + '\n') - if module: - fp.write(' (in-module "' + module + '")\n') - fp.write(' (c-name "' + cname + '")\n') - fp.write(' (gtype-id "' + typecode(cname) + '")\n') - prefix = entries[0] - for ent in entries: - # shorten prefix til we get a match ... - # and handle GDK_FONT_FONT, GDK_FONT_FONTSET case - while ent[:len(prefix)] != prefix or len(prefix) >= len(ent): - prefix = prefix[:-1] - prefix_len = len(prefix) - fp.write(' (values\n') - for ent in entries: - fp.write(' \'("%s" "%s")\n' % - (string.translate(ent[prefix_len:], trans), ent)) - fp.write(' )\n') - fp.write(')\n\n') - - def write_obj_defs(self, objdefs, fp=None): - if not fp: - fp = self.fp - - fp.write(';; -*- scheme -*-\n') - fp.write('; object definitions ...\n') - - filter = self._objects - for klass, parent in objdefs: - if filter: - if klass in filter: - continue - m = split_prefix_pat.match(klass) - cmodule = None - cname = klass - if m: - cmodule = m.group(1) - cname = m.group(2) - fp.write('(define-object ' + cname + '\n') - if cmodule: - fp.write(' (in-module "' + cmodule + '")\n') - if parent: - fp.write(' (parent "' + parent + '")\n') - fp.write(' (c-name "' + klass + '")\n') - fp.write(' (gtype-id "' + typecode(klass) + '")\n') - # should do something about accessible fields - fp.write(')\n\n') - - def _define_func(self, buf): - buf = clean_func(buf) - buf = string.split(buf,'\n') - filter = self._functions - for p in buf: - if not p: - continue - m = proto_pat.match(p) - if m == None: - if self.verbose: - sys.stderr.write('No match:|%s|\n' % p) - continue - func = m.group('func') - if func[0] == '_': - continue - if filter: - if func in filter: - continue - ret = m.group('ret') - args = m.group('args') - args = arg_split_pat.split(args) - for i in range(len(args)): - spaces = string.count(args[i], ' ') - if spaces > 1: - args[i] = string.replace(args[i], ' ', '-', spaces - 1) - - self._write_func(func, ret, args) - - def _write_func(self, name, ret, args): - if len(args) >= 1: - # methods must have at least one argument - munged_name = name.replace('_', '') - m = get_type_pat.match(args[0]) - if m: - obj = m.group(2) - if munged_name[:len(obj)] == obj.lower(): - self._write_method(obj, name, ret, args) - return - - if self.prefix: - l = len(self.prefix) - if name[:l] == self.prefix and name[l] == '_': - fname = name[l+1:] - else: - fname = name - else: - fname = name - - # it is either a constructor or normal function - self.fp.write('(define-function ' + fname + '\n') - self.fp.write(' (c-name "' + name + '")\n') - - # Hmmm... Let's asume that a constructor function name - # ends with '_new' and it returns a pointer. - m = func_new_pat.match(name) - if pointer_pat.match(ret) and m: - cname = '' - for s in m.group(1).split ('_'): - cname += s.title() - if cname != '': - self.fp.write(' (is-constructor-of "' + cname + '")\n') - - self._write_return(ret) - self._write_arguments(args) - - def _write_method(self, obj, name, ret, args): - regex = string.join(map(lambda x: x+'_?', string.lower(obj)),'') - mname = re.sub(regex, '', name, 1) - if self.prefix: - l = len(self.prefix) + 1 - if mname[:l] == self.prefix and mname[l+1] == '_': - mname = mname[l+1:] - self.fp.write('(define-method ' + mname + '\n') - self.fp.write(' (of-object "' + obj + '")\n') - self.fp.write(' (c-name "' + name + '")\n') - self._write_return(ret) - self._write_arguments(args[1:]) - - def _write_return(self, ret): - if ret != 'void': - self.fp.write(' (return-type "' + ret + '")\n') - else: - self.fp.write(' (return-type "none")\n') - - def _write_arguments(self, args): - is_varargs = 0 - has_args = len(args) > 0 - for arg in args: - if arg == '...': - is_varargs = 1 - elif arg in ('void', 'void '): - has_args = 0 - if has_args: - self.fp.write(' (parameters\n') - for arg in args: - if arg != '...': - tupleArg = tuple(string.split(arg)) - if len(tupleArg) == 2: - self.fp.write(' \'("%s" "%s")\n' % tupleArg) - self.fp.write(' )\n') - if is_varargs: - self.fp.write(' (varargs #t)\n') - self.fp.write(')\n\n') - -# ------------------ Main function ----------------- - -def main(args): - verbose = False - onlyenums = False - onlyobjdefs = False - separate = False - modulename = None - defsfilter = None - opts, args = getopt.getopt(args[1:], 'vs:m:f:', - ['onlyenums', 'onlyobjdefs', - 'modulename=', 'separate=', - 'defsfilter=']) - for o, v in opts: - if o == '-v': - verbose = True - if o == '--onlyenums': - onlyenums = True - if o == '--onlyobjdefs': - onlyobjdefs = True - if o in ('-s', '--separate'): - separate = v - if o in ('-m', '--modulename'): - modulename = v - if o in ('-f', '--defsfilter'): - defsfilter = v - - if not args[0:1]: - print 'Must specify at least one input file name' - return -1 - - # read all the object definitions in - objdefs = [] - enums = [] - for filename in args: - buf = open(filename).read() - find_obj_defs(buf, objdefs) - find_enum_defs(buf, enums) - objdefs = sort_obj_defs(objdefs) - - if separate: - methods = file(separate + '.defs', 'w') - types = file(separate + '-types.defs', 'w') - - dw = DefsWriter(methods, prefix=modulename, verbose=verbose, - defsfilter=defsfilter) - dw.write_obj_defs(objdefs, types) - dw.write_enum_defs(enums, types) - print "Wrote %s-types.defs" % separate - - for filename in args: - dw.write_def(filename) - print "Wrote %s.defs" % separate - else: - dw = DefsWriter(prefix=modulename, verbose=verbose, - defsfilter=defsfilter) - - if onlyenums: - dw.write_enum_defs(enums) - elif onlyobjdefs: - dw.write_obj_defs(objdefs) - else: - dw.write_obj_defs(objdefs) - dw.write_enum_defs(enums) - - for filename in args: - dw.write_def(filename) - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/bindings/python/codegen/mergedefs.py b/bindings/python/codegen/mergedefs.py deleted file mode 100755 index 773e499bb0..0000000000 --- a/bindings/python/codegen/mergedefs.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# -*- Mode: Python; py-indent-offset: 4 -*- - -import optparse - -import defsparser - -parser = optparse.OptionParser( - usage="usage: %prog [options] generated-defs old-defs") -parser.add_option("-p", "--merge-parameters", - help="Merge changes in function/methods parameter lists", - action="store_true", dest="parmerge", default=False) -(options, args) = parser.parse_args() - -if len(args) != 2: - parser.error("wrong number of arguments") - -newp = defsparser.DefsParser(args[0]) -oldp = defsparser.DefsParser(args[1]) - -newp.startParsing() -oldp.startParsing() - -newp.merge(oldp, options.parmerge) - -newp.write_defs() diff --git a/bindings/python/codegen/mkskel.py b/bindings/python/codegen/mkskel.py deleted file mode 100755 index 61f520bf73..0000000000 --- a/bindings/python/codegen/mkskel.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python -# -*- Mode: Python; py-indent-offset: 4 -*- - -import sys, os, getopt - -module_init_template = \ -'/* -*- Mode: C; c-basic-offset: 4 -*- */\n' + \ -'#ifdef HAVE_CONFIG_H\n' + \ -'# include "config.h"\n' + \ -'#endif\n' + \ -'#include \n' + \ -'#include \n' + \ -'\n' + \ -'/* include any extra headers needed here */\n' + \ -'\n' + \ -'void %(prefix)s_register_classes(PyObject *d);\n' + \ -'extern PyMethodDef %(prefix)s_functions[];\n' + \ -'\n' + \ -'DL_EXPORT(void)\n' + \ -'init%(module)s(void)\n' + \ -'{\n' + \ -' PyObject *m, *d;\n' + \ -'\n' + \ -' /* perform any initialisation required by the library here */\n' + \ -'\n' + \ -' m = Py_InitModule("%(module)s", %(prefix)s_functions);\n' + \ -' d = PyModule_GetDict(m);\n' + \ -'\n' + \ -' init_pygtk();\n' + \ -'\n' + \ -' %(prefix)s_register_classes(d);\n' + \ -'\n' + \ -' /* add anything else to the module dictionary (such as constants) */\n' +\ -'\n' + \ -' if (PyErr_Occurred())\n' + \ -' Py_FatalError("could not initialise module %(module)s");\n' + \ -'}\n' - -override_template = \ -'/* -*- Mode: C; c-basic-offset: 4 -*- */\n' + \ -'%%%%\n' + \ -'headers\n' + \ -'/* include any required headers here */\n' + \ -'%%%%\n' + \ -'init\n' + \ -' /* include any code here that needs to be executed before the\n' + \ -' * extension classes get initialised */\n' + \ -'%%%%\n' + \ -'\n' + \ -'/* you should add appropriate ignore, ignore-glob and\n' + \ -' * override sections here */\n' - -def open_with_backup(file): - if os.path.exists(file): - try: - os.rename(file, file+'~') - except OSError: - # fail silently if we can't make a backup - pass - return open(file, 'w') - -def write_skels(fileprefix, prefix, module): - fp = open_with_backup(fileprefix+'module.c') - fp.write(module_init_template % { 'prefix': prefix, 'module': module }) - fp.close() - fp = open_with_backup(fileprefix+'.override') - fp.write(override_template % { 'prefix': prefix, 'module': module }) - fp.close() - -if __name__ == '__main__': - opts, args = getopt.getopt(sys.argv[1:], 'f:p:m:h', - ['file-prefix=', 'prefix=', 'module=', 'help']) - fileprefix = None - prefix = None - module = None - for opt, arg in opts: - if opt in ('-f', '--file-prefix'): - fileprefix = arg - elif opt in ('-p', '--prefix'): - prefix = arg - elif opt in ('-m', '--module'): - module = arg - elif opt in ('-h', '--help'): - print 'usage: mkskel.py -f fileprefix -p prefix -m module' - sys.exit(0) - if not fileprefix or not prefix or not module: - print 'usage: mkskel.py -f fileprefix -p prefix -m module' - sys.exit(1) - write_skels(fileprefix, prefix, module) diff --git a/bindings/python/codegen/override.py b/bindings/python/codegen/override.py deleted file mode 100644 index 2e8c6a4c30..0000000000 --- a/bindings/python/codegen/override.py +++ /dev/null @@ -1,288 +0,0 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- - -# this file contains code for loading up an override file. The override file -# provides implementations of functions where the code generator could not -# do its job correctly. - -import fnmatch -import os -import re -import string -import sys - -def class2cname(klass, method): - c_name = '' - for c in klass: - if c.isupper(): - c_name += '_' + c.lower() - else: - c_name += c - return c_name[1:] + '_' + method - -import_pat = re.compile(r'\s*import\s+(\S+)\.([^\s.]+)\s+as\s+(\S+)') - -class Overrides: - def __init__(self, filename=None, path=[]): - self.modulename = None - self.ignores = {} - self.glob_ignores = [] - self.type_ignores = {} - self.overrides = {} - self.overridden = {} - self.kwargs = {} - self.noargs = {} - self.onearg = {} - self.staticmethod = {} - self.classmethod = {} - self.startlines = {} - self.override_attrs = {} - self.override_slots = {} - self.headers = '' - self.body = '' - self.init = '' - self.imports = [] - self.defines = {} - self.functions = {} - self.newstyle_constructors = {} - self.path = [os.path.abspath(x) for x in path] - if filename: - self.handle_file(filename) - - def handle_file(self, filename): - oldpath = os.getcwd() - - fp = None - for path in self.path: - os.chdir(oldpath) - os.chdir(path) - try: - fp = open(filename, 'r') - break - except: - os.chdir(oldpath) - if not fp: - raise Exception, "Couldn't find file %s" % filename - - dirname = path - - if dirname != oldpath: - os.chdir(dirname) - - # read all the components of the file ... - bufs = [] - startline = 1 - lines = [] - line = fp.readline() - linenum = 1 - while line: - if line == '%%\n' or line == '%%': - if lines: - bufs.append((string.join(lines, ''), startline)) - startline = linenum + 1 - lines = [] - else: - lines.append(line) - line = fp.readline() - linenum = linenum + 1 - if lines: - bufs.append((string.join(lines, ''), startline)) - if not bufs: return - - for buf, startline in bufs: - self.__parse_override(buf, startline, filename) - - os.chdir(oldpath) - - def __parse_override(self, buffer, startline, filename): - pos = string.find(buffer, '\n') - if pos >= 0: - line = buffer[:pos] - rest = buffer[pos+1:] - else: - line = buffer ; rest = '' - words = string.split(line) - command = words[0] - if (command == 'ignore' or - command == 'ignore-' + sys.platform): - "ignore/ignore-platform [functions..]" - for func in words[1:]: - self.ignores[func] = 1 - for func in string.split(rest): - self.ignores[func] = 1 - elif (command == 'ignore-glob' or - command == 'ignore-glob-' + sys.platform): - "ignore-glob/ignore-glob-platform [globs..]" - for func in words[1:]: - self.glob_ignores.append(func) - for func in string.split(rest): - self.glob_ignores.append(func) - elif (command == 'ignore-type' or - command == 'ignore-type-' + sys.platform): - "ignore-type/ignore-type-platform [typenames..]" - for typename in words[1:]: - self.type_ignores[typename] = 1 - for typename in string.split(rest): - self.type_ignores[typename] = 1 - elif command == 'override': - "override function/method [kwargs|noargs|onearg] [staticmethod|classmethod]" - func = words[1] - if 'kwargs' in words[1:]: - self.kwargs[func] = 1 - elif 'noargs' in words[1:]: - self.noargs[func] = 1 - elif 'onearg' in words[1:]: - self.onearg[func] = True - - if 'staticmethod' in words[1:]: - self.staticmethod[func] = True - elif 'classmethod' in words[1:]: - self.classmethod[func] = True - if func in self.overrides: - raise RuntimeError("Function %s is being overridden more than once" % (func,)) - self.overrides[func] = rest - self.startlines[func] = (startline + 1, filename) - elif command == 'override-attr': - "override-slot Class.attr" - attr = words[1] - self.override_attrs[attr] = rest - self.startlines[attr] = (startline + 1, filename) - elif command == 'override-slot': - "override-slot Class.slot" - slot = words[1] - self.override_slots[slot] = rest - self.startlines[slot] = (startline + 1, filename) - elif command == 'headers': - "headers" - self.headers = '%s\n#line %d "%s"\n%s' % \ - (self.headers, startline + 1, filename, rest) - elif command == 'body': - "body" - self.body = '%s\n#line %d "%s"\n%s' % \ - (self.body, startline + 1, filename, rest) - elif command == 'init': - "init" - self.init = '%s\n#line %d "%s"\n%s' % \ - (self.init, startline + 1, filename, rest) - elif command == 'modulename': - "modulename name" - self.modulename = words[1] - elif command == 'include': - "include filename" - for filename in words[1:]: - self.handle_file(filename) - for filename in string.split(rest): - self.handle_file(filename) - elif command == 'import': - "import module1 [\n module2, \n module3 ...]" - for line in string.split(buffer, '\n'): - match = import_pat.match(line) - if match: - self.imports.append(match.groups()) - elif command == 'define': - "define funcname [kwargs|noargs|onearg] [classmethod|staticmethod]" - "define Class.method [kwargs|noargs|onearg] [classmethod|staticmethod]" - func = words[1] - klass = None - if func.find('.') != -1: - klass, func = func.split('.', 1) - - if not self.defines.has_key(klass): - self.defines[klass] = {} - self.defines[klass][func] = rest - else: - self.functions[func] = rest - - if 'kwargs' in words[1:]: - self.kwargs[func] = 1 - elif 'noargs' in words[1:]: - self.noargs[func] = 1 - elif 'onearg' in words[1:]: - self.onearg[func] = 1 - - if 'staticmethod' in words[1:]: - self.staticmethod[func] = True - elif 'classmethod' in words[1:]: - self.classmethod[func] = True - - self.startlines[func] = (startline + 1, filename) - - elif command == 'new-constructor': - "new-constructor GType" - gtype, = words[1:] - self.newstyle_constructors[gtype] = True - - def is_ignored(self, name): - if self.ignores.has_key(name): - return 1 - for glob in self.glob_ignores: - if fnmatch.fnmatchcase(name, glob): - return 1 - return 0 - - def is_type_ignored(self, name): - return name in self.type_ignores - - def is_overriden(self, name): - return self.overrides.has_key(name) - - def is_already_included(self, name): - return self.overridden.has_key(name) - - def override(self, name): - self.overridden[name] = 1 - return self.overrides[name] - - def define(self, klass, name): - self.overridden[class2cname(klass, name)] = 1 - return self.defines[klass][name] - - def function(self, name): - return self.functions[name] - - def getstartline(self, name): - return self.startlines[name] - - def wants_kwargs(self, name): - return self.kwargs.has_key(name) - - def wants_noargs(self, name): - return self.noargs.has_key(name) - - def wants_onearg(self, name): - return self.onearg.has_key(name) - - def is_staticmethod(self, name): - return self.staticmethod.has_key(name) - - def is_classmethod(self, name): - return self.classmethod.has_key(name) - - def attr_is_overriden(self, attr): - return self.override_attrs.has_key(attr) - - def attr_override(self, attr): - return self.override_attrs[attr] - - def slot_is_overriden(self, slot): - return self.override_slots.has_key(slot) - - def slot_override(self, slot): - return self.override_slots[slot] - - def get_headers(self): - return self.headers - - def get_body(self): - return self.body - - def get_init(self): - return self.init - - def get_imports(self): - return self.imports - - def get_defines_for(self, klass): - return self.defines.get(klass, {}) - - def get_functions(self): - return self.functions diff --git a/bindings/python/codegen/reversewrapper.py b/bindings/python/codegen/reversewrapper.py deleted file mode 100644 index f528828ef1..0000000000 --- a/bindings/python/codegen/reversewrapper.py +++ /dev/null @@ -1,771 +0,0 @@ -### -*- python -*- -### Code to generate "Reverse Wrappers", i.e. C->Python wrappers -### (C) 2004 Gustavo Carneiro -import argtypes -import os - -DEBUG_MODE = ('PYGTK_CODEGEN_DEBUG' in os.environ) - -def join_ctype_name(ctype, name): - '''Joins a C type and a variable name into a single string''' - if ctype[-1] != '*': - return " ".join((ctype, name)) - else: - return "".join((ctype, name)) - - -class CodeSink(object): - def __init__(self): - self.indent_level = 0 # current indent level - self.indent_stack = [] # previous indent levels - - def _format_code(self, code): - assert isinstance(code, str) - l = [] - for line in code.split('\n'): - l.append(' '*self.indent_level + line) - if l[-1]: - l.append('') - return '\n'.join(l) - - def writeln(self, line=''): - raise NotImplementedError - - def indent(self, level=4): - '''Add a certain ammount of indentation to all lines written - from now on and until unindent() is called''' - self.indent_stack.append(self.indent_level) - self.indent_level += level - - def unindent(self): - '''Revert indentation level to the value before last indent() call''' - self.indent_level = self.indent_stack.pop() - - -class FileCodeSink(CodeSink): - def __init__(self, fp): - CodeSink.__init__(self) - assert isinstance(fp, file) - self.fp = fp - - def writeln(self, line=''): - self.fp.write(self._format_code(line)) - -class MemoryCodeSink(CodeSink): - def __init__(self): - CodeSink.__init__(self) - self.lines = [] - - def writeln(self, line=''): - self.lines.append(self._format_code(line)) - - def flush_to(self, sink): - assert isinstance(sink, CodeSink) - for line in self.lines: - sink.writeln(line.rstrip()) - self.lines = [] - - def flush(self): - l = [] - for line in self.lines: - l.append(self._format_code(line)) - self.lines = [] - return "".join(l) - -class ReverseWrapper(object): - '''Object that generates a C->Python wrapper''' - def __init__(self, cname, is_static=True): - assert isinstance(cname, str) - - self.cname = cname - ## function object we will call, or object whose method we will call - self.called_pyobj = None - ## name of method of self.called_pyobj we will call - self.method_name = None - self.is_static = is_static - - self.parameters = [] - self.declarations = MemoryCodeSink() - self.post_return_code = MemoryCodeSink() - self.body = MemoryCodeSink() - self.cleanup_actions = [] - self.pyargv_items = [] - self.pyargv_optional_items = [] - self.pyret_parse_items = [] # list of (format_spec, parameter) - - def set_call_target(self, called_pyobj, method_name=None): - assert called_pyobj is not None - assert self.called_pyobj is None - self.called_pyobj = called_pyobj - self.method_name = method_name - - def set_return_type(self, return_type): - assert isinstance(return_type, ReturnType) - self.return_type = return_type - - def add_parameter(self, param): - assert isinstance(param, Parameter) - self.parameters.append(param) - - def add_declaration(self, decl_code): - self.declarations.writeln(decl_code) - - def add_pyargv_item(self, variable, optional=False): - if optional: - self.pyargv_optional_items.append(variable) - else: - self.pyargv_items.append(variable) - - def add_pyret_parse_item(self, format_specifier, parameter, prepend=False): - if prepend: - self.pyret_parse_items.insert(0, (format_specifier, parameter)) - else: - self.pyret_parse_items.append((format_specifier, parameter)) - - def write_code(self, code, - cleanup=None, - failure_expression=None, - failure_cleanup=None, - failure_exception=None, - code_sink=None): - '''Add a chunk of code with cleanup and error handling - - This method is to be used by TypeHandlers when generating code - - Keywork arguments: - code -- code to add - cleanup -- code to cleanup any dynamic resources created by @code - (except in case of failure) (default None) - failure_expression -- C boolean expression to indicate - if anything failed (default None) - failure_cleanup -- code to cleanup any dynamic resources - created by @code in case of failure (default None) - failure_exception -- code to raise an exception in case of - failure (which will be immediately - printed and cleared), (default None) - code_sink -- "code sink" to use; by default, - ReverseWrapper.body is used, which writes the - main body of the wrapper, before calling the - python method. Alternatively, - ReverseWrapper.after_pyret_parse can be used, to - write code after the PyArg_ParseTuple that - parses the python method return value. - ''' - if code_sink is None: - code_sink = self.body - if code is not None: - code_sink.writeln(code) - if failure_expression is not None: - code_sink.writeln("if (%s) {" % (failure_expression,)) - code_sink.indent() - if failure_exception is None: - code_sink.writeln("if (PyErr_Occurred())") - code_sink.indent() - code_sink.writeln("PyErr_Print();") - code_sink.unindent() - else: - code_sink.writeln(failure_exception) - code_sink.writeln("PyErr_Print();") - if failure_cleanup is not None: - code_sink.writeln(failure_cleanup) - for cleanup_action in self.cleanup_actions: - code_sink.writeln(cleanup_action) - self.return_type.write_error_return() - code_sink.unindent() - code_sink.writeln("}") - if cleanup is not None: - self.cleanup_actions.insert(0, cleanup) - - def generate(self, sink): - '''Generate the code into a CodeSink object''' - assert isinstance(sink, CodeSink) - - if DEBUG_MODE: - self.declarations.writeln("/* begin declarations */") - self.body.writeln("/* begin main body */") - self.post_return_code.writeln("/* begin post-return code */") - - self.add_declaration("PyGILState_STATE __py_state;") - self.write_code(code="__py_state = pyg_gil_state_ensure();", - cleanup="pyg_gil_state_release(__py_state);") - - for param in self.parameters: - param.convert_c2py() - - assert self.called_pyobj is not None,\ - "Parameters failed to provide a target function or method." - - if self.is_static: - sink.writeln('static %s' % self.return_type.get_c_type()) - else: - sink.writeln(self.return_type.get_c_type()) - c_proto_params = map(Parameter.format_for_c_proto, self.parameters) - sink.writeln("%s(%s)\n{" % (self.cname, ", ".join(c_proto_params))) - - self.return_type.write_decl() - self.add_declaration("PyObject *py_retval;") - - ## Handle number of arguments - if self.pyargv_items: - self.add_declaration("PyObject *py_args;") - py_args = "py_args" - if self.pyargv_optional_items: - self.add_declaration("int argc = %i;" % len(self.pyargv_items)) - argc = "argc" - for arg in self.pyargv_optional_items: - self.body.writeln("if (%s)" % arg) - self.body.indent() - self.body.writeln("++argc;") - self.body.unindent() - else: - argc = str(len(self.pyargv_items)) - else: - if self.pyargv_optional_items: - self.add_declaration("PyObject *py_args;") - py_args = "py_args" - self.add_declaration("int argc = 0;") - argc = "argc" - for arg in self.pyargv_optional_items: - self.body.writeln("if (%s)" % arg) - self.body.indent() - self.body.writeln("++argc;") - self.body.unindent() - else: - py_args = "NULL" - argc = None - - self.body.writeln() - - if py_args != "NULL": - self.write_code("py_args = PyTuple_New(%s);" % argc, - cleanup="Py_DECREF(py_args);") - pos = 0 - for arg in self.pyargv_items: - try: # try to remove the Py_DECREF cleanup action, if we can - self.cleanup_actions.remove("Py_DECREF(%s);" % arg) - except ValueError: # otherwise we have to Py_INCREF.. - self.body.writeln("Py_INCREF(%s);" % arg) - self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg)) - pos += 1 - for arg in self.pyargv_optional_items: - self.body.writeln("if (%s) {" % arg) - self.body.indent() - try: # try to remove the Py_DECREF cleanup action, if we can - self.cleanup_actions.remove("Py_XDECREF(%s);" % arg) - except ValueError: # otherwise we have to Py_INCREF.. - self.body.writeln("Py_INCREF(%s);" % arg) - self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg)) - self.body.unindent() - self.body.writeln("}") - pos += 1 - - self.body.writeln() - - ## Call the python method - if self.method_name is None: - self.write_code("py_retval = PyObject_Call(%s, %s);" - % (self.called_pyobj, py_args), - cleanup="Py_DECREF(py_retval);", - failure_expression="!py_retval") - else: - self.add_declaration("PyObject *py_method;") - self.write_code("py_method = PyObject_GetAttrString(%s, \"%s\");" - % (self.called_pyobj, self.method_name), - cleanup="Py_DECREF(py_method);", - failure_expression="!py_method") - self.write_code("py_retval = PyObject_CallObject(py_method, %s);" - % (py_args,), - cleanup="Py_DECREF(py_retval);", - failure_expression="!py_retval") - - ## -- Handle the return value -- - - ## we need to check if the return_type object is prepared to cooperate with multiple return values - len_before = len(self.pyret_parse_items) - self.return_type.write_conversion() - len_after = len(self.pyret_parse_items) - assert (self.return_type.get_c_type() == 'void' - or not (len_before == len_after and len_after > 0)),\ - ("Bug in reverse wrappers: return type handler %s" - " is not prepared to cooperate multiple return values") % (type(self.return_type),) - - sink.indent() - - if len(self.pyret_parse_items) == 1: - ## if retval is one item only, pack it in a tuple so we - ## can use PyArg_ParseTuple as usual.. - self.write_code('py_retval = Py_BuildValue("(N)", py_retval);') - if len(self.pyret_parse_items) > 0: - ## Parse return values using PyArg_ParseTuple - self.write_code(code=None, failure_expression=( - '!PyArg_ParseTuple(py_retval, "%s", %s)' % ( - "".join([format for format, param in self.pyret_parse_items]), - ", ".join([param for format, param in self.pyret_parse_items])))) - - if DEBUG_MODE: - self.declarations.writeln("/* end declarations */") - self.declarations.flush_to(sink) - sink.writeln() - if DEBUG_MODE: - self.body.writeln("/* end main body */") - self.body.flush_to(sink) - sink.writeln() - if DEBUG_MODE: - self.post_return_code.writeln("/* end post-return code */") - self.post_return_code.flush_to(sink) - sink.writeln() - - for cleanup_action in self.cleanup_actions: - sink.writeln(cleanup_action) - if self.return_type.get_c_type() != 'void': - sink.writeln() - sink.writeln("return retval;") - sink.unindent() - sink.writeln("}") - -class TypeHandler(object): - def __init__(self, wrapper, **props): - assert isinstance(wrapper, ReverseWrapper) - self.wrapper = wrapper - self.props = props - -class ReturnType(TypeHandler): - - def get_c_type(self): - raise NotImplementedError - - def write_decl(self): - raise NotImplementedError - - def write_error_return(self): - '''Write "return " code in case of error''' - raise NotImplementedError - - def write_conversion(self): - '''Writes code to convert Python return value in 'py_retval' - into C 'retval'. Returns a string with C boolean expression - that determines if anything went wrong. ''' - raise NotImplementedError - -class Parameter(TypeHandler): - - def __init__(self, wrapper, name, **props): - TypeHandler.__init__(self, wrapper, **props) - self.name = name - - def get_c_type(self): - raise NotImplementedError - - def convert_c2py(self): - '''Write some code before calling the Python method.''' - pass - - def format_for_c_proto(self): - return join_ctype_name(self.get_c_type(), self.name) - - -###--- -class StringParam(Parameter): - - def get_c_type(self): - return self.props.get('c_type', 'char *').replace('const-', 'const ') - - def convert_c2py(self): - if self.props.get('optional', False): - self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name) - self.wrapper.write_code(code=("if (%s)\n" - " py_%s = PyString_FromString(%s);\n" - % (self.name, self.name, self.name)), - cleanup=("Py_XDECREF(py_%s);" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name, optional=True) - else: - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" % - (self.name, self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name), - failure_expression=("!py_%s" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -for ctype in ('char*', 'gchar*', 'const-char*', 'char-const*', 'const-gchar*', - 'gchar-const*', 'string', 'static_string'): - argtypes.matcher.register_reverse(ctype, StringParam) -del ctype - -class StringReturn(ReturnType): - - def get_c_type(self): - return "char *" - - def write_decl(self): - self.wrapper.add_declaration("char *retval;") - - def write_error_return(self): - self.wrapper.write_code("return NULL;") - - def write_conversion(self): - self.wrapper.add_pyret_parse_item("s", "&retval", prepend=True) - self.wrapper.write_code("retval = g_strdup(retval);", code_sink=self.wrapper.post_return_code) - -for ctype in ('char*', 'gchar*'): - argtypes.matcher.register_reverse_ret(ctype, StringReturn) -del ctype - - -class VoidReturn(ReturnType): - - def get_c_type(self): - return "void" - - def write_decl(self): - pass - - def write_error_return(self): - self.wrapper.write_code("return;") - - def write_conversion(self): - self.wrapper.write_code( - code=None, - failure_expression="py_retval != Py_None", - failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be None");') - -argtypes.matcher.register_reverse_ret('void', VoidReturn) -argtypes.matcher.register_reverse_ret('none', VoidReturn) - -class GObjectParam(Parameter): - - def get_c_type(self): - return self.props.get('c_type', 'GObject *') - - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name) - self.wrapper.write_code(code=("if (%s)\n" - " py_%s = pygobject_new((GObject *) %s);\n" - "else {\n" - " Py_INCREF(Py_None);\n" - " py_%s = Py_None;\n" - "}" - % (self.name, self.name, self.name, self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -argtypes.matcher.register_reverse('GObject*', GObjectParam) - -class GObjectReturn(ReturnType): - - def get_c_type(self): - return self.props.get('c_type', 'GObject *') - - def write_decl(self): - self.wrapper.add_declaration("%s retval;" % self.get_c_type()) - - def write_error_return(self): - self.wrapper.write_code("return NULL;") - - def write_conversion(self): - self.wrapper.write_code( - code=None, - failure_expression="!PyObject_TypeCheck(py_retval, &PyGObject_Type)", - failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be a GObject");') - self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);" - % self.get_c_type()) - self.wrapper.write_code("g_object_ref((GObject *) retval);") - -argtypes.matcher.register_reverse_ret('GObject*', GObjectReturn) - - - -class IntParam(Parameter): - - def get_c_type(self): - return self.props.get('c_type', 'int') - - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = PyInt_FromLong(%s);" % - (self.name, self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -class IntReturn(ReturnType): - def get_c_type(self): - return self.props.get('c_type', 'int') - def write_decl(self): - self.wrapper.add_declaration("%s retval;" % self.get_c_type()) - def write_error_return(self): - self.wrapper.write_code("return -G_MAXINT;") - def write_conversion(self): - self.wrapper.add_pyret_parse_item("i", "&retval", prepend=True) - -for argtype in ('int', 'gint', 'guint', 'short', 'gshort', 'gushort', 'long', - 'glong', 'gsize', 'gssize', 'guint8', 'gint8', 'guint16', - 'gint16', 'gint32', 'GTime'): - argtypes.matcher.register_reverse(argtype, IntParam) - argtypes.matcher.register_reverse_ret(argtype, IntReturn) -del argtype - -class IntPtrParam(Parameter): - def __init__(self, wrapper, name, **props): - if "direction" not in props: - raise ValueError("cannot use int* parameter without direction") - if props["direction"] not in ("out", "inout"): - raise ValueError("cannot use int* parameter with direction '%s'" % (props["direction"],)) - Parameter.__init__(self, wrapper, name, **props) - def get_c_type(self): - return self.props.get('c_type', 'int*') - def convert_c2py(self): - if self.props["direction"] == "inout": - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = PyInt_FromLong(*%s);" % - (self.name, self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - self.wrapper.add_pyret_parse_item("i", self.name) -for argtype in ('int*', 'gint*'): - argtypes.matcher.register_reverse(argtype, IntPtrParam) -del argtype - - -class GEnumReturn(IntReturn): - def write_conversion(self): - self.wrapper.write_code( - code=None, - failure_expression=("pyg_enum_get_value(%s, py_retval, (gint *)&retval)" % - self.props['typecode'])) - -argtypes.matcher.register_reverse_ret("GEnum", GEnumReturn) - -class GEnumParam(IntParam): - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = pyg_enum_from_gtype(%s, %s);" % - (self.name, self.props['typecode'], self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name), - failure_expression=("!py_%s" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -argtypes.matcher.register_reverse("GEnum", GEnumParam) - -class GFlagsReturn(IntReturn): - def write_conversion(self): - self.wrapper.write_code( - code=None, - failure_expression=("pyg_flags_get_value(%s, py_retval, (gint *)&retval)" % - self.props['typecode'])) - -argtypes.matcher.register_reverse_ret("GFlags", GFlagsReturn) - -class GFlagsParam(IntParam): - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = pyg_flags_from_gtype(%s, %s);" % - (self.name, self.props['typecode'], self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name), - failure_expression=("!py_%s" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -argtypes.matcher.register_reverse("GFlags", GFlagsParam) - - -class GtkTreePathParam(IntParam): - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = pygtk_tree_path_to_pyobject(%s);" % - (self.name, self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name), - failure_expression=("!py_%s" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -argtypes.matcher.register_reverse("GtkTreePath*", GtkTreePathParam) - - -class BooleanReturn(ReturnType): - def get_c_type(self): - return "gboolean" - def write_decl(self): - self.wrapper.add_declaration("gboolean retval;") - self.wrapper.add_declaration("PyObject *py_main_retval;") - def write_error_return(self): - self.wrapper.write_code("return FALSE;") - def write_conversion(self): - self.wrapper.add_pyret_parse_item("O", "&py_main_retval", prepend=True) - self.wrapper.write_code("retval = PyObject_IsTrue(py_main_retval)? TRUE : FALSE;", - code_sink=self.wrapper.post_return_code) -argtypes.matcher.register_reverse_ret("gboolean", BooleanReturn) - -class BooleanParam(Parameter): - def get_c_type(self): - return "gboolean" - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code("py_%s = %s? Py_True : Py_False;" - % (self.name, self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -argtypes.matcher.register_reverse("gboolean", BooleanParam) - - -class DoubleParam(Parameter): - def get_c_type(self): - return self.props.get('c_type', 'gdouble') - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = PyFloat_FromDouble(%s);" % - (self.name, self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -class DoublePtrParam(Parameter): - def __init__(self, wrapper, name, **props): - if "direction" not in props: - raise ValueError("cannot use double* parameter without direction") - if props["direction"] not in ("out", ): # inout not yet implemented - raise ValueError("cannot use double* parameter with direction '%s'" % (props["direction"],)) - Parameter.__init__(self, wrapper, name, **props) - def get_c_type(self): - return self.props.get('c_type', 'double*') - def convert_c2py(self): - self.wrapper.add_pyret_parse_item("d", self.name) -for argtype in ('double*', 'gdouble*'): - argtypes.matcher.register_reverse(argtype, DoublePtrParam) -del argtype - -class DoubleReturn(ReturnType): - def get_c_type(self): - return self.props.get('c_type', 'gdouble') - def write_decl(self): - self.wrapper.add_declaration("%s retval;" % self.get_c_type()) - def write_error_return(self): - self.wrapper.write_code("return -G_MAXFLOAT;") - def write_conversion(self): - self.wrapper.write_code( - code=None, - failure_expression="!PyFloat_AsDouble(py_retval)", - failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a float");') - self.wrapper.write_code("retval = PyFloat_AsDouble(py_retval);") - -for argtype in ('float', 'double', 'gfloat', 'gdouble'): - argtypes.matcher.register_reverse(argtype, DoubleParam) - argtypes.matcher.register_reverse_ret(argtype, DoubleReturn) - - -class GBoxedParam(Parameter): - def get_c_type(self): - return self.props.get('c_type').replace('const-', 'const ') - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - ctype = self.get_c_type() - if ctype.startswith('const '): - ctype_no_const = ctype[len('const '):] - self.wrapper.write_code( - code=('py_%s = pyg_boxed_new(%s, (%s) %s, TRUE, TRUE);' % - (self.name, self.props['typecode'], - ctype_no_const, self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name)) - else: - self.wrapper.write_code( - code=('py_%s = pyg_boxed_new(%s, %s, FALSE, FALSE);' % - (self.name, self.props['typecode'], self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -argtypes.matcher.register_reverse("GBoxed", GBoxedParam) - -class GBoxedReturn(ReturnType): - def get_c_type(self): - return self.props.get('c_type') - def write_decl(self): - self.wrapper.add_declaration("%s retval;" % self.get_c_type()) - def write_error_return(self): - self.wrapper.write_code("return retval;") - def write_conversion(self): - self.wrapper.write_code( - failure_expression=("!pyg_boxed_check(py_retval, %s)" % - (self.props['typecode'],)), - failure_cleanup=('PyErr_SetString(PyExc_TypeError, "retval should be a %s");' - % (self.props['typename'],))) - self.wrapper.write_code('retval = pyg_boxed_get(py_retval, %s);' % - self.props['typename']) - -argtypes.matcher.register_reverse_ret("GBoxed", GBoxedReturn) - - -class GdkRectanglePtrParam(Parameter): - def get_c_type(self): - return self.props.get('c_type').replace('const-', 'const ') - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code( - code=('py_%s = pyg_boxed_new(GDK_TYPE_RECTANGLE, %s, TRUE, TRUE);' % - (self.name, self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name)) - self.wrapper.add_pyargv_item("py_%s" % self.name) - -argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam) -argtypes.matcher.register_reverse('GtkAllocation*', GdkRectanglePtrParam) - - -class PyGObjectMethodParam(Parameter): - def __init__(self, wrapper, name, method_name, **props): - Parameter.__init__(self, wrapper, name, **props) - self.method_name = method_name - - def get_c_type(self): - return self.props.get('c_type', 'GObject *') - - def convert_c2py(self): - self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = pygobject_new((GObject *) %s);" % - (self.name, self.name)), - cleanup=("Py_DECREF(py_%s);" % self.name), - failure_expression=("!py_%s" % self.name)) - self.wrapper.set_call_target("py_%s" % self.name, self.method_name) - -class CallbackInUserDataParam(Parameter): - def __init__(self, wrapper, name, free_it, **props): - Parameter.__init__(self, wrapper, name, **props) - self.free_it = free_it - - def get_c_type(self): - return "gpointer" - - def convert_c2py(self): - self.wrapper.add_declaration("PyObject **_user_data;") - cleanup = self.free_it and ("g_free(%s);" % self.name) or None - self.wrapper.write_code(code=("_real_user_data = (PyObject **) %s;" - % self.name), - cleanup=cleanup) - - self.wrapper.add_declaration("PyObject *py_func;") - cleanup = self.free_it and "Py_DECREF(py_func);" or None - self.wrapper.write_code(code="py_func = _user_data[0];", - cleanup=cleanup) - self.wrapper.set_call_target("py_func") - - self.wrapper.add_declaration("PyObject *py_user_data;") - cleanup = self.free_it and "Py_XDECREF(py_user_data);" or None - self.wrapper.write_code(code="py_user_data = _user_data[1];", - cleanup=cleanup) - self.wrapper.add_pyargv_item("py_user_data", optional=True) - -def _test(): - import sys - - if 1: - wrapper = ReverseWrapper("this_is_the_c_function_name", is_static=True) - wrapper.set_return_type(StringReturn(wrapper)) - wrapper.add_parameter(PyGObjectMethodParam(wrapper, "self", method_name="do_xxx")) - wrapper.add_parameter(StringParam(wrapper, "param2", optional=True)) - wrapper.add_parameter(GObjectParam(wrapper, "param3")) - #wrapper.add_parameter(InoutIntParam(wrapper, "param4")) - wrapper.generate(FileCodeSink(sys.stderr)) - - if 0: - wrapper = ReverseWrapper("this_a_callback_wrapper") - wrapper.set_return_type(VoidReturn(wrapper)) - wrapper.add_parameter(StringParam(wrapper, "param1", optional=False)) - wrapper.add_parameter(GObjectParam(wrapper, "param2")) - wrapper.add_parameter(CallbackInUserDataParam(wrapper, "data", free_it=True)) - wrapper.generate(FileCodeSink(sys.stderr)) - -if __name__ == '__main__': - _test() diff --git a/bindings/python/codegen/scmexpr.py b/bindings/python/codegen/scmexpr.py deleted file mode 100644 index d08c517adb..0000000000 --- a/bindings/python/codegen/scmexpr.py +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/env python -# -*- Mode: Python; py-indent-offset: 4 -*- -from __future__ import generators - -import string -import types -from cStringIO import StringIO - -class error(Exception): - def __init__(self, filename, lineno, msg): - Exception.__init__(self, msg) - self.filename = filename - self.lineno = lineno - self.msg = msg - def __str__(self): - return '%s:%d: error: %s' % (self.filename, self.lineno, self.msg) - -trans = [' '] * 256 -for i in range(256): - if chr(i) in string.letters + string.digits + '_': - trans[i] = chr(i) - else: - trans[i] = '_' -trans = string.join(trans, '') - -def parse(filename): - if isinstance(filename, str): - fp = open(filename, 'r') - else: # if not string, assume it is some kind of iterator - fp = filename - filename = getattr(fp, 'name', '') - whitespace = ' \t\n\r\x0b\x0c' - nonsymbol = whitespace + '();\'"' - stack = [] - openlines = [] - lineno = 0 - for line in fp: - pos = 0 - lineno += 1 - while pos < len(line): - if line[pos] in whitespace: # ignore whitespace - pass - elif line[pos] == ';': # comment - break - elif line[pos:pos+2] == "'(": - pass # the open parenthesis will be handled next iteration - elif line[pos] == '(': - stack.append(()) - openlines.append(lineno) - elif line[pos] == ')': - if len(stack) == 0: - raise error(filename, lineno, 'close parenthesis found when none open') - closed = stack[-1] - del stack[-1] - del openlines[-1] - if stack: - stack[-1] += (closed,) - else: - yield closed - elif line[pos] == '"': # quoted string - if not stack: - raise error(filename, lineno, - 'string found outside of s-expression') - endpos = pos + 1 - chars = [] - while endpos < len(line): - if endpos+1 < len(line) and line[endpos] == '\\': - endpos += 1 - if line[endpos] == 'n': - chars.append('\n') - elif line[endpos] == 'r': - chars.append('\r') - elif line[endpos] == 't': - chars.append('\t') - else: - chars.append('\\') - chars.append(line[endpos]) - elif line[endpos] == '"': - break - else: - chars.append(line[endpos]) - endpos += 1 - if endpos >= len(line): - raise error(filename, lineno, "unclosed quoted string") - pos = endpos - stack[-1] += (''.join(chars),) - else: # symbol/number - if not stack: - raise error(filename, lineno, - 'identifier found outside of s-expression') - endpos = pos - while endpos < len(line) and line[endpos] not in nonsymbol: - endpos += 1 - symbol = line[pos:endpos] - pos = max(pos, endpos-1) - try: symbol = int(symbol) - except ValueError: - try: symbol = float(symbol) - except ValueError: pass - stack[-1] += (symbol,) - pos += 1 - if len(stack) != 0: - msg = '%d unclosed parentheses found at end of ' \ - 'file (opened on line(s) %s)' % (len(stack), - ', '.join(map(str, openlines))) - raise error(filename, lineno, msg) - -class Parser: - def __init__(self, filename): - """Argument is either a string, a parse tree, or file object""" - self.filename = filename - def startParsing(self, filename=None): - statements = parse(filename or self.filename) - for statement in statements: - self.handle(statement) - def handle(self, tup): - cmd = string.translate(tup[0], trans) - if hasattr(self, cmd): - getattr(self, cmd)(*tup[1:]) - else: - self.unknown(tup) - def unknown(self, tup): - pass - -_testString = """; a scheme file -(define-func gdk_font_load ; a comment at end of line - GdkFont - ((string name))) - -(define-boxed GdkEvent - gdk_event_copy - gdk_event_free - "sizeof(GdkEvent)") -""" - -if __name__ == '__main__': - import sys - if sys.argv[1:]: - fp = open(sys.argv[1]) - else: - fp = StringIO(_testString) - statements = parse(fp) - for s in statements: - print `s` diff --git a/bindings/python/rtspserver-types.defs b/bindings/python/rtspserver-types.defs deleted file mode 100644 index 04949afe48..0000000000 --- a/bindings/python/rtspserver-types.defs +++ /dev/null @@ -1,63 +0,0 @@ -;; From gst/rtsp-server/rtsp-server.h - -(define-object Server - (in-module "Gst.RTSPServer") - (parent "GObject") - (c-name "GstRTSPServer") - (gtype-id "GST_TYPE_RTSP_SERVER") -) - -;; From gst/rtsp-server/rtsp-media-mapping.h - -(define-object MediaMapping - (in-module "Gst.RTSPServer") - (parent "GObject") - (c-name "GstRTSPMediaMapping") - (gtype-id "GST_TYPE_RTSP_MEDIA_MAPPING") -) - -;; From gst/rtsp-server/rtsp-media-factory.h - -(define-object MediaFactory - (in-module "Gst.RTSPServer") - (parent "GObject") - (c-name "GstRTSPMediaFactory") - (gtype-id "GST_TYPE_RTSP_MEDIA_FACTORY") -) - -;; From gst/rtsp-server/rtsp-media.h - -(define-object Media - (in-module "Gst.RTSPServer") - (parent "GObject") - (c-name "GstRTSPMedia") - (gtype-id "GST_TYPE_RTSP_MEDIA") -) - -;; From gst/rtsp-server/rtsp-session-pool.h - -(define-object SessionPool - (in-module "Gst") - (parent "GObject") - (c-name "GstRTSPSessionPool") - (gtype-id "GST_TYPE_RTSP_SESSION_POOL") -) - -;; From gst/rtsp-server/rtsp-session.h - -(define-object Session - (in-module "Gst") - (parent "GObject") - (c-name "GstRTSPSession") - (gtype-id "GST_TYPE_RTSP_SESSION") -) - -;; From gst/rtsp-server/rtsp-client.h - -(define-object Client - (in-module "Gst") - (parent "GObject") - (c-name "GstRTSPClient") - (gtype-id "GST_TYPE_RTSP_CLIENT") -) - diff --git a/bindings/python/rtspserver.defs b/bindings/python/rtspserver.defs deleted file mode 100644 index f000434cf6..0000000000 --- a/bindings/python/rtspserver.defs +++ /dev/null @@ -1,399 +0,0 @@ -(include "rtspserver-types.defs") - -;; From gst/rtsp-server/rtsp-server.h - -(define-function rtsp_server_new - (c-name "gst_rtsp_server_new") - (is-constructor-of "GstRTSPServer") - (return-type "GstRTSPServer*") -) - -(define-method set_address - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_set_address") - (parameters - '("const-gchar*" "address") - ) -) - -(define-method get_address - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_get_address") - (return-type "const-gchar*") -) - -(define-method set_service - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_set_service") - (parameters - '("const-gchar*" "service") - ) -) - -(define-method get_service - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_get_service") - (return-type "const-gchar*") -) - -(define-method set_backlog - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_set_backlog") - (parameters - '("gint" "backlog") - ) -) - -(define-method get_backlog - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_get_backlog") - (return-type "gint") -) - -(define-method set_session_pool - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_set_session_pool") - (parameters - '("GstRTSPSessionPool*" "pool") - ) -) - -(define-method get_session_pool - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_get_session_pool") - (return-type "GstRTSPSessionPool*") -) - -(define-method set_media_mapping - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_set_media_mapping") - (parameters - '("GstRTSPMediaMapping*" "mapping") - ) -) - -(define-method get_media_mapping - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_get_media_mapping") - (return-type "GstRTSPMediaMapping*") -) - -(define-function io_func - (c-name "gst_rtsp_server_io_func") - (return-type "gboolean") - (parameters - '("GIOChannel*" "channel") - '("GIOCondition" "condition") - '("GstRTSPServer*" "server") - ) -) - -(define-method get_io_channel - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_get_io_channel") - (return-type "GIOChannel*") -) - -(define-method attach - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_attach") - (return-type "guint") - (parameters - '("GMainContext*" "context") - ) -) - -(define-method create_watch - (of-object "GstRTSPServer") - (c-name "gst_rtsp_server_create_watch") - (return-type "GSource*") -) - -;; From gst/rtsp-server/rtsp-media-mapping.h - -(define-function rtsp_media_mapping_new - (c-name "gst_rtsp_media_mapping_new") - (is-constructor-of "GstRTSPMediaMapping") - (return-type "GstRTSPMediaMapping*") -) - - -;; TODO define const-GstRTSPUrl* on arg-types.py -(define-method find_factory - (of-object "GstRTSPMediaMapping") - (c-name "gst_rtsp_media_mapping_find_factory") - (return-type "GstRTSPMediaFactory*") - (parameters - '("const-GstRTSPUrl*" "url") - ) -) - -(define-method add_factory - (of-object "GstRTSPMediaMapping") - (c-name "gst_rtsp_media_mapping_add_factory") - (parameters - '("const-gchar*" "path") - '("GstRTSPMediaFactory*" "factory") - ) -) - -(define-method remove_factory - (of-object "GstRTSPMediaMapping") - (c-name "gst_rtsp_media_mapping_remove_factory") - (parameters - '("const-gchar*" "path") - ) -) - -;; From gst/rtsp-server/rtsp-media-factory.h - -(define-function rtsp_media_factory_new - (c-name "gst_rtsp_media_factory_new") - (is-constructor-of "GstRTSMediaFactory") - (return-type "GstRTSPMediaFactory*") -) - -(define-method set_launch - (of-object "GstRTSPMediaFactory") - (c-name "gst_rtsp_media_factory_set_launch") - (parameters - '("gchar*" "launch") - ) -) - -(define-method get_launch - (of-object "GstRTSPMediaFactory") - (c-name "gst_rtsp_media_factory_get_launch") - (return-type "gchar*") -) - -(define-method set_shared - (of-object "GstRTSPMediaFactory") - (c-name "gst_rtsp_media_factory_set_shared") - (parameters - '("gboolean" "shared") - ) -) - -(define-method is_shared - (of-object "GstRTSPMediaFactory") - (c-name "gst_rtsp_media_factory_is_shared") - (return-type "gboolean") -) - -(define-method set_eos_shutdown - (of-object "GstRTSPMediaFactory") - (c-name "gst_rtsp_media_factory_set_eos_shutdown") - (parameters - '("gboolean" "eos_shutdown") - ) -) - -(define-method is_eos_shutdown - (of-object "GstRTSPMediaFactory") - (c-name "gst_rtsp_media_factory_is_eos_shutdown") - (return-type "gboolean") -) - -;; TODO define const-GstRTSPUrl* on arg-types.py -(define-method construct - (of-object "GstRTSPMediaFactory") - (c-name "gst_rtsp_media_factory_construct") - (return-type "GstRTSPMedia*") - (parameters - '("const-GstRTSPUrl*" "url") - ) -) - -(define-method collect_streams - (of-object "GstRTSPMediaFactory") - (c-name "gst_rtsp_media_factory_collect_streams") - (parameters - '("const-GstRTSPUrl*" "url") - '("GstRTSPMedia*" "media") - ) -) - -(define-virtual get_element - (of-object "GstRTSPMediaFactory") - (parameters - '("const-GstRTSPUrl*" "url") - ) - (return-type "GstElement*") -) - - -(define-virtual construct - (of-object "GstRTSPMediaFactory") - (parameters - '("const-GstRTSPUrl*" "url") - ) - (return-type "GstRTSPMedia*") -) - - -(define-virtual configure - (of-object "GstRTSPMediaFactory") - (parameters - '("GstRTSPMedia*" "media") - ) - (return-type "none") -) - - -(define-virtual create_pipeline - (of-object "GstRTSPMediaFactory") - (parameters - '("GstRTSPMedia*" "media") - ) - (return-type "GstElement*") -) - - -;; From gst/rtsp-server/rtsp-session-pool.h - -(define-function gst_rtsp_session_pool_new - (c-name "gst_rtsp_session_pool_new") - (is-constructor-of "GstRTSPSessionPool") - (return-type "GstRTSPSessionPool*") -) - -(define-method set_max_sessions - (of-object "GstRTSPSessionPool") - (c-name "gst_rtsp_session_pool_set_max_sessions") - (return-type "none") - (parameters - '("guint" "max") - ) -) - -(define-method get_max_sessions - (of-object "GstRTSPSessionPool") - (c-name "gst_rtsp_session_pool_get_max_sessions") - (return-type "guint") -) - -(define-method get_n_sessions - (of-object "GstRTSPSessionPool") - (c-name "gst_rtsp_session_pool_get_n_sessions") - (return-type "guint") -) - -(define-method create - (of-object "GstRTSPSessionPool") - (c-name "gst_rtsp_session_pool_create") - (return-type "GstRTSPSession*") -) - -(define-method find - (of-object "GstRTSPSessionPool") - (c-name "gst_rtsp_session_pool_find") - (return-type "GstRTSPSession*") - (parameters - '("const-gchar*" "sessionid") - ) -) - -(define-method remove - (of-object "GstRTSPSessionPool") - (c-name "gst_rtsp_session_pool_remove") - (return-type "gboolean") - (parameters - '("GstRTSPSession*" "sess") - ) -) - -(define-method filter - (of-object "GstRTSPSessionPool") - (c-name "gst_rtsp_session_pool_filter") - (return-type "GList*") - (parameters - '("GstRTSPSessionFilterFunc" "func") - '("gpointer" "user_data") - ) -) - -(define-method cleanup - (of-object "GstRTSPSessionPool") - (c-name "gst_rtsp_session_pool_cleanup") - (return-type "guint") -) - -(define-method create_watch - (of-object "GstRTSPSessionPool") - (c-name "gst_rtsp_session_pool_create_watch") - (return-type "GSource*") -) - -;; From gst/rtsp-server/rtsp-client.h - -(define-function gst_rtsp_client_new - (c-name "gst_rtsp_client_new") - (is-constructor-of "GstRTSPClient") - (return-type "GstRTSPClient*") -) - -(define-method set_session_pool - (of-object "GstRTSPClient") - (c-name "gst_rtsp_client_set_session_pool") - (return-type "none") - (parameters - '("GstRTSPSessionPool*" "pool") - ) -) - -(define-method get_session_pool - (of-object "GstRTSPClient") - (c-name "gst_rtsp_client_get_session_pool") - (return-type "GstRTSPSessionPool*") -) - -(define-method set_media_mapping - (of-object "GstRTSPClient") - (c-name "gst_rtsp_client_set_media_mapping") - (return-type "none") - (parameters - '("GstRTSPMediaMapping*" "mapping") - ) -) - -(define-method get_media_mapping - (of-object "GstRTSPClient") - (c-name "gst_rtsp_client_get_media_mapping") - (return-type "GstRTSPMediaMapping*") -) - -(define-method accept - (of-object "GstRTSPClient") - (c-name "gst_rtsp_client_accept") - (return-type "gboolean") - (parameters - '("GIOChannel*" "channel") - ) -) - -;; From bindings/python/rtsp-params.h - -(define-function gst_rtsp_params_set - (c-name "gst_rtsp_params_set") - (return-type "GstRTSPResult") - (parameters - '("GstRTSPClient*" "client") - '("GstRTSPUrl*" "uri") - '("GstRTSPSession*" "session") - '("GstRTSPMessage*" "request") - '("GstRTSPMessage*" "response") - ) -) - -(define-function gst_rtsp_params_get - (c-name "gst_rtsp_params_get") - (return-type "GstRTSPResult") - (parameters - '("GstRTSPClient*" "client") - '("GstRTSPUrl*" "uri") - '("GstRTSPSession*" "session") - '("GstRTSPMessage*" "request") - '("GstRTSPMessage*" "response") - ) -) diff --git a/bindings/python/rtspserver.override b/bindings/python/rtspserver.override deleted file mode 100644 index 2fd69a718a..0000000000 --- a/bindings/python/rtspserver.override +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- */ -%% -headers -/* include any required headers here */ -#define NO_IMPORT_PYGOBJECT -#include - -#include -#include - -#include - -#ifdef HAVE_CONFIG_H -# include -#endif - -/* Boonky define that allows for backwards compatibility with Python 2.4 */ -#if PY_VERSION_HEX < 0x02050000 -#define Py_ssize_t int -#endif - -#include - -typedef struct { - PyObject_HEAD - GMainContext *context; -} PyGMainContext; - -%% -import gobject.GObject as PyGObject_Type -import gobject.MainContext as PyGMainContext_Type -%% -override gst_rtsp_server_attach kwargs -static PyObject * -_wrap_gst_rtsp_server_attach (PyGObject *self, - PyObject *args, PyObject *keywords) -{ - static char *kwlist[] = {"context", NULL}; - PyGMainContext *py_context = NULL; - GMainContext *context = NULL; - guint res; - - if (!PyArg_ParseTupleAndKeywords (args, keywords, - "|O!:GstRTSPServer.__init__", kwlist, - &PyGMainContext_Type, &py_context)) - return NULL; - - if (py_context) - context = py_context->context; - - pyg_begin_allow_threads; - res = gst_rtsp_server_attach (GST_RTSP_SERVER (self->obj), context); - pyg_end_allow_threads; - - return PyLong_FromLong (res); -} -%% -override gst_rtsp_server_create_watch kwargs -static PyObject * -_wrap_gst_rtsp_server_create_watch(PyGObject *self, PyObject *args, PyObject *keywords) -{ - GSource *ret; - pyg_begin_allow_threads; - ret = gst_rtsp_server_create_watch(GST_RTSP_SERVER(self->obj)); - pyg_end_allow_threads; - return pygobject_new((GObject *)ret); -} - -%% -override gst_rtsp_media_mapping_add_factory kwargs -static PyObject * -_wrap_gst_rtsp_media_mapping_add_factory(PyGObject *self, PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = { "path", "factory", NULL }; - char *path; - PyGObject *factory; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs,"sO!:GstRTSPMediaMapping.add_factory", kwlist, &path, &PyGstRTSPMediaFactory_Type, &factory)) - return NULL; - pyg_begin_allow_threads; - gst_rtsp_media_mapping_add_factory(GST_RTSP_MEDIA_MAPPING(self->obj), path, - g_object_ref (GST_RTSP_MEDIA_FACTORY(factory->obj))); - pyg_end_allow_threads; - Py_INCREF(Py_None); - return Py_None; -} - diff --git a/bindings/python/rtspservermodule.c b/bindings/python/rtspservermodule.c deleted file mode 100644 index e5e7d56e67..0000000000 --- a/bindings/python/rtspservermodule.c +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include -#include - -/* include any extra headers needed here */ - -void pygst_rtsp_server_register_classes(PyObject *d); -extern PyMethodDef pygst_rtsp_server_functions[]; - -DL_EXPORT(void) -initrtspserver(void) -{ - PyObject *m, *d; - - /* perform any initialisation required by the library here */ - - m = Py_InitModule("rtspserver", pygst_rtsp_server_functions); - d = PyModule_GetDict(m); - - init_pygobject(); - - pygst_rtsp_server_register_classes(d); - - /* add anything else to the module dictionary (such as constants) */ - - if (PyErr_Occurred()) - Py_FatalError("could not initialise module rtspserver"); -} diff --git a/bindings/python/test.py b/bindings/python/test.py deleted file mode 100644 index 3278faa058..0000000000 --- a/bindings/python/test.py +++ /dev/null @@ -1,130 +0,0 @@ -import unittest -import rtspserver - - -def pubdir(obj): - return [d for d in dir(obj) if not d.startswith('_')] - -#print 'Module listing:', pubdir(rtspserver) - -from rtspserver import Server, SessionPool, Session, MediaMapping, MediaFactory - -#print 'Server listing: ', pubdir(Server) -#print 'MediaMapping listing: ', pubdir(MediaMapping) -#print 'MediaFactory listing: ', pubdir(MediaFactory) -#print 'SessionPool listing: ', pubdir(SessionPool) -#print 'Session listing: ', pubdir(Session) - - -class ServerTestCase(unittest.TestCase): - - def setUp(self): - self.server = Server() - - def tearDown(self): - del self.server - - def test_address(self): - """ Server address set/get """ - addr = '1.2.3.4' - self.server.set_address(addr) - self.assertEquals(addr, self.server.get_address()) - - def test_service(self): - """ Server service set/get """ - service = '12345' - self.server.set_service(service) - self.assertEquals(service, self.server.get_service()) - - def test_backlog(self): - """ Server backlog set/get """ - backlog = 1234 - self.server.set_backlog(backlog) - self.assertEquals(backlog, self.server.get_backlog()) - - def test_session_pool(self): - """ Server session pool set/get """ - pool = SessionPool() - self.server.set_session_pool(pool) - self.assertEquals(pool, self.server.get_session_pool()) - - def test_media_mapping(self): - """ Server media mapping set/get """ - mmap = MediaMapping() - self.server.set_media_mapping(mmap) - self.assertEquals(mmap, self.server.get_media_mapping()) - - -class MediaMappingTestCase(unittest.TestCase): - - def setUp(self): - self.mmap = MediaMapping() - - def tearDown(self): - del self.mmap - - def test_factory(self): - """ MediaMapping factory add/remove """ - self.factory = MediaFactory() - self.mmap.add_factory("/test", self.factory) - self.mmap.remove_factory("/test") - - -class MediaFactoryTestCase(unittest.TestCase): - - def setUp(self): - self.factory = MediaFactory() - - def tearDown(self): - del self.factory - - def test_launch(self): - """ MediaFactory launch set/get """ - launch = "videotestsrc ! xvimagesink" - self.factory.set_launch(launch) - self.assertEquals(launch, self.factory.get_launch()) - - def test_shared(self): - """ MediaFactory shared set/is """ - self.factory.set_shared(True) - self.assert_(self.factory.is_shared()) - self.factory.set_shared(False) - self.assert_(not self.factory.is_shared()) - - def test_eos_shutdown(self): - """ MediaFactory eos_shutdown set/is """ - self.factory.set_eos_shutdown(True) - self.assert_(self.factory.is_eos_shutdown()) - self.factory.set_eos_shutdown(False) - self.assert_(not self.factory.is_eos_shutdown()) - - - -def alltests(): - tests = [] - - for p in dir(ServerTestCase): - try: - if 'test_' in p: - tests.append(ServerTestCase(p)) - except: - pass - - for p in dir(MediaMappingTestCase): - try: - if 'test_' in p: - tests.append(MediaMappingTestCase(p)) - except: - pass - - for p in dir(MediaFactoryTestCase): - try: - if 'test_' in p: - tests.append(MediaFactoryTestCase(p)) - except: - pass - - return unittest.TestSuite(tests) - - -unittest.TextTestRunner(verbosity=2).run(alltests()) diff --git a/configure.ac b/configure.ac index 610d1e3846..3ced3eb732 100644 --- a/configure.ac +++ b/configure.ac @@ -90,54 +90,6 @@ dnl check for documentation tools AG_GST_DOCBOOK_CHECK GTK_DOC_CHECK([1.3]) -dnl check for python -AM_PATH_PYTHON -AC_MSG_CHECKING(for python >= 2.3) -prog=" -import sys, string -minver = (2,3,0,'final',0) -if sys.version_info < minver: - sys.exit(1) -sys.exit(0)" - -if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC -then - HAVE_PYTHON=yes - AC_MSG_RESULT(okay) -else - HAVE_PYTHON=no - AC_MSG_RESULT(no python) -fi - -AM_CHECK_PYTHON_HEADERS([HAVE_PYTHON_HEADERS=yes],[HAVE_PYTHON_HEADERS=no]) - -dnl check for pygobject (optional, used in the bindings) -PYGOBJECT_REQ=2.11.2 -PKG_CHECK_MODULES(PYGOBJECT, pygobject-2.0 >= $PYGOBJECT_REQ, - [HAVE_PYGOBJECT="yes"], [HAVE_PYGOBJECT="no"]) -AC_SUBST(PYGOBJECT_CFLAGS) - -dnl check for gst-python -PKG_CHECK_MODULES(PYGST, gst-python-0.10, - [HAVE_PYGST="yes"], [HAVE_PYGST="no"]) - -if test "x$HAVE_PYGST" = "xyes"; then - PYGST_DEFSDIR=`pkg-config gst-python-0.10 --variable=defsdir` -fi -AC_SUBST(PYGST_DEFSDIR, $PYGST_DEFSDIR) - -if test \ - "x$HAVE_PYTHON" = "xyes" -a \ - "x$HAVE_PYTHON_HEADERS" = "xyes" -a \ - "x$HAVE_PYGOBJECT" = "xyes" -a \ - "x$HAVE_PYGST" = "xyes"; then - HAVE_PYTHON_BINDINGS="yes" -else - HAVE_PYTHON_BINDINGS="no" -fi - -AM_CONDITIONAL(WITH_PYTHON, [test "x$HAVE_PYTHON_BINDINGS" = "xyes"]) - dnl Check for Vala AC_ARG_ENABLE([vala], AC_HELP_STRING([--enable-vala],[enable Vala bindings (default=yes)]), @@ -288,8 +240,6 @@ gst/rtsp-server/Makefile examples/Makefile tests/Makefile bindings/Makefile -bindings/python/Makefile -bindings/python/codegen/Makefile bindings/vala/Makefile pkgconfig/Makefile pkgconfig/gst-rtsp-server.pc @@ -308,7 +258,6 @@ Configuration Prefix : ${prefix} Compiler : ${CC} Vala bindings : ${enable_vala} - Python bindings: : ${HAVE_PYTHON_BINDINGS} Gst-rtsp-server configured. Type 'make' to build. " From e67a1c664c4d9d6e6c1dad2ceb7d9a9a27b41bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 13 Feb 2012 11:06:33 +0000 Subject: [PATCH 0378/1776] rtsp-client: update for new map API --- gst/rtsp-server/rtsp-client.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 393884e546..6f17918054 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -400,22 +400,23 @@ static gboolean do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) { GstRTSPMessage message = { 0 }; + GstMapInfo map_info; guint8 *data; guint usize; - gsize size; gst_rtsp_message_init_data (&message, channel); - data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ); - usize = size; - gst_rtsp_message_take_body (&message, data, usize); + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) + return FALSE; + + gst_rtsp_message_take_body (&message, map_info.data, map_info.size); /* FIXME, client->watch could have been finalized here, we need to keep an * extra refcount to the watch. */ gst_rtsp_watch_send_message (client->watch, &message, NULL); gst_rtsp_message_steal_body (&message, &data, &usize); - gst_buffer_unmap (buffer, data, size); + gst_buffer_unmap (buffer, &map_info); gst_rtsp_message_unset (&message); From 3173fee92beccef2308a1e54d8cb004bbeb7a122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 13 Feb 2012 11:40:44 +0000 Subject: [PATCH 0379/1776] pkg-config: rename gst-rtsp-server-0.11.pc to gstreamer-rtsp-server-0.11.pc For consistency with all other modules. --- configure.ac | 4 ++-- pkgconfig/Makefile.am | 8 ++++---- ...lled.pc.in => gstreamer-rtsp-server-uninstalled.pc.in} | 0 ...{gst-rtsp-server.pc.in => gstreamer-rtsp-server.pc.in} | 0 4 files changed, 6 insertions(+), 6 deletions(-) rename pkgconfig/{gst-rtsp-server-uninstalled.pc.in => gstreamer-rtsp-server-uninstalled.pc.in} (100%) rename pkgconfig/{gst-rtsp-server.pc.in => gstreamer-rtsp-server.pc.in} (100%) diff --git a/configure.ac b/configure.ac index 3ced3eb732..65aebe7805 100644 --- a/configure.ac +++ b/configure.ac @@ -242,8 +242,8 @@ tests/Makefile bindings/Makefile bindings/vala/Makefile pkgconfig/Makefile -pkgconfig/gst-rtsp-server.pc -pkgconfig/gst-rtsp-server-uninstalled.pc +pkgconfig/gstreamer-rtsp-server.pc +pkgconfig/gstreamer-rtsp-server-uninstalled.pc docs/Makefile docs/version.entities docs/libs/Makefile diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am index 8d38e35bb3..54f82ac654 100644 --- a/pkgconfig/Makefile.am +++ b/pkgconfig/Makefile.am @@ -1,8 +1,8 @@ pcfiles = \ - gst-rtsp-server-@GST_MAJORMINOR@.pc + gstreamer-rtsp-server-@GST_MAJORMINOR@.pc pcfiles_uninstalled = \ - gst-rtsp-server-@GST_MAJORMINOR@-uninstalled.pc + gstreamer-rtsp-server-@GST_MAJORMINOR@-uninstalled.pc all-local: $(pcfiles) $(pcfiles_uninstalled) @@ -16,6 +16,6 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pcfiles) EXTRA_DIST = \ - gst-rtsp-server.pc.in \ - gst-rtsp-server-uninstalled.pc.in + gstreamer-rtsp-server.pc.in \ + gstreamer-rtsp-server-uninstalled.pc.in CLEANFILES = $(pcfiles) $(pcfiles_uninstalled) diff --git a/pkgconfig/gst-rtsp-server-uninstalled.pc.in b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in similarity index 100% rename from pkgconfig/gst-rtsp-server-uninstalled.pc.in rename to pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in diff --git a/pkgconfig/gst-rtsp-server.pc.in b/pkgconfig/gstreamer-rtsp-server.pc.in similarity index 100% rename from pkgconfig/gst-rtsp-server.pc.in rename to pkgconfig/gstreamer-rtsp-server.pc.in From 449bc0dffb78b62c4525a99b524717e0637da7a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 13 Feb 2012 11:42:51 +0000 Subject: [PATCH 0380/1776] First rule of gst-rtsp-server club: don't talk about gst-phonon --- configure.ac | 8 ++++---- examples/Makefile.am | 9 +++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 65aebe7805..d0cf04b746 100644 --- a/configure.ac +++ b/configure.ac @@ -203,7 +203,7 @@ dnl vars common to for all internal objects (core libs, elements, applications) dnl CFLAGS: dnl - src and build dirs need to be added because every piece that gets built dnl will need the GStreamer source and generated headers -GST_ALL_CFLAGS="-I\$(top_srcdir) -I\$(top_builddir) $GST_CFLAGS \$(GST_OPTION_CFLAGS)" +GST_ALL_CFLAGS="-I\$(top_srcdir) -I\$(top_builddir) $GST_PLUGINS_BASE_CFLAGS $GST_CFLAGS \$(GST_OPTION_CFLAGS)" AC_SUBST([GST_ALL_CFLAGS]) dnl FIXME: check if LTLIBINTL is needed everywhere @@ -217,11 +217,11 @@ GST_ALL_LDFLAGS="-no-undefined" AC_SUBST(GST_ALL_LDFLAGS) dnl GST_OBJ_* -dnl default vars for all internal objects built on libgstphonon +dnl default vars for all internal objects built on libgstrtspserver dnl includes GST_ALL_* GST_OBJ_CFLAGS="\$(GST_ALL_CFLAGS)" AC_SUBST([GST_OBJ_CFLAGS]) -GST_OBJ_LIBS="\$(top_builddir)/gst-phonon/libgstphonon.la \$(GST_ALL_LIBS)" +GST_OBJ_LIBS="\$(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_MAJORMINOR@.la \$(GST_ALL_LIBS)" AC_SUBST([GST_OBJ_LIBS]) dnl this really should only contain flags, not libs - they get added before @@ -259,5 +259,5 @@ Configuration Compiler : ${CC} Vala bindings : ${enable_vala} -Gst-rtsp-server configured. Type 'make' to build. +gst-rtsp-server configured. Type 'make' to build. " diff --git a/examples/Makefile.am b/examples/Makefile.am index 92f6cf4ce8..9c643050ad 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,9 +1,6 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp test-uri test-auth -INCLUDES = -I$(top_srcdir) -I$(srcdir) - -AM_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) -AM_LDFLAGS = \ - $(GST_LIBS) \ - $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_MAJORMINOR@.la +#INCLUDES = -I$(top_srcdir) -I$(srcdir) +AM_CFLAGS = $(GST_OBJ_CFLAGS) +AM_LDFLAGS = $(GST_OBJ_LIBS) From 3c768123b4d60618e1197b902de956cb251dbfb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 29 Feb 2012 15:56:06 +0000 Subject: [PATCH 0381/1776] docs: fix for gst_rtsp_server_set_port() -> _set_service() https://bugzilla.gnome.org/show_bug.cgi?id=666548 --- docs/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README b/docs/README index 5b223b6340..e1ece70d82 100644 --- a/docs/README +++ b/docs/README @@ -58,7 +58,7 @@ can build simple server applications with it. server = gst_rtsp_server_new (); The server will by default listen on port 8554 for new connections. This can be - changed by calling gst_rtsp_server_set_port() or with the 'port' GObject + changed by calling gst_rtsp_server_set_service() or with the 'service' GObject property. This makes it possible to run multiple server instances listening on multiple ports on one machine. From f5c6572bbcdc6132c69bb2c340bd0337cf6d0822 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 7 Mar 2012 15:03:24 +0100 Subject: [PATCH 0382/1776] configure: fix build --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d0cf04b746..85c013a971 100644 --- a/configure.ac +++ b/configure.ac @@ -221,7 +221,7 @@ dnl default vars for all internal objects built on libgstrtspserver dnl includes GST_ALL_* GST_OBJ_CFLAGS="\$(GST_ALL_CFLAGS)" AC_SUBST([GST_OBJ_CFLAGS]) -GST_OBJ_LIBS="\$(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_MAJORMINOR@.la \$(GST_ALL_LIBS)" +GST_OBJ_LIBS="\$(top_builddir)/gst/rtsp-server/libgstrtspserver-$GST_MAJORMINOR.la \$(GST_ALL_LIBS)" AC_SUBST([GST_OBJ_LIBS]) dnl this really should only contain flags, not libs - they get added before From 4c59e211e2ed604f8bbcec18955833b002757982 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 7 Mar 2012 15:03:55 +0100 Subject: [PATCH 0383/1776] rtsp-server: port to GIO Port to GIO --- gst/rtsp-server/rtsp-client.c | 40 ++-- gst/rtsp-server/rtsp-client.h | 4 +- gst/rtsp-server/rtsp-media-factory-uri.c | 2 +- gst/rtsp-server/rtsp-media.c | 15 +- gst/rtsp-server/rtsp-server.c | 226 ++++++++++++----------- gst/rtsp-server/rtsp-server.h | 16 +- gst/rtsp-server/rtsp-session-pool.c | 2 +- 7 files changed, 168 insertions(+), 137 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6f17918054..f814c5164a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1435,7 +1435,7 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) buffer = gst_buffer_new (); gst_buffer_take_memory (buffer, -1, - gst_memory_new_wrapped (0, data, g_free, size, 0, size)); + gst_memory_new_wrapped (0, data, size, 0, size, data, g_free)); handled = FALSE; for (walk = client->streams; walk; walk = g_list_next (walk)) { @@ -1890,9 +1890,11 @@ client_watch_notify (GstRTSPClient * client) /** * gst_rtsp_client_attach: * @client: a #GstRTSPClient - * @channel: a #GIOChannel + * @socket: a #GSocket + * @cancellable: a #GCancellable + * @error: a #GError * - * Accept a new connection for @client on the socket in @channel. + * Accept a new connection for @client on @socket. * * This function should be called when the client properties and urls are fully * configured and the client is ready to start. @@ -1900,11 +1902,13 @@ client_watch_notify (GstRTSPClient * client) * Returns: %TRUE if the client could be accepted. */ gboolean -gst_rtsp_client_accept (GstRTSPClient * client, GIOChannel * channel) +gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, + GCancellable * cancellable, GError ** error) { - int sock, fd; GstRTSPConnection *conn; GstRTSPResult res; + GSocket *read_socket; + GSocketAddress *addres; GSource *source; GMainContext *context; GstRTSPUrl *url; @@ -1913,17 +1917,18 @@ gst_rtsp_client_accept (GstRTSPClient * client, GIOChannel * channel) gchar ip[INET6_ADDRSTRLEN]; /* a new client connected. */ - sock = g_io_channel_unix_get_fd (channel); + GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, cancellable), + accept_failed); - GST_RTSP_CHECK (gst_rtsp_connection_accept (sock, &conn), accept_failed); + read_socket = gst_rtsp_connection_get_read_socket (conn); + client->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6; - fd = gst_rtsp_connection_get_readfd (conn); + if (!(addres = g_socket_get_remote_address (read_socket, error))) + goto no_address; addrlen = sizeof (addr); - if (getsockname (fd, (struct sockaddr *) &addr, &addrlen) < 0) - goto getpeername_failed; - - client->is_ipv6 = addr.ss_family == AF_INET6; + if (!g_socket_address_to_native (addres, &addr, addrlen, error)) + goto native_failed; if (getnameinfo ((struct sockaddr *) &addr, addrlen, ip, sizeof (ip), NULL, 0, NI_NUMERICHOST) != 0) @@ -1963,13 +1968,18 @@ accept_failed: { gchar *str = gst_rtsp_strresult (res); - GST_ERROR ("Could not accept client on server socket %d: %s", sock, str); + GST_ERROR ("Could not accept client on server socket %p: %s", socket, str); g_free (str); return FALSE; } -getpeername_failed: +no_address: { - GST_ERROR ("getpeername failed: %s", g_strerror (errno)); + GST_ERROR ("could not get remote address %s", (*error)->message); + return FALSE; + } +native_failed: + { + GST_ERROR ("could not get native address %s", (*error)->message); return FALSE; } getnameinfo_failed: diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index dc2c79c088..bc56cc7c55 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -132,7 +132,9 @@ GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); gboolean gst_rtsp_client_accept (GstRTSPClient *client, - GIOChannel *channel); + GSocket *socket, + GCancellable *cancellable, + GError **error); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 2f32d2b418..5e86ee331f 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -166,7 +166,7 @@ gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory) factory->use_gstpay = DEFAULT_USE_GSTPAY; /* get the feature list using the filter */ - gst_default_registry_feature_filter ((GstPluginFeatureFilter) + gst_registry_feature_filter (gst_registry_get (), (GstPluginFeatureFilter) payloader_filter, FALSE, &data); /* sort */ factory->demuxers = diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 028407e18d..ba6b77df9e 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -851,7 +851,8 @@ alloc_udp_ports (GstRTSPMedia * media, GstRTSPMediaStream * stream) GstElement *udpsink0, *udpsink1; gint tmp_rtp, tmp_rtcp; guint count; - gint rtpport, rtcpport, sockfd; + gint rtpport, rtcpport; + GSocket *socket; const gchar *host; udpsrc0 = NULL; @@ -944,9 +945,9 @@ again: if (!udpsink0) goto no_udp_protocol; - g_object_get (G_OBJECT (udpsrc0), "sock", &sockfd, NULL); - g_object_set (G_OBJECT (udpsink0), "sockfd", sockfd, NULL); - g_object_set (G_OBJECT (udpsink0), "closefd", FALSE, NULL); + g_object_get (G_OBJECT (udpsrc0), "socket", &socket, NULL); + g_object_set (G_OBJECT (udpsink0), "socket", socket, NULL); + g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL); udpsink1 = gst_element_factory_make ("multiudpsink", NULL); if (!udpsink1) @@ -968,9 +969,9 @@ again: GST_WARNING ("multiudpsink version found without buffer-size property"); } - g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL); - g_object_set (G_OBJECT (udpsink1), "sockfd", sockfd, NULL); - g_object_set (G_OBJECT (udpsink1), "closefd", FALSE, NULL); + g_object_get (G_OBJECT (udpsrc1), "socket", &socket, NULL); + g_object_set (G_OBJECT (udpsink1), "socket", socket, NULL); + g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index f1f431ffe4..6cef1967a8 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -78,7 +78,7 @@ static void gst_rtsp_server_finalize (GObject * object); static GstRTSPClient *default_create_client (GstRTSPServer * server); static gboolean default_accept_client (GstRTSPServer * server, - GstRTSPClient * client, GIOChannel * channel); + GstRTSPClient * client, GSocket * socket, GError ** error); static void gst_rtsp_server_class_init (GstRTSPServerClass * klass) @@ -546,87 +546,94 @@ gst_rtsp_server_set_property (GObject * object, guint propid, } /** - * gst_rtsp_server_get_io_channel: + * gst_rtsp_server_create_socket: * @server: a #GstRTSPServer + * @cancellable: a #GCancellable + * @error: a #GError * - * Create a #GIOChannel for @server. The io channel will listen on the + * Create a #GSocket for @server. The socket will listen on the * configured service. * - * Returns: the GIOChannel for @server or NULL when an error occured. + * Returns: the #GSocket for @server or NULL when an error occured. */ -GIOChannel * -gst_rtsp_server_get_io_channel (GstRTSPServer * server) +GSocket * +gst_rtsp_server_create_socket (GstRTSPServer * server, + GCancellable * cancellable, GError ** error) { - GIOChannel *channel; - int ret, sockfd = -1; - struct addrinfo hints; - struct addrinfo *result, *rp; + GSocketConnectable *conn; + GSocketAddressEnumerator *enumerator; + GSocket *socket; #ifdef USE_SOLINGER struct linger linger; #endif + GError *sock_error = NULL; + GError *bind_error = NULL; + guint16 port; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - memset (&hints, 0, sizeof (struct addrinfo)); - hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ - hints.ai_socktype = SOCK_STREAM; /* stream socket */ - hints.ai_flags = AI_PASSIVE | AI_CANONNAME; /* For wildcard IP address */ - hints.ai_protocol = 0; /* Any protocol */ - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; - + GST_RTSP_SERVER_LOCK (server); GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address, server->service); - GST_RTSP_SERVER_LOCK (server); /* resolve the server IP address */ - if ((ret = - getaddrinfo (server->address, server->service, &hints, &result)) != 0) - goto no_address; + port = atoi (server->service); + if (port != 0) + conn = g_network_address_new (server->address, port); + else + conn = g_network_service_new (server->service, "tcp", server->address); + + enumerator = g_socket_connectable_enumerate (conn); + g_object_unref (conn); /* create server socket, we loop through all the addresses until we manage to * create a socket and bind. */ - for (rp = result; rp; rp = rp->ai_next) { - sockfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if (sockfd == -1) { + while (TRUE) { + GSocketAddress *sockaddr; + + sockaddr = + g_socket_address_enumerator_next (enumerator, cancellable, error); + if (!sockaddr) { + GST_DEBUG_OBJECT (server, "no more addresses %s", (*error)->message); + break; + } + + /* only keep the first error */ + socket = g_socket_new (g_socket_address_get_family (sockaddr), + G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, + sock_error ? NULL : &sock_error); + + if (socket == NULL) { GST_DEBUG_OBJECT (server, "failed to make socket (%s), try next", - g_strerror (errno)); + sock_error->message); continue; } - /* make address reusable */ - ret = 1; - if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, - (void *) &ret, sizeof (ret)) < 0) { - /* warn but try to bind anyway */ - GST_WARNING_OBJECT (server, "failed to reuse socker (%s)", - g_strerror (errno)); - } - - if (bind (sockfd, rp->ai_addr, rp->ai_addrlen) == 0) { - GST_DEBUG_OBJECT (server, "bind on %s", rp->ai_canonname); + if (g_socket_bind (socket, sockaddr, TRUE, bind_error ? NULL : &bind_error)) { + g_object_unref (sockaddr); break; } GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next", - g_strerror (errno)); - close (sockfd); - sockfd = -1; + bind_error->message); + g_object_unref (sockaddr); + g_object_unref (socket); + socket = NULL; } - freeaddrinfo (result); + g_object_unref (enumerator); - if (sockfd == -1) + if (socket == NULL) goto no_socket; - GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d", sockfd); + g_clear_error (&sock_error); + g_clear_error (&bind_error); + + GST_DEBUG_OBJECT (server, "opened sending server socket"); /* keep connection alive; avoids SIGPIPE during write */ - ret = 1; - if (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE, - (void *) &ret, sizeof (ret)) < 0) - goto keepalive_failed; + g_socket_set_keepalive (socket, TRUE); +#if 0 #ifdef USE_SOLINGER /* make sure socket is reset 5 seconds after close. This ensure that we can * reuse the socket quickly while still having a chance to send data to the @@ -636,51 +643,32 @@ gst_rtsp_server_get_io_channel (GstRTSPServer * server) if (setsockopt (sockfd, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof (linger)) < 0) goto linger_failed; +#endif #endif /* set the server socket to nonblocking */ - fcntl (sockfd, F_SETFL, O_NONBLOCK); + g_socket_set_blocking (socket, FALSE); - GST_DEBUG_OBJECT (server, "listening on server socket %d with queue of %d", - sockfd, server->backlog); - if (listen (sockfd, server->backlog) == -1) + /* set listen backlog */ + g_socket_set_listen_backlog (socket, server->backlog); + + if (!g_socket_listen (socket, error)) goto listen_failed; - GST_DEBUG_OBJECT (server, - "listened on server socket %d, returning from connection setup", sockfd); + GST_DEBUG_OBJECT (server, "listening on server socket %p with queue of %d", + socket, server->backlog); - /* create IO channel for the socket */ -#ifdef G_OS_WIN32 - channel = g_io_channel_win32_new_socket (sockfd); -#else - channel = g_io_channel_unix_new (sockfd); -#endif - g_io_channel_set_close_on_unref (channel, TRUE); - - GST_INFO_OBJECT (server, "listening on service %s", server->service); GST_RTSP_SERVER_UNLOCK (server); - return channel; + return socket; /* ERRORS */ -no_address: - { - GST_ERROR_OBJECT (server, "failed to resolve address: %s", - gai_strerror (ret)); - goto close_error; - } no_socket: { - GST_ERROR_OBJECT (server, "failed to create socket: %s", - g_strerror (errno)); - goto close_error; - } -keepalive_failed: - { - GST_ERROR_OBJECT (server, "failed to configure keepalive socket: %s", - g_strerror (errno)); + GST_ERROR_OBJECT (server, "failed to create socket"); goto close_error; } +#if 0 #ifdef USE_SOLINGER linger_failed: { @@ -689,16 +677,29 @@ linger_failed: goto close_error; } #endif +#endif listen_failed: { GST_ERROR_OBJECT (server, "failed to listen on socket: %s", - g_strerror (errno)); + (*error)->message); goto close_error; } close_error: { - if (sockfd >= 0) { - close (sockfd); + if (socket) + g_object_unref (socket); + + if (sock_error) { + if (error == NULL) + g_propagate_error (error, sock_error); + else + g_error_free (sock_error); + } + if (bind_error) { + if (error == NULL) + g_propagate_error (error, bind_error); + else + g_error_free (bind_error); } GST_RTSP_SERVER_UNLOCK (server); return NULL; @@ -759,12 +760,12 @@ default_create_client (GstRTSPServer * server) * handle a client connection on this server */ static gboolean default_accept_client (GstRTSPServer * server, GstRTSPClient * client, - GIOChannel * channel) + GSocket * socket, GError ** error) { /* accept connections for that client, this function returns after accepting * the connection and will run the remainder of the communication with the * client asyncronously. */ - if (!gst_rtsp_client_accept (client, channel)) + if (!gst_rtsp_client_accept (client, socket, NULL, error)) goto accept_failed; return TRUE; @@ -773,29 +774,29 @@ default_accept_client (GstRTSPServer * server, GstRTSPClient * client, accept_failed: { GST_ERROR_OBJECT (server, - "Could not accept client on server : %s (%d)", g_strerror (errno), - errno); + "Could not accept client on server : %s", (*error)->message); return FALSE; } } /** * gst_rtsp_server_io_func: - * @channel: a #GIOChannel + * @socket: a #GSocket * @condition: the condition on @source * - * A default #GIOFunc that creates a new #GstRTSPClient to accept and handle a - * new connection on @channel or @server. + * A default #GSocketSourceFunc that creates a new #GstRTSPClient to accept and handle a + * new connection on @socket or @server. * * Returns: TRUE if the source could be connected, FALSE if an error occured. */ gboolean -gst_rtsp_server_io_func (GIOChannel * channel, GIOCondition condition, +gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, GstRTSPServer * server) { gboolean result; GstRTSPClient *client = NULL; GstRTSPServerClass *klass; + GError *error = NULL; if (condition & G_IO_IN) { klass = GST_RTSP_SERVER_GET_CLASS (server); @@ -807,7 +808,7 @@ gst_rtsp_server_io_func (GIOChannel * channel, GIOCondition condition, /* a new client connected, create a client object to handle the client. */ if (klass->accept_client) - result = klass->accept_client (server, client, channel); + result = klass->accept_client (server, client, socket, &error); if (!result) goto accept_failed; @@ -829,7 +830,8 @@ client_failed: } accept_failed: { - GST_ERROR_OBJECT (server, "failed to accept client"); + GST_ERROR_OBJECT (server, "failed to accept client: %s", error->message); + g_error_free (error); gst_object_unref (client); return FALSE; } @@ -843,30 +845,39 @@ watch_destroyed (GstRTSPServer * server) } /** - * gst_rtsp_server_create_watch: + * gst_rtsp_server_create_source: * @server: a #GstRTSPServer + * @cancellable: a #GCancellable or %NULL. + * @error: a #GError * * Create a #GSource for @server. The new source will have a default - * #GIOFunc of gst_rtsp_server_io_func(). + * #GSocketSourceFunc of gst_rtsp_server_io_func(). * - * Returns: the #GSource for @server or NULL when an error occured. + * @cancellable if not NULL can be used to cancel the source, which will cause + * the source to trigger, reporting the current condition (which is likely 0 + * unless cancellation happened at the same time as a condition change). You can + * check for this in the callback using g_cancellable_is_cancelled(). + * + * Returns: the #GSource for @server or NULL when an error occured. Free with + * g_source_unref () */ GSource * -gst_rtsp_server_create_watch (GstRTSPServer * server) +gst_rtsp_server_create_source (GstRTSPServer * server, + GCancellable * cancellable, GError ** error) { - GIOChannel *channel; + GSocket *socket; GSource *source; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - channel = gst_rtsp_server_get_io_channel (server); - if (channel == NULL) - goto no_channel; + socket = gst_rtsp_server_create_socket (server, NULL, error); + if (socket == NULL) + goto no_socket; /* create a watch for reads (new connections) and possible errors */ - source = g_io_create_watch (channel, G_IO_IN | - G_IO_ERR | G_IO_HUP | G_IO_NVAL); - g_io_channel_unref (channel); + source = g_socket_create_source (socket, G_IO_IN | + G_IO_ERR | G_IO_HUP | G_IO_NVAL, cancellable); + g_object_unref (socket); /* configure the callback */ g_source_set_callback (source, @@ -875,9 +886,9 @@ gst_rtsp_server_create_watch (GstRTSPServer * server) return source; -no_channel: +no_socket: { - GST_ERROR_OBJECT (server, "failed to create IO channel"); + GST_ERROR_OBJECT (server, "failed to create socket"); return NULL; } } @@ -886,6 +897,7 @@ no_channel: * gst_rtsp_server_attach: * @server: a #GstRTSPServer * @context: a #GMainContext + * @error: a #GError * * Attaches @server to @context. When the mainloop for @context is run, the * server will be dispatched. When @context is NULL, the default context will be @@ -901,10 +913,11 @@ gst_rtsp_server_attach (GstRTSPServer * server, GMainContext * context) { guint res; GSource *source; + GError *error = NULL; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), 0); - source = gst_rtsp_server_create_watch (server); + source = gst_rtsp_server_create_source (server, NULL, &error); if (source == NULL) goto no_source; @@ -916,7 +929,8 @@ gst_rtsp_server_attach (GstRTSPServer * server, GMainContext * context) /* ERRORS */ no_source: { - GST_ERROR_OBJECT (server, "failed to create watch"); + GST_ERROR_OBJECT (server, "failed to create watch: %s", error->message); + g_error_free (error); return 0; } } diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 98a3391dad..dd6e386d1e 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -79,7 +79,7 @@ struct _GstRTSPServer { * GstRTSPServerClass: * * @create_client: Create, configure a new GstRTSPClient - * object that handles the new connection on @channel. + * object that handles the new connection on @socket. * @accept_client: accept a new GstRTSPClient * * The RTSP server class structure @@ -88,8 +88,8 @@ struct _GstRTSPServerClass { GObjectClass parent_class; GstRTSPClient * (*create_client) (GstRTSPServer *server); - gboolean (*accept_client) (GstRTSPServer *server, GstRTSPClient *client, GIOChannel *channel); - + gboolean (*accept_client) (GstRTSPServer *server, GstRTSPClient *client, + GSocket *socket, GError **error); /* signals */ void (*client_connected) (GstRTSPServer *server, GstRTSPClient *client); }; @@ -116,11 +116,15 @@ GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *serve void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server); -gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, +gboolean gst_rtsp_server_io_func (GSocket *socket, GIOCondition condition, GstRTSPServer *server); -GIOChannel * gst_rtsp_server_get_io_channel (GstRTSPServer *server); -GSource * gst_rtsp_server_create_watch (GstRTSPServer *server); +GSocket * gst_rtsp_server_create_socket (GstRTSPServer *server, + GCancellable *cancellable, + GError **error); +GSource * gst_rtsp_server_create_source (GstRTSPServer *server, + GCancellable * cancellable, + GError **error); guint gst_rtsp_server_attach (GstRTSPServer *server, GMainContext *context); diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index de9234edbe..1d00dc448d 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -477,7 +477,7 @@ collect_timeout (gchar * sessionid, GstRTSPSession * sess, GstPoolSource * psrc) gint timeout; GTimeVal now; - g_source_get_current_time ((GSource *) psrc, &now); + g_get_current_time (&now); timeout = gst_rtsp_session_next_timeout (sess, &now); GST_INFO ("%p: next timeout: %d", sess, timeout); From 377f6d91567f8c26a353f770f243a39aa0eb70cd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 13 Mar 2012 16:02:47 +0100 Subject: [PATCH 0384/1776] factory: change to new style caps --- gst/rtsp-server/rtsp-media-factory-uri.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 5e86ee331f..1f107ced8e 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -34,13 +34,10 @@ enum #define RAW_VIDEO_CAPS \ - "video/x-raw-yuv; " \ - "video/x-raw-rgb; " \ - "video/x-raw-gray" + "video/x-raw" #define RAW_AUDIO_CAPS \ - "audio/x-raw-int; " \ - "audio/x-raw-float" + "audio/x-raw" static GstStaticCaps raw_video_caps = GST_STATIC_CAPS (RAW_VIDEO_CAPS); static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS (RAW_AUDIO_CAPS); From 6403227471eefeaace90ba14799574902d2a93cd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 13 Mar 2012 16:06:50 +0100 Subject: [PATCH 0385/1776] factory: use videoconvert --- gst/rtsp-server/rtsp-media-factory-uri.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 1f107ced8e..eee112ab3d 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -397,7 +397,7 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) /* check for raw caps */ if (gst_caps_can_intersect (caps, urifact->raw_vcaps)) { /* we have raw video caps, insert converter */ - convert = gst_element_factory_make ("ffmpegcolorspace", NULL); + convert = gst_element_factory_make ("videoconvert", NULL); } else if (gst_caps_can_intersect (caps, urifact->raw_acaps)) { /* we have raw audio caps, insert converter */ convert = gst_element_factory_make ("audioconvert", NULL); From e0be150e9198c8d39abdaad4003916b9d9989502 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 13 Mar 2012 18:10:53 +0100 Subject: [PATCH 0386/1776] media: fix state of the appqueue --- gst/rtsp-server/rtsp-media.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index ba6b77df9e..fef99caa0a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1636,6 +1636,7 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) for (i = 0; i < 2; i++) { gst_element_set_state (stream->udpsink[i], GST_STATE_PAUSED); gst_element_set_state (stream->appsink[i], GST_STATE_PAUSED); + gst_element_set_state (stream->appqueue[i], GST_STATE_PAUSED); gst_element_set_state (stream->tee[i], GST_STATE_PAUSED); gst_element_set_state (stream->selector[i], GST_STATE_PAUSED); gst_element_set_state (stream->appsrc[i], GST_STATE_PAUSED); @@ -2055,6 +2056,7 @@ gst_rtsp_media_remove_elements (GstRTSPMedia * media) gst_element_set_state (stream->udpsink[j], GST_STATE_NULL); gst_element_set_state (stream->appsrc[j], GST_STATE_NULL); gst_element_set_state (stream->appsink[j], GST_STATE_NULL); + gst_element_set_state (stream->appqueue[j], GST_STATE_NULL); gst_element_set_state (stream->tee[j], GST_STATE_NULL); gst_element_set_state (stream->selector[j], GST_STATE_NULL); @@ -2062,6 +2064,7 @@ gst_rtsp_media_remove_elements (GstRTSPMedia * media) gst_bin_remove (GST_BIN (media->pipeline), stream->udpsink[j]); gst_bin_remove (GST_BIN (media->pipeline), stream->appsrc[j]); gst_bin_remove (GST_BIN (media->pipeline), stream->appsink[j]); + gst_bin_remove (GST_BIN (media->pipeline), stream->appqueue[j]); gst_bin_remove (GST_BIN (media->pipeline), stream->tee[j]); gst_bin_remove (GST_BIN (media->pipeline), stream->selector[j]); } From d1df0f3a2242edf4add833467aec84f3285079be Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 19 Mar 2012 10:48:09 +0000 Subject: [PATCH 0387/1776] A couple minor typo fixes --- docs/README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README b/docs/README index e1ece70d82..e35fc7cd33 100644 --- a/docs/README +++ b/docs/README @@ -117,7 +117,7 @@ can build simple server applications with it. The object that can create such pipeline is called a GstRTSPMediaFactory object. The default implementation of GstRTSPMediaFactory allows you to easily create - GStreamer pipelines using the gst-launch syntax. It possible to create a + GStreamer pipelines using the gst-launch syntax. It is possible to create a GstRTSPMediaFactory subclass that uses different methods for constructing pipelines. @@ -171,7 +171,7 @@ can build simple server applications with it. The GstRTSPMediaFactory is responsible for creating and caching GstRTSPMedia objects. - A freshly created GstRTSPMedia object from the factory initialy only contains a + A freshly created GstRTSPMedia object from the factory initially only contains a GstElement containing the elements to produce the RTP streams for the media and a GArray of GstRTSPMediaStream objects describing the payloader and its source pad. The media is unprepared in this state. From 1f442d45b63be0ceacec801aee6eec7af540790a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 27 Mar 2012 10:13:20 +0200 Subject: [PATCH 0389/1776] rtsp-server: Don't use deprecated GLib API --- gst/rtsp-server/rtsp-session-pool.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index de9234edbe..da0c1c30ea 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -476,8 +476,15 @@ collect_timeout (gchar * sessionid, GstRTSPSession * sess, GstPoolSource * psrc) { gint timeout; GTimeVal now; +#if GLIB_CHECK_VERSION(2,28,0) + gint64 tmp; + tmp = g_source_get_time ((GSource *) psrc); + now.tv_sec = tmp / G_USEC_PER_SEC; + now.tv_usec = tmp % G_USEC_PER_SEC; +#else g_source_get_current_time ((GSource *) psrc, &now); +#endif timeout = gst_rtsp_session_next_timeout (sess, &now); GST_INFO ("%p: next timeout: %d", sess, timeout); From fb0718a036e9d4480b213be0682fd44e82a00990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 4 Apr 2012 14:45:55 +0200 Subject: [PATCH 0390/1776] rtsp-server: Update versioning --- configure.ac | 24 ++++---- docs/libs/Makefile.am | 8 +-- docs/version.entities.in | 2 +- gst-rtsp.spec.in | 2 +- gst/rtsp-server/Makefile.am | 56 +++++++++---------- pkgconfig/Makefile.am | 8 +-- .../gstreamer-rtsp-server-uninstalled.pc.in | 4 +- pkgconfig/gstreamer-rtsp-server.pc.in | 6 +- tests/Makefile.am | 2 +- 9 files changed, 56 insertions(+), 56 deletions(-) diff --git a/configure.ac b/configure.ac index 85c013a971..f7be88ffb7 100644 --- a/configure.ac +++ b/configure.ac @@ -34,10 +34,10 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])], AC_SUBST(AM_DEFAULT_VERBOSITY)]) dnl our libraries and install dirs use major.minor as a version -GST_MAJORMINOR=$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR +dnl GST_API_VERSION=$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR dnl we override it here if we need to for the release candidate of new series -GST_MAJORMINOR=0.11 -AC_SUBST(GST_MAJORMINOR) +GST_API_VERSION=1.0 +AC_SUBST(GST_API_VERSION) AM_PROG_LIBTOOL @@ -58,7 +58,7 @@ dnl set up gettext dnl the version check needs to stay here because autopoint greps for it AM_GNU_GETTEXT_VERSION([0.17]) AM_GNU_GETTEXT([external]) -AG_GST_GETTEXT([gstreamer-$GST_MAJORMINOR]) +AG_GST_GETTEXT([gstreamer-$GST_API_VERSION]) dnl *** check for arguments to configure *** @@ -123,26 +123,26 @@ AG_GST_GLIB_CHECK([$GLIB_REQ]) dnl checks for gstreamer dnl uninstalled is selected preferentially -- see pkg-config(1) -AG_GST_CHECK_GST($GST_MAJORMINOR, [$GST_REQ], [yes]) +AG_GST_CHECK_GST($GST_API_VERSION, [$GST_REQ], [yes]) -GST_TOOLS_DIR=`$PKG_CONFIG --variable=toolsdir gstreamer-$GST_MAJORMINOR` +GST_TOOLS_DIR=`$PKG_CONFIG --variable=toolsdir gstreamer-$GST_API_VERSION` if test -z $GST_TOOLS_DIR; then AC_MSG_ERROR([no tools dir defined in GStreamer pkg-config file; core upgrade needed.]) fi AC_SUBST(GST_TOOLS_DIR) -GST_PLUGINS_DIR=`$PKG_CONFIG gstreamer-$GST_MAJORMINOR --variable pluginsdir` +GST_PLUGINS_DIR=`$PKG_CONFIG gstreamer-$GST_API_VERSION --variable pluginsdir` AC_SUBST(GST_PLUGINS_DIR) AC_MSG_NOTICE(Using GStreamer Core Plugins in $GST_PLUGINS_DIR) -AG_GST_CHECK_GST_BASE($GST_MAJORMINOR, [$GST_REQ], [yes]) +AG_GST_CHECK_GST_BASE($GST_API_VERSION, [$GST_REQ], [yes]) -AG_GST_CHECK_GST_PLUGINS_BASE($GST_MAJORMINOR, [$GSTPB_REQ], [yes]) -GSTPB_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-base-$GST_MAJORMINOR --variable pluginsdir` +AG_GST_CHECK_GST_PLUGINS_BASE($GST_API_VERSION, [$GSTPB_REQ], [yes]) +GSTPB_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-base-$GST_API_VERSION --variable pluginsdir` AC_SUBST(GSTPB_PLUGINS_DIR) AC_MSG_NOTICE(Using GStreamer Base Plugins in $GSTPB_PLUGINS_DIR) -AG_GST_CHECK_GST_CHECK($GST_MAJORMINOR, [$GST_REQ], no) +AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) dnl FIXME: get rid of this by making sure gstreamer-check brings it in dnl check for "check", unit testing library/header @@ -221,7 +221,7 @@ dnl default vars for all internal objects built on libgstrtspserver dnl includes GST_ALL_* GST_OBJ_CFLAGS="\$(GST_ALL_CFLAGS)" AC_SUBST([GST_OBJ_CFLAGS]) -GST_OBJ_LIBS="\$(top_builddir)/gst/rtsp-server/libgstrtspserver-$GST_MAJORMINOR.la \$(GST_ALL_LIBS)" +GST_OBJ_LIBS="\$(top_builddir)/gst/rtsp-server/libgstrtspserver-$GST_API_VERSION.la \$(GST_ALL_LIBS)" AC_SUBST([GST_OBJ_LIBS]) dnl this really should only contain flags, not libs - they get added before diff --git a/docs/libs/Makefile.am b/docs/libs/Makefile.am index 574e9e59e9..38a958e252 100644 --- a/docs/libs/Makefile.am +++ b/docs/libs/Makefile.am @@ -23,11 +23,11 @@ include $(top_srcdir)/common/upload-doc.mak # BUILDDIR=`pwd` && \ # cd $(srcdir)/tmpl && \ # ln -sf gstreamer-libs-unused.sgml \ -# $$BUILDDIR/tmpl/gstreamer-libs-@GST_MAJORMINOR@-unused.sgml +# $$BUILDDIR/tmpl/gstreamer-libs-@GST_API_VERSION@-unused.sgml # touch unused-build.stamp -# these rules are added to create parallel docs using GST_MAJORMINOR -#$(basefiles): gstreamer-libs-@GST_MAJORMINOR@%: gstreamer-libs% +# these rules are added to create parallel docs using GST_API_VERSION +#$(basefiles): gstreamer-libs-@GST_API_VERSION@%: gstreamer-libs% # cp $< $@ #CLEANFILES = $(basefiles) @@ -61,7 +61,7 @@ HFILE_GLOB=$(DOC_SOURCE_DIR)/*.h CFILE_GLOB=$(DOC_SOURCE_DIR)/*.c SCANOBJ_DEPS = \ - $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_MAJORMINOR@.la + $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la # Extra options to supply to gtkdoc-scan. SCANOBJ_OPTIONS=--type-init-func="g_type_init();gst_init(&argc,&argv)" diff --git a/docs/version.entities.in b/docs/version.entities.in index 79a68981d5..286989f56e 100644 --- a/docs/version.entities.in +++ b/docs/version.entities.in @@ -1,2 +1,2 @@ - + diff --git a/gst-rtsp.spec.in b/gst-rtsp.spec.in index 2c4eebcb5a..12224f8bab 100644 --- a/gst-rtsp.spec.in +++ b/gst-rtsp.spec.in @@ -1,4 +1,4 @@ -%define gst_majorminor @GST_MAJORMINOR@ +%define gst_majorminor @GST_API_VERSION@ Name: gstreamer-rtsp-server Version: @VERSION@ diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index eeac445206..991165dc15 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -27,52 +27,52 @@ c_sources = \ noinst_HEADERS = lib_LTLIBRARIES = \ - libgstrtspserver-@GST_MAJORMINOR@.la + libgstrtspserver-@GST_API_VERSION@.la -libgstrtspserver_@GST_MAJORMINOR@_la_SOURCES = \ +libgstrtspserver_@GST_API_VERSION@_la_SOURCES = \ $(c_sources) -libgstrtspserver_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) -libgstrtspserver_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstrtspserver_@GST_MAJORMINOR@_la_LIBADD = \ +libgstrtspserver_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstrtspserver_@GST_API_VERSION@_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstrtspserver_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ - -lgstsdp-@GST_MAJORMINOR@ \ - -lgstapp-@GST_MAJORMINOR@ \ + -lgstrtp-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ \ + -lgstsdp-@GST_API_VERSION@ \ + -lgstapp-@GST_API_VERSION@ \ $(GST_LIBS) $(LIBM) -libgstrtspserver_@GST_MAJORMINOR@_la_LIBTOOLFLAGS = --tag=disable-static +libgstrtspserver_@GST_API_VERSION@_la_LIBTOOLFLAGS = --tag=disable-static -libgstrtspserver_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/rtsp-server -libgstrtspserver_@GST_MAJORMINOR@include_HEADERS = $(public_headers) +libgstrtspserver_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/rtsp-server +libgstrtspserver_@GST_API_VERSION@include_HEADERS = $(public_headers) CLEANFILES = if HAVE_INTROSPECTION -BUILT_GIRSOURCES = GstRtspServer-@GST_MAJORMINOR@.gir +BUILT_GIRSOURCES = GstRtspServer-@GST_API_VERSION@.gir -gir_headers=$(patsubst %,$(srcdir)/%, $(libgstrtspserver_@GST_MAJORMINOR@include_HEADERS)) -gir_sources=$(patsubst %,$(srcdir)/%, $(libgstrtspserver_@GST_MAJORMINOR@_la_SOURCES)) +gir_headers=$(patsubst %,$(srcdir)/%, $(libgstrtspserver_@GST_API_VERSION@include_HEADERS)) +gir_sources=$(patsubst %,$(srcdir)/%, $(libgstrtspserver_@GST_API_VERSION@_la_SOURCES)) gir_cincludes=$(patsubst %,--c-include='gst/rtsp-server/%',$(libgstrtspinclude_HEADERS)) -GstRtspServer-@GST_MAJORMINOR@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@GST_MAJORMINOR@.la +GstRtspServer-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@GST_API_VERSION@.la $(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \ $(INTROSPECTION_SCANNER) -v --namespace GstRtspServer \ - --nsversion=@GST_MAJORMINOR@ \ + --nsversion=@GST_API_VERSION@ \ --strip-prefix=Gst \ -I$(top_srcdir) \ -I$(top_builddir) \ -DIN_GOBJECT_INTROSPECTION=1 \ --c-include='gst/gst.h' \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_MAJORMINOR@` \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_MAJORMINOR@` \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_MAJORMINOR@` \ - --library=libgstrtspserver-@GST_MAJORMINOR@.la \ - --include=Gst-@GST_MAJORMINOR@ \ - --include=GstRtsp-@GST_MAJORMINOR@ \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_API_VERSION@` \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_API_VERSION@` \ + --library=libgstrtspserver-@GST_API_VERSION@.la \ + --include=Gst-@GST_API_VERSION@ \ + --include=GstRtsp-@GST_API_VERSION@ \ --libtool="$(top_builddir)/libtool" \ - --pkg gstreamer-@GST_MAJORMINOR@ \ - --pkg gstreamer-rtsp-@GST_MAJORMINOR@ \ - --pkg-export gstreamer-rtsp-server-@GST_MAJORMINOR@ \ + --pkg gstreamer-@GST_API_VERSION@ \ + --pkg gstreamer-rtsp-@GST_API_VERSION@ \ + --pkg-export gstreamer-rtsp-server-@GST_API_VERSION@ \ --output $@ \ $(gir_headers) \ $(gir_sources) @@ -91,9 +91,9 @@ typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) $(INTROSPECTION_COMPILER) \ --includedir=$(srcdir) \ --includedir=$(builddir) \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_MAJORMINOR@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_MAJORMINOR@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_MAJORMINOR@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_API_VERSION@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_API_VERSION@` \ $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA) diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am index 54f82ac654..c45755eaf9 100644 --- a/pkgconfig/Makefile.am +++ b/pkgconfig/Makefile.am @@ -1,15 +1,15 @@ pcfiles = \ - gstreamer-rtsp-server-@GST_MAJORMINOR@.pc + gstreamer-rtsp-server-@GST_API_VERSION@.pc pcfiles_uninstalled = \ - gstreamer-rtsp-server-@GST_MAJORMINOR@-uninstalled.pc + gstreamer-rtsp-server-@GST_API_VERSION@-uninstalled.pc all-local: $(pcfiles) $(pcfiles_uninstalled) ### how to generate pc files -%-@GST_MAJORMINOR@.pc: %.pc +%-@GST_API_VERSION@.pc: %.pc cp $< $@ -%-@GST_MAJORMINOR@-uninstalled.pc: %-uninstalled.pc +%-@GST_API_VERSION@-uninstalled.pc: %-uninstalled.pc cp $< $@ pkgconfigdir = $(libdir)/pkgconfig diff --git a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in index cd591be913..e45380566b 100644 --- a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in +++ b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in @@ -7,6 +7,6 @@ includedir=${pcfiledir}/.. Name: gst-rtsp-server Description: GStreamer based RTSP server Version: @VERSION@ -Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-plugins-base-@GST_MAJORMINOR@ -Libs: ${libdir}/libgstrtspserver-@GST_MAJORMINOR@.la +Requires: gstreamer-@GST_API_VERSION@ gstreamer-plugins-base-@GST_API_VERSION@ +Libs: ${libdir}/libgstrtspserver-@GST_API_VERSION@.la Cflags: -I${includedir} -I@srcdir@/.. diff --git a/pkgconfig/gstreamer-rtsp-server.pc.in b/pkgconfig/gstreamer-rtsp-server.pc.in index 52e33c5a42..3a1d8206c7 100644 --- a/pkgconfig/gstreamer-rtsp-server.pc.in +++ b/pkgconfig/gstreamer-rtsp-server.pc.in @@ -1,11 +1,11 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ -includedir=@includedir@/gstreamer-@GST_MAJORMINOR@ +includedir=@includedir@/gstreamer-@GST_API_VERSION@ Name: gst-rtsp-server Description: GStreamer based RTSP server Version: @VERSION@ -Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@ -Libs: -L${libdir} -lgstrtspserver-@GST_MAJORMINOR@ +Requires: gstreamer-@GST_API_VERSION@ gstreamer-base-@GST_API_VERSION@ +Libs: -L${libdir} -lgstrtspserver-@GST_API_VERSION@ Cflags: -I${includedir} diff --git a/tests/Makefile.am b/tests/Makefile.am index a4a47d9704..ce9caf3e21 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -5,5 +5,5 @@ INCLUDES = -I$(top_srcdir) -I$(srcdir) AM_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) AM_LDFLAGS = \ $(GST_LIBS) \ - $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_MAJORMINOR@.la + $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la From 8e13fc8fdc070bf3db395e700a01e898b2c44d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 5 Apr 2012 18:45:43 +0200 Subject: [PATCH 0391/1776] Automatic update of common submodule From 7fda524 to 464fe15 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 7fda5249ab..464fe15069 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 7fda5249ab56f0de09277df330780a3b90a2b306 +Subproject commit 464fe150690a0d37a2e76e671edf1a3e39a991a8 From 31ba6bda9982ec00e61c30eb0e6ef96d56ac9cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 13 Apr 2012 13:39:40 +0200 Subject: [PATCH 0392/1776] Automatic update of common submodule From 464fe15 to 6db25be --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 464fe15069..6db25be667 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 464fe150690a0d37a2e76e671edf1a3e39a991a8 +Subproject commit 6db25be667fe05e7184f8f90553b5de89a942a78 From 7df1696713b45897cdefab412de4ce696d3c548a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 13 Apr 2012 13:49:08 +0200 Subject: [PATCH 0393/1776] configure: Modernize autotools setup a bit Also we now only create tar.bz2 and tar.xz tarballs. --- autogen.sh | 13 ++++++------- configure.ac | 16 +++++++++++----- gst/rtsp-server/Makefile.am | 2 +- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/autogen.sh b/autogen.sh index 5f1971433f..376fc9dd19 100755 --- a/autogen.sh +++ b/autogen.sh @@ -35,20 +35,19 @@ autogen_options $@ printf "+ check for build tools" if test ! -z "$NOCHECK"; then echo ": skipped version checks"; else echo; fi -version_check "autoconf" "$AUTOCONF autoconf autoconf270 autoconf269 autoconf268 autoconf267 autoconf266 autoconf265 autoconf264 autoconf263 autoconf262 autoconf261 autoconf260" \ - "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 60 || DIE=1 -version_check "automake" "$AUTOMAKE automake automake-1.11 automake-1.10" \ - "ftp://ftp.gnu.org/pub/gnu/automake/" 1 10 || DIE=1 +version_check "autoconf" "$AUTOCONF autoconf autoconf270 autoconf269 autoconf268 autoconf267 autoconf266 autoconf265 autoconf264 autoconf263 autoconf262" \ + "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 62 || DIE=1 +version_check "automake" "$AUTOMAKE automake automake-1.11" \ + "ftp://ftp.gnu.org/pub/gnu/automake/" 1 11 || DIE=1 version_check "autopoint" "autopoint" \ "ftp://ftp.gnu.org/pub/gnu/gettext/" 0 17 || DIE=1 -version_check "libtoolize" "libtoolize libtoolize15 glibtoolize" \ - "ftp://ftp.gnu.org/pub/gnu/libtool/" 1 5 0 || DIE=1 +version_check "libtoolize" "libtoolize glibtoolize" \ + "ftp://ftp.gnu.org/pub/gnu/libtool/" 2 2 6 || DIE=1 version_check "pkg-config" "" \ "http://www.freedesktop.org/software/pkgconfig" 0 8 0 || DIE=1 die_check $DIE -autoconf_2_52d_check || DIE=1 aclocal_check || DIE=1 autoheader_check || DIE=1 diff --git a/configure.ac b/configure.ac index f7be88ffb7..c742de0341 100644 --- a/configure.ac +++ b/configure.ac @@ -1,14 +1,14 @@ -AC_PREREQ(2.60) +AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.11.0.1, +AC_INIT(Gst-RTSP, 0.11.89.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-rtsp) AG_GST_INIT dnl initialize automake -AM_INIT_AUTOMAKE([-Wno-portability 1.10]) +AM_INIT_AUTOMAKE([-Wno-portability 1.11 no-dist-gzip dist-xz tar-ustar]) dnl define PACKAGE_VERSION_* variables AS_VERSION @@ -23,7 +23,7 @@ dnl define the output header for config AM_CONFIG_HEADER([config.h]) dnl AM_MAINTAINER_MODE only provides the option to configure to enable it -AM_MAINTAINER_MODE +AM_MAINTAINER_MODE([enable]) dnl sets host_* variables AC_CANONICAL_HOST @@ -39,7 +39,7 @@ dnl we override it here if we need to for the release candidate of new series GST_API_VERSION=1.0 AC_SUBST(GST_API_VERSION) -AM_PROG_LIBTOOL +AS_LIBTOOL(GST, 0, 0, 0) dnl *** required versions of GStreamer stuff *** GST_REQ=0.11.0 @@ -216,6 +216,12 @@ 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 +GST_LIB_LDFLAGS="-export-symbols-regex \^[_]?\(gst_\|Gst\|GST_\).*" +AC_SUBST(GST_LIB_LDFLAGS) + dnl GST_OBJ_* dnl default vars for all internal objects built on libgstrtspserver dnl includes GST_ALL_* diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 991165dc15..43b54c4105 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -33,7 +33,7 @@ libgstrtspserver_@GST_API_VERSION@_la_SOURCES = \ $(c_sources) libgstrtspserver_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) -libgstrtspserver_@GST_API_VERSION@_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstrtspserver_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) libgstrtspserver_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ -lgstrtp-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ \ From e2f10f5ba586c5c4d1bdf400b3bab55d3a7f742c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 13 Apr 2012 15:27:22 +0200 Subject: [PATCH 0394/1776] rtsp-server: Fix compilation and compiler warnings --- gst/rtsp-server/rtsp-auth.c | 4 ++-- gst/rtsp-server/rtsp-auth.h | 2 +- gst/rtsp-server/rtsp-client.c | 14 ++++++-------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index e01315ccdb..11656776b6 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -189,7 +189,7 @@ default_check_method (GstRTSPAuth * auth, GstRTSPClient * client, gboolean result = TRUE; GstRTSPResult res; - if (state->method & auth->methods != 0) { + if ((state->method & auth->methods) != 0) { gchar *authorization; result = FALSE; @@ -221,7 +221,7 @@ no_auth: } /** - * gst_rtsp_auth_check_method: + * gst_rtsp_auth_check: * @auth: a #GstRTSPAuth * @client: the client * @hint: a hint diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 3aadeffd67..5f06acbde7 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -70,7 +70,7 @@ void gst_rtsp_auth_set_basic (GstRTSPAuth *auth, const gc gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth *auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState *state); -gboolean gst_rtsp_auth_check_method (GstRTSPAuth *auth, GstRTSPClient * client, +gboolean gst_rtsp_auth_check (GstRTSPAuth *auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState *state); /* helpers */ gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass); diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f814c5164a..8c08fd1c27 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -429,7 +429,7 @@ do_send_data_list (GstBufferList * blist, guint8 channel, { guint len, i; - len = gst_buffer_list_len (blist); + len = gst_buffer_list_length (blist); for (i = 0; i < len; i++) { GstBuffer *group = gst_buffer_list_get (blist, i); @@ -1351,7 +1351,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) state.session = session; if (client->auth) { - if (!gst_rtsp_auth_check (client->auth, client, &state)) + if (!gst_rtsp_auth_check (client->auth, client, 0, &state)) goto not_authorized; } @@ -1433,9 +1433,7 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) gst_rtsp_message_steal_body (message, &data, &size); - buffer = gst_buffer_new (); - gst_buffer_take_memory (buffer, -1, - gst_memory_new_wrapped (0, data, size, 0, size, data, g_free)); + buffer = gst_buffer_new_wrapped (data, size); handled = FALSE; for (walk = client->streams; walk; walk = g_list_next (walk)) { @@ -1849,20 +1847,20 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) no_tunnelid: { GST_INFO ("client %p: no tunnelid provided", client); - return GST_RTSP_STS_SERVICE_UNAVAILABLE; + return GST_RTSP_ERROR; } no_tunnel: { g_mutex_unlock (tunnels_lock); GST_INFO ("client %p: tunnel session %s not found", client, tunnelid); - return GST_RTSP_STS_SERVICE_UNAVAILABLE; + return GST_RTSP_ERROR; } tunnel_closed: { g_mutex_unlock (tunnels_lock); GST_INFO ("client %p: tunnel session %s was closed", client, tunnelid); g_object_unref (oclient); - return GST_RTSP_STS_SERVICE_UNAVAILABLE; + return GST_RTSP_ERROR; } } From a798e8dcfd539d00d0316d79aa021fc3666ffd5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 16 Apr 2012 09:11:54 +0200 Subject: [PATCH 0395/1776] Automatic update of common submodule From 6db25be to dc70203 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 6db25be667..dc702037b0 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 6db25be667fe05e7184f8f90553b5de89a942a78 +Subproject commit dc702037b0490052dfc1fa5a3e5890bd55cf7b34 From 6cc2fb9bfcfdc03ff0a8a88041eec3a646ee13ab Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 11 May 2012 09:42:47 +0200 Subject: [PATCH 0396/1776] rtsp-server: port to new thread API --- gst/rtsp-server/rtsp-client.c | 26 ++++++++-------- gst/rtsp-server/rtsp-media-factory.c | 16 +++++----- gst/rtsp-server/rtsp-media-factory.h | 8 ++--- gst/rtsp-server/rtsp-media.c | 40 ++++++++++++------------- gst/rtsp-server/rtsp-media.h | 4 +-- gst/rtsp-server/rtsp-server.c | 4 +-- gst/rtsp-server/rtsp-server.h | 4 +-- gst/rtsp-server/rtsp-session-pool.c | 44 ++++++++++++++-------------- gst/rtsp-server/rtsp-session-pool.h | 2 +- 9 files changed, 72 insertions(+), 76 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8c08fd1c27..8147fd66bf 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -36,7 +36,7 @@ #include "rtsp-sdp.h" #include "rtsp-params.h" -static GMutex *tunnels_lock; +static GMutex tunnels_lock; static GHashTable *tunnels; enum @@ -101,7 +101,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - tunnels_lock = g_mutex_new (); + g_mutex_init (&tunnels_lock); GST_DEBUG_CATEGORY_INIT (rtsp_client_debug, "rtspclient", 0, "GstRTSPClient"); } @@ -495,10 +495,10 @@ close_connection (GstRTSPClient * client) GST_DEBUG ("client %p: closing connection", client); if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) { - g_mutex_lock (tunnels_lock); + g_mutex_lock (&tunnels_lock); /* remove from tunnelids */ g_hash_table_remove (tunnels, tunnelid); - g_mutex_unlock (tunnels_lock); + g_mutex_unlock (&tunnels_lock); } gst_rtsp_connection_close (client->connection); @@ -1687,10 +1687,10 @@ closed (GstRTSPWatch * watch, gpointer user_data) GST_INFO ("client %p: connection closed", client); if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) { - g_mutex_lock (tunnels_lock); + g_mutex_lock (&tunnels_lock); /* remove from tunnelids */ g_hash_table_remove (tunnels, tunnelid); - g_mutex_unlock (tunnels_lock); + g_mutex_unlock (&tunnels_lock); } return GST_RTSP_OK; @@ -1738,12 +1738,12 @@ remember_tunnel (GstRTSPClient * client) GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid); /* we can't have two clients connecting with the same tunnelid */ - g_mutex_lock (tunnels_lock); + g_mutex_lock (&tunnels_lock); if (g_hash_table_lookup (tunnels, tunnelid)) goto tunnel_existed; g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client)); - g_mutex_unlock (tunnels_lock); + g_mutex_unlock (&tunnels_lock); return TRUE; @@ -1755,7 +1755,7 @@ no_tunnelid: } tunnel_existed: { - g_mutex_unlock (tunnels_lock); + g_mutex_unlock (&tunnels_lock); GST_ERROR ("client %p: tunnel session %s already existed", client, tunnelid); return FALSE; @@ -1815,7 +1815,7 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) if (tunnelid == NULL) goto no_tunnelid; - g_mutex_lock (tunnels_lock); + g_mutex_lock (&tunnels_lock); if (!(oclient = g_hash_table_lookup (tunnels, tunnelid))) goto no_tunnel; @@ -1826,7 +1826,7 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) if (oclient->watch == NULL) goto tunnel_closed; - g_mutex_unlock (tunnels_lock); + g_mutex_unlock (&tunnels_lock); GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient, oclient->connection, client->connection); @@ -1851,13 +1851,13 @@ no_tunnelid: } no_tunnel: { - g_mutex_unlock (tunnels_lock); + g_mutex_unlock (&tunnels_lock); GST_INFO ("client %p: tunnel session %s not found", client, tunnelid); return GST_RTSP_ERROR; } tunnel_closed: { - g_mutex_unlock (tunnels_lock); + g_mutex_unlock (&tunnels_lock); GST_INFO ("client %p: tunnel session %s was closed", client, tunnelid); g_object_unref (oclient); return GST_RTSP_ERROR; diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index ca4527ef4c..e7b60f779b 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -158,8 +158,8 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) factory->buffer_size = DEFAULT_BUFFER_SIZE; factory->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP); - factory->lock = g_mutex_new (); - factory->medias_lock = g_mutex_new (); + g_mutex_init (&factory->lock); + g_mutex_init (&factory->medias_lock); factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } @@ -170,10 +170,10 @@ gst_rtsp_media_factory_finalize (GObject * obj) GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj); g_hash_table_unref (factory->medias); - g_mutex_free (factory->medias_lock); + g_mutex_clear (&factory->medias_lock); g_free (factory->launch); g_free (factory->multicast_group); - g_mutex_free (factory->lock); + g_mutex_clear (&factory->lock); if (factory->auth) g_object_unref (factory->auth); @@ -568,9 +568,9 @@ compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) static void media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory) { - g_mutex_lock (factory->medias_lock); + g_mutex_lock (&factory->medias_lock); g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, media); - g_mutex_unlock (factory->medias_lock); + g_mutex_unlock (&factory->medias_lock); } /** @@ -605,7 +605,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, else key = NULL; - g_mutex_lock (factory->medias_lock); + g_mutex_lock (&factory->medias_lock); if (key) { /* we have a key, see if we find a cached media */ media = g_hash_table_lookup (factory->medias, key); @@ -649,7 +649,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, } } } - g_mutex_unlock (factory->medias_lock); + g_mutex_unlock (&factory->medias_lock); if (key) g_free (key); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 225d9b26d6..baabc86337 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -41,7 +41,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPMediaFactory GstRTSPMediaFactory; typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; -#define GST_RTSP_MEDIA_FACTORY_GET_LOCK(f) (GST_RTSP_MEDIA_FACTORY_CAST(f)->lock) +#define GST_RTSP_MEDIA_FACTORY_GET_LOCK(f) (&(GST_RTSP_MEDIA_FACTORY_CAST(f)->lock)) #define GST_RTSP_MEDIA_FACTORY_LOCK(f) (g_mutex_lock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f))) #define GST_RTSP_MEDIA_FACTORY_UNLOCK(f) (g_mutex_unlock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f))) @@ -62,9 +62,9 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; * can contain multiple streams like audio and video. */ struct _GstRTSPMediaFactory { - GObject parent; + GObject parent; - GMutex *lock; + GMutex lock; gchar *launch; gboolean shared; gboolean eos_shutdown; @@ -73,7 +73,7 @@ struct _GstRTSPMediaFactory { guint buffer_size; gchar *multicast_group; - GMutex *medias_lock; + GMutex medias_lock; GHashTable *medias; }; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index fef99caa0a..3d2377c673 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -81,7 +81,6 @@ static void gst_rtsp_media_class_init (GstRTSPMediaClass * klass) { GObjectClass *gobject_class; - GError *error = NULL; gobject_class = G_OBJECT_CLASS (klass); @@ -139,10 +138,8 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); - klass->thread = g_thread_create ((GThreadFunc) do_loop, klass, TRUE, &error); - if (error != NULL) { - g_critical ("could not start bus thread: %s", error->message); - } + klass->thread = g_thread_new ("Bus Thread", (GThreadFunc) do_loop, klass); + klass->handle_message = default_handle_message; klass->unprepare = default_unprepare; @@ -153,8 +150,8 @@ static void gst_rtsp_media_init (GstRTSPMedia * media) { media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); - media->lock = g_mutex_new (); - media->cond = g_cond_new (); + g_mutex_init (&media->lock); + g_cond_init (&media->cond); media->shared = DEFAULT_SHARED; media->reusable = DEFAULT_REUSABLE; @@ -235,8 +232,8 @@ gst_rtsp_media_finalize (GObject * obj) g_source_unref (media->source); } g_free (media->multicast_group); - g_mutex_free (media->lock); - g_cond_free (media->cond); + g_mutex_clear (&media->lock); + g_cond_clear (&media->cond); G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); } @@ -550,10 +547,10 @@ gst_rtsp_media_set_multicast_group (GstRTSPMedia * media, const gchar * mc) { g_return_if_fail (GST_IS_RTSP_MEDIA (media)); - g_mutex_lock (media->lock); + g_mutex_lock (&media->lock); g_free (media->multicast_group); media->multicast_group = g_strdup (mc); - g_mutex_unlock (media->lock); + g_mutex_unlock (&media->lock); } /** @@ -571,9 +568,9 @@ gst_rtsp_media_get_multicast_group (GstRTSPMedia * media) g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - g_mutex_lock (media->lock); + g_mutex_lock (&media->lock); result = g_strdup (media->multicast_group); - g_mutex_unlock (media->lock); + g_mutex_unlock (&media->lock); return result; } @@ -1445,28 +1442,27 @@ unlock_streams (GstRTSPMedia * media) static void gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status) { - g_mutex_lock (media->lock); + g_mutex_lock (&media->lock); /* never overwrite the error status */ if (media->status != GST_RTSP_MEDIA_STATUS_ERROR) media->status = status; GST_DEBUG ("setting new status to %d", status); - g_cond_broadcast (media->cond); - g_mutex_unlock (media->lock); + g_cond_broadcast (&media->cond); + g_mutex_unlock (&media->lock); } static GstRTSPMediaStatus gst_rtsp_media_get_status (GstRTSPMedia * media) { GstRTSPMediaStatus result; - GTimeVal timeout; + gint64 end_time; - g_mutex_lock (media->lock); - g_get_current_time (&timeout); - g_time_val_add (&timeout, 20 * G_USEC_PER_SEC); + g_mutex_lock (&media->lock); + end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND; /* while we are preparing, wait */ while (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) { GST_DEBUG ("waiting for status change"); - if (!g_cond_timed_wait (media->cond, media->lock, &timeout)) { + if (!g_cond_wait_until (&media->cond, &media->lock, end_time)) { GST_DEBUG ("timeout, assuming error status"); media->status = GST_RTSP_MEDIA_STATUS_ERROR; } @@ -1474,7 +1470,7 @@ gst_rtsp_media_get_status (GstRTSPMedia * media) /* could be success or error */ result = media->status; GST_DEBUG ("got status %d", result); - g_mutex_unlock (media->lock); + g_mutex_unlock (&media->lock); return result; } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 38f7c353b6..e48b013e88 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -191,8 +191,8 @@ typedef enum { struct _GstRTSPMedia { GObject parent; - GMutex *lock; - GCond *cond; + GMutex lock; + GCond cond; gboolean shared; gboolean reusable; diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 6cef1967a8..8a18cc2e92 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -164,7 +164,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) static void gst_rtsp_server_init (GstRTSPServer * server) { - server->lock = g_mutex_new (); + g_mutex_init (&server->lock); server->address = g_strdup (DEFAULT_ADDRESS); server->service = g_strdup (DEFAULT_SERVICE); server->backlog = DEFAULT_BACKLOG; @@ -188,7 +188,7 @@ gst_rtsp_server_finalize (GObject * object) if (server->auth) g_object_unref (server->auth); - g_mutex_free (server->lock); + g_mutex_clear (&server->lock); G_OBJECT_CLASS (gst_rtsp_server_parent_class)->finalize (object); } diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index dd6e386d1e..1c5cb0c632 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -42,7 +42,7 @@ typedef struct _GstRTSPServerClass GstRTSPServerClass; #define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj)) #define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass)) -#define GST_RTSP_SERVER_GET_LOCK(server) (GST_RTSP_SERVER_CAST(server)->lock) +#define GST_RTSP_SERVER_GET_LOCK(server) (&(GST_RTSP_SERVER_CAST(server)->lock)) #define GST_RTSP_SERVER_LOCK(server) (g_mutex_lock(GST_RTSP_SERVER_GET_LOCK(server))) #define GST_RTSP_SERVER_UNLOCK(server) (g_mutex_unlock(GST_RTSP_SERVER_GET_LOCK(server))) @@ -55,7 +55,7 @@ typedef struct _GstRTSPServerClass GstRTSPServerClass; struct _GstRTSPServer { GObject parent; - GMutex *lock; + GMutex lock; /* server information */ gchar *address; diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index c1619c70fb..7f3bd01f54 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -77,7 +77,7 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) static void gst_rtsp_session_pool_init (GstRTSPSessionPool * pool) { - pool->lock = g_mutex_new (); + g_mutex_init (&pool->lock); pool->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); pool->max_sessions = DEFAULT_MAX_SESSIONS; @@ -88,7 +88,7 @@ gst_rtsp_session_pool_finalize (GObject * object) { GstRTSPSessionPool *pool = GST_RTSP_SESSION_POOL (object); - g_mutex_free (pool->lock); + g_mutex_clear (&pool->lock); g_hash_table_unref (pool->sessions); G_OBJECT_CLASS (gst_rtsp_session_pool_parent_class)->finalize (object); @@ -156,9 +156,9 @@ gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool * pool, guint max) { g_return_if_fail (GST_IS_RTSP_SESSION_POOL (pool)); - g_mutex_lock (pool->lock); + g_mutex_lock (&pool->lock); pool->max_sessions = max; - g_mutex_unlock (pool->lock); + g_mutex_unlock (&pool->lock); } /** @@ -177,9 +177,9 @@ gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool * pool) g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0); - g_mutex_lock (pool->lock); + g_mutex_lock (&pool->lock); result = pool->max_sessions; - g_mutex_unlock (pool->lock); + g_mutex_unlock (&pool->lock); return result; } @@ -199,9 +199,9 @@ gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool * pool) g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0); - g_mutex_lock (pool->lock); + g_mutex_lock (&pool->lock); result = g_hash_table_size (pool->sessions); - g_mutex_unlock (pool->lock); + g_mutex_unlock (&pool->lock); return result; } @@ -225,13 +225,13 @@ gst_rtsp_session_pool_find (GstRTSPSessionPool * pool, const gchar * sessionid) g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL); g_return_val_if_fail (sessionid != NULL, NULL); - g_mutex_lock (pool->lock); + g_mutex_lock (&pool->lock); result = g_hash_table_lookup (pool->sessions, sessionid); if (result) { g_object_ref (result); gst_rtsp_session_touch (result); } - g_mutex_unlock (pool->lock); + g_mutex_unlock (&pool->lock); return result; } @@ -283,7 +283,7 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) if (id == NULL) goto no_session; - g_mutex_lock (pool->lock); + g_mutex_lock (&pool->lock); /* check session limit */ if (pool->max_sessions > 0) { if (g_hash_table_size (pool->sessions) >= pool->max_sessions) @@ -304,7 +304,7 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) g_object_ref (result); g_hash_table_insert (pool->sessions, result->sessionid, result); } - g_mutex_unlock (pool->lock); + g_mutex_unlock (&pool->lock); g_free (id); } while (result == NULL); @@ -325,14 +325,14 @@ no_session: collision: { GST_WARNING ("can't find unique sessionid for GstRTSPSessionPool %p", pool); - g_mutex_unlock (pool->lock); + g_mutex_unlock (&pool->lock); g_free (id); return NULL; } too_many_sessions: { GST_WARNING ("session pool reached max sessions of %d", pool->max_sessions); - g_mutex_unlock (pool->lock); + g_mutex_unlock (&pool->lock); g_free (id); return NULL; } @@ -355,9 +355,9 @@ gst_rtsp_session_pool_remove (GstRTSPSessionPool * pool, GstRTSPSession * sess) g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), FALSE); g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), FALSE); - g_mutex_lock (pool->lock); + g_mutex_lock (&pool->lock); found = g_hash_table_remove (pool->sessions, sess->sessionid); - g_mutex_unlock (pool->lock); + g_mutex_unlock (&pool->lock); return found; } @@ -387,11 +387,11 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool) g_get_current_time (&now); - g_mutex_lock (pool->lock); + g_mutex_lock (&pool->lock); result = g_hash_table_foreach_remove (pool->sessions, (GHRFunc) cleanup_func, &now); - g_mutex_unlock (pool->lock); + g_mutex_unlock (&pool->lock); return result; } @@ -457,9 +457,9 @@ gst_rtsp_session_pool_filter (GstRTSPSessionPool * pool, data.user_data = user_data; data.list = NULL; - g_mutex_lock (pool->lock); + g_mutex_lock (&pool->lock); g_hash_table_foreach_remove (pool->sessions, (GHRFunc) filter_func, &data); - g_mutex_unlock (pool->lock); + g_mutex_unlock (&pool->lock); return data.list; } @@ -497,9 +497,9 @@ gst_pool_source_prepare (GSource * source, gint * timeout) psrc = (GstPoolSource *) source; psrc->timeout = -1; - g_mutex_lock (psrc->pool->lock); + g_mutex_lock (&psrc->pool->lock); g_hash_table_foreach (psrc->pool->sessions, (GHFunc) collect_timeout, psrc); - g_mutex_unlock (psrc->pool->lock); + g_mutex_unlock (&psrc->pool->lock); if (timeout) *timeout = psrc->timeout; diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index f432208737..642242f16f 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -53,7 +53,7 @@ struct _GstRTSPSessionPool { guint max_sessions; - GMutex *lock; + GMutex lock; GHashTable *sessions; }; From 93f42c7d73aace15eddea3fd9dc64691aa0aca4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 13 May 2012 15:59:10 +0200 Subject: [PATCH 0397/1776] Automatic update of common submodule From dc70203 to 3429ba6 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index dc702037b0..3429ba64cf 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit dc702037b0490052dfc1fa5a3e5890bd55cf7b34 +Subproject commit 3429ba64cfe418492a9192496d7d23004c0d0872 From ffa3166fbd4ae475047a746bf8e477cc5c4d32c2 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Tue, 22 May 2012 15:37:25 +0200 Subject: [PATCH 0398/1776] rtsp: fix compiler warnings Fixes https://bugzilla.gnome.org/show_bug.cgi?id=676500 --- gst/rtsp-server/rtsp-auth.c | 4 ---- gst/rtsp-server/rtsp-client.c | 17 ----------------- gst/rtsp-server/rtsp-media-factory-uri.c | 5 +---- gst/rtsp-server/rtsp-server.c | 4 ++-- 4 files changed, 3 insertions(+), 27 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 11656776b6..c8aa14008a 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -87,8 +87,6 @@ static void gst_rtsp_auth_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec) { - GstRTSPAuth *auth = GST_RTSP_AUTH (object); - switch (propid) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -99,8 +97,6 @@ static void gst_rtsp_auth_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec) { - GstRTSPAuth *auth = GST_RTSP_AUTH (object); - switch (propid) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8147fd66bf..b82800202c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -423,23 +423,6 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) return TRUE; } -static gboolean -do_send_data_list (GstBufferList * blist, guint8 channel, - GstRTSPClient * client) -{ - guint len, i; - - len = gst_buffer_list_length (blist); - - for (i = 0; i < len; i++) { - GstBuffer *group = gst_buffer_list_get (blist, i); - - do_send_data (group, channel, client); - } - - return TRUE; -} - static void link_stream (GstRTSPClient * client, GstRTSPSession * session, GstRTSPSessionStream * stream) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index eee112ab3d..c544449c66 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -121,7 +121,6 @@ typedef struct static gboolean payloader_filter (GstPluginFeature * feature, FilterData * data) { - gboolean res; const gchar *klass; GstElementFactory *fact; GList **list = NULL; @@ -290,7 +289,7 @@ gst_rtsp_media_factory_uri_get_uri (GstRTSPMediaFactoryURI * factory) static GstElementFactory * find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps) { - GList *list, *tmp; + GList *list; GstElementFactory *factory = NULL; /* first find a demuxer that can link */ @@ -337,10 +336,8 @@ static gboolean autoplug_continue_cb (GstElement * uribin, GstPad * pad, GstCaps * caps, GstElement * element) { - GList *list, *tmp; FactoryData *data; GstElementFactory *factory; - gboolean res; GST_DEBUG ("found pad %s:%s of caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME (pad), caps); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 8a18cc2e92..c4b951e22f 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -562,7 +562,7 @@ gst_rtsp_server_create_socket (GstRTSPServer * server, { GSocketConnectable *conn; GSocketAddressEnumerator *enumerator; - GSocket *socket; + GSocket *socket = NULL; #ifdef USE_SOLINGER struct linger linger; #endif @@ -793,7 +793,7 @@ gboolean gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, GstRTSPServer * server) { - gboolean result; + gboolean result = TRUE; GstRTSPClient *client = NULL; GstRTSPServerClass *klass; GError *error = NULL; From 81f62e76df4b13525bf01aed7282a8fccd5c1be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 30 May 2012 11:27:31 +0200 Subject: [PATCH 0399/1776] Automatic update of common submodule From 3429ba6 to ec1c4a8 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 3429ba64cf..ec1c4a83e3 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 3429ba64cfe418492a9192496d7d23004c0d0872 +Subproject commit ec1c4a83e31ac2bedf84ca265bf18dfbf1226200 From 365c838b80bcee76cc199a79dc0740ff47804646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 30 May 2012 12:48:51 +0200 Subject: [PATCH 0400/1776] Automatic update of common submodule From ec1c4a8 to 92b7266 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index ec1c4a83e3..92b7266e72 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit ec1c4a83e31ac2bedf84ca265bf18dfbf1226200 +Subproject commit 92b7266e721fb83069373c122dd87401cb7e4294 From 3b1258100439a727ab856feefec61931d63d68fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 31 May 2012 13:11:43 +0200 Subject: [PATCH 0401/1776] Automatic update of common submodule From 92b7266 to f1b5a96 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 92b7266e72..f1b5a966f3 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 92b7266e721fb83069373c122dd87401cb7e4294 +Subproject commit f1b5a966f3cf50fbbc4a2f02a1a3b64b9668e375 From a9bf210747e0ce979a87c26c08ada30c8bddc4cc Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 1 Jun 2012 10:30:58 +0200 Subject: [PATCH 0402/1776] Automatic update of common submodule From f1b5a96 to 1fab359 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index f1b5a966f3..1fab359dd2 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit f1b5a966f3cf50fbbc4a2f02a1a3b64b9668e375 +Subproject commit 1fab359dd212f0604592fca4bd602cfb9b8f68a4 From 7b145aeeab24971a4e305b9f4fd26782f35365cd Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Wed, 6 Jun 2012 14:49:02 +0200 Subject: [PATCH 0403/1776] client: fix GSocketAddress leak in gst_rtsp_client_accept Fixes https://bugzilla.gnome.org/show_bug.cgi?id=677463 --- gst/rtsp-server/rtsp-client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b82800202c..e35efee88c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1910,6 +1910,7 @@ gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, addrlen = sizeof (addr); if (!g_socket_address_to_native (addres, &addr, addrlen, error)) goto native_failed; + g_object_unref (addres); if (getnameinfo ((struct sockaddr *) &addr, addrlen, ip, sizeof (ip), NULL, 0, NI_NUMERICHOST) != 0) @@ -1960,6 +1961,7 @@ no_address: } native_failed: { + g_object_unref (addres); GST_ERROR ("could not get native address %s", (*error)->message); return FALSE; } From b2f4dd35c165e83adf7b14fd51736a02094f0e9c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 6 Jun 2012 18:20:49 +0200 Subject: [PATCH 0404/1776] Automatic update of common submodule From 1fab359 to 03a0e57 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 1fab359dd2..03a0e57367 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 1fab359dd212f0604592fca4bd602cfb9b8f68a4 +Subproject commit 03a0e5736761a72d4ed880e8c485bbf9e4a8ea47 From 8ae2b9f61fbfe54ba3a59092fd73f4217fe85477 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 8 Jun 2012 15:07:06 +0200 Subject: [PATCH 0405/1776] Automatic update of common submodule From 03a0e57 to 98e386f --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 03a0e57367..98e386f58e 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 03a0e5736761a72d4ed880e8c485bbf9e4a8ea47 +Subproject commit 98e386f58eb299db9228ba04b433526b0bc89311 From b59f2354606b86c53dab5346525ab9bdf64decdf Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Fri, 25 May 2012 17:11:53 +0200 Subject: [PATCH 0406/1776] configure: Add warning flags for compiler when configuring Fixes https://bugzilla.gnome.org/show_bug.cgi?id=676824 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c742de0341..83f1f79292 100644 --- a/configure.ac +++ b/configure.ac @@ -188,7 +188,7 @@ DEPRECATED_CFLAGS="-DGST_DISABLE_DEPRECATED" AC_SUBST(DEPRECATED_CFLAGS) dnl every flag in GST_OPTION_CFLAGS can be overridden at make time -GST_OPTION_CFLAGS="\$(ERROR_CFLAGS) \$(DEBUG_CFLAGS) \$(PROFILE_CFLAGS) \$(GCOV_CFLAGS) \$(OPT_CFLAGS) \$(DEPRECATED_CFLAGS)" +GST_OPTION_CFLAGS="\$(WARNING_CFLAGS) \$(ERROR_CFLAGS) \$(DEBUG_CFLAGS) \$(PROFILE_CFLAGS) \$(GCOV_CFLAGS) \$(OPT_CFLAGS) \$(DEPRECATED_CFLAGS)" AC_SUBST(GST_OPTION_CFLAGS) dnl FIXME: do we want to rename to GST_ALL_* ? From c3766ad376fbcd968919cbeb9654dad6cac0ca9e Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Fri, 25 May 2012 16:38:15 +0200 Subject: [PATCH 0407/1776] docs: include headers defining rtsp-server object types Fixes compiler warnings during docs build. https://bugzilla.gnome.org/show_bug.cgi?id=676824 --- docs/libs/gst-rtsp-server.types | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/libs/gst-rtsp-server.types b/docs/libs/gst-rtsp-server.types index 37ae5ccfa7..3189f2a5fc 100644 --- a/docs/libs/gst-rtsp-server.types +++ b/docs/libs/gst-rtsp-server.types @@ -1,9 +1,25 @@ #include + +#include gst_rtsp_auth_get_type + +#include gst_rtsp_media_mapping_get_type + +#include gst_rtsp_media_factory_get_type + +#include gst_rtsp_media_get_type + +#include gst_rtsp_server_get_type + +#include gst_rtsp_session_pool_get_type + +#include gst_rtsp_session_get_type + +#include gst_rtsp_client_get_type From 62532769a70e535d90e5065f1bdecab39fa14ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 9 Jun 2012 17:41:05 +0100 Subject: [PATCH 0408/1776] docs: fix build in uninstalled setup Include gst-plugins-base libs properly. --- docs/libs/Makefile.am | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/libs/Makefile.am b/docs/libs/Makefile.am index 38a958e252..0bfb22f785 100644 --- a/docs/libs/Makefile.am +++ b/docs/libs/Makefile.am @@ -91,8 +91,10 @@ extra_files = # CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib # contains GtkObjects/GObjects and you want to document signals and properties. -GTKDOC_CFLAGS = -I$(top_srcdir) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GST_PBUTILS_CFLAGS) -GTKDOC_LIBS = $(SCANOBJ_DEPS) $(GST_BASE_LIBS) $(GST_LIBS) +GTKDOC_CFLAGS = -I$(top_srcdir) $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) $(GST_CFLAGS) +GTKDOC_LIBS = $(SCANOBJ_DEPS) $(GST_PLUGINS_BASE_LIBS) \ + $(GST_BASE_LIBS) $(GST_LIBS) GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC) GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) From ef29cc6d78312c303f1f79fdc4c7623436be5eaa Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Fri, 25 May 2012 16:43:38 +0200 Subject: [PATCH 0409/1776] configure: suppress some warnings when debug is disabled Warnings about unused variables should be suppressed if core has the debug system disabled. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=676824 --- configure.ac | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 83f1f79292..50fe7a4638 100644 --- a/configure.ac +++ b/configure.ac @@ -159,8 +159,13 @@ AC_SUBST(GST_LICENSE) dnl set location of plugin directory AG_GST_SET_PLUGINDIR +# set by AG_GST_PARSE_SUBSYSTEM_DISABLES above +dnl make sure it doesn't complain about unused variables if debugging is disabled +NO_WARNINGS="" +AG_GST_CHECK_GST_DEBUG_DISABLED([NO_WARNINGS="-Wno-unused"], [NO_WARNINGS=""]) + dnl define an ERROR_CFLAGS Makefile variable -AG_GST_SET_ERROR_CFLAGS($GST_GIT) +AG_GST_SET_ERROR_CFLAGS($GST_GIT, [$NO_WARNINGS]) dnl define correct level for debugging messages AG_GST_SET_LEVEL_DEFAULT($GST_GIT) From aa158fa738bd3a5b7ba2aa561d9f1347af155570 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Tue, 12 Jun 2012 13:36:57 +0200 Subject: [PATCH 0410/1776] factory: plug pad leak in collect_streams In gst_rtsp_media_factory_collect_streams: unref the srcpad that was retrieved using gst_element_get_static_pad. gst_ghost_pad_new will take one reference, and the other reference will otherwise give a memory leak. --- gst/rtsp-server/rtsp-media-factory.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index e7b60f779b..8db3357c94 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -750,6 +750,7 @@ gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory * factory, /* ghost the pad of the payloader to the element */ stream->srcpad = gst_ghost_pad_new (name, pad); + g_object_unref (pad); gst_pad_set_active (stream->srcpad, TRUE); gst_element_add_pad (media->element, stream->srcpad); gst_object_unref (elem); From dc796bf075abbec437cb50a2a8383a7e3f04c532 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Tue, 12 Jun 2012 13:39:35 +0200 Subject: [PATCH 0411/1776] rtsp-client: don't use g_object_unref on GstRTSPSessionMedia GstRTSPSessionMedia is not a GObject type. When the GstRTSPSession is freed, it will free the media. --- gst/rtsp-server/rtsp-client.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e35efee88c..a70d38821e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1019,7 +1019,6 @@ not_found: no_stream: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); - g_object_unref (media); g_object_unref (session); return FALSE; } From 8f5d82be6d3c185524507d3509db5adc0179da9e Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Tue, 12 Jun 2012 14:33:35 +0200 Subject: [PATCH 0412/1776] rtsp-client: changed session media iteration In client_unlink_session: now don't iterate in session->medias list where items are removed by gst_rtsp_session_release_media. Instead, repeatedly remove the first item. --- gst/rtsp-server/rtsp-client.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a70d38821e..49ad173c14 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -114,15 +114,13 @@ gst_rtsp_client_init (GstRTSPClient * client) static void client_unlink_session (GstRTSPClient * client, GstRTSPSession * session) { - GList *medias; - /* unlink all media managed in this session */ - for (medias = session->medias; medias; medias = g_list_next (medias)) { - GstRTSPSessionMedia *media = medias->data; + while (g_list_length (session->medias) > 0) { + GstRTSPSessionMedia *media = g_list_first (session->medias)->data; gst_rtsp_session_media_set_state (media, GST_STATE_NULL); unlink_session_streams (client, session, media); - /* unmanage the media in the session. */ + /* unmanage the media in the session. this will modify session->medias */ gst_rtsp_session_release_media (session, media); } } From 3f49c2d8f454b1ffbd21cf88bf49b6f90de3d510 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Tue, 12 Jun 2012 14:45:39 +0200 Subject: [PATCH 0413/1776] rtsp-client: free transport on no_stream in SETUP handler --- gst/rtsp-server/rtsp-client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 49ad173c14..0c631084c1 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1018,6 +1018,7 @@ no_stream: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); g_object_unref (session); + gst_rtsp_transport_free (ct); return FALSE; } no_transport: From 853128e1c79d38c6c5a784231a47939f66b98fec Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 14 Jun 2012 09:59:06 +0200 Subject: [PATCH 0414/1776] client: don't leak transports --- gst/rtsp-server/rtsp-client.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 0c631084c1..c1194dad68 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1012,6 +1012,7 @@ not_found: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); g_object_unref (session); + gst_rtsp_transport_free (ct); return FALSE; } no_stream: @@ -1035,11 +1036,13 @@ unsupported_transports: no_pool: { send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + gst_rtsp_transport_free (ct); return FALSE; } service_unavailable: { send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + gst_rtsp_transport_free (ct); return FALSE; } } From 36df0dd8beac12c15e6c423aa28be13a1ad10dc5 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Wed, 13 Jun 2012 11:43:17 +0200 Subject: [PATCH 0415/1776] rtsp-media: don't collect media stats when going to NULL Fixes https://bugzilla.gnome.org/show_bug.cgi?id=678015 --- gst/rtsp-server/rtsp-media.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 3d2377c673..c2f37d48f0 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2017,7 +2017,8 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, } /* remember where we are */ - if (state == GST_STATE_PAUSED || old_active != media->active) + if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED || + old_active != media->active)) collect_media_stats (media); return TRUE; From df54c553ae343e69acb8b206c480ca46cbc2556b Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Tue, 19 Jun 2012 15:25:36 +0200 Subject: [PATCH 0416/1776] rtsp: add unit test Fixes https://bugzilla.gnome.org/show_bug.cgi?id=678076 --- configure.ac | 7 + tests/Makefile.am | 11 + tests/check/Makefile.am | 54 +++ tests/check/gst/rtspserver.c | 710 +++++++++++++++++++++++++++++++++++ 4 files changed, 782 insertions(+) create mode 100644 tests/check/Makefile.am create mode 100644 tests/check/gst/rtspserver.c diff --git a/configure.ac b/configure.ac index 50fe7a4638..c61282fb00 100644 --- a/configure.ac +++ b/configure.ac @@ -44,6 +44,7 @@ AS_LIBTOOL(GST, 0, 0, 0) dnl *** required versions of GStreamer stuff *** GST_REQ=0.11.0 GSTPB_REQ=0.11.0 +GSTPG_REQ=0.11.0 dnl *** autotools stuff **** @@ -142,6 +143,11 @@ GSTPB_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-base-$GST_API_VERSION --variabl AC_SUBST(GSTPB_PLUGINS_DIR) AC_MSG_NOTICE(Using GStreamer Base Plugins in $GSTPB_PLUGINS_DIR) +AG_GST_CHECK_GST_PLUGINS_GOOD($GST_API_VERSION, [$GSTPG_REQ], [yes]) +GSTPG_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-good-$GST_API_VERSION --variable pluginsdir` +AC_SUBST(GSTPG_PLUGINS_DIR) +AC_MSG_NOTICE(Using GStreamer Good Plugins in $GSTPG_PLUGINS_DIR) + AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) dnl FIXME: get rid of this by making sure gstreamer-check brings it in @@ -250,6 +256,7 @@ gst/Makefile gst/rtsp-server/Makefile examples/Makefile tests/Makefile +tests/check/Makefile bindings/Makefile bindings/vala/Makefile pkgconfig/Makefile diff --git a/tests/Makefile.am b/tests/Makefile.am index ce9caf3e21..2c845405e1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,3 +7,14 @@ AM_LDFLAGS = \ $(GST_LIBS) \ $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la +if HAVE_CHECK +SUBDIRS_CHECK = check +else +SUBDIRS_CHECK = +endif + +SUBDIRS = \ + $(SUBDIRS_CHECK) + +DIST_SUBDIRS = \ + check diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am new file mode 100644 index 0000000000..af5f6c1d21 --- /dev/null +++ b/tests/check/Makefile.am @@ -0,0 +1,54 @@ +include $(top_srcdir)/common/check.mak + +CHECK_REGISTRY = $(top_builddir)/tests/check/test-registry.reg +TEST_FILES_DIRECTORY = $(top_srcdir)/tests/files + +REGISTRY_ENVIRONMENT = \ + GST_REGISTRY=$(CHECK_REGISTRY) + +TESTS_ENVIRONMENT = \ + CK_DEFAULT_TIMEOUT=120 \ + GST_STATE_IGNORE_ELEMENTS="$(STATE_IGNORE_ELEMENTS)" \ + $(REGISTRY_ENVIRONMENT) \ + GST_PLUGIN_SYSTEM_PATH= \ + GST_PLUGIN_PATH=$(GST_PLUGINS_DIR):$(GSTPB_PLUGINS_DIR):$(GSTPG_PLUGINS_DIR) \ + GST_PLUGIN_LOADING_WHITELIST="gstreamer:gst-plugins-base:gst-plugins-good" + + +# ths core dumps of some machines have PIDs appended +CLEANFILES = core.* test-registry.* + +clean-local: clean-local-check + +$(CHECK_REGISTRY): + $(TESTS_ENVIRONMENT) + +TESTS = $(check_PROGRAMS) + +check_PROGRAMS = \ + gst/rtspserver + +# these tests don't even pass +noinst_PROGRAMS = + +AM_CFLAGS = $(GST_CFLAGS) $(GST_CHECK_CFLAGS) \ + -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ + -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS +AM_CXXFLAGS = $(GST_CXXFLAGS) $(GST_CHECK_CFLAGS) \ + -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ + -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS +LDADD = $(GST_LIBS) $(GST_CHECK_LIBS) $(GST_RTSP_SERVER_LIBS) + +SUPPRESSIONS = $(top_srcdir)/common/gst.supp + +gst_rtspserver_CFLAGS = \ + $(GST_PLUGINS_GOOD_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(AM_CFLAGS) + +gst_rtspserver_LDADD = \ + $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la \ + $(GST_PLUGINS_GOOD_LIBS) \ + $(GST_BASE_LIBS) -lgstrtsp-@GST_API_VERSION@ -lgstsdp-@GST_API_VERSION@ \ + $(LDADD) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c new file mode 100644 index 0000000000..5d1bdb0694 --- /dev/null +++ b/tests/check/gst/rtspserver.c @@ -0,0 +1,710 @@ +/* GStreamer + * + * unit test for GstRTSPServer + * + * Copyright (C) 2012 Axis Communications + * @author David Svensson Fors + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include +#include + +#define VIDEO_PIPELINE "videotestsrc ! " \ + "video/x-raw,width=352,height=288 ! " \ + "rtpgstpay name=pay0 pt=96" +#define AUDIO_PIPELINE "audiotestsrc ! " \ + "audio/x-raw,rate=8000 ! " \ + "rtpgstpay name=pay1 pt=97" + +#define TEST_MOUNT_POINT "/test" +#define TEST_PROTO "RTP/AVP" +#define TEST_ENCODING "X-GST" +#define TEST_CLOCK_RATE "90000" + +/* tested rtsp server */ +static GstRTSPServer *server = NULL; + +/* tcp port that the test server listens for rtsp requests on */ +static gint test_port = 0; + +/* id of the server's source within the GMainContext */ +static guint source_id; + +/* iterate the default main loop until there are no events to dispatch */ +static void +iterate (void) +{ + while (g_main_context_iteration (NULL, FALSE)) { + GST_DEBUG ("iteration"); + } +} + +/* returns an unused port that can be used by the test */ +static int +get_unused_port (gint type) +{ + int sock; + struct sockaddr_in addr; + socklen_t addr_len; + gint port; + + /* create socket */ + fail_unless ((sock = socket (AF_INET, type, 0)) > 0); + + /* pass port 0 to bind, which will bind to any free port */ + memset (&addr, 0, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons (0); + fail_unless (bind (sock, (struct sockaddr *) &addr, sizeof addr) == 0); + + /* ask what port was bound using getsockname */ + addr_len = sizeof addr; + memset (&addr, 0, addr_len); + fail_unless (getsockname (sock, (struct sockaddr *) &addr, &addr_len) == 0); + port = ntohs (addr.sin_port); + + /* close the socket so the port gets unbound again (and can be used by the + * test) */ + close (sock); + + return port; +} + +/* returns TRUE if the given port is not currently bound */ +static gboolean +port_is_unused (gint port, gint type) +{ + int sock; + struct sockaddr_in addr; + gboolean is_bound; + + /* create socket */ + fail_unless ((sock = socket (AF_INET, type, 0)) > 0); + + /* check if the port is already bound by trying to bind to it (again) */ + memset (&addr, 0, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons (port); + is_bound = (bind (sock, (struct sockaddr *) &addr, sizeof addr) != 0); + + /* close the socket, which will unbind if bound by our call to bind */ + close (sock); + + return !is_bound; +} + +/* get a free rtp/rtcp client port pair */ +static void +get_client_ports (GstRTSPRange * range) +{ + gint rtp_port; + gint rtcp_port; + + /* get a pair of unused ports, where the rtp port is even */ + do { + rtp_port = get_unused_port (SOCK_DGRAM); + rtcp_port = rtp_port + 1; + } while (rtp_port % 2 != 0 || !port_is_unused (rtcp_port, SOCK_DGRAM)); + range->min = rtp_port; + range->max = rtcp_port; + GST_DEBUG ("client_port=%d-%d", range->min, range->max); +} + +/* start the tested rtsp server */ +static void +start_server () +{ + GstRTSPMediaMapping *mapping; + gchar *service; + GstRTSPMediaFactory *factory; + + mapping = gst_rtsp_server_get_media_mapping (server); + + factory = gst_rtsp_media_factory_new (); + + gst_rtsp_media_factory_set_launch (factory, + "( " VIDEO_PIPELINE " " AUDIO_PIPELINE " )"); + + gst_rtsp_media_mapping_add_factory (mapping, TEST_MOUNT_POINT, factory); + g_object_unref (mapping); + + /* set port */ + test_port = get_unused_port (SOCK_STREAM); + service = g_strdup_printf ("%d", test_port); + gst_rtsp_server_set_service (server, service); + g_free (service); + + /* attach to default main context */ + source_id = gst_rtsp_server_attach (server, NULL); + fail_if (source_id == 0); + + GST_DEBUG ("rtsp server listening on port %d", test_port); +} + +/* stop the tested rtsp server */ +static void +stop_server () +{ + g_source_remove (source_id); + source_id = 0; + + GST_DEBUG ("rtsp server stopped"); +} + +/* create an rtsp connection to the server on test_port */ +static GstRTSPConnection * +connect_to_server (gint port, const gchar * mount_point) +{ + GstRTSPConnection *conn = NULL; + gchar *address; + gchar *uri_string; + GstRTSPUrl *url = NULL; + + address = gst_rtsp_server_get_address (server); + uri_string = g_strdup_printf ("rtsp://%s:%d%s", address, port, mount_point); + g_free (address); + gst_rtsp_url_parse (uri_string, &url); + g_free (uri_string); + + fail_unless (gst_rtsp_connection_create (url, &conn) == GST_RTSP_OK); + gst_rtsp_url_free (url); + + fail_unless (gst_rtsp_connection_connect (conn, NULL) == GST_RTSP_OK); + + return conn; +} + +/* create an rtsp request */ +static GstRTSPMessage * +create_request (GstRTSPConnection * conn, GstRTSPMethod method, + const gchar * control) +{ + GstRTSPMessage *request = NULL; + gchar *base_uri; + gchar *full_uri; + + base_uri = gst_rtsp_url_get_request_uri (gst_rtsp_connection_get_url (conn)); + full_uri = g_strdup_printf ("%s/%s", base_uri, control ? control : ""); + g_free (base_uri); + if (gst_rtsp_message_new_request (&request, method, full_uri) != GST_RTSP_OK) { + GST_DEBUG ("failed to create request object"); + g_free (full_uri); + return NULL; + } + g_free (full_uri); + return request; +} + +/* send an rtsp request */ +static gboolean +send_request (GstRTSPConnection * conn, GstRTSPMessage * request) +{ + if (gst_rtsp_connection_send (conn, request, NULL) != GST_RTSP_OK) { + GST_DEBUG ("failed to send request"); + return FALSE; + } + return TRUE; +} + +/* read rtsp response. response must be freed by the caller */ +static GstRTSPMessage * +read_response (GstRTSPConnection * conn) +{ + GstRTSPMessage *response = NULL; + + if (gst_rtsp_message_new (&response) != GST_RTSP_OK) { + GST_DEBUG ("failed to create response object"); + return NULL; + } + if (gst_rtsp_connection_receive (conn, response, NULL) != GST_RTSP_OK) { + GST_DEBUG ("failed to read response"); + gst_rtsp_message_free (response); + return NULL; + } + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + return response; +} + +/* send an rtsp request and receive response. gchar** parameters are out + * parameters that have to be freed by the caller */ +static GstRTSPStatusCode +do_request (GstRTSPConnection * conn, GstRTSPMethod method, + const gchar * control, const gchar * session_in, const gchar * transport_in, + gchar ** content_type, gchar ** content_base, gchar ** body, + gchar ** session_out, gchar ** transport_out) +{ + GstRTSPMessage *request; + GstRTSPMessage *response; + GstRTSPStatusCode code; + gchar *value; + + /* create request */ + request = create_request (conn, method, control); + + /* add headers */ + if (session_in) { + gst_rtsp_message_add_header (request, GST_RTSP_HDR_SESSION, session_in); + } + if (transport_in) { + gst_rtsp_message_add_header (request, GST_RTSP_HDR_TRANSPORT, transport_in); + } + + /* send request */ + fail_unless (send_request (conn, request)); + gst_rtsp_message_free (request); + + iterate (); + + /* read response */ + response = read_response (conn); + + /* check status line */ + gst_rtsp_message_parse_response (response, &code, NULL, NULL); + if (code != GST_RTSP_STS_OK) { + gst_rtsp_message_free (response); + return code; + } + + /* get information from response */ + if (content_type) { + gst_rtsp_message_get_header (response, GST_RTSP_HDR_CONTENT_TYPE, + &value, 0); + *content_type = g_strdup (value); + } + if (content_base) { + gst_rtsp_message_get_header (response, GST_RTSP_HDR_CONTENT_BASE, + &value, 0); + *content_base = g_strdup (value); + } + if (body) { + *body = g_malloc (response->body_size + 1); + strncpy (*body, (gchar *) response->body, response->body_size); + } + if (session_out) { + gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &value, 0); + if (session_in) { + /* check that we got the same session back */ + fail_unless (!g_strcmp0 (value, session_in)); + } + *session_out = g_strdup (value); + } + if (transport_out) { + gst_rtsp_message_get_header (response, GST_RTSP_HDR_TRANSPORT, &value, 0); + *transport_out = g_strdup (value); + } + + gst_rtsp_message_free (response); + return code; +} + +/* send an rtsp request with a method and a session, and receive response */ +static GstRTSPStatusCode +do_simple_request (GstRTSPConnection * conn, GstRTSPMethod method, + const gchar * session) +{ + return do_request (conn, method, NULL, session, NULL, NULL, NULL, + NULL, NULL, NULL); +} + +/* send a DESCRIBE request and receive response. returns a received + * GstSDPMessage that must be freed by the caller */ +static GstSDPMessage * +do_describe (GstRTSPConnection * conn, const gchar * mount_point) +{ + GstSDPMessage *sdp_message; + gchar *content_type; + gchar *content_base; + gchar *body; + gchar *address; + gchar *expected_content_base; + + /* send DESCRIBE request */ + fail_unless (do_request (conn, GST_RTSP_DESCRIBE, NULL, NULL, NULL, + &content_type, &content_base, &body, NULL, NULL) == GST_RTSP_STS_OK); + + /* check response values */ + fail_unless (!g_strcmp0 (content_type, "application/sdp")); + address = gst_rtsp_server_get_address (server); + expected_content_base = + g_strdup_printf ("rtsp://%s:%d%s/", address, test_port, mount_point); + fail_unless (!g_strcmp0 (content_base, expected_content_base)); + + /* create sdp message */ + fail_unless (gst_sdp_message_new (&sdp_message) == GST_SDP_OK); + fail_unless (gst_sdp_message_parse_buffer ((guint8 *) body, + strlen (body), sdp_message) == GST_SDP_OK); + + /* clean up */ + g_free (content_type); + g_free (content_base); + g_free (body); + g_free (address); + g_free (expected_content_base); + + return sdp_message; +} + +/* send a SETUP request and receive response. if *session is not NULL, + * it is used in the request. otherwise, *session is set to a returned + * session string that must be freed by the caller. the returned + * transport must be freed by the caller. */ +static GstRTSPStatusCode +do_setup (GstRTSPConnection * conn, const gchar * control, + const GstRTSPRange * client_ports, gchar ** session, + GstRTSPTransport ** transport) +{ + GstRTSPStatusCode code; + gchar *session_in = NULL; + gchar *transport_string_in = NULL; + gchar **session_out = NULL; + gchar *transport_string_out = NULL; + + /* prepare and send SETUP request */ + if (session) { + if (*session) { + session_in = *session; + } else { + session_out = session; + } + } + transport_string_in = + g_strdup_printf (TEST_PROTO ";unicast;client_port=%d-%d", + client_ports->min, client_ports->max); + code = + do_request (conn, GST_RTSP_SETUP, control, session_in, + transport_string_in, NULL, NULL, NULL, session_out, + &transport_string_out); + g_free (transport_string_in); + + if (transport_string_out) { + /* create transport */ + fail_unless (gst_rtsp_transport_new (transport) == GST_RTSP_OK); + fail_unless (gst_rtsp_transport_parse (transport_string_out, + *transport) == GST_RTSP_OK); + g_free (transport_string_out); + } + + return code; +} + +/* fixture setup function */ +static void +setup (void) +{ + server = gst_rtsp_server_new (); +} + +/* fixture clean-up function */ +static void +teardown (void) +{ + if (server) { + g_object_unref (server); + server = NULL; + } + test_port = 0; +} + +GST_START_TEST (test_connect) +{ + GstRTSPConnection *conn; + + start_server (); + + /* connect to server */ + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + /* clean up */ + gst_rtsp_connection_free (conn); + stop_server (); + + /* iterate so the clean-up can finish */ + iterate (); +} + +GST_END_TEST; + +GST_START_TEST (test_describe) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + gint32 format; + gchar *expected_rtpmap; + const gchar *rtpmap; + const gchar *control_video; + const gchar *control_audio; + + start_server (); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + /* send DESCRIBE request */ + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + + /* check video sdp */ + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + fail_unless (!g_strcmp0 (gst_sdp_media_get_proto (sdp_media), TEST_PROTO)); + fail_unless (gst_sdp_media_formats_len (sdp_media) == 1); + sscanf (gst_sdp_media_get_format (sdp_media, 0), "%" G_GINT32_FORMAT, + &format); + expected_rtpmap = + g_strdup_printf ("%d " TEST_ENCODING "/" TEST_CLOCK_RATE, format); + rtpmap = gst_sdp_media_get_attribute_val (sdp_media, "rtpmap"); + fail_unless (!g_strcmp0 (rtpmap, expected_rtpmap)); + g_free (expected_rtpmap); + control_video = gst_sdp_media_get_attribute_val (sdp_media, "control"); + fail_unless (!g_strcmp0 (control_video, "stream=0")); + + /* check audio sdp */ + sdp_media = gst_sdp_message_get_media (sdp_message, 1); + fail_unless (!g_strcmp0 (gst_sdp_media_get_proto (sdp_media), TEST_PROTO)); + fail_unless (gst_sdp_media_formats_len (sdp_media) == 1); + sscanf (gst_sdp_media_get_format (sdp_media, 0), "%" G_GINT32_FORMAT, + &format); + expected_rtpmap = + g_strdup_printf ("%d " TEST_ENCODING "/" TEST_CLOCK_RATE, format); + rtpmap = gst_sdp_media_get_attribute_val (sdp_media, "rtpmap"); + fail_unless (!g_strcmp0 (rtpmap, expected_rtpmap)); + g_free (expected_rtpmap); + control_audio = gst_sdp_media_get_attribute_val (sdp_media, "control"); + fail_unless (!g_strcmp0 (control_audio, "stream=1")); + + /* clean up and iterate so the clean-up can finish */ + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); +} + +GST_END_TEST; + +GST_START_TEST (test_describe_non_existing_mount_point) +{ + GstRTSPConnection *conn; + + start_server (); + + /* send DESCRIBE request for a non-existing mount point + * and check that we get a 404 Not Found */ + conn = connect_to_server (test_port, "/non-existing"); + fail_unless (do_simple_request (conn, GST_RTSP_DESCRIBE, NULL) + == GST_RTSP_STS_NOT_FOUND); + + /* clean up and iterate so the clean-up can finish */ + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); +} + +GST_END_TEST; + +GST_START_TEST (test_setup) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + const gchar *audio_control; + GstRTSPRange client_ports; + gchar *session = NULL; + GstRTSPTransport *video_transport = NULL; + GstRTSPTransport *audio_transport = NULL; + + start_server (); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + sdp_media = gst_sdp_message_get_media (sdp_message, 1); + audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports (&client_ports); + + /* send SETUP request for video */ + fail_unless (do_setup (conn, video_control, &client_ports, &session, + &video_transport) == GST_RTSP_STS_OK); + GST_DEBUG ("set up video %s, got session '%s'", video_control, session); + + /* check response from SETUP */ + fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP); + fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP); + fail_unless (video_transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP); + fail_unless (video_transport->mode_play); + gst_rtsp_transport_free (video_transport); + + /* send SETUP request for audio */ + fail_unless (do_setup (conn, audio_control, &client_ports, &session, + &audio_transport) == GST_RTSP_STS_OK); + GST_DEBUG ("set up audio %s with session '%s'", audio_control, session); + + /* check response from SETUP */ + fail_unless (audio_transport->trans == GST_RTSP_TRANS_RTP); + fail_unless (audio_transport->profile == GST_RTSP_PROFILE_AVP); + fail_unless (audio_transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP); + fail_unless (audio_transport->mode_play); + gst_rtsp_transport_free (audio_transport); + + /* clean up and iterate so the clean-up can finish */ + g_free (session); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); +} + +GST_END_TEST; + +GST_START_TEST (test_setup_non_existing_stream) +{ + GstRTSPConnection *conn; + GstRTSPRange client_ports; + + start_server (); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + get_client_ports (&client_ports); + + /* send SETUP request with a non-existing stream and check that we get a + * 404 Not Found */ + fail_unless (do_setup (conn, "stream=7", &client_ports, NULL, + NULL) == GST_RTSP_STS_NOT_FOUND); + + /* clean up and iterate so the clean-up can finish */ + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); + + /* need to unref the server here, otherwise threads will remain + * and teardown won't be run */ + g_object_unref (server); + server = NULL; +} + +GST_END_TEST; + +GST_START_TEST (test_play) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + const gchar *audio_control; + GstRTSPRange client_port; + gchar *session = NULL; + GstRTSPTransport *video_transport = NULL; + GstRTSPTransport *audio_transport = NULL; + + start_server (); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + sdp_media = gst_sdp_message_get_media (sdp_message, 1); + audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports (&client_port); + + /* do SETUP for video and audio */ + fail_unless (do_setup (conn, video_control, &client_port, &session, + &video_transport) == GST_RTSP_STS_OK); + fail_unless (do_setup (conn, audio_control, &client_port, &session, + &audio_transport) == GST_RTSP_STS_OK); + + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_PLAY, + session) == GST_RTSP_STS_OK); + + /* send TEARDOWN request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session) == GST_RTSP_STS_OK); + + /* clean up and iterate so the clean-up can finish */ + g_free (session); + gst_rtsp_transport_free (video_transport); + gst_rtsp_transport_free (audio_transport); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); +} + +GST_END_TEST; + +GST_START_TEST (test_play_without_session) +{ + GstRTSPConnection *conn; + + start_server (); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + /* send PLAY request without a session and check that we get a + * 454 Session Not Found */ + fail_unless (do_simple_request (conn, GST_RTSP_PLAY, + NULL) == GST_RTSP_STS_SESSION_NOT_FOUND); + + /* clean up and iterate so the clean-up can finish */ + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); +} + +GST_END_TEST; + +static Suite * +rtspserver_suite (void) +{ + Suite *s = suite_create ("rtspserver"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_add_checked_fixture (tc, setup, teardown); + tcase_set_timeout (tc, 20); + tcase_add_test (tc, test_connect); + tcase_add_test (tc, test_describe); + tcase_add_test (tc, test_describe_non_existing_mount_point); + tcase_add_test (tc, test_setup); + tcase_add_test (tc, test_setup_non_existing_stream); + tcase_add_test (tc, test_play); + tcase_add_test (tc, test_play_without_session); + + return s; +} + +GST_CHECK_MAIN (rtspserver); From 217a46e4c121fbac22f471abb4cc003220bad1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 23 Jun 2012 15:06:11 +0100 Subject: [PATCH 0417/1776] rtsp-media: update for gst_element_make_from_uri() changes --- gst/rtsp-server/rtsp-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c2f37d48f0..43290cfc05 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -869,7 +869,7 @@ alloc_udp_ports (GstRTSPMedia * media, GstRTSPMediaStream * stream) /* try to allocate 2 UDP ports, the RTP port should be an even * number and the RTCP port should be the next (uneven) port */ again: - udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL); + udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); if (udpsrc0 == NULL) goto no_udp_protocol; g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL); @@ -905,7 +905,7 @@ again: } /* allocate port+1 for RTCP now */ - udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL); + udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); if (udpsrc1 == NULL) goto no_udp_rtcp_protocol; From 4743624bb51b72fb1c566c2b7b8950cedd922409 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Mon, 25 Jun 2012 14:28:10 +0200 Subject: [PATCH 0418/1776] Have unit test get header from source dir, not installed dir This makes compilation of unit tests work in a build directory other than the source directory. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=678789 --- tests/check/Makefile.am | 4 ++++ tests/check/gst/rtspserver.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index af5f6c1d21..b32412e7c8 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -41,7 +41,11 @@ LDADD = $(GST_LIBS) $(GST_CHECK_LIBS) $(GST_RTSP_SERVER_LIBS) SUPPRESSIONS = $(top_srcdir)/common/gst.supp +gst_rtspserver_SOURCES = gst/rtspserver.c \ + $(top_srcdir)/gst/rtsp-server/rtsp-server.h + gst_rtspserver_CFLAGS = \ + -I$(top_srcdir)/gst/rtsp-server \ $(GST_PLUGINS_GOOD_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) \ diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 5d1bdb0694..84d9bfe974 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -22,12 +22,13 @@ */ #include -#include #include #include #include +#include "rtsp-server.h" + #define VIDEO_PIPELINE "videotestsrc ! " \ "video/x-raw,width=352,height=288 ! " \ "rtpgstpay name=pay0 pt=96" From 86e53af34a12a1e23613fd1a3dac2be3efbbbf99 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Tue, 3 Jul 2012 13:26:30 +0200 Subject: [PATCH 0419/1776] rtsp: Handle the blocksize parameter Fixes https://bugzilla.gnome.org/show_bug.cgi?id=679325 --- gst/rtsp-server/rtsp-client.c | 35 ++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.c | 36 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 4 ++++ 3 files changed, 75 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c1194dad68..57d1441baa 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -817,6 +817,31 @@ do_keepalive (GstRTSPSession * session) gst_rtsp_session_touch (session); } +static gboolean +handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request) +{ + gchar *blocksize_str; + gboolean ret = TRUE; + + if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_BLOCKSIZE, + &blocksize_str, 0) == GST_RTSP_OK) { + guint64 blocksize; + gchar *end; + + blocksize = g_ascii_strtoull (blocksize_str, &end, 10); + if (end == blocksize_str) { + GST_ERROR ("failed to parse blocksize"); + ret = FALSE; + } else { + if (blocksize > G_MAXUINT) + blocksize = G_MAXUINT; + gst_rtsp_media_handle_mtu (media, (guint)blocksize); + } + } + + return ret; +} + static gboolean handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) { @@ -944,6 +969,9 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) state->sessmedia = media; + if (!handle_blocksize (media->media, state->request)) + goto invalid_blocksize; + /* we have a valid transport now, set the destination of the client. */ g_free (ct->destination); if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { @@ -1015,6 +1043,13 @@ not_found: gst_rtsp_transport_free (ct); return FALSE; } +invalid_blocksize: + { + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + g_object_unref (session); + gst_rtsp_transport_free (ct); + return FALSE; + } no_stream: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 43290cfc05..18f2e8554f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -72,6 +72,7 @@ static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message); static gboolean default_unprepare (GstRTSPMedia * media); static void unlock_streams (GstRTSPMedia * media); +static void default_handle_mtu (GstRTSPMedia * media, guint mtu); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; @@ -142,6 +143,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->handle_message = default_handle_message; klass->unprepare = default_unprepare; + klass->handle_mtu = default_handle_mtu; ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); } @@ -2078,3 +2080,37 @@ gst_rtsp_media_remove_elements (GstRTSPMedia * media) gst_object_unref (media->pipeline); media->pipeline = NULL; } + +static void +default_handle_mtu (GstRTSPMedia * media, guint mtu) +{ + gint i; + + for (i = 0; i < media->streams->len; i++) { + GstRTSPMediaStream *stream; + + GST_INFO ("Setting mtu %d for stream %d", mtu, i); + + stream = g_array_index (media->streams, GstRTSPMediaStream *, i); + + g_object_set (G_OBJECT (stream->payloader), "mtu", mtu, NULL); + } +} + +/** + * gst_rtsp_media_handle_mtu: + * @media: a #GstRTSPMedia + * @mtu: the mtu + * + * Set maximum size of one RTP packet on the payloaders. + */ +void +gst_rtsp_media_handle_mtu (GstRTSPMedia * media, guint mtu) +{ + GstRTSPMediaClass *klass; + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + + if (klass->handle_mtu) + klass->handle_mtu (media, mtu); +} diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index e48b013e88..fb86a288c5 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -238,6 +238,7 @@ struct _GstRTSPMedia { * @handle_message: handle a message * @unprepare: the default implementation sets the pipeline's state * to GST_STATE_NULL. + * @handle_mtu: handle a mtu * * The RTSP media class */ @@ -252,6 +253,7 @@ struct _GstRTSPMediaClass { /* vmethods */ gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message); gboolean (*unprepare) (GstRTSPMedia *media); + void (*handle_mtu) (GstRTSPMedia *media, guint mtu); /* signals */ gboolean (*prepared) (GstRTSPMedia *media); @@ -306,6 +308,8 @@ gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstS void gst_rtsp_media_remove_elements (GstRTSPMedia *media); +void gst_rtsp_media_handle_mtu (GstRTSPMedia *media, guint mtu); + void gst_rtsp_media_trans_cleanup (GstRTSPMediaTrans *trans); G_END_DECLS From ed66f974dd14a66ae72ad8fdd34cb84376bf226a Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Tue, 3 Jul 2012 18:06:00 +0200 Subject: [PATCH 0420/1776] rtsp-server: use an existing socket to establish HTTP tunnel Make it possible to transfer a socket from an HTTP server to be used as an RTSP over HTTP tunnel. --- gst/rtsp-server/rtsp-client.c | 108 ++++++++++++++++++++++++---------- gst/rtsp-server/rtsp-client.h | 7 +++ gst/rtsp-server/rtsp-server.c | 59 +++++++++++++++++++ gst/rtsp-server/rtsp-server.h | 2 + 4 files changed, 145 insertions(+), 31 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 57d1441baa..adc892478a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1904,26 +1904,10 @@ client_watch_notify (GstRTSPClient * client) g_object_unref (client); } -/** - * gst_rtsp_client_attach: - * @client: a #GstRTSPClient - * @socket: a #GSocket - * @cancellable: a #GCancellable - * @error: a #GError - * - * Accept a new connection for @client on @socket. - * - * This function should be called when the client properties and urls are fully - * configured and the client is ready to start. - * - * Returns: %TRUE if the client could be accepted. - */ -gboolean -gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, - GCancellable * cancellable, GError ** error) +static gboolean +attach_client (GstRTSPClient * client, GSocket * socket, + GstRTSPConnection *conn, GError ** error) { - GstRTSPConnection *conn; - GstRTSPResult res; GSocket *read_socket; GSocketAddress *addres; GSource *source; @@ -1933,10 +1917,6 @@ gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, socklen_t addrlen; gchar ip[INET6_ADDRSTRLEN]; - /* a new client connected. */ - GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, cancellable), - accept_failed); - read_socket = gst_rtsp_connection_get_read_socket (conn); client->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6; @@ -1982,14 +1962,6 @@ gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, return TRUE; /* ERRORS */ -accept_failed: - { - gchar *str = gst_rtsp_strresult (res); - - GST_ERROR ("Could not accept client on server socket %p: %s", socket, str); - g_free (str); - return FALSE; - } no_address: { GST_ERROR ("could not get remote address %s", (*error)->message); @@ -2007,3 +1979,77 @@ getnameinfo_failed: return FALSE; } } + +/** + * gst_rtsp_client_create_from_socket: + * @client: a #GstRTSPClient + * @socket: a #GSocket + * @ip: the IP address of the remote client + * @port: the port used by the other end + * @initial_buffer: any initial data that was already read from the socket + * @error: a #GError + * + * Take an existing network socket and use it for an RTSP connection. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_client_create_from_socket (GstRTSPClient * client, GSocket * socket, + const gchar * ip, gint port, const gchar * initial_buffer, GError ** error) +{ + GstRTSPConnection *conn; + GstRTSPResult res; + + GST_RTSP_CHECK (gst_rtsp_connection_create_from_socket (socket, ip, port, + initial_buffer, &conn), no_connection); + + return attach_client (client, socket, conn, error); + + /* ERRORS */ +no_connection: + { + gchar *str = gst_rtsp_strresult (res); + + GST_ERROR ("could not create connection from socket %p: %s", socket, str); + g_free (str); + return FALSE; + } +} + +/** + * gst_rtsp_client_attach: + * @client: a #GstRTSPClient + * @socket: a #GSocket + * @cancellable: a #GCancellable + * @error: a #GError + * + * Accept a new connection for @client on @socket. + * + * This function should be called when the client properties and urls are fully + * configured and the client is ready to start. + * + * Returns: %TRUE if the client could be accepted. + */ +gboolean +gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, + GCancellable * cancellable, GError ** error) +{ + GstRTSPConnection *conn; + GstRTSPResult res; + + /* a new client connected. */ + GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, cancellable), + accept_failed); + + return attach_client (client, socket, conn, error); + + /* ERRORS */ +accept_failed: + { + gchar *str = gst_rtsp_strresult (res); + + GST_ERROR ("Could not accept client on server socket %p: %s", socket, str); + g_free (str); + return FALSE; + } +} diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index bc56cc7c55..97bb0c2417 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -136,6 +136,13 @@ gboolean gst_rtsp_client_accept (GstRTSPClient *client, GCancellable *cancellable, GError **error); +gboolean gst_rtsp_client_create_from_socket(GstRTSPClient * client, + GSocket *socket, + const gchar * ip, + gint port, + const gchar *initial_buffer, + GError **error); + G_END_DECLS #endif /* __GST_RTSP_CLIENT_H__ */ diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index c4b951e22f..9c4594a360 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -779,6 +779,65 @@ accept_failed: } } +/** + * gst_rtsp_server_transfer_connection: + * @server: a #GstRTSPServer + * @socket: a network socket + * @ip: the IP address of the remote client + * @port: the port used by the other end + * @initial_buffer: any initial data that was already read from the socket + * + * Take an existing network socket and use it for an RTSP connection. This + * is used when transferring a socket from an HTTP server which should be used + * as an RTSP over HTTP tunnel. The @initial_buffer contains any remaining data + * that the HTTP server read from the socket while parsing the HTTP header. + * + * Returns: TRUE if all was ok, FALSE if an error occured. + */ +gboolean +gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket * socket, + const gchar * ip, gint port, const gchar *initial_buffer) +{ + GstRTSPClient *client = NULL; + GstRTSPServerClass *klass; + GError *error = NULL; + + klass = GST_RTSP_SERVER_GET_CLASS (server); + + if (klass->create_client) + client = klass->create_client (server); + if (client == NULL) + goto client_failed; + + /* a new client connected, create a client object to handle the client. */ + if (!gst_rtsp_client_create_from_socket (client, socket, ip, port, + initial_buffer, &error)) { + goto transfer_failed; + } + + /* manage the client connection */ + manage_client (server, client); + + g_signal_emit (server, gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED], 0, + client); + + return TRUE; + + /* ERRORS */ +client_failed: + { + GST_ERROR_OBJECT (server, "failed to create a client"); + return FALSE; + } +transfer_failed: + { + GST_ERROR_OBJECT (server, "failed to accept client: %s", error->message); + g_error_free (error); + gst_object_unref (client); + return FALSE; + } +} + /** * gst_rtsp_server_io_func: * @socket: a #GSocket diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 1c5cb0c632..595f2f1bd5 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -116,6 +116,8 @@ GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *serve void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server); +gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket *socket, const gchar * ip, gint port, const gchar *initial_buffer); + gboolean gst_rtsp_server_io_func (GSocket *socket, GIOCondition condition, GstRTSPServer *server); From f3050206366739ebc24cf17689d5058a9e3e4c57 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 10 Jul 2012 11:39:58 +0200 Subject: [PATCH 0421/1776] client: fix docs --- gst/rtsp-server/rtsp-client.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index adc892478a..9e9332f6c9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -824,7 +824,7 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request) gboolean ret = TRUE; if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_BLOCKSIZE, - &blocksize_str, 0) == GST_RTSP_OK) { + &blocksize_str, 0) == GST_RTSP_OK) { guint64 blocksize; gchar *end; @@ -835,7 +835,7 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request) } else { if (blocksize > G_MAXUINT) blocksize = G_MAXUINT; - gst_rtsp_media_handle_mtu (media, (guint)blocksize); + gst_rtsp_media_handle_mtu (media, (guint) blocksize); } } @@ -1906,7 +1906,7 @@ client_watch_notify (GstRTSPClient * client) static gboolean attach_client (GstRTSPClient * client, GSocket * socket, - GstRTSPConnection *conn, GError ** error) + GstRTSPConnection * conn, GError ** error) { GSocket *read_socket; GSocketAddress *addres; @@ -2001,7 +2001,7 @@ gst_rtsp_client_create_from_socket (GstRTSPClient * client, GSocket * socket, GstRTSPResult res; GST_RTSP_CHECK (gst_rtsp_connection_create_from_socket (socket, ip, port, - initial_buffer, &conn), no_connection); + initial_buffer, &conn), no_connection); return attach_client (client, socket, conn, error); @@ -2017,7 +2017,7 @@ no_connection: } /** - * gst_rtsp_client_attach: + * gst_rtsp_client_accept: * @client: a #GstRTSPClient * @socket: a #GSocket * @cancellable: a #GCancellable From d803c8e29f70d23bd1b6da78d7b1b548d15d23f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 23 Jul 2012 08:48:25 +0200 Subject: [PATCH 0422/1776] Automatic update of common submodule From 98e386f to 94ccf4c --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 98e386f58e..94ccf4cadb 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 98e386f58eb299db9228ba04b433526b0bc89311 +Subproject commit 94ccf4cadba30549c22a13a5b9c95cc7548060ed From 228e2ccc2d7fb5df5620645b372069376b67683a Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Wed, 18 Jul 2012 15:54:49 +0200 Subject: [PATCH 0423/1776] rtsp-client: make create_sdp virtual method Fixes https://bugzilla.gnome.org/show_bug.cgi?id=680173 --- gst/rtsp-server/rtsp-client.c | 9 ++++++++- gst/rtsp-server/rtsp-client.h | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 9e9332f6c9..159a718a43 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -64,6 +64,7 @@ static void gst_rtsp_client_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_client_finalize (GObject * obj); +static GstSDPMessage * create_sdp (GstRTSPClient * client, GstRTSPMedia * media); static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session); static void unlink_session_streams (GstRTSPClient * client, @@ -82,6 +83,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gobject_class->set_property = gst_rtsp_client_set_property; gobject_class->finalize = gst_rtsp_client_finalize; + klass->create_sdp = create_sdp; + g_object_class_install_property (gobject_class, PROP_SESSION_POOL, g_param_spec_object ("session-pool", "Session Pool", "The session pool to use for client session", @@ -1143,6 +1146,9 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) guint i, str_len; gchar *str, *content_base; GstRTSPMedia *media; + GstRTSPClientClass *klass; + + klass = GST_RTSP_CLIENT_GET_CLASS (client); /* check what kind of format is accepted, we don't really do anything with it * and always return SDP for now. */ @@ -1163,8 +1169,9 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) if (!(media = find_media (client, state))) goto no_media; + /* create an SDP for the media object on this client */ - if (!(sdp = create_sdp (client, media))) + if (!(sdp = klass->create_sdp (client, media))) goto no_sdp; g_object_unref (media); diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 97bb0c2417..dae2014ba1 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -34,6 +34,7 @@ typedef struct _GstRTSPClientState GstRTSPClientState; #include "rtsp-media-mapping.h" #include "rtsp-session-pool.h" #include "rtsp-auth.h" +#include "rtsp-sdp.h" #define GST_TYPE_RTSP_CLIENT (gst_rtsp_client_get_type ()) #define GST_IS_RTSP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_CLIENT)) @@ -108,6 +109,8 @@ struct _GstRTSPClient { struct _GstRTSPClientClass { GObjectClass parent_class; + GstSDPMessage * (*create_sdp) (GstRTSPClient *client, GstRTSPMedia *media); + /* signals */ void (*closed) (GstRTSPClient *client); }; From 41f9875366d1f85c8700631b82ab19f0e662c7e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 5 Aug 2012 16:43:53 +0100 Subject: [PATCH 0424/1776] Automatic update of common submodule From 94ccf4c to 668acee --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 94ccf4cadb..668acee6b7 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 94ccf4cadba30549c22a13a5b9c95cc7548060ed +Subproject commit 668acee6b7f0967e841523f78f31152b3cb91302 From 50e4c7e8c494d4fa1ec57d67f009f24d1ff92ef8 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Wed, 15 Aug 2012 15:54:32 +0200 Subject: [PATCH 0425/1776] rtsp-server: fixed segfault in gst_rtsp_server_create_socket Do not assume that *error is set in g_socket_address_enumerator_next. Added test_bind_already_in_use unit-test. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=681914 --- gst/rtsp-server/rtsp-server.c | 7 +++++-- tests/check/gst/rtspserver.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 9c4594a360..b59ccdb8cb 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -594,7 +594,10 @@ gst_rtsp_server_create_socket (GstRTSPServer * server, sockaddr = g_socket_address_enumerator_next (enumerator, cancellable, error); if (!sockaddr) { - GST_DEBUG_OBJECT (server, "no more addresses %s", (*error)->message); + if (!*error) + GST_DEBUG_OBJECT (server, "no more addresses %s", *error ? (*error)->message : ""); + else + GST_DEBUG_OBJECT (server, "failed to retrieve next address %s", (*error)->message); break; } @@ -696,7 +699,7 @@ close_error: g_error_free (sock_error); } if (bind_error) { - if (error == NULL) + if ((error == NULL) || (*error == NULL)) g_propagate_error (error, bind_error); else g_error_free (bind_error); diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 84d9bfe974..3aec449927 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -688,6 +688,39 @@ GST_START_TEST (test_play_without_session) GST_END_TEST; +GST_START_TEST (test_bind_already_in_use) +{ + GstRTSPServer *serv; + GSocketService *service; + GError *error = NULL; + guint16 port; + gchar *port_str; + + serv = gst_rtsp_server_new (); + service = g_socket_service_new (); + + /* bind service to port */ + port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (service), NULL, &error); + g_assert_no_error (error); + + port_str = g_strdup_printf ("%d\n", port); + + /* try to bind server to the same port */ + g_object_set (serv, "service", port_str, NULL); + g_free (port_str); + + /* attach to default main context */ + fail_unless (gst_rtsp_server_attach (serv, NULL) == 0); + + /* cleanup */ + g_object_unref (serv); + g_socket_listener_close (G_SOCKET_LISTENER (service)); + g_object_unref (service); +} + +GST_END_TEST; + + static Suite * rtspserver_suite (void) { @@ -704,6 +737,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_setup_non_existing_stream); tcase_add_test (tc, test_play); tcase_add_test (tc, test_play_without_session); + tcase_add_test (tc, test_bind_already_in_use); return s; } From 02b17d6baa87ad4e03cd1e415c73b044c3abf5dc Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 22 Aug 2012 13:34:55 +0200 Subject: [PATCH 0426/1776] Automatic update of common submodule From 668acee to 4f962f7 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 668acee6b7..4f962f7835 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 668acee6b7f0967e841523f78f31152b3cb91302 +Subproject commit 4f962f78357a11e545510d48227f41af24bfaab7 From ebc4ce4de126050106b41829d116e181ff8e7929 Mon Sep 17 00:00:00 2001 From: Aleix Conchillo Flaque Date: Thu, 30 Aug 2012 12:03:27 -0700 Subject: [PATCH 0427/1776] add new-session signal to rtsp-client (fixes #683058) --- gst/rtsp-server/rtsp-client.c | 9 +++++++++ gst/rtsp-server/rtsp-client.h | 1 + 2 files changed, 10 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 159a718a43..4742ad3b81 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -50,6 +50,7 @@ enum enum { SIGNAL_CLOSED, + SIGNAL_NEW_SESSION, SIGNAL_LAST }; @@ -102,6 +103,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + gst_rtsp_client_signals[SIGNAL_NEW_SESSION] = + g_signal_new ("new-session", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstRTSPClientClass, new_session), NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION); + tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); g_mutex_init (&tunnels_lock); @@ -1313,6 +1319,9 @@ client_watch_session (GstRTSPClient * client, GstRTSPSession * session) g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client); client->sessions = g_list_prepend (client->sessions, session); + + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0, + session); } static void diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index dae2014ba1..9acfa65c46 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -113,6 +113,7 @@ struct _GstRTSPClientClass { /* signals */ void (*closed) (GstRTSPClient *client); + void (*new_session) (GstRTSPClient *client, GstRTSPSession *session); }; GType gst_rtsp_client_get_type (void); From bef57648b84221a2ce3054fae7702b1ad12271c9 Mon Sep 17 00:00:00 2001 From: Aleix Conchillo Flaque Date: Mon, 3 Sep 2012 10:48:14 -0700 Subject: [PATCH 0428/1776] rtsp-client: add signals for rtsp requests (fixes #683287) --- gst/rtsp-server/rtsp-client.c | 83 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-client.h | 12 ++++- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4742ad3b81..89a8b64c75 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -51,6 +51,14 @@ enum { SIGNAL_CLOSED, SIGNAL_NEW_SESSION, + SIGNAL_OPTIONS_REQUEST, + SIGNAL_DESCRIBE_REQUEST, + SIGNAL_SETUP_REQUEST, + SIGNAL_PLAY_REQUEST, + SIGNAL_PAUSE_REQUEST, + SIGNAL_TEARDOWN_REQUEST, + SIGNAL_SET_PARAMETER_REQUEST, + SIGNAL_GET_PARAMETER_REQUEST, SIGNAL_LAST }; @@ -108,6 +116,54 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) G_STRUCT_OFFSET (GstRTSPClientClass, new_session), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION); + gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST] = + g_signal_new ("options-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, options_request), + NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, + G_TYPE_POINTER); + + gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST] = + g_signal_new ("describe-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, describe_request), + NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, + G_TYPE_POINTER); + + gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST] = + g_signal_new ("setup-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, setup_request), + NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, + G_TYPE_POINTER); + + gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST] = + g_signal_new ("play-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, play_request), + NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, + G_TYPE_POINTER); + + gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST] = + g_signal_new ("pause-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, pause_request), + NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, + G_TYPE_POINTER); + + gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST] = + g_signal_new ("teardown-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, teardown_request), + NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, + G_TYPE_POINTER); + + gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST] = + g_signal_new ("set-parameter-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + set_parameter_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST] = + g_signal_new ("get-parameter-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + get_parameter_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); g_mutex_init (&tunnels_lock); @@ -544,6 +600,10 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) send_response (client, session, state->response); + /* we emit the signal before closing the connection */ + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], + 0, state); + close_connection (client); return TRUE; @@ -583,6 +643,10 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state) send_response (client, state->session, state->response); } + + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST], + 0, state); + return TRUE; /* ERRORS */ @@ -615,6 +679,10 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state) send_response (client, state->session, state->response); } + + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST], + 0, state); + return TRUE; /* ERRORS */ @@ -663,6 +731,9 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) /* the state is now READY */ media->state = GST_RTSP_STATE_READY; + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST], + 0, state); + return TRUE; /* ERRORS */ @@ -798,6 +869,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) media->state = GST_RTSP_STATE_PLAYING; + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST], + 0, state); + return TRUE; /* ERRORS */ @@ -1037,6 +1111,9 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) } g_object_unref (session); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], + 0, state); + return TRUE; /* ERRORS */ @@ -1216,6 +1293,9 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) send_response (client, state->session, state->response); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST], + 0, state); + return TRUE; /* ERRORS */ @@ -1255,6 +1335,9 @@ handle_options_request (GstRTSPClient * client, GstRTSPClientState * state) send_response (client, state->session, state->response); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST], + 0, state); + return TRUE; } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 9acfa65c46..5baf21e7c1 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -112,8 +112,16 @@ struct _GstRTSPClientClass { GstSDPMessage * (*create_sdp) (GstRTSPClient *client, GstRTSPMedia *media); /* signals */ - void (*closed) (GstRTSPClient *client); - void (*new_session) (GstRTSPClient *client, GstRTSPSession *session); + void (*closed) (GstRTSPClient *client); + void (*new_session) (GstRTSPClient *client, GstRTSPSession *session); + void (*options_request) (GstRTSPClient *client, GstRTSPClientState *state); + void (*describe_request) (GstRTSPClient *client, GstRTSPClientState *state); + void (*setup_request) (GstRTSPClient *client, GstRTSPClientState *state); + void (*play_request) (GstRTSPClient *client, GstRTSPClientState *state); + void (*pause_request) (GstRTSPClient *client, GstRTSPClientState *state); + void (*teardown_request) (GstRTSPClient *client, GstRTSPClientState *state); + void (*set_parameter_request) (GstRTSPClient *client, GstRTSPClientState *state); + void (*get_parameter_request) (GstRTSPClient *client, GstRTSPClientState *state); }; GType gst_rtsp_client_get_type (void); From c6cce4a6b9a61e24574ee54ca5c89cec5f93eb40 Mon Sep 17 00:00:00 2001 From: Aleix Conchillo Flaque Date: Mon, 3 Sep 2012 17:33:17 -0700 Subject: [PATCH 0429/1776] rtsp-media: also initialize transports in on_ssrc_active (bug #683304) * gst/rtsp-server/rtsp-media.c: GstRTSPMediaStream transports might not be available in "on_new_ssrc". The transports are added in gst_rtsp_media_set_state when going to PLAYING state. However, "on_new_ssrc" might be called before this happens. https://bugzilla.gnome.org/show_bug.cgi?id=683304 --- gst/rtsp-server/rtsp-media.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 18f2e8554f..2bd81ebf41 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -361,7 +361,7 @@ collect_media_stats (GstRTSPMedia * media) * gst_rtsp_media_new: * * Create a new #GstRTSPMedia instance. The #GstRTSPMedia object contains the - * element to produde RTP data for one or more related (audio/video/..) + * element to produce RTP data for one or more related (audio/video/..) * streams. * * Returns: a new #GstRTSPMedia object. @@ -1078,7 +1078,8 @@ find_transport (GstRTSPMediaStream * stream, const gchar * rtcp_from) port = atoi (tmp + 1); dest = g_strndup (rtcp_from, tmp - rtcp_from); - GST_INFO ("finding %s:%d", dest, port); + GST_INFO ("finding %s:%d in %d transports", dest, port, + g_list_length (stream->transports)); for (walk = stream->transports; walk; walk = g_list_next (walk)) { GstRTSPMediaTrans *trans = walk->data; @@ -1098,14 +1099,12 @@ find_transport (GstRTSPMediaStream * stream, const gchar * rtcp_from) return result; } -static void -on_new_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream) +static GstRTSPMediaTrans * +check_transport (GObject * source, GstRTSPMediaStream * stream) { GstStructure *stats; GstRTSPMediaTrans *trans; - GST_INFO ("%p: new source %p", stream, source); - /* see if we have a stream to match with the origin of the RTCP packet */ trans = g_object_get_qdata (source, ssrc_stream_map_key); if (trans == NULL) { @@ -1127,9 +1126,22 @@ on_new_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream) } gst_structure_free (stats); } - } else { - GST_INFO ("%p: source %p for transport %p", stream, source, trans); } + + return trans; +} + +static void +on_new_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream) +{ + GstRTSPMediaTrans *trans; + + GST_INFO ("%p: new source %p", stream, source); + + trans = check_transport (source, stream); + + if (trans) + GST_INFO ("%p: source %p for transport %p", stream, source, trans); } static void @@ -1144,9 +1156,10 @@ on_ssrc_active (GObject * session, GObject * source, { GstRTSPMediaTrans *trans; - trans = g_object_get_qdata (source, ssrc_stream_map_key); + trans = check_transport (source, stream); - GST_INFO ("%p: source %p in transport %p is active", stream, source, trans); + if (trans) + GST_INFO ("%p: source %p in transport %p is active", stream, source, trans); if (trans && trans->keep_alive) trans->keep_alive (trans->ka_user_data); From 87c73c06fbc2f17ba18cf0d4ad0c31a1fb89b126 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 7 Sep 2012 17:14:10 +0200 Subject: [PATCH 0430/1776] server: remove obsolete includes --- gst/rtsp-server/rtsp-server.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index b59ccdb8cb..81c59c706b 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -17,20 +17,8 @@ * Boston, MA 02111-1307, USA. */ -#include #include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "rtsp-server.h" #include "rtsp-client.h" @@ -595,9 +583,11 @@ gst_rtsp_server_create_socket (GstRTSPServer * server, g_socket_address_enumerator_next (enumerator, cancellable, error); if (!sockaddr) { if (!*error) - GST_DEBUG_OBJECT (server, "no more addresses %s", *error ? (*error)->message : ""); + GST_DEBUG_OBJECT (server, "no more addresses %s", + *error ? (*error)->message : ""); else - GST_DEBUG_OBJECT (server, "failed to retrieve next address %s", (*error)->message); + GST_DEBUG_OBJECT (server, "failed to retrieve next address %s", + (*error)->message); break; } @@ -799,7 +789,7 @@ accept_failed: */ gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket * socket, - const gchar * ip, gint port, const gchar *initial_buffer) + const gchar * ip, gint port, const gchar * initial_buffer) { GstRTSPClient *client = NULL; GstRTSPServerClass *klass; @@ -814,7 +804,7 @@ gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket * socket, /* a new client connected, create a client object to handle the client. */ if (!gst_rtsp_client_create_from_socket (client, socket, ip, port, - initial_buffer, &error)) { + initial_buffer, &error)) { goto transfer_failed; } From 3e55e0e46784ed687a863064e49015918525fcb1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 7 Sep 2012 17:14:30 +0200 Subject: [PATCH 0431/1776] client: use more GIO Fixes https://bugzilla.gnome.org/show_bug.cgi?id=681593 --- gst/rtsp-server/rtsp-client.c | 49 ++++++++--------------------------- 1 file changed, 11 insertions(+), 38 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 89a8b64c75..81b5bd8435 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -18,19 +18,7 @@ */ #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "rtsp-client.h" #include "rtsp-sdp.h" @@ -73,7 +61,7 @@ static void gst_rtsp_client_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_client_finalize (GObject * obj); -static GstSDPMessage * create_sdp (GstRTSPClient * client, GstRTSPMedia * media); +static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media); static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session); static void unlink_session_streams (GstRTSPClient * client, @@ -2012,9 +2000,6 @@ attach_client (GstRTSPClient * client, GSocket * socket, GSource *source; GMainContext *context; GstRTSPUrl *url; - struct sockaddr_storage addr; - socklen_t addrlen; - gchar ip[INET6_ADDRSTRLEN]; read_socket = gst_rtsp_connection_get_read_socket (conn); client->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6; @@ -2022,18 +2007,17 @@ attach_client (GstRTSPClient * client, GSocket * socket, if (!(addres = g_socket_get_remote_address (read_socket, error))) goto no_address; - addrlen = sizeof (addr); - if (!g_socket_address_to_native (addres, &addr, addrlen, error)) - goto native_failed; - g_object_unref (addres); - - if (getnameinfo ((struct sockaddr *) &addr, addrlen, ip, sizeof (ip), NULL, 0, - NI_NUMERICHOST) != 0) - goto getnameinfo_failed; - - /* keep the original ip that the client connected to */ g_free (client->server_ip); - client->server_ip = g_strndup (ip, sizeof (ip)); + /* keep the original ip that the client connected to */ + if (G_IS_INET_SOCKET_ADDRESS (addres)) { + GInetAddress *iaddr; + + iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addres)); + + client->server_ip = g_inet_address_to_string (iaddr); + } else { + client->server_ip = g_strdup ("unknown"); + } GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client, client->server_ip, client->is_ipv6); @@ -2066,17 +2050,6 @@ no_address: GST_ERROR ("could not get remote address %s", (*error)->message); return FALSE; } -native_failed: - { - g_object_unref (addres); - GST_ERROR ("could not get native address %s", (*error)->message); - return FALSE; - } -getnameinfo_failed: - { - GST_ERROR ("getnameinfo failed: %s", g_strerror (errno)); - return FALSE; - } } /** From f4a0a371b7df920a91d04b6ee6b5d1aa9d8e92d4 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 10 Sep 2012 16:25:57 +0200 Subject: [PATCH 0432/1776] media: fix check for seekability --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 2bd81ebf41..9b26148bc4 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -714,7 +714,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (range != NULL, FALSE); - if (media->seekable) { + if (!media->seekable) { GST_INFO ("pipeline is not seekable"); return TRUE; } From 71645325363d0d32e29d9f99a4745a411d0928fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 22 Sep 2012 16:11:48 +0100 Subject: [PATCH 0433/1776] Automatic update of common submodule From 4f962f7 to 6c0b52c --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 4f962f7835..6c0b52c72c 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 4f962f78357a11e545510d48227f41af24bfaab7 +Subproject commit 6c0b52c72c0958952b79b573105a270d7a651b33 From 870b8db2791663b081b625d3b78a80c8fda15f42 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Mon, 1 Oct 2012 16:13:50 +0200 Subject: [PATCH 0434/1776] rtsp-client: do not destroy the rtsp watch Don't destroy the client watch while dispatching. The rtsp watch is automatically destroyed after the rtsp watch function closed() has been called. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=685220 --- gst/rtsp-server/rtsp-client.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 81b5bd8435..3e30084712 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -202,6 +202,9 @@ gst_rtsp_client_finalize (GObject * obj) GST_INFO ("finalize client %p", client); + if (client->watchid) + g_source_destroy ((GSource *) client->watch); + client_cleanup_sessions (client); gst_rtsp_connection_free (client->connection); @@ -536,11 +539,6 @@ close_connection (GstRTSPClient * client) } gst_rtsp_connection_close (client->connection); - if (client->watchid) { - g_source_destroy ((GSource *) client->watch); - client->watchid = 0; - client->watch = NULL; - } } static gboolean @@ -1942,11 +1940,6 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) gst_rtsp_watch_reset (oclient->watch); g_object_unref (oclient); - /* we don't need this watch anymore */ - g_source_destroy ((GSource *) client->watch); - client->watchid = 0; - client->watch = NULL; - return GST_RTSP_OK; /* ERRORS */ From 1a5cf33f0fde902d62f1b66348a02e7e3a05eccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 6 Oct 2012 15:02:27 +0100 Subject: [PATCH 0435/1776] Automatic update of common submodule From 6c0b52c to 6bb6951 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 6c0b52c72c..6bb695159b 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 6c0b52c72c0958952b79b573105a270d7a651b33 +Subproject commit 6bb695159bf15fe64d31b26dd2a07d1ba2bb7f1d From d581b7bd4e9be7e97e016975f499c5929602e851 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 10 Oct 2012 11:06:02 +0200 Subject: [PATCH 0436/1776] client: Use client transport settings for multicast if allowed. This patch makes it possible for the client to send transport settings for multicast (destination && ttl). Client settings must be explicitly allowed or the server will use its own settings. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=685561 --- gst/rtsp-server/rtsp-client.c | 60 +++++++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-client.h | 6 ++++ gst/rtsp-server/rtsp-media.c | 13 ++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3e30084712..a6301965fc 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -27,11 +27,16 @@ static GMutex tunnels_lock; static GHashTable *tunnels; +#define DEFAULT_SESSION_POOL NULL +#define DEFAULT_MEDIA_MAPPING NULL +#define DEFAULT_USE_CLIENT_SETTINGS FALSE + enum { PROP_0, PROP_SESSION_POOL, PROP_MEDIA_MAPPING, + PROP_USE_CLIENT_SETTINGS, PROP_LAST }; @@ -94,6 +99,12 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_USE_CLIENT_SETTINGS, + g_param_spec_boolean ("use-client-settings", "Use Client Settings", + "Use client settings for ttl and destination in multicast", + DEFAULT_USE_CLIENT_SETTINGS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_client_signals[SIGNAL_CLOSED] = g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL, @@ -162,6 +173,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) static void gst_rtsp_client_init (GstRTSPClient * client) { + client->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS; } static void @@ -238,6 +250,10 @@ gst_rtsp_client_get_property (GObject * object, guint propid, case PROP_MEDIA_MAPPING: g_value_take_object (value, gst_rtsp_client_get_media_mapping (client)); break; + case PROP_USE_CLIENT_SETTINGS: + g_value_set_boolean (value, + gst_rtsp_client_get_use_client_settings (client)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -256,6 +272,10 @@ gst_rtsp_client_set_property (GObject * object, guint propid, case PROP_MEDIA_MAPPING: gst_rtsp_client_set_media_mapping (client, g_value_get_object (value)); break; + case PROP_USE_CLIENT_SETTINGS: + gst_rtsp_client_set_use_client_settings (client, + g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1042,13 +1062,20 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) goto invalid_blocksize; /* we have a valid transport now, set the destination of the client. */ - g_free (ct->destination); if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - ct->destination = gst_rtsp_media_get_multicast_group (media->media); + if (ct->destination == NULL || !client->use_client_settings) { + g_free (ct->destination); + ct->destination = gst_rtsp_media_get_multicast_group (media->media); + } + /* reset ttl if client settings are not allowed */ + if (!client->use_client_settings) { + ct->ttl = 0; + } } else { GstRTSPUrl *url; url = gst_rtsp_connection_get_url (client->connection); + g_free (ct->destination); ct->destination = g_strdup (url->host); if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) { @@ -1701,6 +1728,35 @@ gst_rtsp_client_get_media_mapping (GstRTSPClient * client) return result; } +/** + * gst_rtsp_client_set_use_client_settings: + * @client: a #GstRTSPClient + * @use_client_settings: whether to use client settings for multicast + * + * Use client transport settings (destination and ttl) for multicast. + * When @use_client_settings is %FALSE, the server settings will be + * used. + */ +void +gst_rtsp_client_set_use_client_settings (GstRTSPClient * client, + gboolean use_client_settings) +{ + client->use_client_settings = use_client_settings; +} + +/** + * gst_rtsp_client_get_use_client_settings: + * @client: a #GstRTSPClient + * + * Check if client transport settings (destination and ttl) for multicast + * will be used. + */ +gboolean +gst_rtsp_client_get_use_client_settings (GstRTSPClient * client) +{ + return client->use_client_settings; +} + /** * gst_rtsp_client_set_auth: * @client: a #GstRTSPClient diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 5baf21e7c1..4712d1e546 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -76,6 +76,7 @@ struct _GstRTSPClientState{ * @watch: watch for the connection * @watchid: id of the watch * @ip: ip address used by the client to connect to us + * @use_client_settings: whether to allow client transport settings for multicast * @session_pool: handle to the session pool used by the client. * @media_mapping: handle to the media mapping used by the client. * @uri: cached uri @@ -93,6 +94,7 @@ struct _GstRTSPClient { guint watchid; gchar *server_ip; gboolean is_ipv6; + gboolean use_client_settings; GstRTSPServer *server; GstRTSPSessionPool *session_pool; @@ -139,6 +141,10 @@ void gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *mapping); GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client); +void gst_rtsp_client_set_use_client_settings (GstRTSPClient * client, + gboolean use_client_settings); +gboolean gst_rtsp_client_get_use_client_settings (GstRTSPClient * client); + void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 9b26148bc4..1e11561fd1 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1891,6 +1891,14 @@ remove_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream, g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); } +static void +set_multicast_ttl (GstRTSPMedia * media, GstRTSPMediaStream * stream, guint ttl) +{ + GST_INFO ("setting ttl-mc %d", ttl); + g_object_set (G_OBJECT (stream->udpsink[0]), "ttl-mc", ttl, NULL); + g_object_set (G_OBJECT (stream->udpsink[1]), "ttl-mc", ttl, NULL); +} + /** * gst_rtsp_media_set_state: * @media: a #GstRTSPMedia @@ -1962,11 +1970,13 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, { gchar *dest; gint min, max; + guint ttl = 0; dest = trans->destination; if (trans->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { min = trans->port.min; max = trans->port.max; + ttl = trans->ttl; } else { min = trans->client_port.min; max = trans->client_port.max; @@ -1974,6 +1984,9 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, if (add && !tr->active) { add_udp_destination (media, stream, dest, min, max); + if (ttl > 0) { + set_multicast_ttl (media, stream, ttl); + } stream->transports = g_list_prepend (stream->transports, tr); tr->active = TRUE; media->active++; From 4f0ef292f0a3b05a2a9e234c219d826998ce4bf9 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 10 Oct 2012 11:13:10 +0200 Subject: [PATCH 0437/1776] session: add ttl to the transport header in SETUP See https://bugzilla.gnome.org/show_bug.cgi?id=685561 --- gst/rtsp-server/rtsp-session.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index de16415cb6..6bb71681d2 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -528,6 +528,7 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream, case GST_RTSP_LOWER_TRANS_UDP_MCAST: ct->port = st->port = stream->media_stream->server_port; st->destination = g_strdup (ct->destination); + st->ttl = ct->ttl; break; case GST_RTSP_LOWER_TRANS_TCP: st->interleaved = ct->interleaved; From 8da18a85efe3f33eaa8e21e599bb83de8f627d38 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Sat, 6 Oct 2012 15:49:07 +0200 Subject: [PATCH 0438/1776] Explicitly link against gio. Fix link error on mac. --- gst/rtsp-server/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 43b54c4105..bbc6632fb4 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -39,7 +39,7 @@ libgstrtspserver_@GST_API_VERSION@_la_LIBADD = \ -lgstrtp-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ \ -lgstsdp-@GST_API_VERSION@ \ -lgstapp-@GST_API_VERSION@ \ - $(GST_LIBS) $(LIBM) + $(GST_LIBS) $(GIO_LIBS) $(LIBM) libgstrtspserver_@GST_API_VERSION@_la_LIBTOOLFLAGS = --tag=disable-static libgstrtspserver_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/rtsp-server From 3a49b8e7836a49fcb0a2ef74fc193d7220a7e8df Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Fri, 12 Oct 2012 06:07:07 +0200 Subject: [PATCH 0439/1776] rtsp-media-factory-uri: don't autoplug parsers in a loop Stop autoplugging parsers if caps have parsed=true set. Fixes autoplugging h264parse forever. --- gst/rtsp-server/rtsp-media-factory-uri.c | 38 ++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index c544449c66..d31484fcf9 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -291,17 +291,49 @@ find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps) { GList *list; GstElementFactory *factory = NULL; + gboolean autoplug_more = FALSE; /* first find a demuxer that can link */ list = gst_element_factory_list_filter (urifact->demuxers, caps, GST_PAD_SINK, FALSE); - if (list != NULL) { - /* we have a demuxer, try that one first */ + if (list) { + GstStructure *structure = gst_caps_get_structure (caps, 0); + gboolean parsed = FALSE; + + gst_structure_get_boolean (structure, "parsed", &parsed); + + /* Avoid plugging parsers in a loop. This is not 100% correct, as some + * parsers don't set parsed=true in caps. We should do something like + * decodebin does and track decode chains and elements plugged in those + * chains... + */ + if (parsed) { + GList *walk; + const gchar *klass; + + for (walk = list; walk; walk = walk->next) { + factory = GST_ELEMENT_FACTORY (walk->data); + klass = gst_element_factory_get_klass (factory); + if (strstr (klass, "Parser")) + /* caps have parsed=true, so skip this parser to avoid loops */ + continue; + + autoplug_more = TRUE; + break; + } + } else { + /* caps don't have parsed=true set and we have a demuxer/parser */ + autoplug_more = TRUE; + } + gst_plugin_feature_list_free (list); - return NULL; } + if (autoplug_more) + /* we have a demuxer, try that one first */ + return NULL; + /* no demuxer try a depayloader */ list = gst_element_factory_list_filter (urifact->payloaders, caps, GST_PAD_SINK, FALSE); From 8f507e4512bb0d20ad134a386a429f2779d257c2 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Fri, 12 Oct 2012 06:11:36 +0200 Subject: [PATCH 0440/1776] rtsp-media-factory: make ::get_element overridable by GI bindings The way to annotate vfuncs with GI seems to be to create an invoker (GI term) for them and to annotate the invoker. Add gst_rtsp_media_factory_get_element() as the invoker for ::get_element(), making it overridable by GI generated bindings. --- gst/rtsp-server/rtsp-media-factory.c | 15 +++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 8db3357c94..2a4074a096 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -877,3 +877,18 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) g_free (mc); } } + +/** + * gst_rtsp_media_factory_get_element: + * @factory: a #GstRTSPMediaFactory + * @url: the url used + * + * Returns: (transfer floating) a new #GstElement. + */ +GstElement * +gst_rtsp_media_factory_get_element (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url) +{ + GstRTSPMediaFactoryClass *klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); + return klass->get_element (factory, url); +} diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index baabc86337..ede1e0cebd 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -151,6 +151,8 @@ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory * void gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory *factory, const GstRTSPUrl *url, GstRTSPMedia *media); + +GstElement * gst_rtsp_media_factory_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); G_END_DECLS From 6a49744088fa41fcf86e326c109fe1def92ffce5 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Fri, 12 Oct 2012 06:21:24 +0200 Subject: [PATCH 0441/1776] rtsp-server: add bound-port property bound-port can be used to retrieve the port number when the server is bound on port 0, which binds on a random port. --- gst/rtsp-server/rtsp-server.c | 43 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-server.h | 4 ++++ 2 files changed, 47 insertions(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 81c59c706b..0219a9d06c 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -24,6 +24,7 @@ #include "rtsp-client.h" #define DEFAULT_ADDRESS "0.0.0.0" +#define DEFAULT_BOUND_PORT -1 /* #define DEFAULT_ADDRESS "::0" */ #define DEFAULT_SERVICE "8554" #define DEFAULT_BACKLOG 5 @@ -38,6 +39,7 @@ enum PROP_0, PROP_ADDRESS, PROP_SERVICE, + PROP_BOUND_PORT, PROP_BACKLOG, PROP_SESSION_POOL, @@ -99,6 +101,18 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) g_param_spec_string ("service", "Service", "The service or port number the server uses to listen on", DEFAULT_SERVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPServer::bound-port + * + * The actual port the server is listening on. Can be used to retrieve the + * port number when the server is started on port 0, which means bind to a + * random port. Set to -1 if the server has not been bound yet. + */ + g_object_class_install_property (gobject_class, PROP_BOUND_PORT, + g_param_spec_int ("bound-port", "Bound port", + "The port number the server is listening on", + -1, G_MAXUINT16, DEFAULT_BOUND_PORT, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * GstRTSPServer::backlog * @@ -155,6 +169,7 @@ gst_rtsp_server_init (GstRTSPServer * server) g_mutex_init (&server->lock); server->address = g_strdup (DEFAULT_ADDRESS); server->service = g_strdup (DEFAULT_SERVICE); + server->socket = NULL; server->backlog = DEFAULT_BACKLOG; server->session_pool = gst_rtsp_session_pool_new (); server->media_mapping = gst_rtsp_media_mapping_new (); @@ -169,6 +184,8 @@ gst_rtsp_server_finalize (GObject * object) g_free (server->address); g_free (server->service); + if (server->socket) + g_object_unref (server->socket); g_object_unref (server->session_pool); g_object_unref (server->media_mapping); @@ -238,6 +255,28 @@ gst_rtsp_server_get_address (GstRTSPServer * server) return result; } +int +gst_rtsp_server_get_bound_port (GstRTSPServer * server) +{ + GSocketAddress *address; + int result = -1; + + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), result); + + GST_RTSP_SERVER_LOCK (server); + if (server->socket == NULL) + goto out; + + address = g_socket_get_local_address (server->socket, NULL); + result = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address)); + g_object_unref (address); + +out: + GST_RTSP_SERVER_UNLOCK (server); + + return result; +} + /** * gst_rtsp_server_set_service: * @server: a #GstRTSPServer @@ -492,6 +531,9 @@ gst_rtsp_server_get_property (GObject * object, guint propid, case PROP_SERVICE: g_value_take_string (value, gst_rtsp_server_get_service (server)); break; + case PROP_BOUND_PORT: + g_value_set_int (value, gst_rtsp_server_get_bound_port (server)); + break; case PROP_BACKLOG: g_value_set_int (value, gst_rtsp_server_get_backlog (server)); break; @@ -923,6 +965,7 @@ gst_rtsp_server_create_source (GstRTSPServer * server, g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); socket = gst_rtsp_server_create_socket (server, NULL, error); + server->socket = g_object_ref (socket); if (socket == NULL) goto no_socket; diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 595f2f1bd5..5220ce111b 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -62,6 +62,8 @@ struct _GstRTSPServer { gchar *service; gint backlog; + GSocket *socket; + /* sessions on this server */ GstRTSPSessionPool *session_pool; @@ -104,6 +106,8 @@ gchar * gst_rtsp_server_get_address (GstRTSPServer *serve void gst_rtsp_server_set_service (GstRTSPServer *server, const gchar *service); gchar * gst_rtsp_server_get_service (GstRTSPServer *server); +int gst_rtsp_server_get_bound_port (GstRTSPServer *server); + void gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog); gint gst_rtsp_server_get_backlog (GstRTSPServer *server); From 1e954a1a5e7954da06e0398307b67c77eb055664 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Fri, 12 Oct 2012 07:08:57 +0200 Subject: [PATCH 0442/1776] rtsp-server: allow binding on port 0 (binds on a random port) --- gst/rtsp-server/rtsp-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 0219a9d06c..36c75eb3e8 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -608,7 +608,7 @@ gst_rtsp_server_create_socket (GstRTSPServer * server, /* resolve the server IP address */ port = atoi (server->service); - if (port != 0) + if (port != 0 || !strcmp (server->service, "0")) conn = g_network_address_new (server->address, port); else conn = g_network_service_new (server->service, "tcp", server->address); From bc474a5b2616ffcabf225fbe332a0ad00d46a188 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Fri, 12 Oct 2012 07:18:19 +0200 Subject: [PATCH 0443/1776] media-mapping: fix transfer mode for gst_rtsp_media_mapping_add_factory --- gst/rtsp-server/rtsp-media-mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c index 5943c3032a..5e4c8d5005 100644 --- a/gst/rtsp-server/rtsp-media-mapping.c +++ b/gst/rtsp-server/rtsp-media-mapping.c @@ -123,7 +123,7 @@ gst_rtsp_media_mapping_find_factory (GstRTSPMediaMapping * mapping, * gst_rtsp_media_mapping_add_factory: * @mapping: a #GstRTSPMediaMapping * @path: a mount point - * @factory: a #GstRTSPMediaFactory + * @factory: (transfer full): a #GstRTSPMediaFactory * * Attach @factory to the mount point @path in @mapping. * From e11e855ac8b3b3b90fc410631a0608050c4453e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Mon, 1 Oct 2012 19:46:15 +0200 Subject: [PATCH 0444/1776] rtsp-server: fixed comments and GIR annotations https://bugzilla.gnome.org/show_bug.cgi?id=680777 --- gst/rtsp-server/rtsp-auth.c | 6 ++---- gst/rtsp-server/rtsp-client.c | 8 ++++---- gst/rtsp-server/rtsp-media-factory-uri.c | 4 ++-- gst/rtsp-server/rtsp-media-factory.c | 6 +++--- gst/rtsp-server/rtsp-media-mapping.c | 2 +- gst/rtsp-server/rtsp-media.c | 2 +- gst/rtsp-server/rtsp-server.c | 23 +++++++++++------------ gst/rtsp-server/rtsp-session-pool.c | 12 ++++++------ gst/rtsp-server/rtsp-session.c | 8 +++----- 9 files changed, 33 insertions(+), 38 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index c8aa14008a..0da47f16b4 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -152,10 +152,8 @@ default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, * gst_rtsp_auth_setup_auth: * @auth: a #GstRTSPAuth * @client: the client - * @uri: the requested uri - * @session: the session - * @request: the request - * @response: the response + * @hint: TODO + * @state: TODO * * Add authentication tokens to @response. * diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a6301965fc..da7ea1b43c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1629,7 +1629,7 @@ gst_rtsp_client_set_session_pool (GstRTSPClient * client, * * Get the #GstRTSPSessionPool object that @client uses to manage its sessions. * - * Returns: a #GstRTSPSessionPool, unref after usage. + * Returns: (transfer full): a #GstRTSPSessionPool, unref after usage. */ GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient * client) @@ -1670,7 +1670,7 @@ gst_rtsp_client_set_server (GstRTSPClient * client, GstRTSPServer * server) * * Get the #GstRTSPServer object that @client was created from. * - * Returns: a #GstRTSPServer, unref after usage. + * Returns: (transfer full): a #GstRTSPServer, unref after usage. */ GstRTSPServer * gst_rtsp_client_get_server (GstRTSPClient * client) @@ -1715,7 +1715,7 @@ gst_rtsp_client_set_media_mapping (GstRTSPClient * client, * * Get the #GstRTSPMediaMapping object that @client uses to manage its sessions. * - * Returns: a #GstRTSPMediaMapping, unref after usage. + * Returns: (transfer full): a #GstRTSPMediaMapping, unref after usage. */ GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient * client) @@ -1789,7 +1789,7 @@ gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth) * * Get the #GstRTSPAuth used as the authentication manager of @client. * - * Returns: the #GstRTSPAuth of @client. g_object_unref() after + * Returns: (transfer full): the #GstRTSPAuth of @client. g_object_unref() after * usage. */ GstRTSPAuth * diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index d31484fcf9..f4f1bdef73 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -86,7 +86,7 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass) gobject_class->finalize = gst_rtsp_media_factory_uri_finalize; /** - * GstRTSPMediaFactoryURI::uri + * GstRTSPMediaFactoryURI::uri: * * The uri of the resource that will be served by this factory. */ @@ -95,7 +95,7 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass) "The URI of the resource to stream", DEFAULT_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRTSPMediaFactoryURI::use-gstpay + * GstRTSPMediaFactoryURI::use-gstpay: * * Allow the usage of gstpay in order to avoid decoding of compressed formats * without a payloader. diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 2a4074a096..86db9fdf48 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -81,7 +81,7 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) gobject_class->finalize = gst_rtsp_media_factory_finalize; /** - * GstRTSPMediaFactory::launch + * GstRTSPMediaFactory::launch: * * The gst_parse_launch() line to use for constructing the pipeline in the * default prepare vmethod. @@ -510,7 +510,7 @@ gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory, * * Get the #GstRTSPAuth used as the authentication manager of @factory. * - * Returns: the #GstRTSPAuth of @factory. g_object_unref() after + * Returns: (transfer full): the #GstRTSPAuth of @factory. g_object_unref() after * usage. */ GstRTSPAuth * @@ -586,7 +586,7 @@ media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory) * the srcpad member set to a source pad that produces buffer of type * application/x-rtp. * - * Returns: a new #GstRTSPMedia if the media could be prepared. + * Returns: (transfer full): a new #GstRTSPMedia if the media could be prepared. */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c index 5e4c8d5005..ab2d2b59e1 100644 --- a/gst/rtsp-server/rtsp-media-mapping.c +++ b/gst/rtsp-server/rtsp-media-mapping.c @@ -100,7 +100,7 @@ find_media (GstRTSPMediaMapping * mapping, const GstRTSPUrl * url) * Find the #GstRTSPMediaFactory for @url. The default implementation of this object * will use the mappings added with gst_rtsp_media_mapping_add_factory (). * - * Returns: the #GstRTSPMediaFactory for @url. g_object_unref() after usage. + * Returns: (transfer full): the #GstRTSPMediaFactory for @url. g_object_unref() after usage. */ GstRTSPMediaFactory * gst_rtsp_media_mapping_find_factory (GstRTSPMediaMapping * mapping, diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1e11561fd1..c5efd278df 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -608,7 +608,7 @@ gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth) * * Get the #GstRTSPAuth used as the authentication manager of @media. * - * Returns: the #GstRTSPAuth of @media. g_object_unref() after + * Returns: (transfer full): the #GstRTSPAuth of @media. g_object_unref() after * usage. */ GstRTSPAuth * diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 36c75eb3e8..125d252c61 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -82,7 +82,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) gobject_class->finalize = gst_rtsp_server_finalize; /** - * GstRTSPServer::address + * GstRTSPServer::address: * * The address of the server. This is the address where the server will * listen on. @@ -92,7 +92,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) "The address the server uses to listen on", DEFAULT_ADDRESS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRTSPServer::service + * GstRTSPServer::service: * * The service of the server. This is either a string with the service name or * a port number (as a string) the server will listen on. @@ -102,7 +102,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) "The service or port number the server uses to listen on", DEFAULT_SERVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRTSPServer::bound-port + * GstRTSPServer::bound-port: * * The actual port the server is listening on. Can be used to retrieve the * port number when the server is started on port 0, which means bind to a @@ -114,7 +114,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) -1, G_MAXUINT16, DEFAULT_BOUND_PORT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** - * GstRTSPServer::backlog + * GstRTSPServer::backlog: * * The backlog argument defines the maximum length to which the queue of * pending connections for the server may grow. If a connection request arrives @@ -128,7 +128,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) "of pending connections may grow", 0, G_MAXINT, DEFAULT_BACKLOG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRTSPServer::session-pool + * GstRTSPServer::session-pool: * * The session pool of the server. By default each server has a separate * session pool but sessions can be shared between servers by setting the same @@ -140,7 +140,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRTSPServer::media-mapping + * GstRTSPServer::media-mapping: * * The media mapping to use for this server. By default the server has no * media mapping and thus cannot map urls to media streams. @@ -397,7 +397,7 @@ gst_rtsp_server_set_session_pool (GstRTSPServer * server, * * Get the #GstRTSPSessionPool used as the session pool of @server. * - * Returns: the #GstRTSPSessionPool used for sessions. g_object_unref() after + * Returns: (transfer full): the #GstRTSPSessionPool used for sessions. g_object_unref() after * usage. */ GstRTSPSessionPool * @@ -449,7 +449,7 @@ gst_rtsp_server_set_media_mapping (GstRTSPServer * server, * * Get the #GstRTSPMediaMapping used as the media mapping of @server. * - * Returns: the #GstRTSPMediaMapping of @server. g_object_unref() after + * Returns: (transfer full): the #GstRTSPMediaMapping of @server. g_object_unref() after * usage. */ GstRTSPMediaMapping * @@ -500,7 +500,7 @@ gst_rtsp_server_set_auth (GstRTSPServer * server, GstRTSPAuth * auth) * * Get the #GstRTSPAuth used as the authentication manager of @server. * - * Returns: the #GstRTSPAuth of @server. g_object_unref() after + * Returns: (transfer full): the #GstRTSPAuth of @server. g_object_unref() after * usage. */ GstRTSPAuth * @@ -584,7 +584,7 @@ gst_rtsp_server_set_property (GObject * object, guint propid, * Create a #GSocket for @server. The socket will listen on the * configured service. * - * Returns: the #GSocket for @server or NULL when an error occured. + * Returns: (transfer full): the #GSocket for @server or NULL when an error occured. */ GSocket * gst_rtsp_server_create_socket (GstRTSPServer * server, @@ -991,8 +991,7 @@ no_socket: /** * gst_rtsp_server_attach: * @server: a #GstRTSPServer - * @context: a #GMainContext - * @error: a #GError + * @context: (allow-none): a #GMainContext * * Attaches @server to @context. When the mainloop for @context is run, the * server will be dispatched. When @context is NULL, the default context will be diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 7f3bd01f54..24d788bd23 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -214,7 +214,7 @@ gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool * pool) * Find the session with @sessionid in @pool. The access time of the session * will be updated with gst_rtsp_session_touch(). * - * Returns: the #GstRTSPSession with @sessionid or %NULL when the session did + * Returns: (transfer full): the #GstRTSPSession with @sessionid or %NULL when the session did * not exist. g_object_unref() after usage. */ GstRTSPSession * @@ -257,7 +257,7 @@ create_session_id (GstRTSPSessionPool * pool) * * Create a new #GstRTSPSession object in @pool. * - * Returns: a new #GstRTSPSession. + * Returns: (transfer none): a new #GstRTSPSession. */ GstRTSPSession * gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) @@ -423,7 +423,7 @@ filter_func (gchar * sessionid, GstRTSPSession * sess, FilterData * data) /** * gst_rtsp_session_pool_filter: * @pool: a #GstRTSPSessionPool - * @func: a callback + * @func: (scope call): a callback * @user_data: user data passed to @func * * Call @func for each session in @pool. The result value of @func determines @@ -439,9 +439,9 @@ filter_func (gchar * sessionid, GstRTSPSession * sess, FilterData * data) * will also be added with an additional ref to the result GList of this * function.. * - * Returns: a GList with all sessions for which @func returned - * #GST_RTSP_FILTER_REF. After usage, each element in the GList should be unreffed - * before the list is freed. + * Returns: (element-type GstRTSPSession) (transfer full): a GList with all + * sessions for which @func returned #GST_RTSP_FILTER_REF. After usage, each + * element in the GList should be unreffed before the list is freed. */ GList * gst_rtsp_session_pool_filter (GstRTSPSessionPool * pool, diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 6bb71681d2..3d76670bc0 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -182,7 +182,7 @@ gst_rtsp_session_set_property (GObject * object, guint propid, * gst_rtsp_session_manage_media: * @sess: a #GstRTSPSession * @uri: the uri for the media - * @media: a #GstRTSPMedia + * @media: (transfer full): a #GstRTSPMedia * * Manage the media object @obj in @sess. @uri will be used to retrieve this * media from the session with gst_rtsp_session_get_media(). @@ -551,10 +551,8 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream, /** * gst_rtsp_session_stream_set_callbacks: * @stream: a #GstRTSPSessionStream - * @send_rtp: a callback called when RTP should be sent - * @send_rtcp: a callback called when RTCP should be sent - * @send_rtp_list: a callback called when RTP should be sent - * @send_rtcp_list: a callback called when RTCP should be sent + * @send_rtp: (scope notified): a callback called when RTP should be sent + * @send_rtcp: (scope notified): a callback called when RTCP should be sent * @user_data: user data passed to callbacks * @notify: called with the user_data when no longer needed. * From 5cec59737ba163409176af4a5e910aae177c8938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Mon, 1 Oct 2012 20:03:43 +0200 Subject: [PATCH 0445/1776] rtsp-media-mapping: rename find_media vfunc to find_factory The virtual method and class method should have the same name so it is correctly represented in GIR file https://bugzilla.gnome.org/show_bug.cgi?id=680777 --- gst/rtsp-server/rtsp-media-mapping.c | 10 +++++----- gst/rtsp-server/rtsp-media-mapping.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c index ab2d2b59e1..8a28db98fd 100644 --- a/gst/rtsp-server/rtsp-media-mapping.c +++ b/gst/rtsp-server/rtsp-media-mapping.c @@ -26,7 +26,7 @@ GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug); static void gst_rtsp_media_mapping_finalize (GObject * obj); -static GstRTSPMediaFactory *find_media (GstRTSPMediaMapping * mapping, +static GstRTSPMediaFactory *find_factory (GstRTSPMediaMapping * mapping, const GstRTSPUrl * url); static void @@ -38,7 +38,7 @@ gst_rtsp_media_mapping_class_init (GstRTSPMediaMappingClass * klass) gobject_class->finalize = gst_rtsp_media_mapping_finalize; - klass->find_media = find_media; + klass->find_factory = find_factory; GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediamapping", 0, "GstRTSPMediaMapping"); @@ -76,7 +76,7 @@ gst_rtsp_media_mapping_new (void) } static GstRTSPMediaFactory * -find_media (GstRTSPMediaMapping * mapping, const GstRTSPUrl * url) +find_factory (GstRTSPMediaMapping * mapping, const GstRTSPUrl * url) { GstRTSPMediaFactory *result; @@ -111,8 +111,8 @@ gst_rtsp_media_mapping_find_factory (GstRTSPMediaMapping * mapping, klass = GST_RTSP_MEDIA_MAPPING_GET_CLASS (mapping); - if (klass->find_media) - result = klass->find_media (mapping, url); + if (klass->find_factory) + result = klass->find_factory (mapping, url); else result = NULL; diff --git a/gst/rtsp-server/rtsp-media-mapping.h b/gst/rtsp-server/rtsp-media-mapping.h index 5c3e46f2df..19f1acf67f 100644 --- a/gst/rtsp-server/rtsp-media-mapping.h +++ b/gst/rtsp-server/rtsp-media-mapping.h @@ -54,7 +54,7 @@ struct _GstRTSPMediaMapping { /** * GstRTSPMediaMappingClass: - * @find_media: Create or return a previously cached #GstRTSPMediaFactory object + * @find_factory: Create or return a previously cached #GstRTSPMediaFactory object * for the given url. the default implementation will use the mappings * added with gst_rtsp_media_mapping_add_factory(). * @@ -63,7 +63,7 @@ struct _GstRTSPMediaMapping { struct _GstRTSPMediaMappingClass { GObjectClass parent_class; - GstRTSPMediaFactory * (*find_media) (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url); + GstRTSPMediaFactory * (*find_factory) (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url); }; GType gst_rtsp_media_mapping_get_type (void); From 1240f98206852b2151fe585a721dee03b1096678 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Mon, 22 Oct 2012 16:29:09 +0200 Subject: [PATCH 0446/1776] tests: Add libgio link dependency Fixes https://bugzilla.gnome.org/show_bug.cgi?id=686647 --- tests/check/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index b32412e7c8..458cd47176 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -49,10 +49,12 @@ gst_rtspserver_CFLAGS = \ $(GST_PLUGINS_GOOD_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) \ + $(GIO_CFLAGS) \ $(AM_CFLAGS) gst_rtspserver_LDADD = \ $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la \ $(GST_PLUGINS_GOOD_LIBS) \ $(GST_BASE_LIBS) -lgstrtsp-@GST_API_VERSION@ -lgstsdp-@GST_API_VERSION@ \ + $(GIO_LIBS) \ $(LDADD) From 78bde6fa3e1642a1117c3d1e0eca69db6650ec7e Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 22 Oct 2012 16:09:24 +0200 Subject: [PATCH 0447/1776] rtsp-server: don't ref server socket if it is NULL Fixes test_bind_already_in_use unit test again after commit 6a497440. https://bugzilla.gnome.org/show_bug.cgi?id=686644 --- gst/rtsp-server/rtsp-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 125d252c61..c6229818a8 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -965,9 +965,9 @@ gst_rtsp_server_create_source (GstRTSPServer * server, g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); socket = gst_rtsp_server_create_socket (server, NULL, error); - server->socket = g_object_ref (socket); if (socket == NULL) goto no_socket; + server->socket = g_object_ref (socket); /* create a watch for reads (new connections) and possible errors */ source = g_socket_create_source (socket, G_IO_IN | From 0de6262dc4f816c69d2a768068fd548c923cb61c Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Tue, 23 Oct 2012 22:11:17 +0200 Subject: [PATCH 0448/1776] rtsp-client: Unref server address clients connected to Fixes https://bugzilla.gnome.org/show_bug.cgi?id=686725 --- gst/rtsp-server/rtsp-client.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index da7ea1b43c..659b499ce6 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2045,7 +2045,7 @@ attach_client (GstRTSPClient * client, GSocket * socket, GstRTSPConnection * conn, GError ** error) { GSocket *read_socket; - GSocketAddress *addres; + GSocketAddress *address; GSource *source; GMainContext *context; GstRTSPUrl *url; @@ -2053,17 +2053,18 @@ attach_client (GstRTSPClient * client, GSocket * socket, read_socket = gst_rtsp_connection_get_read_socket (conn); client->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6; - if (!(addres = g_socket_get_remote_address (read_socket, error))) + if (!(address = g_socket_get_remote_address (read_socket, error))) goto no_address; g_free (client->server_ip); /* keep the original ip that the client connected to */ - if (G_IS_INET_SOCKET_ADDRESS (addres)) { + if (G_IS_INET_SOCKET_ADDRESS (address)) { GInetAddress *iaddr; - iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addres)); + iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address)); client->server_ip = g_inet_address_to_string (iaddr); + g_object_unref (address); } else { client->server_ip = g_strdup ("unknown"); } From de7c72dec2a022b90cefe21ec0a92b1ad452c19d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 25 Oct 2012 21:29:58 +0200 Subject: [PATCH 0449/1776] rtsp: massive refactoring Make GObjects from the remaining simple structures. Remove GstRTSPSessionStream, it's not needed. Rename GstRTSPMediaStream -> GstRTSPStream: It is shorter Rename GstRTSPMediaTrans -> GstRTSPStreamTransport: It describes how a GstRTSPStream should be transported to a client. Rename GstRTSPMediaFactory::get_element -> create_element because that more accurately describes what it does. Make nice methods instead of poking in the structures. Move some methods inside the relevant object source code. Use GPtrArray to store objects instead of plain arrays, it is more natural and allows us to more easily clean up. Move the allocation of udp ports to the Stream object. The Stream object contains the elements needed to stream the media to a client. Improve the prepare and unprepare methods. Unprepare should now undo everything prepare did. Improve also async unprepare when doing EOS on shutdown. Make sure we always unprepare correctly. --- gst/rtsp-server/Makefile.am | 6 + gst/rtsp-server/rtsp-client.c | 97 +- gst/rtsp-server/rtsp-client.h | 7 +- gst/rtsp-server/rtsp-media-factory-uri.c | 6 +- gst/rtsp-server/rtsp-media-factory.c | 111 +-- gst/rtsp-server/rtsp-media-factory.h | 17 +- gst/rtsp-server/rtsp-media.c | 1082 ++++------------------ gst/rtsp-server/rtsp-media.h | 154 +-- gst/rtsp-server/rtsp-sdp.c | 2 +- gst/rtsp-server/rtsp-session-media.c | 202 ++++ gst/rtsp-server/rtsp-session-media.h | 86 ++ gst/rtsp-server/rtsp-session.c | 259 +----- gst/rtsp-server/rtsp-session.h | 65 +- gst/rtsp-server/rtsp-stream-transport.c | 202 ++++ gst/rtsp-server/rtsp-stream-transport.h | 111 +++ gst/rtsp-server/rtsp-stream.c | 971 +++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 142 +++ 17 files changed, 2036 insertions(+), 1484 deletions(-) create mode 100644 gst/rtsp-server/rtsp-session-media.c create mode 100644 gst/rtsp-server/rtsp-session-media.h create mode 100644 gst/rtsp-server/rtsp-stream-transport.c create mode 100644 gst/rtsp-server/rtsp-stream-transport.h create mode 100644 gst/rtsp-server/rtsp-stream.c create mode 100644 gst/rtsp-server/rtsp-stream.h diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index bbc6632fb4..2d6a603875 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -6,7 +6,10 @@ public_headers = \ rtsp-media-factory.h \ rtsp-media-factory-uri.h \ rtsp-media-mapping.h \ + rtsp-stream.h \ + rtsp-stream-transport.h \ rtsp-session.h \ + rtsp-session-media.h \ rtsp-session-pool.h \ rtsp-client.h \ rtsp-server.h @@ -19,7 +22,10 @@ c_sources = \ rtsp-media-factory.c \ rtsp-media-factory-uri.c \ rtsp-media-mapping.c \ + rtsp-stream.c \ + rtsp-stream-transport.c \ rtsp-session.c \ + rtsp-session-media.c \ rtsp-session-pool.c \ rtsp-client.c \ rtsp-server.c diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 659b499ce6..c78aeddc9b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -69,7 +69,7 @@ static void gst_rtsp_client_finalize (GObject * obj); static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media); static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session); -static void unlink_session_streams (GstRTSPClient * client, +static void unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, GstRTSPSessionMedia * media); G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); @@ -184,7 +184,7 @@ client_unlink_session (GstRTSPClient * client, GstRTSPSession * session) GstRTSPSessionMedia *media = g_list_first (session->medias)->data; gst_rtsp_session_media_set_state (media, GST_STATE_NULL); - unlink_session_streams (client, session, media); + unlink_session_transports (client, session, media); /* unmanage the media in the session. this will modify session->medias */ gst_rtsp_session_release_media (session, media); } @@ -480,6 +480,7 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) gst_rtsp_message_init_data (&message, channel); + /* FIXME, need some sort of iovec RTSPMessage here */ if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) return FALSE; @@ -498,48 +499,49 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) } static void -link_stream (GstRTSPClient * client, GstRTSPSession * session, - GstRTSPSessionStream * stream) +link_transport (GstRTSPClient * client, GstRTSPSession * session, + GstRTSPStreamTransport * trans) { - GST_DEBUG ("client %p: linking stream %p", client, stream); - gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data, + GST_DEBUG ("client %p: linking transport %p", client, trans); + gst_rtsp_stream_transport_set_callbacks (trans, + (GstRTSPSendFunc) do_send_data, (GstRTSPSendFunc) do_send_data, client, NULL); - client->streams = g_list_prepend (client->streams, stream); + client->transports = g_list_prepend (client->transports, trans); /* make sure our session can't expire */ gst_rtsp_session_prevent_expire (session); } static void -unlink_stream (GstRTSPClient * client, GstRTSPSession * session, - GstRTSPSessionStream * stream) +unlink_transport (GstRTSPClient * client, GstRTSPSession * session, + GstRTSPStreamTransport * trans) { - GST_DEBUG ("client %p: unlinking stream %p", client, stream); - gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); - client->streams = g_list_remove (client->streams, stream); + GST_DEBUG ("client %p: unlinking transport %p", client, trans); + gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL); + client->transports = g_list_remove (client->transports, trans); /* our session can now expire */ gst_rtsp_session_allow_expire (session); } static void -unlink_session_streams (GstRTSPClient * client, GstRTSPSession * session, +unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, GstRTSPSessionMedia * media) { guint n_streams, i; n_streams = gst_rtsp_media_n_streams (media->media); for (i = 0; i < n_streams; i++) { - GstRTSPSessionStream *sstream; + GstRTSPStreamTransport *trans; GstRTSPTransport *tr; /* get the stream as configured in the session */ - sstream = gst_rtsp_session_media_get_stream (media, i); + trans = gst_rtsp_session_media_get_transport (media, i); /* get the transport, if there is no transport configured, skip this stream */ - if (!(tr = sstream->trans.transport)) + if (!(tr = trans->transport)) continue; if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { /* for TCP, unlink the stream from the TCP connection of the client */ - unlink_stream (client, session, sstream); + unlink_transport (client, session, trans); } } } @@ -581,7 +583,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) state->sessmedia = media; /* unlink the all TCP callbacks */ - unlink_session_streams (client, session, media); + unlink_session_transports (client, session, media); /* remove the session from the watched sessions */ g_object_weak_unref (G_OBJECT (session), @@ -722,7 +724,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) goto invalid_state; /* unlink the all TCP callbacks */ - unlink_session_streams (client, session, media); + unlink_session_transports (client, session, media); /* then pause sending */ gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED); @@ -769,7 +771,6 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPStatusCode code; GString *rtpinfo; guint n_streams, i, infocount; - guint timestamp, seqnum; gchar *str; GstRTSPTimeRange *range; GstRTSPResult res; @@ -805,44 +806,31 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) n_streams = gst_rtsp_media_n_streams (media->media); for (i = 0, infocount = 0; i < n_streams; i++) { - GstRTSPSessionStream *sstream; - GstRTSPMediaStream *stream; + GstRTSPStreamTransport *trans; GstRTSPTransport *tr; - GObjectClass *payobjclass; gchar *uristr; + guint rtptime, seq; /* get the stream as configured in the session */ - sstream = gst_rtsp_session_media_get_stream (media, i); + trans = gst_rtsp_session_media_get_transport (media, i); /* get the transport, if there is no transport configured, skip this stream */ - if (!(tr = sstream->trans.transport)) { + if (!(tr = trans->transport)) { GST_INFO ("stream %d is not configured", i); continue; } if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { /* for TCP, link the stream to the TCP connection of the client */ - link_stream (client, session, sstream); + link_transport (client, session, trans); } - stream = sstream->media_stream; - - payobjclass = G_OBJECT_GET_CLASS (stream->payloader); - - if (g_object_class_find_property (payobjclass, "seqnum") && - g_object_class_find_property (payobjclass, "timestamp")) { - GObject *payobj; - - payobj = G_OBJECT (stream->payloader); - - /* only add RTP-Info for streams with seqnum and timestamp */ - g_object_get (payobj, "seqnum", &seqnum, "timestamp", ×tamp, NULL); - + if (gst_rtsp_stream_get_rtpinfo (trans->stream, &rtptime, &seq)) { if (infocount > 0) g_string_append (rtpinfo, ", "); uristr = gst_rtsp_url_get_request_uri (state->uri); g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", - uristr, i, seqnum, timestamp); + uristr, i, seq, rtptime); g_free (uristr); infocount++; @@ -944,7 +932,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPLowerTrans supported; GstRTSPStatusCode code; GstRTSPSession *session; - GstRTSPSessionStream *stream; + GstRTSPStreamTransport *trans; gchar *trans_str, *pos; guint streamid; GstRTSPSessionMedia *media; @@ -1086,14 +1074,14 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) } } - /* get a handle to the stream in the media */ - if (!(stream = gst_rtsp_session_media_get_stream (media, streamid))) - goto no_stream; + /* get a handle to the transport of the media in this session */ + if (!(trans = gst_rtsp_session_media_get_transport (media, streamid))) + goto no_stream_transport; - st = gst_rtsp_session_stream_set_transport (stream, ct); + st = gst_rtsp_stream_transport_set_transport (trans, ct); /* configure keepalive for this transport */ - gst_rtsp_session_stream_set_keepalive (stream, + gst_rtsp_stream_transport_set_keepalive (trans, (GstRTSPKeepAliveFunc) do_keepalive, session, NULL); /* serialize the server transport */ @@ -1149,7 +1137,7 @@ invalid_blocksize: gst_rtsp_transport_free (ct); return FALSE; } -no_stream: +no_stream_transport: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); g_object_unref (session); @@ -1265,7 +1253,6 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) if (!(media = find_media (client, state))) goto no_media; - /* create an SDP for the media object on this client */ if (!(sdp = klass->create_sdp (client, media))) goto no_sdp; @@ -1567,28 +1554,28 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) buffer = gst_buffer_new_wrapped (data, size); handled = FALSE; - for (walk = client->streams; walk; walk = g_list_next (walk)) { - GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data; - GstRTSPMediaStream *mstream; + for (walk = client->transports; walk; walk = g_list_next (walk)) { + GstRTSPStreamTransport *trans = (GstRTSPStreamTransport *) walk->data; + GstRTSPStream *stream; GstRTSPTransport *tr; /* get the transport, if there is no transport configured, skip this stream */ - if (!(tr = stream->trans.transport)) + if (!(tr = trans->transport)) continue; /* we also need a media stream */ - if (!(mstream = stream->media_stream)) + if (!(stream = trans->stream)) continue; /* check for TCP transport */ if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { /* dispatch to the stream based on the channel number */ if (tr->interleaved.min == channel) { - gst_rtsp_media_stream_rtp (mstream, buffer); + gst_rtsp_stream_recv_rtp (stream, buffer); handled = TRUE; break; } else if (tr->interleaved.max == channel) { - gst_rtsp_media_stream_rtcp (mstream, buffer); + gst_rtsp_stream_recv_rtcp (stream, buffer); handled = TRUE; break; } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 4712d1e546..cd08f7e0f4 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -33,6 +33,7 @@ typedef struct _GstRTSPClientState GstRTSPClientState; #include "rtsp-media.h" #include "rtsp-media-mapping.h" #include "rtsp-session-pool.h" +#include "rtsp-session-media.h" #include "rtsp-auth.h" #include "rtsp-sdp.h" @@ -58,7 +59,7 @@ typedef struct _GstRTSPClientState GstRTSPClientState; * * Information passed around containing the client state of a request. */ -struct _GstRTSPClientState{ +struct _GstRTSPClientState { GstRTSPMessage *request; GstRTSPUrl *uri; GstRTSPMethod method; @@ -81,7 +82,7 @@ struct _GstRTSPClientState{ * @media_mapping: handle to the media mapping used by the client. * @uri: cached uri * @media: cached media - * @streams: a list of streams using @connection. + * @transports: a list of #GstRTSPStreamTransport using @connection. * @sessions: a list of sessions managed by @connection. * * The client structure. @@ -104,7 +105,7 @@ struct _GstRTSPClient { GstRTSPUrl *uri; GstRTSPMedia *media; - GList *streams; + GList *transports; GList *sessions; }; diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index f4f1bdef73..620b53e03e 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -66,7 +66,7 @@ static void gst_rtsp_media_factory_uri_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_media_factory_uri_finalize (GObject * obj); -static GstElement *rtsp_media_factory_uri_get_element (GstRTSPMediaFactory * +static GstElement *rtsp_media_factory_uri_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url); G_DEFINE_TYPE (GstRTSPMediaFactoryURI, gst_rtsp_media_factory_uri, @@ -105,7 +105,7 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass) "Use the gstpay payloader to avoid decoding", DEFAULT_USE_GSTPAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - mediafactory_class->get_element = rtsp_media_factory_uri_get_element; + mediafactory_class->create_element = rtsp_media_factory_uri_create_element; GST_DEBUG_CATEGORY_INIT (rtsp_media_factory_uri_debug, "rtspmediafactoryuri", 0, "GstRTSPMediaFactoryUri"); @@ -528,7 +528,7 @@ no_more_pads_cb (GstElement * uribin, GstElement * element) } static GstElement * -rtsp_media_factory_uri_get_element (GstRTSPMediaFactory * factory, +rtsp_media_factory_uri_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { GstElement *topbin, *element, *uribin; diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 86db9fdf48..fb7af92dcc 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -58,7 +58,7 @@ static void gst_rtsp_media_factory_finalize (GObject * obj); static gchar *default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url); -static GstElement *default_get_element (GstRTSPMediaFactory * factory, +static GstElement *default_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url); static GstRTSPMedia *default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url); @@ -139,7 +139,7 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA); klass->gen_key = default_gen_key; - klass->get_element = default_get_element; + klass->create_element = default_create_element; klass->construct = default_construct; klass->configure = default_configure; klass->create_pipeline = default_create_pipeline; @@ -578,13 +578,15 @@ media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory) * @factory: a #GstRTSPMediaFactory * @url: the url used * - * Prepare the media object and create its streams. Implementations + * Construct the media object and create its streams. Implementations * should create the needed gstreamer elements and add them to the result * object. No state changes should be performed on them yet. * - * One or more GstRTSPMediaStream objects should be added to the result with - * the srcpad member set to a source pad that produces buffer of type - * application/x-rtp. + * One or more GstRTSPStream objects should be created from the result + * with gst_rtsp_media_create_stream (). + * + * After the media is constructed, it can be configured and then prepared + * with gst_rtsp_media_prepare (). * * Returns: (transfer full): a new #GstRTSPMedia if the media could be prepared. */ @@ -596,6 +598,9 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, GstRTSPMedia *media; GstRTSPMediaFactoryClass *klass; + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + g_return_val_if_fail (url != NULL, NULL); + klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); /* convert the url to a key for the hashtable. NULL return or a NULL function @@ -676,7 +681,7 @@ default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) } static GstElement * -default_get_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) +default_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { GstElement *element; GError *error = NULL; @@ -718,63 +723,6 @@ parse_error: } } -/* try to find all the payloader elements, they should be named 'pay%d'. for - * each of the payloaders we will create a stream and collect the source pad. */ -void -gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory * factory, - const GstRTSPUrl * url, GstRTSPMedia * media) -{ - GstElement *element, *elem; - GstPad *pad; - gint i; - GstRTSPMediaStream *stream; - gboolean have_elem; - - element = media->element; - - have_elem = TRUE; - for (i = 0; have_elem; i++) { - gchar *name; - - have_elem = FALSE; - - name = g_strdup_printf ("pay%d", i); - if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { - /* create the stream */ - stream = g_new0 (GstRTSPMediaStream, 1); - stream->payloader = elem; - - GST_INFO ("found stream %d with payloader %p", i, elem); - - pad = gst_element_get_static_pad (elem, "src"); - - /* ghost the pad of the payloader to the element */ - stream->srcpad = gst_ghost_pad_new (name, pad); - g_object_unref (pad); - gst_pad_set_active (stream->srcpad, TRUE); - gst_element_add_pad (media->element, stream->srcpad); - gst_object_unref (elem); - - /* add stream now */ - g_array_append_val (media->streams, stream); - have_elem = TRUE; - } - g_free (name); - - name = g_strdup_printf ("dynpay%d", i); - if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { - /* a stream that will dynamically create pads to provide RTP packets */ - - GST_INFO ("found dynamic element %d, %p", i, elem); - - media->dynamic = g_list_prepend (media->dynamic, elem); - - have_elem = TRUE; - } - g_free (name); - } -} - static GstRTSPMedia * default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { @@ -787,10 +735,7 @@ default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) if (!klass->create_pipeline) goto no_create; - if (klass->get_element) - element = klass->get_element (factory, url); - else - element = NULL; + element = gst_rtsp_media_factory_create_element (factory, url); if (element == NULL) goto no_element; @@ -798,12 +743,12 @@ default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) media = gst_rtsp_media_new (); media->element = element; + gst_rtsp_media_collect_streams (media); + media->pipeline = klass->create_pipeline (factory, media); if (media->pipeline == NULL) goto no_pipeline; - gst_rtsp_media_factory_collect_streams (factory, url, media); - return media; /* ERRORS */ @@ -879,16 +824,34 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) } /** - * gst_rtsp_media_factory_get_element: + * gst_rtsp_media_factory_create_element: * @factory: a #GstRTSPMediaFactory * @url: the url used * + * Construct and return a #GstElement that is a #GstBin containing + * the elements to use for streaming the media. + * + * The bin should contain payloaders pay%d for each stream. The default + * implementation of this function returns the bin created from the + * launch parameter. + * * Returns: (transfer floating) a new #GstElement. */ GstElement * -gst_rtsp_media_factory_get_element (GstRTSPMediaFactory * factory, +gst_rtsp_media_factory_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { - GstRTSPMediaFactoryClass *klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); - return klass->get_element (factory, url); + GstRTSPMediaFactoryClass *klass; + GstElement *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + + klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); + + if (klass->create_element) + result = klass->create_element (factory, url); + else + result = NULL; + + return result; } diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index ede1e0cebd..d20e502702 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -82,13 +82,13 @@ struct _GstRTSPMediaFactory { * @gen_key: convert @url to a key for caching shared #GstRTSPMedia objects. * The default implementation of this function will use the complete URL * including the query parameters to return a key. - * @get_element: Construct and return a #GstElement that is a #GstBin containing + * @create_element: Construct and return a #GstElement that is a #GstBin containing * the elements to use for streaming the media. The bin should contain * payloaders pay%d for each stream. The default implementation of this * function returns the bin created from the launch parameter. * @construct: the vmethod that will be called when the factory has to create the * #GstRTSPMedia for @url. The default implementation of this - * function calls get_element to retrieve an element and then looks for + * function calls create_element to retrieve an element and then looks for * pay%d to create the streams. * @configure: configure the media created with @construct. The default * implementation will configure the 'shared' property of the media. @@ -104,7 +104,7 @@ struct _GstRTSPMediaFactoryClass { gchar * (*gen_key) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); - GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); + GstElement * (*create_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); GstElement * (*create_pipeline) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); @@ -145,14 +145,11 @@ void gst_rtsp_media_factory_set_multicast_group (GstRTSPMediaFa gchar * gst_rtsp_media_factory_get_multicast_group (GstRTSPMediaFactory * factory); /* creating the media from the factory and a url */ -GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, - const GstRTSPUrl *url); +GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, + const GstRTSPUrl *url); -void gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory *factory, - const GstRTSPUrl *url, - GstRTSPMedia *media); - -GstElement * gst_rtsp_media_factory_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); +GstElement * gst_rtsp_media_factory_create_element (GstRTSPMediaFactory *factory, + const GstRTSPUrl *url); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c5efd278df..7987a97f3e 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -59,8 +59,6 @@ enum GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug); #define GST_CAT_DEFAULT rtsp_media_debug -static GQuark ssrc_stream_map_key; - static void gst_rtsp_media_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec); static void gst_rtsp_media_set_property (GObject * object, guint propid, @@ -70,6 +68,7 @@ static void gst_rtsp_media_finalize (GObject * obj); static gpointer do_loop (GstRTSPMediaClass * klass); static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message); +static void finish_unprepare (GstRTSPMedia * media); static gboolean default_unprepare (GstRTSPMedia * media); static void unlock_streams (GstRTSPMedia * media); static void default_handle_mtu (GstRTSPMedia * media, guint mtu); @@ -144,14 +143,12 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->handle_message = default_handle_message; klass->unprepare = default_unprepare; klass->handle_mtu = default_handle_mtu; - - ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); } static void gst_rtsp_media_init (GstRTSPMedia * media) { - media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); + media->streams = g_ptr_array_new_with_free_func (g_object_unref); g_mutex_init (&media->lock); g_cond_init (&media->cond); @@ -163,71 +160,20 @@ gst_rtsp_media_init (GstRTSPMedia * media) media->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP); } -void -gst_rtsp_media_trans_cleanup (GstRTSPMediaTrans * trans) -{ - if (trans->transport) { - gst_rtsp_transport_free (trans->transport); - trans->transport = NULL; - } - if (trans->rtpsource) { - g_object_set_qdata (trans->rtpsource, ssrc_stream_map_key, NULL); - trans->rtpsource = NULL; - } -} - -static void -gst_rtsp_media_stream_free (GstRTSPMediaStream * stream) -{ - if (stream->session) - g_object_unref (stream->session); - - if (stream->caps) - gst_caps_unref (stream->caps); - - if (stream->send_rtp_sink) - gst_object_unref (stream->send_rtp_sink); - if (stream->send_rtp_src) - gst_object_unref (stream->send_rtp_src); - if (stream->send_rtcp_src) - gst_object_unref (stream->send_rtcp_src); - if (stream->recv_rtcp_sink) - gst_object_unref (stream->recv_rtcp_sink); - if (stream->recv_rtp_sink) - gst_object_unref (stream->recv_rtp_sink); - - g_list_free (stream->transports); - - g_free (stream); -} - static void gst_rtsp_media_finalize (GObject * obj) { GstRTSPMedia *media; - guint i; media = GST_RTSP_MEDIA (obj); GST_INFO ("finalize media %p", media); - if (media->pipeline) { - unlock_streams (media); - gst_element_set_state (media->pipeline, GST_STATE_NULL); - gst_object_unref (media->pipeline); - } + gst_rtsp_media_unprepare (media); - for (i = 0; i < media->streams->len; i++) { - GstRTSPMediaStream *stream; + g_ptr_array_unref (media->streams); - stream = g_array_index (media->streams, GstRTSPMediaStream *, i); - - gst_rtsp_media_stream_free (stream); - } - g_array_free (media->streams, TRUE); - - g_list_foreach (media->dynamic, (GFunc) gst_object_unref, NULL); - g_list_free (media->dynamic); + g_list_free_full (media->dynamic, gst_object_unref); if (media->source) { g_source_destroy (media->source); @@ -624,6 +570,104 @@ gst_rtsp_media_get_auth (GstRTSPMedia * media) return result; } +/** + * gst_rtsp_media_collect_streams: + * @media: a #GstRTSPMedia + * + * Find all payloader elements, they should be named pay%d in the + * element of @media, and create #GstRTSPStreams for them. + * + * Collect all dynamic elements, named dynpay%d, and add them to + * the list of dynamic elements. + */ +void +gst_rtsp_media_collect_streams (GstRTSPMedia * media) +{ + GstElement *element, *elem; + GstPad *pad; + gint i; + gboolean have_elem; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + element = media->element; + + have_elem = TRUE; + for (i = 0; have_elem; i++) { + gchar *name; + + have_elem = FALSE; + + name = g_strdup_printf ("pay%d", i); + if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { + GST_INFO ("found stream %d with payloader %p", i, elem); + + /* take the pad of the payloader */ + pad = gst_element_get_static_pad (elem, "src"); + /* create the stream */ + gst_rtsp_media_create_stream (media, elem, pad); + g_object_unref (pad); + + gst_object_unref (elem); + + have_elem = TRUE; + } + g_free (name); + + name = g_strdup_printf ("dynpay%d", i); + if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { + /* a stream that will dynamically create pads to provide RTP packets */ + + GST_INFO ("found dynamic element %d, %p", i, elem); + + media->dynamic = g_list_prepend (media->dynamic, elem); + + have_elem = TRUE; + } + g_free (name); + } +} + +/** + * gst_rtsp_media_create_stream: + * @media: a #GstRTSPMedia + * @payloader: a #GstElement + * @srcpad: a source #GstPad + * + * Create a new stream in @media that provides RTP data on @srcpad. + * @srcpad should be a pad of an element inside @media->element. + * + * Returns: a new #GstRTSPStream that remains valid for as long + * as @media exists. + */ +GstRTSPStream * +gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, + GstPad * pad) +{ + GstRTSPStream *stream; + GstPad *srcpad; + gchar *name; + gint idx; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL); + g_return_val_if_fail (GST_IS_PAD (pad), NULL); + g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL); + + idx = media->streams->len; + + name = g_strdup_printf ("src_%u", idx); + srcpad = gst_ghost_pad_new (name, pad); + gst_pad_set_active (srcpad, TRUE); + gst_element_add_pad (media->element, srcpad); + g_free (name); + + stream = gst_rtsp_stream_new (idx, payloader, srcpad); + + g_ptr_array_add (media->streams, stream); + + return stream; +} /** * gst_rtsp_media_n_streams: @@ -648,18 +692,18 @@ gst_rtsp_media_n_streams (GstRTSPMedia * media) * * Retrieve the stream with index @idx from @media. * - * Returns: the #GstRTSPMediaStream at index @idx or %NULL when a stream with + * Returns: the #GstRTSPStream at index @idx or %NULL when a stream with * that index did not exist. */ -GstRTSPMediaStream * +GstRTSPStream * gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) { - GstRTSPMediaStream *res; + GstRTSPStream *res; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); if (idx < media->streams->len) - res = g_array_index (media->streams, GstRTSPMediaStream *, idx); + res = g_ptr_array_index (media->streams, idx); else res = NULL; @@ -684,7 +728,7 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play) /* make copy */ range = media->range; - if (!play && media->active > 0) { + if (!play && media->n_active > 0) { range.min.type = GST_RTSP_TIME_NOW; range.min.seconds = -1; } @@ -797,657 +841,16 @@ weird_type: } } -/** - * gst_rtsp_media_stream_rtp: - * @stream: a #GstRTSPMediaStream - * @buffer: a #GstBuffer - * - * Handle an RTP buffer for the stream. This method is usually called when a - * message has been received from a client using the TCP transport. - * - * This function takes ownership of @buffer. - * - * Returns: a GstFlowReturn. - */ -GstFlowReturn -gst_rtsp_media_stream_rtp (GstRTSPMediaStream * stream, GstBuffer * buffer) -{ - GstFlowReturn ret; - - ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[0]), buffer); - - return ret; -} - -/** - * gst_rtsp_media_stream_rtcp: - * @stream: a #GstRTSPMediaStream - * @buffer: a #GstBuffer - * - * Handle an RTCP buffer for the stream. This method is usually called when a - * message has been received from a client using the TCP transport. - * - * This function takes ownership of @buffer. - * - * Returns: a GstFlowReturn. - */ -GstFlowReturn -gst_rtsp_media_stream_rtcp (GstRTSPMediaStream * stream, GstBuffer * buffer) -{ - GstFlowReturn ret; - - ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[1]), buffer); - - return ret; -} - -/* Allocate the udp ports and sockets */ -static gboolean -alloc_udp_ports (GstRTSPMedia * media, GstRTSPMediaStream * stream) -{ - GstStateChangeReturn ret; - GstElement *udpsrc0, *udpsrc1; - GstElement *udpsink0, *udpsink1; - gint tmp_rtp, tmp_rtcp; - guint count; - gint rtpport, rtcpport; - GSocket *socket; - const gchar *host; - - udpsrc0 = NULL; - udpsrc1 = NULL; - udpsink0 = NULL; - udpsink1 = NULL; - count = 0; - - /* Start with random port */ - tmp_rtp = 0; - - if (media->is_ipv6) - host = "udp://[::0]"; - else - host = "udp://0.0.0.0"; - - /* try to allocate 2 UDP ports, the RTP port should be an even - * number and the RTCP port should be the next (uneven) port */ -again: - udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); - if (udpsrc0 == NULL) - goto no_udp_protocol; - g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL); - - ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED); - if (ret == GST_STATE_CHANGE_FAILURE) { - if (tmp_rtp != 0) { - tmp_rtp += 2; - if (++count > 20) - goto no_ports; - - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - - goto again; - } - goto no_udp_protocol; - } - - g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); - - /* check if port is even */ - if ((tmp_rtp & 1) != 0) { - /* port not even, close and allocate another */ - if (++count > 20) - goto no_ports; - - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - - tmp_rtp++; - goto again; - } - - /* allocate port+1 for RTCP now */ - udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); - if (udpsrc1 == NULL) - goto no_udp_rtcp_protocol; - - /* set port */ - tmp_rtcp = tmp_rtp + 1; - g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL); - - ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED); - /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */ - if (ret == GST_STATE_CHANGE_FAILURE) { - - if (++count > 20) - goto no_ports; - - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - - gst_element_set_state (udpsrc1, GST_STATE_NULL); - gst_object_unref (udpsrc1); - - tmp_rtp += 2; - goto again; - } - - /* all fine, do port check */ - g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL); - g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL); - - /* this should not happen... */ - if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) - goto port_error; - - udpsink0 = gst_element_factory_make ("multiudpsink", NULL); - if (!udpsink0) - goto no_udp_protocol; - - g_object_get (G_OBJECT (udpsrc0), "socket", &socket, NULL); - g_object_set (G_OBJECT (udpsink0), "socket", socket, NULL); - g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL); - - udpsink1 = gst_element_factory_make ("multiudpsink", NULL); - if (!udpsink1) - goto no_udp_protocol; - - if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), - "send-duplicates")) { - g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); - } else { - g_warning - ("old multiudpsink version found without send-duplicates property"); - } - - if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), - "buffer-size")) { - g_object_set (G_OBJECT (udpsink0), "buffer-size", media->buffer_size, NULL); - } else { - GST_WARNING ("multiudpsink version found without buffer-size property"); - } - - g_object_get (G_OBJECT (udpsrc1), "socket", &socket, NULL); - g_object_set (G_OBJECT (udpsink1), "socket", socket, NULL); - g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); - - g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL); - g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "auto-multicast", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL); - - /* we keep these elements, we configure all in configure_transport when the - * server told us to really use the UDP ports. */ - stream->udpsrc[0] = udpsrc0; - stream->udpsrc[1] = udpsrc1; - stream->udpsink[0] = udpsink0; - stream->udpsink[1] = udpsink1; - stream->server_port.min = rtpport; - stream->server_port.max = rtcpport; - - return TRUE; - - /* ERRORS */ -no_udp_protocol: - { - goto cleanup; - } -no_ports: - { - goto cleanup; - } -no_udp_rtcp_protocol: - { - goto cleanup; - } -port_error: - { - goto cleanup; - } -cleanup: - { - if (udpsrc0) { - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - } - if (udpsrc1) { - gst_element_set_state (udpsrc1, GST_STATE_NULL); - gst_object_unref (udpsrc1); - } - if (udpsink0) { - gst_element_set_state (udpsink0, GST_STATE_NULL); - gst_object_unref (udpsink0); - } - if (udpsink1) { - gst_element_set_state (udpsink1, GST_STATE_NULL); - gst_object_unref (udpsink1); - } - return FALSE; - } -} - -/* executed from streaming thread */ -static void -caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream) -{ - gchar *capsstr; - GstCaps *newcaps, *oldcaps; - - newcaps = gst_pad_get_current_caps (pad); - - oldcaps = stream->caps; - stream->caps = newcaps; - - if (oldcaps) - gst_caps_unref (oldcaps); - - capsstr = gst_caps_to_string (newcaps); - GST_INFO ("stream %p received caps %p, %s", stream, newcaps, capsstr); - g_free (capsstr); -} - -static void -dump_structure (const GstStructure * s) -{ - gchar *sstr; - - sstr = gst_structure_to_string (s); - GST_INFO ("structure: %s", sstr); - g_free (sstr); -} - -static GstRTSPMediaTrans * -find_transport (GstRTSPMediaStream * stream, const gchar * rtcp_from) -{ - GList *walk; - GstRTSPMediaTrans *result = NULL; - const gchar *tmp; - gchar *dest; - guint port; - - if (rtcp_from == NULL) - return NULL; - - tmp = g_strrstr (rtcp_from, ":"); - if (tmp == NULL) - return NULL; - - port = atoi (tmp + 1); - dest = g_strndup (rtcp_from, tmp - rtcp_from); - - GST_INFO ("finding %s:%d in %d transports", dest, port, - g_list_length (stream->transports)); - - for (walk = stream->transports; walk; walk = g_list_next (walk)) { - GstRTSPMediaTrans *trans = walk->data; - gint min, max; - - min = trans->transport->client_port.min; - max = trans->transport->client_port.max; - - if ((strcmp (trans->transport->destination, dest) == 0) && (min == port - || max == port)) { - result = trans; - break; - } - } - g_free (dest); - - return result; -} - -static GstRTSPMediaTrans * -check_transport (GObject * source, GstRTSPMediaStream * stream) -{ - GstStructure *stats; - GstRTSPMediaTrans *trans; - - /* see if we have a stream to match with the origin of the RTCP packet */ - trans = g_object_get_qdata (source, ssrc_stream_map_key); - if (trans == NULL) { - g_object_get (source, "stats", &stats, NULL); - if (stats) { - const gchar *rtcp_from; - - dump_structure (stats); - - rtcp_from = gst_structure_get_string (stats, "rtcp-from"); - if ((trans = find_transport (stream, rtcp_from))) { - GST_INFO ("%p: found transport %p for source %p", stream, trans, - source); - - /* keep ref to the source */ - trans->rtpsource = source; - - g_object_set_qdata (source, ssrc_stream_map_key, trans); - } - gst_structure_free (stats); - } - } - - return trans; -} - -static void -on_new_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream) -{ - GstRTSPMediaTrans *trans; - - GST_INFO ("%p: new source %p", stream, source); - - trans = check_transport (source, stream); - - if (trans) - GST_INFO ("%p: source %p for transport %p", stream, source, trans); -} - -static void -on_ssrc_sdes (GObject * session, GObject * source, GstRTSPMediaStream * stream) -{ - GST_INFO ("%p: new SDES %p", stream, source); -} - -static void -on_ssrc_active (GObject * session, GObject * source, - GstRTSPMediaStream * stream) -{ - GstRTSPMediaTrans *trans; - - trans = check_transport (source, stream); - - if (trans) - GST_INFO ("%p: source %p in transport %p is active", stream, source, trans); - - if (trans && trans->keep_alive) - trans->keep_alive (trans->ka_user_data); - -#ifdef DUMP_STATS - { - GstStructure *stats; - g_object_get (source, "stats", &stats, NULL); - if (stats) { - dump_structure (stats); - gst_structure_free (stats); - } - } -#endif -} - -static void -on_bye_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream) -{ - GST_INFO ("%p: source %p bye", stream, source); -} - -static void -on_bye_timeout (GObject * session, GObject * source, - GstRTSPMediaStream * stream) -{ - GstRTSPMediaTrans *trans; - - GST_INFO ("%p: source %p bye timeout", stream, source); - - if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) { - trans->rtpsource = NULL; - trans->timeout = TRUE; - } -} - -static void -on_timeout (GObject * session, GObject * source, GstRTSPMediaStream * stream) -{ - GstRTSPMediaTrans *trans; - - GST_INFO ("%p: source %p timeout", stream, source); - - if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) { - trans->rtpsource = NULL; - trans->timeout = TRUE; - } -} - -static GstFlowReturn -handle_new_sample (GstAppSink * sink, gpointer user_data) -{ - GList *walk; - GstSample *sample; - GstBuffer *buffer; - GstRTSPMediaStream *stream; - - sample = gst_app_sink_pull_sample (sink); - if (!sample) - return GST_FLOW_OK; - - stream = (GstRTSPMediaStream *) user_data; - buffer = gst_sample_get_buffer (sample); - - for (walk = stream->transports; walk; walk = g_list_next (walk)) { - GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data; - - if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) { - if (tr->send_rtp) - tr->send_rtp (buffer, tr->transport->interleaved.min, tr->user_data); - } else { - if (tr->send_rtcp) - tr->send_rtcp (buffer, tr->transport->interleaved.max, tr->user_data); - } - } - gst_sample_unref (sample); - - return GST_FLOW_OK; -} - -static GstAppSinkCallbacks sink_cb = { - NULL, /* not interested in EOS */ - NULL, /* not interested in preroll samples */ - handle_new_sample, -}; - -/* prepare the pipeline objects to handle @stream in @media */ -static gboolean -setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media) -{ - gchar *name; - GstPad *pad, *teepad, *queuepad, *selpad; - GstPadLinkReturn ret; - gint i; - - /* allocate udp ports, we will have 4 of them, 2 for receiving RTP/RTCP and 2 - * for sending RTP/RTCP. The sender and receiver ports are shared between the - * elements */ - if (!alloc_udp_ports (media, stream)) - return FALSE; - - /* add the ports to the pipeline */ - for (i = 0; i < 2; i++) { - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsink[i]); - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsrc[i]); - } - - /* create elements for the TCP transfer */ - for (i = 0; i < 2; i++) { - stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL); - stream->appqueue[i] = gst_element_factory_make ("queue", NULL); - stream->appsink[i] = gst_element_factory_make ("appsink", NULL); - g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL); - g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL); - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appqueue[i]); - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsink[i]); - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsrc[i]); - gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]), - &sink_cb, stream, NULL); - } - - /* hook up the stream to the RTP session elements. */ - name = g_strdup_printf ("send_rtp_sink_%u", idx); - stream->send_rtp_sink = gst_element_get_request_pad (media->rtpbin, name); - g_free (name); - name = g_strdup_printf ("send_rtp_src_%u", idx); - stream->send_rtp_src = gst_element_get_static_pad (media->rtpbin, name); - g_free (name); - name = g_strdup_printf ("send_rtcp_src_%u", idx); - stream->send_rtcp_src = gst_element_get_request_pad (media->rtpbin, name); - g_free (name); - name = g_strdup_printf ("recv_rtcp_sink_%u", idx); - stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name); - g_free (name); - name = g_strdup_printf ("recv_rtp_sink_%u", idx); - stream->recv_rtp_sink = gst_element_get_request_pad (media->rtpbin, name); - g_free (name); - - /* get the session */ - g_signal_emit_by_name (media->rtpbin, "get-internal-session", idx, - &stream->session); - - g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc, - stream); - g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes, - stream); - g_signal_connect (stream->session, "on-ssrc-active", - (GCallback) on_ssrc_active, stream); - g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, - stream); - g_signal_connect (stream->session, "on-bye-timeout", - (GCallback) on_bye_timeout, stream); - g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout, - stream); - - /* link the RTP pad to the session manager */ - ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink); - if (ret != GST_PAD_LINK_OK) - goto link_failed; - - /* make tee for RTP and link to stream */ - stream->tee[0] = gst_element_factory_make ("tee", NULL); - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[0]); - - pad = gst_element_get_static_pad (stream->tee[0], "sink"); - gst_pad_link (stream->send_rtp_src, pad); - gst_object_unref (pad); - - /* link RTP sink, we're pretty sure this will work. */ - teepad = gst_element_get_request_pad (stream->tee[0], "src_%u"); - pad = gst_element_get_static_pad (stream->udpsink[0], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); - - teepad = gst_element_get_request_pad (stream->tee[0], "src_%u"); - pad = gst_element_get_static_pad (stream->appqueue[0], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); - - queuepad = gst_element_get_static_pad (stream->appqueue[0], "src"); - pad = gst_element_get_static_pad (stream->appsink[0], "sink"); - gst_pad_link (queuepad, pad); - gst_object_unref (pad); - gst_object_unref (queuepad); - - /* make tee for RTCP */ - stream->tee[1] = gst_element_factory_make ("tee", NULL); - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[1]); - - pad = gst_element_get_static_pad (stream->tee[1], "sink"); - gst_pad_link (stream->send_rtcp_src, pad); - gst_object_unref (pad); - - /* link RTCP elements */ - teepad = gst_element_get_request_pad (stream->tee[1], "src_%u"); - pad = gst_element_get_static_pad (stream->udpsink[1], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); - - teepad = gst_element_get_request_pad (stream->tee[1], "src_%u"); - pad = gst_element_get_static_pad (stream->appqueue[1], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); - - queuepad = gst_element_get_static_pad (stream->appqueue[1], "src"); - pad = gst_element_get_static_pad (stream->appsink[1], "sink"); - gst_pad_link (queuepad, pad); - gst_object_unref (pad); - gst_object_unref (queuepad); - - /* make selector for the RTP receivers */ - stream->selector[0] = gst_element_factory_make ("funnel", NULL); - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]); - - pad = gst_element_get_static_pad (stream->selector[0], "src"); - gst_pad_link (pad, stream->recv_rtp_sink); - gst_object_unref (pad); - - selpad = gst_element_get_request_pad (stream->selector[0], "sink_%u"); - pad = gst_element_get_static_pad (stream->udpsrc[0], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - - selpad = gst_element_get_request_pad (stream->selector[0], "sink_%u"); - pad = gst_element_get_static_pad (stream->appsrc[0], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - - /* make selector for the RTCP receivers */ - stream->selector[1] = gst_element_factory_make ("funnel", NULL); - gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]); - - pad = gst_element_get_static_pad (stream->selector[1], "src"); - gst_pad_link (pad, stream->recv_rtcp_sink); - gst_object_unref (pad); - - selpad = gst_element_get_request_pad (stream->selector[1], "sink_%u"); - pad = gst_element_get_static_pad (stream->udpsrc[1], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - - selpad = gst_element_get_request_pad (stream->selector[1], "sink_%u"); - pad = gst_element_get_static_pad (stream->appsrc[1], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values */ - gst_element_set_state (stream->udpsrc[0], GST_STATE_PLAYING); - gst_element_set_state (stream->udpsrc[1], GST_STATE_PLAYING); - gst_element_set_locked_state (stream->udpsrc[0], TRUE); - gst_element_set_locked_state (stream->udpsrc[1], TRUE); - - /* be notified of caps changes */ - stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps", - (GCallback) caps_notify, stream); - - stream->prepared = TRUE; - - return TRUE; - - /* ERRORS */ -link_failed: - { - GST_WARNING ("failed to link stream %d", idx); - return FALSE; - } -} - static void unlock_streams (GstRTSPMedia * media) { - guint i, n_streams; + guint i; /* unlock the udp src elements */ - n_streams = gst_rtsp_media_n_streams (media); - for (i = 0; i < n_streams; i++) { - GstRTSPMediaStream *stream; + for (i = 0; i < media->streams->len; i++) { + GstRTSPStream *stream; - stream = gst_rtsp_media_get_stream (media, i); + stream = g_ptr_array_index (media->streams, i); gst_element_set_locked_state (stream->udpsrc[0], FALSE); gst_element_set_locked_state (stream->udpsrc[1], FALSE); @@ -1583,10 +986,9 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) break; case GST_MESSAGE_EOS: GST_INFO ("%p: got EOS", media); - if (media->eos_pending) { + if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) { GST_DEBUG ("shutting down after EOS"); - gst_element_set_state (media->pipeline, GST_STATE_NULL); - media->eos_pending = FALSE; + finish_unprepare (media); g_object_unref (media); } break; @@ -1618,31 +1020,16 @@ bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media) static void pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) { - GstRTSPMediaStream *stream; - gchar *name; + GstRTSPStream *stream; gint i; - i = media->streams->len + 1; - - GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), i); - - stream = g_new0 (GstRTSPMediaStream, 1); - stream->payloader = element; - - name = g_strdup_printf ("dynpay%d", i); + stream = gst_rtsp_media_create_stream (media, element, pad); + GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), + stream->idx); media->adding = TRUE; - /* ghost the pad of the payloader to the element */ - stream->srcpad = gst_ghost_pad_new (name, pad); - gst_pad_set_active (stream->srcpad, TRUE); - gst_element_add_pad (media->element, stream->srcpad); - g_free (name); - - /* add stream now */ - g_array_append_val (media->streams, stream); - - setup_stream (stream, i, media); + gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline), media->rtpbin); for (i = 0; i < 2; i++) { gst_element_set_state (stream->udpsink[i], GST_STATE_PAUSED); @@ -1652,6 +1039,7 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) gst_element_set_state (stream->selector[i], GST_STATE_PAUSED); gst_element_set_state (stream->appsrc[i], GST_STATE_PAUSED); } + media->adding = FALSE; } @@ -1686,7 +1074,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) { GstStateChangeReturn ret; GstRTSPMediaStatus status; - guint i, n_streams; + guint i; GstRTSPMediaClass *klass; GstBus *bus; GList *walk; @@ -1726,13 +1114,12 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) /* link streams we already have, other streams might appear when we have * dynamic elements */ - n_streams = gst_rtsp_media_n_streams (media); - for (i = 0; i < n_streams; i++) { - GstRTSPMediaStream *stream; + for (i = 0; i < media->streams->len; i++) { + GstRTSPStream *stream; - stream = gst_rtsp_media_get_stream (media, i); + stream = g_ptr_array_index (media->streams, i); - setup_stream (stream, i, media); + gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline), media->rtpbin); } for (walk = media->dynamic; walk; walk = g_list_next (walk)) { @@ -1809,8 +1196,6 @@ no_rtpbin: state_failed: { GST_WARNING ("failed to preroll pipeline"); - unlock_streams (media); - gst_element_set_state (media->pipeline, GST_STATE_NULL); gst_rtsp_media_unprepare (media); return FALSE; } @@ -1829,7 +1214,6 @@ state_failed: gboolean gst_rtsp_media_unprepare (GstRTSPMedia * media) { - GstRTSPMediaClass *klass; gboolean success; if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED) @@ -1837,14 +1221,18 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) GST_INFO ("unprepare media %p", media); media->target_state = GST_STATE_NULL; + success = TRUE; - klass = GST_RTSP_MEDIA_GET_CLASS (media); - if (klass->unprepare) - success = klass->unprepare (media); - else - success = TRUE; + if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) { + GstRTSPMediaClass *klass; + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + if (klass->unprepare) + success = klass->unprepare (media); + } else { + finish_unprepare (media); + } - media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED; media->reused = TRUE; /* when the media is not reusable, this will effectively unref the media and @@ -1854,6 +1242,36 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) return success; } +static void +finish_unprepare (GstRTSPMedia * media) +{ + gint i; + + GST_DEBUG ("shutting down"); + + unlock_streams (media); + gst_element_set_state (media->pipeline, GST_STATE_NULL); + + for (i = 0; i < media->streams->len; i++) { + GstRTSPStream *stream; + + GST_INFO ("Removing elements of stream %d from pipeline", i); + + stream = g_ptr_array_index (media->streams, i); + + gst_rtsp_stream_leave_bin (stream, GST_BIN (media->pipeline), + media->rtpbin); + } + g_ptr_array_set_size (media->streams, 0); + + gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin); + + gst_object_unref (media->pipeline); + media->pipeline = NULL; + + media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED; +} + static gboolean default_unprepare (GstRTSPMedia * media) { @@ -1861,49 +1279,22 @@ default_unprepare (GstRTSPMedia * media) GST_DEBUG ("sending EOS for shutdown"); /* ref so that we don't disappear */ g_object_ref (media); - media->eos_pending = TRUE; gst_element_send_event (media->pipeline, gst_event_new_eos ()); /* we need to go to playing again for the EOS to propagate, normally in this * state, nothing is receiving data from us anymore so this is ok. */ gst_element_set_state (media->pipeline, GST_STATE_PLAYING); + media->status = GST_RTSP_MEDIA_STATUS_UNPREPARING; } else { - GST_DEBUG ("shutting down"); - gst_element_set_state (media->pipeline, GST_STATE_NULL); + finish_unprepare (media); } return TRUE; } -static void -add_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream, - gchar * dest, gint min, gint max) -{ - GST_INFO ("adding %s:%d-%d", dest, min, max); - g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); -} - -static void -remove_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream, - gchar * dest, gint min, gint max) -{ - GST_INFO ("removing %s:%d-%d", dest, min, max); - g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); -} - -static void -set_multicast_ttl (GstRTSPMedia * media, GstRTSPMediaStream * stream, guint ttl) -{ - GST_INFO ("setting ttl-mc %d", ttl); - g_object_set (G_OBJECT (stream->udpsink[0]), "ttl-mc", ttl, NULL); - g_object_set (G_OBJECT (stream->udpsink[1]), "ttl-mc", ttl, NULL); -} - /** * gst_rtsp_media_set_state: * @media: a #GstRTSPMedia * @state: the target state of the media - * @transports: a #GArray of #GstRTSPMediaTrans pointers + * @transports: a #GPtrArray of #GstRTSPStreamTransport pointers * * Set the state of @media to @state and for the transports in @transports. * @@ -1911,7 +1302,7 @@ set_multicast_ttl (GstRTSPMedia * media, GstRTSPMediaStream * stream, guint ttl) */ gboolean gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, - GArray * transports) + GPtrArray * transports) { gint i; gboolean add, remove, do_state; @@ -1946,74 +1337,26 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, default: break; } - old_active = media->active; + old_active = media->n_active; for (i = 0; i < transports->len; i++) { - GstRTSPMediaTrans *tr; - GstRTSPMediaStream *stream; - GstRTSPTransport *trans; + GstRTSPStreamTransport *trans; /* we need a non-NULL entry in the array */ - tr = g_array_index (transports, GstRTSPMediaTrans *, i); - if (tr == NULL) + trans = g_ptr_array_index (transports, i); + if (trans == NULL) continue; /* we need a transport */ - if (!(trans = tr->transport)) + if (!trans->transport) continue; - /* get the stream and add the destinations */ - stream = gst_rtsp_media_get_stream (media, tr->idx); - switch (trans->lower_transport) { - case GST_RTSP_LOWER_TRANS_UDP: - case GST_RTSP_LOWER_TRANS_UDP_MCAST: - { - gchar *dest; - gint min, max; - guint ttl = 0; - - dest = trans->destination; - if (trans->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - min = trans->port.min; - max = trans->port.max; - ttl = trans->ttl; - } else { - min = trans->client_port.min; - max = trans->client_port.max; - } - - if (add && !tr->active) { - add_udp_destination (media, stream, dest, min, max); - if (ttl > 0) { - set_multicast_ttl (media, stream, ttl); - } - stream->transports = g_list_prepend (stream->transports, tr); - tr->active = TRUE; - media->active++; - } else if (remove && tr->active) { - remove_udp_destination (media, stream, dest, min, max); - stream->transports = g_list_remove (stream->transports, tr); - tr->active = FALSE; - media->active--; - } - break; - } - case GST_RTSP_LOWER_TRANS_TCP: - if (add && !tr->active) { - GST_INFO ("adding TCP %s", trans->destination); - stream->transports = g_list_prepend (stream->transports, tr); - tr->active = TRUE; - media->active++; - } else if (remove && tr->active) { - GST_INFO ("removing TCP %s", trans->destination); - stream->transports = g_list_remove (stream->transports, tr); - tr->active = FALSE; - media->active--; - } - break; - default: - GST_INFO ("Unknown transport %d", trans->lower_transport); - break; + if (add) { + if (gst_rtsp_stream_add_transport (trans->stream, trans)) + media->n_active++; + } else if (remove) { + if (gst_rtsp_stream_remove_transport (trans->stream, trans)) + media->n_active--; } } @@ -2021,12 +1364,12 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, if (old_active == 0 && add) do_state = TRUE; /* if we have no more active media, do the downward state changes */ - else if (media->active == 0) + else if (media->n_active == 0) do_state = TRUE; else do_state = FALSE; - GST_INFO ("state %d active %d media %p do_state %d", state, media->active, + GST_INFO ("state %d active %d media %p do_state %d", state, media->n_active, media, do_state); if (media->target_state != state) { @@ -2046,78 +1389,23 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, /* remember where we are */ if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED || - old_active != media->active)) + old_active != media->n_active)) collect_media_stats (media); return TRUE; } -/** - * gst_rtsp_media_remove_elements: - * @media: a #GstRTSPMedia - * - * Remove all elements and the pipeline controlled by @media. - */ -void -gst_rtsp_media_remove_elements (GstRTSPMedia * media) -{ - gint i, j; - - unlock_streams (media); - - for (i = 0; i < media->streams->len; i++) { - GstRTSPMediaStream *stream; - - GST_INFO ("Removing elements of stream %d from pipeline", i); - - stream = g_array_index (media->streams, GstRTSPMediaStream *, i); - - gst_pad_unlink (stream->srcpad, stream->send_rtp_sink); - - g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig); - - for (j = 0; j < 2; j++) { - gst_element_set_state (stream->udpsrc[j], GST_STATE_NULL); - gst_element_set_state (stream->udpsink[j], GST_STATE_NULL); - gst_element_set_state (stream->appsrc[j], GST_STATE_NULL); - gst_element_set_state (stream->appsink[j], GST_STATE_NULL); - gst_element_set_state (stream->appqueue[j], GST_STATE_NULL); - gst_element_set_state (stream->tee[j], GST_STATE_NULL); - gst_element_set_state (stream->selector[j], GST_STATE_NULL); - - gst_bin_remove (GST_BIN (media->pipeline), stream->udpsrc[j]); - gst_bin_remove (GST_BIN (media->pipeline), stream->udpsink[j]); - gst_bin_remove (GST_BIN (media->pipeline), stream->appsrc[j]); - gst_bin_remove (GST_BIN (media->pipeline), stream->appsink[j]); - gst_bin_remove (GST_BIN (media->pipeline), stream->appqueue[j]); - gst_bin_remove (GST_BIN (media->pipeline), stream->tee[j]); - gst_bin_remove (GST_BIN (media->pipeline), stream->selector[j]); - } - if (stream->caps) - gst_caps_unref (stream->caps); - stream->caps = NULL; - gst_rtsp_media_stream_free (stream); - } - g_array_remove_range (media->streams, 0, media->streams->len); - - gst_element_set_state (media->rtpbin, GST_STATE_NULL); - gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin); - - gst_object_unref (media->pipeline); - media->pipeline = NULL; -} - static void default_handle_mtu (GstRTSPMedia * media, guint mtu) { gint i; for (i = 0; i < media->streams->len; i++) { - GstRTSPMediaStream *stream; + GstRTSPStream *stream; GST_INFO ("Setting mtu %d for stream %d", mtu, i); - stream = g_array_index (media->streams, GstRTSPMediaStream *, i); + stream = g_ptr_array_index (media->streams, i); g_object_set (G_OBJECT (stream->payloader), "mtu", mtu, NULL); } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index fb86a288c5..16b2cceab2 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -36,115 +36,17 @@ G_BEGIN_DECLS #define GST_RTSP_MEDIA_CAST(obj) ((GstRTSPMedia*)(obj)) #define GST_RTSP_MEDIA_CLASS_CAST(klass) ((GstRTSPMediaClass*)(klass)) -typedef struct _GstRTSPMediaStream GstRTSPMediaStream; typedef struct _GstRTSPMedia GstRTSPMedia; typedef struct _GstRTSPMediaClass GstRTSPMediaClass; -typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans; - -typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); -typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); - -/** - * GstRTSPMediaTrans: - * @idx: a stream index - * @send_rtp: callback for sending RTP messages - * @send_rtcp: callback for sending RTCP messages - * @send_rtp_list: callback for sending RTP messages - * @send_rtcp_list: callback for sending RTCP messages - * @user_data: user data passed in the callbacks - * @notify: free function for the user_data. - * @keep_alive: keep alive callback - * @ka_user_data: data passed to @keep_alive - * @ka_notify: called when @ka_user_data is freed - * @active: if we are actively sending - * @timeout: if we timed out - * @transport: a transport description - * @rtpsource: the receiver rtp source object - * - * A Transport description for stream @idx - */ -struct _GstRTSPMediaTrans { - guint idx; - - GstRTSPSendFunc send_rtp; - GstRTSPSendFunc send_rtcp; - gpointer user_data; - GDestroyNotify notify; - - GstRTSPKeepAliveFunc keep_alive; - gpointer ka_user_data; - GDestroyNotify ka_notify; - gboolean active; - gboolean timeout; - - GstRTSPTransport *transport; - - GObject *rtpsource; -}; +#include "rtsp-stream.h" #include "rtsp-auth.h" -/** - * GstRTSPMediaStream: - * @srcpad: the srcpad of the stream - * @payloader: the payloader of the format - * @prepared: if the stream is prepared for streaming - * @recv_rtp_sink: sinkpad for RTP buffers - * @recv_rtcp_sink: sinkpad for RTCP buffers - * @send_rtp_src: srcpad for RTP buffers - * @send_rtcp_src: srcpad for RTCP buffers - * @udpsrc: the udp source elements for RTP/RTCP - * @udpsink: the udp sink elements for RTP/RTCP - * @appsrc: the app source elements for RTP/RTCP - * @appsink: the app sink elements for RTP/RTCP - * @server_port: the server ports for this stream - * @caps_sig: the signal id for detecting caps - * @caps: the caps of the stream - * @tranports: the current transports being streamed - * - * The definition of a media stream. The streams are identified by @id. - */ -struct _GstRTSPMediaStream { - GstPad *srcpad; - GstElement *payloader; - gboolean prepared; - - /* pads on the rtpbin */ - GstPad *recv_rtcp_sink; - GstPad *recv_rtp_sink; - GstPad *send_rtp_sink; - GstPad *send_rtp_src; - GstPad *send_rtcp_src; - - /* the RTPSession object */ - GObject *session; - - /* sinks used for sending and receiving RTP and RTCP, they share - * sockets */ - GstElement *udpsrc[2]; - GstElement *udpsink[2]; - /* for TCP transport */ - GstElement *appsrc[2]; - GstElement *appqueue[2]; - GstElement *appsink[2]; - - GstElement *tee[2]; - GstElement *selector[2]; - - /* server ports for sending/receiving */ - GstRTSPRange server_port; - - /* the caps of the stream */ - gulong caps_sig; - GstCaps *caps; - - /* transports we stream to */ - GList *transports; -}; - /** * GstRTSPMediaStatus: * @GST_RTSP_MEDIA_STATUS_UNPREPARED: media pipeline not prerolled + * @GST_RTSP_MEDIA_STATUS_UNPREPARING: media pipeline is busy doing a clean + * shutdown. * @GST_RTSP_MEDIA_STATUS_PREPARING: media pipeline is prerolling * @GST_RTSP_MEDIA_STATUS_PREPARED: media pipeline is prerolled * @GST_RTSP_MEDIA_STATUS_ERROR: media pipeline is in error @@ -152,10 +54,11 @@ struct _GstRTSPMediaStream { * The state of the media pipeline. */ typedef enum { - GST_RTSP_MEDIA_STATUS_UNPREPARED = 0, - GST_RTSP_MEDIA_STATUS_PREPARING = 1, - GST_RTSP_MEDIA_STATUS_PREPARED = 2, - GST_RTSP_MEDIA_STATUS_ERROR = 3 + GST_RTSP_MEDIA_STATUS_UNPREPARED = 0, + GST_RTSP_MEDIA_STATUS_UNPREPARING = 1, + GST_RTSP_MEDIA_STATUS_PREPARING = 2, + GST_RTSP_MEDIA_STATUS_PREPARED = 3, + GST_RTSP_MEDIA_STATUS_ERROR = 4 } GstRTSPMediaStatus; /** @@ -168,10 +71,10 @@ typedef enum { * @reused: if this media has been reused * @is_ipv6: if this media is using ipv6 * @element: the data providing element - * @streams: the different streams provided by @element + * @streams: the different #GstRTSPStream provided by @element * @dynamic: list of dynamic elements managed by @element * @status: the status of the media pipeline - * @active: the number of active connections + * @n_active: the number of active connections * @pipeline: the toplevel pipeline * @fakesink: for making state changes async * @source: the bus watch for pipeline messages. @@ -184,7 +87,7 @@ typedef enum { * @range: the range of the media being streamed * * A class that contains the GStreamer element along with a list of - * #GstRTSPMediaStream objects that can produce data. + * #GstRTSPStream objects that can produce data. * * This object is usually created from a #GstRTSPMediaFactory. */ @@ -205,11 +108,10 @@ struct _GstRTSPMedia { gchar *multicast_group; GstElement *element; - GArray *streams; + GPtrArray *streams; GList *dynamic; GstRTSPMediaStatus status; - gint active; - gboolean eos_pending; + gint n_active; gboolean adding; /* the pipeline for the media */ @@ -251,15 +153,15 @@ struct _GstRTSPMediaClass { GThread *thread; /* vmethods */ - gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message); - gboolean (*unprepare) (GstRTSPMedia *media); - void (*handle_mtu) (GstRTSPMedia *media, guint mtu); + gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message); + gboolean (*unprepare) (GstRTSPMedia *media); + void (*handle_mtu) (GstRTSPMedia *media, guint mtu); /* signals */ - gboolean (*prepared) (GstRTSPMedia *media); - gboolean (*unprepared) (GstRTSPMedia *media); + gboolean (*prepared) (GstRTSPMedia *media); + gboolean (*unprepared) (GstRTSPMedia *media); - gboolean (*new_state) (GstRTSPMedia *media, GstState state); + gboolean (*new_state) (GstRTSPMedia *media, GstState state); }; GType gst_rtsp_media_get_type (void); @@ -294,24 +196,24 @@ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media); gboolean gst_rtsp_media_unprepare (GstRTSPMedia *media); +/* creating streams */ +void gst_rtsp_media_collect_streams (GstRTSPMedia *media); +GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia *media, + GstElement *payloader, + GstPad *srcpad); + /* dealing with the media */ guint gst_rtsp_media_n_streams (GstRTSPMedia *media); -GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); +GstRTSPStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range); gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, gboolean play); -GstFlowReturn gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer); -GstFlowReturn gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer); - -gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GArray *transports); - -void gst_rtsp_media_remove_elements (GstRTSPMedia *media); +gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, + GPtrArray *transports); void gst_rtsp_media_handle_mtu (GstRTSPMedia *media, guint mtu); -void gst_rtsp_media_trans_cleanup (GstRTSPMediaTrans *trans); - G_END_DECLS #endif /* __GST_RTSP_MEDIA_H__ */ diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index c6b379b830..cfbe6f9fe0 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -48,7 +48,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, g_free (rangestr); for (i = 0; i < n_streams; i++) { - GstRTSPMediaStream *stream; + GstRTSPStream *stream; GstSDPMedia *smedia; GstStructure *s; const gchar *caps_str, *caps_enc, *caps_params; diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c new file mode 100644 index 0000000000..12a01d4703 --- /dev/null +++ b/gst/rtsp-server/rtsp-session-media.c @@ -0,0 +1,202 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include + +#include "rtsp-session.h" + +#undef DEBUG + +#define DEFAULT_TIMEOUT 60 + +enum +{ + PROP_0, + PROP_LAST +}; + +GST_DEBUG_CATEGORY_STATIC (rtsp_session_media_debug); +#define GST_CAT_DEFAULT rtsp_session_media_debug + +static void gst_rtsp_session_media_finalize (GObject * obj); + +G_DEFINE_TYPE (GstRTSPSessionMedia, gst_rtsp_session_media, G_TYPE_OBJECT); + +static void +gst_rtsp_session_media_class_init (GstRTSPSessionMediaClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gst_rtsp_session_media_finalize; + + GST_DEBUG_CATEGORY_INIT (rtsp_session_media_debug, "rtspsessionmedia", 0, + "GstRTSPSessionMedia"); +} + +static void +gst_rtsp_session_media_init (GstRTSPSessionMedia * media) +{ + media->state = GST_RTSP_STATE_INIT; +} + +static void +gst_rtsp_session_media_finalize (GObject * obj) +{ + GstRTSPSessionMedia *media; + + media = GST_RTSP_SESSION_MEDIA (obj); + + GST_INFO ("free session media %p", media); + + gst_rtsp_session_media_set_state (media, GST_STATE_NULL); + + g_ptr_array_unref (media->transports); + + gst_rtsp_url_free (media->url); + g_object_unref (media->media); + + G_OBJECT_CLASS (gst_rtsp_session_media_parent_class)->finalize (obj); +} + +static void +free_session_media (gpointer data) +{ + if (data) + g_object_unref (data); +} + +/** + * gst_rtsp_session_media_new: + * @url: the #GstRTSPUrl + * @media: the #GstRTSPMedia + * + * Create a new #GstRTPSessionMedia that manages the streams + * in @media for @url. @media should be prepared. + * + * Ownership is taken of @media. + * + * Returns: a new #GstRTSPSessionMedia. + */ +GstRTSPSessionMedia * +gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media) +{ + GstRTSPSessionMedia *result; + guint n_streams; + + g_return_val_if_fail (url != NULL, NULL); + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + g_return_val_if_fail (media->status == GST_RTSP_MEDIA_STATUS_PREPARED, NULL); + + result = g_object_new (GST_TYPE_RTSP_SESSION_MEDIA, NULL); + result->url = gst_rtsp_url_copy ((GstRTSPUrl *) url); + result->media = media; + + /* prealloc the streams now, filled with NULL */ + n_streams = gst_rtsp_media_n_streams (media); + result->transports = g_ptr_array_new_full (n_streams, free_session_media); + g_ptr_array_set_size (result->transports, n_streams); + + return result; +} + +/** + * gst_rtsp_session_media_get_transport: + * @media: a #GstRTSPSessionMedia + * @idx: the stream index + * + * Get a previously created or create a new #GstRTSPStreamTransport at @idx. + * + * Returns: a #GstRTSPStreamTransport that is valid until the session of @media + * is unreffed. + */ +GstRTSPStreamTransport * +gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx) +{ + GstRTSPStreamTransport *result; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL); + g_return_val_if_fail (media->media != NULL, NULL); + + if (idx >= media->transports->len) + return NULL; + + result = g_ptr_array_index (media->transports, idx); + if (result == NULL) { + GstRTSPStream *stream; + + stream = gst_rtsp_media_get_stream (media->media, idx); + if (stream == NULL) + goto no_media; + + result = gst_rtsp_stream_transport_new (stream); + + g_ptr_array_index (media->transports, idx) = result; + } + return result; + + /* ERRORS */ +no_media: + { + return NULL; + } +} + +/** + * gst_rtsp_session_media_alloc_channels: + * @media: a #GstRTSPSessionMedia + * @range: a #GstRTSPRange + * + * Fill @range with the next available min and max channels for + * interleaved transport. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia * media, + GstRTSPRange * range) +{ + g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE); + + range->min = media->counter++; + range->max = media->counter++; + + return TRUE; +} + +/** + * gst_rtsp_session_media_set_state: + * @media: a #GstRTSPSessionMedia + * @state: the new state + * + * Tell the media object @media to change to @state. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_session_media_set_state (GstRTSPSessionMedia * media, GstState state) +{ + gboolean ret; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE); + + ret = gst_rtsp_media_set_state (media->media, state, media->transports); + + return ret; +} diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h new file mode 100644 index 0000000000..ac9588f0b3 --- /dev/null +++ b/gst/rtsp-server/rtsp-session-media.h @@ -0,0 +1,86 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + +#ifndef __GST_RTSP_SESSION_MEDIA_H__ +#define __GST_RTSP_SESSION_MEDIA_H__ + +G_BEGIN_DECLS + +#define GST_TYPE_RTSP_SESSION_MEDIA (gst_rtsp_session_media_get_type ()) +#define GST_IS_RTSP_SESSION_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SESSION_MEDIA)) +#define GST_IS_RTSP_SESSION_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SESSION_MEDIA)) +#define GST_RTSP_SESSION_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_SESSION_MEDIA, GstRTSPSessionMediaClass)) +#define GST_RTSP_SESSION_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_SESSION_MEDIA, GstRTSPSessionMedia)) +#define GST_RTSP_SESSION_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_SESSION_MEDIA, GstRTSPSessionMediaClass)) +#define GST_RTSP_SESSION_MEDIA_CAST(obj) ((GstRTSPSessionMedia*)(obj)) +#define GST_RTSP_SESSION_MEDIA_CLASS_CAST(klass) ((GstRTSPSessionMediaClass*)(klass)) + +typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia; +typedef struct _GstRTSPSessionMediaClass GstRTSPSessionMediaClass; + +/** + * GstRTSPSessionMedia: + * @url: the url of the media + * @media: the pipeline for the media + * @state: the server state + * @counter: counter for channels + * @transports: array of #GstRTSPStreamTransport with the configuration + * for the transport for each selected stream from @media. + * + * State of a client session regarding a specific media identified by uri. + */ +struct _GstRTSPSessionMedia +{ + GObject parent; + + GstRTSPUrl *url; + GstRTSPMedia *media; + GstRTSPState state; + guint counter; + + GPtrArray *transports; +}; + +struct _GstRTSPSessionMediaClass +{ + GObjectClass parent_class; +}; + +GType gst_rtsp_session_media_get_type (void); + +GstRTSPSessionMedia * gst_rtsp_session_media_new (const GstRTSPUrl *url, + GstRTSPMedia *media); +/* control media */ +gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media, + GstState state); + +/* get stream transport config */ +GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia *media, + guint idx); + +gboolean gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia *media, + GstRTSPRange *range); + +G_END_DECLS + +#endif /* __GST_RTSP_SESSION_MEDIA_H__ */ diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 3d76670bc0..7b8cac035d 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -76,51 +76,6 @@ gst_rtsp_session_init (GstRTSPSession * session) gst_rtsp_session_touch (session); } -static void -gst_rtsp_session_free_stream (GstRTSPSessionStream * stream) -{ - GST_INFO ("free session stream %p", stream); - - /* remove callbacks now */ - gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); - gst_rtsp_session_stream_set_keepalive (stream, NULL, NULL, NULL); - - gst_rtsp_media_trans_cleanup (&stream->trans); - - g_free (stream); -} - -static void -gst_rtsp_session_free_media (GstRTSPSessionMedia * media, - GstRTSPSession * session) -{ - guint size, i; - - size = media->streams->len; - - GST_INFO ("free session media %p", media); - - gst_rtsp_session_media_set_state (media, GST_STATE_NULL); - - for (i = 0; i < size; i++) { - GstRTSPSessionStream *stream; - - stream = g_array_index (media->streams, GstRTSPSessionStream *, i); - - if (stream) - gst_rtsp_session_free_stream (stream); - } - g_array_free (media->streams, TRUE); - - if (media->url) - gst_rtsp_url_free (media->url); - - if (media->media) - g_object_unref (media->media); - - g_free (media); -} - static void gst_rtsp_session_finalize (GObject * obj) { @@ -131,9 +86,7 @@ gst_rtsp_session_finalize (GObject * obj) GST_INFO ("finalize session %p", session); /* free all media */ - g_list_foreach (session->medias, (GFunc) gst_rtsp_session_free_media, - session); - g_list_free (session->medias); + g_list_free_full (session->medias, g_object_unref); /* free session id */ g_free (session->sessionid); @@ -196,24 +149,13 @@ gst_rtsp_session_manage_media (GstRTSPSession * sess, const GstRTSPUrl * uri, GstRTSPMedia * media) { GstRTSPSessionMedia *result; - guint n_streams; g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); g_return_val_if_fail (uri != NULL, NULL); g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); g_return_val_if_fail (media->status == GST_RTSP_MEDIA_STATUS_PREPARED, NULL); - result = g_new0 (GstRTSPSessionMedia, 1); - result->media = media; - result->url = gst_rtsp_url_copy ((GstRTSPUrl *) uri); - result->state = GST_RTSP_STATE_INIT; - - /* prealloc the streams now, filled with NULL */ - n_streams = gst_rtsp_media_n_streams (media); - result->streams = - g_array_sized_new (FALSE, TRUE, sizeof (GstRTSPSessionStream *), - n_streams); - g_array_set_size (result->streams, n_streams); + result = gst_rtsp_session_media_new (uri, media); sess->medias = g_list_prepend (sess->medias, result); @@ -235,24 +177,15 @@ gboolean gst_rtsp_session_release_media (GstRTSPSession * sess, GstRTSPSessionMedia * media) { - GList *walk, *next; + GList *find; g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), FALSE); g_return_val_if_fail (media != NULL, FALSE); - for (walk = sess->medias; walk;) { - GstRTSPSessionMedia *find; - - find = (GstRTSPSessionMedia *) walk->data; - next = g_list_next (walk); - - if (find == media) { - sess->medias = g_list_delete_link (sess->medias, walk); - - gst_rtsp_session_free_media (find, sess); - break; - } - walk = next; + find = g_list_find (sess->medias, media); + if (find) { + g_object_unref (find->data); + sess->medias = g_list_delete_link (sess->medias, find); } return (sess->medias != NULL); } @@ -280,7 +213,7 @@ gst_rtsp_session_get_media (GstRTSPSession * sess, const GstRTSPUrl * url) for (walk = sess->medias; walk; walk = g_list_next (walk)) { result = (GstRTSPSessionMedia *) walk->data; - if (strcmp (result->url->abspath, url->abspath) == 0) + if (g_str_equal (result->url->abspath, url->abspath)) break; result = NULL; @@ -288,61 +221,6 @@ gst_rtsp_session_get_media (GstRTSPSession * sess, const GstRTSPUrl * url) return result; } -/** - * gst_rtsp_session_media_get_stream: - * @media: a #GstRTSPSessionMedia - * @idx: the stream index - * - * Get a previously created or create a new #GstRTSPSessionStream at @idx. - * - * Returns: a #GstRTSPSessionStream that is valid until the session of @media - * is unreffed. - */ -GstRTSPSessionStream * -gst_rtsp_session_media_get_stream (GstRTSPSessionMedia * media, guint idx) -{ - GstRTSPSessionStream *result; - - g_return_val_if_fail (media != NULL, NULL); - g_return_val_if_fail (media->media != NULL, NULL); - - if (idx >= media->streams->len) - return NULL; - - result = g_array_index (media->streams, GstRTSPSessionStream *, idx); - if (result == NULL) { - GstRTSPMediaStream *media_stream; - - media_stream = gst_rtsp_media_get_stream (media->media, idx); - if (media_stream == NULL) - goto no_media; - - result = g_new0 (GstRTSPSessionStream, 1); - result->trans.idx = idx; - result->trans.transport = NULL; - result->media_stream = media_stream; - - g_array_index (media->streams, GstRTSPSessionStream *, idx) = result; - } - return result; - - /* ERRORS */ -no_media: - { - return NULL; - } -} - -gboolean -gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia * media, - GstRTSPRange * range) -{ - range->min = media->counter++; - range->max = media->counter++; - - return TRUE; -} - /** * gst_rtsp_session_new: * @@ -492,124 +370,3 @@ gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) return res; } - -/** - * gst_rtsp_session_stream_init_udp: - * @stream: a #GstRTSPSessionStream - * @ct: a client #GstRTSPTransport - * - * Set @ct as the client transport and create and return a matching server - * transport. This function takes ownership of the passed @ct. - * - * Returns: a server transport or NULL if something went wrong. Use - * gst_rtsp_transport_free () after usage. - */ -GstRTSPTransport * -gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream, - GstRTSPTransport * ct) -{ - GstRTSPTransport *st; - - g_return_val_if_fail (stream != NULL, NULL); - g_return_val_if_fail (ct != NULL, NULL); - - /* prepare the server transport */ - gst_rtsp_transport_new (&st); - - st->trans = ct->trans; - st->profile = ct->profile; - st->lower_transport = ct->lower_transport; - - switch (st->lower_transport) { - case GST_RTSP_LOWER_TRANS_UDP: - st->client_port = ct->client_port; - st->server_port = stream->media_stream->server_port; - break; - case GST_RTSP_LOWER_TRANS_UDP_MCAST: - ct->port = st->port = stream->media_stream->server_port; - st->destination = g_strdup (ct->destination); - st->ttl = ct->ttl; - break; - case GST_RTSP_LOWER_TRANS_TCP: - st->interleaved = ct->interleaved; - default: - break; - } - - if (stream->media_stream->session) - g_object_get (stream->media_stream->session, "internal-ssrc", &st->ssrc, - NULL); - - /* keep track of the transports in the stream. */ - if (stream->trans.transport) - gst_rtsp_transport_free (stream->trans.transport); - stream->trans.transport = ct; - - return st; -} - -/** - * gst_rtsp_session_stream_set_callbacks: - * @stream: a #GstRTSPSessionStream - * @send_rtp: (scope notified): a callback called when RTP should be sent - * @send_rtcp: (scope notified): a callback called when RTCP should be sent - * @user_data: user data passed to callbacks - * @notify: called with the user_data when no longer needed. - * - * Install callbacks that will be called when data for a stream should be sent - * to a client. This is usually used when sending RTP/RTCP over TCP. - */ -void -gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream * stream, - GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, - gpointer user_data, GDestroyNotify notify) -{ - stream->trans.send_rtp = send_rtp; - stream->trans.send_rtcp = send_rtcp; - if (stream->trans.notify) - stream->trans.notify (stream->trans.user_data); - stream->trans.user_data = user_data; - stream->trans.notify = notify; -} - -/** - * gst_rtsp_session_stream_set_keepalive: - * @stream: a #GstRTSPSessionStream - * @keep_alive: a callback called when the receiver is active - * @user_data: user data passed to callback - * @notify: called with the user_data when no longer needed. - * - * Install callbacks that will be called when RTCP packets are received from the - * receiver of @stream. - */ -void -gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream * stream, - GstRTSPKeepAliveFunc keep_alive, gpointer user_data, GDestroyNotify notify) -{ - stream->trans.keep_alive = keep_alive; - if (stream->trans.ka_notify) - stream->trans.ka_notify (stream->trans.ka_user_data); - stream->trans.ka_user_data = user_data; - stream->trans.ka_notify = notify; -} - -/** - * gst_rtsp_session_media_set_state: - * @media: a #GstRTSPSessionMedia - * @state: the new state - * - * Tell the media object @media to change to @state. - * - * Returns: %TRUE on success. - */ -gboolean -gst_rtsp_session_media_set_state (GstRTSPSessionMedia * media, GstState state) -{ - gboolean ret; - - g_return_val_if_fail (media != NULL, FALSE); - - ret = gst_rtsp_media_set_state (media->media, state, media->streams); - - return ret; -} diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 973f196cf4..f7815c9185 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -38,49 +38,8 @@ G_BEGIN_DECLS typedef struct _GstRTSPSession GstRTSPSession; typedef struct _GstRTSPSessionClass GstRTSPSessionClass; -typedef struct _GstRTSPSessionStream GstRTSPSessionStream; -typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia; - #include "rtsp-media.h" - -/** - * GstRTSPSessionStream: - * @trans: the media transport - * @media_stream: the controlled media stream - * - * Configuration of a stream. A stream is an audio or video stream related to a - * media. - */ -struct _GstRTSPSessionStream -{ - GstRTSPMediaTrans trans; - - /* the stream of the media */ - GstRTSPMediaStream *media_stream; -}; - -/** - * GstRTSPSessionMedia: - * - * State of a client session regarding a specific media identified by uri. - */ -struct _GstRTSPSessionMedia -{ - /* the url of the media */ - GstRTSPUrl *url; - - /* the pipeline for the media */ - GstRTSPMedia *media; - - /* the server state */ - GstRTSPState state; - - /* counter for channels */ - guint counter; - - /* configuration for the different streams */ - GArray *streams; -}; +#include "rtsp-session-media.h" /** * GstRTSPSession: @@ -138,28 +97,6 @@ gboolean gst_rtsp_session_release_media (GstRTSPSession *se /* get media in a session */ GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *url); -/* control media */ -gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media, GstState state); - -/* get stream config */ -GstRTSPSessionStream * gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, - guint idx); - -gboolean gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia *media, - GstRTSPRange *range); - -/* configure transport */ -GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream, - GstRTSPTransport *ct); -void gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream *stream, - GstRTSPSendFunc send_rtp, - GstRTSPSendFunc send_rtcp, - gpointer user_data, - GDestroyNotify notify); -void gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream *stream, - GstRTSPKeepAliveFunc keep_alive, - gpointer user_data, - GDestroyNotify notify); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c new file mode 100644 index 0000000000..7b5609a131 --- /dev/null +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -0,0 +1,202 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include +#include + +#include "rtsp-stream-transport.h" + +enum +{ + PROP_0, + PROP_LAST +}; + +GST_DEBUG_CATEGORY_STATIC (rtsp_stream_transport_debug); +#define GST_CAT_DEFAULT rtsp_stream_transport_debug + +static void gst_rtsp_stream_transport_finalize (GObject * obj); + +G_DEFINE_TYPE (GstRTSPStreamTransport, gst_rtsp_stream_transport, + G_TYPE_OBJECT); + +static void +gst_rtsp_stream_transport_class_init (GstRTSPStreamTransportClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gst_rtsp_stream_transport_finalize; + + GST_DEBUG_CATEGORY_INIT (rtsp_stream_transport_debug, "rtspmediatransport", + 0, "GstRTSPStreamTransport"); +} + +static void +gst_rtsp_stream_transport_init (GstRTSPStreamTransport * trans) +{ +} + +static void +gst_rtsp_stream_transport_finalize (GObject * obj) +{ + GstRTSPStreamTransport *trans; + + trans = GST_RTSP_STREAM_TRANSPORT (obj); + + /* remove callbacks now */ + gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL); + gst_rtsp_stream_transport_set_keepalive (trans, NULL, NULL, NULL); + + if (trans->transport) + gst_rtsp_transport_free (trans->transport); + +#if 0 + if (trans->rtpsource) + g_object_set_qdata (trans->rtpsource, ssrc_stream_map_key, NULL); +#endif + + G_OBJECT_CLASS (gst_rtsp_stream_transport_parent_class)->finalize (obj); +} + +/** + * gst_rtsp_stream_transport_new: + * @stream: a #GstRTSPStream + * + * Create a new #GstRTSPStreamTransport that can be used for + * @stream. + * + * Returns: a new #GstRTSPStreamTransport + */ +GstRTSPStreamTransport * +gst_rtsp_stream_transport_new (GstRTSPStream * stream) +{ + GstRTSPStreamTransport *trans; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + trans = g_object_new (GST_TYPE_RTSP_STREAM_TRANSPORT, NULL); + trans->stream = stream; + + return trans; +} + +/** + * gst_rtsp_stream_transport_set_callbacks: + * @trans: a #GstRTSPStreamTransport + * @send_rtp: (scope notified): a callback called when RTP should be sent + * @send_rtcp: (scope notified): a callback called when RTCP should be sent + * @user_data: user data passed to callbacks + * @notify: called with the user_data when no longer needed. + * + * Install callbacks that will be called when data for a stream should be sent + * to a client. This is usually used when sending RTP/RTCP over TCP. + */ +void +gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport * trans, + GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, + gpointer user_data, GDestroyNotify notify) +{ + trans->send_rtp = send_rtp; + trans->send_rtcp = send_rtcp; + if (trans->notify) + trans->notify (trans->user_data); + trans->user_data = user_data; + trans->notify = notify; +} + +/** + * gst_rtsp_stream_transport_set_keepalive: + * @trans: a #GstRTSPStreamTransport + * @keep_alive: a callback called when the receiver is active + * @user_data: user data passed to callback + * @notify: called with the user_data when no longer needed. + * + * Install callbacks that will be called when RTCP packets are received from the + * receiver of @trans. + */ +void +gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans, + GstRTSPKeepAliveFunc keep_alive, gpointer user_data, GDestroyNotify notify) +{ + trans->keep_alive = keep_alive; + if (trans->ka_notify) + trans->ka_notify (trans->ka_user_data); + trans->ka_user_data = user_data; + trans->ka_notify = notify; +} + + +/** + * gst_rtsp_stream_transport_set_transport: + * @trans: a #GstRTSPStreamTransport + * @ct: a client #GstRTSPTransport + * + * Set @ct as the client transport and create and return a matching server + * transport. This function takes ownership of the passed @ct. + * + * Returns: a server transport or NULL if something went wrong. Use + * gst_rtsp_transport_free () after usage. + */ +GstRTSPTransport * +gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans, + GstRTSPTransport * ct) +{ + GstRTSPTransport *st; + + g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL); + g_return_val_if_fail (ct != NULL, NULL); + + /* prepare the server transport */ + gst_rtsp_transport_new (&st); + + st->trans = ct->trans; + st->profile = ct->profile; + st->lower_transport = ct->lower_transport; + + switch (st->lower_transport) { + case GST_RTSP_LOWER_TRANS_UDP: + st->client_port = ct->client_port; + st->server_port = trans->stream->server_port; + break; + case GST_RTSP_LOWER_TRANS_UDP_MCAST: + ct->port = st->port = trans->stream->server_port; + st->destination = g_strdup (ct->destination); + st->ttl = ct->ttl; + break; + case GST_RTSP_LOWER_TRANS_TCP: + st->interleaved = ct->interleaved; + default: + break; + } + + if (trans->stream->session) + g_object_get (trans->stream->session, "internal-ssrc", &st->ssrc, NULL); + + /* keep track of the transports in the stream. */ + if (trans->transport) + gst_rtsp_transport_free (trans->transport); + trans->transport = ct; + + return st; +} diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h new file mode 100644 index 0000000000..cd1733293d --- /dev/null +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -0,0 +1,111 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#ifndef __GST_RTSP_STREAM_TRANSPORT_H__ +#define __GST_RTSP_STREAM_TRANSPORT_H__ + +G_BEGIN_DECLS + +/* types for the media */ +#define GST_TYPE_RTSP_STREAM_TRANSPORT (gst_rtsp_stream_transport_get_type ()) +#define GST_IS_RTSP_STREAM_TRANSPORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_STREAM_TRANSPORT)) +#define GST_IS_RTSP_STREAM_TRANSPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_STREAM_TRANSPORT)) +#define GST_RTSP_STREAM_TRANSPORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_STREAM_TRANSPORT, GstRTSPStreamTransportClass)) +#define GST_RTSP_STREAM_TRANSPORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_STREAM_TRANSPORT, GstRTSPStreamTransport)) +#define GST_RTSP_STREAM_TRANSPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_STREAM_TRANSPORT, GstRTSPStreamTransportClass)) +#define GST_RTSP_STREAM_TRANSPORT_CAST(obj) ((GstRTSPStreamTransport*)(obj)) +#define GST_RTSP_STREAM_TRANSPORT_CLASS_CAST(klass) ((GstRTSPStreamTransportClass*)(klass)) + +typedef struct _GstRTSPStreamTransport GstRTSPStreamTransport; +typedef struct _GstRTSPStreamTransportClass GstRTSPStreamTransportClass; + +#include "rtsp-stream.h" + +typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); +typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); + +/** + * GstRTSPStreamTransport: + * @parent: parent instance + * @idx: the stream index + * @send_rtp: callback for sending RTP messages + * @send_rtcp: callback for sending RTCP messages + * @send_rtp_list: callback for sending RTP messages + * @send_rtcp_list: callback for sending RTCP messages + * @user_data: user data passed in the callbacks + * @notify: free function for the user_data. + * @keep_alive: keep alive callback + * @ka_user_data: data passed to @keep_alive + * @ka_notify: called when @ka_user_data is freed + * @active: if we are actively sending + * @timeout: if we timed out + * @transport: a transport description + * @rtpsource: the receiver rtp source object + * + * A Transport description for stream @idx + */ +struct _GstRTSPStreamTransport { + GObject parent; + + GstRTSPStream *stream; + + GstRTSPSendFunc send_rtp; + GstRTSPSendFunc send_rtcp; + gpointer user_data; + GDestroyNotify notify; + + GstRTSPKeepAliveFunc keep_alive; + gpointer ka_user_data; + GDestroyNotify ka_notify; + gboolean active; + gboolean timeout; + + GstRTSPTransport *transport; + + GObject *rtpsource; +}; + +struct _GstRTSPStreamTransportClass { + GObjectClass parent_class; +}; + +GType gst_rtsp_stream_transport_get_type (void); + +GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream); + +GstRTSPTransport * gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans, + GstRTSPTransport * ct); + +void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans, + GstRTSPSendFunc send_rtp, + GstRTSPSendFunc send_rtcp, + gpointer user_data, + GDestroyNotify notify); +void gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport *trans, + GstRTSPKeepAliveFunc keep_alive, + gpointer user_data, + GDestroyNotify notify); + +G_END_DECLS + +#endif /* __GST_RTSP_STREAM_TRANSPORT_H__ */ diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c new file mode 100644 index 0000000000..9f5bd1e77a --- /dev/null +++ b/gst/rtsp-server/rtsp-stream.c @@ -0,0 +1,971 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include + +#include +#include + +#include "rtsp-stream.h" + +enum +{ + PROP_0, + PROP_LAST +}; + +GST_DEBUG_CATEGORY_STATIC (rtsp_stream_debug); +#define GST_CAT_DEFAULT rtsp_stream_debug + +static GQuark ssrc_stream_map_key; + +static void gst_rtsp_stream_finalize (GObject * obj); + +G_DEFINE_TYPE (GstRTSPStream, gst_rtsp_stream, G_TYPE_OBJECT); + +static void +gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gst_rtsp_stream_finalize; + + GST_DEBUG_CATEGORY_INIT (rtsp_stream_debug, "rtspstream", 0, "GstRTSPStream"); + + ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); +} + +static void +gst_rtsp_stream_init (GstRTSPStream * media) +{ +} + +static void +gst_rtsp_stream_finalize (GObject * obj) +{ + GstRTSPStream *stream; + + stream = GST_RTSP_STREAM (obj); + + g_assert (!stream->is_joined); + + gst_object_unref (stream->payloader); + gst_object_unref (stream->srcpad); + + if (stream->session) + g_object_unref (stream->session); + + if (stream->caps) + gst_caps_unref (stream->caps); + + if (stream->send_rtp_sink) + gst_object_unref (stream->send_rtp_sink); + if (stream->send_rtp_src) + gst_object_unref (stream->send_rtp_src); + if (stream->send_rtcp_src) + gst_object_unref (stream->send_rtcp_src); + if (stream->recv_rtcp_sink) + gst_object_unref (stream->recv_rtcp_sink); + if (stream->recv_rtp_sink) + gst_object_unref (stream->recv_rtp_sink); + + g_list_free (stream->transports); + + G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); +} + +/** + * gst_rtsp_stream_new: + * @idx: an index + * @srcpad: a #GstPad + * @payloader: a #GstElement + * + * Create a new media stream with index @idx that handles RTP data on + * @srcpad and has a payloader element @payloader. + * + * Returns: a new #GstRTSPStream + */ +GstRTSPStream * +gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad) +{ + GstRTSPStream *stream; + + g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL); + g_return_val_if_fail (GST_IS_PAD (srcpad), NULL); + g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), NULL); + + stream = g_object_new (GST_TYPE_RTSP_STREAM, NULL); + stream->idx = idx; + stream->payloader = gst_object_ref (payloader); + stream->srcpad = gst_object_ref (srcpad); + + return stream; +} + +static gboolean +alloc_ports (GstRTSPStream * stream) +{ + GstStateChangeReturn ret; + GstElement *udpsrc0, *udpsrc1; + GstElement *udpsink0, *udpsink1; + gint tmp_rtp, tmp_rtcp; + guint count; + gint rtpport, rtcpport; + GSocket *socket; + const gchar *host; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + udpsrc0 = NULL; + udpsrc1 = NULL; + udpsink0 = NULL; + udpsink1 = NULL; + count = 0; + + /* Start with random port */ + tmp_rtp = 0; + + if (stream->is_ipv6) + host = "udp://[::0]"; + else + host = "udp://0.0.0.0"; + + /* try to allocate 2 UDP ports, the RTP port should be an even + * number and the RTCP port should be the next (uneven) port */ +again: + udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); + if (udpsrc0 == NULL) + goto no_udp_protocol; + g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL); + + ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED); + if (ret == GST_STATE_CHANGE_FAILURE) { + if (tmp_rtp != 0) { + tmp_rtp += 2; + if (++count > 20) + goto no_ports; + + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + + goto again; + } + goto no_udp_protocol; + } + + g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); + + /* check if port is even */ + if ((tmp_rtp & 1) != 0) { + /* port not even, close and allocate another */ + if (++count > 20) + goto no_ports; + + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + + tmp_rtp++; + goto again; + } + + /* allocate port+1 for RTCP now */ + udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); + if (udpsrc1 == NULL) + goto no_udp_rtcp_protocol; + + /* set port */ + tmp_rtcp = tmp_rtp + 1; + g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL); + + ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED); + /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */ + if (ret == GST_STATE_CHANGE_FAILURE) { + + if (++count > 20) + goto no_ports; + + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + + gst_element_set_state (udpsrc1, GST_STATE_NULL); + gst_object_unref (udpsrc1); + + tmp_rtp += 2; + goto again; + } + /* all fine, do port check */ + g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL); + g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL); + + /* this should not happen... */ + if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) + goto port_error; + + udpsink0 = gst_element_factory_make ("multiudpsink", NULL); + if (!udpsink0) + goto no_udp_protocol; + + g_object_get (G_OBJECT (udpsrc0), "socket", &socket, NULL); + g_object_set (G_OBJECT (udpsink0), "socket", socket, NULL); + g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL); + + udpsink1 = gst_element_factory_make ("multiudpsink", NULL); + if (!udpsink1) + goto no_udp_protocol; + + if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), + "send-duplicates")) { + g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); + } else { + g_warning + ("old multiudpsink version found without send-duplicates property"); + } + + if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), + "buffer-size")) { + g_object_set (G_OBJECT (udpsink0), "buffer-size", stream->buffer_size, + NULL); + } else { + GST_WARNING ("multiudpsink version found without buffer-size property"); + } + + g_object_get (G_OBJECT (udpsrc1), "socket", &socket, NULL); + g_object_set (G_OBJECT (udpsink1), "socket", socket, NULL); + g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); + g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL); + g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "auto-multicast", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL); + + /* we keep these elements, we will further configure them when the + * client told us to really use the UDP ports. */ + stream->udpsrc[0] = udpsrc0; + stream->udpsrc[1] = udpsrc1; + stream->udpsink[0] = udpsink0; + stream->udpsink[1] = udpsink1; + stream->server_port.min = rtpport; + stream->server_port.max = rtcpport; + + return TRUE; + + /* ERRORS */ +no_udp_protocol: + { + goto cleanup; + } +no_ports: + { + goto cleanup; + } +no_udp_rtcp_protocol: + { + goto cleanup; + } +port_error: + { + goto cleanup; + } +cleanup: + { + if (udpsrc0) { + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + } + if (udpsrc1) { + gst_element_set_state (udpsrc1, GST_STATE_NULL); + gst_object_unref (udpsrc1); + } + if (udpsink0) { + gst_element_set_state (udpsink0, GST_STATE_NULL); + gst_object_unref (udpsink0); + } + if (udpsink1) { + gst_element_set_state (udpsink1, GST_STATE_NULL); + gst_object_unref (udpsink1); + } + return FALSE; + } +} + +/* executed from streaming thread */ +static void +caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) +{ + GstCaps *newcaps, *oldcaps; + + newcaps = gst_pad_get_current_caps (pad); + + oldcaps = stream->caps; + stream->caps = newcaps; + + if (oldcaps) + gst_caps_unref (oldcaps); + + GST_INFO ("stream %p received caps %p, %" GST_PTR_FORMAT, stream, newcaps, + newcaps); +} + +static void +dump_structure (const GstStructure * s) +{ + gchar *sstr; + + sstr = gst_structure_to_string (s); + GST_INFO ("structure: %s", sstr); + g_free (sstr); +} + +static GstRTSPStreamTransport * +find_transport (GstRTSPStream * stream, const gchar * rtcp_from) +{ + GList *walk; + GstRTSPStreamTransport *result = NULL; + const gchar *tmp; + gchar *dest; + guint port; + + if (rtcp_from == NULL) + return NULL; + + tmp = g_strrstr (rtcp_from, ":"); + if (tmp == NULL) + return NULL; + + port = atoi (tmp + 1); + dest = g_strndup (rtcp_from, tmp - rtcp_from); + + GST_INFO ("finding %s:%d in %d transports", dest, port, + g_list_length (stream->transports)); + + for (walk = stream->transports; walk; walk = g_list_next (walk)) { + GstRTSPStreamTransport *trans = walk->data; + gint min, max; + + min = trans->transport->client_port.min; + max = trans->transport->client_port.max; + + if ((strcmp (trans->transport->destination, dest) == 0) && (min == port + || max == port)) { + result = trans; + break; + } + } + g_free (dest); + + return result; +} + +static GstRTSPStreamTransport * +check_transport (GObject * source, GstRTSPStream * stream) +{ + GstStructure *stats; + GstRTSPStreamTransport *trans; + + /* see if we have a stream to match with the origin of the RTCP packet */ + trans = g_object_get_qdata (source, ssrc_stream_map_key); + if (trans == NULL) { + g_object_get (source, "stats", &stats, NULL); + if (stats) { + const gchar *rtcp_from; + + dump_structure (stats); + + rtcp_from = gst_structure_get_string (stats, "rtcp-from"); + if ((trans = find_transport (stream, rtcp_from))) { + GST_INFO ("%p: found transport %p for source %p", stream, trans, + source); + + /* keep ref to the source */ + trans->rtpsource = source; + + g_object_set_qdata (source, ssrc_stream_map_key, trans); + } + gst_structure_free (stats); + } + } + + return trans; +} + + +static void +on_new_ssrc (GObject * session, GObject * source, GstRTSPStream * stream) +{ + GstRTSPStreamTransport *trans; + + GST_INFO ("%p: new source %p", stream, source); + + trans = check_transport (source, stream); + + if (trans) + GST_INFO ("%p: source %p for transport %p", stream, source, trans); +} + +static void +on_ssrc_sdes (GObject * session, GObject * source, GstRTSPStream * stream) +{ + GST_INFO ("%p: new SDES %p", stream, source); +} + +static void +on_ssrc_active (GObject * session, GObject * source, GstRTSPStream * stream) +{ + GstRTSPStreamTransport *trans; + + trans = check_transport (source, stream); + + if (trans) + GST_INFO ("%p: source %p in transport %p is active", stream, source, trans); + + if (trans && trans->keep_alive) + trans->keep_alive (trans->ka_user_data); + +#ifdef DUMP_STATS + { + GstStructure *stats; + g_object_get (source, "stats", &stats, NULL); + if (stats) { + dump_structure (stats); + gst_structure_free (stats); + } + } +#endif +} + +static void +on_bye_ssrc (GObject * session, GObject * source, GstRTSPStream * stream) +{ + GST_INFO ("%p: source %p bye", stream, source); +} + +static void +on_bye_timeout (GObject * session, GObject * source, GstRTSPStream * stream) +{ + GstRTSPStreamTransport *trans; + + GST_INFO ("%p: source %p bye timeout", stream, source); + + if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) { + trans->rtpsource = NULL; + trans->timeout = TRUE; + } +} + +static void +on_timeout (GObject * session, GObject * source, GstRTSPStream * stream) +{ + GstRTSPStreamTransport *trans; + + GST_INFO ("%p: source %p timeout", stream, source); + + if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) { + trans->rtpsource = NULL; + trans->timeout = TRUE; + } +} + +static GstFlowReturn +handle_new_sample (GstAppSink * sink, gpointer user_data) +{ + GList *walk; + GstSample *sample; + GstBuffer *buffer; + GstRTSPStream *stream; + + sample = gst_app_sink_pull_sample (sink); + if (!sample) + return GST_FLOW_OK; + + stream = (GstRTSPStream *) user_data; + buffer = gst_sample_get_buffer (sample); + + for (walk = stream->transports; walk; walk = g_list_next (walk)) { + GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; + + if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) { + if (tr->send_rtp) + tr->send_rtp (buffer, tr->transport->interleaved.min, tr->user_data); + } else { + if (tr->send_rtcp) + tr->send_rtcp (buffer, tr->transport->interleaved.max, tr->user_data); + } + } + gst_sample_unref (sample); + + return GST_FLOW_OK; +} + +static GstAppSinkCallbacks sink_cb = { + NULL, /* not interested in EOS */ + NULL, /* not interested in preroll samples */ + handle_new_sample, +}; + +/** + * gst_rtsp_stream_join_bin: + * @stream: a #GstRTSPStream + * @bin: a #GstBin to join + * @rtpbin: a rtpbin element in @bin + * + * Join the #Gstbin @bin that contains the element @rtpbin. + * + * @stream will link to @rtpbin, which must be inside @bin. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, + GstElement * rtpbin) +{ + gint i, idx; + gchar *name; + GstPad *pad, *teepad, *queuepad, *selpad; + GstPadLinkReturn ret; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + g_return_val_if_fail (GST_IS_BIN (bin), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE); + + idx = stream->idx; + + if (stream->is_joined) + return TRUE; + + GST_INFO ("stream %p joining bin", stream); + + if (!alloc_ports (stream)) + goto no_ports; + + /* add the ports to the pipeline */ + for (i = 0; i < 2; i++) { + gst_bin_add (bin, stream->udpsink[i]); + gst_bin_add (bin, stream->udpsrc[i]); + } + + /* create elements for the TCP transfer */ + for (i = 0; i < 2; i++) { + stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL); + stream->appqueue[i] = gst_element_factory_make ("queue", NULL); + stream->appsink[i] = gst_element_factory_make ("appsink", NULL); + g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL); + g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL); + gst_bin_add (bin, stream->appqueue[i]); + gst_bin_add (bin, stream->appsink[i]); + gst_bin_add (bin, stream->appsrc[i]); + gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]), + &sink_cb, stream, NULL); + } + + /* hook up the stream to the RTP session elements. */ + name = g_strdup_printf ("send_rtp_sink_%u", idx); + stream->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); + g_free (name); + name = g_strdup_printf ("send_rtp_src_%u", idx); + stream->send_rtp_src = gst_element_get_static_pad (rtpbin, name); + g_free (name); + name = g_strdup_printf ("send_rtcp_src_%u", idx); + stream->send_rtcp_src = gst_element_get_request_pad (rtpbin, name); + g_free (name); + name = g_strdup_printf ("recv_rtcp_sink_%u", idx); + stream->recv_rtcp_sink = gst_element_get_request_pad (rtpbin, name); + g_free (name); + name = g_strdup_printf ("recv_rtp_sink_%u", idx); + stream->recv_rtp_sink = gst_element_get_request_pad (rtpbin, name); + g_free (name); + /* get the session */ + g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &stream->session); + + g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc, + stream); + g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes, + stream); + g_signal_connect (stream->session, "on-ssrc-active", + (GCallback) on_ssrc_active, stream); + g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, + stream); + g_signal_connect (stream->session, "on-bye-timeout", + (GCallback) on_bye_timeout, stream); + g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout, + stream); + + /* link the RTP pad to the session manager */ + ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink); + if (ret != GST_PAD_LINK_OK) + goto link_failed; + + /* make tee for RTP and link to stream */ + stream->tee[0] = gst_element_factory_make ("tee", NULL); + gst_bin_add (bin, stream->tee[0]); + + pad = gst_element_get_static_pad (stream->tee[0], "sink"); + gst_pad_link (stream->send_rtp_src, pad); + gst_object_unref (pad); + + /* link RTP sink, we're pretty sure this will work. */ + teepad = gst_element_get_request_pad (stream->tee[0], "src_%u"); + pad = gst_element_get_static_pad (stream->udpsink[0], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); + + teepad = gst_element_get_request_pad (stream->tee[0], "src_%u"); + pad = gst_element_get_static_pad (stream->appqueue[0], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); + + queuepad = gst_element_get_static_pad (stream->appqueue[0], "src"); + pad = gst_element_get_static_pad (stream->appsink[0], "sink"); + gst_pad_link (queuepad, pad); + gst_object_unref (pad); + gst_object_unref (queuepad); + + /* make tee for RTCP */ + stream->tee[1] = gst_element_factory_make ("tee", NULL); + gst_bin_add (bin, stream->tee[1]); + + pad = gst_element_get_static_pad (stream->tee[1], "sink"); + gst_pad_link (stream->send_rtcp_src, pad); + gst_object_unref (pad); + + /* link RTCP elements */ + teepad = gst_element_get_request_pad (stream->tee[1], "src_%u"); + pad = gst_element_get_static_pad (stream->udpsink[1], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); + + teepad = gst_element_get_request_pad (stream->tee[1], "src_%u"); + pad = gst_element_get_static_pad (stream->appqueue[1], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); + + queuepad = gst_element_get_static_pad (stream->appqueue[1], "src"); + pad = gst_element_get_static_pad (stream->appsink[1], "sink"); + gst_pad_link (queuepad, pad); + gst_object_unref (pad); + gst_object_unref (queuepad); + + /* make selector for the RTP receivers */ + stream->selector[0] = gst_element_factory_make ("funnel", NULL); + gst_bin_add (bin, stream->selector[0]); + + pad = gst_element_get_static_pad (stream->selector[0], "src"); + gst_pad_link (pad, stream->recv_rtp_sink); + gst_object_unref (pad); + + selpad = gst_element_get_request_pad (stream->selector[0], "sink_%u"); + pad = gst_element_get_static_pad (stream->udpsrc[0], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + selpad = gst_element_get_request_pad (stream->selector[0], "sink_%u"); + pad = gst_element_get_static_pad (stream->appsrc[0], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + + /* make selector for the RTCP receivers */ + stream->selector[1] = gst_element_factory_make ("funnel", NULL); + gst_bin_add (bin, stream->selector[1]); + + pad = gst_element_get_static_pad (stream->selector[1], "src"); + gst_pad_link (pad, stream->recv_rtcp_sink); + gst_object_unref (pad); + + selpad = gst_element_get_request_pad (stream->selector[1], "sink_%u"); + pad = gst_element_get_static_pad (stream->udpsrc[1], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + + selpad = gst_element_get_request_pad (stream->selector[1], "sink_%u"); + pad = gst_element_get_static_pad (stream->appsrc[1], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values */ + gst_element_set_state (stream->udpsrc[0], GST_STATE_PLAYING); + gst_element_set_state (stream->udpsrc[1], GST_STATE_PLAYING); + gst_element_set_locked_state (stream->udpsrc[0], TRUE); + gst_element_set_locked_state (stream->udpsrc[1], TRUE); + + /* be notified of caps changes */ + stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps", + (GCallback) caps_notify, stream); + + stream->is_joined = TRUE; + + return TRUE; + + /* ERRORS */ +no_ports: + { + GST_WARNING ("failed to allocate ports %d", idx); + return FALSE; + } +link_failed: + { + GST_WARNING ("failed to link stream %d", idx); + return FALSE; + } +} + +/** + * gst_rtsp_stream_leave_bin: + * @stream: a #GstRTSPStream + * @bin: a #GstBin + * @rtpbin: a rtpbin #GstElement + * + * Remove the elements of @stream from the bin + * + * Return: %TRUE on success. + */ +gboolean +gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, + GstElement * rtpbin) +{ + gint i; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + g_return_val_if_fail (GST_IS_BIN (bin), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE); + + if (!stream->is_joined) + return TRUE; + + GST_INFO ("stream %p leaving bin", stream); + + gst_pad_unlink (stream->srcpad, stream->send_rtp_sink); + + g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig); + + /* FIXME not entirely the opposite of join_bin */ + for (i = 0; i < 2; i++) { + gst_bin_remove (bin, stream->udpsrc[i]); + gst_bin_remove (bin, stream->udpsink[i]); + gst_bin_remove (bin, stream->appsrc[i]); + gst_bin_remove (bin, stream->appsink[i]); + gst_bin_remove (bin, stream->appqueue[i]); + gst_bin_remove (bin, stream->tee[i]); + gst_bin_remove (bin, stream->selector[i]); + } + stream->is_joined = FALSE; + + return TRUE; +} + +/** + * gst_rtsp_stream_get_rtpinfo: + * @stream: a #GstRTSPStream + * @rtptime: result RTP timestamp + * @seq: result RTP seqnum + * + * Retrieve the current rtptime and seq. This is used to + * construct a RTPInfo reply header. + * + * Returns: %TRUE when rtptime and seq could be determined. + */ +gboolean +gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, + guint * rtptime, guint * seq) +{ + GObjectClass *payobjclass; + + payobjclass = G_OBJECT_GET_CLASS (stream->payloader); + + if (!g_object_class_find_property (payobjclass, "seqnum") || + !g_object_class_find_property (payobjclass, "timestamp")) + return FALSE; + + g_object_get (stream->payloader, "seqnum", seq, "timestamp", rtptime, NULL); + + return TRUE; +} + +/** + * gst_rtsp_stream_recv_rtp: + * @stream: a #GstRTSPStream + * @buffer: (transfer full): a #GstBuffer + * + * Handle an RTP buffer for the stream. This method is usually called when a + * message has been received from a client using the TCP transport. + * + * This function takes ownership of @buffer. + * + * Returns: a GstFlowReturn. + */ +GstFlowReturn +gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * buffer) +{ + GstFlowReturn ret; + + ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[0]), buffer); + + return ret; +} + +/** + * gst_rtsp_stream_recv_rtcp: + * @stream: a #GstRTSPStream + * @buffer: (transfer full): a #GstBuffer + * + * Handle an RTCP buffer for the stream. This method is usually called when a + * message has been received from a client using the TCP transport. + * + * This function takes ownership of @buffer. + * + * Returns: a GstFlowReturn. + */ +GstFlowReturn +gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer) +{ + GstFlowReturn ret; + + ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[1]), buffer); + + return ret; +} + +static gboolean +update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, + gboolean add) +{ + GstRTSPTransport *tr; + gboolean updated; + + updated = FALSE; + + tr = trans->transport; + + switch (tr->lower_transport) { + case GST_RTSP_LOWER_TRANS_UDP: + case GST_RTSP_LOWER_TRANS_UDP_MCAST: + { + gchar *dest; + gint min, max; + guint ttl = 0; + + dest = tr->destination; + if (tr->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + min = tr->port.min; + max = tr->port.max; + ttl = tr->ttl; + } else { + min = tr->client_port.min; + max = tr->client_port.max; + } + + if (add && !trans->active) { + GST_INFO ("adding %s:%d-%d", dest, min, max); + g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); + if (ttl > 0) { + GST_INFO ("setting ttl-mc %d", ttl); + g_object_set (G_OBJECT (stream->udpsink[0]), "ttl-mc", ttl, NULL); + g_object_set (G_OBJECT (stream->udpsink[1]), "ttl-mc", ttl, NULL); + } + stream->transports = g_list_prepend (stream->transports, trans); + trans->active = TRUE; + updated = TRUE; + } else if (trans->active) { + GST_INFO ("removing %s:%d-%d", dest, min, max); + g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); + g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); + stream->transports = g_list_remove (stream->transports, trans); + trans->active = FALSE; + updated = TRUE; + } + break; + } + case GST_RTSP_LOWER_TRANS_TCP: + if (add && !trans->active) { + GST_INFO ("adding TCP %s", tr->destination); + stream->transports = g_list_prepend (stream->transports, trans); + trans->active = TRUE; + updated = TRUE; + } else if (trans->active) { + GST_INFO ("removing TCP %s", tr->destination); + stream->transports = g_list_remove (stream->transports, trans); + trans->active = FALSE; + updated = TRUE; + } + break; + default: + GST_INFO ("Unknown transport %d", tr->lower_transport); + break; + } + return updated; +} + + +/** + * gst_rtsp_stream_add_transport: + * @stream: a #GstRTSPStream + * @trans: a #GstRTSPStreamTransport + * + * Add the transport in @trans to @stream. The media of @stream will + * then also be send to the values configured in @trans. + * + * @trans must contain a valid #GstRTSPTransport. + * + * Returns: %TRUE if @trans was added + */ +gboolean +gst_rtsp_stream_add_transport (GstRTSPStream * stream, + GstRTSPStreamTransport * trans) +{ + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE); + g_return_val_if_fail (trans->transport != NULL, FALSE); + + return update_transport (stream, trans, TRUE); +} + +/** + * gst_rtsp_stream_remove_transport: + * @stream: a #GstRTSPStream + * @trans: a #GstRTSPStreamTransport + * + * Remove the transport in @trans from @stream. The media of @stream will + * not be sent to the values configured in @trans. + * + * Returns: %TRUE if @trans was removed + */ +gboolean +gst_rtsp_stream_remove_transport (GstRTSPStream * stream, + GstRTSPStreamTransport * trans) +{ + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE); + g_return_val_if_fail (trans->transport != NULL, FALSE); + + return update_transport (stream, trans, FALSE); +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h new file mode 100644 index 0000000000..29a813b09d --- /dev/null +++ b/gst/rtsp-server/rtsp-stream.h @@ -0,0 +1,142 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#ifndef __GST_RTSP_STREAM_H__ +#define __GST_RTSP_STREAM_H__ + +G_BEGIN_DECLS + +/* types for the media stream */ +#define GST_TYPE_RTSP_STREAM (gst_rtsp_stream_get_type ()) +#define GST_IS_RTSP_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_STREAM)) +#define GST_IS_RTSP_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_STREAM)) +#define GST_RTSP_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_STREAM, GstRTSPStreamClass)) +#define GST_RTSP_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_STREAM, GstRTSPStream)) +#define GST_RTSP_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_STREAM, GstRTSPStreamClass)) +#define GST_RTSP_STREAM_CAST(obj) ((GstRTSPStream*)(obj)) +#define GST_RTSP_STREAM_CLASS_CAST(klass) ((GstRTSPStreamClass*)(klass)) + +typedef struct _GstRTSPStream GstRTSPStream; +typedef struct _GstRTSPStreamClass GstRTSPStreamClass; + +#include "rtsp-stream-transport.h" + +/** + * GstRTSPStream: + * @parent: the parent instance + * @idx: the stream index + * @srcpad: the srcpad of the stream + * @payloader: the payloader of the format + * @is_ipv6: should this stream be IPv6 + * @buffer_size: the UDP buffer size + * @is_joined: if the stream is joined in a bin + * @recv_rtp_sink: sinkpad for RTP buffers + * @recv_rtcp_sink: sinkpad for RTCP buffers + * @send_rtp_src: srcpad for RTP buffers + * @send_rtcp_src: srcpad for RTCP buffers + * @udpsrc: the udp source elements for RTP/RTCP + * @udpsink: the udp sink elements for RTP/RTCP + * @appsrc: the app source elements for RTP/RTCP + * @appsink: the app sink elements for RTP/RTCP + * @server_port: the server ports for this stream + * @caps_sig: the signal id for detecting caps + * @caps: the caps of the stream + * @n_active: the number of active transports in @transports + * @tranports: list of #GstStreamTransport being streamed to + * + * The definition of a media stream. The streams are identified by @id. + */ +struct _GstRTSPStream { + GObject parent; + + guint idx; + GstPad *srcpad; + GstElement *payloader; + gboolean is_ipv6; + guint buffer_size; + gboolean is_joined; + + /* pads on the rtpbin */ + GstPad *recv_rtcp_sink; + GstPad *recv_rtp_sink; + GstPad *send_rtp_sink; + GstPad *send_rtp_src; + GstPad *send_rtcp_src; + + /* the RTPSession object */ + GObject *session; + + /* sinks used for sending and receiving RTP and RTCP, they share + * sockets */ + GstElement *udpsrc[2]; + GstElement *udpsink[2]; + /* for TCP transport */ + GstElement *appsrc[2]; + GstElement *appqueue[2]; + GstElement *appsink[2]; + + GstElement *tee[2]; + GstElement *selector[2]; + + /* server ports for sending/receiving */ + GstRTSPRange server_port; + + /* the caps of the stream */ + gulong caps_sig; + GstCaps *caps; + + /* transports we stream to */ + guint n_active; + GList *transports; +}; + +struct _GstRTSPStreamClass { + GObjectClass parent_class; +}; + +GType gst_rtsp_stream_get_type (void); + +GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement *payloader, + GstPad *srcpad); + +gboolean gst_rtsp_stream_join_bin (GstRTSPStream * stream, + GstBin *bin, GstElement *rtpbin); +gboolean gst_rtsp_stream_leave_bin (GstRTSPStream * stream, + GstBin *bin, GstElement *rtpbin); + +gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, + guint *rtptime, guint * seq); + +GstFlowReturn gst_rtsp_stream_recv_rtp (GstRTSPStream *stream, + GstBuffer *buffer); +GstFlowReturn gst_rtsp_stream_recv_rtcp (GstRTSPStream *stream, + GstBuffer *buffer); + +gboolean gst_rtsp_stream_add_transport (GstRTSPStream *stream, + GstRTSPStreamTransport *trans); +gboolean gst_rtsp_stream_remove_transport (GstRTSPStream *stream, + GstRTSPStreamTransport *trans); + +G_END_DECLS + +#endif /* __GST_RTSP_STREAM_H__ */ From a8186f90e839f1e5a9c999fc8e796f9c19fbde59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 26 Oct 2012 11:24:55 +0100 Subject: [PATCH 0450/1776] configure: bump version number after refactoring --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index c61282fb00..e3f5b4b236 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.11.89.1, +AC_INIT(Gst-RTSP, 0.11.90.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-rtsp) AG_GST_INIT @@ -42,9 +42,9 @@ AC_SUBST(GST_API_VERSION) AS_LIBTOOL(GST, 0, 0, 0) dnl *** required versions of GStreamer stuff *** -GST_REQ=0.11.0 -GSTPB_REQ=0.11.0 -GSTPG_REQ=0.11.0 +GST_REQ=1.0.0 +GSTPB_REQ=1.0.0 +GSTPG_REQ=1.0.0 dnl *** autotools stuff **** From 0c8c9e328297b9a6143937dcffed1391c2cc0beb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 26 Oct 2012 11:02:43 +0200 Subject: [PATCH 0451/1776] docs: update docs --- docs/README | 131 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 101 insertions(+), 30 deletions(-) diff --git a/docs/README b/docs/README index e35fc7cd33..bbf1343052 100644 --- a/docs/README +++ b/docs/README @@ -1,7 +1,7 @@ README ------ -(Last updated on Fri 30 jan 2009, version 0.10.1.1) +(Last updated on Fri 26 oct 2012, version 0.11.89.1) This HOWTO describes the basic usage of the GStreamer RTSP libraries and how you can build simple server applications with it. @@ -10,11 +10,11 @@ can build simple server applications with it. The server relies heavily on the RTSP infrastructure of GStreamer. This includes all of the media acquisition, decoding, encoding, payloading and UDP/TCP - streaming. We use the gstrtpbin element for all the session management. Most of + streaming. We use the rtpbin element for all the session management. Most of the RTSP message parsing and construction in the server is done using the RTSP library that comes with gst-plugins-base. - The result is that the server is rather small (a few 1000 lines of code) and easy + The result is that the server is rather small (a few 6000 lines of code) and easy to understand and extend. In its current state of development, things change fast, API and ABI are unstable. We encourage people to use it for their various use cases and participate by suggesting changes/features. @@ -23,9 +23,11 @@ can build simple server applications with it. that provide reasonable default functionality but has a fair amount of hooks to override the default behaviour. - The server currently integrates with the glib mainloop nicely. It is also a - heavy user of multiple threads. It's currently not meant to be used in - high-load scenarios and you should probably not put it on a public IP address. + The server currently integrates with the glib mainloop nicely. The network part + is currently single threaded but the GStreamer bits are a heavy user of multiple + threads. It's currently not meant to be used in high-load scenarios and because + no security audit has been done, you should probably not put it on a public + IP address. * Initialisation @@ -173,7 +175,7 @@ can build simple server applications with it. A freshly created GstRTSPMedia object from the factory initially only contains a GstElement containing the elements to produce the RTP streams for the media and - a GArray of GstRTSPMediaStream objects describing the payloader and its source + a GPtrArray of GstRTSPStream objects describing the payloader and its source pad. The media is unprepared in this state. Usually the url will determine what kind of pipeline should be created. You can @@ -194,7 +196,7 @@ can build simple server applications with it. After creating the GstRTSPMedia object from the factory, it can be prepared with gst_rtsp_media_prepare(). This method will put those objects in a GstPipeline and will construct and link the streaming elements and the - gstrtpbin session manager object. + rtpbin session manager object. The _prepare() method will then preroll the pipeline in order to figure out the caps on the payloaders. After the GstRTSPMedia prerolled it will be in the @@ -205,8 +207,8 @@ can build simple server applications with it. used for sending and receiving RTP/RTCP from clients. These port numbers will have to be negotiated with the client in the SETUP requests. - When preparing a GstRTSPMedia, a multifdsink is also constructed for streaming - the stream over TCP when requested. + When preparing a GstRTSPMedia, an appsink and asppsrc is also constructed + for streaming the stream over TCP when requested. * the GstRTSPClient object @@ -226,7 +228,8 @@ can build simple server applications with it. connection open with the server. Since is possible for a client to open and close the TCP connection between requests, we cannot store the state related to the configured RTSP session in the GstRTSPClient object. This server state - is instead stored in the GstRTSPSession object. + is instead stored in the GstRTSPSession object, identified with the session + id. * GstRTSPSession @@ -242,12 +245,13 @@ can build simple server applications with it. can refer to its previously configured state by sending the session id in further requests. - A client will then use the session id to configure one or more streams, - identified by their url. This information is kept in a GstRTSPSessionMedia - structure that is refered to from the GstRTSPSession. + A client will then use the session id to configure one or more + GstRTSPSessionMedia objects, identified by their url. This SessionMedia object + contains the configuration of a GstRTSPMedia and its configured + GstRTSPStreamTransport. -* GstRTSPSessionMedia and GstRTSPSessionStream +* GstRTSPSessionMedia and GstRTSPStreamTransport A GstRTSPSessionMedia is identified by a URL and is referenced by a GstRTSPSession. It is created as soon as a client performs a SETUP operation on @@ -256,13 +260,13 @@ can build simple server applications with it. for each of the streams in the media. Each SETUP request performed by the client will configure a - GstRTSPSessionStream object linked to by the GstRTSPSessionMedia structure. + GstRTSPStreamTransport object linked to by the GstRTSPSessionMedia structure. It will contain the transport information needed to send this stream to the - client. The GstRTSPSessionStream also contains a link to the GstRTSPMediaStream + client. The GstRTSPStreamTransport also contains a link to the GstRTSPStream object that generates the actual data to be streamed to the client. - Note how GstRTSPMedia and GstRTSPMediaStream (the providers of the data to - stream) are decoupled from GstRTSPSessionMedia and GstRTSPSessionStream (the + Note how GstRTSPMedia and GstRTSPStream (the providers of the data to + stream) are decoupled from GstRTSPSessionMedia and GstRTSPStreamTransport (the configuration of how to send this stream to a client) in order to be able to send the data of one GstRTSPMedia to multiple clients. @@ -270,15 +274,15 @@ can build simple server applications with it. * media control After a client has configured the transports for a GstRTSPMedia and its - GstRTSPMediaStreams, the client can play/pause/stop the stream. + GstRTSPStreams, the client can play/pause/stop the stream. The GstRTSPMedia object was prepared in the DESCRIBE call (or during SETUP when the client skipped the DESCRIBE request). As seen earlier, this configures a - couple of multiudpsink and udpsrc elements to respectively send and receive the + couple of udpsink and udpsrc elements to respectively send and receive the media to clients. When a client performs a PLAY request, its configured destination UDP ports are - added to the GstRTSPMediaStream target destinations, at which point data will + added to the GstRTSPStream target destinations, at which point data will be sent to the client. The corresponding GstRTSPMedia object will be set to the PLAYING state if it was not allready in order to send the data to the destination. @@ -289,7 +293,7 @@ can build simple server applications with it. information when it prerolled the pipeline. When a client performs a PAUSE request, the destination UDP ports are removed - from the GstRTSPMediaStream object and the GstRTSPMedia object is set to PAUSED + from the GstRTSPStream object and the GstRTSPMedia object is set to PAUSED if no other destinations are configured anymore. @@ -317,7 +321,7 @@ can build simple server applications with it. Various ways exist to detect activity from a client: - RTSP keepalive requests. When a client is receiving RTP data, the RTSP TCP - connection is largely unused. It is the client responsability to + connection is largely unused. It is the client's responsability to periodically send keep-alive requests over the TCP channel. Whenever a keep-alive request is received by the server (any request that @@ -340,19 +344,86 @@ can build simple server applications with it. receiving RTCP exactly for this reason. If there was no activity in a particular session for a long time (by default 60 - seconds), the sessionpool will destroy the session along with all related - objects and media as if a TEARDOWN happened from the client. + seconds), the application should remove the session from the pool. For this, + the application should periodically (say every 2 seconds) check if no sessions + expired and call gst_rtsp_session_pool_cleanup() to remove them. + + When a session is removed from the sessionpool and its last reference is + unreffef, all related objects and media are destroyed as if a TEARDOWN happened + from the client. * TEARDOWN - A TEARDOWN request will first location the GstRTSPSessionMedia of the URL. It + A TEARDOWN request will first locate the GstRTSPSessionMedia of the URL. It will then remove all transports from the streams, making sure that streaming - stops to the client. It will then remove the GstRTSPSessionMedia and - GstRTSPSessionStream structures. Finally the GstRTSPSession is released back + stops to the clients. It will then remove the GstRTSPSessionMedia and + GstRTSPStreamTransport objects. Finally the GstRTSPSession is released back into the pool. When there are no more references to the GstRTSPMedia, the media pipeline is - shut down and destroyed. + shut down (with _unprepare) and destroyed. This will then also destroy the + GstRTSPStream objects. + + +Objects +------- + +GstRTSPServer + - Toplevel object listening for connections and creating new + GstRTSPClient objects + +GstRTSPClient + - Handle RTSP Requests from connected clients. All other objects + are called by this object. + +GstRTSPClientState + - Helper structure contaning the current state of the request + handled by the client. + +GstRTSPAuth + - Hooks for checking authorizations, all client activity will call this + object with the GstRTSPClientState structure. By default it supports + basic authentication. + + +GstRTSPMediaMapping + - Maps a url to a GstRTSPMediaFactory implementation. The default + implementation uses a simple hashtable to map a url to a factory. + +GstRTSPMediaFactory + - Creates and caches GstRTSPMedia objects. The default implementation + can create GstRTSPMedia objects based on gst-launch syntax. + +GstRTSPMediaFactoryURI + - Specialized GstRTSPMediaFactory that can stream the content of any + URI. + +GstRTSPMedia + - The object that contains the media pipeline and various GstRTSPStream + objects that produce RTP packets + +GstRTSPStream + - Manages the elements to stream a stream of a GstRTSPMedia to one or + more GstRTSPStreamTransports. + + +GstRTSPSessionPool + - Creates and manages GstRTSPSession objects identified by an id. + +GstRTSPSession + - An object containing the various GstRTSPSessionMedia objects managed + by this session. + +GstRTSPSessionMedia + - The state of a GstRTSPMedia and the configuration of a GstRTSPStream + objects. The configuration for the GstRTSPStream is stored in + GstRTSPStreamTransport objects. + +GstRTSPStreamTransport + - Configuration of how a GstRTSPStream is send to a particular client. It + contains the transport that was negotiated with the client in the SETUP + request. + From 6b7ff45ca6bf1922202b0b367c32c7b53e4d9d4a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 26 Oct 2012 12:04:02 +0200 Subject: [PATCH 0452/1776] rtsp: fix MTU setting Fix setting of the MTU. There is no need for a vmethod. --- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-media-mapping.h | 2 + gst/rtsp-server/rtsp-media.c | 92 +++++++++++++++++----------- gst/rtsp-server/rtsp-media.h | 7 ++- gst/rtsp-server/rtsp-server.h | 4 +- gst/rtsp-server/rtsp-stream.c | 35 +++++++++++ gst/rtsp-server/rtsp-stream.h | 3 + 7 files changed, 104 insertions(+), 41 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c78aeddc9b..c04eec56e4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -912,7 +912,7 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request) } else { if (blocksize > G_MAXUINT) blocksize = G_MAXUINT; - gst_rtsp_media_handle_mtu (media, (guint) blocksize); + gst_rtsp_media_set_mtu (media, blocksize); } } diff --git a/gst/rtsp-server/rtsp-media-mapping.h b/gst/rtsp-server/rtsp-media-mapping.h index 19f1acf67f..1f3e120245 100644 --- a/gst/rtsp-server/rtsp-media-mapping.h +++ b/gst/rtsp-server/rtsp-media-mapping.h @@ -42,6 +42,7 @@ typedef struct _GstRTSPMediaMappingClass GstRTSPMediaMappingClass; /** * GstRTSPMediaMapping: + * @parent: parent GObject * @mappings: the mountpoint to media mappings * * Creates a #GstRTSPMediaFactory object for a given url. @@ -54,6 +55,7 @@ struct _GstRTSPMediaMapping { /** * GstRTSPMediaMappingClass: + * @parent_class: parent GObject class * @find_factory: Create or return a previously cached #GstRTSPMediaFactory object * for the given url. the default implementation will use the mappings * added with gst_rtsp_media_mapping_add_factory(). diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 7987a97f3e..65c470cc31 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -32,6 +32,7 @@ #define DEFAULT_EOS_SHUTDOWN FALSE #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_MULTICAST_GROUP "224.2.0.1" +#define DEFAULT_MTU 0 /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -45,6 +46,7 @@ enum PROP_EOS_SHUTDOWN, PROP_BUFFER_SIZE, PROP_MULTICAST_GROUP, + PROP_MTU, PROP_LAST }; @@ -71,7 +73,6 @@ static gboolean default_handle_message (GstRTSPMedia * media, static void finish_unprepare (GstRTSPMedia * media); static gboolean default_unprepare (GstRTSPMedia * media); static void unlock_streams (GstRTSPMedia * media); -static void default_handle_mtu (GstRTSPMedia * media, guint mtu); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; @@ -118,6 +119,12 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "The Multicast group to send media to", DEFAULT_MULTICAST_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MTU, + g_param_spec_uint ("mtu", "MTU", + "The MTU for the payloaders (0 = default)", + 0, G_MAXUINT, DEFAULT_MTU, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_PREPARED] = g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL, @@ -142,7 +149,6 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->handle_message = default_handle_message; klass->unprepare = default_unprepare; - klass->handle_mtu = default_handle_mtu; } static void @@ -211,6 +217,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_MULTICAST_GROUP: g_value_take_string (value, gst_rtsp_media_get_multicast_group (media)); break; + case PROP_MTU: + g_value_set_uint (value, gst_rtsp_media_get_mtu (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -241,6 +250,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_MULTICAST_GROUP: gst_rtsp_media_set_multicast_group (media, g_value_get_string (value)); break; + case PROP_MTU: + gst_rtsp_media_set_mtu (media, g_value_get_uint (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -570,6 +582,46 @@ gst_rtsp_media_get_auth (GstRTSPMedia * media) return result; } +/** + * gst_rtsp_media_set_mtu: + * @media: a #GstRTSPMedia + * @mtu: a new MTU + * + * Set maximum size of one RTP packet on the payloaders. + * The @mtu will be set on all streams. + */ +void +gst_rtsp_media_set_mtu (GstRTSPMedia * media, guint mtu) +{ + gint i; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + media->mtu = mtu; + for (i = 0; i < media->streams->len; i++) { + GstRTSPStream *stream; + + GST_INFO ("Setting mtu %u for stream %d", mtu, i); + + stream = g_ptr_array_index (media->streams, i); + gst_rtsp_stream_set_mtu (stream, mtu); + } +} + +/** + * gst_rtsp_media_get_mtu: + * @media: a #GstRTSPMedia + * + * Get the configured MTU. + */ +guint +gst_rtsp_media_get_mtu (GstRTSPMedia * media) +{ + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0); + + return media->mtu; +} + /** * gst_rtsp_media_collect_streams: * @media: a #GstRTSPMedia @@ -663,6 +715,8 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, g_free (name); stream = gst_rtsp_stream_new (idx, payloader, srcpad); + if (media->mtu) + gst_rtsp_stream_set_mtu (stream, media->mtu); g_ptr_array_add (media->streams, stream); @@ -1394,37 +1448,3 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, return TRUE; } - -static void -default_handle_mtu (GstRTSPMedia * media, guint mtu) -{ - gint i; - - for (i = 0; i < media->streams->len; i++) { - GstRTSPStream *stream; - - GST_INFO ("Setting mtu %d for stream %d", mtu, i); - - stream = g_ptr_array_index (media->streams, i); - - g_object_set (G_OBJECT (stream->payloader), "mtu", mtu, NULL); - } -} - -/** - * gst_rtsp_media_handle_mtu: - * @media: a #GstRTSPMedia - * @mtu: the mtu - * - * Set maximum size of one RTP packet on the payloaders. - */ -void -gst_rtsp_media_handle_mtu (GstRTSPMedia * media, guint mtu) -{ - GstRTSPMediaClass *klass; - - klass = GST_RTSP_MEDIA_GET_CLASS (media); - - if (klass->handle_mtu) - klass->handle_mtu (media, mtu); -} diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 16b2cceab2..88c5d81f36 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -106,6 +106,7 @@ struct _GstRTSPMedia { guint buffer_size; GstRTSPAuth *auth; gchar *multicast_group; + guint mtu; GstElement *element; GPtrArray *streams; @@ -155,7 +156,6 @@ struct _GstRTSPMediaClass { /* vmethods */ gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message); gboolean (*unprepare) (GstRTSPMedia *media); - void (*handle_mtu) (GstRTSPMedia *media, guint mtu); /* signals */ gboolean (*prepared) (GstRTSPMedia *media); @@ -190,6 +190,9 @@ guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media); void gst_rtsp_media_set_multicast_group (GstRTSPMedia *media, const gchar * mc); gchar * gst_rtsp_media_get_multicast_group (GstRTSPMedia *media); +void gst_rtsp_media_set_mtu (GstRTSPMedia *media, guint mtu); +guint gst_rtsp_media_get_mtu (GstRTSPMedia *media); + /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); @@ -212,8 +215,6 @@ gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, gboo gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GPtrArray *transports); -void gst_rtsp_media_handle_mtu (GstRTSPMedia *media, guint mtu); - G_END_DECLS #endif /* __GST_RTSP_MEDIA_H__ */ diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 5220ce111b..83277e0d09 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -120,7 +120,9 @@ GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *serve void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server); -gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket *socket, const gchar * ip, gint port, const gchar *initial_buffer); +gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket *socket, + const gchar * ip, gint port, + const gchar *initial_buffer); gboolean gst_rtsp_server_io_func (GSocket *socket, GIOCondition condition, GstRTSPServer *server); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 9f5bd1e77a..13360bfe93 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -123,6 +123,41 @@ gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad) return stream; } +/** + * gst_rtsp_stream_set_mtu: + * @stream: a #GstRTSPStream + * @mtu: a new MTU + * + * Configure the mtu in the payloader of @stream to @mtu. + */ +void +gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guint mtu) +{ + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + g_object_set (G_OBJECT (stream->payloader), "mtu", mtu, NULL); +} + +/** + * gst_rtsp_stream_get_mtu: + * @stream: a #GstRTSPStream + * + * Get the configured MTU in the payloader of @stream. + * + * Returns: the MTU of the payloader. + */ +guint +gst_rtsp_stream_get_mtu (GstRTSPStream * stream) +{ + guint mtu; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), 0); + + g_object_get (G_OBJECT (stream->payloader), "mtu", &mtu, NULL); + + return mtu; +} + static gboolean alloc_ports (GstRTSPStream * stream) { diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 29a813b09d..98403139f6 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -119,6 +119,9 @@ GType gst_rtsp_stream_get_type (void); GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement *payloader, GstPad *srcpad); +void gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guint mtu); +guint gst_rtsp_stream_get_mtu (GstRTSPStream * stream); + gboolean gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin *bin, GstElement *rtpbin); gboolean gst_rtsp_stream_leave_bin (GstRTSPStream * stream, From 348b7f9c21f63cb9f4d895f62034884ba33bd648 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 26 Oct 2012 12:33:21 +0200 Subject: [PATCH 0453/1776] docs: update docs --- docs/libs/gst-rtsp-server-sections.txt | 137 +++++++++++++++++++----- gst/rtsp-server/rtsp-media-factory.h | 1 + gst/rtsp-server/rtsp-media-mapping.c | 7 ++ gst/rtsp-server/rtsp-media.h | 11 +- gst/rtsp-server/rtsp-params.c | 18 ++++ gst/rtsp-server/rtsp-server.c | 9 ++ gst/rtsp-server/rtsp-session-pool.h | 2 +- gst/rtsp-server/rtsp-session.c | 16 ++- gst/rtsp-server/rtsp-session.h | 3 +- gst/rtsp-server/rtsp-stream-transport.h | 4 +- gst/rtsp-server/rtsp-stream.h | 2 +- 11 files changed, 174 insertions(+), 36 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 9ac66c1c30..561f664ed6 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -31,9 +31,20 @@ gst_rtsp_media_factory_set_shared gst_rtsp_media_factory_is_shared gst_rtsp_media_factory_set_eos_shutdown gst_rtsp_media_factory_is_eos_shutdown +gst_rtsp_media_factory_set_protocols +gst_rtsp_media_factory_get_protocols +gst_rtsp_media_factory_set_auth +gst_rtsp_media_factory_get_auth +gst_rtsp_media_factory_set_buffer_size +gst_rtsp_media_factory_get_buffer_size +gst_rtsp_media_factory_set_multicast_group +gst_rtsp_media_factory_get_multicast_group gst_rtsp_media_factory_construct -gst_rtsp_media_factory_collect_streams +gst_rtsp_media_factory_create_element +GST_RTSP_MEDIA_FACTORY_GET_LOCK +GST_RTSP_MEDIA_FACTORY_LOCK +GST_RTSP_MEDIA_FACTORY_UNLOCK GST_RTSP_MEDIA_FACTORY_CLASS GST_RTSP_MEDIA_FACTORY_CAST GST_RTSP_MEDIA_FACTORY_CLASS_CAST @@ -48,9 +59,6 @@ GST_RTSP_MEDIA_FACTORY_GET_CLASS
rtsp-media-factory-uri GstRTSPMediaFactoryURI -GST_RTSP_MEDIA_FACTORY_GET_LOCK -GST_RTSP_MEDIA_FACTORY_LOCK -GST_RTSP_MEDIA_FACTORY_UNLOCK GstRTSPMediaFactoryURI GstRTSPMediaFactoryURIClass gst_rtsp_media_factory_uri_new @@ -72,15 +80,11 @@ gst_rtsp_media_factory_uri_get_type
rtsp-media GstRTSPMedia -GstRTSPMediaStream +GstRTSPMediaStatus GstRTSPMedia GstRTSPMediaClass -GstRTSPMediaTrans -GstRTSPSendFunc -GstRTSPSendListFunc -GstRTSPKeepAliveFunc -GstRTSPMediaStatus gst_rtsp_media_new + gst_rtsp_media_set_shared gst_rtsp_media_is_shared gst_rtsp_media_set_reusable @@ -89,18 +93,27 @@ gst_rtsp_media_set_protocols gst_rtsp_media_get_protocols gst_rtsp_media_set_eos_shutdown gst_rtsp_media_is_eos_shutdown +gst_rtsp_media_set_auth +gst_rtsp_media_get_auth +gst_rtsp_media_set_buffer_size +gst_rtsp_media_get_buffer_size +gst_rtsp_media_set_multicast_group +gst_rtsp_media_get_multicast_group +gst_rtsp_media_get_mtu +gst_rtsp_media_set_mtu + gst_rtsp_media_prepare -gst_rtsp_media_is_prepared gst_rtsp_media_unprepare + +gst_rtsp_media_collect_streams +gst_rtsp_media_create_stream + gst_rtsp_media_n_streams gst_rtsp_media_get_stream + gst_rtsp_media_seek gst_rtsp_media_get_range_string -gst_rtsp_media_stream_rtp -gst_rtsp_media_stream_rtcp gst_rtsp_media_set_state -gst_rtsp_media_remove_elements -gst_rtsp_media_trans_cleanup GST_RTSP_MEDIA_CLASS GST_RTSP_MEDIA_CAST @@ -123,6 +136,7 @@ gst_rtsp_server_set_address gst_rtsp_server_get_address gst_rtsp_server_set_service gst_rtsp_server_get_service +gst_rtsp_server_get_bound_port gst_rtsp_server_set_backlog gst_rtsp_server_get_backlog gst_rtsp_server_set_session_pool @@ -131,11 +145,15 @@ gst_rtsp_server_set_media_mapping gst_rtsp_server_get_media_mapping gst_rtsp_server_get_auth gst_rtsp_server_set_auth +gst_rtsp_server_transfer_connection gst_rtsp_server_io_func -gst_rtsp_server_get_io_channel -gst_rtsp_server_create_watch +gst_rtsp_server_create_socket +gst_rtsp_server_create_source gst_rtsp_server_attach +GST_RTSP_SERVER_GET_LOCK +GST_RTSP_SERVER_LOCK +GST_RTSP_SERVER_UNLOCK GST_RTSP_SERVER_CLASS GST_RTSP_SERVER_CAST GST_RTSP_SERVER_CLASS_CAST @@ -182,8 +200,6 @@ GST_RTSP_SESSION_POOL_GET_CLASS GstRTSPSession GstRTSPSession GstRTSPSessionClass -GstRTSPSessionStream -GstRTSPSessionMedia gst_rtsp_session_new gst_rtsp_session_get_sessionid gst_rtsp_session_set_timeout @@ -196,12 +212,6 @@ gst_rtsp_session_is_expired gst_rtsp_session_manage_media gst_rtsp_session_release_media gst_rtsp_session_get_media -gst_rtsp_session_media_set_state -gst_rtsp_session_media_get_stream -gst_rtsp_session_media_alloc_channels -gst_rtsp_session_stream_set_transport -gst_rtsp_session_stream_set_callbacks -gst_rtsp_session_stream_set_keepalive GST_RTSP_SESSION_CLASS GST_RTSP_SESSION_CAST @@ -214,6 +224,27 @@ GST_IS_RTSP_SESSION_CLASS GST_RTSP_SESSION_GET_CLASS
+
+rtsp-session-media +GstRTSPSessionMedia +GstRTSPSessionMedia +GstRTSPSessionMediaClass +gst_rtsp_session_media_new +gst_rtsp_session_media_set_state +gst_rtsp_session_media_get_transport +gst_rtsp_session_media_alloc_channels + +GST_RTSP_SESSION_MEDIA_CAST +GST_RTSP_SESSION_MEDIA_CLASS_CAST +GST_IS_RTSP_SESSION_MEDIA +GST_IS_RTSP_SESSION_MEDIA_CLASS +GST_RTSP_SESSION_MEDIA +GST_RTSP_SESSION_MEDIA_CLASS +GST_RTSP_SESSION_MEDIA_GET_CLASS +GST_TYPE_RTSP_SESSION_MEDIA +gst_rtsp_session_media_get_type +
+
rtsp-auth GstRTSPAuth @@ -222,7 +253,7 @@ GstRTSPAuthClass gst_rtsp_auth_new gst_rtsp_auth_set_basic gst_rtsp_auth_setup_auth -gst_rtsp_auth_check_method +gst_rtsp_auth_check gst_rtsp_auth_make_basic GST_IS_RTSP_AUTH @@ -239,6 +270,7 @@ gst_rtsp_auth_get_type
rtsp-client GstRTSPClient +GstRTSPClientState GstRTSPClient GstRTSPClientClass gst_rtsp_client_new @@ -248,9 +280,12 @@ gst_rtsp_client_set_session_pool gst_rtsp_client_get_session_pool gst_rtsp_client_set_media_mapping gst_rtsp_client_get_media_mapping +gst_rtsp_client_set_use_client_settings +gst_rtsp_client_get_use_client_settings gst_rtsp_client_set_auth gst_rtsp_client_get_auth gst_rtsp_client_accept +gst_rtsp_client_create_from_socket GST_RTSP_CLIENT_CLASS GST_RTSP_CLIENT_CAST @@ -275,3 +310,53 @@ GstSDPInfo gst_rtsp_sdp_from_media
+
+rtsp-stream +GstRTSPStream +GstRTSPStream +GstRTSPStreamClass +gst_rtsp_stream_new +gst_rtsp_stream_get_mtu +gst_rtsp_stream_set_mtu +gst_rtsp_stream_join_bin +gst_rtsp_stream_leave_bin +gst_rtsp_stream_get_rtpinfo +gst_rtsp_stream_recv_rtcp +gst_rtsp_stream_recv_rtp +gst_rtsp_stream_add_transport +gst_rtsp_stream_remove_transport + +GST_RTSP_STREAM_CAST +GST_RTSP_STREAM_CLASS_CAST +GST_IS_RTSP_STREAM +GST_IS_RTSP_STREAM_CLASS +GST_RTSP_STREAM +GST_RTSP_STREAM_CLASS +GST_RTSP_STREAM_GET_CLASS +GST_TYPE_RTSP_STREAM +gst_rtsp_stream_get_type +
+ +
+rtsp-stream-transport +GstRTSPStreamTransport +GstRTSPKeepAliveFunc +GstRTSPSendFunc +GstRTSPStreamTransport +GstRTSPStreamTransportClass +gst_rtsp_stream_transport_new +gst_rtsp_stream_transport_set_callbacks +gst_rtsp_stream_transport_set_keepalive +gst_rtsp_stream_transport_set_transport + +GST_RTSP_STREAM_TRANSPORT_CAST +GST_RTSP_STREAM_TRANSPORT_CLASS_CAST +GST_IS_RTSP_STREAM_TRANSPORT +GST_IS_RTSP_STREAM_TRANSPORT_CLASS +GST_RTSP_STREAM_TRANSPORT +GST_RTSP_STREAM_TRANSPORT_CLASS +GST_RTSP_STREAM_TRANSPORT_GET_CLASS +GST_TYPE_RTSP_STREAM_TRANSPORT +gst_rtsp_stream_transport_get_type +
+ diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index d20e502702..7a80fe0607 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -47,6 +47,7 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; /** * GstRTSPMediaFactory: + * @parent: the parent GObject * @lock: mutex protecting the datastructure. * @launch: the launch description * @shared: if media from this factory can be shared between clients diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c index 8a28db98fd..634439441f 100644 --- a/gst/rtsp-server/rtsp-media-mapping.c +++ b/gst/rtsp-server/rtsp-media-mapping.c @@ -65,6 +65,13 @@ gst_rtsp_media_mapping_finalize (GObject * obj) G_OBJECT_CLASS (gst_rtsp_media_mapping_parent_class)->finalize (obj); } +/** + * gst_rtsp_media_mapping_new: + * + * Make a new media mapping object. + * + * Returns: a new #GstRTSPMediaMapping + */ GstRTSPMediaMapping * gst_rtsp_media_mapping_new (void) { diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 88c5d81f36..b7ba346b57 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -63,6 +63,7 @@ typedef enum { /** * GstRTSPMedia: + * @parent: parent GObject * @lock: for protecting the object * @cond: for signaling the object * @shared: if this media can be shared between clients @@ -70,11 +71,17 @@ typedef enum { * @protocols: the allowed lower transport for this stream * @reused: if this media has been reused * @is_ipv6: if this media is using ipv6 + * @eos_shutdown: if EOS should be sent on shutdown + * @buffer_size: The UDP buffer size + * @auth: the authentication service in use + * @multicast_group: the multicast group to use + * @mtu: the MTU of the payloaders * @element: the data providing element * @streams: the different #GstRTSPStream provided by @element * @dynamic: list of dynamic elements managed by @element * @status: the status of the media pipeline * @n_active: the number of active connections + * @adding: when elements are added to the pipeline * @pipeline: the toplevel pipeline * @fakesink: for making state changes async * @source: the bus watch for pipeline messages. @@ -140,8 +147,7 @@ struct _GstRTSPMedia { * @thread: the thread dispatching messages. * @handle_message: handle a message * @unprepare: the default implementation sets the pipeline's state - * to GST_STATE_NULL. - * @handle_mtu: handle a mtu + * to GST_STATE_NULL and removes all elements. * * The RTSP media class */ @@ -196,7 +202,6 @@ guint gst_rtsp_media_get_mtu (GstRTSPMedia *media); /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); -gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media); gboolean gst_rtsp_media_unprepare (GstRTSPMedia *media); /* creating streams */ diff --git a/gst/rtsp-server/rtsp-params.c b/gst/rtsp-server/rtsp-params.c index 95614fdce5..a5d46b37c6 100644 --- a/gst/rtsp-server/rtsp-params.c +++ b/gst/rtsp-server/rtsp-params.c @@ -20,6 +20,15 @@ #include "rtsp-params.h" +/** + * gst_rtsp_params_set: + * @client: a #GstRTSPClient + * @state: a #GstRTSPClientState + * + * Set parameters (not implemented yet) + * + * Returns: a #GstRTSPResult + */ GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state) { @@ -35,6 +44,15 @@ gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state) return GST_RTSP_OK; } +/** + * gst_rtsp_params_get: + * @client: a #GstRTSPClient + * @state: a #GstRTSPClientState + * + * Get parameters (not implemented yet) + * + * Returns: a #GstRTSPResult + */ GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPClientState * state) { diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index c6229818a8..1b4bbf6b77 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -255,6 +255,14 @@ gst_rtsp_server_get_address (GstRTSPServer * server) return result; } +/** + * gst_rtsp_server_get_bound_port: + * @server: a #GstRTSPServer + * + * Get the port number where the server was bound to. + * + * Returns: the port number + */ int gst_rtsp_server_get_bound_port (GstRTSPServer * server) { @@ -877,6 +885,7 @@ transfer_failed: * gst_rtsp_server_io_func: * @socket: a #GSocket * @condition: the condition on @source + * @server: a #GstRTSPServer * * A default #GSocketSourceFunc that creates a new #GstRTSPClient to accept and handle a * new connection on @socket or @server. diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 642242f16f..645dab37ea 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -43,7 +43,7 @@ typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; * GstRTSPSessionPool: * @max_sessions: the maximum number of sessions. * @lock: locking the session hashtable - * @session: hashtable of sessions indexed by the session id. + * @sessions: hashtable of sessions indexed by the session id. * * An object that keeps track of the active sessions. This object is usually * attached to a #GstRTSPServer object to manage the sessions in that server. diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 7b8cac035d..58abc4bc8f 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -223,8 +223,9 @@ gst_rtsp_session_get_media (GstRTSPSession * sess, const GstRTSPUrl * url) /** * gst_rtsp_session_new: + * @sessionid: a session id * - * Create a new #GstRTSPSession instance. + * Create a new #GstRTSPSession instance with @sessionid. */ GstRTSPSession * gst_rtsp_session_new (const gchar * sessionid) @@ -301,6 +302,12 @@ gst_rtsp_session_touch (GstRTSPSession * session) g_get_current_time (&session->last_access); } +/** + * gst_rtsp_session_prevent_expire: + * @session: a #GstRTSPSession + * + * Prevent @session from expiring. + */ void gst_rtsp_session_prevent_expire (GstRTSPSession * session) { @@ -309,6 +316,13 @@ gst_rtsp_session_prevent_expire (GstRTSPSession * session) g_atomic_int_add (&session->expire_count, 1); } +/** + * gst_rtsp_session_allow_expire: + * @session: a #GstRTSPSession + * + * Allow @session to expire. This method must be called an equal + * amount of time as gst_rtsp_session_prevent_expire(). + */ void gst_rtsp_session_allow_expire (GstRTSPSession * session) { diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index f7815c9185..b6236dc8e2 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -43,12 +43,13 @@ typedef struct _GstRTSPSessionClass GstRTSPSessionClass; /** * GstRTSPSession: + * @parent: the parent GObject * @sessionid: the session id of the session * @timeout: the timeout of the session * @create_time: the time when the session was created * @last_access: the time the session was last accessed * @expire_count: the expire prevention counter - * @media: a list of #GstRTSPSessionMedia managed in this session + * @medias: a list of #GstRTSPSessionMedia managed in this session * * Session information kept by the server for a specific client. * One client session, identified with a session id, can handle multiple medias diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index cd1733293d..fe39b989fd 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -47,11 +47,9 @@ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); /** * GstRTSPStreamTransport: * @parent: parent instance - * @idx: the stream index + * @stream: the GstRTSPStream we manage * @send_rtp: callback for sending RTP messages * @send_rtcp: callback for sending RTCP messages - * @send_rtp_list: callback for sending RTP messages - * @send_rtcp_list: callback for sending RTCP messages * @user_data: user data passed in the callbacks * @notify: free function for the user_data. * @keep_alive: keep alive callback diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 98403139f6..db923d0b12 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -62,7 +62,7 @@ typedef struct _GstRTSPStreamClass GstRTSPStreamClass; * @caps_sig: the signal id for detecting caps * @caps: the caps of the stream * @n_active: the number of active transports in @transports - * @tranports: list of #GstStreamTransport being streamed to + * @transports: list of #GstStreamTransport being streamed to * * The definition of a media stream. The streams are identified by @id. */ From 84b7cf1590e1408814412e337a88ae0000b348f4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 26 Oct 2012 15:19:23 +0200 Subject: [PATCH 0454/1776] media: no need to unlock, unprepare does that when needed --- gst/rtsp-server/rtsp-media.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 65c470cc31..bce78d5424 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1376,9 +1376,6 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, switch (state) { case GST_STATE_NULL: - /* unlock the streams so that they follow the state changes from now on */ - unlock_streams (media); - /* fallthrough */ case GST_STATE_PAUSED: /* we're going from PLAYING to PAUSED, READY or NULL, remove */ if (media->target_state == GST_STATE_PLAYING) From 0d55e1f50c36ebee094349813c0d461d28d087e8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 26 Oct 2012 15:21:50 +0200 Subject: [PATCH 0455/1776] media: signal unprepared when we actually finish --- gst/rtsp-server/rtsp-media.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index bce78d5424..1f216e8807 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1287,12 +1287,6 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) finish_unprepare (media); } - media->reused = TRUE; - - /* when the media is not reusable, this will effectively unref the media and - * recreate it */ - g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL); - return success; } @@ -1323,7 +1317,12 @@ finish_unprepare (GstRTSPMedia * media) gst_object_unref (media->pipeline); media->pipeline = NULL; + media->reused = TRUE; media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED; + + /* when the media is not reusable, this will effectively unref the media and + * recreate it */ + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL); } static gboolean From 693dd3cfc4357f55030639f3cdedeb73400a6587 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 26 Oct 2012 15:23:16 +0200 Subject: [PATCH 0456/1776] media: move unprepare below default implementation Makes it easier to find the default implementation --- gst/rtsp-server/rtsp-media.c | 70 ++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1f216e8807..d00a51b9de 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1255,41 +1255,6 @@ state_failed: } } -/** - * gst_rtsp_media_unprepare: - * @media: a #GstRTSPMedia - * - * Unprepare @media. After this call, the media should be prepared again before - * it can be used again. If the media is set to be non-reusable, a new instance - * must be created. - * - * Returns: %TRUE on success. - */ -gboolean -gst_rtsp_media_unprepare (GstRTSPMedia * media) -{ - gboolean success; - - if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED) - return TRUE; - - GST_INFO ("unprepare media %p", media); - media->target_state = GST_STATE_NULL; - success = TRUE; - - if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) { - GstRTSPMediaClass *klass; - - klass = GST_RTSP_MEDIA_GET_CLASS (media); - if (klass->unprepare) - success = klass->unprepare (media); - } else { - finish_unprepare (media); - } - - return success; -} - static void finish_unprepare (GstRTSPMedia * media) { @@ -1343,6 +1308,41 @@ default_unprepare (GstRTSPMedia * media) return TRUE; } +/** + * gst_rtsp_media_unprepare: + * @media: a #GstRTSPMedia + * + * Unprepare @media. After this call, the media should be prepared again before + * it can be used again. If the media is set to be non-reusable, a new instance + * must be created. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_media_unprepare (GstRTSPMedia * media) +{ + gboolean success; + + if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED) + return TRUE; + + GST_INFO ("unprepare media %p", media); + media->target_state = GST_STATE_NULL; + success = TRUE; + + if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) { + GstRTSPMediaClass *klass; + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + if (klass->unprepare) + success = klass->unprepare (media); + } else { + finish_unprepare (media); + } + + return success; +} + /** * gst_rtsp_media_set_state: * @media: a #GstRTSPMedia From 6f7d755894057418ee46cb0082656d6ef51f2cf4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 26 Oct 2012 17:28:10 +0200 Subject: [PATCH 0457/1776] stream: improve join and leave of the pipeline simplify code Do the cleanup properly Add some docs --- gst/rtsp-server/rtsp-media.c | 46 ++--- gst/rtsp-server/rtsp-stream.c | 333 +++++++++++++++++++--------------- gst/rtsp-server/rtsp-stream.h | 24 +-- 3 files changed, 212 insertions(+), 191 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d00a51b9de..3fc6483181 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -72,7 +72,6 @@ static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message); static void finish_unprepare (GstRTSPMedia * media); static gboolean default_unprepare (GstRTSPMedia * media); -static void unlock_streams (GstRTSPMedia * media); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; @@ -895,22 +894,6 @@ weird_type: } } -static void -unlock_streams (GstRTSPMedia * media) -{ - guint i; - - /* unlock the udp src elements */ - for (i = 0; i < media->streams->len; i++) { - GstRTSPStream *stream; - - stream = g_ptr_array_index (media->streams, i); - - gst_element_set_locked_state (stream->udpsrc[0], FALSE); - gst_element_set_locked_state (stream->udpsrc[1], FALSE); - } -} - static void gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status) { @@ -1075,24 +1058,21 @@ static void pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) { GstRTSPStream *stream; - gint i; stream = gst_rtsp_media_create_stream (media, element, pad); + GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), stream->idx); + /* we will be adding elements below that will cause ASYNC_DONE to be + * posted in the bus. We want to ignore those messages until the + * pipeline really prerolled. */ media->adding = TRUE; - gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline), media->rtpbin); - - for (i = 0; i < 2; i++) { - gst_element_set_state (stream->udpsink[i], GST_STATE_PAUSED); - gst_element_set_state (stream->appsink[i], GST_STATE_PAUSED); - gst_element_set_state (stream->appqueue[i], GST_STATE_PAUSED); - gst_element_set_state (stream->tee[i], GST_STATE_PAUSED); - gst_element_set_state (stream->selector[i], GST_STATE_PAUSED); - gst_element_set_state (stream->appsrc[i], GST_STATE_PAUSED); - } + /* join the element in the PAUSED state because this callback is + * called from the streaming thread and it is PAUSED */ + gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline), + media->rtpbin, GST_STATE_PAUSED); media->adding = FALSE; } @@ -1173,7 +1153,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) stream = g_ptr_array_index (media->streams, i); - gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline), media->rtpbin); + gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline), + media->rtpbin, GST_STATE_NULL); } for (walk = media->dynamic; walk; walk = g_list_next (walk)) { @@ -1208,7 +1189,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) /* we need to go to PLAYING */ GST_INFO ("NO_PREROLL state change: live media %p", media); /* FIXME we disable seeking for live streams for now. We should perform a - * seeking query in preroll instead and do a seeking query. */ + * seeking query in preroll instead */ media->seekable = FALSE; media->is_live = TRUE; ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); @@ -1219,7 +1200,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) goto state_failed; } - /* now wait for all pads to be prerolled */ + /* now wait for all pads to be prerolled, FIXME, we should somehow be + * able to do this async so that we don't block the server thread. */ status = gst_rtsp_media_get_status (media); if (status == GST_RTSP_MEDIA_STATUS_ERROR) goto state_failed; @@ -1262,7 +1244,6 @@ finish_unprepare (GstRTSPMedia * media) GST_DEBUG ("shutting down"); - unlock_streams (media); gst_element_set_state (media->pipeline, GST_STATE_NULL); for (i = 0; i < media->streams->len; i++) { @@ -1278,6 +1259,7 @@ finish_unprepare (GstRTSPMedia * media) g_ptr_array_set_size (media->streams, 0); gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin); + media->rtpbin = NULL; gst_object_unref (media->pipeline); media->pipeline = NULL; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 13360bfe93..cd0d967b31 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -68,28 +68,12 @@ gst_rtsp_stream_finalize (GObject * obj) stream = GST_RTSP_STREAM (obj); - g_assert (!stream->is_joined); + /* we really need to be unjoined now */ + g_return_if_fail (!stream->is_joined); gst_object_unref (stream->payloader); gst_object_unref (stream->srcpad); - if (stream->session) - g_object_unref (stream->session); - - if (stream->caps) - gst_caps_unref (stream->caps); - - if (stream->send_rtp_sink) - gst_object_unref (stream->send_rtp_sink); - if (stream->send_rtp_src) - gst_object_unref (stream->send_rtp_src); - if (stream->send_rtcp_src) - gst_object_unref (stream->send_rtcp_src); - if (stream->recv_rtcp_sink) - gst_object_unref (stream->recv_rtcp_sink); - if (stream->recv_rtp_sink) - gst_object_unref (stream->recv_rtp_sink); - g_list_free (stream->transports); G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); @@ -565,16 +549,18 @@ static GstAppSinkCallbacks sink_cb = { * @stream: a #GstRTSPStream * @bin: a #GstBin to join * @rtpbin: a rtpbin element in @bin + * @state: the target state of the new elements * * Join the #Gstbin @bin that contains the element @rtpbin. * - * @stream will link to @rtpbin, which must be inside @bin. + * @stream will link to @rtpbin, which must be inside @bin. The elements + * added to @bin will be set to the state given in @state. * * Returns: %TRUE on success. */ gboolean gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, - GstElement * rtpbin) + GstElement * rtpbin, GstState state) { gint i, idx; gchar *name; @@ -585,52 +571,42 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, g_return_val_if_fail (GST_IS_BIN (bin), FALSE); g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE); - idx = stream->idx; - if (stream->is_joined) return TRUE; - GST_INFO ("stream %p joining bin", stream); + /* create a session with the same index as the stream */ + idx = stream->idx; + + GST_INFO ("stream %p joining bin as session %d", stream, idx); if (!alloc_ports (stream)) goto no_ports; - /* add the ports to the pipeline */ - for (i = 0; i < 2; i++) { - gst_bin_add (bin, stream->udpsink[i]); - gst_bin_add (bin, stream->udpsrc[i]); - } - - /* create elements for the TCP transfer */ - for (i = 0; i < 2; i++) { - stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL); - stream->appqueue[i] = gst_element_factory_make ("queue", NULL); - stream->appsink[i] = gst_element_factory_make ("appsink", NULL); - g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL); - g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL); - gst_bin_add (bin, stream->appqueue[i]); - gst_bin_add (bin, stream->appsink[i]); - gst_bin_add (bin, stream->appsrc[i]); - gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]), - &sink_cb, stream, NULL); - } - - /* hook up the stream to the RTP session elements. */ + /* get a pad for sending RTP */ name = g_strdup_printf ("send_rtp_sink_%u", idx); stream->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); g_free (name); + /* link the RTP pad to the session manager, it should not really fail unless + * this is not really an RTP pad */ + ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink); + if (ret != GST_PAD_LINK_OK) + goto link_failed; + + /* get pads from the RTP session element for sending and receiving + * RTP/RTCP*/ name = g_strdup_printf ("send_rtp_src_%u", idx); - stream->send_rtp_src = gst_element_get_static_pad (rtpbin, name); + stream->send_src[0] = gst_element_get_static_pad (rtpbin, name); g_free (name); name = g_strdup_printf ("send_rtcp_src_%u", idx); - stream->send_rtcp_src = gst_element_get_request_pad (rtpbin, name); - g_free (name); - name = g_strdup_printf ("recv_rtcp_sink_%u", idx); - stream->recv_rtcp_sink = gst_element_get_request_pad (rtpbin, name); + stream->send_src[1] = gst_element_get_request_pad (rtpbin, name); g_free (name); name = g_strdup_printf ("recv_rtp_sink_%u", idx); - stream->recv_rtp_sink = gst_element_get_request_pad (rtpbin, name); + stream->recv_sink[0] = gst_element_get_request_pad (rtpbin, name); g_free (name); + name = g_strdup_printf ("recv_rtcp_sink_%u", idx); + stream->recv_sink[1] = gst_element_get_request_pad (rtpbin, name); + g_free (name); + /* get the session */ g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &stream->session); @@ -647,110 +623,119 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout, stream); - /* link the RTP pad to the session manager */ - ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink); - if (ret != GST_PAD_LINK_OK) - goto link_failed; + for (i = 0; i < 2; i++) { + /* For the sender we create this bit of pipeline for both + * RTP and RTCP. Sync and preroll are enabled on udpsink so + * we need to add a queue before appsink to make the pipeline + * not block. For the TCP case, we want to pump data to the + * client as fast as possible anyway. + * + * .--------. .-----. .---------. + * | rtpbin | | tee | | udpsink | + * | send->sink src->sink | + * '--------' | | '---------' + * | | .---------. .---------. + * | | | queue | | appsink | + * | src->sink src->sink | + * '-----' '---------' '---------' + */ + /* make tee for RTP/RTCP */ + stream->tee[i] = gst_element_factory_make ("tee", NULL); + gst_bin_add (bin, stream->tee[i]); - /* make tee for RTP and link to stream */ - stream->tee[0] = gst_element_factory_make ("tee", NULL); - gst_bin_add (bin, stream->tee[0]); + /* and link to rtpbin send pad */ + pad = gst_element_get_static_pad (stream->tee[i], "sink"); + gst_pad_link (stream->send_src[i], pad); + gst_object_unref (pad); - pad = gst_element_get_static_pad (stream->tee[0], "sink"); - gst_pad_link (stream->send_rtp_src, pad); - gst_object_unref (pad); + /* add udpsink */ + gst_bin_add (bin, stream->udpsink[i]); - /* link RTP sink, we're pretty sure this will work. */ - teepad = gst_element_get_request_pad (stream->tee[0], "src_%u"); - pad = gst_element_get_static_pad (stream->udpsink[0], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); + /* link tee to udpsink */ + teepad = gst_element_get_request_pad (stream->tee[i], "src_%u"); + pad = gst_element_get_static_pad (stream->udpsink[i], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); - teepad = gst_element_get_request_pad (stream->tee[0], "src_%u"); - pad = gst_element_get_static_pad (stream->appqueue[0], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); + /* make queue */ + stream->appqueue[i] = gst_element_factory_make ("queue", NULL); + gst_bin_add (bin, stream->appqueue[i]); + /* and link to tee */ + teepad = gst_element_get_request_pad (stream->tee[i], "src_%u"); + pad = gst_element_get_static_pad (stream->appqueue[i], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); - queuepad = gst_element_get_static_pad (stream->appqueue[0], "src"); - pad = gst_element_get_static_pad (stream->appsink[0], "sink"); - gst_pad_link (queuepad, pad); - gst_object_unref (pad); - gst_object_unref (queuepad); + /* make appsink */ + stream->appsink[i] = gst_element_factory_make ("appsink", NULL); + g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL); + g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL); + gst_bin_add (bin, stream->appsink[i]); + gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]), + &sink_cb, stream, NULL); + /* and link to queue */ + queuepad = gst_element_get_static_pad (stream->appqueue[i], "src"); + pad = gst_element_get_static_pad (stream->appsink[i], "sink"); + gst_pad_link (queuepad, pad); + gst_object_unref (pad); + gst_object_unref (queuepad); - /* make tee for RTCP */ - stream->tee[1] = gst_element_factory_make ("tee", NULL); - gst_bin_add (bin, stream->tee[1]); + /* For the receiver we create this bit of pipeline for both + * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc + * and it is all funneled into the rtpbin receive pad. + * + * .--------. .--------. .--------. + * | udpsrc | | funnel | | rtpbin | + * | src->sink src->sink | + * '--------' | | '--------' + * .--------. | | + * | appsrc | | | + * | src->sink | + * '--------' '--------' + */ + /* make funnel for the RTP/RTCP receivers */ + stream->funnel[i] = gst_element_factory_make ("funnel", NULL); + gst_bin_add (bin, stream->funnel[i]); - pad = gst_element_get_static_pad (stream->tee[1], "sink"); - gst_pad_link (stream->send_rtcp_src, pad); - gst_object_unref (pad); + pad = gst_element_get_static_pad (stream->funnel[i], "src"); + gst_pad_link (pad, stream->recv_sink[i]); + gst_object_unref (pad); - /* link RTCP elements */ - teepad = gst_element_get_request_pad (stream->tee[1], "src_%u"); - pad = gst_element_get_static_pad (stream->udpsink[1], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); + /* add udpsrc */ + gst_bin_add (bin, stream->udpsrc[i]); + /* and link to the funnel */ + selpad = gst_element_get_request_pad (stream->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (stream->udpsrc[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); - teepad = gst_element_get_request_pad (stream->tee[1], "src_%u"); - pad = gst_element_get_static_pad (stream->appqueue[1], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); + /* make and add appsrc */ + stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL); + gst_bin_add (bin, stream->appsrc[i]); + /* and link to the funnel */ + selpad = gst_element_get_request_pad (stream->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (stream->appsrc[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); - queuepad = gst_element_get_static_pad (stream->appqueue[1], "src"); - pad = gst_element_get_static_pad (stream->appsink[1], "sink"); - gst_pad_link (queuepad, pad); - gst_object_unref (pad); - gst_object_unref (queuepad); - - /* make selector for the RTP receivers */ - stream->selector[0] = gst_element_factory_make ("funnel", NULL); - gst_bin_add (bin, stream->selector[0]); - - pad = gst_element_get_static_pad (stream->selector[0], "src"); - gst_pad_link (pad, stream->recv_rtp_sink); - gst_object_unref (pad); - - selpad = gst_element_get_request_pad (stream->selector[0], "sink_%u"); - pad = gst_element_get_static_pad (stream->udpsrc[0], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - selpad = gst_element_get_request_pad (stream->selector[0], "sink_%u"); - pad = gst_element_get_static_pad (stream->appsrc[0], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - - /* make selector for the RTCP receivers */ - stream->selector[1] = gst_element_factory_make ("funnel", NULL); - gst_bin_add (bin, stream->selector[1]); - - pad = gst_element_get_static_pad (stream->selector[1], "src"); - gst_pad_link (pad, stream->recv_rtcp_sink); - gst_object_unref (pad); - - selpad = gst_element_get_request_pad (stream->selector[1], "sink_%u"); - pad = gst_element_get_static_pad (stream->udpsrc[1], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - - selpad = gst_element_get_request_pad (stream->selector[1], "sink_%u"); - pad = gst_element_get_static_pad (stream->appsrc[1], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values */ - gst_element_set_state (stream->udpsrc[0], GST_STATE_PLAYING); - gst_element_set_state (stream->udpsrc[1], GST_STATE_PLAYING); - gst_element_set_locked_state (stream->udpsrc[0], TRUE); - gst_element_set_locked_state (stream->udpsrc[1], TRUE); + /* check if we need to set to a special state */ + if (state != GST_STATE_NULL) { + gst_element_set_state (stream->udpsink[i], state); + gst_element_set_state (stream->appsink[i], state); + gst_element_set_state (stream->appqueue[i], state); + gst_element_set_state (stream->tee[i], state); + gst_element_set_state (stream->funnel[i], state); + gst_element_set_state (stream->appsrc[i], state); + } + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values */ + gst_element_set_state (stream->udpsrc[i], GST_STATE_PLAYING); + gst_element_set_locked_state (stream->udpsrc[i], TRUE); + } /* be notified of caps changes */ stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps", @@ -769,6 +754,8 @@ no_ports: link_failed: { GST_WARNING ("failed to link stream %d", idx); + gst_object_unref (stream->send_rtp_sink); + stream->send_rtp_sink = NULL; return FALSE; } } @@ -779,7 +766,8 @@ link_failed: * @bin: a #GstBin * @rtpbin: a rtpbin #GstElement * - * Remove the elements of @stream from the bin + * Remove the elements of @stream from @bin. @bin must be set + * to the NULL state before calling this. * * Return: %TRUE on success. */ @@ -796,22 +784,55 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, if (!stream->is_joined) return TRUE; + /* all transports must be removed by now */ + g_return_val_if_fail (stream->transports == NULL, FALSE); + GST_INFO ("stream %p leaving bin", stream); gst_pad_unlink (stream->srcpad, stream->send_rtp_sink); - g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig); + gst_element_release_request_pad (rtpbin, stream->send_rtp_sink); + gst_object_unref (stream->send_rtp_sink); + stream->send_rtp_sink = NULL; - /* FIXME not entirely the opposite of join_bin */ for (i = 0; i < 2; i++) { + /* and set udpsrc to NULL now before removing */ + gst_element_set_locked_state (stream->udpsrc[i], FALSE); + gst_element_set_state (stream->udpsrc[i], GST_STATE_NULL); + + /* removing them should also nicely release the request + * pads when they finalize */ gst_bin_remove (bin, stream->udpsrc[i]); gst_bin_remove (bin, stream->udpsink[i]); gst_bin_remove (bin, stream->appsrc[i]); gst_bin_remove (bin, stream->appsink[i]); gst_bin_remove (bin, stream->appqueue[i]); gst_bin_remove (bin, stream->tee[i]); - gst_bin_remove (bin, stream->selector[i]); + gst_bin_remove (bin, stream->funnel[i]); + + gst_element_release_request_pad (rtpbin, stream->recv_sink[i]); + gst_object_unref (stream->recv_sink[i]); + stream->recv_sink[i] = NULL; + + stream->udpsrc[i] = NULL; + stream->udpsink[i] = NULL; + stream->appsrc[i] = NULL; + stream->appsink[i] = NULL; + stream->appqueue[i] = NULL; + stream->tee[i] = NULL; + stream->funnel[i] = NULL; } + gst_object_unref (stream->send_src[0]); + stream->send_src[0] = NULL; + + gst_element_release_request_pad (rtpbin, stream->send_src[1]); + gst_object_unref (stream->send_src[1]); + stream->send_src[1] = NULL; + + g_object_unref (stream->session); + if (stream->caps) + gst_caps_unref (stream->caps); + stream->is_joined = FALSE; return TRUE; @@ -862,6 +883,10 @@ gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * buffer) { GstFlowReturn ret; + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR); + g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); + g_return_val_if_fail (stream->is_joined, FALSE); + ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[0]), buffer); return ret; @@ -884,6 +909,10 @@ gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer) { GstFlowReturn ret; + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR); + g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); + g_return_val_if_fail (stream->is_joined, FALSE); + ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[1]), buffer); return ret; @@ -969,6 +998,8 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, * Add the transport in @trans to @stream. The media of @stream will * then also be send to the values configured in @trans. * + * @stream must be joined to a bin. + * * @trans must contain a valid #GstRTSPTransport. * * Returns: %TRUE if @trans was added @@ -979,6 +1010,7 @@ gst_rtsp_stream_add_transport (GstRTSPStream * stream, { g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE); + g_return_val_if_fail (stream->is_joined, FALSE); g_return_val_if_fail (trans->transport != NULL, FALSE); return update_transport (stream, trans, TRUE); @@ -992,6 +1024,10 @@ gst_rtsp_stream_add_transport (GstRTSPStream * stream, * Remove the transport in @trans from @stream. The media of @stream will * not be sent to the values configured in @trans. * + * @stream must be joined to a bin. + * + * @trans must contain a valid #GstRTSPTransport. + * * Returns: %TRUE if @trans was removed */ gboolean @@ -1000,6 +1036,7 @@ gst_rtsp_stream_remove_transport (GstRTSPStream * stream, { g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE); + g_return_val_if_fail (stream->is_joined, FALSE); g_return_val_if_fail (trans->transport != NULL, FALSE); return update_transport (stream, trans, FALSE); diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index db923d0b12..d5fb03d9b3 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -50,21 +50,24 @@ typedef struct _GstRTSPStreamClass GstRTSPStreamClass; * @is_ipv6: should this stream be IPv6 * @buffer_size: the UDP buffer size * @is_joined: if the stream is joined in a bin - * @recv_rtp_sink: sinkpad for RTP buffers - * @recv_rtcp_sink: sinkpad for RTCP buffers - * @send_rtp_src: srcpad for RTP buffers - * @send_rtcp_src: srcpad for RTCP buffers + * @send_rtp_sink: sinkpad for sending RTP buffers + * @recv_sink: sinkpad for receiving RTP/RTCP buffers + * @send_src: srcpad for sending RTP/RTCP buffers + * @session: the RTP session object * @udpsrc: the udp source elements for RTP/RTCP * @udpsink: the udp sink elements for RTP/RTCP * @appsrc: the app source elements for RTP/RTCP + * @appqueue: the app queue elements for RTP/RTCP * @appsink: the app sink elements for RTP/RTCP + * @tee: tee for the sending to udpsink and appsink + * @funnel: tee for the receiving from udpsrc and appsrc * @server_port: the server ports for this stream * @caps_sig: the signal id for detecting caps * @caps: the caps of the stream * @n_active: the number of active transports in @transports * @transports: list of #GstStreamTransport being streamed to * - * The definition of a media stream. The streams are identified by @id. + * The definition of a media stream. The streams are identified by @idx. */ struct _GstRTSPStream { GObject parent; @@ -77,11 +80,9 @@ struct _GstRTSPStream { gboolean is_joined; /* pads on the rtpbin */ - GstPad *recv_rtcp_sink; - GstPad *recv_rtp_sink; GstPad *send_rtp_sink; - GstPad *send_rtp_src; - GstPad *send_rtcp_src; + GstPad *recv_sink[2]; + GstPad *send_src[2]; /* the RTPSession object */ GObject *session; @@ -96,7 +97,7 @@ struct _GstRTSPStream { GstElement *appsink[2]; GstElement *tee[2]; - GstElement *selector[2]; + GstElement *funnel[2]; /* server ports for sending/receiving */ GstRTSPRange server_port; @@ -123,7 +124,8 @@ void gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guin guint gst_rtsp_stream_get_mtu (GstRTSPStream * stream); gboolean gst_rtsp_stream_join_bin (GstRTSPStream * stream, - GstBin *bin, GstElement *rtpbin); + GstBin *bin, GstElement *rtpbin, + GstState state); gboolean gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin *bin, GstElement *rtpbin); From 6a838fd5c824b1590a37549428e8da9ca045a335 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 26 Oct 2012 17:29:30 +0200 Subject: [PATCH 0458/1776] stream: transports must already have been removed --- gst/rtsp-server/rtsp-stream.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index cd0d967b31..a6dccce114 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -74,8 +74,6 @@ gst_rtsp_stream_finalize (GObject * obj) gst_object_unref (stream->payloader); gst_object_unref (stream->srcpad); - g_list_free (stream->transports); - G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); } From 0bb0e3733c5d418406abe584e403a76aff0e1f46 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 27 Oct 2012 11:53:51 +0200 Subject: [PATCH 0459/1776] small fixes to docs and debug --- examples/test-mp4.c | 2 +- gst/rtsp-server/rtsp-media.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/test-mp4.c b/examples/test-mp4.c index ba31ca2ab0..8593da4c6c 100644 --- a/examples/test-mp4.c +++ b/examples/test-mp4.c @@ -33,7 +33,7 @@ main (int argc, char *argv[]) gst_init (&argc, &argv); if (argc < 2) { - g_message ("usage: %s ", argv[0]); + g_message ("usage: %s ", argv[0]); return -1; } diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 3fc6483181..e7328c0afe 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -274,6 +274,8 @@ collect_media_stats (GstRTSPMedia * media) media->range.unit = GST_RTSP_RANGE_NPT; + GST_INFO ("collect media stats"); + if (media->is_live) { media->range.min.type = GST_RTSP_TIME_NOW; media->range.min.seconds = -1; @@ -1059,6 +1061,7 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) { GstRTSPStream *stream; + /* FIXME, element is likely not a payloader, find the payloader here */ stream = gst_rtsp_media_create_stream (media, element, pad); GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), From fee8216513aab5d7dec8635ea55a809b1a2562e5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 27 Oct 2012 21:05:03 +0200 Subject: [PATCH 0460/1776] client: refuse to change the MTU on shared media If we change the MTU of chared media, it changes for all clients. We don't want to set the MTU to something large for clients that stream over UDP. --- gst/rtsp-server/rtsp-client.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c04eec56e4..cdf1b2c209 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -910,6 +910,11 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request) GST_ERROR ("failed to parse blocksize"); ret = FALSE; } else { + /* we don't want to change the mtu when this media + * can be shared because it impacts other clients */ + if (gst_rtsp_media_is_shared (media)) + return TRUE; + if (blocksize > G_MAXUINT) blocksize = G_MAXUINT; gst_rtsp_media_set_mtu (media, blocksize); From 8c30d050fa5cc2e9813a042d38c95f41fd9e3ebe Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 27 Oct 2012 21:26:55 +0200 Subject: [PATCH 0461/1776] client: refactor transport parsing --- gst/rtsp-server/rtsp-client.c | 97 ++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index cdf1b2c209..6b9b6d51d4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -894,6 +894,57 @@ do_keepalive (GstRTSPSession * session) gst_rtsp_session_touch (session); } +/* parse @transport and return a valid transport in @tr. only transports + * from @supported are returned. Returns FALSE if no valid transport + * was found. */ +static gboolean +parse_transport (const char *transport, GstRTSPLowerTrans supported, + GstRTSPTransport * tr) +{ + gint i; + gboolean res; + gchar **transports; + + res = FALSE; + gst_rtsp_transport_init (tr); + + GST_WARNING ("parsing transports %s", transport); + + transports = g_strsplit (transport, ",", 0); + + /* loop through the transports, try to parse */ + for (i = 0; transports[i]; i++) { + res = gst_rtsp_transport_parse (transports[i], tr); + if (res != GST_RTSP_OK) { + /* no valid transport, search some more */ + GST_WARNING ("could not parse transport %s", transports[i]); + goto next; + } + + /* we have a transport, see if it's RTP/AVP */ + if (tr->trans != GST_RTSP_TRANS_RTP || tr->profile != GST_RTSP_PROFILE_AVP) { + GST_WARNING ("invalid transport %s", transports[i]); + goto next; + } + + if (!(tr->lower_transport & supported)) { + GST_WARNING ("unsupported transport %s", transports[i]); + goto next; + } + + /* we have a valid transport */ + GST_INFO ("found valid transport %s", transports[i]); + res = TRUE; + break; + + next: + gst_rtsp_transport_init (tr); + } + g_strfreev (transports); + + return res; +} + static gboolean handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request) { @@ -930,10 +981,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPResult res; GstRTSPUrl *uri; gchar *transport; - gchar **transports; - gboolean have_transport; GstRTSPTransport *ct, *st; - gint i; GstRTSPLowerTrans supported; GstRTSPStatusCode code; GstRTSPSession *session; @@ -945,7 +993,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) uri = state->uri; /* the uri contains the stream number we added in the SDP config, which is - * always /stream=%d so we need to strip that off + * always /stream=%d so we need to strip that off * parse the stream we need to configure, look for the stream in the abspath * first and then in the query. */ if (uri->abspath == NULL || !(pos = strstr (uri->abspath, "/stream="))) { @@ -953,7 +1001,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) goto bad_request; } - /* we can mofify the parse uri in place */ + /* we can mofify the parsed uri in place */ *pos = '\0'; pos += strlen ("/stream="); @@ -967,49 +1015,14 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) if (res != GST_RTSP_OK) goto no_transport; - transports = g_strsplit (transport, ",", 0); gst_rtsp_transport_new (&ct); - /* init transports */ - have_transport = FALSE; - gst_rtsp_transport_init (ct); - /* our supported transports */ supported = GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP; - /* loop through the transports, try to parse */ - for (i = 0; transports[i]; i++) { - res = gst_rtsp_transport_parse (transports[i], ct); - if (res != GST_RTSP_OK) { - /* no valid transport, search some more */ - GST_WARNING ("could not parse transport %s", transports[i]); - goto next; - } - - /* we have a transport, see if it's RTP/AVP */ - if (ct->trans != GST_RTSP_TRANS_RTP || ct->profile != GST_RTSP_PROFILE_AVP) { - GST_WARNING ("invalid transport %s", transports[i]); - goto next; - } - - if (!(ct->lower_transport & supported)) { - GST_WARNING ("unsupported transport %s", transports[i]); - goto next; - } - - /* we have a valid transport */ - GST_INFO ("found valid transport %s", transports[i]); - have_transport = TRUE; - break; - - next: - gst_rtsp_transport_init (ct); - } - g_strfreev (transports); - - /* we have not found anything usable, error out */ - if (!have_transport) + /* parse and find a usable supported transport */ + if (!parse_transport (transport, supported, ct)) goto unsupported_transports; if (client->session_pool == NULL) From fb117a4f751f7860c9d0d96e3291855bdba9bdfe Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 27 Oct 2012 23:49:24 +0200 Subject: [PATCH 0462/1776] rtsp: refactor configuration of transport Move the configuration of the transport to a place where it makes more sense. --- gst/rtsp-server/rtsp-client.c | 166 +++++++++++++++--------- gst/rtsp-server/rtsp-client.h | 4 +- gst/rtsp-server/rtsp-stream-transport.c | 45 +------ gst/rtsp-server/rtsp-stream-transport.h | 2 +- 4 files changed, 118 insertions(+), 99 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6b9b6d51d4..d74f6ae080 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -506,7 +506,9 @@ link_transport (GstRTSPClient * client, GstRTSPSession * session, gst_rtsp_stream_transport_set_callbacks (trans, (GstRTSPSendFunc) do_send_data, (GstRTSPSendFunc) do_send_data, client, NULL); + client->transports = g_list_prepend (client->transports, trans); + /* make sure our session can't expire */ gst_rtsp_session_prevent_expire (session); } @@ -517,7 +519,9 @@ unlink_transport (GstRTSPClient * client, GstRTSPSession * session, { GST_DEBUG ("client %p: unlinking transport %p", client, trans); gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL); + client->transports = g_list_remove (client->transports, trans); + /* our session can now expire */ gst_rtsp_session_allow_expire (session); } @@ -971,10 +975,77 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request) gst_rtsp_media_set_mtu (media, blocksize); } } - return ret; } +static gboolean +configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, + GstRTSPTransport * ct) +{ + /* we have a valid transport now, set the destination of the client. */ + if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + if (ct->destination == NULL || !client->use_client_settings) { + g_free (ct->destination); + ct->destination = gst_rtsp_media_get_multicast_group (state->media); + } + /* reset ttl and port if client settings are not allowed */ + if (!client->use_client_settings) { + ct->port = state->stream->server_port; + ct->ttl = 0; + } + } else { + GstRTSPUrl *url; + + url = gst_rtsp_connection_get_url (client->connection); + g_free (ct->destination); + ct->destination = g_strdup (url->host); + + if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) { + /* check if the client selected channels for TCP */ + if (ct->interleaved.min == -1 || ct->interleaved.max == -1) { + gst_rtsp_session_media_alloc_channels (state->sessmedia, + &ct->interleaved); + } + } + } + return TRUE; +} + +static GstRTSPTransport * +make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, + GstRTSPTransport * ct) +{ + GstRTSPTransport *st; + + /* prepare the server transport */ + gst_rtsp_transport_new (&st); + + st->trans = ct->trans; + st->profile = ct->profile; + st->lower_transport = ct->lower_transport; + + switch (st->lower_transport) { + case GST_RTSP_LOWER_TRANS_UDP: + st->client_port = ct->client_port; + st->server_port = state->stream->server_port; + break; + case GST_RTSP_LOWER_TRANS_UDP_MCAST: + st->port = ct->port; + st->destination = g_strdup (ct->destination); + st->ttl = ct->ttl; + break; + case GST_RTSP_LOWER_TRANS_TCP: + st->interleaved = ct->interleaved; + default: + break; + } + + if (state->stream->session) + g_object_get (state->stream->session, "internal-ssrc", &st->ssrc, NULL); + + return st; +} + static gboolean handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) { @@ -988,7 +1059,9 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPStreamTransport *trans; gchar *trans_str, *pos; guint streamid; - GstRTSPSessionMedia *media; + GstRTSPSessionMedia *sessmedia; + GstRTSPMedia *media; + GstRTSPStream *stream; uri = state->uri; @@ -1025,6 +1098,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) if (!parse_transport (transport, supported, ct)) goto unsupported_transports; + /* we create the session after parsing stuff so that we don't make + * a session for malformed requests */ if (client->session_pool == NULL) goto no_pool; @@ -1034,7 +1109,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) g_object_ref (session); /* get a handle to the configuration of the media in the session, this can * return NULL if this is a new url to manage in this session. */ - media = gst_rtsp_session_get_media (session, uri); + sessmedia = gst_rtsp_session_get_media (session, uri); } else { /* create a session if this fails we probably reached our session limit or * something. */ @@ -1044,65 +1119,49 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) state->session = session; /* we need a new media configuration in this session */ - media = NULL; + sessmedia = NULL; } /* we have no media, find one and manage it */ - if (media == NULL) { - GstRTSPMedia *m; - + if (sessmedia == NULL) { /* get a handle to the configuration of the media in the session */ - if ((m = find_media (client, state))) { + if ((media = find_media (client, state))) { /* manage the media in our session now */ - media = gst_rtsp_session_manage_media (session, uri, m); + sessmedia = gst_rtsp_session_manage_media (session, uri, media); } } /* if we stil have no media, error */ - if (media == NULL) + if (sessmedia == NULL) goto not_found; - state->sessmedia = media; + state->sessmedia = sessmedia; + state->media = media = sessmedia->media; - if (!handle_blocksize (media->media, state->request)) + /* now get the stream */ + stream = gst_rtsp_media_get_stream (media, streamid); + if (stream == NULL) + goto not_found; + + state->stream = stream; + + /* FIXME set only on this stream */ + if (!handle_blocksize (media, state->request)) goto invalid_blocksize; - /* we have a valid transport now, set the destination of the client. */ - if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - if (ct->destination == NULL || !client->use_client_settings) { - g_free (ct->destination); - ct->destination = gst_rtsp_media_get_multicast_group (media->media); - } - /* reset ttl if client settings are not allowed */ - if (!client->use_client_settings) { - ct->ttl = 0; - } - } else { - GstRTSPUrl *url; + /* update the client transport */ + configure_client_transport (client, state, ct); - url = gst_rtsp_connection_get_url (client->connection); - g_free (ct->destination); - ct->destination = g_strdup (url->host); - - if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) { - /* check if the client selected channels for TCP */ - if (ct->interleaved.min == -1 || ct->interleaved.max == -1) { - gst_rtsp_session_media_alloc_channels (media, &ct->interleaved); - } - } - } - - /* get a handle to the transport of the media in this session */ - if (!(trans = gst_rtsp_session_media_get_transport (media, streamid))) - goto no_stream_transport; - - st = gst_rtsp_stream_transport_set_transport (trans, ct); + /* set in the session media transport */ + trans = gst_rtsp_session_media_get_transport (sessmedia, streamid); + gst_rtsp_stream_transport_set_transport (trans, ct); /* configure keepalive for this transport */ gst_rtsp_stream_transport_set_keepalive (trans, (GstRTSPKeepAliveFunc) do_keepalive, session, NULL); - /* serialize the server transport */ + /* create and serialize the server transport */ + st = make_server_transport (client, state, ct); trans_str = gst_rtsp_transport_as_text (st); gst_rtsp_transport_free (st); @@ -1118,14 +1177,14 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) send_response (client, session, state->response); /* update the state */ - switch (media->state) { + switch (sessmedia->state) { case GST_RTSP_STATE_PLAYING: case GST_RTSP_STATE_RECORDING: case GST_RTSP_STATE_READY: /* no state change */ break; default: - media->state = GST_RTSP_STATE_READY; + sessmedia->state = GST_RTSP_STATE_READY; break; } g_object_unref (session); @@ -1155,13 +1214,6 @@ invalid_blocksize: gst_rtsp_transport_free (ct); return FALSE; } -no_stream_transport: - { - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); - g_object_unref (session); - gst_rtsp_transport_free (ct); - return FALSE; - } no_transport: { send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); @@ -1573,17 +1625,15 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) handled = FALSE; for (walk = client->transports; walk; walk = g_list_next (walk)) { - GstRTSPStreamTransport *trans = (GstRTSPStreamTransport *) walk->data; + GstRTSPStreamTransport *trans; GstRTSPStream *stream; GstRTSPTransport *tr; - /* get the transport, if there is no transport configured, skip this stream */ - if (!(tr = trans->transport)) - continue; + trans = walk->data; - /* we also need a media stream */ - if (!(stream = trans->stream)) - continue; + /* we only add clients with a transport to the list */ + tr = trans->transport; + stream = trans->stream; /* check for TCP transport */ if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index cd08f7e0f4..a896ea6993 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -54,7 +54,8 @@ typedef struct _GstRTSPClientState GstRTSPClientState; * @session: the session, can be NULL * @sessmedia: the session media for the url can be NULL * @factory: the media factory for the url, can be NULL. - * @media: the session media for the url can be NULL + * @media: the media for the url can be NULL + * @stream: the stream for the url can be NULL * @response: the response * * Information passed around containing the client state of a request. @@ -67,6 +68,7 @@ struct _GstRTSPClientState { GstRTSPSessionMedia *sessmedia; GstRTSPMediaFactory *factory; GstRTSPMedia *media; + GstRTSPStream *stream; GstRTSPMessage *response; }; diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 7b5609a131..1151f3de1c 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -83,7 +83,7 @@ gst_rtsp_stream_transport_finalize (GObject * obj) * gst_rtsp_stream_transport_new: * @stream: a #GstRTSPStream * - * Create a new #GstRTSPStreamTransport that can be used for + * Create a new #GstRTSPStreamTransport that can be used to manage * @stream. * * Returns: a new #GstRTSPStreamTransport @@ -152,51 +152,18 @@ gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans, * @trans: a #GstRTSPStreamTransport * @ct: a client #GstRTSPTransport * - * Set @ct as the client transport and create and return a matching server - * transport. This function takes ownership of the passed @ct. - * - * Returns: a server transport or NULL if something went wrong. Use - * gst_rtsp_transport_free () after usage. + * Set @ct as the client transport. This function takes ownership of + * the passed @ct. */ -GstRTSPTransport * +void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans, GstRTSPTransport * ct) { - GstRTSPTransport *st; - - g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL); - g_return_val_if_fail (ct != NULL, NULL); - - /* prepare the server transport */ - gst_rtsp_transport_new (&st); - - st->trans = ct->trans; - st->profile = ct->profile; - st->lower_transport = ct->lower_transport; - - switch (st->lower_transport) { - case GST_RTSP_LOWER_TRANS_UDP: - st->client_port = ct->client_port; - st->server_port = trans->stream->server_port; - break; - case GST_RTSP_LOWER_TRANS_UDP_MCAST: - ct->port = st->port = trans->stream->server_port; - st->destination = g_strdup (ct->destination); - st->ttl = ct->ttl; - break; - case GST_RTSP_LOWER_TRANS_TCP: - st->interleaved = ct->interleaved; - default: - break; - } - - if (trans->stream->session) - g_object_get (trans->stream->session, "internal-ssrc", &st->ssrc, NULL); + g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); + g_return_if_fail (ct != NULL); /* keep track of the transports in the stream. */ if (trans->transport) gst_rtsp_transport_free (trans->transport); trans->transport = ct; - - return st; } diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index fe39b989fd..913e789149 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -91,7 +91,7 @@ GType gst_rtsp_stream_transport_get_type (void); GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream); -GstRTSPTransport * gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans, +void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans, GstRTSPTransport * ct); void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans, From 66a29c7ed9dcea4863f06221b8e61cd57e16b72d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 27 Oct 2012 23:53:35 +0200 Subject: [PATCH 0463/1776] client: small cleanup --- gst/rtsp-server/rtsp-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d74f6ae080..7421065d2f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -180,8 +180,8 @@ static void client_unlink_session (GstRTSPClient * client, GstRTSPSession * session) { /* unlink all media managed in this session */ - while (g_list_length (session->medias) > 0) { - GstRTSPSessionMedia *media = g_list_first (session->medias)->data; + while (session->medias) { + GstRTSPSessionMedia *media = session->medias->data; gst_rtsp_session_media_set_state (media, GST_STATE_NULL); unlink_session_transports (client, session, media); From 543aa383e772cdb53345c53110884a622d3a498d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 28 Oct 2012 00:23:57 +0200 Subject: [PATCH 0464/1776] rtsp: only create transport when needed Only create the StreamTransport when configured. --- gst/rtsp-server/rtsp-client.c | 16 ++++---- gst/rtsp-server/rtsp-session-media.c | 53 +++++++++++++++---------- gst/rtsp-server/rtsp-session-media.h | 3 ++ gst/rtsp-server/rtsp-stream-transport.c | 17 ++++---- gst/rtsp-server/rtsp-stream-transport.h | 5 ++- 5 files changed, 56 insertions(+), 38 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 7421065d2f..f6483332ce 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -537,12 +537,13 @@ unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, GstRTSPStreamTransport *trans; GstRTSPTransport *tr; - /* get the stream as configured in the session */ - trans = gst_rtsp_session_media_get_transport (media, i); /* get the transport, if there is no transport configured, skip this stream */ - if (!(tr = trans->transport)) + trans = gst_rtsp_session_media_get_transport (media, i); + if (trans == NULL) continue; + tr = trans->transport; + if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { /* for TCP, unlink the stream from the TCP connection of the client */ unlink_transport (client, session, trans); @@ -815,13 +816,13 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) gchar *uristr; guint rtptime, seq; - /* get the stream as configured in the session */ - trans = gst_rtsp_session_media_get_transport (media, i); /* get the transport, if there is no transport configured, skip this stream */ - if (!(tr = trans->transport)) { + trans = gst_rtsp_session_media_get_transport (media, i); + if (trans == NULL) { GST_INFO ("stream %d is not configured", i); continue; } + tr = trans->transport; if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { /* for TCP, link the stream to the TCP connection of the client */ @@ -1153,8 +1154,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) configure_client_transport (client, state, ct); /* set in the session media transport */ - trans = gst_rtsp_session_media_get_transport (sessmedia, streamid); - gst_rtsp_stream_transport_set_transport (trans, ct); + trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct); /* configure keepalive for this transport */ gst_rtsp_stream_transport_set_keepalive (trans, diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 12a01d4703..7b100a6af8 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -116,12 +116,42 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media) return result; } +/** + * gst_rtsp_session_media_set_transport: + * @media: a #GstRTSPSessionMedia + * @stream: a #GstRTSPStream + * @tr: a #GstRTSPTransport + * + * Configure the transport for @stream to @tr in @media. + * + * Returns: the new or updated #GstRTSPStreamTransport for @stream. + */ +GstRTSPStreamTransport * +gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, + GstRTSPStream * stream, GstRTSPTransport * tr) +{ + GstRTSPStreamTransport *result; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL); + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + g_return_val_if_fail (stream->idx < media->transports->len, NULL); + + result = g_ptr_array_index (media->transports, stream->idx); + if (result == NULL) { + result = gst_rtsp_stream_transport_new (stream, tr); + g_ptr_array_index (media->transports, stream->idx) = result; + } else { + gst_rtsp_stream_transport_set_transport (result, tr); + } + return result; +} + /** * gst_rtsp_session_media_get_transport: * @media: a #GstRTSPSessionMedia * @idx: the stream index * - * Get a previously created or create a new #GstRTSPStreamTransport at @idx. + * Get a previously created #GstRTSPStreamTransport for the stream at @idx. * * Returns: a #GstRTSPStreamTransport that is valid until the session of @media * is unreffed. @@ -132,30 +162,11 @@ gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx) GstRTSPStreamTransport *result; g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL); - g_return_val_if_fail (media->media != NULL, NULL); - - if (idx >= media->transports->len) - return NULL; + g_return_val_if_fail (idx < media->transports->len, NULL); result = g_ptr_array_index (media->transports, idx); - if (result == NULL) { - GstRTSPStream *stream; - stream = gst_rtsp_media_get_stream (media->media, idx); - if (stream == NULL) - goto no_media; - - result = gst_rtsp_stream_transport_new (stream); - - g_ptr_array_index (media->transports, idx) = result; - } return result; - - /* ERRORS */ -no_media: - { - return NULL; - } } /** diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index ac9588f0b3..45e1bb2759 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -75,6 +75,9 @@ gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMe GstState state); /* get stream transport config */ +GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia *media, + GstRTSPStream *stream, + GstRTSPTransport *tr); GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia *media, guint idx); diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 1151f3de1c..c8ef8b0e12 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -82,21 +82,24 @@ gst_rtsp_stream_transport_finalize (GObject * obj) /** * gst_rtsp_stream_transport_new: * @stream: a #GstRTSPStream + * @tr: (transfer full): a GstRTSPTransport * * Create a new #GstRTSPStreamTransport that can be used to manage - * @stream. + * @stream with transport @tr. * * Returns: a new #GstRTSPStreamTransport */ GstRTSPStreamTransport * -gst_rtsp_stream_transport_new (GstRTSPStream * stream) +gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr) { GstRTSPStreamTransport *trans; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + g_return_val_if_fail (tr != NULL, NULL); trans = g_object_new (GST_TYPE_RTSP_STREAM_TRANSPORT, NULL); trans->stream = stream; + trans->transport = tr; return trans; } @@ -150,20 +153,20 @@ gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans, /** * gst_rtsp_stream_transport_set_transport: * @trans: a #GstRTSPStreamTransport - * @ct: a client #GstRTSPTransport + * @tr: (transfer full): a client #GstRTSPTransport * * Set @ct as the client transport. This function takes ownership of - * the passed @ct. + * the passed @tr. */ void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans, - GstRTSPTransport * ct) + GstRTSPTransport * tr) { g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); - g_return_if_fail (ct != NULL); + g_return_if_fail (tr != NULL); /* keep track of the transports in the stream. */ if (trans->transport) gst_rtsp_transport_free (trans->transport); - trans->transport = ct; + trans->transport = tr; } diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 913e789149..eec7c04480 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -89,10 +89,11 @@ struct _GstRTSPStreamTransportClass { GType gst_rtsp_stream_transport_get_type (void); -GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream); +GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream, + GstRTSPTransport *tr); void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans, - GstRTSPTransport * ct); + GstRTSPTransport * tr); void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans, GstRTSPSendFunc send_rtp, From 09718e294dd423b3a46a43f740ccad01b6f96997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 28 Oct 2012 15:09:04 +0000 Subject: [PATCH 0465/1776] bindings: remove vala bindings They'll be reunited with the other GStreamer bindings https://bugzilla.gnome.org/show_bug.cgi?id=680777 --- Makefile.am | 1 - bindings/Makefile.am | 5 - bindings/vala/Makefile.am | 13 - bindings/vala/gst-rtsp-server-0.10.deps | 4 - bindings/vala/gst-rtsp-server-0.10.vapi | 292 ------- .../vala/packages/gst-rtsp-server-0.10.deps | 4 - .../vala/packages/gst-rtsp-server-0.10.files | 2 - .../vala/packages/gst-rtsp-server-0.10.gi | 817 ------------------ .../packages/gst-rtsp-server-0.10.metadata | 48 - .../packages/gst-rtsp-server-0.10.namespace | 1 - configure.ac | 15 - 11 files changed, 1202 deletions(-) delete mode 100644 bindings/Makefile.am delete mode 100644 bindings/vala/Makefile.am delete mode 100644 bindings/vala/gst-rtsp-server-0.10.deps delete mode 100644 bindings/vala/gst-rtsp-server-0.10.vapi delete mode 100644 bindings/vala/packages/gst-rtsp-server-0.10.deps delete mode 100644 bindings/vala/packages/gst-rtsp-server-0.10.files delete mode 100644 bindings/vala/packages/gst-rtsp-server-0.10.gi delete mode 100644 bindings/vala/packages/gst-rtsp-server-0.10.metadata delete mode 100644 bindings/vala/packages/gst-rtsp-server-0.10.namespace diff --git a/Makefile.am b/Makefile.am index e923327255..a748dbc3b8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,6 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc SUBDIRS = \ gst \ - bindings \ common \ pkgconfig \ docs \ diff --git a/bindings/Makefile.am b/bindings/Makefile.am deleted file mode 100644 index 7a9ca5ad71..0000000000 --- a/bindings/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -SUBDIRS = - -if WITH_VALA - SUBDIRS += vala -endif diff --git a/bindings/vala/Makefile.am b/bindings/vala/Makefile.am deleted file mode 100644 index acdf20fcaa..0000000000 --- a/bindings/vala/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ - -DEPS_FILES = gst-rtsp-server-0.10.deps -VAPI_FILES = gst-rtsp-server-0.10.vapi - -gst-rtsp-server-0.10.deps: - cp $(srcdir)/packages/gst-rtsp-server-0.10.deps $@ - -vapidir = $(datadir)/vala/vapi -vapi_DATA = $(VAPI_FILES) $(DEPS_FILES) - -EXTRA_DIST = packages $(VAPI_FILES) - -CLEANFILES = $(DEPS_FILES) diff --git a/bindings/vala/gst-rtsp-server-0.10.deps b/bindings/vala/gst-rtsp-server-0.10.deps deleted file mode 100644 index c8d8ea9d63..0000000000 --- a/bindings/vala/gst-rtsp-server-0.10.deps +++ /dev/null @@ -1,4 +0,0 @@ -gstreamer-0.10 -gstreamer-sdp-0.10 -gstreamer-rtsp-0.10 -gmodule-2.0 diff --git a/bindings/vala/gst-rtsp-server-0.10.vapi b/bindings/vala/gst-rtsp-server-0.10.vapi deleted file mode 100644 index d537a96926..0000000000 --- a/bindings/vala/gst-rtsp-server-0.10.vapi +++ /dev/null @@ -1,292 +0,0 @@ -/* gst-rtsp-server-0.10.vapi generated by vapigen, do not modify. */ - -[CCode (cprefix = "Gst", lower_case_cprefix = "gst_")] -namespace Gst { - [CCode (cheader_filename = "gst/rtsp-server/rtsp-client.h")] - public class RTSPClient : GLib.Object { - public weak Gst.RTSPConnection connection; - public bool is_ipv6; - public weak Gst.RTSPMedia media; - public weak string server_ip; - public weak GLib.List sessions; - public weak GLib.List streams; - public weak Gst.RTSPUrl uri; - public weak Gst.RTSPWatch watch; - public uint watchid; - [CCode (has_construct_function = false)] - public RTSPClient (); - public bool accept (GLib.IOChannel channel); - public Gst.RTSPMediaMapping get_media_mapping (); - public Gst.RTSPSessionPool get_session_pool (); - public void set_media_mapping (Gst.RTSPMediaMapping mapping); - public void set_session_pool (Gst.RTSPSessionPool pool); - public Gst.RTSPMediaMapping media_mapping { get; set; } - public Gst.RTSPSessionPool session_pool { get; set; } - } - [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] - public class RTSPMedia : GLib.Object { - public int active; - public bool buffering; - public weak GLib.Cond cond; - public weak GLib.List @dynamic; - public weak Gst.Element element; - public bool eos_pending; - public weak Gst.Element fakesink; - public uint id; - public bool is_ipv6; - public bool is_live; - public weak GLib.Mutex @lock; - public Gst.Element pipeline; - public weak Gst.RTSPTimeRange range; - public bool reused; - public weak Gst.Element rtpbin; - public weak GLib.TimeoutSource source; - public Gst.RTSPMediaStatus status; - public weak GLib.Array streams; - public Gst.State target_state; - [CCode (has_construct_function = false)] - public RTSPMedia (); - public Gst.RTSPLowerTrans get_protocols (); - public unowned Gst.RTSPMediaStream get_stream (uint idx); - [NoWrapper] - public virtual bool handle_message (Gst.Message message); - public bool is_eos_shutdown (); - public bool is_prepared (); - public bool is_reusable (); - public bool is_shared (); - public uint n_streams (); - public bool prepare (); - public void remove_elements (); - public bool seek (Gst.RTSPTimeRange range); - public void set_eos_shutdown (bool eos_shutdown); - public void set_protocols (Gst.RTSPLowerTrans protocols); - public void set_reusable (bool reusable); - public void set_shared (bool shared); - public bool set_state (Gst.State state, GLib.Array trans); - public virtual bool unprepare (); - [NoAccessorMethod] - public bool eos_shutdown { get; set; } - public Gst.RTSPLowerTrans protocols { get; set; } - [NoAccessorMethod] - public bool reusable { get; set; } - [NoAccessorMethod] - public bool shared { get; set; } - public virtual signal void unprepared (); - } - [CCode (cheader_filename = "gst/rtsp-server/rtsp-media-factory.h")] - public class RTSPMediaFactory : GLib.Object { - public weak GLib.Mutex @lock; - public weak GLib.HashTable medias; - public weak GLib.Mutex medias_lock; - [CCode (has_construct_function = false)] - public RTSPMediaFactory (); - public void collect_streams (Gst.RTSPUrl url, Gst.RTSPMedia media); - [NoWrapper] - public virtual void configure (Gst.RTSPMedia media); - public virtual Gst.RTSPMedia? @construct (Gst.RTSPUrl url); - [NoWrapper] - public virtual Gst.Element create_pipeline (Gst.RTSPMedia media); - [NoWrapper] - public virtual string gen_key (Gst.RTSPUrl url); - [NoWrapper] - public virtual Gst.Element? get_element (Gst.RTSPUrl url); - public string get_launch (); - public bool is_eos_shutdown (); - public bool is_shared (); - public void set_eos_shutdown (bool eos_shutdown); - public void set_launch (string launch); - public void set_shared (bool shared); - [NoAccessorMethod] - public bool eos_shutdown { get; set; } - public string launch { get; set; } - [NoAccessorMethod] - public bool shared { get; set; } - } - [CCode (cheader_filename = "gst/rtsp-server/rtsp-media-mapping.h")] - public class RTSPMediaMapping : GLib.Object { - public weak GLib.HashTable mappings; - [CCode (has_construct_function = false)] - public RTSPMediaMapping (); - public void add_factory (string path, Gst.RTSPMediaFactory factory); - public Gst.RTSPMediaFactory? find_factory (Gst.RTSPUrl url); - [NoWrapper] - public virtual Gst.RTSPMediaFactory? find_media (Gst.RTSPUrl url); - public void remove_factory (string path); - } - [Compact] - [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] - public class RTSPMediaStream { - [CCode (array_length = false)] - public weak Gst.Element[] appsink; - [CCode (array_length = false)] - public weak Gst.Element[] appsrc; - public weak Gst.Caps caps; - public ulong caps_sig; - public weak GLib.List destinations; - public bool filter_duplicates; - public weak Gst.Element payloader; - public bool prepared; - public weak Gst.Pad recv_rtcp_sink; - public weak Gst.Pad recv_rtp_sink; - [CCode (array_length = false)] - public weak Gst.Element[] selector; - public weak Gst.Pad send_rtcp_src; - public weak Gst.Pad send_rtp_sink; - public weak Gst.Pad send_rtp_src; - public weak Gst.RTSPRange server_port; - public weak GLib.Object session; - public weak Gst.Pad srcpad; - [CCode (array_length = false)] - public weak Gst.Element[] tee; - public weak GLib.List transports; - [CCode (array_length = false)] - public weak Gst.Element[] udpsink; - [CCode (array_length = false)] - public weak Gst.Element[] udpsrc; - public Gst.FlowReturn rtcp (Gst.Buffer buffer); - public Gst.FlowReturn rtp (Gst.Buffer buffer); - } - [Compact] - [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] - public class RTSPMediaTrans { - public bool active; - public uint idx; - public weak GLib.DestroyNotify ka_notify; - public void* ka_user_data; - public weak Gst.RTSPKeepAliveFunc keep_alive; - public weak GLib.DestroyNotify notify; - public weak GLib.Object rtpsource; - public weak Gst.RTSPSendFunc send_rtcp; - public weak Gst.RTSPSendFunc send_rtp; - public bool timeout; - public weak Gst.RTSPTransport transport; - public void* user_data; - public void cleanup (); - } - [CCode (cheader_filename = "gst/rtsp-server/rtsp-server.h")] - public class RTSPServer : GLib.Object { - public signal void client_connected (RTSPClient client); - public weak GLib.IOChannel io_channel; - public weak GLib.TimeoutSource io_watch; - public void* server_sin; - public Gst.PollFD server_sock; - [CCode (has_construct_function = false)] - public RTSPServer (); - [NoWrapper] - public virtual Gst.RTSPClient? accept_client (GLib.IOChannel channel); - public uint attach (GLib.MainContext? context); - public GLib.TimeoutSource? create_watch (); - public string get_address (); - public int get_backlog (); - public GLib.IOChannel? get_io_channel (); - public Gst.RTSPMediaMapping get_media_mapping (); - public string get_service (); - public Gst.RTSPSessionPool get_session_pool (); - public static bool io_func (GLib.IOChannel channel, GLib.IOCondition condition, Gst.RTSPServer server); - public void set_address (string address); - public void set_backlog (int backlog); - public void set_media_mapping (Gst.RTSPMediaMapping mapping); - public void set_service (string service); - public void set_session_pool (Gst.RTSPSessionPool pool); - public string address { get; set; } - public int backlog { get; set; } - public Gst.RTSPMediaMapping media_mapping { get; set; } - public string service { get; set; } - public Gst.RTSPSessionPool session_pool { get; set; } - } - [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] - public class RTSPSession : GLib.Object { - public GLib.TimeVal create_time; - public int expire_count; - public GLib.TimeVal last_access; - public weak GLib.List medias; - [CCode (has_construct_function = false)] - public RTSPSession (string sessionid); - public void allow_expire (); - public unowned Gst.RTSPSessionMedia get_media (Gst.RTSPUrl uri); - public unowned string get_sessionid (); - public uint get_timeout (); - public bool is_expired (GLib.TimeVal now); - public unowned Gst.RTSPSessionMedia manage_media (Gst.RTSPUrl uri, owned Gst.RTSPMedia media); - public int next_timeout (GLib.TimeVal now); - public void prevent_expire (); - public bool release_media (Gst.RTSPSessionMedia media); - public void set_timeout (uint timeout); - public void touch (); - public string sessionid { get; construct; } - public uint timeout { get; set; } - } - [Compact] - [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] - public class RTSPSessionMedia { - public uint counter; - public weak Gst.RTSPMedia media; - public Gst.RTSPState state; - public weak GLib.Array streams; - public weak Gst.RTSPUrl url; - public bool alloc_channels (Gst.RTSPRange range); - public unowned Gst.RTSPSessionStream get_stream (uint idx); - public bool set_state (Gst.State state); - } - [CCode (cheader_filename = "gst/rtsp-server/rtsp-session-pool.h")] - public class RTSPSessionPool : GLib.Object { - public weak GLib.Mutex @lock; - public weak GLib.HashTable sessions; - [CCode (has_construct_function = false)] - public RTSPSessionPool (); - public uint cleanup (); - public Gst.RTSPSession create (); - [NoWrapper] - public virtual string create_session_id (); - public GLib.TimeoutSource create_watch (); - public GLib.List filter (Gst.RTSPSessionFilterFunc func); - public Gst.RTSPSession? find (string sessionid); - public uint get_max_sessions (); - public uint get_n_sessions (); - public bool remove (Gst.RTSPSession sess); - public void set_max_sessions (uint max); - public uint max_sessions { get; set; } - } - [Compact] - [CCode (cheader_filename = "gst/rtsp-server/rtsp-session.h")] - public class RTSPSessionStream { - public weak Gst.RTSPMediaStream media_stream; - public weak Gst.RTSPMediaTrans trans; - public void set_callbacks (Gst.RTSPSendFunc send_rtp, Gst.RTSPSendFunc send_rtcp, GLib.DestroyNotify notify); - public void set_keepalive (Gst.RTSPKeepAliveFunc keep_alive, GLib.DestroyNotify notify); - public Gst.RTSPTransport set_transport (Gst.RTSPTransport ct); - } - [Compact] - [CCode (cheader_filename = "gst/rtsp-server/rtsp-sdp.h")] - public class SDPInfo { - public weak string server_ip; - public weak string server_proto; - } - [CCode (cprefix = "GST_RTSP_FILTER_", has_type_id = false, cheader_filename = "gst/rtsp-server/rtsp-session-pool.h")] - public enum RTSPFilterResult { - REMOVE, - KEEP, - REF - } - [CCode (cprefix = "GST_RTSP_MEDIA_STATUS_", has_type_id = false, cheader_filename = "gst/rtsp-server/rtsp-media.h")] - public enum RTSPMediaStatus { - UNPREPARED, - PREPARING, - PREPARED, - ERROR - } - [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] - public delegate void RTSPKeepAliveFunc (); - [CCode (cheader_filename = "gst/rtsp-server/rtsp-media.h")] - public delegate bool RTSPSendFunc (Gst.Buffer buffer, uchar channel); - [CCode (cheader_filename = "gst/rtsp-server/rtsp-session-pool.h")] - public delegate Gst.RTSPFilterResult RTSPSessionFilterFunc (Gst.RTSPSessionPool pool, Gst.RTSPSession session); - [CCode (cheader_filename = "gst/rtsp-server/rtsp-session-pool.h")] - public delegate bool RTSPSessionPoolFunc (Gst.RTSPSessionPool pool); - [CCode (cheader_filename = "gst/gst.h")] - public static Gst.RTSPResult rtsp_params_get (Gst.RTSPClient client, Gst.RTSPUrl uri, Gst.RTSPSession session, Gst.RTSPMessage request, Gst.RTSPMessage response); - [CCode (cheader_filename = "gst/gst.h")] - public static Gst.RTSPResult rtsp_params_set (Gst.RTSPClient client, Gst.RTSPUrl uri, Gst.RTSPSession session, Gst.RTSPMessage request, Gst.RTSPMessage response); - [CCode (cheader_filename = "gst/rtsp-server/rtsp-sdp.h")] - public static bool rtsp_sdp_from_media (ref unowned Gst.SDPMessage sdp, Gst.SDPInfo info, Gst.RTSPMedia media); -} diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.deps b/bindings/vala/packages/gst-rtsp-server-0.10.deps deleted file mode 100644 index c8d8ea9d63..0000000000 --- a/bindings/vala/packages/gst-rtsp-server-0.10.deps +++ /dev/null @@ -1,4 +0,0 @@ -gstreamer-0.10 -gstreamer-sdp-0.10 -gstreamer-rtsp-0.10 -gmodule-2.0 diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.files b/bindings/vala/packages/gst-rtsp-server-0.10.files deleted file mode 100644 index f7e4d23730..0000000000 --- a/bindings/vala/packages/gst-rtsp-server-0.10.files +++ /dev/null @@ -1,2 +0,0 @@ -include/gstreamer-0.10/gst/rtsp-server -lib/libgstrtspserver-0.10.so diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.gi b/bindings/vala/packages/gst-rtsp-server-0.10.gi deleted file mode 100644 index 8933d3bae0..0000000000 --- a/bindings/vala/packages/gst-rtsp-server-0.10.gi +++ /dev/null @@ -1,817 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.metadata b/bindings/vala/packages/gst-rtsp-server-0.10.metadata deleted file mode 100644 index a69c2ed53e..0000000000 --- a/bindings/vala/packages/gst-rtsp-server-0.10.metadata +++ /dev/null @@ -1,48 +0,0 @@ -Gst cprefix="Gst" lower_case_cprefix="gst_" cheader_filename="gst/gst.h" -GstRTSPClient cheader_filename="gst/rtsp-server/rtsp-client.h" -GstRTSPMedia cheader_filename="gst/rtsp-server/rtsp-media.h" -GstRTSPMediaTrans cheader_filename="gst/rtsp-server/rtsp-media.h" -GstRTSPMediaFactory cheader_filename="gst/rtsp-server/rtsp-media-factory.h" -GstRTSPMediaMapping cheader_filename="gst/rtsp-server/rtsp-media-mapping.h" -GstRTSPMediaStatus cheader_filename="gst/rtsp-server/rtsp-media.h" -GstRTSPMediaStream cheader_filename="gst/rtsp-server/rtsp-media.h" -GstRTSPServer cheader_filename="gst/rtsp-server/rtsp-server.h" -GstRTSPSession cheader_filename="gst/rtsp-server/rtsp-session.h" -GstRTSPSessionMedia cheader_filename="gst/rtsp-server/rtsp-session.h" -GstRTSPSessionPool cheader_filename="gst/rtsp-server/rtsp-session-pool.h" -GstRTSPSessionStream cheader_filename="gst/rtsp-server/rtsp-session.h" -GstRTSPSessionFilterFunc cheader_filename="gst/rtsp-server/rtsp-session-pool.h" -GstRTSPSessionPoolFunc cheader_filename="gst/rtsp-server/rtsp-session-pool.h" -GstSDPInfo cheader_filename="gst/rtsp-server/rtsp-sdp.h" -GstRTSPFilterResult cheader_filename="gst/rtsp-server/rtsp-session-pool.h" -GstRTSPKeepAliveFunc cheader_filename="gst/rtsp-server/rtsp-media.h" -GstRTSPSendFunc cheader_filename="gst/rtsp-server/rtsp-media.h" -gst_rtsp_sdp_from_media cheader_filename="gst/rtsp-server/rtsp-sdp.h" -gst_rtsp_client_get_media_mapping transfer_ownership="1" -gst_rtsp_client_get_session_pool transfer_ownership="1" -gst_rtsp_media_factory_get_launch transfer_ownership="1" -gst_rtsp_media_factory_construct transfer_ownership="1" nullable="1" -gst_rtsp_media_factory_gen_key transfer_ownership="1" -gst_rtsp_media_factory_get_element transfer_ownership="1" nullable="1" -gst_rtsp_media_factory_create_pipeline transfer_ownership="1" -gst_rtsp_media_mapping_find_factory transfer_ownership="1" nullable="1" -gst_rtsp_media_mapping_find_media transfer_ownership="1" nullable="1" -gst_rtsp_media_mapping_add_factory transfer_ownership="1" -gst_rtsp_sdp_from_media.sdp is_ref="1" -gst_rtsp_server_accept_client transfer_ownership="1" nullable="1" -gst_rtsp_server_create_watch transfer_ownership="1" nullable="1" -gst_rtsp_server_get_address transfer_ownership="1" -gst_rtsp_server_get_io_channel transfer_ownership="1" nullable="1" -gst_rtsp_server_get_media_mapping transfer_ownership="1" -gst_rtsp_server_get_service transfer_ownership="1" -gst_rtsp_server_get_session_pool transfer_ownership="1" -gst_rtsp_server_get_service transfer_ownership="1" -gst_rtsp_server_attach.context nullable="1" -gst_rtsp_session_manage_media.media takes_ownership="1" -gst_rtsp_session_pool_create transfer_ownership="1" -gst_rtsp_session_pool_create_session_id transfer_ownership="1" -gst_rtsp_session_pool_create_watch transfer_ownership="1" -gst_rtsp_session_pool_find transfer_ownership="1" nullable="1" -gst_rtsp_session_pool_filter transfer_ownership="1" type_arguments="RTSPSession" -gst_rtsp_session_stream_set_transport transfer_ownership="1" -GstRTSPMedia.pipeline weak="0" diff --git a/bindings/vala/packages/gst-rtsp-server-0.10.namespace b/bindings/vala/packages/gst-rtsp-server-0.10.namespace deleted file mode 100644 index 100750e4d7..0000000000 --- a/bindings/vala/packages/gst-rtsp-server-0.10.namespace +++ /dev/null @@ -1 +0,0 @@ -Gst diff --git a/configure.ac b/configure.ac index e3f5b4b236..df0e04842b 100644 --- a/configure.ac +++ b/configure.ac @@ -91,18 +91,6 @@ dnl check for documentation tools AG_GST_DOCBOOK_CHECK GTK_DOC_CHECK([1.3]) -dnl Check for Vala -AC_ARG_ENABLE([vala], - AC_HELP_STRING([--enable-vala],[enable Vala bindings (default=yes)]), - [case "${enableval}" in - yes) enable_vala=yes ;; - no) enable_vala=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-vala) ;; - esac - ], - [enable_vala=yes]) dnl Default value -AM_CONDITIONAL(WITH_VALA, [test "x$enable_vala" = "xyes"]) - dnl *** checks for libraries *** dnl *** checks for header files *** @@ -257,8 +245,6 @@ gst/rtsp-server/Makefile examples/Makefile tests/Makefile tests/check/Makefile -bindings/Makefile -bindings/vala/Makefile pkgconfig/Makefile pkgconfig/gstreamer-rtsp-server.pc pkgconfig/gstreamer-rtsp-server-uninstalled.pc @@ -275,7 +261,6 @@ Configuration Source code location : ${srcdir} Prefix : ${prefix} Compiler : ${CC} - Vala bindings : ${enable_vala} gst-rtsp-server configured. Type 'make' to build. " From 9499be62322fbf16b581e3fa5f373bd9d0cd6acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 28 Oct 2012 15:37:51 +0000 Subject: [PATCH 0466/1776] No need to define GST_USE_UNSTABLE_API any more, 1.0 is stable now --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index df0e04842b..e832a866fd 100644 --- a/configure.ac +++ b/configure.ac @@ -193,7 +193,7 @@ AC_SUBST(GST_OPTION_CFLAGS) dnl FIXME: do we want to rename to GST_ALL_* ? dnl prefer internal headers to already installed ones dnl add GST_OPTION_CFLAGS, but overridable -GST_CFLAGS="$GST_CFLAGS -DGST_USE_UNSTABLE_API \$(GST_OPTION_CFLAGS)" +GST_CFLAGS="$GST_CFLAGS \$(GST_OPTION_CFLAGS)" AC_SUBST(GST_CFLAGS) AC_SUBST(GST_LIBS) From 75598337a90ad7dd390e81063d62c464e52ec56e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Sun, 28 Oct 2012 13:48:44 +0100 Subject: [PATCH 0467/1776] rtsp-server: added annotations to indicate type of ownership transfer of return values https://bugzilla.gnome.org/show_bug.cgi?id=680777 --- gst/rtsp-server/rtsp-media.c | 4 ++-- gst/rtsp-server/rtsp-session-media.c | 6 +++--- gst/rtsp-server/rtsp-session.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e7328c0afe..ddad38d264 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -690,7 +690,7 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) * Create a new stream in @media that provides RTP data on @srcpad. * @srcpad should be a pad of an element inside @media->element. * - * Returns: a new #GstRTSPStream that remains valid for as long + * Returns: (transfer none): a new #GstRTSPStream that remains valid for as long * as @media exists. */ GstRTSPStream * @@ -747,7 +747,7 @@ gst_rtsp_media_n_streams (GstRTSPMedia * media) * * Retrieve the stream with index @idx from @media. * - * Returns: the #GstRTSPStream at index @idx or %NULL when a stream with + * Returns: (transfer none): the #GstRTSPStream at index @idx or %NULL when a stream with * that index did not exist. */ GstRTSPStream * diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 7b100a6af8..c8b08d6a0f 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -124,7 +124,7 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media) * * Configure the transport for @stream to @tr in @media. * - * Returns: the new or updated #GstRTSPStreamTransport for @stream. + * Returns: (transfer none): the new or updated #GstRTSPStreamTransport for @stream. */ GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, @@ -153,8 +153,8 @@ gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, * * Get a previously created #GstRTSPStreamTransport for the stream at @idx. * - * Returns: a #GstRTSPStreamTransport that is valid until the session of @media - * is unreffed. + * Returns: (transfer none): a #GstRTSPStreamTransport that is valid until the + * session of @media is unreffed. */ GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 58abc4bc8f..1c810915e2 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -142,7 +142,7 @@ gst_rtsp_session_set_property (GObject * object, guint propid, * * Ownership is taken from @media. * - * Returns: a new @GstRTSPSessionMedia object. + * Returns: (transfer none): a new @GstRTSPSessionMedia object. */ GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession * sess, const GstRTSPUrl * uri, @@ -197,7 +197,7 @@ gst_rtsp_session_release_media (GstRTSPSession * sess, * * Get the session media of the @url. * - * Returns: the configuration for @url in @sess. + * Returns: (transfer none): the configuration for @url in @sess. */ GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession * sess, const GstRTSPUrl * url) From 4dba434f1623c0d00cc99e7fbd0a54eebd923c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 4 Nov 2012 00:14:25 +0000 Subject: [PATCH 0468/1776] Fix FSF address --- COPYING | 4 ++-- COPYING.LIB | 4 ++-- examples/test-auth.c | 4 ++-- examples/test-launch.c | 4 ++-- examples/test-mp4.c | 4 ++-- examples/test-ogg.c | 4 ++-- examples/test-readme.c | 4 ++-- examples/test-sdp.c | 4 ++-- examples/test-uri.c | 4 ++-- examples/test-video.c | 4 ++-- gst/rtsp-server/rtsp-auth.c | 4 ++-- gst/rtsp-server/rtsp-auth.h | 4 ++-- gst/rtsp-server/rtsp-client.c | 4 ++-- gst/rtsp-server/rtsp-client.h | 4 ++-- gst/rtsp-server/rtsp-media-factory-uri.c | 4 ++-- gst/rtsp-server/rtsp-media-factory-uri.h | 4 ++-- gst/rtsp-server/rtsp-media-factory.c | 4 ++-- gst/rtsp-server/rtsp-media-factory.h | 4 ++-- gst/rtsp-server/rtsp-media-mapping.c | 4 ++-- gst/rtsp-server/rtsp-media-mapping.h | 4 ++-- gst/rtsp-server/rtsp-media.c | 4 ++-- gst/rtsp-server/rtsp-media.h | 4 ++-- gst/rtsp-server/rtsp-params.c | 4 ++-- gst/rtsp-server/rtsp-params.h | 4 ++-- gst/rtsp-server/rtsp-sdp.c | 4 ++-- gst/rtsp-server/rtsp-sdp.h | 4 ++-- gst/rtsp-server/rtsp-server.c | 4 ++-- gst/rtsp-server/rtsp-server.h | 4 ++-- gst/rtsp-server/rtsp-session-media.c | 4 ++-- gst/rtsp-server/rtsp-session-media.h | 4 ++-- gst/rtsp-server/rtsp-session-pool.c | 4 ++-- gst/rtsp-server/rtsp-session-pool.h | 4 ++-- gst/rtsp-server/rtsp-session.c | 4 ++-- gst/rtsp-server/rtsp-session.h | 4 ++-- gst/rtsp-server/rtsp-stream-transport.c | 4 ++-- gst/rtsp-server/rtsp-stream-transport.h | 4 ++-- gst/rtsp-server/rtsp-stream.c | 4 ++-- gst/rtsp-server/rtsp-stream.h | 4 ++-- tests/check/gst/rtspserver.c | 4 ++-- tests/test-cleanup.c | 4 ++-- 40 files changed, 80 insertions(+), 80 deletions(-) diff --git a/COPYING b/COPYING index eb685a5ec9..c87cfe8c99 100644 --- a/COPYING +++ b/COPYING @@ -2,7 +2,7 @@ Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + 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. @@ -464,7 +464,7 @@ convey the exclusion of warranty; and each file should have at least the You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + 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. diff --git a/COPYING.LIB b/COPYING.LIB index eb685a5ec9..c87cfe8c99 100644 --- a/COPYING.LIB +++ b/COPYING.LIB @@ -2,7 +2,7 @@ Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + 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. @@ -464,7 +464,7 @@ convey the exclusion of warranty; and each file should have at least the You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + 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. diff --git a/examples/test-auth.c b/examples/test-auth.c index 5cba45bff9..eeb61fdf5c 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/examples/test-launch.c b/examples/test-launch.c index 2a2242d22c..407e576a83 100644 --- a/examples/test-launch.c +++ b/examples/test-launch.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/examples/test-mp4.c b/examples/test-mp4.c index 8593da4c6c..b2e96600e7 100644 --- a/examples/test-mp4.c +++ b/examples/test-mp4.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/examples/test-ogg.c b/examples/test-ogg.c index 555bc7fc7e..d7f2d2d195 100644 --- a/examples/test-ogg.c +++ b/examples/test-ogg.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/examples/test-readme.c b/examples/test-readme.c index bbe8b14488..0d2bcd7680 100644 --- a/examples/test-readme.c +++ b/examples/test-readme.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/examples/test-sdp.c b/examples/test-sdp.c index 416e9ac94c..b5508e44e5 100644 --- a/examples/test-sdp.c +++ b/examples/test-sdp.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/examples/test-uri.c b/examples/test-uri.c index db610dd42c..d738b33107 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/examples/test-video.c b/examples/test-video.c index b2536cb725..ab5ce9db31 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 0da47f16b4..153b46caea 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 5f06acbde7..5e1e696d53 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f6483332ce..b0a6d9002b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index a896ea6993..4ca95fa345 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 620b53e03e..91f0193bc5 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-media-factory-uri.h b/gst/rtsp-server/rtsp-media-factory-uri.h index fcc2dd501d..da71aa78bc 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.h +++ b/gst/rtsp-server/rtsp-media-factory-uri.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index fb7af92dcc..3db7a417bf 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include "rtsp-media-factory.h" diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 7a80fe0607..167dcd5061 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c index 634439441f..1a8682e757 100644 --- a/gst/rtsp-server/rtsp-media-mapping.c +++ b/gst/rtsp-server/rtsp-media-mapping.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include "rtsp-media-mapping.h" diff --git a/gst/rtsp-server/rtsp-media-mapping.h b/gst/rtsp-server/rtsp-media-mapping.h index 1f3e120245..b754920340 100644 --- a/gst/rtsp-server/rtsp-media-mapping.h +++ b/gst/rtsp-server/rtsp-media-mapping.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index ddad38d264..352a045bdb 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index b7ba346b57..9a99f99d1f 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-params.c b/gst/rtsp-server/rtsp-params.c index a5d46b37c6..be45e0fc66 100644 --- a/gst/rtsp-server/rtsp-params.c +++ b/gst/rtsp-server/rtsp-params.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-params.h b/gst/rtsp-server/rtsp-params.h index 3b0d001bc3..93fb95991b 100644 --- a/gst/rtsp-server/rtsp-params.h +++ b/gst/rtsp-server/rtsp-params.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index cfbe6f9fe0..14ba38e3a0 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h index e6ac1b28cd..e5f3fd3518 100644 --- a/gst/rtsp-server/rtsp-sdp.h +++ b/gst/rtsp-server/rtsp-sdp.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 1b4bbf6b77..6e6cacffc8 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 83277e0d09..d3500b96b6 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #ifndef __GST_RTSP_SERVER_H__ diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index c8b08d6a0f..8e7deddf12 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 45e1bb2759..845a5fbe6c 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 24d788bd23..38f1519e5c 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include "rtsp-session-pool.h" diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 645dab37ea..d60167e882 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 1c810915e2..6b93bee183 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index b6236dc8e2..ced2251dee 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index c8ef8b0e12..3db5c39350 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index eec7c04480..cbc82555bb 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index a6dccce114..be262d1ab6 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index d5fb03d9b3..36d476774a 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 3aec449927..805f3c935b 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -17,8 +17,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include diff --git a/tests/test-cleanup.c b/tests/test-cleanup.c index 13dba5c77f..3b6f7f6954 100644 --- a/tests/test-cleanup.c +++ b/tests/test-cleanup.c @@ -13,8 +13,8 @@ * * You should 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include From 5b4340067a0bc29d8efdded823064ccdf54c3257 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 12:40:34 +0100 Subject: [PATCH 0469/1776] session: move session header code in session object --- gst/rtsp-server/rtsp-client.c | 12 ++---------- gst/rtsp-server/rtsp-session.c | 24 ++++++++++++++++++++++++ gst/rtsp-server/rtsp-session.h | 2 ++ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b0a6d9002b..3f1efa871c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -310,16 +310,8 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, /* add the new session header for new session ids */ if (session) { - gchar *str; - - if (session->timeout != 60) - str = - g_strdup_printf ("%s; timeout=%d", session->sessionid, - session->timeout); - else - str = g_strdup (session->sessionid); - - gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION, str); + gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION, + gst_rtsp_session_get_header (session)); } if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) { diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 6b93bee183..a6a24096da 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -256,6 +256,30 @@ gst_rtsp_session_get_sessionid (GstRTSPSession * session) return session->sessionid; } +/** + * gst_rtsp_session_get_header: + * @session: a #GstRTSPSession + * + * Get the string that can be placed in the Session header field. + * + * Returns: (transfer full): the Session header of @session. g_free() after usage. + */ +gchar * +gst_rtsp_session_get_header (GstRTSPSession * session) +{ + gchar *result; + + g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL); + + if (session->timeout != 60) + result = g_strdup_printf ("%s; timeout=%d", session->sessionid, + session->timeout); + else + result = g_strdup (session->sessionid); + + return result; +} + /** * gst_rtsp_session_set_timeout: * @session: a #GstRTSPSession diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index ced2251dee..efac74ce0b 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -79,6 +79,8 @@ GstRTSPSession * gst_rtsp_session_new (const gchar *sessi const gchar * gst_rtsp_session_get_sessionid (GstRTSPSession *session); +gchar * gst_rtsp_session_get_header (GstRTSPSession *session); + void gst_rtsp_session_set_timeout (GstRTSPSession *session, guint timeout); guint gst_rtsp_session_get_timeout (GstRTSPSession *session); From a58d404e1f703d89c31cd950b921b71ca99ee322 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 14:09:09 +0100 Subject: [PATCH 0470/1776] server: rework maincontext handling in clients Make a separate method to attach a client to a MainContext. Let the server decide in what GMainContext the client will operate and give this context to the client in attach. Then the server can later decide to use a separate thread for each client or just use the mainthread. --- gst/rtsp-server/rtsp-client.c | 68 +++++++++++++++----------- gst/rtsp-server/rtsp-client.h | 6 ++- gst/rtsp-server/rtsp-server.c | 91 ++++++++++++++++++++++++++++++----- 3 files changed, 123 insertions(+), 42 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3f1efa871c..bcf8b89dfd 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -214,7 +214,7 @@ gst_rtsp_client_finalize (GObject * obj) GST_INFO ("finalize client %p", client); - if (client->watchid) + if (client->watch) g_source_destroy ((GSource *) client->watch); client_cleanup_sessions (client); @@ -2081,20 +2081,17 @@ static void client_watch_notify (GstRTSPClient * client) { GST_INFO ("client %p: watch destroyed", client); - client->watchid = 0; client->watch = NULL; g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL); g_object_unref (client); } static gboolean -attach_client (GstRTSPClient * client, GSocket * socket, +setup_client (GstRTSPClient * client, GSocket * socket, GstRTSPConnection * conn, GError ** error) { GSocket *read_socket; GSocketAddress *address; - GSource *source; - GMainContext *context; GstRTSPUrl *url; read_socket = gst_rtsp_connection_get_read_socket (conn); @@ -2124,21 +2121,6 @@ attach_client (GstRTSPClient * client, GSocket * socket, client->connection = conn; - /* create watch for the connection and attach */ - client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs, - g_object_ref (client), (GDestroyNotify) client_watch_notify); - - /* find the context to add the watch */ - if ((source = g_main_current_source ())) - context = g_source_get_context (source); - else - context = NULL; - - GST_INFO ("attaching to context %p", context); - - client->watchid = gst_rtsp_watch_attach (client->watch, context); - gst_rtsp_watch_unref (client->watch); - return TRUE; /* ERRORS */ @@ -2155,7 +2137,8 @@ no_address: * @socket: a #GSocket * @ip: the IP address of the remote client * @port: the port used by the other end - * @initial_buffer: any initial data that was already read from the socket + * @initial_buffer: any zero terminated initial data that was already read from + * the socket * @error: a #GError * * Take an existing network socket and use it for an RTSP connection. @@ -2163,7 +2146,7 @@ no_address: * Returns: %TRUE on success. */ gboolean -gst_rtsp_client_create_from_socket (GstRTSPClient * client, GSocket * socket, +gst_rtsp_client_use_socket (GstRTSPClient * client, GSocket * socket, const gchar * ip, gint port, const gchar * initial_buffer, GError ** error) { GstRTSPConnection *conn; @@ -2172,7 +2155,7 @@ gst_rtsp_client_create_from_socket (GstRTSPClient * client, GSocket * socket, GST_RTSP_CHECK (gst_rtsp_connection_create_from_socket (socket, ip, port, initial_buffer, &conn), no_connection); - return attach_client (client, socket, conn, error); + return setup_client (client, socket, conn, error); /* ERRORS */ no_connection: @@ -2189,14 +2172,12 @@ no_connection: * gst_rtsp_client_accept: * @client: a #GstRTSPClient * @socket: a #GSocket + * @context: the context to run in * @cancellable: a #GCancellable * @error: a #GError * * Accept a new connection for @client on @socket. * - * This function should be called when the client properties and urls are fully - * configured and the client is ready to start. - * * Returns: %TRUE if the client could be accepted. */ gboolean @@ -2210,7 +2191,7 @@ gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, cancellable), accept_failed); - return attach_client (client, socket, conn, error); + return setup_client (client, socket, conn, error); /* ERRORS */ accept_failed: @@ -2222,3 +2203,36 @@ accept_failed: return FALSE; } } + +/** + * gst_rtsp_client_attach: + * @client: a #GstRTSPClient + * @context: (allow-none): a #GMainContext + * + * Attaches @client to @context. When the mainloop for @context is run, the + * client will be dispatched. When @context is NULL, the default context will be + * used). + * + * This function should be called when the client properties and urls are fully + * configured and the client is ready to start. + * + * Returns: the ID (greater than 0) for the source within the GMainContext. + */ +guint +gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) +{ + guint res; + + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0); + g_return_val_if_fail (client->watch == NULL, 0); + + /* create watch for the connection and attach */ + client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs, + g_object_ref (client), (GDestroyNotify) client_watch_notify); + + GST_INFO ("attaching to context %p", context); + res = gst_rtsp_watch_attach (client->watch, context); + gst_rtsp_watch_unref (client->watch); + + return res; +} diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 4ca95fa345..80c6dc8a0c 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -77,7 +77,6 @@ struct _GstRTSPClientState { * * @connection: the connection object handling the client request. * @watch: watch for the connection - * @watchid: id of the watch * @ip: ip address used by the client to connect to us * @use_client_settings: whether to allow client transport settings for multicast * @session_pool: handle to the session pool used by the client. @@ -94,7 +93,6 @@ struct _GstRTSPClient { GstRTSPConnection *connection; GstRTSPWatch *watch; - guint watchid; gchar *server_ip; gboolean is_ipv6; gboolean use_client_settings; @@ -164,6 +162,10 @@ gboolean gst_rtsp_client_create_from_socket(GstRTSPClient * client, const gchar *initial_buffer, GError **error); +guint gst_rtsp_client_attach (GstRTSPClient *client, + GMainContext *context); + + G_END_DECLS #endif /* __GST_RTSP_CLIENT_H__ */ diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 6e6cacffc8..25f3666feb 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -749,34 +749,99 @@ close_error: } } -static void -unmanage_client (GstRTSPClient * client, GstRTSPServer * server) +typedef struct { + GstRTSPServer *server; + GMainLoop *loop; + GMainContext *context; + GstRTSPClient *client; +} ClientContext; + +static void +free_client_context (ClientContext * ctx) +{ + g_main_context_unref (ctx->context); + if (ctx->loop) + g_main_loop_unref (ctx->loop); + g_object_unref (ctx->client); + g_slice_free (ClientContext, ctx); +} + +static gpointer +do_loop (ClientContext * ctx) +{ + GST_INFO ("enter mainloop"); + g_main_loop_run (ctx->loop); + GST_INFO ("exit mainloop"); + + free_client_context (ctx); + + return NULL; +} + +static void +unmanage_client (GstRTSPClient * client, ClientContext * ctx) +{ + GstRTSPServer *server = ctx->server; + GST_DEBUG_OBJECT (server, "unmanage client %p", client); g_object_ref (server); gst_rtsp_client_set_server (client, NULL); GST_RTSP_SERVER_LOCK (server); - server->clients = g_list_remove (server->clients, client); + server->clients = g_list_remove (server->clients, ctx); GST_RTSP_SERVER_UNLOCK (server); - g_object_unref (server); - g_object_unref (client); + if (ctx->loop) + g_main_loop_quit (ctx->loop); + else + free_client_context (ctx); + + g_object_unref (server); } -/* add the client to the active list of clients, takes ownership of - * the client */ +/* add the client context to the active list of clients, takes ownership + * of client */ static void manage_client (GstRTSPServer * server, GstRTSPClient * client) { + ClientContext *ctx; + GST_DEBUG_OBJECT (server, "manage client %p", client); gst_rtsp_client_set_server (client, server); + ctx = g_slice_new0 (ClientContext); + ctx->server = server; + ctx->client = client; +#if 1 + { + GSource *source; + + /* find the context to add the watch */ + if ((source = g_main_current_source ())) + ctx->context = g_main_context_ref (g_source_get_context (source)); + else + ctx->context = NULL; + } +#else + ctx->context = g_main_context_new (); + ctx->loop = g_main_loop_new (ctx->context, TRUE); + ctx->dothread = TRUE; +#endif + gst_rtsp_client_attach (client, ctx->context); + GST_RTSP_SERVER_LOCK (server); - g_signal_connect (client, "closed", (GCallback) unmanage_client, server); - server->clients = g_list_prepend (server->clients, client); + g_signal_connect (client, "closed", (GCallback) unmanage_client, ctx); + server->clients = g_list_prepend (server->clients, ctx); GST_RTSP_SERVER_UNLOCK (server); + + if (ctx->loop) { + GThread *thread; + + thread = g_thread_new ("MainLoop Thread", (GThreadFunc) do_loop, ctx); + g_thread_unref (thread); + } } static GstRTSPClient * @@ -853,8 +918,8 @@ gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket * socket, goto client_failed; /* a new client connected, create a client object to handle the client. */ - if (!gst_rtsp_client_create_from_socket (client, socket, ip, port, - initial_buffer, &error)) { + if (!gst_rtsp_client_use_socket (client, socket, ip, + port, initial_buffer, &error)) { goto transfer_failed; } @@ -876,7 +941,7 @@ transfer_failed: { GST_ERROR_OBJECT (server, "failed to accept client: %s", error->message); g_error_free (error); - gst_object_unref (client); + g_object_unref (client); return FALSE; } } @@ -935,7 +1000,7 @@ accept_failed: { GST_ERROR_OBJECT (server, "failed to accept client: %s", error->message); g_error_free (error); - gst_object_unref (client); + g_object_unref (client); return FALSE; } } From c431592976acd62ea8931437fd9bd588b6789366 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 14:30:43 +0100 Subject: [PATCH 0471/1776] client: rename method gst_rtsp_client_create_from_socket -> gst_rtsp_client_use_socket: we don't really create the client from the socket, we use the socket for the client. --- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-client.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index bcf8b89dfd..38fffb894c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2132,7 +2132,7 @@ no_address: } /** - * gst_rtsp_client_create_from_socket: + * gst_rtsp_client_use_socket: * @client: a #GstRTSPClient * @socket: a #GSocket * @ip: the IP address of the remote client diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 80c6dc8a0c..71a28adc9c 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -155,7 +155,7 @@ gboolean gst_rtsp_client_accept (GstRTSPClient *client, GCancellable *cancellable, GError **error); -gboolean gst_rtsp_client_create_from_socket(GstRTSPClient * client, +gboolean gst_rtsp_client_use_socket (GstRTSPClient * client, GSocket *socket, const gchar * ip, gint port, From 8523c9ca92284ddcf90d88ec1f352f3a1aaca3b0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 15:29:39 +0100 Subject: [PATCH 0472/1776] server: use a threadpool for the mainloops --- gst/rtsp-server/rtsp-server.c | 14 +++++++++----- gst/rtsp-server/rtsp-server.h | 2 ++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 25f3666feb..c1d645dc53 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -58,6 +58,8 @@ G_DEFINE_TYPE (GstRTSPServer, gst_rtsp_server, G_TYPE_OBJECT); GST_DEBUG_CATEGORY_STATIC (rtsp_server_debug); #define GST_CAT_DEFAULT rtsp_server_debug +typedef struct _ClientContext ClientContext; + static guint gst_rtsp_server_signals[SIGNAL_LAST] = { 0 }; static void gst_rtsp_server_get_property (GObject * object, guint propid, @@ -66,6 +68,7 @@ static void gst_rtsp_server_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_server_finalize (GObject * object); +static gpointer do_loop (ClientContext * ctx); static GstRTSPClient *default_create_client (GstRTSPServer * server); static gboolean default_accept_client (GstRTSPServer * server, GstRTSPClient * client, GSocket * socket, GError ** error); @@ -160,6 +163,8 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) klass->create_client = default_create_client; klass->accept_client = default_accept_client; + klass->pool = g_thread_pool_new ((GFunc) do_loop, klass, -1, FALSE, NULL); + GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer"); } @@ -749,13 +754,13 @@ close_error: } } -typedef struct +struct _ClientContext { GstRTSPServer *server; GMainLoop *loop; GMainContext *context; GstRTSPClient *client; -} ClientContext; +}; static void free_client_context (ClientContext * ctx) @@ -837,10 +842,9 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) GST_RTSP_SERVER_UNLOCK (server); if (ctx->loop) { - GThread *thread; + GstRTSPServerClass *klass = GST_RTSP_SERVER_GET_CLASS (server); - thread = g_thread_new ("MainLoop Thread", (GThreadFunc) do_loop, ctx); - g_thread_unref (thread); + g_thread_pool_push (klass->pool, ctx, NULL); } } diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index d3500b96b6..c50aa87a6f 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -89,6 +89,8 @@ struct _GstRTSPServer { struct _GstRTSPServerClass { GObjectClass parent_class; + GThreadPool *pool; + GstRTSPClient * (*create_client) (GstRTSPServer *server); gboolean (*accept_client) (GstRTSPServer *server, GstRTSPClient *client, GSocket *socket, GError **error); From 06cadebe71d72ed238f010e3fd1d744b7ce92bb2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 15:53:28 +0100 Subject: [PATCH 0473/1776] server: add max-thread property --- gst/rtsp-server/rtsp-server.c | 74 +++++++++++++++++++++++++++++++---- gst/rtsp-server/rtsp-server.h | 4 ++ 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index c1d645dc53..a36757bb5a 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -28,6 +28,7 @@ /* #define DEFAULT_ADDRESS "::0" */ #define DEFAULT_SERVICE "8554" #define DEFAULT_BACKLOG 5 +#define DEFAULT_MAX_THREADS 0 /* Define to use the SO_LINGER option so that the server sockets can be resused * sooner. Disabled for now because it is not very well implemented by various @@ -44,6 +45,7 @@ enum PROP_SESSION_POOL, PROP_MEDIA_MAPPING, + PROP_MAX_THREADS, PROP_LAST }; @@ -153,6 +155,18 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) "The media mapping to use for client session", GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPServer::max-threads: + * + * The maximum amount of threads to use for client connections. A value of + * 0 means to use only the mainloop, -1 means an unlimited amount of + * threads. + */ + g_object_class_install_property (gobject_class, PROP_MAX_THREADS, + g_param_spec_int ("max-threads", "Max Threads", + "The maximum amount of threads to use for client connections " + "(0 = only mainloop, -1 = unlimited)", -1, G_MAXINT, + DEFAULT_MAX_THREADS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED] = g_signal_new ("client-connected", G_TYPE_FROM_CLASS (gobject_class), @@ -531,6 +545,49 @@ gst_rtsp_server_get_auth (GstRTSPServer * server) return result; } +/** + * gst_rtsp_server_set_max_threads: + * @server: a #GstRTSPServer + * @max_threads: maximum threads + * + * Set the maximum threads used by the server to handle client requests. + * A value of 0 will use the server mainloop, a value of -1 will use an + * unlimited number of threads. + */ +void +gst_rtsp_server_set_max_threads (GstRTSPServer * server, gint max_threads) +{ + g_return_if_fail (GST_IS_RTSP_SERVER (server)); + + GST_RTSP_SERVER_LOCK (server); + server->max_threads = max_threads; + GST_RTSP_SERVER_UNLOCK (server); +} + +/** + * gst_rtsp_server_get_max_threads: + * @server: a #GstRTSPServer + * + * Get the maximum number of threads used for client connections. + * See gst_rtsp_server_set_max_threads(). + * + * Returns: the maximum number of threads. + */ +gint +gst_rtsp_server_get_max_threads (GstRTSPServer * server) +{ + gint res; + + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1); + + GST_RTSP_SERVER_LOCK (server); + res = server->max_threads; + GST_RTSP_SERVER_UNLOCK (server); + + return res; +} + + static void gst_rtsp_server_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec) @@ -556,6 +613,9 @@ gst_rtsp_server_get_property (GObject * object, guint propid, case PROP_MEDIA_MAPPING: g_value_take_object (value, gst_rtsp_server_get_media_mapping (server)); break; + case PROP_MAX_THREADS: + g_value_set_int (value, gst_rtsp_server_get_max_threads (server)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -583,6 +643,9 @@ gst_rtsp_server_set_property (GObject * object, guint propid, case PROP_MEDIA_MAPPING: gst_rtsp_server_set_media_mapping (server, g_value_get_object (value)); break; + case PROP_MAX_THREADS: + gst_rtsp_server_set_max_threads (server, g_value_get_int (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -819,8 +882,7 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) ctx = g_slice_new0 (ClientContext); ctx->server = server; ctx->client = client; -#if 1 - { + if (server->max_threads == 0) { GSource *source; /* find the context to add the watch */ @@ -828,12 +890,10 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) ctx->context = g_main_context_ref (g_source_get_context (source)); else ctx->context = NULL; + } else { + ctx->context = g_main_context_new (); + ctx->loop = g_main_loop_new (ctx->context, TRUE); } -#else - ctx->context = g_main_context_new (); - ctx->loop = g_main_loop_new (ctx->context, TRUE); - ctx->dothread = TRUE; -#endif gst_rtsp_client_attach (client, ctx->context); GST_RTSP_SERVER_LOCK (server); diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index c50aa87a6f..42a37b1273 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -61,6 +61,7 @@ struct _GstRTSPServer { gchar *address; gchar *service; gint backlog; + gint max_threads; GSocket *socket; @@ -122,6 +123,9 @@ GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *serve void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server); +void gst_rtsp_server_set_max_threads (GstRTSPServer *server, gint max_threads); +gint gst_rtsp_server_get_max_threads (GstRTSPServer *server); + gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket *socket, const gchar * ip, gint port, const gchar *initial_buffer); From e61c84c9bbe0d6c5dfa30fd4b1946cb80165f887 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 16:03:21 +0100 Subject: [PATCH 0474/1776] auth: add locking --- gst/rtsp-server/rtsp-auth.c | 19 +++++++++++++++++++ gst/rtsp-server/rtsp-auth.h | 1 + 2 files changed, 20 insertions(+) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 153b46caea..398bc28c07 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -63,6 +63,7 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) static void gst_rtsp_auth_init (GstRTSPAuth * auth) { + g_mutex_init (&auth->lock); /* bitwise or of all methods that need authentication */ auth->methods = GST_RTSP_DESCRIBE | GST_RTSP_ANNOUNCE | @@ -79,6 +80,7 @@ gst_rtsp_auth_finalize (GObject * obj) GST_INFO ("finalize auth %p", auth); g_free (auth->basic); + g_mutex_clear (&auth->lock); G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj); } @@ -130,8 +132,12 @@ gst_rtsp_auth_new (void) void gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic) { + g_return_if_fail (GST_IS_RTSP_AUTH (auth)); + + g_mutex_lock (&auth->lock); g_free (auth->basic); auth->basic = g_strdup (basic); + g_mutex_unlock (&auth->lock); } static gboolean @@ -166,6 +172,10 @@ gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, gboolean result = FALSE; GstRTSPAuthClass *klass; + g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE); + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); + g_return_val_if_fail (state != NULL, FALSE); + klass = GST_RTSP_AUTH_GET_CLASS (auth); GST_DEBUG_OBJECT (auth, "setup auth"); @@ -197,8 +207,10 @@ default_check_method (GstRTSPAuth * auth, GstRTSPClient * client, /* parse type */ if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) { GST_DEBUG_OBJECT (auth, "check Basic auth"); + g_mutex_lock (&auth->lock); if (auth->basic && strcmp (&authorization[6], auth->basic) == 0) result = TRUE; + g_mutex_unlock (&auth->lock); } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) { GST_DEBUG_OBJECT (auth, "check Digest auth"); /* not implemented yet */ @@ -232,6 +244,10 @@ gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client, gboolean result = FALSE; GstRTSPAuthClass *klass; + g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE); + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); + g_return_val_if_fail (state != NULL, FALSE); + klass = GST_RTSP_AUTH_GET_CLASS (auth); GST_DEBUG_OBJECT (auth, "check state"); @@ -258,6 +274,9 @@ gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass) gchar *user_pass; gchar *result; + g_return_val_if_fail (user != NULL, NULL); + g_return_val_if_fail (pass != NULL, NULL); + user_pass = g_strjoin (":", user, pass, NULL); result = g_base64_encode ((guchar *) user_pass, strlen (user_pass)); g_free (user_pass); diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 5e1e696d53..250c05cc5b 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -49,6 +49,7 @@ struct _GstRTSPAuth { GObject parent; /*< private >*/ + GMutex lock; gchar *basic; GstRTSPMethod methods; }; From b8cba7719c37acd36ca36f4d4ed1deeb440f3d3f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 16:14:19 +0100 Subject: [PATCH 0475/1776] media-factory: add locking --- gst/rtsp-server/rtsp-media-factory.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 3db7a417bf..2a6cbd7e53 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -493,15 +493,15 @@ gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory, g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); - old = factory->auth; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + if ((old = factory->auth) != auth) + factory->auth = auth ? g_object_ref (auth) : NULL; + else + old = NULL; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); - if (old != auth) { - if (auth) - g_object_ref (auth); - factory->auth = auth; - if (old) - g_object_unref (old); - } + if (old) + g_object_unref (old); } /** @@ -520,8 +520,10 @@ gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory) g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + GST_RTSP_MEDIA_FACTORY_LOCK (factory); if ((result = factory->auth)) g_object_ref (result); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); return result; } @@ -539,7 +541,9 @@ gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * factory, { g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + GST_RTSP_MEDIA_FACTORY_LOCK (factory); factory->protocols = protocols; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); } /** @@ -553,10 +557,16 @@ gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * factory, GstRTSPLowerTrans gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory) { + GstRTSPLowerTrans res; + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), GST_RTSP_LOWER_TRANS_UNKNOWN); - return factory->protocols; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + res = factory->protocols; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return res; } static gboolean From 04881bd63230caccea9dd110c53bfe12ad70b7ed Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 16:18:57 +0100 Subject: [PATCH 0476/1776] mapping: add locking --- gst/rtsp-server/rtsp-media-mapping.c | 8 ++++++++ gst/rtsp-server/rtsp-media-mapping.h | 1 + 2 files changed, 9 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c index 1a8682e757..db2a38d242 100644 --- a/gst/rtsp-server/rtsp-media-mapping.c +++ b/gst/rtsp-server/rtsp-media-mapping.c @@ -49,6 +49,7 @@ gst_rtsp_media_mapping_init (GstRTSPMediaMapping * mapping) { GST_DEBUG_OBJECT (mapping, "created"); + g_mutex_init (&mapping->lock); mapping->mappings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } @@ -61,6 +62,7 @@ gst_rtsp_media_mapping_finalize (GObject * obj) GST_DEBUG_OBJECT (mapping, "finalized"); g_hash_table_unref (mapping->mappings); + g_mutex_clear (&mapping->lock); G_OBJECT_CLASS (gst_rtsp_media_mapping_parent_class)->finalize (obj); } @@ -87,12 +89,14 @@ find_factory (GstRTSPMediaMapping * mapping, const GstRTSPUrl * url) { GstRTSPMediaFactory *result; + g_mutex_lock (&mapping->lock); /* find the location of the media in the hashtable we only use the absolute * path of the uri to find a mapping. If the mapping depends on other * properties found in the url, this method should be overridden. */ result = g_hash_table_lookup (mapping->mappings, url->abspath); if (result) g_object_ref (result); + g_mutex_unlock (&mapping->lock); GST_INFO ("found media %p for url abspath %s", result, url->abspath); @@ -147,7 +151,9 @@ gst_rtsp_media_mapping_add_factory (GstRTSPMediaMapping * mapping, g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); g_return_if_fail (path != NULL); + g_mutex_lock (&mapping->lock); g_hash_table_insert (mapping->mappings, g_strdup (path), factory); + g_mutex_unlock (&mapping->lock); } /** @@ -164,5 +170,7 @@ gst_rtsp_media_mapping_remove_factory (GstRTSPMediaMapping * mapping, g_return_if_fail (GST_IS_RTSP_MEDIA_MAPPING (mapping)); g_return_if_fail (path != NULL); + g_mutex_lock (&mapping->lock); g_hash_table_remove (mapping->mappings, path); + g_mutex_unlock (&mapping->lock); } diff --git a/gst/rtsp-server/rtsp-media-mapping.h b/gst/rtsp-server/rtsp-media-mapping.h index b754920340..4025cebd31 100644 --- a/gst/rtsp-server/rtsp-media-mapping.h +++ b/gst/rtsp-server/rtsp-media-mapping.h @@ -50,6 +50,7 @@ typedef struct _GstRTSPMediaMappingClass GstRTSPMediaMappingClass; struct _GstRTSPMediaMapping { GObject parent; + GMutex lock; GHashTable *mappings; }; From 65fa5166779e6accd2cbf2829097a85e59f9f7c2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 16:30:16 +0100 Subject: [PATCH 0477/1776] server: free old socket --- gst/rtsp-server/rtsp-server.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index a36757bb5a..0edf635a08 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1097,7 +1097,7 @@ GSource * gst_rtsp_server_create_source (GstRTSPServer * server, GCancellable * cancellable, GError ** error) { - GSocket *socket; + GSocket *socket, *old; GSource *source; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); @@ -1105,7 +1105,14 @@ gst_rtsp_server_create_source (GstRTSPServer * server, socket = gst_rtsp_server_create_socket (server, NULL, error); if (socket == NULL) goto no_socket; + + GST_RTSP_SERVER_LOCK (server); + old = server->socket; server->socket = g_object_ref (socket); + GST_RTSP_SERVER_UNLOCK (server); + + if (old) + g_object_unref (old); /* create a watch for reads (new connections) and possible errors */ source = g_socket_create_source (socket, G_IO_IN | From 11cf3f3ccb365fafaacf250375424c29aa9f8254 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 16:42:37 +0100 Subject: [PATCH 0478/1776] session: add locking --- gst/rtsp-server/rtsp-session.c | 37 +++++++++++++++++++++++++++++----- gst/rtsp-server/rtsp-session.h | 1 + 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index a6a24096da..7f2202627d 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -71,6 +71,7 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass) static void gst_rtsp_session_init (GstRTSPSession * session) { + g_mutex_init (&session->lock); session->timeout = DEFAULT_TIMEOUT; g_get_current_time (&session->create_time); gst_rtsp_session_touch (session); @@ -90,6 +91,7 @@ gst_rtsp_session_finalize (GObject * obj) /* free session id */ g_free (session->sessionid); + g_mutex_clear (&session->lock); G_OBJECT_CLASS (gst_rtsp_session_parent_class)->finalize (obj); } @@ -157,7 +159,9 @@ gst_rtsp_session_manage_media (GstRTSPSession * sess, const GstRTSPUrl * uri, result = gst_rtsp_session_media_new (uri, media); + g_mutex_lock (&sess->lock); sess->medias = g_list_prepend (sess->medias, result); + g_mutex_unlock (&sess->lock); GST_INFO ("manage new media %p in session %p", media, result); @@ -178,16 +182,22 @@ gst_rtsp_session_release_media (GstRTSPSession * sess, GstRTSPSessionMedia * media) { GList *find; + gboolean more; g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), FALSE); g_return_val_if_fail (media != NULL, FALSE); + g_mutex_lock (&sess->lock); find = g_list_find (sess->medias, media); - if (find) { - g_object_unref (find->data); + if (find) sess->medias = g_list_delete_link (sess->medias, find); - } - return (sess->medias != NULL); + more = (sess->medias != NULL); + g_mutex_unlock (&sess->lock); + + if (find) + g_object_unref (media); + + return more; } /** @@ -210,6 +220,7 @@ gst_rtsp_session_get_media (GstRTSPSession * sess, const GstRTSPUrl * url) result = NULL; + g_mutex_lock (&sess->lock); for (walk = sess->medias; walk; walk = g_list_next (walk)) { result = (GstRTSPSessionMedia *) walk->data; @@ -218,6 +229,8 @@ gst_rtsp_session_get_media (GstRTSPSession * sess, const GstRTSPUrl * url) result = NULL; } + g_mutex_unlock (&sess->lock); + return result; } @@ -271,11 +284,13 @@ gst_rtsp_session_get_header (GstRTSPSession * session) g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL); + g_mutex_lock (&session->lock); if (session->timeout != 60) result = g_strdup_printf ("%s; timeout=%d", session->sessionid, session->timeout); else result = g_strdup (session->sessionid); + g_mutex_unlock (&session->lock); return result; } @@ -293,7 +308,9 @@ gst_rtsp_session_set_timeout (GstRTSPSession * session, guint timeout) { g_return_if_fail (GST_IS_RTSP_SESSION (session)); + g_mutex_lock (&session->lock); session->timeout = timeout; + g_mutex_unlock (&session->lock); } /** @@ -307,9 +324,15 @@ gst_rtsp_session_set_timeout (GstRTSPSession * session, guint timeout) guint gst_rtsp_session_get_timeout (GstRTSPSession * session) { + guint res; + g_return_val_if_fail (GST_IS_RTSP_SESSION (session), 0); - return session->timeout; + g_mutex_lock (&session->lock); + res = session->timeout; + g_mutex_unlock (&session->lock); + + return res; } /** @@ -323,7 +346,9 @@ gst_rtsp_session_touch (GstRTSPSession * session) { g_return_if_fail (GST_IS_RTSP_SESSION (session)); + g_mutex_lock (&session->lock); g_get_current_time (&session->last_access); + g_mutex_unlock (&session->lock); } /** @@ -371,6 +396,7 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) g_return_val_if_fail (GST_IS_RTSP_SESSION (session), -1); g_return_val_if_fail (now != NULL, -1); + g_mutex_lock (&session->lock); if (g_atomic_int_get (&session->expire_count) != 0) { /* touch session when the expire count is not 0 */ g_get_current_time (&session->last_access); @@ -379,6 +405,7 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) last_access = GST_TIMEVAL_TO_TIME (session->last_access); /* add timeout allow for 5 seconds of extra time */ last_access += session->timeout * GST_SECOND + (5 * GST_SECOND); + g_mutex_unlock (&session->lock); now_ns = GST_TIMEVAL_TO_TIME (*now); diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index efac74ce0b..f5c4fcd87f 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -58,6 +58,7 @@ typedef struct _GstRTSPSessionClass GstRTSPSessionClass; struct _GstRTSPSession { GObject parent; + GMutex lock; gchar *sessionid; guint timeout; From 883cf794e469e2fc957b72cc771fb96ff7e1f08c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 16:51:03 +0100 Subject: [PATCH 0479/1776] session-media: add locking --- gst/rtsp-server/rtsp-session-media.c | 12 ++++++++++++ gst/rtsp-server/rtsp-session-media.h | 1 + 2 files changed, 13 insertions(+) diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 8e7deddf12..e8eda2bc98 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -53,6 +53,7 @@ gst_rtsp_session_media_class_init (GstRTSPSessionMediaClass * klass) static void gst_rtsp_session_media_init (GstRTSPSessionMedia * media) { + g_mutex_init (&media->lock); media->state = GST_RTSP_STATE_INIT; } @@ -71,6 +72,7 @@ gst_rtsp_session_media_finalize (GObject * obj) gst_rtsp_url_free (media->url); g_object_unref (media->media); + g_mutex_clear (&media->lock); G_OBJECT_CLASS (gst_rtsp_session_media_parent_class)->finalize (obj); } @@ -136,13 +138,17 @@ gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); g_return_val_if_fail (stream->idx < media->transports->len, NULL); + g_mutex_lock (&media->lock); result = g_ptr_array_index (media->transports, stream->idx); if (result == NULL) { result = gst_rtsp_stream_transport_new (stream, tr); g_ptr_array_index (media->transports, stream->idx) = result; + g_mutex_unlock (&media->lock); } else { gst_rtsp_stream_transport_set_transport (result, tr); + g_mutex_unlock (&media->lock); } + return result; } @@ -164,7 +170,9 @@ gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx) g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL); g_return_val_if_fail (idx < media->transports->len, NULL); + g_mutex_lock (&media->lock); result = g_ptr_array_index (media->transports, idx); + g_mutex_unlock (&media->lock); return result; } @@ -185,8 +193,10 @@ gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia * media, { g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE); + g_mutex_lock (&media->lock); range->min = media->counter++; range->max = media->counter++; + g_mutex_unlock (&media->lock); return TRUE; } @@ -207,7 +217,9 @@ gst_rtsp_session_media_set_state (GstRTSPSessionMedia * media, GstState state) g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE); + g_mutex_lock (&media->lock); ret = gst_rtsp_media_set_state (media->media, state, media->transports); + g_mutex_unlock (&media->lock); return ret; } diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 845a5fbe6c..2156f303ba 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -53,6 +53,7 @@ struct _GstRTSPSessionMedia { GObject parent; + GMutex lock; GstRTSPUrl *url; GstRTSPMedia *media; GstRTSPState state; From 75473fc88d3e3a479890956c010eb03feb31ae8d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 17:06:42 +0100 Subject: [PATCH 0480/1776] stream-transport: add method to handle RTP/RTCP Call new methods instead of poking into the structures directly. --- gst/rtsp-server/rtsp-stream-transport.c | 46 +++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream-transport.h | 5 +++ gst/rtsp-server/rtsp-stream.c | 6 ++-- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 3db5c39350..3d97db6d51 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -170,3 +170,49 @@ gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans, gst_rtsp_transport_free (trans->transport); trans->transport = tr; } + +/** + * gst_rtsp_stream_transport_send_rtp: + * @trans: a #GstRTSPStreamTransport + * @buffer: a #GstBuffer + * + * Send @buffer to the installed RTP callback for @trans. + * + * Returns: %TRUE on success + */ +gboolean +gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport * trans, + GstBuffer * buffer) +{ + gboolean res = FALSE; + + if (trans->send_rtp) + res = + trans->send_rtp (buffer, trans->transport->interleaved.min, + trans->user_data); + + return res; +} + +/** + * gst_rtsp_stream_transport_send_rtcp: + * @trans: a #GstRTSPStreamTransport + * @buffer: a #GstBuffer + * + * Send @buffer to the installed RTCP callback for @trans. + * + * Returns: %TRUE on success + */ +gboolean +gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport * trans, + GstBuffer * buffer) +{ + gboolean res = FALSE; + + if (trans->send_rtcp) + res = + trans->send_rtcp (buffer, trans->transport->interleaved.max, + trans->user_data); + + return res; +} diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index cbc82555bb..f4788059ba 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -105,6 +105,11 @@ void gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamT gpointer user_data, GDestroyNotify notify); +gboolean gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport *trans, + GstBuffer *buffer); +gboolean gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport *trans, + GstBuffer *buffer); + G_END_DECLS #endif /* __GST_RTSP_STREAM_TRANSPORT_H__ */ diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index be262d1ab6..f9aba19e4b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -524,11 +524,9 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) { - if (tr->send_rtp) - tr->send_rtp (buffer, tr->transport->interleaved.min, tr->user_data); + gst_rtsp_stream_transport_send_rtp (tr, buffer); } else { - if (tr->send_rtcp) - tr->send_rtcp (buffer, tr->transport->interleaved.max, tr->user_data); + gst_rtsp_stream_transport_send_rtcp (tr, buffer); } } gst_sample_unref (sample); From c7d20e560370539f32395f8db9796f19c544fe8e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2012 17:11:18 +0100 Subject: [PATCH 0481/1776] stream-transport: add keep-alive method --- gst/rtsp-server/rtsp-stream-transport.c | 13 +++++++++++++ gst/rtsp-server/rtsp-stream-transport.h | 2 ++ gst/rtsp-server/rtsp-stream.c | 8 +++----- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 3d97db6d51..c81a1495de 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -216,3 +216,16 @@ gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport * trans, return res; } + +/** + * gst_rtsp_stream_transport_keep_alive: + * @trans: a #GstRTSPStreamTransport + * + * Signal the installed keep_alive callback for @trans. + */ +void +gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport * trans) +{ + if (trans->keep_alive) + trans->keep_alive (trans->ka_user_data); +} diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index f4788059ba..96bf7b67c4 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -110,6 +110,8 @@ gboolean gst_rtsp_stream_transport_send_rtp (GstRTSPStreamT gboolean gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport *trans, GstBuffer *buffer); +void gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport *trans); + G_END_DECLS #endif /* __GST_RTSP_STREAM_TRANSPORT_H__ */ diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index f9aba19e4b..de35bc7eaf 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -455,12 +455,10 @@ on_ssrc_active (GObject * session, GObject * source, GstRTSPStream * stream) trans = check_transport (source, stream); - if (trans) + if (trans) { GST_INFO ("%p: source %p in transport %p is active", stream, source, trans); - - if (trans && trans->keep_alive) - trans->keep_alive (trans->ka_user_data); - + gst_rtsp_stream_transport_keep_alive (trans); + } #ifdef DUMP_STATS { GstStructure *stats; From 4753588b09f0b16908be5186e7b7d3ab212d0cdc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 13 Nov 2012 11:14:49 +0100 Subject: [PATCH 0482/1776] stream: add locking --- gst/rtsp-server/rtsp-stream.c | 74 ++++++++++++++++++++++++++++++----- gst/rtsp-server/rtsp-stream.h | 2 + 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index de35bc7eaf..6a207a9c7c 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -57,8 +57,9 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) } static void -gst_rtsp_stream_init (GstRTSPStream * media) +gst_rtsp_stream_init (GstRTSPStream * stream) { + g_mutex_init (&stream->lock); } static void @@ -73,6 +74,7 @@ gst_rtsp_stream_finalize (GObject * obj) gst_object_unref (stream->payloader); gst_object_unref (stream->srcpad); + g_mutex_clear (&stream->lock); G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); } @@ -140,6 +142,7 @@ gst_rtsp_stream_get_mtu (GstRTSPStream * stream) return mtu; } +/* must be called with lock */ static gboolean alloc_ports (GstRTSPStream * stream) { @@ -336,14 +339,16 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) newcaps = gst_pad_get_current_caps (pad); + GST_INFO ("stream %p received caps %p, %" GST_PTR_FORMAT, stream, newcaps, + newcaps); + + g_mutex_lock (&stream->lock); oldcaps = stream->caps; stream->caps = newcaps; + g_mutex_unlock (&stream->lock); if (oldcaps) gst_caps_unref (oldcaps); - - GST_INFO ("stream %p received caps %p, %" GST_PTR_FORMAT, stream, newcaps, - newcaps); } static void @@ -375,6 +380,7 @@ find_transport (GstRTSPStream * stream, const gchar * rtcp_from) port = atoi (tmp + 1); dest = g_strndup (rtcp_from, tmp - rtcp_from); + g_mutex_lock (&stream->lock); GST_INFO ("finding %s:%d in %d transports", dest, port, g_list_length (stream->transports)); @@ -391,6 +397,8 @@ find_transport (GstRTSPStream * stream, const gchar * rtcp_from) break; } } + g_mutex_unlock (&stream->lock); + g_free (dest); return result; @@ -518,6 +526,7 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) stream = (GstRTSPStream *) user_data; buffer = gst_sample_get_buffer (sample); + g_mutex_lock (&stream->lock); for (walk = stream->transports; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; @@ -527,6 +536,8 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) gst_rtsp_stream_transport_send_rtcp (tr, buffer); } } + g_mutex_unlock (&stream->lock); + gst_sample_unref (sample); return GST_FLOW_OK; @@ -565,8 +576,9 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, g_return_val_if_fail (GST_IS_BIN (bin), FALSE); g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE); + g_mutex_lock (&stream->lock); if (stream->is_joined) - return TRUE; + goto was_joined; /* create a session with the same index as the stream */ idx = stream->idx; @@ -736,12 +748,19 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, (GCallback) caps_notify, stream); stream->is_joined = TRUE; + g_mutex_unlock (&stream->lock); return TRUE; /* ERRORS */ +was_joined: + { + g_mutex_unlock (&stream->lock); + return TRUE; + } no_ports: { + g_mutex_unlock (&stream->lock); GST_WARNING ("failed to allocate ports %d", idx); return FALSE; } @@ -750,6 +769,7 @@ link_failed: GST_WARNING ("failed to link stream %d", idx); gst_object_unref (stream->send_rtp_sink); stream->send_rtp_sink = NULL; + g_mutex_unlock (&stream->lock); return FALSE; } } @@ -775,8 +795,9 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, g_return_val_if_fail (GST_IS_BIN (bin), FALSE); g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE); + g_mutex_lock (&stream->lock); if (!stream->is_joined) - return TRUE; + goto was_not_joined; /* all transports must be removed by now */ g_return_val_if_fail (stream->transports == NULL, FALSE); @@ -828,8 +849,14 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_caps_unref (stream->caps); stream->is_joined = FALSE; + g_mutex_unlock (&stream->lock); return TRUE; + +was_not_joined: + { + return TRUE; + } } /** @@ -876,12 +903,19 @@ GstFlowReturn gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * buffer) { GstFlowReturn ret; + GstElement *element; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR); g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); g_return_val_if_fail (stream->is_joined, FALSE); - ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[0]), buffer); + g_mutex_lock (&stream->lock); + element = gst_object_ref (stream->appsrc[0]); + g_mutex_unlock (&stream->lock); + + ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (element), buffer); + + gst_object_unref (element); return ret; } @@ -902,16 +936,24 @@ GstFlowReturn gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer) { GstFlowReturn ret; + GstElement *element; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR); g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); g_return_val_if_fail (stream->is_joined, FALSE); - ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[1]), buffer); + g_mutex_lock (&stream->lock); + element = gst_object_ref (stream->appsrc[1]); + g_mutex_unlock (&stream->lock); + + ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (element), buffer); + + gst_object_unref (element); return ret; } +/* must be called with lock */ static gboolean update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, gboolean add) @@ -1002,12 +1044,18 @@ gboolean gst_rtsp_stream_add_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans) { + gboolean res; + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE); g_return_val_if_fail (stream->is_joined, FALSE); g_return_val_if_fail (trans->transport != NULL, FALSE); - return update_transport (stream, trans, TRUE); + g_mutex_lock (&stream->lock); + res = update_transport (stream, trans, TRUE); + g_mutex_unlock (&stream->lock); + + return res; } /** @@ -1028,10 +1076,16 @@ gboolean gst_rtsp_stream_remove_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans) { + gboolean res; + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE); g_return_val_if_fail (stream->is_joined, FALSE); g_return_val_if_fail (trans->transport != NULL, FALSE); - return update_transport (stream, trans, FALSE); + g_mutex_lock (&stream->lock); + res = update_transport (stream, trans, FALSE); + g_mutex_unlock (&stream->lock); + + return res; } diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 36d476774a..166baffb9a 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -44,6 +44,7 @@ typedef struct _GstRTSPStreamClass GstRTSPStreamClass; /** * GstRTSPStream: * @parent: the parent instance + * @lock: mutex protecting the stream * @idx: the stream index * @srcpad: the srcpad of the stream * @payloader: the payloader of the format @@ -72,6 +73,7 @@ typedef struct _GstRTSPStreamClass GstRTSPStreamClass; struct _GstRTSPStream { GObject parent; + GMutex lock; guint idx; GstPad *srcpad; GstElement *payloader; From 9a97de88ea9b9ca1613b57db2933cfbbd988a547 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 13 Nov 2012 11:15:35 +0100 Subject: [PATCH 0483/1776] media: add lock to protect state changes --- gst/rtsp-server/rtsp-media.c | 164 +++++++++++++++++++++++++++++------ gst/rtsp-server/rtsp-media.h | 1 + 2 files changed, 138 insertions(+), 27 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 352a045bdb..17bc52ab92 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -156,6 +156,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) media->streams = g_ptr_array_new_with_free_func (g_object_unref); g_mutex_init (&media->lock); g_cond_init (&media->cond); + g_rec_mutex_init (&media->state_lock); media->shared = DEFAULT_SHARED; media->reusable = DEFAULT_REUSABLE; @@ -187,6 +188,7 @@ gst_rtsp_media_finalize (GObject * obj) g_free (media->multicast_group); g_mutex_clear (&media->lock); g_cond_clear (&media->cond); + g_rec_mutex_clear (&media->state_lock); G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); } @@ -267,6 +269,7 @@ do_loop (GstRTSPMediaClass * klass) return NULL; } +/* must be called with state lock */ static void collect_media_stats (GstRTSPMedia * media) { @@ -349,7 +352,9 @@ gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared) { g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + g_mutex_lock (&media->lock); media->shared = shared; + g_mutex_unlock (&media->lock); } /** @@ -363,9 +368,15 @@ gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared) gboolean gst_rtsp_media_is_shared (GstRTSPMedia * media) { + gboolean res; + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - return media->shared; + g_mutex_lock (&media->lock); + res = media->shared; + g_mutex_unlock (&media->lock); + + return res; } /** @@ -381,7 +392,9 @@ gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable) { g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + g_mutex_lock (&media->lock); media->reusable = reusable; + g_mutex_unlock (&media->lock); } /** @@ -395,9 +408,15 @@ gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable) gboolean gst_rtsp_media_is_reusable (GstRTSPMedia * media) { + gboolean res; + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - return media->reusable; + g_mutex_lock (&media->lock); + res = media->reusable; + g_mutex_unlock (&media->lock); + + return res; } /** @@ -412,7 +431,9 @@ gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols) { g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + g_mutex_lock (&media->lock); media->protocols = protocols; + g_mutex_unlock (&media->lock); } /** @@ -426,10 +447,16 @@ gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols) GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia * media) { + GstRTSPLowerTrans res; + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_RTSP_LOWER_TRANS_UNKNOWN); - return media->protocols; + g_mutex_lock (&media->lock); + res = media->protocols; + g_mutex_unlock (&media->lock); + + return res; } /** @@ -445,7 +472,9 @@ gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown) { g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + g_mutex_lock (&media->lock); media->eos_shutdown = eos_shutdown; + g_mutex_unlock (&media->lock); } /** @@ -460,9 +489,15 @@ gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown) gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media) { + gboolean res; + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - return media->eos_shutdown; + g_mutex_lock (&media->lock); + res = media->eos_shutdown; + g_mutex_unlock (&media->lock); + + return res; } /** @@ -477,7 +512,9 @@ gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size) { g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + g_mutex_lock (&media->lock); media->buffer_size = size; + g_mutex_unlock (&media->lock); } /** @@ -491,9 +528,15 @@ gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size) guint gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) { + guint res; + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - return media->buffer_size; + g_mutex_unlock (&media->lock); + res = media->buffer_size; + g_mutex_unlock (&media->lock); + + return res; } /** @@ -516,11 +559,11 @@ gst_rtsp_media_set_multicast_group (GstRTSPMedia * media, const gchar * mc) /** * gst_rtsp_media_get_multicast_group: - * @media: a #GstRTSPMedia + * @media: (transfer full): a #GstRTSPMedia * * Get the multicast group that media from @media will be streamed to. * - * Returns: the multicast group + * Returns: the multicast group, g_free after usage. */ gchar * gst_rtsp_media_get_multicast_group (GstRTSPMedia * media) @@ -550,15 +593,15 @@ gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth) g_return_if_fail (GST_IS_RTSP_MEDIA (media)); - old = media->auth; + g_mutex_lock (&media->lock); + if ((old = media->auth) != auth) + media->auth = auth ? g_object_ref (auth) : NULL; + else + old = NULL; + g_mutex_unlock (&media->lock); - if (old != auth) { - if (auth) - g_object_ref (auth); - media->auth = auth; - if (old) - g_object_unref (old); - } + if (old) + g_object_unref (old); } /** @@ -577,8 +620,10 @@ gst_rtsp_media_get_auth (GstRTSPMedia * media) g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + g_mutex_lock (&media->lock); if ((result = media->auth)) g_object_ref (result); + g_mutex_unlock (&media->lock); return result; } @@ -598,6 +643,7 @@ gst_rtsp_media_set_mtu (GstRTSPMedia * media, guint mtu) g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + g_mutex_lock (&media->lock); media->mtu = mtu; for (i = 0; i < media->streams->len; i++) { GstRTSPStream *stream; @@ -607,6 +653,7 @@ gst_rtsp_media_set_mtu (GstRTSPMedia * media, guint mtu) stream = g_ptr_array_index (media->streams, i); gst_rtsp_stream_set_mtu (stream, mtu); } + g_mutex_unlock (&media->lock); } /** @@ -618,9 +665,15 @@ gst_rtsp_media_set_mtu (GstRTSPMedia * media, guint mtu) guint gst_rtsp_media_get_mtu (GstRTSPMedia * media) { + guint res; + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0); - return media->mtu; + g_mutex_lock (&media->lock); + res = media->mtu; + g_mutex_unlock (&media->lock); + + return res; } /** @@ -673,7 +726,9 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) GST_INFO ("found dynamic element %d, %p", i, elem); + g_mutex_lock (&media->lock); media->dynamic = g_list_prepend (media->dynamic, elem); + g_mutex_unlock (&media->lock); have_elem = TRUE; } @@ -707,6 +762,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, g_return_val_if_fail (GST_IS_PAD (pad), NULL); g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL); + g_mutex_lock (&media->lock); idx = media->streams->len; name = g_strdup_printf ("src_%u", idx); @@ -720,6 +776,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, gst_rtsp_stream_set_mtu (stream, media->mtu); g_ptr_array_add (media->streams, stream); + g_mutex_unlock (&media->lock); return stream; } @@ -735,9 +792,15 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, guint gst_rtsp_media_n_streams (GstRTSPMedia * media) { + guint res; + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0); - return media->streams->len; + g_mutex_lock (&media->lock); + res = media->streams->len; + g_mutex_unlock (&media->lock); + + return res; } /** @@ -757,10 +820,12 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + g_mutex_lock (&media->lock); if (idx < media->streams->len) res = g_ptr_array_index (media->streams, idx); else res = NULL; + g_mutex_unlock (&media->lock); return res; } @@ -780,6 +845,7 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play) gchar *result; GstRTSPTimeRange range; + g_mutex_lock (&media->lock); /* make copy */ range = media->range; @@ -787,6 +853,7 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play) range.min.type = GST_RTSP_TIME_NOW; range.min.seconds = -1; } + g_mutex_unlock (&media->lock); result = gst_rtsp_range_to_string (&range); @@ -813,10 +880,9 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (range != NULL, FALSE); - if (!media->seekable) { - GST_INFO ("pipeline is not seekable"); - return TRUE; - } + g_rec_mutex_lock (&media->state_lock); + if (!media->seekable) + goto not_seekable; if (range->unit != GST_RTSP_RANGE_NPT) goto not_supported; @@ -880,17 +946,26 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GST_INFO ("no seek needed"); res = TRUE; } + g_rec_mutex_unlock (&media->state_lock); return res; /* ERRORS */ +not_seekable: + { + g_rec_mutex_unlock (&media->state_lock); + GST_INFO ("pipeline is not seekable"); + return TRUE; + } not_supported: { + g_rec_mutex_unlock (&media->state_lock); GST_WARNING ("seek unit %d not supported", range->unit); return FALSE; } weird_type: { + g_rec_mutex_unlock (&media->state_lock); GST_WARNING ("weird range type %d not supported", range->min.type); return FALSE; } @@ -952,6 +1027,7 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) if (media->is_live) break; + g_rec_mutex_lock (&media->state_lock); if (percent == 100) { /* a 100% message means buffering is done */ media->buffering = FALSE; @@ -974,6 +1050,7 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) } } media->buffering = TRUE; + g_rec_mutex_unlock (&media->state_lock); } break; } @@ -1011,6 +1088,7 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) case GST_MESSAGE_STREAM_STATUS: break; case GST_MESSAGE_ASYNC_DONE: + g_rec_mutex_lock (&media->state_lock); if (!media->adding) { /* when we are dynamically adding pads, the addition of the udpsrc will * temporarily produce ASYNC_DONE messages. We have to ignore them and @@ -1022,14 +1100,18 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) } else { GST_INFO ("%p: ignoring ASYNC_DONE", media); } + g_rec_mutex_unlock (&media->state_lock); break; case GST_MESSAGE_EOS: GST_INFO ("%p: got EOS", media); + + g_rec_mutex_lock (&media->state_lock); if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) { GST_DEBUG ("shutting down after EOS"); finish_unprepare (media); g_object_unref (media); } + g_rec_mutex_unlock (&media->state_lock); break; default: GST_INFO ("%p: got message type %s", media, @@ -1067,6 +1149,7 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), stream->idx); + g_rec_mutex_lock (&media->state_lock); /* we will be adding elements below that will cause ASYNC_DONE to be * posted in the bus. We want to ignore those messages until the * pipeline really prerolled. */ @@ -1078,18 +1161,24 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) media->rtpbin, GST_STATE_PAUSED); media->adding = FALSE; + g_rec_mutex_unlock (&media->state_lock); } static void no_more_pads_cb (GstElement * element, GstRTSPMedia * media) { + GstElement *fakesink; + + g_mutex_lock (&media->lock); GST_INFO ("no more pads"); - if (media->fakesink) { - gst_object_ref (media->fakesink); - gst_bin_remove (GST_BIN (media->pipeline), media->fakesink); - gst_element_set_state (media->fakesink, GST_STATE_NULL); - gst_object_unref (media->fakesink); + if ((fakesink = media->fakesink)) { + gst_object_ref (fakesink); media->fakesink = NULL; + g_mutex_unlock (&media->lock); + + gst_bin_remove (GST_BIN (media->pipeline), fakesink); + gst_element_set_state (fakesink, GST_STATE_NULL); + gst_object_unref (fakesink); GST_INFO ("removed fakesink"); } } @@ -1116,6 +1205,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) GstBus *bus; GList *walk; + g_rec_mutex_lock (&media->state_lock); if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) goto was_prepared; @@ -1202,6 +1292,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) case GST_STATE_CHANGE_FAILURE: goto state_failed; } + g_rec_mutex_unlock (&media->state_lock); /* now wait for all pads to be prerolled, FIXME, we should somehow be * able to do this async so that we don't block the server thread. */ @@ -1218,16 +1309,19 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) /* OK */ was_prepared: { + g_rec_mutex_unlock (&media->state_lock); return TRUE; } /* ERRORS */ is_reused: { + g_rec_mutex_unlock (&media->state_lock); GST_WARNING ("can not reuse media %p", media); return FALSE; } no_rtpbin: { + g_rec_mutex_unlock (&media->state_lock); GST_WARNING ("no rtpbin element"); g_warning ("failed to create element 'rtpbin', check your installation"); return FALSE; @@ -1236,10 +1330,12 @@ state_failed: { GST_WARNING ("failed to preroll pipeline"); gst_rtsp_media_unprepare (media); + g_rec_mutex_unlock (&media->state_lock); return FALSE; } } +/* must be called with state-lock */ static void finish_unprepare (GstRTSPMedia * media) { @@ -1275,6 +1371,7 @@ finish_unprepare (GstRTSPMedia * media) g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL); } +/* called with state-lock */ static gboolean default_unprepare (GstRTSPMedia * media) { @@ -1308,8 +1405,9 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) { gboolean success; + g_rec_mutex_lock (&media->state_lock); if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED) - return TRUE; + goto was_unprepared; GST_INFO ("unprepare media %p", media); media->target_state = GST_STATE_NULL; @@ -1324,8 +1422,16 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) } else { finish_unprepare (media); } + g_rec_mutex_unlock (&media->state_lock); return success; + +was_unprepared: + { + g_rec_mutex_unlock (&media->state_lock); + GST_INFO ("media %p was already unprepared", media); + return TRUE; + } } /** @@ -1349,6 +1455,8 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (transports != NULL, FALSE); + g_rec_mutex_lock (&media->state_lock); + /* NULL and READY are the same */ if (state == GST_STATE_READY) state = GST_STATE_NULL; @@ -1427,5 +1535,7 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, old_active != media->n_active)) collect_media_stats (media); + g_rec_mutex_unlock (&media->state_lock); + return TRUE; } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 9a99f99d1f..bf2d0e5663 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -116,6 +116,7 @@ struct _GstRTSPMedia { guint mtu; GstElement *element; + GRecMutex state_lock; GPtrArray *streams; GList *dynamic; GstRTSPMediaStatus status; From 47127bd2703ede9a1fc43dc59e25e218bb7000da Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 13 Nov 2012 11:49:08 +0100 Subject: [PATCH 0484/1776] media: add lock around message handler We don't want to dispatch messages while we are still processing the result of the state change. --- gst/rtsp-server/rtsp-media.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 17bc52ab92..df65a15e28 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1007,6 +1007,7 @@ gst_rtsp_media_get_status (GstRTSPMedia * media) return result; } +/* called with state-lock */ static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message) { @@ -1027,7 +1028,6 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) if (media->is_live) break; - g_rec_mutex_lock (&media->state_lock); if (percent == 100) { /* a 100% message means buffering is done */ media->buffering = FALSE; @@ -1050,7 +1050,6 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) } } media->buffering = TRUE; - g_rec_mutex_unlock (&media->state_lock); } break; } @@ -1088,7 +1087,6 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) case GST_MESSAGE_STREAM_STATUS: break; case GST_MESSAGE_ASYNC_DONE: - g_rec_mutex_lock (&media->state_lock); if (!media->adding) { /* when we are dynamically adding pads, the addition of the udpsrc will * temporarily produce ASYNC_DONE messages. We have to ignore them and @@ -1100,18 +1098,15 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) } else { GST_INFO ("%p: ignoring ASYNC_DONE", media); } - g_rec_mutex_unlock (&media->state_lock); break; case GST_MESSAGE_EOS: GST_INFO ("%p: got EOS", media); - g_rec_mutex_lock (&media->state_lock); if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) { GST_DEBUG ("shutting down after EOS"); finish_unprepare (media); g_object_unref (media); } - g_rec_mutex_unlock (&media->state_lock); break; default: GST_INFO ("%p: got message type %s", media, @@ -1129,10 +1124,12 @@ bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media) klass = GST_RTSP_MEDIA_GET_CLASS (media); + g_rec_mutex_lock (&media->state_lock); if (klass->handle_message) ret = klass->handle_message (media, message); else ret = FALSE; + g_rec_mutex_unlock (&media->state_lock); return ret; } @@ -1209,6 +1206,9 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) goto was_prepared; + if (media->status != GST_RTSP_MEDIA_STATUS_UNPREPARED) + goto not_unprepared; + if (!media->reusable && media->reused) goto is_reused; @@ -1309,10 +1309,17 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) /* OK */ was_prepared: { + GST_LOG ("media %p was prepared", media); g_rec_mutex_unlock (&media->state_lock); return TRUE; } /* ERRORS */ +not_unprepared: + { + GST_WARNING ("media %p was not unprepared", media); + g_rec_mutex_unlock (&media->state_lock); + return FALSE; + } is_reused: { g_rec_mutex_unlock (&media->state_lock); From dfe3efef743c2d73dbc0c6b607947812358c01d9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 13 Nov 2012 11:54:17 +0100 Subject: [PATCH 0485/1776] media: wait for concurrent _prepare If a prepare is busy, wait for the result. --- gst/rtsp-server/rtsp-media.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index df65a15e28..1797dac2ec 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1206,6 +1206,9 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) goto was_prepared; + if (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) + goto wait_status; + if (media->status != GST_RTSP_MEDIA_STATUS_UNPREPARED) goto not_unprepared; @@ -1292,6 +1295,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) case GST_STATE_CHANGE_FAILURE: goto state_failed; } +wait_status: g_rec_mutex_unlock (&media->state_lock); /* now wait for all pads to be prerolled, FIXME, we should somehow be From 7d6e4606fa1c4204c6e87a5f1ae0ef88aa4d565d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 13 Nov 2012 12:05:42 +0100 Subject: [PATCH 0486/1776] server: set default max-threads property --- gst/rtsp-server/rtsp-server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 0edf635a08..af44b537e8 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -192,6 +192,7 @@ gst_rtsp_server_init (GstRTSPServer * server) server->backlog = DEFAULT_BACKLOG; server->session_pool = gst_rtsp_session_pool_new (); server->media_mapping = gst_rtsp_media_mapping_new (); + server->max_threads = DEFAULT_MAX_THREADS; } static void From b30202b17450f5f591328255c712b1b19c90e779 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 14 Nov 2012 15:49:06 +0100 Subject: [PATCH 0487/1776] address-pool: add object to manage multicast addresses Make an object that can manage a rage of multicast addresses and ports. --- gst/rtsp-server/Makefile.am | 2 + gst/rtsp-server/rtsp-address-pool.c | 428 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-address-pool.h | 85 ++++++ 3 files changed, 515 insertions(+) create mode 100644 gst/rtsp-server/rtsp-address-pool.c create mode 100644 gst/rtsp-server/rtsp-address-pool.h diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 2d6a603875..f8da7447cd 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -1,5 +1,6 @@ public_headers = \ rtsp-auth.h \ + rtsp-address-pool.h \ rtsp-params.h \ rtsp-sdp.h \ rtsp-media.h \ @@ -16,6 +17,7 @@ public_headers = \ c_sources = \ rtsp-auth.c \ + rtsp-address-pool.c \ rtsp-params.c \ rtsp-sdp.c \ rtsp-media.c \ diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c new file mode 100644 index 0000000000..8a9e4a7f89 --- /dev/null +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -0,0 +1,428 @@ +/* GStreamer + * Copyright (C) 2012 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "rtsp-address-pool.h" + +GST_DEBUG_CATEGORY_STATIC (rtsp_address_pool_debug); +#define GST_CAT_DEFAULT rtsp_address_pool_debug + +#define GST_RTSP_ADDRESS_POOL_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_ADDRESS_POOL, GstRTSPAddressPoolPrivate)) + +struct _GstRTSPAddressPoolPrivate +{ + GMutex lock; + GList *addresses; + GList *allocated; +}; + +#define ADDR_IS_IPV4(a) ((a)->size == 4) +#define ADDR_IS_IPV6(a) ((a)->size == 16) +#define ADDR_IS_EVEN_PORT(a) (((a)->port & 1) == 0) + +typedef struct +{ + guint8 bytes[16]; + gsize size; + guint16 port; +} Addr; + +typedef struct +{ + Addr min; + Addr max; + guint8 ttl; +} AddrRange; + +#define RANGE_IS_SINGLE(r) (memcmp ((r)->min.bytes, (r)->max.bytes, (r)->min.size) == 0) + +#define gst_rtsp_address_pool_parent_class parent_class +G_DEFINE_TYPE (GstRTSPAddressPool, gst_rtsp_address_pool, G_TYPE_OBJECT); + +static void gst_rtsp_address_pool_finalize (GObject * obj); + +static void +gst_rtsp_address_pool_class_init (GstRTSPAddressPoolClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gst_rtsp_address_pool_finalize; + + g_type_class_add_private (klass, sizeof (GstRTSPAddressPoolPrivate)); + + GST_DEBUG_CATEGORY_INIT (rtsp_address_pool_debug, "rtspaddresspool", 0, + "GstRTSPAddressPool"); +} + +static void +gst_rtsp_address_pool_init (GstRTSPAddressPool * pool) +{ + pool->priv = GST_RTSP_ADDRESS_POOL_GET_PRIVATE (pool); + + g_mutex_init (&pool->priv->lock); +} + +static void +free_range (AddrRange * range) +{ + g_slice_free (AddrRange, range); +} + +static void +gst_rtsp_address_pool_finalize (GObject * obj) +{ + GstRTSPAddressPool *pool; + + pool = GST_RTSP_ADDRESS_POOL (obj); + + g_list_free_full (pool->priv->addresses, (GDestroyNotify) free_range); + g_list_free_full (pool->priv->allocated, (GDestroyNotify) free_range); + g_mutex_clear (&pool->priv->lock); + + G_OBJECT_CLASS (parent_class)->finalize (obj); +} + +/** + * gst_rtsp_address_pool_new: + * + * Make a new #GstRTSPAddressPool. + * + * Returns: a new #GstRTSPAddressPool + */ +GstRTSPAddressPool * +gst_rtsp_address_pool_new (void) +{ + GstRTSPAddressPool *pool; + + pool = g_object_new (GST_TYPE_RTSP_ADDRESS_POOL, NULL); + + return pool; +} + +static gboolean +fill_address (const gchar * address, guint16 port, Addr * addr) +{ + GInetAddress *inet; + + inet = g_inet_address_new_from_string (address); + if (inet == NULL) + return FALSE; + + addr->size = g_inet_address_get_native_size (inet); + memcpy (addr->bytes, g_inet_address_to_bytes (inet), addr->size); + g_object_unref (inet); + addr->port = port; + + return TRUE; +} + +/** + * gst_rtsp_address_pool_add_range: + * @pool: a #GstRTSPAddressPool + * @min_address: a minimum address to add + * @max_address: a maximum address to add + * @min_port: the minimum port + * @max_port: the maximum port + * @ttl: a TTL + * + * Adds the multicast addresses from @min_addess to @max_address (inclusive) + * to @pool. The valid port range for the addresses will be from @min_port to + * @max_port inclusive. + * + * Returns: %TRUE if the addresses could be added. + */ +gboolean +gst_rtsp_address_pool_add_range (GstRTSPAddressPool * pool, + const gchar * min_address, const gchar * max_address, + guint16 min_port, guint16 max_port, guint8 ttl) +{ + AddrRange *range; + GstRTSPAddressPoolPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), FALSE); + g_return_val_if_fail (min_port <= max_port, FALSE); + + priv = pool->priv; + + range = g_slice_new0 (AddrRange); + + if (!fill_address (min_address, min_port, &range->min)) + goto invalid; + if (!fill_address (max_address, max_port, &range->max)) + goto invalid; + + if (range->min.size != range->max.size) + goto invalid; + if (memcmp (range->min.bytes, range->max.bytes, range->min.size) > 0) + goto invalid; + + range->ttl = ttl; + + GST_DEBUG_OBJECT (pool, "adding %s-%s:%u-%u ttl %u", min_address, max_address, + min_port, max_port, ttl); + + g_mutex_lock (&priv->lock); + priv->addresses = g_list_prepend (priv->addresses, range); + g_mutex_unlock (&priv->lock); + + return TRUE; + + /* ERRORS */ +invalid: + { + GST_ERROR_OBJECT (pool, "invalid address range %s-%s", min_address, + max_address); + g_slice_free (AddrRange, range); + return FALSE; + } +} + +static void +inc_address (GstRTSPAddressPool * pool, Addr * addr) +{ + gint i; + guint carry; + + carry = 1; + for (i = addr->size - 1; i >= 0 && carry > 0; i--) { + carry += addr->bytes[i]; + addr->bytes[i] = carry & 0xff; + carry >>= 8; + } +} + +static AddrRange * +split_range (GstRTSPAddressPool * pool, AddrRange * range, gint skip, + gint n_ports) +{ + GstRTSPAddressPoolPrivate *priv = pool->priv; + AddrRange *temp; + + if (!RANGE_IS_SINGLE (range)) { + /* min and max are not the same, we have more than one address. */ + temp = g_slice_dup (AddrRange, range); + /* increment the range min address */ + inc_address (pool, &temp->min); + /* and store back in pool */ + priv->addresses = g_list_prepend (priv->addresses, temp); + + /* adjust range with only the first address */ + memcpy (range->max.bytes, range->min.bytes, range->min.size); + } + + /* range now contains only one single address */ + if (skip > 0) { + /* make a range with the skipped ports */ + temp = g_slice_dup (AddrRange, range); + temp->max.port = temp->min.port + skip; + /* and store back in pool */ + priv->addresses = g_list_prepend (priv->addresses, temp); + + /* increment range port */ + range->min.port += skip; + } + /* range now contains single address with desired port number */ + if (range->max.port - range->min.port + 1 > n_ports) { + /* make a range with the remaining ports */ + temp = g_slice_dup (AddrRange, range); + temp->min.port += n_ports; + /* and store back in pool */ + priv->addresses = g_list_prepend (priv->addresses, temp); + + /* and truncate port */ + range->max.port = range->min.port + n_ports - 1; + } + return range; +} + +/** + * gst_rtsp_address_pool_acquire_address: + * @pool: a #GstRTSPAddressPool + * @flags: flags + * @n_ports: the amount of ports + * @address: result address + * @port: result port + * @ttl: result TTL + * + * Take an address and ports from @pool. @flags can be used to control the + * allocation. @n_ports consecutive ports will be allocated of which the first + * one can be found in @port. + * + * Returns: a pointer that should be used to release the address with + * gst_rtsp_address_pool_release_address() after usage or %NULL when no + * address could be acquired. + */ +gpointer +gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, + GstRTSPAddressFlags flags, gint n_ports, gchar ** address, + guint16 * port, guint8 * ttl) +{ + GstRTSPAddressPoolPrivate *priv; + GList *walk, *next; + AddrRange *result; + + g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), NULL); + g_return_val_if_fail (n_ports > 0, NULL); + g_return_val_if_fail (address != NULL, NULL); + g_return_val_if_fail (port != NULL, NULL); + g_return_val_if_fail (ttl != NULL, NULL); + + priv = pool->priv; + result = NULL; + + g_mutex_lock (&priv->lock); + /* go over available ranges */ + for (walk = priv->addresses; walk; walk = next) { + AddrRange *range; + gint ports, skip; + + range = walk->data; + next = walk->next; + + /* check address type when given */ + if (flags & GST_RTSP_ADDRESS_FLAG_IPV4 && !ADDR_IS_IPV4 (&range->min)) + continue; + if (flags & GST_RTSP_ADDRESS_FLAG_IPV6 && !ADDR_IS_IPV6 (&range->min)) + continue; + + /* check for enough ports */ + ports = range->max.port - range->min.port + 1; + if (flags & GST_RTSP_ADDRESS_FLAG_EVEN_PORT + && !ADDR_IS_EVEN_PORT (&range->min)) + skip = 1; + else + skip = 0; + if (ports - skip < n_ports) + continue; + + /* we found a range, remove from the list */ + priv->addresses = g_list_delete_link (priv->addresses, walk); + /* now split and exit our loop */ + result = split_range (pool, range, skip, n_ports); + priv->allocated = g_list_prepend (priv->allocated, result); + break; + } + g_mutex_unlock (&priv->lock); + + if (result) { + GInetAddress *inet; + + inet = g_inet_address_new_from_bytes (result->min.bytes, + result->min.size == 4 ? G_SOCKET_FAMILY_IPV4 : G_SOCKET_FAMILY_IPV6); + + *address = g_inet_address_to_string (inet); + g_object_unref (inet); + + *port = result->min.port; + *ttl = result->ttl; + + GST_DEBUG_OBJECT (pool, "got address %s:%u ttl %u", *address, *port, *ttl); + } + return result; +} + +/** + * gst_rtsp_address_pool_release_address: + * @pool: a #GstRTSPAddressPool + * @id: an address id + * + * Release a previously acquired address (with + * gst_rtsp_address_pool_acquire_address()) back into @pool. + */ +void +gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool, gpointer id) +{ + GstRTSPAddressPoolPrivate *priv; + GList *find; + + g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool)); + g_return_if_fail (id != NULL); + + priv = pool->priv; + + g_mutex_lock (&priv->lock); + find = g_list_find (priv->allocated, id); + if (find == NULL) + goto not_found; + + priv->allocated = g_list_delete_link (priv->allocated, find); + + /* FIXME, merge and do something clever */ + priv->addresses = g_list_prepend (priv->addresses, id); + g_mutex_unlock (&priv->lock); + + return; + + /* ERRORS */ +not_found: + { + g_mutex_unlock (&priv->lock); + return; + } +} + +static void +dump_range (GstRTSPAddressPool * pool, AddrRange * range) +{ + GInetAddress *inet; + gchar *addr1, *addr2; + + inet = g_inet_address_new_from_bytes (range->min.bytes, + range->max.size == 4 ? G_SOCKET_FAMILY_IPV4 : G_SOCKET_FAMILY_IPV6); + addr1 = g_inet_address_to_string (inet); + g_object_unref (inet); + + inet = g_inet_address_new_from_bytes (range->max.bytes, + range->max.size == 4 ? G_SOCKET_FAMILY_IPV4 : G_SOCKET_FAMILY_IPV6); + addr2 = g_inet_address_to_string (inet); + g_object_unref (inet); + + g_print (" address %s-%s, port %u-%u, ttl %u\n", addr1, addr2, + range->min.port, range->max.port, range->ttl); + + g_free (addr1); + g_free (addr2); +} + +void +gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool) +{ + GstRTSPAddressPoolPrivate *priv; + GList *walk; + + g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool)); + + priv = pool->priv; + + g_mutex_lock (&priv->lock); + g_print ("free:\n"); + for (walk = priv->addresses; walk; walk = walk->next) { + dump_range (pool, (AddrRange *) walk->data); + } + g_print ("allocated:\n"); + for (walk = priv->allocated; walk; walk = walk->next) { + dump_range (pool, (AddrRange *) walk->data); + } + g_mutex_unlock (&priv->lock); +} diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h new file mode 100644 index 0000000000..57a52fc401 --- /dev/null +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -0,0 +1,85 @@ +/* GStreamer + * Copyright (C) 2012 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#ifndef __GST_RTSP_ADDRESS_POOL_H__ +#define __GST_RTSP_ADDRESS_POOL_H__ + +G_BEGIN_DECLS + +#define GST_TYPE_RTSP_ADDRESS_POOL (gst_rtsp_address_pool_get_type ()) +#define GST_IS_RTSP_ADDRESS_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_ADDRESS_POOL)) +#define GST_IS_RTSP_ADDRESS_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_ADDRESS_POOL)) +#define GST_RTSP_ADDRESS_POOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_ADDRESS_POOL, GstRTSPAddressPoolClass)) +#define GST_RTSP_ADDRESS_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_ADDRESS_POOL, GstRTSPAddressPool)) +#define GST_RTSP_ADDRESS_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_ADDRESS_POOL, GstRTSPAddressPoolClass)) +#define GST_RTSP_ADDRESS_POOL_CAST(obj) ((GstRTSPAddressPool*)(obj)) +#define GST_RTSP_ADDRESS_POOL_CLASS_CAST(klass) ((GstRTSPAddressPoolClass*)(klass)) + +typedef struct _GstRTSPAddressPool GstRTSPAddressPool; +typedef struct _GstRTSPAddressPoolClass GstRTSPAddressPoolClass; +typedef struct _GstRTSPAddressPoolPrivate GstRTSPAddressPoolPrivate; + +typedef enum { + GST_RTSP_ADDRESS_FLAG_NONE = 0, + GST_RTSP_ADDRESS_FLAG_IPV4 = (1 << 0), + GST_RTSP_ADDRESS_FLAG_IPV6 = (1 << 1), + GST_RTSP_ADDRESS_FLAG_EVEN_PORT = (1 << 2) +} GstRTSPAddressFlags; + +/** + * GstRTSPAddressPool: + * @parent: the parent GObject + * + */ +struct _GstRTSPAddressPool { + GObject parent; + + GstRTSPAddressPoolPrivate *priv; +}; + +struct _GstRTSPAddressPoolClass { + GObjectClass parent_class; +}; + +GType gst_rtsp_address_pool_get_type (void); + +/* create a new address pool */ +GstRTSPAddressPool * gst_rtsp_address_pool_new (void); + +void gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool); + +gboolean gst_rtsp_address_pool_add_range (GstRTSPAddressPool * pool, + const gchar *min_address, + const gchar *max_address, + guint16 min_port, + guint16 max_port, + guint8 ttl); + +gpointer gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, + GstRTSPAddressFlags flags, + gint n_ports, + gchar **address, + guint16 *port, guint8 *ttl); +void gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool, + gpointer); +G_END_DECLS + +#endif /* __GST_RTSP_ADDRESS_POOL_H__ */ From d6fcf926010e9b90fbae67d7d53cd3578ec83117 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 14 Nov 2012 15:50:42 +0100 Subject: [PATCH 0488/1776] tests: add addresspool unit test --- tests/check/Makefile.am | 33 +++++--------- tests/check/gst/addresspool.c | 83 +++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 21 deletions(-) create mode 100644 tests/check/gst/addresspool.c diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 458cd47176..c9c438abad 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -26,35 +26,26 @@ $(CHECK_REGISTRY): TESTS = $(check_PROGRAMS) check_PROGRAMS = \ - gst/rtspserver + gst/rtspserver \ + gst/addresspool # these tests don't even pass noinst_PROGRAMS = -AM_CFLAGS = $(GST_CFLAGS) $(GST_CHECK_CFLAGS) \ +AM_CFLAGS = -I$(top_srcdir)/gst/rtsp-server \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GIO_CFLAGS) \ + $(GST_CFLAGS) \ + $(GST_CHECK_CFLAGS) \ -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS AM_CXXFLAGS = $(GST_CXXFLAGS) $(GST_CHECK_CFLAGS) \ -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS -LDADD = $(GST_LIBS) $(GST_CHECK_LIBS) $(GST_RTSP_SERVER_LIBS) - -SUPPRESSIONS = $(top_srcdir)/common/gst.supp - -gst_rtspserver_SOURCES = gst/rtspserver.c \ - $(top_srcdir)/gst/rtsp-server/rtsp-server.h - -gst_rtspserver_CFLAGS = \ - -I$(top_srcdir)/gst/rtsp-server \ - $(GST_PLUGINS_GOOD_CFLAGS) \ - $(GST_PLUGINS_BASE_CFLAGS) \ - $(GST_BASE_CFLAGS) \ - $(GIO_CFLAGS) \ - $(AM_CFLAGS) - -gst_rtspserver_LDADD = \ - $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la \ - $(GST_PLUGINS_GOOD_LIBS) \ +LDADD = $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la \ $(GST_BASE_LIBS) -lgstrtsp-@GST_API_VERSION@ -lgstsdp-@GST_API_VERSION@ \ $(GIO_LIBS) \ - $(LDADD) + $(GST_LIBS) $(GST_CHECK_LIBS) $(GST_RTSP_SERVER_LIBS) + +SUPPRESSIONS = $(top_srcdir)/common/gst.supp diff --git a/tests/check/gst/addresspool.c b/tests/check/gst/addresspool.c new file mode 100644 index 0000000000..7e25f7a694 --- /dev/null +++ b/tests/check/gst/addresspool.c @@ -0,0 +1,83 @@ +/* GStreamer + * Copyright (C) 2012 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +GST_START_TEST (test_pool) +{ + gpointer id; + GstRTSPAddressPool *pool; + gchar *address; + guint16 port; + guint8 ttl; + + pool = gst_rtsp_address_pool_new (); + + fail_if (gst_rtsp_address_pool_add_range (pool, + "233.252.0.1", "233.252.0.0", 5000, 5010, 1)); + ASSERT_CRITICAL (gst_rtsp_address_pool_add_range (pool, + "233.252.0.0", "233.252.0.1", 5010, 5000, 1)); + + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.252.0.0", "233.252.0.255", 5000, 5010, 1)); + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.255.0.0", "233.255.0.0", 5000, 5010, 1)); + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.255.0.0", "233.255.0.0", 5020, 5020, 1)); + + /* should fail, we can't allocate a block of 256 ports */ + id = gst_rtsp_address_pool_acquire_address (pool, + 0, 256, &address, &port, &ttl); + fail_unless (id == NULL); + + id = gst_rtsp_address_pool_acquire_address (pool, + 0, 2, &address, &port, &ttl); + fail_unless (id != NULL); + + gst_rtsp_address_pool_release_address (pool, id); + g_free (address); + + id = gst_rtsp_address_pool_acquire_address (pool, + 0, 4, &address, &port, &ttl); + fail_unless (id != NULL); + + gst_rtsp_address_pool_release_address (pool, id); + g_free (address); + + g_object_unref (pool); +} + +GST_END_TEST; + +static Suite * +rtspaddresspool_suite (void) +{ + Suite *s = suite_create ("rtspaddresspool"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_set_timeout (tc, 20); + tcase_add_test (tc, test_pool); + + return s; +} + +GST_CHECK_MAIN (rtspaddresspool); From 6085b1fcc12a494c9100e29eb64ef2a41cf31a03 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 14 Nov 2012 16:10:45 +0100 Subject: [PATCH 0489/1776] address-pool: small cleanups --- gst/rtsp-server/rtsp-address-pool.c | 55 ++++++++++++++--------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 8a9e4a7f89..957814efeb 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -137,6 +137,20 @@ fill_address (const gchar * address, guint16 port, Addr * addr) return TRUE; } +static gchar * +get_address_string (Addr * addr) +{ + gchar *res; + GInetAddress *inet; + + inet = g_inet_address_new_from_bytes (addr->bytes, + addr->size == 4 ? G_SOCKET_FAMILY_IPV4 : G_SOCKET_FAMILY_IPV6); + res = g_inet_address_to_string (inet); + g_object_unref (inet); + + return res; +} + /** * gst_rtsp_address_pool_add_range: * @pool: a #GstRTSPAddressPool @@ -326,14 +340,7 @@ gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, g_mutex_unlock (&priv->lock); if (result) { - GInetAddress *inet; - - inet = g_inet_address_new_from_bytes (result->min.bytes, - result->min.size == 4 ? G_SOCKET_FAMILY_IPV4 : G_SOCKET_FAMILY_IPV6); - - *address = g_inet_address_to_string (inet); - g_object_unref (inet); - + *address = get_address_string (&result->min); *port = result->min.port; *ttl = result->ttl; @@ -377,39 +384,35 @@ gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool, gpointer id) /* ERRORS */ not_found: { + g_warning ("Released unknown id %p", id); g_mutex_unlock (&priv->lock); return; } } static void -dump_range (GstRTSPAddressPool * pool, AddrRange * range) +dump_range (AddrRange * range, GstRTSPAddressPool * pool) { - GInetAddress *inet; gchar *addr1, *addr2; - inet = g_inet_address_new_from_bytes (range->min.bytes, - range->max.size == 4 ? G_SOCKET_FAMILY_IPV4 : G_SOCKET_FAMILY_IPV6); - addr1 = g_inet_address_to_string (inet); - g_object_unref (inet); - - inet = g_inet_address_new_from_bytes (range->max.bytes, - range->max.size == 4 ? G_SOCKET_FAMILY_IPV4 : G_SOCKET_FAMILY_IPV6); - addr2 = g_inet_address_to_string (inet); - g_object_unref (inet); - + addr1 = get_address_string (&range->min); + addr2 = get_address_string (&range->max); g_print (" address %s-%s, port %u-%u, ttl %u\n", addr1, addr2, range->min.port, range->max.port, range->ttl); - g_free (addr1); g_free (addr2); } +/** + * gst_rtsp_address_pool_dump: + * @pool: a #GstRTSPAddressPool + * + * Dump the free and allocated addresses to stdout. + */ void gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool) { GstRTSPAddressPoolPrivate *priv; - GList *walk; g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool)); @@ -417,12 +420,8 @@ gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool) g_mutex_lock (&priv->lock); g_print ("free:\n"); - for (walk = priv->addresses; walk; walk = walk->next) { - dump_range (pool, (AddrRange *) walk->data); - } + g_list_foreach (priv->addresses, (GFunc) dump_range, pool); g_print ("allocated:\n"); - for (walk = priv->allocated; walk; walk = walk->next) { - dump_range (pool, (AddrRange *) walk->data); - } + g_list_foreach (priv->allocated, (GFunc) dump_range, pool); g_mutex_unlock (&priv->lock); } From d0ffc8e67954a73489c1c95f7c8932f5c290dd8b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 14 Nov 2012 16:17:33 +0100 Subject: [PATCH 0490/1776] address-pool: add clear method --- gst/rtsp-server/rtsp-address-pool.c | 23 +++++++++++++++++++++++ gst/rtsp-server/rtsp-address-pool.h | 1 + 2 files changed, 24 insertions(+) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 957814efeb..194e29094a 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -120,6 +120,29 @@ gst_rtsp_address_pool_new (void) return pool; } +/** + * gst_rtsp_address_pool_clear: + * @pool: a #GstRTSPAddressPool + * + * Clear all addresses in @pool. There should be no outstanding + * allocations. + */ +void +gst_rtsp_address_pool_clear (GstRTSPAddressPool * pool) +{ + GstRTSPAddressPoolPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool)); + g_return_if_fail (pool->priv->allocated == NULL); + + priv = pool->priv; + + g_mutex_lock (&priv->lock); + g_list_free_full (priv->addresses, (GDestroyNotify) free_range); + priv->addresses = NULL; + g_mutex_unlock (&priv->lock); +} + static gboolean fill_address (const gchar * address, guint16 port, Addr * addr) { diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index 57a52fc401..d29e1e0170 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -64,6 +64,7 @@ GType gst_rtsp_address_pool_get_type (void); /* create a new address pool */ GstRTSPAddressPool * gst_rtsp_address_pool_new (void); +void gst_rtsp_address_pool_clear (GstRTSPAddressPool * pool); void gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool); gboolean gst_rtsp_address_pool_add_range (GstRTSPAddressPool * pool, From f15ffb521c894910d82c34eec1c11745dde324c7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 14 Nov 2012 17:23:59 +0100 Subject: [PATCH 0491/1776] rtsp: use AddressPool Remove the multicast_group property. Use the configured addresspool to allocate multicast addresses. --- gst/rtsp-server/rtsp-client.c | 49 ++++++++++-- gst/rtsp-server/rtsp-media-factory.c | 68 ++++++++--------- gst/rtsp-server/rtsp-media-factory.h | 12 +-- gst/rtsp-server/rtsp-media.c | 109 +++++++++++++-------------- gst/rtsp-server/rtsp-media.h | 9 ++- 5 files changed, 139 insertions(+), 108 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 38fffb894c..7dbddce77b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -978,13 +978,26 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, /* we have a valid transport now, set the destination of the client. */ if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { if (ct->destination == NULL || !client->use_client_settings) { + GstRTSPAddressPool *pool; + gchar *address; + guint16 port; + guint8 ttl; + gpointer id; + + pool = gst_rtsp_media_get_address_pool (state->media); + if (pool == NULL) + goto no_pool; + + id = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2, &address, &port, &ttl); + if (id == NULL) + goto no_address; + g_free (ct->destination); - ct->destination = gst_rtsp_media_get_multicast_group (state->media); - } - /* reset ttl and port if client settings are not allowed */ - if (!client->use_client_settings) { - ct->port = state->stream->server_port; - ct->ttl = 0; + ct->destination = address; + ct->port.min = port; + ct->port.max = port + 1; + ct->ttl = ttl; } } else { GstRTSPUrl *url; @@ -1002,6 +1015,16 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, } } return TRUE; + + /* ERRORS */ +no_pool: + { + return FALSE; + } +no_address: + { + return FALSE; + } } static GstRTSPTransport * @@ -1143,7 +1166,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) goto invalid_blocksize; /* update the client transport */ - configure_client_transport (client, state, ct); + if (!configure_client_transport (client, state, ct)) + goto unsupported_client_transport; /* set in the session media transport */ trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct); @@ -1206,6 +1230,13 @@ invalid_blocksize: gst_rtsp_transport_free (ct); return FALSE; } +unsupported_client_transport: + { + send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); + g_object_unref (session); + gst_rtsp_transport_free (ct); + return FALSE; + } no_transport: { send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); @@ -1262,7 +1293,11 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) info.server_proto = proto; protocols = gst_rtsp_media_get_protocols (media); if (protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) +#if 0 info.server_ip = gst_rtsp_media_get_multicast_group (media); +#else + info.server_ip = g_strdup (client->server_ip); +#endif else info.server_ip = g_strdup (client->server_ip); diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 2a6cbd7e53..1140e8bbd5 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -24,7 +24,6 @@ #define DEFAULT_EOS_SHUTDOWN FALSE #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_BUFFER_SIZE 0x80000 -#define DEFAULT_MULTICAST_GROUP "224.2.0.1" enum { @@ -34,7 +33,6 @@ enum PROP_EOS_SHUTDOWN, PROP_PROTOCOLS, PROP_BUFFER_SIZE, - PROP_MULTICAST_GROUP, PROP_LAST }; @@ -121,11 +119,6 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "The kernel UDP buffer size to use", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP, - g_param_spec_string ("multicast-group", "Multicast Group", - "The Multicast group to send media to", - DEFAULT_MULTICAST_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, @@ -156,7 +149,6 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN; factory->protocols = DEFAULT_PROTOCOLS; factory->buffer_size = DEFAULT_BUFFER_SIZE; - factory->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP); g_mutex_init (&factory->lock); g_mutex_init (&factory->medias_lock); @@ -172,10 +164,11 @@ gst_rtsp_media_factory_finalize (GObject * obj) g_hash_table_unref (factory->medias); g_mutex_clear (&factory->medias_lock); g_free (factory->launch); - g_free (factory->multicast_group); g_mutex_clear (&factory->lock); if (factory->auth) g_object_unref (factory->auth); + if (factory->pool) + g_object_unref (factory->pool); G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj); } @@ -204,10 +197,6 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_uint (value, gst_rtsp_media_factory_get_buffer_size (factory)); break; - case PROP_MULTICAST_GROUP: - g_value_take_string (value, - gst_rtsp_media_factory_get_multicast_group (factory)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -237,10 +226,6 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_buffer_size (factory, g_value_get_uint (value)); break; - case PROP_MULTICAST_GROUP: - gst_rtsp_media_factory_set_multicast_group (factory, - g_value_get_string (value)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -438,41 +423,50 @@ gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory) } /** - * gst_rtsp_media_factory_set_multicast_group: - * @factory: a #GstRTSPMedia - * @mc: the new multicast group + * gst_rtsp_media_factory_set_address_pool: + * @factory: a #GstRTSPMediaFactory + * @pool: a #GstRTSPAddressPool * - * Set the multicast group that media from @factory will be streamed to. + * configure @pool to be used as the address pool of @factory. */ void -gst_rtsp_media_factory_set_multicast_group (GstRTSPMediaFactory * factory, - const gchar * mc) +gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory, + GstRTSPAddressPool * pool) { + GstRTSPAddressPool *old; + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); GST_RTSP_MEDIA_FACTORY_LOCK (factory); - g_free (factory->multicast_group); - factory->multicast_group = g_strdup (mc); + if ((old = factory->pool) != pool) + factory->pool = pool ? g_object_ref (pool) : NULL; + else + old = NULL; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + if (old) + g_object_unref (old); } /** - * gst_rtsp_media_factory_get_multicast_group: - * @factory: a #GstRTSPMedia + * gst_rtsp_media_factory_get_address_pool: + * @factory: a #GstRTSPMediaFactory * - * Get the multicast group that media from @factory will be streamed to. + * Get the #GstRTSPAddressPool used as the address pool of @factory. * - * Returns: the multicast group + * Returns: (transfer full): the #GstRTSPAddressPool of @factory. g_object_unref() after + * usage. */ -gchar * -gst_rtsp_media_factory_get_multicast_group (GstRTSPMediaFactory * factory) +GstRTSPAddressPool * +gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory) { - gchar *result; + GstRTSPAddressPool *result; g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); GST_RTSP_MEDIA_FACTORY_LOCK (factory); - result = g_strdup (factory->multicast_group); + if ((result = factory->pool)) + g_object_ref (result); GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); return result; @@ -808,7 +802,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) guint size; GstRTSPAuth *auth; GstRTSPLowerTrans protocols; - gchar *mc; + GstRTSPAddressPool *pool; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -827,9 +821,9 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_auth (media, auth); g_object_unref (auth); } - if ((mc = gst_rtsp_media_factory_get_multicast_group (factory))) { - gst_rtsp_media_set_multicast_group (media, mc); - g_free (mc); + if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) { + gst_rtsp_media_set_address_pool (media, pool); + g_object_unref (pool); } } diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 167dcd5061..2a4745acf9 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -22,6 +22,7 @@ #include "rtsp-media.h" #include "rtsp-auth.h" +#include "rtsp-address-pool.h" #ifndef __GST_RTSP_MEDIA_FACTORY_H__ #define __GST_RTSP_MEDIA_FACTORY_H__ @@ -55,7 +56,7 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; * @protocols: allowed transport protocols * @auth: the authentication manager * @buffer_size: the kernel udp buffer size - * @multicast_group: the multicast group to send to + * @pool: the multicast address pool to use * @medias_lock: mutex protecting the medias. * @medias: hashtable of shared media * @@ -72,7 +73,7 @@ struct _GstRTSPMediaFactory { GstRTSPLowerTrans protocols; GstRTSPAuth *auth; guint buffer_size; - gchar *multicast_group; + GstRTSPAddressPool *pool; GMutex medias_lock; GHashTable *medias; @@ -139,12 +140,13 @@ GstRTSPLowerTrans gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory void gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory *factory, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory, + GstRTSPAddressPool * pool); +GstRTSPAddressPool * gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory); + void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint size); guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory); -void gst_rtsp_media_factory_set_multicast_group (GstRTSPMediaFactory * factory, const gchar *mc); -gchar * gst_rtsp_media_factory_get_multicast_group (GstRTSPMediaFactory * factory); - /* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1797dac2ec..4052cf119c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -31,7 +31,6 @@ //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST #define DEFAULT_EOS_SHUTDOWN FALSE #define DEFAULT_BUFFER_SIZE 0x80000 -#define DEFAULT_MULTICAST_GROUP "224.2.0.1" #define DEFAULT_MTU 0 /* define to dump received RTCP packets */ @@ -45,7 +44,6 @@ enum PROP_PROTOCOLS, PROP_EOS_SHUTDOWN, PROP_BUFFER_SIZE, - PROP_MULTICAST_GROUP, PROP_MTU, PROP_LAST }; @@ -113,11 +111,6 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "The kernel UDP buffer size to use", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP, - g_param_spec_string ("multicast-group", "Multicast Group", - "The Multicast group to send media to", - DEFAULT_MULTICAST_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_MTU, g_param_spec_uint ("mtu", "MTU", "The MTU for the payloaders (0 = default)", @@ -163,7 +156,6 @@ gst_rtsp_media_init (GstRTSPMedia * media) media->protocols = DEFAULT_PROTOCOLS; media->eos_shutdown = DEFAULT_EOS_SHUTDOWN; media->buffer_size = DEFAULT_BUFFER_SIZE; - media->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP); } static void @@ -185,7 +177,10 @@ gst_rtsp_media_finalize (GObject * obj) g_source_destroy (media->source); g_source_unref (media->source); } - g_free (media->multicast_group); + if (media->auth) + g_object_unref (media->auth); + if (media->pool) + g_object_unref (media->pool); g_mutex_clear (&media->lock); g_cond_clear (&media->cond); g_rec_mutex_clear (&media->state_lock); @@ -215,9 +210,6 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_BUFFER_SIZE: g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media)); break; - case PROP_MULTICAST_GROUP: - g_value_take_string (value, gst_rtsp_media_get_multicast_group (media)); - break; case PROP_MTU: g_value_set_uint (value, gst_rtsp_media_get_mtu (media)); break; @@ -248,9 +240,6 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_BUFFER_SIZE: gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value)); break; - case PROP_MULTICAST_GROUP: - gst_rtsp_media_set_multicast_group (media, g_value_get_string (value)); - break; case PROP_MTU: gst_rtsp_media_set_mtu (media, g_value_get_uint (value)); break; @@ -539,46 +528,6 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) return res; } -/** - * gst_rtsp_media_set_multicast_group: - * @media: a #GstRTSPMedia - * @mc: the new multicast group - * - * Set the multicast group that media from @media will be streamed to. - */ -void -gst_rtsp_media_set_multicast_group (GstRTSPMedia * media, const gchar * mc) -{ - g_return_if_fail (GST_IS_RTSP_MEDIA (media)); - - g_mutex_lock (&media->lock); - g_free (media->multicast_group); - media->multicast_group = g_strdup (mc); - g_mutex_unlock (&media->lock); -} - -/** - * gst_rtsp_media_get_multicast_group: - * @media: (transfer full): a #GstRTSPMedia - * - * Get the multicast group that media from @media will be streamed to. - * - * Returns: the multicast group, g_free after usage. - */ -gchar * -gst_rtsp_media_get_multicast_group (GstRTSPMedia * media) -{ - gchar *result; - - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - - g_mutex_lock (&media->lock); - result = g_strdup (media->multicast_group); - g_mutex_unlock (&media->lock); - - return result; -} - /** * gst_rtsp_media_set_auth: * @media: a #GstRTSPMedia @@ -628,6 +577,56 @@ gst_rtsp_media_get_auth (GstRTSPMedia * media) return result; } +/** + * gst_rtsp_media_set_address_pool: + * @media: a #GstRTSPMedia + * @pool: a #GstRTSPAddressPool + * + * configure @pool to be used as the address pool of @media. + */ +void +gst_rtsp_media_set_address_pool (GstRTSPMedia * media, + GstRTSPAddressPool * pool) +{ + GstRTSPAddressPool *old; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + g_mutex_lock (&media->lock); + if ((old = media->pool) != pool) + media->pool = pool ? g_object_ref (pool) : NULL; + else + old = NULL; + g_mutex_unlock (&media->lock); + + if (old) + g_object_unref (old); +} + +/** + * gst_rtsp_media_get_address_pool: + * @media: a #GstRTSPMedia + * + * Get the #GstRTSPAddressPool used as the address pool of @media. + * + * Returns: (transfer full): the #GstRTSPAddressPool of @media. g_object_unref() after + * usage. + */ +GstRTSPAddressPool * +gst_rtsp_media_get_address_pool (GstRTSPMedia * media) +{ + GstRTSPAddressPool *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + + g_mutex_lock (&media->lock); + if ((result = media->pool)) + g_object_ref (result); + g_mutex_unlock (&media->lock); + + return result; +} + /** * gst_rtsp_media_set_mtu: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index bf2d0e5663..22889e4af4 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -41,6 +41,7 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass; #include "rtsp-stream.h" #include "rtsp-auth.h" +#include "rtsp-address-pool.h" /** * GstRTSPMediaStatus: @@ -112,7 +113,7 @@ struct _GstRTSPMedia { gboolean eos_shutdown; guint buffer_size; GstRTSPAuth *auth; - gchar *multicast_group; + GstRTSPAddressPool*pool; guint mtu; GstElement *element; @@ -191,12 +192,12 @@ gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media); void gst_rtsp_media_set_auth (GstRTSPMedia *media, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_media_get_auth (GstRTSPMedia *media); +void gst_rtsp_media_set_address_pool (GstRTSPMedia *media, GstRTSPAddressPool *pool); +GstRTSPAddressPool * gst_rtsp_media_get_address_pool (GstRTSPMedia *media); + void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size); guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media); -void gst_rtsp_media_set_multicast_group (GstRTSPMedia *media, const gchar * mc); -gchar * gst_rtsp_media_get_multicast_group (GstRTSPMedia *media); - void gst_rtsp_media_set_mtu (GstRTSPMedia *media, guint mtu); guint gst_rtsp_media_get_mtu (GstRTSPMedia *media); From fde8c01a85571950ec586c971a8cd7d11b2258e1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 13:22:54 +0100 Subject: [PATCH 0492/1776] examples: add multicast example Show how to set up the multicast address pool so that media can be server with multicast. --- examples/Makefile.am | 4 +- examples/test-multicast.c | 99 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 examples/test-multicast.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 9c643050ad..32537a47e8 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,4 +1,6 @@ -noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp test-uri test-auth +noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ + test-launch test-sdp test-uri test-auth \ + test-multicast #INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/examples/test-multicast.c b/examples/test-multicast.c new file mode 100644 index 0000000000..0156a8c5af --- /dev/null +++ b/examples/test-multicast.c @@ -0,0 +1,99 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + + +static gboolean +timeout (GstRTSPServer * server, gboolean ignored) +{ + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_cleanup (pool); + g_object_unref (pool); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMediaMapping *mapping; + GstRTSPMediaFactory *factory; + GstRTSPAddressPool *pool; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mapping for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mapping = gst_rtsp_server_get_media_mapping (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, "( " + "videotestsrc ! video/x-raw,width=352,height=288,framerate=15/1 ! " + "x264enc ! rtph264pay name=pay0 pt=96 " + "audiotestsrc ! audio/x-raw,rate=8000 ! " + "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); + + /* make a new address pool */ + pool = gst_rtsp_address_pool_new (); + gst_rtsp_address_pool_add_range (pool, + "224.3.0.0", "224.3.0.10", 5000, 5010, 1); + gst_rtsp_media_factory_set_address_pool (factory, pool); + g_object_unref (pool); + + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mapping); + + /* attach the server to the default maincontext */ + if (gst_rtsp_server_attach (server, NULL) == 0) + goto failed; + + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + + /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + g_main_loop_run (loop); + + return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } +} From 45b6693b39b44f8f29d51dc008f4efacff697247 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 13:25:14 +0100 Subject: [PATCH 0493/1776] rtsp: make address-pool return an address object Return a boxed GstRTSPAddress from the GstRTSPAddressPool. This allows us to store more info in the structure and allows us to more easily return the address to the right pool when no longer needed. Pass the address to the StreamTransport so that we can return it to the pool when the stream transport is freed or changed. --- gst/rtsp-server/rtsp-address-pool.c | 93 +++++++++++++++++++------ gst/rtsp-server/rtsp-address-pool.h | 27 +++++-- gst/rtsp-server/rtsp-client.c | 31 +++++---- gst/rtsp-server/rtsp-session-media.c | 7 +- gst/rtsp-server/rtsp-session-media.h | 3 +- gst/rtsp-server/rtsp-stream-transport.c | 17 +++-- gst/rtsp-server/rtsp-stream-transport.h | 9 ++- tests/check/gst/addresspool.c | 26 +++---- 8 files changed, 143 insertions(+), 70 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 194e29094a..45a969b497 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -22,6 +22,43 @@ #include "rtsp-address-pool.h" +GstRTSPAddress * +gst_rtsp_address_copy (GstRTSPAddress * addr) +{ + GstRTSPAddress *copy; + + g_return_val_if_fail (addr != NULL, NULL); + + copy = g_slice_dup (GstRTSPAddress, addr); + /* only release to the pool when the original is freed. It's a bit + * weird but this will do for now as it avoid us to use refcounting. */ + copy->pool = NULL; + copy->address = g_strdup (copy->address); + + return copy; +} + +static void gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool, + GstRTSPAddress * addr); + +void +gst_rtsp_address_free (GstRTSPAddress * addr) +{ + g_return_if_fail (addr != NULL); + + if (addr->pool) { + /* unrefs the pool and sets it to NULL */ + gst_rtsp_address_pool_release_address (addr->pool, addr); + } + g_free (addr->address); + g_slice_free (GstRTSPAddress, addr); +} + + +G_DEFINE_BOXED_TYPE (GstRTSPAddress, gst_rtsp_address, + (GBoxedCopyFunc) gst_rtsp_address_copy, + (GBoxedFreeFunc) gst_rtsp_address_free); + GST_DEBUG_CATEGORY_STATIC (rtsp_address_pool_debug); #define GST_CAT_DEFAULT rtsp_address_pool_debug @@ -298,35 +335,29 @@ split_range (GstRTSPAddressPool * pool, AddrRange * range, gint skip, * @pool: a #GstRTSPAddressPool * @flags: flags * @n_ports: the amount of ports - * @address: result address - * @port: result port - * @ttl: result TTL * * Take an address and ports from @pool. @flags can be used to control the * allocation. @n_ports consecutive ports will be allocated of which the first * one can be found in @port. * - * Returns: a pointer that should be used to release the address with - * gst_rtsp_address_pool_release_address() after usage or %NULL when no - * address could be acquired. + * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free + * after use or %NULL when no address could be acquired. */ -gpointer +GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, - GstRTSPAddressFlags flags, gint n_ports, gchar ** address, - guint16 * port, guint8 * ttl) + GstRTSPAddressFlags flags, gint n_ports) { GstRTSPAddressPoolPrivate *priv; GList *walk, *next; AddrRange *result; + GstRTSPAddress *addr; g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), NULL); g_return_val_if_fail (n_ports > 0, NULL); - g_return_val_if_fail (address != NULL, NULL); - g_return_val_if_fail (port != NULL, NULL); - g_return_val_if_fail (ttl != NULL, NULL); priv = pool->priv; result = NULL; + addr = NULL; g_mutex_lock (&priv->lock); /* go over available ranges */ @@ -363,13 +394,19 @@ gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, g_mutex_unlock (&priv->lock); if (result) { - *address = get_address_string (&result->min); - *port = result->min.port; - *ttl = result->ttl; + addr = g_slice_new0 (GstRTSPAddress); + addr->pool = g_object_ref (pool); + addr->address = get_address_string (&result->min); + addr->n_ports = n_ports; + addr->port = result->min.port; + addr->ttl = result->ttl; + addr->priv = result; - GST_DEBUG_OBJECT (pool, "got address %s:%u ttl %u", *address, *port, *ttl); + GST_DEBUG_OBJECT (pool, "got address %s:%u ttl %u", addr->address, + addr->port, addr->ttl); } - return result; + + return addr; } /** @@ -380,34 +417,44 @@ gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, * Release a previously acquired address (with * gst_rtsp_address_pool_acquire_address()) back into @pool. */ -void -gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool, gpointer id) +static void +gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool, + GstRTSPAddress * addr) { GstRTSPAddressPoolPrivate *priv; GList *find; + AddrRange *range; g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool)); - g_return_if_fail (id != NULL); + g_return_if_fail (addr != NULL); + g_return_if_fail (addr->pool == pool); priv = pool->priv; + range = addr->priv; + + /* we don't want to free twice */ + addr->priv = NULL; + addr->pool = NULL; g_mutex_lock (&priv->lock); - find = g_list_find (priv->allocated, id); + find = g_list_find (priv->allocated, range); if (find == NULL) goto not_found; priv->allocated = g_list_delete_link (priv->allocated, find); /* FIXME, merge and do something clever */ - priv->addresses = g_list_prepend (priv->addresses, id); + priv->addresses = g_list_prepend (priv->addresses, range); g_mutex_unlock (&priv->lock); + g_object_unref (pool); + return; /* ERRORS */ not_found: { - g_warning ("Released unknown id %p", id); + g_warning ("Released unknown address %p", addr); g_mutex_unlock (&priv->lock); return; } diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index d29e1e0170..b8937907e9 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -33,10 +33,29 @@ G_BEGIN_DECLS #define GST_RTSP_ADDRESS_POOL_CAST(obj) ((GstRTSPAddressPool*)(obj)) #define GST_RTSP_ADDRESS_POOL_CLASS_CAST(klass) ((GstRTSPAddressPoolClass*)(klass)) +typedef struct _GstRTSPAddress GstRTSPAddress; +typedef struct _GstRTSPAddressClass GstRTSPAddressClass; + typedef struct _GstRTSPAddressPool GstRTSPAddressPool; typedef struct _GstRTSPAddressPoolClass GstRTSPAddressPoolClass; typedef struct _GstRTSPAddressPoolPrivate GstRTSPAddressPoolPrivate; +struct _GstRTSPAddress { + GstRTSPAddressPool *pool; + + gchar *address; + guint16 port; + gint n_ports; + guint8 ttl; + + gpointer priv; +}; + +GType gst_rtsp_address_get_type (void); + +GstRTSPAddress * gst_rtsp_address_copy (GstRTSPAddress *addr); +void gst_rtsp_address_free (GstRTSPAddress *addr); + typedef enum { GST_RTSP_ADDRESS_FLAG_NONE = 0, GST_RTSP_ADDRESS_FLAG_IPV4 = (1 << 0), @@ -74,13 +93,9 @@ gboolean gst_rtsp_address_pool_add_range (GstRTSPAddressPool guint16 max_port, guint8 ttl); -gpointer gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, +GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, GstRTSPAddressFlags flags, - gint n_ports, - gchar **address, - guint16 *port, guint8 *ttl); -void gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool, - gpointer); + gint n_ports); G_END_DECLS #endif /* __GST_RTSP_ADDRESS_POOL_H__ */ diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 7dbddce77b..a9582e0594 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -973,31 +973,30 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request) static gboolean configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, - GstRTSPTransport * ct) + GstRTSPTransport * ct, GstRTSPAddress ** addr) { /* we have a valid transport now, set the destination of the client. */ if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { if (ct->destination == NULL || !client->use_client_settings) { GstRTSPAddressPool *pool; - gchar *address; - guint16 port; - guint8 ttl; - gpointer id; + GstRTSPAddress *ad; pool = gst_rtsp_media_get_address_pool (state->media); if (pool == NULL) goto no_pool; - id = gst_rtsp_address_pool_acquire_address (pool, - GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2, &address, &port, &ttl); - if (id == NULL) + ad = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); + if (ad == NULL) goto no_address; g_free (ct->destination); - ct->destination = address; - ct->port.min = port; - ct->port.max = port + 1; - ct->ttl = ttl; + ct->destination = g_strdup (ad->address); + ct->port.min = ad->port; + ct->port.max = ad->port + 1; + ct->ttl = ad->ttl; + + *addr = ad; } } else { GstRTSPUrl *url; @@ -1019,10 +1018,12 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, /* ERRORS */ no_pool: { + GST_ERROR_OBJECT (client, "no address pool specified"); return FALSE; } no_address: { + GST_ERROR_OBJECT (client, "failed to acquire address from pool"); return FALSE; } } @@ -1078,6 +1079,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPSessionMedia *sessmedia; GstRTSPMedia *media; GstRTSPStream *stream; + GstRTSPAddress *addr; uri = state->uri; @@ -1166,11 +1168,12 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) goto invalid_blocksize; /* update the client transport */ - if (!configure_client_transport (client, state, ct)) + addr = NULL; + if (!configure_client_transport (client, state, ct, &addr)) goto unsupported_client_transport; /* set in the session media transport */ - trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct); + trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct, addr); /* configure keepalive for this transport */ gst_rtsp_stream_transport_set_keepalive (trans, diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index e8eda2bc98..4d365f03fd 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -123,6 +123,7 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media) * @media: a #GstRTSPSessionMedia * @stream: a #GstRTSPStream * @tr: a #GstRTSPTransport + * @addr: (transfer full) (allow none): an optional #GstRTSPAddress * * Configure the transport for @stream to @tr in @media. * @@ -130,7 +131,7 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media) */ GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, - GstRTSPStream * stream, GstRTSPTransport * tr) + GstRTSPStream * stream, GstRTSPTransport * tr, GstRTSPAddress * addr) { GstRTSPStreamTransport *result; @@ -141,11 +142,11 @@ gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, g_mutex_lock (&media->lock); result = g_ptr_array_index (media->transports, stream->idx); if (result == NULL) { - result = gst_rtsp_stream_transport_new (stream, tr); + result = gst_rtsp_stream_transport_new (stream, tr, addr); g_ptr_array_index (media->transports, stream->idx) = result; g_mutex_unlock (&media->lock); } else { - gst_rtsp_stream_transport_set_transport (result, tr); + gst_rtsp_stream_transport_set_transport (result, tr, addr); g_mutex_unlock (&media->lock); } diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 2156f303ba..2ccfc0ed35 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -78,7 +78,8 @@ gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMe /* get stream transport config */ GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia *media, GstRTSPStream *stream, - GstRTSPTransport *tr); + GstRTSPTransport *tr, + GstRTSPAddress *addr); GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia *media, guint idx); diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index c81a1495de..5101f46679 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -70,6 +70,8 @@ gst_rtsp_stream_transport_finalize (GObject * obj) if (trans->transport) gst_rtsp_transport_free (trans->transport); + if (trans->addr) + gst_rtsp_address_free (trans->addr); #if 0 if (trans->rtpsource) @@ -83,6 +85,7 @@ gst_rtsp_stream_transport_finalize (GObject * obj) * gst_rtsp_stream_transport_new: * @stream: a #GstRTSPStream * @tr: (transfer full): a GstRTSPTransport + * @addr: (transfer full) (allow none): an optional GstRTSPAddress * * Create a new #GstRTSPStreamTransport that can be used to manage * @stream with transport @tr. @@ -90,7 +93,8 @@ gst_rtsp_stream_transport_finalize (GObject * obj) * Returns: a new #GstRTSPStreamTransport */ GstRTSPStreamTransport * -gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr) +gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr, + GstRTSPAddress * addr) { GstRTSPStreamTransport *trans; @@ -100,6 +104,7 @@ gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr) trans = g_object_new (GST_TYPE_RTSP_STREAM_TRANSPORT, NULL); trans->stream = stream; trans->transport = tr; + trans->addr = addr; return trans; } @@ -154,13 +159,14 @@ gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans, * gst_rtsp_stream_transport_set_transport: * @trans: a #GstRTSPStreamTransport * @tr: (transfer full): a client #GstRTSPTransport + * @addr: (transfer full) (allow none): a ##GstRTSPAddress * - * Set @ct as the client transport. This function takes ownership of - * the passed @tr. + * Set @tr and the optional @addr as the client transport. This function + * takes ownership of the passed @tr and @addr. */ void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans, - GstRTSPTransport * tr) + GstRTSPTransport * tr, GstRTSPAddress * addr) { g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); g_return_if_fail (tr != NULL); @@ -169,6 +175,9 @@ gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans, if (trans->transport) gst_rtsp_transport_free (trans->transport); trans->transport = tr; + if (trans->addr) + gst_rtsp_address_free (trans->addr); + trans->addr = addr; } /** diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 96bf7b67c4..44a3237dfa 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -40,6 +40,7 @@ typedef struct _GstRTSPStreamTransport GstRTSPStreamTransport; typedef struct _GstRTSPStreamTransportClass GstRTSPStreamTransportClass; #include "rtsp-stream.h" +#include "rtsp-address-pool.h" typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); @@ -58,6 +59,7 @@ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); * @active: if we are actively sending * @timeout: if we timed out * @transport: a transport description + * @addr: an optional address * @rtpsource: the receiver rtp source object * * A Transport description for stream @idx @@ -79,6 +81,7 @@ struct _GstRTSPStreamTransport { gboolean timeout; GstRTSPTransport *transport; + GstRTSPAddress *addr; GObject *rtpsource; }; @@ -90,10 +93,12 @@ struct _GstRTSPStreamTransportClass { GType gst_rtsp_stream_transport_get_type (void); GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream, - GstRTSPTransport *tr); + GstRTSPTransport *tr, + GstRTSPAddress *addr); void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans, - GstRTSPTransport * tr); + GstRTSPTransport * tr, + GstRTSPAddress *addr); void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans, GstRTSPSendFunc send_rtp, diff --git a/tests/check/gst/addresspool.c b/tests/check/gst/addresspool.c index 7e25f7a694..b05e973b4f 100644 --- a/tests/check/gst/addresspool.c +++ b/tests/check/gst/addresspool.c @@ -23,11 +23,8 @@ GST_START_TEST (test_pool) { - gpointer id; GstRTSPAddressPool *pool; - gchar *address; - guint16 port; - guint8 ttl; + GstRTSPAddress *addr; pool = gst_rtsp_address_pool_new (); @@ -44,23 +41,18 @@ GST_START_TEST (test_pool) "233.255.0.0", "233.255.0.0", 5020, 5020, 1)); /* should fail, we can't allocate a block of 256 ports */ - id = gst_rtsp_address_pool_acquire_address (pool, - 0, 256, &address, &port, &ttl); - fail_unless (id == NULL); + addr = gst_rtsp_address_pool_acquire_address (pool, 0, 256); + fail_unless (addr == NULL); - id = gst_rtsp_address_pool_acquire_address (pool, - 0, 2, &address, &port, &ttl); - fail_unless (id != NULL); + addr = gst_rtsp_address_pool_acquire_address (pool, 0, 2); + fail_unless (addr != NULL); - gst_rtsp_address_pool_release_address (pool, id); - g_free (address); + gst_rtsp_address_free (addr); - id = gst_rtsp_address_pool_acquire_address (pool, - 0, 4, &address, &port, &ttl); - fail_unless (id != NULL); + addr = gst_rtsp_address_pool_acquire_address (pool, 0, 4); + fail_unless (addr != NULL); - gst_rtsp_address_pool_release_address (pool, id); - g_free (address); + gst_rtsp_address_free (addr); g_object_unref (pool); } From 6c2947e68b04ac011cb36f3176cfdcabaf509c26 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 13:52:07 +0100 Subject: [PATCH 0494/1776] stream: share src and sink sockets the allocated socket is in the used-socket property, not socket. --- gst/rtsp-server/rtsp-stream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 6a207a9c7c..798bf87a6f 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -246,7 +246,7 @@ again: if (!udpsink0) goto no_udp_protocol; - g_object_get (G_OBJECT (udpsrc0), "socket", &socket, NULL); + g_object_get (G_OBJECT (udpsrc0), "used-socket", &socket, NULL); g_object_set (G_OBJECT (udpsink0), "socket", socket, NULL); g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL); @@ -271,7 +271,7 @@ again: GST_WARNING ("multiudpsink version found without buffer-size property"); } - g_object_get (G_OBJECT (udpsrc1), "socket", &socket, NULL); + g_object_get (G_OBJECT (udpsrc1), "used-socket", &socket, NULL); g_object_set (G_OBJECT (udpsink1), "socket", socket, NULL); g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); From 2160d6dbd35721ee04703f473f033e33ad10c13f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 15:29:35 +0100 Subject: [PATCH 0495/1776] client: set blocksize only on stream Set the blocksize only on the current stream. --- gst/rtsp-server/rtsp-client.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a9582e0594..a930a7c912 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -943,7 +943,8 @@ parse_transport (const char *transport, GstRTSPLowerTrans supported, } static gboolean -handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request) +handle_blocksize (GstRTSPMedia * media, GstRTSPStream * stream, + GstRTSPMessage * request) { gchar *blocksize_str; gboolean ret = TRUE; @@ -965,7 +966,7 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request) if (blocksize > G_MAXUINT) blocksize = G_MAXUINT; - gst_rtsp_media_set_mtu (media, blocksize); + gst_rtsp_stream_set_mtu (stream, blocksize); } } return ret; @@ -1163,8 +1164,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) state->stream = stream; - /* FIXME set only on this stream */ - if (!handle_blocksize (media, state->request)) + /* set blocksize on this stream */ + if (!handle_blocksize (media, stream, state->request)) goto invalid_blocksize; /* update the client transport */ From 1b4ac6e5b0f39f285c29da3e3b410140ce9e6f0d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 15:32:43 +0100 Subject: [PATCH 0496/1776] media: remove MTU property It is a stream property --- docs/libs/gst-rtsp-server-sections.txt | 2 - gst/rtsp-server/rtsp-media.c | 64 -------------------------- gst/rtsp-server/rtsp-media.h | 5 -- 3 files changed, 71 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 561f664ed6..02aacc9752 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -99,8 +99,6 @@ gst_rtsp_media_set_buffer_size gst_rtsp_media_get_buffer_size gst_rtsp_media_set_multicast_group gst_rtsp_media_get_multicast_group -gst_rtsp_media_get_mtu -gst_rtsp_media_set_mtu gst_rtsp_media_prepare gst_rtsp_media_unprepare diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4052cf119c..1b87149041 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -31,7 +31,6 @@ //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST #define DEFAULT_EOS_SHUTDOWN FALSE #define DEFAULT_BUFFER_SIZE 0x80000 -#define DEFAULT_MTU 0 /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -44,7 +43,6 @@ enum PROP_PROTOCOLS, PROP_EOS_SHUTDOWN, PROP_BUFFER_SIZE, - PROP_MTU, PROP_LAST }; @@ -111,12 +109,6 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "The kernel UDP buffer size to use", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_MTU, - g_param_spec_uint ("mtu", "MTU", - "The MTU for the payloaders (0 = default)", - 0, G_MAXUINT, DEFAULT_MTU, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - gst_rtsp_media_signals[SIGNAL_PREPARED] = g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL, @@ -210,9 +202,6 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_BUFFER_SIZE: g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media)); break; - case PROP_MTU: - g_value_set_uint (value, gst_rtsp_media_get_mtu (media)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -240,9 +229,6 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_BUFFER_SIZE: gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value)); break; - case PROP_MTU: - gst_rtsp_media_set_mtu (media, g_value_get_uint (value)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -627,54 +613,6 @@ gst_rtsp_media_get_address_pool (GstRTSPMedia * media) return result; } -/** - * gst_rtsp_media_set_mtu: - * @media: a #GstRTSPMedia - * @mtu: a new MTU - * - * Set maximum size of one RTP packet on the payloaders. - * The @mtu will be set on all streams. - */ -void -gst_rtsp_media_set_mtu (GstRTSPMedia * media, guint mtu) -{ - gint i; - - g_return_if_fail (GST_IS_RTSP_MEDIA (media)); - - g_mutex_lock (&media->lock); - media->mtu = mtu; - for (i = 0; i < media->streams->len; i++) { - GstRTSPStream *stream; - - GST_INFO ("Setting mtu %u for stream %d", mtu, i); - - stream = g_ptr_array_index (media->streams, i); - gst_rtsp_stream_set_mtu (stream, mtu); - } - g_mutex_unlock (&media->lock); -} - -/** - * gst_rtsp_media_get_mtu: - * @media: a #GstRTSPMedia - * - * Get the configured MTU. - */ -guint -gst_rtsp_media_get_mtu (GstRTSPMedia * media) -{ - guint res; - - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0); - - g_mutex_lock (&media->lock); - res = media->mtu; - g_mutex_unlock (&media->lock); - - return res; -} - /** * gst_rtsp_media_collect_streams: * @media: a #GstRTSPMedia @@ -771,8 +709,6 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, g_free (name); stream = gst_rtsp_stream_new (idx, payloader, srcpad); - if (media->mtu) - gst_rtsp_stream_set_mtu (stream, media->mtu); g_ptr_array_add (media->streams, stream); g_mutex_unlock (&media->lock); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 22889e4af4..710e2bde6c 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -76,7 +76,6 @@ typedef enum { * @buffer_size: The UDP buffer size * @auth: the authentication service in use * @multicast_group: the multicast group to use - * @mtu: the MTU of the payloaders * @element: the data providing element * @streams: the different #GstRTSPStream provided by @element * @dynamic: list of dynamic elements managed by @element @@ -114,7 +113,6 @@ struct _GstRTSPMedia { guint buffer_size; GstRTSPAuth *auth; GstRTSPAddressPool*pool; - guint mtu; GstElement *element; GRecMutex state_lock; @@ -198,9 +196,6 @@ GstRTSPAddressPool * gst_rtsp_media_get_address_pool (GstRTSPMedia *media); void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size); guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media); -void gst_rtsp_media_set_mtu (GstRTSPMedia *media, guint mtu); -guint gst_rtsp_media_get_mtu (GstRTSPMedia *media); - /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); From 44a2855eb3d94eb20912a45a9e14955347341046 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 15:36:21 +0100 Subject: [PATCH 0497/1776] stream: add methods to deal with address pool Add methods to get and set the address pool for the stream Add method to allocate and get the multicast addresses for this stream. --- gst/rtsp-server/rtsp-stream.c | 98 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 13 +++++ 2 files changed, 111 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 798bf87a6f..81650eed72 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -72,6 +72,10 @@ gst_rtsp_stream_finalize (GObject * obj) /* we really need to be unjoined now */ g_return_if_fail (!stream->is_joined); + if (stream->addr) + gst_rtsp_address_free (stream->addr); + if (stream->pool) + g_object_unref (stream->pool); gst_object_unref (stream->payloader); gst_object_unref (stream->srcpad); g_mutex_clear (&stream->lock); @@ -142,6 +146,100 @@ gst_rtsp_stream_get_mtu (GstRTSPStream * stream) return mtu; } +/** + * gst_rtsp_stream_set_address_pool: + * @stream: a #GstRTSPStream + * @pool: a #GstRTSPAddressPool + * + * configure @pool to be used as the address pool of @stream. + */ +void +gst_rtsp_stream_set_address_pool (GstRTSPStream * stream, + GstRTSPAddressPool * pool) +{ + GstRTSPAddressPool *old; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + g_mutex_lock (&stream->lock); + if ((old = stream->pool) != pool) + stream->pool = pool ? g_object_ref (pool) : NULL; + else + old = NULL; + g_mutex_unlock (&stream->lock); + + if (old) + g_object_unref (old); +} + +/** + * gst_rtsp_stream_get_address_pool: + * @stream: a #GstRTSPStream + * + * Get the #GstRTSPAddressPool used as the address pool of @stream. + * + * Returns: (transfer full): the #GstRTSPAddressPool of @stream. g_object_unref() after + * usage. + */ +GstRTSPAddressPool * +gst_rtsp_stream_get_address_pool (GstRTSPStream * stream) +{ + GstRTSPAddressPool *result; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + g_mutex_lock (&stream->lock); + if ((result = stream->pool)) + g_object_ref (result); + g_mutex_unlock (&stream->lock); + + return result; +} + +/** + * gst_rtsp_stream_get_address: + * @stream: a #GstRTSPStream + * + * Get the multicast address of @stream. + * + * Returns: the #GstRTSPAddress of @stream or %NULL when no address could be + * allocated. gst_rtsp_address_free() after usage. + */ +GstRTSPAddress * +gst_rtsp_stream_get_address (GstRTSPStream * stream) +{ + GstRTSPAddress *result; + + g_mutex_lock (&stream->lock); + if (stream->addr == NULL) { + if (stream->pool == NULL) + goto no_pool; + + stream->addr = gst_rtsp_address_pool_acquire_address (stream->pool, + GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); + if (stream->addr == NULL) + goto no_address; + } + result = gst_rtsp_address_copy (stream->addr); + g_mutex_unlock (&stream->lock); + + return result; + + /* ERRORS */ +no_pool: + { + GST_ERROR_OBJECT (stream, "no address pool specified"); + g_mutex_unlock (&stream->lock); + return NULL; + } +no_address: + { + GST_ERROR_OBJECT (stream, "failed to acquire address from pool"); + g_mutex_unlock (&stream->lock); + return NULL; + } +} + /* must be called with lock */ static gboolean alloc_ports (GstRTSPStream * stream) diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 166baffb9a..bdb50c2c14 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -40,6 +40,7 @@ typedef struct _GstRTSPStream GstRTSPStream; typedef struct _GstRTSPStreamClass GstRTSPStreamClass; #include "rtsp-stream-transport.h" +#include "rtsp-address-pool.h" /** * GstRTSPStream: @@ -63,6 +64,8 @@ typedef struct _GstRTSPStreamClass GstRTSPStreamClass; * @tee: tee for the sending to udpsink and appsink * @funnel: tee for the receiving from udpsrc and appsrc * @server_port: the server ports for this stream + * @pool: the address pool for this stream + * @addr: the address for this stream * @caps_sig: the signal id for detecting caps * @caps: the caps of the stream * @n_active: the number of active transports in @transports @@ -104,6 +107,10 @@ struct _GstRTSPStream { /* server ports for sending/receiving */ GstRTSPRange server_port; + /* multicast addresses */ + GstRTSPAddressPool *pool; + GstRTSPAddress *addr; + /* the caps of the stream */ gulong caps_sig; GstCaps *caps; @@ -125,6 +132,12 @@ GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement *paylo void gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guint mtu); guint gst_rtsp_stream_get_mtu (GstRTSPStream * stream); +void gst_rtsp_stream_set_address_pool (GstRTSPStream *stream, GstRTSPAddressPool *pool); +GstRTSPAddressPool * + gst_rtsp_stream_get_address_pool (GstRTSPStream *stream); + +GstRTSPAddress * gst_rtsp_stream_get_address (GstRTSPStream *stream); + gboolean gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin *bin, GstElement *rtpbin, GstState state); From 4168a679924188cc590fcbe19f50eaeaef25667b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 15:41:19 +0100 Subject: [PATCH 0498/1776] media: configure address pool in new streams --- gst/rtsp-server/rtsp-media.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1b87149041..ad5315de90 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -709,6 +709,8 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, g_free (name); stream = gst_rtsp_stream_new (idx, payloader, srcpad); + if (media->pool) + gst_rtsp_stream_set_address_pool (stream, media->pool); g_ptr_array_add (media->streams, stream); g_mutex_unlock (&media->lock); From c34f5d1c1afeb37c490b4fe1d5fa4c27f88260b4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 15:41:42 +0100 Subject: [PATCH 0499/1776] media: add signal for new streams This allows applications to listen for new streams and configure properties on them, like the address pool. --- gst/rtsp-server/rtsp-media.c | 9 +++++++++ gst/rtsp-server/rtsp-media.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index ad5315de90..d4bfa0e85a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -48,6 +48,7 @@ enum enum { + SIGNAL_NEW_STREAM, SIGNAL_PREPARED, SIGNAL_UNPREPARED, SIGNAL_NEW_STATE, @@ -109,6 +110,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "The kernel UDP buffer size to use", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = + g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, + g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_STREAM); + gst_rtsp_media_signals[SIGNAL_PREPARED] = g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL, @@ -715,6 +721,9 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, g_ptr_array_add (media->streams, stream); g_mutex_unlock (&media->lock); + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STREAM], 0, stream, + NULL); + return stream; } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 710e2bde6c..bef1972a1a 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -164,6 +164,8 @@ struct _GstRTSPMediaClass { gboolean (*unprepare) (GstRTSPMedia *media); /* signals */ + gboolean (*new_stream) (GstRTSPMedia *media, GstRTSPStream * stream); + gboolean (*prepared) (GstRTSPMedia *media); gboolean (*unprepared) (GstRTSPMedia *media); From ba21661ce4d10a08610a3e8e789c9eac7d09d3b1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 16:15:20 +0100 Subject: [PATCH 0500/1776] rtsp: improve debug --- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-media.c | 6 ++++++ gst/rtsp-server/rtsp-stream.c | 4 ++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a930a7c912..4a1ed67676 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -905,7 +905,7 @@ parse_transport (const char *transport, GstRTSPLowerTrans supported, res = FALSE; gst_rtsp_transport_init (tr); - GST_WARNING ("parsing transports %s", transport); + GST_DEBUG ("parsing transports %s", transport); transports = g_strsplit (transport, ",", 0); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d4bfa0e85a..3fd8d3afde 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -493,6 +493,8 @@ gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size) { g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + GST_LOG_OBJECT (media, "set buffer size %u", size); + g_mutex_lock (&media->lock); media->buffer_size = size; g_mutex_unlock (&media->lock); @@ -534,6 +536,8 @@ gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth) g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + GST_LOG_OBJECT (media, "set auth %p", auth); + g_mutex_lock (&media->lock); if ((old = media->auth) != auth) media->auth = auth ? g_object_ref (auth) : NULL; @@ -584,6 +588,8 @@ gst_rtsp_media_set_address_pool (GstRTSPMedia * media, g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + GST_LOG_OBJECT (media, "set address pool %p", pool); + g_mutex_lock (&media->lock); if ((old = media->pool) != pool) media->pool = pool ? g_object_ref (pool) : NULL; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 81650eed72..4676e41e77 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -123,6 +123,8 @@ gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guint mtu) { g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + GST_LOG_OBJECT (stream, "set MTU %u", mtu); + g_object_set (G_OBJECT (stream->payloader), "mtu", mtu, NULL); } @@ -161,6 +163,8 @@ gst_rtsp_stream_set_address_pool (GstRTSPStream * stream, g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + GST_LOG_OBJECT (stream, "set address pool %p", pool); + g_mutex_lock (&stream->lock); if ((old = stream->pool) != pool) stream->pool = pool ? g_object_ref (pool) : NULL; From e4ea72ccdf11ea418483c6a6af454f3499ca6e3b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 16:18:29 +0100 Subject: [PATCH 0501/1776] stream: use the address managed by the stream Use the address managed by the stream for multicast. This allows us to have 1 multicast address for each stream. Because the address is now managed by the stream we don't have to pass it around anymore. Set the address pool on the streams. --- gst/rtsp-server/rtsp-client.c | 37 ++++++++----------------- gst/rtsp-server/rtsp-media.c | 2 ++ gst/rtsp-server/rtsp-session-media.c | 7 ++--- gst/rtsp-server/rtsp-session-media.h | 3 +- gst/rtsp-server/rtsp-stream-transport.c | 17 +++--------- gst/rtsp-server/rtsp-stream-transport.h | 7 ++--- 6 files changed, 23 insertions(+), 50 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4a1ed67676..9bbec270c0 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -974,30 +974,22 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPStream * stream, static gboolean configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, - GstRTSPTransport * ct, GstRTSPAddress ** addr) + GstRTSPTransport * ct) { /* we have a valid transport now, set the destination of the client. */ if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { if (ct->destination == NULL || !client->use_client_settings) { - GstRTSPAddressPool *pool; - GstRTSPAddress *ad; + GstRTSPAddress *addr; - pool = gst_rtsp_media_get_address_pool (state->media); - if (pool == NULL) - goto no_pool; - - ad = gst_rtsp_address_pool_acquire_address (pool, - GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); - if (ad == NULL) + addr = gst_rtsp_stream_get_address (state->stream); + if (addr == NULL) goto no_address; g_free (ct->destination); - ct->destination = g_strdup (ad->address); - ct->port.min = ad->port; - ct->port.max = ad->port + 1; - ct->ttl = ad->ttl; - - *addr = ad; + ct->destination = g_strdup (addr->address); + ct->port.min = addr->port; + ct->port.max = addr->port + addr->n_ports - 1; + ct->ttl = addr->ttl; } } else { GstRTSPUrl *url; @@ -1017,14 +1009,9 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, return TRUE; /* ERRORS */ -no_pool: - { - GST_ERROR_OBJECT (client, "no address pool specified"); - return FALSE; - } no_address: { - GST_ERROR_OBJECT (client, "failed to acquire address from pool"); + GST_ERROR_OBJECT (client, "failed to acquire address for stream"); return FALSE; } } @@ -1080,7 +1067,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPSessionMedia *sessmedia; GstRTSPMedia *media; GstRTSPStream *stream; - GstRTSPAddress *addr; uri = state->uri; @@ -1169,12 +1155,11 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) goto invalid_blocksize; /* update the client transport */ - addr = NULL; - if (!configure_client_transport (client, state, ct, &addr)) + if (!configure_client_transport (client, state, ct)) goto unsupported_client_transport; /* set in the session media transport */ - trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct, addr); + trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct); /* configure keepalive for this transport */ gst_rtsp_stream_transport_set_keepalive (trans, diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 3fd8d3afde..dfd89bc872 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -595,6 +595,8 @@ gst_rtsp_media_set_address_pool (GstRTSPMedia * media, media->pool = pool ? g_object_ref (pool) : NULL; else old = NULL; + g_ptr_array_foreach (media->streams, (GFunc) gst_rtsp_stream_set_address_pool, + pool); g_mutex_unlock (&media->lock); if (old) diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 4d365f03fd..e8eda2bc98 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -123,7 +123,6 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media) * @media: a #GstRTSPSessionMedia * @stream: a #GstRTSPStream * @tr: a #GstRTSPTransport - * @addr: (transfer full) (allow none): an optional #GstRTSPAddress * * Configure the transport for @stream to @tr in @media. * @@ -131,7 +130,7 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media) */ GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, - GstRTSPStream * stream, GstRTSPTransport * tr, GstRTSPAddress * addr) + GstRTSPStream * stream, GstRTSPTransport * tr) { GstRTSPStreamTransport *result; @@ -142,11 +141,11 @@ gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, g_mutex_lock (&media->lock); result = g_ptr_array_index (media->transports, stream->idx); if (result == NULL) { - result = gst_rtsp_stream_transport_new (stream, tr, addr); + result = gst_rtsp_stream_transport_new (stream, tr); g_ptr_array_index (media->transports, stream->idx) = result; g_mutex_unlock (&media->lock); } else { - gst_rtsp_stream_transport_set_transport (result, tr, addr); + gst_rtsp_stream_transport_set_transport (result, tr); g_mutex_unlock (&media->lock); } diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 2ccfc0ed35..2156f303ba 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -78,8 +78,7 @@ gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMe /* get stream transport config */ GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia *media, GstRTSPStream *stream, - GstRTSPTransport *tr, - GstRTSPAddress *addr); + GstRTSPTransport *tr); GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia *media, guint idx); diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 5101f46679..6df8d4d8e3 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -70,8 +70,6 @@ gst_rtsp_stream_transport_finalize (GObject * obj) if (trans->transport) gst_rtsp_transport_free (trans->transport); - if (trans->addr) - gst_rtsp_address_free (trans->addr); #if 0 if (trans->rtpsource) @@ -85,7 +83,6 @@ gst_rtsp_stream_transport_finalize (GObject * obj) * gst_rtsp_stream_transport_new: * @stream: a #GstRTSPStream * @tr: (transfer full): a GstRTSPTransport - * @addr: (transfer full) (allow none): an optional GstRTSPAddress * * Create a new #GstRTSPStreamTransport that can be used to manage * @stream with transport @tr. @@ -93,8 +90,7 @@ gst_rtsp_stream_transport_finalize (GObject * obj) * Returns: a new #GstRTSPStreamTransport */ GstRTSPStreamTransport * -gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr, - GstRTSPAddress * addr) +gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr) { GstRTSPStreamTransport *trans; @@ -104,7 +100,6 @@ gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr, trans = g_object_new (GST_TYPE_RTSP_STREAM_TRANSPORT, NULL); trans->stream = stream; trans->transport = tr; - trans->addr = addr; return trans; } @@ -159,14 +154,13 @@ gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans, * gst_rtsp_stream_transport_set_transport: * @trans: a #GstRTSPStreamTransport * @tr: (transfer full): a client #GstRTSPTransport - * @addr: (transfer full) (allow none): a ##GstRTSPAddress * - * Set @tr and the optional @addr as the client transport. This function - * takes ownership of the passed @tr and @addr. + * Set @tr as the client transport. This function takes ownership of the + * passed @tr. */ void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans, - GstRTSPTransport * tr, GstRTSPAddress * addr) + GstRTSPTransport * tr) { g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); g_return_if_fail (tr != NULL); @@ -175,9 +169,6 @@ gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans, if (trans->transport) gst_rtsp_transport_free (trans->transport); trans->transport = tr; - if (trans->addr) - gst_rtsp_address_free (trans->addr); - trans->addr = addr; } /** diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 44a3237dfa..8839267cd1 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -81,7 +81,6 @@ struct _GstRTSPStreamTransport { gboolean timeout; GstRTSPTransport *transport; - GstRTSPAddress *addr; GObject *rtpsource; }; @@ -93,12 +92,10 @@ struct _GstRTSPStreamTransportClass { GType gst_rtsp_stream_transport_get_type (void); GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream, - GstRTSPTransport *tr, - GstRTSPAddress *addr); + GstRTSPTransport *tr); void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans, - GstRTSPTransport * tr, - GstRTSPAddress *addr); + GstRTSPTransport * tr); void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans, GstRTSPSendFunc send_rtp, From a75d83e26d3cb5a7634bb7412be11004a22d64f7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 16:21:51 +0100 Subject: [PATCH 0502/1776] test: set shared --- examples/test-multicast.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/test-multicast.c b/examples/test-multicast.c index 0156a8c5af..4cd064e7aa 100644 --- a/examples/test-multicast.c +++ b/examples/test-multicast.c @@ -65,6 +65,8 @@ main (int argc, char *argv[]) "audiotestsrc ! audio/x-raw,rate=8000 ! " "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); + gst_rtsp_media_factory_set_shared (factory, TRUE); + /* make a new address pool */ pool = gst_rtsp_address_pool_new (); gst_rtsp_address_pool_add_range (pool, From 18d6152af2330e0857f984ce0dfc99595c70997a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 16:52:42 +0100 Subject: [PATCH 0503/1776] examples: add another multicast example Add an example for how to configure separate multicast ranges for each media stream. --- examples/Makefile.am | 2 +- examples/test-multicast2.c | 125 +++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 examples/test-multicast2.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 32537a47e8..47b2cf96e1 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,6 +1,6 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ test-launch test-sdp test-uri test-auth \ - test-multicast + test-multicast test-multicast2 #INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/examples/test-multicast2.c b/examples/test-multicast2.c new file mode 100644 index 0000000000..7a95374d24 --- /dev/null +++ b/examples/test-multicast2.c @@ -0,0 +1,125 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + + +static gboolean +timeout (GstRTSPServer * server, gboolean ignored) +{ + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_cleanup (pool); + g_object_unref (pool); + + return TRUE; +} + +static void +media_constructed (GstRTSPMediaFactory * factory, GstRTSPMedia * media) +{ + guint i, n_streams; + + n_streams = gst_rtsp_media_n_streams (media); + + for (i = 0; i < n_streams; i++) { + GstRTSPAddressPool *pool; + GstRTSPStream *stream; + gchar *min, *max; + + stream = gst_rtsp_media_get_stream (media, i); + + /* make a new address pool */ + pool = gst_rtsp_address_pool_new (); + + min = g_strdup_printf ("224.3.0.%d", (2 * i) + 1); + max = g_strdup_printf ("224.3.0.%d", (2 * i) + 2); + gst_rtsp_address_pool_add_range (pool, min, max, + 5000 + (10 * i), 5010 + (10 * i), 1); + g_free (min); + g_free (max); + + gst_rtsp_stream_set_address_pool (stream, pool); + g_object_unref (pool); + } +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMediaMapping *mapping; + GstRTSPMediaFactory *factory; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mapping for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mapping = gst_rtsp_server_get_media_mapping (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, "( " + "videotestsrc ! video/x-raw,width=352,height=288,framerate=15/1 ! " + "x264enc ! rtph264pay name=pay0 pt=96 " + "audiotestsrc ! audio/x-raw,rate=8000 ! " + "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); + + gst_rtsp_media_factory_set_shared (factory, TRUE); + + g_signal_connect (factory, "media-constructed", (GCallback) + media_constructed, NULL); + + /* attach the test factory to the /test url */ + gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mapping); + + /* attach the server to the default maincontext */ + if (gst_rtsp_server_attach (server, NULL) == 0) + goto failed; + + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + + /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + g_main_loop_run (loop); + + return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } +} From 26ff5fc0738d7e5221bdb2ef31e5e77fb6e23dbf Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Nov 2012 17:11:16 +0100 Subject: [PATCH 0504/1776] rtsp: cleanups --- TODO | 1 - docs/libs/gst-rtsp-server-sections.txt | 4 ---- gst/rtsp-server/rtsp-client.c | 9 +-------- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/TODO b/TODO index 1b28c23ea5..53d7d1c0f5 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,3 @@ - - implement multicast and TCP transports - use a config file to configure the server - error recovery diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 02aacc9752..fa46f302dc 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -37,8 +37,6 @@ gst_rtsp_media_factory_set_auth gst_rtsp_media_factory_get_auth gst_rtsp_media_factory_set_buffer_size gst_rtsp_media_factory_get_buffer_size -gst_rtsp_media_factory_set_multicast_group -gst_rtsp_media_factory_get_multicast_group gst_rtsp_media_factory_construct gst_rtsp_media_factory_create_element @@ -97,8 +95,6 @@ gst_rtsp_media_set_auth gst_rtsp_media_get_auth gst_rtsp_media_set_buffer_size gst_rtsp_media_get_buffer_size -gst_rtsp_media_set_multicast_group -gst_rtsp_media_get_multicast_group gst_rtsp_media_prepare gst_rtsp_media_unprepare diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 9bbec270c0..f353a796c9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1281,14 +1281,7 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) info.server_proto = proto; protocols = gst_rtsp_media_get_protocols (media); - if (protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) -#if 0 - info.server_ip = gst_rtsp_media_get_multicast_group (media); -#else - info.server_ip = g_strdup (client->server_ip); -#endif - else - info.server_ip = g_strdup (client->server_ip); + info.server_ip = g_strdup (client->server_ip); /* create an SDP for the media object */ if (!gst_rtsp_sdp_from_media (sdp, &info, media)) From 290968eb8c763a4ac9ef3f8d347483ceea28d95e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 17 Nov 2012 00:03:42 +0000 Subject: [PATCH 0505/1776] rtsp-client: fix unused-but-set-variable compiler warning rtsp-client.c:1260:21: error: variable 'protocols' set but not used --- gst/rtsp-server/rtsp-client.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f353a796c9..9389160f3e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1257,7 +1257,6 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) GstSDPMessage *sdp; GstSDPInfo info; const gchar *proto; - GstRTSPLowerTrans protocols; gst_sdp_message_new (&sdp); @@ -1280,7 +1279,6 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) gst_sdp_message_add_attribute (sdp, "control", "*"); info.server_proto = proto; - protocols = gst_rtsp_media_get_protocols (media); info.server_ip = g_strdup (client->server_ip); /* create an SDP for the media object */ From 0006ca6d60639aa0f12d688298f9a31769246cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 17 Nov 2012 00:11:27 +0000 Subject: [PATCH 0506/1776] rtsp-server: don't use deprecated API --- gst/rtsp-server/rtsp-media-factory-uri.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 91f0193bc5..733103c894 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -134,7 +134,7 @@ payloader_filter (GstPluginFeature * feature, FilterData * data) fact = GST_ELEMENT_FACTORY_CAST (feature); - klass = gst_element_factory_get_klass (fact); + klass = gst_element_factory_get_metadata (fact, GST_ELEMENT_METADATA_KLASS); if (strstr (klass, "Decoder")) list = &data->decode; @@ -314,7 +314,8 @@ find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps) for (walk = list; walk; walk = walk->next) { factory = GST_ELEMENT_FACTORY (walk->data); - klass = gst_element_factory_get_klass (factory); + klass = gst_element_factory_get_metadata (factory, + GST_ELEMENT_METADATA_KLASS); if (strstr (klass, "Parser")) /* caps have parsed=true, so skip this parser to avoid loops */ continue; From ff22750eabf6813004024f2f42aed45a696f7895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 19 Nov 2012 11:31:12 +0000 Subject: [PATCH 0507/1776] Automatic update of common submodule From 6bb6951 to a72faea --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 6bb695159b..a72faea054 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 6bb695159bf15fe64d31b26dd2a07d1ba2bb7f1d +Subproject commit a72faea054977054ec66e894fd0a07e7d6585d50 From 0996266342aa486d7680ccb9f414fa9c08fa42aa Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Mon, 19 Nov 2012 15:44:27 +0100 Subject: [PATCH 0508/1776] rtsp-stream: plug socket leak Fixes https://bugzilla.gnome.org/show_bug.cgi?id=688703 --- gst/rtsp-server/rtsp-stream.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4676e41e77..0a80687edf 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -350,6 +350,7 @@ again: g_object_get (G_OBJECT (udpsrc0), "used-socket", &socket, NULL); g_object_set (G_OBJECT (udpsink0), "socket", socket, NULL); + g_object_unref (socket); g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL); udpsink1 = gst_element_factory_make ("multiudpsink", NULL); @@ -375,6 +376,7 @@ again: g_object_get (G_OBJECT (udpsrc1), "used-socket", &socket, NULL); g_object_set (G_OBJECT (udpsink1), "socket", socket, NULL); + g_object_unref (socket); g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); From 65042a9551a9cf4586d6e3fa49e6a10f25873553 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Sat, 17 Nov 2012 14:51:52 +0100 Subject: [PATCH 0509/1776] client: wait until the TEARDOWN response is sent to close the connection Responses can be sent async so we need to wait until the TEARDOWN response has been written before we close the connection to the client. This avoids the risk of writing/polling closed sockets. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=688535 --- gst/rtsp-server/rtsp-client.c | 40 +++++++++++++++++++---------------- gst/rtsp-server/rtsp-client.h | 2 ++ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 9389160f3e..799b42e512 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -174,6 +174,7 @@ static void gst_rtsp_client_init (GstRTSPClient * client) { client->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS; + client->teardown_response_seq = 0; } static void @@ -300,7 +301,7 @@ gst_rtsp_client_new (void) static void send_response (GstRTSPClient * client, GstRTSPSession * session, - GstRTSPMessage * response) + GstRTSPMessage * response, guint * id) { gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER, "GStreamer RTSP server"); @@ -318,7 +319,7 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, gst_rtsp_message_dump (response); } - gst_rtsp_watch_send_message (client->watch, response, NULL); + gst_rtsp_watch_send_message (client->watch, response, id); gst_rtsp_message_unset (response); } @@ -329,7 +330,7 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); - send_response (client, NULL, state->response); + send_response (client, NULL, state->response, NULL); } static void @@ -344,7 +345,7 @@ handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth, gst_rtsp_auth_setup_auth (auth, client, 0, state); } - send_response (client, state->session, state->response); + send_response (client, state->session, state->response, NULL); } @@ -603,14 +604,15 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONNECTION, "close"); - send_response (client, session, state->response); + /* send the response and store the seq number so we can wait until it's + * written to the client to close the connection */ + send_response (client, session, state->response, + &client->teardown_response_seq); /* we emit the signal before closing the connection */ g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], 0, state); - close_connection (client); - return TRUE; /* ERRORS */ @@ -646,7 +648,7 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state) if (res != GST_RTSP_OK) goto bad_request; - send_response (client, state->session, state->response); + send_response (client, state->session, state->response, NULL); } g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST], @@ -682,7 +684,7 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state) if (res != GST_RTSP_OK) goto bad_request; - send_response (client, state->session, state->response); + send_response (client, state->session, state->response, NULL); } g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST], @@ -731,7 +733,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); - send_response (client, session, state->response); + send_response (client, session, state->response, NULL); /* the state is now READY */ media->state = GST_RTSP_STATE_READY; @@ -853,7 +855,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) str = gst_rtsp_media_get_range_string (media->media, TRUE); gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str); - send_response (client, session, state->response); + send_response (client, session, state->response, NULL); /* start playing after sending the request */ gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING); @@ -1179,7 +1181,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) trans_str); g_free (trans_str); - send_response (client, session, state->response); + send_response (client, session, state->response, NULL); /* update the state */ switch (sessmedia->state) { @@ -1368,7 +1370,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_message_take_body (state->response, (guint8 *) str, strlen (str)); gst_sdp_message_free (sdp); - send_response (client, state->session, state->response); + send_response (client, state->session, state->response, NULL); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST], 0, state); @@ -1410,7 +1412,7 @@ handle_options_request (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_PUBLIC, str); g_free (str); - send_response (client, state->session, state->response); + send_response (client, state->session, state->response, NULL); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST], 0, state); @@ -1891,11 +1893,13 @@ message_received (GstRTSPWatch * watch, GstRTSPMessage * message, static GstRTSPResult message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) { - /* GstRTSPClient *client; */ + GstRTSPClient *client; - /* client = GST_RTSP_CLIENT (user_data); */ - - /* GST_INFO ("client %p: sent a message with cseq %d", client, cseq); */ + client = GST_RTSP_CLIENT (user_data); + if (client->teardown_response_seq && client->teardown_response_seq == cseq) { + client->teardown_response_seq = 0; + close_connection (client); + } return GST_RTSP_OK; } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 71a28adc9c..dd4e71230e 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -107,6 +107,8 @@ struct _GstRTSPClient { GList *transports; GList *sessions; + + guint teardown_response_seq; }; struct _GstRTSPClientClass { From 01973c924d3fc850b812a7aaf1b2691a8fd01ae0 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Mon, 19 Nov 2012 15:47:08 +0100 Subject: [PATCH 0510/1776] rtsp-media: remove bus watch before finalizing * A GDestroyNotify function is set for the bus watch in gst_rtsp_media_prepare. * An extra media ref is added for the bus watch. This extra ref is unreffed by the GDestroyNotify function. * gst_rtsp_media_unprepare destroys the source so the bus watch is removed. * GstRTSPClient, which calls gst_rtsp_media_prepare, also calls gst_rtsp_media_unprepare before unreffing the media. This way, the bus watch will be removed before the media is finalized. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=688707 --- gst/rtsp-server/rtsp-client.c | 8 ++++++-- gst/rtsp-server/rtsp-media.c | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 799b42e512..a0ba3c52e5 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -230,8 +230,10 @@ gst_rtsp_client_finalize (GObject * obj) if (client->uri) gst_rtsp_url_free (client->uri); - if (client->media) + if (client->media) { + gst_rtsp_media_unprepare (client->media); g_object_unref (client->media); + } g_free (client->server_ip); @@ -377,8 +379,10 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) if (client->uri) gst_rtsp_url_free (client->uri); client->uri = NULL; - if (client->media) + if (client->media) { + gst_rtsp_media_unprepare (client->media); g_object_unref (client->media); + } client->media = NULL; if (!client->media_mapping) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index dfd89bc872..d8191bbf24 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1088,6 +1088,13 @@ bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media) return ret; } +static void +watch_destroyed (GstRTSPMedia * media) +{ + GST_DEBUG_OBJECT (media, "source destroyed"); + gst_object_unref (media); +} + /* called from streaming threads */ static void pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) @@ -1188,7 +1195,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) media->source = gst_bus_create_watch (bus); gst_object_unref (bus); - g_source_set_callback (media->source, (GSourceFunc) bus_message, media, NULL); + g_source_set_callback (media->source, (GSourceFunc) bus_message, + gst_object_ref (media), (GDestroyNotify) watch_destroyed); klass = GST_RTSP_MEDIA_GET_CLASS (media); media->id = g_source_attach (media->source, klass->context); @@ -1387,6 +1395,11 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) } else { finish_unprepare (media); } + if (media->source) { + g_source_destroy (media->source); + g_source_unref (media->source); + media->source = NULL; + } g_rec_mutex_unlock (&media->state_lock); return success; From 989f004e24e6e6e8d8a0a041849d9ce593403666 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Nov 2012 09:42:51 +0100 Subject: [PATCH 0511/1776] media: unref source in finish_unprepare The source is created in prepare, unref it in finish_unprepare. See https://bugzilla.gnome.org/show_bug.cgi?id=688707 --- gst/rtsp-server/rtsp-media.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d8191bbf24..979ba826eb 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -171,10 +171,6 @@ gst_rtsp_media_finalize (GObject * obj) g_list_free_full (media->dynamic, gst_object_unref); - if (media->source) { - g_source_destroy (media->source); - g_source_unref (media->source); - } if (media->auth) g_object_unref (media->auth); if (media->pool) @@ -1339,6 +1335,12 @@ finish_unprepare (GstRTSPMedia * media) media->reused = TRUE; media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED; + if (media->source) { + g_source_destroy (media->source); + g_source_unref (media->source); + media->source = NULL; + } + /* when the media is not reusable, this will effectively unref the media and * recreate it */ g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL); @@ -1395,11 +1397,6 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) } else { finish_unprepare (media); } - if (media->source) { - g_source_destroy (media->source); - g_source_unref (media->source); - media->source = NULL; - } g_rec_mutex_unlock (&media->state_lock); return success; From 8a7197f078f90a873af335518e3df627ca78151c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Nov 2012 11:24:35 +0100 Subject: [PATCH 0512/1776] server: fix small leak --- gst/rtsp-server/rtsp-server.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index af44b537e8..6151c836ef 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -204,6 +204,7 @@ gst_rtsp_server_finalize (GObject * object) g_free (server->address); g_free (server->service); + if (server->socket) g_object_unref (server->socket); @@ -718,6 +719,7 @@ gst_rtsp_server_create_socket (GstRTSPServer * server, if (socket == NULL) { GST_DEBUG_OBJECT (server, "failed to make socket (%s), try next", sock_error->message); + g_object_unref (sockaddr); continue; } From 0eeb4a5c733a42378a9909ded740ae9aeec84a80 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Thu, 15 Nov 2012 14:02:37 +0100 Subject: [PATCH 0513/1776] server: start and stop multiple times Stop listening on the RTSP port when the GSource is removed, so clients can't connect and the server can be started again. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=688395 --- gst/rtsp-server/rtsp-server.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 6151c836ef..9f557ba0cc 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1076,6 +1076,8 @@ static void watch_destroyed (GstRTSPServer * server) { GST_DEBUG_OBJECT (server, "source destroyed"); + g_object_unref (server->socket); + server->socket = NULL; g_object_unref (server); } From a0c2dca4ddb930cc70532b4e7943a641cb687b82 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Nov 2012 11:30:09 +0100 Subject: [PATCH 0514/1776] test: add test for server reuse See https://bugzilla.gnome.org/show_bug.cgi?id=688395 --- tests/Makefile.am | 2 +- tests/test-reuse.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 tests/test-reuse.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 2c845405e1..8b3c6ab669 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,4 @@ -noinst_PROGRAMS = test-cleanup +noinst_PROGRAMS = test-cleanup test-reuse INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/tests/test-reuse.c b/tests/test-reuse.c new file mode 100644 index 0000000000..67063a8675 --- /dev/null +++ b/tests/test-reuse.c @@ -0,0 +1,90 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#define TIMEOUT 2 + +static gboolean timeout_1 (GMainLoop * loop, gboolean ignored); + +static guint id; +static gint rounds = 3; +static GstRTSPServer *server; + +static gboolean +timeout_2 (GMainLoop * loop, gboolean ignored) +{ + rounds--; + if (rounds > 0) { + id = gst_rtsp_server_attach (server, NULL); + g_print ("have attached\n"); + g_timeout_add_seconds (TIMEOUT, (GSourceFunc) timeout_1, loop); + } else { + g_main_loop_quit (loop); + } + return FALSE; +} + +static gboolean +timeout_1 (GMainLoop * loop, gboolean ignored) +{ + g_source_remove (id); + g_print ("have removed\n"); + g_timeout_add_seconds (TIMEOUT, (GSourceFunc) timeout_2, loop); + return FALSE; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* attach the server to the default maincontext */ + if ((id = gst_rtsp_server_attach (server, NULL)) == 0) + goto failed; + g_print ("have attached\n"); + + g_timeout_add_seconds (TIMEOUT, (GSourceFunc) timeout_1, loop); + + /* start serving */ + g_main_loop_run (loop); + + /* cleanup */ + g_object_unref (server); + g_main_loop_unref (loop); + + g_print ("quit\n"); + return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } +} From 8211cdfdc2c17ca32ac6f5811ebaa6a2fbf29055 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Nov 2012 12:10:16 +0100 Subject: [PATCH 0515/1776] factory-uri: take ref to factory Take a ref to the factory that we place in our list. --- gst/rtsp-server/rtsp-media-factory-uri.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 733103c894..ddcaf3fd0b 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -147,7 +147,7 @@ payloader_filter (GstPluginFeature * feature, FilterData * data) if (list) { GST_DEBUG ("adding %s", GST_OBJECT_NAME (fact)); - *list = g_list_prepend (*list, fact); + *list = g_list_prepend (*list, gst_object_ref (fact)); } return FALSE; From 1826844ee47f4007204fa570303083bcce220ae0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Nov 2012 12:24:13 +0100 Subject: [PATCH 0516/1776] stream: set udp sources to PLAYING Set the UDP sources to PLAYING and locked state before we add it to the pipeline so that it doesn't cause our pipeline to produce ASYNC-DONE. --- gst/rtsp-server/rtsp-stream.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 0a80687edf..a4f52dc3cc 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -813,6 +813,10 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, gst_pad_link (pad, stream->recv_sink[i]); gst_object_unref (pad); + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values */ + gst_element_set_state (stream->udpsrc[i], GST_STATE_PLAYING); + gst_element_set_locked_state (stream->udpsrc[i], TRUE); /* add udpsrc */ gst_bin_add (bin, stream->udpsrc[i]); /* and link to the funnel */ @@ -841,10 +845,6 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, gst_element_set_state (stream->funnel[i], state); gst_element_set_state (stream->appsrc[i], state); } - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values */ - gst_element_set_state (stream->udpsrc[i], GST_STATE_PLAYING); - gst_element_set_locked_state (stream->udpsrc[i], TRUE); } /* be notified of caps changes */ From 8fcdca987daad1b30404cd8fc4726ff7f744a0f1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Nov 2012 12:29:26 +0100 Subject: [PATCH 0517/1776] factory-uri: add some debug --- gst/rtsp-server/rtsp-media-factory-uri.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index ddcaf3fd0b..538338dfc0 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -158,6 +158,8 @@ gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory) { FilterData data = { NULL, NULL, NULL }; + GST_DEBUG_OBJECT (factory, "new"); + factory->uri = g_strdup (DEFAULT_URI); factory->use_gstpay = DEFAULT_USE_GSTPAY; @@ -181,6 +183,8 @@ gst_rtsp_media_factory_uri_finalize (GObject * obj) { GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (obj); + GST_DEBUG_OBJECT (factory, "finalize"); + g_free (factory->uri); gst_plugin_feature_list_free (factory->demuxers); gst_plugin_feature_list_free (factory->payloaders); From 37a7ec8033511cc8950047daad7e28953b9f5fe9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Nov 2012 12:29:55 +0100 Subject: [PATCH 0518/1776] factory: keep ref to factory while media active While the media from a factory is alive, keep a ref to the factory. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=663555 --- gst/rtsp-server/rtsp-media-factory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 1140e8bbd5..29308c0267 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -653,8 +653,8 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, if (!gst_rtsp_media_is_reusable (media)) { /* when not reusable, connect to the unprepare signal to remove the item * from our cache when it gets unprepared */ - g_signal_connect (media, "unprepared", (GCallback) media_unprepared, - factory); + g_signal_connect_object (media, "unprepared", + (GCallback) media_unprepared, factory, 0); } } } From f494eec5e7d5331ed0e61a76e9d7440534288f9b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Nov 2012 12:47:20 +0100 Subject: [PATCH 0519/1776] test-uri: fix callback signature --- examples/test-uri.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/test-uri.c b/examples/test-uri.c index d738b33107..62c06e68b7 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -23,7 +23,7 @@ static gboolean -timeout (GstRTSPServer * server, gboolean ignored) +timeout (GstRTSPServer * server) { GstRTSPSessionPool *pool; From 1023b60959062d49df8a3cfccb6bc1cb28d548ba Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Nov 2012 12:47:49 +0100 Subject: [PATCH 0520/1776] test-uri: remove mapping example --- examples/test-uri.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/examples/test-uri.c b/examples/test-uri.c index 62c06e68b7..5d134a0845 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -34,6 +34,19 @@ timeout (GstRTSPServer * server) return TRUE; } +static gboolean +remove_map (GstRTSPServer * server) +{ + GstRTSPMediaMapping *mapping; + + g_print ("removing /test mapping\n"); + mapping = gst_rtsp_server_get_media_mapping (server); + gst_rtsp_media_mapping_remove_factory (mapping, "/test"); + g_object_unref (mapping); + + return FALSE; +} + int main (int argc, char *argv[]) { @@ -79,7 +92,11 @@ main (int argc, char *argv[]) if (gst_rtsp_server_attach (server, NULL) == 0) goto failed; + /* do session cleanup every 2 seconds */ g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + /* remove the mapping after 10 seconds, new clients won't be able to use the + * /test url anymore */ + g_timeout_add_seconds (10, (GSourceFunc) remove_map, server); /* start serving */ g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); From ca11abd193012f99b33412a0f7eaca8a8ea02a5d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 Nov 2012 13:34:46 +0100 Subject: [PATCH 0521/1776] test-auth: add example of how to remove sessions Add an example of the session filter api. --- examples/test-auth.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/examples/test-auth.c b/examples/test-auth.c index eeb61fdf5c..2375bc0991 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -21,9 +21,29 @@ #include +static gboolean +remove_func (GstRTSPSessionPool * pool, GstRTSPSession * session, + GstRTSPServer * server) +{ + return GST_RTSP_FILTER_REMOVE; +} static gboolean -timeout (GstRTSPServer * server, gboolean ignored) +remove_sessions (GstRTSPServer * server) +{ + GstRTSPSessionPool *pool; + + g_print ("removing all sessions\n"); + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_filter (pool, (GstRTSPSessionFilterFunc) remove_func, + server); + g_object_unref (pool); + + return FALSE; +} + +static gboolean +timeout (GstRTSPServer * server) { GstRTSPSessionPool *pool; @@ -100,8 +120,11 @@ main (int argc, char *argv[]) goto failed; g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + g_timeout_add_seconds (10, (GSourceFunc) remove_sessions, server); /* start serving */ + g_print ("stream with user:admin ready at rtsp://127.0.0.1:8554/test\n"); + g_print ("stream with user2:admin2 ready at rtsp://127.0.0.1:8554/test2\n"); g_main_loop_run (loop); return 0; From 9387c4b451fbc7e26a7d35124c438ab68049736e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 21 Nov 2012 16:41:37 +0100 Subject: [PATCH 0522/1776] examples: fix whitespace --- examples/test-launch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/test-launch.c b/examples/test-launch.c index 407e576a83..539b9c5c2c 100644 --- a/examples/test-launch.c +++ b/examples/test-launch.c @@ -48,7 +48,7 @@ main (int argc, char *argv[]) mapping = gst_rtsp_server_get_media_mapping (server); /* make a media factory for a test stream. The default media factory can use - * gst-launch syntax to create pipelines. + * gst-launch syntax to create pipelines. * any launch line works as long as it contains elements named pay%d. Each * element with pay%d names will be a stream */ factory = gst_rtsp_media_factory_new (); From 5eb5fd45f323eaf5240a3387a641a4e2190142c5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 21 Nov 2012 16:41:56 +0100 Subject: [PATCH 0523/1776] media: support more Range formats Use the new -base methods to convert the Range string into a seek start and stop value. --- gst/rtsp-server/rtsp-media.c | 66 +++++++++++------------------------- gst/rtsp-server/rtsp-media.h | 4 +++ 2 files changed, 24 insertions(+), 46 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 979ba826eb..9d471de72c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -259,8 +259,10 @@ collect_media_stats (GstRTSPMedia * media) if (media->is_live) { media->range.min.type = GST_RTSP_TIME_NOW; media->range.min.seconds = -1; + media->range_start = -1; media->range.max.type = GST_RTSP_TIME_END; media->range.max.seconds = -1; + media->range_stop = -1; } else { /* get the position */ if (!gst_element_query_position (media->pipeline, GST_FORMAT_TIME, @@ -282,16 +284,20 @@ collect_media_stats (GstRTSPMedia * media) if (position == -1) { media->range.min.type = GST_RTSP_TIME_NOW; media->range.min.seconds = -1; + media->range_start = -1; } else { media->range.min.type = GST_RTSP_TIME_SECONDS; media->range.min.seconds = ((gdouble) position) / GST_SECOND; + media->range_start = position; } if (duration == -1) { media->range.max.type = GST_RTSP_TIME_END; media->range.max.seconds = -1; + media->range_start = -1; } else { media->range.max.type = GST_RTSP_TIME_SECONDS; media->range.max.seconds = ((gdouble) duration) / GST_SECOND; + media->range_stop = duration; } } } @@ -824,7 +830,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) { GstSeekFlags flags; gboolean res; - gint64 start, stop; + GstClockTime start, stop; GstSeekType start_type, stop_type; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); @@ -834,52 +840,26 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) if (!media->seekable) goto not_seekable; - if (range->unit != GST_RTSP_RANGE_NPT) - goto not_supported; - /* depends on the current playing state of the pipeline. We might need to * queue this until we get EOS. */ flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT; start_type = stop_type = GST_SEEK_TYPE_NONE; - switch (range->min.type) { - case GST_RTSP_TIME_NOW: - start = -1; - break; - case GST_RTSP_TIME_SECONDS: - /* only seek when something changed */ - if (media->range.min.seconds == range->min.seconds) { - start = -1; - } else { - start = range->min.seconds * GST_SECOND; - start_type = GST_SEEK_TYPE_SET; - } - break; - case GST_RTSP_TIME_END: - default: - goto weird_type; - } - switch (range->max.type) { - case GST_RTSP_TIME_SECONDS: - /* only seek when something changed */ - if (media->range.max.seconds == range->max.seconds) { - stop = -1; - } else { - stop = range->max.seconds * GST_SECOND; - stop_type = GST_SEEK_TYPE_SET; - } - break; - case GST_RTSP_TIME_END: - stop = -1; - stop_type = GST_SEEK_TYPE_SET; - break; - case GST_RTSP_TIME_NOW: - default: - goto weird_type; - } + if (!gst_rtsp_range_get_times (range, &start, &stop)) + goto not_supported; - if (start != -1 || stop != -1) { + if (media->range_start == start) + start = GST_CLOCK_TIME_NONE; + else if (start != GST_CLOCK_TIME_NONE) + start_type = GST_SEEK_TYPE_SET; + + if (media->range_stop == stop) + stop = GST_CLOCK_TIME_NONE; + else if (stop != GST_CLOCK_TIME_NONE) + stop_type = GST_SEEK_TYPE_SET; + + if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) { GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); @@ -913,12 +893,6 @@ not_supported: GST_WARNING ("seek unit %d not supported", range->unit); return FALSE; } -weird_type: - { - g_rec_mutex_unlock (&media->state_lock); - GST_WARNING ("weird range type %d not supported", range->min.type); - return FALSE; - } } static void diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index bef1972a1a..b848a105f4 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -92,6 +92,8 @@ typedef enum { * @target_state: the desired target state of the pipeline * @rtpbin: the rtpbin * @range: the range of the media being streamed + * @range_start: range start in #GstClockTime + * @range_stop: range stop in #GstClockTime * * A class that contains the GStreamer element along with a list of * #GstRTSPStream objects that can produce data. @@ -138,6 +140,8 @@ struct _GstRTSPMedia { /* the range of media */ GstRTSPTimeRange range; + GstClockTime range_start; + GstClockTime range_stop; }; /** From 0f93879b2c21790c07f9bc5e1cfabdca4e7c51c7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 21 Nov 2012 17:21:28 +0100 Subject: [PATCH 0524/1776] media: fix seeking --- gst/rtsp-server/rtsp-media.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 9d471de72c..9004b0115f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -293,7 +293,7 @@ collect_media_stats (GstRTSPMedia * media) if (duration == -1) { media->range.max.type = GST_RTSP_TIME_END; media->range.max.seconds = -1; - media->range_start = -1; + media->range_stop = -1; } else { media->range.max.type = GST_RTSP_TIME_SECONDS; media->range.max.seconds = ((gdouble) duration) / GST_SECOND; @@ -849,6 +849,11 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) if (!gst_rtsp_range_get_times (range, &start, &stop)) goto not_supported; + GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, + GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); + GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, + GST_TIME_ARGS (media->range_start), GST_TIME_ARGS (media->range_stop)); + if (media->range_start == start) start = GST_CLOCK_TIME_NONE; else if (start != GST_CLOCK_TIME_NONE) From d6ac48fcfd0e94164e64fe6b515e2a3bc5dfa158 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 09:36:09 +0100 Subject: [PATCH 0525/1776] configure: bump required version of -base --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index e832a866fd..46a0714485 100644 --- a/configure.ac +++ b/configure.ac @@ -43,7 +43,7 @@ AS_LIBTOOL(GST, 0, 0, 0) dnl *** required versions of GStreamer stuff *** GST_REQ=1.0.0 -GSTPB_REQ=1.0.0 +GSTPB_REQ=1.1.0.1 GSTPG_REQ=1.0.0 dnl *** autotools stuff **** From 1d53c46d23a251cd43495b04ab016a2ca6a4a93a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 12:34:05 +0100 Subject: [PATCH 0526/1776] MediaMapping -> MountPoints Describes better what the object manages. --- docs/README | 22 ++-- docs/libs/gst-rtsp-server-docs.sgml | 2 +- docs/libs/gst-rtsp-server-sections.txt | 42 +++--- docs/libs/gst-rtsp-server.types | 4 +- examples/test-auth.c | 12 +- examples/test-launch.c | 10 +- examples/test-mp4.c | 10 +- examples/test-multicast.c | 10 +- examples/test-multicast2.c | 10 +- examples/test-ogg.c | 10 +- examples/test-readme.c | 10 +- examples/test-sdp.c | 10 +- examples/test-uri.c | 22 ++-- examples/test-video.c | 10 +- gst/rtsp-server/Makefile.am | 4 +- gst/rtsp-server/rtsp-auth.h | 2 - gst/rtsp-server/rtsp-client.c | 70 +++++----- gst/rtsp-server/rtsp-client.h | 12 +- gst/rtsp-server/rtsp-media-mapping.c | 176 ------------------------- gst/rtsp-server/rtsp-media-mapping.h | 87 ------------ gst/rtsp-server/rtsp-mount-points.c | 176 +++++++++++++++++++++++++ gst/rtsp-server/rtsp-mount-points.h | 87 ++++++++++++ gst/rtsp-server/rtsp-server.c | 66 +++++----- gst/rtsp-server/rtsp-server.h | 10 +- gst/rtsp-server/rtsp-session-media.c | 4 - gst/rtsp-server/rtsp-session-pool.c | 2 - gst/rtsp-server/rtsp-session-pool.h | 2 +- tests/check/gst/rtspserver.c | 12 +- 28 files changed, 444 insertions(+), 450 deletions(-) delete mode 100644 gst/rtsp-server/rtsp-media-mapping.c delete mode 100644 gst/rtsp-server/rtsp-media-mapping.h create mode 100644 gst/rtsp-server/rtsp-mount-points.c create mode 100644 gst/rtsp-server/rtsp-mount-points.h diff --git a/docs/README b/docs/README index bbf1343052..943382e29f 100644 --- a/docs/README +++ b/docs/README @@ -94,7 +94,7 @@ can build simple server applications with it. } The server manages two other objects: GstRTSPSessionPool and - GstRTSPMediaMapping. + GstRTSPMountPoints. The GstRTSPSessionPool is an object that keeps track of all the active sessions in the server. A session will usually be kept for each client that performed a @@ -104,13 +104,13 @@ can build simple server applications with it. The default implementation of the session pool is usually sufficient but alternative implementation can be used by the server. - The GstRTSPMediaMapping object is more interesting and needs more configuration + The GstRTSPMountPoints object is more interesting and needs more configuration before the server object is useful. This object manages the mapping from a request URL to a specific stream and its configuration. We explain in the next topic how to configure this object. -* Making url mappings +* Making url mount points Next we need to define what media is attached to a particular URL. What we want to achieve is that when the user asks our server for a specific URL, say /test, @@ -141,19 +141,19 @@ can build simple server applications with it. "( videotestsrc ! x264enc ! rtph264pay pt=96 name=pay0 )"); Now that we have the media factory, we can attach it to a specific url. To do - this we get the default GstRTSPMediaMapping from our server and add the url to - factory mapping to it like this: + this we get the default GstRTSPMountPoints from our server and add the url to + factory mount points to it like this: - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; ...create server..create factory.. - /* get the default mapping from the server */ - mapping = gst_rtsp_server_get_media_mapping (server); + /* get the default mount points from the server */ + mounts = gst_rtsp_server_get_mount_points (server); /* attach the video test signal to the "/test" URL */ - gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); - g_object_unref (mapping); + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + g_object_unref (mounts); When starting the server now and directing an RTP client to the URL (like with vlc, mplayer or gstreamer): @@ -387,7 +387,7 @@ GstRTSPAuth basic authentication. -GstRTSPMediaMapping +GstRTSPMountPoints - Maps a url to a GstRTSPMediaFactory implementation. The default implementation uses a simple hashtable to map a url to a factory. diff --git a/docs/libs/gst-rtsp-server-docs.sgml b/docs/libs/gst-rtsp-server-docs.sgml index 2311bd36b2..5e0229952f 100644 --- a/docs/libs/gst-rtsp-server-docs.sgml +++ b/docs/libs/gst-rtsp-server-docs.sgml @@ -17,7 +17,7 @@ - + diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index fa46f302dc..86dce469ba 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -1,22 +1,22 @@
-rtsp-media-mapping -GstRTSPMediaMapping -GstRTSPMediaMapping -GstRTSPMediaMappingClass -gst_rtsp_media_mapping_new -gst_rtsp_media_mapping_find_factory -gst_rtsp_media_mapping_add_factory -gst_rtsp_media_mapping_remove_factory +rtsp-mount-points +GstRTSPMountPoints +GstRTSPMountPoints +GstRTSPMountPointsClass +gst_rtsp_mount_points_new +gst_rtsp_mount_points_find_factory +gst_rtsp_mount_points_add_factory +gst_rtsp_mount_points_remove_factory -GST_RTSP_MEDIA_MAPPING_CLASS -GST_RTSP_MEDIA_MAPPING_CAST -GST_RTSP_MEDIA_MAPPING_CLASS_CAST -GST_RTSP_MEDIA_MAPPING -GST_IS_RTSP_MEDIA_MAPPING -GST_TYPE_RTSP_MEDIA_MAPPING -gst_rtsp_media_mapping_get_type -GST_IS_RTSP_MEDIA_MAPPING_CLASS -GST_RTSP_MEDIA_MAPPING_GET_CLASS +GST_RTSP_MOUNT_POINTS_CLASS +GST_RTSP_MOUNT_POINTS_CAST +GST_RTSP_MOUNT_POINTS_CLASS_CAST +GST_RTSP_MOUNT_POINTS +GST_IS_RTSP_MOUNT_POINTS +GST_TYPE_RTSP_MOUNT_POINTS +gst_rtsp_mount_points_get_type +GST_IS_RTSP_MOUNT_POINTS_CLASS +GST_RTSP_MOUNT_POINTS_GET_CLASS
@@ -135,8 +135,8 @@ gst_rtsp_server_set_backlog gst_rtsp_server_get_backlog gst_rtsp_server_set_session_pool gst_rtsp_server_get_session_pool -gst_rtsp_server_set_media_mapping -gst_rtsp_server_get_media_mapping +gst_rtsp_server_set_mount_points +gst_rtsp_server_get_mount_points gst_rtsp_server_get_auth gst_rtsp_server_set_auth gst_rtsp_server_transfer_connection @@ -272,8 +272,8 @@ gst_rtsp_client_set_server gst_rtsp_client_get_server gst_rtsp_client_set_session_pool gst_rtsp_client_get_session_pool -gst_rtsp_client_set_media_mapping -gst_rtsp_client_get_media_mapping +gst_rtsp_client_set_mount_points +gst_rtsp_client_get_mount_points gst_rtsp_client_set_use_client_settings gst_rtsp_client_get_use_client_settings gst_rtsp_client_set_auth diff --git a/docs/libs/gst-rtsp-server.types b/docs/libs/gst-rtsp-server.types index 3189f2a5fc..f4476f2e09 100644 --- a/docs/libs/gst-rtsp-server.types +++ b/docs/libs/gst-rtsp-server.types @@ -3,8 +3,8 @@ #include gst_rtsp_auth_get_type -#include -gst_rtsp_media_mapping_get_type +#include +gst_rtsp_mount_points_get_type #include gst_rtsp_media_factory_get_type diff --git a/examples/test-auth.c b/examples/test-auth.c index 2375bc0991..a5057437a8 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -59,7 +59,7 @@ main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; GstRTSPAuth *auth; gchar *basic; @@ -71,9 +71,9 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); - /* get the mapping for this server, every server has a default mapper object + /* get the mounts for this server, every server has a default mapper object * that be used to map uri mount points to media factories */ - mapping = gst_rtsp_server_get_media_mapping (server); + mounts = gst_rtsp_server_get_mount_points (server); /* make a media factory for a test stream. The default media factory can use @@ -95,7 +95,7 @@ main (int argc, char *argv[]) gst_rtsp_media_factory_set_auth (factory, auth); g_object_unref (auth); /* attach the test factory to the /test url */ - gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); /* make another factory */ factory = gst_rtsp_media_factory_new (); @@ -110,10 +110,10 @@ main (int argc, char *argv[]) gst_rtsp_media_factory_set_auth (factory, auth); g_object_unref (auth); /* attach the test factory to the /test url */ - gst_rtsp_media_mapping_add_factory (mapping, "/test2", factory); + gst_rtsp_mount_points_add_factory (mounts, "/test2", factory); /* don't need the ref to the mapper anymore */ - g_object_unref (mapping); + g_object_unref (mounts); /* attach the server to the default maincontext */ if (gst_rtsp_server_attach (server, NULL) == 0) diff --git a/examples/test-launch.c b/examples/test-launch.c index 539b9c5c2c..0466224146 100644 --- a/examples/test-launch.c +++ b/examples/test-launch.c @@ -26,7 +26,7 @@ main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; gst_init (&argc, &argv); @@ -43,9 +43,9 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); - /* get the mapping for this server, every server has a default mapper object + /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ - mapping = gst_rtsp_server_get_media_mapping (server); + mounts = gst_rtsp_server_get_mount_points (server); /* make a media factory for a test stream. The default media factory can use * gst-launch syntax to create pipelines. @@ -55,10 +55,10 @@ main (int argc, char *argv[]) gst_rtsp_media_factory_set_launch (factory, argv[1]); /* attach the test factory to the /test url */ - gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); /* don't need the ref to the mapper anymore */ - g_object_unref (mapping); + g_object_unref (mounts); /* attach the server to the default maincontext */ gst_rtsp_server_attach (server, NULL); diff --git a/examples/test-mp4.c b/examples/test-mp4.c index b2e96600e7..b69c7cd295 100644 --- a/examples/test-mp4.c +++ b/examples/test-mp4.c @@ -26,7 +26,7 @@ main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; gchar *str; @@ -42,9 +42,9 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); - /* get the mapping for this server, every server has a default mapper object + /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ - mapping = gst_rtsp_server_get_media_mapping (server); + mounts = gst_rtsp_server_get_mount_points (server); str = g_strdup_printf ("( " "filesrc location=%s ! qtdemux name=d " @@ -60,10 +60,10 @@ main (int argc, char *argv[]) g_free (str); /* attach the test factory to the /test url */ - gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); /* don't need the ref to the mapper anymore */ - g_object_unref (mapping); + g_object_unref (mounts); /* attach the server to the default maincontext */ gst_rtsp_server_attach (server, NULL); diff --git a/examples/test-multicast.c b/examples/test-multicast.c index 4cd064e7aa..6d4234e268 100644 --- a/examples/test-multicast.c +++ b/examples/test-multicast.c @@ -39,7 +39,7 @@ main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; GstRTSPAddressPool *pool; @@ -50,9 +50,9 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); - /* get the mapping for this server, every server has a default mapper object + /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ - mapping = gst_rtsp_server_get_media_mapping (server); + mounts = gst_rtsp_server_get_mount_points (server); /* make a media factory for a test stream. The default media factory can use * gst-launch syntax to create pipelines. @@ -75,10 +75,10 @@ main (int argc, char *argv[]) g_object_unref (pool); /* attach the test factory to the /test url */ - gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); /* don't need the ref to the mapper anymore */ - g_object_unref (mapping); + g_object_unref (mounts); /* attach the server to the default maincontext */ if (gst_rtsp_server_attach (server, NULL) == 0) diff --git a/examples/test-multicast2.c b/examples/test-multicast2.c index 7a95374d24..1d8e6f2654 100644 --- a/examples/test-multicast2.c +++ b/examples/test-multicast2.c @@ -68,7 +68,7 @@ main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; gst_init (&argc, &argv); @@ -78,9 +78,9 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); - /* get the mapping for this server, every server has a default mapper object + /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ - mapping = gst_rtsp_server_get_media_mapping (server); + mounts = gst_rtsp_server_get_mount_points (server); /* make a media factory for a test stream. The default media factory can use * gst-launch syntax to create pipelines. @@ -99,10 +99,10 @@ main (int argc, char *argv[]) media_constructed, NULL); /* attach the test factory to the /test url */ - gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); /* don't need the ref to the mapper anymore */ - g_object_unref (mapping); + g_object_unref (mounts); /* attach the server to the default maincontext */ if (gst_rtsp_server_attach (server, NULL) == 0) diff --git a/examples/test-ogg.c b/examples/test-ogg.c index d7f2d2d195..5e844ad779 100644 --- a/examples/test-ogg.c +++ b/examples/test-ogg.c @@ -26,7 +26,7 @@ main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; gchar *str; @@ -42,9 +42,9 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); - /* get the mapping for this server, every server has a default mapper object + /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ - mapping = gst_rtsp_server_get_media_mapping (server); + mounts = gst_rtsp_server_get_mount_points (server); str = g_strdup_printf ("( " "filesrc location=%s ! oggdemux name=d " @@ -60,10 +60,10 @@ main (int argc, char *argv[]) g_free (str); /* attach the test factory to the /test url */ - gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); /* don't need the ref to the mapper anymore */ - g_object_unref (mapping); + g_object_unref (mounts); /* attach the server to the default maincontext */ gst_rtsp_server_attach (server, NULL); diff --git a/examples/test-readme.c b/examples/test-readme.c index 0d2bcd7680..2e2caa6766 100644 --- a/examples/test-readme.c +++ b/examples/test-readme.c @@ -26,7 +26,7 @@ main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; gst_init (&argc, &argv); @@ -36,9 +36,9 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); - /* get the mapping for this server, every server has a default mapper object + /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ - mapping = gst_rtsp_server_get_media_mapping (server); + mounts = gst_rtsp_server_get_mount_points (server); /* make a media factory for a test stream. The default media factory can use * gst-launch syntax to create pipelines. @@ -51,10 +51,10 @@ main (int argc, char *argv[]) gst_rtsp_media_factory_set_shared (factory, TRUE); /* attach the test factory to the /test url */ - gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); /* don't need the ref to the mapper anymore */ - g_object_unref (mapping); + g_object_unref (mounts); /* attach the server to the default maincontext */ gst_rtsp_server_attach (server, NULL); diff --git a/examples/test-sdp.c b/examples/test-sdp.c index b5508e44e5..f3d9e57f70 100644 --- a/examples/test-sdp.c +++ b/examples/test-sdp.c @@ -39,7 +39,7 @@ main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; gchar *str; @@ -55,9 +55,9 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); - /* get the mapping for this server, every server has a default mapper object + /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ - mapping = gst_rtsp_server_get_media_mapping (server); + mounts = gst_rtsp_server_get_mount_points (server); /* make a media factory for a test stream. The default media factory can use * gst-launch syntax to create pipelines. @@ -73,10 +73,10 @@ main (int argc, char *argv[]) g_free (str); /* attach the test factory to the /test url */ - gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); /* don't need the ref to the mapper anymore */ - g_object_unref (mapping); + g_object_unref (mounts); /* attach the server to the default maincontext */ gst_rtsp_server_attach (server, NULL); diff --git a/examples/test-uri.c b/examples/test-uri.c index 5d134a0845..62f1caa582 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -37,12 +37,12 @@ timeout (GstRTSPServer * server) static gboolean remove_map (GstRTSPServer * server) { - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; - g_print ("removing /test mapping\n"); - mapping = gst_rtsp_server_get_media_mapping (server); - gst_rtsp_media_mapping_remove_factory (mapping, "/test"); - g_object_unref (mapping); + g_print ("removing /test mount point\n"); + mounts = gst_rtsp_server_get_mount_points (server); + gst_rtsp_mount_points_remove_factory (mounts, "/test"); + g_object_unref (mounts); return FALSE; } @@ -52,7 +52,7 @@ main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; GstRTSPMediaFactoryURI *factory; gst_init (&argc, &argv); @@ -67,9 +67,9 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); - /* get the mapping for this server, every server has a default mapper object + /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ - mapping = gst_rtsp_server_get_media_mapping (server); + mounts = gst_rtsp_server_get_mount_points (server); /* make a URI media factory for a test stream. */ factory = gst_rtsp_media_factory_uri_new (); @@ -82,11 +82,11 @@ main (int argc, char *argv[]) /* gst_rtsp_media_factory_set_shared ( GST_RTSP_MEDIA_FACTORY (factory), TRUE); */ /* attach the test factory to the /test url */ - gst_rtsp_media_mapping_add_factory (mapping, "/test", + gst_rtsp_mount_points_add_factory (mounts, "/test", GST_RTSP_MEDIA_FACTORY (factory)); /* don't need the ref to the mapper anymore */ - g_object_unref (mapping); + g_object_unref (mounts); /* attach the server to the default maincontext */ if (gst_rtsp_server_attach (server, NULL) == 0) @@ -94,7 +94,7 @@ main (int argc, char *argv[]) /* do session cleanup every 2 seconds */ g_timeout_add_seconds (2, (GSourceFunc) timeout, server); - /* remove the mapping after 10 seconds, new clients won't be able to use the + /* remove the mount point after 10 seconds, new clients won't be able to use the * /test url anymore */ g_timeout_add_seconds (10, (GSourceFunc) remove_map, server); diff --git a/examples/test-video.c b/examples/test-video.c index ab5ce9db31..2cfe483975 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -45,7 +45,7 @@ main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; #ifdef WITH_AUTH GstRTSPAuth *auth; @@ -59,9 +59,9 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); - /* get the mapping for this server, every server has a default mapper object + /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ - mapping = gst_rtsp_server_get_media_mapping (server); + mounts = gst_rtsp_server_get_mount_points (server); #ifdef WITH_AUTH /* make a new authentication manager. it can be added to control access to all @@ -86,10 +86,10 @@ main (int argc, char *argv[]) "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); /* attach the test factory to the /test url */ - gst_rtsp_media_mapping_add_factory (mapping, "/test", factory); + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); /* don't need the ref to the mapper anymore */ - g_object_unref (mapping); + g_object_unref (mounts); /* attach the server to the default maincontext */ if (gst_rtsp_server_attach (server, NULL) == 0) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index f8da7447cd..008e4189da 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -6,7 +6,7 @@ public_headers = \ rtsp-media.h \ rtsp-media-factory.h \ rtsp-media-factory-uri.h \ - rtsp-media-mapping.h \ + rtsp-mount-points.h \ rtsp-stream.h \ rtsp-stream-transport.h \ rtsp-session.h \ @@ -23,7 +23,7 @@ c_sources = \ rtsp-media.c \ rtsp-media-factory.c \ rtsp-media-factory-uri.c \ - rtsp-media-mapping.c \ + rtsp-mount-points.c \ rtsp-stream.c \ rtsp-stream-transport.c \ rtsp-session.c \ diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 250c05cc5b..a71388cde0 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -26,8 +26,6 @@ typedef struct _GstRTSPAuth GstRTSPAuth; typedef struct _GstRTSPAuthClass GstRTSPAuthClass; #include "rtsp-client.h" -#include "rtsp-media-mapping.h" -#include "rtsp-session-pool.h" G_BEGIN_DECLS diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a0ba3c52e5..0620233c7e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -28,14 +28,14 @@ static GMutex tunnels_lock; static GHashTable *tunnels; #define DEFAULT_SESSION_POOL NULL -#define DEFAULT_MEDIA_MAPPING NULL +#define DEFAULT_MOUNT_POINTS NULL #define DEFAULT_USE_CLIENT_SETTINGS FALSE enum { PROP_0, PROP_SESSION_POOL, - PROP_MEDIA_MAPPING, + PROP_MOUNT_POINTS, PROP_USE_CLIENT_SETTINGS, PROP_LAST }; @@ -93,10 +93,10 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING, - g_param_spec_object ("media-mapping", "Media Mapping", - "The media mapping to use for client session", - GST_TYPE_RTSP_MEDIA_MAPPING, + g_object_class_install_property (gobject_class, PROP_MOUNT_POINTS, + g_param_spec_object ("mount-points", "Mount Points", + "The mount points to use for client session", + GST_TYPE_RTSP_MOUNT_POINTS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_USE_CLIENT_SETTINGS, @@ -223,8 +223,8 @@ gst_rtsp_client_finalize (GObject * obj) gst_rtsp_connection_free (client->connection); if (client->session_pool) g_object_unref (client->session_pool); - if (client->media_mapping) - g_object_unref (client->media_mapping); + if (client->mount_points) + g_object_unref (client->mount_points); if (client->auth) g_object_unref (client->auth); @@ -250,8 +250,8 @@ gst_rtsp_client_get_property (GObject * object, guint propid, case PROP_SESSION_POOL: g_value_take_object (value, gst_rtsp_client_get_session_pool (client)); break; - case PROP_MEDIA_MAPPING: - g_value_take_object (value, gst_rtsp_client_get_media_mapping (client)); + case PROP_MOUNT_POINTS: + g_value_take_object (value, gst_rtsp_client_get_mount_points (client)); break; case PROP_USE_CLIENT_SETTINGS: g_value_set_boolean (value, @@ -272,8 +272,8 @@ gst_rtsp_client_set_property (GObject * object, guint propid, case PROP_SESSION_POOL: gst_rtsp_client_set_session_pool (client, g_value_get_object (value)); break; - case PROP_MEDIA_MAPPING: - gst_rtsp_client_set_media_mapping (client, g_value_get_object (value)); + case PROP_MOUNT_POINTS: + gst_rtsp_client_set_mount_points (client, g_value_get_object (value)); break; case PROP_USE_CLIENT_SETTINGS: gst_rtsp_client_set_use_client_settings (client, @@ -385,12 +385,12 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) } client->media = NULL; - if (!client->media_mapping) - goto no_mapping; + if (!client->mount_points) + goto no_mount_points; /* find the factory for the uri first */ if (!(factory = - gst_rtsp_media_mapping_find_factory (client->media_mapping, + gst_rtsp_mount_points_find_factory (client->mount_points, state->uri))) goto no_factory; @@ -436,7 +436,7 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) return media; /* ERRORS */ -no_mapping: +no_mount_points: { send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return NULL; @@ -1752,45 +1752,45 @@ gst_rtsp_client_get_server (GstRTSPClient * client) } /** - * gst_rtsp_client_set_media_mapping: + * gst_rtsp_client_set_mount_points: * @client: a #GstRTSPClient - * @mapping: a #GstRTSPMediaMapping + * @mounts: a #GstRTSPMountPoints * - * Set @mapping as the media mapping for @client which it will use to map urls - * to media streams. These mapping is usually inherited from the server that + * Set @mounts as the mount points for @client which it will use to map urls + * to media streams. These mount points are usually inherited from the server that * created the client but can be overriden later. */ void -gst_rtsp_client_set_media_mapping (GstRTSPClient * client, - GstRTSPMediaMapping * mapping) +gst_rtsp_client_set_mount_points (GstRTSPClient * client, + GstRTSPMountPoints * mounts) { - GstRTSPMediaMapping *old; + GstRTSPMountPoints *old; - old = client->media_mapping; + old = client->mount_points; - if (old != mapping) { - if (mapping) - g_object_ref (mapping); - client->media_mapping = mapping; + if (old != mounts) { + if (mounts) + g_object_ref (mounts); + client->mount_points = mounts; if (old) g_object_unref (old); } } /** - * gst_rtsp_client_get_media_mapping: + * gst_rtsp_client_get_mount_points: * @client: a #GstRTSPClient * - * Get the #GstRTSPMediaMapping object that @client uses to manage its sessions. + * Get the #GstRTSPMountPoints object that @client uses to manage its sessions. * - * Returns: (transfer full): a #GstRTSPMediaMapping, unref after usage. + * Returns: (transfer full): a #GstRTSPMountPoints, unref after usage. */ -GstRTSPMediaMapping * -gst_rtsp_client_get_media_mapping (GstRTSPClient * client) +GstRTSPMountPoints * +gst_rtsp_client_get_mount_points (GstRTSPClient * client) { - GstRTSPMediaMapping *result; + GstRTSPMountPoints *result; - if ((result = client->media_mapping)) + if ((result = client->mount_points)) g_object_ref (result); return result; diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index dd4e71230e..2b84319601 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -31,7 +31,7 @@ typedef struct _GstRTSPClientState GstRTSPClientState; #include "rtsp-server.h" #include "rtsp-media.h" -#include "rtsp-media-mapping.h" +#include "rtsp-mount-points.h" #include "rtsp-session-pool.h" #include "rtsp-session-media.h" #include "rtsp-auth.h" @@ -80,7 +80,7 @@ struct _GstRTSPClientState { * @ip: ip address used by the client to connect to us * @use_client_settings: whether to allow client transport settings for multicast * @session_pool: handle to the session pool used by the client. - * @media_mapping: handle to the media mapping used by the client. + * @mount_points: handle to the mount points used by the client. * @uri: cached uri * @media: cached media * @transports: a list of #GstRTSPStreamTransport using @connection. @@ -99,7 +99,7 @@ struct _GstRTSPClient { GstRTSPServer *server; GstRTSPSessionPool *session_pool; - GstRTSPMediaMapping *media_mapping; + GstRTSPMountPoints *mount_points; GstRTSPAuth *auth; GstRTSPUrl *uri; @@ -140,9 +140,9 @@ void gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool); GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client); -void gst_rtsp_client_set_media_mapping (GstRTSPClient *client, - GstRTSPMediaMapping *mapping); -GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client); +void gst_rtsp_client_set_mount_points (GstRTSPClient *client, + GstRTSPMountPoints *mounts); +GstRTSPMountPoints * gst_rtsp_client_get_mount_points (GstRTSPClient *client); void gst_rtsp_client_set_use_client_settings (GstRTSPClient * client, gboolean use_client_settings); diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c deleted file mode 100644 index db2a38d242..0000000000 --- a/gst/rtsp-server/rtsp-media-mapping.c +++ /dev/null @@ -1,176 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "rtsp-media-mapping.h" - -G_DEFINE_TYPE (GstRTSPMediaMapping, gst_rtsp_media_mapping, G_TYPE_OBJECT); - -GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug); -#define GST_CAT_DEFAULT rtsp_media_debug - -static void gst_rtsp_media_mapping_finalize (GObject * obj); - -static GstRTSPMediaFactory *find_factory (GstRTSPMediaMapping * mapping, - const GstRTSPUrl * url); - -static void -gst_rtsp_media_mapping_class_init (GstRTSPMediaMappingClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->finalize = gst_rtsp_media_mapping_finalize; - - klass->find_factory = find_factory; - - GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediamapping", 0, - "GstRTSPMediaMapping"); -} - -static void -gst_rtsp_media_mapping_init (GstRTSPMediaMapping * mapping) -{ - GST_DEBUG_OBJECT (mapping, "created"); - - g_mutex_init (&mapping->lock); - mapping->mappings = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); -} - -static void -gst_rtsp_media_mapping_finalize (GObject * obj) -{ - GstRTSPMediaMapping *mapping = GST_RTSP_MEDIA_MAPPING (obj); - - GST_DEBUG_OBJECT (mapping, "finalized"); - - g_hash_table_unref (mapping->mappings); - g_mutex_clear (&mapping->lock); - - G_OBJECT_CLASS (gst_rtsp_media_mapping_parent_class)->finalize (obj); -} - -/** - * gst_rtsp_media_mapping_new: - * - * Make a new media mapping object. - * - * Returns: a new #GstRTSPMediaMapping - */ -GstRTSPMediaMapping * -gst_rtsp_media_mapping_new (void) -{ - GstRTSPMediaMapping *result; - - result = g_object_new (GST_TYPE_RTSP_MEDIA_MAPPING, NULL); - - return result; -} - -static GstRTSPMediaFactory * -find_factory (GstRTSPMediaMapping * mapping, const GstRTSPUrl * url) -{ - GstRTSPMediaFactory *result; - - g_mutex_lock (&mapping->lock); - /* find the location of the media in the hashtable we only use the absolute - * path of the uri to find a mapping. If the mapping depends on other - * properties found in the url, this method should be overridden. */ - result = g_hash_table_lookup (mapping->mappings, url->abspath); - if (result) - g_object_ref (result); - g_mutex_unlock (&mapping->lock); - - GST_INFO ("found media %p for url abspath %s", result, url->abspath); - - return result; -} - -/** - * gst_rtsp_media_mapping_find_factory: - * @mapping: a #GstRTSPMediaMapping - * @url: a url - * - * Find the #GstRTSPMediaFactory for @url. The default implementation of this object - * will use the mappings added with gst_rtsp_media_mapping_add_factory (). - * - * Returns: (transfer full): the #GstRTSPMediaFactory for @url. g_object_unref() after usage. - */ -GstRTSPMediaFactory * -gst_rtsp_media_mapping_find_factory (GstRTSPMediaMapping * mapping, - const GstRTSPUrl * url) -{ - GstRTSPMediaFactory *result; - GstRTSPMediaMappingClass *klass; - - klass = GST_RTSP_MEDIA_MAPPING_GET_CLASS (mapping); - - if (klass->find_factory) - result = klass->find_factory (mapping, url); - else - result = NULL; - - return result; -} - -/** - * gst_rtsp_media_mapping_add_factory: - * @mapping: a #GstRTSPMediaMapping - * @path: a mount point - * @factory: (transfer full): a #GstRTSPMediaFactory - * - * Attach @factory to the mount point @path in @mapping. - * - * @path is of the form (/node)+. Any previous mapping will be freed. - * - * Ownership is taken of the reference on @factory so that @factory should not be - * used after calling this function. - */ -void -gst_rtsp_media_mapping_add_factory (GstRTSPMediaMapping * mapping, - const gchar * path, GstRTSPMediaFactory * factory) -{ - g_return_if_fail (GST_IS_RTSP_MEDIA_MAPPING (mapping)); - g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); - g_return_if_fail (path != NULL); - - g_mutex_lock (&mapping->lock); - g_hash_table_insert (mapping->mappings, g_strdup (path), factory); - g_mutex_unlock (&mapping->lock); -} - -/** - * gst_rtsp_media_mapping_remove_factory: - * @mapping: a #GstRTSPMediaMapping - * @path: a mount point - * - * Remove the #GstRTSPMediaFactory associated with @path in @mapping. - */ -void -gst_rtsp_media_mapping_remove_factory (GstRTSPMediaMapping * mapping, - const gchar * path) -{ - g_return_if_fail (GST_IS_RTSP_MEDIA_MAPPING (mapping)); - g_return_if_fail (path != NULL); - - g_mutex_lock (&mapping->lock); - g_hash_table_remove (mapping->mappings, path); - g_mutex_unlock (&mapping->lock); -} diff --git a/gst/rtsp-server/rtsp-media-mapping.h b/gst/rtsp-server/rtsp-media-mapping.h deleted file mode 100644 index 4025cebd31..0000000000 --- a/gst/rtsp-server/rtsp-media-mapping.h +++ /dev/null @@ -1,87 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include - -#include - -#include "rtsp-media-factory.h" - -#ifndef __GST_RTSP_MEDIA_MAPPING_H__ -#define __GST_RTSP_MEDIA_MAPPING_H__ - -G_BEGIN_DECLS - -#define GST_TYPE_RTSP_MEDIA_MAPPING (gst_rtsp_media_mapping_get_type ()) -#define GST_IS_RTSP_MEDIA_MAPPING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA_MAPPING)) -#define GST_IS_RTSP_MEDIA_MAPPING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA_MAPPING)) -#define GST_RTSP_MEDIA_MAPPING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA_MAPPING, GstRTSPMediaMappingClass)) -#define GST_RTSP_MEDIA_MAPPING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA_MAPPING, GstRTSPMediaMapping)) -#define GST_RTSP_MEDIA_MAPPING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA_MAPPING, GstRTSPMediaMappingClass)) -#define GST_RTSP_MEDIA_MAPPING_CAST(obj) ((GstRTSPMediaMapping*)(obj)) -#define GST_RTSP_MEDIA_MAPPING_CLASS_CAST(klass) ((GstRTSPMediaMappingClass*)(klass)) - -typedef struct _GstRTSPMediaMapping GstRTSPMediaMapping; -typedef struct _GstRTSPMediaMappingClass GstRTSPMediaMappingClass; - -/** - * GstRTSPMediaMapping: - * @parent: parent GObject - * @mappings: the mountpoint to media mappings - * - * Creates a #GstRTSPMediaFactory object for a given url. - */ -struct _GstRTSPMediaMapping { - GObject parent; - - GMutex lock; - GHashTable *mappings; -}; - -/** - * GstRTSPMediaMappingClass: - * @parent_class: parent GObject class - * @find_factory: Create or return a previously cached #GstRTSPMediaFactory object - * for the given url. the default implementation will use the mappings - * added with gst_rtsp_media_mapping_add_factory(). - * - * The class for the media mapping object. - */ -struct _GstRTSPMediaMappingClass { - GObjectClass parent_class; - - GstRTSPMediaFactory * (*find_factory) (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url); -}; - -GType gst_rtsp_media_mapping_get_type (void); - -/* creating a mapping */ -GstRTSPMediaMapping * gst_rtsp_media_mapping_new (void); - -/* finding a media factory */ -GstRTSPMediaFactory * gst_rtsp_media_mapping_find_factory (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url); - -/* managing media to a path */ -void gst_rtsp_media_mapping_add_factory (GstRTSPMediaMapping *mapping, const gchar *path, - GstRTSPMediaFactory *factory); -void gst_rtsp_media_mapping_remove_factory (GstRTSPMediaMapping *mapping, const gchar *path); - -G_END_DECLS - -#endif /* __GST_RTSP_MEDIA_MAPPING_H__ */ diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c new file mode 100644 index 0000000000..d633fe32a7 --- /dev/null +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -0,0 +1,176 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "rtsp-mount-points.h" + +G_DEFINE_TYPE (GstRTSPMountPoints, gst_rtsp_mount_points, G_TYPE_OBJECT); + +GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug); +#define GST_CAT_DEFAULT rtsp_media_debug + +static void gst_rtsp_mount_points_finalize (GObject * obj); + +static GstRTSPMediaFactory *find_factory (GstRTSPMountPoints * mounts, + const GstRTSPUrl * url); + +static void +gst_rtsp_mount_points_class_init (GstRTSPMountPointsClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gst_rtsp_mount_points_finalize; + + klass->find_factory = find_factory; + + GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmountpoints", 0, + "GstRTSPMountPoints"); +} + +static void +gst_rtsp_mount_points_init (GstRTSPMountPoints * mounts) +{ + GST_DEBUG_OBJECT (mounts, "created"); + + g_mutex_init (&mounts->lock); + mounts->mounts = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); +} + +static void +gst_rtsp_mount_points_finalize (GObject * obj) +{ + GstRTSPMountPoints *mounts = GST_RTSP_MOUNT_POINTS (obj); + + GST_DEBUG_OBJECT (mounts, "finalized"); + + g_hash_table_unref (mounts->mounts); + g_mutex_clear (&mounts->lock); + + G_OBJECT_CLASS (gst_rtsp_mount_points_parent_class)->finalize (obj); +} + +/** + * gst_rtsp_mount_points_new: + * + * Make a new mount points object. + * + * Returns: a new #GstRTSPMountPoints + */ +GstRTSPMountPoints * +gst_rtsp_mount_points_new (void) +{ + GstRTSPMountPoints *result; + + result = g_object_new (GST_TYPE_RTSP_MOUNT_POINTS, NULL); + + return result; +} + +static GstRTSPMediaFactory * +find_factory (GstRTSPMountPoints * mounts, const GstRTSPUrl * url) +{ + GstRTSPMediaFactory *result; + + g_mutex_lock (&mounts->lock); + /* find the location of the media in the hashtable we only use the absolute + * path of the uri to find a media factory. If the factory depends on other + * properties found in the url, this method should be overridden. */ + result = g_hash_table_lookup (mounts->mounts, url->abspath); + if (result) + g_object_ref (result); + g_mutex_unlock (&mounts->lock); + + GST_INFO ("found media factory %p for url abspath %s", result, url->abspath); + + return result; +} + +/** + * gst_rtsp_mount_points_find_factory: + * @mounts: a #GstRTSPMountPoints + * @url: a url + * + * Find the #GstRTSPMediaFactory for @url. The default implementation of this object + * will use the media factory added with gst_rtsp_mount_points_add_factory (). + * + * Returns: (transfer full): the #GstRTSPMediaFactory for @url. g_object_unref() after usage. + */ +GstRTSPMediaFactory * +gst_rtsp_mount_points_find_factory (GstRTSPMountPoints * mounts, + const GstRTSPUrl * url) +{ + GstRTSPMediaFactory *result; + GstRTSPMountPointsClass *klass; + + klass = GST_RTSP_MOUNT_POINTS_GET_CLASS (mounts); + + if (klass->find_factory) + result = klass->find_factory (mounts, url); + else + result = NULL; + + return result; +} + +/** + * gst_rtsp_mount_points_add_factory: + * @mounts: a #GstRTSPMountPoints + * @path: a mount point + * @factory: (transfer full): a #GstRTSPMediaFactory + * + * Attach @factory to the mount point @path in @mounts. + * + * @path is of the form (/node)+. Any previous mount point will be freed. + * + * Ownership is taken of the reference on @factory so that @factory should not be + * used after calling this function. + */ +void +gst_rtsp_mount_points_add_factory (GstRTSPMountPoints * mounts, + const gchar * path, GstRTSPMediaFactory * factory) +{ + g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts)); + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + g_return_if_fail (path != NULL); + + g_mutex_lock (&mounts->lock); + g_hash_table_insert (mounts->mounts, g_strdup (path), factory); + g_mutex_unlock (&mounts->lock); +} + +/** + * gst_rtsp_mount_points_remove_factory: + * @mounts: a #GstRTSPMountPoints + * @path: a mount point + * + * Remove the #GstRTSPMediaFactory associated with @path in @mounts. + */ +void +gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints * mounts, + const gchar * path) +{ + g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts)); + g_return_if_fail (path != NULL); + + g_mutex_lock (&mounts->lock); + g_hash_table_remove (mounts->mounts, path); + g_mutex_unlock (&mounts->lock); +} diff --git a/gst/rtsp-server/rtsp-mount-points.h b/gst/rtsp-server/rtsp-mount-points.h new file mode 100644 index 0000000000..3ab601642b --- /dev/null +++ b/gst/rtsp-server/rtsp-mount-points.h @@ -0,0 +1,87 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include "rtsp-media-factory.h" + +#ifndef __GST_RTSP_MOUNT_POINTS_H__ +#define __GST_RTSP_MOUNT_POINTS_H__ + +G_BEGIN_DECLS + +#define GST_TYPE_RTSP_MOUNT_POINTS (gst_rtsp_mount_points_get_type ()) +#define GST_IS_RTSP_MOUNT_POINTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MOUNT_POINTS)) +#define GST_IS_RTSP_MOUNT_POINTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MOUNT_POINTS)) +#define GST_RTSP_MOUNT_POINTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MOUNT_POINTS, GstRTSPMountPointsClass)) +#define GST_RTSP_MOUNT_POINTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MOUNT_POINTS, GstRTSPMountPoints)) +#define GST_RTSP_MOUNT_POINTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MOUNT_POINTS, GstRTSPMountPointsClass)) +#define GST_RTSP_MOUNT_POINTS_CAST(obj) ((GstRTSPMountPoints*)(obj)) +#define GST_RTSP_MOUNT_POINTS_CLASS_CAST(klass) ((GstRTSPMountPointsClass*)(klass)) + +typedef struct _GstRTSPMountPoints GstRTSPMountPoints; +typedef struct _GstRTSPMountPointsClass GstRTSPMountPointsClass; + +/** + * GstRTSPMountPoints: + * @parent: parent GObject + * @mounts: the mountpoints to mediafactory mapping + * + * Creates a #GstRTSPMediaFactory object for a given url. + */ +struct _GstRTSPMountPoints { + GObject parent; + + GMutex lock; + GHashTable *mounts; +}; + +/** + * GstRTSPMountPointsClass: + * @parent_class: parent GObject class + * @find_factory: Create or return a previously cached #GstRTSPMediaFactory object + * for the given url. the default implementation will use the factory + * added with gst_rtsp_mount_points_add_factory(). + * + * The class for the media mounts object. + */ +struct _GstRTSPMountPointsClass { + GObjectClass parent_class; + + GstRTSPMediaFactory * (*find_factory) (GstRTSPMountPoints *mounts, const GstRTSPUrl *url); +}; + +GType gst_rtsp_mount_points_get_type (void); + +/* creating a mount points */ +GstRTSPMountPoints * gst_rtsp_mount_points_new (void); + +/* finding a media factory */ +GstRTSPMediaFactory * gst_rtsp_mount_points_find_factory (GstRTSPMountPoints *mounts, const GstRTSPUrl *url); + +/* managing media to a mount point */ +void gst_rtsp_mount_points_add_factory (GstRTSPMountPoints *mounts, const gchar *path, + GstRTSPMediaFactory *factory); +void gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints *mounts, const gchar *path); + +G_END_DECLS + +#endif /* __GST_RTSP_MOUNT_POINTS_H__ */ diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 9f557ba0cc..4809cb8acc 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -44,7 +44,7 @@ enum PROP_BACKLOG, PROP_SESSION_POOL, - PROP_MEDIA_MAPPING, + PROP_MOUNT_POINTS, PROP_MAX_THREADS, PROP_LAST }; @@ -145,15 +145,15 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRTSPServer::media-mapping: + * GstRTSPServer::mount-points: * - * The media mapping to use for this server. By default the server has no - * media mapping and thus cannot map urls to media streams. + * The mount points to use for this server. By default the server has no + * mount points and thus cannot map urls to media streams. */ - g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING, - g_param_spec_object ("media-mapping", "Media Mapping", - "The media mapping to use for client session", - GST_TYPE_RTSP_MEDIA_MAPPING, + g_object_class_install_property (gobject_class, PROP_MOUNT_POINTS, + g_param_spec_object ("mount-points", "Mount Points", + "The mount points to use for client session", + GST_TYPE_RTSP_MOUNT_POINTS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstRTSPServer::max-threads: @@ -191,7 +191,7 @@ gst_rtsp_server_init (GstRTSPServer * server) server->socket = NULL; server->backlog = DEFAULT_BACKLOG; server->session_pool = gst_rtsp_session_pool_new (); - server->media_mapping = gst_rtsp_media_mapping_new (); + server->mount_points = gst_rtsp_mount_points_new (); server->max_threads = DEFAULT_MAX_THREADS; } @@ -209,7 +209,7 @@ gst_rtsp_server_finalize (GObject * object) g_object_unref (server->socket); g_object_unref (server->session_pool); - g_object_unref (server->media_mapping); + g_object_unref (server->mount_points); if (server->auth) g_object_unref (server->auth); @@ -445,26 +445,26 @@ gst_rtsp_server_get_session_pool (GstRTSPServer * server) } /** - * gst_rtsp_server_set_media_mapping: + * gst_rtsp_server_set_mount_points: * @server: a #GstRTSPServer - * @mapping: a #GstRTSPMediaMapping + * @mounts: a #GstRTSPMountPoints * - * configure @mapping to be used as the media mapping of @server. + * configure @mounts to be used as the mount points of @server. */ void -gst_rtsp_server_set_media_mapping (GstRTSPServer * server, - GstRTSPMediaMapping * mapping) +gst_rtsp_server_set_mount_points (GstRTSPServer * server, + GstRTSPMountPoints * mounts) { - GstRTSPMediaMapping *old; + GstRTSPMountPoints *old; g_return_if_fail (GST_IS_RTSP_SERVER (server)); - if (mapping) - g_object_ref (mapping); + if (mounts) + g_object_ref (mounts); GST_RTSP_SERVER_LOCK (server); - old = server->media_mapping; - server->media_mapping = mapping; + old = server->mount_points; + server->mount_points = mounts; GST_RTSP_SERVER_UNLOCK (server); if (old) @@ -473,23 +473,23 @@ gst_rtsp_server_set_media_mapping (GstRTSPServer * server, /** - * gst_rtsp_server_get_media_mapping: + * gst_rtsp_server_get_mount_points: * @server: a #GstRTSPServer * - * Get the #GstRTSPMediaMapping used as the media mapping of @server. + * Get the #GstRTSPMountPoints used as the mount points of @server. * - * Returns: (transfer full): the #GstRTSPMediaMapping of @server. g_object_unref() after + * Returns: (transfer full): the #GstRTSPMountPoints of @server. g_object_unref() after * usage. */ -GstRTSPMediaMapping * -gst_rtsp_server_get_media_mapping (GstRTSPServer * server) +GstRTSPMountPoints * +gst_rtsp_server_get_mount_points (GstRTSPServer * server) { - GstRTSPMediaMapping *result; + GstRTSPMountPoints *result; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); GST_RTSP_SERVER_LOCK (server); - if ((result = server->media_mapping)) + if ((result = server->mount_points)) g_object_ref (result); GST_RTSP_SERVER_UNLOCK (server); @@ -612,8 +612,8 @@ gst_rtsp_server_get_property (GObject * object, guint propid, case PROP_SESSION_POOL: g_value_take_object (value, gst_rtsp_server_get_session_pool (server)); break; - case PROP_MEDIA_MAPPING: - g_value_take_object (value, gst_rtsp_server_get_media_mapping (server)); + case PROP_MOUNT_POINTS: + g_value_take_object (value, gst_rtsp_server_get_mount_points (server)); break; case PROP_MAX_THREADS: g_value_set_int (value, gst_rtsp_server_get_max_threads (server)); @@ -642,8 +642,8 @@ gst_rtsp_server_set_property (GObject * object, guint propid, case PROP_SESSION_POOL: gst_rtsp_server_set_session_pool (server, g_value_get_object (value)); break; - case PROP_MEDIA_MAPPING: - gst_rtsp_server_set_media_mapping (server, g_value_get_object (value)); + case PROP_MOUNT_POINTS: + gst_rtsp_server_set_mount_points (server, g_value_get_object (value)); break; case PROP_MAX_THREADS: gst_rtsp_server_set_max_threads (server, g_value_get_int (value)); @@ -922,8 +922,8 @@ default_create_client (GstRTSPServer * server) /* set the session pool that this client should use */ GST_RTSP_SERVER_LOCK (server); gst_rtsp_client_set_session_pool (client, server->session_pool); - /* set the media mapping that this client should use */ - gst_rtsp_client_set_media_mapping (client, server->media_mapping); + /* set the mount points that this client should use */ + gst_rtsp_client_set_mount_points (client, server->mount_points); /* set authentication manager */ gst_rtsp_client_set_auth (client, server->auth); GST_RTSP_SERVER_UNLOCK (server); diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 42a37b1273..e851ed472b 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -28,7 +28,7 @@ typedef struct _GstRTSPServer GstRTSPServer; typedef struct _GstRTSPServerClass GstRTSPServerClass; #include "rtsp-session-pool.h" -#include "rtsp-media-mapping.h" +#include "rtsp-mount-points.h" #include "rtsp-media-factory-uri.h" #include "rtsp-client.h" #include "rtsp-auth.h" @@ -68,8 +68,8 @@ struct _GstRTSPServer { /* sessions on this server */ GstRTSPSessionPool *session_pool; - /* media mapper for this server */ - GstRTSPMediaMapping *media_mapping; + /* mount points for this server */ + GstRTSPMountPoints *mount_points; /* authentication manager */ GstRTSPAuth *auth; @@ -117,8 +117,8 @@ gint gst_rtsp_server_get_backlog (GstRTSPServer *serve void gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool); GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *server); -void gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *mapping); -GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *server); +void gst_rtsp_server_set_mount_points (GstRTSPServer *server, GstRTSPMountPoints *mounts); +GstRTSPMountPoints * gst_rtsp_server_get_mount_points (GstRTSPServer *server); void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server); diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index e8eda2bc98..31caca7bcd 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -20,10 +20,6 @@ #include "rtsp-session.h" -#undef DEBUG - -#define DEFAULT_TIMEOUT 60 - enum { PROP_0, diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 38f1519e5c..7a3231d237 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -19,8 +19,6 @@ #include "rtsp-session-pool.h" -#undef DEBUG - #define DEFAULT_MAX_SESSIONS 0 enum diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index d60167e882..ede06ceb82 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -117,7 +117,7 @@ typedef enum * * Returns: a #GstRTSPFilterResult. */ -typedef GstRTSPFilterResult (*GstRTSPSessionFilterFunc) (GstRTSPSessionPool *pool, +typedef GstRTSPFilterResult (*GstRTSPSessionFilterFunc) (GstRTSPSessionPool *pool, GstRTSPSession *session, gpointer user_data); diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 805f3c935b..835ae65e5c 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -136,19 +136,19 @@ get_client_ports (GstRTSPRange * range) static void start_server () { - GstRTSPMediaMapping *mapping; + GstRTSPMountPoints *mounts; gchar *service; GstRTSPMediaFactory *factory; - mapping = gst_rtsp_server_get_media_mapping (server); + mounts = gst_rtsp_server_get_mount_points (server); factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, "( " VIDEO_PIPELINE " " AUDIO_PIPELINE " )"); - gst_rtsp_media_mapping_add_factory (mapping, TEST_MOUNT_POINT, factory); - g_object_unref (mapping); + gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); + g_object_unref (mounts); /* set port */ test_port = get_unused_port (SOCK_STREAM); @@ -700,7 +700,9 @@ GST_START_TEST (test_bind_already_in_use) service = g_socket_service_new (); /* bind service to port */ - port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (service), NULL, &error); + port = + g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (service), NULL, + &error); g_assert_no_error (error); port_str = g_strdup_printf ("%d\n", port); From 84e72262d012959354ca337529c2db4bb31d3d51 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 13:16:59 +0100 Subject: [PATCH 0527/1776] client: add generic close-after-send support Add a property to send_response() to close the connection after the response has been sent to the client. --- gst/rtsp-server/rtsp-client.c | 43 ++++++++++++++++++----------------- gst/rtsp-server/rtsp-client.h | 2 +- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 0620233c7e..3f6cd0ac4b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -174,7 +174,7 @@ static void gst_rtsp_client_init (GstRTSPClient * client) { client->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS; - client->teardown_response_seq = 0; + client->close_response_seq = 0; } static void @@ -303,7 +303,7 @@ gst_rtsp_client_new (void) static void send_response (GstRTSPClient * client, GstRTSPSession * session, - GstRTSPMessage * response, guint * id) + GstRTSPMessage * response, gboolean close) { gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER, "GStreamer RTSP server"); @@ -321,7 +321,14 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, gst_rtsp_message_dump (response); } - gst_rtsp_watch_send_message (client->watch, response, id); + if (close) { + gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONNECTION, + "close"); + } + /* send the response and store the seq number so we can wait until it's + * written to the client to close the connection */ + gst_rtsp_watch_send_message (client->watch, response, close ? + &client->close_response_seq : NULL); gst_rtsp_message_unset (response); } @@ -332,7 +339,7 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); - send_response (client, NULL, state->response, NULL); + send_response (client, NULL, state->response, FALSE); } static void @@ -347,7 +354,7 @@ handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth, gst_rtsp_auth_setup_auth (auth, client, 0, state); } - send_response (client, state->session, state->response, NULL); + send_response (client, state->session, state->response, FALSE); } @@ -605,13 +612,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); - gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONNECTION, - "close"); - - /* send the response and store the seq number so we can wait until it's - * written to the client to close the connection */ - send_response (client, session, state->response, - &client->teardown_response_seq); + send_response (client, session, state->response, TRUE); /* we emit the signal before closing the connection */ g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], @@ -652,7 +653,7 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state) if (res != GST_RTSP_OK) goto bad_request; - send_response (client, state->session, state->response, NULL); + send_response (client, state->session, state->response, FALSE); } g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST], @@ -688,7 +689,7 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state) if (res != GST_RTSP_OK) goto bad_request; - send_response (client, state->session, state->response, NULL); + send_response (client, state->session, state->response, FALSE); } g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST], @@ -737,7 +738,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); - send_response (client, session, state->response, NULL); + send_response (client, session, state->response, FALSE); /* the state is now READY */ media->state = GST_RTSP_STATE_READY; @@ -859,7 +860,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) str = gst_rtsp_media_get_range_string (media->media, TRUE); gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str); - send_response (client, session, state->response, NULL); + send_response (client, session, state->response, FALSE); /* start playing after sending the request */ gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING); @@ -1185,7 +1186,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) trans_str); g_free (trans_str); - send_response (client, session, state->response, NULL); + send_response (client, session, state->response, FALSE); /* update the state */ switch (sessmedia->state) { @@ -1374,7 +1375,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_message_take_body (state->response, (guint8 *) str, strlen (str)); gst_sdp_message_free (sdp); - send_response (client, state->session, state->response, NULL); + send_response (client, state->session, state->response, FALSE); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST], 0, state); @@ -1416,7 +1417,7 @@ handle_options_request (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_PUBLIC, str); g_free (str); - send_response (client, state->session, state->response, NULL); + send_response (client, state->session, state->response, FALSE); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST], 0, state); @@ -1900,8 +1901,8 @@ message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) GstRTSPClient *client; client = GST_RTSP_CLIENT (user_data); - if (client->teardown_response_seq && client->teardown_response_seq == cseq) { - client->teardown_response_seq = 0; + if (client->close_response_seq && client->close_response_seq == cseq) { + client->close_response_seq = 0; close_connection (client); } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 2b84319601..f4211167a6 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -108,7 +108,7 @@ struct _GstRTSPClient { GList *transports; GList *sessions; - guint teardown_response_seq; + guint close_response_seq; }; struct _GstRTSPClientClass { From f460e7360eed5ee5def048e97635dd9b46844b25 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 13:35:48 +0100 Subject: [PATCH 0528/1776] client: fix compilation --- gst/rtsp-server/rtsp-client.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3f6cd0ac4b..b883e018a4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -322,8 +322,7 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, } if (close) { - gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONNECTION, - "close"); + gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONNECTION, "close"); } /* send the response and store the seq number so we can wait until it's * written to the client to close the connection */ From b21b46ec4db2e39f93c1f77e4b56fe96bc0e315c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 13:37:20 +0100 Subject: [PATCH 0529/1776] client: log more errors --- gst/rtsp-server/rtsp-client.c | 37 +++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b883e018a4..2a4229401e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -444,16 +444,19 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) /* ERRORS */ no_mount_points: { + GST_ERROR ("client %p: no mount points configured", client); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return NULL; } no_factory: { + GST_ERROR ("client %p: no factory for uri", client); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return NULL; } not_allowed: { + GST_ERROR ("client %p: unauthorized request", client); handle_unauthorized_request (client, auth, state); g_object_unref (factory); g_object_unref (auth); @@ -461,12 +464,14 @@ not_allowed: } no_media: { + GST_ERROR ("client %p: can't create media", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); g_object_unref (factory); return NULL; } no_prepare: { + GST_ERROR ("client %p: can't prepare media", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); g_object_unref (media); return NULL; @@ -622,11 +627,13 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) /* ERRORS */ no_session: { + GST_ERROR ("client %p: no session", client); send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); return FALSE; } not_found: { + GST_ERROR ("client %p: no media for uri", client); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return FALSE; } @@ -663,6 +670,7 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state) /* ERRORS */ bad_request: { + GST_ERROR ("client %p: bad request", client); send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); return FALSE; } @@ -699,6 +707,7 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state) /* ERRORS */ bad_request: { + GST_ERROR ("client %p: bad request", client); send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); return FALSE; } @@ -750,16 +759,19 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) /* ERRORS */ no_session: { + GST_ERROR ("client %p: no seesion", client); send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); return FALSE; } not_found: { + GST_ERROR ("client %p: no media for uri", client); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return FALSE; } invalid_state: { + GST_ERROR ("client %p: not PLAYING or RECORDING", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, state); return FALSE; @@ -874,16 +886,19 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) /* ERRORS */ no_session: { + GST_ERROR ("client %p: no session", client); send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); return FALSE; } not_found: { + GST_ERROR ("client %p: media not found", client); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return FALSE; } invalid_state: { + GST_ERROR ("client %p: not PLAYING or READY", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, state); return FALSE; @@ -1208,11 +1223,13 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) /* ERRORS */ bad_request: { + GST_ERROR ("client %p: bad request", client); send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); return FALSE; } not_found: { + GST_ERROR ("client %p: media not found", client); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); g_object_unref (session); gst_rtsp_transport_free (ct); @@ -1220,6 +1237,7 @@ not_found: } invalid_blocksize: { + GST_ERROR ("client %p: invalid blocksize", client); send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); g_object_unref (session); gst_rtsp_transport_free (ct); @@ -1227,6 +1245,7 @@ invalid_blocksize: } unsupported_client_transport: { + GST_ERROR ("client %p: unsupported client transport", client); send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); g_object_unref (session); gst_rtsp_transport_free (ct); @@ -1234,23 +1253,27 @@ unsupported_client_transport: } no_transport: { + GST_ERROR ("client %p: no transport", client); send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); return FALSE; } unsupported_transports: { + GST_ERROR ("client %p: unsupported transports", client); send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); gst_rtsp_transport_free (ct); return FALSE; } no_pool: { + GST_ERROR ("client %p: no session pool configured", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); gst_rtsp_transport_free (ct); return FALSE; } service_unavailable: { + GST_ERROR ("client %p: can't create session", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); gst_rtsp_transport_free (ct); return FALSE; @@ -1298,6 +1321,7 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) /* ERRORS */ no_sdp: { + GST_ERROR ("client %p: could not create SDP", client); g_free (info.server_ip); gst_sdp_message_free (sdp); return NULL; @@ -1384,11 +1408,13 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) /* ERRORS */ no_media: { + GST_ERROR ("client %p: no media", client); /* error reply is already sent */ return FALSE; } no_sdp: { + GST_ERROR ("client %p: can't create SDP", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); g_object_unref (media); return FALSE; @@ -1601,16 +1627,19 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) /* ERRORS */ no_pool: { + GST_ERROR ("client %p: no pool configured", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, &state); return; } session_not_found: { + GST_ERROR ("client %p: session not found", client); send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state); return; } not_authorized: { + GST_ERROR ("client %p: not allowed", client); handle_unauthorized_request (client, client->auth, &state); return; } @@ -2022,7 +2051,7 @@ tunnel_lost (GstRTSPWatch * watch, gpointer user_data) client = GST_RTSP_CLIENT (user_data); - GST_INFO ("client %p: tunnel lost (connection %p)", client, + GST_WARNING ("client %p: tunnel lost (connection %p)", client, client->connection); /* ignore error, it'll only be a problem when the client does a POST again */ @@ -2071,19 +2100,19 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) /* ERRORS */ no_tunnelid: { - GST_INFO ("client %p: no tunnelid provided", client); + GST_ERROR ("client %p: no tunnelid provided", client); return GST_RTSP_ERROR; } no_tunnel: { g_mutex_unlock (&tunnels_lock); - GST_INFO ("client %p: tunnel session %s not found", client, tunnelid); + GST_ERROR ("client %p: tunnel session %s not found", client, tunnelid); return GST_RTSP_ERROR; } tunnel_closed: { g_mutex_unlock (&tunnels_lock); - GST_INFO ("client %p: tunnel session %s was closed", client, tunnelid); + GST_ERROR ("client %p: tunnel session %s was closed", client, tunnelid); g_object_unref (oclient); return GST_RTSP_ERROR; } From 4fa7502fd969680d3ef1483ff4338b786c44fb95 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 16:30:16 +0100 Subject: [PATCH 0530/1776] client: add locking Also add some g_return_if() --- gst/rtsp-server/rtsp-client.c | 108 ++++++++++++++++++++++++---------- gst/rtsp-server/rtsp-client.h | 1 + 2 files changed, 78 insertions(+), 31 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 2a4229401e..fe048de2fa 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -173,6 +173,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) static void gst_rtsp_client_init (GstRTSPClient * client) { + g_mutex_init (&client->lock); client->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS; client->close_response_seq = 0; } @@ -236,6 +237,7 @@ gst_rtsp_client_finalize (GObject * obj) } g_free (client->server_ip); + g_mutex_clear (&client->lock); G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj); } @@ -1710,14 +1712,18 @@ gst_rtsp_client_set_session_pool (GstRTSPClient * client, { GstRTSPSessionPool *old; + g_return_if_fail (GST_IS_RTSP_CLIENT (client)); + + if (pool) + g_object_ref (pool); + + g_mutex_lock (&client->lock); old = client->session_pool; - if (old != pool) { - if (pool) - g_object_ref (pool); - client->session_pool = pool; - if (old) - g_object_unref (old); - } + client->session_pool = pool; + g_mutex_unlock (&client->lock); + + if (old) + g_object_unref (old); } /** @@ -1733,8 +1739,12 @@ gst_rtsp_client_get_session_pool (GstRTSPClient * client) { GstRTSPSessionPool *result; + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); + + g_mutex_lock (&client->lock); if ((result = client->session_pool)) g_object_ref (result); + g_mutex_unlock (&client->lock); return result; } @@ -1751,14 +1761,18 @@ gst_rtsp_client_set_server (GstRTSPClient * client, GstRTSPServer * server) { GstRTSPServer *old; + g_return_if_fail (GST_IS_RTSP_CLIENT (client)); + + if (server) + g_object_ref (server); + + g_mutex_lock (&client->lock); old = client->server; - if (old != server) { - if (server) - g_object_ref (server); - client->server = server; - if (old) - g_object_unref (old); - } + client->server = server; + g_mutex_unlock (&client->lock); + + if (old) + g_object_unref (old); } /** @@ -1774,8 +1788,12 @@ gst_rtsp_client_get_server (GstRTSPClient * client) { GstRTSPServer *result; + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); + + g_mutex_lock (&client->lock); if ((result = client->server)) g_object_ref (result); + g_mutex_unlock (&client->lock); return result; } @@ -1795,15 +1813,18 @@ gst_rtsp_client_set_mount_points (GstRTSPClient * client, { GstRTSPMountPoints *old; - old = client->mount_points; + g_return_if_fail (GST_IS_RTSP_CLIENT (client)); - if (old != mounts) { - if (mounts) - g_object_ref (mounts); - client->mount_points = mounts; - if (old) - g_object_unref (old); - } + if (mounts) + g_object_ref (mounts); + + g_mutex_lock (&client->lock); + old = client->mount_points; + client->mount_points = mounts; + g_mutex_unlock (&client->lock); + + if (old) + g_object_unref (old); } /** @@ -1819,8 +1840,12 @@ gst_rtsp_client_get_mount_points (GstRTSPClient * client) { GstRTSPMountPoints *result; + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); + + g_mutex_lock (&client->lock); if ((result = client->mount_points)) g_object_ref (result); + g_mutex_unlock (&client->lock); return result; } @@ -1838,7 +1863,11 @@ void gst_rtsp_client_set_use_client_settings (GstRTSPClient * client, gboolean use_client_settings) { + g_return_if_fail (GST_IS_RTSP_CLIENT (client)); + + g_mutex_lock (&client->lock); client->use_client_settings = use_client_settings; + g_mutex_unlock (&client->lock); } /** @@ -1851,7 +1880,15 @@ gst_rtsp_client_set_use_client_settings (GstRTSPClient * client, gboolean gst_rtsp_client_get_use_client_settings (GstRTSPClient * client) { - return client->use_client_settings; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); + + g_mutex_lock (&client->lock); + res = client->use_client_settings; + g_mutex_unlock (&client->lock); + + return res; } /** @@ -1868,15 +1905,16 @@ gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth) g_return_if_fail (GST_IS_RTSP_CLIENT (client)); - old = client->auth; + if (auth) + g_object_ref (auth); - if (old != auth) { - if (auth) - g_object_ref (auth); - client->auth = auth; - if (old) - g_object_unref (old); - } + g_mutex_lock (&client->lock); + old = client->auth; + client->auth = auth; + g_mutex_unlock (&client->lock); + + if (old) + g_object_unref (old); } @@ -1896,8 +1934,10 @@ gst_rtsp_client_get_auth (GstRTSPClient * client) g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); + g_mutex_lock (&client->lock); if ((result = client->auth)) g_object_ref (result); + g_mutex_unlock (&client->lock); return result; } @@ -2204,6 +2244,9 @@ gst_rtsp_client_use_socket (GstRTSPClient * client, GSocket * socket, GstRTSPConnection *conn; GstRTSPResult res; + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); + g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); + GST_RTSP_CHECK (gst_rtsp_connection_create_from_socket (socket, ip, port, initial_buffer, &conn), no_connection); @@ -2239,6 +2282,9 @@ gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, GstRTSPConnection *conn; GstRTSPResult res; + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); + g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); + /* a new client connected. */ GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, cancellable), accept_failed); diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index f4211167a6..e240bcfa81 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -91,6 +91,7 @@ struct _GstRTSPClientState { struct _GstRTSPClient { GObject parent; + GMutex lock; GstRTSPConnection *connection; GstRTSPWatch *watch; gchar *server_ip; From 8da4171055c3706eed25b6724ca0fdb2d8ef2067 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 16:39:26 +0100 Subject: [PATCH 0531/1776] client: remove reference to server We don't need to keep a ref to the server --- docs/libs/gst-rtsp-server-sections.txt | 2 -- gst/rtsp-server/rtsp-client.c | 49 -------------------------- gst/rtsp-server/rtsp-client.h | 14 ++++---- gst/rtsp-server/rtsp-server.c | 2 -- 4 files changed, 6 insertions(+), 61 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 86dce469ba..a94dea9f1c 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -268,8 +268,6 @@ GstRTSPClientState GstRTSPClient GstRTSPClientClass gst_rtsp_client_new -gst_rtsp_client_set_server -gst_rtsp_client_get_server gst_rtsp_client_set_session_pool gst_rtsp_client_get_session_pool gst_rtsp_client_set_mount_points diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index fe048de2fa..db37e1e58e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1749,55 +1749,6 @@ gst_rtsp_client_get_session_pool (GstRTSPClient * client) return result; } -/** - * gst_rtsp_client_set_server: - * @client: a #GstRTSPClient - * @server: a #GstRTSPServer - * - * Set @server as the server that created @client. - */ -void -gst_rtsp_client_set_server (GstRTSPClient * client, GstRTSPServer * server) -{ - GstRTSPServer *old; - - g_return_if_fail (GST_IS_RTSP_CLIENT (client)); - - if (server) - g_object_ref (server); - - g_mutex_lock (&client->lock); - old = client->server; - client->server = server; - g_mutex_unlock (&client->lock); - - if (old) - g_object_unref (old); -} - -/** - * gst_rtsp_client_get_server: - * @client: a #GstRTSPClient - * - * Get the #GstRTSPServer object that @client was created from. - * - * Returns: (transfer full): a #GstRTSPServer, unref after usage. - */ -GstRTSPServer * -gst_rtsp_client_get_server (GstRTSPClient * client) -{ - GstRTSPServer *result; - - g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); - - g_mutex_lock (&client->lock); - if ((result = client->server)) - g_object_ref (result); - g_mutex_unlock (&client->lock); - - return result; -} - /** * gst_rtsp_client_set_mount_points: * @client: a #GstRTSPClient diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index e240bcfa81..e91f817717 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -74,13 +74,16 @@ struct _GstRTSPClientState { /** * GstRTSPClient: - * + * @lock: lock protecting the client object * @connection: the connection object handling the client request. * @watch: watch for the connection - * @ip: ip address used by the client to connect to us + * @close_response_seq: sequence number of message with close header + * @server_ip: ip address of the server + * @is_ipv6: if we are IPv6 * @use_client_settings: whether to allow client transport settings for multicast * @session_pool: handle to the session pool used by the client. * @mount_points: handle to the mount points used by the client. + * @auth: authorization object * @uri: cached uri * @media: cached media * @transports: a list of #GstRTSPStreamTransport using @connection. @@ -94,11 +97,11 @@ struct _GstRTSPClient { GMutex lock; GstRTSPConnection *connection; GstRTSPWatch *watch; + guint close_response_seq; gchar *server_ip; gboolean is_ipv6; gboolean use_client_settings; - GstRTSPServer *server; GstRTSPSessionPool *session_pool; GstRTSPMountPoints *mount_points; GstRTSPAuth *auth; @@ -108,8 +111,6 @@ struct _GstRTSPClient { GList *transports; GList *sessions; - - guint close_response_seq; }; struct _GstRTSPClientClass { @@ -134,9 +135,6 @@ GType gst_rtsp_client_get_type (void); GstRTSPClient * gst_rtsp_client_new (void); -void gst_rtsp_client_set_server (GstRTSPClient * client, GstRTSPServer * server); -GstRTSPServer * gst_rtsp_client_get_server (GstRTSPClient * client); - void gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool); GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 4809cb8acc..dfd4de87e5 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -858,7 +858,6 @@ unmanage_client (GstRTSPClient * client, ClientContext * ctx) GST_DEBUG_OBJECT (server, "unmanage client %p", client); g_object_ref (server); - gst_rtsp_client_set_server (client, NULL); GST_RTSP_SERVER_LOCK (server); server->clients = g_list_remove (server->clients, ctx); @@ -880,7 +879,6 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) ClientContext *ctx; GST_DEBUG_OBJECT (server, "manage client %p", client); - gst_rtsp_client_set_server (client, server); ctx = g_slice_new0 (ClientContext); ctx->server = server; From 26a4b98ab005dbfcc67f746d709d3b1dfee18e33 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 16:45:04 +0100 Subject: [PATCH 0532/1776] client: small cleanup --- gst/rtsp-server/rtsp-client.c | 11 +++++------ gst/rtsp-server/rtsp-client.h | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index db37e1e58e..76c53dae45 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -175,7 +175,7 @@ gst_rtsp_client_init (GstRTSPClient * client) { g_mutex_init (&client->lock); client->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS; - client->close_response_seq = 0; + client->close_seq = 0; } static void @@ -329,7 +329,7 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, /* send the response and store the seq number so we can wait until it's * written to the client to close the connection */ gst_rtsp_watch_send_message (client->watch, response, close ? - &client->close_response_seq : NULL); + &client->close_seq : NULL); gst_rtsp_message_unset (response); } @@ -1917,11 +1917,10 @@ message_received (GstRTSPWatch * watch, GstRTSPMessage * message, static GstRTSPResult message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) { - GstRTSPClient *client; + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); - client = GST_RTSP_CLIENT (user_data); - if (client->close_response_seq && client->close_response_seq == cseq) { - client->close_response_seq = 0; + if (client->close_seq && client->close_seq == cseq) { + client->close_seq = 0; close_connection (client); } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index e91f817717..5cf7b14925 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -77,7 +77,7 @@ struct _GstRTSPClientState { * @lock: lock protecting the client object * @connection: the connection object handling the client request. * @watch: watch for the connection - * @close_response_seq: sequence number of message with close header + * @close_seq: sequence number of message with close header * @server_ip: ip address of the server * @is_ipv6: if we are IPv6 * @use_client_settings: whether to allow client transport settings for multicast @@ -97,7 +97,7 @@ struct _GstRTSPClient { GMutex lock; GstRTSPConnection *connection; GstRTSPWatch *watch; - guint close_response_seq; + guint close_seq; gchar *server_ip; gboolean is_ipv6; gboolean use_client_settings; From 33da3af265e1b3d5f658306080f99e69e99ce63d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 17:20:39 +0100 Subject: [PATCH 0533/1776] client: make the client usable without a socket Make a method to let the client handle a message and a callback when the client wants us to send a response message back. This makes it possible to also use the client object without the sockets, which should make it easier to test. --- gst/rtsp-server/rtsp-client.c | 81 +++++++++++++++++++++++++++++------ gst/rtsp-server/rtsp-client.h | 31 ++++++++++++++ 2 files changed, 99 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 76c53dae45..87fea29d84 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -219,6 +219,9 @@ gst_rtsp_client_finalize (GObject * obj) if (client->watch) g_source_destroy ((GSource *) client->watch); + if (client->send_notify) + client->send_notify (client->send_data); + client_cleanup_sessions (client); gst_rtsp_connection_free (client->connection); @@ -323,13 +326,12 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, gst_rtsp_message_dump (response); } - if (close) { + if (close) gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONNECTION, "close"); - } - /* send the response and store the seq number so we can wait until it's - * written to the client to close the connection */ - gst_rtsp_watch_send_message (client->watch, response, close ? - &client->close_seq : NULL); + + if (client->send_func) + client->send_func (client, response, close, client->send_data); + gst_rtsp_message_unset (response); } @@ -496,9 +498,8 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) gst_rtsp_message_take_body (&message, map_info.data, map_info.size); - /* FIXME, client->watch could have been finalized here, we need to keep an - * extra refcount to the watch. */ - gst_rtsp_watch_send_message (client->watch, &message, NULL); + if (client->send_func) + client->send_func (client, &message, FALSE, client->send_data); gst_rtsp_message_steal_body (&message, &data, &usize); gst_buffer_unmap (buffer, &map_info); @@ -1893,11 +1894,47 @@ gst_rtsp_client_get_auth (GstRTSPClient * client) return result; } -static GstRTSPResult -message_received (GstRTSPWatch * watch, GstRTSPMessage * message, - gpointer user_data) +/** + * gst_rtsp_client_set_send_func: + * @client: a #GstRTSPClient + * @func: a #GstRTSPClientSendFunc + * @user_data: user data passed to @func + * @notify: called when @user_data is no longer in use + * + * Set @func as the callback that will be called when a new message needs to be + * sent to the client. @user_data is passed to @func and @notify is called when + * @user_data is no longer in use. + */ +void +gst_rtsp_client_set_send_func (GstRTSPClient * client, + GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify) { - GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + g_return_if_fail (GST_IS_RTSP_CLIENT (client)); + + g_mutex_lock (&client->lock); + client->send_func = func; + if (client->send_notify) + client->send_notify (client->send_data); + client->send_data = user_data; + client->send_notify = notify; + g_mutex_unlock (&client->lock); +} + +/** + * gst_rtsp_client_handle_message: + * @client: a #GstRTSPClient + * @message: an #GstRTSPMessage + * + * Let the client handle @message. + * + * Returns: a #GstRTSPResult. + */ +GstRTSPResult +gst_rtsp_client_handle_message (GstRTSPClient * client, + GstRTSPMessage * message) +{ + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL); + g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL); switch (message->type) { case GST_RTSP_MESSAGE_REQUEST: @@ -1914,6 +1951,23 @@ message_received (GstRTSPWatch * watch, GstRTSPMessage * message, return GST_RTSP_OK; } +static GstRTSPResult +do_send_message (GstRTSPClient * client, GstRTSPMessage * message, + gboolean close, gpointer user_data) +{ + /* send the response and store the seq number so we can wait until it's + * written to the client to close the connection */ + return gst_rtsp_watch_send_message (client->watch, message, close ? + &client->close_seq : NULL); +} + +static GstRTSPResult +message_received (GstRTSPWatch * watch, GstRTSPMessage * message, + gpointer user_data) +{ + return gst_rtsp_client_handle_message (GST_RTSP_CLIENT (user_data), message); +} + static GstRTSPResult message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) { @@ -2277,6 +2331,7 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) /* create watch for the connection and attach */ client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs, g_object_ref (client), (GDestroyNotify) client_watch_notify); + gst_rtsp_client_set_send_func (client, do_send_message, NULL, NULL); GST_INFO ("attaching to context %p", context); res = gst_rtsp_watch_attach (client->watch, context); diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 5cf7b14925..ab3344b136 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -72,6 +72,23 @@ struct _GstRTSPClientState { GstRTSPMessage *response; }; +/** + * GstRTSPClientSendFunc: + * @client: a #GstRTSPClient + * @message: a #GstRTSPMessage + * @close: close the connection + * @user_data: user data when registering the callback + * + * This callback is called when @client wants to send @message. When @close is + * %TRUE, the connection should be closed when the message has been sent. + * + * Returns: %TRUE on success. + */ +typedef gboolean (*GstRTSPClientSendFunc) (GstRTSPClient *client, + GstRTSPMessage *message, + gboolean close, + gpointer user_data); + /** * GstRTSPClient: * @lock: lock protecting the client object @@ -81,6 +98,10 @@ struct _GstRTSPClientState { * @server_ip: ip address of the server * @is_ipv6: if we are IPv6 * @use_client_settings: whether to allow client transport settings for multicast + * @send_func: a #GstRTSPClientSendFunc called when an RTSP message needs to be + * sent to the client. + * @send_data: user data passed to @send_func + * @send_notify: notify called when @send_data is no longer used. * @session_pool: handle to the session pool used by the client. * @mount_points: handle to the mount points used by the client. * @auth: authorization object @@ -102,6 +123,10 @@ struct _GstRTSPClient { gboolean is_ipv6; gboolean use_client_settings; + GstRTSPClientSendFunc send_func; + gpointer send_data; + GDestroyNotify send_notify; + GstRTSPSessionPool *session_pool; GstRTSPMountPoints *mount_points; GstRTSPAuth *auth; @@ -150,6 +175,12 @@ gboolean gst_rtsp_client_get_use_client_settings (GstRTSPClient * c void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); +void gst_rtsp_client_set_send_func (GstRTSPClient *client, + GstRTSPClientSendFunc func, + gpointer user_data, + GDestroyNotify notify); +GstRTSPResult gst_rtsp_client_handle_message (GstRTSPClient *client, + GstRTSPMessage *message); gboolean gst_rtsp_client_accept (GstRTSPClient *client, GSocket *socket, From eb88fa9e76402e34c25003d425640a772dd90576 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 17:28:29 +0100 Subject: [PATCH 0534/1776] client: call destroy without the lock --- gst/rtsp-server/rtsp-client.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 87fea29d84..3dcd590f9a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1909,15 +1909,21 @@ void gst_rtsp_client_set_send_func (GstRTSPClient * client, GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify) { + GstRTSPClientSendFunc old_func; + gpointer old_data; + g_return_if_fail (GST_IS_RTSP_CLIENT (client)); g_mutex_lock (&client->lock); client->send_func = func; - if (client->send_notify) - client->send_notify (client->send_data); - client->send_data = user_data; + old_func = client->send_notify; + old_data = client->send_data; client->send_notify = notify; + client->send_data = user_data; g_mutex_unlock (&client->lock); + + if (old_func) + old_func (old_data); } /** From 9f8e8bc02dc9a126d305a43146cba99815bfa59d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 17:34:24 +0100 Subject: [PATCH 0535/1776] client: fix compilation --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3dcd590f9a..33202846b1 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1909,7 +1909,7 @@ void gst_rtsp_client_set_send_func (GstRTSPClient * client, GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify) { - GstRTSPClientSendFunc old_func; + GDestroyNotify old_func; gpointer old_data; g_return_if_fail (GST_IS_RTSP_CLIENT (client)); From fc0f176a17e427b8915a4ca1183411cb9a89372f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 17:34:35 +0100 Subject: [PATCH 0536/1776] client: remove unused include --- gst/rtsp-server/rtsp-client.h | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index ab3344b136..6ec1f86c13 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -29,7 +29,6 @@ typedef struct _GstRTSPClient GstRTSPClient; typedef struct _GstRTSPClientClass GstRTSPClientClass; typedef struct _GstRTSPClientState GstRTSPClientState; -#include "rtsp-server.h" #include "rtsp-media.h" #include "rtsp-mount-points.h" #include "rtsp-session-pool.h" From 18bb9ffa6bc2e2d3f6592a75b270e334dee5b492 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 17:35:51 +0100 Subject: [PATCH 0537/1776] client: small cleanup --- gst/rtsp-server/rtsp-client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 33202846b1..f382282f9c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1909,21 +1909,21 @@ void gst_rtsp_client_set_send_func (GstRTSPClient * client, GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify) { - GDestroyNotify old_func; + GDestroyNotify old_notify; gpointer old_data; g_return_if_fail (GST_IS_RTSP_CLIENT (client)); g_mutex_lock (&client->lock); client->send_func = func; - old_func = client->send_notify; + old_notify = client->send_notify; old_data = client->send_data; client->send_notify = notify; client->send_data = user_data; g_mutex_unlock (&client->lock); - if (old_func) - old_func (old_data); + if (old_notify) + old_notify (old_data); } /** From 3baaf0b0df61e8ecf2338eb24d1758d38f8445f2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 27 Nov 2012 11:17:31 +0100 Subject: [PATCH 0538/1776] tests: add unit test for the client object --- tests/check/Makefile.am | 1 + tests/check/gst/client.c | 105 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 tests/check/gst/client.c diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index c9c438abad..8c23c8c02b 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -27,6 +27,7 @@ TESTS = $(check_PROGRAMS) check_PROGRAMS = \ gst/rtspserver \ + gst/client \ gst/addresspool # these tests don't even pass diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c new file mode 100644 index 0000000000..19a36ef5f9 --- /dev/null +++ b/tests/check/gst/client.c @@ -0,0 +1,105 @@ +/* GStreamer + * Copyright (C) 2012 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +static gint cseq; + +static gboolean +test_option_response (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + gchar *str; + GstRTSPMethod methods; + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + gst_rtsp_message_dump (response); + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_OK); + fail_unless (g_str_equal (reason, "OK")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, + 0) == GST_RTSP_OK); + fail_unless (atoi (str) == cseq++); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_PUBLIC, &str, + 0) == GST_RTSP_OK); + + methods = gst_rtsp_options_from_text (str); + fail_if (methods == 0); + fail_unless (methods == (GST_RTSP_DESCRIBE | + GST_RTSP_OPTIONS | + GST_RTSP_PAUSE | + GST_RTSP_PLAY | + GST_RTSP_SETUP | + GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN)); + + return TRUE; +} + +GST_START_TEST (test_options) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = gst_rtsp_client_new (); + + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + + gst_rtsp_client_set_send_func (client, test_option_response, NULL, NULL); + gst_rtsp_message_dump (&request); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + + gst_rtsp_message_unset (&request); + + g_object_unref (client); +} + +GST_END_TEST; + +static Suite * +rtspclient_suite (void) +{ + Suite *s = suite_create ("rtspclient"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_set_timeout (tc, 20); + tcase_add_test (tc, test_options); + + return s; +} + +GST_CHECK_MAIN (rtspclient); From 4782d08bdc88f523076a0f97e8ebd62cb2e65839 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 27 Nov 2012 11:17:45 +0100 Subject: [PATCH 0539/1776] client: only free connection when there is one It's possible that the client doesn't have a connection when we try to free it. --- gst/rtsp-server/rtsp-client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f382282f9c..94c5d4c32b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -224,7 +224,8 @@ gst_rtsp_client_finalize (GObject * obj) client_cleanup_sessions (client); - gst_rtsp_connection_free (client->connection); + if (client->connection) + gst_rtsp_connection_free (client->connection); if (client->session_pool) g_object_unref (client->session_pool); if (client->mount_points) From a26e9b621ea5ba0fd88f090abc9e251c75672fa7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 27 Nov 2012 12:11:41 +0100 Subject: [PATCH 0540/1776] client: use 454 when session can't be found We should use 454 when a session can't be found because there was no session pool configured in the server. This is not a server configuration problem because the server on which the request is done might not be the same one that will keep the sessions for us and so it does not need to support sessions. --- gst/rtsp-server/rtsp-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 94c5d4c32b..cd7d6a44da 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1271,7 +1271,7 @@ unsupported_transports: no_pool: { GST_ERROR ("client %p: no session pool configured", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); gst_rtsp_transport_free (ct); return FALSE; } @@ -1632,7 +1632,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) no_pool: { GST_ERROR ("client %p: no pool configured", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, &state); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state); return; } session_not_found: From faa0c446f7e35a14ed2b6177e134cf12cf2eb8c5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 27 Nov 2012 12:13:59 +0100 Subject: [PATCH 0541/1776] test: add test for session in options request --- tests/check/gst/client.c | 41 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 19a36ef5f9..b12e0adbfb 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -24,7 +24,7 @@ static gint cseq; static gboolean -test_option_response (GstRTSPClient * client, GstRTSPMessage * response, +test_option_response_200 (GstRTSPClient * client, GstRTSPMessage * response, gboolean close, gpointer user_data) { GstRTSPStatusCode code; @@ -63,6 +63,28 @@ test_option_response (GstRTSPClient * client, GstRTSPMessage * response, return TRUE; } +static gboolean +test_option_response_454 (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + gst_rtsp_message_dump (response); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_SESSION_NOT_FOUND); + fail_unless (g_str_equal (reason, "Session Not Found")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + return TRUE; +} + GST_START_TEST (test_options) { GstRTSPClient *client; @@ -71,13 +93,28 @@ GST_START_TEST (test_options) client = gst_rtsp_client_new (); + /* simple OPTIONS */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, "rtsp://localhost/test") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); g_free (str); - gst_rtsp_client_set_send_func (client, test_option_response, NULL, NULL); + gst_rtsp_client_set_send_func (client, test_option_response_200, NULL, NULL); + gst_rtsp_message_dump (&request); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + /* OPTIONS with unknown session id */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, "foobar"); + + gst_rtsp_client_set_send_func (client, test_option_response_454, NULL, NULL); gst_rtsp_message_dump (&request); fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); From 04f26e84e68a9c990dce4d2c3fc7b0aa15725b13 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 27 Nov 2012 12:17:05 +0100 Subject: [PATCH 0542/1776] update common --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index a72faea054..acb04d9fec 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit a72faea054977054ec66e894fd0a07e7d6585d50 +Subproject commit acb04d9fec79a11bf27d4b58f34c95028c83f2be From d5389c940d71c11ad8155095dc136caaab0de701 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 27 Nov 2012 12:24:21 +0100 Subject: [PATCH 0543/1776] client: improve debug and fix leaks Cleanup the uri and session when there is a bad request. --- gst/rtsp-server/rtsp-client.c | 55 ++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index cd7d6a44da..da5cdfa9eb 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1525,10 +1525,10 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) { GstRTSPMethod method; const gchar *uristr; - GstRTSPUrl *uri; + GstRTSPUrl *uri = NULL; GstRTSPVersion version; GstRTSPResult res; - GstRTSPSession *session; + GstRTSPSession *session = NULL; GstRTSPClientState state = { NULL }; GstRTSPMessage response = { 0 }; gchar *sessid; @@ -1544,23 +1544,15 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) gst_rtsp_message_parse_request (request, &method, &uristr, &version); - if (version != GST_RTSP_VERSION_1_0) { - /* we can only handle 1.0 requests */ - send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, - &state); - return; - } + /* we can only handle 1.0 requests */ + if (version != GST_RTSP_VERSION_1_0) + goto not_supported; + state.method = method; /* we always try to parse the url first */ - if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) { - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state); - return; - } - - /* sanitize the uri */ - sanitize_uri (uri); - state.uri = uri; + if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) + goto bad_request; /* get the session if there is any */ res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); @@ -1576,9 +1568,11 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) * disappears because it times out, we will be notified. If all sessions are * gone, we will close the connection */ client_watch_session (client, session); - } else - session = NULL; + } + /* sanitize the uri */ + sanitize_uri (uri); + state.uri = uri; state.session = session; if (client->auth) { @@ -1622,30 +1616,45 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state); break; } + +done: if (session) g_object_unref (session); - - gst_rtsp_url_free (uri); + if (uri) + gst_rtsp_url_free (uri); return; /* ERRORS */ +not_supported: + { + GST_ERROR ("client %p: version %d not supported", client, version); + send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, + &state); + goto done; + } +bad_request: + { + GST_ERROR ("client %p: bad request", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state); + goto done; + } no_pool: { GST_ERROR ("client %p: no pool configured", client); send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state); - return; + goto done; } session_not_found: { GST_ERROR ("client %p: session not found", client); send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state); - return; + goto done; } not_authorized: { GST_ERROR ("client %p: not allowed", client); handle_unauthorized_request (client, client->auth, &state); - return; + goto done; } } From b3fe3357ab88b4d7a0fc9e74a87800fa628f71bb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 27 Nov 2012 12:33:02 +0100 Subject: [PATCH 0544/1776] client: improve debug --- gst/rtsp-server/rtsp-client.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index da5cdfa9eb..98c8c2f3cf 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1609,12 +1609,10 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) case GST_RTSP_ANNOUNCE: case GST_RTSP_RECORD: case GST_RTSP_REDIRECT: - send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &state); - break; + goto not_implemented; case GST_RTSP_INVALID: default: - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state); - break; + goto bad_request; } done: @@ -1656,6 +1654,12 @@ not_authorized: handle_unauthorized_request (client, client->auth, &state); goto done; } +not_implemented: + { + GST_ERROR ("client %p: method %d not implemented", client, method); + send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &state); + goto done; + } } static void From 46f8692087304369dd29a748fac1d98e53203b87 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 27 Nov 2012 12:51:55 +0100 Subject: [PATCH 0545/1776] tests: add more tests --- tests/check/gst/client.c | 151 +++++++++++++++++++++++++++++++-------- 1 file changed, 121 insertions(+), 30 deletions(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index b12e0adbfb..59d5972725 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -23,6 +23,109 @@ static gint cseq; +static gboolean +test_response_400 (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_BAD_REQUEST); + fail_unless (g_str_equal (reason, "Bad Request")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + return TRUE; +} + +static gboolean +test_response_404 (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_NOT_FOUND); + fail_unless (g_str_equal (reason, "Not Found")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + return TRUE; +} + +static gboolean +test_response_454 (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_SESSION_NOT_FOUND); + fail_unless (g_str_equal (reason, "Session Not Found")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + return TRUE; +} + +GST_START_TEST (test_request) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = gst_rtsp_client_new (); + + /* OPTIONS with invalid url */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, + "foopy://padoop/") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + + gst_rtsp_client_set_send_func (client, test_response_400, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + + gst_rtsp_message_unset (&request); + + /* OPTIONS with unknown session id */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, "foobar"); + + gst_rtsp_client_set_send_func (client, test_response_454, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + + gst_rtsp_message_unset (&request); + + g_object_unref (client); +} + +GST_END_TEST; + static gboolean test_option_response_200 (GstRTSPClient * client, GstRTSPMessage * response, gboolean close, gpointer user_data) @@ -36,7 +139,6 @@ test_option_response_200 (GstRTSPClient * client, GstRTSPMessage * response, fail_unless (gst_rtsp_message_get_type (response) == GST_RTSP_MESSAGE_RESPONSE); - gst_rtsp_message_dump (response); fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, &version) == GST_RTSP_OK); @@ -63,28 +165,6 @@ test_option_response_200 (GstRTSPClient * client, GstRTSPMessage * response, return TRUE; } -static gboolean -test_option_response_454 (GstRTSPClient * client, GstRTSPMessage * response, - gboolean close, gpointer user_data) -{ - GstRTSPStatusCode code; - const gchar *reason; - GstRTSPVersion version; - - fail_unless (gst_rtsp_message_get_type (response) == - GST_RTSP_MESSAGE_RESPONSE); - gst_rtsp_message_dump (response); - - fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, - &version) - == GST_RTSP_OK); - fail_unless (code == GST_RTSP_STS_SESSION_NOT_FOUND); - fail_unless (g_str_equal (reason, "Session Not Found")); - fail_unless (version == GST_RTSP_VERSION_1_0); - - return TRUE; -} - GST_START_TEST (test_options) { GstRTSPClient *client; @@ -101,24 +181,33 @@ GST_START_TEST (test_options) g_free (str); gst_rtsp_client_set_send_func (client, test_option_response_200, NULL, NULL); - gst_rtsp_message_dump (&request); fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - /* OPTIONS with unknown session id */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, + g_object_unref (client); +} + +GST_END_TEST; + +GST_START_TEST (test_describe) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = gst_rtsp_client_new (); + + /* simple DESCRIBE for non-existing url */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, "rtsp://localhost/test") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); g_free (str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, "foobar"); - gst_rtsp_client_set_send_func (client, test_option_response_454, NULL, NULL); - gst_rtsp_message_dump (&request); + gst_rtsp_client_set_send_func (client, test_response_404, NULL, NULL); fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); g_object_unref (client); @@ -134,7 +223,9 @@ rtspclient_suite (void) suite_add_tcase (s, tc); tcase_set_timeout (tc, 20); + tcase_add_test (tc, test_request); tcase_add_test (tc, test_options); + tcase_add_test (tc, test_describe); return s; } From b4c168c71dec09db5f30c7f2fa88cc4c2a8bc134 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Nov 2012 10:40:14 +0100 Subject: [PATCH 0546/1776] mounts: add g_return_if guards --- gst/rtsp-server/rtsp-mount-points.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index d633fe32a7..3a92d55875 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -120,6 +120,9 @@ gst_rtsp_mount_points_find_factory (GstRTSPMountPoints * mounts, GstRTSPMediaFactory *result; GstRTSPMountPointsClass *klass; + g_return_val_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts), NULL); + g_return_val_if_fail (url != NULL, NULL); + klass = GST_RTSP_MOUNT_POINTS_GET_CLASS (mounts); if (klass->find_factory) From e5ba3728086094b0518a980c3a42574f22a81ecc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Nov 2012 11:05:08 +0100 Subject: [PATCH 0547/1776] client: fix factory leak Keep the factory in the state object only for authorization checks and make sure we unref it on failure. Also don't keep invalid objects in the state object. --- gst/rtsp-server/rtsp-client.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 98c8c2f3cf..15d3696983 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -405,13 +405,14 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) state->uri))) goto no_factory; - state->factory = factory; - /* check if we have access to the factory */ if ((auth = gst_rtsp_media_factory_get_auth (factory))) { + state->factory = factory; + if (!gst_rtsp_auth_check (auth, client, 0, state)) goto not_allowed; + state->factory = NULL; g_object_unref (auth); } @@ -421,12 +422,9 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) g_object_unref (factory); factory = NULL; - state->factory = NULL; /* set ipv6 on the media before preparing */ media->is_ipv6 = client->is_ipv6; - state->media = media; - /* prepare the media */ if (!(gst_rtsp_media_prepare (media))) goto no_prepare; @@ -434,6 +432,7 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) /* now keep track of the uri and the media */ client->uri = gst_rtsp_url_copy (state->uri); client->media = media; + state->media = media; } else { /* we have seen this uri before, used cached media */ media = client->media; @@ -464,6 +463,7 @@ not_allowed: GST_ERROR ("client %p: unauthorized request", client); handle_unauthorized_request (client, auth, state); g_object_unref (factory); + state->factory = NULL; g_object_unref (auth); return NULL; } From 89974f2db1d39fc60767ecfef6f59beecfb3b315 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Nov 2012 11:07:57 +0100 Subject: [PATCH 0548/1776] tests: add test for mountpoints --- tests/check/Makefile.am | 1 + tests/check/gst/mountpoints.c | 72 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 tests/check/gst/mountpoints.c diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 8c23c8c02b..1a1a2592fc 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -28,6 +28,7 @@ TESTS = $(check_PROGRAMS) check_PROGRAMS = \ gst/rtspserver \ gst/client \ + gst/mountpoints \ gst/addresspool # these tests don't even pass diff --git a/tests/check/gst/mountpoints.c b/tests/check/gst/mountpoints.c new file mode 100644 index 0000000000..209975d9d0 --- /dev/null +++ b/tests/check/gst/mountpoints.c @@ -0,0 +1,72 @@ +/* GStreamer + * Copyright (C) 2012 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +GST_START_TEST (test_create) +{ + GstRTSPMountPoints *mounts; + GstRTSPUrl *url, *url2; + GstRTSPMediaFactory *factory; + + mounts = gst_rtsp_mount_points_new (); + + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test2", + &url2) == GST_RTSP_OK); + + fail_unless (gst_rtsp_mount_points_find_factory (mounts, url) == NULL); + + factory = gst_rtsp_media_factory_new (); + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + fail_unless (gst_rtsp_mount_points_find_factory (mounts, url) == factory); + g_object_unref (factory); + fail_unless (gst_rtsp_mount_points_find_factory (mounts, url2) == NULL); + + gst_rtsp_mount_points_remove_factory (mounts, "/test"); + + fail_unless (gst_rtsp_mount_points_find_factory (mounts, url) == NULL); + fail_unless (gst_rtsp_mount_points_find_factory (mounts, url2) == NULL); + + gst_rtsp_url_free (url); + gst_rtsp_url_free (url2); + + g_object_unref (mounts); +} + +GST_END_TEST; + +static Suite * +rtspmountpoints_suite (void) +{ + Suite *s = suite_create ("rtspmountpoints"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_set_timeout (tc, 20); + tcase_add_test (tc, test_create); + + return s; +} + +GST_CHECK_MAIN (rtspmountpoints); From 20f09bf3e7ab8bd08ad2d128aa234ba82cee2e69 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Nov 2012 11:17:27 +0100 Subject: [PATCH 0549/1776] server: remove unused include --- gst/rtsp-server/rtsp-server.h | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index e851ed472b..3d56376598 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -29,7 +29,6 @@ typedef struct _GstRTSPServerClass GstRTSPServerClass; #include "rtsp-session-pool.h" #include "rtsp-mount-points.h" -#include "rtsp-media-factory-uri.h" #include "rtsp-client.h" #include "rtsp-auth.h" From 922a7865191bb00043342f1d1a81d3e9f685c7ea Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Nov 2012 11:40:33 +0100 Subject: [PATCH 0550/1776] examples: fix include --- examples/test-uri.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/test-uri.c b/examples/test-uri.c index 62f1caa582..b0daebc798 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -20,6 +20,7 @@ #include #include +#include static gboolean From 6b36241816756076bb228ac0c0fd1d5d7d7fdc5b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Nov 2012 12:10:14 +0100 Subject: [PATCH 0551/1776] media-factory: require an url --- gst/rtsp-server/rtsp-media-factory.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 29308c0267..0861c97fb9 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -849,6 +849,7 @@ gst_rtsp_media_factory_create_element (GstRTSPMediaFactory * factory, GstElement *result; g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + g_return_val_if_fail (url != NULL, NULL); klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); From d43a31055e145354fa24a289c9b8648613bc407c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Nov 2012 12:10:47 +0100 Subject: [PATCH 0552/1776] rtsp: use gst_object_unref on GstObjects --- gst/rtsp-server/rtsp-media-factory-uri.c | 2 +- gst/rtsp-server/rtsp-media.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 538338dfc0..cd262b3658 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -580,7 +580,7 @@ rtsp_media_factory_uri_create_element (GstRTSPMediaFactory * factory, no_uridecodebin: { g_critical ("can't create uridecodebin element"); - g_object_unref (element); + gst_object_unref (element); return NULL; } } diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 9004b0115f..e5abb0e456 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -665,7 +665,7 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) pad = gst_element_get_static_pad (elem, "src"); /* create the stream */ gst_rtsp_media_create_stream (media, elem, pad); - g_object_unref (pad); + gst_object_unref (pad); gst_object_unref (elem); From fe71114a7dc6544491d522cc4793e11b534d43ec Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Nov 2012 12:39:37 +0100 Subject: [PATCH 0553/1776] media: unref pipeline in finalize to avoid leaking it --- gst/rtsp-server/rtsp-media.c | 3 ++- gst/rtsp-server/rtsp-media.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e5abb0e456..3fee991bd0 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -171,6 +171,8 @@ gst_rtsp_media_finalize (GObject * obj) g_list_free_full (media->dynamic, gst_object_unref); + if (media->pipeline) + gst_object_unref (media->pipeline); if (media->auth) g_object_unref (media->auth); if (media->pool) @@ -666,7 +668,6 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) /* create the stream */ gst_rtsp_media_create_stream (media, elem, pad); gst_object_unref (pad); - gst_object_unref (elem); have_elem = TRUE; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index b848a105f4..64cda5e381 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -76,7 +76,7 @@ typedef enum { * @buffer_size: The UDP buffer size * @auth: the authentication service in use * @multicast_group: the multicast group to use - * @element: the data providing element + * @element: the data providing element, owned by @pipeline * @streams: the different #GstRTSPStream provided by @element * @dynamic: list of dynamic elements managed by @element * @status: the status of the media pipeline From d3d74ab77b6cb045d373ee9adbaa0199e78cb7ec Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Nov 2012 12:40:18 +0100 Subject: [PATCH 0554/1776] stream: improve debug --- gst/rtsp-server/rtsp-stream.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index a4f52dc3cc..6e35d8f84f 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -59,6 +59,8 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) static void gst_rtsp_stream_init (GstRTSPStream * stream) { + GST_DEBUG ("new stream %p", stream); + g_mutex_init (&stream->lock); } @@ -69,6 +71,8 @@ gst_rtsp_stream_finalize (GObject * obj) stream = GST_RTSP_STREAM (obj); + GST_DEBUG ("finalize stream %p", stream); + /* we really need to be unjoined now */ g_return_if_fail (!stream->is_joined); From b5fe0c29f1272ebebff3ccca021baa0ad020395f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Nov 2012 12:40:46 +0100 Subject: [PATCH 0555/1776] tests: add mediafactory test --- tests/check/Makefile.am | 1 + tests/check/gst/mediafactory.c | 147 +++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 tests/check/gst/mediafactory.c diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 1a1a2592fc..0954a81b4b 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -29,6 +29,7 @@ check_PROGRAMS = \ gst/rtspserver \ gst/client \ gst/mountpoints \ + gst/mediafactory \ gst/addresspool # these tests don't even pass diff --git a/tests/check/gst/mediafactory.c b/tests/check/gst/mediafactory.c new file mode 100644 index 0000000000..46ff8252ae --- /dev/null +++ b/tests/check/gst/mediafactory.c @@ -0,0 +1,147 @@ +/* GStreamer + * Copyright (C) 2012 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +GST_START_TEST (test_parse_error) +{ + GstRTSPMediaFactory *factory; + GstRTSPUrl *url; + + factory = gst_rtsp_media_factory_new (); + + gst_rtsp_media_factory_set_launch (factory, "foo"); + gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + ASSERT_CRITICAL (gst_rtsp_media_factory_create_element (factory, url)); + ASSERT_CRITICAL (gst_rtsp_media_factory_construct (factory, url)); + + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + +GST_START_TEST (test_launch) +{ + GstRTSPMediaFactory *factory; + GstElement *element; + GstRTSPUrl *url; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + element = gst_rtsp_media_factory_create_element (factory, url); + fail_unless (GST_IS_BIN (element)); + fail_if (GST_IS_PIPELINE (element)); + gst_object_unref (element); + + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + +GST_START_TEST (test_launch_construct) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media, *media2; + GstRTSPUrl *url; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + g_object_unref (media); + + media2 = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media2)); + fail_if (media == media2); + g_object_unref (media2); + + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + +GST_START_TEST (test_shared) +{ + GstRTSPMediaFactory *factory; + GstElement *element; + GstRTSPMedia *media, *media2; + GstRTSPUrl *url; + + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_shared (factory, TRUE); + fail_unless (gst_rtsp_media_factory_is_shared (factory)); + + gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + element = gst_rtsp_media_factory_create_element (factory, url); + fail_unless (GST_IS_BIN (element)); + fail_if (GST_IS_PIPELINE (element)); + gst_object_unref (element); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + media2 = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media2)); + fail_unless (media == media2); + + g_object_unref (media); + g_object_unref (media2); + + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + +static Suite * +rtspmediafactory_suite (void) +{ + Suite *s = suite_create ("rtspmediafactory"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_set_timeout (tc, 20); + tcase_add_test (tc, test_parse_error); + tcase_add_test (tc, test_launch); + tcase_add_test (tc, test_launch_construct); + tcase_add_test (tc, test_shared); + + return s; +} + +GST_CHECK_MAIN (rtspmediafactory); From e11287eb7c73440300f0d55c6734a4eab8411854 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Nov 2012 14:45:30 +0100 Subject: [PATCH 0556/1776] media: check if prepared for some methods Check that the media object is prepared before doing seek and getting the current position etc. Add some g_return checks. --- gst/rtsp-server/rtsp-media.c | 46 ++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 3fee991bd0..766f67057c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -792,7 +792,8 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) * @media: a #GstRTSPMedia * @play: for the PLAY request * - * Get the current range as a string. + * Get the current range as a string. @media must be prepared with + * gst_rtsp_media_prepare (). * * Returns: The range as a string, g_free() after usage. */ @@ -802,6 +803,12 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play) gchar *result; GstRTSPTimeRange range; + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + + g_rec_mutex_lock (&media->state_lock); + if (media->status != GST_RTSP_MEDIA_STATUS_PREPARED) + goto not_prepared; + g_mutex_lock (&media->lock); /* make copy */ range = media->range; @@ -811,10 +818,19 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play) range.min.seconds = -1; } g_mutex_unlock (&media->lock); + g_rec_mutex_unlock (&media->state_lock); result = gst_rtsp_range_to_string (&range); return result; + + /* ERRORS */ +not_prepared: + { + GST_WARNING ("media %p was not prepared", media); + g_rec_mutex_unlock (&media->state_lock); + return NULL; + } } /** @@ -822,7 +838,8 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play) * @media: a #GstRTSPMedia * @range: a #GstRTSPTimeRange * - * Seek the pipeline to @range. + * Seek the pipeline of @media to @range. @media must be prepared with + * gst_rtsp_media_prepare(). * * Returns: %TRUE on success. */ @@ -838,6 +855,9 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) g_return_val_if_fail (range != NULL, FALSE); g_rec_mutex_lock (&media->state_lock); + if (media->status != GST_RTSP_MEDIA_STATUS_PREPARED) + goto not_prepared; + if (!media->seekable) goto not_seekable; @@ -887,6 +907,12 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) return res; /* ERRORS */ +not_prepared: + { + g_rec_mutex_unlock (&media->state_lock); + GST_INFO ("media %p is not prepared", media); + return FALSE; + } not_seekable: { g_rec_mutex_unlock (&media->state_lock); @@ -1139,6 +1165,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) GstBus *bus; GList *walk; + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + g_rec_mutex_lock (&media->state_lock); if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) goto was_prepared; @@ -1360,6 +1388,8 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) { gboolean success; + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + g_rec_mutex_lock (&media->state_lock); if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED) goto was_unprepared; @@ -1397,6 +1427,8 @@ was_unprepared: * * Set the state of @media to @state and for the transports in @transports. * + * @media must be prepared with gst_rtsp_media_prepare(); + * * Returns: %TRUE on success. */ gboolean @@ -1411,6 +1443,8 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, g_return_val_if_fail (transports != NULL, FALSE); g_rec_mutex_lock (&media->state_lock); + if (media->status != GST_RTSP_MEDIA_STATUS_PREPARED) + goto not_prepared; /* NULL and READY are the same */ if (state == GST_STATE_READY) @@ -1493,4 +1527,12 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, g_rec_mutex_unlock (&media->state_lock); return TRUE; + + /* ERRORS */ +not_prepared: + { + GST_WARNING ("media %p was not prepared", media); + g_rec_mutex_unlock (&media->state_lock); + return FALSE; + } } From 8665c3b4941fafaa67814f7bc234611aa1355390 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Nov 2012 14:50:47 +0100 Subject: [PATCH 0557/1776] tests: add media tests --- tests/check/Makefile.am | 1 + tests/check/gst/media.c | 117 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 tests/check/gst/media.c diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 0954a81b4b..c2bb3e4f8d 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -30,6 +30,7 @@ check_PROGRAMS = \ gst/client \ gst/mountpoints \ gst/mediafactory \ + gst/media \ gst/addresspool # these tests don't even pass diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c new file mode 100644 index 0000000000..f7bff0120f --- /dev/null +++ b/tests/check/gst/media.c @@ -0,0 +1,117 @@ +/* GStreamer + * Copyright (C) 2012 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +GST_START_TEST (test_launch) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPStream *stream; + GstRTSPTimeRange *range; + gchar *str; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + fail_unless (gst_rtsp_media_n_streams (media) == 1); + + stream = gst_rtsp_media_get_stream (media, 0); + fail_unless (stream != NULL); + + /* fails, need to be prepared */ + str = gst_rtsp_media_get_range_string (media, FALSE); + fail_unless (str == NULL); + + fail_unless (gst_rtsp_range_parse ("npt=5.0-", &range) == GST_RTSP_OK); + /* fails, need to be prepared */ + fail_if (gst_rtsp_media_seek (media, range)); + + fail_unless (gst_rtsp_media_prepare (media)); + + str = gst_rtsp_media_get_range_string (media, FALSE); + fail_unless (g_str_equal (str, "npt=0-")); + g_free (str); + + str = gst_rtsp_media_get_range_string (media, TRUE); + fail_unless (g_str_equal (str, "npt=0-")); + g_free (str); + + fail_unless (gst_rtsp_media_seek (media, range)); + + str = gst_rtsp_media_get_range_string (media, FALSE); + fail_unless (g_str_equal (str, "npt=5-")); + g_free (str); + + str = gst_rtsp_media_get_range_string (media, TRUE); + fail_unless (g_str_equal (str, "npt=5-")); + g_free (str); + + fail_unless (gst_rtsp_media_unprepare (media)); + + /* should fail again */ + str = gst_rtsp_media_get_range_string (media, FALSE); + fail_unless (str == NULL); + fail_if (gst_rtsp_media_seek (media, range)); + + gst_rtsp_range_free (range); + g_object_unref (media); + + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + +GST_START_TEST (test_media) +{ + GstRTSPMedia *media; + + media = gst_rtsp_media_new (); + fail_unless (GST_IS_RTSP_MEDIA (media)); + g_object_unref (media); +} + +GST_END_TEST; + +static Suite * +rtspmedia_suite (void) +{ + Suite *s = suite_create ("rtspmedia"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_set_timeout (tc, 20); + tcase_add_test (tc, test_launch); + tcase_add_test (tc, test_media); + + return s; +} + +GST_CHECK_MAIN (rtspmedia); From ad00c5e79278593174217d40f8f45740731d3bf1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Nov 2012 11:11:05 +0100 Subject: [PATCH 0558/1776] rtsp: make object details private Make all object details private Add methods to access private bits --- docs/libs/gst-rtsp-server-sections.txt | 1 + examples/test-auth.c | 4 +- gst/rtsp-server/rtsp-auth.c | 44 +- gst/rtsp-server/rtsp-auth.h | 6 +- gst/rtsp-server/rtsp-client.c | 436 ++++++++------ gst/rtsp-server/rtsp-client.h | 41 +- gst/rtsp-server/rtsp-media-factory-uri.c | 95 +++- gst/rtsp-server/rtsp-media-factory-uri.h | 11 +- gst/rtsp-server/rtsp-media-factory.c | 197 ++++--- gst/rtsp-server/rtsp-media-factory.h | 27 +- gst/rtsp-server/rtsp-media.c | 691 ++++++++++++++--------- gst/rtsp-server/rtsp-media.h | 77 +-- gst/rtsp-server/rtsp-mount-points.c | 51 +- gst/rtsp-server/rtsp-mount-points.h | 4 +- gst/rtsp-server/rtsp-sdp.c | 14 +- gst/rtsp-server/rtsp-server.c | 213 +++++-- gst/rtsp-server/rtsp-server.h | 27 +- gst/rtsp-server/rtsp-session-media.c | 180 +++++- gst/rtsp-server/rtsp-session-media.h | 19 +- gst/rtsp-server/rtsp-session-pool.c | 128 +++-- gst/rtsp-server/rtsp-session-pool.h | 31 +- gst/rtsp-server/rtsp-session.c | 204 +++++-- gst/rtsp-server/rtsp-session.h | 62 +- gst/rtsp-server/rtsp-stream-transport.c | 217 ++++++- gst/rtsp-server/rtsp-stream-transport.h | 46 +- gst/rtsp-server/rtsp-stream.c | 604 +++++++++++++------- gst/rtsp-server/rtsp-stream.h | 90 +-- tests/check/gst/media.c | 2 +- 28 files changed, 2238 insertions(+), 1284 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index a94dea9f1c..0122798fee 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -313,6 +313,7 @@ gst_rtsp_stream_set_mtu gst_rtsp_stream_join_bin gst_rtsp_stream_leave_bin gst_rtsp_stream_get_rtpinfo +gst_rtsp_stream_get_caps gst_rtsp_stream_recv_rtcp gst_rtsp_stream_recv_rtp gst_rtsp_stream_add_transport diff --git a/examples/test-auth.c b/examples/test-auth.c index a5057437a8..a810b4df7a 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -35,8 +35,8 @@ remove_sessions (GstRTSPServer * server) g_print ("removing all sessions\n"); pool = gst_rtsp_server_get_session_pool (server); - gst_rtsp_session_pool_filter (pool, (GstRTSPSessionFilterFunc) remove_func, - server); + gst_rtsp_session_pool_filter (pool, + (GstRTSPSessionPoolFilterFunc) remove_func, server); g_object_unref (pool); return FALSE; diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 398bc28c07..5a156fbd31 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -21,6 +21,16 @@ #include "rtsp-auth.h" +#define GST_RTSP_AUTH_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuthPrivate)) + +struct _GstRTSPAuthPrivate +{ + GMutex lock; + gchar *basic; + GstRTSPMethod methods; +}; + enum { PROP_0, @@ -48,6 +58,8 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) { GObjectClass *gobject_class; + g_type_class_add_private (klass, sizeof (GstRTSPAuthPrivate)); + gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_auth_get_property; @@ -63,9 +75,11 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) static void gst_rtsp_auth_init (GstRTSPAuth * auth) { - g_mutex_init (&auth->lock); + auth->priv = GST_RTSP_AUTH_GET_PRIVATE (auth); + + g_mutex_init (&auth->priv->lock); /* bitwise or of all methods that need authentication */ - auth->methods = GST_RTSP_DESCRIBE | + auth->priv->methods = GST_RTSP_DESCRIBE | GST_RTSP_ANNOUNCE | GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | @@ -77,10 +91,11 @@ static void gst_rtsp_auth_finalize (GObject * obj) { GstRTSPAuth *auth = GST_RTSP_AUTH (obj); + GstRTSPAuthPrivate *priv = auth->priv; GST_INFO ("finalize auth %p", auth); - g_free (auth->basic); - g_mutex_clear (&auth->lock); + g_free (priv->basic); + g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj); } @@ -132,12 +147,16 @@ gst_rtsp_auth_new (void) void gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic) { + GstRTSPAuthPrivate *priv; + g_return_if_fail (GST_IS_RTSP_AUTH (auth)); - g_mutex_lock (&auth->lock); - g_free (auth->basic); - auth->basic = g_strdup (basic); - g_mutex_unlock (&auth->lock); + priv = auth->priv; + + g_mutex_lock (&priv->lock); + g_free (priv->basic); + priv->basic = g_strdup (basic); + g_mutex_unlock (&priv->lock); } static gboolean @@ -190,10 +209,11 @@ static gboolean default_check_method (GstRTSPAuth * auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState * state) { + GstRTSPAuthPrivate *priv = auth->priv; gboolean result = TRUE; GstRTSPResult res; - if ((state->method & auth->methods) != 0) { + if ((state->method & priv->methods) != 0) { gchar *authorization; result = FALSE; @@ -207,10 +227,10 @@ default_check_method (GstRTSPAuth * auth, GstRTSPClient * client, /* parse type */ if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) { GST_DEBUG_OBJECT (auth, "check Basic auth"); - g_mutex_lock (&auth->lock); - if (auth->basic && strcmp (&authorization[6], auth->basic) == 0) + g_mutex_lock (&priv->lock); + if (priv->basic && strcmp (&authorization[6], priv->basic) == 0) result = TRUE; - g_mutex_unlock (&auth->lock); + g_mutex_unlock (&priv->lock); } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) { GST_DEBUG_OBJECT (auth, "check Digest auth"); /* not implemented yet */ diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index a71388cde0..6fd1a2f5f9 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -24,6 +24,7 @@ typedef struct _GstRTSPAuth GstRTSPAuth; typedef struct _GstRTSPAuthClass GstRTSPAuthClass; +typedef struct _GstRTSPAuthPrivate GstRTSPAuthPrivate; #include "rtsp-client.h" @@ -46,10 +47,7 @@ G_BEGIN_DECLS struct _GstRTSPAuth { GObject parent; - /*< private >*/ - GMutex lock; - gchar *basic; - GstRTSPMethod methods; + GstRTSPAuthPrivate *priv; }; struct _GstRTSPAuthClass { diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 15d3696983..e8f3957f55 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -24,6 +24,34 @@ #include "rtsp-sdp.h" #include "rtsp-params.h" +#define GST_RTSP_CLIENT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_CLIENT, GstRTSPClientPrivate)) + +struct _GstRTSPClientPrivate +{ + GMutex lock; + GstRTSPConnection *connection; + GstRTSPWatch *watch; + guint close_seq; + gchar *server_ip; + gboolean is_ipv6; + gboolean use_client_settings; + + GstRTSPClientSendFunc send_func; + gpointer send_data; + GDestroyNotify send_notify; + + GstRTSPSessionPool *session_pool; + GstRTSPMountPoints *mount_points; + GstRTSPAuth *auth; + + GstRTSPUrl *uri; + GstRTSPMedia *media; + + GList *transports; + GList *sessions; +}; + static GMutex tunnels_lock; static GHashTable *tunnels; @@ -79,6 +107,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) { GObjectClass *gobject_class; + g_type_class_add_private (klass, sizeof (GstRTSPClientPrivate)); + gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_client_get_property; @@ -173,39 +203,50 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) static void gst_rtsp_client_init (GstRTSPClient * client) { - g_mutex_init (&client->lock); - client->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS; - client->close_seq = 0; + GstRTSPClientPrivate *priv = GST_RTSP_CLIENT_GET_PRIVATE (client); + + client->priv = priv; + + g_mutex_init (&priv->lock); + priv->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS; + priv->close_seq = 0; +} + +static GstRTSPFilterResult +filter_session (GstRTSPSession * sess, GstRTSPSessionMedia * media, + gpointer user_data) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + + gst_rtsp_session_media_set_state (media, GST_STATE_NULL); + unlink_session_transports (client, sess, media); + + /* unmanage the media in the session */ + return GST_RTSP_FILTER_REMOVE; } static void client_unlink_session (GstRTSPClient * client, GstRTSPSession * session) { /* unlink all media managed in this session */ - while (session->medias) { - GstRTSPSessionMedia *media = session->medias->data; - - gst_rtsp_session_media_set_state (media, GST_STATE_NULL); - unlink_session_transports (client, session, media); - /* unmanage the media in the session. this will modify session->medias */ - gst_rtsp_session_release_media (session, media); - } + gst_rtsp_session_filter (session, filter_session, client); } static void client_cleanup_sessions (GstRTSPClient * client) { + GstRTSPClientPrivate *priv = client->priv; GList *sessions; /* remove weak-ref from sessions */ - for (sessions = client->sessions; sessions; sessions = g_list_next (sessions)) { + for (sessions = priv->sessions; sessions; sessions = g_list_next (sessions)) { GstRTSPSession *session = (GstRTSPSession *) sessions->data; g_object_weak_unref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client); client_unlink_session (client, session); } - g_list_free (client->sessions); - client->sessions = NULL; + g_list_free (priv->sessions); + priv->sessions = NULL; } /* A client is finalized when the connection is broken */ @@ -213,35 +254,36 @@ static void gst_rtsp_client_finalize (GObject * obj) { GstRTSPClient *client = GST_RTSP_CLIENT (obj); + GstRTSPClientPrivate *priv = client->priv; GST_INFO ("finalize client %p", client); - if (client->watch) - g_source_destroy ((GSource *) client->watch); + if (priv->watch) + g_source_destroy ((GSource *) priv->watch); - if (client->send_notify) - client->send_notify (client->send_data); + if (priv->send_notify) + priv->send_notify (priv->send_data); client_cleanup_sessions (client); - if (client->connection) - gst_rtsp_connection_free (client->connection); - if (client->session_pool) - g_object_unref (client->session_pool); - if (client->mount_points) - g_object_unref (client->mount_points); - if (client->auth) - g_object_unref (client->auth); + if (priv->connection) + gst_rtsp_connection_free (priv->connection); + if (priv->session_pool) + g_object_unref (priv->session_pool); + if (priv->mount_points) + g_object_unref (priv->mount_points); + if (priv->auth) + g_object_unref (priv->auth); - if (client->uri) - gst_rtsp_url_free (client->uri); - if (client->media) { - gst_rtsp_media_unprepare (client->media); - g_object_unref (client->media); + if (priv->uri) + gst_rtsp_url_free (priv->uri); + if (priv->media) { + gst_rtsp_media_unprepare (priv->media); + g_object_unref (priv->media); } - g_free (client->server_ip); - g_mutex_clear (&client->lock); + g_free (priv->server_ip); + g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj); } @@ -311,6 +353,8 @@ static void send_response (GstRTSPClient * client, GstRTSPSession * session, GstRTSPMessage * response, gboolean close) { + GstRTSPClientPrivate *priv = client->priv; + gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER, "GStreamer RTSP server"); @@ -330,8 +374,8 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, if (close) gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONNECTION, "close"); - if (client->send_func) - client->send_func (client, response, close, client->send_data); + if (priv->send_func) + priv->send_func (client, response, close, priv->send_data); gst_rtsp_message_unset (response); } @@ -380,28 +424,29 @@ compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2) static GstRTSPMedia * find_media (GstRTSPClient * client, GstRTSPClientState * state) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPMediaFactory *factory; GstRTSPMedia *media; GstRTSPAuth *auth; - if (!compare_uri (client->uri, state->uri)) { + if (!compare_uri (priv->uri, state->uri)) { /* remove any previously cached values before we try to construct a new * media for uri */ - if (client->uri) - gst_rtsp_url_free (client->uri); - client->uri = NULL; - if (client->media) { - gst_rtsp_media_unprepare (client->media); - g_object_unref (client->media); + if (priv->uri) + gst_rtsp_url_free (priv->uri); + priv->uri = NULL; + if (priv->media) { + gst_rtsp_media_unprepare (priv->media); + g_object_unref (priv->media); } - client->media = NULL; + priv->media = NULL; - if (!client->mount_points) + if (!priv->mount_points) goto no_mount_points; /* find the factory for the uri first */ if (!(factory = - gst_rtsp_mount_points_find_factory (client->mount_points, + gst_rtsp_mount_points_find_factory (priv->mount_points, state->uri))) goto no_factory; @@ -423,19 +468,17 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) g_object_unref (factory); factory = NULL; - /* set ipv6 on the media before preparing */ - media->is_ipv6 = client->is_ipv6; /* prepare the media */ if (!(gst_rtsp_media_prepare (media))) goto no_prepare; /* now keep track of the uri and the media */ - client->uri = gst_rtsp_url_copy (state->uri); - client->media = media; + priv->uri = gst_rtsp_url_copy (state->uri); + priv->media = media; state->media = media; } else { /* we have seen this uri before, used cached media */ - media = client->media; + media = priv->media; state->media = media; GST_INFO ("reusing cached media %p", media); } @@ -486,6 +529,7 @@ no_prepare: static gboolean do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPMessage message = { 0 }; GstMapInfo map_info; guint8 *data; @@ -499,8 +543,8 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) gst_rtsp_message_take_body (&message, map_info.data, map_info.size); - if (client->send_func) - client->send_func (client, &message, FALSE, client->send_data); + if (priv->send_func) + priv->send_func (client, &message, FALSE, priv->send_data); gst_rtsp_message_steal_body (&message, &data, &usize); gst_buffer_unmap (buffer, &map_info); @@ -514,12 +558,15 @@ static void link_transport (GstRTSPClient * client, GstRTSPSession * session, GstRTSPStreamTransport * trans) { + GstRTSPClientPrivate *priv = client->priv; + GST_DEBUG ("client %p: linking transport %p", client, trans); + gst_rtsp_stream_transport_set_callbacks (trans, (GstRTSPSendFunc) do_send_data, (GstRTSPSendFunc) do_send_data, client, NULL); - client->transports = g_list_prepend (client->transports, trans); + priv->transports = g_list_prepend (priv->transports, trans); /* make sure our session can't expire */ gst_rtsp_session_prevent_expire (session); @@ -529,10 +576,13 @@ static void unlink_transport (GstRTSPClient * client, GstRTSPSession * session, GstRTSPStreamTransport * trans) { + GstRTSPClientPrivate *priv = client->priv; + GST_DEBUG ("client %p: unlinking transport %p", client, trans); + gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL); - client->transports = g_list_remove (client->transports, trans); + priv->transports = g_list_remove (priv->transports, trans); /* our session can now expire */ gst_rtsp_session_allow_expire (session); @@ -544,17 +594,18 @@ unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, { guint n_streams, i; - n_streams = gst_rtsp_media_n_streams (media->media); + n_streams = + gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (media)); for (i = 0; i < n_streams; i++) { GstRTSPStreamTransport *trans; - GstRTSPTransport *tr; + const GstRTSPTransport *tr; /* get the transport, if there is no transport configured, skip this stream */ trans = gst_rtsp_session_media_get_transport (media, i); if (trans == NULL) continue; - tr = trans->transport; + tr = gst_rtsp_stream_transport_get_transport (trans); if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { /* for TCP, unlink the stream from the TCP connection of the client */ @@ -566,23 +617,25 @@ unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, static void close_connection (GstRTSPClient * client) { + GstRTSPClientPrivate *priv = client->priv; const gchar *tunnelid; GST_DEBUG ("client %p: closing connection", client); - if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) { + if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) { g_mutex_lock (&tunnels_lock); /* remove from tunnelids */ g_hash_table_remove (tunnels, tunnelid); g_mutex_unlock (&tunnels_lock); } - gst_rtsp_connection_close (client->connection); + gst_rtsp_connection_close (priv->connection); } static gboolean handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPSession *session; GstRTSPSessionMedia *media; GstRTSPStatusCode code; @@ -605,7 +658,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) /* remove the session from the watched sessions */ g_object_weak_unref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client); - client->sessions = g_list_remove (client->sessions, session); + priv->sessions = g_list_remove (priv->sessions, session); gst_rtsp_session_media_set_state (media, GST_STATE_NULL); @@ -613,7 +666,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) * are torn down. */ if (!gst_rtsp_session_release_media (session, media)) { /* remove the session */ - gst_rtsp_session_pool_remove (client->session_pool, session); + gst_rtsp_session_pool_remove (priv->session_pool, session); } /* construct the response now */ code = GST_RTSP_STS_OK; @@ -723,6 +776,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPSession *session; GstRTSPSessionMedia *media; GstRTSPStatusCode code; + GstRTSPState rtspstate; if (!(session = state->session)) goto no_session; @@ -734,9 +788,10 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) state->sessmedia = media; + rtspstate = gst_rtsp_session_media_get_rtsp_state (media); /* the session state must be playing or recording */ - if (media->state != GST_RTSP_STATE_PLAYING && - media->state != GST_RTSP_STATE_RECORDING) + if (rtspstate != GST_RTSP_STATE_PLAYING && + rtspstate != GST_RTSP_STATE_RECORDING) goto invalid_state; /* unlink the all TCP callbacks */ @@ -753,7 +808,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) send_response (client, session, state->response, FALSE); /* the state is now READY */ - media->state = GST_RTSP_STATE_READY; + gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_READY); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST], 0, state); @@ -793,6 +848,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) gchar *str; GstRTSPTimeRange *range; GstRTSPResult res; + GstRTSPState rtspstate; if (!(session = state->session)) goto no_session; @@ -805,8 +861,8 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) state->sessmedia = media; /* the session state must be playing or ready */ - if (media->state != GST_RTSP_STATE_PLAYING && - media->state != GST_RTSP_STATE_READY) + rtspstate = gst_rtsp_session_media_get_rtsp_state (media); + if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY) goto invalid_state; /* parse the range header if we have one */ @@ -815,7 +871,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) if (res == GST_RTSP_OK) { if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) { /* we have a range, seek to the position */ - gst_rtsp_media_seek (media->media, range); + gst_rtsp_media_seek (gst_rtsp_session_media_get_media (media), range); gst_rtsp_range_free (range); } } @@ -823,10 +879,12 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) /* grab RTPInfo from the payloaders now */ rtpinfo = g_string_new (""); - n_streams = gst_rtsp_media_n_streams (media->media); + n_streams = + gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (media)); for (i = 0, infocount = 0; i < n_streams; i++) { GstRTSPStreamTransport *trans; - GstRTSPTransport *tr; + GstRTSPStream *stream; + const GstRTSPTransport *tr; gchar *uristr; guint rtptime, seq; @@ -836,14 +894,15 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) GST_INFO ("stream %d is not configured", i); continue; } - tr = trans->transport; + tr = gst_rtsp_stream_transport_get_transport (trans); if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { /* for TCP, link the stream to the TCP connection of the client */ link_transport (client, session, trans); } - if (gst_rtsp_stream_get_rtpinfo (trans->stream, &rtptime, &seq)) { + stream = gst_rtsp_stream_transport_get_stream (trans); + if (gst_rtsp_stream_get_rtpinfo (stream, &rtptime, &seq)) { if (infocount > 0) g_string_append (rtpinfo, ", "); @@ -872,7 +931,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) } /* add the range */ - str = gst_rtsp_media_get_range_string (media->media, TRUE); + str = + gst_rtsp_media_get_range_string (gst_rtsp_session_media_get_media (media), + TRUE); gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str); send_response (client, session, state->response, FALSE); @@ -880,7 +941,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) /* start playing after sending the request */ gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING); - media->state = GST_RTSP_STATE_PLAYING; + gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_PLAYING); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST], 0, state); @@ -1001,9 +1062,11 @@ static gboolean configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, GstRTSPTransport * ct) { + GstRTSPClientPrivate *priv = client->priv; + /* we have a valid transport now, set the destination of the client. */ if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - if (ct->destination == NULL || !client->use_client_settings) { + if (ct->destination == NULL || !priv->use_client_settings) { GstRTSPAddress *addr; addr = gst_rtsp_stream_get_address (state->stream); @@ -1019,7 +1082,7 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, } else { GstRTSPUrl *url; - url = gst_rtsp_connection_get_url (client->connection); + url = gst_rtsp_connection_get_url (priv->connection); g_free (ct->destination); ct->destination = g_strdup (url->host); @@ -1057,7 +1120,7 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, switch (st->lower_transport) { case GST_RTSP_LOWER_TRANS_UDP: st->client_port = ct->client_port; - st->server_port = state->stream->server_port; + gst_rtsp_stream_get_server_port (state->stream, &st->server_port); break; case GST_RTSP_LOWER_TRANS_UDP_MCAST: st->port = ct->port; @@ -1070,8 +1133,7 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, break; } - if (state->stream->session) - g_object_get (state->stream->session, "internal-ssrc", &st->ssrc, NULL); + gst_rtsp_stream_get_ssrc (state->stream, &st->ssrc); return st; } @@ -1079,6 +1141,7 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, static gboolean handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPResult res; GstRTSPUrl *uri; gchar *transport; @@ -1092,6 +1155,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPSessionMedia *sessmedia; GstRTSPMedia *media; GstRTSPStream *stream; + GstRTSPState rtspstate; uri = state->uri; @@ -1130,7 +1194,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) /* we create the session after parsing stuff so that we don't make * a session for malformed requests */ - if (client->session_pool == NULL) + if (priv->session_pool == NULL) goto no_pool; session = state->session; @@ -1143,7 +1207,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) } else { /* create a session if this fails we probably reached our session limit or * something. */ - if (!(session = gst_rtsp_session_pool_create (client->session_pool))) + if (!(session = gst_rtsp_session_pool_create (priv->session_pool))) goto service_unavailable; state->session = session; @@ -1166,7 +1230,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) goto not_found; state->sessmedia = sessmedia; - state->media = media = sessmedia->media; + state->media = media = gst_rtsp_session_media_get_media (sessmedia); /* now get the stream */ stream = gst_rtsp_media_get_stream (media, streamid); @@ -1207,14 +1271,15 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) send_response (client, session, state->response, FALSE); /* update the state */ - switch (sessmedia->state) { + rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); + switch (rtspstate) { case GST_RTSP_STATE_PLAYING: case GST_RTSP_STATE_RECORDING: case GST_RTSP_STATE_READY: /* no state change */ break; default: - sessmedia->state = GST_RTSP_STATE_READY; + gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY); break; } g_object_unref (session); @@ -1287,6 +1352,7 @@ service_unavailable: static GstSDPMessage * create_sdp (GstRTSPClient * client, GstRTSPMedia * media) { + GstRTSPClientPrivate *priv = client->priv; GstSDPMessage *sdp; GstSDPInfo info; const gchar *proto; @@ -1296,13 +1362,13 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) /* some standard things first */ gst_sdp_message_set_version (sdp, "0"); - if (client->is_ipv6) + if (priv->is_ipv6) proto = "IP6"; else proto = "IP4"; gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", proto, - client->server_ip); + priv->server_ip); gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer"); gst_sdp_message_set_information (sdp, "rtsp-server"); @@ -1312,7 +1378,7 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) gst_sdp_message_add_attribute (sdp, "control", "*"); info.server_proto = proto; - info.server_ip = g_strdup (client->server_ip); + info.server_ip = g_strdup (priv->server_ip); /* create an SDP for the media object */ if (!gst_rtsp_sdp_from_media (sdp, &info, media)) @@ -1484,13 +1550,15 @@ sanitize_uri (GstRTSPUrl * uri) static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) { + GstRTSPClientPrivate *priv = client->priv; + GST_INFO ("client %p: session %p finished", client, session); /* unlink all media managed in this session */ client_unlink_session (client, session); /* remove the session */ - if (!(client->sessions = g_list_remove (client->sessions, session))) { + if (!(priv->sessions = g_list_remove (priv->sessions, session))) { GST_INFO ("client %p: all sessions finalized, close the connection", client); close_connection (client); @@ -1500,9 +1568,10 @@ client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) static void client_watch_session (GstRTSPClient * client, GstRTSPSession * session) { + GstRTSPClientPrivate *priv = client->priv; GList *walk; - for (walk = client->sessions; walk; walk = g_list_next (walk)) { + for (walk = priv->sessions; walk; walk = g_list_next (walk)) { GstRTSPSession *msession = (GstRTSPSession *) walk->data; /* we already know about this session */ @@ -1514,7 +1583,7 @@ client_watch_session (GstRTSPClient * client, GstRTSPSession * session) g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client); - client->sessions = g_list_prepend (client->sessions, session); + priv->sessions = g_list_prepend (priv->sessions, session); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0, session); @@ -1523,6 +1592,7 @@ client_watch_session (GstRTSPClient * client, GstRTSPSession * session) static void handle_request (GstRTSPClient * client, GstRTSPMessage * request) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPMethod method; const gchar *uristr; GstRTSPUrl *uri = NULL; @@ -1557,11 +1627,11 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) /* get the session if there is any */ res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); if (res == GST_RTSP_OK) { - if (client->session_pool == NULL) + if (priv->session_pool == NULL) goto no_pool; /* we had a session in the request, find it again */ - if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid))) + if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid))) goto session_not_found; /* we add the session to the client list of watched sessions. When a session @@ -1575,8 +1645,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) state.uri = uri; state.session = session; - if (client->auth) { - if (!gst_rtsp_auth_check (client->auth, client, 0, &state)) + if (priv->auth) { + if (!gst_rtsp_auth_check (priv->auth, client, 0, &state)) goto not_authorized; } @@ -1651,7 +1721,7 @@ session_not_found: not_authorized: { GST_ERROR ("client %p: not allowed", client); - handle_unauthorized_request (client, client->auth, &state); + handle_unauthorized_request (client, priv->auth, &state); goto done; } not_implemented: @@ -1665,6 +1735,7 @@ not_implemented: static void handle_data (GstRTSPClient * client, GstRTSPMessage * message) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPResult res; guint8 channel; GList *walk; @@ -1683,16 +1754,15 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) buffer = gst_buffer_new_wrapped (data, size); handled = FALSE; - for (walk = client->transports; walk; walk = g_list_next (walk)) { + for (walk = priv->transports; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *trans; GstRTSPStream *stream; - GstRTSPTransport *tr; + const GstRTSPTransport *tr; trans = walk->data; - /* we only add clients with a transport to the list */ - tr = trans->transport; - stream = trans->stream; + tr = gst_rtsp_stream_transport_get_transport (trans); + stream = gst_rtsp_stream_transport_get_stream (trans); /* check for TCP transport */ if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { @@ -1726,16 +1796,19 @@ gst_rtsp_client_set_session_pool (GstRTSPClient * client, GstRTSPSessionPool * pool) { GstRTSPSessionPool *old; + GstRTSPClientPrivate *priv; g_return_if_fail (GST_IS_RTSP_CLIENT (client)); + priv = client->priv; + if (pool) g_object_ref (pool); - g_mutex_lock (&client->lock); - old = client->session_pool; - client->session_pool = pool; - g_mutex_unlock (&client->lock); + g_mutex_lock (&priv->lock); + old = priv->session_pool; + priv->session_pool = pool; + g_mutex_unlock (&priv->lock); if (old) g_object_unref (old); @@ -1752,14 +1825,17 @@ gst_rtsp_client_set_session_pool (GstRTSPClient * client, GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient * client) { + GstRTSPClientPrivate *priv; GstRTSPSessionPool *result; g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); - g_mutex_lock (&client->lock); - if ((result = client->session_pool)) + priv = client->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->session_pool)) g_object_ref (result); - g_mutex_unlock (&client->lock); + g_mutex_unlock (&priv->lock); return result; } @@ -1777,17 +1853,20 @@ void gst_rtsp_client_set_mount_points (GstRTSPClient * client, GstRTSPMountPoints * mounts) { + GstRTSPClientPrivate *priv; GstRTSPMountPoints *old; g_return_if_fail (GST_IS_RTSP_CLIENT (client)); + priv = client->priv; + if (mounts) g_object_ref (mounts); - g_mutex_lock (&client->lock); - old = client->mount_points; - client->mount_points = mounts; - g_mutex_unlock (&client->lock); + g_mutex_lock (&priv->lock); + old = priv->mount_points; + priv->mount_points = mounts; + g_mutex_unlock (&priv->lock); if (old) g_object_unref (old); @@ -1804,14 +1883,17 @@ gst_rtsp_client_set_mount_points (GstRTSPClient * client, GstRTSPMountPoints * gst_rtsp_client_get_mount_points (GstRTSPClient * client) { + GstRTSPClientPrivate *priv; GstRTSPMountPoints *result; g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); - g_mutex_lock (&client->lock); - if ((result = client->mount_points)) + priv = client->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->mount_points)) g_object_ref (result); - g_mutex_unlock (&client->lock); + g_mutex_unlock (&priv->lock); return result; } @@ -1829,11 +1911,15 @@ void gst_rtsp_client_set_use_client_settings (GstRTSPClient * client, gboolean use_client_settings) { + GstRTSPClientPrivate *priv; + g_return_if_fail (GST_IS_RTSP_CLIENT (client)); - g_mutex_lock (&client->lock); - client->use_client_settings = use_client_settings; - g_mutex_unlock (&client->lock); + priv = client->priv; + + g_mutex_lock (&priv->lock); + priv->use_client_settings = use_client_settings; + g_mutex_unlock (&priv->lock); } /** @@ -1846,13 +1932,16 @@ gst_rtsp_client_set_use_client_settings (GstRTSPClient * client, gboolean gst_rtsp_client_get_use_client_settings (GstRTSPClient * client) { + GstRTSPClientPrivate *priv; gboolean res; g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); - g_mutex_lock (&client->lock); - res = client->use_client_settings; - g_mutex_unlock (&client->lock); + priv = client->priv; + + g_mutex_lock (&priv->lock); + res = priv->use_client_settings; + g_mutex_unlock (&priv->lock); return res; } @@ -1867,17 +1956,20 @@ gst_rtsp_client_get_use_client_settings (GstRTSPClient * client) void gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth) { + GstRTSPClientPrivate *priv; GstRTSPAuth *old; g_return_if_fail (GST_IS_RTSP_CLIENT (client)); + priv = client->priv; + if (auth) g_object_ref (auth); - g_mutex_lock (&client->lock); - old = client->auth; - client->auth = auth; - g_mutex_unlock (&client->lock); + g_mutex_lock (&priv->lock); + old = priv->auth; + priv->auth = auth; + g_mutex_unlock (&priv->lock); if (old) g_object_unref (old); @@ -1896,14 +1988,17 @@ gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth) GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient * client) { + GstRTSPClientPrivate *priv; GstRTSPAuth *result; g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); - g_mutex_lock (&client->lock); - if ((result = client->auth)) + priv = client->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->auth)) g_object_ref (result); - g_mutex_unlock (&client->lock); + g_mutex_unlock (&priv->lock); return result; } @@ -1923,18 +2018,21 @@ void gst_rtsp_client_set_send_func (GstRTSPClient * client, GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify) { + GstRTSPClientPrivate *priv; GDestroyNotify old_notify; gpointer old_data; g_return_if_fail (GST_IS_RTSP_CLIENT (client)); - g_mutex_lock (&client->lock); - client->send_func = func; - old_notify = client->send_notify; - old_data = client->send_data; - client->send_notify = notify; - client->send_data = user_data; - g_mutex_unlock (&client->lock); + priv = client->priv; + + g_mutex_lock (&priv->lock); + priv->send_func = func; + old_notify = priv->send_notify; + old_data = priv->send_data; + priv->send_notify = notify; + priv->send_data = user_data; + g_mutex_unlock (&priv->lock); if (old_notify) old_notify (old_data); @@ -1975,10 +2073,12 @@ static GstRTSPResult do_send_message (GstRTSPClient * client, GstRTSPMessage * message, gboolean close, gpointer user_data) { + GstRTSPClientPrivate *priv = client->priv; + /* send the response and store the seq number so we can wait until it's * written to the client to close the connection */ - return gst_rtsp_watch_send_message (client->watch, message, close ? - &client->close_seq : NULL); + return gst_rtsp_watch_send_message (priv->watch, message, close ? + &priv->close_seq : NULL); } static GstRTSPResult @@ -1992,9 +2092,10 @@ static GstRTSPResult message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + GstRTSPClientPrivate *priv = client->priv; - if (client->close_seq && client->close_seq == cseq) { - client->close_seq = 0; + if (priv->close_seq && priv->close_seq == cseq) { + priv->close_seq = 0; close_connection (client); } @@ -2005,11 +2106,12 @@ static GstRTSPResult closed (GstRTSPWatch * watch, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + GstRTSPClientPrivate *priv = client->priv; const gchar *tunnelid; GST_INFO ("client %p: connection closed", client); - if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) { + if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) { g_mutex_lock (&tunnels_lock); /* remove from tunnelids */ g_hash_table_remove (tunnels, tunnelid); @@ -2051,10 +2153,11 @@ error_full (GstRTSPWatch * watch, GstRTSPResult result, static gboolean remember_tunnel (GstRTSPClient * client) { + GstRTSPClientPrivate *priv = client->priv; const gchar *tunnelid; /* store client in the pending tunnels */ - tunnelid = gst_rtsp_connection_get_tunnelid (client->connection); + tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection); if (tunnelid == NULL) goto no_tunnelid; @@ -2088,12 +2191,11 @@ tunnel_existed: static GstRTSPStatusCode tunnel_start (GstRTSPWatch * watch, gpointer user_data) { - GstRTSPClient *client; - - client = GST_RTSP_CLIENT (user_data); + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + GstRTSPClientPrivate *priv = client->priv; GST_INFO ("client %p: tunnel start (connection %p)", client, - client->connection); + priv->connection); if (!remember_tunnel (client)) goto tunnel_error; @@ -2111,12 +2213,11 @@ tunnel_error: static GstRTSPResult tunnel_lost (GstRTSPWatch * watch, gpointer user_data) { - GstRTSPClient *client; - - client = GST_RTSP_CLIENT (user_data); + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + GstRTSPClientPrivate *priv = client->priv; GST_WARNING ("client %p: tunnel lost (connection %p)", client, - client->connection); + priv->connection); /* ignore error, it'll only be a problem when the client does a POST again */ remember_tunnel (client); @@ -2129,12 +2230,14 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) { const gchar *tunnelid; GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + GstRTSPClientPrivate *priv = client->priv; GstRTSPClient *oclient; + GstRTSPClientPrivate *opriv; GST_INFO ("client %p: tunnel complete", client); /* find previous tunnel */ - tunnelid = gst_rtsp_connection_get_tunnelid (client->connection); + tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection); if (tunnelid == NULL) goto no_tunnelid; @@ -2147,16 +2250,18 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) g_object_ref (oclient); g_hash_table_remove (tunnels, tunnelid); - if (oclient->watch == NULL) + opriv = oclient->priv; + + if (opriv->watch == NULL) goto tunnel_closed; g_mutex_unlock (&tunnels_lock); GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient, - oclient->connection, client->connection); + opriv->connection, priv->connection); /* merge the tunnels into the first client */ - gst_rtsp_connection_do_tunnel (oclient->connection, client->connection); - gst_rtsp_watch_reset (oclient->watch); + gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection); + gst_rtsp_watch_reset (opriv->watch); g_object_unref (oclient); return GST_RTSP_OK; @@ -2196,8 +2301,10 @@ static GstRTSPWatchFuncs watch_funcs = { static void client_watch_notify (GstRTSPClient * client) { + GstRTSPClientPrivate *priv = client->priv; + GST_INFO ("client %p: watch destroyed", client); - client->watch = NULL; + priv->watch = NULL; g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL); g_object_unref (client); } @@ -2206,36 +2313,37 @@ static gboolean setup_client (GstRTSPClient * client, GSocket * socket, GstRTSPConnection * conn, GError ** error) { + GstRTSPClientPrivate *priv = client->priv; GSocket *read_socket; GSocketAddress *address; GstRTSPUrl *url; read_socket = gst_rtsp_connection_get_read_socket (conn); - client->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6; + priv->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6; if (!(address = g_socket_get_remote_address (read_socket, error))) goto no_address; - g_free (client->server_ip); + g_free (priv->server_ip); /* keep the original ip that the client connected to */ if (G_IS_INET_SOCKET_ADDRESS (address)) { GInetAddress *iaddr; iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address)); - client->server_ip = g_inet_address_to_string (iaddr); + priv->server_ip = g_inet_address_to_string (iaddr); g_object_unref (address); } else { - client->server_ip = g_strdup ("unknown"); + priv->server_ip = g_strdup ("unknown"); } GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client, - client->server_ip, client->is_ipv6); + priv->server_ip, priv->is_ipv6); url = gst_rtsp_connection_get_url (conn); GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port); - client->connection = conn; + priv->connection = conn; return TRUE; @@ -2343,19 +2451,21 @@ accept_failed: guint gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) { + GstRTSPClientPrivate *priv; guint res; g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0); - g_return_val_if_fail (client->watch == NULL, 0); + priv = client->priv; + g_return_val_if_fail (priv->watch == NULL, 0); /* create watch for the connection and attach */ - client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs, + priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs, g_object_ref (client), (GDestroyNotify) client_watch_notify); gst_rtsp_client_set_send_func (client, do_send_message, NULL, NULL); GST_INFO ("attaching to context %p", context); - res = gst_rtsp_watch_attach (client->watch, context); - gst_rtsp_watch_unref (client->watch); + res = gst_rtsp_watch_attach (priv->watch, context); + gst_rtsp_watch_unref (priv->watch); return res; } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 6ec1f86c13..a718cc7ce6 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -28,6 +28,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPClient GstRTSPClient; typedef struct _GstRTSPClientClass GstRTSPClientClass; typedef struct _GstRTSPClientState GstRTSPClientState; +typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; #include "rtsp-media.h" #include "rtsp-mount-points.h" @@ -90,51 +91,13 @@ typedef gboolean (*GstRTSPClientSendFunc) (GstRTSPClient *client, /** * GstRTSPClient: - * @lock: lock protecting the client object - * @connection: the connection object handling the client request. - * @watch: watch for the connection - * @close_seq: sequence number of message with close header - * @server_ip: ip address of the server - * @is_ipv6: if we are IPv6 - * @use_client_settings: whether to allow client transport settings for multicast - * @send_func: a #GstRTSPClientSendFunc called when an RTSP message needs to be - * sent to the client. - * @send_data: user data passed to @send_func - * @send_notify: notify called when @send_data is no longer used. - * @session_pool: handle to the session pool used by the client. - * @mount_points: handle to the mount points used by the client. - * @auth: authorization object - * @uri: cached uri - * @media: cached media - * @transports: a list of #GstRTSPStreamTransport using @connection. - * @sessions: a list of sessions managed by @connection. * * The client structure. */ struct _GstRTSPClient { GObject parent; - GMutex lock; - GstRTSPConnection *connection; - GstRTSPWatch *watch; - guint close_seq; - gchar *server_ip; - gboolean is_ipv6; - gboolean use_client_settings; - - GstRTSPClientSendFunc send_func; - gpointer send_data; - GDestroyNotify send_notify; - - GstRTSPSessionPool *session_pool; - GstRTSPMountPoints *mount_points; - GstRTSPAuth *auth; - - GstRTSPUrl *uri; - GstRTSPMedia *media; - - GList *transports; - GList *sessions; + GstRTSPClientPrivate *priv; }; struct _GstRTSPClientClass { diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index cd262b3658..84022a39c7 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -21,6 +21,22 @@ #include "rtsp-media-factory-uri.h" +#define GST_RTSP_MEDIA_FACTORY_URI_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY_URI, GstRTSPMediaFactoryURIPrivate)) + +struct _GstRTSPMediaFactoryURIPrivate +{ + GMutex lock; + gchar *uri; + gboolean use_gstpay; + + GstCaps *raw_vcaps; + GstCaps *raw_acaps; + GList *demuxers; + GList *payloaders; + GList *decoders; +}; + #define DEFAULT_URI NULL #define DEFAULT_USE_GSTPAY FALSE @@ -156,41 +172,48 @@ payloader_filter (GstPluginFeature * feature, FilterData * data) static void gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory) { + GstRTSPMediaFactoryURIPrivate *priv = + GST_RTSP_MEDIA_FACTORY_URI_GET_PRIVATE (factory); FilterData data = { NULL, NULL, NULL }; GST_DEBUG_OBJECT (factory, "new"); - factory->uri = g_strdup (DEFAULT_URI); - factory->use_gstpay = DEFAULT_USE_GSTPAY; + factory->priv = priv; + + priv->uri = g_strdup (DEFAULT_URI); + priv->use_gstpay = DEFAULT_USE_GSTPAY; + g_mutex_init (&priv->lock); /* get the feature list using the filter */ gst_registry_feature_filter (gst_registry_get (), (GstPluginFeatureFilter) payloader_filter, FALSE, &data); /* sort */ - factory->demuxers = + priv->demuxers = g_list_sort (data.demux, gst_plugin_feature_rank_compare_func); - factory->payloaders = + priv->payloaders = g_list_sort (data.payload, gst_plugin_feature_rank_compare_func); - factory->decoders = + priv->decoders = g_list_sort (data.decode, gst_plugin_feature_rank_compare_func); - factory->raw_vcaps = gst_static_caps_get (&raw_video_caps); - factory->raw_acaps = gst_static_caps_get (&raw_audio_caps); + priv->raw_vcaps = gst_static_caps_get (&raw_video_caps); + priv->raw_acaps = gst_static_caps_get (&raw_audio_caps); } static void gst_rtsp_media_factory_uri_finalize (GObject * obj) { GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (obj); + GstRTSPMediaFactoryURIPrivate *priv = factory->priv; GST_DEBUG_OBJECT (factory, "finalize"); - g_free (factory->uri); - gst_plugin_feature_list_free (factory->demuxers); - gst_plugin_feature_list_free (factory->payloaders); - gst_plugin_feature_list_free (factory->decoders); - gst_caps_unref (factory->raw_vcaps); - gst_caps_unref (factory->raw_acaps); + g_free (priv->uri); + gst_plugin_feature_list_free (priv->demuxers); + gst_plugin_feature_list_free (priv->payloaders); + gst_plugin_feature_list_free (priv->decoders); + gst_caps_unref (priv->raw_vcaps); + gst_caps_unref (priv->raw_acaps); + g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_media_factory_uri_parent_class)->finalize (obj); } @@ -200,13 +223,14 @@ gst_rtsp_media_factory_uri_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec) { GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (object); + GstRTSPMediaFactoryURIPrivate *priv = factory->priv; switch (propid) { case PROP_URI: g_value_take_string (value, gst_rtsp_media_factory_uri_get_uri (factory)); break; case PROP_USE_GSTPAY: - g_value_set_boolean (value, factory->use_gstpay); + g_value_set_boolean (value, priv->use_gstpay); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -218,13 +242,14 @@ gst_rtsp_media_factory_uri_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec) { GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (object); + GstRTSPMediaFactoryURIPrivate *priv = factory->priv; switch (propid) { case PROP_URI: gst_rtsp_media_factory_uri_set_uri (factory, g_value_get_string (value)); break; case PROP_USE_GSTPAY: - factory->use_gstpay = g_value_get_boolean (value); + priv->use_gstpay = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -259,13 +284,17 @@ void gst_rtsp_media_factory_uri_set_uri (GstRTSPMediaFactoryURI * factory, const gchar * uri) { + GstRTSPMediaFactoryURIPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY_URI (factory)); g_return_if_fail (uri != NULL); - GST_RTSP_MEDIA_FACTORY_LOCK (factory); - g_free (factory->uri); - factory->uri = g_strdup (uri); - GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + priv = factory->priv; + + g_mutex_lock (&priv->lock); + g_free (priv->uri); + priv->uri = g_strdup (uri); + g_mutex_unlock (&priv->lock); } /** @@ -279,13 +308,16 @@ gst_rtsp_media_factory_uri_set_uri (GstRTSPMediaFactoryURI * factory, gchar * gst_rtsp_media_factory_uri_get_uri (GstRTSPMediaFactoryURI * factory) { + GstRTSPMediaFactoryURIPrivate *priv; gchar *result; g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY_URI (factory), NULL); - GST_RTSP_MEDIA_FACTORY_LOCK (factory); - result = g_strdup (factory->uri); - GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + priv = factory->priv; + + g_mutex_lock (&priv->lock); + result = g_strdup (priv->uri); + g_mutex_unlock (&priv->lock); return result; } @@ -293,12 +325,13 @@ gst_rtsp_media_factory_uri_get_uri (GstRTSPMediaFactoryURI * factory) static GstElementFactory * find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps) { + GstRTSPMediaFactoryURIPrivate *priv = urifact->priv; GList *list; GstElementFactory *factory = NULL; gboolean autoplug_more = FALSE; /* first find a demuxer that can link */ - list = gst_element_factory_list_filter (urifact->demuxers, caps, + list = gst_element_factory_list_filter (priv->demuxers, caps, GST_PAD_SINK, FALSE); if (list) { @@ -340,17 +373,17 @@ find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps) return NULL; /* no demuxer try a depayloader */ - list = gst_element_factory_list_filter (urifact->payloaders, caps, + list = gst_element_factory_list_filter (priv->payloaders, caps, GST_PAD_SINK, FALSE); if (list == NULL) { - if (urifact->use_gstpay) { + if (priv->use_gstpay) { /* no depayloader or parser/demuxer, use gstpay when allowed */ factory = gst_element_factory_find ("rtpgstpay"); } else { /* no depayloader, try a decoder, we'll get to a payloader for a decoded * video or audio format, worst case. */ - list = gst_element_factory_list_filter (urifact->decoders, caps, + list = gst_element_factory_list_filter (priv->decoders, caps, GST_PAD_SINK, FALSE); if (list != NULL) { @@ -405,6 +438,7 @@ static void pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) { GstRTSPMediaFactoryURI *urifact; + GstRTSPMediaFactoryURIPrivate *priv; FactoryData *data; GstElementFactory *factory; GstElement *payloader; @@ -418,6 +452,7 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) /* link the element now and expose the pad */ data = g_object_get_data (G_OBJECT (element), factory_key); urifact = data->factory; + priv = urifact->priv; /* ref to make refcounting easier later */ gst_object_ref (pad); @@ -429,10 +464,10 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) goto no_caps; /* check for raw caps */ - if (gst_caps_can_intersect (caps, urifact->raw_vcaps)) { + if (gst_caps_can_intersect (caps, priv->raw_vcaps)) { /* we have raw video caps, insert converter */ convert = gst_element_factory_make ("videoconvert", NULL); - } else if (gst_caps_can_intersect (caps, urifact->raw_acaps)) { + } else if (gst_caps_can_intersect (caps, priv->raw_acaps)) { /* we have raw audio caps, insert converter */ convert = gst_element_factory_make ("audioconvert", NULL); } else { @@ -536,11 +571,13 @@ static GstElement * rtsp_media_factory_uri_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { + GstRTSPMediaFactoryURIPrivate *priv; GstElement *topbin, *element, *uribin; GstRTSPMediaFactoryURI *urifact; FactoryData *data; urifact = GST_RTSP_MEDIA_FACTORY_URI_CAST (factory); + priv = urifact->priv; GST_LOG ("creating element"); @@ -555,7 +592,7 @@ rtsp_media_factory_uri_create_element (GstRTSPMediaFactory * factory, if (uribin == NULL) goto no_uridecodebin; - g_object_set (uribin, "uri", urifact->uri, NULL); + g_object_set (uribin, "uri", priv->uri, NULL); /* keep factory data around */ data = g_new0 (FactoryData, 1); diff --git a/gst/rtsp-server/rtsp-media-factory-uri.h b/gst/rtsp-server/rtsp-media-factory-uri.h index da71aa78bc..fd1eb98c8b 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.h +++ b/gst/rtsp-server/rtsp-media-factory-uri.h @@ -38,24 +38,17 @@ G_BEGIN_DECLS typedef struct _GstRTSPMediaFactoryURI GstRTSPMediaFactoryURI; typedef struct _GstRTSPMediaFactoryURIClass GstRTSPMediaFactoryURIClass; +typedef struct _GstRTSPMediaFactoryURIPrivate GstRTSPMediaFactoryURIPrivate; /** * GstRTSPMediaFactoryURI: - * @uri: the uri * * A media factory that creates a pipeline to play and uri. */ struct _GstRTSPMediaFactoryURI { GstRTSPMediaFactory parent; - gchar *uri; - gboolean use_gstpay; - - GstCaps *raw_vcaps; - GstCaps *raw_acaps; - GList *demuxers; - GList *payloaders; - GList *decoders; + GstRTSPMediaFactoryURIPrivate *priv; }; /** diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 0861c97fb9..cd4b1a7388 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -19,6 +19,28 @@ #include "rtsp-media-factory.h" +#define GST_RTSP_MEDIA_FACTORY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY, GstRTSPMediaFactoryPrivate)) + +#define GST_RTSP_MEDIA_FACTORY_GET_LOCK(f) (&(GST_RTSP_MEDIA_FACTORY_CAST(f)->priv->lock)) +#define GST_RTSP_MEDIA_FACTORY_LOCK(f) (g_mutex_lock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f))) +#define GST_RTSP_MEDIA_FACTORY_UNLOCK(f) (g_mutex_unlock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f))) + +struct _GstRTSPMediaFactoryPrivate +{ + GMutex lock; + gchar *launch; + gboolean shared; + gboolean eos_shutdown; + GstRTSPLowerTrans protocols; + GstRTSPAuth *auth; + guint buffer_size; + GstRTSPAddressPool *pool; + + GMutex medias_lock; + GHashTable *medias; +}; + #define DEFAULT_LAUNCH NULL #define DEFAULT_SHARED FALSE #define DEFAULT_EOS_SHUTDOWN FALSE @@ -72,6 +94,8 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) { GObjectClass *gobject_class; + g_type_class_add_private (klass, sizeof (GstRTSPMediaFactoryPrivate)); + gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_media_factory_get_property; @@ -144,15 +168,19 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) static void gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) { - factory->launch = g_strdup (DEFAULT_LAUNCH); - factory->shared = DEFAULT_SHARED; - factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN; - factory->protocols = DEFAULT_PROTOCOLS; - factory->buffer_size = DEFAULT_BUFFER_SIZE; + GstRTSPMediaFactoryPrivate *priv = + GST_RTSP_MEDIA_FACTORY_GET_PRIVATE (factory); + factory->priv = priv; - g_mutex_init (&factory->lock); - g_mutex_init (&factory->medias_lock); - factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal, + priv->launch = g_strdup (DEFAULT_LAUNCH); + priv->shared = DEFAULT_SHARED; + priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN; + priv->protocols = DEFAULT_PROTOCOLS; + priv->buffer_size = DEFAULT_BUFFER_SIZE; + + g_mutex_init (&priv->lock); + g_mutex_init (&priv->medias_lock); + priv->medias = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } @@ -160,15 +188,16 @@ static void gst_rtsp_media_factory_finalize (GObject * obj) { GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj); + GstRTSPMediaFactoryPrivate *priv = factory->priv; - g_hash_table_unref (factory->medias); - g_mutex_clear (&factory->medias_lock); - g_free (factory->launch); - g_mutex_clear (&factory->lock); - if (factory->auth) - g_object_unref (factory->auth); - if (factory->pool) - g_object_unref (factory->pool); + g_hash_table_unref (priv->medias); + g_mutex_clear (&priv->medias_lock); + g_free (priv->launch); + g_mutex_clear (&priv->lock); + if (priv->auth) + g_object_unref (priv->auth); + if (priv->pool) + g_object_unref (priv->pool); G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj); } @@ -268,12 +297,16 @@ void gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory, const gchar * launch) { + GstRTSPMediaFactoryPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); g_return_if_fail (launch != NULL); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - g_free (factory->launch); - factory->launch = g_strdup (launch); + g_free (priv->launch); + priv->launch = g_strdup (launch); GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); } @@ -289,12 +322,15 @@ gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory, gchar * gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory) { + GstRTSPMediaFactoryPrivate *priv; gchar *result; g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - result = g_strdup (factory->launch); + result = g_strdup (priv->launch); GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); return result; @@ -311,10 +347,14 @@ void gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory, gboolean shared) { + GstRTSPMediaFactoryPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - factory->shared = shared; + priv->shared = shared; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); } @@ -329,12 +369,15 @@ gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory * factory, gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory * factory) { + GstRTSPMediaFactoryPrivate *priv; gboolean result; g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - result = factory->shared; + result = priv->shared; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); return result; @@ -352,10 +395,14 @@ void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory, gboolean eos_shutdown) { + GstRTSPMediaFactoryPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - factory->eos_shutdown = eos_shutdown; + priv->eos_shutdown = eos_shutdown; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); } @@ -371,12 +418,15 @@ gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory, gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory) { + GstRTSPMediaFactoryPrivate *priv; gboolean result; g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - result = factory->eos_shutdown; + result = priv->eos_shutdown; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); return result; @@ -393,10 +443,14 @@ void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint size) { + GstRTSPMediaFactoryPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - factory->buffer_size = size; + priv->buffer_size = size; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); } @@ -411,12 +465,15 @@ gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory) { + GstRTSPMediaFactoryPrivate *priv; guint result; g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - result = factory->buffer_size; + result = priv->buffer_size; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); return result; @@ -433,13 +490,16 @@ void gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory, GstRTSPAddressPool * pool) { + GstRTSPMediaFactoryPrivate *priv; GstRTSPAddressPool *old; g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - if ((old = factory->pool) != pool) - factory->pool = pool ? g_object_ref (pool) : NULL; + if ((old = priv->pool) != pool) + priv->pool = pool ? g_object_ref (pool) : NULL; else old = NULL; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); @@ -460,12 +520,15 @@ gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory, GstRTSPAddressPool * gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory) { + GstRTSPMediaFactoryPrivate *priv; GstRTSPAddressPool *result; g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - if ((result = factory->pool)) + if ((result = priv->pool)) g_object_ref (result); GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); @@ -483,13 +546,16 @@ void gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory, GstRTSPAuth * auth) { + GstRTSPMediaFactoryPrivate *priv; GstRTSPAuth *old; g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - if ((old = factory->auth) != auth) - factory->auth = auth ? g_object_ref (auth) : NULL; + if ((old = priv->auth) != auth) + priv->auth = auth ? g_object_ref (auth) : NULL; else old = NULL; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); @@ -510,12 +576,15 @@ gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory, GstRTSPAuth * gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory) { + GstRTSPMediaFactoryPrivate *priv; GstRTSPAuth *result; g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - if ((result = factory->auth)) + if ((result = priv->auth)) g_object_ref (result); GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); @@ -533,10 +602,14 @@ void gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * factory, GstRTSPLowerTrans protocols) { + GstRTSPMediaFactoryPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - factory->protocols = protocols; + priv->protocols = protocols; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); } @@ -551,13 +624,16 @@ gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * factory, GstRTSPLowerTrans gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory) { + GstRTSPMediaFactoryPrivate *priv; GstRTSPLowerTrans res; g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), GST_RTSP_LOWER_TRANS_UNKNOWN); + priv = factory->priv; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); - res = factory->protocols; + res = priv->protocols; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); return res; @@ -572,9 +648,11 @@ compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) static void media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory) { - g_mutex_lock (&factory->medias_lock); - g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, media); - g_mutex_unlock (&factory->medias_lock); + GstRTSPMediaFactoryPrivate *priv = factory->priv;; + + g_mutex_lock (&priv->medias_lock); + g_hash_table_foreach_remove (priv->medias, (GHRFunc) compare_media, media); + g_mutex_unlock (&priv->medias_lock); } /** @@ -598,6 +676,7 @@ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { + GstRTSPMediaFactoryPrivate *priv; gchar *key; GstRTSPMedia *media; GstRTSPMediaFactoryClass *klass; @@ -605,6 +684,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); g_return_val_if_fail (url != NULL, NULL); + priv = factory->priv;; klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); /* convert the url to a key for the hashtable. NULL return or a NULL function @@ -614,10 +694,10 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, else key = NULL; - g_mutex_lock (&factory->medias_lock); + g_mutex_lock (&priv->medias_lock); if (key) { /* we have a key, see if we find a cached media */ - media = g_hash_table_lookup (factory->medias, key); + media = g_hash_table_lookup (priv->medias, key); if (media) g_object_ref (media); } else @@ -647,7 +727,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, if (gst_rtsp_media_is_shared (media)) { /* insert in the hashtable, takes ownership of the key */ g_object_ref (media); - g_hash_table_insert (factory->medias, key, media); + g_hash_table_insert (priv->medias, key, media); key = NULL; } if (!gst_rtsp_media_is_reusable (media)) { @@ -658,7 +738,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, } } } - g_mutex_unlock (&factory->medias_lock); + g_mutex_unlock (&priv->medias_lock); if (key) g_free (key); @@ -687,16 +767,17 @@ default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) static GstElement * default_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { + GstRTSPMediaFactoryPrivate *priv = factory->priv; GstElement *element; GError *error = NULL; GST_RTSP_MEDIA_FACTORY_LOCK (factory); /* we need a parse syntax */ - if (factory->launch == NULL) + if (priv->launch == NULL) goto no_launch; /* parse the user provided launch line */ - element = gst_parse_launch (factory->launch, &error); + element = gst_parse_launch (priv->launch, &error); if (element == NULL) goto parse_error; @@ -719,7 +800,7 @@ no_launch: parse_error: { GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); - g_critical ("could not parse launch syntax (%s): %s", factory->launch, + g_critical ("could not parse launch syntax (%s): %s", priv->launch, (error ? error->message : "unknown reason")); if (error) g_error_free (error); @@ -731,7 +812,7 @@ static GstRTSPMedia * default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { GstRTSPMedia *media; - GstElement *element; + GstElement *element, *pipeline; GstRTSPMediaFactoryClass *klass; klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); @@ -744,13 +825,12 @@ default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) goto no_element; /* create a new empty media */ - media = gst_rtsp_media_new (); - media->element = element; + media = gst_rtsp_media_new (element); gst_rtsp_media_collect_streams (media); - media->pipeline = klass->create_pipeline (factory, media); - if (media->pipeline == NULL) + pipeline = klass->create_pipeline (factory, media); + if (pipeline == NULL) goto no_pipeline; return media; @@ -779,25 +859,16 @@ default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media) { GstElement *pipeline; - if (media->element == NULL) - goto no_element; - pipeline = gst_pipeline_new ("media-pipeline"); - gst_bin_add (GST_BIN_CAST (pipeline), media->element); + gst_rtsp_media_take_pipeline (media, GST_PIPELINE_CAST (pipeline)); return pipeline; - - /* ERRORS */ -no_element: - { - g_critical ("no element"); - return NULL; - } } static void default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) { + GstRTSPMediaFactoryPrivate *priv = factory->priv; gboolean shared, eos_shutdown; guint size; GstRTSPAuth *auth; @@ -806,10 +877,10 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); - shared = factory->shared; - eos_shutdown = factory->eos_shutdown; - size = factory->buffer_size; - protocols = factory->protocols; + shared = priv->shared; + eos_shutdown = priv->eos_shutdown; + size = priv->buffer_size; + protocols = priv->protocols; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_shared (media, shared); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 2a4745acf9..dce19e516a 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -41,24 +41,11 @@ G_BEGIN_DECLS typedef struct _GstRTSPMediaFactory GstRTSPMediaFactory; typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; - -#define GST_RTSP_MEDIA_FACTORY_GET_LOCK(f) (&(GST_RTSP_MEDIA_FACTORY_CAST(f)->lock)) -#define GST_RTSP_MEDIA_FACTORY_LOCK(f) (g_mutex_lock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f))) -#define GST_RTSP_MEDIA_FACTORY_UNLOCK(f) (g_mutex_unlock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f))) +typedef struct _GstRTSPMediaFactoryPrivate GstRTSPMediaFactoryPrivate; /** * GstRTSPMediaFactory: * @parent: the parent GObject - * @lock: mutex protecting the datastructure. - * @launch: the launch description - * @shared: if media from this factory can be shared between clients - * @eos_shutdown: if shutdown should first send EOS to the pipeline - * @protocols: allowed transport protocols - * @auth: the authentication manager - * @buffer_size: the kernel udp buffer size - * @pool: the multicast address pool to use - * @medias_lock: mutex protecting the medias. - * @medias: hashtable of shared media * * The definition and logic for constructing the pipeline for a media. The media * can contain multiple streams like audio and video. @@ -66,17 +53,7 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass; struct _GstRTSPMediaFactory { GObject parent; - GMutex lock; - gchar *launch; - gboolean shared; - gboolean eos_shutdown; - GstRTSPLowerTrans protocols; - GstRTSPAuth *auth; - guint buffer_size; - GstRTSPAddressPool *pool; - - GMutex medias_lock; - GHashTable *medias; + GstRTSPMediaFactoryPrivate *priv; }; /** diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 766f67057c..01657693dd 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -25,6 +25,51 @@ #include "rtsp-media.h" +#define GST_RTSP_MEDIA_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMediaPrivate)) + +struct _GstRTSPMediaPrivate +{ + GMutex lock; + GCond cond; + + gboolean shared; + gboolean reusable; + GstRTSPLowerTrans protocols; + gboolean reused; + gboolean eos_shutdown; + guint buffer_size; + GstRTSPAuth *auth; + GstRTSPAddressPool *pool; + + GstElement *element; + GRecMutex state_lock; + GPtrArray *streams; + GList *dynamic; + GstRTSPMediaStatus status; + gint n_active; + gboolean adding; + + /* the pipeline for the media */ + GstElement *pipeline; + GstElement *fakesink; + GSource *source; + guint id; + + gboolean is_live; + gboolean seekable; + gboolean buffering; + GstState target_state; + + /* RTP session manager */ + GstElement *rtpbin; + + /* the range of media */ + GstRTSPTimeRange range; + GstClockTime range_start; + GstClockTime range_stop; +}; + #define DEFAULT_SHARED FALSE #define DEFAULT_REUSABLE FALSE #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP @@ -79,6 +124,8 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) { GObjectClass *gobject_class; + g_type_class_add_private (klass, sizeof (GstRTSPMediaPrivate)); + gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_media_get_property; @@ -144,42 +191,48 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) static void gst_rtsp_media_init (GstRTSPMedia * media) { - media->streams = g_ptr_array_new_with_free_func (g_object_unref); - g_mutex_init (&media->lock); - g_cond_init (&media->cond); - g_rec_mutex_init (&media->state_lock); + GstRTSPMediaPrivate *priv = GST_RTSP_MEDIA_GET_PRIVATE (media); - media->shared = DEFAULT_SHARED; - media->reusable = DEFAULT_REUSABLE; - media->protocols = DEFAULT_PROTOCOLS; - media->eos_shutdown = DEFAULT_EOS_SHUTDOWN; - media->buffer_size = DEFAULT_BUFFER_SIZE; + media->priv = priv; + + priv->streams = g_ptr_array_new_with_free_func (g_object_unref); + g_mutex_init (&priv->lock); + g_cond_init (&priv->cond); + g_rec_mutex_init (&priv->state_lock); + + priv->shared = DEFAULT_SHARED; + priv->reusable = DEFAULT_REUSABLE; + priv->protocols = DEFAULT_PROTOCOLS; + priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN; + priv->buffer_size = DEFAULT_BUFFER_SIZE; } static void gst_rtsp_media_finalize (GObject * obj) { + GstRTSPMediaPrivate *priv; GstRTSPMedia *media; media = GST_RTSP_MEDIA (obj); + priv = media->priv; GST_INFO ("finalize media %p", media); gst_rtsp_media_unprepare (media); - g_ptr_array_unref (media->streams); + g_ptr_array_unref (priv->streams); - g_list_free_full (media->dynamic, gst_object_unref); + g_list_free_full (priv->dynamic, gst_object_unref); - if (media->pipeline) - gst_object_unref (media->pipeline); - if (media->auth) - g_object_unref (media->auth); - if (media->pool) - g_object_unref (media->pool); - g_mutex_clear (&media->lock); - g_cond_clear (&media->cond); - g_rec_mutex_clear (&media->state_lock); + if (priv->pipeline) + gst_object_unref (priv->pipeline); + if (priv->auth) + g_object_unref (priv->auth); + if (priv->pool) + g_object_unref (priv->pool); + g_mutex_clear (&priv->lock); + g_cond_clear (&priv->cond); + g_rec_mutex_clear (&priv->state_lock); G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); } @@ -252,29 +305,30 @@ do_loop (GstRTSPMediaClass * klass) static void collect_media_stats (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv = media->priv; gint64 position, duration; - media->range.unit = GST_RTSP_RANGE_NPT; + priv->range.unit = GST_RTSP_RANGE_NPT; GST_INFO ("collect media stats"); - if (media->is_live) { - media->range.min.type = GST_RTSP_TIME_NOW; - media->range.min.seconds = -1; - media->range_start = -1; - media->range.max.type = GST_RTSP_TIME_END; - media->range.max.seconds = -1; - media->range_stop = -1; + if (priv->is_live) { + priv->range.min.type = GST_RTSP_TIME_NOW; + priv->range.min.seconds = -1; + priv->range_start = -1; + priv->range.max.type = GST_RTSP_TIME_END; + priv->range.max.seconds = -1; + priv->range_stop = -1; } else { /* get the position */ - if (!gst_element_query_position (media->pipeline, GST_FORMAT_TIME, + if (!gst_element_query_position (priv->pipeline, GST_FORMAT_TIME, &position)) { GST_INFO ("position query failed"); position = 0; } /* get the duration */ - if (!gst_element_query_duration (media->pipeline, GST_FORMAT_TIME, + if (!gst_element_query_duration (priv->pipeline, GST_FORMAT_TIME, &duration)) { GST_INFO ("duration query failed"); duration = -1; @@ -284,45 +338,80 @@ collect_media_stats (GstRTSPMedia * media) GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); if (position == -1) { - media->range.min.type = GST_RTSP_TIME_NOW; - media->range.min.seconds = -1; - media->range_start = -1; + priv->range.min.type = GST_RTSP_TIME_NOW; + priv->range.min.seconds = -1; + priv->range_start = -1; } else { - media->range.min.type = GST_RTSP_TIME_SECONDS; - media->range.min.seconds = ((gdouble) position) / GST_SECOND; - media->range_start = position; + priv->range.min.type = GST_RTSP_TIME_SECONDS; + priv->range.min.seconds = ((gdouble) position) / GST_SECOND; + priv->range_start = position; } if (duration == -1) { - media->range.max.type = GST_RTSP_TIME_END; - media->range.max.seconds = -1; - media->range_stop = -1; + priv->range.max.type = GST_RTSP_TIME_END; + priv->range.max.seconds = -1; + priv->range_stop = -1; } else { - media->range.max.type = GST_RTSP_TIME_SECONDS; - media->range.max.seconds = ((gdouble) duration) / GST_SECOND; - media->range_stop = duration; + priv->range.max.type = GST_RTSP_TIME_SECONDS; + priv->range.max.seconds = ((gdouble) duration) / GST_SECOND; + priv->range_stop = duration; } } } /** * gst_rtsp_media_new: + * @element: (transfer full): a #GstElement * - * Create a new #GstRTSPMedia instance. The #GstRTSPMedia object contains the + * Create a new #GstRTSPMedia instance. @element is the bin element that + * provides the different streams. The #GstRTSPMedia object contains the * element to produce RTP data for one or more related (audio/video/..) * streams. * + * Ownership is taken of @element. + * * Returns: a new #GstRTSPMedia object. */ GstRTSPMedia * -gst_rtsp_media_new (void) +gst_rtsp_media_new (GstElement * element) { GstRTSPMedia *result; result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL); + result->priv->element = element; return result; } +/** + * gst_rtsp_media_take_element: + * @media: a #GstRTSPMedia + * @pipeline: (transfer full): a #GstPipeline + * + * Set @pipeline as the #GstPipeline for @media. Ownership is + * taken of @pipeline. + */ +void +gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline) +{ + GstRTSPMediaPrivate *priv; + GstElement *old; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + g_return_if_fail (GST_IS_PIPELINE (pipeline)); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + old = priv->pipeline; + priv->pipeline = GST_ELEMENT_CAST (pipeline); + g_mutex_unlock (&priv->lock); + + if (old) + gst_object_unref (old); + + gst_bin_add (GST_BIN_CAST (pipeline), priv->element); +} + /** * gst_rtsp_media_set_shared: * @media: a #GstRTSPMedia @@ -335,11 +424,15 @@ gst_rtsp_media_new (void) void gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared) { + GstRTSPMediaPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); - g_mutex_lock (&media->lock); - media->shared = shared; - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->shared = shared; + g_mutex_unlock (&priv->lock); } /** @@ -353,13 +446,16 @@ gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared) gboolean gst_rtsp_media_is_shared (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; gboolean res; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - g_mutex_lock (&media->lock); - res = media->shared; - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->shared; + g_mutex_unlock (&priv->lock); return res; } @@ -375,11 +471,15 @@ gst_rtsp_media_is_shared (GstRTSPMedia * media) void gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable) { + GstRTSPMediaPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); - g_mutex_lock (&media->lock); - media->reusable = reusable; - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->reusable = reusable; + g_mutex_unlock (&priv->lock); } /** @@ -393,13 +493,16 @@ gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable) gboolean gst_rtsp_media_is_reusable (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; gboolean res; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - g_mutex_lock (&media->lock); - res = media->reusable; - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->reusable; + g_mutex_unlock (&priv->lock); return res; } @@ -414,11 +517,15 @@ gst_rtsp_media_is_reusable (GstRTSPMedia * media) void gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols) { + GstRTSPMediaPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); - g_mutex_lock (&media->lock); - media->protocols = protocols; - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->protocols = protocols; + g_mutex_unlock (&priv->lock); } /** @@ -432,14 +539,17 @@ gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols) GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; GstRTSPLowerTrans res; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_RTSP_LOWER_TRANS_UNKNOWN); - g_mutex_lock (&media->lock); - res = media->protocols; - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->protocols; + g_mutex_unlock (&priv->lock); return res; } @@ -455,11 +565,15 @@ gst_rtsp_media_get_protocols (GstRTSPMedia * media) void gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown) { + GstRTSPMediaPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); - g_mutex_lock (&media->lock); - media->eos_shutdown = eos_shutdown; - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->eos_shutdown = eos_shutdown; + g_mutex_unlock (&priv->lock); } /** @@ -474,13 +588,16 @@ gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown) gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; gboolean res; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - g_mutex_lock (&media->lock); - res = media->eos_shutdown; - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->eos_shutdown; + g_mutex_unlock (&priv->lock); return res; } @@ -495,13 +612,17 @@ gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media) void gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size) { + GstRTSPMediaPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); GST_LOG_OBJECT (media, "set buffer size %u", size); - g_mutex_lock (&media->lock); - media->buffer_size = size; - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->buffer_size = size; + g_mutex_unlock (&priv->lock); } /** @@ -515,13 +636,16 @@ gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size) guint gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; guint res; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - g_mutex_unlock (&media->lock); - res = media->buffer_size; - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_unlock (&priv->lock); + res = priv->buffer_size; + g_mutex_unlock (&priv->lock); return res; } @@ -536,18 +660,21 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) void gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth) { + GstRTSPMediaPrivate *priv; GstRTSPAuth *old; g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + priv = media->priv; + GST_LOG_OBJECT (media, "set auth %p", auth); - g_mutex_lock (&media->lock); - if ((old = media->auth) != auth) - media->auth = auth ? g_object_ref (auth) : NULL; + g_mutex_lock (&priv->lock); + if ((old = priv->auth) != auth) + priv->auth = auth ? g_object_ref (auth) : NULL; else old = NULL; - g_mutex_unlock (&media->lock); + g_mutex_unlock (&priv->lock); if (old) g_object_unref (old); @@ -565,14 +692,17 @@ gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth) GstRTSPAuth * gst_rtsp_media_get_auth (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; GstRTSPAuth *result; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - g_mutex_lock (&media->lock); - if ((result = media->auth)) + priv = media->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->auth)) g_object_ref (result); - g_mutex_unlock (&media->lock); + g_mutex_unlock (&priv->lock); return result; } @@ -588,20 +718,23 @@ void gst_rtsp_media_set_address_pool (GstRTSPMedia * media, GstRTSPAddressPool * pool) { + GstRTSPMediaPrivate *priv; GstRTSPAddressPool *old; g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + priv = media->priv; + GST_LOG_OBJECT (media, "set address pool %p", pool); - g_mutex_lock (&media->lock); - if ((old = media->pool) != pool) - media->pool = pool ? g_object_ref (pool) : NULL; + g_mutex_lock (&priv->lock); + if ((old = priv->pool) != pool) + priv->pool = pool ? g_object_ref (pool) : NULL; else old = NULL; - g_ptr_array_foreach (media->streams, (GFunc) gst_rtsp_stream_set_address_pool, + g_ptr_array_foreach (priv->streams, (GFunc) gst_rtsp_stream_set_address_pool, pool); - g_mutex_unlock (&media->lock); + g_mutex_unlock (&priv->lock); if (old) g_object_unref (old); @@ -619,14 +752,17 @@ gst_rtsp_media_set_address_pool (GstRTSPMedia * media, GstRTSPAddressPool * gst_rtsp_media_get_address_pool (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; GstRTSPAddressPool *result; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - g_mutex_lock (&media->lock); - if ((result = media->pool)) + priv = media->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->pool)) g_object_ref (result); - g_mutex_unlock (&media->lock); + g_mutex_unlock (&priv->lock); return result; } @@ -644,6 +780,7 @@ gst_rtsp_media_get_address_pool (GstRTSPMedia * media) void gst_rtsp_media_collect_streams (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; GstElement *element, *elem; GstPad *pad; gint i; @@ -651,7 +788,8 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) g_return_if_fail (GST_IS_RTSP_MEDIA (media)); - element = media->element; + priv = media->priv; + element = priv->element; have_elem = TRUE; for (i = 0; have_elem; i++) { @@ -680,9 +818,9 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) GST_INFO ("found dynamic element %d, %p", i, elem); - g_mutex_lock (&media->lock); - media->dynamic = g_list_prepend (media->dynamic, elem); - g_mutex_unlock (&media->lock); + g_mutex_lock (&priv->lock); + priv->dynamic = g_list_prepend (priv->dynamic, elem); + g_mutex_unlock (&priv->lock); have_elem = TRUE; } @@ -706,6 +844,7 @@ GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, GstPad * pad) { + GstRTSPMediaPrivate *priv; GstRTSPStream *stream; GstPad *srcpad; gchar *name; @@ -716,21 +855,25 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, g_return_val_if_fail (GST_IS_PAD (pad), NULL); g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL); - g_mutex_lock (&media->lock); - idx = media->streams->len; + priv = media->priv; + + g_mutex_lock (&priv->lock); + idx = priv->streams->len; + + GST_DEBUG ("media %p: creating stream with index %d", media, idx); name = g_strdup_printf ("src_%u", idx); srcpad = gst_ghost_pad_new (name, pad); gst_pad_set_active (srcpad, TRUE); - gst_element_add_pad (media->element, srcpad); + gst_element_add_pad (priv->element, srcpad); g_free (name); stream = gst_rtsp_stream_new (idx, payloader, srcpad); - if (media->pool) - gst_rtsp_stream_set_address_pool (stream, media->pool); + if (priv->pool) + gst_rtsp_stream_set_address_pool (stream, priv->pool); - g_ptr_array_add (media->streams, stream); - g_mutex_unlock (&media->lock); + g_ptr_array_add (priv->streams, stream); + g_mutex_unlock (&priv->lock); g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STREAM], 0, stream, NULL); @@ -749,13 +892,16 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, guint gst_rtsp_media_n_streams (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; guint res; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0); - g_mutex_lock (&media->lock); - res = media->streams->len; - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->streams->len; + g_mutex_unlock (&priv->lock); return res; } @@ -773,16 +919,19 @@ gst_rtsp_media_n_streams (GstRTSPMedia * media) GstRTSPStream * gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) { + GstRTSPMediaPrivate *priv; GstRTSPStream *res; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - g_mutex_lock (&media->lock); - if (idx < media->streams->len) - res = g_ptr_array_index (media->streams, idx); + priv = media->priv; + + g_mutex_lock (&priv->lock); + if (idx < priv->streams->len) + res = g_ptr_array_index (priv->streams, idx); else res = NULL; - g_mutex_unlock (&media->lock); + g_mutex_unlock (&priv->lock); return res; } @@ -800,25 +949,28 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) gchar * gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play) { + GstRTSPMediaPrivate *priv; gchar *result; GstRTSPTimeRange range; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - g_rec_mutex_lock (&media->state_lock); - if (media->status != GST_RTSP_MEDIA_STATUS_PREPARED) + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) goto not_prepared; - g_mutex_lock (&media->lock); + g_mutex_lock (&priv->lock); /* make copy */ - range = media->range; + range = priv->range; - if (!play && media->n_active > 0) { + if (!play && priv->n_active > 0) { range.min.type = GST_RTSP_TIME_NOW; range.min.seconds = -1; } - g_mutex_unlock (&media->lock); - g_rec_mutex_unlock (&media->state_lock); + g_mutex_unlock (&priv->lock); + g_rec_mutex_unlock (&priv->state_lock); result = gst_rtsp_range_to_string (&range); @@ -828,7 +980,7 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play) not_prepared: { GST_WARNING ("media %p was not prepared", media); - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); return NULL; } } @@ -846,6 +998,7 @@ not_prepared: gboolean gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) { + GstRTSPMediaPrivate *priv; GstSeekFlags flags; gboolean res; GstClockTime start, stop; @@ -854,11 +1007,13 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (range != NULL, FALSE); - g_rec_mutex_lock (&media->state_lock); - if (media->status != GST_RTSP_MEDIA_STATUS_PREPARED) + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) goto not_prepared; - if (!media->seekable) + if (!priv->seekable) goto not_seekable; /* depends on the current playing state of the pipeline. We might need to @@ -873,14 +1028,14 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, - GST_TIME_ARGS (media->range_start), GST_TIME_ARGS (media->range_stop)); + GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop)); - if (media->range_start == start) + if (priv->range_start == start) start = GST_CLOCK_TIME_NONE; else if (start != GST_CLOCK_TIME_NONE) start_type = GST_SEEK_TYPE_SET; - if (media->range_stop == stop) + if (priv->range_stop == stop) stop = GST_CLOCK_TIME_NONE; else if (stop != GST_CLOCK_TIME_NONE) stop_type = GST_SEEK_TYPE_SET; @@ -889,12 +1044,12 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); - res = gst_element_seek (media->pipeline, 1.0, GST_FORMAT_TIME, + res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME, flags, start_type, start, stop_type, stop); /* and block for the seek to complete */ GST_INFO ("done seeking %d", res); - gst_element_get_state (media->pipeline, NULL, NULL, -1); + gst_element_get_state (priv->pipeline, NULL, NULL, -1); GST_INFO ("prerolled again"); collect_media_stats (media); @@ -902,26 +1057,26 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GST_INFO ("no seek needed"); res = TRUE; } - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); return res; /* ERRORS */ not_prepared: { - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); GST_INFO ("media %p is not prepared", media); return FALSE; } not_seekable: { - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); GST_INFO ("pipeline is not seekable"); return TRUE; } not_supported: { - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); GST_WARNING ("seek unit %d not supported", range->unit); return FALSE; } @@ -930,35 +1085,47 @@ not_supported: static void gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status) { - g_mutex_lock (&media->lock); + GstRTSPMediaPrivate *priv = media->priv; + + g_mutex_lock (&priv->lock); /* never overwrite the error status */ - if (media->status != GST_RTSP_MEDIA_STATUS_ERROR) - media->status = status; + if (priv->status != GST_RTSP_MEDIA_STATUS_ERROR) + priv->status = status; GST_DEBUG ("setting new status to %d", status); - g_cond_broadcast (&media->cond); - g_mutex_unlock (&media->lock); + g_cond_broadcast (&priv->cond); + g_mutex_unlock (&priv->lock); } -static GstRTSPMediaStatus +/** + * gst_rtsp_media_get_status: + * @media: a #GstRTSPMedia + * + * Get the status of @media. When @media is busy preparing, this function waits + * until @media is prepared or in error. + * + * Returns: the status of @media. + */ +GstRTSPMediaStatus gst_rtsp_media_get_status (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv = media->priv; GstRTSPMediaStatus result; gint64 end_time; - g_mutex_lock (&media->lock); + g_mutex_lock (&priv->lock); end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND; /* while we are preparing, wait */ - while (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) { + while (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) { GST_DEBUG ("waiting for status change"); - if (!g_cond_wait_until (&media->cond, &media->lock, end_time)) { + if (!g_cond_wait_until (&priv->cond, &priv->lock, end_time)) { GST_DEBUG ("timeout, assuming error status"); - media->status = GST_RTSP_MEDIA_STATUS_ERROR; + priv->status = GST_RTSP_MEDIA_STATUS_ERROR; } } /* could be success or error */ - result = media->status; + result = priv->status; GST_DEBUG ("got status %d", result); - g_mutex_unlock (&media->lock); + g_mutex_unlock (&priv->lock); return result; } @@ -967,6 +1134,7 @@ gst_rtsp_media_get_status (GstRTSPMedia * media) static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message) { + GstRTSPMediaPrivate *priv = media->priv; GstMessageType type; type = GST_MESSAGE_TYPE (message); @@ -981,37 +1149,37 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) gst_message_parse_buffering (message, &percent); /* no state management needed for live pipelines */ - if (media->is_live) + if (priv->is_live) break; if (percent == 100) { /* a 100% message means buffering is done */ - media->buffering = FALSE; + priv->buffering = FALSE; /* if the desired state is playing, go back */ - if (media->target_state == GST_STATE_PLAYING) { + if (priv->target_state == GST_STATE_PLAYING) { GST_INFO ("Buffering done, setting pipeline to PLAYING"); - gst_element_set_state (media->pipeline, GST_STATE_PLAYING); + gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); } else { GST_INFO ("Buffering done"); } } else { /* buffering busy */ - if (media->buffering == FALSE) { - if (media->target_state == GST_STATE_PLAYING) { + if (priv->buffering == FALSE) { + if (priv->target_state == GST_STATE_PLAYING) { /* we were not buffering but PLAYING, PAUSE the pipeline. */ GST_INFO ("Buffering, setting pipeline to PAUSED ..."); - gst_element_set_state (media->pipeline, GST_STATE_PAUSED); + gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); } else { GST_INFO ("Buffering ..."); } } - media->buffering = TRUE; + priv->buffering = TRUE; } break; } case GST_MESSAGE_LATENCY: { - gst_bin_recalculate_latency (GST_BIN_CAST (media->pipeline)); + gst_bin_recalculate_latency (GST_BIN_CAST (priv->pipeline)); break; } case GST_MESSAGE_ERROR: @@ -1043,7 +1211,7 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) case GST_MESSAGE_STREAM_STATUS: break; case GST_MESSAGE_ASYNC_DONE: - if (!media->adding) { + if (!priv->adding) { /* when we are dynamically adding pads, the addition of the udpsrc will * temporarily produce ASYNC_DONE messages. We have to ignore them and * wait for the final ASYNC_DONE after everything prerolled */ @@ -1058,7 +1226,7 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) case GST_MESSAGE_EOS: GST_INFO ("%p: got EOS", media); - if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) { + if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) { GST_DEBUG ("shutting down after EOS"); finish_unprepare (media); g_object_unref (media); @@ -1075,17 +1243,18 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) static gboolean bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv = media->priv; GstRTSPMediaClass *klass; gboolean ret; klass = GST_RTSP_MEDIA_GET_CLASS (media); - g_rec_mutex_lock (&media->state_lock); + g_rec_mutex_lock (&priv->state_lock); if (klass->handle_message) ret = klass->handle_message (media, message); else ret = FALSE; - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); return ret; } @@ -1101,42 +1270,43 @@ watch_destroyed (GstRTSPMedia * media) static void pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv = media->priv; GstRTSPStream *stream; /* FIXME, element is likely not a payloader, find the payloader here */ stream = gst_rtsp_media_create_stream (media, element, pad); - GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), - stream->idx); + GST_INFO ("pad added %s:%s, stream %s", GST_DEBUG_PAD_NAME (pad), stream); - g_rec_mutex_lock (&media->state_lock); + g_rec_mutex_lock (&priv->state_lock); /* we will be adding elements below that will cause ASYNC_DONE to be * posted in the bus. We want to ignore those messages until the * pipeline really prerolled. */ - media->adding = TRUE; + priv->adding = TRUE; /* join the element in the PAUSED state because this callback is * called from the streaming thread and it is PAUSED */ - gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline), - media->rtpbin, GST_STATE_PAUSED); + gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline), + priv->rtpbin, GST_STATE_PAUSED); - media->adding = FALSE; - g_rec_mutex_unlock (&media->state_lock); + priv->adding = FALSE; + g_rec_mutex_unlock (&priv->state_lock); } static void no_more_pads_cb (GstElement * element, GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv = media->priv; GstElement *fakesink; - g_mutex_lock (&media->lock); + g_mutex_lock (&priv->lock); GST_INFO ("no more pads"); - if ((fakesink = media->fakesink)) { + if ((fakesink = priv->fakesink)) { gst_object_ref (fakesink); - media->fakesink = NULL; - g_mutex_unlock (&media->lock); + priv->fakesink = NULL; + g_mutex_unlock (&priv->lock); - gst_bin_remove (GST_BIN (media->pipeline), fakesink); + gst_bin_remove (GST_BIN (priv->pipeline), fakesink); gst_element_set_state (fakesink, GST_STATE_NULL); gst_object_unref (fakesink); GST_INFO ("removed fakesink"); @@ -1158,6 +1328,7 @@ no_more_pads_cb (GstElement * element, GstRTSPMedia * media) gboolean gst_rtsp_media_prepare (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; GstStateChangeReturn ret; GstRTSPMediaStatus status; guint i; @@ -1167,59 +1338,61 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - g_rec_mutex_lock (&media->state_lock); - if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) goto was_prepared; - if (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) goto wait_status; - if (media->status != GST_RTSP_MEDIA_STATUS_UNPREPARED) + if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED) goto not_unprepared; - if (!media->reusable && media->reused) + if (!priv->reusable && priv->reused) goto is_reused; - media->rtpbin = gst_element_factory_make ("rtpbin", NULL); - if (media->rtpbin == NULL) + priv->rtpbin = gst_element_factory_make ("rtpbin", NULL); + if (priv->rtpbin == NULL) goto no_rtpbin; GST_INFO ("preparing media %p", media); /* reset some variables */ - media->is_live = FALSE; - media->seekable = FALSE; - media->buffering = FALSE; + priv->is_live = FALSE; + priv->seekable = FALSE; + priv->buffering = FALSE; /* we're preparing now */ - media->status = GST_RTSP_MEDIA_STATUS_PREPARING; + priv->status = GST_RTSP_MEDIA_STATUS_PREPARING; - bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline)); + bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline)); /* add the pipeline bus to our custom mainloop */ - media->source = gst_bus_create_watch (bus); + priv->source = gst_bus_create_watch (bus); gst_object_unref (bus); - g_source_set_callback (media->source, (GSourceFunc) bus_message, + g_source_set_callback (priv->source, (GSourceFunc) bus_message, gst_object_ref (media), (GDestroyNotify) watch_destroyed); klass = GST_RTSP_MEDIA_GET_CLASS (media); - media->id = g_source_attach (media->source, klass->context); + priv->id = g_source_attach (priv->source, klass->context); /* add stuff to the bin */ - gst_bin_add (GST_BIN (media->pipeline), media->rtpbin); + gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin); /* link streams we already have, other streams might appear when we have * dynamic elements */ - for (i = 0; i < media->streams->len; i++) { + for (i = 0; i < priv->streams->len; i++) { GstRTSPStream *stream; - stream = g_ptr_array_index (media->streams, i); + stream = g_ptr_array_index (priv->streams, i); - gst_rtsp_stream_join_bin (stream, GST_BIN (media->pipeline), - media->rtpbin, GST_STATE_NULL); + gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline), + priv->rtpbin, GST_STATE_NULL); } - for (walk = media->dynamic; walk; walk = g_list_next (walk)) { + for (walk = priv->dynamic; walk; walk = g_list_next (walk)) { GstElement *elem = walk->data; GST_INFO ("adding callbacks for dynamic element %p", elem); @@ -1229,32 +1402,32 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) /* we add a fakesink here in order to make the state change async. We remove * the fakesink again in the no-more-pads callback. */ - media->fakesink = gst_element_factory_make ("fakesink", "fakesink"); - gst_bin_add (GST_BIN (media->pipeline), media->fakesink); + priv->fakesink = gst_element_factory_make ("fakesink", "fakesink"); + gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink); } GST_INFO ("setting pipeline to PAUSED for media %p", media); /* first go to PAUSED */ - ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED); - media->target_state = GST_STATE_PAUSED; + ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); + priv->target_state = GST_STATE_PAUSED; switch (ret) { case GST_STATE_CHANGE_SUCCESS: GST_INFO ("SUCCESS state change for media %p", media); - media->seekable = TRUE; + priv->seekable = TRUE; break; case GST_STATE_CHANGE_ASYNC: GST_INFO ("ASYNC state change for media %p", media); - media->seekable = TRUE; + priv->seekable = TRUE; break; case GST_STATE_CHANGE_NO_PREROLL: /* we need to go to PLAYING */ GST_INFO ("NO_PREROLL state change: live media %p", media); /* FIXME we disable seeking for live streams for now. We should perform a * seeking query in preroll instead */ - media->seekable = FALSE; - media->is_live = TRUE; - ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING); + priv->seekable = FALSE; + priv->is_live = TRUE; + ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; break; @@ -1262,7 +1435,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) goto state_failed; } wait_status: - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); /* now wait for all pads to be prerolled, FIXME, we should somehow be * able to do this async so that we don't block the server thread. */ @@ -1280,25 +1453,25 @@ wait_status: was_prepared: { GST_LOG ("media %p was prepared", media); - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); return TRUE; } /* ERRORS */ not_unprepared: { GST_WARNING ("media %p was not unprepared", media); - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); return FALSE; } is_reused: { - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); GST_WARNING ("can not reuse media %p", media); return FALSE; } no_rtpbin: { - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); GST_WARNING ("no rtpbin element"); g_warning ("failed to create element 'rtpbin', check your installation"); return FALSE; @@ -1307,7 +1480,7 @@ state_failed: { GST_WARNING ("failed to preroll pipeline"); gst_rtsp_media_unprepare (media); - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); return FALSE; } } @@ -1316,37 +1489,37 @@ state_failed: static void finish_unprepare (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv = media->priv; gint i; GST_DEBUG ("shutting down"); - gst_element_set_state (media->pipeline, GST_STATE_NULL); + gst_element_set_state (priv->pipeline, GST_STATE_NULL); - for (i = 0; i < media->streams->len; i++) { + for (i = 0; i < priv->streams->len; i++) { GstRTSPStream *stream; GST_INFO ("Removing elements of stream %d from pipeline", i); - stream = g_ptr_array_index (media->streams, i); + stream = g_ptr_array_index (priv->streams, i); - gst_rtsp_stream_leave_bin (stream, GST_BIN (media->pipeline), - media->rtpbin); + gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin); } - g_ptr_array_set_size (media->streams, 0); + g_ptr_array_set_size (priv->streams, 0); - gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin); - media->rtpbin = NULL; + gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin); + priv->rtpbin = NULL; - gst_object_unref (media->pipeline); - media->pipeline = NULL; + gst_object_unref (priv->pipeline); + priv->pipeline = NULL; - media->reused = TRUE; - media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED; + priv->reused = TRUE; + priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARED; - if (media->source) { - g_source_destroy (media->source); - g_source_unref (media->source); - media->source = NULL; + if (priv->source) { + g_source_destroy (priv->source); + g_source_unref (priv->source); + priv->source = NULL; } /* when the media is not reusable, this will effectively unref the media and @@ -1358,15 +1531,17 @@ finish_unprepare (GstRTSPMedia * media) static gboolean default_unprepare (GstRTSPMedia * media) { - if (media->eos_shutdown) { + GstRTSPMediaPrivate *priv = media->priv; + + if (priv->eos_shutdown) { GST_DEBUG ("sending EOS for shutdown"); /* ref so that we don't disappear */ g_object_ref (media); - gst_element_send_event (media->pipeline, gst_event_new_eos ()); + gst_element_send_event (priv->pipeline, gst_event_new_eos ()); /* we need to go to playing again for the EOS to propagate, normally in this * state, nothing is receiving data from us anymore so this is ok. */ - gst_element_set_state (media->pipeline, GST_STATE_PLAYING); - media->status = GST_RTSP_MEDIA_STATUS_UNPREPARING; + gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); + priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARING; } else { finish_unprepare (media); } @@ -1386,19 +1561,22 @@ default_unprepare (GstRTSPMedia * media) gboolean gst_rtsp_media_unprepare (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; gboolean success; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - g_rec_mutex_lock (&media->state_lock); - if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED) + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARED) goto was_unprepared; GST_INFO ("unprepare media %p", media); - media->target_state = GST_STATE_NULL; + priv->target_state = GST_STATE_NULL; success = TRUE; - if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED) { + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) { GstRTSPMediaClass *klass; klass = GST_RTSP_MEDIA_GET_CLASS (media); @@ -1407,13 +1585,13 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) } else { finish_unprepare (media); } - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); return success; was_unprepared: { - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); GST_INFO ("media %p was already unprepared", media); return TRUE; } @@ -1435,22 +1613,25 @@ gboolean gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, GPtrArray * transports) { + GstRTSPMediaPrivate *priv; gint i; - gboolean add, remove, do_state; + gboolean activate, deactivate, do_state; gint old_active; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (transports != NULL, FALSE); - g_rec_mutex_lock (&media->state_lock); - if (media->status != GST_RTSP_MEDIA_STATUS_PREPARED) + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) goto not_prepared; /* NULL and READY are the same */ if (state == GST_STATE_READY) state = GST_STATE_NULL; - add = remove = FALSE; + activate = deactivate = FALSE; GST_INFO ("going to state %s media %p", gst_element_state_get_name (state), media); @@ -1458,18 +1639,18 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, switch (state) { case GST_STATE_NULL: case GST_STATE_PAUSED: - /* we're going from PLAYING to PAUSED, READY or NULL, remove */ - if (media->target_state == GST_STATE_PLAYING) - remove = TRUE; + /* we're going from PLAYING to PAUSED, READY or NULL, deactivate */ + if (priv->target_state == GST_STATE_PLAYING) + deactivate = TRUE; break; case GST_STATE_PLAYING: - /* we're going to PLAYING, add */ - add = TRUE; + /* we're going to PLAYING, activate */ + activate = TRUE; break; default: break; } - old_active = media->n_active; + old_active = priv->n_active; for (i = 0; i < transports->len; i++) { GstRTSPStreamTransport *trans; @@ -1479,40 +1660,36 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, if (trans == NULL) continue; - /* we need a transport */ - if (!trans->transport) - continue; - - if (add) { - if (gst_rtsp_stream_add_transport (trans->stream, trans)) - media->n_active++; - } else if (remove) { - if (gst_rtsp_stream_remove_transport (trans->stream, trans)) - media->n_active--; + if (activate) { + if (gst_rtsp_stream_transport_set_active (trans, TRUE)) + priv->n_active++; + } else if (deactivate) { + if (gst_rtsp_stream_transport_set_active (trans, FALSE)) + priv->n_active--; } } - /* we just added the first media, do the playing state change */ - if (old_active == 0 && add) + /* we just activated the first media, do the playing state change */ + if (old_active == 0 && activate) do_state = TRUE; /* if we have no more active media, do the downward state changes */ - else if (media->n_active == 0) + else if (priv->n_active == 0) do_state = TRUE; else do_state = FALSE; - GST_INFO ("state %d active %d media %p do_state %d", state, media->n_active, + GST_INFO ("state %d active %d media %p do_state %d", state, priv->n_active, media, do_state); - if (media->target_state != state) { + if (priv->target_state != state) { if (do_state) { if (state == GST_STATE_NULL) { gst_rtsp_media_unprepare (media); } else { GST_INFO ("state %s media %p", gst_element_state_get_name (state), media); - media->target_state = state; - gst_element_set_state (media->pipeline, state); + priv->target_state = state; + gst_element_set_state (priv->pipeline, state); } } g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state, @@ -1521,10 +1698,10 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, /* remember where we are */ if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED || - old_active != media->n_active)) + old_active != priv->n_active)) collect_media_stats (media); - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); return TRUE; @@ -1532,7 +1709,7 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, not_prepared: { GST_WARNING ("media %p was not prepared", media); - g_rec_mutex_unlock (&media->state_lock); + g_rec_mutex_unlock (&priv->state_lock); return FALSE; } } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 64cda5e381..230806bf48 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -38,6 +38,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPMedia GstRTSPMedia; typedef struct _GstRTSPMediaClass GstRTSPMediaClass; +typedef struct _GstRTSPMediaPrivate GstRTSPMediaPrivate; #include "rtsp-stream.h" #include "rtsp-auth.h" @@ -64,36 +65,6 @@ typedef enum { /** * GstRTSPMedia: - * @parent: parent GObject - * @lock: for protecting the object - * @cond: for signaling the object - * @shared: if this media can be shared between clients - * @reusable: if this media can be reused after an unprepare - * @protocols: the allowed lower transport for this stream - * @reused: if this media has been reused - * @is_ipv6: if this media is using ipv6 - * @eos_shutdown: if EOS should be sent on shutdown - * @buffer_size: The UDP buffer size - * @auth: the authentication service in use - * @multicast_group: the multicast group to use - * @element: the data providing element, owned by @pipeline - * @streams: the different #GstRTSPStream provided by @element - * @dynamic: list of dynamic elements managed by @element - * @status: the status of the media pipeline - * @n_active: the number of active connections - * @adding: when elements are added to the pipeline - * @pipeline: the toplevel pipeline - * @fakesink: for making state changes async - * @source: the bus watch for pipeline messages. - * @id: the id of the watch - * @is_live: if the pipeline is live - * @seekable: if the pipeline can perform a seek - * @buffering: if the pipeline is buffering - * @target_state: the desired target state of the pipeline - * @rtpbin: the rtpbin - * @range: the range of the media being streamed - * @range_start: range start in #GstClockTime - * @range_stop: range stop in #GstClockTime * * A class that contains the GStreamer element along with a list of * #GstRTSPStream objects that can produce data. @@ -103,45 +74,7 @@ typedef enum { struct _GstRTSPMedia { GObject parent; - GMutex lock; - GCond cond; - - gboolean shared; - gboolean reusable; - GstRTSPLowerTrans protocols; - gboolean reused; - gboolean is_ipv6; - gboolean eos_shutdown; - guint buffer_size; - GstRTSPAuth *auth; - GstRTSPAddressPool*pool; - - GstElement *element; - GRecMutex state_lock; - GPtrArray *streams; - GList *dynamic; - GstRTSPMediaStatus status; - gint n_active; - gboolean adding; - - /* the pipeline for the media */ - GstElement *pipeline; - GstElement *fakesink; - GSource *source; - guint id; - - gboolean is_live; - gboolean seekable; - gboolean buffering; - GstState target_state; - - /* RTP session manager */ - GstElement *rtpbin; - - /* the range of media */ - GstRTSPTimeRange range; - GstClockTime range_start; - GstClockTime range_stop; + GstRTSPMediaPrivate *priv; }; /** @@ -179,7 +112,11 @@ struct _GstRTSPMediaClass { GType gst_rtsp_media_get_type (void); /* creating the media */ -GstRTSPMedia * gst_rtsp_media_new (void); +GstRTSPMedia * gst_rtsp_media_new (GstElement *element); + +void gst_rtsp_media_take_pipeline (GstRTSPMedia *media, GstPipeline *pipeline); + +GstRTSPMediaStatus gst_rtsp_media_get_status (GstRTSPMedia *media); void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared); gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media); diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 3a92d55875..c18cb63d1d 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -19,6 +19,15 @@ #include "rtsp-mount-points.h" +#define GST_RTSP_MOUNT_POINTS_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MOUNT_POINTS, GstRTSPMountPointsPrivate)) + +struct _GstRTSPMountPointsPrivate +{ + GMutex lock; + GHashTable *mounts; +}; + G_DEFINE_TYPE (GstRTSPMountPoints, gst_rtsp_mount_points, G_TYPE_OBJECT); GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug); @@ -34,6 +43,8 @@ gst_rtsp_mount_points_class_init (GstRTSPMountPointsClass * klass) { GObjectClass *gobject_class; + g_type_class_add_private (klass, sizeof (GstRTSPMountPointsPrivate)); + gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gst_rtsp_mount_points_finalize; @@ -47,10 +58,14 @@ gst_rtsp_mount_points_class_init (GstRTSPMountPointsClass * klass) static void gst_rtsp_mount_points_init (GstRTSPMountPoints * mounts) { + GstRTSPMountPointsPrivate *priv = GST_RTSP_MOUNT_POINTS_GET_PRIVATE (mounts); + GST_DEBUG_OBJECT (mounts, "created"); - g_mutex_init (&mounts->lock); - mounts->mounts = g_hash_table_new_full (g_str_hash, g_str_equal, + mounts->priv = priv; + + g_mutex_init (&priv->lock); + priv->mounts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } @@ -58,11 +73,12 @@ static void gst_rtsp_mount_points_finalize (GObject * obj) { GstRTSPMountPoints *mounts = GST_RTSP_MOUNT_POINTS (obj); + GstRTSPMountPointsPrivate *priv = mounts->priv; GST_DEBUG_OBJECT (mounts, "finalized"); - g_hash_table_unref (mounts->mounts); - g_mutex_clear (&mounts->lock); + g_hash_table_unref (priv->mounts); + g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_mount_points_parent_class)->finalize (obj); } @@ -87,16 +103,17 @@ gst_rtsp_mount_points_new (void) static GstRTSPMediaFactory * find_factory (GstRTSPMountPoints * mounts, const GstRTSPUrl * url) { + GstRTSPMountPointsPrivate *priv = mounts->priv; GstRTSPMediaFactory *result; - g_mutex_lock (&mounts->lock); + g_mutex_lock (&priv->lock); /* find the location of the media in the hashtable we only use the absolute * path of the uri to find a media factory. If the factory depends on other * properties found in the url, this method should be overridden. */ - result = g_hash_table_lookup (mounts->mounts, url->abspath); + result = g_hash_table_lookup (priv->mounts, url->abspath); if (result) g_object_ref (result); - g_mutex_unlock (&mounts->lock); + g_mutex_unlock (&priv->lock); GST_INFO ("found media factory %p for url abspath %s", result, url->abspath); @@ -150,13 +167,17 @@ void gst_rtsp_mount_points_add_factory (GstRTSPMountPoints * mounts, const gchar * path, GstRTSPMediaFactory * factory) { + GstRTSPMountPointsPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts)); g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); g_return_if_fail (path != NULL); - g_mutex_lock (&mounts->lock); - g_hash_table_insert (mounts->mounts, g_strdup (path), factory); - g_mutex_unlock (&mounts->lock); + priv = mounts->priv; + + g_mutex_lock (&priv->lock); + g_hash_table_insert (priv->mounts, g_strdup (path), factory); + g_mutex_unlock (&priv->lock); } /** @@ -170,10 +191,14 @@ void gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints * mounts, const gchar * path) { + GstRTSPMountPointsPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts)); g_return_if_fail (path != NULL); - g_mutex_lock (&mounts->lock); - g_hash_table_remove (mounts->mounts, path); - g_mutex_unlock (&mounts->lock); + priv = mounts->priv; + + g_mutex_lock (&priv->lock); + g_hash_table_remove (priv->mounts, path); + g_mutex_unlock (&priv->lock); } diff --git a/gst/rtsp-server/rtsp-mount-points.h b/gst/rtsp-server/rtsp-mount-points.h index 3ab601642b..d8dd1b8ea8 100644 --- a/gst/rtsp-server/rtsp-mount-points.h +++ b/gst/rtsp-server/rtsp-mount-points.h @@ -39,6 +39,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPMountPoints GstRTSPMountPoints; typedef struct _GstRTSPMountPointsClass GstRTSPMountPointsClass; +typedef struct _GstRTSPMountPointsPrivate GstRTSPMountPointsPrivate; /** * GstRTSPMountPoints: @@ -50,8 +51,7 @@ typedef struct _GstRTSPMountPointsClass GstRTSPMountPointsClass; struct _GstRTSPMountPoints { GObject parent; - GMutex lock; - GHashTable *mounts; + GstRTSPMountPointsPrivate *priv; }; /** diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 14ba38e3a0..847b48761e 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -38,12 +38,12 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, guint i, n_streams; gchar *rangestr; - if (media->status != GST_RTSP_MEDIA_STATUS_PREPARED) - goto not_prepared; - n_streams = gst_rtsp_media_n_streams (media); rangestr = gst_rtsp_media_get_range_string (media, FALSE); + if (rangestr == NULL) + goto not_prepared; + gst_sdp_message_add_attribute (sdp, "range", rangestr); g_free (rangestr); @@ -57,16 +57,19 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, guint n_fields, j; gboolean first; GString *fmtp; + GstCaps *caps; stream = gst_rtsp_media_get_stream (media, i); + caps = gst_rtsp_stream_get_caps (stream); - if (stream->caps == NULL) { + if (caps == NULL) { g_warning ("ignoring stream %d without media type", i); continue; } - s = gst_caps_get_structure (stream->caps, 0); + s = gst_caps_get_structure (caps, 0); if (s == NULL) { + gst_caps_unref (caps); g_warning ("ignoring stream %d without media type", i); continue; } @@ -152,6 +155,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, } gst_sdp_message_add_media (sdp, smedia); gst_sdp_media_free (smedia); + gst_caps_unref (caps); } return TRUE; diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index dfd4de87e5..f66b23a48b 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -23,6 +23,38 @@ #include "rtsp-server.h" #include "rtsp-client.h" +#define GST_RTSP_SERVER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SERVER, GstRTSPServerPrivate)) + +#define GST_RTSP_SERVER_GET_LOCK(server) (&(GST_RTSP_SERVER_CAST(server)->priv->lock)) +#define GST_RTSP_SERVER_LOCK(server) (g_mutex_lock(GST_RTSP_SERVER_GET_LOCK(server))) +#define GST_RTSP_SERVER_UNLOCK(server) (g_mutex_unlock(GST_RTSP_SERVER_GET_LOCK(server))) + +struct _GstRTSPServerPrivate +{ + GMutex lock; + + /* server information */ + gchar *address; + gchar *service; + gint backlog; + gint max_threads; + + GSocket *socket; + + /* sessions on this server */ + GstRTSPSessionPool *session_pool; + + /* mount points for this server */ + GstRTSPMountPoints *mount_points; + + /* authentication manager */ + GstRTSPAuth *auth; + + /* the clients that are connected */ + GList *clients; +}; + #define DEFAULT_ADDRESS "0.0.0.0" #define DEFAULT_BOUND_PORT -1 /* #define DEFAULT_ADDRESS "::0" */ @@ -80,6 +112,8 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) { GObjectClass *gobject_class; + g_type_class_add_private (klass, sizeof (GstRTSPServerPrivate)); + gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_server_get_property; @@ -185,36 +219,41 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) static void gst_rtsp_server_init (GstRTSPServer * server) { - g_mutex_init (&server->lock); - server->address = g_strdup (DEFAULT_ADDRESS); - server->service = g_strdup (DEFAULT_SERVICE); - server->socket = NULL; - server->backlog = DEFAULT_BACKLOG; - server->session_pool = gst_rtsp_session_pool_new (); - server->mount_points = gst_rtsp_mount_points_new (); - server->max_threads = DEFAULT_MAX_THREADS; + GstRTSPServerPrivate *priv = GST_RTSP_SERVER_GET_PRIVATE (server); + + server->priv = priv; + + g_mutex_init (&priv->lock); + priv->address = g_strdup (DEFAULT_ADDRESS); + priv->service = g_strdup (DEFAULT_SERVICE); + priv->socket = NULL; + priv->backlog = DEFAULT_BACKLOG; + priv->session_pool = gst_rtsp_session_pool_new (); + priv->mount_points = gst_rtsp_mount_points_new (); + priv->max_threads = DEFAULT_MAX_THREADS; } static void gst_rtsp_server_finalize (GObject * object) { GstRTSPServer *server = GST_RTSP_SERVER (object); + GstRTSPServerPrivate *priv = server->priv; GST_DEBUG_OBJECT (server, "finalize server"); - g_free (server->address); - g_free (server->service); + g_free (priv->address); + g_free (priv->service); - if (server->socket) - g_object_unref (server->socket); + if (priv->socket) + g_object_unref (priv->socket); - g_object_unref (server->session_pool); - g_object_unref (server->mount_points); + g_object_unref (priv->session_pool); + g_object_unref (priv->mount_points); - if (server->auth) - g_object_unref (server->auth); + if (priv->auth) + g_object_unref (priv->auth); - g_mutex_clear (&server->lock); + g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_server_parent_class)->finalize (object); } @@ -246,12 +285,16 @@ gst_rtsp_server_new (void) void gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address) { + GstRTSPServerPrivate *priv; + g_return_if_fail (GST_IS_RTSP_SERVER (server)); g_return_if_fail (address != NULL); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - g_free (server->address); - server->address = g_strdup (address); + g_free (priv->address); + priv->address = g_strdup (address); GST_RTSP_SERVER_UNLOCK (server); } @@ -266,11 +309,15 @@ gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address) gchar * gst_rtsp_server_get_address (GstRTSPServer * server) { + GstRTSPServerPrivate *priv; gchar *result; + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - result = g_strdup (server->address); + result = g_strdup (priv->address); GST_RTSP_SERVER_UNLOCK (server); return result; @@ -287,16 +334,19 @@ gst_rtsp_server_get_address (GstRTSPServer * server) int gst_rtsp_server_get_bound_port (GstRTSPServer * server) { + GstRTSPServerPrivate *priv; GSocketAddress *address; int result = -1; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), result); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - if (server->socket == NULL) + if (priv->socket == NULL) goto out; - address = g_socket_get_local_address (server->socket, NULL); + address = g_socket_get_local_address (priv->socket, NULL); result = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address)); g_object_unref (address); @@ -320,12 +370,16 @@ out: void gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service) { + GstRTSPServerPrivate *priv; + g_return_if_fail (GST_IS_RTSP_SERVER (server)); g_return_if_fail (service != NULL); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - g_free (server->service); - server->service = g_strdup (service); + g_free (priv->service); + priv->service = g_strdup (service); GST_RTSP_SERVER_UNLOCK (server); } @@ -340,12 +394,15 @@ gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service) gchar * gst_rtsp_server_get_service (GstRTSPServer * server) { + GstRTSPServerPrivate *priv; gchar *result; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - result = g_strdup (server->service); + result = g_strdup (priv->service); GST_RTSP_SERVER_UNLOCK (server); return result; @@ -364,10 +421,14 @@ gst_rtsp_server_get_service (GstRTSPServer * server) void gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog) { + GstRTSPServerPrivate *priv; + g_return_if_fail (GST_IS_RTSP_SERVER (server)); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - server->backlog = backlog; + priv->backlog = backlog; GST_RTSP_SERVER_UNLOCK (server); } @@ -382,12 +443,15 @@ gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog) gint gst_rtsp_server_get_backlog (GstRTSPServer * server) { + GstRTSPServerPrivate *priv; gint result; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - result = server->backlog; + result = priv->backlog; GST_RTSP_SERVER_UNLOCK (server); return result; @@ -404,16 +468,19 @@ void gst_rtsp_server_set_session_pool (GstRTSPServer * server, GstRTSPSessionPool * pool) { + GstRTSPServerPrivate *priv; GstRTSPSessionPool *old; g_return_if_fail (GST_IS_RTSP_SERVER (server)); + priv = server->priv; + if (pool) g_object_ref (pool); GST_RTSP_SERVER_LOCK (server); - old = server->session_pool; - server->session_pool = pool; + old = priv->session_pool; + priv->session_pool = pool; GST_RTSP_SERVER_UNLOCK (server); if (old) @@ -432,12 +499,15 @@ gst_rtsp_server_set_session_pool (GstRTSPServer * server, GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer * server) { + GstRTSPServerPrivate *priv; GstRTSPSessionPool *result; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - if ((result = server->session_pool)) + if ((result = priv->session_pool)) g_object_ref (result); GST_RTSP_SERVER_UNLOCK (server); @@ -455,16 +525,19 @@ void gst_rtsp_server_set_mount_points (GstRTSPServer * server, GstRTSPMountPoints * mounts) { + GstRTSPServerPrivate *priv; GstRTSPMountPoints *old; g_return_if_fail (GST_IS_RTSP_SERVER (server)); + priv = server->priv; + if (mounts) g_object_ref (mounts); GST_RTSP_SERVER_LOCK (server); - old = server->mount_points; - server->mount_points = mounts; + old = priv->mount_points; + priv->mount_points = mounts; GST_RTSP_SERVER_UNLOCK (server); if (old) @@ -484,12 +557,15 @@ gst_rtsp_server_set_mount_points (GstRTSPServer * server, GstRTSPMountPoints * gst_rtsp_server_get_mount_points (GstRTSPServer * server) { + GstRTSPServerPrivate *priv; GstRTSPMountPoints *result; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - if ((result = server->mount_points)) + if ((result = priv->mount_points)) g_object_ref (result); GST_RTSP_SERVER_UNLOCK (server); @@ -506,16 +582,19 @@ gst_rtsp_server_get_mount_points (GstRTSPServer * server) void gst_rtsp_server_set_auth (GstRTSPServer * server, GstRTSPAuth * auth) { + GstRTSPServerPrivate *priv; GstRTSPAuth *old; g_return_if_fail (GST_IS_RTSP_SERVER (server)); + priv = server->priv; + if (auth) g_object_ref (auth); GST_RTSP_SERVER_LOCK (server); - old = server->auth; - server->auth = auth; + old = priv->auth; + priv->auth = auth; GST_RTSP_SERVER_UNLOCK (server); if (old) @@ -535,12 +614,15 @@ gst_rtsp_server_set_auth (GstRTSPServer * server, GstRTSPAuth * auth) GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer * server) { + GstRTSPServerPrivate *priv; GstRTSPAuth *result; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - if ((result = server->auth)) + if ((result = priv->auth)) g_object_ref (result); GST_RTSP_SERVER_UNLOCK (server); @@ -559,10 +641,14 @@ gst_rtsp_server_get_auth (GstRTSPServer * server) void gst_rtsp_server_set_max_threads (GstRTSPServer * server, gint max_threads) { + GstRTSPServerPrivate *priv; + g_return_if_fail (GST_IS_RTSP_SERVER (server)); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - server->max_threads = max_threads; + priv->max_threads = max_threads; GST_RTSP_SERVER_UNLOCK (server); } @@ -578,12 +664,15 @@ gst_rtsp_server_set_max_threads (GstRTSPServer * server, gint max_threads) gint gst_rtsp_server_get_max_threads (GstRTSPServer * server) { + GstRTSPServerPrivate *priv; gint res; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - res = server->max_threads; + res = priv->max_threads; GST_RTSP_SERVER_UNLOCK (server); return res; @@ -668,6 +757,7 @@ GSocket * gst_rtsp_server_create_socket (GstRTSPServer * server, GCancellable * cancellable, GError ** error) { + GstRTSPServerPrivate *priv; GSocketConnectable *conn; GSocketAddressEnumerator *enumerator; GSocket *socket = NULL; @@ -680,16 +770,18 @@ gst_rtsp_server_create_socket (GstRTSPServer * server, g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + priv = server->priv; + GST_RTSP_SERVER_LOCK (server); - GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address, - server->service); + GST_DEBUG_OBJECT (server, "getting address info of %s/%s", priv->address, + priv->service); /* resolve the server IP address */ - port = atoi (server->service); - if (port != 0 || !strcmp (server->service, "0")) - conn = g_network_address_new (server->address, port); + port = atoi (priv->service); + if (port != 0 || !strcmp (priv->service, "0")) + conn = g_network_address_new (priv->address, port); else - conn = g_network_service_new (server->service, "tcp", server->address); + conn = g_network_service_new (priv->service, "tcp", priv->address); enumerator = g_socket_connectable_enumerate (conn); g_object_unref (conn); @@ -764,13 +856,13 @@ gst_rtsp_server_create_socket (GstRTSPServer * server, g_socket_set_blocking (socket, FALSE); /* set listen backlog */ - g_socket_set_listen_backlog (socket, server->backlog); + g_socket_set_listen_backlog (socket, priv->backlog); if (!g_socket_listen (socket, error)) goto listen_failed; GST_DEBUG_OBJECT (server, "listening on server socket %p with queue of %d", - socket, server->backlog); + socket, priv->backlog); GST_RTSP_SERVER_UNLOCK (server); @@ -854,13 +946,14 @@ static void unmanage_client (GstRTSPClient * client, ClientContext * ctx) { GstRTSPServer *server = ctx->server; + GstRTSPServerPrivate *priv = server->priv; GST_DEBUG_OBJECT (server, "unmanage client %p", client); g_object_ref (server); GST_RTSP_SERVER_LOCK (server); - server->clients = g_list_remove (server->clients, ctx); + priv->clients = g_list_remove (priv->clients, ctx); GST_RTSP_SERVER_UNLOCK (server); if (ctx->loop) @@ -877,13 +970,14 @@ static void manage_client (GstRTSPServer * server, GstRTSPClient * client) { ClientContext *ctx; + GstRTSPServerPrivate *priv = server->priv; GST_DEBUG_OBJECT (server, "manage client %p", client); ctx = g_slice_new0 (ClientContext); ctx->server = server; ctx->client = client; - if (server->max_threads == 0) { + if (priv->max_threads == 0) { GSource *source; /* find the context to add the watch */ @@ -899,7 +993,7 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) GST_RTSP_SERVER_LOCK (server); g_signal_connect (client, "closed", (GCallback) unmanage_client, ctx); - server->clients = g_list_prepend (server->clients, ctx); + priv->clients = g_list_prepend (priv->clients, ctx); GST_RTSP_SERVER_UNLOCK (server); if (ctx->loop) { @@ -913,17 +1007,18 @@ static GstRTSPClient * default_create_client (GstRTSPServer * server) { GstRTSPClient *client; + GstRTSPServerPrivate *priv = server->priv; /* a new client connected, create a session to handle the client. */ client = gst_rtsp_client_new (); /* set the session pool that this client should use */ GST_RTSP_SERVER_LOCK (server); - gst_rtsp_client_set_session_pool (client, server->session_pool); + gst_rtsp_client_set_session_pool (client, priv->session_pool); /* set the mount points that this client should use */ - gst_rtsp_client_set_mount_points (client, server->mount_points); + gst_rtsp_client_set_mount_points (client, priv->mount_points); /* set authentication manager */ - gst_rtsp_client_set_auth (client, server->auth); + gst_rtsp_client_set_auth (client, priv->auth); GST_RTSP_SERVER_UNLOCK (server); return client; @@ -1073,9 +1168,12 @@ accept_failed: static void watch_destroyed (GstRTSPServer * server) { + GstRTSPServerPrivate *priv = server->priv; + GST_DEBUG_OBJECT (server, "source destroyed"); - g_object_unref (server->socket); - server->socket = NULL; + + g_object_unref (priv->socket); + priv->socket = NULL; g_object_unref (server); } @@ -1100,18 +1198,21 @@ GSource * gst_rtsp_server_create_source (GstRTSPServer * server, GCancellable * cancellable, GError ** error) { + GstRTSPServerPrivate *priv; GSocket *socket, *old; GSource *source; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + priv = server->priv; + socket = gst_rtsp_server_create_socket (server, NULL, error); if (socket == NULL) goto no_socket; GST_RTSP_SERVER_LOCK (server); - old = server->socket; - server->socket = g_object_ref (socket); + old = priv->socket; + priv->socket = g_object_ref (socket); GST_RTSP_SERVER_UNLOCK (server); if (old) diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 3d56376598..6df3a6d51a 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -26,6 +26,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPServer GstRTSPServer; typedef struct _GstRTSPServerClass GstRTSPServerClass; +typedef struct _GstRTSPServerPrivate GstRTSPServerPrivate; #include "rtsp-session-pool.h" #include "rtsp-mount-points.h" @@ -41,10 +42,6 @@ typedef struct _GstRTSPServerClass GstRTSPServerClass; #define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj)) #define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass)) -#define GST_RTSP_SERVER_GET_LOCK(server) (&(GST_RTSP_SERVER_CAST(server)->lock)) -#define GST_RTSP_SERVER_LOCK(server) (g_mutex_lock(GST_RTSP_SERVER_GET_LOCK(server))) -#define GST_RTSP_SERVER_UNLOCK(server) (g_mutex_unlock(GST_RTSP_SERVER_GET_LOCK(server))) - /** * GstRTSPServer: * @@ -54,27 +51,7 @@ typedef struct _GstRTSPServerClass GstRTSPServerClass; struct _GstRTSPServer { GObject parent; - GMutex lock; - - /* server information */ - gchar *address; - gchar *service; - gint backlog; - gint max_threads; - - GSocket *socket; - - /* sessions on this server */ - GstRTSPSessionPool *session_pool; - - /* mount points for this server */ - GstRTSPMountPoints *mount_points; - - /* authentication manager */ - GstRTSPAuth *auth; - - /* the clients that are connected */ - GList *clients; + GstRTSPServerPrivate *priv; }; /** diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 31caca7bcd..fb4d71c455 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -20,6 +20,20 @@ #include "rtsp-session.h" +#define GST_RTSP_SESSION_MEDIA_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION_MEDIA, GstRTSPSessionMediaPrivate)) + +struct _GstRTSPSessionMediaPrivate +{ + GMutex lock; + GstRTSPUrl *url; + GstRTSPMedia *media; + GstRTSPState state; + guint counter; + + GPtrArray *transports; +}; + enum { PROP_0, @@ -38,6 +52,8 @@ gst_rtsp_session_media_class_init (GstRTSPSessionMediaClass * klass) { GObjectClass *gobject_class; + g_type_class_add_private (klass, sizeof (GstRTSPSessionMediaPrivate)); + gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gst_rtsp_session_media_finalize; @@ -49,26 +65,32 @@ gst_rtsp_session_media_class_init (GstRTSPSessionMediaClass * klass) static void gst_rtsp_session_media_init (GstRTSPSessionMedia * media) { - g_mutex_init (&media->lock); - media->state = GST_RTSP_STATE_INIT; + GstRTSPSessionMediaPrivate *priv = GST_RTSP_SESSION_MEDIA_GET_PRIVATE (media); + + media->priv = priv; + + g_mutex_init (&priv->lock); + priv->state = GST_RTSP_STATE_INIT; } static void gst_rtsp_session_media_finalize (GObject * obj) { GstRTSPSessionMedia *media; + GstRTSPSessionMediaPrivate *priv; media = GST_RTSP_SESSION_MEDIA (obj); + priv = media->priv; GST_INFO ("free session media %p", media); gst_rtsp_session_media_set_state (media, GST_STATE_NULL); - g_ptr_array_unref (media->transports); + g_ptr_array_unref (priv->transports); - gst_rtsp_url_free (media->url); - g_object_unref (media->media); - g_mutex_clear (&media->lock); + gst_rtsp_url_free (priv->url); + g_object_unref (priv->media); + g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_session_media_parent_class)->finalize (obj); } @@ -95,25 +117,65 @@ free_session_media (gpointer data) GstRTSPSessionMedia * gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media) { + GstRTSPSessionMediaPrivate *priv; GstRTSPSessionMedia *result; guint n_streams; g_return_val_if_fail (url != NULL, NULL); g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - g_return_val_if_fail (media->status == GST_RTSP_MEDIA_STATUS_PREPARED, NULL); + g_return_val_if_fail (gst_rtsp_media_get_status (media) == + GST_RTSP_MEDIA_STATUS_PREPARED, NULL); result = g_object_new (GST_TYPE_RTSP_SESSION_MEDIA, NULL); - result->url = gst_rtsp_url_copy ((GstRTSPUrl *) url); - result->media = media; + priv = result->priv; + + priv->url = gst_rtsp_url_copy ((GstRTSPUrl *) url); + priv->media = media; /* prealloc the streams now, filled with NULL */ n_streams = gst_rtsp_media_n_streams (media); - result->transports = g_ptr_array_new_full (n_streams, free_session_media); - g_ptr_array_set_size (result->transports, n_streams); + priv->transports = g_ptr_array_new_full (n_streams, free_session_media); + g_ptr_array_set_size (priv->transports, n_streams); return result; } +/** + * gst_rtsp_session_media_matches_url: + * @media: a #GstRTSPSessionMedia + * @url: a #GstRTSPUrl + * + * Check if the url of @media matches @url. + * + * Returns: %TRUE when @url matches the url of @media. + */ +gboolean +gst_rtsp_session_media_matches_url (GstRTSPSessionMedia * media, + const GstRTSPUrl * url) +{ + g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE); + g_return_val_if_fail (url != NULL, FALSE); + + return g_str_equal (media->priv->url->abspath, url->abspath); +} + +/** + * gst_rtsp_session_media_get_media: + * @media: a #GstRTSPSessionMedia + * + * Get the #GstRTSPMedia that was used when constructing @media + * + * Returns: (transfer none): the #GstRTSPMedia of @media. Remains valid as long + * as @media is valid. + */ +GstRTSPMedia * +gst_rtsp_session_media_get_media (GstRTSPSessionMedia * media) +{ + g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL); + + return media->priv->media; +} + /** * gst_rtsp_session_media_set_transport: * @media: a #GstRTSPSessionMedia @@ -128,21 +190,26 @@ GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, GstRTSPStream * stream, GstRTSPTransport * tr) { + GstRTSPSessionMediaPrivate *priv; GstRTSPStreamTransport *result; + guint idx; g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL); g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); - g_return_val_if_fail (stream->idx < media->transports->len, NULL); + g_return_val_if_fail (tr != NULL, NULL); + priv = media->priv; + idx = gst_rtsp_stream_get_index (stream); + g_return_val_if_fail (idx < priv->transports->len, NULL); - g_mutex_lock (&media->lock); - result = g_ptr_array_index (media->transports, stream->idx); + g_mutex_lock (&priv->lock); + result = g_ptr_array_index (priv->transports, idx); if (result == NULL) { result = gst_rtsp_stream_transport_new (stream, tr); - g_ptr_array_index (media->transports, stream->idx) = result; - g_mutex_unlock (&media->lock); + g_ptr_array_index (priv->transports, idx) = result; + g_mutex_unlock (&priv->lock); } else { gst_rtsp_stream_transport_set_transport (result, tr); - g_mutex_unlock (&media->lock); + g_mutex_unlock (&priv->lock); } return result; @@ -161,14 +228,16 @@ gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx) { + GstRTSPSessionMediaPrivate *priv; GstRTSPStreamTransport *result; g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL); - g_return_val_if_fail (idx < media->transports->len, NULL); + priv = media->priv; + g_return_val_if_fail (idx < priv->transports->len, NULL); - g_mutex_lock (&media->lock); - result = g_ptr_array_index (media->transports, idx); - g_mutex_unlock (&media->lock); + g_mutex_lock (&priv->lock); + result = g_ptr_array_index (priv->transports, idx); + g_mutex_unlock (&priv->lock); return result; } @@ -187,12 +256,16 @@ gboolean gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia * media, GstRTSPRange * range) { + GstRTSPSessionMediaPrivate *priv; + g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE); - g_mutex_lock (&media->lock); - range->min = media->counter++; - range->max = media->counter++; - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_lock (&priv->lock); + range->min = priv->counter++; + range->max = priv->counter++; + g_mutex_unlock (&priv->lock); return TRUE; } @@ -209,13 +282,64 @@ gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia * media, gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMedia * media, GstState state) { + GstRTSPSessionMediaPrivate *priv; gboolean ret; g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE); - g_mutex_lock (&media->lock); - ret = gst_rtsp_media_set_state (media->media, state, media->transports); - g_mutex_unlock (&media->lock); + priv = media->priv; + + g_mutex_lock (&priv->lock); + ret = gst_rtsp_media_set_state (priv->media, state, priv->transports); + g_mutex_unlock (&priv->lock); + + return ret; +} + +/** + * gst_rtsp_session_media_set_rtsp_state: + * @media: a #GstRTSPSessionMedia + * @state: a #GstRTSPState + * + * Set the RTSP state of @media to @state. + */ +void +gst_rtsp_session_media_set_rtsp_state (GstRTSPSessionMedia * media, + GstRTSPState state) +{ + GstRTSPSessionMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_SESSION_MEDIA (media)); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->state = state; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_session_media_set_rtsp_state: + * @media: a #GstRTSPSessionMedia + * + * Get the current RTSP state of @media. + * + * Returns: the current RTSP state of @media. + */ +GstRTSPState +gst_rtsp_session_media_get_rtsp_state (GstRTSPSessionMedia * media) +{ + GstRTSPSessionMediaPrivate *priv; + GstRTSPState ret; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), + GST_RTSP_STATE_INVALID); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + ret = priv->state; + g_mutex_unlock (&priv->lock); return ret; } diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 2156f303ba..ed5284d130 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -37,6 +37,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia; typedef struct _GstRTSPSessionMediaClass GstRTSPSessionMediaClass; +typedef struct _GstRTSPSessionMediaPrivate GstRTSPSessionMediaPrivate; /** * GstRTSPSessionMedia: @@ -53,13 +54,7 @@ struct _GstRTSPSessionMedia { GObject parent; - GMutex lock; - GstRTSPUrl *url; - GstRTSPMedia *media; - GstRTSPState state; - guint counter; - - GPtrArray *transports; + GstRTSPSessionMediaPrivate *priv; }; struct _GstRTSPSessionMediaClass @@ -71,10 +66,20 @@ GType gst_rtsp_session_media_get_type (void); GstRTSPSessionMedia * gst_rtsp_session_media_new (const GstRTSPUrl *url, GstRTSPMedia *media); + +gboolean gst_rtsp_session_media_matches_url (GstRTSPSessionMedia *media, + const GstRTSPUrl *url); +GstRTSPMedia * gst_rtsp_session_media_get_media (GstRTSPSessionMedia *media); + /* control media */ + gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media, GstState state); +void gst_rtsp_session_media_set_rtsp_state (GstRTSPSessionMedia *media, + GstRTSPState state); +GstRTSPState gst_rtsp_session_media_get_rtsp_state (GstRTSPSessionMedia *media); + /* get stream transport config */ GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia *media, GstRTSPStream *stream, diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 7a3231d237..2fe209f9b9 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -19,6 +19,17 @@ #include "rtsp-session-pool.h" +#define GST_RTSP_SESSION_POOL_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION_POOL, GstRTSPSessionPoolPrivate)) + +struct _GstRTSPSessionPoolPrivate +{ + guint max_sessions; + + GMutex lock; + GHashTable *sessions; +}; + #define DEFAULT_MAX_SESSIONS 0 enum @@ -54,6 +65,8 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) { GObjectClass *gobject_class; + g_type_class_add_private (klass, sizeof (GstRTSPSessionPoolPrivate)); + gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_session_pool_get_property; @@ -75,19 +88,24 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) static void gst_rtsp_session_pool_init (GstRTSPSessionPool * pool) { - g_mutex_init (&pool->lock); - pool->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, + GstRTSPSessionPoolPrivate *priv = GST_RTSP_SESSION_POOL_GET_PRIVATE (pool); + + pool->priv = priv; + + g_mutex_init (&priv->lock); + priv->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); - pool->max_sessions = DEFAULT_MAX_SESSIONS; + priv->max_sessions = DEFAULT_MAX_SESSIONS; } static void gst_rtsp_session_pool_finalize (GObject * object) { GstRTSPSessionPool *pool = GST_RTSP_SESSION_POOL (object); + GstRTSPSessionPoolPrivate *priv = pool->priv; - g_mutex_clear (&pool->lock); - g_hash_table_unref (pool->sessions); + g_mutex_clear (&priv->lock); + g_hash_table_unref (priv->sessions); G_OBJECT_CLASS (gst_rtsp_session_pool_parent_class)->finalize (object); } @@ -152,11 +170,15 @@ gst_rtsp_session_pool_new (void) void gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool * pool, guint max) { + GstRTSPSessionPoolPrivate *priv; + g_return_if_fail (GST_IS_RTSP_SESSION_POOL (pool)); - g_mutex_lock (&pool->lock); - pool->max_sessions = max; - g_mutex_unlock (&pool->lock); + priv = pool->priv; + + g_mutex_lock (&priv->lock); + priv->max_sessions = max; + g_mutex_unlock (&priv->lock); } /** @@ -171,13 +193,16 @@ gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool * pool, guint max) guint gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool * pool) { + GstRTSPSessionPoolPrivate *priv; guint result; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0); - g_mutex_lock (&pool->lock); - result = pool->max_sessions; - g_mutex_unlock (&pool->lock); + priv = pool->priv; + + g_mutex_lock (&priv->lock); + result = priv->max_sessions; + g_mutex_unlock (&priv->lock); return result; } @@ -193,13 +218,16 @@ gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool * pool) guint gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool * pool) { + GstRTSPSessionPoolPrivate *priv; guint result; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0); - g_mutex_lock (&pool->lock); - result = g_hash_table_size (pool->sessions); - g_mutex_unlock (&pool->lock); + priv = pool->priv; + + g_mutex_lock (&priv->lock); + result = g_hash_table_size (priv->sessions); + g_mutex_unlock (&priv->lock); return result; } @@ -218,18 +246,21 @@ gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool * pool) GstRTSPSession * gst_rtsp_session_pool_find (GstRTSPSessionPool * pool, const gchar * sessionid) { + GstRTSPSessionPoolPrivate *priv; GstRTSPSession *result; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL); g_return_val_if_fail (sessionid != NULL, NULL); - g_mutex_lock (&pool->lock); - result = g_hash_table_lookup (pool->sessions, sessionid); + priv = pool->priv; + + g_mutex_lock (&priv->lock); + result = g_hash_table_lookup (priv->sessions, sessionid); if (result) { g_object_ref (result); gst_rtsp_session_touch (result); } - g_mutex_unlock (&pool->lock); + g_mutex_unlock (&priv->lock); return result; } @@ -260,6 +291,7 @@ create_session_id (GstRTSPSessionPool * pool) GstRTSPSession * gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) { + GstRTSPSessionPoolPrivate *priv; GstRTSPSession *result = NULL; GstRTSPSessionPoolClass *klass; gchar *id = NULL; @@ -267,6 +299,8 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL); + priv = pool->priv; + klass = GST_RTSP_SESSION_POOL_GET_CLASS (pool); retry = 0; @@ -281,14 +315,14 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) if (id == NULL) goto no_session; - g_mutex_lock (&pool->lock); + g_mutex_lock (&priv->lock); /* check session limit */ - if (pool->max_sessions > 0) { - if (g_hash_table_size (pool->sessions) >= pool->max_sessions) + if (priv->max_sessions > 0) { + if (g_hash_table_size (priv->sessions) >= priv->max_sessions) goto too_many_sessions; } /* check if the sessionid existed */ - result = g_hash_table_lookup (pool->sessions, id); + result = g_hash_table_lookup (priv->sessions, id); if (result) { /* found, retry with a different session id */ result = NULL; @@ -300,9 +334,10 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) result = gst_rtsp_session_new (id); /* take additional ref for the pool */ g_object_ref (result); - g_hash_table_insert (pool->sessions, result->sessionid, result); + g_hash_table_insert (priv->sessions, + (gchar *) gst_rtsp_session_get_sessionid (result), result); } - g_mutex_unlock (&pool->lock); + g_mutex_unlock (&priv->lock); g_free (id); } while (result == NULL); @@ -323,14 +358,14 @@ no_session: collision: { GST_WARNING ("can't find unique sessionid for GstRTSPSessionPool %p", pool); - g_mutex_unlock (&pool->lock); + g_mutex_unlock (&priv->lock); g_free (id); return NULL; } too_many_sessions: { - GST_WARNING ("session pool reached max sessions of %d", pool->max_sessions); - g_mutex_unlock (&pool->lock); + GST_WARNING ("session pool reached max sessions of %d", priv->max_sessions); + g_mutex_unlock (&priv->lock); g_free (id); return NULL; } @@ -348,14 +383,19 @@ too_many_sessions: gboolean gst_rtsp_session_pool_remove (GstRTSPSessionPool * pool, GstRTSPSession * sess) { + GstRTSPSessionPoolPrivate *priv; gboolean found; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), FALSE); g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), FALSE); - g_mutex_lock (&pool->lock); - found = g_hash_table_remove (pool->sessions, sess->sessionid); - g_mutex_unlock (&pool->lock); + priv = pool->priv; + + g_mutex_lock (&priv->lock); + found = + g_hash_table_remove (priv->sessions, + gst_rtsp_session_get_sessionid (sess)); + g_mutex_unlock (&priv->lock); return found; } @@ -378,18 +418,21 @@ cleanup_func (gchar * sessionid, GstRTSPSession * sess, GTimeVal * now) guint gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool) { + GstRTSPSessionPoolPrivate *priv; guint result; GTimeVal now; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0); + priv = pool->priv; + g_get_current_time (&now); - g_mutex_lock (&pool->lock); + g_mutex_lock (&priv->lock); result = - g_hash_table_foreach_remove (pool->sessions, (GHRFunc) cleanup_func, + g_hash_table_foreach_remove (priv->sessions, (GHRFunc) cleanup_func, &now); - g_mutex_unlock (&pool->lock); + g_mutex_unlock (&priv->lock); return result; } @@ -397,7 +440,7 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool) typedef struct { GstRTSPSessionPool *pool; - GstRTSPSessionFilterFunc func; + GstRTSPSessionPoolFilterFunc func; gpointer user_data; GList *list; } FilterData; @@ -443,21 +486,24 @@ filter_func (gchar * sessionid, GstRTSPSession * sess, FilterData * data) */ GList * gst_rtsp_session_pool_filter (GstRTSPSessionPool * pool, - GstRTSPSessionFilterFunc func, gpointer user_data) + GstRTSPSessionPoolFilterFunc func, gpointer user_data) { + GstRTSPSessionPoolPrivate *priv; FilterData data; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL); g_return_val_if_fail (func != NULL, NULL); + priv = pool->priv; + data.pool = pool; data.func = func; data.user_data = user_data; data.list = NULL; - g_mutex_lock (&pool->lock); - g_hash_table_foreach_remove (pool->sessions, (GHRFunc) filter_func, &data); - g_mutex_unlock (&pool->lock); + g_mutex_lock (&priv->lock); + g_hash_table_foreach_remove (priv->sessions, (GHRFunc) filter_func, &data); + g_mutex_unlock (&priv->lock); return data.list; } @@ -489,15 +535,17 @@ collect_timeout (gchar * sessionid, GstRTSPSession * sess, GstPoolSource * psrc) static gboolean gst_pool_source_prepare (GSource * source, gint * timeout) { + GstRTSPSessionPoolPrivate *priv; GstPoolSource *psrc; gboolean result; psrc = (GstPoolSource *) source; psrc->timeout = -1; + priv = psrc->pool->priv; - g_mutex_lock (&psrc->pool->lock); - g_hash_table_foreach (psrc->pool->sessions, (GHFunc) collect_timeout, psrc); - g_mutex_unlock (&psrc->pool->lock); + g_mutex_lock (&priv->lock); + g_hash_table_foreach (priv->sessions, (GHFunc) collect_timeout, psrc); + g_mutex_unlock (&priv->lock); if (timeout) *timeout = psrc->timeout; diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index ede06ceb82..ca490de724 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -27,6 +27,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPSessionPool GstRTSPSessionPool; typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; +typedef struct _GstRTSPSessionPoolPrivate GstRTSPSessionPoolPrivate; #include "rtsp-session.h" @@ -51,10 +52,7 @@ typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass; struct _GstRTSPSessionPool { GObject parent; - guint max_sessions; - - GMutex lock; - GHashTable *sessions; + GstRTSPSessionPoolPrivate *priv; }; /** @@ -83,22 +81,7 @@ struct _GstRTSPSessionPoolClass { typedef gboolean (*GstRTSPSessionPoolFunc) (GstRTSPSessionPool *pool, gpointer user_data); /** - * GstRTSPFilterResult: - * @GST_RTSP_FILTER_REMOVE: Remove session - * @GST_RTSP_FILTER_KEEP: Keep session in the pool - * @GST_RTSP_FILTER_REF: Ref session in the result list - * - * Possible return values for gst_rtsp_session_pool_filter(). - */ -typedef enum -{ - GST_RTSP_FILTER_REMOVE, - GST_RTSP_FILTER_KEEP, - GST_RTSP_FILTER_REF, -} GstRTSPFilterResult; - -/** - * GstRTSPSessionFilterFunc: + * GstRTSPSessionPoolFilterFunc: * @pool: a #GstRTSPSessionPool object * @session: a #GstRTSPSession in @pool * @user_data: user data that has been given to gst_rtsp_session_pool_filter() @@ -117,9 +100,9 @@ typedef enum * * Returns: a #GstRTSPFilterResult. */ -typedef GstRTSPFilterResult (*GstRTSPSessionFilterFunc) (GstRTSPSessionPool *pool, - GstRTSPSession *session, - gpointer user_data); +typedef GstRTSPFilterResult (*GstRTSPSessionPoolFilterFunc) (GstRTSPSessionPool *pool, + GstRTSPSession *session, + gpointer user_data); GType gst_rtsp_session_pool_get_type (void); @@ -142,7 +125,7 @@ gboolean gst_rtsp_session_pool_remove (GstRTSPSessionPoo /* perform session maintenance */ GList * gst_rtsp_session_pool_filter (GstRTSPSessionPool *pool, - GstRTSPSessionFilterFunc func, + GstRTSPSessionPoolFilterFunc func, gpointer user_data); guint gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool); GSource * gst_rtsp_session_pool_create_watch (GstRTSPSessionPool *pool); diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 7f2202627d..f50a476140 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -20,6 +20,22 @@ #include "rtsp-session.h" +#define GST_RTSP_SESSION_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION, GstRTSPSessionPrivate)) + +struct _GstRTSPSessionPrivate +{ + GMutex lock; + gchar *sessionid; + + guint timeout; + GTimeVal create_time; + GTimeVal last_access; + gint expire_count; + + GList *medias; +}; + #undef DEBUG #define DEFAULT_TIMEOUT 60 @@ -48,6 +64,8 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass) { GObjectClass *gobject_class; + g_type_class_add_private (klass, sizeof (GstRTSPSessionPrivate)); + gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_session_get_property; @@ -71,9 +89,13 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass) static void gst_rtsp_session_init (GstRTSPSession * session) { - g_mutex_init (&session->lock); - session->timeout = DEFAULT_TIMEOUT; - g_get_current_time (&session->create_time); + GstRTSPSessionPrivate *priv = GST_RTSP_SESSION_GET_PRIVATE (session); + + session->priv = priv; + + g_mutex_init (&priv->lock); + priv->timeout = DEFAULT_TIMEOUT; + g_get_current_time (&priv->create_time); gst_rtsp_session_touch (session); } @@ -81,17 +103,19 @@ static void gst_rtsp_session_finalize (GObject * obj) { GstRTSPSession *session; + GstRTSPSessionPrivate *priv; session = GST_RTSP_SESSION (obj); + priv = session->priv; GST_INFO ("finalize session %p", session); /* free all media */ - g_list_free_full (session->medias, g_object_unref); + g_list_free_full (priv->medias, g_object_unref); /* free session id */ - g_free (session->sessionid); - g_mutex_clear (&session->lock); + g_free (priv->sessionid); + g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_session_parent_class)->finalize (obj); } @@ -101,10 +125,11 @@ gst_rtsp_session_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec) { GstRTSPSession *session = GST_RTSP_SESSION (object); + GstRTSPSessionPrivate *priv = session->priv; switch (propid) { case PROP_SESSIONID: - g_value_set_string (value, session->sessionid); + g_value_set_string (value, priv->sessionid); break; case PROP_TIMEOUT: g_value_set_uint (value, gst_rtsp_session_get_timeout (session)); @@ -119,11 +144,12 @@ gst_rtsp_session_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec) { GstRTSPSession *session = GST_RTSP_SESSION (object); + GstRTSPSessionPrivate *priv = session->priv; switch (propid) { case PROP_SESSIONID: - g_free (session->sessionid); - session->sessionid = g_value_dup_string (value); + g_free (priv->sessionid); + priv->sessionid = g_value_dup_string (value); break; case PROP_TIMEOUT: gst_rtsp_session_set_timeout (session, g_value_get_uint (value)); @@ -150,18 +176,22 @@ GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession * sess, const GstRTSPUrl * uri, GstRTSPMedia * media) { + GstRTSPSessionPrivate *priv; GstRTSPSessionMedia *result; g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); g_return_val_if_fail (uri != NULL, NULL); g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - g_return_val_if_fail (media->status == GST_RTSP_MEDIA_STATUS_PREPARED, NULL); + g_return_val_if_fail (gst_rtsp_media_get_status (media) == + GST_RTSP_MEDIA_STATUS_PREPARED, NULL); + + priv = sess->priv; result = gst_rtsp_session_media_new (uri, media); - g_mutex_lock (&sess->lock); - sess->medias = g_list_prepend (sess->medias, result); - g_mutex_unlock (&sess->lock); + g_mutex_lock (&priv->lock); + priv->medias = g_list_prepend (priv->medias, result); + g_mutex_unlock (&priv->lock); GST_INFO ("manage new media %p in session %p", media, result); @@ -181,18 +211,21 @@ gboolean gst_rtsp_session_release_media (GstRTSPSession * sess, GstRTSPSessionMedia * media) { + GstRTSPSessionPrivate *priv; GList *find; gboolean more; g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), FALSE); g_return_val_if_fail (media != NULL, FALSE); - g_mutex_lock (&sess->lock); - find = g_list_find (sess->medias, media); + priv = sess->priv; + + g_mutex_lock (&priv->lock); + find = g_list_find (priv->medias, media); if (find) - sess->medias = g_list_delete_link (sess->medias, find); - more = (sess->medias != NULL); - g_mutex_unlock (&sess->lock); + priv->medias = g_list_delete_link (priv->medias, find); + more = (priv->medias != NULL); + g_mutex_unlock (&priv->lock); if (find) g_object_unref (media); @@ -212,24 +245,87 @@ gst_rtsp_session_release_media (GstRTSPSession * sess, GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession * sess, const GstRTSPUrl * url) { + GstRTSPSessionPrivate *priv; GstRTSPSessionMedia *result; GList *walk; g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); g_return_val_if_fail (url != NULL, NULL); + priv = sess->priv; result = NULL; - g_mutex_lock (&sess->lock); - for (walk = sess->medias; walk; walk = g_list_next (walk)) { + g_mutex_lock (&priv->lock); + for (walk = priv->medias; walk; walk = g_list_next (walk)) { result = (GstRTSPSessionMedia *) walk->data; - if (g_str_equal (result->url->abspath, url->abspath)) + if (gst_rtsp_session_media_matches_url (result, url)) break; result = NULL; } - g_mutex_unlock (&sess->lock); + g_mutex_unlock (&priv->lock); + + return result; +} + +/** + * gst_rtsp_session_filter: + * @sess: a #GstRTSPSession + * @func: (scope call): a callback + * @user_data: user data passed to @func + * + * Call @func for each media in @sess. The result value of @func determines + * what happens to the media. @func will be called with @sess + * locked so no further actions on @sess can be performed from @func. + * + * If @func returns #GST_RTSP_FILTER_REMOVE, the media will be removed from + * @sess. + * + * If @func returns #GST_RTSP_FILTER_KEEP, the media will remain in @sess. + * + * If @func returns #GST_RTSP_FILTER_REF, the media will remain in @sess but + * will also be added with an additional ref to the result #GList of this + * function.. + * + * Returns: (element-type GstRTSPSessionMedia) (transfer full): a GList with all + * media for which @func returned #GST_RTSP_FILTER_REF. After usage, each + * element in the #GList should be unreffed before the list is freed. + */ +GList * +gst_rtsp_session_filter (GstRTSPSession * sess, + GstRTSPSessionFilterFunc func, gpointer user_data) +{ + GstRTSPSessionPrivate *priv; + GList *result, *walk, *next; + + g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); + g_return_val_if_fail (func != NULL, NULL); + + priv = sess->priv; + + result = NULL; + + g_mutex_lock (&priv->lock); + for (walk = priv->medias; walk; walk = next) { + GstRTSPSessionMedia *media = walk->data; + + next = g_list_next (walk); + + switch (func (sess, media, user_data)) { + case GST_RTSP_FILTER_REMOVE: + g_object_unref (media); + priv->medias = g_list_delete_link (priv->medias, walk); + break; + case GST_RTSP_FILTER_REF: + result = g_list_prepend (result, g_object_ref (media)); + break; + case GST_RTSP_FILTER_KEEP: + default: + break; + } + } + g_mutex_unlock (&priv->lock); return result; } @@ -266,7 +362,7 @@ gst_rtsp_session_get_sessionid (GstRTSPSession * session) { g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL); - return session->sessionid; + return session->priv->sessionid; } /** @@ -280,17 +376,19 @@ gst_rtsp_session_get_sessionid (GstRTSPSession * session) gchar * gst_rtsp_session_get_header (GstRTSPSession * session) { + GstRTSPSessionPrivate *priv; gchar *result; g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL); - g_mutex_lock (&session->lock); - if (session->timeout != 60) - result = g_strdup_printf ("%s; timeout=%d", session->sessionid, - session->timeout); + priv = session->priv; + + g_mutex_lock (&priv->lock); + if (priv->timeout != 60) + result = g_strdup_printf ("%s; timeout=%d", priv->sessionid, priv->timeout); else - result = g_strdup (session->sessionid); - g_mutex_unlock (&session->lock); + result = g_strdup (priv->sessionid); + g_mutex_unlock (&priv->lock); return result; } @@ -306,11 +404,15 @@ gst_rtsp_session_get_header (GstRTSPSession * session) void gst_rtsp_session_set_timeout (GstRTSPSession * session, guint timeout) { + GstRTSPSessionPrivate *priv; + g_return_if_fail (GST_IS_RTSP_SESSION (session)); - g_mutex_lock (&session->lock); - session->timeout = timeout; - g_mutex_unlock (&session->lock); + priv = session->priv; + + g_mutex_lock (&priv->lock); + priv->timeout = timeout; + g_mutex_unlock (&priv->lock); } /** @@ -324,13 +426,16 @@ gst_rtsp_session_set_timeout (GstRTSPSession * session, guint timeout) guint gst_rtsp_session_get_timeout (GstRTSPSession * session) { + GstRTSPSessionPrivate *priv; guint res; g_return_val_if_fail (GST_IS_RTSP_SESSION (session), 0); - g_mutex_lock (&session->lock); - res = session->timeout; - g_mutex_unlock (&session->lock); + priv = session->priv; + + g_mutex_lock (&priv->lock); + res = priv->timeout; + g_mutex_unlock (&priv->lock); return res; } @@ -344,11 +449,15 @@ gst_rtsp_session_get_timeout (GstRTSPSession * session) void gst_rtsp_session_touch (GstRTSPSession * session) { + GstRTSPSessionPrivate *priv; + g_return_if_fail (GST_IS_RTSP_SESSION (session)); - g_mutex_lock (&session->lock); - g_get_current_time (&session->last_access); - g_mutex_unlock (&session->lock); + priv = session->priv; + + g_mutex_lock (&priv->lock); + g_get_current_time (&priv->last_access); + g_mutex_unlock (&priv->lock); } /** @@ -362,7 +471,7 @@ gst_rtsp_session_prevent_expire (GstRTSPSession * session) { g_return_if_fail (GST_IS_RTSP_SESSION (session)); - g_atomic_int_add (&session->expire_count, 1); + g_atomic_int_add (&session->priv->expire_count, 1); } /** @@ -375,7 +484,7 @@ gst_rtsp_session_prevent_expire (GstRTSPSession * session) void gst_rtsp_session_allow_expire (GstRTSPSession * session) { - g_atomic_int_add (&session->expire_count, -1); + g_atomic_int_add (&session->priv->expire_count, -1); } /** @@ -390,22 +499,25 @@ gst_rtsp_session_allow_expire (GstRTSPSession * session) gint gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) { + GstRTSPSessionPrivate *priv; gint res; GstClockTime last_access, now_ns; g_return_val_if_fail (GST_IS_RTSP_SESSION (session), -1); g_return_val_if_fail (now != NULL, -1); - g_mutex_lock (&session->lock); - if (g_atomic_int_get (&session->expire_count) != 0) { + priv = session->priv; + + g_mutex_lock (&priv->lock); + if (g_atomic_int_get (&priv->expire_count) != 0) { /* touch session when the expire count is not 0 */ - g_get_current_time (&session->last_access); + g_get_current_time (&priv->last_access); } - last_access = GST_TIMEVAL_TO_TIME (session->last_access); + last_access = GST_TIMEVAL_TO_TIME (priv->last_access); /* add timeout allow for 5 seconds of extra time */ - last_access += session->timeout * GST_SECOND + (5 * GST_SECOND); - g_mutex_unlock (&session->lock); + last_access += priv->timeout * GST_SECOND + (5 * GST_SECOND); + g_mutex_unlock (&priv->lock); now_ns = GST_TIMEVAL_TO_TIME (*now); diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index f5c4fcd87f..844795d27f 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -37,19 +37,28 @@ G_BEGIN_DECLS typedef struct _GstRTSPSession GstRTSPSession; typedef struct _GstRTSPSessionClass GstRTSPSessionClass; +typedef struct _GstRTSPSessionPrivate GstRTSPSessionPrivate; + +/** + * GstRTSPFilterResult: + * @GST_RTSP_FILTER_REMOVE: Remove session + * @GST_RTSP_FILTER_KEEP: Keep session in the pool + * @GST_RTSP_FILTER_REF: Ref session in the result list + * + * Possible return values for gst_rtsp_session_pool_filter(). + */ +typedef enum +{ + GST_RTSP_FILTER_REMOVE, + GST_RTSP_FILTER_KEEP, + GST_RTSP_FILTER_REF, +} GstRTSPFilterResult; #include "rtsp-media.h" #include "rtsp-session-media.h" /** * GstRTSPSession: - * @parent: the parent GObject - * @sessionid: the session id of the session - * @timeout: the timeout of the session - * @create_time: the time when the session was created - * @last_access: the time the session was last accessed - * @expire_count: the expire prevention counter - * @medias: a list of #GstRTSPSessionMedia managed in this session * * Session information kept by the server for a specific client. * One client session, identified with a session id, can handle multiple medias @@ -58,15 +67,7 @@ typedef struct _GstRTSPSessionClass GstRTSPSessionClass; struct _GstRTSPSession { GObject parent; - GMutex lock; - gchar *sessionid; - - guint timeout; - GTimeVal create_time; - GTimeVal last_access; - gint expire_count; - - GList *medias; + GstRTSPSessionPrivate *priv; }; struct _GstRTSPSessionClass { @@ -102,6 +103,35 @@ gboolean gst_rtsp_session_release_media (GstRTSPSession *se GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *url); +/** + * GstRTSPSessionFilterFunc: + * @sess: a #GstRTSPSession object + * @media: a #GstRTSPSessionMedia in @sess + * @user_data: user data that has been given to gst_rtsp_session_filter() + * + * This function will be called by the gst_rtsp_session_filter(). An + * implementation should return a value of #GstRTSPFilterResult. + * + * When this function returns #GST_RTSP_FILTER_REMOVE, @media will be removed + * from @sess. + * + * A return value of #GST_RTSP_FILTER_KEEP will leave @media untouched in + * @sess. + * + * A value of GST_RTSP_FILTER_REF will add @media to the result #GList of + * gst_rtsp_session_filter(). + * + * Returns: a #GstRTSPFilterResult. + */ +typedef GstRTSPFilterResult (*GstRTSPSessionFilterFunc) (GstRTSPSession *sess, + GstRTSPSessionMedia *media, + gpointer user_data); + +GList * gst_rtsp_session_filter (GstRTSPSession *sess, + GstRTSPSessionFilterFunc func, + gpointer user_data); + + G_END_DECLS #endif /* __GST_RTSP_SESSION_H__ */ diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 6df8d4d8e3..0859573d81 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -20,11 +20,31 @@ #include #include -#include -#include - #include "rtsp-stream-transport.h" +#define GST_RTSP_STREAM_TRANSPORT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_STREAM_TRANSPORT, GstRTSPStreamTransportPrivate)) + +struct _GstRTSPStreamTransportPrivate +{ + GstRTSPStream *stream; + + GstRTSPSendFunc send_rtp; + GstRTSPSendFunc send_rtcp; + gpointer user_data; + GDestroyNotify notify; + + GstRTSPKeepAliveFunc keep_alive; + gpointer ka_user_data; + GDestroyNotify ka_notify; + gboolean active; + gboolean timed_out; + + GstRTSPTransport *transport; + + GObject *rtpsource; +}; + enum { PROP_0, @@ -44,6 +64,8 @@ gst_rtsp_stream_transport_class_init (GstRTSPStreamTransportClass * klass) { GObjectClass *gobject_class; + g_type_class_add_private (klass, sizeof (GstRTSPStreamTransportPrivate)); + gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gst_rtsp_stream_transport_finalize; @@ -55,25 +77,31 @@ gst_rtsp_stream_transport_class_init (GstRTSPStreamTransportClass * klass) static void gst_rtsp_stream_transport_init (GstRTSPStreamTransport * trans) { + GstRTSPStreamTransportPrivate *priv = + GST_RTSP_STREAM_TRANSPORT_GET_PRIVATE (trans); + + trans->priv = priv; } static void gst_rtsp_stream_transport_finalize (GObject * obj) { + GstRTSPStreamTransportPrivate *priv; GstRTSPStreamTransport *trans; trans = GST_RTSP_STREAM_TRANSPORT (obj); + priv = trans->priv; /* remove callbacks now */ gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL); gst_rtsp_stream_transport_set_keepalive (trans, NULL, NULL, NULL); - if (trans->transport) - gst_rtsp_transport_free (trans->transport); + if (priv->transport) + gst_rtsp_transport_free (priv->transport); #if 0 - if (trans->rtpsource) - g_object_set_qdata (trans->rtpsource, ssrc_stream_map_key, NULL); + if (priv->rtpsource) + g_object_set_qdata (priv->rtpsource, ssrc_stream_map_key, NULL); #endif G_OBJECT_CLASS (gst_rtsp_stream_transport_parent_class)->finalize (obj); @@ -92,18 +120,36 @@ gst_rtsp_stream_transport_finalize (GObject * obj) GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr) { + GstRTSPStreamTransportPrivate *priv; GstRTSPStreamTransport *trans; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); g_return_val_if_fail (tr != NULL, NULL); trans = g_object_new (GST_TYPE_RTSP_STREAM_TRANSPORT, NULL); - trans->stream = stream; - trans->transport = tr; + priv = trans->priv; + priv->stream = stream; + priv->transport = tr; return trans; } +/** + * gst_rtsp_stream_transport_get_stream: + * @trans: a #GstRTSPStreamTransport + * + * Get the #GstRTSPStream used when constructing @trans. + * + * Returns: (transfer none): the stream used when constructing @trans. + */ +GstRTSPStream * +gst_rtsp_stream_transport_get_stream (GstRTSPStreamTransport * trans) +{ + g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL); + + return trans->priv->stream; +} + /** * gst_rtsp_stream_transport_set_callbacks: * @trans: a #GstRTSPStreamTransport @@ -120,12 +166,18 @@ gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport * trans, GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, gpointer user_data, GDestroyNotify notify) { - trans->send_rtp = send_rtp; - trans->send_rtcp = send_rtcp; - if (trans->notify) - trans->notify (trans->user_data); - trans->user_data = user_data; - trans->notify = notify; + GstRTSPStreamTransportPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); + + priv = trans->priv; + + priv->send_rtp = send_rtp; + priv->send_rtcp = send_rtcp; + if (priv->notify) + priv->notify (priv->user_data); + priv->user_data = user_data; + priv->notify = notify; } /** @@ -142,11 +194,17 @@ void gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans, GstRTSPKeepAliveFunc keep_alive, gpointer user_data, GDestroyNotify notify) { - trans->keep_alive = keep_alive; - if (trans->ka_notify) - trans->ka_notify (trans->ka_user_data); - trans->ka_user_data = user_data; - trans->ka_notify = notify; + GstRTSPStreamTransportPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); + + priv = trans->priv; + + priv->keep_alive = keep_alive; + if (priv->ka_notify) + priv->ka_notify (priv->ka_user_data); + priv->ka_user_data = user_data; + priv->ka_notify = notify; } @@ -162,13 +220,100 @@ void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans, GstRTSPTransport * tr) { + GstRTSPStreamTransportPrivate *priv; + g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); g_return_if_fail (tr != NULL); + priv = trans->priv; + /* keep track of the transports in the stream. */ - if (trans->transport) - gst_rtsp_transport_free (trans->transport); - trans->transport = tr; + if (priv->transport) + gst_rtsp_transport_free (priv->transport); + priv->transport = tr; +} + +/** + * gst_rtsp_stream_transport_get_transport: + * @trans: a #GstRTSPStreamTransport + * + * Get the transport configured in @trans. + * + * Returns: (transfer none): the transport configured in @trans. It remains + * valid for as long as @trans is valid. + */ +const GstRTSPTransport * +gst_rtsp_stream_transport_get_transport (GstRTSPStreamTransport * trans) +{ + g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL); + + return trans->priv->transport; +} + +/** + * gst_rtsp_stream_transport_set_active: + * @trans: a #GstRTSPStreamTransport + * @active: new state of @trans + * + * Activate or deactivate datatransfer configured in @trans. + * + * Returns: %TRUE when the state was changed. + */ +gboolean +gst_rtsp_stream_transport_set_active (GstRTSPStreamTransport * trans, + gboolean active) +{ + GstRTSPStreamTransportPrivate *priv; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE); + + priv = trans->priv; + + if (priv->active == active) + return FALSE; + + if (active) + res = gst_rtsp_stream_add_transport (priv->stream, trans); + else + res = gst_rtsp_stream_remove_transport (priv->stream, trans); + + if (res) + priv->active = active; + + return res; +} + +/** + * gst_rtsp_stream_transport_set_timed_out: + * @trans: a #GstRTSPStreamTransport + * @timedout: timed out value + * + * Set the timed out state of @trans to @timedout + */ +void +gst_rtsp_stream_transport_set_timed_out (GstRTSPStreamTransport * trans, + gboolean timedout) +{ + g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); + + trans->priv->timed_out = timedout; +} + +/** + * gst_rtsp_stream_transport_is_timed_out: + * @trans: a #GstRTSPStreamTransport + * + * Check if @trans is timed out. + * + * Returns: %TRUE if @trans timed out. + */ +gboolean +gst_rtsp_stream_transport_is_timed_out (GstRTSPStreamTransport * trans) +{ + g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE); + + return trans->priv->timed_out; } /** @@ -184,12 +329,15 @@ gboolean gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport * trans, GstBuffer * buffer) { + GstRTSPStreamTransportPrivate *priv; gboolean res = FALSE; - if (trans->send_rtp) + priv = trans->priv; + + if (priv->send_rtp) res = - trans->send_rtp (buffer, trans->transport->interleaved.min, - trans->user_data); + priv->send_rtp (buffer, priv->transport->interleaved.min, + priv->user_data); return res; } @@ -207,12 +355,15 @@ gboolean gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport * trans, GstBuffer * buffer) { + GstRTSPStreamTransportPrivate *priv; gboolean res = FALSE; - if (trans->send_rtcp) + priv = trans->priv; + + if (priv->send_rtcp) res = - trans->send_rtcp (buffer, trans->transport->interleaved.max, - trans->user_data); + priv->send_rtcp (buffer, priv->transport->interleaved.max, + priv->user_data); return res; } @@ -226,6 +377,10 @@ gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport * trans, void gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport * trans) { - if (trans->keep_alive) - trans->keep_alive (trans->ka_user_data); + GstRTSPStreamTransportPrivate *priv; + + priv = trans->priv; + + if (priv->keep_alive) + priv->keep_alive (priv->ka_user_data); } diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 8839267cd1..ed69faa632 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -38,9 +38,9 @@ G_BEGIN_DECLS typedef struct _GstRTSPStreamTransport GstRTSPStreamTransport; typedef struct _GstRTSPStreamTransportClass GstRTSPStreamTransportClass; +typedef struct _GstRTSPStreamTransportPrivate GstRTSPStreamTransportPrivate; #include "rtsp-stream.h" -#include "rtsp-address-pool.h" typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); @@ -48,41 +48,13 @@ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); /** * GstRTSPStreamTransport: * @parent: parent instance - * @stream: the GstRTSPStream we manage - * @send_rtp: callback for sending RTP messages - * @send_rtcp: callback for sending RTCP messages - * @user_data: user data passed in the callbacks - * @notify: free function for the user_data. - * @keep_alive: keep alive callback - * @ka_user_data: data passed to @keep_alive - * @ka_notify: called when @ka_user_data is freed - * @active: if we are actively sending - * @timeout: if we timed out - * @transport: a transport description - * @addr: an optional address - * @rtpsource: the receiver rtp source object * - * A Transport description for stream @idx + * A Transport description for a stream */ struct _GstRTSPStreamTransport { GObject parent; - GstRTSPStream *stream; - - GstRTSPSendFunc send_rtp; - GstRTSPSendFunc send_rtcp; - gpointer user_data; - GDestroyNotify notify; - - GstRTSPKeepAliveFunc keep_alive; - gpointer ka_user_data; - GDestroyNotify ka_notify; - gboolean active; - gboolean timeout; - - GstRTSPTransport *transport; - - GObject *rtpsource; + GstRTSPStreamTransportPrivate *priv; }; struct _GstRTSPStreamTransportClass { @@ -94,8 +66,11 @@ GType gst_rtsp_stream_transport_get_type (void); GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream, GstRTSPTransport *tr); +GstRTSPStream * gst_rtsp_stream_transport_get_stream (GstRTSPStreamTransport *trans); + void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans, GstRTSPTransport * tr); +const GstRTSPTransport * gst_rtsp_stream_transport_get_transport (GstRTSPStreamTransport *trans); void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans, GstRTSPSendFunc send_rtp, @@ -107,6 +82,15 @@ void gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamT gpointer user_data, GDestroyNotify notify); +gboolean gst_rtsp_stream_transport_set_active (GstRTSPStreamTransport *trans, + gboolean active); + +void gst_rtsp_stream_transport_set_timed_out (GstRTSPStreamTransport *trans, + gboolean timedout); +gboolean gst_rtsp_stream_transport_is_timed_out (GstRTSPStreamTransport *trans); + + + gboolean gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport *trans, GstBuffer *buffer); gboolean gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport *trans, diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 6e35d8f84f..d1776e8e60 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -27,6 +27,56 @@ #include "rtsp-stream.h" +#define GST_RTSP_STREAM_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_STREAM, GstRTSPStreamPrivate)) + +struct _GstRTSPStreamPrivate +{ + GMutex lock; + guint idx; + GstPad *srcpad; + GstElement *payloader; + gboolean is_ipv6; + guint buffer_size; + gboolean is_joined; + + /* pads on the rtpbin */ + GstPad *send_rtp_sink; + GstPad *recv_sink[2]; + GstPad *send_src[2]; + + /* the RTPSession object */ + GObject *session; + + /* sinks used for sending and receiving RTP and RTCP, they share + * sockets */ + GstElement *udpsrc[2]; + GstElement *udpsink[2]; + /* for TCP transport */ + GstElement *appsrc[2]; + GstElement *appqueue[2]; + GstElement *appsink[2]; + + GstElement *tee[2]; + GstElement *funnel[2]; + + /* server ports for sending/receiving */ + GstRTSPRange server_port; + + /* multicast addresses */ + GstRTSPAddressPool *pool; + GstRTSPAddress *addr; + + /* the caps of the stream */ + gulong caps_sig; + GstCaps *caps; + + /* transports we stream to */ + guint n_active; + GList *transports; +}; + + enum { PROP_0, @@ -47,6 +97,8 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) { GObjectClass *gobject_class; + g_type_class_add_private (klass, sizeof (GstRTSPStreamPrivate)); + gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gst_rtsp_stream_finalize; @@ -59,30 +111,36 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) static void gst_rtsp_stream_init (GstRTSPStream * stream) { + GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); + GST_DEBUG ("new stream %p", stream); - g_mutex_init (&stream->lock); + stream->priv = priv; + + g_mutex_init (&priv->lock); } static void gst_rtsp_stream_finalize (GObject * obj) { GstRTSPStream *stream; + GstRTSPStreamPrivate *priv; stream = GST_RTSP_STREAM (obj); + priv = stream->priv; GST_DEBUG ("finalize stream %p", stream); /* we really need to be unjoined now */ - g_return_if_fail (!stream->is_joined); + g_return_if_fail (!priv->is_joined); - if (stream->addr) - gst_rtsp_address_free (stream->addr); - if (stream->pool) - g_object_unref (stream->pool); - gst_object_unref (stream->payloader); - gst_object_unref (stream->srcpad); - g_mutex_clear (&stream->lock); + if (priv->addr) + gst_rtsp_address_free (priv->addr); + if (priv->pool) + g_object_unref (priv->pool); + gst_object_unref (priv->payloader); + gst_object_unref (priv->srcpad); + g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); } @@ -101,6 +159,7 @@ gst_rtsp_stream_finalize (GObject * obj) GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad) { + GstRTSPStreamPrivate *priv; GstRTSPStream *stream; g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL); @@ -108,13 +167,30 @@ gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad) g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), NULL); stream = g_object_new (GST_TYPE_RTSP_STREAM, NULL); - stream->idx = idx; - stream->payloader = gst_object_ref (payloader); - stream->srcpad = gst_object_ref (srcpad); + priv = stream->priv; + priv->idx = idx; + priv->payloader = gst_object_ref (payloader); + priv->srcpad = gst_object_ref (srcpad); return stream; } +/** + * gst_rtsp_stream_get_index: + * @stream: a #GstRTSPStream + * + * Get the stream index. + * + * Return: the stream index. + */ +guint +gst_rtsp_stream_get_index (GstRTSPStream * stream) +{ + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), -1); + + return stream->priv->idx; +} + /** * gst_rtsp_stream_set_mtu: * @stream: a #GstRTSPStream @@ -125,11 +201,15 @@ gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad) void gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guint mtu) { + GstRTSPStreamPrivate *priv; + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + priv = stream->priv; + GST_LOG_OBJECT (stream, "set MTU %u", mtu); - g_object_set (G_OBJECT (stream->payloader), "mtu", mtu, NULL); + g_object_set (G_OBJECT (priv->payloader), "mtu", mtu, NULL); } /** @@ -143,11 +223,14 @@ gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guint mtu) guint gst_rtsp_stream_get_mtu (GstRTSPStream * stream) { + GstRTSPStreamPrivate *priv; guint mtu; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), 0); - g_object_get (G_OBJECT (stream->payloader), "mtu", &mtu, NULL); + priv = stream->priv; + + g_object_get (G_OBJECT (priv->payloader), "mtu", &mtu, NULL); return mtu; } @@ -163,18 +246,21 @@ void gst_rtsp_stream_set_address_pool (GstRTSPStream * stream, GstRTSPAddressPool * pool) { + GstRTSPStreamPrivate *priv; GstRTSPAddressPool *old; g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + priv = stream->priv; + GST_LOG_OBJECT (stream, "set address pool %p", pool); - g_mutex_lock (&stream->lock); - if ((old = stream->pool) != pool) - stream->pool = pool ? g_object_ref (pool) : NULL; + g_mutex_lock (&priv->lock); + if ((old = priv->pool) != pool) + priv->pool = pool ? g_object_ref (pool) : NULL; else old = NULL; - g_mutex_unlock (&stream->lock); + g_mutex_unlock (&priv->lock); if (old) g_object_unref (old); @@ -192,14 +278,17 @@ gst_rtsp_stream_set_address_pool (GstRTSPStream * stream, GstRTSPAddressPool * gst_rtsp_stream_get_address_pool (GstRTSPStream * stream) { + GstRTSPStreamPrivate *priv; GstRTSPAddressPool *result; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); - g_mutex_lock (&stream->lock); - if ((result = stream->pool)) + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->pool)) g_object_ref (result); - g_mutex_unlock (&stream->lock); + g_mutex_unlock (&priv->lock); return result; } @@ -216,20 +305,25 @@ gst_rtsp_stream_get_address_pool (GstRTSPStream * stream) GstRTSPAddress * gst_rtsp_stream_get_address (GstRTSPStream * stream) { + GstRTSPStreamPrivate *priv; GstRTSPAddress *result; - g_mutex_lock (&stream->lock); - if (stream->addr == NULL) { - if (stream->pool == NULL) + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if (priv->addr == NULL) { + if (priv->pool == NULL) goto no_pool; - stream->addr = gst_rtsp_address_pool_acquire_address (stream->pool, + priv->addr = gst_rtsp_address_pool_acquire_address (priv->pool, GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); - if (stream->addr == NULL) + if (priv->addr == NULL) goto no_address; } - result = gst_rtsp_address_copy (stream->addr); - g_mutex_unlock (&stream->lock); + result = gst_rtsp_address_copy (priv->addr); + g_mutex_unlock (&priv->lock); return result; @@ -237,13 +331,13 @@ gst_rtsp_stream_get_address (GstRTSPStream * stream) no_pool: { GST_ERROR_OBJECT (stream, "no address pool specified"); - g_mutex_unlock (&stream->lock); + g_mutex_unlock (&priv->lock); return NULL; } no_address: { GST_ERROR_OBJECT (stream, "failed to acquire address from pool"); - g_mutex_unlock (&stream->lock); + g_mutex_unlock (&priv->lock); return NULL; } } @@ -252,6 +346,7 @@ no_address: static gboolean alloc_ports (GstRTSPStream * stream) { + GstRTSPStreamPrivate *priv = stream->priv; GstStateChangeReturn ret; GstElement *udpsrc0, *udpsrc1; GstElement *udpsink0, *udpsink1; @@ -261,8 +356,6 @@ alloc_ports (GstRTSPStream * stream) GSocket *socket; const gchar *host; - g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); - udpsrc0 = NULL; udpsrc1 = NULL; udpsink0 = NULL; @@ -272,7 +365,7 @@ alloc_ports (GstRTSPStream * stream) /* Start with random port */ tmp_rtp = 0; - if (stream->is_ipv6) + if (priv->is_ipv6) host = "udp://[::0]"; else host = "udp://0.0.0.0"; @@ -372,8 +465,7 @@ again: if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), "buffer-size")) { - g_object_set (G_OBJECT (udpsink0), "buffer-size", stream->buffer_size, - NULL); + g_object_set (G_OBJECT (udpsink0), "buffer-size", priv->buffer_size, NULL); } else { GST_WARNING ("multiudpsink version found without buffer-size property"); } @@ -391,12 +483,12 @@ again: /* we keep these elements, we will further configure them when the * client told us to really use the UDP ports. */ - stream->udpsrc[0] = udpsrc0; - stream->udpsrc[1] = udpsrc1; - stream->udpsink[0] = udpsink0; - stream->udpsink[1] = udpsink1; - stream->server_port.min = rtpport; - stream->server_port.max = rtcpport; + priv->udpsrc[0] = udpsrc0; + priv->udpsrc[1] = udpsrc1; + priv->udpsink[0] = udpsink0; + priv->udpsink[1] = udpsink1; + priv->server_port.min = rtpport; + priv->server_port.max = rtcpport; return TRUE; @@ -439,10 +531,58 @@ cleanup: } } +/** + * gst_rtsp_stream_get_server_port: + * @stream: a #GstRTSPStream + * @server_port: (out): result server port + * + * Fill @server_port with the port pair used by the server. This function can + * only be called when @stream has been joined. + */ +void +gst_rtsp_stream_get_server_port (GstRTSPStream * stream, + GstRTSPRange * server_port) +{ + GstRTSPStreamPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + priv = stream->priv; + g_return_if_fail (priv->is_joined); + + g_mutex_lock (&priv->lock); + if (server_port) + *server_port = priv->server_port; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_stream_get_ssrc: + * @stream: a #GstRTSPStream + * @ssrc: (out): result ssrc + * + * Get the SSRC used by the RTP session of this stream. This function can only + * be called when @stream has been joined. + */ +void +gst_rtsp_stream_get_ssrc (GstRTSPStream * stream, guint * ssrc) +{ + GstRTSPStreamPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + priv = stream->priv; + g_return_if_fail (priv->is_joined); + + g_mutex_lock (&priv->lock); + if (ssrc && priv->session) + g_object_get (priv->session, "internal-ssrc", ssrc, NULL); + g_mutex_unlock (&priv->lock); +} + /* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) { + GstRTSPStreamPrivate *priv = stream->priv; GstCaps *newcaps, *oldcaps; newcaps = gst_pad_get_current_caps (pad); @@ -450,10 +590,10 @@ caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) GST_INFO ("stream %p received caps %p, %" GST_PTR_FORMAT, stream, newcaps, newcaps); - g_mutex_lock (&stream->lock); - oldcaps = stream->caps; - stream->caps = newcaps; - g_mutex_unlock (&stream->lock); + g_mutex_lock (&priv->lock); + oldcaps = priv->caps; + priv->caps = newcaps; + g_mutex_unlock (&priv->lock); if (oldcaps) gst_caps_unref (oldcaps); @@ -472,6 +612,7 @@ dump_structure (const GstStructure * s) static GstRTSPStreamTransport * find_transport (GstRTSPStream * stream, const gchar * rtcp_from) { + GstRTSPStreamPrivate *priv = stream->priv; GList *walk; GstRTSPStreamTransport *result = NULL; const gchar *tmp; @@ -488,24 +629,26 @@ find_transport (GstRTSPStream * stream, const gchar * rtcp_from) port = atoi (tmp + 1); dest = g_strndup (rtcp_from, tmp - rtcp_from); - g_mutex_lock (&stream->lock); + g_mutex_lock (&priv->lock); GST_INFO ("finding %s:%d in %d transports", dest, port, - g_list_length (stream->transports)); + g_list_length (priv->transports)); - for (walk = stream->transports; walk; walk = g_list_next (walk)) { + for (walk = priv->transports; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *trans = walk->data; + const GstRTSPTransport *tr; gint min, max; - min = trans->transport->client_port.min; - max = trans->transport->client_port.max; + tr = gst_rtsp_stream_transport_get_transport (trans); - if ((strcmp (trans->transport->destination, dest) == 0) && (min == port - || max == port)) { + min = tr->client_port.min; + max = tr->client_port.max; + + if ((strcmp (tr->destination, dest) == 0) && (min == port || max == port)) { result = trans; break; } } - g_mutex_unlock (&stream->lock); + g_mutex_unlock (&priv->lock); g_free (dest); @@ -531,16 +674,11 @@ check_transport (GObject * source, GstRTSPStream * stream) if ((trans = find_transport (stream, rtcp_from))) { GST_INFO ("%p: found transport %p for source %p", stream, trans, source); - - /* keep ref to the source */ - trans->rtpsource = source; - g_object_set_qdata (source, ssrc_stream_map_key, trans); } gst_structure_free (stats); } } - return trans; } @@ -601,8 +739,7 @@ on_bye_timeout (GObject * session, GObject * source, GstRTSPStream * stream) GST_INFO ("%p: source %p bye timeout", stream, source); if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) { - trans->rtpsource = NULL; - trans->timeout = TRUE; + gst_rtsp_stream_transport_set_timed_out (trans, TRUE); } } @@ -614,14 +751,14 @@ on_timeout (GObject * session, GObject * source, GstRTSPStream * stream) GST_INFO ("%p: source %p timeout", stream, source); if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) { - trans->rtpsource = NULL; - trans->timeout = TRUE; + gst_rtsp_stream_transport_set_timed_out (trans, TRUE); } } static GstFlowReturn handle_new_sample (GstAppSink * sink, gpointer user_data) { + GstRTSPStreamPrivate *priv; GList *walk; GstSample *sample; GstBuffer *buffer; @@ -632,19 +769,20 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) return GST_FLOW_OK; stream = (GstRTSPStream *) user_data; + priv = stream->priv; buffer = gst_sample_get_buffer (sample); - g_mutex_lock (&stream->lock); - for (walk = stream->transports; walk; walk = g_list_next (walk)) { + g_mutex_lock (&priv->lock); + for (walk = priv->transports; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) { + if (GST_ELEMENT_CAST (sink) == priv->appsink[0]) { gst_rtsp_stream_transport_send_rtp (tr, buffer); } else { gst_rtsp_stream_transport_send_rtcp (tr, buffer); } } - g_mutex_unlock (&stream->lock); + g_mutex_unlock (&priv->lock); gst_sample_unref (sample); @@ -675,6 +813,7 @@ gboolean gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, GstElement * rtpbin, GstState state) { + GstRTSPStreamPrivate *priv; gint i, idx; gchar *name; GstPad *pad, *teepad, *queuepad, *selpad; @@ -684,12 +823,14 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, g_return_val_if_fail (GST_IS_BIN (bin), FALSE); g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE); - g_mutex_lock (&stream->lock); - if (stream->is_joined) + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if (priv->is_joined) goto was_joined; /* create a session with the same index as the stream */ - idx = stream->idx; + idx = priv->idx; GST_INFO ("stream %p joining bin as session %d", stream, idx); @@ -698,43 +839,43 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, /* get a pad for sending RTP */ name = g_strdup_printf ("send_rtp_sink_%u", idx); - stream->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); + priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); g_free (name); /* link the RTP pad to the session manager, it should not really fail unless * this is not really an RTP pad */ - ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink); + ret = gst_pad_link (priv->srcpad, priv->send_rtp_sink); if (ret != GST_PAD_LINK_OK) goto link_failed; /* get pads from the RTP session element for sending and receiving * RTP/RTCP*/ name = g_strdup_printf ("send_rtp_src_%u", idx); - stream->send_src[0] = gst_element_get_static_pad (rtpbin, name); + priv->send_src[0] = gst_element_get_static_pad (rtpbin, name); g_free (name); name = g_strdup_printf ("send_rtcp_src_%u", idx); - stream->send_src[1] = gst_element_get_request_pad (rtpbin, name); + priv->send_src[1] = gst_element_get_request_pad (rtpbin, name); g_free (name); name = g_strdup_printf ("recv_rtp_sink_%u", idx); - stream->recv_sink[0] = gst_element_get_request_pad (rtpbin, name); + priv->recv_sink[0] = gst_element_get_request_pad (rtpbin, name); g_free (name); name = g_strdup_printf ("recv_rtcp_sink_%u", idx); - stream->recv_sink[1] = gst_element_get_request_pad (rtpbin, name); + priv->recv_sink[1] = gst_element_get_request_pad (rtpbin, name); g_free (name); /* get the session */ - g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &stream->session); + g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &priv->session); - g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc, + g_signal_connect (priv->session, "on-new-ssrc", (GCallback) on_new_ssrc, stream); - g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes, + g_signal_connect (priv->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes, stream); - g_signal_connect (stream->session, "on-ssrc-active", + g_signal_connect (priv->session, "on-ssrc-active", (GCallback) on_ssrc_active, stream); - g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, + g_signal_connect (priv->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, stream); - g_signal_connect (stream->session, "on-bye-timeout", + g_signal_connect (priv->session, "on-bye-timeout", (GCallback) on_bye_timeout, stream); - g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout, + g_signal_connect (priv->session, "on-timeout", (GCallback) on_timeout, stream); for (i = 0; i < 2; i++) { @@ -754,44 +895,44 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, * '-----' '---------' '---------' */ /* make tee for RTP/RTCP */ - stream->tee[i] = gst_element_factory_make ("tee", NULL); - gst_bin_add (bin, stream->tee[i]); + priv->tee[i] = gst_element_factory_make ("tee", NULL); + gst_bin_add (bin, priv->tee[i]); /* and link to rtpbin send pad */ - pad = gst_element_get_static_pad (stream->tee[i], "sink"); - gst_pad_link (stream->send_src[i], pad); + pad = gst_element_get_static_pad (priv->tee[i], "sink"); + gst_pad_link (priv->send_src[i], pad); gst_object_unref (pad); /* add udpsink */ - gst_bin_add (bin, stream->udpsink[i]); + gst_bin_add (bin, priv->udpsink[i]); /* link tee to udpsink */ - teepad = gst_element_get_request_pad (stream->tee[i], "src_%u"); - pad = gst_element_get_static_pad (stream->udpsink[i], "sink"); + teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); + pad = gst_element_get_static_pad (priv->udpsink[i], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); /* make queue */ - stream->appqueue[i] = gst_element_factory_make ("queue", NULL); - gst_bin_add (bin, stream->appqueue[i]); + priv->appqueue[i] = gst_element_factory_make ("queue", NULL); + gst_bin_add (bin, priv->appqueue[i]); /* and link to tee */ - teepad = gst_element_get_request_pad (stream->tee[i], "src_%u"); - pad = gst_element_get_static_pad (stream->appqueue[i], "sink"); + teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); + pad = gst_element_get_static_pad (priv->appqueue[i], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); /* make appsink */ - stream->appsink[i] = gst_element_factory_make ("appsink", NULL); - g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL); - g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL); - gst_bin_add (bin, stream->appsink[i]); - gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]), + priv->appsink[i] = gst_element_factory_make ("appsink", NULL); + g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); + g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); + gst_bin_add (bin, priv->appsink[i]); + gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), &sink_cb, stream, NULL); /* and link to queue */ - queuepad = gst_element_get_static_pad (stream->appqueue[i], "src"); - pad = gst_element_get_static_pad (stream->appsink[i], "sink"); + queuepad = gst_element_get_static_pad (priv->appqueue[i], "src"); + pad = gst_element_get_static_pad (priv->appsink[i], "sink"); gst_pad_link (queuepad, pad); gst_object_unref (pad); gst_object_unref (queuepad); @@ -810,74 +951,74 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, * '--------' '--------' */ /* make funnel for the RTP/RTCP receivers */ - stream->funnel[i] = gst_element_factory_make ("funnel", NULL); - gst_bin_add (bin, stream->funnel[i]); + priv->funnel[i] = gst_element_factory_make ("funnel", NULL); + gst_bin_add (bin, priv->funnel[i]); - pad = gst_element_get_static_pad (stream->funnel[i], "src"); - gst_pad_link (pad, stream->recv_sink[i]); + pad = gst_element_get_static_pad (priv->funnel[i], "src"); + gst_pad_link (pad, priv->recv_sink[i]); gst_object_unref (pad); /* we set and keep these to playing so that they don't cause NO_PREROLL return * values */ - gst_element_set_state (stream->udpsrc[i], GST_STATE_PLAYING); - gst_element_set_locked_state (stream->udpsrc[i], TRUE); + gst_element_set_state (priv->udpsrc[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc[i], TRUE); /* add udpsrc */ - gst_bin_add (bin, stream->udpsrc[i]); + gst_bin_add (bin, priv->udpsrc[i]); /* and link to the funnel */ - selpad = gst_element_get_request_pad (stream->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (stream->udpsrc[i], "src"); + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->udpsrc[i], "src"); gst_pad_link (pad, selpad); gst_object_unref (pad); gst_object_unref (selpad); /* make and add appsrc */ - stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL); - gst_bin_add (bin, stream->appsrc[i]); + priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); + gst_bin_add (bin, priv->appsrc[i]); /* and link to the funnel */ - selpad = gst_element_get_request_pad (stream->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (stream->appsrc[i], "src"); + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->appsrc[i], "src"); gst_pad_link (pad, selpad); gst_object_unref (pad); gst_object_unref (selpad); /* check if we need to set to a special state */ if (state != GST_STATE_NULL) { - gst_element_set_state (stream->udpsink[i], state); - gst_element_set_state (stream->appsink[i], state); - gst_element_set_state (stream->appqueue[i], state); - gst_element_set_state (stream->tee[i], state); - gst_element_set_state (stream->funnel[i], state); - gst_element_set_state (stream->appsrc[i], state); + gst_element_set_state (priv->udpsink[i], state); + gst_element_set_state (priv->appsink[i], state); + gst_element_set_state (priv->appqueue[i], state); + gst_element_set_state (priv->tee[i], state); + gst_element_set_state (priv->funnel[i], state); + gst_element_set_state (priv->appsrc[i], state); } } /* be notified of caps changes */ - stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps", + priv->caps_sig = g_signal_connect (priv->send_rtp_sink, "notify::caps", (GCallback) caps_notify, stream); - stream->is_joined = TRUE; - g_mutex_unlock (&stream->lock); + priv->is_joined = TRUE; + g_mutex_unlock (&priv->lock); return TRUE; /* ERRORS */ was_joined: { - g_mutex_unlock (&stream->lock); + g_mutex_unlock (&priv->lock); return TRUE; } no_ports: { - g_mutex_unlock (&stream->lock); + g_mutex_unlock (&priv->lock); GST_WARNING ("failed to allocate ports %d", idx); return FALSE; } link_failed: { GST_WARNING ("failed to link stream %d", idx); - gst_object_unref (stream->send_rtp_sink); - stream->send_rtp_sink = NULL; - g_mutex_unlock (&stream->lock); + gst_object_unref (priv->send_rtp_sink); + priv->send_rtp_sink = NULL; + g_mutex_unlock (&priv->lock); return FALSE; } } @@ -897,67 +1038,70 @@ gboolean gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, GstElement * rtpbin) { + GstRTSPStreamPrivate *priv; gint i; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); g_return_val_if_fail (GST_IS_BIN (bin), FALSE); g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE); - g_mutex_lock (&stream->lock); - if (!stream->is_joined) + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if (!priv->is_joined) goto was_not_joined; /* all transports must be removed by now */ - g_return_val_if_fail (stream->transports == NULL, FALSE); + g_return_val_if_fail (priv->transports == NULL, FALSE); GST_INFO ("stream %p leaving bin", stream); - gst_pad_unlink (stream->srcpad, stream->send_rtp_sink); - g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig); - gst_element_release_request_pad (rtpbin, stream->send_rtp_sink); - gst_object_unref (stream->send_rtp_sink); - stream->send_rtp_sink = NULL; + gst_pad_unlink (priv->srcpad, priv->send_rtp_sink); + g_signal_handler_disconnect (priv->send_rtp_sink, priv->caps_sig); + gst_element_release_request_pad (rtpbin, priv->send_rtp_sink); + gst_object_unref (priv->send_rtp_sink); + priv->send_rtp_sink = NULL; for (i = 0; i < 2; i++) { /* and set udpsrc to NULL now before removing */ - gst_element_set_locked_state (stream->udpsrc[i], FALSE); - gst_element_set_state (stream->udpsrc[i], GST_STATE_NULL); + gst_element_set_locked_state (priv->udpsrc[i], FALSE); + gst_element_set_state (priv->udpsrc[i], GST_STATE_NULL); /* removing them should also nicely release the request * pads when they finalize */ - gst_bin_remove (bin, stream->udpsrc[i]); - gst_bin_remove (bin, stream->udpsink[i]); - gst_bin_remove (bin, stream->appsrc[i]); - gst_bin_remove (bin, stream->appsink[i]); - gst_bin_remove (bin, stream->appqueue[i]); - gst_bin_remove (bin, stream->tee[i]); - gst_bin_remove (bin, stream->funnel[i]); + gst_bin_remove (bin, priv->udpsrc[i]); + gst_bin_remove (bin, priv->udpsink[i]); + gst_bin_remove (bin, priv->appsrc[i]); + gst_bin_remove (bin, priv->appsink[i]); + gst_bin_remove (bin, priv->appqueue[i]); + gst_bin_remove (bin, priv->tee[i]); + gst_bin_remove (bin, priv->funnel[i]); - gst_element_release_request_pad (rtpbin, stream->recv_sink[i]); - gst_object_unref (stream->recv_sink[i]); - stream->recv_sink[i] = NULL; + gst_element_release_request_pad (rtpbin, priv->recv_sink[i]); + gst_object_unref (priv->recv_sink[i]); + priv->recv_sink[i] = NULL; - stream->udpsrc[i] = NULL; - stream->udpsink[i] = NULL; - stream->appsrc[i] = NULL; - stream->appsink[i] = NULL; - stream->appqueue[i] = NULL; - stream->tee[i] = NULL; - stream->funnel[i] = NULL; + priv->udpsrc[i] = NULL; + priv->udpsink[i] = NULL; + priv->appsrc[i] = NULL; + priv->appsink[i] = NULL; + priv->appqueue[i] = NULL; + priv->tee[i] = NULL; + priv->funnel[i] = NULL; } - gst_object_unref (stream->send_src[0]); - stream->send_src[0] = NULL; + gst_object_unref (priv->send_src[0]); + priv->send_src[0] = NULL; - gst_element_release_request_pad (rtpbin, stream->send_src[1]); - gst_object_unref (stream->send_src[1]); - stream->send_src[1] = NULL; + gst_element_release_request_pad (rtpbin, priv->send_src[1]); + gst_object_unref (priv->send_src[1]); + priv->send_src[1] = NULL; - g_object_unref (stream->session); - if (stream->caps) - gst_caps_unref (stream->caps); + g_object_unref (priv->session); + if (priv->caps) + gst_caps_unref (priv->caps); - stream->is_joined = FALSE; - g_mutex_unlock (&stream->lock); + priv->is_joined = FALSE; + g_mutex_unlock (&priv->lock); return TRUE; @@ -982,19 +1126,53 @@ gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, guint * rtptime, guint * seq) { + GstRTSPStreamPrivate *priv; GObjectClass *payobjclass; - payobjclass = G_OBJECT_GET_CLASS (stream->payloader); + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + g_return_val_if_fail (rtptime != NULL, FALSE); + g_return_val_if_fail (seq != NULL, FALSE); + + priv = stream->priv; + + payobjclass = G_OBJECT_GET_CLASS (priv->payloader); if (!g_object_class_find_property (payobjclass, "seqnum") || !g_object_class_find_property (payobjclass, "timestamp")) return FALSE; - g_object_get (stream->payloader, "seqnum", seq, "timestamp", rtptime, NULL); + g_object_get (priv->payloader, "seqnum", seq, "timestamp", rtptime, NULL); return TRUE; } +/** + * gst_rtsp_stream_get_caps: + * @stream: a #GstRTSPStream + * + * Retrieve the current caps of @stream. + * + * Returns: (transfer full): the #GstCaps of @stream. use gst_caps_unref() + * after usage. + */ +GstCaps * +gst_rtsp_stream_get_caps (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + GstCaps *result; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->caps)) + gst_caps_ref (result); + g_mutex_unlock (&priv->lock); + + return result; +} + /** * gst_rtsp_stream_recv_rtp: * @stream: a #GstRTSPStream @@ -1010,16 +1188,18 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, GstFlowReturn gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * buffer) { + GstRTSPStreamPrivate *priv; GstFlowReturn ret; GstElement *element; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR); + priv = stream->priv; g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); - g_return_val_if_fail (stream->is_joined, FALSE); + g_return_val_if_fail (priv->is_joined, FALSE); - g_mutex_lock (&stream->lock); - element = gst_object_ref (stream->appsrc[0]); - g_mutex_unlock (&stream->lock); + g_mutex_lock (&priv->lock); + element = gst_object_ref (priv->appsrc[0]); + g_mutex_unlock (&priv->lock); ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (element), buffer); @@ -1043,16 +1223,18 @@ gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * buffer) GstFlowReturn gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer) { + GstRTSPStreamPrivate *priv; GstFlowReturn ret; GstElement *element; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR); + priv = stream->priv; g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); - g_return_val_if_fail (stream->is_joined, FALSE); + g_return_val_if_fail (priv->is_joined, FALSE); - g_mutex_lock (&stream->lock); - element = gst_object_ref (stream->appsrc[1]); - g_mutex_unlock (&stream->lock); + g_mutex_lock (&priv->lock); + element = gst_object_ref (priv->appsrc[1]); + g_mutex_unlock (&priv->lock); ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (element), buffer); @@ -1066,12 +1248,10 @@ static gboolean update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, gboolean add) { - GstRTSPTransport *tr; - gboolean updated; + GstRTSPStreamPrivate *priv = stream->priv; + const GstRTSPTransport *tr; - updated = FALSE; - - tr = trans->transport; + tr = gst_rtsp_stream_transport_get_transport (trans); switch (tr->lower_transport) { case GST_RTSP_LOWER_TRANS_UDP: @@ -1091,46 +1271,44 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, max = tr->client_port.max; } - if (add && !trans->active) { + if (add) { GST_INFO ("adding %s:%d-%d", dest, min, max); - g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); + g_signal_emit_by_name (priv->udpsink[0], "add", dest, min, NULL); + g_signal_emit_by_name (priv->udpsink[1], "add", dest, max, NULL); if (ttl > 0) { GST_INFO ("setting ttl-mc %d", ttl); - g_object_set (G_OBJECT (stream->udpsink[0]), "ttl-mc", ttl, NULL); - g_object_set (G_OBJECT (stream->udpsink[1]), "ttl-mc", ttl, NULL); + g_object_set (G_OBJECT (priv->udpsink[0]), "ttl-mc", ttl, NULL); + g_object_set (G_OBJECT (priv->udpsink[1]), "ttl-mc", ttl, NULL); } - stream->transports = g_list_prepend (stream->transports, trans); - trans->active = TRUE; - updated = TRUE; - } else if (trans->active) { + priv->transports = g_list_prepend (priv->transports, trans); + } else { GST_INFO ("removing %s:%d-%d", dest, min, max); - g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); - g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); - stream->transports = g_list_remove (stream->transports, trans); - trans->active = FALSE; - updated = TRUE; + g_signal_emit_by_name (priv->udpsink[0], "remove", dest, min, NULL); + g_signal_emit_by_name (priv->udpsink[1], "remove", dest, max, NULL); + priv->transports = g_list_remove (priv->transports, trans); } break; } case GST_RTSP_LOWER_TRANS_TCP: - if (add && !trans->active) { + if (add) { GST_INFO ("adding TCP %s", tr->destination); - stream->transports = g_list_prepend (stream->transports, trans); - trans->active = TRUE; - updated = TRUE; - } else if (trans->active) { + priv->transports = g_list_prepend (priv->transports, trans); + } else { GST_INFO ("removing TCP %s", tr->destination); - stream->transports = g_list_remove (stream->transports, trans); - trans->active = FALSE; - updated = TRUE; + priv->transports = g_list_remove (priv->transports, trans); } break; default: - GST_INFO ("Unknown transport %d", tr->lower_transport); - break; + goto unknown_transport; + } + return TRUE; + + /* ERRORS */ +unknown_transport: + { + GST_INFO ("Unknown transport %d", tr->lower_transport); + return FALSE; } - return updated; } @@ -1152,16 +1330,17 @@ gboolean gst_rtsp_stream_add_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans) { + GstRTSPStreamPrivate *priv; gboolean res; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + priv = stream->priv; g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE); - g_return_val_if_fail (stream->is_joined, FALSE); - g_return_val_if_fail (trans->transport != NULL, FALSE); + g_return_val_if_fail (priv->is_joined, FALSE); - g_mutex_lock (&stream->lock); + g_mutex_lock (&priv->lock); res = update_transport (stream, trans, TRUE); - g_mutex_unlock (&stream->lock); + g_mutex_unlock (&priv->lock); return res; } @@ -1184,16 +1363,17 @@ gboolean gst_rtsp_stream_remove_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans) { + GstRTSPStreamPrivate *priv; gboolean res; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + priv = stream->priv; g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE); - g_return_val_if_fail (stream->is_joined, FALSE); - g_return_val_if_fail (trans->transport != NULL, FALSE); + g_return_val_if_fail (priv->is_joined, FALSE); - g_mutex_lock (&stream->lock); + g_mutex_lock (&priv->lock); res = update_transport (stream, trans, FALSE); - g_mutex_unlock (&stream->lock); + g_mutex_unlock (&priv->lock); return res; } diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index bdb50c2c14..3367fe251c 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -38,6 +38,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPStream GstRTSPStream; typedef struct _GstRTSPStreamClass GstRTSPStreamClass; +typedef struct _GstRTSPStreamPrivate GstRTSPStreamPrivate; #include "rtsp-stream-transport.h" #include "rtsp-address-pool.h" @@ -45,79 +46,13 @@ typedef struct _GstRTSPStreamClass GstRTSPStreamClass; /** * GstRTSPStream: * @parent: the parent instance - * @lock: mutex protecting the stream - * @idx: the stream index - * @srcpad: the srcpad of the stream - * @payloader: the payloader of the format - * @is_ipv6: should this stream be IPv6 - * @buffer_size: the UDP buffer size - * @is_joined: if the stream is joined in a bin - * @send_rtp_sink: sinkpad for sending RTP buffers - * @recv_sink: sinkpad for receiving RTP/RTCP buffers - * @send_src: srcpad for sending RTP/RTCP buffers - * @session: the RTP session object - * @udpsrc: the udp source elements for RTP/RTCP - * @udpsink: the udp sink elements for RTP/RTCP - * @appsrc: the app source elements for RTP/RTCP - * @appqueue: the app queue elements for RTP/RTCP - * @appsink: the app sink elements for RTP/RTCP - * @tee: tee for the sending to udpsink and appsink - * @funnel: tee for the receiving from udpsrc and appsrc - * @server_port: the server ports for this stream - * @pool: the address pool for this stream - * @addr: the address for this stream - * @caps_sig: the signal id for detecting caps - * @caps: the caps of the stream - * @n_active: the number of active transports in @transports - * @transports: list of #GstStreamTransport being streamed to * - * The definition of a media stream. The streams are identified by @idx. + * The definition of a media stream. */ struct _GstRTSPStream { GObject parent; - GMutex lock; - guint idx; - GstPad *srcpad; - GstElement *payloader; - gboolean is_ipv6; - guint buffer_size; - gboolean is_joined; - - /* pads on the rtpbin */ - GstPad *send_rtp_sink; - GstPad *recv_sink[2]; - GstPad *send_src[2]; - - /* the RTPSession object */ - GObject *session; - - /* sinks used for sending and receiving RTP and RTCP, they share - * sockets */ - GstElement *udpsrc[2]; - GstElement *udpsink[2]; - /* for TCP transport */ - GstElement *appsrc[2]; - GstElement *appqueue[2]; - GstElement *appsink[2]; - - GstElement *tee[2]; - GstElement *funnel[2]; - - /* server ports for sending/receiving */ - GstRTSPRange server_port; - - /* multicast addresses */ - GstRTSPAddressPool *pool; - GstRTSPAddress *addr; - - /* the caps of the stream */ - gulong caps_sig; - GstCaps *caps; - - /* transports we stream to */ - guint n_active; - GList *transports; + GstRTSPStreamPrivate *priv; }; struct _GstRTSPStreamClass { @@ -128,9 +63,10 @@ GType gst_rtsp_stream_get_type (void); GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement *payloader, GstPad *srcpad); +guint gst_rtsp_stream_get_index (GstRTSPStream *stream); -void gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guint mtu); -guint gst_rtsp_stream_get_mtu (GstRTSPStream * stream); +void gst_rtsp_stream_set_mtu (GstRTSPStream *stream, guint mtu); +guint gst_rtsp_stream_get_mtu (GstRTSPStream *stream); void gst_rtsp_stream_set_address_pool (GstRTSPStream *stream, GstRTSPAddressPool *pool); GstRTSPAddressPool * @@ -138,14 +74,20 @@ GstRTSPAddressPool * GstRTSPAddress * gst_rtsp_stream_get_address (GstRTSPStream *stream); -gboolean gst_rtsp_stream_join_bin (GstRTSPStream * stream, +gboolean gst_rtsp_stream_join_bin (GstRTSPStream *stream, GstBin *bin, GstElement *rtpbin, GstState state); -gboolean gst_rtsp_stream_leave_bin (GstRTSPStream * stream, +gboolean gst_rtsp_stream_leave_bin (GstRTSPStream *stream, GstBin *bin, GstElement *rtpbin); -gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, - guint *rtptime, guint * seq); +void gst_rtsp_stream_get_server_port (GstRTSPStream *stream, + GstRTSPRange *server_port); +void gst_rtsp_stream_get_ssrc (GstRTSPStream *stream, + guint *ssrc); + +gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream *stream, + guint *rtptime, guint *seq); +GstCaps * gst_rtsp_stream_get_caps (GstRTSPStream *stream); GstFlowReturn gst_rtsp_stream_recv_rtp (GstRTSPStream *stream, GstBuffer *buffer); diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index f7bff0120f..c1115de98e 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -93,7 +93,7 @@ GST_START_TEST (test_media) { GstRTSPMedia *media; - media = gst_rtsp_media_new (); + media = gst_rtsp_media_new (NULL); fail_unless (GST_IS_RTSP_MEDIA (media)); g_object_unref (media); } From 4b61fdad85a3ca84752bf074fdb2fa203954b32e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Nov 2012 12:30:20 +0100 Subject: [PATCH 0559/1776] client: TEARDOWN brings that state to Init again --- gst/rtsp-server/rtsp-client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e8f3957f55..ce3194b694 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -675,6 +675,8 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) send_response (client, session, state->response, TRUE); + gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_INIT); + /* we emit the signal before closing the connection */ g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], 0, state); From 865c9a6b30c997c071c72218c2e2cba5bea702c1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Nov 2012 17:07:30 +0100 Subject: [PATCH 0560/1776] Revert "client: TEARDOWN brings that state to Init again" This reverts commit 4b61fdad85a3ca84752bf074fdb2fa203954b32e. The object is already disposed, there is no point in setting the state. --- gst/rtsp-server/rtsp-client.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index ce3194b694..e8f3957f55 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -675,8 +675,6 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) send_response (client, session, state->response, TRUE); - gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_INIT); - /* we emit the signal before closing the connection */ g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], 0, state); From 4eb010824ed049012984ade9e1f1403db11137fc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Nov 2012 17:20:26 +0100 Subject: [PATCH 0561/1776] media: require an element in media constructor --- gst/rtsp-server/rtsp-media.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 01657693dd..2258ccafeb 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -376,6 +376,8 @@ gst_rtsp_media_new (GstElement * element) { GstRTSPMedia *result; + g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); + result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL); result->priv->element = element; From 28fd887547ee98988ceae019bdbadf99a1189cc2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Nov 2012 17:20:56 +0100 Subject: [PATCH 0562/1776] media: avoid element leak --- gst/rtsp-server/rtsp-media.c | 2 ++ tests/check/gst/media.c | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 2258ccafeb..efe0be66fd 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -226,6 +226,7 @@ gst_rtsp_media_finalize (GObject * obj) if (priv->pipeline) gst_object_unref (priv->pipeline); + gst_object_unref (priv->element); if (priv->auth) g_object_unref (priv->auth); if (priv->pool) @@ -411,6 +412,7 @@ gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline) if (old) gst_object_unref (old); + gst_object_ref (priv->element); gst_bin_add (GST_BIN_CAST (pipeline), priv->element); } diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index c1115de98e..a237339d08 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -92,8 +92,22 @@ GST_END_TEST; GST_START_TEST (test_media) { GstRTSPMedia *media; + GstElement *bin, *e1, *e2; - media = gst_rtsp_media_new (NULL); + bin = gst_bin_new ("bin"); + fail_if (bin == NULL); + + e1 = gst_element_factory_make ("videotestsrc", NULL); + fail_if (e1 == NULL); + + e2 = gst_element_factory_make ("rtpvrawpay", "pay0"); + fail_if (e2 == NULL); + g_object_set (e2, "pt", 96, NULL); + + gst_bin_add_many (GST_BIN_CAST (bin), e1, e2, NULL); + gst_element_link_many (e1, e2, NULL); + + media = gst_rtsp_media_new (bin); fail_unless (GST_IS_RTSP_MEDIA (media)); g_object_unref (media); } From 1abc9be68232df6a6d09a0decfabff0022d49c9b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 29 Nov 2012 17:21:12 +0100 Subject: [PATCH 0563/1776] small cleanup --- gst/rtsp-server/rtsp-session-media.h | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index ed5284d130..b6816b30d2 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -72,7 +72,6 @@ gboolean gst_rtsp_session_media_matches_url (GstRTSPSessionMe GstRTSPMedia * gst_rtsp_session_media_get_media (GstRTSPSessionMedia *media); /* control media */ - gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media, GstState state); From e2a7690cb34ec82502d25c60265ab563b6f76e11 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Fri, 30 Nov 2012 06:14:49 +0100 Subject: [PATCH 0564/1776] Add missing g_type_class_add_private in GstRTSPMediaFactoryURI --- gst/rtsp-server/rtsp-media-factory-uri.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 84022a39c7..c83d87da4b 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -94,6 +94,8 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass) GObjectClass *gobject_class; GstRTSPMediaFactoryClass *mediafactory_class; + g_type_class_add_private (klass, sizeof (GstRTSPMediaFactoryURIPrivate)); + gobject_class = G_OBJECT_CLASS (klass); mediafactory_class = GST_RTSP_MEDIA_FACTORY_CLASS (klass); From 00d9a94e1aafdf52de608e6a0e497a1e5fb755c5 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Fri, 30 Nov 2012 06:17:46 +0100 Subject: [PATCH 0565/1776] Fix compiler warning --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index efe0be66fd..b5a686f8dd 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1280,7 +1280,7 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) /* FIXME, element is likely not a payloader, find the payloader here */ stream = gst_rtsp_media_create_stream (media, element, pad); - GST_INFO ("pad added %s:%s, stream %s", GST_DEBUG_PAD_NAME (pad), stream); + GST_INFO ("pad added %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream); g_rec_mutex_lock (&priv->state_lock); /* we will be adding elements below that will cause ASYNC_DONE to be From ba5b78ff2ff223049188eb456e228c709ccd3e05 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Fri, 30 Nov 2012 07:05:25 +0100 Subject: [PATCH 0566/1776] client: never call gst_rtsp_media_unprepare, let gst_rtsp_media_finalize do it Calling gst_rtsp_media_unprepare breaks shared medias. Just unref GstRTSPMedia instances and let gst_rtsp_media_finalize unprepare when a media isn't being used anymore. --- gst/rtsp-server/rtsp-client.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e8f3957f55..becfb0eeb6 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -278,7 +278,6 @@ gst_rtsp_client_finalize (GObject * obj) if (priv->uri) gst_rtsp_url_free (priv->uri); if (priv->media) { - gst_rtsp_media_unprepare (priv->media); g_object_unref (priv->media); } @@ -436,7 +435,6 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_url_free (priv->uri); priv->uri = NULL; if (priv->media) { - gst_rtsp_media_unprepare (priv->media); g_object_unref (priv->media); } priv->media = NULL; From edf2ef4f0b60684f18c26634c1f2e4a90d416b46 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Nov 2012 10:05:48 +0100 Subject: [PATCH 0567/1776] media: use g_object_ref/unref for GObjects --- gst/rtsp-server/rtsp-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b5a686f8dd..26897dc525 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1267,7 +1267,7 @@ static void watch_destroyed (GstRTSPMedia * media) { GST_DEBUG_OBJECT (media, "source destroyed"); - gst_object_unref (media); + g_object_unref (media); } /* called from streaming threads */ @@ -1377,7 +1377,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) gst_object_unref (bus); g_source_set_callback (priv->source, (GSourceFunc) bus_message, - gst_object_ref (media), (GDestroyNotify) watch_destroyed); + g_object_ref (media), (GDestroyNotify) watch_destroyed); klass = GST_RTSP_MEDIA_GET_CLASS (media); priv->id = g_source_attach (priv->source, klass->context); From 241baba20aa01b4869cf0f68906fc48fae6b7388 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Nov 2012 12:53:02 +0100 Subject: [PATCH 0568/1776] media: check state Make sure we are in the right state when collecting the position and duration. Only make ourselves PREPARED when we were previously PREPARING. --- gst/rtsp-server/rtsp-media.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 26897dc525..f09f326207 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -309,6 +309,10 @@ collect_media_stats (GstRTSPMedia * media) GstRTSPMediaPrivate *priv = media->priv; gint64 position, duration; + if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED && + priv->status != GST_RTSP_MEDIA_STATUS_PREPARING) + return; + priv->range.unit = GST_RTSP_RANGE_NPT; GST_INFO ("collect media stats"); @@ -1092,9 +1096,7 @@ gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status) GstRTSPMediaPrivate *priv = media->priv; g_mutex_lock (&priv->lock); - /* never overwrite the error status */ - if (priv->status != GST_RTSP_MEDIA_STATUS_ERROR) - priv->status = status; + priv->status = status; GST_DEBUG ("setting new status to %d", status); g_cond_broadcast (&priv->cond); g_mutex_unlock (&priv->lock); @@ -1222,7 +1224,8 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) GST_INFO ("%p: got ASYNC_DONE", media); collect_media_stats (media); - gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); } else { GST_INFO ("%p: ignoring ASYNC_DONE", media); } From 339ea9b085ea37de216d8ff31d908753963b8ab1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Nov 2012 12:54:10 +0100 Subject: [PATCH 0569/1776] media: improve debug --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index f09f326207..a6bfd04699 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1240,7 +1240,7 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) } break; default: - GST_INFO ("%p: got message type %s", media, + GST_INFO ("%p: got message type %d (%s)", media, type, gst_message_type_get_name (type)); break; } From 119674a828d7ce1655647e63f5ddfbde40ca4ad4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Nov 2012 13:35:05 +0100 Subject: [PATCH 0570/1776] media: let the source unref the last media ref the last ref to the media is held by the source so we don't need to add more ref and unrefs, we simply destroy the media when the source is gone. --- gst/rtsp-server/rtsp-media.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index a6bfd04699..fee2167287 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1236,7 +1236,6 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARING) { GST_DEBUG ("shutting down after EOS"); finish_unprepare (media); - g_object_unref (media); } break; default: @@ -1523,15 +1522,16 @@ finish_unprepare (GstRTSPMedia * media) priv->reused = TRUE; priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARED; - if (priv->source) { - g_source_destroy (priv->source); - g_source_unref (priv->source); - priv->source = NULL; - } - /* when the media is not reusable, this will effectively unref the media and * recreate it */ g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL); + + /* the source has the last ref to the media */ + if (priv->source) { + GST_DEBUG ("destroy source"); + g_source_destroy (priv->source); + g_source_unref (priv->source); + } } /* called with state-lock */ @@ -1543,7 +1543,6 @@ default_unprepare (GstRTSPMedia * media) if (priv->eos_shutdown) { GST_DEBUG ("sending EOS for shutdown"); /* ref so that we don't disappear */ - g_object_ref (media); gst_element_send_event (priv->pipeline, gst_event_new_eos ()); /* we need to go to playing again for the EOS to propagate, normally in this * state, nothing is receiving data from us anymore so this is ok. */ From 38addd7822a9dbcfd959d8b3f05d3302e2ca28c3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Nov 2012 14:36:30 +0100 Subject: [PATCH 0571/1776] Revert "client: never call gst_rtsp_media_unprepare, let gst_rtsp_media_finalize do it" This reverts commit ba5b78ff2ff223049188eb456e228c709ccd3e05. We can't use the refcount to trigger unprepare because it is the unprepare call that removes the last refcount after all messages are consumed. What we should probably do is make a prepared refcount and only unprepare when the refcount reaches 0. --- gst/rtsp-server/rtsp-client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index becfb0eeb6..e8f3957f55 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -278,6 +278,7 @@ gst_rtsp_client_finalize (GObject * obj) if (priv->uri) gst_rtsp_url_free (priv->uri); if (priv->media) { + gst_rtsp_media_unprepare (priv->media); g_object_unref (priv->media); } @@ -435,6 +436,7 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_url_free (priv->uri); priv->uri = NULL; if (priv->media) { + gst_rtsp_media_unprepare (priv->media); g_object_unref (priv->media); } priv->media = NULL; From ca26588c7e3facd834f5b2e1164e8cbf896c1596 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Nov 2012 14:58:46 +0100 Subject: [PATCH 0572/1776] media: media has to be unprepared in finalize Because unprepare takes away the last ref on the media. --- gst/rtsp-server/rtsp-media.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index fee2167287..b2bba06734 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -218,8 +218,6 @@ gst_rtsp_media_finalize (GObject * obj) GST_INFO ("finalize media %p", media); - gst_rtsp_media_unprepare (media); - g_ptr_array_unref (priv->streams); g_list_free_full (priv->dynamic, gst_object_unref); From 6beabf1ed417a23978349cd1c8b4122b1b3746c3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Nov 2012 15:03:15 +0100 Subject: [PATCH 0573/1776] media: match prepare with unprepare Really unprepare when there were an equal amount of prepare calls. --- gst/rtsp-server/rtsp-media.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b2bba06734..4fdd4c255a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -47,6 +47,7 @@ struct _GstRTSPMediaPrivate GPtrArray *streams; GList *dynamic; GstRTSPMediaStatus status; + gint prepare_count; gint n_active; gboolean adding; @@ -1345,6 +1346,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) priv = media->priv; g_rec_mutex_lock (&priv->state_lock); + priv->prepare_count++; + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) goto was_prepared; @@ -1464,17 +1467,20 @@ was_prepared: not_unprepared: { GST_WARNING ("media %p was not unprepared", media); + priv->prepare_count--; g_rec_mutex_unlock (&priv->state_lock); return FALSE; } is_reused: { + priv->prepare_count--; g_rec_mutex_unlock (&priv->state_lock); GST_WARNING ("can not reuse media %p", media); return FALSE; } no_rtpbin: { + priv->prepare_count--; g_rec_mutex_unlock (&priv->state_lock); GST_WARNING ("no rtpbin element"); g_warning ("failed to create element 'rtpbin', check your installation"); @@ -1576,6 +1582,10 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) if (priv->status == GST_RTSP_MEDIA_STATUS_UNPREPARED) goto was_unprepared; + priv->prepare_count--; + if (priv->prepare_count > 0) + goto is_busy; + GST_INFO ("unprepare media %p", media); priv->target_state = GST_STATE_NULL; success = TRUE; @@ -1599,6 +1609,12 @@ was_unprepared: GST_INFO ("media %p was already unprepared", media); return TRUE; } +is_busy: + { + GST_INFO ("media %p still prepared %d times", media, priv->prepare_count); + g_rec_mutex_unlock (&priv->state_lock); + return TRUE; + } } /** From e2d02097a612a3661ce922ff2617ddbb90465383 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Tue, 4 Dec 2012 01:05:31 +0100 Subject: [PATCH 0574/1776] docs: Link with gcov library when gcov is enabled Fixes https://bugzilla.gnome.org/show_bug.cgi?id=689583 --- docs/libs/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/libs/Makefile.am b/docs/libs/Makefile.am index 0bfb22f785..0aadfe4b50 100644 --- a/docs/libs/Makefile.am +++ b/docs/libs/Makefile.am @@ -94,7 +94,7 @@ extra_files = GTKDOC_CFLAGS = -I$(top_srcdir) $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) $(GST_CFLAGS) GTKDOC_LIBS = $(SCANOBJ_DEPS) $(GST_PLUGINS_BASE_LIBS) \ - $(GST_BASE_LIBS) $(GST_LIBS) + $(GST_BASE_LIBS) $(GST_LIBS) $(GCOV_LIBS) GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC) GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) From 0844e8afbc2f9d4892463bc0b0327d12af4b0878 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Tue, 4 Dec 2012 09:47:35 +0100 Subject: [PATCH 0575/1776] rtsp-media: Make the element a constructor parameter https://bugzilla.gnome.org/show_bug.cgi?id=689594 --- gst/rtsp-server/rtsp-media.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4fdd4c255a..10610ffd03 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -89,6 +89,7 @@ enum PROP_PROTOCOLS, PROP_EOS_SHUTDOWN, PROP_BUFFER_SIZE, + PROP_ELEMENT, PROP_LAST }; @@ -158,6 +159,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "The kernel UDP buffer size to use", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ELEMENT, + g_param_spec_object ("element", "The Element", + "The GstBin to use for streaming the media", GST_TYPE_ELEMENT, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, @@ -244,6 +250,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, GstRTSPMedia *media = GST_RTSP_MEDIA (object); switch (propid) { + case PROP_ELEMENT: + g_value_set_object (value, media->priv->element); + break; case PROP_SHARED: g_value_set_boolean (value, gst_rtsp_media_is_shared (media)); break; @@ -271,6 +280,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, GstRTSPMedia *media = GST_RTSP_MEDIA (object); switch (propid) { + case PROP_ELEMENT: + media->priv->element = g_value_get_object (value); + break; case PROP_SHARED: gst_rtsp_media_set_shared (media, g_value_get_boolean (value)); break; @@ -382,8 +394,7 @@ gst_rtsp_media_new (GstElement * element) g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); - result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL); - result->priv->element = element; + result = g_object_new (GST_TYPE_RTSP_MEDIA, "element", element, NULL); return result; } From 4100b20b0ab0df189be926635aa8261323867d25 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 14 Dec 2012 11:58:29 +0100 Subject: [PATCH 0576/1776] rtsp-client: set the client backlog Set the client backlog to a reasonable default --- gst/rtsp-server/rtsp-client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e8f3957f55..a6510e5d19 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2463,6 +2463,10 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) g_object_ref (client), (GDestroyNotify) client_watch_notify); gst_rtsp_client_set_send_func (client, do_send_message, NULL, NULL); + /* FIXME make this configurable. We don't want to do this yet because it will + * be superceeded by a cache object later */ + gst_rtsp_watch_set_send_backlog (priv->watch, 0, 100); + GST_INFO ("attaching to context %p", context); res = gst_rtsp_watch_attach (priv->watch, context); gst_rtsp_watch_unref (priv->watch); From 7cb268bf9f52e1c55e643e17961b28e6fcc631d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 15 Jan 2013 15:09:24 +0000 Subject: [PATCH 0577/1776] Automatic update of common submodule From acb04d9 to a942293 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index acb04d9fec..a94229318f 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit acb04d9fec79a11bf27d4b58f34c95028c83f2be +Subproject commit a94229318f7fc480c79279bb3f604a11ddf8f2f4 From 114442bdb8d1f045b2a0d27fc73cf882c24dfcd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 16 Jan 2013 12:16:32 +0000 Subject: [PATCH 0578/1776] tests: use GST_*_1_0 environment variables everywhere The _1_0 suffixed environment variables override the non-suffixed ones, so if we're in an environment that sets the _1_0 suffixed ones, such as jhbuild, we need to set those to make sure ours actually always get used. --- tests/check/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index c2bb3e4f8d..b6765a5d61 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -4,14 +4,14 @@ CHECK_REGISTRY = $(top_builddir)/tests/check/test-registry.reg TEST_FILES_DIRECTORY = $(top_srcdir)/tests/files REGISTRY_ENVIRONMENT = \ - GST_REGISTRY=$(CHECK_REGISTRY) + GST_REGISTRY_1_0=$(CHECK_REGISTRY) TESTS_ENVIRONMENT = \ CK_DEFAULT_TIMEOUT=120 \ GST_STATE_IGNORE_ELEMENTS="$(STATE_IGNORE_ELEMENTS)" \ $(REGISTRY_ENVIRONMENT) \ - GST_PLUGIN_SYSTEM_PATH= \ - GST_PLUGIN_PATH=$(GST_PLUGINS_DIR):$(GSTPB_PLUGINS_DIR):$(GSTPG_PLUGINS_DIR) \ + GST_PLUGIN_SYSTEM_PATH_1_0= \ + GST_PLUGIN_PATH_1_0=$(GST_PLUGINS_DIR):$(GSTPB_PLUGINS_DIR):$(GSTPG_PLUGINS_DIR) \ GST_PLUGIN_LOADING_WHITELIST="gstreamer:gst-plugins-base:gst-plugins-good" From 6db0dbc76cf215eac8e4771e9672a268fb840bb9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 28 Jan 2013 10:31:50 +0100 Subject: [PATCH 0579/1776] client: make sure the watch exists while sending data Protect the send_func with a lock. This allows us to wait for sending to complete before changing the send_func and user_data. We add an extra ref to the watch to make sure that it remains valid during sending. When closing the connection, set the send_func to NULL Fixes https://bugzilla.gnome.org/show_bug.cgi?id=692433 --- gst/rtsp-server/rtsp-client.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a6510e5d19..9da27ade80 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -30,6 +30,7 @@ struct _GstRTSPClientPrivate { GMutex lock; + GMutex send_lock; GstRTSPConnection *connection; GstRTSPWatch *watch; guint close_seq; @@ -208,6 +209,7 @@ gst_rtsp_client_init (GstRTSPClient * client) client->priv = priv; g_mutex_init (&priv->lock); + g_mutex_init (&priv->send_lock); priv->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS; priv->close_seq = 0; } @@ -258,12 +260,11 @@ gst_rtsp_client_finalize (GObject * obj) GST_INFO ("finalize client %p", client); + gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + if (priv->watch) g_source_destroy ((GSource *) priv->watch); - if (priv->send_notify) - priv->send_notify (priv->send_data); - client_cleanup_sessions (client); if (priv->connection) @@ -284,6 +285,7 @@ gst_rtsp_client_finalize (GObject * obj) g_free (priv->server_ip); g_mutex_clear (&priv->lock); + g_mutex_clear (&priv->send_lock); G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj); } @@ -374,8 +376,10 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, if (close) gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONNECTION, "close"); + g_mutex_lock (&priv->send_lock); if (priv->send_func) priv->send_func (client, response, close, priv->send_data); + g_mutex_unlock (&priv->send_lock); gst_rtsp_message_unset (response); } @@ -543,8 +547,10 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) gst_rtsp_message_take_body (&message, map_info.data, map_info.size); + g_mutex_lock (&priv->send_lock); if (priv->send_func) priv->send_func (client, &message, FALSE, priv->send_data); + g_mutex_unlock (&priv->send_lock); gst_rtsp_message_steal_body (&message, &data, &usize); gst_buffer_unmap (buffer, &map_info); @@ -2026,13 +2032,13 @@ gst_rtsp_client_set_send_func (GstRTSPClient * client, priv = client->priv; - g_mutex_lock (&priv->lock); + g_mutex_lock (&priv->send_lock); priv->send_func = func; old_notify = priv->send_notify; old_data = priv->send_data; priv->send_notify = notify; priv->send_data = user_data; - g_mutex_unlock (&priv->lock); + g_mutex_unlock (&priv->send_lock); if (old_notify) old_notify (old_data); @@ -2118,6 +2124,8 @@ closed (GstRTSPWatch * watch, gpointer user_data) g_mutex_unlock (&tunnels_lock); } + gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + return GST_RTSP_OK; } @@ -2461,7 +2469,8 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) /* create watch for the connection and attach */ priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs, g_object_ref (client), (GDestroyNotify) client_watch_notify); - gst_rtsp_client_set_send_func (client, do_send_message, NULL, NULL); + gst_rtsp_client_set_send_func (client, do_send_message, priv->watch, + (GDestroyNotify) gst_rtsp_watch_unref); /* FIXME make this configurable. We don't want to do this yet because it will * be superceeded by a cache object later */ @@ -2469,7 +2478,6 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) GST_INFO ("attaching to context %p", context); res = gst_rtsp_watch_attach (priv->watch, context); - gst_rtsp_watch_unref (priv->watch); return res; } From 938cba2e282a6268a44a479fd41bbc44a62085f4 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 28 Jan 2013 20:45:44 +0100 Subject: [PATCH 0580/1776] Automatic update of common submodule From a942293 to 2de221c --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index a94229318f..2de221ce94 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit a94229318f7fc480c79279bb3f604a11ddf8f2f4 +Subproject commit 2de221ce94b657f9c9a75aa3cc0cb84dbb5da78b From 084141fb60478c86c88de300b1665d3fa17835d2 Mon Sep 17 00:00:00 2001 From: George McCollister Date: Thu, 7 Feb 2013 16:18:08 -0600 Subject: [PATCH 0581/1776] configure: replace deprecated AM_CONFIG_HEADER with AC_CONFIG_HEADERS AM_CONFIG_HEADER was removed in automake 1.13 https://bugzilla.gnome.org/show_bug.cgi?id=693368 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 46a0714485..2728f15ff7 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ dnl can autoconf find the source ? AC_CONFIG_SRCDIR([gst/rtsp-server/rtsp-server.c]) dnl define the output header for config -AM_CONFIG_HEADER([config.h]) +AC_CONFIG_HEADERS([config.h]) dnl AM_MAINTAINER_MODE only provides the option to configure to enable it AM_MAINTAINER_MODE([enable]) From 82828852ee3eb887bf2d8bfc58440204688fdc12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 7 Mar 2013 00:04:19 +0000 Subject: [PATCH 0582/1776] Automatic update of common submodule From 2de221c to 04c7a1e --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 2de221ce94..04c7a1ec1b 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 2de221ce94b657f9c9a75aa3cc0cb84dbb5da78b +Subproject commit 04c7a1ec1b9ced0b4359b3bbb2d8dc87bc7642c8 From 456f4367e3741f985d187d259ae23a175e281bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 12 Feb 2013 16:29:25 -0500 Subject: [PATCH 0583/1776] address-pool: Fix off by one error When splitting a port range, the port after a skip is not part of range. --- gst/rtsp-server/rtsp-address-pool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 45a969b497..002751ea12 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -309,7 +309,7 @@ split_range (GstRTSPAddressPool * pool, AddrRange * range, gint skip, if (skip > 0) { /* make a range with the skipped ports */ temp = g_slice_dup (AddrRange, range); - temp->max.port = temp->min.port + skip; + temp->max.port = temp->min.port + skip - 1; /* and store back in pool */ priv->addresses = g_list_prepend (priv->addresses, temp); From 2581cc103cad9974ca4c2a2be867ff9973ab0a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 12 Feb 2013 16:34:37 -0500 Subject: [PATCH 0584/1776] tests: Add more tests for the address pool --- tests/check/gst/addresspool.c | 60 ++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/tests/check/gst/addresspool.c b/tests/check/gst/addresspool.c index b05e973b4f..9df35c74b5 100644 --- a/tests/check/gst/addresspool.c +++ b/tests/check/gst/addresspool.c @@ -24,12 +24,18 @@ GST_START_TEST (test_pool) { GstRTSPAddressPool *pool; - GstRTSPAddress *addr; + GstRTSPAddress *addr, *addr2; pool = gst_rtsp_address_pool_new (); fail_if (gst_rtsp_address_pool_add_range (pool, "233.252.0.1", "233.252.0.0", 5000, 5010, 1)); + fail_if (gst_rtsp_address_pool_add_range (pool, + "233.252.0.1", "::1", 5000, 5010, 1)); + fail_if (gst_rtsp_address_pool_add_range (pool, + "233.252.0.1.1", "233.252.0.1", 5000, 5010, 1)); + fail_if (gst_rtsp_address_pool_add_range (pool, + "233.252.0.1", "233.252.0.1.1", 5000, 5010, 1)); ASSERT_CRITICAL (gst_rtsp_address_pool_add_range (pool, "233.252.0.0", "233.252.0.1", 5010, 5000, 1)); @@ -47,13 +53,65 @@ GST_START_TEST (test_pool) addr = gst_rtsp_address_pool_acquire_address (pool, 0, 2); fail_unless (addr != NULL); + addr2 = gst_rtsp_address_copy (addr); + + gst_rtsp_address_free (addr2); gst_rtsp_address_free (addr); addr = gst_rtsp_address_pool_acquire_address (pool, 0, 4); fail_unless (addr != NULL); + /* Will fail because pool is NULL */ + ASSERT_CRITICAL (gst_rtsp_address_pool_clear (NULL)); + + /* will fail because an address is allocated */ + ASSERT_CRITICAL (gst_rtsp_address_pool_clear (pool)); + gst_rtsp_address_free (addr); + gst_rtsp_address_pool_clear (pool); + + /* start with odd port to make sure we are allocated address + * starting with even port + */ + fail_unless (gst_rtsp_address_pool_add_range (pool, + "2001:DB8::1", "2001:DB8::1", 5001, 5003, 1)); + + addr = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_IPV6 | GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); + fail_unless (addr != NULL); + fail_unless (addr->port == 5002); + + /* Will fail becuse there is only one IPv6 address left */ + addr2 = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_IPV6, 2); + fail_unless (addr2 == NULL); + + /* Will fail because the only IPv6 address left has an odd port */ + addr2 = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_IPV6 | GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 1); + fail_unless (addr2 == NULL); + + gst_rtsp_address_free (addr); + + gst_rtsp_address_pool_clear (pool); + + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.252.0.0", "233.252.0.255", 5000, 5002, 1)); + + addr = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); + fail_unless (addr != NULL); + fail_unless (addr->port == 5000); + + addr2 = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); + fail_unless (addr2 != NULL); + fail_unless (addr2->port == 5000); + + gst_rtsp_address_free (addr); + gst_rtsp_address_free (addr2); + g_object_unref (pool); } From bb7a8af0772acb64597a47cf6b5749571c5b53a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 12 Feb 2013 19:34:24 -0500 Subject: [PATCH 0585/1776] tests: Check the passing around of a RTSPAddressPool Make sure the RTSPAddressPool is propagated from the MediaFactory all the way down to the stream. --- tests/check/gst/mediafactory.c | 77 ++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/tests/check/gst/mediafactory.c b/tests/check/gst/mediafactory.c index 46ff8252ae..e99af5323b 100644 --- a/tests/check/gst/mediafactory.c +++ b/tests/check/gst/mediafactory.c @@ -128,6 +128,82 @@ GST_START_TEST (test_shared) GST_END_TEST; +GST_START_TEST (test_addresspool) +{ + GstRTSPMediaFactory *factory; + GstElement *element; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPAddressPool *pool, *tmppool; + GstRTSPStream *stream; + GstRTSPAddress *addr; + + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_shared (factory, TRUE); + gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 " + " audiotestsrc ! audioconvert ! rtpL16pay name=pay1 )"); + + pool = gst_rtsp_address_pool_new (); + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.252.0.1", "233.252.0.1", 5000, 5001, 3)); + + gst_rtsp_media_factory_set_address_pool (factory, pool); + + tmppool = gst_rtsp_media_factory_get_address_pool (factory); + fail_unless (pool == tmppool); + g_object_unref (tmppool); + + element = gst_rtsp_media_factory_create_element (factory, url); + fail_unless (GST_IS_BIN (element)); + fail_if (GST_IS_PIPELINE (element)); + gst_object_unref (element); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + tmppool = gst_rtsp_media_get_address_pool (media); + fail_unless (pool == tmppool); + g_object_unref (tmppool); + + fail_unless (gst_rtsp_media_n_streams (media) == 2); + + stream = gst_rtsp_media_get_stream (media, 0); + fail_unless (stream != NULL); + + tmppool = gst_rtsp_stream_get_address_pool (stream); + fail_unless (pool == tmppool); + g_object_unref (tmppool); + + addr = gst_rtsp_stream_get_address (stream); + fail_unless (addr != NULL); + fail_unless (addr->port == 5000); + fail_unless (addr->n_ports == 2); + fail_unless (addr->ttl == 3); + gst_rtsp_address_free (addr); + + stream = gst_rtsp_media_get_stream (media, 1); + fail_unless (stream != NULL); + + tmppool = gst_rtsp_stream_get_address_pool (stream); + fail_unless (pool == tmppool); + g_object_unref (tmppool); + + addr = gst_rtsp_stream_get_address (stream); + fail_unless (addr == NULL); + + + g_object_unref (media); + + g_object_unref (pool); + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + static Suite * rtspmediafactory_suite (void) { @@ -140,6 +216,7 @@ rtspmediafactory_suite (void) tcase_add_test (tc, test_launch); tcase_add_test (tc, test_launch_construct); tcase_add_test (tc, test_shared); + tcase_add_test (tc, test_addresspool); return s; } From cda75709bb2dcad6daeba4ad139a9f5ffc05176e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Wed, 13 Feb 2013 18:01:43 -0500 Subject: [PATCH 0586/1776] address-pool: Add API to request a specific address from the pool Also add relevant unit tests. --- gst/rtsp-server/rtsp-address-pool.c | 143 ++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-address-pool.h | 8 ++ tests/check/gst/addresspool.c | 69 +++++++++++++- 3 files changed, 210 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 002751ea12..54fe834300 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -272,13 +272,15 @@ invalid: } } +/* increments the address by count */ + static void -inc_address (GstRTSPAddressPool * pool, Addr * addr) +inc_address (Addr * addr, guint8 count) { gint i; guint carry; - carry = 1; + carry = count; for (i = addr->size - 1; i >= 0 && carry > 0; i--) { carry += addr->bytes[i]; addr->bytes[i] = carry & 0xff; @@ -286,18 +288,48 @@ inc_address (GstRTSPAddressPool * pool, Addr * addr) } } +/* tells us the number of addresses between min_addr and max_addr */ + +static guint +diff_address (Addr * max_addr, Addr * min_addr) +{ + gint i; + guint result = 0; + + g_return_val_if_fail (min_addr->size == max_addr->size, 0); + + for (i = 0; i < min_addr->size; i++) { + g_return_val_if_fail (result < (1 << 24), result); + + result <<= 8; + result += max_addr->bytes[i] - min_addr->bytes[i]; + } + + return result; +} + + static AddrRange * -split_range (GstRTSPAddressPool * pool, AddrRange * range, gint skip, - gint n_ports) +split_range (GstRTSPAddressPool * pool, AddrRange * range, guint skip_addr, + guint skip_port, gint n_ports) { GstRTSPAddressPoolPrivate *priv = pool->priv; AddrRange *temp; + if (skip_addr) { + temp = g_slice_dup (AddrRange, range); + memcpy (temp->max.bytes, temp->min.bytes, temp->min.size); + inc_address (&temp->max, skip_addr - 1); + priv->addresses = g_list_prepend (priv->addresses, temp); + + inc_address (&range->min, skip_addr); + } + if (!RANGE_IS_SINGLE (range)) { /* min and max are not the same, we have more than one address. */ temp = g_slice_dup (AddrRange, range); /* increment the range min address */ - inc_address (pool, &temp->min); + inc_address (&temp->min, 1); /* and store back in pool */ priv->addresses = g_list_prepend (priv->addresses, temp); @@ -306,15 +338,15 @@ split_range (GstRTSPAddressPool * pool, AddrRange * range, gint skip, } /* range now contains only one single address */ - if (skip > 0) { + if (skip_port > 0) { /* make a range with the skipped ports */ temp = g_slice_dup (AddrRange, range); - temp->max.port = temp->min.port + skip - 1; + temp->max.port = temp->min.port + skip_port - 1; /* and store back in pool */ priv->addresses = g_list_prepend (priv->addresses, temp); /* increment range port */ - range->min.port += skip; + range->min.port += skip_port; } /* range now contains single address with desired port number */ if (range->max.port - range->min.port + 1 > n_ports) { @@ -387,7 +419,7 @@ gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, /* we found a range, remove from the list */ priv->addresses = g_list_delete_link (priv->addresses, walk); /* now split and exit our loop */ - result = split_range (pool, range, skip, n_ports); + result = split_range (pool, range, 0, skip, n_ports); priv->allocated = g_list_prepend (priv->allocated, result); break; } @@ -495,3 +527,96 @@ gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool) g_list_foreach (priv->allocated, (GFunc) dump_range, pool); g_mutex_unlock (&priv->lock); } + +/** + * gst_rtsp_address_pool_reserve_address: + * @pool: a #GstRTSPAddressPool + * @address: The IP address to reserve + * @port: The first port to reserve + * @n_ports: The number of ports + * @ttl: The requested ttl + * + * Take a specific address and ports from @pool. @n_ports consecutive + * ports will be allocated of which the first one can be found in + * @port. + * + * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free + * after use or %NULL when no address could be acquired. + */ + +GstRTSPAddress * +gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, + const gchar * address, guint port, guint n_ports, guint ttl) +{ + GstRTSPAddressPoolPrivate *priv; + Addr input_addr; + GList *walk, *next; + AddrRange *result; + GstRTSPAddress *addr; + + g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), NULL); + g_return_val_if_fail (address != NULL, NULL); + g_return_val_if_fail (port > 0, NULL); + g_return_val_if_fail (n_ports > 0, NULL); + + priv = pool->priv; + result = NULL; + addr = NULL; + + if (!fill_address (address, port, &input_addr)) { + GST_ERROR_OBJECT (pool, "invalid address %s", address); + return NULL; + } + + g_mutex_lock (&priv->lock); + /* go over available ranges */ + for (walk = priv->addresses; walk; walk = next) { + AddrRange *range; + gint skip_port, skip_addr; + + range = walk->data; + next = walk->next; + + /* Not the right type of address */ + if (range->min.size != input_addr.size) + continue; + + /* Check that the address is in the interval */ + if (memcmp (range->min.bytes, input_addr.bytes, input_addr.size) > 0 || + memcmp (range->max.bytes, input_addr.bytes, input_addr.size) < 0) + continue; + + /* Make sure the requested ports are inside the range */ + if (port < range->min.port || port + n_ports - 1 > range->max.port) + continue; + + if (ttl != range->ttl) + continue; + + skip_addr = diff_address (&input_addr, &range->min); + skip_port = port - range->min.port; + + /* we found a range, remove from the list */ + priv->addresses = g_list_delete_link (priv->addresses, walk); + /* now split and exit our loop */ + result = split_range (pool, range, skip_addr, skip_port, n_ports); + priv->allocated = g_list_prepend (priv->allocated, result); + break; + } + g_mutex_unlock (&priv->lock); + + if (result) { + addr = g_slice_new0 (GstRTSPAddress); + addr->pool = g_object_ref (pool); + addr->address = get_address_string (&result->min); + addr->n_ports = n_ports; + addr->port = result->min.port; + addr->ttl = result->ttl; + addr->priv = result; + + GST_DEBUG_OBJECT (pool, "reserved address %s:%u ttl %u", addr->address, + addr->port, addr->ttl); + } + + return addr; +} diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index b8937907e9..2f7a80af75 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -96,6 +96,14 @@ gboolean gst_rtsp_address_pool_add_range (GstRTSPAddressPool GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, GstRTSPAddressFlags flags, gint n_ports); + +GstRTSPAddress * gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, + const gchar *address, + guint port, + guint n_ports, + guint ttl); + + G_END_DECLS #endif /* __GST_RTSP_ADDRESS_POOL_H__ */ diff --git a/tests/check/gst/addresspool.c b/tests/check/gst/addresspool.c index 9df35c74b5..4152a4485f 100644 --- a/tests/check/gst/addresspool.c +++ b/tests/check/gst/addresspool.c @@ -24,7 +24,7 @@ GST_START_TEST (test_pool) { GstRTSPAddressPool *pool; - GstRTSPAddress *addr, *addr2; + GstRTSPAddress *addr, *addr2, *addr3; pool = gst_rtsp_address_pool_new (); @@ -81,6 +81,7 @@ GST_START_TEST (test_pool) GST_RTSP_ADDRESS_FLAG_IPV6 | GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); fail_unless (addr != NULL); fail_unless (addr->port == 5002); + fail_unless (!g_ascii_strcasecmp (addr->address, "2001:DB8::1")); /* Will fail becuse there is only one IPv6 address left */ addr2 = gst_rtsp_address_pool_acquire_address (pool, @@ -103,15 +104,81 @@ GST_START_TEST (test_pool) GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); fail_unless (addr != NULL); fail_unless (addr->port == 5000); + fail_unless (!strcmp (addr->address, "233.252.0.0")); addr2 = gst_rtsp_address_pool_acquire_address (pool, GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); fail_unless (addr2 != NULL); fail_unless (addr2->port == 5000); + fail_unless (!strcmp (addr2->address, "233.252.0.1")); gst_rtsp_address_free (addr); gst_rtsp_address_free (addr2); + gst_rtsp_address_pool_clear (pool); + + + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.252.1.1", "233.252.1.1", 5000, 5001, 1)); + + addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 3, + 1); + fail_unless (addr == NULL); + + addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.2", 5000, 2, + 1); + fail_unless (addr == NULL); + + addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 500, 2, 1); + fail_unless (addr == NULL); + + addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2, + 2); + fail_unless (addr == NULL); + + addr = gst_rtsp_address_pool_reserve_address (pool, "2000::1", 5000, 2, 2); + fail_unless (addr == NULL); + + addr = gst_rtsp_address_pool_reserve_address (pool, "1.1", 5000, 2, 2); + fail_unless (addr == NULL); + + addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2, + 1); + fail_unless (addr != NULL); + fail_unless (addr->port == 5000); + fail_unless (!strcmp (addr->address, "233.252.1.1")); + + gst_rtsp_address_free (addr); + gst_rtsp_address_pool_clear (pool); + + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.252.1.1", "233.252.1.3", 5000, 5001, 1)); + + addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2, + 1); + fail_unless (addr != NULL); + fail_unless (addr->port == 5000); + fail_unless (!strcmp (addr->address, "233.252.1.1")); + + addr2 = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.3", 5000, 2, + 1); + fail_unless (addr2 != NULL); + fail_unless (addr2->port == 5000); + fail_unless (!strcmp (addr2->address, "233.252.1.3")); + + addr3 = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); + fail_unless (addr3 != NULL); + fail_unless (addr3->port == 5000); + fail_unless (!strcmp (addr3->address, "233.252.1.2")); + + fail_unless (gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2) == NULL); + + gst_rtsp_address_free (addr); + gst_rtsp_address_free (addr2); + gst_rtsp_address_free (addr3); + g_object_unref (pool); } From 773c48e22f0ec76d133679d6537a046bddcfccf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Wed, 13 Feb 2013 18:32:20 -0500 Subject: [PATCH 0587/1776] client: Check client provided addresses against the address pool --- gst/rtsp-server/rtsp-client.c | 14 +++++++- gst/rtsp-server/rtsp-stream.c | 67 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 6 ++++ 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 9da27ade80..4b4602c303 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1072,7 +1072,17 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, /* we have a valid transport now, set the destination of the client. */ if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - if (ct->destination == NULL || !priv->use_client_settings) { + if (ct->destination && priv->use_client_settings) { + GstRTSPAddress *addr; + + addr = gst_rtsp_stream_reserve_address (state->stream, ct->destination, + ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl); + + if (addr == NULL) + goto no_address; + + gst_rtsp_address_free (addr); + } else { GstRTSPAddress *addr; addr = gst_rtsp_stream_get_address (state->stream); @@ -1084,6 +1094,8 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, ct->port.min = addr->port; ct->port.max = addr->port + addr->n_ports - 1; ct->ttl = addr->ttl; + + gst_rtsp_address_free (addr); } } else { GstRTSPUrl *url; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index d1776e8e60..c0634bf694 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -342,6 +342,73 @@ no_address: } } +/** + * gst_rtsp_stream_reserve_address: + * @stream: a #GstRTSPStream + * + * Get a specific multicast address of @stream. + * + * Returns: the #GstRTSPAddress of @stream or %NULL when no address could be + * allocated. gst_rtsp_address_free() after usage. + */ +GstRTSPAddress * +gst_rtsp_stream_reserve_address (GstRTSPStream * stream, + const gchar * address, guint port, guint n_ports, guint ttl) +{ + GstRTSPStreamPrivate *priv; + GstRTSPAddress *result; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + g_return_val_if_fail (address != NULL, NULL); + g_return_val_if_fail (port > 0, NULL); + g_return_val_if_fail (n_ports > 0, NULL); + g_return_val_if_fail (ttl > 0, NULL); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if (priv->addr == NULL) { + if (priv->pool == NULL) + goto no_pool; + + priv->addr = gst_rtsp_address_pool_reserve_address (priv->pool, address, + port, n_ports, ttl); + if (priv->addr == NULL) + goto no_address; + } else { + if (strcmp (priv->addr->address, address) || + priv->addr->port != port || priv->addr->n_ports != n_ports || + priv->addr->ttl != ttl) + goto different_address; + } + result = gst_rtsp_address_copy (priv->addr); + g_mutex_unlock (&priv->lock); + + return result; + + /* ERRORS */ +no_pool: + { + GST_ERROR_OBJECT (stream, "no address pool specified"); + g_mutex_unlock (&priv->lock); + return NULL; + } +no_address: + { + GST_ERROR_OBJECT (stream, "failed to acquire address %s from pool", + address); + g_mutex_unlock (&priv->lock); + return NULL; + } +different_address: + { + GST_ERROR_OBJECT (stream, "address %s is not the same that was already" + " reserved", address); + g_mutex_unlock (&priv->lock); + return NULL; + } +} + /* must be called with lock */ static gboolean alloc_ports (GstRTSPStream * stream) diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 3367fe251c..ba3bf40810 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -74,6 +74,12 @@ GstRTSPAddressPool * GstRTSPAddress * gst_rtsp_stream_get_address (GstRTSPStream *stream); +GstRTSPAddress * gst_rtsp_stream_reserve_address (GstRTSPStream *stream, + const gchar * address, + guint port, + guint n_ports, + guint ttl); + gboolean gst_rtsp_stream_join_bin (GstRTSPStream *stream, GstBin *bin, GstElement *rtpbin, GstState state); From f0ab7ce1bffa1e0abae51702897725c1a4ea5ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Thu, 14 Feb 2013 13:38:07 -0500 Subject: [PATCH 0588/1776] docs: Generate docs for GstRTSPAddressPool --- docs/libs/gst-rtsp-server-docs.sgml | 1 + docs/libs/gst-rtsp-server-sections.txt | 22 ++++++++++++++++++++++ gst/rtsp-server/rtsp-address-pool.c | 4 ++++ gst/rtsp-server/rtsp-address-pool.h | 1 + 4 files changed, 28 insertions(+) diff --git a/docs/libs/gst-rtsp-server-docs.sgml b/docs/libs/gst-rtsp-server-docs.sgml index 5e0229952f..4f196973aa 100644 --- a/docs/libs/gst-rtsp-server-docs.sgml +++ b/docs/libs/gst-rtsp-server-docs.sgml @@ -25,6 +25,7 @@ + diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 0122798fee..7bb58df58e 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -353,3 +353,25 @@ GST_TYPE_RTSP_STREAM_TRANSPORT gst_rtsp_stream_transport_get_type
+
+rtsp-address-pool +GstRTSPAddressPool +GstRTSPAddressPool +gst_rtsp_address_pool_new +gst_rtsp_address_pool_add_range +gst_rtsp_address_pool_clear +gst_rtsp_address_pool_dump +gst_rtsp_address_pool_acquire_address +gst_rtsp_address_pool_reserve_address + +GstRTSPAddressPoolClass +GstRTSPAddressPoolPrivate +gst_rtsp_address_get_type +gst_rtsp_address_pool_get_type + +GstRTSPAddress +GstRTSPAddressClass +GstRTSPAddressFlags +gst_rtsp_address_copy +gst_rtsp_address_free +
diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 54fe834300..b064cf7514 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -372,6 +372,8 @@ split_range (GstRTSPAddressPool * pool, AddrRange * range, guint skip_addr, * allocation. @n_ports consecutive ports will be allocated of which the first * one can be found in @port. * + * This function should only be used internally. + * * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free * after use or %NULL when no address could be acquired. */ @@ -540,6 +542,8 @@ gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool) * ports will be allocated of which the first one can be found in * @port. * + * This function should only be used internally. + * * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free * after use or %NULL when no address could be acquired. */ diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index 2f7a80af75..001b3970ad 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -67,6 +67,7 @@ typedef enum { * GstRTSPAddressPool: * @parent: the parent GObject * + * An address pool, all member are prive */ struct _GstRTSPAddressPool { GObject parent; From 41951c4afd50879e575f7415a197819f7a89dd22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Thu, 14 Feb 2013 13:44:54 -0500 Subject: [PATCH 0589/1776] docs: Put the various functions in the right sections --- docs/libs/gst-rtsp-server-sections.txt | 62 +++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 7bb58df58e..350596b63a 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -8,6 +8,7 @@ gst_rtsp_mount_points_find_factory gst_rtsp_mount_points_add_factory gst_rtsp_mount_points_remove_factory +GstRTSPMountPointsPrivate GST_RTSP_MOUNT_POINTS_CLASS GST_RTSP_MOUNT_POINTS_CAST GST_RTSP_MOUNT_POINTS_CLASS_CAST @@ -52,6 +53,7 @@ GST_TYPE_RTSP_MEDIA_FACTORY gst_rtsp_media_factory_get_type GST_IS_RTSP_MEDIA_FACTORY_CLASS GST_RTSP_MEDIA_FACTORY_GET_CLASS +GstRTSPMediaFactoryPrivate
@@ -62,6 +64,8 @@ GstRTSPMediaFactoryURIClass gst_rtsp_media_factory_uri_new gst_rtsp_media_factory_uri_set_uri gst_rtsp_media_factory_uri_get_uri +gst_rtsp_media_factory_get_address_pool +gst_rtsp_media_factory_set_address_pool GST_IS_RTSP_MEDIA_FACTORY_URI GST_IS_RTSP_MEDIA_FACTORY_URI_CLASS @@ -72,6 +76,7 @@ GST_RTSP_MEDIA_FACTORY_URI_CLASS_CAST GST_RTSP_MEDIA_FACTORY_URI_GET_CLASS GST_TYPE_RTSP_MEDIA_FACTORY_URI gst_rtsp_media_factory_uri_get_type +GstRTSPMediaFactoryURIPrivate
@@ -108,6 +113,13 @@ gst_rtsp_media_get_stream gst_rtsp_media_seek gst_rtsp_media_get_range_string gst_rtsp_media_set_state + +gst_rtsp_media_get_status + +gst_rtsp_media_get_address_pool +gst_rtsp_media_set_address_pool + +gst_rtsp_media_take_pipeline GST_RTSP_MEDIA_CLASS GST_RTSP_MEDIA_CAST @@ -118,6 +130,7 @@ GST_TYPE_RTSP_MEDIA gst_rtsp_media_get_type GST_IS_RTSP_MEDIA_CLASS GST_RTSP_MEDIA_GET_CLASS +GstRTSPMediaPrivate
@@ -144,6 +157,8 @@ gst_rtsp_server_io_func gst_rtsp_server_create_socket gst_rtsp_server_create_source gst_rtsp_server_attach +gst_rtsp_server_get_max_threads +gst_rtsp_server_set_max_threads GST_RTSP_SERVER_GET_LOCK GST_RTSP_SERVER_LOCK @@ -157,6 +172,7 @@ GST_TYPE_RTSP_SERVER gst_rtsp_server_get_type GST_IS_RTSP_SERVER_CLASS GST_RTSP_SERVER_GET_CLASS +GstRTSPServerPrivate
@@ -177,6 +193,7 @@ gst_rtsp_session_pool_remove gst_rtsp_session_pool_filter gst_rtsp_session_pool_cleanup gst_rtsp_session_pool_create_watch +GstRTSPSessionPoolFilterFunc GST_RTSP_SESSION_POOL_CLASS GST_RTSP_SESSION_POOL_CAST @@ -187,6 +204,7 @@ GST_TYPE_RTSP_SESSION_POOL gst_rtsp_session_pool_get_type GST_IS_RTSP_SESSION_POOL_CLASS GST_RTSP_SESSION_POOL_GET_CLASS +GstRTSPSessionPoolPrivate
@@ -206,6 +224,8 @@ gst_rtsp_session_is_expired gst_rtsp_session_manage_media gst_rtsp_session_release_media gst_rtsp_session_get_media +gst_rtsp_session_get_header +gst_rtsp_session_filter GST_RTSP_SESSION_CLASS GST_RTSP_SESSION_CAST @@ -216,6 +236,7 @@ GST_TYPE_RTSP_SESSION gst_rtsp_session_get_type GST_IS_RTSP_SESSION_CLASS GST_RTSP_SESSION_GET_CLASS +GstRTSPSessionPrivate
@@ -227,6 +248,12 @@ gst_rtsp_session_media_new gst_rtsp_session_media_set_state gst_rtsp_session_media_get_transport gst_rtsp_session_media_alloc_channels + +gst_rtsp_session_media_get_media +gst_rtsp_session_media_get_rtsp_state +gst_rtsp_session_media_matches_url +gst_rtsp_session_media_set_rtsp_state +gst_rtsp_session_media_set_transport GST_RTSP_SESSION_MEDIA_CAST GST_RTSP_SESSION_MEDIA_CLASS_CAST @@ -237,6 +264,7 @@ GST_RTSP_SESSION_MEDIA_CLASS GST_RTSP_SESSION_MEDIA_GET_CLASS GST_TYPE_RTSP_SESSION_MEDIA gst_rtsp_session_media_get_type +GstRTSPSessionMediaPrivate
@@ -259,6 +287,7 @@ GST_RTSP_AUTH_CLASS_CAST GST_RTSP_AUTH_GET_CLASS GST_TYPE_RTSP_AUTH gst_rtsp_auth_get_type +GstRTSPAuthPrivate
@@ -278,6 +307,11 @@ gst_rtsp_client_set_auth gst_rtsp_client_get_auth gst_rtsp_client_accept gst_rtsp_client_create_from_socket +gst_rtsp_client_attach +gst_rtsp_client_handle_message +gst_rtsp_client_set_send_func +GstRTSPClientSendFunc +gst_rtsp_client_use_socket GST_RTSP_CLIENT_CLASS GST_RTSP_CLIENT_CAST @@ -288,6 +322,7 @@ GST_TYPE_RTSP_CLIENT gst_rtsp_client_get_type GST_IS_RTSP_CLIENT_CLASS GST_RTSP_CLIENT_GET_CLASS +GstRTSPClientPrivate
@@ -318,6 +353,13 @@ gst_rtsp_stream_recv_rtcp gst_rtsp_stream_recv_rtp gst_rtsp_stream_add_transport gst_rtsp_stream_remove_transport +gst_rtsp_stream_set_address_pool +gst_rtsp_stream_get_address_pool +gst_rtsp_stream_get_index +gst_rtsp_stream_get_server_port +gst_rtsp_stream_get_ssrc +gst_rtsp_stream_get_address +gst_rtsp_stream_reserve_address GST_RTSP_STREAM_CAST GST_RTSP_STREAM_CLASS_CAST @@ -328,6 +370,7 @@ GST_RTSP_STREAM_CLASS GST_RTSP_STREAM_GET_CLASS GST_TYPE_RTSP_STREAM gst_rtsp_stream_get_type +GstRTSPStreamPrivate
@@ -341,7 +384,15 @@ gst_rtsp_stream_transport_new gst_rtsp_stream_transport_set_callbacks gst_rtsp_stream_transport_set_keepalive gst_rtsp_stream_transport_set_transport - +gst_rtsp_stream_transport_get_stream +gst_rtsp_stream_transport_get_transport +gst_rtsp_stream_transport_is_timed_out +gst_rtsp_stream_transport_keep_alive +gst_rtsp_stream_transport_send_rtcp +gst_rtsp_stream_transport_send_rtp +gst_rtsp_stream_transport_set_active +gst_rtsp_stream_transport_set_timed_out + GST_RTSP_STREAM_TRANSPORT_CAST GST_RTSP_STREAM_TRANSPORT_CLASS_CAST GST_IS_RTSP_STREAM_TRANSPORT @@ -351,6 +402,7 @@ GST_RTSP_STREAM_TRANSPORT_CLASS GST_RTSP_STREAM_TRANSPORT_GET_CLASS GST_TYPE_RTSP_STREAM_TRANSPORT gst_rtsp_stream_transport_get_type +GstRTSPStreamTransportPrivate
@@ -368,6 +420,14 @@ GstRTSPAddressPoolClass GstRTSPAddressPoolPrivate gst_rtsp_address_get_type gst_rtsp_address_pool_get_type +GST_IS_RTSP_ADDRESS_POOL +GST_IS_RTSP_ADDRESS_POOL_CLASS +GST_RTSP_ADDRESS_POOL +GST_RTSP_ADDRESS_POOL_CAST +GST_RTSP_ADDRESS_POOL_CLASS +GST_RTSP_ADDRESS_POOL_CLASS_CAST +GST_RTSP_ADDRESS_POOL_GET_CLASS +GST_TYPE_RTSP_ADDRESS_POOL GstRTSPAddress GstRTSPAddressClass From 29d9878536dbc359fdd6225616193ffedd394f82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Thu, 14 Feb 2013 19:52:09 -0500 Subject: [PATCH 0590/1776] tests: Add tests for client-requested multicast address --- tests/check/gst/client.c | 327 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 59d5972725..e59e06a4a3 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -215,6 +215,328 @@ GST_START_TEST (test_describe) GST_END_TEST; +gchar *expected_transport = NULL;; + +static gboolean +test_setup_response_200_multicast (GstRTSPClient * client, + GstRTSPMessage * response, gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + gchar *str; + GstRTSPSessionPool *session_pool; + GstRTSPSession *session; + + fail_unless (expected_transport != NULL); + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_OK); + fail_unless (g_str_equal (reason, "OK")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, + 0) == GST_RTSP_OK); + fail_unless (atoi (str) == cseq++); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_TRANSPORT, + &str, 0) == GST_RTSP_OK); + + fail_unless (!strcmp (str, expected_transport)); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, + &str, 0) == GST_RTSP_OK); + + session_pool = gst_rtsp_client_get_session_pool (client); + fail_unless (session_pool != NULL); + + fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 1); + session = gst_rtsp_session_pool_find (session_pool, str); + fail_unless (session != NULL); + g_object_unref (session); + + g_object_unref (session_pool); + + + return TRUE; +} + +static GstRTSPClient * +setup_multicast_client (void) +{ + GstRTSPClient *client; + GstRTSPSessionPool *session_pool; + GstRTSPMountPoints *mount_points; + GstRTSPMediaFactory *factory; + GstRTSPAddressPool *address_pool; + + client = gst_rtsp_client_new (); + + session_pool = gst_rtsp_session_pool_new (); + gst_rtsp_client_set_session_pool (client, session_pool); + + mount_points = gst_rtsp_mount_points_new (); + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, + "audiotestsrc ! audio/x-raw,rate=44100 ! audioconvert ! rtpL16pay name=pay0"); + address_pool = gst_rtsp_address_pool_new (); + fail_unless (gst_rtsp_address_pool_add_range (address_pool, + "233.252.0.1", "233.252.0.1", 5000, 5010, 1)); + gst_rtsp_media_factory_set_address_pool (factory, address_pool); + gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); + gst_rtsp_client_set_mount_points (client, mount_points); + + g_object_unref (mount_points); + g_object_unref (session_pool); + g_object_unref (address_pool); + + return client; +} + +GST_START_TEST (test_client_multicast_transport_404) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = setup_multicast_client (); + + /* simple SETUP for non-existing url */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test2/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast"); + + gst_rtsp_client_set_send_func (client, test_response_404, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + g_object_unref (client); +} + +GST_END_TEST; + +GST_START_TEST (test_client_multicast_transport) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = setup_multicast_client (); + + /* simple SETUP with a valid URI and multicast */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast"); + + expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, + NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + expected_transport = NULL; + + g_object_unref (client); +} + +GST_END_TEST; + +GST_START_TEST (test_client_multicast_ignore_transport_specific) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = setup_multicast_client (); + + /* simple SETUP with a valid URI and multicast and a specific dest, + * but ignore it */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast;destination=233.252.0.2;ttl=2;port=5001-5006;"); + + expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, + NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + expected_transport = NULL; + + g_object_unref (client); +} + +GST_END_TEST; + +static gboolean +test_setup_response_461 (GstRTSPClient * client, + GstRTSPMessage * response, gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + gchar *str; + + fail_unless (expected_transport == NULL); + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_UNSUPPORTED_TRANSPORT); + fail_unless (g_str_equal (reason, "Unsupported transport")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, + 0) == GST_RTSP_OK); + fail_unless (atoi (str) == cseq++); + + + return TRUE; +} + +GST_START_TEST (test_client_multicast_invalid_transport_specific) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + GstRTSPSessionPool *session_pool; + + client = setup_multicast_client (); + + gst_rtsp_client_set_use_client_settings (client, TRUE); + fail_unless (gst_rtsp_client_get_use_client_settings (client)); + + + /* simple SETUP with a valid URI and multicast, but an invalid ip */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast;destination=233.252.0.2;ttl=1;port=5000-5001;"); + + gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + session_pool = gst_rtsp_client_get_session_pool (client); + fail_unless (session_pool != NULL); + /* FIXME: There seems to be a leak of a session here ! */ + /* fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); */ + g_object_unref (session_pool); + + + + /* simple SETUP with a valid URI and multicast, but an invalid prt */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast;destination=233.252.0.1;ttl=1;port=6000-6001;"); + + gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + session_pool = gst_rtsp_client_get_session_pool (client); + fail_unless (session_pool != NULL); + /* FIXME: There seems to be a leak of a session here ! */ + /* fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); */ + g_object_unref (session_pool); + + + + /* simple SETUP with a valid URI and multicast, but an invalid ttl */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast;destination=233.252.0.1;ttl=2;port=5000-5001;"); + + gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + session_pool = gst_rtsp_client_get_session_pool (client); + fail_unless (session_pool != NULL); + /* FIXME: There seems to be a leak of a session here ! */ + /* fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); */ + g_object_unref (session_pool); + + + g_object_unref (client); +} + +GST_END_TEST; + +GST_START_TEST (test_client_multicast_transport_specific) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + GstRTSPSessionPool *session_pool; + + client = setup_multicast_client (); + + gst_rtsp_client_set_use_client_settings (client, TRUE); + fail_unless (gst_rtsp_client_get_use_client_settings (client)); + + expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + + /* simple SETUP with a valid URI and multicast, but an invalid ip */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + expected_transport); + + gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, + NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + expected_transport = NULL; + + gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, + NULL, NULL); + session_pool = gst_rtsp_client_get_session_pool (client); + fail_unless (session_pool != NULL); + fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 1); + g_object_unref (session_pool); + + g_object_unref (client); +} + +GST_END_TEST; + + static Suite * rtspclient_suite (void) { @@ -226,6 +548,11 @@ rtspclient_suite (void) tcase_add_test (tc, test_request); tcase_add_test (tc, test_options); tcase_add_test (tc, test_describe); + tcase_add_test (tc, test_client_multicast_transport_404); + tcase_add_test (tc, test_client_multicast_transport); + tcase_add_test (tc, test_client_multicast_ignore_transport_specific); + tcase_add_test (tc, test_client_multicast_invalid_transport_specific); + tcase_add_test (tc, test_client_multicast_transport_specific); return s; } From 176f5dd0beaf600b02479e3545151516a00eb47f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 15 Feb 2013 20:02:31 -0500 Subject: [PATCH 0591/1776] tests: Test that slow DESCRIBE don't block other clients --- tests/check/gst/rtspserver.c | 115 ++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 3 deletions(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 835ae65e5c..71d8d7a78d 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -614,7 +614,8 @@ GST_START_TEST (test_setup_non_existing_stream) GST_END_TEST; -GST_START_TEST (test_play) +static void +do_test_play (void) { GstRTSPConnection *conn; GstSDPMessage *sdp_message = NULL; @@ -626,8 +627,6 @@ GST_START_TEST (test_play) GstRTSPTransport *video_transport = NULL; GstRTSPTransport *audio_transport = NULL; - start_server (); - conn = connect_to_server (test_port, TEST_MOUNT_POINT); sdp_message = do_describe (conn, TEST_MOUNT_POINT); @@ -661,6 +660,15 @@ GST_START_TEST (test_play) gst_rtsp_transport_free (audio_transport); gst_sdp_message_free (sdp_message); gst_rtsp_connection_free (conn); +} + + +GST_START_TEST (test_play) +{ + start_server (); + + do_test_play (); + stop_server (); iterate (); } @@ -723,6 +731,105 @@ GST_START_TEST (test_bind_already_in_use) GST_END_TEST; +GST_START_TEST (test_play_multithreaded) +{ + gst_rtsp_server_set_max_threads (server, -1); + + start_server (); + + do_test_play (); + + stop_server (); + iterate (); +} + +GST_END_TEST; + +enum +{ + BLOCK_ME, + BLOCKED, + UNBLOCK +}; + + +static void +media_constructed_block (GstRTSPMediaFactory * factory, + GstRTSPMedia * media, gpointer user_data) +{ + gint *block_state = user_data; + + g_mutex_lock (&check_mutex); + + *block_state = BLOCKED; + g_cond_broadcast (&check_cond); + + while (*block_state != UNBLOCK) + g_cond_wait (&check_cond, &check_mutex); + g_mutex_unlock (&check_mutex); +} + + +GST_START_TEST (test_play_multithreaded_block_in_describe) +{ + GstRTSPConnection *conn; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + gint block_state = BLOCK_ME; + GstRTSPMessage *request; + GstRTSPMessage *response; + GstRTSPStatusCode code; + + gst_rtsp_server_set_max_threads (server, 1); + + mounts = gst_rtsp_server_get_mount_points (server); + fail_unless (mounts != NULL); + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, + "( " VIDEO_PIPELINE " " AUDIO_PIPELINE " )"); + g_signal_connect (factory, "media-constructed", + G_CALLBACK (media_constructed_block), &block_state); + gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT "2", factory); + g_object_unref (mounts); + + start_server (); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT "2"); + iterate (); + + /* do describe, it will not return now as we've blocked it */ + request = create_request (conn, GST_RTSP_DESCRIBE, NULL); + fail_unless (send_request (conn, request)); + gst_rtsp_message_free (request); + + g_mutex_lock (&check_mutex); + while (block_state != BLOCKED) + g_cond_wait (&check_cond, &check_mutex); + g_mutex_unlock (&check_mutex); + + /* Do a second connection while the first one is blocked */ + do_test_play (); + + /* Now unblock the describe */ + g_mutex_lock (&check_mutex); + block_state = UNBLOCK; + g_cond_broadcast (&check_cond); + g_mutex_unlock (&check_mutex); + + response = read_response (conn); + gst_rtsp_message_parse_response (response, &code, NULL, NULL); + fail_unless (code == GST_RTSP_STS_OK); + gst_rtsp_message_free (response); + + + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); + +} + +GST_END_TEST; + static Suite * rtspserver_suite (void) { @@ -740,6 +847,8 @@ rtspserver_suite (void) tcase_add_test (tc, test_play); tcase_add_test (tc, test_play_without_session); tcase_add_test (tc, test_bind_already_in_use); + tcase_add_test (tc, test_play_multithreaded); + tcase_add_test (tc, test_play_multithreaded_block_in_describe); return s; } From b9d111372e57d2d822099271fd51ff72349d3b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Mon, 18 Feb 2013 14:59:58 -0500 Subject: [PATCH 0592/1776] Document locking and its order --- gst/rtsp-server/rtsp-address-pool.c | 2 +- gst/rtsp-server/rtsp-auth.c | 2 +- gst/rtsp-server/rtsp-client.c | 14 +++++++++----- gst/rtsp-server/rtsp-media-factory-uri.c | 2 +- gst/rtsp-server/rtsp-media-factory.c | 6 +++--- gst/rtsp-server/rtsp-media.c | 13 +++++++------ gst/rtsp-server/rtsp-mount-points.c | 2 +- gst/rtsp-server/rtsp-server.c | 2 +- gst/rtsp-server/rtsp-session-media.c | 10 +++++----- gst/rtsp-server/rtsp-session-pool.c | 3 +-- gst/rtsp-server/rtsp-session.c | 4 ++-- 11 files changed, 32 insertions(+), 28 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index b064cf7514..375c25d351 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -67,7 +67,7 @@ GST_DEBUG_CATEGORY_STATIC (rtsp_address_pool_debug); struct _GstRTSPAddressPoolPrivate { - GMutex lock; + GMutex lock; /* protects everything in this struct */ GList *addresses; GList *allocated; }; diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 5a156fbd31..faaf0f7e52 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -27,7 +27,7 @@ struct _GstRTSPAuthPrivate { GMutex lock; - gchar *basic; + gchar *basic; /* protected by lock */ GstRTSPMethod methods; }; diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4b4602c303..1bb43c1098 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -27,9 +27,13 @@ #define GST_RTSP_CLIENT_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_CLIENT, GstRTSPClientPrivate)) +/* locking order: + * send_lock, lock, tunnels_lock + */ + struct _GstRTSPClientPrivate { - GMutex lock; + GMutex lock; /* protects everything else */ GMutex send_lock; GstRTSPConnection *connection; GstRTSPWatch *watch; @@ -38,9 +42,9 @@ struct _GstRTSPClientPrivate gboolean is_ipv6; gboolean use_client_settings; - GstRTSPClientSendFunc send_func; - gpointer send_data; - GDestroyNotify send_notify; + GstRTSPClientSendFunc send_func; /* protected by send_lock */ + gpointer send_data; /* protected by send_lock */ + GDestroyNotify send_notify; /* protected by send_lock */ GstRTSPSessionPool *session_pool; GstRTSPMountPoints *mount_points; @@ -54,7 +58,7 @@ struct _GstRTSPClientPrivate }; static GMutex tunnels_lock; -static GHashTable *tunnels; +static GHashTable *tunnels; /* protected by tunnels_lock */ #define DEFAULT_SESSION_POOL NULL #define DEFAULT_MOUNT_POINTS NULL diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index c83d87da4b..e2e80d93ef 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -27,7 +27,7 @@ struct _GstRTSPMediaFactoryURIPrivate { GMutex lock; - gchar *uri; + gchar *uri; /* protected by lock */ gboolean use_gstpay; GstCaps *raw_vcaps; diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index cd4b1a7388..ced81ecde3 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -28,7 +28,7 @@ struct _GstRTSPMediaFactoryPrivate { - GMutex lock; + GMutex lock; /* protects everything but medias */ gchar *launch; gboolean shared; gboolean eos_shutdown; @@ -38,7 +38,7 @@ struct _GstRTSPMediaFactoryPrivate GstRTSPAddressPool *pool; GMutex medias_lock; - GHashTable *medias; + GHashTable *medias; /* protected by medias_lock */ }; #define DEFAULT_LAUNCH NULL @@ -799,9 +799,9 @@ no_launch: } parse_error: { - GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); g_critical ("could not parse launch syntax (%s): %s", priv->launch, (error ? error->message : "unknown reason")); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); if (error) g_error_free (error); return NULL; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 10610ffd03..9826a1d45e 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -33,6 +33,7 @@ struct _GstRTSPMediaPrivate GMutex lock; GCond cond; + /* protected by lock */ gboolean shared; gboolean reusable; GstRTSPLowerTrans protocols; @@ -43,17 +44,17 @@ struct _GstRTSPMediaPrivate GstRTSPAddressPool *pool; GstElement *element; - GRecMutex state_lock; - GPtrArray *streams; - GList *dynamic; - GstRTSPMediaStatus status; + GRecMutex state_lock; /* locking order: state lock, lock */ + GPtrArray *streams; /* protected by lock */ + GList *dynamic; /* protected by lock */ + GstRTSPMediaStatus status; /* protected by lock */ gint prepare_count; gint n_active; gboolean adding; /* the pipeline for the media */ GstElement *pipeline; - GstElement *fakesink; + GstElement *fakesink; /* protected by lock */ GSource *source; guint id; @@ -66,7 +67,7 @@ struct _GstRTSPMediaPrivate GstElement *rtpbin; /* the range of media */ - GstRTSPTimeRange range; + GstRTSPTimeRange range; /* protected by lock */ GstClockTime range_start; GstClockTime range_stop; }; diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index c18cb63d1d..3d3b61c392 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -25,7 +25,7 @@ struct _GstRTSPMountPointsPrivate { GMutex lock; - GHashTable *mounts; + GHashTable *mounts; /* protected by lock */ }; G_DEFINE_TYPE (GstRTSPMountPoints, gst_rtsp_mount_points, G_TYPE_OBJECT); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index f66b23a48b..f41b390e27 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -32,7 +32,7 @@ struct _GstRTSPServerPrivate { - GMutex lock; + GMutex lock; /* protects everything in this struct */ /* server information */ gchar *address; diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index fb4d71c455..d708163061 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -26,12 +26,12 @@ struct _GstRTSPSessionMediaPrivate { GMutex lock; - GstRTSPUrl *url; - GstRTSPMedia *media; - GstRTSPState state; - guint counter; + GstRTSPUrl *url; /* unmutable */ + GstRTSPMedia *media; /* unmutable */ + GstRTSPState state; /* protected by lock */ + guint counter; /* protected by lock */ - GPtrArray *transports; + GPtrArray *transports; /* protected by lock */ }; enum diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 2fe209f9b9..c4709c5c00 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -24,9 +24,8 @@ struct _GstRTSPSessionPoolPrivate { + GMutex lock; /* protects everything in this struct */ guint max_sessions; - - GMutex lock; GHashTable *sessions; }; diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index f50a476140..87d03ffd05 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -25,11 +25,11 @@ struct _GstRTSPSessionPrivate { - GMutex lock; + GMutex lock; /* protects everything but sessionid and create_time */ gchar *sessionid; guint timeout; - GTimeVal create_time; + GTimeVal create_time; /* immutable */ GTimeVal last_access; gint expire_count; From 2e111841714049a4ca30b91abc943df16826101a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Mon, 18 Feb 2013 20:15:41 -0500 Subject: [PATCH 0593/1776] tests: Test client and session timeouts with multiple threads --- tests/check/gst/rtspserver.c | 191 ++++++++++++++++++++++++++++++++++- 1 file changed, 190 insertions(+), 1 deletion(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 71d8d7a78d..3464f2f0c0 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -305,11 +305,20 @@ do_request (GstRTSPConnection * conn, GstRTSPMethod method, } if (session_out) { gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &value, 0); + + value = g_strdup (value); + + /* Remove the timeout */ + if (value) { + char *pos = strchr (value, ';'); + if (pos) + *pos = 0; + } if (session_in) { /* check that we got the same session back */ fail_unless (!g_strcmp0 (value, session_in)); } - *session_out = g_strdup (value); + *session_out = value; } if (transport_out) { gst_rtsp_message_get_header (response, GST_RTSP_HDR_TRANSPORT, &value, 0); @@ -830,6 +839,184 @@ GST_START_TEST (test_play_multithreaded_block_in_describe) GST_END_TEST; + +static void +new_session_timeout_one (GstRTSPClient * client, + GstRTSPSession * session, gpointer user_data) +{ + gst_rtsp_session_set_timeout (session, 1); + + g_signal_handlers_disconnect_by_func (client, new_session_timeout_one, + user_data); +} + +static void +session_connected_new_session_cb (GstRTSPServer * server, + GstRTSPClient * client, gpointer user_data) +{ + + g_signal_connect (client, "new-session", user_data, NULL); +} + +GST_START_TEST (test_play_multithreaded_timeout_client) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + const gchar *audio_control; + GstRTSPRange client_port; + gchar *session = NULL; + GstRTSPTransport *video_transport = NULL; + GstRTSPTransport *audio_transport = NULL; + GstRTSPSessionPool *pool; + GstRTSPMessage *request; + GstRTSPMessage *response; + + gst_rtsp_server_set_max_threads (server, -1); + pool = gst_rtsp_server_get_session_pool (server); + g_signal_connect (server, "client-connected", + G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one); + + start_server (); + + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + sdp_media = gst_sdp_message_get_media (sdp_message, 1); + audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports (&client_port); + + /* do SETUP for video and audio */ + fail_unless (do_setup (conn, video_control, &client_port, &session, + &video_transport) == GST_RTSP_STS_OK); + fail_unless (do_setup (conn, audio_control, &client_port, &session, + &audio_transport) == GST_RTSP_STS_OK); + + fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 1); + + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_PLAY, + session) == GST_RTSP_STS_OK); + + sleep (7); + + fail_unless (gst_rtsp_session_pool_cleanup (pool) == 1); + + + /* send TEARDOWN request and check that we get 454 Session Not found */ + request = create_request (conn, GST_RTSP_TEARDOWN, NULL); + gst_rtsp_message_add_header (request, GST_RTSP_HDR_SESSION, session); + fail_unless (send_request (conn, request)); + gst_rtsp_message_free (request); + + fail_unless (gst_rtsp_message_new (&response) == GST_RTSP_OK); + fail_unless (gst_rtsp_connection_receive (conn, response, NULL) == + GST_RTSP_ESYS); + fail_unless (errno == ECONNRESET); + gst_rtsp_message_free (response); + + /* clean up and iterate so the clean-up can finish */ + g_object_unref (pool); + g_free (session); + gst_rtsp_transport_free (video_transport); + gst_rtsp_transport_free (audio_transport); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + + stop_server (); + iterate (); +} + +GST_END_TEST; + + +GST_START_TEST (test_play_multithreaded_timeout_session) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + const gchar *audio_control; + GstRTSPRange client_port; + gchar *session1 = NULL; + gchar *session2 = NULL; + GstRTSPTransport *video_transport = NULL; + GstRTSPTransport *audio_transport = NULL; + GstRTSPSessionPool *pool; + + gst_rtsp_server_set_max_threads (server, -1); + pool = gst_rtsp_server_get_session_pool (server); + g_signal_connect (server, "client-connected", + G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one); + + start_server (); + + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + gst_rtsp_connection_set_remember_session_id (conn, FALSE); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + sdp_media = gst_sdp_message_get_media (sdp_message, 1); + audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports (&client_port); + + /* do SETUP for video and audio */ + fail_unless (do_setup (conn, video_control, &client_port, &session1, + &video_transport) == GST_RTSP_STS_OK); + fail_unless (do_setup (conn, audio_control, &client_port, &session2, + &audio_transport) == GST_RTSP_STS_OK); + + fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 2); + + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_PLAY, + session1) == GST_RTSP_STS_OK); + fail_unless (do_simple_request (conn, GST_RTSP_PLAY, + session2) == GST_RTSP_STS_OK); + + sleep (7); + + fail_unless (gst_rtsp_session_pool_cleanup (pool) == 1); + + /* send TEARDOWN request and check that we get 454 Session Not found */ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session1) == GST_RTSP_STS_SESSION_NOT_FOUND); + + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session2) == GST_RTSP_STS_OK); + + /* clean up and iterate so the clean-up can finish */ + g_object_unref (pool); + g_free (session1); + g_free (session2); + gst_rtsp_transport_free (video_transport); + gst_rtsp_transport_free (audio_transport); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + + stop_server (); + iterate (); +} + +GST_END_TEST; + + + static Suite * rtspserver_suite (void) { @@ -849,6 +1036,8 @@ rtspserver_suite (void) tcase_add_test (tc, test_bind_already_in_use); tcase_add_test (tc, test_play_multithreaded); tcase_add_test (tc, test_play_multithreaded_block_in_describe); + tcase_add_test (tc, test_play_multithreaded_timeout_client); + tcase_add_test (tc, test_play_multithreaded_timeout_session); return s; } From dcc92cbde12ad4c591ca8c67648bba82fb22b01f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Mon, 18 Feb 2013 20:22:18 -0500 Subject: [PATCH 0594/1776] tests: Add test for client disconnection --- tests/check/gst/rtspserver.c | 66 ++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 3464f2f0c0..524ca7fa71 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1017,6 +1017,71 @@ GST_END_TEST; +GST_START_TEST (test_play_disconnect) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + const gchar *audio_control; + GstRTSPRange client_port; + gchar *session = NULL; + GstRTSPTransport *video_transport = NULL; + GstRTSPTransport *audio_transport = NULL; + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + g_signal_connect (server, "client-connected", + G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one); + + start_server (); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + sdp_media = gst_sdp_message_get_media (sdp_message, 1); + audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports (&client_port); + + /* do SETUP for video and audio */ + fail_unless (do_setup (conn, video_control, &client_port, &session, + &video_transport) == GST_RTSP_STS_OK); + fail_unless (do_setup (conn, audio_control, &client_port, &session, + &audio_transport) == GST_RTSP_STS_OK); + + fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 1); + + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_PLAY, + session) == GST_RTSP_STS_OK); + + gst_rtsp_connection_free (conn); + + sleep (7); + + fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 1); + fail_unless (gst_rtsp_session_pool_cleanup (pool) == 1); + + + /* clean up and iterate so the clean-up can finish */ + g_object_unref (pool); + g_free (session); + gst_rtsp_transport_free (video_transport); + gst_rtsp_transport_free (audio_transport); + gst_sdp_message_free (sdp_message); + + stop_server (); + iterate (); +} + +GST_END_TEST; + static Suite * rtspserver_suite (void) { @@ -1038,6 +1103,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_play_multithreaded_block_in_describe); tcase_add_test (tc, test_play_multithreaded_timeout_client); tcase_add_test (tc, test_play_multithreaded_timeout_session); + tcase_add_test (tc, test_play_disconnect); return s; } From 4071e1b9990c6f1d0958bf5c635a0c4699f73581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 19 Feb 2013 12:31:23 -0500 Subject: [PATCH 0595/1776] rtsp-server: No need to store the GMainContext in the client context --- gst/rtsp-server/rtsp-server.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index f41b390e27..9ab709ee25 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -916,14 +916,12 @@ struct _ClientContext { GstRTSPServer *server; GMainLoop *loop; - GMainContext *context; GstRTSPClient *client; }; static void free_client_context (ClientContext * ctx) { - g_main_context_unref (ctx->context); if (ctx->loop) g_main_loop_unref (ctx->loop); g_object_unref (ctx->client); @@ -971,6 +969,7 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) { ClientContext *ctx; GstRTSPServerPrivate *priv = server->priv; + GMainContext *mainctx; GST_DEBUG_OBJECT (server, "manage client %p", client); @@ -982,14 +981,15 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) /* find the context to add the watch */ if ((source = g_main_current_source ())) - ctx->context = g_main_context_ref (g_source_get_context (source)); + mainctx = g_source_get_context (source); else - ctx->context = NULL; + mainctx = NULL; } else { - ctx->context = g_main_context_new (); - ctx->loop = g_main_loop_new (ctx->context, TRUE); + mainctx = g_main_context_new (); + ctx->loop = g_main_loop_new (mainctx, TRUE); + g_main_context_unref (mainctx); } - gst_rtsp_client_attach (client, ctx->context); + gst_rtsp_client_attach (client, mainctx); GST_RTSP_SERVER_LOCK (server); g_signal_connect (client, "closed", (GCallback) unmanage_client, ctx); From 4c61c6d308f4102259148bc9c1f2771fcadd3532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 19 Feb 2013 13:19:41 -0500 Subject: [PATCH 0596/1776] rtsp-server: Limit the number of threads per server instance If we exceed the maximum, just round robin the clients over the existing threads. --- configure.ac | 2 +- gst/rtsp-server/rtsp-server.c | 108 +++++++++++++++++++++++++++------- tests/check/gst/rtspserver.c | 8 +-- 3 files changed, 92 insertions(+), 26 deletions(-) diff --git a/configure.ac b/configure.ac index 2728f15ff7..0a07f73d2e 100644 --- a/configure.ac +++ b/configure.ac @@ -106,7 +106,7 @@ dnl *** checks for library functions *** dnl *** checks for dependancy libraries *** dnl GLib is required (GStreamer is ok with GLib-2.8, but we want at least 2.10) -GLIB_REQ=2.10.0 +GLIB_REQ=2.32.0 AC_SUBST([GLIB_REQ]) AG_GST_GLIB_CHECK([$GLIB_REQ]) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 9ab709ee25..ccfcf498e2 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -53,6 +53,7 @@ struct _GstRTSPServerPrivate /* the clients that are connected */ GList *clients; + GQueue loops; /* the main loops used in the threads */ }; #define DEFAULT_ADDRESS "0.0.0.0" @@ -93,6 +94,7 @@ GST_DEBUG_CATEGORY_STATIC (rtsp_server_debug); #define GST_CAT_DEFAULT rtsp_server_debug typedef struct _ClientContext ClientContext; +typedef struct _Loop Loop; static guint gst_rtsp_server_signals[SIGNAL_LAST] = { 0 }; @@ -102,7 +104,7 @@ static void gst_rtsp_server_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_server_finalize (GObject * object); -static gpointer do_loop (ClientContext * ctx); +static gpointer do_loop (Loop * loop); static GstRTSPClient *default_create_client (GstRTSPServer * server); static gboolean default_accept_client (GstRTSPServer * server, GstRTSPClient * client, GSocket * socket, GError ** error); @@ -231,6 +233,7 @@ gst_rtsp_server_init (GstRTSPServer * server) priv->session_pool = gst_rtsp_session_pool_new (); priv->mount_points = gst_rtsp_mount_points_new (); priv->max_threads = DEFAULT_MAX_THREADS; + g_queue_init (&priv->loops); } static void @@ -912,34 +915,95 @@ close_error: } } +struct _Loop +{ + gint refcnt; + + GstRTSPServer *server; + GMainLoop *mainloop; + GMainContext *mainctx; +}; + +/* must be called with the lock held */ +static void +loop_unref (Loop * loop) +{ + GstRTSPServer *server = loop->server; + GstRTSPServerPrivate *priv = server->priv; + + loop->refcnt--; + + if (loop->refcnt <= 0) { + g_queue_remove (&priv->loops, loop); + g_main_loop_quit (loop->mainloop); + } +} + struct _ClientContext { GstRTSPServer *server; - GMainLoop *loop; + Loop *loop; GstRTSPClient *client; }; -static void +static gboolean free_client_context (ClientContext * ctx) { + GST_RTSP_SERVER_LOCK (ctx->server); if (ctx->loop) - g_main_loop_unref (ctx->loop); + loop_unref (ctx->loop); + GST_RTSP_SERVER_UNLOCK (ctx->server); + g_object_unref (ctx->client); g_slice_free (ClientContext, ctx); + + return G_SOURCE_REMOVE; } static gpointer -do_loop (ClientContext * ctx) +do_loop (Loop * loop) { GST_INFO ("enter mainloop"); - g_main_loop_run (ctx->loop); + g_main_loop_run (loop->mainloop); GST_INFO ("exit mainloop"); - free_client_context (ctx); + g_main_context_unref (loop->mainctx); + g_main_loop_unref (loop->mainloop); + g_object_unref (loop->server); + g_slice_free (Loop, loop); return NULL; } +/* Must be called with lock held */ + +static Loop * +gst_rtsp_server_get_main_loop (GstRTSPServer * server) +{ + GstRTSPServerPrivate *priv = server->priv; + Loop *loop; + + if (priv->max_threads > 0 && + g_queue_get_length (&priv->loops) >= priv->max_threads) { + loop = g_queue_pop_head (&priv->loops); + loop->refcnt++; + } else { + GstRTSPServerClass *klass = GST_RTSP_SERVER_GET_CLASS (server); + + loop = g_slice_new0 (Loop); + loop->refcnt = 1; + loop->server = g_object_ref (server); + loop->mainctx = g_main_context_new (); + loop->mainloop = g_main_loop_new (loop->mainctx, FALSE); + + g_thread_pool_push (klass->pool, loop, NULL); + } + + g_queue_push_tail (&priv->loops, loop); + + return loop; +} + static void unmanage_client (GstRTSPClient * client, ClientContext * ctx) { @@ -954,10 +1018,16 @@ unmanage_client (GstRTSPClient * client, ClientContext * ctx) priv->clients = g_list_remove (priv->clients, ctx); GST_RTSP_SERVER_UNLOCK (server); - if (ctx->loop) - g_main_loop_quit (ctx->loop); - else + if (ctx->loop) { + GSource *src; + + src = g_idle_source_new (); + g_source_set_callback (src, (GSourceFunc) free_client_context, ctx, NULL); + g_source_attach (src, ctx->loop->mainctx); + g_source_unref (src); + } else { free_client_context (ctx); + } g_object_unref (server); } @@ -976,6 +1046,8 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) ctx = g_slice_new0 (ClientContext); ctx->server = server; ctx->client = client; + + GST_RTSP_SERVER_LOCK (server); if (priv->max_threads == 0) { GSource *source; @@ -985,22 +1057,16 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) else mainctx = NULL; } else { - mainctx = g_main_context_new (); - ctx->loop = g_main_loop_new (mainctx, TRUE); - g_main_context_unref (mainctx); + ctx->loop = gst_rtsp_server_get_main_loop (server); + mainctx = ctx->loop->mainctx; } - gst_rtsp_client_attach (client, mainctx); - GST_RTSP_SERVER_LOCK (server); g_signal_connect (client, "closed", (GCallback) unmanage_client, ctx); priv->clients = g_list_prepend (priv->clients, ctx); + + gst_rtsp_client_attach (client, mainctx); + GST_RTSP_SERVER_UNLOCK (server); - - if (ctx->loop) { - GstRTSPServerClass *klass = GST_RTSP_SERVER_GET_CLASS (server); - - g_thread_pool_push (klass->pool, ctx, NULL); - } } static GstRTSPClient * diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 524ca7fa71..9cd07ad627 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -742,7 +742,7 @@ GST_END_TEST; GST_START_TEST (test_play_multithreaded) { - gst_rtsp_server_set_max_threads (server, -1); + gst_rtsp_server_set_max_threads (server, 2); start_server (); @@ -789,7 +789,7 @@ GST_START_TEST (test_play_multithreaded_block_in_describe) GstRTSPMessage *response; GstRTSPStatusCode code; - gst_rtsp_server_set_max_threads (server, 1); + gst_rtsp_server_set_max_threads (server, 2); mounts = gst_rtsp_server_get_mount_points (server); fail_unless (mounts != NULL); @@ -873,7 +873,7 @@ GST_START_TEST (test_play_multithreaded_timeout_client) GstRTSPMessage *request; GstRTSPMessage *response; - gst_rtsp_server_set_max_threads (server, -1); + gst_rtsp_server_set_max_threads (server, 2); pool = gst_rtsp_server_get_session_pool (server); g_signal_connect (server, "client-connected", G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one); @@ -952,7 +952,7 @@ GST_START_TEST (test_play_multithreaded_timeout_session) GstRTSPTransport *audio_transport = NULL; GstRTSPSessionPool *pool; - gst_rtsp_server_set_max_threads (server, -1); + gst_rtsp_server_set_max_threads (server, 2); pool = gst_rtsp_server_get_session_pool (server); g_signal_connect (server, "client-connected", G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one); From d06e68abd112d88f04c3840c11b28003c3d3584e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 19 Feb 2013 16:34:16 -0500 Subject: [PATCH 0597/1776] address-pool: Add unicast addresses --- docs/libs/gst-rtsp-server-sections.txt | 4 ++ gst/rtsp-server/rtsp-address-pool.c | 62 ++++++++++++++++++++++++++ gst/rtsp-server/rtsp-address-pool.h | 28 +++++++++++- gst/rtsp-server/rtsp-stream.c | 2 +- tests/check/gst/addresspool.c | 26 ++++++----- 5 files changed, 110 insertions(+), 12 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 350596b63a..e536a7ddfb 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -411,10 +411,14 @@ GstRTSPStreamTransportPrivate GstRTSPAddressPool gst_rtsp_address_pool_new gst_rtsp_address_pool_add_range +GST_RTSP_ADDRESS_POOL_ANY_IPV4 +GST_RTSP_ADDRESS_POOL_ANY_IPV6 +gst_rtsp_address_pool_add_range_unicast gst_rtsp_address_pool_clear gst_rtsp_address_pool_dump gst_rtsp_address_pool_acquire_address gst_rtsp_address_pool_reserve_address +gst_rtsp_address_pool_has_unicast_addresses GstRTSPAddressPoolClass GstRTSPAddressPoolPrivate diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 375c25d351..c339ac5ff7 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -70,6 +70,8 @@ struct _GstRTSPAddressPoolPrivate GMutex lock; /* protects everything in this struct */ GList *addresses; GList *allocated; + + gboolean has_unicast_addresses; }; #define ADDR_IS_IPV4(a) ((a)->size == 4) @@ -258,6 +260,9 @@ gst_rtsp_address_pool_add_range (GstRTSPAddressPool * pool, g_mutex_lock (&priv->lock); priv->addresses = g_list_prepend (priv->addresses, range); + + if (ttl == 0) + priv->has_unicast_addresses = TRUE; g_mutex_unlock (&priv->lock); return TRUE; @@ -272,6 +277,33 @@ invalid: } } +/** + * gst_rtsp_address_pool_add_range_unicast: + * @pool: a #GstRTSPAddressPool + * @min_address: a minimum address to add + * @max_address: a maximum address to add + * @min_port: the minimum port + * @max_port: the maximum port + * + * Adds the unicast addresses from @min_addess to @max_address (inclusive) + * to @pool. The valid port range for the addresses will be from @min_port to + * @max_port inclusive. + * + * @min_address and @max_address can be set to + * #GST_RTSP_ADDRESS_POOL_ANY_IPV4 or #GST_RTSP_ADDRESS_POOL_ANY_IPV6 to bind + * to all available IPv4 or IPv6 addresses. + * + * Returns: %TRUE if the addresses could be added. + */ +gboolean +gst_rtsp_address_pool_add_range_unicast (GstRTSPAddressPool * pool, + const gchar * min_address, const gchar * max_address, + guint16 min_port, guint16 max_port) +{ + return gst_rtsp_address_pool_add_range (pool, min_address, max_address, + min_port, max_port, 0); +} + /* increments the address by count */ static void @@ -407,6 +439,10 @@ gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, continue; if (flags & GST_RTSP_ADDRESS_FLAG_IPV6 && !ADDR_IS_IPV6 (&range->min)) continue; + if (flags & GST_RTSP_ADDRESS_FLAG_MULTICAST && range->ttl == 0) + continue; + if (flags & GST_RTSP_ADDRESS_FLAG_UNICAST && range->ttl != 0) + continue; /* check for enough ports */ ports = range->max.port - range->min.port + 1; @@ -624,3 +660,29 @@ gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, return addr; } + +/** + * gst_rtsp_address_pool_has_unicast_addresses: + * @pool: a #GstRTSPAddressPool + * + * Used to know if the pool includes any unicast addresses. + * + * Returns: %TRUE if the pool includes any unicast addresses, %FALSE otherwise + */ + +gboolean +gst_rtsp_address_pool_has_unicast_addresses (GstRTSPAddressPool * pool) +{ + GstRTSPAddressPoolPrivate *priv; + gboolean has_unicast_addresses; + + g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), FALSE); + + priv = pool->priv; + + g_mutex_lock (&priv->lock); + has_unicast_addresses = priv->has_unicast_addresses; + g_mutex_unlock (&priv->lock); + + return has_unicast_addresses; +} diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index 001b3970ad..9a0cb8c8c5 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -60,9 +60,28 @@ typedef enum { GST_RTSP_ADDRESS_FLAG_NONE = 0, GST_RTSP_ADDRESS_FLAG_IPV4 = (1 << 0), GST_RTSP_ADDRESS_FLAG_IPV6 = (1 << 1), - GST_RTSP_ADDRESS_FLAG_EVEN_PORT = (1 << 2) + GST_RTSP_ADDRESS_FLAG_EVEN_PORT = (1 << 2), + GST_RTSP_ADDRESS_FLAG_MULTICAST = (1 << 3), + GST_RTSP_ADDRESS_FLAG_UNICAST = (1 << 4), } GstRTSPAddressFlags; +/** + * GST_RTSP_ADDRESS_POOL_ANY_IPV4: + * + * Used with gst_rtsp_address_pool_add_range_unicast() to bind to all + * IPv4 addresses + */ + +/** + * GST_RTSP_ADDRESS_POOL_ANY_IPV6: + * + * Used with gst_rtsp_address_pool_add_range_unicast() to bind to all + * IPv6 addresses + */ + +#define GST_RTSP_ADDRESS_POOL_ANY_IPV4 "0.0.0.0" +#define GST_RTSP_ADDRESS_POOL_ANY_IPV6 "::" + /** * GstRTSPAddressPool: * @parent: the parent GObject @@ -94,6 +113,12 @@ gboolean gst_rtsp_address_pool_add_range (GstRTSPAddressPool guint16 max_port, guint8 ttl); +gboolean gst_rtsp_address_pool_add_range_unicast (GstRTSPAddressPool * pool, + const gchar *min_address, + const gchar *max_address, + guint16 min_port, + guint16 max_port); + GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, GstRTSPAddressFlags flags, gint n_ports); @@ -104,6 +129,7 @@ GstRTSPAddress * gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool guint n_ports, guint ttl); +gboolean gst_rtsp_address_pool_has_unicast_addresses (GstRTSPAddressPool * pool); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index c0634bf694..4a13c2db5b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -318,7 +318,7 @@ gst_rtsp_stream_get_address (GstRTSPStream * stream) goto no_pool; priv->addr = gst_rtsp_address_pool_acquire_address (priv->pool, - GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); + GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST, 2); if (priv->addr == NULL) goto no_address; } diff --git a/tests/check/gst/addresspool.c b/tests/check/gst/addresspool.c index 4152a4485f..3341e48094 100644 --- a/tests/check/gst/addresspool.c +++ b/tests/check/gst/addresspool.c @@ -47,10 +47,12 @@ GST_START_TEST (test_pool) "233.255.0.0", "233.255.0.0", 5020, 5020, 1)); /* should fail, we can't allocate a block of 256 ports */ - addr = gst_rtsp_address_pool_acquire_address (pool, 0, 256); + addr = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_MULTICAST, 256); fail_unless (addr == NULL); - addr = gst_rtsp_address_pool_acquire_address (pool, 0, 2); + addr = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_MULTICAST, 2); fail_unless (addr != NULL); addr2 = gst_rtsp_address_copy (addr); @@ -58,7 +60,8 @@ GST_START_TEST (test_pool) gst_rtsp_address_free (addr2); gst_rtsp_address_free (addr); - addr = gst_rtsp_address_pool_acquire_address (pool, 0, 4); + addr = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_MULTICAST, 4); fail_unless (addr != NULL); /* Will fail because pool is NULL */ @@ -78,19 +81,21 @@ GST_START_TEST (test_pool) "2001:DB8::1", "2001:DB8::1", 5001, 5003, 1)); addr = gst_rtsp_address_pool_acquire_address (pool, - GST_RTSP_ADDRESS_FLAG_IPV6 | GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); + GST_RTSP_ADDRESS_FLAG_IPV6 | GST_RTSP_ADDRESS_FLAG_EVEN_PORT | + GST_RTSP_ADDRESS_FLAG_MULTICAST, 2); fail_unless (addr != NULL); fail_unless (addr->port == 5002); fail_unless (!g_ascii_strcasecmp (addr->address, "2001:DB8::1")); /* Will fail becuse there is only one IPv6 address left */ addr2 = gst_rtsp_address_pool_acquire_address (pool, - GST_RTSP_ADDRESS_FLAG_IPV6, 2); + GST_RTSP_ADDRESS_FLAG_IPV6 | GST_RTSP_ADDRESS_FLAG_MULTICAST, 2); fail_unless (addr2 == NULL); /* Will fail because the only IPv6 address left has an odd port */ addr2 = gst_rtsp_address_pool_acquire_address (pool, - GST_RTSP_ADDRESS_FLAG_IPV6 | GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 1); + GST_RTSP_ADDRESS_FLAG_IPV6 | GST_RTSP_ADDRESS_FLAG_EVEN_PORT | + GST_RTSP_ADDRESS_FLAG_MULTICAST, 1); fail_unless (addr2 == NULL); gst_rtsp_address_free (addr); @@ -101,13 +106,13 @@ GST_START_TEST (test_pool) "233.252.0.0", "233.252.0.255", 5000, 5002, 1)); addr = gst_rtsp_address_pool_acquire_address (pool, - GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); + GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST, 2); fail_unless (addr != NULL); fail_unless (addr->port == 5000); fail_unless (!strcmp (addr->address, "233.252.0.0")); addr2 = gst_rtsp_address_pool_acquire_address (pool, - GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); + GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST, 2); fail_unless (addr2 != NULL); fail_unless (addr2->port == 5000); fail_unless (!strcmp (addr2->address, "233.252.0.1")); @@ -167,13 +172,14 @@ GST_START_TEST (test_pool) fail_unless (!strcmp (addr2->address, "233.252.1.3")); addr3 = gst_rtsp_address_pool_acquire_address (pool, - GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2); + GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST, 2); fail_unless (addr3 != NULL); fail_unless (addr3->port == 5000); fail_unless (!strcmp (addr3->address, "233.252.1.2")); fail_unless (gst_rtsp_address_pool_acquire_address (pool, - GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2) == NULL); + GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST, 2) + == NULL); gst_rtsp_address_free (addr); gst_rtsp_address_free (addr2); From 27a057962ca6b87987e5167cfcb47d1424f1dedf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Wed, 20 Feb 2013 14:26:03 -0500 Subject: [PATCH 0598/1776] address-pool: Verify that multicast addresses are used for multicast and vice-versa --- gst/rtsp-server/rtsp-address-pool.c | 14 ++++++++++---- tests/check/gst/addresspool.c | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index c339ac5ff7..b6e2711ab0 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -183,7 +183,8 @@ gst_rtsp_address_pool_clear (GstRTSPAddressPool * pool) } static gboolean -fill_address (const gchar * address, guint16 port, Addr * addr) +fill_address (const gchar * address, guint16 port, Addr * addr, + gboolean is_multicast) { GInetAddress *inet; @@ -191,6 +192,11 @@ fill_address (const gchar * address, guint16 port, Addr * addr) if (inet == NULL) return FALSE; + if (is_multicast != g_inet_address_get_is_multicast (inet)) { + g_object_unref (inet); + return FALSE; + } + addr->size = g_inet_address_get_native_size (inet); memcpy (addr->bytes, g_inet_address_to_bytes (inet), addr->size); g_object_unref (inet); @@ -243,9 +249,9 @@ gst_rtsp_address_pool_add_range (GstRTSPAddressPool * pool, range = g_slice_new0 (AddrRange); - if (!fill_address (min_address, min_port, &range->min)) + if (!fill_address (min_address, min_port, &range->min, (ttl != 0))) goto invalid; - if (!fill_address (max_address, max_port, &range->max)) + if (!fill_address (max_address, max_port, &range->max, (ttl != 0))) goto invalid; if (range->min.size != range->max.size) @@ -603,7 +609,7 @@ gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, result = NULL; addr = NULL; - if (!fill_address (address, port, &input_addr)) { + if (!fill_address (address, port, &input_addr, (ttl != 0))) { GST_ERROR_OBJECT (pool, "invalid address %s", address); return NULL; } diff --git a/tests/check/gst/addresspool.c b/tests/check/gst/addresspool.c index 3341e48094..b4d774285c 100644 --- a/tests/check/gst/addresspool.c +++ b/tests/check/gst/addresspool.c @@ -78,14 +78,14 @@ GST_START_TEST (test_pool) * starting with even port */ fail_unless (gst_rtsp_address_pool_add_range (pool, - "2001:DB8::1", "2001:DB8::1", 5001, 5003, 1)); + "FF11:DB8::1", "FF11:DB8::1", 5001, 5003, 1)); addr = gst_rtsp_address_pool_acquire_address (pool, GST_RTSP_ADDRESS_FLAG_IPV6 | GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST, 2); fail_unless (addr != NULL); fail_unless (addr->port == 5002); - fail_unless (!g_ascii_strcasecmp (addr->address, "2001:DB8::1")); + fail_unless (!g_ascii_strcasecmp (addr->address, "FF11:DB8::1")); /* Will fail becuse there is only one IPv6 address left */ addr2 = gst_rtsp_address_pool_acquire_address (pool, From 444c5892f7759f240b2309c249522ce52bd7dbfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 19 Feb 2013 16:36:20 -0500 Subject: [PATCH 0599/1776] tests: Add tests for unicast addresses in pool --- tests/check/gst/addresspool.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/check/gst/addresspool.c b/tests/check/gst/addresspool.c index b4d774285c..2d58209496 100644 --- a/tests/check/gst/addresspool.c +++ b/tests/check/gst/addresspool.c @@ -184,6 +184,27 @@ GST_START_TEST (test_pool) gst_rtsp_address_free (addr); gst_rtsp_address_free (addr2); gst_rtsp_address_free (addr3); + gst_rtsp_address_pool_clear (pool); + + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.252.1.1", "233.252.1.1", 5000, 5001, 1)); + fail_unless (gst_rtsp_address_pool_add_range_unicast (pool, + "192.168.1.1", "192.168.1.1", 6000, 6001)); + + addr = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST, 2); + fail_unless (addr != NULL); + fail_unless (addr->port == 5000); + fail_unless (!strcmp (addr->address, "233.252.1.1")); + gst_rtsp_address_free (addr); + + addr = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_UNICAST, 2); + fail_unless (addr != NULL); + fail_unless (addr->port == 6000); + fail_unless (!strcmp (addr->address, "192.168.1.1")); + gst_rtsp_address_free (addr); + g_object_unref (pool); } From a797cbde06ddff2518019b916f7a1fdc16e76e29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 19 Feb 2013 16:43:08 -0500 Subject: [PATCH 0600/1776] stream: Properties are always there in Gst 1.0 --- gst/rtsp-server/rtsp-stream.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4a13c2db5b..9ec568d1d6 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -521,21 +521,9 @@ again: if (!udpsink1) goto no_udp_protocol; - if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), - "send-duplicates")) { - g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); - } else { - g_warning - ("old multiudpsink version found without send-duplicates property"); - } - - if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0), - "buffer-size")) { - g_object_set (G_OBJECT (udpsink0), "buffer-size", priv->buffer_size, NULL); - } else { - GST_WARNING ("multiudpsink version found without buffer-size property"); - } + g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); + g_object_set (G_OBJECT (udpsink0), "buffer-size", priv->buffer_size, NULL); g_object_get (G_OBJECT (udpsrc1), "used-socket", &socket, NULL); g_object_set (G_OBJECT (udpsink1), "socket", socket, NULL); From 5a39e259497bf71ff3364a833be4544dd32a0f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 19 Feb 2013 18:27:20 -0500 Subject: [PATCH 0601/1776] stream: Select unicast address from pool if appropriate --- gst/rtsp-server/rtsp-stream.c | 174 +++++++++++++++++++++++----------- 1 file changed, 121 insertions(+), 53 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 9ec568d1d6..eb64c2da13 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -62,6 +62,7 @@ struct _GstRTSPStreamPrivate /* server ports for sending/receiving */ GstRTSPRange server_port; + GstRTSPAddress *server_addr; /* multicast addresses */ GstRTSPAddressPool *pool; @@ -136,6 +137,8 @@ gst_rtsp_stream_finalize (GObject * obj) if (priv->addr) gst_rtsp_address_free (priv->addr); + if (priv->server_addr) + gst_rtsp_address_free (priv->server_addr); if (priv->pool) g_object_unref (priv->pool); gst_object_unref (priv->payloader); @@ -417,11 +420,17 @@ alloc_ports (GstRTSPStream * stream) GstStateChangeReturn ret; GstElement *udpsrc0, *udpsrc1; GstElement *udpsink0, *udpsink1; + GSocket *rtp_socket = NULL; + GSocket *rtcp_socket; gint tmp_rtp, tmp_rtcp; guint count; gint rtpport, rtcpport; - GSocket *socket; - const gchar *host; + GList *rejected_addresses = NULL; + GstRTSPAddress *addr = NULL; + GSocketFamily family; + GInetAddress *inetaddr = NULL; + GSocketAddress *rtp_sockaddr = NULL; + GSocketAddress *rtcp_sockaddr = NULL; udpsrc0 = NULL; udpsrc1 = NULL; @@ -432,74 +441,117 @@ alloc_ports (GstRTSPStream * stream) /* Start with random port */ tmp_rtp = 0; - if (priv->is_ipv6) - host = "udp://[::0]"; - else - host = "udp://0.0.0.0"; + if (priv->is_ipv6) { + family = G_SOCKET_FAMILY_IPV6; + } else { + family = G_SOCKET_FAMILY_IPV4; + } + + rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, + G_SOCKET_PROTOCOL_UDP, NULL); + if (!rtcp_socket) + goto no_udp_protocol; + + if (priv->server_addr) + gst_rtsp_address_free (priv->server_addr); /* try to allocate 2 UDP ports, the RTP port should be an even * number and the RTCP port should be the next (uneven) port */ again: - udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); - if (udpsrc0 == NULL) - goto no_udp_protocol; - g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL); - ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED); - if (ret == GST_STATE_CHANGE_FAILURE) { + if (rtp_socket == NULL) { + rtp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, + G_SOCKET_PROTOCOL_UDP, NULL); + if (!rtp_socket) + goto no_udp_protocol; + } + + if (priv->pool && gst_rtsp_address_pool_has_unicast_addresses (priv->pool)) { + GstRTSPAddressFlags flags; + + if (addr) + rejected_addresses = g_list_prepend (rejected_addresses, addr); + + flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_UNICAST; + if (priv->is_ipv6) + flags |= GST_RTSP_ADDRESS_FLAG_IPV6; + else + flags |= GST_RTSP_ADDRESS_FLAG_IPV4; + + addr = gst_rtsp_address_pool_acquire_address (priv->pool, flags, 2); + + if (addr == NULL) + goto no_ports; + + tmp_rtp = addr->port; + + g_clear_object (&inetaddr); + inetaddr = g_inet_address_new_from_string (addr->address); + } else { if (tmp_rtp != 0) { tmp_rtp += 2; if (++count > 20) goto no_ports; - - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - - goto again; } - goto no_udp_protocol; + + if (inetaddr == NULL) + inetaddr = g_inet_address_new_any (family); } - g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); + rtp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtp); + if (!g_socket_bind (rtp_socket, rtp_sockaddr, FALSE, NULL)) { + g_object_unref (rtp_sockaddr); + goto again; + } + g_object_unref (rtp_sockaddr); + + rtp_sockaddr = g_socket_get_local_address (rtp_socket, NULL); + if (rtp_sockaddr == NULL || !G_IS_INET_SOCKET_ADDRESS (rtp_sockaddr)) { + g_clear_object (&rtp_sockaddr); + goto socket_error; + } + + tmp_rtp = + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (rtp_sockaddr)); + g_object_unref (rtp_sockaddr); /* check if port is even */ if ((tmp_rtp & 1) != 0) { /* port not even, close and allocate another */ - if (++count > 20) - goto no_ports; - - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - tmp_rtp++; + g_clear_object (&rtp_socket); goto again; } - /* allocate port+1 for RTCP now */ - udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); - if (udpsrc1 == NULL) - goto no_udp_rtcp_protocol; - /* set port */ tmp_rtcp = tmp_rtp + 1; - g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL); - ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED); - /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */ - if (ret == GST_STATE_CHANGE_FAILURE) { - - if (++count > 20) - goto no_ports; - - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - - gst_element_set_state (udpsrc1, GST_STATE_NULL); - gst_object_unref (udpsrc1); - - tmp_rtp += 2; + rtcp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtcp); + if (!g_socket_bind (rtcp_socket, rtcp_sockaddr, FALSE, NULL)) { + g_object_unref (rtcp_sockaddr); + g_clear_object (&rtp_socket); goto again; } + g_object_unref (rtcp_sockaddr); + + g_clear_object (&inetaddr); + + udpsrc0 = gst_element_factory_make ("udpsrc", NULL); + udpsrc1 = gst_element_factory_make ("udpsrc", NULL); + + if (udpsrc0 == NULL || udpsrc1 == NULL) + goto no_udp_protocol; + + g_object_set (G_OBJECT (udpsrc0), "socket", rtp_socket, NULL); + g_object_set (G_OBJECT (udpsrc1), "socket", rtcp_socket, NULL); + + ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED); + if (ret == GST_STATE_CHANGE_FAILURE) + goto element_error; + ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED); + if (ret == GST_STATE_CHANGE_FAILURE) + goto element_error; + /* all fine, do port check */ g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL); g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL); @@ -512,10 +564,8 @@ again: if (!udpsink0) goto no_udp_protocol; - g_object_get (G_OBJECT (udpsrc0), "used-socket", &socket, NULL); - g_object_set (G_OBJECT (udpsink0), "socket", socket, NULL); - g_object_unref (socket); g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL); + g_object_set (G_OBJECT (udpsink0), "socket", rtp_socket, NULL); udpsink1 = gst_element_factory_make ("multiudpsink", NULL); if (!udpsink1) @@ -525,10 +575,8 @@ again: g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); g_object_set (G_OBJECT (udpsink0), "buffer-size", priv->buffer_size, NULL); - g_object_get (G_OBJECT (udpsrc1), "used-socket", &socket, NULL); - g_object_set (G_OBJECT (udpsink1), "socket", socket, NULL); - g_object_unref (socket); g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "socket", rtcp_socket, NULL); g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL); @@ -545,6 +593,12 @@ again: priv->server_port.min = rtpport; priv->server_port.max = rtcpport; + priv->server_addr = addr; + g_list_free_full (rejected_addresses, (GDestroyNotify) gst_rtsp_address_free); + + g_object_unref (rtp_socket); + g_object_unref (rtcp_socket); + return TRUE; /* ERRORS */ @@ -556,11 +610,15 @@ no_ports: { goto cleanup; } -no_udp_rtcp_protocol: +port_error: { goto cleanup; } -port_error: +socket_error: + { + goto cleanup; + } +element_error: { goto cleanup; } @@ -582,6 +640,16 @@ cleanup: gst_element_set_state (udpsink1, GST_STATE_NULL); gst_object_unref (udpsink1); } + if (inetaddr) + g_object_unref (inetaddr); + g_list_free_full (rejected_addresses, + (GDestroyNotify) gst_rtsp_address_free); + if (addr) + gst_rtsp_address_free (addr); + if (rtp_socket) + g_object_unref (rtp_socket); + if (rtcp_socket) + g_object_unref (rtcp_socket); return FALSE; } } From d3c70d4d51cc1b62374c754609d913d024939244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Wed, 20 Feb 2013 18:30:01 -0500 Subject: [PATCH 0602/1776] tests: Make sure packets are actually received --- tests/check/gst/rtspserver.c | 194 +++++++++++++++++++++++++++++------ 1 file changed, 162 insertions(+), 32 deletions(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 9cd07ad627..001450f961 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -23,6 +23,8 @@ #include #include +#include +#include #include #include @@ -91,50 +93,96 @@ get_unused_port (gint type) return port; } -/* returns TRUE if the given port is not currently bound */ -static gboolean -port_is_unused (gint port, gint type) +static void +get_client_ports_full (GstRTSPRange * range, GSocket ** rtp_socket, + GSocket ** rtcp_socket) { - int sock; - struct sockaddr_in addr; - gboolean is_bound; + GSocket *rtp = NULL; + GSocket *rtcp = NULL; + gint rtp_port = 0; + gint rtcp_port; + GInetAddress *anyaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4); + GSocketAddress *sockaddr; + gboolean bound; - /* create socket */ - fail_unless ((sock = socket (AF_INET, type, 0)) > 0); + for (;;) { + if (rtp_port != 0) + rtp_port += 2; - /* check if the port is already bound by trying to bind to it (again) */ - memset (&addr, 0, sizeof addr); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons (port); - is_bound = (bind (sock, (struct sockaddr *) &addr, sizeof addr) != 0); + rtp = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, + G_SOCKET_PROTOCOL_UDP, NULL); + fail_unless (rtp != NULL); - /* close the socket, which will unbind if bound by our call to bind */ - close (sock); + sockaddr = g_inet_socket_address_new (anyaddr, rtp_port); + fail_unless (sockaddr != NULL); + bound = g_socket_bind (rtp, sockaddr, FALSE, NULL); + g_object_unref (sockaddr); + if (!bound) { + g_object_unref (rtp); + continue; + } - return !is_bound; + sockaddr = g_socket_get_local_address (rtp, NULL); + fail_unless (sockaddr != NULL && G_IS_INET_SOCKET_ADDRESS (sockaddr)); + rtp_port = + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (sockaddr)); + g_object_unref (sockaddr); + + if (rtp_port % 2 != 0) { + rtp_port += 1; + g_object_unref (rtp); + continue; + } + + rtcp_port = rtp_port + 1; + + rtcp = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, + G_SOCKET_PROTOCOL_UDP, NULL); + fail_unless (rtcp != NULL); + + sockaddr = g_inet_socket_address_new (anyaddr, rtcp_port); + fail_unless (sockaddr != NULL); + bound = g_socket_bind (rtcp, sockaddr, FALSE, NULL); + g_object_unref (sockaddr); + if (!bound) { + g_object_unref (rtp); + g_object_unref (rtcp); + continue; + } + + sockaddr = g_socket_get_local_address (rtcp, NULL); + fail_unless (sockaddr != NULL && G_IS_INET_SOCKET_ADDRESS (sockaddr)); + fail_unless (rtcp_port == + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (sockaddr))); + g_object_unref (sockaddr); + + break; + } + + range->min = rtp_port; + range->max = rtcp_port; + if (rtp_socket) + *rtp_socket = rtp; + else + g_object_unref (rtp); + if (rtcp_socket) + *rtcp_socket = rtcp; + else + g_object_unref (rtcp); + GST_DEBUG ("client_port=%d-%d", range->min, range->max); + g_object_unref (anyaddr); } /* get a free rtp/rtcp client port pair */ static void get_client_ports (GstRTSPRange * range) { - gint rtp_port; - gint rtcp_port; - - /* get a pair of unused ports, where the rtp port is even */ - do { - rtp_port = get_unused_port (SOCK_DGRAM); - rtcp_port = rtp_port + 1; - } while (rtp_port % 2 != 0 || !port_is_unused (rtcp_port, SOCK_DGRAM)); - range->min = rtp_port; - range->max = rtcp_port; - GST_DEBUG ("client_port=%d-%d", range->min, range->max); + get_client_ports_full (range, NULL, NULL); } /* start the tested rtsp server */ static void -start_server () +start_server (void) { GstRTSPMountPoints *mounts; gchar *service; @@ -146,7 +194,6 @@ start_server () gst_rtsp_media_factory_set_launch (factory, "( " VIDEO_PIPELINE " " AUDIO_PIPELINE " )"); - gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); g_object_unref (mounts); @@ -623,6 +670,79 @@ GST_START_TEST (test_setup_non_existing_stream) GST_END_TEST; +static void +receive_rtp (GSocket * socket, GSocketAddress ** addr) +{ + GstBuffer *buffer = gst_buffer_new_allocate (NULL, 65536, NULL); + + for (;;) { + gssize bytes; + GstMapInfo map = GST_MAP_INFO_INIT; + GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; + + gst_buffer_map (buffer, &map, GST_MAP_WRITE); + bytes = g_socket_receive_from (socket, addr, (gchar *) map.data, + map.maxsize, NULL, NULL); + fail_unless (bytes > 0); + gst_buffer_unmap (buffer, &map); + gst_buffer_set_size (buffer, bytes); + + if (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtpbuffer)) { + gst_rtp_buffer_unmap (&rtpbuffer); + break; + } + + if (addr) + g_clear_object (addr); + } + + gst_buffer_unref (buffer); +} + +static void +receive_rtcp (GSocket * socket, GSocketAddress ** addr, GstRTCPType type) +{ + GstBuffer *buffer = gst_buffer_new_allocate (NULL, 65536, NULL); + + for (;;) { + gssize bytes; + GstMapInfo map = GST_MAP_INFO_INIT; + + gst_buffer_map (buffer, &map, GST_MAP_WRITE); + bytes = g_socket_receive_from (socket, addr, (gchar *) map.data, + map.maxsize, NULL, NULL); + fail_unless (bytes > 0); + gst_buffer_unmap (buffer, &map); + gst_buffer_set_size (buffer, bytes); + + if (gst_rtcp_buffer_validate (buffer)) { + GstRTCPBuffer rtcpbuffer = GST_RTCP_BUFFER_INIT; + GstRTCPPacket packet; + + if (type) { + fail_unless (gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcpbuffer)); + fail_unless (gst_rtcp_buffer_get_first_packet (&rtcpbuffer, &packet)); + do { + if (gst_rtcp_packet_get_type (&packet) == type) { + gst_rtcp_buffer_unmap (&rtcpbuffer); + goto done; + } + } while (gst_rtcp_packet_move_to_next (&packet)); + gst_rtcp_buffer_unmap (&rtcpbuffer); + } else { + break; + } + } + + if (addr) + g_clear_object (addr); + } + +done: + + gst_buffer_unref (buffer); +} + static void do_test_play (void) { @@ -635,6 +755,7 @@ do_test_play (void) gchar *session = NULL; GstRTSPTransport *video_transport = NULL; GstRTSPTransport *audio_transport = NULL; + GSocket *rtp_socket, *rtcp_socket; conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -647,7 +768,7 @@ do_test_play (void) sdp_media = gst_sdp_message_get_media (sdp_message, 1); audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); - get_client_ports (&client_port); + get_client_ports_full (&client_port, &rtp_socket, &rtcp_socket); /* do SETUP for video and audio */ fail_unless (do_setup (conn, video_control, &client_port, &session, @@ -659,11 +780,21 @@ do_test_play (void) fail_unless (do_simple_request (conn, GST_RTSP_PLAY, session) == GST_RTSP_STS_OK); + receive_rtp (rtp_socket, NULL); + receive_rtcp (rtcp_socket, NULL, 0); + /* send TEARDOWN request and check that we get 200 OK */ fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, session) == GST_RTSP_STS_OK); + /* FIXME: The rtsp-server always disconnects the transport before + * sending the RTCP BYE + * receive_rtcp (rtcp_socket, NULL, GST_RTCP_TYPE_BYE); + */ + /* clean up and iterate so the clean-up can finish */ + g_object_unref (rtp_socket); + g_object_unref (rtcp_socket); g_free (session); gst_rtsp_transport_free (video_transport); gst_rtsp_transport_free (audio_transport); @@ -1016,7 +1147,6 @@ GST_START_TEST (test_play_multithreaded_timeout_session) GST_END_TEST; - GST_START_TEST (test_play_disconnect) { GstRTSPConnection *conn; From 6a2238b2fb2b57b0cea92e6468ed6d6399128b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Wed, 20 Feb 2013 19:37:51 -0500 Subject: [PATCH 0603/1776] tests: Add test to check selecting a port the server will send from --- tests/check/gst/rtspserver.c | 105 ++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 001450f961..be51945a5a 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1212,6 +1212,109 @@ GST_START_TEST (test_play_disconnect) GST_END_TEST; +/* Only different with test_play is the specific ports selected */ + +GST_START_TEST (test_play_specific_server_port) +{ + GstRTSPMountPoints *mounts; + gchar *service; + GstRTSPMediaFactory *factory; + GstRTSPAddressPool *pool; + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + GstRTSPRange client_port; + gchar *session = NULL; + GstRTSPTransport *video_transport = NULL; + GSocket *rtp_socket, *rtcp_socket; + GSocketAddress *rtp_address, *rtcp_address; + guint16 rtp_port, rtcp_port; + + mounts = gst_rtsp_server_get_mount_points (server); + + factory = gst_rtsp_media_factory_new (); + pool = gst_rtsp_address_pool_new (); + gst_rtsp_address_pool_add_range_unicast (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV4, + GST_RTSP_ADDRESS_POOL_ANY_IPV4, 7770, 7780); + gst_rtsp_media_factory_set_address_pool (factory, pool); + g_object_unref (pool); + gst_rtsp_media_factory_set_launch (factory, "( " VIDEO_PIPELINE " )"); + gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); + g_object_unref (mounts); + + /* set port */ + test_port = get_unused_port (SOCK_STREAM); + service = g_strdup_printf ("%d", test_port); + gst_rtsp_server_set_service (server, service); + g_free (service); + + /* attach to default main context */ + source_id = gst_rtsp_server_attach (server, NULL); + fail_if (source_id == 0); + + GST_DEBUG ("rtsp server listening on port %d", test_port); + + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 1); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports_full (&client_port, &rtp_socket, &rtcp_socket); + + /* do SETUP for video */ + fail_unless (do_setup (conn, video_control, &client_port, &session, + &video_transport) == GST_RTSP_STS_OK); + + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_PLAY, + session) == GST_RTSP_STS_OK); + + receive_rtp (rtp_socket, &rtp_address); + receive_rtcp (rtcp_socket, &rtcp_address, 0); + + fail_unless (G_IS_INET_SOCKET_ADDRESS (rtp_address)); + fail_unless (G_IS_INET_SOCKET_ADDRESS (rtcp_address)); + rtp_port = + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (rtp_address)); + rtcp_port = + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (rtcp_address)); + fail_unless (rtp_port >= 7770 && rtp_port <= 7780 && rtp_port % 2 == 0); + fail_unless (rtcp_port >= 7770 && rtcp_port <= 7780 && rtcp_port % 2 == 1); + fail_unless (rtp_port + 1 == rtcp_port); + + g_object_unref (rtp_address); + g_object_unref (rtcp_address); + + /* send TEARDOWN request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session) == GST_RTSP_STS_OK); + + /* FIXME: The rtsp-server always disconnects the transport before + * sending the RTCP BYE + * receive_rtcp (rtcp_socket, NULL, GST_RTCP_TYPE_BYE); + */ + + /* clean up and iterate so the clean-up can finish */ + g_object_unref (rtp_socket); + g_object_unref (rtcp_socket); + g_free (session); + gst_rtsp_transport_free (video_transport); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + + + stop_server (); + iterate (); +} + +GST_END_TEST; + static Suite * rtspserver_suite (void) { @@ -1234,7 +1337,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_play_multithreaded_timeout_client); tcase_add_test (tc, test_play_multithreaded_timeout_session); tcase_add_test (tc, test_play_disconnect); - + tcase_add_test (tc, test_play_specific_server_port); return s; } From 4a2276c0e657220d6c6cd1565a7817dea18ebbb4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 11 Mar 2013 11:35:14 +0100 Subject: [PATCH 0604/1776] check: add librtp to libs --- tests/check/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index b6765a5d61..c6cafebfdb 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -48,7 +48,8 @@ AM_CXXFLAGS = $(GST_CXXFLAGS) $(GST_CHECK_CFLAGS) \ -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS LDADD = $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la \ - $(GST_BASE_LIBS) -lgstrtsp-@GST_API_VERSION@ -lgstsdp-@GST_API_VERSION@ \ + $(GST_BASE_LIBS) -lgstrtp-@GST_API_VERSION@ \ + -lgstrtsp-@GST_API_VERSION@ -lgstsdp-@GST_API_VERSION@ \ $(GIO_LIBS) \ $(GST_LIBS) $(GST_CHECK_LIBS) $(GST_RTSP_SERVER_LIBS) From fba09126a8cedab19ecdba4261b7f0a31e3cc75d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 12 Mar 2013 00:03:36 +0000 Subject: [PATCH 0605/1776] tests: use right _LIBS variable for gst-plugins-base libs --- tests/check/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index c6cafebfdb..ff17bbf2bf 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -48,9 +48,9 @@ AM_CXXFLAGS = $(GST_CXXFLAGS) $(GST_CHECK_CFLAGS) \ -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS LDADD = $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la \ - $(GST_BASE_LIBS) -lgstrtp-@GST_API_VERSION@ \ + $(GST_PLUGINS_BASE_LIBS) -lgstrtp-@GST_API_VERSION@ \ -lgstrtsp-@GST_API_VERSION@ -lgstsdp-@GST_API_VERSION@ \ - $(GIO_LIBS) \ + $(GST_BASE_LIBS) $(GIO_LIBS) \ $(GST_LIBS) $(GST_CHECK_LIBS) $(GST_RTSP_SERVER_LIBS) SUPPRESSIONS = $(top_srcdir)/common/gst.supp From 9da40095c39bf7ffcf189037d717742b06d8e474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 12 Mar 2013 00:05:49 +0000 Subject: [PATCH 0606/1776] .gitignore: ignore more build files --- .gitignore | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.gitignore b/.gitignore index c84ca4c3a4..04c2d86a8e 100644 --- a/.gitignore +++ b/.gitignore @@ -35,5 +35,23 @@ stamp-h1 tags gst-rtsp.spec stamp-h.in +.dirstamp /m4/*m4 + +/gst/rtsp-server/GstRtspServer-1.0.gir +/gst/rtsp-server/GstRtspServer-1.0.typelib + +/examples/test-multicast +/examples/test-multicast2 + +/tests/check/gst/addresspool +/tests/check/gst/client +/tests/check/gst/media +/tests/check/gst/mediafactory +/tests/check/gst/mountpoints +/tests/check/gst/rtspserver +/tests/check/test-registry.reg +/tests/test-reuse + +/po From 025ac3458015a1dcc4cb20feece5ba7fa38e3c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 12 Mar 2013 00:10:18 +0000 Subject: [PATCH 0607/1776] configure: remove out-of-date comment --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0a07f73d2e..d538367f06 100644 --- a/configure.ac +++ b/configure.ac @@ -105,7 +105,7 @@ dnl *** checks for library functions *** dnl *** checks for dependancy libraries *** -dnl GLib is required (GStreamer is ok with GLib-2.8, but we want at least 2.10) +dnl GLib is required GLIB_REQ=2.32.0 AC_SUBST([GLIB_REQ]) AG_GST_GLIB_CHECK([$GLIB_REQ]) From 4a99e1cf56e5fe65ca269f39bcb3b533fcf8eb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Wed, 13 Mar 2013 17:46:58 -0400 Subject: [PATCH 0608/1776] tests: Hold ref while creating second media To test if the media aren't shared, make sure we keep the first one while creating a second otherwise the same memory address may be reused. --- tests/check/gst/mediafactory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/check/gst/mediafactory.c b/tests/check/gst/mediafactory.c index e99af5323b..75667cf547 100644 --- a/tests/check/gst/mediafactory.c +++ b/tests/check/gst/mediafactory.c @@ -78,11 +78,12 @@ GST_START_TEST (test_launch_construct) media = gst_rtsp_media_factory_construct (factory, url); fail_unless (GST_IS_RTSP_MEDIA (media)); - g_object_unref (media); media2 = gst_rtsp_media_factory_construct (factory, url); fail_unless (GST_IS_RTSP_MEDIA (media2)); fail_if (media == media2); + + g_object_unref (media); g_object_unref (media2); gst_rtsp_url_free (url); From 8a08fddb41c7a25e025eaccf92961e1797fd6576 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Mon, 18 Mar 2013 09:25:54 +0100 Subject: [PATCH 0609/1776] rtsp-client: expose uri --- gst/rtsp-server/rtsp-client.c | 27 +++++++++++++ gst/rtsp-server/rtsp-client.h | 2 + tests/check/gst/client.c | 76 +++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1bb43c1098..e48bf211b5 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2025,6 +2025,33 @@ gst_rtsp_client_get_auth (GstRTSPClient * client) return result; } +/** + * gst_rtsp_client_get_uri: + * @client: a #GstRTSPClient + * + * Get the #GstRTSPUrl of @client. + * + * Returns: (transfer full): the #GstRTSPUrl of @client. Free with + * gst_rtsp_url_free () after usage. + */ +GstRTSPUrl * +gst_rtsp_client_get_uri (GstRTSPClient * client) +{ + GstRTSPClientPrivate *priv; + GstRTSPUrl *result = NULL; + + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); + + priv = client->priv; + + g_mutex_lock (&priv->lock); + if (priv->uri != NULL) + result = gst_rtsp_url_copy (priv->uri); + g_mutex_unlock (&priv->lock); + + return result; +} + /** * gst_rtsp_client_set_send_func: * @client: a #GstRTSPClient diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index a718cc7ce6..ddb04e92d2 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -137,6 +137,8 @@ gboolean gst_rtsp_client_get_use_client_settings (GstRTSPClient * c void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); +GstRTSPUrl * gst_rtsp_client_get_uri (GstRTSPClient *client); + void gst_rtsp_client_set_send_func (GstRTSPClient *client, GstRTSPClientSendFunc func, gpointer user_data, diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index e59e06a4a3..52ef2ae332 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -23,6 +23,27 @@ static gint cseq; +static gboolean +test_response_200 (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_OK); + fail_unless (g_str_equal (reason, "OK")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + return TRUE; +} + static gboolean test_response_400 (GstRTSPClient * client, GstRTSPMessage * response, gboolean close, gpointer user_data) @@ -86,6 +107,32 @@ test_response_454 (GstRTSPClient * client, GstRTSPMessage * response, return TRUE; } +static GstRTSPClient * +setup_client (void) +{ + GstRTSPClient *client; + GstRTSPSessionPool *session_pool; + GstRTSPMountPoints *mount_points; + GstRTSPMediaFactory *factory; + + client = gst_rtsp_client_new (); + + session_pool = gst_rtsp_session_pool_new (); + gst_rtsp_client_set_session_pool (client, session_pool); + + mount_points = gst_rtsp_mount_points_new (); + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, + "videotestsrc ! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96"); + gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); + gst_rtsp_client_set_mount_points (client, mount_points); + + g_object_unref (mount_points); + g_object_unref (session_pool); + + return client; +} + GST_START_TEST (test_request) { GstRTSPClient *client; @@ -195,6 +242,8 @@ GST_START_TEST (test_describe) GstRTSPClient *client; GstRTSPMessage request = { 0, }; gchar *str; + GstRTSPUrl *uri_client; + gchar *uri_str; client = gst_rtsp_client_new (); @@ -210,6 +259,33 @@ GST_START_TEST (test_describe) &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); + uri_client = gst_rtsp_client_get_uri (client); + fail_unless (uri_client == NULL); + gst_rtsp_url_free (uri_client); + + + g_object_unref (client); + + /* simple DESCRIBE for an existing url */ + client = setup_client (); + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + + gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + uri_client = gst_rtsp_client_get_uri (client); + fail_unless (uri_client != NULL); + uri_str = gst_rtsp_url_get_request_uri (uri_client); + gst_rtsp_url_free (uri_client); + fail_unless (g_strcmp0 (uri_str, "rtsp://localhost/test") == 0); + g_free (uri_str); + g_object_unref (client); } From c18eafbb242bcddfe71d1b8f0e6897d809e40699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 22 Feb 2013 14:17:29 -0500 Subject: [PATCH 0610/1776] rtsp-media/client: Reply to PLAY request with same type of Range Remember the type of Range from the PLAY request and use the same type for the reply. --- gst/rtsp-server/rtsp-client.c | 4 ++- gst/rtsp-server/rtsp-media.c | 6 +++- gst/rtsp-server/rtsp-media.h | 4 ++- gst/rtsp-server/rtsp-sdp.c | 2 +- tests/check/gst/media.c | 12 ++++---- tests/check/gst/rtspserver.c | 56 +++++++++++++++++++++++++++-------- 6 files changed, 62 insertions(+), 22 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e48bf211b5..009014b997 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -859,6 +859,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPTimeRange *range; GstRTSPResult res; GstRTSPState rtspstate; + GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT; if (!(session = state->session)) goto no_session; @@ -882,6 +883,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) { /* we have a range, seek to the position */ gst_rtsp_media_seek (gst_rtsp_session_media_get_media (media), range); + unit = range->unit; gst_rtsp_range_free (range); } } @@ -943,7 +945,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) /* add the range */ str = gst_rtsp_media_get_range_string (gst_rtsp_session_media_get_media (media), - TRUE); + TRUE, unit); gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str); send_response (client, session, state->response, FALSE); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 9826a1d45e..9c6c881595 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -959,6 +959,7 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) * gst_rtsp_media_get_range_string: * @media: a #GstRTSPMedia * @play: for the PLAY request + * @unit: the unit to use for the string * * Get the current range as a string. @media must be prepared with * gst_rtsp_media_prepare (). @@ -966,7 +967,8 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) * Returns: The range as a string, g_free() after usage. */ gchar * -gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play) +gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play, + GstRTSPRangeUnit unit) { GstRTSPMediaPrivate *priv; gchar *result; @@ -991,6 +993,8 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play) g_mutex_unlock (&priv->lock); g_rec_mutex_unlock (&priv->state_lock); + gst_rtsp_range_convert_units (&range, unit); + result = gst_rtsp_range_to_string (&range); return result; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 230806bf48..f68a899652 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -155,7 +155,9 @@ guint gst_rtsp_media_n_streams (GstRTSPMedia *media); GstRTSPStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range); -gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, gboolean play); +gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, + gboolean play, + GstRTSPRangeUnit unit); gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GPtrArray *transports); diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 847b48761e..5966a4aa11 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -40,7 +40,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, n_streams = gst_rtsp_media_n_streams (media); - rangestr = gst_rtsp_media_get_range_string (media, FALSE); + rangestr = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT); if (rangestr == NULL) goto not_prepared; diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index a237339d08..b62887115b 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -46,7 +46,7 @@ GST_START_TEST (test_launch) fail_unless (stream != NULL); /* fails, need to be prepared */ - str = gst_rtsp_media_get_range_string (media, FALSE); + str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT); fail_unless (str == NULL); fail_unless (gst_rtsp_range_parse ("npt=5.0-", &range) == GST_RTSP_OK); @@ -55,28 +55,28 @@ GST_START_TEST (test_launch) fail_unless (gst_rtsp_media_prepare (media)); - str = gst_rtsp_media_get_range_string (media, FALSE); + str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT); fail_unless (g_str_equal (str, "npt=0-")); g_free (str); - str = gst_rtsp_media_get_range_string (media, TRUE); + str = gst_rtsp_media_get_range_string (media, TRUE, GST_RTSP_RANGE_NPT); fail_unless (g_str_equal (str, "npt=0-")); g_free (str); fail_unless (gst_rtsp_media_seek (media, range)); - str = gst_rtsp_media_get_range_string (media, FALSE); + str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT); fail_unless (g_str_equal (str, "npt=5-")); g_free (str); - str = gst_rtsp_media_get_range_string (media, TRUE); + str = gst_rtsp_media_get_range_string (media, TRUE, GST_RTSP_RANGE_NPT); fail_unless (g_str_equal (str, "npt=5-")); g_free (str); fail_unless (gst_rtsp_media_unprepare (media)); /* should fail again */ - str = gst_rtsp_media_get_range_string (media, FALSE); + str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT); fail_unless (str == NULL); fail_if (gst_rtsp_media_seek (media, range)); diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index be51945a5a..1c35a22747 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -300,8 +300,9 @@ read_response (GstRTSPConnection * conn) static GstRTSPStatusCode do_request (GstRTSPConnection * conn, GstRTSPMethod method, const gchar * control, const gchar * session_in, const gchar * transport_in, + const gchar * range_in, gchar ** content_type, gchar ** content_base, gchar ** body, - gchar ** session_out, gchar ** transport_out) + gchar ** session_out, gchar ** transport_out, gchar ** range_out) { GstRTSPMessage *request; GstRTSPMessage *response; @@ -318,6 +319,9 @@ do_request (GstRTSPConnection * conn, GstRTSPMethod method, if (transport_in) { gst_rtsp_message_add_header (request, GST_RTSP_HDR_TRANSPORT, transport_in); } + if (range_in) { + gst_rtsp_message_add_header (request, GST_RTSP_HDR_RANGE, range_in); + } /* send request */ fail_unless (send_request (conn, request)); @@ -371,6 +375,10 @@ do_request (GstRTSPConnection * conn, GstRTSPMethod method, gst_rtsp_message_get_header (response, GST_RTSP_HDR_TRANSPORT, &value, 0); *transport_out = g_strdup (value); } + if (range_out) { + gst_rtsp_message_get_header (response, GST_RTSP_HDR_RANGE, &value, 0); + *range_out = g_strdup (value); + } gst_rtsp_message_free (response); return code; @@ -382,7 +390,7 @@ do_simple_request (GstRTSPConnection * conn, GstRTSPMethod method, const gchar * session) { return do_request (conn, method, NULL, session, NULL, NULL, NULL, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); } /* send a DESCRIBE request and receive response. returns a received @@ -398,8 +406,9 @@ do_describe (GstRTSPConnection * conn, const gchar * mount_point) gchar *expected_content_base; /* send DESCRIBE request */ - fail_unless (do_request (conn, GST_RTSP_DESCRIBE, NULL, NULL, NULL, - &content_type, &content_base, &body, NULL, NULL) == GST_RTSP_STS_OK); + fail_unless (do_request (conn, GST_RTSP_DESCRIBE, NULL, NULL, NULL, NULL, + &content_type, &content_base, &body, NULL, NULL, NULL) == + GST_RTSP_STS_OK); /* check response values */ fail_unless (!g_strcmp0 (content_type, "application/sdp")); @@ -451,8 +460,8 @@ do_setup (GstRTSPConnection * conn, const gchar * control, client_ports->min, client_ports->max); code = do_request (conn, GST_RTSP_SETUP, control, session_in, - transport_string_in, NULL, NULL, NULL, session_out, - &transport_string_out); + transport_string_in, NULL, NULL, NULL, NULL, session_out, + &transport_string_out, NULL); g_free (transport_string_in); if (transport_string_out) { @@ -744,7 +753,7 @@ done: } static void -do_test_play (void) +do_test_play (const gchar * range) { GstRTSPConnection *conn; GstSDPMessage *sdp_message = NULL; @@ -756,6 +765,7 @@ do_test_play (void) GstRTSPTransport *video_transport = NULL; GstRTSPTransport *audio_transport = NULL; GSocket *rtp_socket, *rtcp_socket; + gchar *range_out = NULL; conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -777,8 +787,11 @@ do_test_play (void) &audio_transport) == GST_RTSP_STS_OK); /* send PLAY request and check that we get 200 OK */ - fail_unless (do_simple_request (conn, GST_RTSP_PLAY, - session) == GST_RTSP_STS_OK); + fail_unless (do_request (conn, GST_RTSP_PLAY, NULL, session, NULL, range, + NULL, NULL, NULL, NULL, NULL, &range_out) == GST_RTSP_STS_OK); + if (range) + fail_unless_equals_string (range, range_out); + g_free (range_out); receive_rtp (rtp_socket, NULL); receive_rtcp (rtcp_socket, NULL, 0); @@ -807,7 +820,7 @@ GST_START_TEST (test_play) { start_server (); - do_test_play (); + do_test_play (NULL); stop_server (); iterate (); @@ -877,7 +890,7 @@ GST_START_TEST (test_play_multithreaded) start_server (); - do_test_play (); + do_test_play (NULL); stop_server (); iterate (); @@ -948,7 +961,7 @@ GST_START_TEST (test_play_multithreaded_block_in_describe) g_mutex_unlock (&check_mutex); /* Do a second connection while the first one is blocked */ - do_test_play (); + do_test_play (NULL); /* Now unblock the describe */ g_mutex_lock (&check_mutex); @@ -1315,6 +1328,24 @@ GST_START_TEST (test_play_specific_server_port) GST_END_TEST; + +GST_START_TEST (test_play_smpte_range) +{ + start_server (); + + do_test_play ("npt=5-"); + do_test_play ("smpte=0:00:00-"); + do_test_play ("smpte=1:00:00-"); + do_test_play ("smpte=1:00:03-"); + do_test_play ("clock=20120321T152256Z-"); + + stop_server (); + iterate (); +} + +GST_END_TEST; + + static Suite * rtspserver_suite (void) { @@ -1338,6 +1369,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_play_multithreaded_timeout_session); tcase_add_test (tc, test_play_disconnect); tcase_add_test (tc, test_play_specific_server_port); + tcase_add_test (tc, test_play_smpte_range); return s; } From 91210f40f2dd563ee7a8ce28665cde24bb87b8fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 22 Mar 2013 18:25:07 -0400 Subject: [PATCH 0611/1776] rtsp-media-factory: g_signal_connect_object is not thread safe, can't use it here Instead use a GWeakRef which is safe to use This is a known GLib bug, see: https://bugzilla.gnome.org/show_bug.cgi?id=667145 --- gst/rtsp-server/rtsp-media-factory.c | 33 ++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index ced81ecde3..f448276276 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -646,13 +646,37 @@ compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) } static void -media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory) +media_unprepared (GstRTSPMedia * media, GWeakRef * ref) { - GstRTSPMediaFactoryPrivate *priv = factory->priv;; + GstRTSPMediaFactory *factory = g_weak_ref_get (ref); + GstRTSPMediaFactoryPrivate *priv; + + if (!factory) + return; + + priv = factory->priv;; g_mutex_lock (&priv->medias_lock); g_hash_table_foreach_remove (priv->medias, (GHRFunc) compare_media, media); g_mutex_unlock (&priv->medias_lock); + + g_object_unref (factory); +} + +static GWeakRef * +weak_ref_new (gpointer obj) +{ + GWeakRef *ref = g_slice_new (GWeakRef); + + g_weak_ref_init (ref, obj); + return ref; +} + +static void +weak_ref_free (GWeakRef * ref) +{ + g_weak_ref_clear (ref); + g_slice_free (GWeakRef, ref); } /** @@ -733,8 +757,9 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, if (!gst_rtsp_media_is_reusable (media)) { /* when not reusable, connect to the unprepare signal to remove the item * from our cache when it gets unprepared */ - g_signal_connect_object (media, "unprepared", - (GCallback) media_unprepared, factory, 0); + g_signal_connect_data (media, "unprepared", + (GCallback) media_unprepared, weak_ref_new (factory), + (GClosureNotify) weak_ref_free, 0); } } } From 75221ac8e3780fb2e8f9e23bfb616389d505515e Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Wed, 20 Mar 2013 11:28:11 +0100 Subject: [PATCH 0612/1776] tests: GSocketService cleanup in test_bind_already_in_use Use g_socket_service_stop so the rtspserver test stops listening for incoming connections in test_bind_already_in_use. https://bugzilla.gnome.org/show_bug.cgi?id=696541 --- tests/check/gst/rtspserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 1c35a22747..3377a80468 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -877,7 +877,7 @@ GST_START_TEST (test_bind_already_in_use) /* cleanup */ g_object_unref (serv); - g_socket_listener_close (G_SOCKET_LISTENER (service)); + g_socket_service_stop (service); g_object_unref (service); } From d728d59a00bbe1084782b048baece2caddd63bfd Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Wed, 20 Mar 2013 12:33:54 +0100 Subject: [PATCH 0613/1776] tests: remove extra unref in test_setup_non_existing_stream The unref is not needed anymore, teardown runs without it. https://bugzilla.gnome.org/show_bug.cgi?id=696542 --- tests/check/gst/rtspserver.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 3377a80468..2a01aed4e5 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -670,11 +670,6 @@ GST_START_TEST (test_setup_non_existing_stream) gst_rtsp_connection_free (conn); stop_server (); iterate (); - - /* need to unref the server here, otherwise threads will remain - * and teardown won't be run */ - g_object_unref (server); - server = NULL; } GST_END_TEST; From ec0718d7c9ee657a64215fce0c4f71e1769e4c88 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Apr 2013 20:11:35 +0200 Subject: [PATCH 0614/1776] media: small cleanup --- gst/rtsp-server/rtsp-media.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 9c6c881595..551d1a19a5 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1232,17 +1232,17 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) case GST_MESSAGE_STREAM_STATUS: break; case GST_MESSAGE_ASYNC_DONE: - if (!priv->adding) { + if (priv->adding) { /* when we are dynamically adding pads, the addition of the udpsrc will * temporarily produce ASYNC_DONE messages. We have to ignore them and * wait for the final ASYNC_DONE after everything prerolled */ + GST_INFO ("%p: ignoring ASYNC_DONE", media); + } else { GST_INFO ("%p: got ASYNC_DONE", media); collect_media_stats (media); if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); - } else { - GST_INFO ("%p: ignoring ASYNC_DONE", media); } break; case GST_MESSAGE_EOS: From 95bf53513f6888c2254786ffe1b4944fb0fc364d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Apr 2013 20:39:58 +0200 Subject: [PATCH 0615/1776] media: wait for buffering to complete Wait for buffering to complete before changing the state to the target state. --- gst/rtsp-server/rtsp-media.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 551d1a19a5..1cce85d2fa 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1725,7 +1725,13 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, GST_INFO ("state %s media %p", gst_element_state_get_name (state), media); priv->target_state = state; - gst_element_set_state (priv->pipeline, state); + /* when we are buffering, don't update the state yet, this will be done + * when buffering finishes */ + if (priv->buffering) { + GST_INFO ("Buffering busy, delay state change"); + } else { + gst_element_set_state (priv->pipeline, state); + } } } g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state, From 1704018d5d070eff575414b6f46380985d8fe8d1 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 9 Apr 2013 21:02:47 +0200 Subject: [PATCH 0616/1776] Automatic update of common submodule From 04c7a1e to aed87ae --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 04c7a1ec1b..aed87ae3f2 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 04c7a1ec1b9ced0b4359b3bbb2d8dc87bc7642c8 +Subproject commit aed87ae3f28b85b24eff734937b85473828e297d From 36ff6795580661e9a99afbd59c26eedef8b837d5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Apr 2013 22:35:28 +0200 Subject: [PATCH 0617/1776] media: add GstNetTimeProvider support Add a property to let the media provide a GstNetTimeProvider for its clock. Make methods to get the clock and nettimeprovider Add a x-gst-clock property to the SDP with the IP and port number of the nettime provider and also the current time of the clock. This should make it possible for (GStreamer) clients to slave their clock to the server clock. --- gst/rtsp-server/Makefile.am | 1 + gst/rtsp-server/rtsp-media.c | 158 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 7 ++ gst/rtsp-server/rtsp-sdp.c | 24 ++++++ 4 files changed, 190 insertions(+) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 008e4189da..2f9dfc62af 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -45,6 +45,7 @@ libgstrtspserver_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDF libgstrtspserver_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ -lgstrtp-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ \ + -lgstnet-@GST_API_VERSION@ \ -lgstsdp-@GST_API_VERSION@ \ -lgstapp-@GST_API_VERSION@ \ $(GST_LIBS) $(GIO_LIBS) $(LIBM) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1cce85d2fa..0b0d33ceca 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -58,6 +58,9 @@ struct _GstRTSPMediaPrivate GSource *source; guint id; + gboolean time_provider; + GstNetTimeProvider *nettime; + gboolean is_live; gboolean seekable; gboolean buffering; @@ -78,6 +81,7 @@ struct _GstRTSPMediaPrivate //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST #define DEFAULT_EOS_SHUTDOWN FALSE #define DEFAULT_BUFFER_SIZE 0x80000 +#define DEFAULT_TIME_PROVIDER FALSE /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -91,6 +95,7 @@ enum PROP_EOS_SHUTDOWN, PROP_BUFFER_SIZE, PROP_ELEMENT, + PROP_TIME_PROVIDER, PROP_LAST }; @@ -165,6 +170,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "The GstBin to use for streaming the media", GST_TYPE_ELEMENT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN, + g_param_spec_boolean ("time-provider", "Time Provider", + "Use a NetTimeProvider for clients", + DEFAULT_TIME_PROVIDER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, @@ -213,6 +223,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->protocols = DEFAULT_PROTOCOLS; priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN; priv->buffer_size = DEFAULT_BUFFER_SIZE; + priv->time_provider = DEFAULT_TIME_PROVIDER; } static void @@ -232,6 +243,8 @@ gst_rtsp_media_finalize (GObject * obj) if (priv->pipeline) gst_object_unref (priv->pipeline); + if (priv->nettime) + gst_object_unref (priv->nettime); gst_object_unref (priv->element); if (priv->auth) g_object_unref (priv->auth); @@ -269,6 +282,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_BUFFER_SIZE: g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media)); break; + case PROP_TIME_PROVIDER: + g_value_set_boolean (value, gst_rtsp_media_is_time_provider (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -299,6 +315,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_BUFFER_SIZE: gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value)); break; + case PROP_TIME_PROVIDER: + gst_rtsp_media_use_time_provider (media, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -413,6 +432,7 @@ gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline) { GstRTSPMediaPrivate *priv; GstElement *old; + GstNetTimeProvider *nettime; g_return_if_fail (GST_IS_RTSP_MEDIA (media)); g_return_if_fail (GST_IS_PIPELINE (pipeline)); @@ -422,11 +442,16 @@ gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline) g_mutex_lock (&priv->lock); old = priv->pipeline; priv->pipeline = GST_ELEMENT_CAST (pipeline); + nettime = priv->nettime; + priv->nettime = NULL; g_mutex_unlock (&priv->lock); if (old) gst_object_unref (old); + if (nettime) + gst_object_unref (nettime); + gst_object_ref (priv->element); gst_bin_add (GST_BIN_CAST (pipeline), priv->element); } @@ -669,6 +694,53 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) return res; } +/** + * gst_rtsp_media_use_time_provider: + * @media: a #GstRTSPMedia + * + * Set @media to provide a GstNetTimeProvider. + */ +void +gst_rtsp_media_use_time_provider (GstRTSPMedia * media, gboolean time_provider) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->time_provider = time_provider; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_is_time_provider: + * @media: a #GstRTSPMedia + * + * Check if @media can provide a #GstNetTimeProvider for its pipeline clock. + * + * Use gst_rtsp_media_get_time_provider() to get the network clock. + * + * Returns: %TRUE if @media can provide a #GstNetTimeProvider. + */ +gboolean +gst_rtsp_media_is_time_provider (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + priv = media->priv; + + g_mutex_unlock (&priv->lock); + res = priv->time_provider; + g_mutex_unlock (&priv->lock); + + return res; +} + /** * gst_rtsp_media_set_auth: * @media: a #GstRTSPMedia @@ -1536,6 +1608,10 @@ finish_unprepare (GstRTSPMedia * media) gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin); priv->rtpbin = NULL; + if (priv->nettime) + gst_object_unref (priv->nettime); + priv->nettime = NULL; + gst_object_unref (priv->pipeline); priv->pipeline = NULL; @@ -1633,6 +1709,88 @@ is_busy: } } +/* should be called with state-lock */ +static GstClock * +get_clock_unlocked (GstRTSPMedia * media) +{ + if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) { + GST_DEBUG_OBJECT (media, "media was not prepared"); + return NULL; + } + return gst_pipeline_get_clock (GST_PIPELINE_CAST (media->priv->pipeline)); +} + +/** + * gst_rtsp_media_get_clock: + * @media: a #GstRTSPMedia + * + * Get the clock that is used by the pipeline in @media. + * + * @media must be prepared before this method returns a valid clock object. + * + * Returns: the #GstClock used by @media. unref after usage. + */ +GstClock * +gst_rtsp_media_get_clock (GstRTSPMedia * media) +{ + GstClock *clock; + GstRTSPMediaPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + clock = get_clock_unlocked (media); + g_rec_mutex_unlock (&priv->state_lock); + + return clock; + +} + +/** + * gst_rtsp_media_get_time_provider: + * @media: a #GstRTSPMedia + * @address: an address or NULL + * @port: a port or 0 + * + * Get the #GstNetTimeProvider for the clock used by @media. The time provider + * will listen on @address and @port for client time requests. + * + * Returns: the #GstNetTimeProvider of @media. + */ +GstNetTimeProvider * +gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address, + guint16 port) +{ + GstRTSPMediaPrivate *priv; + GstNetTimeProvider *provider = NULL; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + if (priv->time_provider) { + if ((provider = priv->nettime) == NULL) { + GstClock *clock; + + if (priv->time_provider && (clock = get_clock_unlocked (media))) { + provider = gst_net_time_provider_new (clock, address, port); + gst_object_unref (clock); + + priv->nettime = provider; + } + } + } + g_rec_mutex_unlock (&priv->state_lock); + + if (provider) + gst_object_ref (provider); + + return provider; +} + /** * gst_rtsp_media_set_state: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index f68a899652..a103ad2741 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -20,6 +20,7 @@ #include #include #include +#include #ifndef __GST_RTSP_MEDIA_H__ #define __GST_RTSP_MEDIA_H__ @@ -139,6 +140,10 @@ GstRTSPAddressPool * gst_rtsp_media_get_address_pool (GstRTSPMedia *media); void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size); guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media); +void gst_rtsp_media_use_time_provider (GstRTSPMedia *media, gboolean time_provider); +gboolean gst_rtsp_media_is_time_provider (GstRTSPMedia *media); +GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media, + const gchar *address, guint16 port); /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); @@ -151,6 +156,8 @@ GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia *media, GstPad *srcpad); /* dealing with the media */ +GstClock * gst_rtsp_media_get_clock (GstRTSPMedia *media); + guint gst_rtsp_media_n_streams (GstRTSPMedia *media); GstRTSPStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 5966a4aa11..7597bb48a3 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -158,6 +158,30 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, gst_caps_unref (caps); } + { + GstNetTimeProvider *provider; + + if ((provider = + gst_rtsp_media_get_time_provider (media, info->server_ip, 0))) { + GstClock *clock; + gchar *address, *str; + gint port; + + g_object_get (provider, "clock", &clock, "address", &address, "port", + &port, NULL); + + str = g_strdup_printf ("GstNetTimeProvider %s %s:%d %" G_GUINT64_FORMAT, + g_type_name (G_TYPE_FROM_INSTANCE (clock)), address, port, + gst_clock_get_time (clock)); + + gst_sdp_message_add_attribute (sdp, "x-gst-clock", str); + g_free (str); + gst_object_unref (clock); + g_free (address); + gst_object_unref (provider); + } + } + return TRUE; /* ERRORS */ From a64cb68164c91d4bcc5a25a22ed9cec8bf947346 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Apr 2013 11:34:38 +0100 Subject: [PATCH 0618/1776] media: add method to get the base_time of the pipeline Together with a shared clock, this base-time could eventually be sent to the client so that it can reconstruct the exact running-time of the clock on the server. --- gst/rtsp-server/rtsp-media.c | 37 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 1 + gst/rtsp-server/rtsp-session-media.c | 16 ++++++++++++ gst/rtsp-server/rtsp-session-media.h | 1 + 4 files changed, 55 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 0b0d33ceca..2f7d498a3e 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1745,7 +1745,44 @@ gst_rtsp_media_get_clock (GstRTSPMedia * media) g_rec_mutex_unlock (&priv->state_lock); return clock; +} +/** + * gst_rtsp_media_get_base_time: + * @media: a #GstRTSPMedia + * + * Get the base_time that is used by the pipeline in @media. + * + * @media must be prepared before this method returns a valid base_time. + * + * Returns: the base_time used by @media. + */ +GstClockTime +gst_rtsp_media_get_base_time (GstRTSPMedia * media) +{ + GstClockTime result; + GstRTSPMediaPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_CLOCK_TIME_NONE); + + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) + goto not_prepared; + + result = gst_element_get_base_time (media->priv->pipeline); + g_rec_mutex_unlock (&priv->state_lock); + + return result; + + /* ERRORS */ +not_prepared: + { + g_rec_mutex_unlock (&priv->state_lock); + GST_DEBUG_OBJECT (media, "media was not prepared"); + return GST_CLOCK_TIME_NONE; + } } /** diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index a103ad2741..2a7c3dbaa5 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -157,6 +157,7 @@ GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia *media, /* dealing with the media */ GstClock * gst_rtsp_media_get_clock (GstRTSPMedia *media); +GstClockTime gst_rtsp_media_get_base_time (GstRTSPMedia *media); guint gst_rtsp_media_n_streams (GstRTSPMedia *media); GstRTSPStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index d708163061..c475f8f481 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -176,6 +176,22 @@ gst_rtsp_session_media_get_media (GstRTSPSessionMedia * media) return media->priv->media; } +/** + * gst_rtsp_session_media_get_base_time: + * @media: a #GstRTSPSessionMedia + * + * Get the base_time of the #GstRTSPMedia in @media + * + * Returns: the base_time of the media. + */ +GstClockTime +gst_rtsp_session_media_get_base_time (GstRTSPSessionMedia * media) +{ + g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), GST_CLOCK_TIME_NONE); + + return gst_rtsp_media_get_base_time (media->priv->media); +} + /** * gst_rtsp_session_media_set_transport: * @media: a #GstRTSPSessionMedia diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index b6816b30d2..167c0aaba5 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -71,6 +71,7 @@ gboolean gst_rtsp_session_media_matches_url (GstRTSPSessionMe const GstRTSPUrl *url); GstRTSPMedia * gst_rtsp_session_media_get_media (GstRTSPSessionMedia *media); +GstClockTime gst_rtsp_session_media_get_base_time (GstRTSPSessionMedia *media); /* control media */ gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media, GstState state); From 3ba1342906c58f0d476729d6b5179bc5bc024810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 14 Apr 2013 17:58:22 +0100 Subject: [PATCH 0619/1776] Automatic update of common submodule From aed87ae to 3cb3d3c --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index aed87ae3f2..3cb3d3cbbf 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit aed87ae3f28b85b24eff734937b85473828e297d +Subproject commit 3cb3d3cbbf794c18a6f91866c6d7fa38880c1eb8 From 825d6f0b5190a465ad31dd17c83cc691bc2f421a Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Mon, 15 Apr 2013 12:17:34 +0200 Subject: [PATCH 0620/1776] client: expose connection Fixes https://bugzilla.gnome.org/show_bug.cgi?id=697546 --- gst/rtsp-server/rtsp-client.c | 17 +++++++++++++++++ gst/rtsp-server/rtsp-client.h | 1 + 2 files changed, 18 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 009014b997..af0725378f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2054,6 +2054,23 @@ gst_rtsp_client_get_uri (GstRTSPClient * client) return result; } +/** + * gst_rtsp_client_get_connection: + * @client: a #GstRTSPClient + * + * Get the #GstRTSPConnection of @client. + * + * Returns: (transfer none): the #GstRTSPConnection of @client. + * The connection object returned remains valid until the client is freed. + */ +GstRTSPConnection * +gst_rtsp_client_get_connection (GstRTSPClient * client) +{ + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); + + return client->priv->connection; +} + /** * gst_rtsp_client_set_send_func: * @client: a #GstRTSPClient diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index ddb04e92d2..5e0f3f3033 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -138,6 +138,7 @@ void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); GstRTSPUrl * gst_rtsp_client_get_uri (GstRTSPClient *client); +GstRTSPConnection * gst_rtsp_client_get_connection (GstRTSPClient *client); void gst_rtsp_client_set_send_func (GstRTSPClient *client, GstRTSPClientSendFunc func, From bba7c4042d1d0384affa0f94ae0cff7c1a2c9908 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Mon, 15 Apr 2013 12:21:54 +0200 Subject: [PATCH 0621/1776] client: send out teardown signal before tearing down The advantage is that in the signal handler you get direct access to information about what streams are about to get torn down (in the GstRTSPClientState). Fixes https://bugzilla.gnome.org/show_bug.cgi?id=697686 --- gst/rtsp-server/rtsp-client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index af0725378f..5b5affe2b7 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -662,6 +662,10 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) state->sessmedia = media; + /* we emit the signal before closing the connection */ + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], + 0, state); + /* unlink the all TCP callbacks */ unlink_session_transports (client, session, media); @@ -685,10 +689,6 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) send_response (client, session, state->response, TRUE); - /* we emit the signal before closing the connection */ - g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], - 0, state); - return TRUE; /* ERRORS */ From 6081f913515f5e318e39679b29f9b7ba4e3e3f6b Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 22 Apr 2013 16:09:22 +0200 Subject: [PATCH 0622/1776] stream: clear session and caps for reuse Set the session and caps to NULL after unref otherwise we might unref them again later. See https://bugzilla.gnome.org/show_bug.cgi?id=698376 --- gst/rtsp-server/rtsp-stream.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index eb64c2da13..ebf50a0b23 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1220,8 +1220,10 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->send_src[1] = NULL; g_object_unref (priv->session); + priv->session = NULL; if (priv->caps) gst_caps_unref (priv->caps); + priv->caps = NULL; priv->is_joined = FALSE; g_mutex_unlock (&priv->lock); From 0bdff0161c14ccc29c60c3296c748b1434ecde0a Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 22 Apr 2013 16:19:35 +0200 Subject: [PATCH 0623/1776] media: don't unref the pipeline in unprepare Unprepare() should undo what prepare() does. Because the pipeline is not created in prepare(), we should not unref it in unprepare() --- gst/rtsp-server/rtsp-media.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 2f7d498a3e..e30bc0e742 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1410,8 +1410,9 @@ no_more_pads_cb (GstElement * element, GstRTSPMedia * media) * gst_rtsp_media_prepare: * @media: a #GstRTSPMedia * - * Prepare @media for streaming. This function will create the pipeline and - * other objects to manage the streaming. + * Prepare @media for streaming. This function will create the objects + * to manage the streaming. A pipeline must have been set on @media with + * gst_rtsp_media_take_pipeline(). * * It will preroll the pipeline and collect vital information about the streams * such as the duration. @@ -1612,9 +1613,6 @@ finish_unprepare (GstRTSPMedia * media) gst_object_unref (priv->nettime); priv->nettime = NULL; - gst_object_unref (priv->pipeline); - priv->pipeline = NULL; - priv->reused = TRUE; priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARED; From 9b31fcc7f869a16d138c3be073720bf452777709 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 22 Apr 2013 16:25:17 +0200 Subject: [PATCH 0624/1776] media: don't free streams array Don't free the streams array in the unprepare() method, they were not added in prepare(). See https://bugzilla.gnome.org/show_bug.cgi?id=698376 --- gst/rtsp-server/rtsp-media.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e30bc0e742..e81aa126d7 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1604,7 +1604,6 @@ finish_unprepare (GstRTSPMedia * media) gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin); } - g_ptr_array_set_size (priv->streams, 0); gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin); priv->rtpbin = NULL; From a26b06cc69b2dfed17b64eab236e0f1aafaea084 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 22 Apr 2013 16:40:48 +0200 Subject: [PATCH 0625/1776] media: disconnect from signal handlers in unprepare() We connected to the pad-added and no-more-pads signals in prepare() so we need to disconnect from them in unprepare(). See https://bugzilla.gnome.org/show_bug.cgi?id=698376 --- gst/rtsp-server/rtsp-media.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e81aa126d7..5eaf979075 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1406,6 +1406,14 @@ no_more_pads_cb (GstElement * element, GstRTSPMedia * media) } } +typedef struct _DynPaySignalHandlers DynPaySignalHandlers; + +struct _DynPaySignalHandlers +{ + gulong pad_added_handler; + gulong no_more_pads_handler; +}; + /** * gst_rtsp_media_prepare: * @media: a #GstRTSPMedia @@ -1490,11 +1498,16 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) for (walk = priv->dynamic; walk; walk = g_list_next (walk)) { GstElement *elem = walk->data; + DynPaySignalHandlers *handlers = g_slice_new (DynPaySignalHandlers); GST_INFO ("adding callbacks for dynamic element %p", elem); - g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media); - g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media); + handlers->pad_added_handler = g_signal_connect (elem, "pad-added", + (GCallback) pad_added_cb, media); + handlers->no_more_pads_handler = g_signal_connect (elem, "no-more-pads", + (GCallback) no_more_pads_cb, media); + + g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers); /* we add a fakesink here in order to make the state change async. We remove * the fakesink again in the no-more-pads callback. */ @@ -1590,6 +1603,7 @@ finish_unprepare (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; gint i; + GList *walk; GST_DEBUG ("shutting down"); @@ -1605,6 +1619,21 @@ finish_unprepare (GstRTSPMedia * media) gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin); } + /* remove the pad signal handlers */ + for (walk = priv->dynamic; walk; walk = g_list_next (walk)) { + GstElement *elem = walk->data; + DynPaySignalHandlers *handlers; + + handlers = g_object_steal_data (G_OBJECT (elem), "gst-rtsp-dypay-handlers"); + g_assert (handlers != NULL); + + g_signal_handler_disconnect (G_OBJECT (elem), handlers->pad_added_handler); + g_signal_handler_disconnect (G_OBJECT (elem), + handlers->no_more_pads_handler); + + g_slice_free (DynPaySignalHandlers, handlers); + } + gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin); priv->rtpbin = NULL; From f15288259edcc74362fcb44ba876a4ebaa947969 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 22 Apr 2013 16:49:39 +0200 Subject: [PATCH 0626/1776] check: add media prepare/unprepare test See https://bugzilla.gnome.org/show_bug.cgi?id=698376 --- tests/check/gst/media.c | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index b62887115b..64fae708f5 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -114,6 +114,60 @@ GST_START_TEST (test_media) GST_END_TEST; +GST_START_TEST (test_media_prepare) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + + /* test non-reusable media first */ + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 1); + + fail_unless (gst_rtsp_media_prepare (media)); + fail_unless (gst_rtsp_media_unprepare (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 1); + fail_if (gst_rtsp_media_prepare (media)); + + g_object_unref (media); + gst_rtsp_url_free (url); + g_object_unref (factory); + + /* test reusable media */ + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 1); + + g_object_set (G_OBJECT (media), "reusable", TRUE, NULL); + + fail_unless (gst_rtsp_media_prepare (media)); + fail_unless (gst_rtsp_media_unprepare (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 1); + fail_unless (gst_rtsp_media_prepare (media)); + fail_unless (gst_rtsp_media_unprepare (media)); + + g_object_unref (media); + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + static Suite * rtspmedia_suite (void) { @@ -124,6 +178,7 @@ rtspmedia_suite (void) tcase_set_timeout (tc, 20); tcase_add_test (tc, test_launch); tcase_add_test (tc, test_media); + tcase_add_test (tc, test_media_prepare); return s; } From 00291e528514f9311e859dc29560cce4c3aabe55 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 22 Apr 2013 17:32:31 +0200 Subject: [PATCH 0627/1776] stream: add method to get the srcpad --- gst/rtsp-server/rtsp-stream.c | 16 ++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 1 + 2 files changed, 17 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index ebf50a0b23..dbcb26ead4 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -194,6 +194,22 @@ gst_rtsp_stream_get_index (GstRTSPStream * stream) return stream->priv->idx; } + /** + * gst_rtsp_stream_get_srcpad: + * @stream: a #GstRTSPStream + * + * Get the srcpad associated with @stream. + * + * Return: the srcpad. Unref after usage. + */ +GstPad * +gst_rtsp_stream_get_srcpad (GstRTSPStream * stream) +{ + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + return gst_object_ref (stream->priv->srcpad); +} + /** * gst_rtsp_stream_set_mtu: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index ba3bf40810..b0512d82b2 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -64,6 +64,7 @@ GType gst_rtsp_stream_get_type (void); GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement *payloader, GstPad *srcpad); guint gst_rtsp_stream_get_index (GstRTSPStream *stream); +GstPad * gst_rtsp_stream_get_srcpad (GstRTSPStream *stream); void gst_rtsp_stream_set_mtu (GstRTSPStream *stream, guint mtu); guint gst_rtsp_stream_get_mtu (GstRTSPStream *stream); From b61431962240feee8e7cf908be9175763b0c6328 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 22 Apr 2013 17:33:30 +0200 Subject: [PATCH 0628/1776] tests: add example of reusable pipelines --- examples/test-sdp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/test-sdp.c b/examples/test-sdp.c index f3d9e57f70..98efe9e51f 100644 --- a/examples/test-sdp.c +++ b/examples/test-sdp.c @@ -34,6 +34,12 @@ timeout (GstRTSPServer * server, gboolean ignored) return TRUE; } +static void +media_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) +{ + gst_rtsp_media_set_reusable (media, TRUE); +} + int main (int argc, char *argv[]) { @@ -70,6 +76,8 @@ main (int argc, char *argv[]) argv[1]); gst_rtsp_media_factory_set_launch (factory, str); gst_rtsp_media_factory_set_shared (factory, TRUE); + g_signal_connect (factory, "media-configure", (GCallback) media_configure, + NULL); g_free (str); /* attach the test factory to the /test url */ From b80b8824be2f792a6d9ac831af185c950cbc56b8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 22 Apr 2013 17:34:37 +0200 Subject: [PATCH 0629/1776] media: listen to pad-removed signals Listen to the pad-removed signal and remove the stream associated with the removed pad. Add signal to be notified of the removed pad. Remove the fakesink in unprepare() Fix signatures of the signal methods --- gst/rtsp-server/rtsp-media.c | 72 ++++++++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-media.h | 9 +++-- 2 files changed, 74 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 5eaf979075..e48f70cdf1 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -102,6 +102,7 @@ enum enum { SIGNAL_NEW_STREAM, + SIGNAL_REMOVED_STREAM, SIGNAL_PREPARED, SIGNAL_UNPREPARED, SIGNAL_NEW_STATE, @@ -180,6 +181,12 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_STREAM); + gst_rtsp_media_signals[SIGNAL_REMOVED_STREAM] = + g_signal_new ("removed-stream", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, removed_stream), + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, + GST_TYPE_RTSP_STREAM); + gst_rtsp_media_signals[SIGNAL_PREPARED] = g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL, @@ -972,6 +979,30 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, return stream; } +static void +gst_rtsp_media_remove_stream (GstRTSPMedia * media, GstRTSPStream * stream) +{ + GstRTSPMediaPrivate *priv; + GstPad *srcpad; + + priv = media->priv; + + g_mutex_lock (&priv->lock); + /* remove the ghostpad */ + srcpad = gst_rtsp_stream_get_srcpad (stream); + gst_element_remove_pad (priv->element, srcpad); + gst_object_unref (srcpad); + /* now remove the stream */ + g_object_ref (stream); + g_ptr_array_remove (priv->streams, stream); + g_mutex_unlock (&priv->lock); + + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_REMOVED_STREAM], 0, + stream, NULL); + + g_object_unref (stream); +} + /** * gst_rtsp_media_n_streams: * @media: a #GstRTSPMedia @@ -1369,6 +1400,8 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) /* FIXME, element is likely not a payloader, find the payloader here */ stream = gst_rtsp_media_create_stream (media, element, pad); + g_object_set_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream", stream); + GST_INFO ("pad added %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream); g_rec_mutex_lock (&priv->state_lock); @@ -1387,13 +1420,30 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) } static void -no_more_pads_cb (GstElement * element, GstRTSPMedia * media) +pad_removed_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; + GstRTSPStream *stream; + + stream = g_object_get_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream"); + if (stream == NULL) + return; + + GST_INFO ("pad removed %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream); + + g_rec_mutex_lock (&priv->state_lock); + gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin); + g_rec_mutex_unlock (&priv->state_lock); + + gst_rtsp_media_remove_stream (media, stream); +} + +static void +remove_fakesink (GstRTSPMediaPrivate * priv) +{ GstElement *fakesink; g_mutex_lock (&priv->lock); - GST_INFO ("no more pads"); if ((fakesink = priv->fakesink)) { gst_object_ref (fakesink); priv->fakesink = NULL; @@ -1406,11 +1456,21 @@ no_more_pads_cb (GstElement * element, GstRTSPMedia * media) } } +static void +no_more_pads_cb (GstElement * element, GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + + GST_INFO ("no more pads"); + remove_fakesink (priv); +} + typedef struct _DynPaySignalHandlers DynPaySignalHandlers; struct _DynPaySignalHandlers { gulong pad_added_handler; + gulong pad_removed_handler; gulong no_more_pads_handler; }; @@ -1504,6 +1564,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) handlers->pad_added_handler = g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media); + handlers->pad_removed_handler = g_signal_connect (elem, "pad-removed", + (GCallback) pad_removed_cb, media); handlers->no_more_pads_handler = g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media); @@ -1608,6 +1670,7 @@ finish_unprepare (GstRTSPMedia * media) GST_DEBUG ("shutting down"); gst_element_set_state (priv->pipeline, GST_STATE_NULL); + remove_fakesink (priv); for (i = 0; i < priv->streams->len; i++) { GstRTSPStream *stream; @@ -1624,10 +1687,13 @@ finish_unprepare (GstRTSPMedia * media) GstElement *elem = walk->data; DynPaySignalHandlers *handlers; - handlers = g_object_steal_data (G_OBJECT (elem), "gst-rtsp-dypay-handlers"); + handlers = + g_object_steal_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers"); g_assert (handlers != NULL); g_signal_handler_disconnect (G_OBJECT (elem), handlers->pad_added_handler); + g_signal_handler_disconnect (G_OBJECT (elem), + handlers->pad_removed_handler); g_signal_handler_disconnect (G_OBJECT (elem), handlers->no_more_pads_handler); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 2a7c3dbaa5..66e83de033 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -102,12 +102,13 @@ struct _GstRTSPMediaClass { gboolean (*unprepare) (GstRTSPMedia *media); /* signals */ - gboolean (*new_stream) (GstRTSPMedia *media, GstRTSPStream * stream); + void (*new_stream) (GstRTSPMedia *media, GstRTSPStream * stream); + void (*removed_stream) (GstRTSPMedia *media, GstRTSPStream * stream); - gboolean (*prepared) (GstRTSPMedia *media); - gboolean (*unprepared) (GstRTSPMedia *media); + void (*prepared) (GstRTSPMedia *media); + void (*unprepared) (GstRTSPMedia *media); - gboolean (*new_state) (GstRTSPMedia *media, GstState state); + void (*new_state) (GstRTSPMedia *media, GstState state); }; GType gst_rtsp_media_get_type (void); From a09210b6486c1555e3bbdd5029278fdb1532c4d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 22 Apr 2013 23:55:48 +0100 Subject: [PATCH 0630/1776] Automatic update of common submodule From 3cb3d3c to 5edcd85 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 3cb3d3cbbf..5edcd857b2 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 3cb3d3cbbf794c18a6f91866c6d7fa38880c1eb8 +Subproject commit 5edcd857b2107cd8b78c16232dd10877513ec157 From 0ddd98bfa6420e87d33078a6ae22b73752e625d5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 23 Apr 2013 10:16:17 +0200 Subject: [PATCH 0631/1776] stream: set elements to NULL before removing When removing a stream, set the elements to NULL first. This avoids element-is-not-in-NULL-state errors when we dispose the elements. --- gst/rtsp-server/rtsp-stream.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index dbcb26ead4..8f2cd91044 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1168,8 +1168,7 @@ link_failed: * @bin: a #GstBin * @rtpbin: a rtpbin #GstElement * - * Remove the elements of @stream from @bin. @bin must be set - * to the NULL state before calling this. + * Remove the elements of @stream from @bin. * * Return: %TRUE on success. */ @@ -1202,6 +1201,12 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->send_rtp_sink = NULL; for (i = 0; i < 2; i++) { + gst_element_set_state (priv->udpsink[i], GST_STATE_NULL); + gst_element_set_state (priv->appsink[i], GST_STATE_NULL); + gst_element_set_state (priv->appqueue[i], GST_STATE_NULL); + gst_element_set_state (priv->tee[i], GST_STATE_NULL); + gst_element_set_state (priv->funnel[i], GST_STATE_NULL); + gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); /* and set udpsrc to NULL now before removing */ gst_element_set_locked_state (priv->udpsrc[i], FALSE); gst_element_set_state (priv->udpsrc[i], GST_STATE_NULL); From 573b10bc83defa2c9cdfb8f786c195b4d39e4078 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 23 Apr 2013 10:27:35 +0200 Subject: [PATCH 0632/1776] media: release lock when removing fakesink --- gst/rtsp-server/rtsp-media.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e48f70cdf1..7609bff04f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1444,11 +1444,12 @@ remove_fakesink (GstRTSPMediaPrivate * priv) GstElement *fakesink; g_mutex_lock (&priv->lock); - if ((fakesink = priv->fakesink)) { + if ((fakesink = priv->fakesink)) gst_object_ref (fakesink); - priv->fakesink = NULL; - g_mutex_unlock (&priv->lock); + priv->fakesink = NULL; + g_mutex_unlock (&priv->lock); + if (fakesink) { gst_bin_remove (GST_BIN (priv->pipeline), fakesink); gst_element_set_state (fakesink, GST_STATE_NULL); gst_object_unref (fakesink); From 6065400a62bccfd46a33824d9ee7b1bc06ff0b27 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Tue, 23 Apr 2013 11:28:39 +0200 Subject: [PATCH 0633/1776] tests: add dynamic payloader prepare/unprepare check --- tests/check/gst/media.c | 70 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 64fae708f5..874a207eae 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -168,6 +168,75 @@ GST_START_TEST (test_media_prepare) GST_END_TEST; +static void +on_notify_caps (GstPad * pad, GParamSpec * pspec, GstElement * pay) +{ + GstCaps *caps; + + g_object_get (pad, "caps", &caps, NULL); + + GST_DEBUG ("notify %" GST_PTR_FORMAT, caps); + + if (caps) { + g_signal_emit_by_name (pay, "pad-added", pad); + g_signal_emit_by_name (pay, "no-more-pads", NULL); + } else { + g_signal_emit_by_name (pay, "pad-removed", pad); + } +} + +GST_START_TEST (test_media_dyn_prepare) +{ + GstRTSPMedia *media; + GstElement *bin, *src, *pay; + GstElement *pipeline; + GstPad *srcpad; + + bin = gst_bin_new ("bin"); + fail_if (bin == NULL); + + src = gst_element_factory_make ("videotestsrc", NULL); + fail_if (src == NULL); + + pay = gst_element_factory_make ("rtpvrawpay", "dynpay0"); + fail_if (pay == NULL); + g_object_set (pay, "pt", 96, NULL); + + gst_bin_add_many (GST_BIN_CAST (bin), src, pay, NULL); + gst_element_link_many (src, pay, NULL); + + media = gst_rtsp_media_new (bin); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + g_object_set (G_OBJECT (media), "reusable", TRUE, NULL); + + pipeline = gst_pipeline_new ("media-pipeline"); + gst_rtsp_media_take_pipeline (media, GST_PIPELINE_CAST (pipeline)); + + gst_rtsp_media_collect_streams (media); + + srcpad = gst_element_get_static_pad (pay, "src"); + + g_signal_connect (srcpad, "notify::caps", (GCallback) on_notify_caps, pay); + + fail_unless (gst_rtsp_media_n_streams (media) == 0); + fail_unless (gst_rtsp_media_prepare (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 1); + fail_unless (gst_rtsp_media_unprepare (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 0); + + fail_unless (gst_rtsp_media_n_streams (media) == 0); + fail_unless (gst_rtsp_media_prepare (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 1); + fail_unless (gst_rtsp_media_unprepare (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 0); + + gst_object_unref (srcpad); + g_object_unref (media); +} + +GST_END_TEST; + static Suite * rtspmedia_suite (void) { @@ -179,6 +248,7 @@ rtspmedia_suite (void) tcase_add_test (tc, test_launch); tcase_add_test (tc, test_media); tcase_add_test (tc, test_media_prepare); + tcase_add_test (tc, test_media_dyn_prepare); return s; } From be193ceb86e4fce44094d08946f85605806f6658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 15 May 2013 10:55:09 +0200 Subject: [PATCH 0634/1776] Automatic update of common submodule From 5edcd85 to 098c0d7 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 5edcd857b2..098c0d7432 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 5edcd857b2107cd8b78c16232dd10877513ec157 +Subproject commit 098c0d7432be323d631b95b5d35f6f0840bf21bd From 0951aa37e19d1ad285c24bab6de4b268993a1c28 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Mon, 29 Apr 2013 14:46:30 +0200 Subject: [PATCH 0635/1776] rtsp-sdp: add bandwidth line https://bugzilla.gnome.org/show_bug.cgi?id=699220 --- gst/rtsp-server/rtsp-sdp.c | 45 +++++++++++ tests/check/gst/client.c | 148 ++++++++++++++++++++++++++++++++++++- 2 files changed, 189 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 7597bb48a3..63845686f7 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -20,6 +20,48 @@ #include "rtsp-sdp.h" +static gboolean +get_info_from_tags (GstPad * pad, GstEvent ** event, gpointer user_data) +{ + GstSDPMedia * media = (GstSDPMedia *) user_data; + + if (GST_EVENT_TYPE (*event) == GST_EVENT_TAG) { + GstTagList *tags; + guint bitrate = 0; + + gst_event_parse_tag (*event, &tags); + + if (gst_tag_list_get_scope (tags) != GST_TAG_SCOPE_STREAM) + return TRUE; + + if (!gst_tag_list_get_uint (tags, GST_TAG_MAXIMUM_BITRATE, + &bitrate) || bitrate == 0) + if (!gst_tag_list_get_uint (tags, GST_TAG_BITRATE, &bitrate) || + bitrate == 0) + return TRUE; + + /* set bandwidth (kbits/s) */ + gst_sdp_media_add_bandwidth (media, GST_SDP_BWTYPE_AS, bitrate/1000); + + return FALSE; + + } + + return TRUE; +} + +static void +update_sdp_from_tags (GstRTSPStream * stream, GstSDPMedia * stream_media) +{ + GstPad *src_pad; + + src_pad = gst_rtsp_stream_get_srcpad (stream); + + gst_pad_sticky_events_foreach (src_pad, get_info_from_tags, stream_media); + + gst_object_unref (src_pad); +} + /** * gst_rtsp_sdp_from_media: * @sdp: a #GstSDPMessage @@ -153,6 +195,9 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, } else { g_string_free (fmtp, TRUE); } + + update_sdp_from_tags (stream, smedia); + gst_sdp_message_add_media (sdp, smedia); gst_sdp_media_free (smedia); gst_caps_unref (caps); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 52ef2ae332..db962f79c3 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -108,7 +108,7 @@ test_response_454 (GstRTSPClient * client, GstRTSPMessage * response, } static GstRTSPClient * -setup_client (void) +setup_client (const gchar * launch_line) { GstRTSPClient *client; GstRTSPSessionPool *session_pool; @@ -122,8 +122,12 @@ setup_client (void) mount_points = gst_rtsp_mount_points_new (); factory = gst_rtsp_media_factory_new (); - gst_rtsp_media_factory_set_launch (factory, - "videotestsrc ! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96"); + if (launch_line == NULL) + gst_rtsp_media_factory_set_launch (factory, + "videotestsrc ! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96"); + else + gst_rtsp_media_factory_set_launch (factory, launch_line); + gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); gst_rtsp_client_set_mount_points (client, mount_points); @@ -267,7 +271,7 @@ GST_START_TEST (test_describe) g_object_unref (client); /* simple DESCRIBE for an existing url */ - client = setup_client (); + client = setup_client (NULL); fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, "rtsp://localhost/test") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); @@ -612,6 +616,138 @@ GST_START_TEST (test_client_multicast_transport_specific) GST_END_TEST; +static gboolean +test_response_sdp (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + guint8 *data; + guint size; + GstSDPMessage *sdp_msg; + const GstSDPMedia *sdp_media; + const GstSDPBandwidth *bw; + gint bandwidth_val = GPOINTER_TO_INT (user_data); + + fail_unless (gst_rtsp_message_get_body (response, &data, &size) + == GST_RTSP_OK); + gst_sdp_message_new (&sdp_msg); + fail_unless (gst_sdp_message_parse_buffer (data, size, sdp_msg) + == GST_SDP_OK); + + /* session description */ + /* v= */ + fail_unless (gst_sdp_message_get_version (sdp_msg) != NULL); + /* o= */ + fail_unless (gst_sdp_message_get_origin (sdp_msg) != NULL); + /* s= */ + fail_unless (gst_sdp_message_get_session_name (sdp_msg) != NULL); + /* t=0 0 */ + fail_unless (gst_sdp_message_times_len (sdp_msg) == 0); + + /* verify number of medias */ + fail_unless (gst_sdp_message_medias_len (sdp_msg) == 1); + + /* media description */ + sdp_media = gst_sdp_message_get_media (sdp_msg, 0); + fail_unless (sdp_media != NULL); + + /* m= */ + fail_unless (gst_sdp_media_get_media (sdp_media) != NULL); + + /* media bandwidth */ + if (bandwidth_val) { + fail_unless (gst_sdp_media_bandwidths_len (sdp_media) == 1); + bw = gst_sdp_media_get_bandwidth (sdp_media, 0); + fail_unless (bw != NULL); + fail_unless (g_strcmp0 (bw->bwtype, "AS") == 0); + fail_unless (bw->bandwidth == bandwidth_val); + } else { + fail_unless (gst_sdp_media_bandwidths_len (sdp_media) == 0); + } + + gst_sdp_message_free (sdp_msg); + + return TRUE; +} + +static void +test_client_sdp (const gchar * launch_line, guint * bandwidth_val) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + + /* simple DESCRIBE for an existing url */ + client = setup_client (launch_line); + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + + gst_rtsp_client_set_send_func (client, test_response_sdp, (gpointer) bandwidth_val, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + g_object_unref (client); + +} + +GST_START_TEST (test_client_sdp_with_max_bitrate_tag) +{ + test_client_sdp ("videotestsrc " + "! taginject tags=\"maximum-bitrate=(uint)50000000\" " + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (50000)); + + + /* max-bitrate=0: no bandwidth line */ + test_client_sdp ("videotestsrc " + "! taginject tags=\"maximum-bitrate=(uint)0\" " + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (0)); +} + +GST_END_TEST; + +GST_START_TEST (test_client_sdp_with_bitrate_tag) +{ + test_client_sdp ("videotestsrc " + "! taginject tags=\"bitrate=(uint)7000000\" " + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (7000)); + + /* bitrate=0: no bandwdith line */ + test_client_sdp ("videotestsrc " + "! taginject tags=\"bitrate=(uint)0\" " + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (0)); +} + +GST_END_TEST; + +GST_START_TEST (test_client_sdp_with_max_bitrate_and_bitrate_tags) +{ + test_client_sdp ("videotestsrc " + "! taginject tags=\"bitrate=(uint)7000000,maximum-bitrate=(uint)50000000\" " + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (50000)); + + /* max-bitrate is zero: fallback to bitrate */ + test_client_sdp ("videotestsrc " + "! taginject tags=\"bitrate=(uint)7000000,maximum-bitrate=(uint)0\" " + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (7000)); + + /* max-bitrate=bitrate=0o: no bandwidth line */ + test_client_sdp ("videotestsrc " + "! taginject tags=\"bitrate=(uint)0,maximum-bitrate=(uint)0\" " + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (0)); +} + +GST_END_TEST; + +GST_START_TEST (test_client_sdp_with_no_bitrate_tags) +{ + test_client_sdp ("videotestsrc " + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", NULL); +} + +GST_END_TEST; static Suite * rtspclient_suite (void) @@ -629,6 +765,10 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_ignore_transport_specific); tcase_add_test (tc, test_client_multicast_invalid_transport_specific); tcase_add_test (tc, test_client_multicast_transport_specific); + tcase_add_test (tc, test_client_sdp_with_max_bitrate_tag); + tcase_add_test (tc, test_client_sdp_with_bitrate_tag); + tcase_add_test (tc, test_client_sdp_with_max_bitrate_and_bitrate_tags); + tcase_add_test (tc, test_client_sdp_with_no_bitrate_tags); return s; } From 5fd034ff1a517db7f629ffcc3ed16839c61f5c97 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Wed, 22 May 2013 03:29:30 +0200 Subject: [PATCH 0636/1776] rtsp-sdp: Parse width/height from caps and set SDP attribute The SDP attribute and its format is described in RFC6064. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=700747 --- gst/rtsp-server/rtsp-sdp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 63845686f7..67f031bcb9 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -100,6 +100,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, gboolean first; GString *fmtp; GstCaps *caps; + gint width, height; stream = gst_rtsp_media_get_stream (media, i); caps = gst_rtsp_stream_get_caps (stream); @@ -150,6 +151,18 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, g_free (tmp); } + /* create framesize SDP attribute */ + if (gst_structure_get_int (s, "width", &width) && width > 0 && + gst_structure_get_int (s, "height", &height) && height > 0) { + tmp = g_strdup_printf ("%d %d-%d", caps_pt, width, height); + gst_sdp_media_add_attribute (smedia, "framesize", tmp); + g_free (tmp); + + tmp = g_strdup_printf (" %d,%d", width, height); + gst_sdp_media_add_attribute (smedia, "x-dimensions", tmp); + g_free (tmp); + } + /* the config uri */ tmp = g_strdup_printf ("stream=%d", i); gst_sdp_media_add_attribute (smedia, "control", tmp); @@ -182,6 +195,10 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, continue; if (!strcmp (fname, "seqnum-base")) continue; + if (!strcmp (fname, "width")) + continue; + if (!strcmp (fname, "height")) + continue; if ((fval = gst_structure_get_string (s, fname))) { g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval); From d6a4dee03642a2d2c05fec4752dc3ccb60b19494 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Wed, 22 May 2013 03:29:38 +0200 Subject: [PATCH 0637/1776] rtsp-sdp: Parse framerate caps field and set SDP attribute The SDP attribute and its format is described in RFC4566. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=700747 --- gst/rtsp-server/rtsp-sdp.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 67f031bcb9..6b0a046c43 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -101,6 +101,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, GString *fmtp; GstCaps *caps; gint width, height; + gint num = 0, denom = 1; stream = gst_rtsp_media_get_stream (media, i); caps = gst_rtsp_stream_get_caps (stream); @@ -163,6 +164,16 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, g_free (tmp); } + /* create framerate SDP attribute if frame is not zero */ + if (gst_structure_get_fraction (s, "framerate", &num, &denom) && num > 0) { + gdouble rate; + gchar framerate [G_ASCII_DTOSTR_BUF_SIZE]; + + gst_util_fraction_to_double (num, denom, &rate); + g_ascii_formatd (framerate, sizeof (framerate), " %.17g", rate); + gst_sdp_media_add_attribute (smedia, "framerate", framerate); + } + /* the config uri */ tmp = g_strdup_printf ("stream=%d", i); gst_sdp_media_add_attribute (smedia, "control", tmp); @@ -199,6 +210,8 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, continue; if (!strcmp (fname, "height")) continue; + if (!strcmp (fname, "framerate")) + continue; if ((fval = gst_structure_get_string (s, fname))) { g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval); From e047c9fec11429b878865f2814d4bf3d9325427a Mon Sep 17 00:00:00 2001 From: Alexander Schrab Date: Fri, 24 May 2013 13:39:50 +0200 Subject: [PATCH 0638/1776] rtsp-client: ipv4 adress should not be marked ipv6 even if socket is ipv6 https://bugzilla.gnome.org/show_bug.cgi?id=700953 --- gst/rtsp-server/rtsp-client.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 5b5affe2b7..8496aa02ad 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2389,7 +2389,6 @@ setup_client (GstRTSPClient * client, GSocket * socket, GstRTSPUrl *url; read_socket = gst_rtsp_connection_get_read_socket (conn); - priv->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6; if (!(address = g_socket_get_remote_address (read_socket, error))) goto no_address; @@ -2401,9 +2400,12 @@ setup_client (GstRTSPClient * client, GSocket * socket, iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address)); + /* socket might be ipv6 but adress still ipv4 */ + priv->is_ipv6 = g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV6; priv->server_ip = g_inet_address_to_string (iaddr); g_object_unref (address); } else { + priv->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6; priv->server_ip = g_strdup ("unknown"); } From c75e1c6b4741cfe9f3ad4264271ce472f66de7c2 Mon Sep 17 00:00:00 2001 From: Alexander Schrab Date: Mon, 27 May 2013 12:58:07 +0200 Subject: [PATCH 0639/1776] rtsp-server: Do not crash on nmapping of server * generate error when gst_rtsp_connection_accept fails * do not stop accepting incoming connections because accepting a client fails https://bugzilla.gnome.org/show_bug.cgi?id=701072 --- gst/rtsp-server/rtsp-client.c | 3 ++- gst/rtsp-server/rtsp-server.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8496aa02ad..debfbf9f2f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2499,7 +2499,8 @@ gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, accept_failed: { gchar *str = gst_rtsp_strresult (res); - + *error = g_error_new (GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, + "Could not accept client on server socket %p: %s", socket, str); GST_ERROR ("Could not accept client on server socket %p: %s", socket, str); g_free (str); return FALSE; diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index ccfcf498e2..0035987492 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1214,20 +1214,20 @@ gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, } else { GST_WARNING_OBJECT (server, "received unknown event %08x", condition); } - return TRUE; + return G_SOURCE_CONTINUE; /* ERRORS */ client_failed: { GST_ERROR_OBJECT (server, "failed to create a client"); - return FALSE; + return G_SOURCE_CONTINUE; } accept_failed: { GST_ERROR_OBJECT (server, "failed to accept client: %s", error->message); g_error_free (error); g_object_unref (client); - return FALSE; + return G_SOURCE_CONTINUE; } } From 7b880231b18791ebee0666096219e7cf479c2675 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 30 May 2013 06:49:20 +0200 Subject: [PATCH 0640/1776] stream: keep the transport object alive Keep the transport object alive while we have it as qdata on the source. --- gst/rtsp-server/rtsp-stream.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 8f2cd91044..38da5ef301 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -787,6 +787,8 @@ find_transport (GstRTSPStream * stream, const gchar * rtcp_from) break; } } + if (result) + g_object_ref (result); g_mutex_unlock (&priv->lock); g_free (dest); @@ -813,7 +815,8 @@ check_transport (GObject * source, GstRTSPStream * stream) if ((trans = find_transport (stream, rtcp_from))) { GST_INFO ("%p: found transport %p for source %p", stream, trans, source); - g_object_set_qdata (source, ssrc_stream_map_key, trans); + g_object_set_qdata_full (source, ssrc_stream_map_key, trans, + g_object_unref); } gst_structure_free (stats); } @@ -879,6 +882,7 @@ on_bye_timeout (GObject * session, GObject * source, GstRTSPStream * stream) if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) { gst_rtsp_stream_transport_set_timed_out (trans, TRUE); + g_object_set_qdata (source, ssrc_stream_map_key, NULL); } } @@ -891,6 +895,7 @@ on_timeout (GObject * session, GObject * source, GstRTSPStream * stream) if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) { gst_rtsp_stream_transport_set_timed_out (trans, TRUE); + g_object_set_qdata (source, ssrc_stream_map_key, NULL); } } From d638b03ff9559f3fb8e7eeba01814d9d3d0dfffb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 30 May 2013 07:18:22 +0200 Subject: [PATCH 0641/1776] server: refactor connection setup Let the server accept the socket connection and construct a GstRTSPConnection from it. Remove the code from the client and let the client only deal with a fully configure GstRTSPConnection object. We will need this later when the server will configure the connection for TLS. --- gst/rtsp-server/rtsp-client.c | 193 ++++++++++++---------------------- gst/rtsp-server/rtsp-client.h | 14 +-- gst/rtsp-server/rtsp-server.c | 44 +++++--- 3 files changed, 94 insertions(+), 157 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index debfbf9f2f..8c62deb379 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2054,6 +2054,71 @@ gst_rtsp_client_get_uri (GstRTSPClient * client) return result; } +/** + * gst_rtsp_client_set_connection: + * @client: a #GstRTSPClient + * @conn: (transfer full): a #GstRTSPConnection + * + * Set the #GstRTSPConnection of @client. This function takes ownership of + * @conn. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_client_set_connection (GstRTSPClient * client, + GstRTSPConnection * conn) +{ + GstRTSPClientPrivate *priv; + GSocket *read_socket; + GSocketAddress *address; + GstRTSPUrl *url; + GError *error = NULL; + + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); + g_return_val_if_fail (conn != NULL, FALSE); + + priv = client->priv; + + read_socket = gst_rtsp_connection_get_read_socket (conn); + + if (!(address = g_socket_get_remote_address (read_socket, &error))) + goto no_address; + + g_free (priv->server_ip); + /* keep the original ip that the client connected to */ + if (G_IS_INET_SOCKET_ADDRESS (address)) { + GInetAddress *iaddr; + + iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address)); + + /* socket might be ipv6 but adress still ipv4 */ + priv->is_ipv6 = g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV6; + priv->server_ip = g_inet_address_to_string (iaddr); + g_object_unref (address); + } else { + priv->is_ipv6 = g_socket_get_family (read_socket) == G_SOCKET_FAMILY_IPV6; + priv->server_ip = g_strdup ("unknown"); + } + + GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client, + priv->server_ip, priv->is_ipv6); + + url = gst_rtsp_connection_get_url (conn); + GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port); + + priv->connection = conn; + + return TRUE; + + /* ERRORS */ +no_address: + { + GST_ERROR ("could not get remote address %s", error->message); + g_error_free (error); + return FALSE; + } +} + /** * gst_rtsp_client_get_connection: * @client: a #GstRTSPClient @@ -2379,134 +2444,6 @@ client_watch_notify (GstRTSPClient * client) g_object_unref (client); } -static gboolean -setup_client (GstRTSPClient * client, GSocket * socket, - GstRTSPConnection * conn, GError ** error) -{ - GstRTSPClientPrivate *priv = client->priv; - GSocket *read_socket; - GSocketAddress *address; - GstRTSPUrl *url; - - read_socket = gst_rtsp_connection_get_read_socket (conn); - - if (!(address = g_socket_get_remote_address (read_socket, error))) - goto no_address; - - g_free (priv->server_ip); - /* keep the original ip that the client connected to */ - if (G_IS_INET_SOCKET_ADDRESS (address)) { - GInetAddress *iaddr; - - iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address)); - - /* socket might be ipv6 but adress still ipv4 */ - priv->is_ipv6 = g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV6; - priv->server_ip = g_inet_address_to_string (iaddr); - g_object_unref (address); - } else { - priv->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6; - priv->server_ip = g_strdup ("unknown"); - } - - GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client, - priv->server_ip, priv->is_ipv6); - - url = gst_rtsp_connection_get_url (conn); - GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port); - - priv->connection = conn; - - return TRUE; - - /* ERRORS */ -no_address: - { - GST_ERROR ("could not get remote address %s", (*error)->message); - return FALSE; - } -} - -/** - * gst_rtsp_client_use_socket: - * @client: a #GstRTSPClient - * @socket: a #GSocket - * @ip: the IP address of the remote client - * @port: the port used by the other end - * @initial_buffer: any zero terminated initial data that was already read from - * the socket - * @error: a #GError - * - * Take an existing network socket and use it for an RTSP connection. - * - * Returns: %TRUE on success. - */ -gboolean -gst_rtsp_client_use_socket (GstRTSPClient * client, GSocket * socket, - const gchar * ip, gint port, const gchar * initial_buffer, GError ** error) -{ - GstRTSPConnection *conn; - GstRTSPResult res; - - g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); - g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); - - GST_RTSP_CHECK (gst_rtsp_connection_create_from_socket (socket, ip, port, - initial_buffer, &conn), no_connection); - - return setup_client (client, socket, conn, error); - - /* ERRORS */ -no_connection: - { - gchar *str = gst_rtsp_strresult (res); - - GST_ERROR ("could not create connection from socket %p: %s", socket, str); - g_free (str); - return FALSE; - } -} - -/** - * gst_rtsp_client_accept: - * @client: a #GstRTSPClient - * @socket: a #GSocket - * @context: the context to run in - * @cancellable: a #GCancellable - * @error: a #GError - * - * Accept a new connection for @client on @socket. - * - * Returns: %TRUE if the client could be accepted. - */ -gboolean -gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, - GCancellable * cancellable, GError ** error) -{ - GstRTSPConnection *conn; - GstRTSPResult res; - - g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); - g_return_val_if_fail (G_IS_SOCKET (socket), FALSE); - - /* a new client connected. */ - GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, cancellable), - accept_failed); - - return setup_client (client, socket, conn, error); - - /* ERRORS */ -accept_failed: - { - gchar *str = gst_rtsp_strresult (res); - *error = g_error_new (GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, - "Could not accept client on server socket %p: %s", socket, str); - GST_ERROR ("Could not accept client on server socket %p: %s", socket, str); - g_free (str); - return FALSE; - } -} - /** * gst_rtsp_client_attach: * @client: a #GstRTSPClient diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 5e0f3f3033..4fad1f64ff 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -138,6 +138,8 @@ void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); GstRTSPUrl * gst_rtsp_client_get_uri (GstRTSPClient *client); + +gboolean gst_rtsp_client_set_connection (GstRTSPClient *client, GstRTSPConnection *conn); GstRTSPConnection * gst_rtsp_client_get_connection (GstRTSPClient *client); void gst_rtsp_client_set_send_func (GstRTSPClient *client, @@ -147,18 +149,6 @@ void gst_rtsp_client_set_send_func (GstRTSPClient *client, GstRTSPResult gst_rtsp_client_handle_message (GstRTSPClient *client, GstRTSPMessage *message); -gboolean gst_rtsp_client_accept (GstRTSPClient *client, - GSocket *socket, - GCancellable *cancellable, - GError **error); - -gboolean gst_rtsp_client_use_socket (GstRTSPClient * client, - GSocket *socket, - const gchar * ip, - gint port, - const gchar *initial_buffer, - GError **error); - guint gst_rtsp_client_attach (GstRTSPClient *client, GMainContext *context); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 0035987492..fe9657becd 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1096,19 +1096,28 @@ static gboolean default_accept_client (GstRTSPServer * server, GstRTSPClient * client, GSocket * socket, GError ** error) { - /* accept connections for that client, this function returns after accepting - * the connection and will run the remainder of the communication with the - * client asyncronously. */ - if (!gst_rtsp_client_accept (client, socket, NULL, error)) - goto accept_failed; + GstRTSPConnection *conn; + GstRTSPResult res; + + /* a new client connected. */ + GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, NULL), + accept_failed); + + /* configure the connection */ + + /* set connection on the client now */ + gst_rtsp_client_set_connection (client, conn); return TRUE; /* ERRORS */ accept_failed: { - GST_ERROR_OBJECT (server, - "Could not accept client on server : %s", (*error)->message); + gchar *str = gst_rtsp_strresult (res); + *error = g_error_new (GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, + "Could not accept client on server socket %p: %s", socket, str); + GST_ERROR ("Could not accept client on server socket %p: %s", socket, str); + g_free (str); return FALSE; } } @@ -1134,7 +1143,8 @@ gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket * socket, { GstRTSPClient *client = NULL; GstRTSPServerClass *klass; - GError *error = NULL; + GstRTSPConnection *conn; + GstRTSPResult res; klass = GST_RTSP_SERVER_GET_CLASS (server); @@ -1143,11 +1153,11 @@ gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket * socket, if (client == NULL) goto client_failed; - /* a new client connected, create a client object to handle the client. */ - if (!gst_rtsp_client_use_socket (client, socket, ip, - port, initial_buffer, &error)) { - goto transfer_failed; - } + GST_RTSP_CHECK (gst_rtsp_connection_create_from_socket (socket, ip, port, + initial_buffer, &conn), no_connection); + + /* set connection on the client now */ + gst_rtsp_client_set_connection (client, conn); /* manage the client connection */ manage_client (server, client); @@ -1163,11 +1173,11 @@ client_failed: GST_ERROR_OBJECT (server, "failed to create a client"); return FALSE; } -transfer_failed: +no_connection: { - GST_ERROR_OBJECT (server, "failed to accept client: %s", error->message); - g_error_free (error); - g_object_unref (client); + gchar *str = gst_rtsp_strresult (res); + GST_ERROR ("could not create connection from socket %p: %s", socket, str); + g_free (str); return FALSE; } } From 7526178a099db3869011ed090745711e9e05cc81 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 30 May 2013 10:52:46 +0200 Subject: [PATCH 0642/1776] client: improve debug --- gst/rtsp-server/rtsp-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8c62deb379..4b9d5d7947 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2278,8 +2278,8 @@ error_full (GstRTSPWatch * watch, GstRTSPResult result, str = gst_rtsp_strresult (result); GST_INFO - ("client %p: received an error %s when handling message %p with id %d", - client, str, message, id); + ("client %p: error when handling message %p with id %d: %s", + client, message, id, str); g_free (str); return GST_RTSP_OK; From aa50aac669c4a5567ffd37bd08ab251039a4f018 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 30 May 2013 10:46:33 +0200 Subject: [PATCH 0643/1776] rtsp-session-pool: corrected session timeout detection Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701253 --- gst/rtsp-server/rtsp-session-pool.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index c4709c5c00..f0b65dc81c 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -519,11 +519,8 @@ collect_timeout (gchar * sessionid, GstRTSPSession * sess, GstPoolSource * psrc) { gint timeout; GTimeVal now; - gint64 tmp; - tmp = g_source_get_time ((GSource *) psrc); - now.tv_sec = tmp / G_USEC_PER_SEC; - now.tv_usec = tmp % G_USEC_PER_SEC; + g_get_current_time (&now); timeout = gst_rtsp_session_next_timeout (sess, &now); GST_INFO ("%p: next timeout: %d", sess, timeout); From 0091339254d0d52719400bf94bb82ecb9a375b31 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 30 May 2013 17:23:51 +0200 Subject: [PATCH 0644/1776] server: don't crash on NULL GError --- gst/rtsp-server/rtsp-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index fe9657becd..30f7b14d00 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1114,7 +1114,7 @@ default_accept_client (GstRTSPServer * server, GstRTSPClient * client, accept_failed: { gchar *str = gst_rtsp_strresult (res); - *error = g_error_new (GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, + g_set_error (error, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, "Could not accept client on server socket %p: %s", socket, str); GST_ERROR ("Could not accept client on server socket %p: %s", socket, str); g_free (str); From 531ffca0187a5d8cf07759476e12ec2f5daacf1d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 31 May 2013 11:14:17 +0200 Subject: [PATCH 0645/1776] server: remove accept_client vmethod This vmethod is not very useful so remove it. --- gst/rtsp-server/rtsp-server.c | 58 +++++++++-------------------------- gst/rtsp-server/rtsp-server.h | 3 +- 2 files changed, 15 insertions(+), 46 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 30f7b14d00..24f2282bc1 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -106,8 +106,6 @@ static void gst_rtsp_server_finalize (GObject * object); static gpointer do_loop (Loop * loop); static GstRTSPClient *default_create_client (GstRTSPServer * server); -static gboolean default_accept_client (GstRTSPServer * server, - GstRTSPClient * client, GSocket * socket, GError ** error); static void gst_rtsp_server_class_init (GstRTSPServerClass * klass) @@ -211,7 +209,6 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) gst_rtsp_client_get_type ()); klass->create_client = default_create_client; - klass->accept_client = default_accept_client; klass->pool = g_thread_pool_new ((GFunc) do_loop, klass, -1, FALSE, NULL); @@ -1090,38 +1087,6 @@ default_create_client (GstRTSPServer * server) return client; } -/* default method for creating a new client object in the server to accept and - * handle a client connection on this server */ -static gboolean -default_accept_client (GstRTSPServer * server, GstRTSPClient * client, - GSocket * socket, GError ** error) -{ - GstRTSPConnection *conn; - GstRTSPResult res; - - /* a new client connected. */ - GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, NULL), - accept_failed); - - /* configure the connection */ - - /* set connection on the client now */ - gst_rtsp_client_set_connection (client, conn); - - return TRUE; - - /* ERRORS */ -accept_failed: - { - gchar *str = gst_rtsp_strresult (res); - g_set_error (error, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, - "Could not accept client on server socket %p: %s", socket, str); - GST_ERROR ("Could not accept client on server socket %p: %s", socket, str); - g_free (str); - return FALSE; - } -} - /** * gst_rtsp_server_transfer_connection: * @server: a #GstRTSPServer @@ -1197,24 +1162,27 @@ gboolean gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, GstRTSPServer * server) { - gboolean result = TRUE; GstRTSPClient *client = NULL; GstRTSPServerClass *klass; - GError *error = NULL; + GstRTSPResult res; if (condition & G_IO_IN) { + GstRTSPConnection *conn; + klass = GST_RTSP_SERVER_GET_CLASS (server); + /* a new client connected, create a client object to handle the client. */ if (klass->create_client) client = klass->create_client (server); if (client == NULL) goto client_failed; - /* a new client connected, create a client object to handle the client. */ - if (klass->accept_client) - result = klass->accept_client (server, client, socket, &error); - if (!result) - goto accept_failed; + /* a new client connected. */ + GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, NULL), + accept_failed); + + /* set connection on the client now */ + gst_rtsp_client_set_connection (client, conn); /* manage the client connection */ manage_client (server, client); @@ -1234,8 +1202,10 @@ client_failed: } accept_failed: { - GST_ERROR_OBJECT (server, "failed to accept client: %s", error->message); - g_error_free (error); + gchar *str = gst_rtsp_strresult (res); + GST_ERROR_OBJECT (server, "Could not accept client on socket %p: %s", + socket, str); + g_free (str); g_object_unref (client); return G_SOURCE_CONTINUE; } diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 6df3a6d51a..17e1f61541 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -69,8 +69,7 @@ struct _GstRTSPServerClass { GThreadPool *pool; GstRTSPClient * (*create_client) (GstRTSPServer *server); - gboolean (*accept_client) (GstRTSPServer *server, GstRTSPClient *client, - GSocket *socket, GError **error); + /* signals */ void (*client_connected) (GstRTSPServer *server, GstRTSPClient *client); }; From 0a285290cba4af9eb37170cf1edcdcda3b35d41b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 31 May 2013 11:42:36 +0200 Subject: [PATCH 0646/1776] server: add support for TLS Add methods to set and get a TLS certificate. Add vmethod to configure a new connection. By default, configure the TLS certificate in a new connection if needed. --- gst/rtsp-server/rtsp-server.c | 98 ++++++++++++++++++++++++++++++++++- gst/rtsp-server/rtsp-server.h | 9 +++- 2 files changed, 104 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 24f2282bc1..8e3acb3d0b 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -51,6 +51,9 @@ struct _GstRTSPServerPrivate /* authentication manager */ GstRTSPAuth *auth; + /* the TLS certificate */ + GTlsCertificate *certificate; + /* the clients that are connected */ GList *clients; GQueue loops; /* the main loops used in the threads */ @@ -106,6 +109,8 @@ static void gst_rtsp_server_finalize (GObject * object); static gpointer do_loop (Loop * loop); static GstRTSPClient *default_create_client (GstRTSPServer * server); +static gboolean default_setup_connection (GstRTSPServer * server, + GstRTSPClient * client, GstRTSPConnection * conn); static void gst_rtsp_server_class_init (GstRTSPServerClass * klass) @@ -209,6 +214,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) gst_rtsp_client_get_type ()); klass->create_client = default_create_client; + klass->setup_connection = default_setup_connection; klass->pool = g_thread_pool_new ((GFunc) do_loop, klass, -1, FALSE, NULL); @@ -253,6 +259,9 @@ gst_rtsp_server_finalize (GObject * object) if (priv->auth) g_object_unref (priv->auth); + if (priv->certificate) + g_object_unref (priv->certificate); + g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_server_parent_class)->finalize (object); @@ -678,6 +687,63 @@ gst_rtsp_server_get_max_threads (GstRTSPServer * server) return res; } +/** + * gst_rtsp_server_set_tls_certificate: + * @server: a #GstRTSPServer + * @cert: (allow none): a #GTlsCertificate + * + * Set the TLS certificate for the server. Client connections will only + * be accepted when TLS is negotiated. + */ +void +gst_rtsp_server_set_tls_certificate (GstRTSPServer * server, + GTlsCertificate * cert) +{ + GstRTSPServerPrivate *priv; + GTlsCertificate *old; + + g_return_if_fail (GST_IS_RTSP_SERVER (server)); + + priv = server->priv; + + if (cert) + g_object_ref (cert); + + GST_RTSP_SERVER_LOCK (server); + old = priv->certificate; + priv->certificate = cert; + GST_RTSP_SERVER_UNLOCK (server); + + if (old) + g_object_unref (old); +} + +/** + * gst_rtsp_server_get_tls_certificate: + * @server: a #GstRTSPServer + * + * Get the #GTlsCertificate used for negotiating TLS @server. + * + * Returns: (transfer full): the #GTlsCertificate of @server. g_object_unref() after + * usage. + */ +GTlsCertificate * +gst_rtsp_server_get_tls_certificate (GstRTSPServer * server) +{ + GstRTSPServerPrivate *priv; + GTlsCertificate *result; + + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + + priv = server->priv; + + GST_RTSP_SERVER_LOCK (server); + if ((result = priv->certificate)) + g_object_ref (result); + GST_RTSP_SERVER_UNLOCK (server); + + return result; +} static void gst_rtsp_server_get_property (GObject * object, guint propid, @@ -1087,6 +1153,25 @@ default_create_client (GstRTSPServer * server) return client; } +static gboolean +default_setup_connection (GstRTSPServer * server, GstRTSPClient * client, + GstRTSPConnection * conn) +{ + GstRTSPServerPrivate *priv = server->priv; + + GST_RTSP_SERVER_LOCK (server); + if (priv->certificate) { + GTlsConnection *tls; + + /* configure the connection */ + tls = gst_rtsp_connection_get_tls (conn, NULL); + g_tls_connection_set_certificate (tls, priv->certificate); + } + GST_RTSP_SERVER_UNLOCK (server); + + return TRUE; +} + /** * gst_rtsp_server_transfer_connection: * @server: a #GstRTSPServer @@ -1165,9 +1250,9 @@ gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, GstRTSPClient *client = NULL; GstRTSPServerClass *klass; GstRTSPResult res; + GstRTSPConnection *conn = NULL; if (condition & G_IO_IN) { - GstRTSPConnection *conn; klass = GST_RTSP_SERVER_GET_CLASS (server); @@ -1181,6 +1266,10 @@ gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, NULL), accept_failed); + if (klass->setup_connection) + if (!klass->setup_connection (server, client, conn)) + goto setup_failed; + /* set connection on the client now */ gst_rtsp_client_set_connection (client, conn); @@ -1209,6 +1298,13 @@ accept_failed: g_object_unref (client); return G_SOURCE_CONTINUE; } +setup_failed: + { + GST_ERROR_OBJECT (server, "failed to setup client connection"); + gst_rtsp_connection_free (conn); + g_object_unref (client); + return G_SOURCE_CONTINUE; + } } static void diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 17e1f61541..3d24e0b6d9 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -59,7 +59,8 @@ struct _GstRTSPServer { * * @create_client: Create, configure a new GstRTSPClient * object that handles the new connection on @socket. - * @accept_client: accept a new GstRTSPClient + * @setup_connection: Setup the new client connection. The default + * implementation will configure the TLS certificate. * * The RTSP server class structure */ @@ -69,7 +70,8 @@ struct _GstRTSPServerClass { GThreadPool *pool; GstRTSPClient * (*create_client) (GstRTSPServer *server); - + gboolean (*setup_connection) (GstRTSPServer *server, GstRTSPClient *client, + GstRTSPConnection *conn); /* signals */ void (*client_connected) (GstRTSPServer *server, GstRTSPClient *client); }; @@ -101,6 +103,9 @@ GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *serve void gst_rtsp_server_set_max_threads (GstRTSPServer *server, gint max_threads); gint gst_rtsp_server_get_max_threads (GstRTSPServer *server); +void gst_rtsp_server_set_tls_certificate (GstRTSPServer *server, GTlsCertificate *cert); +GTlsCertificate * gst_rtsp_server_get_tls_certificate (GstRTSPServer *server); + gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket *socket, const gchar * ip, gint port, const gchar *initial_buffer); From d1339f60f462c6dc8132cc8d89363dd0a464e20d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 31 May 2013 12:10:28 +0200 Subject: [PATCH 0647/1776] example: add TLS example --- examples/Makefile.am | 2 +- examples/test-video.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/examples/Makefile.am b/examples/Makefile.am index 47b2cf96e1..4b753f6551 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -5,4 +5,4 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ #INCLUDES = -I$(top_srcdir) -I$(srcdir) AM_CFLAGS = $(GST_OBJ_CFLAGS) -AM_LDFLAGS = $(GST_OBJ_LIBS) +AM_LDFLAGS = $(GST_OBJ_LIBS) $(GIO_LIBS) diff --git a/examples/test-video.c b/examples/test-video.c index 2cfe483975..05db5f32d8 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -25,6 +25,9 @@ * user/admin as the password */ #undef WITH_AUTH +/* define this if you want the server to use TLS */ +#undef WITH_TLS + /* this timeout is periodically run to clean up the expired sessions from the * pool. This needs to be run explicitly currently but might be done * automatically as part of the mainloop. */ @@ -51,6 +54,9 @@ main (int argc, char *argv[]) GstRTSPAuth *auth; gchar *basic; #endif +#ifdef WITH_TLS + GTlsCertificate *cert; +#endif gst_init (&argc, &argv); @@ -58,6 +64,33 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); +#ifdef WITH_TLS + cert = g_tls_certificate_new_from_pem ("-----BEGIN CERTIFICATE-----" + "MIICJjCCAY+gAwIBAgIBBzANBgkqhkiG9w0BAQUFADCBhjETMBEGCgmSJomT8ixk" + "ARkWA0NPTTEXMBUGCgmSJomT8ixkARkWB0VYQU1QTEUxHjAcBgNVBAsTFUNlcnRp" + "ZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAxMOY2EuZXhhbXBsZS5jb20xHTAbBgkq" + "hkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMB4XDTExMDExNzE5NDcxN1oXDTIxMDEx" + "NDE5NDcxN1owSzETMBEGCgmSJomT8ixkARkWA0NPTTEXMBUGCgmSJomT8ixkARkW" + "B0VYQU1QTEUxGzAZBgNVBAMTEnNlcnZlci5leGFtcGxlLmNvbTBcMA0GCSqGSIb3" + "DQEBAQUAA0sAMEgCQQDYScTxk55XBmbDM9zzwO+grVySE4rudWuzH2PpObIonqbf" + "hRoAalKVluG9jvbHI81eXxCdSObv1KBP1sbN5RzpAgMBAAGjIjAgMAkGA1UdEwQC" + "MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADgYEAYx6fMqT1" + "Gvo0jq88E8mc+bmp4LfXD4wJ7KxYeadQxt75HFRpj4FhFO3DOpVRFgzHlOEo3Fwk" + "PZOKjvkT0cbcoEq5whLH25dHoQxGoVQgFyAP5s+7Vp5AlHh8Y/vAoXeEVyy/RCIH" + "QkhUlAflfDMcrrYjsmwoOPSjhx6Mm/AopX4=" + "-----END CERTIFICATE-----" + "-----BEGIN PRIVATE KEY-----" + "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEA2EnE8ZOeVwZmwzPc" + "88DvoK1ckhOK7nVrsx9j6TmyKJ6m34UaAGpSlZbhvY72xyPNXl8QnUjm79SgT9bG" + "zeUc6QIDAQABAkBRFJZ32VbqWMP9OVwDJLiwC01AlYLnka0mIQZbT/2xq9dUc9GW" + "U3kiVw4lL8v/+sPjtTPCYYdzHHOyDen6znVhAiEA9qJT7BtQvRxCvGrAhr9MS022" + "tTdPbW829BoUtIeH64cCIQDggG5i48v7HPacPBIH1RaSVhXl8qHCpQD3qrIw3FMw" + "DwIga8PqH5Sf5sHedy2+CiK0V4MRfoU4c3zQ6kArI+bEgSkCIQCLA1vXBiE31B5s" + "bdHoYa1BXebfZVd+1Hd95IfEM5mbRwIgSkDuQwV55BBlvWph3U8wVIMIb4GStaH8" + "W535W8UBbEg=" "-----END PRIVATE KEY-----", -1, NULL); + gst_rtsp_server_set_tls_certificate (server, cert); + g_object_unref (cert); +#endif /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ @@ -99,7 +132,11 @@ main (int argc, char *argv[]) g_timeout_add_seconds (2, (GSourceFunc) timeout, server); /* start serving, this never stops */ +#ifdef WITH_TLS + g_print ("stream ready at rtsps://127.0.0.1:8554/test\n"); +#else g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); +#endif g_main_loop_run (loop); return 0; From cfdf2e6db53ece4456bd1594d66ca9f80c204c59 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 31 May 2013 15:41:55 +0200 Subject: [PATCH 0648/1776] rtsp: place a- and x- properties as attributes application/x-rtp has properties with a- and x- prefixes that should be placed as attributes in the SDP for the media instead of being added to the fmtp. --- gst/rtsp-server/rtsp-sdp.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 6b0a046c43..39b08bb5c1 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -23,7 +23,7 @@ static gboolean get_info_from_tags (GstPad * pad, GstEvent ** event, gpointer user_data) { - GstSDPMedia * media = (GstSDPMedia *) user_data; + GstSDPMedia *media = (GstSDPMedia *) user_data; if (GST_EVENT_TYPE (*event) == GST_EVENT_TAG) { GstTagList *tags; @@ -35,13 +35,13 @@ get_info_from_tags (GstPad * pad, GstEvent ** event, gpointer user_data) return TRUE; if (!gst_tag_list_get_uint (tags, GST_TAG_MAXIMUM_BITRATE, - &bitrate) || bitrate == 0) + &bitrate) || bitrate == 0) if (!gst_tag_list_get_uint (tags, GST_TAG_BITRATE, &bitrate) || bitrate == 0) return TRUE; /* set bandwidth (kbits/s) */ - gst_sdp_media_add_bandwidth (media, GST_SDP_BWTYPE_AS, bitrate/1000); + gst_sdp_media_add_bandwidth (media, GST_SDP_BWTYPE_AS, bitrate / 1000); return FALSE; @@ -179,7 +179,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, gst_sdp_media_add_attribute (smedia, "control", tmp); g_free (tmp); - /* collect all other properties and add them to fmtp */ + /* collect all other properties and add them to fmtp or attributes */ fmtp = g_string_new (""); g_string_append_printf (fmtp, "%d ", caps_pt); first = TRUE; @@ -213,6 +213,19 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, if (!strcmp (fname, "framerate")) continue; + if (g_str_has_prefix (fname, "a-")) { + /* attribute */ + if ((fval = gst_structure_get_string (s, fname))) + gst_sdp_media_add_attribute (smedia, fname + 2, fval); + continue; + } + if (g_str_has_prefix (fname, "x-")) { + /* attribute */ + if ((fval = gst_structure_get_string (s, fname))) + gst_sdp_media_add_attribute (smedia, fname, fval); + continue; + } + if ((fval = gst_structure_get_string (s, fname))) { g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval); first = FALSE; From 2a0aaa1019f6e028f75a60b4a76a0852a0947453 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 31 May 2013 15:27:48 +0200 Subject: [PATCH 0649/1776] Revert "rtsp-sdp: Parse framerate caps field and set SDP attribute" This reverts commit d6a4dee03642a2d2c05fec4752dc3ccb60b19494. We already have a way to place extra attributes in the SDP, just make a string property in the payloader with a- or x- prefix. --- gst/rtsp-server/rtsp-sdp.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 39b08bb5c1..4028b85589 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -101,7 +101,6 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, GString *fmtp; GstCaps *caps; gint width, height; - gint num = 0, denom = 1; stream = gst_rtsp_media_get_stream (media, i); caps = gst_rtsp_stream_get_caps (stream); @@ -164,16 +163,6 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, g_free (tmp); } - /* create framerate SDP attribute if frame is not zero */ - if (gst_structure_get_fraction (s, "framerate", &num, &denom) && num > 0) { - gdouble rate; - gchar framerate [G_ASCII_DTOSTR_BUF_SIZE]; - - gst_util_fraction_to_double (num, denom, &rate); - g_ascii_formatd (framerate, sizeof (framerate), " %.17g", rate); - gst_sdp_media_add_attribute (smedia, "framerate", framerate); - } - /* the config uri */ tmp = g_strdup_printf ("stream=%d", i); gst_sdp_media_add_attribute (smedia, "control", tmp); @@ -210,8 +199,6 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, continue; if (!strcmp (fname, "height")) continue; - if (!strcmp (fname, "framerate")) - continue; if (g_str_has_prefix (fname, "a-")) { /* attribute */ From 17b07d1c0ec4be4f90960e445eed2490020c8daa Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 31 May 2013 15:28:58 +0200 Subject: [PATCH 0650/1776] Revert "rtsp-sdp: Parse width/height from caps and set SDP attribute" This reverts commit 5fd034ff1a517db7f629ffcc3ed16839c61f5c97. We already have a way to place extra attributes in the SDP by using a string property with prefix x- or a- in the caps. --- gst/rtsp-server/rtsp-sdp.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 4028b85589..6be99fc25e 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -100,7 +100,6 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, gboolean first; GString *fmtp; GstCaps *caps; - gint width, height; stream = gst_rtsp_media_get_stream (media, i); caps = gst_rtsp_stream_get_caps (stream); @@ -151,18 +150,6 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, g_free (tmp); } - /* create framesize SDP attribute */ - if (gst_structure_get_int (s, "width", &width) && width > 0 && - gst_structure_get_int (s, "height", &height) && height > 0) { - tmp = g_strdup_printf ("%d %d-%d", caps_pt, width, height); - gst_sdp_media_add_attribute (smedia, "framesize", tmp); - g_free (tmp); - - tmp = g_strdup_printf (" %d,%d", width, height); - gst_sdp_media_add_attribute (smedia, "x-dimensions", tmp); - g_free (tmp); - } - /* the config uri */ tmp = g_strdup_printf ("stream=%d", i); gst_sdp_media_add_attribute (smedia, "control", tmp); @@ -195,10 +182,6 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, continue; if (!strcmp (fname, "seqnum-base")) continue; - if (!strcmp (fname, "width")) - continue; - if (!strcmp (fname, "height")) - continue; if (g_str_has_prefix (fname, "a-")) { /* attribute */ From 3e119be8291556b91c8150837004ed4f2c6848af Mon Sep 17 00:00:00 2001 From: Alexander Schrab Date: Thu, 30 May 2013 08:07:48 +0200 Subject: [PATCH 0651/1776] rtspstream: handle both ipv4 and ipv6 clients Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701129 --- gst/rtsp-server/rtsp-client.c | 16 +++- gst/rtsp-server/rtsp-stream.c | 145 +++++++++++++++++++++++----------- gst/rtsp-server/rtsp-stream.h | 4 +- 3 files changed, 116 insertions(+), 49 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4b9d5d7947..fec3ff3726 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1133,6 +1133,8 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, GstRTSPTransport * ct) { GstRTSPTransport *st; + GInetAddress *addr; + GSocketFamily family; /* prepare the server transport */ gst_rtsp_transport_new (&st); @@ -1141,10 +1143,22 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, st->profile = ct->profile; st->lower_transport = ct->lower_transport; + addr = g_inet_address_new_from_string (ct->destination); + + if (!addr) { + GST_ERROR ("failed to get inet addr from client destination"); + family = G_SOCKET_FAMILY_IPV4; + } else { + family = g_inet_address_get_family (addr); + g_object_unref (addr); + addr = NULL; + } + switch (st->lower_transport) { case GST_RTSP_LOWER_TRANS_UDP: st->client_port = ct->client_port; - gst_rtsp_stream_get_server_port (state->stream, &st->server_port); + gst_rtsp_stream_get_server_port (state->stream, &st->server_port, + family); break; case GST_RTSP_LOWER_TRANS_UDP_MCAST: st->port = ct->port; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 38da5ef301..8b8aa31187 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -36,7 +36,6 @@ struct _GstRTSPStreamPrivate guint idx; GstPad *srcpad; GstElement *payloader; - gboolean is_ipv6; guint buffer_size; gboolean is_joined; @@ -48,10 +47,16 @@ struct _GstRTSPStreamPrivate /* the RTPSession object */ GObject *session; - /* sinks used for sending and receiving RTP and RTCP, they share + /* sinks used for sending and receiving RTP and RTCP over ipv4, they share * sockets */ - GstElement *udpsrc[2]; + GstElement *udpsrc_v4[2]; + + /* sinks used for sending and receiving RTP and RTCP over ipv6, they share + * sockets */ + GstElement *udpsrc_v6[2]; + GstElement *udpsink[2]; + /* for TCP transport */ GstElement *appsrc[2]; GstElement *appqueue[2]; @@ -60,9 +65,13 @@ struct _GstRTSPStreamPrivate GstElement *tee[2]; GstElement *funnel[2]; - /* server ports for sending/receiving */ - GstRTSPRange server_port; - GstRTSPAddress *server_addr; + /* server ports for sending/receiving over ipv4 */ + GstRTSPRange server_port_v4; + GstRTSPAddress *server_addr_v4; + + /* server ports for sending/receiving over ipv6 */ + GstRTSPRange server_port_v6; + GstRTSPAddress *server_addr_v6; /* multicast addresses */ GstRTSPAddressPool *pool; @@ -137,8 +146,10 @@ gst_rtsp_stream_finalize (GObject * obj) if (priv->addr) gst_rtsp_address_free (priv->addr); - if (priv->server_addr) - gst_rtsp_address_free (priv->server_addr); + if (priv->server_addr_v4) + gst_rtsp_address_free (priv->server_addr_v4); + if (priv->server_addr_v6) + gst_rtsp_address_free (priv->server_addr_v6); if (priv->pool) g_object_unref (priv->pool); gst_object_unref (priv->payloader); @@ -428,11 +439,12 @@ different_address: } } -/* must be called with lock */ static gboolean -alloc_ports (GstRTSPStream * stream) +alloc_ports_one_family (GstRTSPAddressPool * pool, gint buffer_size, + GSocketFamily family, GstElement * udpsrc_out[2], + GstElement * udpsink_out[2], GstRTSPRange * server_port_out, + GstRTSPAddress ** server_addr_out) { - GstRTSPStreamPrivate *priv = stream->priv; GstStateChangeReturn ret; GstElement *udpsrc0, *udpsrc1; GstElement *udpsink0, *udpsink1; @@ -443,10 +455,14 @@ alloc_ports (GstRTSPStream * stream) gint rtpport, rtcpport; GList *rejected_addresses = NULL; GstRTSPAddress *addr = NULL; - GSocketFamily family; GInetAddress *inetaddr = NULL; GSocketAddress *rtp_sockaddr = NULL; GSocketAddress *rtcp_sockaddr = NULL; + const gchar *multisink_socket = "socket"; + + if (family == G_SOCKET_FAMILY_IPV6) { + multisink_socket = "socket-v6"; + } udpsrc0 = NULL; udpsrc1 = NULL; @@ -457,19 +473,13 @@ alloc_ports (GstRTSPStream * stream) /* Start with random port */ tmp_rtp = 0; - if (priv->is_ipv6) { - family = G_SOCKET_FAMILY_IPV6; - } else { - family = G_SOCKET_FAMILY_IPV4; - } - rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, NULL); if (!rtcp_socket) goto no_udp_protocol; - if (priv->server_addr) - gst_rtsp_address_free (priv->server_addr); + if (*server_addr_out) + gst_rtsp_address_free (*server_addr_out); /* try to allocate 2 UDP ports, the RTP port should be an even * number and the RTCP port should be the next (uneven) port */ @@ -482,19 +492,19 @@ again: goto no_udp_protocol; } - if (priv->pool && gst_rtsp_address_pool_has_unicast_addresses (priv->pool)) { + if (pool && gst_rtsp_address_pool_has_unicast_addresses (pool)) { GstRTSPAddressFlags flags; if (addr) rejected_addresses = g_list_prepend (rejected_addresses, addr); flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_UNICAST; - if (priv->is_ipv6) + if (family == G_SOCKET_FAMILY_IPV6) flags |= GST_RTSP_ADDRESS_FLAG_IPV6; else flags |= GST_RTSP_ADDRESS_FLAG_IPV4; - addr = gst_rtsp_address_pool_acquire_address (priv->pool, flags, 2); + addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); if (addr == NULL) goto no_ports; @@ -576,23 +586,31 @@ again: if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) goto port_error; - udpsink0 = gst_element_factory_make ("multiudpsink", NULL); + if (udpsink_out[0]) + udpsink0 = udpsink_out[0]; + else + udpsink0 = gst_element_factory_make ("multiudpsink", NULL); + if (!udpsink0) goto no_udp_protocol; g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL); - g_object_set (G_OBJECT (udpsink0), "socket", rtp_socket, NULL); + g_object_set (G_OBJECT (udpsink0), multisink_socket, rtp_socket, NULL); + + if (udpsink_out[1]) + udpsink1 = udpsink_out[1]; + else + udpsink1 = gst_element_factory_make ("multiudpsink", NULL); - udpsink1 = gst_element_factory_make ("multiudpsink", NULL); if (!udpsink1) goto no_udp_protocol; g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); - g_object_set (G_OBJECT (udpsink0), "buffer-size", priv->buffer_size, NULL); + g_object_set (G_OBJECT (udpsink0), "buffer-size", buffer_size, NULL); g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "socket", rtcp_socket, NULL); + g_object_set (G_OBJECT (udpsink1), multisink_socket, rtcp_socket, NULL); g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL); @@ -602,14 +620,14 @@ again: /* we keep these elements, we will further configure them when the * client told us to really use the UDP ports. */ - priv->udpsrc[0] = udpsrc0; - priv->udpsrc[1] = udpsrc1; - priv->udpsink[0] = udpsink0; - priv->udpsink[1] = udpsink1; - priv->server_port.min = rtpport; - priv->server_port.max = rtcpport; + udpsrc_out[0] = udpsrc0; + udpsrc_out[1] = udpsrc1; + udpsink_out[0] = udpsink0; + udpsink_out[1] = udpsink1; + server_port_out->min = rtpport; + server_port_out->max = rtcpport; - priv->server_addr = addr; + *server_addr_out = addr; g_list_free_full (rejected_addresses, (GDestroyNotify) gst_rtsp_address_free); g_object_unref (rtp_socket); @@ -670,6 +688,20 @@ cleanup: } } +/* must be called with lock */ +static gboolean +alloc_ports (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv = stream->priv; + + return alloc_ports_one_family (priv->pool, priv->buffer_size, + G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, priv->udpsink, + &priv->server_port_v4, &priv->server_addr_v4) && + alloc_ports_one_family (priv->pool, priv->buffer_size, + G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, priv->udpsink, + &priv->server_port_v6, &priv->server_addr_v6); +} + /** * gst_rtsp_stream_get_server_port: * @stream: a #GstRTSPStream @@ -680,7 +712,7 @@ cleanup: */ void gst_rtsp_stream_get_server_port (GstRTSPStream * stream, - GstRTSPRange * server_port) + GstRTSPRange * server_port, GSocketFamily family) { GstRTSPStreamPrivate *priv; @@ -689,8 +721,13 @@ gst_rtsp_stream_get_server_port (GstRTSPStream * stream, g_return_if_fail (priv->is_joined); g_mutex_lock (&priv->lock); - if (server_port) - *server_port = priv->server_port; + if (family == G_SOCKET_FAMILY_IPV4) { + if (server_port) + *server_port = priv->server_port_v4; + } else { + if (server_port) + *server_port = priv->server_port_v6; + } g_mutex_unlock (&priv->lock); } @@ -1104,13 +1141,23 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, /* we set and keep these to playing so that they don't cause NO_PREROLL return * values */ - gst_element_set_state (priv->udpsrc[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc[i], TRUE); + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); + gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); /* add udpsrc */ - gst_bin_add (bin, priv->udpsrc[i]); - /* and link to the funnel */ + gst_bin_add (bin, priv->udpsrc_v4[i]); + gst_bin_add (bin, priv->udpsrc_v6[i]); + /* and link to the funnel v4 */ selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc[i], "src"); + pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + + /* and link to the funnel v6 */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src"); gst_pad_link (pad, selpad); gst_object_unref (pad); gst_object_unref (selpad); @@ -1213,12 +1260,15 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_element_set_state (priv->funnel[i], GST_STATE_NULL); gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); /* and set udpsrc to NULL now before removing */ - gst_element_set_locked_state (priv->udpsrc[i], FALSE); - gst_element_set_state (priv->udpsrc[i], GST_STATE_NULL); + gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE); + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); + gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE); + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); /* removing them should also nicely release the request * pads when they finalize */ - gst_bin_remove (bin, priv->udpsrc[i]); + gst_bin_remove (bin, priv->udpsrc_v4[i]); + gst_bin_remove (bin, priv->udpsrc_v6[i]); gst_bin_remove (bin, priv->udpsink[i]); gst_bin_remove (bin, priv->appsrc[i]); gst_bin_remove (bin, priv->appsink[i]); @@ -1230,7 +1280,8 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_object_unref (priv->recv_sink[i]); priv->recv_sink[i] = NULL; - priv->udpsrc[i] = NULL; + priv->udpsrc_v4[i] = NULL; + priv->udpsrc_v6[i] = NULL; priv->udpsink[i] = NULL; priv->appsrc[i] = NULL; priv->appsink[i] = NULL; diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index b0512d82b2..f6507a95d7 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -20,6 +20,7 @@ #include #include #include +#include #ifndef __GST_RTSP_STREAM_H__ #define __GST_RTSP_STREAM_H__ @@ -88,7 +89,8 @@ gboolean gst_rtsp_stream_leave_bin (GstRTSPStream *stream, GstBin *bin, GstElement *rtpbin); void gst_rtsp_stream_get_server_port (GstRTSPStream *stream, - GstRTSPRange *server_port); + GstRTSPRange *server_port, + GSocketFamily family); void gst_rtsp_stream_get_ssrc (GstRTSPStream *stream, guint *ssrc); From c5b3066c3389105099646042f598eda1ddb2969c Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 3 Jun 2013 12:04:44 +0200 Subject: [PATCH 0652/1776] rtsp-server: Expose the use_client_settings API Fixes https://bugzilla.gnome.org/show_bug.cgi?id=699935 --- gst/rtsp-server/rtsp-server.c | 74 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-server.h | 4 ++ 2 files changed, 78 insertions(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 8e3acb3d0b..f056d7d756 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -39,6 +39,7 @@ struct _GstRTSPServerPrivate gchar *service; gint backlog; gint max_threads; + gboolean use_client_settings; GSocket *socket; @@ -65,6 +66,7 @@ struct _GstRTSPServerPrivate #define DEFAULT_SERVICE "8554" #define DEFAULT_BACKLOG 5 #define DEFAULT_MAX_THREADS 0 +#define DEFAULT_USE_CLIENT_SETTINGS FALSE /* Define to use the SO_LINGER option so that the server sockets can be resused * sooner. Disabled for now because it is not very well implemented by various @@ -82,6 +84,7 @@ enum PROP_SESSION_POOL, PROP_MOUNT_POINTS, PROP_MAX_THREADS, + PROP_USE_CLIENT_SETTINGS, PROP_LAST }; @@ -206,6 +209,17 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) "The maximum amount of threads to use for client connections " "(0 = only mainloop, -1 = unlimited)", -1, G_MAXINT, DEFAULT_MAX_THREADS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPServer::use-client-settings: + * + * Use client transport settings (destination, port pair and ttl for + * multicast. FALSE means that the server settings will be used. + */ + g_object_class_install_property (gobject_class, PROP_USE_CLIENT_SETTINGS, + g_param_spec_boolean ("use-client-settings", "Use Client Settings", + "Use client settings for ttl, destination and port pair in multicast", + DEFAULT_USE_CLIENT_SETTINGS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED] = g_signal_new ("client-connected", G_TYPE_FROM_CLASS (gobject_class), @@ -236,6 +250,7 @@ gst_rtsp_server_init (GstRTSPServer * server) priv->session_pool = gst_rtsp_session_pool_new (); priv->mount_points = gst_rtsp_mount_points_new (); priv->max_threads = DEFAULT_MAX_THREADS; + priv->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS; g_queue_init (&priv->loops); } @@ -687,6 +702,55 @@ gst_rtsp_server_get_max_threads (GstRTSPServer * server) return res; } +/** + * gst_rtsp_server_set_use_client_settings: + * @server: a #GstRTSPServer + * @use_client_settings: whether to use client settings for multicast + * + * Use client transport settings (destination, port pair and ttl) for + * multicast. + * When @use_client_settings is %FALSE, the server settings will be + * used. + */ +void +gst_rtsp_server_set_use_client_settings (GstRTSPServer * server, + gboolean use_client_settings) +{ + GstRTSPServerPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_SERVER (server)); + + priv = server->priv; + + GST_RTSP_SERVER_LOCK (server); + priv->use_client_settings = use_client_settings; + GST_RTSP_SERVER_UNLOCK (server); +} + +/** + * gst_rtsp_server_get_use_client_settings: + * @server: a #GstRTSPServer + * + * Check if client transport settings (destination, port pair and ttl) for + * multicast will be used. + */ +gboolean +gst_rtsp_server_get_use_client_settings (GstRTSPServer * server) +{ + GstRTSPServerPrivate *priv; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), FALSE); + + priv = server->priv; + + GST_RTSP_SERVER_LOCK (server); + res = priv->use_client_settings; + GST_RTSP_SERVER_UNLOCK (server); + + return res; +} + /** * gst_rtsp_server_set_tls_certificate: * @server: a #GstRTSPServer @@ -773,6 +837,10 @@ gst_rtsp_server_get_property (GObject * object, guint propid, case PROP_MAX_THREADS: g_value_set_int (value, gst_rtsp_server_get_max_threads (server)); break; + case PROP_USE_CLIENT_SETTINGS: + g_value_set_boolean (value, + gst_rtsp_server_get_use_client_settings (server)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -803,6 +871,10 @@ gst_rtsp_server_set_property (GObject * object, guint propid, case PROP_MAX_THREADS: gst_rtsp_server_set_max_threads (server, g_value_get_int (value)); break; + case PROP_USE_CLIENT_SETTINGS: + gst_rtsp_server_set_use_client_settings (server, + g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1148,6 +1220,8 @@ default_create_client (GstRTSPServer * server) gst_rtsp_client_set_mount_points (client, priv->mount_points); /* set authentication manager */ gst_rtsp_client_set_auth (client, priv->auth); + /* check if client transport settings for multicast are allowed */ + gst_rtsp_client_set_use_client_settings (client, priv->use_client_settings); GST_RTSP_SERVER_UNLOCK (server); return client; diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 3d24e0b6d9..a71c27f47f 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -103,6 +103,10 @@ GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *serve void gst_rtsp_server_set_max_threads (GstRTSPServer *server, gint max_threads); gint gst_rtsp_server_get_max_threads (GstRTSPServer *server); +void gst_rtsp_server_set_use_client_settings (GstRTSPServer *server, + gboolean use_client_settings); +gboolean gst_rtsp_server_get_use_client_settings (GstRTSPServer *server); + void gst_rtsp_server_set_tls_certificate (GstRTSPServer *server, GTlsCertificate *cert); GTlsCertificate * gst_rtsp_server_get_tls_certificate (GstRTSPServer *server); From 7efa871c1f99b4a4e47a0d216bd76a09da89b731 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Wed, 29 May 2013 13:45:00 +0200 Subject: [PATCH 0653/1776] media: possibility to override range time conversion Make it possible to override the conversion from GstRTSPTimeRange to GstClockTimes, that is done before seeking on the media pipeline. Overriding can be useful for UTC ranges, where the default conversion gives nanoseconds since 1900. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701191 --- gst/rtsp-server/rtsp-media.c | 17 ++++++++++++++++- gst/rtsp-server/rtsp-media.h | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 7609bff04f..106c6c97b8 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -123,6 +123,8 @@ static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message); static void finish_unprepare (GstRTSPMedia * media); static gboolean default_unprepare (GstRTSPMedia * media); +static gboolean default_get_range_times (GstRTSPMedia * media, + const GstRTSPTimeRange * range, GstClockTime * min, GstClockTime * max); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; @@ -211,6 +213,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->handle_message = default_handle_message; klass->unprepare = default_unprepare; + klass->get_range_times = default_get_range_times; } static void @@ -1124,14 +1127,18 @@ not_prepared: gboolean gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) { + GstRTSPMediaClass *klass; GstRTSPMediaPrivate *priv; GstSeekFlags flags; gboolean res; GstClockTime start, stop; GstSeekType start_type, stop_type; + klass = GST_RTSP_MEDIA_GET_CLASS (media); + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (range != NULL, FALSE); + g_return_val_if_fail (klass->get_range_times != NULL, FALSE); priv = media->priv; @@ -1148,7 +1155,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) start_type = stop_type = GST_SEEK_TYPE_NONE; - if (!gst_rtsp_range_get_times (range, &start, &stop)) + if (!klass->get_range_times (media, range, &start, &stop)) goto not_supported; GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, @@ -2043,3 +2050,11 @@ not_prepared: return FALSE; } } + +/* called with state-lock */ +static gboolean +default_get_range_times (GstRTSPMedia * media, + const GstRTSPTimeRange * range, GstClockTime * min, GstClockTime * max) +{ + return gst_rtsp_range_get_times (range, min, max); +} diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 66e83de033..bfc61ecd7b 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -100,6 +100,9 @@ struct _GstRTSPMediaClass { /* vmethods */ gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message); gboolean (*unprepare) (GstRTSPMedia *media); + gboolean (*get_range_times) (GstRTSPMedia *media, + const GstRTSPTimeRange * range, + GstClockTime * min, GstClockTime * max); /* signals */ void (*new_stream) (GstRTSPMedia *media, GstRTSPStream * stream); From 1bd497309c8b8232b72c03453775e12c581aa792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 5 Jun 2013 15:18:26 +0200 Subject: [PATCH 0654/1776] Automatic update of common submodule From 098c0d7 to 01a7a46 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 098c0d7432..01a7a46e25 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 098c0d7432be323d631b95b5d35f6f0840bf21bd +Subproject commit 01a7a46e258177ffe9cdb09c6518db749b2325d4 From 275e2d52a4a1a33025509a8da0efa12756ace7e4 Mon Sep 17 00:00:00 2001 From: Alexander Schrab Date: Wed, 12 Jun 2013 10:56:16 +0200 Subject: [PATCH 0655/1776] use local address, not remote, in SDP See https://bugzilla.gnome.org/show_bug.cgi?id=702063 --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index fec3ff3726..6d67ff9a3b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2095,7 +2095,7 @@ gst_rtsp_client_set_connection (GstRTSPClient * client, read_socket = gst_rtsp_connection_get_read_socket (conn); - if (!(address = g_socket_get_remote_address (read_socket, &error))) + if (!(address = g_socket_get_local_address (read_socket, &error))) goto no_address; g_free (priv->server_ip); From f9f994e33d47ead1e4fa82591abde3caa363a03d Mon Sep 17 00:00:00 2001 From: Alexander Schrab Date: Wed, 12 Jun 2013 15:22:57 +0200 Subject: [PATCH 0656/1776] use 0.0.0.0 or :: for c= line instead of server address --- gst/rtsp-server/rtsp-sdp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 6be99fc25e..22f6e00e4a 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -131,8 +131,17 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, gst_sdp_media_set_proto (smedia, "RTP/AVP"); /* for the c= line */ - gst_sdp_media_add_connection (smedia, "IN", info->server_proto, - info->server_ip, 16, 0); + if (strcmp (info->server_proto, "IP6") == 0) { + gst_sdp_media_add_connection (smedia, "IN", info->server_proto, + "::", 16, 0); + } else { + if (strcmp (info->server_proto, "IP4") != 0) { + GST_WARNING ("unknown ip version when creating connection line in sdp," + " using IP4"); + } + gst_sdp_media_add_connection (smedia, "IN", info->server_proto, + "0.0.0.0", 16, 0); + } /* get clock-rate, media type and params for the rtpmap attribute */ gst_structure_get_int (s, "clock-rate", &caps_rate); From 3dbe0e17d4c67a26630f9df956a8a84aa2dec268 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 14 Jun 2013 16:05:59 +0200 Subject: [PATCH 0657/1776] sdp: cleanup sdp info We don't need to pass the proto, we can more easily check a boolean. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702063 --- gst/rtsp-server/rtsp-client.c | 10 +++------- gst/rtsp-server/rtsp-sdp.c | 12 +++--------- gst/rtsp-server/rtsp-sdp.h | 4 ++-- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6d67ff9a3b..d3d9c69aaa 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1157,8 +1157,7 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, switch (st->lower_transport) { case GST_RTSP_LOWER_TRANS_UDP: st->client_port = ct->client_port; - gst_rtsp_stream_get_server_port (state->stream, &st->server_port, - family); + gst_rtsp_stream_get_server_port (state->stream, &st->server_port, family); break; case GST_RTSP_LOWER_TRANS_UDP_MCAST: st->port = ct->port; @@ -1415,22 +1414,19 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) gst_sdp_message_add_attribute (sdp, "type", "broadcast"); gst_sdp_message_add_attribute (sdp, "control", "*"); - info.server_proto = proto; - info.server_ip = g_strdup (priv->server_ip); + info.is_ipv6 = priv->is_ipv6; + info.server_ip = priv->server_ip; /* create an SDP for the media object */ if (!gst_rtsp_sdp_from_media (sdp, &info, media)) goto no_sdp; - g_free (info.server_ip); - return sdp; /* ERRORS */ no_sdp: { GST_ERROR ("client %p: could not create SDP", client); - g_free (info.server_ip); gst_sdp_message_free (sdp); return NULL; } diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 22f6e00e4a..399367a245 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -131,16 +131,10 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, gst_sdp_media_set_proto (smedia, "RTP/AVP"); /* for the c= line */ - if (strcmp (info->server_proto, "IP6") == 0) { - gst_sdp_media_add_connection (smedia, "IN", info->server_proto, - "::", 16, 0); + if (info->is_ipv6) { + gst_sdp_media_add_connection (smedia, "IN", "IP6", "::", 16, 0); } else { - if (strcmp (info->server_proto, "IP4") != 0) { - GST_WARNING ("unknown ip version when creating connection line in sdp," - " using IP4"); - } - gst_sdp_media_add_connection (smedia, "IN", info->server_proto, - "0.0.0.0", 16, 0); + gst_sdp_media_add_connection (smedia, "IN", "IP4", "0.0.0.0", 16, 0); } /* get clock-rate, media type and params for the rtpmap attribute */ diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h index e5f3fd3518..7732f36d90 100644 --- a/gst/rtsp-server/rtsp-sdp.h +++ b/gst/rtsp-server/rtsp-sdp.h @@ -28,8 +28,8 @@ G_BEGIN_DECLS typedef struct { - const gchar *server_proto; - gchar *server_ip; + gboolean is_ipv6; + const gchar *server_ip; } GstSDPInfo; /* creating SDP */ From 6151072a2ebc35988c25e0c88af563c0bab40e90 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Wed, 5 Jun 2013 15:49:45 +0200 Subject: [PATCH 0658/1776] media: convert_range replaces get_range_times get_range_times worked for handling UTC ranges for seeks, but we also need to convert back from NPT to the requested unit in get_range_string. convert_range is now used for both. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702084 --- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-media.c | 33 +++++++++++++++++++++++---------- gst/rtsp-server/rtsp-media.h | 5 ++--- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d3d9c69aaa..dafc2de947 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -882,8 +882,8 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) if (res == GST_RTSP_OK) { if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) { /* we have a range, seek to the position */ - gst_rtsp_media_seek (gst_rtsp_session_media_get_media (media), range); unit = range->unit; + gst_rtsp_media_seek (gst_rtsp_session_media_get_media (media), range); gst_rtsp_range_free (range); } } diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 106c6c97b8..e018829e63 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -123,8 +123,9 @@ static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message); static void finish_unprepare (GstRTSPMedia * media); static gboolean default_unprepare (GstRTSPMedia * media); -static gboolean default_get_range_times (GstRTSPMedia * media, - const GstRTSPTimeRange * range, GstClockTime * min, GstClockTime * max); +static gboolean +default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range, + GstRTSPRangeUnit unit); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; @@ -213,7 +214,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->handle_message = default_handle_message; klass->unprepare = default_unprepare; - klass->get_range_times = default_get_range_times; + klass->convert_range = default_convert_range; } static void @@ -1076,11 +1077,14 @@ gchar * gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play, GstRTSPRangeUnit unit) { + GstRTSPMediaClass *klass; GstRTSPMediaPrivate *priv; gchar *result; GstRTSPTimeRange range; + klass = GST_RTSP_MEDIA_GET_CLASS (media); g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + g_return_val_if_fail (klass->convert_range != NULL, FALSE); priv = media->priv; @@ -1099,7 +1103,9 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play, g_mutex_unlock (&priv->lock); g_rec_mutex_unlock (&priv->state_lock); - gst_rtsp_range_convert_units (&range, unit); + if (!klass->convert_range (media, &range, unit)) { + goto conversion_failed; + } result = gst_rtsp_range_to_string (&range); @@ -1112,6 +1118,12 @@ not_prepared: g_rec_mutex_unlock (&priv->state_lock); return NULL; } +conversion_failed: + { + GST_WARNING ("range conversion to unit %d failed", unit); + g_rec_mutex_unlock (&priv->state_lock); + return NULL; + } } /** @@ -1138,7 +1150,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (range != NULL, FALSE); - g_return_val_if_fail (klass->get_range_times != NULL, FALSE); + g_return_val_if_fail (klass->convert_range != NULL, FALSE); priv = media->priv; @@ -1155,8 +1167,9 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) start_type = stop_type = GST_SEEK_TYPE_NONE; - if (!klass->get_range_times (media, range, &start, &stop)) + if (!klass->convert_range (media, range, GST_RTSP_RANGE_NPT)) goto not_supported; + gst_rtsp_range_get_times (range, &start, &stop); GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); @@ -1210,7 +1223,7 @@ not_seekable: not_supported: { g_rec_mutex_unlock (&priv->state_lock); - GST_WARNING ("seek unit %d not supported", range->unit); + GST_WARNING ("conversion to npt not supported"); return FALSE; } } @@ -2053,8 +2066,8 @@ not_prepared: /* called with state-lock */ static gboolean -default_get_range_times (GstRTSPMedia * media, - const GstRTSPTimeRange * range, GstClockTime * min, GstClockTime * max) +default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range, + GstRTSPRangeUnit unit) { - return gst_rtsp_range_get_times (range, min, max); + return gst_rtsp_range_convert_units (range, unit); } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index bfc61ecd7b..4dbe063271 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -100,9 +100,8 @@ struct _GstRTSPMediaClass { /* vmethods */ gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message); gboolean (*unprepare) (GstRTSPMedia *media); - gboolean (*get_range_times) (GstRTSPMedia *media, - const GstRTSPTimeRange * range, - GstClockTime * min, GstClockTime * max); + gboolean (*convert_range) (GstRTSPMedia *media, GstRTSPTimeRange *range, + GstRTSPRangeUnit unit); /* signals */ void (*new_stream) (GstRTSPMedia *media, GstRTSPStream * stream); From b5f8ff82323cccf8d4e3d21254e0e06f7d13f169 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 12 Jun 2013 12:23:56 +0200 Subject: [PATCH 0659/1776] rtsp-client: Make param_set and param_get virtual Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702072 --- gst/rtsp-server/rtsp-client.c | 30 ++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-client.h | 11 +++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index dafc2de947..47fb1dceb6 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -104,6 +104,10 @@ static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session); static void unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, GstRTSPSessionMedia * media); +static GstRTSPResult default_params_set (GstRTSPClient * client, + GstRTSPClientState * state); +static GstRTSPResult default_params_get (GstRTSPClient * client, + GstRTSPClientState * state); G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); @@ -121,6 +125,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gobject_class->finalize = gst_rtsp_client_finalize; klass->create_sdp = create_sdp; + klass->params_set = default_params_set; + klass->params_get = default_params_get; g_object_class_install_property (gobject_class, PROP_SESSION_POOL, g_param_spec_object ("session-pool", "Session Pool", @@ -706,6 +712,26 @@ not_found: } } +static GstRTSPResult +default_params_set (GstRTSPClient * client, GstRTSPClientState * state) +{ + GstRTSPResult res; + + res = gst_rtsp_params_set (client, state); + + return res; +} + +static GstRTSPResult +default_params_get (GstRTSPClient * client, GstRTSPClientState * state) +{ + GstRTSPResult res; + + res = gst_rtsp_params_get (client, state); + + return res; +} + static gboolean handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state) { @@ -722,7 +748,7 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state) send_generic_response (client, GST_RTSP_STS_OK, state); } else { /* there is a body, handle the params */ - res = gst_rtsp_params_get (client, state); + res = GST_RTSP_CLIENT_GET_CLASS (client)->params_get (client, state); if (res != GST_RTSP_OK) goto bad_request; @@ -759,7 +785,7 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state) send_generic_response (client, GST_RTSP_STS_OK, state); } else { /* there is a body, handle the params */ - res = gst_rtsp_params_set (client, state); + res = GST_RTSP_CLIENT_GET_CLASS (client)->params_set (client, state); if (res != GST_RTSP_OK) goto bad_request; diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 4fad1f64ff..75297b6ad7 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -100,10 +100,21 @@ struct _GstRTSPClient { GstRTSPClientPrivate *priv; }; +/** + * GstRTSPClientClass: + * @params_set: set parameters. This function should also initialize the + * RTSP response(state->response) via a call to gst_rtsp_message_init_response() + * @params_get: get parameters. This function should also initialize the + * RTSP response(state->response) via a call to gst_rtsp_message_init_response() + * + * The client class structure. + */ struct _GstRTSPClientClass { GObjectClass parent_class; GstSDPMessage * (*create_sdp) (GstRTSPClient *client, GstRTSPMedia *media); + GstRTSPResult (*params_set) (GstRTSPClient *client, GstRTSPClientState *state); + GstRTSPResult (*params_get) (GstRTSPClient *client, GstRTSPClientState *state); /* signals */ void (*closed) (GstRTSPClient *client); From 7e9df0e112c0074bda4305294a623efdcd54979c Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 17 Jun 2013 16:18:37 +0200 Subject: [PATCH 0660/1776] rtsp-client: Make configure_client_transport virtual This patch makes configure_client_transport virtual. The functionality is needed to handle some weird clients sending multicast transport settings as url options. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702173 --- gst/rtsp-server/rtsp-client.c | 11 ++++++++--- gst/rtsp-server/rtsp-client.h | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 47fb1dceb6..6029321573 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -104,6 +104,8 @@ static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session); static void unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, GstRTSPSessionMedia * media); +static gboolean default_configure_client_transport (GstRTSPClient * client, + GstRTSPClientState * state, GstRTSPTransport * ct); static GstRTSPResult default_params_set (GstRTSPClient * client, GstRTSPClientState * state); static GstRTSPResult default_params_get (GstRTSPClient * client, @@ -125,6 +127,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gobject_class->finalize = gst_rtsp_client_finalize; klass->create_sdp = create_sdp; + klass->configure_client_transport = default_configure_client_transport; klass->params_set = default_params_set; klass->params_get = default_params_get; @@ -1097,8 +1100,8 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPStream * stream, } static gboolean -configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, - GstRTSPTransport * ct) +default_configure_client_transport (GstRTSPClient * client, + GstRTSPClientState * state, GstRTSPTransport * ct) { GstRTSPClientPrivate *priv = client->priv; @@ -1219,6 +1222,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPMedia *media; GstRTSPStream *stream; GstRTSPState rtspstate; + GstRTSPClientClass *klass; uri = state->uri; @@ -1307,7 +1311,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) goto invalid_blocksize; /* update the client transport */ - if (!configure_client_transport (client, state, ct)) + klass = GST_RTSP_CLIENT_GET_CLASS (client); + if (!klass->configure_client_transport (client, state, ct)) goto unsupported_client_transport; /* set in the session media transport */ diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 75297b6ad7..18bb522109 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -113,6 +113,9 @@ struct _GstRTSPClientClass { GObjectClass parent_class; GstSDPMessage * (*create_sdp) (GstRTSPClient *client, GstRTSPMedia *media); + gboolean (*configure_client_transport) (GstRTSPClient * client, + GstRTSPClientState * state, + GstRTSPTransport * ct); GstRTSPResult (*params_set) (GstRTSPClient *client, GstRTSPClientState *state); GstRTSPResult (*params_get) (GstRTSPClient *client, GstRTSPClientState *state); From d9e245e62eeb9792d2eac3e0c84710c968a1d84f Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 17 Jun 2013 16:47:56 +0200 Subject: [PATCH 0661/1776] rtsp-media: Do not leak the element in take_pipeline Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702470 --- gst/rtsp-server/rtsp-media.c | 2 +- tests/check/gst/media.c | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e018829e63..2482c8e736 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -310,6 +310,7 @@ gst_rtsp_media_set_property (GObject * object, guint propid, switch (propid) { case PROP_ELEMENT: media->priv->element = g_value_get_object (value); + gst_object_ref_sink (media->priv->element); break; case PROP_SHARED: gst_rtsp_media_set_shared (media, g_value_get_boolean (value)); @@ -463,7 +464,6 @@ gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline) if (nettime) gst_object_unref (nettime); - gst_object_ref (priv->element); gst_bin_add (GST_BIN_CAST (pipeline), priv->element); } diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 874a207eae..dd814cfec8 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -237,6 +237,31 @@ GST_START_TEST (test_media_dyn_prepare) GST_END_TEST; +GST_START_TEST (test_media_take_pipeline) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstElement *pipeline; + + factory = gst_rtsp_media_factory_new (); + gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + gst_rtsp_media_factory_set_launch (factory, + "( fakesrc ! text/plain ! rtpgstpay name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + pipeline = gst_pipeline_new ("media-pipeline"); + gst_rtsp_media_take_pipeline (media, GST_PIPELINE_CAST (pipeline)); + + g_object_unref (media); + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + static Suite * rtspmedia_suite (void) { @@ -249,6 +274,7 @@ rtspmedia_suite (void) tcase_add_test (tc, test_media); tcase_add_test (tc, test_media_prepare); tcase_add_test (tc, test_media_dyn_prepare); + tcase_add_test (tc, test_media_take_pipeline); return s; } From 52eb796bec687faa8d0f4c221cb989cd68574543 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Tue, 11 Jun 2013 15:28:32 +0200 Subject: [PATCH 0662/1776] media: use segment stop in collect_media_stats Use segment stop instead of duration as range end point. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701185 --- gst/rtsp-server/rtsp-media.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 2482c8e736..199eb541cc 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -350,7 +350,8 @@ static void collect_media_stats (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; - gint64 position, duration; + GstQuery *query; + gint64 position, stop; if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED && priv->status != GST_RTSP_MEDIA_STATUS_PREPARING) @@ -375,15 +376,18 @@ collect_media_stats (GstRTSPMedia * media) position = 0; } - /* get the duration */ - if (!gst_element_query_duration (priv->pipeline, GST_FORMAT_TIME, - &duration)) { - GST_INFO ("duration query failed"); - duration = -1; + /* get the current segment stop */ + query = gst_query_new_segment (GST_FORMAT_TIME); + if (gst_element_query (priv->pipeline, query)) { + gst_query_parse_segment (query, NULL, NULL, NULL, &stop); + } else { + GST_INFO ("segment query failed"); + stop = -1; } + gst_query_unref (query); - GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %" - GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); + GST_INFO ("stats: position %" GST_TIME_FORMAT ", stop %" + GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (stop)); if (position == -1) { priv->range.min.type = GST_RTSP_TIME_NOW; @@ -394,14 +398,14 @@ collect_media_stats (GstRTSPMedia * media) priv->range.min.seconds = ((gdouble) position) / GST_SECOND; priv->range_start = position; } - if (duration == -1) { + if (stop == -1) { priv->range.max.type = GST_RTSP_TIME_END; priv->range.max.seconds = -1; priv->range_stop = -1; } else { priv->range.max.type = GST_RTSP_TIME_SECONDS; - priv->range.max.seconds = ((gdouble) duration) / GST_SECOND; - priv->range_stop = duration; + priv->range.max.seconds = ((gdouble) stop) / GST_SECOND; + priv->range_stop = stop; } } } From 23ec78faea062808354889b6b555770c77976f6a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Jun 2013 11:14:31 +0200 Subject: [PATCH 0663/1776] media: handle segment query format mismatch It's possible that the segment query returns with a different format than what we asked for, handle this case also. --- gst/rtsp-server/rtsp-media.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 199eb541cc..8a5636b818 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -379,7 +379,10 @@ collect_media_stats (GstRTSPMedia * media) /* get the current segment stop */ query = gst_query_new_segment (GST_FORMAT_TIME); if (gst_element_query (priv->pipeline, query)) { - gst_query_parse_segment (query, NULL, NULL, NULL, &stop); + GstFormat format; + gst_query_parse_segment (query, NULL, &format, NULL, &stop); + if (format != GST_FORMAT_TIME) + stop = -1; } else { GST_INFO ("segment query failed"); stop = -1; From a5490e323be28739369ca477a71fc224797f96d8 Mon Sep 17 00:00:00 2001 From: Alexander Schrab Date: Thu, 20 Jun 2013 11:17:29 +0200 Subject: [PATCH 0664/1776] client: handle asterisk as path in requests Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701266 --- gst/rtsp-server/rtsp-client.c | 52 +++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6029321573..39210bc1c4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -664,6 +664,9 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) session = state->session; + if (!state->uri) + goto no_uri; + /* get a handle to the configuration of the media in the session */ media = gst_rtsp_session_get_media (session, state->uri); if (!media) @@ -707,6 +710,12 @@ no_session: send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); return FALSE; } +no_uri: + { + GST_ERROR ("client %p: no uri supplied", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + return FALSE; + } not_found: { GST_ERROR ("client %p: no media for uri", client); @@ -820,6 +829,9 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) if (!(session = state->session)) goto no_session; + if (!state->uri) + goto no_uri; + /* get a handle to the configuration of the media in the session */ media = gst_rtsp_session_get_media (session, state->uri); if (!media) @@ -861,6 +873,12 @@ no_session: send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); return FALSE; } +no_uri: + { + GST_ERROR ("client %p: no uri supplied", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + return FALSE; + } not_found: { GST_ERROR ("client %p: no media for uri", client); @@ -893,6 +911,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) if (!(session = state->session)) goto no_session; + if (!state->uri) + goto no_uri; + /* get a handle to the configuration of the media in the session */ media = gst_rtsp_session_get_media (session, state->uri); if (!media) @@ -996,6 +1017,12 @@ no_session: send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); return FALSE; } +no_uri: + { + GST_ERROR ("client %p: no uri supplied", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + return FALSE; + } not_found: { GST_ERROR ("client %p: media not found", client); @@ -1224,6 +1251,9 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPState rtspstate; GstRTSPClientClass *klass; + if (!state->uri) + goto no_uri; + uri = state->uri; /* the uri contains the stream number we added in the SDP config, which is @@ -1358,6 +1388,12 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) return TRUE; /* ERRORS */ +no_uri: + { + GST_ERROR ("client %p: no uri", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + return FALSE; + } bad_request: { GST_ERROR ("client %p: bad request", client); @@ -1476,6 +1512,9 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) klass = GST_RTSP_CLIENT_GET_CLASS (client); + if (!state->uri) + goto no_uri; + /* check what kind of format is accepted, we don't really do anything with it * and always return SDP for now. */ for (i = 0; i++;) { @@ -1541,6 +1580,12 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) return TRUE; /* ERRORS */ +no_uri: + { + GST_ERROR ("client %p: no uri", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + return FALSE; + } no_media: { GST_ERROR ("client %p: no media", client); @@ -1686,7 +1731,9 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) state.method = method; /* we always try to parse the url first */ - if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) + if (strcmp (uristr, "*") == 0) { + /* special case where we have * as uri, keep uri = NULL */ + } else if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) goto bad_request; /* get the session if there is any */ @@ -1706,7 +1753,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) } /* sanitize the uri */ - sanitize_uri (uri); + if (uri) + sanitize_uri (uri); state.uri = uri; state.session = session; From 949f11c643676c6b0aa2317a4a7e0555cb8334b2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Jun 2013 12:16:07 +0200 Subject: [PATCH 0665/1776] client: emit new-session when new session is created Only emit new-session when we created a new session for a client, not when a client picked up a previous session. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701587 --- gst/rtsp-server/rtsp-client.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 39210bc1c4..d5c7087b4a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1307,6 +1307,10 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) if (!(session = gst_rtsp_session_pool_create (priv->session_pool))) goto service_unavailable; + /* signal new session */ + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0, + session); + state->session = session; /* we need a new media configuration in this session */ @@ -1694,9 +1698,6 @@ client_watch_session (GstRTSPClient * client, GstRTSPSession * session) g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client); priv->sessions = g_list_prepend (priv->sessions, session); - - g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0, - session); } static void From a8a051f780da6cfc43882b79ffadebaa1a577be8 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 20 Jun 2013 12:18:23 +0200 Subject: [PATCH 0666/1776] tests: add unit test for new-session See https://bugzilla.gnome.org/show_bug.cgi?id=701587 --- tests/check/gst/client.c | 74 ++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index db962f79c3..7dacca4866 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -22,6 +22,7 @@ #include static gint cseq; +static guint expected_session_timeout = 60; static gboolean test_response_200 (GstRTSPClient * client, GstRTSPMessage * response, @@ -273,7 +274,7 @@ GST_START_TEST (test_describe) /* simple DESCRIBE for an existing url */ client = setup_client (NULL); fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, - "rtsp://localhost/test") == GST_RTSP_OK); + "rtsp://localhost/test") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); g_free (str); @@ -307,6 +308,7 @@ test_setup_response_200_multicast (GstRTSPClient * client, gchar *str; GstRTSPSessionPool *session_pool; GstRTSPSession *session; + gchar **session_hdr_params; fail_unless (expected_transport != NULL); @@ -331,12 +333,29 @@ test_setup_response_200_multicast (GstRTSPClient * client, fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &str, 0) == GST_RTSP_OK); + session_hdr_params = g_strsplit (str, ";", -1); + + /* session-id value */ + fail_unless (session_hdr_params[0] != NULL); + + if (expected_session_timeout != 60) { + /* session timeout param */ + gchar *timeout_str = g_strdup_printf ("timeout=%u", + expected_session_timeout); + + fail_unless (session_hdr_params[1] != NULL); + g_strstrip (session_hdr_params[1]); + fail_unless (g_strcmp0 (session_hdr_params[1], timeout_str) == 0); + g_free (timeout_str); + } session_pool = gst_rtsp_client_get_session_pool (client); fail_unless (session_pool != NULL); fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 1); - session = gst_rtsp_session_pool_find (session_pool, str); + session = gst_rtsp_session_pool_find (session_pool, session_hdr_params[0]); + g_strfreev (session_hdr_params); + fail_unless (session != NULL); g_object_unref (session); @@ -404,6 +423,13 @@ GST_START_TEST (test_client_multicast_transport_404) GST_END_TEST; +static void +new_session_cb (GObject * client, GstRTSPSession * session, gpointer user_data) +{ + GST_DEBUG ("%p: new session %p", client, session); + gst_rtsp_session_set_timeout (session, expected_session_timeout); +} + GST_START_TEST (test_client_multicast_transport) { GstRTSPClient *client; @@ -412,6 +438,10 @@ GST_START_TEST (test_client_multicast_transport) client = setup_multicast_client (); + expected_session_timeout = 20; + g_signal_connect (G_OBJECT (client), "new-session", + G_CALLBACK (new_session_cb), NULL); + /* simple SETUP with a valid URI and multicast */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); @@ -428,7 +458,7 @@ GST_START_TEST (test_client_multicast_transport) &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); expected_transport = NULL; - + expected_session_timeout = 60; g_object_unref (client); } @@ -655,13 +685,13 @@ test_response_sdp (GstRTSPClient * client, GstRTSPMessage * response, /* media bandwidth */ if (bandwidth_val) { - fail_unless (gst_sdp_media_bandwidths_len (sdp_media) == 1); - bw = gst_sdp_media_get_bandwidth (sdp_media, 0); - fail_unless (bw != NULL); - fail_unless (g_strcmp0 (bw->bwtype, "AS") == 0); - fail_unless (bw->bandwidth == bandwidth_val); + fail_unless (gst_sdp_media_bandwidths_len (sdp_media) == 1); + bw = gst_sdp_media_get_bandwidth (sdp_media, 0); + fail_unless (bw != NULL); + fail_unless (g_strcmp0 (bw->bwtype, "AS") == 0); + fail_unless (bw->bandwidth == bandwidth_val); } else { - fail_unless (gst_sdp_media_bandwidths_len (sdp_media) == 0); + fail_unless (gst_sdp_media_bandwidths_len (sdp_media) == 0); } gst_sdp_message_free (sdp_msg); @@ -679,12 +709,13 @@ test_client_sdp (const gchar * launch_line, guint * bandwidth_val) /* simple DESCRIBE for an existing url */ client = setup_client (launch_line); fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, - "rtsp://localhost/test") == GST_RTSP_OK); + "rtsp://localhost/test") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); g_free (str); - gst_rtsp_client_set_send_func (client, test_response_sdp, (gpointer) bandwidth_val, NULL); + gst_rtsp_client_set_send_func (client, test_response_sdp, + (gpointer) bandwidth_val, NULL); fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); @@ -697,13 +728,15 @@ GST_START_TEST (test_client_sdp_with_max_bitrate_tag) { test_client_sdp ("videotestsrc " "! taginject tags=\"maximum-bitrate=(uint)50000000\" " - "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (50000)); + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", + GUINT_TO_POINTER (50000)); /* max-bitrate=0: no bandwidth line */ test_client_sdp ("videotestsrc " "! taginject tags=\"maximum-bitrate=(uint)0\" " - "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (0)); + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", + GUINT_TO_POINTER (0)); } GST_END_TEST; @@ -712,12 +745,14 @@ GST_START_TEST (test_client_sdp_with_bitrate_tag) { test_client_sdp ("videotestsrc " "! taginject tags=\"bitrate=(uint)7000000\" " - "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (7000)); + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", + GUINT_TO_POINTER (7000)); /* bitrate=0: no bandwdith line */ test_client_sdp ("videotestsrc " "! taginject tags=\"bitrate=(uint)0\" " - "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (0)); + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", + GUINT_TO_POINTER (0)); } GST_END_TEST; @@ -726,17 +761,20 @@ GST_START_TEST (test_client_sdp_with_max_bitrate_and_bitrate_tags) { test_client_sdp ("videotestsrc " "! taginject tags=\"bitrate=(uint)7000000,maximum-bitrate=(uint)50000000\" " - "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (50000)); + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", + GUINT_TO_POINTER (50000)); /* max-bitrate is zero: fallback to bitrate */ test_client_sdp ("videotestsrc " "! taginject tags=\"bitrate=(uint)7000000,maximum-bitrate=(uint)0\" " - "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (7000)); + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", + GUINT_TO_POINTER (7000)); /* max-bitrate=bitrate=0o: no bandwidth line */ test_client_sdp ("videotestsrc " "! taginject tags=\"bitrate=(uint)0,maximum-bitrate=(uint)0\" " - "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", GUINT_TO_POINTER (0)); + "! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96", + GUINT_TO_POINTER (0)); } GST_END_TEST; From fa1d3354c090916e11347989b11fe360186f819e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Jun 2013 12:20:21 +0200 Subject: [PATCH 0667/1776] client: also watch newly created session When we newly created a session, start watching it immediately instead of on the next request. --- gst/rtsp-server/rtsp-client.c | 45 +++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d5c7087b4a..67aacb05ad 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -247,6 +247,27 @@ client_unlink_session (GstRTSPClient * client, GstRTSPSession * session) gst_rtsp_session_filter (session, filter_session, client); } +static void +client_watch_session (GstRTSPClient * client, GstRTSPSession * session) +{ + GstRTSPClientPrivate *priv = client->priv; + GList *walk; + + for (walk = priv->sessions; walk; walk = g_list_next (walk)) { + GstRTSPSession *msession = (GstRTSPSession *) walk->data; + + /* we already know about this session */ + if (msession == session) + return; + } + + GST_INFO ("watching session %p", session); + + g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, + client); + priv->sessions = g_list_prepend (priv->sessions, session); +} + static void client_cleanup_sessions (GstRTSPClient * client) { @@ -1307,6 +1328,9 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) if (!(session = gst_rtsp_session_pool_create (priv->session_pool))) goto service_unavailable; + /* make sure this client is closed when the session is closed */ + client_watch_session (client, session); + /* signal new session */ g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0, session); @@ -1679,27 +1703,6 @@ client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) } } -static void -client_watch_session (GstRTSPClient * client, GstRTSPSession * session) -{ - GstRTSPClientPrivate *priv = client->priv; - GList *walk; - - for (walk = priv->sessions; walk; walk = g_list_next (walk)) { - GstRTSPSession *msession = (GstRTSPSession *) walk->data; - - /* we already know about this session */ - if (msession == session) - return; - } - - GST_INFO ("watching session %p", session); - - g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, - client); - priv->sessions = g_list_prepend (priv->sessions, session); -} - static void handle_request (GstRTSPClient * client, GstRTSPMessage * request) { From cd8a81b3b140ddee37efcfc606ec62b748428c74 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Jun 2013 17:30:49 +0200 Subject: [PATCH 0668/1776] tests: fix test Actually do what the comment says. Also keep the old code around, not sure what should happen when you get a 454 from a TEARDOWN, does it close the connection? it currently doesn't. --- tests/check/gst/rtspserver.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 2a01aed4e5..5edeffd47e 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1011,6 +1011,7 @@ GST_START_TEST (test_play_multithreaded_timeout_client) GstRTSPSessionPool *pool; GstRTSPMessage *request; GstRTSPMessage *response; + GstRTSPStatusCode code; gst_rtsp_server_set_max_threads (server, 2); pool = gst_rtsp_server_get_session_pool (server); @@ -1056,11 +1057,20 @@ GST_START_TEST (test_play_multithreaded_timeout_client) fail_unless (send_request (conn, request)); gst_rtsp_message_free (request); + fail_unless (gst_rtsp_message_new (&response) == GST_RTSP_OK); + fail_unless (gst_rtsp_connection_receive (conn, response, NULL) == + GST_RTSP_OK); + gst_rtsp_message_parse_response (response, &code, NULL, NULL); + fail_unless (code == GST_RTSP_STS_SESSION_NOT_FOUND); + gst_rtsp_message_free (response); + +#if 0 fail_unless (gst_rtsp_message_new (&response) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_receive (conn, response, NULL) == GST_RTSP_ESYS); fail_unless (errno == ECONNRESET); gst_rtsp_message_free (response); +#endif /* clean up and iterate so the clean-up can finish */ g_object_unref (pool); From c3f867317494ccd38e8bbc76f5235e2287b846b3 Mon Sep 17 00:00:00 2001 From: Alexander Schrab Date: Mon, 24 Jun 2013 10:43:59 +0200 Subject: [PATCH 0669/1776] dscp qos support in gst-rtsp-stream Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702645 --- gst/rtsp-server/rtsp-stream.c | 77 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 3 ++ 2 files changed, 80 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 8b8aa31187..11486e5468 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -84,6 +84,8 @@ struct _GstRTSPStreamPrivate /* transports we stream to */ guint n_active; GList *transports; + + gint dscp_qos; }; @@ -127,6 +129,8 @@ gst_rtsp_stream_init (GstRTSPStream * stream) stream->priv = priv; + stream->priv->dscp_qos = -1; + g_mutex_init (&priv->lock); } @@ -265,6 +269,76 @@ gst_rtsp_stream_get_mtu (GstRTSPStream * stream) return mtu; } +/* Update the dscp qos property on the udp sinks */ +static void +update_dscp_qos (GstRTSPStream *stream) +{ + GstRTSPStreamPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + priv = stream->priv; + + if (priv->udpsink[0]) { + g_object_set (G_OBJECT (priv->udpsink[0]), "qos-dscp", priv->dscp_qos, + NULL); + } + + if (priv->udpsink[1]) { + g_object_set (G_OBJECT (priv->udpsink[1]), "qos-dscp", priv->dscp_qos, + NULL); + } +} + +/** + * gst_rtsp_stream_set_dscp_qos: + * @stream: a #GstRTSPStream + * @dscp_qos: a new dscp qos value (0-63, or -1 to disable) + * + * Configure the dscp qos of the outgoing sockets to @dscp_qos. + */ +void +gst_rtsp_stream_set_dscp_qos (GstRTSPStream *stream, gint dscp_qos) +{ + GstRTSPStreamPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + priv = stream->priv; + + GST_LOG_OBJECT (stream, "set DSCP QoS %d", dscp_qos); + + if (dscp_qos < -1 || dscp_qos > 63) { + GST_WARNING_OBJECT (stream, "trying to set illegal dscp qos %d", dscp_qos); + return; + } + + priv->dscp_qos = dscp_qos; + + update_dscp_qos (stream); +} + +/** + * gst_rtsp_stream_get_dscp_qos: + * @stream: a #GstRTSPStream + * + * Get the configured DSCP QoS in of the outgoing sockets. + * + * Returns: the DSCP QoS value of the outgoing sockets, or -1 if disbled. + */ +gint +gst_rtsp_stream_get_dscp_qos (GstRTSPStream *stream) +{ + GstRTSPStreamPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), -1); + + priv = stream->priv; + + return priv->dscp_qos; +} + + /** * gst_rtsp_stream_set_address_pool: * @stream: a #GstRTSPStream @@ -1018,6 +1092,9 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, if (!alloc_ports (stream)) goto no_ports; + /* update the dscp qos field in the sinks */ + update_dscp_qos (stream); + /* get a pad for sending RTP */ name = g_strdup_printf ("send_rtp_sink_%u", idx); priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index f6507a95d7..4b8e53eb66 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -70,6 +70,9 @@ GstPad * gst_rtsp_stream_get_srcpad (GstRTSPStream *stream); void gst_rtsp_stream_set_mtu (GstRTSPStream *stream, guint mtu); guint gst_rtsp_stream_get_mtu (GstRTSPStream *stream); +void gst_rtsp_stream_set_dscp_qos (GstRTSPStream *stream, gint dscp_qos); +gint gst_rtsp_stream_get_dscp_qos (GstRTSPStream *stream); + void gst_rtsp_stream_set_address_pool (GstRTSPStream *stream, GstRTSPAddressPool *pool); GstRTSPAddressPool * gst_rtsp_stream_get_address_pool (GstRTSPStream *stream); From aeaadf0e5e8ea9e22b2b2720a6e8ba54975cab6f Mon Sep 17 00:00:00 2001 From: Aleix Conchillo Flaque Date: Mon, 24 Jun 2013 11:41:27 -0700 Subject: [PATCH 0670/1776] stream: allow access to the rtp session https://bugzilla.gnome.org/show_bug.cgi?id=703004 --- gst/rtsp-server/rtsp-stream.c | 32 +++++++++++++++++++++++++++++--- gst/rtsp-server/rtsp-stream.h | 3 +++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 11486e5468..f992048c90 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -271,7 +271,7 @@ gst_rtsp_stream_get_mtu (GstRTSPStream * stream) /* Update the dscp qos property on the udp sinks */ static void -update_dscp_qos (GstRTSPStream *stream) +update_dscp_qos (GstRTSPStream * stream) { GstRTSPStreamPrivate *priv; @@ -298,7 +298,7 @@ update_dscp_qos (GstRTSPStream *stream) * Configure the dscp qos of the outgoing sockets to @dscp_qos. */ void -gst_rtsp_stream_set_dscp_qos (GstRTSPStream *stream, gint dscp_qos) +gst_rtsp_stream_set_dscp_qos (GstRTSPStream * stream, gint dscp_qos) { GstRTSPStreamPrivate *priv; @@ -327,7 +327,7 @@ gst_rtsp_stream_set_dscp_qos (GstRTSPStream *stream, gint dscp_qos) * Returns: the DSCP QoS value of the outgoing sockets, or -1 if disbled. */ gint -gst_rtsp_stream_get_dscp_qos (GstRTSPStream *stream) +gst_rtsp_stream_get_dscp_qos (GstRTSPStream * stream) { GstRTSPStreamPrivate *priv; @@ -805,6 +805,32 @@ gst_rtsp_stream_get_server_port (GstRTSPStream * stream, g_mutex_unlock (&priv->lock); } +/** + * gst_rtsp_stream_get_rtpsession: + * @stream: a #GstRTSPStream + * + * Get the RTP session of this stream. + * + * Returns: The RTP session of this stream. Unref after usage. + */ +GObject * +gst_rtsp_stream_get_rtpsession (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + GObject *session; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if ((session = priv->session)) + g_object_ref (session); + g_mutex_unlock (&priv->lock); + + return session; +} + /** * gst_rtsp_stream_get_ssrc: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 4b8e53eb66..1060a05182 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -94,6 +94,9 @@ gboolean gst_rtsp_stream_leave_bin (GstRTSPStream *stream, void gst_rtsp_stream_get_server_port (GstRTSPStream *stream, GstRTSPRange *server_port, GSocketFamily family); + +GObject * gst_rtsp_stream_get_rtpsession (GstRTSPStream *stream); + void gst_rtsp_stream_get_ssrc (GstRTSPStream *stream, guint *ssrc); From 6d69a4ae80fc7be5bd875056d58b50e9e95aa740 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 24 Jun 2013 23:51:38 +0200 Subject: [PATCH 0671/1776] media: fix docs --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 8a5636b818..1cd14d575a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -439,7 +439,7 @@ gst_rtsp_media_new (GstElement * element) } /** - * gst_rtsp_media_take_element: + * gst_rtsp_media_take_pipeline: * @media: a #GstRTSPMedia * @pipeline: (transfer full): a #GstPipeline * From aab11985169d6b27443c3581eadbe0760c6f9bce Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 24 Jun 2013 23:56:57 +0200 Subject: [PATCH 0672/1776] media: add _get_element() method Add method to get the element used when creating the media. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=703008 --- gst/rtsp-server/rtsp-media.c | 16 ++++++++++++++++ gst/rtsp-server/rtsp-media.h | 1 + 2 files changed, 17 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1cd14d575a..e2c62cac57 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -438,6 +438,22 @@ gst_rtsp_media_new (GstElement * element) return result; } +/** + * gst_rtsp_media_get_element: + * @media: a #GstRTSPMedia + * + * Get the element that was used when constructing @media. + * + * Returns: a #GstElement. Unref after usage. + */ +GstElement * +gst_rtsp_media_get_element (GstRTSPMedia * media) +{ + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + + return gst_object_ref (media->priv->element); +} + /** * gst_rtsp_media_take_pipeline: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 4dbe063271..727cac352c 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -117,6 +117,7 @@ GType gst_rtsp_media_get_type (void); /* creating the media */ GstRTSPMedia * gst_rtsp_media_new (GstElement *element); +GstElement * gst_rtsp_media_get_element (GstRTSPMedia *media); void gst_rtsp_media_take_pipeline (GstRTSPMedia *media, GstPipeline *pipeline); From d2dab470852e1959f03ef3410bd795c96b69e418 Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Mon, 10 Jun 2013 17:32:12 -0400 Subject: [PATCH 0673/1776] Add gst_rtsp_client_send_request API This makes it possible to send arbitrary messages to a client, such as SET_PARAMETER or GET_PARAMETER --- gst/rtsp-server/rtsp-client.c | 15 +++++++++++++++ gst/rtsp-server/rtsp-client.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 67aacb05ad..897ab70dc9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2295,6 +2295,21 @@ gst_rtsp_client_handle_message (GstRTSPClient * client, return GST_RTSP_OK; } +/** + * gst_rtsp_client_send_request: + * @client: a #GstRTSPClient + * @session: a #GstRTSPSession to send the request to or %NULL + * @message: The #GstRTSPMessage to send + * + * Send a request message to the client. + */ +void +gst_rtsp_client_send_request (GstRTSPClient * client, GstRTSPSession * session, + GstRTSPMessage * message) +{ + send_response (client, session, message, FALSE); +} + static GstRTSPResult do_send_message (GstRTSPClient * client, GstRTSPMessage * message, gboolean close, gpointer user_data) diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 18bb522109..7e0a07eb24 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -163,6 +163,9 @@ void gst_rtsp_client_set_send_func (GstRTSPClient *client, GstRTSPResult gst_rtsp_client_handle_message (GstRTSPClient *client, GstRTSPMessage *message); +void gst_rtsp_client_send_request (GstRTSPClient * client, + GstRTSPSession *session, + GstRTSPMessage *message); guint gst_rtsp_client_attach (GstRTSPClient *client, GMainContext *context); From 55214d0d52ad01c05fbe963701fd60e3fa518fdc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 25 Jun 2013 15:09:13 +0200 Subject: [PATCH 0674/1776] client: clean some variables Clean some variables and add some guards to _send_request() --- gst/rtsp-server/rtsp-client.c | 53 ++++++++++++++++++++--------------- gst/rtsp-server/rtsp-client.h | 4 +-- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 897ab70dc9..16a8bc069c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -386,36 +386,36 @@ gst_rtsp_client_new (void) } static void -send_response (GstRTSPClient * client, GstRTSPSession * session, - GstRTSPMessage * response, gboolean close) +send_message (GstRTSPClient * client, GstRTSPSession * session, + GstRTSPMessage * message, gboolean close) { GstRTSPClientPrivate *priv = client->priv; - gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER, + gst_rtsp_message_add_header (message, GST_RTSP_HDR_SERVER, "GStreamer RTSP server"); /* remove any previous header */ - gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1); + gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1); /* add the new session header for new session ids */ if (session) { - gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION, + gst_rtsp_message_take_header (message, GST_RTSP_HDR_SESSION, gst_rtsp_session_get_header (session)); } if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) { - gst_rtsp_message_dump (response); + gst_rtsp_message_dump (message); } if (close) - gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONNECTION, "close"); + gst_rtsp_message_add_header (message, GST_RTSP_HDR_CONNECTION, "close"); g_mutex_lock (&priv->send_lock); if (priv->send_func) - priv->send_func (client, response, close, priv->send_data); + priv->send_func (client, message, close, priv->send_data); g_mutex_unlock (&priv->send_lock); - gst_rtsp_message_unset (response); + gst_rtsp_message_unset (message); } static void @@ -425,7 +425,7 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); - send_response (client, NULL, state->response, FALSE); + send_message (client, NULL, state->response, FALSE); } static void @@ -440,7 +440,7 @@ handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth, gst_rtsp_auth_setup_auth (auth, client, 0, state); } - send_response (client, state->session, state->response, FALSE); + send_message (client, state->session, state->response, FALSE); } @@ -720,7 +720,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); - send_response (client, session, state->response, TRUE); + send_message (client, session, state->response, TRUE); return TRUE; @@ -785,7 +785,7 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state) if (res != GST_RTSP_OK) goto bad_request; - send_response (client, state->session, state->response, FALSE); + send_message (client, state->session, state->response, FALSE); } g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST], @@ -822,7 +822,7 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state) if (res != GST_RTSP_OK) goto bad_request; - send_response (client, state->session, state->response, FALSE); + send_message (client, state->session, state->response, FALSE); } g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST], @@ -877,7 +877,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_message_init_response (state->response, code, gst_rtsp_status_as_text (code), state->request); - send_response (client, session, state->response, FALSE); + send_message (client, session, state->response, FALSE); /* the state is now READY */ gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_READY); @@ -1019,7 +1019,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) TRUE, unit); gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str); - send_response (client, session, state->response, FALSE); + send_message (client, session, state->response, FALSE); /* start playing after sending the request */ gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING); @@ -1394,7 +1394,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) trans_str); g_free (trans_str); - send_response (client, session, state->response, FALSE); + send_message (client, session, state->response, FALSE); /* update the state */ rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); @@ -1600,7 +1600,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_message_take_body (state->response, (guint8 *) str, strlen (str)); gst_sdp_message_free (sdp); - send_response (client, state->session, state->response, FALSE); + send_message (client, state->session, state->response, FALSE); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST], 0, state); @@ -1650,7 +1650,7 @@ handle_options_request (GstRTSPClient * client, GstRTSPClientState * state) gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_PUBLIC, str); g_free (str); - send_response (client, state->session, state->response, FALSE); + send_message (client, state->session, state->response, FALSE); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST], 0, state); @@ -2299,15 +2299,22 @@ gst_rtsp_client_handle_message (GstRTSPClient * client, * gst_rtsp_client_send_request: * @client: a #GstRTSPClient * @session: a #GstRTSPSession to send the request to or %NULL - * @message: The #GstRTSPMessage to send + * @request: The request #GstRTSPMessage to send * * Send a request message to the client. */ -void +GstRTSPResult gst_rtsp_client_send_request (GstRTSPClient * client, GstRTSPSession * session, - GstRTSPMessage * message) + GstRTSPMessage * request) { - send_response (client, session, message, FALSE); + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL); + g_return_val_if_fail (request != NULL, GST_RTSP_EINVAL); + g_return_val_if_fail (request->type == GST_RTSP_MESSAGE_REQUEST, + GST_RTSP_EINVAL); + + send_message (client, session, request, FALSE); + + return GST_RTSP_OK; } static GstRTSPResult diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 7e0a07eb24..a6f7cac4e7 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -163,9 +163,9 @@ void gst_rtsp_client_set_send_func (GstRTSPClient *client, GstRTSPResult gst_rtsp_client_handle_message (GstRTSPClient *client, GstRTSPMessage *message); -void gst_rtsp_client_send_request (GstRTSPClient * client, +GstRTSPResult gst_rtsp_client_send_request (GstRTSPClient * client, GstRTSPSession *session, - GstRTSPMessage *message); + GstRTSPMessage *request); guint gst_rtsp_client_attach (GstRTSPClient *client, GMainContext *context); From 842f5ad9c405a9519100c026583265f2a43dda1b Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Mon, 10 Jun 2013 17:33:01 -0400 Subject: [PATCH 0675/1776] Fix typo in property install for rtsp-media's time-provider --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e2c62cac57..47c1aaeecc 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -174,7 +174,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "The GstBin to use for streaming the media", GST_TYPE_ELEMENT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN, + g_object_class_install_property (gobject_class, PROP_TIME_PROVIDER, g_param_spec_boolean ("time-provider", "Time Provider", "Use a NetTimeProvider for clients", DEFAULT_TIME_PROVIDER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); From 0b94f50eabfd0ec8285dec7380163a4090186477 Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Mon, 10 Jun 2013 17:32:40 -0400 Subject: [PATCH 0676/1776] Add query_position and query_stop vmethods to rtsp-media --- gst/rtsp-server/rtsp-media.c | 56 ++++++++++++++++++++++++++++-------- gst/rtsp-server/rtsp-media.h | 2 ++ 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 47c1aaeecc..c343a4df3e 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -126,6 +126,9 @@ static gboolean default_unprepare (GstRTSPMedia * media); static gboolean default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range, GstRTSPRangeUnit unit); +static gboolean default_query_position (GstRTSPMedia * media, + gint64 * position); +static gboolean default_query_stop (GstRTSPMedia * media, gint64 * stop); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; @@ -215,6 +218,8 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->handle_message = default_handle_message; klass->unprepare = default_unprepare; klass->convert_range = default_convert_range; + klass->query_position = default_query_position; + klass->query_stop = default_query_stop; } static void @@ -350,7 +355,6 @@ static void collect_media_stats (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; - GstQuery *query; gint64 position, stop; if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED && @@ -369,25 +373,30 @@ collect_media_stats (GstRTSPMedia * media) priv->range.max.seconds = -1; priv->range_stop = -1; } else { + GstRTSPMediaClass *klass; + gboolean ret; + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + /* get the position */ - if (!gst_element_query_position (priv->pipeline, GST_FORMAT_TIME, - &position)) { + ret = FALSE; + if (klass->query_position) + ret = klass->query_position (media, &position); + + if (!ret) { GST_INFO ("position query failed"); position = 0; } /* get the current segment stop */ - query = gst_query_new_segment (GST_FORMAT_TIME); - if (gst_element_query (priv->pipeline, query)) { - GstFormat format; - gst_query_parse_segment (query, NULL, &format, NULL, &stop); - if (format != GST_FORMAT_TIME) - stop = -1; - } else { - GST_INFO ("segment query failed"); + ret = FALSE; + if (klass->query_stop) + ret = klass->query_stop (media, &stop); + + if (!ret) { + GST_INFO ("stop query failed"); stop = -1; } - gst_query_unref (query); GST_INFO ("stats: position %" GST_TIME_FORMAT ", stop %" GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (stop)); @@ -2094,3 +2103,26 @@ default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range, { return gst_rtsp_range_convert_units (range, unit); } + +static gboolean +default_query_position (GstRTSPMedia * media, gint64 * position) +{ + return gst_element_query_position (media->priv->pipeline, GST_FORMAT_TIME, + position); +} + +static gboolean +default_query_stop (GstRTSPMedia * media, gint64 * stop) +{ + GstQuery *query; + gboolean res; + + query = gst_query_new_segment (GST_FORMAT_TIME); + if ((res = gst_element_query (media->priv->pipeline, query))) { + GstFormat format; + gst_query_parse_segment (query, NULL, &format, NULL, stop); + if (format != GST_FORMAT_TIME) + *stop = -1; + } + return res; +} diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 727cac352c..2b906cf734 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -102,6 +102,8 @@ struct _GstRTSPMediaClass { gboolean (*unprepare) (GstRTSPMedia *media); gboolean (*convert_range) (GstRTSPMedia *media, GstRTSPTimeRange *range, GstRTSPRangeUnit unit); + gboolean (*query_position) (GstRTSPMedia *media, gint64 *position); + gboolean (*query_stop) (GstRTSPMedia *media, gint64 *stop); /* signals */ void (*new_stream) (GstRTSPMedia *media, GstRTSPStream * stream); From 81c3843ad11ba3edca1e43ef211c88394500d3b7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 25 Jun 2013 15:46:41 +0200 Subject: [PATCH 0677/1776] media: don't unlock when conversion fails Don't unlock the state lock when conversion fails because it was not locked. --- gst/rtsp-server/rtsp-media.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c343a4df3e..49e86f233b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1135,9 +1135,8 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play, g_mutex_unlock (&priv->lock); g_rec_mutex_unlock (&priv->state_lock); - if (!klass->convert_range (media, &range, unit)) { + if (!klass->convert_range (media, &range, unit)) goto conversion_failed; - } result = gst_rtsp_range_to_string (&range); @@ -1153,7 +1152,6 @@ not_prepared: conversion_failed: { GST_WARNING ("range conversion to unit %d failed", unit); - g_rec_mutex_unlock (&priv->state_lock); return NULL; } } From cd4120ef265a294555b8f4e945023fcc8e533038 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 26 Jun 2013 14:42:15 +0200 Subject: [PATCH 0678/1776] rtsp-media: Do not leak the query in default_query_stop Fixes https://bugzilla.gnome.org/show_bug.cgi?id=703120 --- gst/rtsp-server/rtsp-media.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 49e86f233b..c8a35d7d15 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2122,5 +2122,6 @@ default_query_stop (GstRTSPMedia * media, gint64 * stop) if (format != GST_FORMAT_TIME) *stop = -1; } + gst_query_unref (query); return res; } From 13ab4905e49c720c67b779fa34e904be3a724dd3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 26 Jun 2013 16:31:39 +0200 Subject: [PATCH 0679/1776] media-factory: fix typo --- gst/rtsp-server/rtsp-media-factory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index dce19e516a..d974fa0148 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -73,7 +73,7 @@ struct _GstRTSPMediaFactory { * implementation will configure the 'shared' property of the media. * @create_pipeline: create a new pipeline or re-use an existing one and * add the #GstRTSPMedia's element created by @construct to the pipeline. - * @media_constructed: signal emited when a media was cunstructed + * @media_constructed: signal emited when a media was constructed * @media_configure: signal emited when a media should be configured * * The #GstRTSPMediaFactory class structure. From 27a786aa4adfff487e231a75bde2c6125e8adf9d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 26 Jun 2013 16:32:06 +0200 Subject: [PATCH 0680/1776] client: remove _get_uri() method Remove the get_uri() method on the client. A client has no uri, the uri property is an internal property to manage the last cached media for the client. --- gst/rtsp-server/rtsp-client.c | 27 --------------------------- gst/rtsp-server/rtsp-client.h | 2 -- 2 files changed, 29 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 16a8bc069c..7e8d35b4cc 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2120,33 +2120,6 @@ gst_rtsp_client_get_auth (GstRTSPClient * client) return result; } -/** - * gst_rtsp_client_get_uri: - * @client: a #GstRTSPClient - * - * Get the #GstRTSPUrl of @client. - * - * Returns: (transfer full): the #GstRTSPUrl of @client. Free with - * gst_rtsp_url_free () after usage. - */ -GstRTSPUrl * -gst_rtsp_client_get_uri (GstRTSPClient * client) -{ - GstRTSPClientPrivate *priv; - GstRTSPUrl *result = NULL; - - g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); - - priv = client->priv; - - g_mutex_lock (&priv->lock); - if (priv->uri != NULL) - result = gst_rtsp_url_copy (priv->uri); - g_mutex_unlock (&priv->lock); - - return result; -} - /** * gst_rtsp_client_set_connection: * @client: a #GstRTSPClient diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index a6f7cac4e7..a5d32d5ab7 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -151,8 +151,6 @@ gboolean gst_rtsp_client_get_use_client_settings (GstRTSPClient * c void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); -GstRTSPUrl * gst_rtsp_client_get_uri (GstRTSPClient *client); - gboolean gst_rtsp_client_set_connection (GstRTSPClient *client, GstRTSPConnection *conn); GstRTSPConnection * gst_rtsp_client_get_connection (GstRTSPClient *client); From ffd4b1aaf11bd2a9755e83768f018640a9e7f19f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 26 Jun 2013 17:18:33 +0200 Subject: [PATCH 0681/1776] client: add method to filter managed sessions Add a method to filter the sessions managed by this client connection. See https://bugzilla.gnome.org/show_bug.cgi?id=703016 --- gst/rtsp-server/rtsp-client.c | 92 ++++++++++++++++++++++++++++++++--- gst/rtsp-server/rtsp-client.h | 29 +++++++++++ 2 files changed, 114 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 7e8d35b4cc..1bc83fa54b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -50,6 +50,8 @@ struct _GstRTSPClientPrivate GstRTSPMountPoints *mount_points; GstRTSPAuth *auth; + /* used to cache the media in the last requested DESCRIBE so that + * we can pick it up in the next SETUP immediately */ GstRTSPUrl *uri; GstRTSPMedia *media; @@ -268,6 +270,26 @@ client_watch_session (GstRTSPClient * client, GstRTSPSession * session) priv->sessions = g_list_prepend (priv->sessions, session); } +static void +client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session) +{ + GstRTSPClientPrivate *priv = client->priv; + + GST_INFO ("unwatching session %p", session); + + g_object_weak_unref (G_OBJECT (session), + (GWeakNotify) client_session_finalized, client); + priv->sessions = g_list_remove (priv->sessions, session); +} + +static void +client_cleanup_session (GstRTSPClient * client, GstRTSPSession * session) +{ + g_object_weak_unref (G_OBJECT (session), + (GWeakNotify) client_session_finalized, client); + client_unlink_session (client, session); +} + static void client_cleanup_sessions (GstRTSPClient * client) { @@ -276,10 +298,7 @@ client_cleanup_sessions (GstRTSPClient * client) /* remove weak-ref from sessions */ for (sessions = priv->sessions; sessions; sessions = g_list_next (sessions)) { - GstRTSPSession *session = (GstRTSPSession *) sessions->data; - g_object_weak_unref (G_OBJECT (session), - (GWeakNotify) client_session_finalized, client); - client_unlink_session (client, session); + client_cleanup_session (client, (GstRTSPSession *) sessions->data); } g_list_free (priv->sessions); priv->sessions = NULL; @@ -703,9 +722,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) unlink_session_transports (client, session, media); /* remove the session from the watched sessions */ - g_object_weak_unref (G_OBJECT (session), - (GWeakNotify) client_session_finalized, client); - priv->sessions = g_list_remove (priv->sessions, session); + client_unwatch_session (client, session); gst_rtsp_session_media_set_state (media, GST_STATE_NULL); @@ -2571,3 +2588,64 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) return res; } + +/** + * gst_rtsp_client_session_filter: + * @client: a #GstRTSPclient + * @func: (scope call): a callback + * @user_data: user data passed to @func + * + * Call @func for each session managed by @client. The result value of @func + * determines what happens to the session. @func will be called with @client + * locked so no further actions on @client can be performed from @func. + * + * If @func returns #GST_RTSP_FILTER_REMOVE, the session will be removed from + * @client. + * + * If @func returns #GST_RTSP_FILTER_KEEP, the session will remain in @client. + * + * If @func returns #GST_RTSP_FILTER_REF, the session will remain in @client but + * will also be added with an additional ref to the result #GList of this + * function.. + * + * Returns: (element-type GstRTSPSession) (transfer full): a #GList with all + * sessions for which @func returned #GST_RTSP_FILTER_REF. After usage, each + * element in the #GList should be unreffed before the list is freed. + */ +GList * +gst_rtsp_client_session_filter (GstRTSPClient * client, + GstRTSPClientSessionFilterFunc func, gpointer user_data) +{ + GstRTSPClientPrivate *priv; + GList *result, *walk, *next; + + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); + g_return_val_if_fail (func != NULL, NULL); + + priv = client->priv; + + result = NULL; + + g_mutex_lock (&priv->lock); + for (walk = priv->sessions; walk; walk = next) { + GstRTSPSession *sess = walk->data; + + next = g_list_next (walk); + + switch (func (client, sess, user_data)) { + case GST_RTSP_FILTER_REMOVE: + /* stop watching the session and pretent it went away */ + client_cleanup_session (client, sess); + break; + case GST_RTSP_FILTER_REF: + result = g_list_prepend (result, g_object_ref (sess)); + break; + case GST_RTSP_FILTER_KEEP: + default: + break; + } + } + g_mutex_unlock (&priv->lock); + + return result; +} diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index a5d32d5ab7..741fed24e6 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -167,6 +167,35 @@ GstRTSPResult gst_rtsp_client_send_request (GstRTSPClient * client, guint gst_rtsp_client_attach (GstRTSPClient *client, GMainContext *context); +/** + * GstRTSPClientSessionFilterFunc: + * @client: a #GstRTSPClient object + * @sess: a #GstRTSPSession in @client + * @user_data: user data that has been given to gst_rtsp_client_session_filter() + * + * This function will be called by the gst_rtsp_client_session_filter(). An + * implementation should return a value of #GstRTSPFilterResult. + * + * When this function returns #GST_RTSP_FILTER_REMOVE, @sess will be removed + * from @client. + * + * A return value of #GST_RTSP_FILTER_KEEP will leave @sess untouched in + * @client. + * + * A value of GST_RTSP_FILTER_REF will add @sess to the result #GList of + * gst_rtsp_client_session_filter(). + * + * Returns: a #GstRTSPFilterResult. + */ +typedef GstRTSPFilterResult (*GstRTSPClientSessionFilterFunc) (GstRTSPClient *client, + GstRTSPSession *sess, + gpointer user_data); + +GList * gst_rtsp_client_session_filter (GstRTSPClient *client, + GstRTSPClientSessionFilterFunc func, + gpointer user_data); + + G_END_DECLS From ffefd9e80bd89ac04710eb5957a40deb340659c2 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 27 Jun 2013 11:21:42 +0200 Subject: [PATCH 0682/1776] tests: fix tests gst_rtsp_client_get_uri() has been removed Fixes https://bugzilla.gnome.org/show_bug.cgi?id=703173 --- tests/check/gst/client.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 7dacca4866..e25ba480ef 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -247,8 +247,6 @@ GST_START_TEST (test_describe) GstRTSPClient *client; GstRTSPMessage request = { 0, }; gchar *str; - GstRTSPUrl *uri_client; - gchar *uri_str; client = gst_rtsp_client_new (); @@ -264,11 +262,6 @@ GST_START_TEST (test_describe) &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - uri_client = gst_rtsp_client_get_uri (client); - fail_unless (uri_client == NULL); - gst_rtsp_url_free (uri_client); - - g_object_unref (client); /* simple DESCRIBE for an existing url */ @@ -284,13 +277,6 @@ GST_START_TEST (test_describe) &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - uri_client = gst_rtsp_client_get_uri (client); - fail_unless (uri_client != NULL); - uri_str = gst_rtsp_url_get_request_uri (uri_client); - gst_rtsp_url_free (uri_client); - fail_unless (g_strcmp0 (uri_str, "rtsp://localhost/test") == 0); - g_free (uri_str); - g_object_unref (client); } From 5b6cbb4edecc76661058e5bbbfe595266fb68abc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 1 Jul 2013 12:04:45 +0200 Subject: [PATCH 0683/1776] stream-transport: remove old if 0 block --- gst/rtsp-server/rtsp-stream-transport.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 0859573d81..0a03ad21c3 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -99,11 +99,6 @@ gst_rtsp_stream_transport_finalize (GObject * obj) if (priv->transport) gst_rtsp_transport_free (priv->transport); -#if 0 - if (priv->rtpsource) - g_object_set_qdata (priv->rtpsource, ssrc_stream_map_key, NULL); -#endif - G_OBJECT_CLASS (gst_rtsp_stream_transport_parent_class)->finalize (obj); } From 284a0a5cd1d9e5df365a385d77d9b25c6eb0762e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 1 Jul 2013 12:20:50 +0200 Subject: [PATCH 0684/1776] stream: improve docs --- gst/rtsp-server/rtsp-stream.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index f992048c90..920a87fe33 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -449,11 +449,15 @@ no_address: /** * gst_rtsp_stream_reserve_address: * @stream: a #GstRTSPStream + * @address: an address + * @port: a port + * @n_ports: n_ports + * @ttl: a TTL * - * Get a specific multicast address of @stream. + * Reserve @address and @port as the address and port of @stream. * - * Returns: the #GstRTSPAddress of @stream or %NULL when no address could be - * allocated. gst_rtsp_address_free() after usage. + * Returns: the #GstRTSPAddress of @stream or %NULL when the address could be + * reserved. gst_rtsp_address_free() after usage. */ GstRTSPAddress * gst_rtsp_stream_reserve_address (GstRTSPStream * stream, From 82812988a6f37da1b19adc00ce4ccd6ac8b97cfb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 1 Jul 2013 14:45:49 +0200 Subject: [PATCH 0685/1776] stream: handle failed port allocation Allow for ipv4 or ipv6 socket allocations to fail. Only report failure if we can't allocate any family at all. Also keep track of what port families we allocated. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=703175 --- gst/rtsp-server/rtsp-stream.c | 89 ++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 920a87fe33..a9d7037ea1 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -68,10 +68,12 @@ struct _GstRTSPStreamPrivate /* server ports for sending/receiving over ipv4 */ GstRTSPRange server_port_v4; GstRTSPAddress *server_addr_v4; + gboolean have_ipv4; /* server ports for sending/receiving over ipv6 */ GstRTSPRange server_port_v6; GstRTSPAddress *server_addr_v6; + gboolean have_ipv6; /* multicast addresses */ GstRTSPAddressPool *pool; @@ -536,11 +538,12 @@ alloc_ports_one_family (GstRTSPAddressPool * pool, gint buffer_size, GInetAddress *inetaddr = NULL; GSocketAddress *rtp_sockaddr = NULL; GSocketAddress *rtcp_sockaddr = NULL; - const gchar *multisink_socket = "socket"; + const gchar *multisink_socket; - if (family == G_SOCKET_FAMILY_IPV6) { + if (family == G_SOCKET_FAMILY_IPV6) multisink_socket = "socket-v6"; - } + else + multisink_socket = "socket"; udpsrc0 = NULL; udpsrc1 = NULL; @@ -772,12 +775,15 @@ alloc_ports (GstRTSPStream * stream) { GstRTSPStreamPrivate *priv = stream->priv; - return alloc_ports_one_family (priv->pool, priv->buffer_size, + priv->have_ipv4 = alloc_ports_one_family (priv->pool, priv->buffer_size, G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, priv->udpsink, - &priv->server_port_v4, &priv->server_addr_v4) && - alloc_ports_one_family (priv->pool, priv->buffer_size, + &priv->server_port_v4, &priv->server_addr_v4); + + priv->have_ipv6 = alloc_ports_one_family (priv->pool, priv->buffer_size, G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, priv->udpsink, &priv->server_port_v6, &priv->server_addr_v6); + + return priv->have_ipv4 || priv->have_ipv6; } /** @@ -1246,28 +1252,34 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, gst_pad_link (pad, priv->recv_sink[i]); gst_object_unref (pad); - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values */ - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); - gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); - /* add udpsrc */ - gst_bin_add (bin, priv->udpsrc_v4[i]); - gst_bin_add (bin, priv->udpsrc_v6[i]); - /* and link to the funnel v4 */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); + if (priv->udpsrc_v4[i]) { + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values */ + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); + /* add udpsrc */ + gst_bin_add (bin, priv->udpsrc_v4[i]); - /* and link to the funnel v6 */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); + /* and link to the funnel v4 */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + } + + if (priv->udpsrc_v6[i]) { + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); + gst_bin_add (bin, priv->udpsrc_v6[i]); + + /* and link to the funnel v6 */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + } /* make and add appsrc */ priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); @@ -1366,16 +1378,19 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_element_set_state (priv->tee[i], GST_STATE_NULL); gst_element_set_state (priv->funnel[i], GST_STATE_NULL); gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); - /* and set udpsrc to NULL now before removing */ - gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE); - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); - gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE); - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); - - /* removing them should also nicely release the request - * pads when they finalize */ - gst_bin_remove (bin, priv->udpsrc_v4[i]); - gst_bin_remove (bin, priv->udpsrc_v6[i]); + if (priv->udpsrc_v4[i]) { + /* and set udpsrc to NULL now before removing */ + gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE); + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); + /* removing them should also nicely release the request + * pads when they finalize */ + gst_bin_remove (bin, priv->udpsrc_v4[i]); + } + if (priv->udpsrc_v6[i]) { + gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE); + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); + gst_bin_remove (bin, priv->udpsrc_v6[i]); + } gst_bin_remove (bin, priv->udpsink[i]); gst_bin_remove (bin, priv->appsrc[i]); gst_bin_remove (bin, priv->appsink[i]); From 13016309b1dddd4f89aa2300a3e0576b451d8171 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 1 Jul 2013 15:18:43 +0200 Subject: [PATCH 0686/1776] client: fix comment --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1bc83fa54b..86887c5a2c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2196,7 +2196,7 @@ gst_rtsp_client_set_connection (GstRTSPClient * client, /* ERRORS */ no_address: { - GST_ERROR ("could not get remote address %s", error->message); + GST_ERROR ("could not get local address %s", error->message); g_error_free (error); return FALSE; } From a7fe63298cd0535eda939ccb3c89d0f0d8d2bdae Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 1 Jul 2013 16:46:07 +0200 Subject: [PATCH 0687/1776] stream: add more support for IPv6 Rename _get_address to _get_multicast_address in GstRTSPStream to make it clear that this function only deals with multicast. Make it possible to have both an IPv4 and IPv6 multicast address on a stream. Give the client an IPv4 or IPv6 address depending on the address it used to connect to the server. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702002 --- gst/rtsp-server/rtsp-client.c | 5 ++- gst/rtsp-server/rtsp-stream.c | 69 ++++++++++++++++++++++++++--------- gst/rtsp-server/rtsp-stream.h | 5 ++- 3 files changed, 58 insertions(+), 21 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 86887c5a2c..7ba6466ab3 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1184,8 +1184,11 @@ default_configure_client_transport (GstRTSPClient * client, gst_rtsp_address_free (addr); } else { GstRTSPAddress *addr; + GSocketFamily family; - addr = gst_rtsp_stream_get_address (state->stream); + family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; + + addr = gst_rtsp_stream_get_multicast_address (state->stream, family); if (addr == NULL) goto no_address; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index a9d7037ea1..b5d318ff0d 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -77,7 +77,8 @@ struct _GstRTSPStreamPrivate /* multicast addresses */ GstRTSPAddressPool *pool; - GstRTSPAddress *addr; + GstRTSPAddress *addr_v4; + GstRTSPAddress *addr_v6; /* the caps of the stream */ gulong caps_sig; @@ -150,8 +151,10 @@ gst_rtsp_stream_finalize (GObject * obj) /* we really need to be unjoined now */ g_return_if_fail (!priv->is_joined); - if (priv->addr) - gst_rtsp_address_free (priv->addr); + if (priv->addr_v4) + gst_rtsp_address_free (priv->addr_v4); + if (priv->addr_v6) + gst_rtsp_address_free (priv->addr_v6); if (priv->server_addr_v4) gst_rtsp_address_free (priv->server_addr_v4); if (priv->server_addr_v6) @@ -400,35 +403,48 @@ gst_rtsp_stream_get_address_pool (GstRTSPStream * stream) } /** - * gst_rtsp_stream_get_address: + * gst_rtsp_stream_get_multicast_address: * @stream: a #GstRTSPStream + * @family: the #GSocketFamily * - * Get the multicast address of @stream. + * Get the multicast address of @stream for @family. * * Returns: the #GstRTSPAddress of @stream or %NULL when no address could be * allocated. gst_rtsp_address_free() after usage. */ GstRTSPAddress * -gst_rtsp_stream_get_address (GstRTSPStream * stream) +gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, + GSocketFamily family) { GstRTSPStreamPrivate *priv; GstRTSPAddress *result; + GstRTSPAddress **addrp; + GstRTSPAddressFlags flags; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); priv = stream->priv; + if (family == G_SOCKET_FAMILY_IPV6) { + flags = GST_RTSP_ADDRESS_FLAG_IPV6; + addrp = &priv->addr_v4; + } else { + flags = GST_RTSP_ADDRESS_FLAG_IPV4; + addrp = &priv->addr_v6; + } + g_mutex_lock (&priv->lock); - if (priv->addr == NULL) { + if (*addrp == NULL) { if (priv->pool == NULL) goto no_pool; - priv->addr = gst_rtsp_address_pool_acquire_address (priv->pool, - GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST, 2); - if (priv->addr == NULL) + flags |= GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST; + + *addrp = gst_rtsp_address_pool_acquire_address (priv->pool, flags, 2); + if (*addrp == NULL) goto no_address; } - result = gst_rtsp_address_copy (priv->addr); + result = gst_rtsp_address_copy (*addrp); g_mutex_unlock (&priv->lock); return result; @@ -467,6 +483,9 @@ gst_rtsp_stream_reserve_address (GstRTSPStream * stream, { GstRTSPStreamPrivate *priv; GstRTSPAddress *result; + GInetAddress *addr; + GSocketFamily family; + GstRTSPAddress **addrp; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); g_return_val_if_fail (address != NULL, NULL); @@ -476,22 +495,36 @@ gst_rtsp_stream_reserve_address (GstRTSPStream * stream, priv = stream->priv; + addr = g_inet_address_new_from_string (address); + if (!addr) { + GST_ERROR ("failed to get inet addr from %s", address); + family = G_SOCKET_FAMILY_IPV4; + } else { + family = g_inet_address_get_family (addr); + g_object_unref (addr); + } + + if (family == G_SOCKET_FAMILY_IPV6) + addrp = &priv->addr_v4; + else + addrp = &priv->addr_v6; + g_mutex_lock (&priv->lock); - if (priv->addr == NULL) { + if (*addrp == NULL) { if (priv->pool == NULL) goto no_pool; - priv->addr = gst_rtsp_address_pool_reserve_address (priv->pool, address, + *addrp = gst_rtsp_address_pool_reserve_address (priv->pool, address, port, n_ports, ttl); - if (priv->addr == NULL) + if (*addrp == NULL) goto no_address; } else { - if (strcmp (priv->addr->address, address) || - priv->addr->port != port || priv->addr->n_ports != n_ports || - priv->addr->ttl != ttl) + if (strcmp ((*addrp)->address, address) || + (*addrp)->port != port || (*addrp)->n_ports != n_ports || + (*addrp)->ttl != ttl) goto different_address; } - result = gst_rtsp_address_copy (priv->addr); + result = gst_rtsp_address_copy (*addrp); g_mutex_unlock (&priv->lock); return result; diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 1060a05182..a2a66b4b58 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -77,8 +77,6 @@ void gst_rtsp_stream_set_address_pool (GstRTSPStream *stream, GstRT GstRTSPAddressPool * gst_rtsp_stream_get_address_pool (GstRTSPStream *stream); -GstRTSPAddress * gst_rtsp_stream_get_address (GstRTSPStream *stream); - GstRTSPAddress * gst_rtsp_stream_reserve_address (GstRTSPStream *stream, const gchar * address, guint port, @@ -94,6 +92,9 @@ gboolean gst_rtsp_stream_leave_bin (GstRTSPStream *stream, void gst_rtsp_stream_get_server_port (GstRTSPStream *stream, GstRTSPRange *server_port, GSocketFamily family); +GstRTSPAddress * gst_rtsp_stream_get_multicast_address (GstRTSPStream *stream, + GSocketFamily family); + GObject * gst_rtsp_stream_get_rtpsession (GstRTSPStream *stream); From 0248775c74ef60d1b6feffc41a23f60b6238e629 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 2 Jul 2013 11:58:02 +0200 Subject: [PATCH 0688/1776] client: cleanups Rename variables for clarity Keep media in state when we can --- gst/rtsp-server/rtsp-client.c | 71 +++++++++++++++++------------------ 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 7ba6466ab3..03bd4e38e1 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -105,7 +105,7 @@ static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media); static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session); static void unlink_session_transports (GstRTSPClient * client, - GstRTSPSession * session, GstRTSPSessionMedia * media); + GstRTSPSession * session, GstRTSPSessionMedia * sessmedia); static gboolean default_configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state, GstRTSPTransport * ct); static GstRTSPResult default_params_set (GstRTSPClient * client, @@ -230,13 +230,13 @@ gst_rtsp_client_init (GstRTSPClient * client) } static GstRTSPFilterResult -filter_session (GstRTSPSession * sess, GstRTSPSessionMedia * media, +filter_session (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); - gst_rtsp_session_media_set_state (media, GST_STATE_NULL); - unlink_session_transports (client, sess, media); + gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL); + unlink_session_transports (client, sess, sessmedia); /* unmanage the media in the session */ return GST_RTSP_FILTER_REMOVE; @@ -649,18 +649,18 @@ unlink_transport (GstRTSPClient * client, GstRTSPSession * session, static void unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, - GstRTSPSessionMedia * media) + GstRTSPSessionMedia * sessmedia) { guint n_streams, i; n_streams = - gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (media)); + gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (sessmedia)); for (i = 0; i < n_streams; i++) { GstRTSPStreamTransport *trans; const GstRTSPTransport *tr; /* get the transport, if there is no transport configured, skip this stream */ - trans = gst_rtsp_session_media_get_transport (media, i); + trans = gst_rtsp_session_media_get_transport (sessmedia, i); if (trans == NULL) continue; @@ -696,7 +696,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPClientPrivate *priv = client->priv; GstRTSPSession *session; - GstRTSPSessionMedia *media; + GstRTSPSessionMedia *sessmedia; GstRTSPStatusCode code; if (!state->session) @@ -708,27 +708,27 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) goto no_uri; /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, state->uri); - if (!media) + sessmedia = gst_rtsp_session_get_media (session, state->uri); + if (!sessmedia) goto not_found; - state->sessmedia = media; + state->sessmedia = sessmedia; /* we emit the signal before closing the connection */ g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], 0, state); /* unlink the all TCP callbacks */ - unlink_session_transports (client, session, media); + unlink_session_transports (client, session, sessmedia); /* remove the session from the watched sessions */ client_unwatch_session (client, session); - gst_rtsp_session_media_set_state (media, GST_STATE_NULL); + gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL); /* unmanage the media in the session, returns false if all media session * are torn down. */ - if (!gst_rtsp_session_release_media (session, media)) { + if (!gst_rtsp_session_release_media (session, sessmedia)) { /* remove the session */ gst_rtsp_session_pool_remove (priv->session_pool, session); } @@ -860,7 +860,7 @@ static gboolean handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPSession *session; - GstRTSPSessionMedia *media; + GstRTSPSessionMedia *sessmedia; GstRTSPStatusCode code; GstRTSPState rtspstate; @@ -871,23 +871,23 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) goto no_uri; /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, state->uri); - if (!media) + sessmedia = gst_rtsp_session_get_media (session, state->uri); + if (!sessmedia) goto not_found; - state->sessmedia = media; + state->sessmedia = sessmedia; - rtspstate = gst_rtsp_session_media_get_rtsp_state (media); + rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); /* the session state must be playing or recording */ if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_RECORDING) goto invalid_state; /* unlink the all TCP callbacks */ - unlink_session_transports (client, session, media); + unlink_session_transports (client, session, sessmedia); /* then pause sending */ - gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED); + gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PAUSED); /* construct the response now */ code = GST_RTSP_STS_OK; @@ -897,7 +897,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) send_message (client, session, state->response, FALSE); /* the state is now READY */ - gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_READY); + gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST], 0, state); @@ -936,7 +936,8 @@ static gboolean handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPSession *session; - GstRTSPSessionMedia *media; + GstRTSPSessionMedia *sessmedia; + GstRTSPMedia *media; GstRTSPStatusCode code; GString *rtpinfo; guint n_streams, i, infocount; @@ -953,14 +954,15 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) goto no_uri; /* get a handle to the configuration of the media in the session */ - media = gst_rtsp_session_get_media (session, state->uri); - if (!media) + sessmedia = gst_rtsp_session_get_media (session, state->uri); + if (!sessmedia) goto not_found; - state->sessmedia = media; + state->sessmedia = sessmedia; + state->media = media = gst_rtsp_session_media_get_media (sessmedia); /* the session state must be playing or ready */ - rtspstate = gst_rtsp_session_media_get_rtsp_state (media); + rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY) goto invalid_state; @@ -971,7 +973,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) { /* we have a range, seek to the position */ unit = range->unit; - gst_rtsp_media_seek (gst_rtsp_session_media_get_media (media), range); + gst_rtsp_media_seek (media, range); gst_rtsp_range_free (range); } } @@ -979,8 +981,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) /* grab RTPInfo from the payloaders now */ rtpinfo = g_string_new (""); - n_streams = - gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (media)); + n_streams = gst_rtsp_media_n_streams (media); for (i = 0, infocount = 0; i < n_streams; i++) { GstRTSPStreamTransport *trans; GstRTSPStream *stream; @@ -989,7 +990,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) guint rtptime, seq; /* get the transport, if there is no transport configured, skip this stream */ - trans = gst_rtsp_session_media_get_transport (media, i); + trans = gst_rtsp_session_media_get_transport (sessmedia, i); if (trans == NULL) { GST_INFO ("stream %d is not configured", i); continue; @@ -1031,17 +1032,15 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) } /* add the range */ - str = - gst_rtsp_media_get_range_string (gst_rtsp_session_media_get_media (media), - TRUE, unit); + str = gst_rtsp_media_get_range_string (media, TRUE, unit); gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str); send_message (client, session, state->response, FALSE); /* start playing after sending the request */ - gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING); + gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING); - gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_PLAYING); + gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST], 0, state); From 2ffb0f69d25f9fef70be3a1891588078574e6c2b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 2 Jul 2013 14:44:35 +0200 Subject: [PATCH 0689/1776] stream: add methods and property to set control string --- gst/rtsp-server/rtsp-stream.c | 99 ++++++++++++++++++++++++++++++++++- gst/rtsp-server/rtsp-stream.h | 3 ++ 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index b5d318ff0d..8e5e141b47 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -38,6 +38,7 @@ struct _GstRTSPStreamPrivate GstElement *payloader; guint buffer_size; gboolean is_joined; + gchar *control; /* pads on the rtpbin */ GstPad *send_rtp_sink; @@ -91,10 +92,12 @@ struct _GstRTSPStreamPrivate gint dscp_qos; }; +#define DEFAULT_CONTROL NULL enum { PROP_0, + PROP_CONTROL, PROP_LAST }; @@ -103,6 +106,11 @@ GST_DEBUG_CATEGORY_STATIC (rtsp_stream_debug); static GQuark ssrc_stream_map_key; +static void gst_rtsp_stream_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec); +static void gst_rtsp_stream_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec); + static void gst_rtsp_stream_finalize (GObject * obj); G_DEFINE_TYPE (GstRTSPStream, gst_rtsp_stream, G_TYPE_OBJECT); @@ -116,8 +124,15 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) gobject_class = G_OBJECT_CLASS (klass); + gobject_class->get_property = gst_rtsp_stream_get_property; + gobject_class->set_property = gst_rtsp_stream_set_property; gobject_class->finalize = gst_rtsp_stream_finalize; + g_object_class_install_property (gobject_class, PROP_CONTROL, + g_param_spec_string ("control", "Control", + "The control string for this stream", DEFAULT_CONTROL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_DEBUG_CATEGORY_INIT (rtsp_stream_debug, "rtspstream", 0, "GstRTSPStream"); ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); @@ -132,7 +147,8 @@ gst_rtsp_stream_init (GstRTSPStream * stream) stream->priv = priv; - stream->priv->dscp_qos = -1; + priv->dscp_qos = -1; + priv->control = g_strdup (DEFAULT_CONTROL); g_mutex_init (&priv->lock); } @@ -163,11 +179,42 @@ gst_rtsp_stream_finalize (GObject * obj) g_object_unref (priv->pool); gst_object_unref (priv->payloader); gst_object_unref (priv->srcpad); + g_free (priv->control); g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); } +static void +gst_rtsp_stream_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec) +{ + GstRTSPStream *stream = GST_RTSP_STREAM (object); + + switch (propid) { + case PROP_CONTROL: + g_value_take_string (value, gst_rtsp_stream_get_control (stream)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static void +gst_rtsp_stream_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec) +{ + GstRTSPStream *stream = GST_RTSP_STREAM (object); + + switch (propid) { + case PROP_CONTROL: + gst_rtsp_stream_set_control (stream, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + /** * gst_rtsp_stream_new: * @idx: an index @@ -214,7 +261,7 @@ gst_rtsp_stream_get_index (GstRTSPStream * stream) return stream->priv->idx; } - /** +/** * gst_rtsp_stream_get_srcpad: * @stream: a #GstRTSPStream * @@ -230,6 +277,54 @@ gst_rtsp_stream_get_srcpad (GstRTSPStream * stream) return gst_object_ref (stream->priv->srcpad); } +/** + * gst_rtsp_stream_get_control: + * @stream: a #GstRTSPStream + * + * Get the control string to identify this stream. + * + * Return: the control string. free after usage. + */ +gchar * +gst_rtsp_stream_get_control (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + gchar *result; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if ((result = g_strdup (priv->control)) == NULL) + result = g_strdup_printf ("stream=%d", priv->idx); + g_mutex_unlock (&priv->lock); + + return result; +} + +/** + * gst_rtsp_stream_set_control: + * @stream: a #GstRTSPStream + * @control: a control string + * + * Set the control string in @stream. + */ +void +gst_rtsp_stream_set_control (GstRTSPStream * stream, const gchar * control) +{ + GstRTSPStreamPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + g_free (priv->control); + priv->control = g_strdup (control); + g_mutex_unlock (&priv->lock); +} + /** * gst_rtsp_stream_set_mtu: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index a2a66b4b58..a4c893a658 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -67,6 +67,9 @@ GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement *paylo guint gst_rtsp_stream_get_index (GstRTSPStream *stream); GstPad * gst_rtsp_stream_get_srcpad (GstRTSPStream *stream); +void gst_rtsp_stream_set_control (GstRTSPStream *stream, const gchar *control); +gchar * gst_rtsp_stream_get_control (GstRTSPStream *stream); + void gst_rtsp_stream_set_mtu (GstRTSPStream *stream, guint mtu); guint gst_rtsp_stream_get_mtu (GstRTSPStream *stream); From 714e84d891137c5b9c9767375d3eb5a20fe0e3b0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 2 Jul 2013 15:54:43 +0200 Subject: [PATCH 0690/1776] sdp: get control string from stream Use the control string as configured in the stream. --- gst/rtsp-server/rtsp-sdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 399367a245..5dfec79d97 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -154,7 +154,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, } /* the config uri */ - tmp = g_strdup_printf ("stream=%d", i); + tmp = gst_rtsp_stream_get_control (stream); gst_sdp_media_add_attribute (smedia, "control", tmp); g_free (tmp); From b2f44fd4dbc5da85132e0f549517bc86db6acf78 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 2 Jul 2013 15:59:16 +0200 Subject: [PATCH 0691/1776] tests: fix compilation --- tests/check/gst/mediafactory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/check/gst/mediafactory.c b/tests/check/gst/mediafactory.c index 75667cf547..ab791cd427 100644 --- a/tests/check/gst/mediafactory.c +++ b/tests/check/gst/mediafactory.c @@ -178,7 +178,7 @@ GST_START_TEST (test_addresspool) fail_unless (pool == tmppool); g_object_unref (tmppool); - addr = gst_rtsp_stream_get_address (stream); + addr = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV4); fail_unless (addr != NULL); fail_unless (addr->port == 5000); fail_unless (addr->n_ports == 2); @@ -192,7 +192,7 @@ GST_START_TEST (test_addresspool) fail_unless (pool == tmppool); g_object_unref (tmppool); - addr = gst_rtsp_stream_get_address (stream); + addr = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV4); fail_unless (addr == NULL); From a22889ac082ec68cecd974cb9dbac926dc749478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 3 Jul 2013 10:40:33 +0200 Subject: [PATCH 0692/1776] rtsp-server: Allow building of static library --- gst/rtsp-server/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 2f9dfc62af..353ab27503 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -49,7 +49,6 @@ libgstrtspserver_@GST_API_VERSION@_la_LIBADD = \ -lgstsdp-@GST_API_VERSION@ \ -lgstapp-@GST_API_VERSION@ \ $(GST_LIBS) $(GIO_LIBS) $(LIBM) -libgstrtspserver_@GST_API_VERSION@_la_LIBTOOLFLAGS = --tag=disable-static libgstrtspserver_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/rtsp-server libgstrtspserver_@GST_API_VERSION@include_HEADERS = $(public_headers) From df08a2dd9e70c490e03e45b5dbc7ef69a1b423c9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 3 Jul 2013 10:25:46 +0200 Subject: [PATCH 0693/1776] mount-points: improve mount point searching Use a GSequence to keep track of the mount points. Match a URL to the longest matching registered mount point. This should be the URL to perform aggreagate control and the remainder is the stream specific control part. Add some unit tests for this. --- gst/rtsp-server/rtsp-mount-points.c | 185 +++++++++++++++++++++++++--- gst/rtsp-server/rtsp-mount-points.h | 17 ++- tests/check/gst/mountpoints.c | 61 +++++++++ 3 files changed, 238 insertions(+), 25 deletions(-) diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 3d3b61c392..a8db8b3681 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -17,15 +17,67 @@ * Boston, MA 02110-1301, USA. */ +#include + #include "rtsp-mount-points.h" #define GST_RTSP_MOUNT_POINTS_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MOUNT_POINTS, GstRTSPMountPointsPrivate)) +typedef struct +{ + gchar *path; + gint len; + GstRTSPMediaFactory *factory; +} DataItem; + +static DataItem * +data_item_new (gchar * path, gint len, GstRTSPMediaFactory * factory) +{ + DataItem *item; + + item = g_slice_alloc (sizeof (DataItem)); + item->path = path; + item->len = len; + item->factory = factory; + + return item; +} + +static void +data_item_free (gpointer data) +{ + DataItem *item = data; + + g_free (item->path); + g_object_unref (item->factory); + g_slice_free1 (sizeof (DataItem), item); +} + +static void +data_item_dump (gconstpointer a, gpointer prefix) +{ + const DataItem *item = a; + + GST_DEBUG ("%s%s %p\n", (gchar *) prefix, item->path, item->factory); +} + +static gint +data_item_compare (gconstpointer a, gconstpointer b, gpointer user_data) +{ + const DataItem *item1 = a, *item2 = b; + gint res; + + res = g_strcmp0 (item1->path, item2->path); + + return res; +} + struct _GstRTSPMountPointsPrivate { GMutex lock; - GHashTable *mounts; /* protected by lock */ + GSequence *mounts; /* protected by lock */ + gboolean dirty; }; G_DEFINE_TYPE (GstRTSPMountPoints, gst_rtsp_mount_points, G_TYPE_OBJECT); @@ -65,8 +117,8 @@ gst_rtsp_mount_points_init (GstRTSPMountPoints * mounts) mounts->priv = priv; g_mutex_init (&priv->lock); - priv->mounts = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); + priv->mounts = g_sequence_new (data_item_free); + priv->dirty = FALSE; } static void @@ -77,7 +129,7 @@ gst_rtsp_mount_points_finalize (GObject * obj) GST_DEBUG_OBJECT (mounts, "finalized"); - g_hash_table_unref (priv->mounts); + g_sequence_free (priv->mounts); g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_mount_points_parent_class)->finalize (obj); @@ -103,21 +155,10 @@ gst_rtsp_mount_points_new (void) static GstRTSPMediaFactory * find_factory (GstRTSPMountPoints * mounts, const GstRTSPUrl * url) { - GstRTSPMountPointsPrivate *priv = mounts->priv; - GstRTSPMediaFactory *result; + g_return_val_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts), NULL); + g_return_val_if_fail (url != NULL, NULL); - g_mutex_lock (&priv->lock); - /* find the location of the media in the hashtable we only use the absolute - * path of the uri to find a media factory. If the factory depends on other - * properties found in the url, this method should be overridden. */ - result = g_hash_table_lookup (priv->mounts, url->abspath); - if (result) - g_object_ref (result); - g_mutex_unlock (&priv->lock); - - GST_INFO ("found media factory %p for url abspath %s", result, url->abspath); - - return result; + return gst_rtsp_mount_points_match (mounts, url->abspath, NULL); } /** @@ -150,6 +191,98 @@ gst_rtsp_mount_points_find_factory (GstRTSPMountPoints * mounts, return result; } +static gboolean +has_prefix (DataItem * str, DataItem * prefix) +{ + /* prefix needs to be smaller than str */ + if (str->len < prefix->len) + return FALSE; + + /* if str is larger, it there should be a / following the prefix */ + if (str->len > prefix->len && str->path[prefix->len] != '/') + return FALSE; + + return strncmp (str->path, prefix->path, prefix->len) == 0; +} + +/** + * gst_rtsp_mount_points_match: + * @mounts: a #GstRTSPMountPoints + * @path: a mount point + * @matched: the amount of @path matched + * + * Find the factory in @mounts that has the longest match with @path. + * + * If @matched is NULL, @path willt match the factory exactly otherwise + * the amount of characters that matched is returned in @matched. + * + * Returns: (transfer full): the #GstRTSPMediaFactory for @path. + * g_object_unref() after usage. + */ +GstRTSPMediaFactory * +gst_rtsp_mount_points_match (GstRTSPMountPoints * mounts, + const gchar * path, gint * matched) +{ + GstRTSPMountPointsPrivate *priv; + GstRTSPMediaFactory *result = NULL; + GSequenceIter *iter, *best; + DataItem item, *ritem; + + g_return_val_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts), NULL); + g_return_val_if_fail (path != NULL, NULL); + + priv = mounts->priv; + + item.path = (gchar *) path; + item.len = strlen (path); + + g_mutex_lock (&priv->lock); + if (priv->dirty) { + g_sequence_sort (priv->mounts, data_item_compare, mounts); + g_sequence_foreach (priv->mounts, (GFunc) data_item_dump, "sort :"); + priv->dirty = FALSE; + } + + /* find the location of the media in the hashtable we only use the absolute + * path of the uri to find a media factory. If the factory depends on other + * properties found in the url, this method should be overridden. */ + iter = g_sequence_get_begin_iter (priv->mounts); + best = NULL; + while (!g_sequence_iter_is_end (iter)) { + ritem = g_sequence_get (iter); + + data_item_dump (ritem, "inspect: "); + + if (best == NULL) { + if (has_prefix (&item, ritem)) { + data_item_dump (ritem, "prefix: "); + best = iter; + } + } else { + if (!has_prefix (&item, ritem)) + break; + + best = iter; + data_item_dump (ritem, "new best: "); + } + iter = g_sequence_iter_next (iter); + } + if (best) { + ritem = g_sequence_get (best); + data_item_dump (ritem, "result: "); + if (matched || ritem->len == item.len) { + result = g_object_ref (ritem->factory); + if (matched) + *matched = ritem->len; + } + } + g_mutex_unlock (&priv->lock); + + GST_INFO ("found media factory %p for path %s", result, path); + + return result; +} + /** * gst_rtsp_mount_points_add_factory: * @mounts: a #GstRTSPMountPoints @@ -168,6 +301,7 @@ gst_rtsp_mount_points_add_factory (GstRTSPMountPoints * mounts, const gchar * path, GstRTSPMediaFactory * factory) { GstRTSPMountPointsPrivate *priv; + DataItem *item; g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts)); g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); @@ -175,8 +309,11 @@ gst_rtsp_mount_points_add_factory (GstRTSPMountPoints * mounts, priv = mounts->priv; + item = data_item_new (g_strdup (path), strlen (path), factory); + g_mutex_lock (&priv->lock); - g_hash_table_insert (priv->mounts, g_strdup (path), factory); + g_sequence_append (priv->mounts, item); + priv->dirty = TRUE; g_mutex_unlock (&priv->lock); } @@ -192,13 +329,21 @@ gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints * mounts, const gchar * path) { GstRTSPMountPointsPrivate *priv; + DataItem item; + GSequenceIter *iter; g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts)); g_return_if_fail (path != NULL); priv = mounts->priv; + item.path = (gchar *) path; + g_mutex_lock (&priv->lock); - g_hash_table_remove (priv->mounts, path); + iter = g_sequence_lookup (priv->mounts, &item, data_item_compare, mounts); + if (iter) { + g_sequence_remove (iter); + priv->dirty = TRUE; + } g_mutex_unlock (&priv->lock); } diff --git a/gst/rtsp-server/rtsp-mount-points.h b/gst/rtsp-server/rtsp-mount-points.h index d8dd1b8ea8..2aae3010cf 100644 --- a/gst/rtsp-server/rtsp-mount-points.h +++ b/gst/rtsp-server/rtsp-mount-points.h @@ -66,7 +66,8 @@ struct _GstRTSPMountPoints { struct _GstRTSPMountPointsClass { GObjectClass parent_class; - GstRTSPMediaFactory * (*find_factory) (GstRTSPMountPoints *mounts, const GstRTSPUrl *url); + GstRTSPMediaFactory * (*find_factory) (GstRTSPMountPoints *mounts, + const GstRTSPUrl *url); }; GType gst_rtsp_mount_points_get_type (void); @@ -74,13 +75,19 @@ GType gst_rtsp_mount_points_get_type (void); /* creating a mount points */ GstRTSPMountPoints * gst_rtsp_mount_points_new (void); -/* finding a media factory */ -GstRTSPMediaFactory * gst_rtsp_mount_points_find_factory (GstRTSPMountPoints *mounts, const GstRTSPUrl *url); +GstRTSPMediaFactory * gst_rtsp_mount_points_find_factory (GstRTSPMountPoints *mounts, + const GstRTSPUrl *url); +GstRTSPMediaFactory * gst_rtsp_mount_points_match (GstRTSPMountPoints *mounts, + const gchar *path, + gint * matched); +/* finding a media factory */ /* managing media to a mount point */ -void gst_rtsp_mount_points_add_factory (GstRTSPMountPoints *mounts, const gchar *path, +void gst_rtsp_mount_points_add_factory (GstRTSPMountPoints *mounts, + const gchar *path, GstRTSPMediaFactory *factory); -void gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints *mounts, const gchar *path); +void gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints *mounts, + const gchar *path); G_END_DECLS diff --git a/tests/check/gst/mountpoints.c b/tests/check/gst/mountpoints.c index 209975d9d0..e620f1611c 100644 --- a/tests/check/gst/mountpoints.c +++ b/tests/check/gst/mountpoints.c @@ -56,6 +56,66 @@ GST_START_TEST (test_create) GST_END_TEST; +static const gchar *paths[] = { + "/test", + "/booz/fooz", + "/booz/foo/zoop", + "/tark/bar", + "/tark/bar/baz", + "/tark/bar/baz/t", + "/boozop", +}; + +GST_START_TEST (test_match) +{ + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *f[G_N_ELEMENTS (paths)], *tmp; + gint i, matched; + + mounts = gst_rtsp_mount_points_new (); + + for (i = 0; i < G_N_ELEMENTS (paths); i++) { + f[i] = gst_rtsp_media_factory_new (); + gst_rtsp_mount_points_add_factory (mounts, paths[i], f[i]); + } + + tmp = gst_rtsp_mount_points_match (mounts, "/test", &matched); + fail_unless (tmp == f[0]); + fail_unless (matched == 5); + tmp = gst_rtsp_mount_points_match (mounts, "/test/stream=1", &matched); + fail_unless (tmp == f[0]); + fail_unless (matched == 5); + tmp = gst_rtsp_mount_points_match (mounts, "/booz", &matched); + fail_unless (tmp == NULL); + tmp = gst_rtsp_mount_points_match (mounts, "/booz/foo", &matched); + fail_unless (tmp == NULL); + tmp = gst_rtsp_mount_points_match (mounts, "/booz/fooz", &matched); + fail_unless (tmp == f[1]); + fail_unless (matched == 10); + tmp = gst_rtsp_mount_points_match (mounts, "/booz/fooz/zoo", &matched); + fail_unless (tmp == f[1]); + fail_unless (matched == 10); + tmp = gst_rtsp_mount_points_match (mounts, "/booz/foo/zoop", &matched); + fail_unless (tmp == f[2]); + fail_unless (matched == 14); + tmp = gst_rtsp_mount_points_match (mounts, "/tark/bar", &matched); + fail_unless (tmp == f[3]); + fail_unless (matched == 9); + tmp = gst_rtsp_mount_points_match (mounts, "/tark/bar/boo", &matched); + fail_unless (tmp == f[3]); + fail_unless (matched == 9); + tmp = gst_rtsp_mount_points_match (mounts, "/tark/bar/ba", &matched); + fail_unless (tmp == f[3]); + fail_unless (matched == 9); + tmp = gst_rtsp_mount_points_match (mounts, "/tark/bar/baz", &matched); + fail_unless (tmp == f[4]); + fail_unless (matched == 13); + + g_object_unref (mounts); +} + +GST_END_TEST; + static Suite * rtspmountpoints_suite (void) { @@ -65,6 +125,7 @@ rtspmountpoints_suite (void) suite_add_tcase (s, tc); tcase_set_timeout (tc, 20); tcase_add_test (tc, test_create); + tcase_add_test (tc, test_match); return s; } From 8f79daef5e007ecc2e32bf1fac53dca9e94dc7ec Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 3 Jul 2013 11:04:53 +0200 Subject: [PATCH 0694/1776] mount-points: remove useless vmethod Making lookups in the mount points should not be done with a URL, if there is a mapping to be done from URL to mount points, we'll need to do it somewhere else. --- gst/rtsp-server/rtsp-client.c | 4 +-- gst/rtsp-server/rtsp-mount-points.c | 44 ----------------------------- gst/rtsp-server/rtsp-mount-points.h | 10 +------ tests/check/gst/mountpoints.c | 15 ++++++---- 4 files changed, 13 insertions(+), 60 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 03bd4e38e1..b61efaa62c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -503,8 +503,8 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) /* find the factory for the uri first */ if (!(factory = - gst_rtsp_mount_points_find_factory (priv->mount_points, - state->uri))) + gst_rtsp_mount_points_match (priv->mount_points, + state->uri->abspath, NULL))) goto no_factory; /* check if we have access to the factory */ diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index a8db8b3681..9df3c757dc 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -87,9 +87,6 @@ GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug); static void gst_rtsp_mount_points_finalize (GObject * obj); -static GstRTSPMediaFactory *find_factory (GstRTSPMountPoints * mounts, - const GstRTSPUrl * url); - static void gst_rtsp_mount_points_class_init (GstRTSPMountPointsClass * klass) { @@ -101,8 +98,6 @@ gst_rtsp_mount_points_class_init (GstRTSPMountPointsClass * klass) gobject_class->finalize = gst_rtsp_mount_points_finalize; - klass->find_factory = find_factory; - GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmountpoints", 0, "GstRTSPMountPoints"); } @@ -152,45 +147,6 @@ gst_rtsp_mount_points_new (void) return result; } -static GstRTSPMediaFactory * -find_factory (GstRTSPMountPoints * mounts, const GstRTSPUrl * url) -{ - g_return_val_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts), NULL); - g_return_val_if_fail (url != NULL, NULL); - - return gst_rtsp_mount_points_match (mounts, url->abspath, NULL); -} - -/** - * gst_rtsp_mount_points_find_factory: - * @mounts: a #GstRTSPMountPoints - * @url: a url - * - * Find the #GstRTSPMediaFactory for @url. The default implementation of this object - * will use the media factory added with gst_rtsp_mount_points_add_factory (). - * - * Returns: (transfer full): the #GstRTSPMediaFactory for @url. g_object_unref() after usage. - */ -GstRTSPMediaFactory * -gst_rtsp_mount_points_find_factory (GstRTSPMountPoints * mounts, - const GstRTSPUrl * url) -{ - GstRTSPMediaFactory *result; - GstRTSPMountPointsClass *klass; - - g_return_val_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts), NULL); - g_return_val_if_fail (url != NULL, NULL); - - klass = GST_RTSP_MOUNT_POINTS_GET_CLASS (mounts); - - if (klass->find_factory) - result = klass->find_factory (mounts, url); - else - result = NULL; - - return result; -} - static gboolean has_prefix (DataItem * str, DataItem * prefix) { diff --git a/gst/rtsp-server/rtsp-mount-points.h b/gst/rtsp-server/rtsp-mount-points.h index 2aae3010cf..b57c041f58 100644 --- a/gst/rtsp-server/rtsp-mount-points.h +++ b/gst/rtsp-server/rtsp-mount-points.h @@ -19,8 +19,6 @@ #include -#include - #include "rtsp-media-factory.h" #ifndef __GST_RTSP_MOUNT_POINTS_H__ @@ -65,9 +63,6 @@ struct _GstRTSPMountPoints { */ struct _GstRTSPMountPointsClass { GObjectClass parent_class; - - GstRTSPMediaFactory * (*find_factory) (GstRTSPMountPoints *mounts, - const GstRTSPUrl *url); }; GType gst_rtsp_mount_points_get_type (void); @@ -75,13 +70,10 @@ GType gst_rtsp_mount_points_get_type (void); /* creating a mount points */ GstRTSPMountPoints * gst_rtsp_mount_points_new (void); -GstRTSPMediaFactory * gst_rtsp_mount_points_find_factory (GstRTSPMountPoints *mounts, - const GstRTSPUrl *url); - +/* finding a media factory */ GstRTSPMediaFactory * gst_rtsp_mount_points_match (GstRTSPMountPoints *mounts, const gchar *path, gint * matched); -/* finding a media factory */ /* managing media to a mount point */ void gst_rtsp_mount_points_add_factory (GstRTSPMountPoints *mounts, const gchar *path, diff --git a/tests/check/gst/mountpoints.c b/tests/check/gst/mountpoints.c index e620f1611c..7099604d30 100644 --- a/tests/check/gst/mountpoints.c +++ b/tests/check/gst/mountpoints.c @@ -34,19 +34,24 @@ GST_START_TEST (test_create) fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test2", &url2) == GST_RTSP_OK); - fail_unless (gst_rtsp_mount_points_find_factory (mounts, url) == NULL); + fail_unless (gst_rtsp_mount_points_match (mounts, url->abspath, + NULL) == NULL); factory = gst_rtsp_media_factory_new (); gst_rtsp_mount_points_add_factory (mounts, "/test", factory); - fail_unless (gst_rtsp_mount_points_find_factory (mounts, url) == factory); + fail_unless (gst_rtsp_mount_points_match (mounts, url->abspath, + NULL) == factory); g_object_unref (factory); - fail_unless (gst_rtsp_mount_points_find_factory (mounts, url2) == NULL); + fail_unless (gst_rtsp_mount_points_match (mounts, url2->abspath, + NULL) == NULL); gst_rtsp_mount_points_remove_factory (mounts, "/test"); - fail_unless (gst_rtsp_mount_points_find_factory (mounts, url) == NULL); - fail_unless (gst_rtsp_mount_points_find_factory (mounts, url2) == NULL); + fail_unless (gst_rtsp_mount_points_match (mounts, url->abspath, + NULL) == NULL); + fail_unless (gst_rtsp_mount_points_match (mounts, url2->abspath, + NULL) == NULL); gst_rtsp_url_free (url); gst_rtsp_url_free (url2); From 5a833f503eb22a25b73646d9a82ecc3f0e9406f9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 3 Jul 2013 12:37:48 +0200 Subject: [PATCH 0695/1776] session: use path matching for session media Use a path string instead of a uri to lookup session media in the sessions. Also use path matching to find the largest possible path that matches. --- gst/rtsp-server/rtsp-client.c | 28 +++++++++++---- gst/rtsp-server/rtsp-session-media.c | 53 +++++++++++++++++++--------- gst/rtsp-server/rtsp-session-media.h | 15 +++----- gst/rtsp-server/rtsp-session.c | 40 +++++++++++++-------- gst/rtsp-server/rtsp-session.h | 5 +-- 5 files changed, 92 insertions(+), 49 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b61efaa62c..09d6daceb5 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -502,8 +502,7 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) goto no_mount_points; /* find the factory for the uri first */ - if (!(factory = - gst_rtsp_mount_points_match (priv->mount_points, + if (!(factory = gst_rtsp_mount_points_match (priv->mount_points, state->uri->abspath, NULL))) goto no_factory; @@ -698,6 +697,8 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; GstRTSPStatusCode code; + const gchar *path; + gint matched; if (!state->session) goto no_session; @@ -707,8 +708,10 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) if (!state->uri) goto no_uri; + path = state->uri->abspath; + /* get a handle to the configuration of the media in the session */ - sessmedia = gst_rtsp_session_get_media (session, state->uri); + sessmedia = gst_rtsp_session_get_media (session, path, &matched); if (!sessmedia) goto not_found; @@ -863,6 +866,8 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPSessionMedia *sessmedia; GstRTSPStatusCode code; GstRTSPState rtspstate; + const gchar *path; + gint matched; if (!(session = state->session)) goto no_session; @@ -870,8 +875,10 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) if (!state->uri) goto no_uri; + path = state->uri->abspath; + /* get a handle to the configuration of the media in the session */ - sessmedia = gst_rtsp_session_get_media (session, state->uri); + sessmedia = gst_rtsp_session_get_media (session, path, &matched); if (!sessmedia) goto not_found; @@ -946,6 +953,8 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPResult res; GstRTSPState rtspstate; GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT; + const gchar *path; + gint matched; if (!(session = state->session)) goto no_session; @@ -953,8 +962,10 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) if (!state->uri) goto no_uri; + path = state->uri->abspath; + /* get a handle to the configuration of the media in the session */ - sessmedia = gst_rtsp_session_get_media (session, state->uri); + sessmedia = gst_rtsp_session_get_media (session, path, &matched); if (!sessmedia) goto not_found; @@ -1290,11 +1301,14 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPStream *stream; GstRTSPState rtspstate; GstRTSPClientClass *klass; + const gchar *path; + gint matched; if (!state->uri) goto no_uri; uri = state->uri; + path = state->uri->abspath; /* the uri contains the stream number we added in the SDP config, which is * always /stream=%d so we need to strip that off @@ -1340,7 +1354,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) g_object_ref (session); /* get a handle to the configuration of the media in the session, this can * return NULL if this is a new url to manage in this session. */ - sessmedia = gst_rtsp_session_get_media (session, uri); + sessmedia = gst_rtsp_session_get_media (session, path, &matched); } else { /* create a session if this fails we probably reached our session limit or * something. */ @@ -1365,7 +1379,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) /* get a handle to the configuration of the media in the session */ if ((media = find_media (client, state))) { /* manage the media in our session now */ - sessmedia = gst_rtsp_session_manage_media (session, uri, media); + sessmedia = gst_rtsp_session_manage_media (session, path, media); } } diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index c475f8f481..57f4473d97 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -26,7 +26,8 @@ struct _GstRTSPSessionMediaPrivate { GMutex lock; - GstRTSPUrl *url; /* unmutable */ + gchar *path; /* unmutable */ + gint path_len; /* unmutable */ GstRTSPMedia *media; /* unmutable */ GstRTSPState state; /* protected by lock */ guint counter; /* protected by lock */ @@ -88,7 +89,7 @@ gst_rtsp_session_media_finalize (GObject * obj) g_ptr_array_unref (priv->transports); - gst_rtsp_url_free (priv->url); + g_free (priv->path); g_object_unref (priv->media); g_mutex_clear (&priv->lock); @@ -104,24 +105,24 @@ free_session_media (gpointer data) /** * gst_rtsp_session_media_new: - * @url: the #GstRTSPUrl + * @path: the path * @media: the #GstRTSPMedia * * Create a new #GstRTPSessionMedia that manages the streams - * in @media for @url. @media should be prepared. + * in @media for @path. @media should be prepared. * * Ownership is taken of @media. * * Returns: a new #GstRTSPSessionMedia. */ GstRTSPSessionMedia * -gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media) +gst_rtsp_session_media_new (const gchar * path, GstRTSPMedia * media) { GstRTSPSessionMediaPrivate *priv; GstRTSPSessionMedia *result; guint n_streams; - g_return_val_if_fail (url != NULL, NULL); + g_return_val_if_fail (path != NULL, NULL); g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); g_return_val_if_fail (gst_rtsp_media_get_status (media) == GST_RTSP_MEDIA_STATUS_PREPARED, NULL); @@ -129,7 +130,8 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media) result = g_object_new (GST_TYPE_RTSP_SESSION_MEDIA, NULL); priv = result->priv; - priv->url = gst_rtsp_url_copy ((GstRTSPUrl *) url); + priv->path = g_strdup (path); + priv->path_len = strlen (path); priv->media = media; /* prealloc the streams now, filled with NULL */ @@ -141,22 +143,41 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media) } /** - * gst_rtsp_session_media_matches_url: + * gst_rtsp_session_media_matches: * @media: a #GstRTSPSessionMedia - * @url: a #GstRTSPUrl + * @path: a path + * @matched: the amount of matched characters of @path * - * Check if the url of @media matches @url. + * Check if the path of @media matches @path. It @path matches, the amount of + * matched characters is returned in @matched. * - * Returns: %TRUE when @url matches the url of @media. + * Returns: %TRUE when @path matches the path of @media. */ gboolean -gst_rtsp_session_media_matches_url (GstRTSPSessionMedia * media, - const GstRTSPUrl * url) +gst_rtsp_session_media_matches (GstRTSPSessionMedia * media, + const gchar * path, gint * matched) { - g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE); - g_return_val_if_fail (url != NULL, FALSE); + GstRTSPSessionMediaPrivate *priv; + gint len; - return g_str_equal (media->priv->url->abspath, url->abspath); + g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE); + g_return_val_if_fail (path != NULL, FALSE); + g_return_val_if_fail (matched != NULL, FALSE); + + priv = media->priv; + len = strlen (path); + + /* path needs to be smaller than the media path */ + if (len < priv->path_len) + return FALSE; + + /* if media path is larger, it there should be a / following the path */ + if (len > priv->path_len && path[priv->path_len] != '/') + return FALSE; + + *matched = priv->path_len; + + return strncmp (path, priv->path, priv->path_len) == 0; } /** diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 167c0aaba5..2cbc60282e 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -41,14 +41,8 @@ typedef struct _GstRTSPSessionMediaPrivate GstRTSPSessionMediaPrivate; /** * GstRTSPSessionMedia: - * @url: the url of the media - * @media: the pipeline for the media - * @state: the server state - * @counter: counter for channels - * @transports: array of #GstRTSPStreamTransport with the configuration - * for the transport for each selected stream from @media. * - * State of a client session regarding a specific media identified by uri. + * State of a client session regarding a specific media identified by path. */ struct _GstRTSPSessionMedia { @@ -64,11 +58,12 @@ struct _GstRTSPSessionMediaClass GType gst_rtsp_session_media_get_type (void); -GstRTSPSessionMedia * gst_rtsp_session_media_new (const GstRTSPUrl *url, +GstRTSPSessionMedia * gst_rtsp_session_media_new (const gchar *path, GstRTSPMedia *media); -gboolean gst_rtsp_session_media_matches_url (GstRTSPSessionMedia *media, - const GstRTSPUrl *url); +gboolean gst_rtsp_session_media_matches (GstRTSPSessionMedia *media, + const gchar *path, + gint * matched); GstRTSPMedia * gst_rtsp_session_media_get_media (GstRTSPSessionMedia *media); GstClockTime gst_rtsp_session_media_get_base_time (GstRTSPSessionMedia *media); diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 87d03ffd05..fe93a5f260 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -162,10 +162,10 @@ gst_rtsp_session_set_property (GObject * object, guint propid, /** * gst_rtsp_session_manage_media: * @sess: a #GstRTSPSession - * @uri: the uri for the media + * @path: the path for the media * @media: (transfer full): a #GstRTSPMedia * - * Manage the media object @obj in @sess. @uri will be used to retrieve this + * Manage the media object @obj in @sess. @path will be used to retrieve this * media from the session with gst_rtsp_session_get_media(). * * Ownership is taken from @media. @@ -173,21 +173,21 @@ gst_rtsp_session_set_property (GObject * object, guint propid, * Returns: (transfer none): a new @GstRTSPSessionMedia object. */ GstRTSPSessionMedia * -gst_rtsp_session_manage_media (GstRTSPSession * sess, const GstRTSPUrl * uri, +gst_rtsp_session_manage_media (GstRTSPSession * sess, const gchar * path, GstRTSPMedia * media) { GstRTSPSessionPrivate *priv; GstRTSPSessionMedia *result; g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); - g_return_val_if_fail (uri != NULL, NULL); + g_return_val_if_fail (path != NULL, NULL); g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); g_return_val_if_fail (gst_rtsp_media_get_status (media) == GST_RTSP_MEDIA_STATUS_PREPARED, NULL); priv = sess->priv; - result = gst_rtsp_session_media_new (uri, media); + result = gst_rtsp_session_media_new (path, media); g_mutex_lock (&priv->lock); priv->medias = g_list_prepend (priv->medias, result); @@ -236,36 +236,48 @@ gst_rtsp_session_release_media (GstRTSPSession * sess, /** * gst_rtsp_session_get_media: * @sess: a #GstRTSPSession - * @url: the url for the media + * @path: the path for the media + * @matched: the amount of matched characters * - * Get the session media of the @url. + * Get the session media for @path. @matched will contain the number of matched + * characters of @path. * - * Returns: (transfer none): the configuration for @url in @sess. + * Returns: (transfer none): the configuration for @path in @sess. */ GstRTSPSessionMedia * -gst_rtsp_session_get_media (GstRTSPSession * sess, const GstRTSPUrl * url) +gst_rtsp_session_get_media (GstRTSPSession * sess, const gchar * path, + gint * matched) { GstRTSPSessionPrivate *priv; GstRTSPSessionMedia *result; GList *walk; + gint best; g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); - g_return_val_if_fail (url != NULL, NULL); + g_return_val_if_fail (path != NULL, NULL); priv = sess->priv; result = NULL; + best = 0; g_mutex_lock (&priv->lock); for (walk = priv->medias; walk; walk = g_list_next (walk)) { - result = (GstRTSPSessionMedia *) walk->data; + GstRTSPSessionMedia *test; - if (gst_rtsp_session_media_matches_url (result, url)) - break; + test = (GstRTSPSessionMedia *) walk->data; - result = NULL; + /* find largest match */ + if (gst_rtsp_session_media_matches (test, path, matched)) { + if (best < *matched) { + result = test; + best = *matched; + } + } } g_mutex_unlock (&priv->lock); + *matched = best; + return result; } diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 844795d27f..e206032735 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -95,13 +95,14 @@ gboolean gst_rtsp_session_is_expired (GstRTSPSession *se /* handle media in a session */ GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess, - const GstRTSPUrl *uri, + const gchar *path, GstRTSPMedia *media); gboolean gst_rtsp_session_release_media (GstRTSPSession *sess, GstRTSPSessionMedia *media); /* get media in a session */ GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, - const GstRTSPUrl *url); + const gchar *path, + gint * matched); /** * GstRTSPSessionFilterFunc: From d4e8d800c932400f859beeb1c5d5f4dcd0e90085 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 3 Jul 2013 15:13:45 +0200 Subject: [PATCH 0696/1776] stream: add method to check control url of stream --- gst/rtsp-server/rtsp-stream.c | 46 ++++++++++++++++++++++++++++++----- gst/rtsp-server/rtsp-stream.h | 1 + 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 8e5e141b47..2a91126d86 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -17,8 +17,9 @@ * Boston, MA 02110-1301, USA. */ -#include #include +#include +#include #include @@ -297,7 +298,7 @@ gst_rtsp_stream_get_control (GstRTSPStream * stream) g_mutex_lock (&priv->lock); if ((result = g_strdup (priv->control)) == NULL) - result = g_strdup_printf ("stream=%d", priv->idx); + result = g_strdup_printf ("stream=%u", priv->idx); g_mutex_unlock (&priv->lock); return result; @@ -325,6 +326,38 @@ gst_rtsp_stream_set_control (GstRTSPStream * stream, const gchar * control) g_mutex_unlock (&priv->lock); } +/** + * gst_rtsp_stream_has_control: + * @stream: a #GstRTSPStream + * @control: a control string + * + * Check if @stream has the control string @control. + * + * Returns: %TRUE is @stream has @control as the control string + */ +gboolean +gst_rtsp_stream_has_control (GstRTSPStream * stream, const gchar * control) +{ + GstRTSPStreamPrivate *priv; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if (priv->control) + res = g_strcmp0 (priv->control, control); + else { + guint streamid; + sscanf (control, "stream=%u", &streamid); + res = (streamid == priv->idx); + } + g_mutex_unlock (&priv->lock); + + return res; +} + /** * gst_rtsp_stream_set_mtu: * @stream: a #GstRTSPStream @@ -1233,7 +1266,8 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, GstElement * rtpbin, GstState state) { GstRTSPStreamPrivate *priv; - gint i, idx; + gint i; + guint idx; gchar *name; GstPad *pad, *teepad, *queuepad, *selpad; GstPadLinkReturn ret; @@ -1251,7 +1285,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, /* create a session with the same index as the stream */ idx = priv->idx; - GST_INFO ("stream %p joining bin as session %d", stream, idx); + GST_INFO ("stream %p joining bin as session %u", stream, idx); if (!alloc_ports (stream)) goto no_ports; @@ -1448,12 +1482,12 @@ was_joined: no_ports: { g_mutex_unlock (&priv->lock); - GST_WARNING ("failed to allocate ports %d", idx); + GST_WARNING ("failed to allocate ports %u", idx); return FALSE; } link_failed: { - GST_WARNING ("failed to link stream %d", idx); + GST_WARNING ("failed to link stream %u", idx); gst_object_unref (priv->send_rtp_sink); priv->send_rtp_sink = NULL; g_mutex_unlock (&priv->lock); diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index a4c893a658..8e5cbc520c 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -69,6 +69,7 @@ GstPad * gst_rtsp_stream_get_srcpad (GstRTSPStream *stream); void gst_rtsp_stream_set_control (GstRTSPStream *stream, const gchar *control); gchar * gst_rtsp_stream_get_control (GstRTSPStream *stream); +gboolean gst_rtsp_stream_has_control (GstRTSPStream *stream, const gchar *control); void gst_rtsp_stream_set_mtu (GstRTSPStream *stream, guint mtu); guint gst_rtsp_stream_get_mtu (GstRTSPStream *stream); From 3999bd4e4e73f1c0812f173b4399eed327bcdf37 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 3 Jul 2013 15:14:39 +0200 Subject: [PATCH 0697/1776] media: add method to find a stream by control url --- gst/rtsp-server/rtsp-media.c | 39 ++++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 1 + 2 files changed, 40 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c8a35d7d15..d20087dbbd 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1094,6 +1094,45 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) return res; } +/** + * gst_rtsp_media_find_stream: + * @media: a #GstRTSPMedia + * @control: the control of the stream + * + * Find a stream in @media with @control as the control uri. + * + * Returns: (transfer none): the #GstRTSPStream with control uri @control + * or %NULL when a stream with that control did not exist. + */ +GstRTSPStream * +gst_rtsp_media_find_stream (GstRTSPMedia * media, const gchar * control) +{ + GstRTSPMediaPrivate *priv; + GstRTSPStream *res; + gint i; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + g_return_val_if_fail (control != NULL, NULL); + + priv = media->priv; + + res = NULL; + + g_mutex_lock (&priv->lock); + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *test; + + test = g_ptr_array_index (priv->streams, i); + if (gst_rtsp_stream_has_control (test, control)) { + res = test; + break; + } + } + g_mutex_unlock (&priv->lock); + + return res; +} + /** * gst_rtsp_media_get_range_string: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 2b906cf734..d6d2153864 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -167,6 +167,7 @@ GstClockTime gst_rtsp_media_get_base_time (GstRTSPMedia *media); guint gst_rtsp_media_n_streams (GstRTSPMedia *media); GstRTSPStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); +GstRTSPStream * gst_rtsp_media_find_stream (GstRTSPMedia *media, const gchar * control); gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range); gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, From 9182263532c15861f3cbc09217e146fb708a823f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 3 Jul 2013 15:55:38 +0200 Subject: [PATCH 0698/1776] client: rework setup request a little Cache the media in DESCRIBE based on the longest matching path with the uri that we can find in the mount points. Rework the setup request a little to get the media from the session or from the longest matching path, this way we can derive the control string as everything after the path instead of hardcoding it. Find the stream based on the control string and only open a session when all this can be done. --- gst/rtsp-server/rtsp-client.c | 236 ++++++++++++++++++---------------- 1 file changed, 127 insertions(+), 109 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 09d6daceb5..8dbd8a5f0e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -52,7 +52,7 @@ struct _GstRTSPClientPrivate /* used to cache the media in the last requested DESCRIBE so that * we can pick it up in the next SETUP immediately */ - GstRTSPUrl *uri; + gchar *path; GstRTSPMedia *media; GList *transports; @@ -329,8 +329,8 @@ gst_rtsp_client_finalize (GObject * obj) if (priv->auth) g_object_unref (priv->auth); - if (priv->uri) - gst_rtsp_url_free (priv->uri); + if (priv->path) + g_free (priv->path); if (priv->media) { gst_rtsp_media_unprepare (priv->media); g_object_unref (priv->media); @@ -464,12 +464,15 @@ handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth, static gboolean -compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2) +paths_are_equal (const gchar * path1, const gchar * path2, gint len2) { - if (uri1 == NULL || uri2 == NULL) + if (path1 == NULL || path2 == NULL) return FALSE; - if (strcmp (uri1->abspath, uri2->abspath)) + if (strlen (path1) != len2) + return FALSE; + + if (strncmp (path1, path2, len2)) return FALSE; return TRUE; @@ -479,33 +482,42 @@ compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2) * but is cached for when the same client (without breaking the connection) is * doing a setup for the exact same url. */ static GstRTSPMedia * -find_media (GstRTSPClient * client, GstRTSPClientState * state) +find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) { GstRTSPClientPrivate *priv = client->priv; GstRTSPMediaFactory *factory; GstRTSPMedia *media; GstRTSPAuth *auth; + gchar *path; + gint path_len; - if (!compare_uri (priv->uri, state->uri)) { + if (!priv->mount_points) + goto no_mount_points; + + path = state->uri->abspath; + + /* find the longest matching factory for the uri first */ + if (!(factory = gst_rtsp_mount_points_match (priv->mount_points, + path, matched))) + goto no_factory; + + if (matched) + path_len = *matched; + else + path_len = strlen (path); + + if (!paths_are_equal (priv->path, path, path_len)) { /* remove any previously cached values before we try to construct a new * media for uri */ - if (priv->uri) - gst_rtsp_url_free (priv->uri); - priv->uri = NULL; + if (priv->path) + g_free (priv->path); + priv->path = NULL; if (priv->media) { gst_rtsp_media_unprepare (priv->media); g_object_unref (priv->media); } priv->media = NULL; - if (!priv->mount_points) - goto no_mount_points; - - /* find the factory for the uri first */ - if (!(factory = gst_rtsp_mount_points_match (priv->mount_points, - state->uri->abspath, NULL))) - goto no_factory; - /* check if we have access to the factory */ if ((auth = gst_rtsp_media_factory_get_auth (factory))) { state->factory = factory; @@ -521,24 +533,23 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state) if (!(media = gst_rtsp_media_factory_construct (factory, state->uri))) goto no_media; - g_object_unref (factory); - factory = NULL; - /* prepare the media */ if (!(gst_rtsp_media_prepare (media))) goto no_prepare; /* now keep track of the uri and the media */ - priv->uri = gst_rtsp_url_copy (state->uri); + priv->path = g_strndup (path, path_len); priv->media = media; state->media = media; } else { - /* we have seen this uri before, used cached media */ + /* we have seen this path before, used cached media */ media = priv->media; state->media = media; - GST_INFO ("reusing cached media %p", media); + GST_INFO ("reusing cached media %p for path %s", media, priv->path); } + g_object_unref (factory); + if (media) g_object_ref (media); @@ -553,7 +564,7 @@ no_mount_points: } no_factory: { - GST_ERROR ("client %p: no factory for uri", client); + GST_ERROR ("client %p: no factory for uri %s", client, path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return NULL; } @@ -578,6 +589,7 @@ no_prepare: GST_ERROR ("client %p: can't prepare media", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); g_object_unref (media); + g_object_unref (factory); return NULL; } } @@ -1294,37 +1306,20 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) GstRTSPStatusCode code; GstRTSPSession *session; GstRTSPStreamTransport *trans; - gchar *trans_str, *pos; - guint streamid; + gchar *trans_str; GstRTSPSessionMedia *sessmedia; GstRTSPMedia *media; GstRTSPStream *stream; GstRTSPState rtspstate; GstRTSPClientClass *klass; - const gchar *path; + gchar *path, *control; gint matched; if (!state->uri) goto no_uri; uri = state->uri; - path = state->uri->abspath; - - /* the uri contains the stream number we added in the SDP config, which is - * always /stream=%d so we need to strip that off - * parse the stream we need to configure, look for the stream in the abspath - * first and then in the query. */ - if (uri->abspath == NULL || !(pos = strstr (uri->abspath, "/stream="))) { - if (uri->query == NULL || !(pos = strstr (uri->query, "/stream="))) - goto bad_request; - } - - /* we can mofify the parsed uri in place */ - *pos = '\0'; - - pos += strlen ("/stream="); - if (sscanf (pos, "%u", &streamid) != 1) - goto bad_request; + path = uri->abspath; /* parse the transport */ res = @@ -1333,16 +1328,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) if (res != GST_RTSP_OK) goto no_transport; - gst_rtsp_transport_new (&ct); - - /* our supported transports */ - supported = GST_RTSP_LOWER_TRANS_UDP | - GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP; - - /* parse and find a usable supported transport */ - if (!parse_transport (transport, supported, ct)) - goto unsupported_transports; - /* we create the session after parsing stuff so that we don't make * a session for malformed requests */ if (priv->session_pool == NULL) @@ -1356,6 +1341,37 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) * return NULL if this is a new url to manage in this session. */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); } else { + /* we need a new media configuration in this session */ + sessmedia = NULL; + } + + /* we have no session media, find one and manage it */ + if (sessmedia == NULL) { + /* get a handle to the configuration of the media in the session */ + media = find_media (client, state, &matched); + } else { + if ((media = gst_rtsp_session_media_get_media (sessmedia))) + g_object_ref (media); + } + /* no media, not found then */ + if (media == NULL) + goto media_not_found; + + /* path is what matched. We can modify the parsed uri in place */ + path[matched] = '\0'; + /* control is remainder */ + control = &path[matched + 1]; + + /* find the stream now using the control part */ + stream = gst_rtsp_media_find_stream (media, control); + if (stream == NULL) + goto stream_not_found; + + /* now we have a uri identifying a valid media and stream */ + state->stream = stream; + state->media = media; + + if (session == NULL) { /* create a session if this fails we probably reached our session limit or * something. */ if (!(session = gst_rtsp_session_pool_create (priv->session_pool))) @@ -1369,38 +1385,34 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) session); state->session = session; - - /* we need a new media configuration in this session */ - sessmedia = NULL; } - /* we have no media, find one and manage it */ if (sessmedia == NULL) { - /* get a handle to the configuration of the media in the session */ - if ((media = find_media (client, state))) { - /* manage the media in our session now */ - sessmedia = gst_rtsp_session_manage_media (session, path, media); - } + /* manage the media in our session now, if not done already */ + sessmedia = gst_rtsp_session_manage_media (session, path, media); + /* if we stil have no media, error */ + if (sessmedia == NULL) + goto sessmedia_unavailable; + } else { + g_object_unref (media); } - /* if we stil have no media, error */ - if (sessmedia == NULL) - goto not_found; - state->sessmedia = sessmedia; - state->media = media = gst_rtsp_session_media_get_media (sessmedia); - - /* now get the stream */ - stream = gst_rtsp_media_get_stream (media, streamid); - if (stream == NULL) - goto not_found; - - state->stream = stream; /* set blocksize on this stream */ if (!handle_blocksize (media, stream, state->request)) goto invalid_blocksize; + gst_rtsp_transport_new (&ct); + + /* our supported transports */ + supported = GST_RTSP_LOWER_TRANS_UDP | + GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP; + + /* parse and find a usable supported transport */ + if (!parse_transport (transport, supported, ct)) + goto unsupported_transports; + /* update the client transport */ klass = GST_RTSP_CLIENT_GET_CLASS (client); if (!klass->configure_client_transport (client, state, ct)) @@ -1455,18 +1467,44 @@ no_uri: send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); return FALSE; } -bad_request: +no_transport: { - GST_ERROR ("client %p: bad request", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + GST_ERROR ("client %p: no transport", client); + send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); return FALSE; } -not_found: +no_pool: { - GST_ERROR ("client %p: media not found", client); + GST_ERROR ("client %p: no session pool configured", client); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); + return FALSE; + } +media_not_found: + { + GST_ERROR ("client %p: media '%s' not found", client, path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); + return FALSE; + } +stream_not_found: + { + GST_ERROR ("client %p: stream '%s' not found", client, control); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); + g_object_unref (media); + return FALSE; + } +service_unavailable: + { + GST_ERROR ("client %p: can't create session", client); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + g_object_unref (media); + return FALSE; + } +sessmedia_unavailable: + { + GST_ERROR ("client %p: can't create session media", client); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + g_object_unref (media); g_object_unref (session); - gst_rtsp_transport_free (ct); return FALSE; } invalid_blocksize: @@ -1474,21 +1512,6 @@ invalid_blocksize: GST_ERROR ("client %p: invalid blocksize", client); send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); g_object_unref (session); - gst_rtsp_transport_free (ct); - return FALSE; - } -unsupported_client_transport: - { - GST_ERROR ("client %p: unsupported client transport", client); - send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); - g_object_unref (session); - gst_rtsp_transport_free (ct); - return FALSE; - } -no_transport: - { - GST_ERROR ("client %p: no transport", client); - send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); return FALSE; } unsupported_transports: @@ -1496,20 +1519,15 @@ unsupported_transports: GST_ERROR ("client %p: unsupported transports", client); send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); gst_rtsp_transport_free (ct); + g_object_unref (session); return FALSE; } -no_pool: +unsupported_client_transport: { - GST_ERROR ("client %p: no session pool configured", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); - gst_rtsp_transport_free (ct); - return FALSE; - } -service_unavailable: - { - GST_ERROR ("client %p: can't create session", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + GST_ERROR ("client %p: unsupported client transport", client); + send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); gst_rtsp_transport_free (ct); + g_object_unref (session); return FALSE; } } @@ -1592,7 +1610,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) } /* find the media object for the uri */ - if (!(media = find_media (client, state))) + if (!(media = find_media (client, state, NULL))) goto no_media; /* create an SDP for the media object on this client */ From a1e5bde58d1f6c3b4452a063d251db8f3d5dbe77 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 3 Jul 2013 16:15:04 +0200 Subject: [PATCH 0699/1776] client: error out on non-aggregate control We require aggregate control (for now) for PLAY, PAUSE and TEARDOWN. --- gst/rtsp-server/rtsp-client.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8dbd8a5f0e..db821746de 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -727,6 +727,10 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) if (!sessmedia) goto not_found; + /* only aggregate control for now.. */ + if (path[matched] != '\0') + goto no_aggregate; + state->sessmedia = sessmedia; /* we emit the signal before closing the connection */ @@ -775,6 +779,13 @@ not_found: send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return FALSE; } +no_aggregate: + { + GST_ERROR ("client %p: no aggregate path %s", client, path); + send_generic_response (client, + GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, state); + return FALSE; + } } static GstRTSPResult @@ -894,6 +905,9 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) if (!sessmedia) goto not_found; + if (path[matched] != '\0') + goto no_aggregate; + state->sessmedia = sessmedia; rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); @@ -942,6 +956,13 @@ not_found: send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return FALSE; } +no_aggregate: + { + GST_ERROR ("client %p: no aggregate path %s", client, path); + send_generic_response (client, + GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, state); + return FALSE; + } invalid_state: { GST_ERROR ("client %p: not PLAYING or RECORDING", client); @@ -981,6 +1002,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) if (!sessmedia) goto not_found; + if (path[matched] != '\0') + goto no_aggregate; + state->sessmedia = sessmedia; state->media = media = gst_rtsp_session_media_get_media (sessmedia); @@ -1089,6 +1113,13 @@ not_found: send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return FALSE; } +no_aggregate: + { + GST_ERROR ("client %p: no aggregate path %s", client, path); + send_generic_response (client, + GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, state); + return FALSE; + } invalid_state: { GST_ERROR ("client %p: not PLAYING or READY", client); From 78bc979690210662067a8adada5c17122f37f9c7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 4 Jul 2013 14:33:59 +0200 Subject: [PATCH 0700/1776] auth: add support for multiple basic auth tokens Make it possible to add multiple basic authorisation tokens to one authorization object. Associate with each token an authorization group that will define what capabilities are allowed. --- examples/test-auth.c | 16 ++++++---- gst/rtsp-server/rtsp-auth.c | 58 ++++++++++++++++++++++++++++------- gst/rtsp-server/rtsp-auth.h | 4 ++- gst/rtsp-server/rtsp-client.h | 2 ++ 4 files changed, 62 insertions(+), 18 deletions(-) diff --git a/examples/test-auth.c b/examples/test-auth.c index a810b4df7a..ee8af5728f 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -89,8 +89,11 @@ main (int argc, char *argv[]) /* make a new authentication manager */ auth = gst_rtsp_auth_new (); - basic = gst_rtsp_auth_make_basic ("user", "admin"); - gst_rtsp_auth_set_basic (auth, basic); + basic = gst_rtsp_auth_make_basic ("user", "password"); + gst_rtsp_auth_add_basic (auth, basic, "user"); + g_free (basic); + basic = gst_rtsp_auth_make_basic ("admin", "power"); + gst_rtsp_auth_add_basic (auth, basic, "admin"); g_free (basic); gst_rtsp_media_factory_set_auth (factory, auth); g_object_unref (auth); @@ -104,8 +107,8 @@ main (int argc, char *argv[]) "x264enc ! rtph264pay name=pay0 pt=96 )"); /* make a new authentication manager */ auth = gst_rtsp_auth_new (); - basic = gst_rtsp_auth_make_basic ("user2", "admin2"); - gst_rtsp_auth_set_basic (auth, basic); + basic = gst_rtsp_auth_make_basic ("admin2", "power2"); + gst_rtsp_auth_add_basic (auth, basic, "admin"); g_free (basic); gst_rtsp_media_factory_set_auth (factory, auth); g_object_unref (auth); @@ -123,8 +126,9 @@ main (int argc, char *argv[]) g_timeout_add_seconds (10, (GSourceFunc) remove_sessions, server); /* start serving */ - g_print ("stream with user:admin ready at rtsp://127.0.0.1:8554/test\n"); - g_print ("stream with user2:admin2 ready at rtsp://127.0.0.1:8554/test2\n"); + g_print ("stream with user:password ready at rtsp://127.0.0.1:8554/test\n"); + g_print ("stream with admin:power ready at rtsp://127.0.0.1:8554/test\n"); + g_print ("stream with admin2:power2 ready at rtsp://127.0.0.1:8554/test2\n"); g_main_loop_run (loop); return 0; diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index faaf0f7e52..6ed627fd68 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -27,7 +27,7 @@ struct _GstRTSPAuthPrivate { GMutex lock; - gchar *basic; /* protected by lock */ + GHashTable *basic; /* protected by lock */ GstRTSPMethod methods; }; @@ -75,11 +75,16 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) static void gst_rtsp_auth_init (GstRTSPAuth * auth) { - auth->priv = GST_RTSP_AUTH_GET_PRIVATE (auth); + GstRTSPAuthPrivate *priv; + + auth->priv = priv = GST_RTSP_AUTH_GET_PRIVATE (auth); + + g_mutex_init (&priv->lock); + + priv->basic = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - g_mutex_init (&auth->priv->lock); /* bitwise or of all methods that need authentication */ - auth->priv->methods = GST_RTSP_DESCRIBE | + priv->methods = GST_RTSP_DESCRIBE | GST_RTSP_ANNOUNCE | GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | @@ -94,7 +99,7 @@ gst_rtsp_auth_finalize (GObject * obj) GstRTSPAuthPrivate *priv = auth->priv; GST_INFO ("finalize auth %p", auth); - g_free (priv->basic); + g_hash_table_unref (priv->basic); g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj); @@ -138,24 +143,51 @@ gst_rtsp_auth_new (void) } /** - * gst_rtsp_auth_set_basic: + * gst_rtsp_auth_add_basic: * @auth: a #GstRTSPAuth * @basic: the basic token + * @authgroup: authorisation group * - * Set the basic token for the default authentication algorithm. + * Add a basic token for the default authentication algorithm that + * enables the client qith privileges from @authgroup. */ void -gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic) +gst_rtsp_auth_add_basic (GstRTSPAuth * auth, const gchar * basic, + const gchar * authgroup) { GstRTSPAuthPrivate *priv; g_return_if_fail (GST_IS_RTSP_AUTH (auth)); + g_return_if_fail (basic != NULL); + g_return_if_fail (authgroup != NULL); priv = auth->priv; g_mutex_lock (&priv->lock); - g_free (priv->basic); - priv->basic = g_strdup (basic); + g_hash_table_replace (priv->basic, g_strdup (basic), g_strdup (authgroup)); + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_auth_remove_basic: + * @auth: a #GstRTSPAuth + * @basic: (transfer none): the basic token + * + * Add a basic token for the default authentication algorithm that + * enables the client qith privileges from @authgroup. + */ +void +gst_rtsp_auth_remove_basic (GstRTSPAuth * auth, const gchar * basic) +{ + GstRTSPAuthPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_AUTH (auth)); + g_return_if_fail (basic != NULL); + + priv = auth->priv; + + g_mutex_lock (&priv->lock); + g_hash_table_remove (priv->basic, basic); g_mutex_unlock (&priv->lock); } @@ -226,10 +258,14 @@ default_check_method (GstRTSPAuth * auth, GstRTSPClient * client, /* parse type */ if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) { + gchar *authgroup; + GST_DEBUG_OBJECT (auth, "check Basic auth"); g_mutex_lock (&priv->lock); - if (priv->basic && strcmp (&authorization[6], priv->basic) == 0) + if ((authgroup = g_hash_table_lookup (priv->basic, &authorization[6]))) { result = TRUE; + state->authgroup = authgroup; + } g_mutex_unlock (&priv->lock); } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) { GST_DEBUG_OBJECT (auth, "check Digest auth"); diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 6fd1a2f5f9..425413b3c3 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -63,7 +63,9 @@ GType gst_rtsp_auth_get_type (void); GstRTSPAuth * gst_rtsp_auth_new (void); -void gst_rtsp_auth_set_basic (GstRTSPAuth *auth, const gchar * basic); +void gst_rtsp_auth_add_basic (GstRTSPAuth *auth, const gchar * basic, + const gchar *authgroup); +void gst_rtsp_auth_remove_basic (GstRTSPAuth *auth, const gchar * basic); gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth *auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState *state); diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 741fed24e6..b5adc104f3 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -51,6 +51,7 @@ typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; * @request: the complete request * @uri: the complete url parsed from @request * @method: the parsed method of @uri + * @authgroup: authorisation group * @session: the session, can be NULL * @sessmedia: the session media for the url can be NULL * @factory: the media factory for the url, can be NULL. @@ -64,6 +65,7 @@ struct _GstRTSPClientState { GstRTSPMessage *request; GstRTSPUrl *uri; GstRTSPMethod method; + const gchar *authgroup; GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; GstRTSPMediaFactory *factory; From 19cffc79996fc3b73e597fa72949b9ed3559a313 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Jul 2013 12:08:36 +0200 Subject: [PATCH 0701/1776] auth: remove auth from media and factory Remove the auth object from media and factory. We want to have the RTSPClient authenticate and authorize resources, there is no need to place another auth manager on the media/factory. --- examples/test-auth.c | 32 ++++--- gst/rtsp-server/rtsp-auth.c | 123 +++++++++++++++++---------- gst/rtsp-server/rtsp-auth.h | 16 ++-- gst/rtsp-server/rtsp-client.c | 25 +----- gst/rtsp-server/rtsp-client.h | 1 + gst/rtsp-server/rtsp-media-factory.c | 64 -------------- gst/rtsp-server/rtsp-media-factory.h | 3 - gst/rtsp-server/rtsp-media.c | 60 ------------- gst/rtsp-server/rtsp-media.h | 3 - 9 files changed, 107 insertions(+), 220 deletions(-) diff --git a/examples/test-auth.c b/examples/test-auth.c index ee8af5728f..f5a129ca8b 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -87,16 +87,6 @@ main (int argc, char *argv[]) "audiotestsrc ! audio/x-raw,rate=8000 ! " "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); - /* make a new authentication manager */ - auth = gst_rtsp_auth_new (); - basic = gst_rtsp_auth_make_basic ("user", "password"); - gst_rtsp_auth_add_basic (auth, basic, "user"); - g_free (basic); - basic = gst_rtsp_auth_make_basic ("admin", "power"); - gst_rtsp_auth_add_basic (auth, basic, "admin"); - g_free (basic); - gst_rtsp_media_factory_set_auth (factory, auth); - g_object_unref (auth); /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test", factory); @@ -105,19 +95,27 @@ main (int argc, char *argv[]) gst_rtsp_media_factory_set_launch (factory, "( " "videotestsrc ! video/x-raw,width=352,height=288,framerate=30/1 ! " "x264enc ! rtph264pay name=pay0 pt=96 )"); - /* make a new authentication manager */ - auth = gst_rtsp_auth_new (); - basic = gst_rtsp_auth_make_basic ("admin2", "power2"); - gst_rtsp_auth_add_basic (auth, basic, "admin"); - g_free (basic); - gst_rtsp_media_factory_set_auth (factory, auth); - g_object_unref (auth); /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test2", factory); /* don't need the ref to the mapper anymore */ g_object_unref (mounts); + /* make a new authentication manager */ + auth = gst_rtsp_auth_new (); + basic = gst_rtsp_auth_make_basic ("user", "password"); + gst_rtsp_auth_add_basic (auth, basic, "user"); + g_free (basic); + basic = gst_rtsp_auth_make_basic ("admin", "power"); + gst_rtsp_auth_add_basic (auth, basic, "admin"); + g_free (basic); + basic = gst_rtsp_auth_make_basic ("admin2", "power2"); + gst_rtsp_auth_add_basic (auth, basic, "admin"); + g_free (basic); + /* set as the server authentication manager */ + gst_rtsp_server_set_auth (server, auth); + g_object_unref (auth); + /* attach the server to the default maincontext */ if (gst_rtsp_server_attach (server, NULL) == 0) goto failed; diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 6ed627fd68..a0df870788 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -46,10 +46,12 @@ static void gst_rtsp_auth_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_auth_finalize (GObject * obj); -static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, +static gboolean default_setup (GstRTSPAuth * auth, GstRTSPClient * client, + GstRTSPClientState * state); +static gboolean default_validate (GstRTSPAuth * auth, + GstRTSPClient * client, GstRTSPClientState * state); +static gboolean default_check (GstRTSPAuth * auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState * state); -static gboolean default_check_method (GstRTSPAuth * auth, - GstRTSPClient * client, GQuark hint, GstRTSPClientState * state); G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT); @@ -66,8 +68,9 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) gobject_class->set_property = gst_rtsp_auth_set_property; gobject_class->finalize = gst_rtsp_auth_finalize; - klass->setup_auth = default_setup_auth; - klass->check_method = default_check_method; + klass->setup = default_setup; + klass->validate = default_validate; + klass->check = default_check; GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth"); } @@ -192,8 +195,8 @@ gst_rtsp_auth_remove_basic (GstRTSPAuth * auth, const gchar * basic) } static gboolean -default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, - GQuark hint, GstRTSPClientState * state) +default_setup (GstRTSPAuth * auth, GstRTSPClient * client, + GstRTSPClientState * state) { if (state->response == NULL) return FALSE; @@ -206,10 +209,9 @@ default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, } /** - * gst_rtsp_auth_setup_auth: + * gst_rtsp_auth_setup: * @auth: a #GstRTSPAuth * @client: the client - * @hint: TODO * @state: TODO * * Add authentication tokens to @response. @@ -217,8 +219,8 @@ default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, * Returns: FALSE if something is wrong. */ gboolean -gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, - GQuark hint, GstRTSPClientState * state) +gst_rtsp_auth_setup (GstRTSPAuth * auth, GstRTSPClient * client, + GstRTSPClientState * state) { gboolean result = FALSE; GstRTSPAuthClass *klass; @@ -231,53 +233,83 @@ gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client, GST_DEBUG_OBJECT (auth, "setup auth"); - if (klass->setup_auth) - result = klass->setup_auth (auth, client, hint, state); + if (klass->setup) + result = klass->setup (auth, client, state); return result; } static gboolean -default_check_method (GstRTSPAuth * auth, GstRTSPClient * client, - GQuark hint, GstRTSPClientState * state) +default_validate (GstRTSPAuth * auth, GstRTSPClient * client, + GstRTSPClientState * state) { GstRTSPAuthPrivate *priv = auth->priv; - gboolean result = TRUE; GstRTSPResult res; + gchar *authorization; - if ((state->method & priv->methods) != 0) { - gchar *authorization; + GST_DEBUG_OBJECT (auth, "validate"); - result = FALSE; + res = + gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION, + &authorization, 0); + if (res < 0) + goto no_auth; - res = - gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION, - &authorization, 0); - if (res < 0) - goto no_auth; + /* parse type */ + if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) { + gchar *authgroup; - /* parse type */ - if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) { - gchar *authgroup; - - GST_DEBUG_OBJECT (auth, "check Basic auth"); - g_mutex_lock (&priv->lock); - if ((authgroup = g_hash_table_lookup (priv->basic, &authorization[6]))) { - result = TRUE; - state->authgroup = authgroup; - } - g_mutex_unlock (&priv->lock); - } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) { - GST_DEBUG_OBJECT (auth, "check Digest auth"); - /* not implemented yet */ - result = FALSE; + GST_DEBUG_OBJECT (auth, "check Basic auth"); + g_mutex_lock (&priv->lock); + if ((authgroup = g_hash_table_lookup (priv->basic, &authorization[6]))) { + GST_DEBUG_OBJECT (auth, "setting authgroup %s", authgroup); + state->authgroup = authgroup; } + g_mutex_unlock (&priv->lock); + } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) { + GST_DEBUG_OBJECT (auth, "check Digest auth"); + /* not implemented yet */ } - return result; + return TRUE; no_auth: { GST_DEBUG_OBJECT (auth, "no authorization header found"); + return TRUE; + } +} + +static gboolean +default_check (GstRTSPAuth * auth, GstRTSPClient * client, + GQuark hint, GstRTSPClientState * state) +{ + GstRTSPAuthPrivate *priv = auth->priv; + GstRTSPAuthClass *klass; + + klass = GST_RTSP_AUTH_GET_CLASS (auth); + + if ((state->method & priv->methods) != 0) { + /* we need an authgroup to check */ + if (state->authgroup == NULL) { + if (klass->validate) { + if (!klass->validate (auth, client, state)) + goto validate_failed; + } + } + + if (state->authgroup == NULL) + goto no_auth; + } + return TRUE; + +validate_failed: + { + GST_DEBUG_OBJECT (auth, "validation failed"); + return FALSE; + } +no_auth: + { + GST_DEBUG_OBJECT (auth, "no authorization group found"); return FALSE; } } @@ -289,9 +321,10 @@ no_auth: * @hint: a hint * @state: client state * - * Check if @client is allowed to perform the actions of @state. + * Check if @client with state is authorized to perform @hint in the + * current @state. * - * Returns: FALSE if the action is not allowed. + * Returns: FALSE if check failed. */ gboolean gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client, @@ -306,10 +339,10 @@ gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client, klass = GST_RTSP_AUTH_GET_CLASS (auth); - GST_DEBUG_OBJECT (auth, "check state"); + GST_DEBUG_OBJECT (auth, "check auth"); - if (klass->check_method) - result = klass->check_method (auth, client, hint, state); + if (klass->check) + result = klass->check (auth, client, hint, state); return result; } diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 425413b3c3..fd9b679a5a 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -53,10 +53,12 @@ struct _GstRTSPAuth { struct _GstRTSPAuthClass { GObjectClass parent_class; - gboolean (*setup_auth) (GstRTSPAuth *auth, GstRTSPClient * client, - GQuark hint, GstRTSPClientState *state); - gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPClient * client, - GQuark hint, GstRTSPClientState *state); + gboolean (*setup) (GstRTSPAuth *auth, GstRTSPClient * client, + GstRTSPClientState *state); + gboolean (*validate) (GstRTSPAuth *auth, GstRTSPClient * client, + GstRTSPClientState *state); + gboolean (*check) (GstRTSPAuth *auth, GstRTSPClient * client, + GQuark hint, GstRTSPClientState *state); }; GType gst_rtsp_auth_get_type (void); @@ -67,10 +69,12 @@ void gst_rtsp_auth_add_basic (GstRTSPAuth *auth, const gc const gchar *authgroup); void gst_rtsp_auth_remove_basic (GstRTSPAuth *auth, const gchar * basic); -gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth *auth, GstRTSPClient * client, - GQuark hint, GstRTSPClientState *state); +gboolean gst_rtsp_auth_setup (GstRTSPAuth *auth, GstRTSPClient * client, + GstRTSPClientState *state); + gboolean gst_rtsp_auth_check (GstRTSPAuth *auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState *state); + /* helpers */ gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass); diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index db821746de..a597916227 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -456,7 +456,7 @@ handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth, if (auth) { /* and let the authentication manager setup the auth tokens */ - gst_rtsp_auth_setup_auth (auth, client, 0, state); + gst_rtsp_auth_setup (auth, client, state); } send_message (client, state->session, state->response, FALSE); @@ -487,7 +487,6 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) GstRTSPClientPrivate *priv = client->priv; GstRTSPMediaFactory *factory; GstRTSPMedia *media; - GstRTSPAuth *auth; gchar *path; gint path_len; @@ -518,17 +517,6 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) } priv->media = NULL; - /* check if we have access to the factory */ - if ((auth = gst_rtsp_media_factory_get_auth (factory))) { - state->factory = factory; - - if (!gst_rtsp_auth_check (auth, client, 0, state)) - goto not_allowed; - - state->factory = NULL; - g_object_unref (auth); - } - /* prepare the media and add it to the pipeline */ if (!(media = gst_rtsp_media_factory_construct (factory, state->uri))) goto no_media; @@ -568,15 +556,6 @@ no_factory: send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return NULL; } -not_allowed: - { - GST_ERROR ("client %p: unauthorized request", client); - handle_unauthorized_request (client, auth, state); - g_object_unref (factory); - state->factory = NULL; - g_object_unref (auth); - return NULL; - } no_media: { GST_ERROR ("client %p: can't create media", client); @@ -1847,6 +1826,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) if (priv->auth) { if (!gst_rtsp_auth_check (priv->auth, client, 0, &state)) goto not_authorized; + + state.auth = priv->auth; } /* now see what is asked and dispatch to a dedicated handler */ diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index b5adc104f3..86ae980ed6 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -65,6 +65,7 @@ struct _GstRTSPClientState { GstRTSPMessage *request; GstRTSPUrl *uri; GstRTSPMethod method; + GstRTSPAuth *auth; const gchar *authgroup; GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index f448276276..b6fa8c033f 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -33,7 +33,6 @@ struct _GstRTSPMediaFactoryPrivate gboolean shared; gboolean eos_shutdown; GstRTSPLowerTrans protocols; - GstRTSPAuth *auth; guint buffer_size; GstRTSPAddressPool *pool; @@ -194,8 +193,6 @@ gst_rtsp_media_factory_finalize (GObject * obj) g_mutex_clear (&priv->medias_lock); g_free (priv->launch); g_mutex_clear (&priv->lock); - if (priv->auth) - g_object_unref (priv->auth); if (priv->pool) g_object_unref (priv->pool); @@ -535,62 +532,6 @@ gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory) return result; } -/** - * gst_rtsp_media_factory_set_auth: - * @factory: a #GstRTSPMediaFactory - * @auth: a #GstRTSPAuth - * - * configure @auth to be used as the authentication manager of @factory. - */ -void -gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory, - GstRTSPAuth * auth) -{ - GstRTSPMediaFactoryPrivate *priv; - GstRTSPAuth *old; - - g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); - - priv = factory->priv; - - GST_RTSP_MEDIA_FACTORY_LOCK (factory); - if ((old = priv->auth) != auth) - priv->auth = auth ? g_object_ref (auth) : NULL; - else - old = NULL; - GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); - - if (old) - g_object_unref (old); -} - -/** - * gst_rtsp_media_factory_get_auth: - * @factory: a #GstRTSPMediaFactory - * - * Get the #GstRTSPAuth used as the authentication manager of @factory. - * - * Returns: (transfer full): the #GstRTSPAuth of @factory. g_object_unref() after - * usage. - */ -GstRTSPAuth * -gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory) -{ - GstRTSPMediaFactoryPrivate *priv; - GstRTSPAuth *result; - - g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); - - priv = factory->priv; - - GST_RTSP_MEDIA_FACTORY_LOCK (factory); - if ((result = priv->auth)) - g_object_ref (result); - GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); - - return result; -} - /** * gst_rtsp_media_factory_set_protocols: * @factory: a #GstRTSPMediaFactory @@ -896,7 +837,6 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstRTSPMediaFactoryPrivate *priv = factory->priv; gboolean shared, eos_shutdown; guint size; - GstRTSPAuth *auth; GstRTSPLowerTrans protocols; GstRTSPAddressPool *pool; @@ -913,10 +853,6 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_buffer_size (media, size); gst_rtsp_media_set_protocols (media, protocols); - if ((auth = gst_rtsp_media_factory_get_auth (factory))) { - gst_rtsp_media_set_auth (media, auth); - g_object_unref (auth); - } if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) { gst_rtsp_media_set_address_pool (media, pool); g_object_unref (pool); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index d974fa0148..a492422e38 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -114,9 +114,6 @@ gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFac void gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory *factory, GstRTSPLowerTrans protocols); GstRTSPLowerTrans gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory *factory); -void gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory *factory, GstRTSPAuth *auth); -GstRTSPAuth * gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory *factory); - void gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory, GstRTSPAddressPool * pool); GstRTSPAddressPool * gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d20087dbbd..4e25e1584f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -40,7 +40,6 @@ struct _GstRTSPMediaPrivate gboolean reused; gboolean eos_shutdown; guint buffer_size; - GstRTSPAuth *auth; GstRTSPAddressPool *pool; GstElement *element; @@ -262,8 +261,6 @@ gst_rtsp_media_finalize (GObject * obj) if (priv->nettime) gst_object_unref (priv->nettime); gst_object_unref (priv->element); - if (priv->auth) - g_object_unref (priv->auth); if (priv->pool) g_object_unref (priv->pool); g_mutex_clear (&priv->lock); @@ -784,63 +781,6 @@ gst_rtsp_media_is_time_provider (GstRTSPMedia * media) return res; } -/** - * gst_rtsp_media_set_auth: - * @media: a #GstRTSPMedia - * @auth: a #GstRTSPAuth - * - * configure @auth to be used as the authentication manager of @media. - */ -void -gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth) -{ - GstRTSPMediaPrivate *priv; - GstRTSPAuth *old; - - g_return_if_fail (GST_IS_RTSP_MEDIA (media)); - - priv = media->priv; - - GST_LOG_OBJECT (media, "set auth %p", auth); - - g_mutex_lock (&priv->lock); - if ((old = priv->auth) != auth) - priv->auth = auth ? g_object_ref (auth) : NULL; - else - old = NULL; - g_mutex_unlock (&priv->lock); - - if (old) - g_object_unref (old); -} - -/** - * gst_rtsp_media_get_auth: - * @media: a #GstRTSPMedia - * - * Get the #GstRTSPAuth used as the authentication manager of @media. - * - * Returns: (transfer full): the #GstRTSPAuth of @media. g_object_unref() after - * usage. - */ -GstRTSPAuth * -gst_rtsp_media_get_auth (GstRTSPMedia * media) -{ - GstRTSPMediaPrivate *priv; - GstRTSPAuth *result; - - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - - priv = media->priv; - - g_mutex_lock (&priv->lock); - if ((result = priv->auth)) - g_object_ref (result); - g_mutex_unlock (&priv->lock); - - return result; -} - /** * gst_rtsp_media_set_address_pool: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index d6d2153864..02be092c7e 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -137,9 +137,6 @@ GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia *media); void gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown); gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media); -void gst_rtsp_media_set_auth (GstRTSPMedia *media, GstRTSPAuth *auth); -GstRTSPAuth * gst_rtsp_media_get_auth (GstRTSPMedia *media); - void gst_rtsp_media_set_address_pool (GstRTSPMedia *media, GstRTSPAddressPool *pool); GstRTSPAddressPool * gst_rtsp_media_get_address_pool (GstRTSPMedia *media); From 48ff096a2574b579fa9a70f3b080cb85bb4108fe Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Jul 2013 20:34:40 +0200 Subject: [PATCH 0702/1776] token: add authorization token Add a simply miniobject that contains the authorizations. The object contains a GstStructure that hold all authorization fields. When a user is authenticated, the auth module will create a Token for the user. The token is then used to check what operations the user is allowed to do and various other configuration values. --- gst/rtsp-server/Makefile.am | 2 + gst/rtsp-server/rtsp-token.c | 156 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-token.h | 93 +++++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 gst/rtsp-server/rtsp-token.c create mode 100644 gst/rtsp-server/rtsp-token.h diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 353ab27503..c414d8cee9 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -12,6 +12,7 @@ public_headers = \ rtsp-session.h \ rtsp-session-media.h \ rtsp-session-pool.h \ + rtsp-token.h \ rtsp-client.h \ rtsp-server.h @@ -29,6 +30,7 @@ c_sources = \ rtsp-session.c \ rtsp-session-media.c \ rtsp-session-pool.c \ + rtsp-token.c \ rtsp-client.c \ rtsp-server.c diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c new file mode 100644 index 0000000000..2a4d29bb51 --- /dev/null +++ b/gst/rtsp-server/rtsp-token.c @@ -0,0 +1,156 @@ +/* GStreamer + * Copyright (C) 2010 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include "rtsp-token.h" + +typedef struct _GstRTSPTokenImpl +{ + GstRTSPToken token; + + GstStructure *structure; +} GstRTSPTokenImpl; + +#define GST_RTSP_TOKEN_STRUCTURE(t) (((GstRTSPTokenImpl *)(t))->structure) + +//GST_DEBUG_CATEGORY_STATIC (rtsp_token_debug); +//#define GST_CAT_DEFAULT rtsp_token_debug + +GST_DEFINE_MINI_OBJECT_TYPE (GstRTSPToken, gst_rtsp_token); + +static void gst_rtsp_token_init (GstRTSPTokenImpl * token, + GstStructure * structure); + +static void +_gst_rtsp_token_free (GstRTSPToken * token) +{ + GstRTSPTokenImpl *impl = (GstRTSPTokenImpl *) token; + + gst_structure_set_parent_refcount (impl->structure, NULL); + gst_structure_free (impl->structure); + + g_slice_free1 (sizeof (GstRTSPTokenImpl), token); +} + +static GstRTSPToken * +_gst_rtsp_token_copy (GstRTSPTokenImpl * token) +{ + GstRTSPTokenImpl *copy; + GstStructure *structure; + + structure = gst_structure_copy (token->structure); + + copy = g_slice_new0 (GstRTSPTokenImpl); + gst_rtsp_token_init (copy, structure); + + return (GstRTSPToken *) copy; +} + +static void +gst_rtsp_token_init (GstRTSPTokenImpl * token, GstStructure * structure) +{ + gst_mini_object_init (GST_MINI_OBJECT_CAST (token), 0, + GST_TYPE_RTSP_TOKEN, + (GstMiniObjectCopyFunction) _gst_rtsp_token_copy, NULL, + (GstMiniObjectFreeFunction) _gst_rtsp_token_free); + + token->structure = structure; + gst_structure_set_parent_refcount (token->structure, + &token->token.mini_object.refcount); +} + +/** + * gst_rtsp_token_new: + * + * Create a new empty Authorization token. + * + * Returns: (transfer full): a new empty authorization token. + */ +GstRTSPToken * +gst_rtsp_token_new (void) +{ + GstRTSPTokenImpl *token; + + token = g_slice_new0 (GstRTSPTokenImpl); + + gst_rtsp_token_init (token, gst_structure_new_empty ("GstRTSPToken")); + + return (GstRTSPToken *) token; +} + + +/** + * gst_rtsp_token_get_structure: + * @token: The #GstRTSPToken. + * + * Access the structure of the token. + * + * Returns: The structure of the token. The structure is still + * owned by the token, which means that you should not free it and + * that the pointer becomes invalid when you free the token. + * + * MT safe. + */ +const GstStructure * +gst_rtsp_token_get_structure (GstRTSPToken * token) +{ + g_return_val_if_fail (GST_IS_RTSP_TOKEN (token), NULL); + + return GST_RTSP_TOKEN_STRUCTURE (token); +} + +/** + * gst_rtsp_token_writable_structure: + * @token: The #GstRTSPToken. + * + * Get a writable version of the structure. + * + * Returns: The structure of the token. The structure is still + * owned by the token, which means that you should not free it and + * that the pointer becomes invalid when you free the token. + * This function checks if @token is writable and will never return NULL. + * + * MT safe. + */ +GstStructure * +gst_rtsp_token_writable_structure (GstRTSPToken * token) +{ + g_return_val_if_fail (GST_IS_RTSP_TOKEN (token), NULL); + g_return_val_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST + (token)), NULL); + + return GST_RTSP_TOKEN_STRUCTURE (token); +} + +/** + * gst_rtsp_token_get_string: + * @token: a #GstRTSPToken + * @field: a field name + * + * Get the string value of @field in @token. + * + * Returns: the string value of @field in @token or NULL when @field is not + * defined in @token. + */ +const gchar * +gst_rtsp_token_get_string (GstRTSPToken * token, const gchar * field) +{ + return gst_structure_get_string (GST_RTSP_TOKEN_STRUCTURE (token), field); +} diff --git a/gst/rtsp-server/rtsp-token.h b/gst/rtsp-server/rtsp-token.h new file mode 100644 index 0000000000..732a683ad7 --- /dev/null +++ b/gst/rtsp-server/rtsp-token.h @@ -0,0 +1,93 @@ +/* GStreamer + * Copyright (C) 2010 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#ifndef __GST_RTSP_TOKEN_H__ +#define __GST_RTSP_TOKEN_H__ + +typedef struct _GstRTSPToken GstRTSPToken; + +#include "rtsp-auth.h" + +G_BEGIN_DECLS + +GType gst_rtsp_token_get_type(void); + +#define GST_TYPE_RTSP_TOKEN (gst_rtsp_token_get_type()) +#define GST_IS_RTSP_TOKEN(obj) (GST_IS_MINI_OBJECT_TYPE (obj, GST_TYPE_RTSP_TOKEN)) +#define GST_RTSP_TOKEN_CAST(obj) ((GstRTSPToken*)(obj)) +#define GST_RTSP_TOKEN(obj) (GST_RTSP_TOKEN_CAST(obj)) + +/** + * GstRTSPToken: + * + * An opaque object used for checking authorisations. + * It is generated after successfull authentication. + */ +struct _GstRTSPToken { + GstMiniObject mini_object; +}; + +/* refcounting */ +/** + * gst_rtsp_token_ref: + * @token: The token to refcount + * + * Increase the refcount of this token. + * + * Returns: (transfer full): @token (for convenience when doing assignments) + */ +#ifdef _FOOL_GTK_DOC_ +G_INLINE_FUNC GstRTSPToken * gst_rtsp_token_ref (GstRTSPToken * token); +#endif + +static inline GstRTSPToken * +gst_rtsp_token_ref (GstRTSPToken * token) +{ + return (GstRTSPToken *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (token)); +} + +/** + * gst_rtsp_token_unref: + * @token: (transfer full): the token to refcount + * + * Decrease the refcount of an token, freeing it if the refcount reaches 0. + */ +#ifdef _FOOL_GTK_DOC_ +G_INLINE_FUNC void gst_rtsp_token_unref (GstRTSPToken * token); +#endif + +static inline void +gst_rtsp_token_unref (GstRTSPToken * token) +{ + gst_mini_object_unref (GST_MINI_OBJECT_CAST (token)); +} + + +GstRTSPToken * gst_rtsp_token_new (void); + +const GstStructure * gst_rtsp_token_get_structure (GstRTSPToken *token); +GstStructure * gst_rtsp_token_writable_structure (GstRTSPToken *token); + +const gchar * gst_rtsp_token_get_string (GstRTSPToken *token, + const gchar *field); +G_END_DECLS + +#endif /* __GST_RTSP_TOKEN_H__ */ From 12583e819ca31099a5d7a2fb92b221aee164244c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Jul 2013 20:43:39 +0200 Subject: [PATCH 0703/1776] media: add optional context for bus messages Add an optional mainloop to _prepare that will handle the bus messages instead of always using the shared mainloop. --- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-media.c | 5 +++-- gst/rtsp-server/rtsp-media.h | 2 +- tests/check/gst/media.c | 14 +++++++------- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a597916227..47956e5583 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -522,7 +522,7 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) goto no_media; /* prepare the media */ - if (!(gst_rtsp_media_prepare (media))) + if (!(gst_rtsp_media_prepare (media, NULL))) goto no_prepare; /* now keep track of the uri and the media */ diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4e25e1584f..2a875b37f9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1507,6 +1507,7 @@ struct _DynPaySignalHandlers /** * gst_rtsp_media_prepare: * @media: a #GstRTSPMedia + * @context: a #GMainContext to run the bus handler or %NULL * * Prepare @media for streaming. This function will create the objects * to manage the streaming. A pipeline must have been set on @media with @@ -1518,7 +1519,7 @@ struct _DynPaySignalHandlers * Returns: %TRUE on success. */ gboolean -gst_rtsp_media_prepare (GstRTSPMedia * media) +gst_rtsp_media_prepare (GstRTSPMedia * media, GMainContext * context) { GstRTSPMediaPrivate *priv; GstStateChangeReturn ret; @@ -1570,7 +1571,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media) g_object_ref (media), (GDestroyNotify) watch_destroyed); klass = GST_RTSP_MEDIA_GET_CLASS (media); - priv->id = g_source_attach (priv->source, klass->context); + priv->id = g_source_attach (priv->source, context ? context : klass->context); /* add stuff to the bin */ gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 02be092c7e..f76a6ddcd5 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -149,7 +149,7 @@ GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media, const gchar *address, guint16 port); /* prepare the media for playback */ -gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); +gboolean gst_rtsp_media_prepare (GstRTSPMedia *media, GMainContext *context); gboolean gst_rtsp_media_unprepare (GstRTSPMedia *media); /* creating streams */ diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index dd814cfec8..0692bcb382 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -53,7 +53,7 @@ GST_START_TEST (test_launch) /* fails, need to be prepared */ fail_if (gst_rtsp_media_seek (media, range)); - fail_unless (gst_rtsp_media_prepare (media)); + fail_unless (gst_rtsp_media_prepare (media, NULL)); str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT); fail_unless (g_str_equal (str, "npt=0-")); @@ -132,10 +132,10 @@ GST_START_TEST (test_media_prepare) fail_unless (GST_IS_RTSP_MEDIA (media)); fail_unless (gst_rtsp_media_n_streams (media) == 1); - fail_unless (gst_rtsp_media_prepare (media)); + fail_unless (gst_rtsp_media_prepare (media, NULL)); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 1); - fail_if (gst_rtsp_media_prepare (media)); + fail_if (gst_rtsp_media_prepare (media, NULL)); g_object_unref (media); gst_rtsp_url_free (url); @@ -155,10 +155,10 @@ GST_START_TEST (test_media_prepare) g_object_set (G_OBJECT (media), "reusable", TRUE, NULL); - fail_unless (gst_rtsp_media_prepare (media)); + fail_unless (gst_rtsp_media_prepare (media, NULL)); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 1); - fail_unless (gst_rtsp_media_prepare (media)); + fail_unless (gst_rtsp_media_prepare (media, NULL)); fail_unless (gst_rtsp_media_unprepare (media)); g_object_unref (media); @@ -220,13 +220,13 @@ GST_START_TEST (test_media_dyn_prepare) g_signal_connect (srcpad, "notify::caps", (GCallback) on_notify_caps, pay); fail_unless (gst_rtsp_media_n_streams (media) == 0); - fail_unless (gst_rtsp_media_prepare (media)); + fail_unless (gst_rtsp_media_prepare (media, NULL)); fail_unless (gst_rtsp_media_n_streams (media) == 1); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 0); fail_unless (gst_rtsp_media_n_streams (media) == 0); - fail_unless (gst_rtsp_media_prepare (media)); + fail_unless (gst_rtsp_media_prepare (media, NULL)); fail_unless (gst_rtsp_media_n_streams (media) == 1); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 0); From fb7c9b812271c1d7d857c093fcb99ace38c6b0f4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Jul 2013 20:48:18 +0200 Subject: [PATCH 0704/1776] auth: use the token after authentication After we authenticated a user, keep the Token around in the state. --- examples/test-auth.c | 27 ++++++++++++++++++++--- gst/rtsp-server/rtsp-auth.c | 40 ++++++++++++++++++----------------- gst/rtsp-server/rtsp-auth.h | 31 +++++++++++++++++++++------ gst/rtsp-server/rtsp-client.h | 6 ++++-- 4 files changed, 73 insertions(+), 31 deletions(-) diff --git a/examples/test-auth.c b/examples/test-auth.c index f5a129ca8b..15843d1d4c 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -62,7 +62,9 @@ main (int argc, char *argv[]) GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; GstRTSPAuth *auth; + GstRTSPToken *token; gchar *basic; + GstStructure *s; gst_init (&argc, &argv); @@ -103,15 +105,34 @@ main (int argc, char *argv[]) /* make a new authentication manager */ auth = gst_rtsp_auth_new (); + + /* make user token */ + token = gst_rtsp_token_new (); + s = gst_rtsp_token_writable_structure (token); + gst_structure_set (s, "manager.cgroup", G_TYPE_STRING, "user", NULL); basic = gst_rtsp_auth_make_basic ("user", "password"); - gst_rtsp_auth_add_basic (auth, basic, "user"); + gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); + gst_rtsp_token_unref (token); + + /* make admin token */ + token = gst_rtsp_token_new (); + s = gst_rtsp_token_writable_structure (token); + gst_structure_set (s, "manager.cgroup", G_TYPE_STRING, "admin", NULL); basic = gst_rtsp_auth_make_basic ("admin", "power"); - gst_rtsp_auth_add_basic (auth, basic, "admin"); + gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); + gst_rtsp_token_unref (token); + + /* make admin2 token */ + token = gst_rtsp_token_new (); + s = gst_rtsp_token_writable_structure (token); + gst_structure_set (s, "manager.cgroup", G_TYPE_STRING, "admin", NULL); basic = gst_rtsp_auth_make_basic ("admin2", "power2"); - gst_rtsp_auth_add_basic (auth, basic, "admin"); + gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); + gst_rtsp_token_unref (token); + /* set as the server authentication manager */ gst_rtsp_server_set_auth (server, auth); g_object_unref (auth); diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index a0df870788..6f115ff6d4 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -48,7 +48,7 @@ static void gst_rtsp_auth_finalize (GObject * obj); static gboolean default_setup (GstRTSPAuth * auth, GstRTSPClient * client, GstRTSPClientState * state); -static gboolean default_validate (GstRTSPAuth * auth, +static gboolean default_authenticate (GstRTSPAuth * auth, GstRTSPClient * client, GstRTSPClientState * state); static gboolean default_check (GstRTSPAuth * auth, GstRTSPClient * client, GQuark hint, GstRTSPClientState * state); @@ -69,7 +69,7 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) gobject_class->finalize = gst_rtsp_auth_finalize; klass->setup = default_setup; - klass->validate = default_validate; + klass->authenticate = default_authenticate; klass->check = default_check; GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth"); @@ -84,7 +84,8 @@ gst_rtsp_auth_init (GstRTSPAuth * auth) g_mutex_init (&priv->lock); - priv->basic = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + priv->basic = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) gst_rtsp_token_unref); /* bitwise or of all methods that need authentication */ priv->methods = GST_RTSP_DESCRIBE | @@ -156,18 +157,19 @@ gst_rtsp_auth_new (void) */ void gst_rtsp_auth_add_basic (GstRTSPAuth * auth, const gchar * basic, - const gchar * authgroup) + GstRTSPToken * token) { GstRTSPAuthPrivate *priv; g_return_if_fail (GST_IS_RTSP_AUTH (auth)); g_return_if_fail (basic != NULL); - g_return_if_fail (authgroup != NULL); + g_return_if_fail (GST_IS_RTSP_TOKEN (token)); priv = auth->priv; g_mutex_lock (&priv->lock); - g_hash_table_replace (priv->basic, g_strdup (basic), g_strdup (authgroup)); + g_hash_table_replace (priv->basic, g_strdup (basic), + gst_rtsp_token_ref (token)); g_mutex_unlock (&priv->lock); } @@ -240,14 +242,14 @@ gst_rtsp_auth_setup (GstRTSPAuth * auth, GstRTSPClient * client, } static gboolean -default_validate (GstRTSPAuth * auth, GstRTSPClient * client, +default_authenticate (GstRTSPAuth * auth, GstRTSPClient * client, GstRTSPClientState * state) { GstRTSPAuthPrivate *priv = auth->priv; GstRTSPResult res; gchar *authorization; - GST_DEBUG_OBJECT (auth, "validate"); + GST_DEBUG_OBJECT (auth, "authenticate"); res = gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION, @@ -257,13 +259,13 @@ default_validate (GstRTSPAuth * auth, GstRTSPClient * client, /* parse type */ if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) { - gchar *authgroup; + GstRTSPToken *token; GST_DEBUG_OBJECT (auth, "check Basic auth"); g_mutex_lock (&priv->lock); - if ((authgroup = g_hash_table_lookup (priv->basic, &authorization[6]))) { - GST_DEBUG_OBJECT (auth, "setting authgroup %s", authgroup); - state->authgroup = authgroup; + if ((token = g_hash_table_lookup (priv->basic, &authorization[6]))) { + GST_DEBUG_OBJECT (auth, "setting token %p", token); + state->token = token; } g_mutex_unlock (&priv->lock); } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) { @@ -290,21 +292,21 @@ default_check (GstRTSPAuth * auth, GstRTSPClient * client, if ((state->method & priv->methods) != 0) { /* we need an authgroup to check */ - if (state->authgroup == NULL) { - if (klass->validate) { - if (!klass->validate (auth, client, state)) - goto validate_failed; + if (state->token == NULL) { + if (klass->authenticate) { + if (!klass->authenticate (auth, client, state)) + goto authenticate_failed; } } - if (state->authgroup == NULL) + if (state->token == NULL) goto no_auth; } return TRUE; -validate_failed: +authenticate_failed: { - GST_DEBUG_OBJECT (auth, "validation failed"); + GST_DEBUG_OBJECT (auth, "check failed"); return FALSE; } no_auth: diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index fd9b679a5a..4da1dbfda7 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -27,6 +27,7 @@ typedef struct _GstRTSPAuthClass GstRTSPAuthClass; typedef struct _GstRTSPAuthPrivate GstRTSPAuthPrivate; #include "rtsp-client.h" +#include "rtsp-token.h" G_BEGIN_DECLS @@ -50,15 +51,31 @@ struct _GstRTSPAuth { GstRTSPAuthPrivate *priv; }; +/** + * GstRTSPAuthClass: + * @setup: called when an unauthorized resource has been accessed and + * authentication needs to be requested to the client. The default + * implementation adds basic authentication to the response. + * @authenticate: check the authentication of a client. The default implementation + * checks if the authentication in the header matches one of the basic + * authentication tokens. This function should set the authgroup field + * in the state. + * @check: check if a resource can be accessed. this function should + * call validate to authenticate the client when needed. The default + * implementation disallows unauthenticated access to all methods + * except OPTIONS. + * + * The authentication class. + */ struct _GstRTSPAuthClass { GObjectClass parent_class; - gboolean (*setup) (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPClientState *state); - gboolean (*validate) (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPClientState *state); - gboolean (*check) (GstRTSPAuth *auth, GstRTSPClient * client, - GQuark hint, GstRTSPClientState *state); + gboolean (*setup) (GstRTSPAuth *auth, GstRTSPClient * client, + GstRTSPClientState *state); + gboolean (*authenticate) (GstRTSPAuth *auth, GstRTSPClient * client, + GstRTSPClientState *state); + gboolean (*check) (GstRTSPAuth *auth, GstRTSPClient * client, + GQuark hint, GstRTSPClientState *state); }; GType gst_rtsp_auth_get_type (void); @@ -66,7 +83,7 @@ GType gst_rtsp_auth_get_type (void); GstRTSPAuth * gst_rtsp_auth_new (void); void gst_rtsp_auth_add_basic (GstRTSPAuth *auth, const gchar * basic, - const gchar *authgroup); + GstRTSPToken *token); void gst_rtsp_auth_remove_basic (GstRTSPAuth *auth, const gchar * basic); gboolean gst_rtsp_auth_setup (GstRTSPAuth *auth, GstRTSPClient * client, diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 86ae980ed6..d772b389df 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -35,6 +35,7 @@ typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; #include "rtsp-session-pool.h" #include "rtsp-session-media.h" #include "rtsp-auth.h" +#include "rtsp-token.h" #include "rtsp-sdp.h" #define GST_TYPE_RTSP_CLIENT (gst_rtsp_client_get_type ()) @@ -51,7 +52,8 @@ typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; * @request: the complete request * @uri: the complete url parsed from @request * @method: the parsed method of @uri - * @authgroup: authorisation group + * @auth: the current auth object or NULL + * @token: authorisation token * @session: the session, can be NULL * @sessmedia: the session media for the url can be NULL * @factory: the media factory for the url, can be NULL. @@ -66,7 +68,7 @@ struct _GstRTSPClientState { GstRTSPUrl *uri; GstRTSPMethod method; GstRTSPAuth *auth; - const gchar *authgroup; + GstRTSPToken *token; GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; GstRTSPMediaFactory *factory; From a63f4a2a4c428be58e32e3f08d1fcbb99f5ac29b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 8 Jul 2013 16:29:01 +0200 Subject: [PATCH 0705/1776] auth: add auth checks Add an enum with auth checks and implement the checks in the auth object. Perform the checks from the client. --- examples/test-auth.c | 11 ++++++++--- gst/rtsp-server/rtsp-auth.c | 35 ++++++++++++++++++++++++----------- gst/rtsp-server/rtsp-auth.h | 16 ++++++++++++++-- gst/rtsp-server/rtsp-client.c | 19 ++++++++++++++++++- 4 files changed, 64 insertions(+), 17 deletions(-) diff --git a/examples/test-auth.c b/examples/test-auth.c index 15843d1d4c..75455de6b9 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -65,6 +65,8 @@ main (int argc, char *argv[]) GstRTSPToken *token; gchar *basic; GstStructure *s; + gchar *role_user[] = { "user", NULL }; + gchar *role_admin[] = { "admin", NULL }; gst_init (&argc, &argv); @@ -109,7 +111,8 @@ main (int argc, char *argv[]) /* make user token */ token = gst_rtsp_token_new (); s = gst_rtsp_token_writable_structure (token); - gst_structure_set (s, "manager.cgroup", G_TYPE_STRING, "user", NULL); + gst_structure_set (s, "manager.role", G_TYPE_STRING, "user", NULL); + gst_structure_set (s, "factory.media.roles", G_TYPE_STRV, role_user, NULL); basic = gst_rtsp_auth_make_basic ("user", "password"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); @@ -118,7 +121,8 @@ main (int argc, char *argv[]) /* make admin token */ token = gst_rtsp_token_new (); s = gst_rtsp_token_writable_structure (token); - gst_structure_set (s, "manager.cgroup", G_TYPE_STRING, "admin", NULL); + gst_structure_set (s, "manager.role", G_TYPE_STRING, "admin", NULL); + gst_structure_set (s, "factory.media.roles", G_TYPE_STRV, role_admin, NULL); basic = gst_rtsp_auth_make_basic ("admin", "power"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); @@ -127,7 +131,8 @@ main (int argc, char *argv[]) /* make admin2 token */ token = gst_rtsp_token_new (); s = gst_rtsp_token_writable_structure (token); - gst_structure_set (s, "manager.cgroup", G_TYPE_STRING, "admin", NULL); + gst_structure_set (s, "manager.role", G_TYPE_STRING, "admin", NULL); + gst_structure_set (s, "factory.media.roles", G_TYPE_STRV, role_admin, NULL); basic = gst_rtsp_auth_make_basic ("admin2", "power2"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 6f115ff6d4..ac3fb3ecf4 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -283,35 +283,48 @@ no_auth: static gboolean default_check (GstRTSPAuth * auth, GstRTSPClient * client, - GQuark hint, GstRTSPClientState * state) + GstRTSPAuthCheck check, GstRTSPClientState * state) { GstRTSPAuthPrivate *priv = auth->priv; GstRTSPAuthClass *klass; + gboolean need_authorized = FALSE; + gboolean res = FALSE; klass = GST_RTSP_AUTH_GET_CLASS (auth); - if ((state->method & priv->methods) != 0) { - /* we need an authgroup to check */ + switch (check) { + case GST_RTSP_AUTH_CHECK_URL: + if ((state->method & priv->methods) != 0) + need_authorized = TRUE; + else + res = TRUE; + break; + case GST_RTSP_AUTH_CHECK_FACTORY: + res = TRUE; + break; + } + + if (need_authorized) { + /* we need a token to check */ if (state->token == NULL) { if (klass->authenticate) { if (!klass->authenticate (auth, client, state)) goto authenticate_failed; } } - if (state->token == NULL) goto no_auth; } - return TRUE; + return res; authenticate_failed: { - GST_DEBUG_OBJECT (auth, "check failed"); + GST_DEBUG_OBJECT (auth, "authenticate failed"); return FALSE; } no_auth: { - GST_DEBUG_OBJECT (auth, "no authorization group found"); + GST_DEBUG_OBJECT (auth, "no authorization token found"); return FALSE; } } @@ -320,17 +333,17 @@ no_auth: * gst_rtsp_auth_check: * @auth: a #GstRTSPAuth * @client: the client - * @hint: a hint + * @check: the item to check * @state: client state * - * Check if @client with state is authorized to perform @hint in the + * Check if @client with state is authorized to perform @check in the * current @state. * * Returns: FALSE if check failed. */ gboolean gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client, - GQuark hint, GstRTSPClientState * state) + GstRTSPAuthCheck check, GstRTSPClientState * state) { gboolean result = FALSE; GstRTSPAuthClass *klass; @@ -344,7 +357,7 @@ gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client, GST_DEBUG_OBJECT (auth, "check auth"); if (klass->check) - result = klass->check (auth, client, hint, state); + result = klass->check (auth, client, check, state); return result; } diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 4da1dbfda7..55c5faf613 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -40,6 +40,18 @@ G_BEGIN_DECLS #define GST_RTSP_AUTH_CAST(obj) ((GstRTSPAuth*)(obj)) #define GST_RTSP_AUTH_CLASS_CAST(klass) ((GstRTSPAuthClass*)(klass)) +/** + * GstRTSPAuthCheck: + * @GST_RTSP_AUTH_CHECK_URL: Check url and method + * @GST_RTSP_AUTH_CHECK_FACTORY: Check access to factory + * + * Different authorization checks + */ +typedef enum { + GST_RTSP_AUTH_CHECK_URL, + GST_RTSP_AUTH_CHECK_FACTORY, +} GstRTSPAuthCheck; + /** * GstRTSPAuth: * @@ -75,7 +87,7 @@ struct _GstRTSPAuthClass { gboolean (*authenticate) (GstRTSPAuth *auth, GstRTSPClient * client, GstRTSPClientState *state); gboolean (*check) (GstRTSPAuth *auth, GstRTSPClient * client, - GQuark hint, GstRTSPClientState *state); + GstRTSPAuthCheck check, GstRTSPClientState *state); }; GType gst_rtsp_auth_get_type (void); @@ -90,7 +102,7 @@ gboolean gst_rtsp_auth_setup (GstRTSPAuth *auth, GstRTSPC GstRTSPClientState *state); gboolean gst_rtsp_auth_check (GstRTSPAuth *auth, GstRTSPClient * client, - GQuark hint, GstRTSPClientState *state); + GstRTSPAuthCheck check, GstRTSPClientState *state); /* helpers */ gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass); diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 47956e5583..542c44dbfb 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -500,6 +500,12 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) path, matched))) goto no_factory; + state->factory = factory; + + if (!gst_rtsp_auth_check (priv->auth, client, GST_RTSP_AUTH_CHECK_FACTORY, + state)) + goto not_authorized; + if (matched) path_len = *matched; else @@ -537,6 +543,7 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) } g_object_unref (factory); + state->factory = NULL; if (media) g_object_ref (media); @@ -556,11 +563,18 @@ no_factory: send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return NULL; } +not_authorized: + { + GST_ERROR ("client %p: not authorized for factory %p", client, factory); + handle_unauthorized_request (client, priv->auth, state); + return NULL; + } no_media: { GST_ERROR ("client %p: can't create media", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); g_object_unref (factory); + state->factory = NULL; return NULL; } no_prepare: @@ -568,7 +582,9 @@ no_prepare: GST_ERROR ("client %p: can't prepare media", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); g_object_unref (media); + state->media = media; g_object_unref (factory); + state->factory = NULL; return NULL; } } @@ -1824,7 +1840,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) state.session = session; if (priv->auth) { - if (!gst_rtsp_auth_check (priv->auth, client, 0, &state)) + if (!gst_rtsp_auth_check (priv->auth, client, GST_RTSP_AUTH_CHECK_URL, + &state)) goto not_authorized; state.auth = priv->auth; From 8f008807add8981ec78c60c6d54c38deafe39fbb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Jul 2013 14:31:15 +0200 Subject: [PATCH 0706/1776] permissions: add permissions object Add a mini object to store permissions based on a role. --- gst/rtsp-server/Makefile.am | 2 + gst/rtsp-server/rtsp-permissions.c | 209 +++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-permissions.h | 95 +++++++++++++ 3 files changed, 306 insertions(+) create mode 100644 gst/rtsp-server/rtsp-permissions.c create mode 100644 gst/rtsp-server/rtsp-permissions.h diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index c414d8cee9..170fce55fb 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -7,6 +7,7 @@ public_headers = \ rtsp-media-factory.h \ rtsp-media-factory-uri.h \ rtsp-mount-points.h \ + rtsp-permissions.h \ rtsp-stream.h \ rtsp-stream-transport.h \ rtsp-session.h \ @@ -25,6 +26,7 @@ c_sources = \ rtsp-media-factory.c \ rtsp-media-factory-uri.c \ rtsp-mount-points.c \ + rtsp-permissions.c \ rtsp-stream.c \ rtsp-stream-transport.c \ rtsp-session.c \ diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c new file mode 100644 index 0000000000..4d5e1928e0 --- /dev/null +++ b/gst/rtsp-server/rtsp-permissions.c @@ -0,0 +1,209 @@ +/* GStreamer + * Copyright (C) 2013 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include "rtsp-permissions.h" + +typedef struct _GstRTSPPermissionsImpl +{ + GstRTSPPermissions permissions; + + /* Roles, array of RoleEntry */ + GArray *roles; +} GstRTSPPermissionsImpl; + +typedef struct +{ + gchar *role; + GstStructure *structure; +} RoleEntry; + +static void +clear_role_entry (RoleEntry * role) +{ + g_free (role->role); + gst_structure_set_parent_refcount (role->structure, NULL); + gst_structure_free (role->structure); +} + +//GST_DEBUG_CATEGORY_STATIC (rtsp_permissions_debug); +//#define GST_CAT_DEFAULT rtsp_permissions_debug + +GST_DEFINE_MINI_OBJECT_TYPE (GstRTSPPermissions, gst_rtsp_permissions); + +static void gst_rtsp_permissions_init (GstRTSPPermissionsImpl * permissions, + GstStructure * structure); + +static void +_gst_rtsp_permissions_free (GstRTSPPermissions * permissions) +{ + GstRTSPPermissionsImpl *impl = (GstRTSPPermissionsImpl *) permissions; + + g_array_free (impl->roles, TRUE); + + g_slice_free1 (sizeof (GstRTSPPermissionsImpl), permissions); +} + +static GstRTSPPermissions * +_gst_rtsp_permissions_copy (GstRTSPPermissionsImpl * permissions) +{ + GstRTSPPermissionsImpl *copy; + GstStructure *structure; + + copy = g_slice_new0 (GstRTSPPermissionsImpl); + gst_rtsp_permissions_init (copy, structure); + + return GST_RTSP_PERMISSIONS (copy); +} + +static void +gst_rtsp_permissions_init (GstRTSPPermissionsImpl * permissions, + GstStructure * structure) +{ + gst_mini_object_init (GST_MINI_OBJECT_CAST (permissions), 0, + GST_TYPE_RTSP_PERMISSIONS, + (GstMiniObjectCopyFunction) _gst_rtsp_permissions_copy, NULL, + (GstMiniObjectFreeFunction) _gst_rtsp_permissions_free); + + permissions->roles = g_array_new (FALSE, TRUE, sizeof (RoleEntry)); + g_array_set_clear_func (permissions->roles, + (GDestroyNotify) clear_role_entry); +} + +/** + * gst_rtsp_permissions_new: + * + * Create a new empty Authorization permissions. + * + * Returns: (transfer full): a new empty authorization permissions. + */ +GstRTSPPermissions * +gst_rtsp_permissions_new (void) +{ + GstRTSPPermissionsImpl *permissions; + + permissions = g_slice_new0 (GstRTSPPermissionsImpl); + + gst_rtsp_permissions_init (permissions, + gst_structure_new_empty ("GstRTSPPermissions")); + + return GST_RTSP_PERMISSIONS (permissions); +} + +/** + * gst_rtsp_permissions_add_role: + * @permissions: a #GstRTSPPermissions + * + * Add the configuration in @structure to @permissions for @role. + */ +void +gst_rtsp_permissions_add_role (GstRTSPPermissions * permissions, + const gchar * role, GstStructure * structure) +{ + GstRTSPPermissionsImpl *impl = (GstRTSPPermissionsImpl *) permissions; + gint i, len; + RoleEntry item; + gboolean found; + + g_return_if_fail (GST_IS_RTSP_PERMISSIONS (permissions)); + g_return_if_fail (gst_mini_object_is_writable (&permissions->mini_object)); + g_return_if_fail (role != NULL); + g_return_if_fail (structure != NULL); + + len = impl->roles->len; + found = FALSE; + for (i = 0; i < len; i++) { + RoleEntry *entry = &g_array_index (impl->roles, RoleEntry, i); + + if (g_str_equal (entry->role, role)) { + gst_structure_free (entry->structure); + entry->structure = structure; + found = TRUE; + break; + } + } + if (!found) { + item.role = g_strdup (role); + item.structure = structure; + gst_structure_set_parent_refcount (structure, + &impl->permissions.mini_object.refcount); + g_array_append_val (impl->roles, item); + } +} + +/** + * gst_rtsp_permissions_remove_role: + * @permissions: a #GstRTSPPermissions + * + */ +void +gst_rtsp_permissions_remove_role (GstRTSPPermissions * permissions, + const gchar * role) +{ + g_return_if_fail (GST_IS_RTSP_PERMISSIONS (permissions)); + g_return_if_fail (gst_mini_object_is_writable (&permissions->mini_object)); + g_return_if_fail (role != NULL); +} + +/** + * gst_rtsp_permissions_get_role: + * @permissions: a #GstRTSPPermissions + * + */ +const GstStructure * +gst_rtsp_permissions_get_role (GstRTSPPermissions * permissions, + const gchar * role) +{ + GstRTSPPermissionsImpl *impl = (GstRTSPPermissionsImpl *) permissions; + gint i, len; + + g_return_val_if_fail (GST_IS_RTSP_PERMISSIONS (permissions), NULL); + g_return_val_if_fail (role != NULL, NULL); + + len = impl->roles->len; + for (i = 0; i < len; i++) { + RoleEntry *entry = &g_array_index (impl->roles, RoleEntry, i); + + if (g_str_equal (entry->role, role)) + return entry->structure; + } + return NULL; +} + +gboolean +gst_rtsp_permissions_is_allowed (GstRTSPPermissions * permissions, + const gchar * role, const gchar * permission) +{ + const GstStructure *str; + gboolean result; + + g_return_val_if_fail (GST_IS_RTSP_PERMISSIONS (permissions), FALSE); + g_return_val_if_fail (role != NULL, FALSE); + g_return_val_if_fail (permission != NULL, FALSE); + + str = gst_rtsp_permissions_get_role (permissions, role); + if (str == NULL) + return FALSE; + + if (!gst_structure_get_boolean (str, permission, &result)) + result = FALSE; + + return result; +} diff --git a/gst/rtsp-server/rtsp-permissions.h b/gst/rtsp-server/rtsp-permissions.h new file mode 100644 index 0000000000..5e06841c23 --- /dev/null +++ b/gst/rtsp-server/rtsp-permissions.h @@ -0,0 +1,95 @@ +/* GStreamer + * Copyright (C) 2010 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#ifndef __GST_RTSP_PERMISSIONS_H__ +#define __GST_RTSP_PERMISSIONS_H__ + +typedef struct _GstRTSPPermissions GstRTSPPermissions; + +G_BEGIN_DECLS + +GType gst_rtsp_permissions_get_type (void); + +#define GST_TYPE_RTSP_PERMISSIONS (gst_rtsp_permissions_get_type ()) +#define GST_IS_RTSP_PERMISSIONS(obj) (GST_IS_MINI_OBJECT_TYPE (obj, GST_TYPE_RTSP_PERMISSIONS)) +#define GST_RTSP_PERMISSIONS_CAST(obj) ((GstRTSPPermissions*)(obj)) +#define GST_RTSP_PERMISSIONS(obj) (GST_RTSP_PERMISSIONS_CAST(obj)) + + +/** + * GstRTSPPermissions: + * + * The opaque permissions structure. It is used to define the permissions + * of objects in different roles. + */ +struct _GstRTSPPermissions { + GstMiniObject mini_object; +}; + +/* refcounting */ +/** + * gst_rtsp_permissions_ref: + * @permissions: The permissions to refcount + * + * Increase the refcount of this permissions. + * + * Returns: (transfer full): @permissions (for convenience when doing assignments) + */ +#ifdef _FOOL_GTK_DOC_ +G_INLINE_FUNC GstRTSPPermissions * gst_rtsp_permissions_ref (GstRTSPPermissions * permissions); +#endif + +static inline GstRTSPPermissions * +gst_rtsp_permissions_ref (GstRTSPPermissions * permissions) +{ + return (GstRTSPPermissions *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (permissions)); +} + +/** + * gst_rtsp_permissions_unref: + * @permissions: (transfer full): the permissions to refcount + * + * Decrease the refcount of an permissions, freeing it if the refcount reaches 0. + */ +#ifdef _FOOL_GTK_DOC_ +G_INLINE_FUNC void gst_rtsp_permissions_unref (GstRTSPPermissions * permissions); +#endif + +static inline void +gst_rtsp_permissions_unref (GstRTSPPermissions * permissions) +{ + gst_mini_object_unref (GST_MINI_OBJECT_CAST (permissions)); +} + + +GstRTSPPermissions * gst_rtsp_permissions_new (void); + +void gst_rtsp_permissions_add_role (GstRTSPPermissions *permissions, const gchar *role, + GstStructure *structure); +void gst_rtsp_permissions_remove_role (GstRTSPPermissions *permissions, const gchar *role); +const GstStructure * gst_rtsp_permissions_get_role (GstRTSPPermissions *permissions, const gchar *role); + +gboolean gst_rtsp_permissions_is_allowed (GstRTSPPermissions *permissions, + const gchar *role, const gchar *permission); + +G_END_DECLS + +#endif /* __GST_RTSP_PERMISSIONS_H__ */ From 0499a1ec7db7911569b53a854eb7eae1b7d7882e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Jul 2013 14:33:43 +0200 Subject: [PATCH 0707/1776] media: make it possible to set permissions Make it possible to set permissions on media and media factory objects --- gst/rtsp-server/rtsp-media-factory.c | 52 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 48 ++++++++++++++----------- gst/rtsp-server/rtsp-media.c | 52 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 6 +++- 4 files changed, 136 insertions(+), 22 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index b6fa8c033f..d210d5f8c7 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -29,6 +29,7 @@ struct _GstRTSPMediaFactoryPrivate { GMutex lock; /* protects everything but medias */ + GstRTSPPermissions *permissions; gchar *launch; gboolean shared; gboolean eos_shutdown; @@ -274,6 +275,57 @@ gst_rtsp_media_factory_new (void) return result; } +/** + * gst_rtsp_media_factory_set_permissions: + * @factory: a #GstRTSPMediaFactory + * @permissions: a #GstRTSPPermissions + * + * Set @permissions on @factory. + */ +void +gst_rtsp_media_factory_set_permissions (GstRTSPMediaFactory * factory, + GstRTSPPermissions * permissions) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + if (priv->permissions) + gst_rtsp_permissions_unref (priv->permissions); + if ((priv->permissions = permissions)) + gst_rtsp_permissions_ref (permissions); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_permissions: + * @factory: a #GstRTSPMediaFactory + * + * Get the permissions object from @factory. + * + * Returns: (transfer full): a #GstRTSPPermissions object, unref after usage. + */ +GstRTSPPermissions * +gst_rtsp_media_factory_get_permissions (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + GstRTSPPermissions *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + if ((result = priv->permissions)) + gst_rtsp_permissions_ref (result); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} + /** * gst_rtsp_media_factory_set_launch: * @factory: a #GstRTSPMediaFactory diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index a492422e38..896261a13b 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -21,7 +21,7 @@ #include #include "rtsp-media.h" -#include "rtsp-auth.h" +#include "rtsp-permissions.h" #include "rtsp-address-pool.h" #ifndef __GST_RTSP_MEDIA_FACTORY_H__ @@ -99,34 +99,40 @@ GType gst_rtsp_media_factory_get_type (void); GstRTSPMediaFactory * gst_rtsp_media_factory_new (void); /* configuring the factory */ -void gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, - const gchar *launch); -gchar * gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_permissions (GstRTSPMediaFactory *factory, + GstRTSPPermissions *permissions); +GstRTSPPermissions * gst_rtsp_media_factory_get_permissions (GstRTSPMediaFactory *factory); -void gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory, - gboolean shared); -gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, + const gchar *launch); +gchar * gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory); -void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory *factory, - gboolean eos_shutdown); -gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory, + gboolean shared); +gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory); -void gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory *factory, GstRTSPLowerTrans protocols); -GstRTSPLowerTrans gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory *factory, + gboolean eos_shutdown); +gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory); -void gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory, - GstRTSPAddressPool * pool); -GstRTSPAddressPool * gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory); +void gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory *factory, + GstRTSPLowerTrans protocols); +GstRTSPLowerTrans gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory *factory); -void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint size); -guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory); +void gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory, + GstRTSPAddressPool * pool); +GstRTSPAddressPool * gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory); + +void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, + guint size); +guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory); /* creating the media from the factory and a url */ -GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, - const GstRTSPUrl *url); +GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, + const GstRTSPUrl *url); -GstElement * gst_rtsp_media_factory_create_element (GstRTSPMediaFactory *factory, - const GstRTSPUrl *url); +GstElement * gst_rtsp_media_factory_create_element (GstRTSPMediaFactory *factory, + const GstRTSPUrl *url); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 2a875b37f9..777a27f93d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -34,6 +34,7 @@ struct _GstRTSPMediaPrivate GCond cond; /* protected by lock */ + GstRTSPPermissions *permissions; gboolean shared; gboolean reusable; GstRTSPLowerTrans protocols; @@ -496,6 +497,57 @@ gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline) gst_bin_add (GST_BIN_CAST (pipeline), priv->element); } +/** + * gst_rtsp_media_set_permissions: + * @media: a #GstRTSPMedia + * @permissions: a #GstRTSPPermissions + * + * Set @permissions on @media. + */ +void +gst_rtsp_media_set_permissions (GstRTSPMedia * media, + GstRTSPPermissions * permissions) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + if (priv->permissions) + gst_rtsp_permissions_unref (priv->permissions); + if ((priv->permissions = permissions)) + gst_rtsp_permissions_ref (permissions); + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_get_permissions: + * @media: a #GstRTSPMedia + * + * Get the permissions object from @media. + * + * Returns: (transfer full): a #GstRTSPPermissions object, unref after usage. + */ +GstRTSPPermissions * +gst_rtsp_media_get_permissions (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + GstRTSPPermissions *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->permissions)) + gst_rtsp_permissions_ref (result); + g_mutex_unlock (&priv->lock); + + return result; +} + /** * gst_rtsp_media_set_shared: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index f76a6ddcd5..8158891ee2 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -42,7 +42,7 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass; typedef struct _GstRTSPMediaPrivate GstRTSPMediaPrivate; #include "rtsp-stream.h" -#include "rtsp-auth.h" +#include "rtsp-permissions.h" #include "rtsp-address-pool.h" /** @@ -125,6 +125,10 @@ void gst_rtsp_media_take_pipeline (GstRTSPMedia *media, GstP GstRTSPMediaStatus gst_rtsp_media_get_status (GstRTSPMedia *media); +void gst_rtsp_media_set_permissions (GstRTSPMedia *media, + GstRTSPPermissions *permissions); +GstRTSPPermissions * gst_rtsp_media_get_permissions (GstRTSPMedia *media); + void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared); gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media); From c9d6455ad31f4d9c19a9396f27c28b535e43fb0a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Jul 2013 16:01:29 +0200 Subject: [PATCH 0708/1776] client: add state to current thread Add the client to the ClientState object. Place the ClientState on the current thread. --- gst/rtsp-server/rtsp-client.c | 20 ++++++++++++++++++++ gst/rtsp-server/rtsp-client.h | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 542c44dbfb..6af4058125 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1780,6 +1780,22 @@ client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) } } +static GPrivate state_key; + +/** + * gst_rtsp_client_state_get_current: + * + * Get the current #GstRTSPClientState. This object is retrieved from the + * current thread that is handling the request for a client. + * + * Returns: a #GstRTSPClientState + */ +GstRTSPClientState * +gst_rtsp_client_state_get_current (void) +{ + return g_private_get (&state_key); +} + static void handle_request (GstRTSPClient * client, GstRTSPMessage * request) { @@ -1794,8 +1810,11 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) GstRTSPMessage response = { 0 }; gchar *sessid; + state.client = client; state.request = request; state.response = &response; + state.auth = priv->auth; + g_private_set (&state_key, &state); if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) { gst_rtsp_message_dump (request); @@ -1883,6 +1902,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) } done: + g_private_set (&state_key, NULL); if (session) g_object_unref (session); if (uri) diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index d772b389df..a7311c234b 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -49,6 +49,7 @@ typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; /** * GstRTSPClientState: + * @client: the client * @request: the complete request * @uri: the complete url parsed from @request * @method: the parsed method of @uri @@ -64,6 +65,7 @@ typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; * Information passed around containing the client state of a request. */ struct _GstRTSPClientState { + GstRTSPClient *client; GstRTSPMessage *request; GstRTSPUrl *uri; GstRTSPMethod method; @@ -77,6 +79,8 @@ struct _GstRTSPClientState { GstRTSPMessage *response; }; +GstRTSPClientState * gst_rtsp_client_state_get_current (void); + /** * GstRTSPClientSendFunc: * @client: a #GstRTSPClient From d7dec333282cdfdcd012ea122633a76689a5a936 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Jul 2013 16:04:35 +0200 Subject: [PATCH 0709/1776] auth: simplify auth checks Remove client from methods, it's now in the state Perform the check specified by the string, use the information from the thread local context. --- gst/rtsp-server/rtsp-auth.c | 126 ++++++++++++++++++++-------------- gst/rtsp-server/rtsp-auth.h | 75 ++++++++++++++------ gst/rtsp-server/rtsp-client.c | 25 ++++--- 3 files changed, 142 insertions(+), 84 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index ac3fb3ecf4..a6db8a6f0a 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -46,12 +46,11 @@ static void gst_rtsp_auth_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_auth_finalize (GObject * obj); -static gboolean default_setup (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state); +static gboolean default_setup (GstRTSPAuth * auth, GstRTSPClientState * state); static gboolean default_authenticate (GstRTSPAuth * auth, - GstRTSPClient * client, GstRTSPClientState * state); -static gboolean default_check (GstRTSPAuth * auth, GstRTSPClient * client, - GQuark hint, GstRTSPClientState * state); + GstRTSPClientState * state); +static gboolean default_check (GstRTSPAuth * auth, GstRTSPClientState * state, + const gchar * check); G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT); @@ -197,8 +196,7 @@ gst_rtsp_auth_remove_basic (GstRTSPAuth * auth, const gchar * basic) } static gboolean -default_setup (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state) +default_setup (GstRTSPAuth * auth, GstRTSPClientState * state) { if (state->response == NULL) return FALSE; @@ -221,14 +219,12 @@ default_setup (GstRTSPAuth * auth, GstRTSPClient * client, * Returns: FALSE if something is wrong. */ gboolean -gst_rtsp_auth_setup (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state) +gst_rtsp_auth_setup (GstRTSPAuth * auth, GstRTSPClientState * state) { gboolean result = FALSE; GstRTSPAuthClass *klass; g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE); - g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); g_return_val_if_fail (state != NULL, FALSE); klass = GST_RTSP_AUTH_GET_CLASS (auth); @@ -236,14 +232,13 @@ gst_rtsp_auth_setup (GstRTSPAuth * auth, GstRTSPClient * client, GST_DEBUG_OBJECT (auth, "setup auth"); if (klass->setup) - result = klass->setup (auth, client, state); + result = klass->setup (auth, state); return result; } static gboolean -default_authenticate (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPClientState * state) +default_authenticate (GstRTSPAuth * auth, GstRTSPClientState * state) { GstRTSPAuthPrivate *priv = auth->priv; GstRTSPResult res; @@ -282,41 +277,25 @@ no_auth: } static gboolean -default_check (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPAuthCheck check, GstRTSPClientState * state) +ensure_authenticated (GstRTSPAuth * auth, GstRTSPClientState * state) { - GstRTSPAuthPrivate *priv = auth->priv; GstRTSPAuthClass *klass; - gboolean need_authorized = FALSE; - gboolean res = FALSE; klass = GST_RTSP_AUTH_GET_CLASS (auth); - switch (check) { - case GST_RTSP_AUTH_CHECK_URL: - if ((state->method & priv->methods) != 0) - need_authorized = TRUE; - else - res = TRUE; - break; - case GST_RTSP_AUTH_CHECK_FACTORY: - res = TRUE; - break; - } - - if (need_authorized) { - /* we need a token to check */ - if (state->token == NULL) { - if (klass->authenticate) { - if (!klass->authenticate (auth, client, state)) - goto authenticate_failed; - } + /* we need a token to check */ + if (state->token == NULL) { + if (klass->authenticate) { + if (!klass->authenticate (auth, state)) + goto authenticate_failed; } - if (state->token == NULL) - goto no_auth; } - return res; + if (state->token == NULL) + goto no_auth; + return TRUE; + +/* ERRORS */ authenticate_failed: { GST_DEBUG_OBJECT (auth, "authenticate failed"); @@ -329,37 +308,82 @@ no_auth: } } +static gboolean +default_check (GstRTSPAuth * auth, GstRTSPClientState * state, + const gchar * check) +{ + GstRTSPAuthPrivate *priv = auth->priv; + gboolean res = FALSE; + + if (g_str_equal (check, GST_RTSP_AUTH_CHECK_URL)) { + if ((state->method & priv->methods) != 0) + res = ensure_authenticated (auth, state); + else + res = TRUE; + } else if (g_str_has_prefix (check, "auth.check.media.factory.")) { + const gchar *role; + GstRTSPPermissions *perms; + + if (!(role = + gst_rtsp_token_get_string (state->token, + GST_RTSP_MEDIA_FACTORY_ROLE))) + goto done; + if (!(perms = gst_rtsp_media_factory_get_permissions (state->factory))) + goto done; + + if (g_str_equal (check, "auth.check.media.factory.access")) + res = + gst_rtsp_permissions_is_allowed (perms, role, + GST_RTSP_MEDIA_FACTORY_PERM_ACCESS); + else if (g_str_equal (check, "auth.check.media.factory.construct")) + res = + gst_rtsp_permissions_is_allowed (perms, role, + GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT); + } +done: + return res; +} + /** * gst_rtsp_auth_check: - * @auth: a #GstRTSPAuth - * @client: the client * @check: the item to check - * @state: client state * - * Check if @client with state is authorized to perform @check in the - * current @state. + * Check if @check is allowed in the current context. * * Returns: FALSE if check failed. */ gboolean -gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client, - GstRTSPAuthCheck check, GstRTSPClientState * state) +gst_rtsp_auth_check (const gchar * check) { gboolean result = FALSE; GstRTSPAuthClass *klass; + GstRTSPClientState *state; + GstRTSPAuth *auth; - g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE); - g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); - g_return_val_if_fail (state != NULL, FALSE); + g_return_val_if_fail (check != NULL, FALSE); + + if (!(state = gst_rtsp_client_state_get_current ())) + goto no_state; + + /* no auth, we don't need to check */ + if (!(auth = state->auth)) + return TRUE; klass = GST_RTSP_AUTH_GET_CLASS (auth); GST_DEBUG_OBJECT (auth, "check auth"); if (klass->check) - result = klass->check (auth, client, check, state); + result = klass->check (auth, state, check); return result; + + /* ERRORS */ +no_state: + { + GST_ERROR ("no clientstate found"); + return FALSE; + } } /** diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 55c5faf613..cb8579fae1 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -40,18 +40,6 @@ G_BEGIN_DECLS #define GST_RTSP_AUTH_CAST(obj) ((GstRTSPAuth*)(obj)) #define GST_RTSP_AUTH_CLASS_CAST(klass) ((GstRTSPAuthClass*)(klass)) -/** - * GstRTSPAuthCheck: - * @GST_RTSP_AUTH_CHECK_URL: Check url and method - * @GST_RTSP_AUTH_CHECK_FACTORY: Check access to factory - * - * Different authorization checks - */ -typedef enum { - GST_RTSP_AUTH_CHECK_URL, - GST_RTSP_AUTH_CHECK_FACTORY, -} GstRTSPAuthCheck; - /** * GstRTSPAuth: * @@ -82,12 +70,10 @@ struct _GstRTSPAuth { struct _GstRTSPAuthClass { GObjectClass parent_class; - gboolean (*setup) (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPClientState *state); - gboolean (*authenticate) (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPClientState *state); - gboolean (*check) (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPAuthCheck check, GstRTSPClientState *state); + gboolean (*setup) (GstRTSPAuth *auth, GstRTSPClientState *state); + gboolean (*authenticate) (GstRTSPAuth *auth, GstRTSPClientState *state); + gboolean (*check) (GstRTSPAuth *auth, GstRTSPClientState *state, + const gchar *check); }; GType gst_rtsp_auth_get_type (void); @@ -98,15 +84,60 @@ void gst_rtsp_auth_add_basic (GstRTSPAuth *auth, const gc GstRTSPToken *token); void gst_rtsp_auth_remove_basic (GstRTSPAuth *auth, const gchar * basic); -gboolean gst_rtsp_auth_setup (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPClientState *state); +gboolean gst_rtsp_auth_setup (GstRTSPAuth *auth, GstRTSPClientState *state); + +gboolean gst_rtsp_auth_check (const gchar *check); -gboolean gst_rtsp_auth_check (GstRTSPAuth *auth, GstRTSPClient * client, - GstRTSPAuthCheck check, GstRTSPClientState *state); /* helpers */ gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass); +/* checks */ +/** + * GST_RTSP_AUTH_CHECK_URL: + * + * Check the URL and methods + */ +#define GST_RTSP_AUTH_CHECK_URL "auth.check.url" +/** + * GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS: + * + * Check if access is allowed to a factory + */ +#define GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS "auth.check.media.factory.access" +/** + * GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT: + * + * Check if media can be constructed from a media factory + */ +#define GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT "auth.check.media.factory.construct" + + +/* tokens */ +/** + * GST_RTSP_MEDIA_FACTORY_ROLE: + * + * G_TYPE_STRING, the role to use when dealing with media factories + */ +#define GST_RTSP_MEDIA_FACTORY_ROLE "media.factory.role" + +/* permissions */ +/** + * GST_RTSP_MEDIA_FACTORY_PERM_ACCESS: + * + * G_TYPE_BOOLEAN, %TRUE if the media can be accessed, %FALSE will + * return a 404 Not Found error when trying to access the media. + */ +#define GST_RTSP_MEDIA_FACTORY_PERM_ACCESS "media.factory.access" +/** + * GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT: + * + * G_TYPE_BOOLEAN, %TRUE if the media can be constructed, %FALSE will + * return a 404 Not Found error when trying to access the media. + */ +#define GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT "media.factory.construct" + + G_END_DECLS #endif /* __GST_RTSP_AUTH_H__ */ diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6af4058125..50d68cfe33 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -456,7 +456,7 @@ handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth, if (auth) { /* and let the authentication manager setup the auth tokens */ - gst_rtsp_auth_setup (auth, client, state); + gst_rtsp_auth_setup (auth, state); } send_message (client, state->session, state->response, FALSE); @@ -502,8 +502,10 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) state->factory = factory; - if (!gst_rtsp_auth_check (priv->auth, client, GST_RTSP_AUTH_CHECK_FACTORY, - state)) + if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS)) + goto no_factory_access; + + if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT)) goto not_authorized; if (matched) @@ -563,9 +565,15 @@ no_factory: send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return NULL; } +no_factory_access: + { + GST_ERROR ("client %p: not authorized to see factory uri %s", client, path); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); + return NULL; + } not_authorized: { - GST_ERROR ("client %p: not authorized for factory %p", client, factory); + GST_ERROR ("client %p: not authorized for factory uri %s", client, path); handle_unauthorized_request (client, priv->auth, state); return NULL; } @@ -1858,13 +1866,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) state.uri = uri; state.session = session; - if (priv->auth) { - if (!gst_rtsp_auth_check (priv->auth, client, GST_RTSP_AUTH_CHECK_URL, - &state)) - goto not_authorized; - - state.auth = priv->auth; - } + if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_URL)) + goto not_authorized; /* now see what is asked and dispatch to a dedicated handler */ switch (method) { From 16cfb7b8c05358dd13b62cb9f021ccf0beb9e1f9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Jul 2013 16:09:07 +0200 Subject: [PATCH 0710/1776] test: add permissions to auth test Ass some permissions to the media factory in the test. --- examples/test-auth.c | 46 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/examples/test-auth.c b/examples/test-auth.c index 75455de6b9..b4fc62a516 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -65,8 +65,7 @@ main (int argc, char *argv[]) GstRTSPToken *token; gchar *basic; GstStructure *s; - gchar *role_user[] = { "user", NULL }; - gchar *role_admin[] = { "admin", NULL }; + GstRTSPPermissions *permissions; gst_init (&argc, &argv); @@ -90,10 +89,28 @@ main (int argc, char *argv[]) "x264enc ! rtph264pay name=pay0 pt=96 " "audiotestsrc ! audio/x-raw,rate=8000 ! " "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); - /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + /* allow user and admin to access this resource */ + permissions = gst_rtsp_permissions_new (); + gst_rtsp_permissions_add_role (permissions, "user", + gst_structure_new ("user", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + gst_rtsp_permissions_add_role (permissions, "admin", + gst_structure_new ("admin", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + /* admin2 can look at the media but not construct so he gets a + * 401 Unauthorized */ + gst_rtsp_permissions_add_role (permissions, "admin2", + gst_structure_new ("admin2", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, FALSE, NULL)); + gst_rtsp_media_factory_set_permissions (factory, permissions); + gst_rtsp_permissions_unref (permissions); + /* make another factory */ factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, "( " @@ -102,6 +119,17 @@ main (int argc, char *argv[]) /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test2", factory); + /* allow admin2 to access this resource */ + permissions = gst_rtsp_permissions_new (); + /* user and admin have no permissions so they can't even see the + * media and get a 404 Not Found */ + gst_rtsp_permissions_add_role (permissions, "admin2", + gst_structure_new ("admin2", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + gst_rtsp_media_factory_set_permissions (factory, permissions); + gst_rtsp_permissions_unref (permissions); + /* don't need the ref to the mapper anymore */ g_object_unref (mounts); @@ -111,8 +139,8 @@ main (int argc, char *argv[]) /* make user token */ token = gst_rtsp_token_new (); s = gst_rtsp_token_writable_structure (token); - gst_structure_set (s, "manager.role", G_TYPE_STRING, "user", NULL); - gst_structure_set (s, "factory.media.roles", G_TYPE_STRV, role_user, NULL); + gst_structure_set (s, "resources.class", G_TYPE_STRING, "user", NULL); + gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "user", NULL); basic = gst_rtsp_auth_make_basic ("user", "password"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); @@ -121,8 +149,8 @@ main (int argc, char *argv[]) /* make admin token */ token = gst_rtsp_token_new (); s = gst_rtsp_token_writable_structure (token); - gst_structure_set (s, "manager.role", G_TYPE_STRING, "admin", NULL); - gst_structure_set (s, "factory.media.roles", G_TYPE_STRV, role_admin, NULL); + gst_structure_set (s, "resources.class", G_TYPE_STRING, "admin", NULL); + gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "admin", NULL); basic = gst_rtsp_auth_make_basic ("admin", "power"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); @@ -131,8 +159,8 @@ main (int argc, char *argv[]) /* make admin2 token */ token = gst_rtsp_token_new (); s = gst_rtsp_token_writable_structure (token); - gst_structure_set (s, "manager.role", G_TYPE_STRING, "admin", NULL); - gst_structure_set (s, "factory.media.roles", G_TYPE_STRV, role_admin, NULL); + gst_structure_set (s, "resources.class", G_TYPE_STRING, "admin", NULL); + gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "admin2", NULL); basic = gst_rtsp_auth_make_basic ("admin2", "power2"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); From ca28a466004b515b504cbef318bce4dba5d67c9e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Jul 2013 16:38:39 +0200 Subject: [PATCH 0711/1776] factory: pass permissions to media by default --- gst/rtsp-server/rtsp-media-factory.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index d210d5f8c7..2864f40ae3 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -891,6 +891,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) guint size; GstRTSPLowerTrans protocols; GstRTSPAddressPool *pool; + GstRTSPPermissions *perms; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -909,6 +910,10 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_address_pool (media, pool); g_object_unref (pool); } + if ((perms = gst_rtsp_media_factory_get_permissions (factory))) { + gst_rtsp_media_set_permissions (media, perms); + gst_rtsp_permissions_unref (perms); + } } /** From c4c9c873b87a8d1a22a886114d9d0c7899eaa9c6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Jul 2013 20:44:51 +0200 Subject: [PATCH 0712/1776] media: start media pipeline in context Start the media pipeline in the provided context (or our default one when NULL). This makes sure that we run the bus thread in this context and that all media threads are children of this context. --- gst/rtsp-server/rtsp-media.c | 162 ++++++++++++++++++++--------------- 1 file changed, 94 insertions(+), 68 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 777a27f93d..c9e83f36e2 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1556,78 +1556,14 @@ struct _DynPaySignalHandlers gulong no_more_pads_handler; }; -/** - * gst_rtsp_media_prepare: - * @media: a #GstRTSPMedia - * @context: a #GMainContext to run the bus handler or %NULL - * - * Prepare @media for streaming. This function will create the objects - * to manage the streaming. A pipeline must have been set on @media with - * gst_rtsp_media_take_pipeline(). - * - * It will preroll the pipeline and collect vital information about the streams - * such as the duration. - * - * Returns: %TRUE on success. - */ -gboolean -gst_rtsp_media_prepare (GstRTSPMedia * media, GMainContext * context) +static gboolean +start_prepare (GstRTSPMedia * media) { - GstRTSPMediaPrivate *priv; + GstRTSPMediaPrivate *priv = media->priv; GstStateChangeReturn ret; - GstRTSPMediaStatus status; guint i; - GstRTSPMediaClass *klass; - GstBus *bus; GList *walk; - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - - priv = media->priv; - - g_rec_mutex_lock (&priv->state_lock); - priv->prepare_count++; - - if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) - goto was_prepared; - - if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) - goto wait_status; - - if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED) - goto not_unprepared; - - if (!priv->reusable && priv->reused) - goto is_reused; - - priv->rtpbin = gst_element_factory_make ("rtpbin", NULL); - if (priv->rtpbin == NULL) - goto no_rtpbin; - - GST_INFO ("preparing media %p", media); - - /* reset some variables */ - priv->is_live = FALSE; - priv->seekable = FALSE; - priv->buffering = FALSE; - /* we're preparing now */ - priv->status = GST_RTSP_MEDIA_STATUS_PREPARING; - - bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline)); - - /* add the pipeline bus to our custom mainloop */ - priv->source = gst_bus_create_watch (bus); - gst_object_unref (bus); - - g_source_set_callback (priv->source, (GSourceFunc) bus_message, - g_object_ref (media), (GDestroyNotify) watch_destroyed); - - klass = GST_RTSP_MEDIA_GET_CLASS (media); - priv->id = g_source_attach (priv->source, context ? context : klass->context); - - /* add stuff to the bin */ - gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin); - /* link streams we already have, other streams might appear when we have * dynamic elements */ for (i = 0; i < priv->streams->len; i++) { @@ -1688,6 +1624,97 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GMainContext * context) case GST_STATE_CHANGE_FAILURE: goto state_failed; } + + return FALSE; + +state_failed: + { + GST_WARNING ("failed to preroll pipeline"); + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR); + return FALSE; + } +} + +/** + * gst_rtsp_media_prepare: + * @media: a #GstRTSPMedia + * @context: a #GMainContext to run the bus handler or %NULL + * + * Prepare @media for streaming. This function will create the objects + * to manage the streaming. A pipeline must have been set on @media with + * gst_rtsp_media_take_pipeline(). + * + * It will preroll the pipeline and collect vital information about the streams + * such as the duration. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_media_prepare (GstRTSPMedia * media, GMainContext * context) +{ + GstRTSPMediaPrivate *priv; + GstRTSPMediaStatus status; + GstRTSPMediaClass *klass; + GstBus *bus; + GSource *source; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + priv->prepare_count++; + + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) + goto was_prepared; + + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) + goto wait_status; + + if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED) + goto not_unprepared; + + if (!priv->reusable && priv->reused) + goto is_reused; + + priv->rtpbin = gst_element_factory_make ("rtpbin", NULL); + if (priv->rtpbin == NULL) + goto no_rtpbin; + + GST_INFO ("preparing media %p", media); + + /* reset some variables */ + priv->is_live = FALSE; + priv->seekable = FALSE; + priv->buffering = FALSE; + /* we're preparing now */ + priv->status = GST_RTSP_MEDIA_STATUS_PREPARING; + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + + if (context == NULL) + context = klass->context; + + bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline)); + + /* add the pipeline bus to our custom mainloop */ + priv->source = gst_bus_create_watch (bus); + gst_object_unref (bus); + + g_source_set_callback (priv->source, (GSourceFunc) bus_message, + g_object_ref (media), (GDestroyNotify) watch_destroyed); + + priv->id = g_source_attach (priv->source, context); + + /* add stuff to the bin */ + gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin); + + /* do remainder in context */ + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) start_prepare, media, NULL); + g_source_attach (source, context); + g_source_unref (source); + wait_status: g_rec_mutex_unlock (&priv->state_lock); @@ -1737,7 +1764,6 @@ state_failed: { GST_WARNING ("failed to preroll pipeline"); gst_rtsp_media_unprepare (media); - g_rec_mutex_unlock (&priv->state_lock); return FALSE; } } From 1a0c7051aa2dfe9a0e4dd12f4d66155de4637270 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Jul 2013 15:28:35 +0200 Subject: [PATCH 0713/1776] auth: debug authorization check --- gst/rtsp-server/rtsp-auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index a6db8a6f0a..a2e38c30b7 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -371,7 +371,7 @@ gst_rtsp_auth_check (const gchar * check) klass = GST_RTSP_AUTH_GET_CLASS (auth); - GST_DEBUG_OBJECT (auth, "check auth"); + GST_DEBUG_OBJECT (auth, "check authorization '%s'", check); if (klass->check) result = klass->check (auth, state, check); From 25269c7b1ae0269cbad0d437efab91e3ca2629f1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Jul 2013 16:47:43 +0200 Subject: [PATCH 0714/1776] thread-pool: add object to manage threads Add an object to manage the client and media threads. --- gst/rtsp-server/Makefile.am | 2 + gst/rtsp-server/rtsp-thread-pool.c | 461 +++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-thread-pool.h | 165 +++++++++++ 3 files changed, 628 insertions(+) create mode 100644 gst/rtsp-server/rtsp-thread-pool.c create mode 100644 gst/rtsp-server/rtsp-thread-pool.h diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 170fce55fb..725537ec2a 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -3,6 +3,7 @@ public_headers = \ rtsp-address-pool.h \ rtsp-params.h \ rtsp-sdp.h \ + rtsp-thread-pool.h \ rtsp-media.h \ rtsp-media-factory.h \ rtsp-media-factory-uri.h \ @@ -22,6 +23,7 @@ c_sources = \ rtsp-address-pool.c \ rtsp-params.c \ rtsp-sdp.c \ + rtsp-thread-pool.c \ rtsp-media.c \ rtsp-media-factory.c \ rtsp-media-factory-uri.c \ diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c new file mode 100644 index 0000000000..5f8121340c --- /dev/null +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -0,0 +1,461 @@ +/* GStreamer + * Copyright (C) 2013 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include "rtsp-thread-pool.h" + +typedef struct _GstRTSPThreadImpl +{ + GstRTSPThread thread; + + gint reused; +} GstRTSPThreadImpl; + +GST_DEFINE_MINI_OBJECT_TYPE (GstRTSPThread, gst_rtsp_thread); + +static void gst_rtsp_thread_init (GstRTSPThreadImpl * impl); + +static void +_gst_rtsp_thread_free (GstRTSPThreadImpl * impl) +{ + GST_DEBUG ("free thread %p", impl); + + g_main_loop_unref (impl->thread.loop); + g_main_context_unref (impl->thread.context); + g_slice_free1 (sizeof (GstRTSPThreadImpl), impl); +} + +static GstRTSPThread * +_gst_rtsp_thread_copy (GstRTSPThreadImpl * impl) +{ + GstRTSPThreadImpl *copy; + + GST_DEBUG ("copy thread %p", impl); + + copy = g_slice_new0 (GstRTSPThreadImpl); + gst_rtsp_thread_init (copy); + copy->thread.context = g_main_context_ref (impl->thread.context); + copy->thread.loop = g_main_loop_ref (impl->thread.loop); + + return GST_RTSP_THREAD (copy); +} + +static void +gst_rtsp_thread_init (GstRTSPThreadImpl * impl) +{ + gst_mini_object_init (GST_MINI_OBJECT_CAST (impl), 0, + GST_TYPE_RTSP_THREAD, + (GstMiniObjectCopyFunction) _gst_rtsp_thread_copy, NULL, + (GstMiniObjectFreeFunction) _gst_rtsp_thread_free); + + g_atomic_int_set (&impl->reused, 1); +} + +/** + * gst_rtsp_thread_new: + * + * Create a new thread object that can run a mainloop. + * + * Returns: a #GstRTSPThread. + */ +GstRTSPThread * +gst_rtsp_thread_new (void) +{ + GstRTSPThreadImpl *impl; + + impl = g_slice_new0 (GstRTSPThreadImpl); + + gst_rtsp_thread_init (impl); + impl->thread.context = g_main_context_new (); + impl->thread.loop = g_main_loop_new (impl->thread.context, TRUE); + + return GST_RTSP_THREAD (impl); +} + +/** + * gst_rtsp_thread_reuse: + * @thread: a #GstRTSPThread + * + * Reuse the mainloop of @thread + */ +void +gst_rtsp_thread_reuse (GstRTSPThread * thread) +{ + GstRTSPThreadImpl *impl = (GstRTSPThreadImpl *) thread; + + g_return_if_fail (GST_IS_RTSP_THREAD (thread)); + + GST_DEBUG ("reuse thread %p", thread); + g_atomic_int_inc (&impl->reused); +} + +/** + * gst_rtsp_thread_stop: + * @thread: a #GstRTSPThread + * + * Stop @thread. When no threads are using the mainloop, the thread will be + * stopped and the final ref to @thread will be released. + */ +void +gst_rtsp_thread_stop (GstRTSPThread * thread) +{ + GstRTSPThreadImpl *impl = (GstRTSPThreadImpl *) thread; + + g_return_if_fail (GST_IS_RTSP_THREAD (thread)); + + GST_DEBUG ("stop thread %p", thread); + + if (g_atomic_int_dec_and_test (&impl->reused)) { + GST_DEBUG ("stop mainloop of thread %p", thread); + g_main_loop_quit (thread->loop); + } +} + +#define GST_RTSP_THREAD_POOL_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_THREAD_POOL, GstRTSPThreadPoolPrivate)) + +struct _GstRTSPThreadPoolPrivate +{ + GMutex lock; + + gint max_threads; + /* currently used mainloops */ + GQueue threads; +}; + +#define DEFAULT_MAX_THREADS 1 + +enum +{ + PROP_0, + PROP_MAX_THREADS, + PROP_LAST +}; + +GST_DEBUG_CATEGORY_STATIC (rtsp_thread_pool_debug); +#define GST_CAT_DEFAULT rtsp_thread_pool_debug + +static GQuark thread_pool; + +static void gst_rtsp_thread_pool_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec); +static void gst_rtsp_thread_pool_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec); +static void gst_rtsp_thread_pool_finalize (GObject * obj); + +static gpointer do_loop (GstRTSPThread * thread, + GstRTSPThreadPoolClass * klass); +static GstRTSPThread *default_get_thread (GstRTSPThreadPool * pool, + GstRTSPThreadType type, GstRTSPClientState * state); + +G_DEFINE_TYPE (GstRTSPThreadPool, gst_rtsp_thread_pool, G_TYPE_OBJECT); + +static void +gst_rtsp_thread_pool_class_init (GstRTSPThreadPoolClass * klass) +{ + GObjectClass *gobject_class; + + g_type_class_add_private (klass, sizeof (GstRTSPThreadPoolPrivate)); + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->get_property = gst_rtsp_thread_pool_get_property; + gobject_class->set_property = gst_rtsp_thread_pool_set_property; + gobject_class->finalize = gst_rtsp_thread_pool_finalize; + + /** + * GstRTSPThreadPool::max-threads: + * + * The maximum amount of threads to use for client connections. A value of + * 0 means to use only the mainloop, -1 means an unlimited amount of + * threads. + */ + g_object_class_install_property (gobject_class, PROP_MAX_THREADS, + g_param_spec_int ("max-threads", "Max Threads", + "The maximum amount of threads to use for client connections " + "(0 = only mainloop, -1 = unlimited)", -1, G_MAXINT, + DEFAULT_MAX_THREADS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + klass->get_thread = default_get_thread; + + klass->pool = g_thread_pool_new ((GFunc) do_loop, klass, -1, FALSE, NULL); + + GST_DEBUG_CATEGORY_INIT (rtsp_thread_pool_debug, "rtspthreadpool", 0, + "GstRTSPThreadPool"); + + thread_pool = g_quark_from_string ("gst.rtsp.thread.pool"); +} + +static void +gst_rtsp_thread_pool_init (GstRTSPThreadPool * pool) +{ + GstRTSPThreadPoolPrivate *priv; + + pool->priv = priv = GST_RTSP_THREAD_POOL_GET_PRIVATE (pool); + + g_mutex_init (&priv->lock); + priv->max_threads = DEFAULT_MAX_THREADS; + g_queue_init (&priv->threads); +} + +static void +gst_rtsp_thread_pool_finalize (GObject * obj) +{ + GstRTSPThreadPool *pool = GST_RTSP_THREAD_POOL (obj); + GstRTSPThreadPoolPrivate *priv = pool->priv; + + GST_INFO ("finalize pool %p", pool); + + g_queue_clear (&priv->threads); + g_mutex_clear (&priv->lock); + + G_OBJECT_CLASS (gst_rtsp_thread_pool_parent_class)->finalize (obj); +} + +static void +gst_rtsp_thread_pool_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec) +{ + GstRTSPThreadPool *pool = GST_RTSP_THREAD_POOL (object); + + switch (propid) { + case PROP_MAX_THREADS: + g_value_set_int (value, gst_rtsp_thread_pool_get_max_threads (pool)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static void +gst_rtsp_thread_pool_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec) +{ + GstRTSPThreadPool *pool = GST_RTSP_THREAD_POOL (object); + + switch (propid) { + case PROP_MAX_THREADS: + gst_rtsp_thread_pool_set_max_threads (pool, g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static gpointer +do_loop (GstRTSPThread * thread, GstRTSPThreadPoolClass * klass) +{ + GstRTSPThreadPoolPrivate *priv; + GstRTSPThreadPool *pool; + + pool = gst_mini_object_get_qdata (GST_MINI_OBJECT (thread), thread_pool); + priv = pool->priv; + + if (klass->thread_enter) + klass->thread_enter (pool, thread); + + GST_INFO ("enter mainloop of thread %p", thread); + g_main_loop_run (thread->loop); + GST_INFO ("exit mainloop of thread %p", thread); + + if (klass->thread_leave) + klass->thread_leave (pool, thread); + + g_mutex_lock (&priv->lock); + g_queue_remove (&priv->threads, thread); + g_mutex_unlock (&priv->lock); + + gst_rtsp_thread_unref (thread); + + return NULL; +} + +/** + * gst_rtsp_thread_pool_new: + * + * Create a new #GstRTSPThreadPool instance. + * + * Returns: a new #GstRTSPThreadPool + */ +GstRTSPThreadPool * +gst_rtsp_thread_pool_new (void) +{ + GstRTSPThreadPool *result; + + result = g_object_new (GST_TYPE_RTSP_THREAD_POOL, NULL); + + return result; +} + +/** + * gst_rtsp_thread_pool_set_max_threads: + * @pool: a #GstRTSPThreadPool + * @max_threads: maximum threads + * + * Set the maximum threads used by the pool to handle client requests. + * A value of 0 will use the pool mainloop, a value of -1 will use an + * unlimited number of threads. + */ +void +gst_rtsp_thread_pool_set_max_threads (GstRTSPThreadPool * pool, + gint max_threads) +{ + GstRTSPThreadPoolPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_THREAD_POOL (pool)); + + priv = pool->priv; + + g_mutex_lock (&priv->lock); + priv->max_threads = max_threads; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_thread_pool_get_max_threads: + * @pool: a #GstRTSPThreadPool + * + * Get the maximum number of threads used for client connections. + * See gst_rtsp_thread_pool_set_max_threads(). + * + * Returns: the maximum number of threads. + */ +gint +gst_rtsp_thread_pool_get_max_threads (GstRTSPThreadPool * pool) +{ + GstRTSPThreadPoolPrivate *priv; + gint res; + + g_return_val_if_fail (GST_IS_RTSP_THREAD_POOL (pool), -1); + + priv = pool->priv; + + g_mutex_lock (&priv->lock); + res = priv->max_threads; + g_mutex_unlock (&priv->lock); + + return res; +} + +static GstRTSPThread * +make_thread (GstRTSPThreadPool * pool, GstRTSPClientState * state) +{ + GstRTSPThreadPoolClass *klass; + GstRTSPThread *thread; + + klass = GST_RTSP_THREAD_POOL_GET_CLASS (pool); + + thread = gst_rtsp_thread_new (); + gst_mini_object_set_qdata (GST_MINI_OBJECT (thread), thread_pool, + g_object_ref (pool), g_object_unref); + + GST_DEBUG_OBJECT (pool, "new thread %p", thread); + + if (klass->configure_thread) + klass->configure_thread (pool, thread, state); + + return thread; +} + +static GstRTSPThread * +default_get_thread (GstRTSPThreadPool * pool, + GstRTSPThreadType type, GstRTSPClientState * state) +{ + GstRTSPThreadPoolPrivate *priv = pool->priv; + GstRTSPThreadPoolClass *klass; + GstRTSPThread *thread; + GError *error = NULL; + + klass = GST_RTSP_THREAD_POOL_GET_CLASS (pool); + + switch (type) { + case GST_RTSP_THREAD_TYPE_CLIENT: + if (priv->max_threads == 0) { + /* no threads allowed */ + GST_DEBUG_OBJECT (pool, "no client threads allowed"); + thread = NULL; + } else { + if (priv->max_threads > 0 && + g_queue_get_length (&priv->threads) >= priv->max_threads) { + /* max threads reached, recycle from queue */ + GST_DEBUG_OBJECT (pool, "recycle client thread"); + thread = g_queue_pop_head (&priv->threads); + gst_rtsp_thread_ref (thread); + } else { + /* make more threads */ + GST_DEBUG_OBJECT (pool, "make new client thread"); + thread = make_thread (pool, state); + + if (!g_thread_pool_push (klass->pool, thread, &error)) + goto thread_error; + } + g_queue_push_tail (&priv->threads, thread); + } + break; + case GST_RTSP_THREAD_TYPE_MEDIA: + GST_DEBUG_OBJECT (pool, "make new media thread"); + thread = make_thread (pool, state); + + if (!g_thread_pool_push (klass->pool, thread, &error)) + goto thread_error; + break; + default: + thread = NULL; + break; + } + return thread; + + /* ERRORS */ +thread_error: + { + GST_ERROR_OBJECT (pool, "failed to push thread %s", error->message); + gst_rtsp_thread_unref (thread); + g_clear_error (&error); + return NULL; + } +} + +/** + * gst_rtsp_thread_pool_get_thread: + * @pool: a #GstRTSPThreadPool + * @type: the #GstRTSPThreadType + * @state: a #GstRTSPClientState + * + * Get a new #GstRTSPThread for @type and @state. + * + * Returns: a new #GstRTSPThread, gst_rtsp_thread_stop() after usage + */ +GstRTSPThread * +gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool * pool, + GstRTSPThreadType type, GstRTSPClientState * state) +{ + GstRTSPThreadPoolClass *klass; + GstRTSPThread *result = NULL; + + g_return_val_if_fail (GST_IS_RTSP_THREAD_POOL (pool), NULL); + g_return_val_if_fail (state != NULL, NULL); + + klass = GST_RTSP_THREAD_POOL_GET_CLASS (pool); + + if (klass->get_thread) + result = klass->get_thread (pool, type, state); + + return result; +} diff --git a/gst/rtsp-server/rtsp-thread-pool.h b/gst/rtsp-server/rtsp-thread-pool.h new file mode 100644 index 0000000000..301b8a1d9d --- /dev/null +++ b/gst/rtsp-server/rtsp-thread-pool.h @@ -0,0 +1,165 @@ +/* GStreamer + * Copyright (C) 2010 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#ifndef __GST_RTSP_THREAD_POOL_H__ +#define __GST_RTSP_THREAD_POOL_H__ + +typedef struct _GstRTSPThread GstRTSPThread; +typedef struct _GstRTSPThreadPool GstRTSPThreadPool; +typedef struct _GstRTSPThreadPoolClass GstRTSPThreadPoolClass; +typedef struct _GstRTSPThreadPoolPrivate GstRTSPThreadPoolPrivate; + +#include "rtsp-client.h" + +G_BEGIN_DECLS + +#define GST_TYPE_RTSP_THREAD_POOL (gst_rtsp_thread_pool_get_type ()) +#define GST_IS_RTSP_THREAD_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_THREAD_POOL)) +#define GST_IS_RTSP_THREAD_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_THREAD_POOL)) +#define GST_RTSP_THREAD_POOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_THREAD_POOL, GstRTSPThreadPoolClass)) +#define GST_RTSP_THREAD_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_THREAD_POOL, GstRTSPThreadPool)) +#define GST_RTSP_THREAD_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_THREAD_POOL, GstRTSPThreadPoolClass)) +#define GST_RTSP_THREAD_POOL_CAST(obj) ((GstRTSPThreadPool*)(obj)) +#define GST_RTSP_THREAD_POOL_CLASS_CAST(klass) ((GstRTSPThreadPoolClass*)(klass)) + +GType gst_rtsp_thread_get_type (void); + +#define GST_TYPE_RTSP_THREAD (gst_rtsp_thread_get_type ()) +#define GST_IS_RTSP_THREAD(obj) (GST_IS_MINI_OBJECT_TYPE (obj, GST_TYPE_RTSP_THREAD)) +#define GST_RTSP_THREAD_CAST(obj) ((GstRTSPThread*)(obj)) +#define GST_RTSP_THREAD(obj) (GST_RTSP_THREAD_CAST(obj)) + +/** + * GstRTSPThread: + * + * Structure holding info about a mainloop running in a thread + */ +struct _GstRTSPThread { + GstMiniObject mini_object; + + GMainContext *context; + GMainLoop *loop; +}; + +GstRTSPThread * gst_rtsp_thread_new (void); + +void gst_rtsp_thread_reuse (GstRTSPThread * thread); +void gst_rtsp_thread_stop (GstRTSPThread * thread); + +/** + * gst_rtsp_thread_ref: + * @thread: The thread to refcount + * + * Increase the refcount of this thread. + * + * Returns: (transfer full): @thread (for convenience when doing assignments) + */ +#ifdef _FOOL_GTK_DOC_ +G_INLINE_FUNC GstRTSPThread * gst_rtsp_thread_ref (GstRTSPThread * thread); +#endif + +static inline GstRTSPThread * +gst_rtsp_thread_ref (GstRTSPThread * thread) +{ + return (GstRTSPThread *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (thread)); +} + +/** + * gst_rtsp_thread_unref: + * @thread: (transfer full): the thread to refcount + * + * Decrease the refcount of an thread, freeing it if the refcount reaches 0. + */ +#ifdef _FOOL_GTK_DOC_ +G_INLINE_FUNC void gst_rtsp_thread_unref (GstRTSPPermissions * thread); +#endif + + +static inline void +gst_rtsp_thread_unref (GstRTSPThread * thread) +{ + gst_mini_object_unref (GST_MINI_OBJECT_CAST (thread)); +} + +/** + * GstRTSPThreadType: + * @GST_RTSP_THREAD_TYPE_CLIENT: a thread to handle the client communication + * @GST_RTSP_THREAD_TYPE_MEDIA: a thread to handle media + * + * Different thread types + */ +typedef enum +{ + GST_RTSP_THREAD_TYPE_CLIENT, + GST_RTSP_THREAD_TYPE_MEDIA +} GstRTSPThreadType; + +/** + * GstRTSPThreadPool: + * + * The thread pool structure. + */ +struct _GstRTSPThreadPool { + GObject parent; + + GstRTSPThreadPoolPrivate *priv; +}; + +/** + * GstRTSPThreadPoolClass: + * @get_thread: get or reuse a thread object + * @configure_thread: configure a thread object + * @thread_enter: called from the thread when it is entered + * @thread_leave: called from the thread when it is left + * + * Class for managing threads. + */ +struct _GstRTSPThreadPoolClass { + GObjectClass parent_class; + + GThreadPool *pool; + + GstRTSPThread * (*get_thread) (GstRTSPThreadPool *pool, + GstRTSPThreadType type, + GstRTSPClientState *state); + void (*configure_thread) (GstRTSPThreadPool *pool, + GstRTSPThread * thread, + GstRTSPClientState *state); + + void (*thread_enter) (GstRTSPThreadPool *pool, + GstRTSPThread *thread); + void (*thread_leave) (GstRTSPThreadPool *pool, + GstRTSPThread *thread); +}; + +GType gst_rtsp_thread_pool_get_type (void); + +GstRTSPThreadPool * gst_rtsp_thread_pool_new (void); + +void gst_rtsp_thread_pool_set_max_threads (GstRTSPThreadPool * pool, gint max_threads); +gint gst_rtsp_thread_pool_get_max_threads (GstRTSPThreadPool * pool); + +GstRTSPThread * gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool *pool, + GstRTSPThreadType type, + GstRTSPClientState *state); +G_END_DECLS + +#endif /* __GST_RTSP_THREAD_POOL_H__ */ From 27917f4ef3ad2cd7fefb2dde16fb0d5df4938479 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Jul 2013 16:49:55 +0200 Subject: [PATCH 0715/1776] server: use thread pool Use the thread pool instead of doing our own thing. --- gst/rtsp-server/rtsp-client.h | 3 + gst/rtsp-server/rtsp-server.c | 178 ++++++++++------------------------ gst/rtsp-server/rtsp-server.h | 4 +- 3 files changed, 56 insertions(+), 129 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index a7311c234b..5b6963f132 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -30,6 +30,7 @@ typedef struct _GstRTSPClientClass GstRTSPClientClass; typedef struct _GstRTSPClientState GstRTSPClientState; typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; +#include "rtsp-server.h" #include "rtsp-media.h" #include "rtsp-mount-points.h" #include "rtsp-session-pool.h" @@ -49,6 +50,7 @@ typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; /** * GstRTSPClientState: + * @server: the server * @client: the client * @request: the complete request * @uri: the complete url parsed from @request @@ -65,6 +67,7 @@ typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; * Information passed around containing the client state of a request. */ struct _GstRTSPClientState { + GstRTSPServer *server; GstRTSPClient *client; GstRTSPMessage *request; GstRTSPUrl *uri; diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index f056d7d756..981df7de2c 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -38,7 +38,6 @@ struct _GstRTSPServerPrivate gchar *address; gchar *service; gint backlog; - gint max_threads; gboolean use_client_settings; GSocket *socket; @@ -52,12 +51,14 @@ struct _GstRTSPServerPrivate /* authentication manager */ GstRTSPAuth *auth; + /* resource manager */ + GstRTSPThreadPool *thread_pool; + /* the TLS certificate */ GTlsCertificate *certificate; /* the clients that are connected */ GList *clients; - GQueue loops; /* the main loops used in the threads */ }; #define DEFAULT_ADDRESS "0.0.0.0" @@ -65,7 +66,6 @@ struct _GstRTSPServerPrivate /* #define DEFAULT_ADDRESS "::0" */ #define DEFAULT_SERVICE "8554" #define DEFAULT_BACKLOG 5 -#define DEFAULT_MAX_THREADS 0 #define DEFAULT_USE_CLIENT_SETTINGS FALSE /* Define to use the SO_LINGER option so that the server sockets can be resused @@ -83,7 +83,6 @@ enum PROP_SESSION_POOL, PROP_MOUNT_POINTS, - PROP_MAX_THREADS, PROP_USE_CLIENT_SETTINGS, PROP_LAST }; @@ -110,7 +109,6 @@ static void gst_rtsp_server_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_server_finalize (GObject * object); -static gpointer do_loop (Loop * loop); static GstRTSPClient *default_create_client (GstRTSPServer * server); static gboolean default_setup_connection (GstRTSPServer * server, GstRTSPClient * client, GstRTSPConnection * conn); @@ -197,18 +195,6 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) "The mount points to use for client session", GST_TYPE_RTSP_MOUNT_POINTS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - /** - * GstRTSPServer::max-threads: - * - * The maximum amount of threads to use for client connections. A value of - * 0 means to use only the mainloop, -1 means an unlimited amount of - * threads. - */ - g_object_class_install_property (gobject_class, PROP_MAX_THREADS, - g_param_spec_int ("max-threads", "Max Threads", - "The maximum amount of threads to use for client connections " - "(0 = only mainloop, -1 = unlimited)", -1, G_MAXINT, - DEFAULT_MAX_THREADS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstRTSPServer::use-client-settings: * @@ -230,8 +216,6 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) klass->create_client = default_create_client; klass->setup_connection = default_setup_connection; - klass->pool = g_thread_pool_new ((GFunc) do_loop, klass, -1, FALSE, NULL); - GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer"); } @@ -249,9 +233,8 @@ gst_rtsp_server_init (GstRTSPServer * server) priv->backlog = DEFAULT_BACKLOG; priv->session_pool = gst_rtsp_session_pool_new (); priv->mount_points = gst_rtsp_mount_points_new (); - priv->max_threads = DEFAULT_MAX_THREADS; + priv->thread_pool = gst_rtsp_thread_pool_new (); priv->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS; - g_queue_init (&priv->loops); } static void @@ -268,8 +251,12 @@ gst_rtsp_server_finalize (GObject * object) if (priv->socket) g_object_unref (priv->socket); - g_object_unref (priv->session_pool); - g_object_unref (priv->mount_points); + if (priv->session_pool) + g_object_unref (priv->session_pool); + if (priv->mount_points) + g_object_unref (priv->mount_points); + if (priv->thread_pool) + g_object_unref (priv->thread_pool); if (priv->auth) g_object_unref (priv->auth); @@ -654,52 +641,60 @@ gst_rtsp_server_get_auth (GstRTSPServer * server) } /** - * gst_rtsp_server_set_max_threads: + * gst_rtsp_server_set_thread_pool: * @server: a #GstRTSPServer - * @max_threads: maximum threads + * @pool: a #GstRTSPThreadPool * - * Set the maximum threads used by the server to handle client requests. - * A value of 0 will use the server mainloop, a value of -1 will use an - * unlimited number of threads. + * configure @pool to be used as the thread pool of @server. */ void -gst_rtsp_server_set_max_threads (GstRTSPServer * server, gint max_threads) +gst_rtsp_server_set_thread_pool (GstRTSPServer * server, + GstRTSPThreadPool * pool) { GstRTSPServerPrivate *priv; + GstRTSPThreadPool *old; g_return_if_fail (GST_IS_RTSP_SERVER (server)); priv = server->priv; + if (pool) + g_object_ref (pool); + GST_RTSP_SERVER_LOCK (server); - priv->max_threads = max_threads; + old = priv->thread_pool; + priv->thread_pool = pool; GST_RTSP_SERVER_UNLOCK (server); + + if (old) + g_object_unref (old); } /** - * gst_rtsp_server_get_max_threads: + * gst_rtsp_server_get_thread_pool: * @server: a #GstRTSPServer * - * Get the maximum number of threads used for client connections. - * See gst_rtsp_server_set_max_threads(). + * Get the #GstRTSPThreadPool used as the thread pool of @server. * - * Returns: the maximum number of threads. + * Returns: (transfer full): the #GstRTSPThreadPool of @server. g_object_unref() after + * usage. */ -gint -gst_rtsp_server_get_max_threads (GstRTSPServer * server) +GstRTSPThreadPool * +gst_rtsp_server_get_thread_pool (GstRTSPServer * server) { GstRTSPServerPrivate *priv; - gint res; + GstRTSPThreadPool *result; - g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1); + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); priv = server->priv; GST_RTSP_SERVER_LOCK (server); - res = priv->max_threads; + if ((result = priv->thread_pool)) + g_object_ref (result); GST_RTSP_SERVER_UNLOCK (server); - return res; + return result; } /** @@ -834,9 +829,6 @@ gst_rtsp_server_get_property (GObject * object, guint propid, case PROP_MOUNT_POINTS: g_value_take_object (value, gst_rtsp_server_get_mount_points (server)); break; - case PROP_MAX_THREADS: - g_value_set_int (value, gst_rtsp_server_get_max_threads (server)); - break; case PROP_USE_CLIENT_SETTINGS: g_value_set_boolean (value, gst_rtsp_server_get_use_client_settings (server)); @@ -868,9 +860,6 @@ gst_rtsp_server_set_property (GObject * object, guint propid, case PROP_MOUNT_POINTS: gst_rtsp_server_set_mount_points (server, g_value_get_object (value)); break; - case PROP_MAX_THREADS: - gst_rtsp_server_set_max_threads (server, g_value_get_int (value)); - break; case PROP_USE_CLIENT_SETTINGS: gst_rtsp_server_set_use_client_settings (server, g_value_get_boolean (value)); @@ -1050,34 +1039,10 @@ close_error: } } -struct _Loop -{ - gint refcnt; - - GstRTSPServer *server; - GMainLoop *mainloop; - GMainContext *mainctx; -}; - -/* must be called with the lock held */ -static void -loop_unref (Loop * loop) -{ - GstRTSPServer *server = loop->server; - GstRTSPServerPrivate *priv = server->priv; - - loop->refcnt--; - - if (loop->refcnt <= 0) { - g_queue_remove (&priv->loops, loop); - g_main_loop_quit (loop->mainloop); - } -} - struct _ClientContext { GstRTSPServer *server; - Loop *loop; + GstRTSPThread *thread; GstRTSPClient *client; }; @@ -1085,8 +1050,8 @@ static gboolean free_client_context (ClientContext * ctx) { GST_RTSP_SERVER_LOCK (ctx->server); - if (ctx->loop) - loop_unref (ctx->loop); + if (ctx->thread) + gst_rtsp_thread_stop (ctx->thread); GST_RTSP_SERVER_UNLOCK (ctx->server); g_object_unref (ctx->client); @@ -1095,50 +1060,6 @@ free_client_context (ClientContext * ctx) return G_SOURCE_REMOVE; } -static gpointer -do_loop (Loop * loop) -{ - GST_INFO ("enter mainloop"); - g_main_loop_run (loop->mainloop); - GST_INFO ("exit mainloop"); - - g_main_context_unref (loop->mainctx); - g_main_loop_unref (loop->mainloop); - g_object_unref (loop->server); - g_slice_free (Loop, loop); - - return NULL; -} - -/* Must be called with lock held */ - -static Loop * -gst_rtsp_server_get_main_loop (GstRTSPServer * server) -{ - GstRTSPServerPrivate *priv = server->priv; - Loop *loop; - - if (priv->max_threads > 0 && - g_queue_get_length (&priv->loops) >= priv->max_threads) { - loop = g_queue_pop_head (&priv->loops); - loop->refcnt++; - } else { - GstRTSPServerClass *klass = GST_RTSP_SERVER_GET_CLASS (server); - - loop = g_slice_new0 (Loop); - loop->refcnt = 1; - loop->server = g_object_ref (server); - loop->mainctx = g_main_context_new (); - loop->mainloop = g_main_loop_new (loop->mainctx, FALSE); - - g_thread_pool_push (klass->pool, loop, NULL); - } - - g_queue_push_tail (&priv->loops, loop); - - return loop; -} - static void unmanage_client (GstRTSPClient * client, ClientContext * ctx) { @@ -1153,12 +1074,12 @@ unmanage_client (GstRTSPClient * client, ClientContext * ctx) priv->clients = g_list_remove (priv->clients, ctx); GST_RTSP_SERVER_UNLOCK (server); - if (ctx->loop) { + if (ctx->thread) { GSource *src; src = g_idle_source_new (); g_source_set_callback (src, (GSourceFunc) free_client_context, ctx, NULL); - g_source_attach (src, ctx->loop->mainctx); + g_source_attach (src, ctx->thread->context); g_source_unref (src); } else { free_client_context (ctx); @@ -1174,7 +1095,8 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) { ClientContext *ctx; GstRTSPServerPrivate *priv = server->priv; - GMainContext *mainctx; + GMainContext *mainctx = NULL; + GstRTSPClientState state = { NULL }; GST_DEBUG_OBJECT (server, "manage client %p", client); @@ -1183,17 +1105,19 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) ctx->client = client; GST_RTSP_SERVER_LOCK (server); - if (priv->max_threads == 0) { - GSource *source; + state.server = server; + state.client = client; + + ctx->thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool, + GST_RTSP_THREAD_TYPE_CLIENT, &state); + if (ctx->thread) + mainctx = ctx->thread->context; + else { + GSource *source; /* find the context to add the watch */ if ((source = g_main_current_source ())) mainctx = g_source_get_context (source); - else - mainctx = NULL; - } else { - ctx->loop = gst_rtsp_server_get_main_loop (server); - mainctx = ctx->loop->mainctx; } g_signal_connect (client, "closed", (GCallback) unmanage_client, ctx); diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index a71c27f47f..b4e83939cc 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -100,8 +100,8 @@ GstRTSPMountPoints * gst_rtsp_server_get_mount_points (GstRTSPServer *serve void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server); -void gst_rtsp_server_set_max_threads (GstRTSPServer *server, gint max_threads); -gint gst_rtsp_server_get_max_threads (GstRTSPServer *server); +void gst_rtsp_server_set_thread_pool (GstRTSPServer *server, GstRTSPThreadPool *pool); +GstRTSPThreadPool * gst_rtsp_server_get_thread_pool (GstRTSPServer *server); void gst_rtsp_server_set_use_client_settings (GstRTSPServer *server, gboolean use_client_settings); From 00997d956ff6f1428c39d9c7245b8840a12749d6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Jul 2013 17:06:36 +0200 Subject: [PATCH 0716/1776] client: add method to configure thread pool --- gst/rtsp-server/rtsp-client.c | 60 ++++++++++++++++++++++++++++++++++- gst/rtsp-server/rtsp-client.h | 4 +++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 50d68cfe33..886bbbe5e3 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -49,6 +49,7 @@ struct _GstRTSPClientPrivate GstRTSPSessionPool *session_pool; GstRTSPMountPoints *mount_points; GstRTSPAuth *auth; + GstRTSPThreadPool *thread_pool; /* used to cache the media in the last requested DESCRIBE so that * we can pick it up in the next SETUP immediately */ @@ -590,7 +591,7 @@ no_prepare: GST_ERROR ("client %p: can't prepare media", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); g_object_unref (media); - state->media = media; + state->media = NULL; g_object_unref (factory); state->factory = NULL; return NULL; @@ -2223,6 +2224,63 @@ gst_rtsp_client_get_auth (GstRTSPClient * client) return result; } +/** + * gst_rtsp_client_set_thread_pool: + * @client: a #GstRTSPClient + * @pool: a #GstRTSPThreadPool + * + * configure @pool to be used as the thread pool of @client. + */ +void +gst_rtsp_client_set_thread_pool (GstRTSPClient * client, + GstRTSPThreadPool * pool) +{ + GstRTSPClientPrivate *priv; + GstRTSPThreadPool *old; + + g_return_if_fail (GST_IS_RTSP_CLIENT (client)); + + priv = client->priv; + + if (pool) + g_object_ref (pool); + + g_mutex_lock (&priv->lock); + old = priv->thread_pool; + priv->thread_pool = pool; + g_mutex_unlock (&priv->lock); + + if (old) + g_object_unref (old); +} + +/** + * gst_rtsp_client_get_thread_pool: + * @client: a #GstRTSPClient + * + * Get the #GstRTSPThreadPool used as the thread pool of @client. + * + * Returns: (transfer full): the #GstRTSPThreadPool of @client. g_object_unref() after + * usage. + */ +GstRTSPThreadPool * +gst_rtsp_client_get_thread_pool (GstRTSPClient * client) +{ + GstRTSPClientPrivate *priv; + GstRTSPThreadPool *result; + + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); + + priv = client->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->thread_pool)) + g_object_ref (result); + g_mutex_unlock (&priv->lock); + + return result; +} + /** * gst_rtsp_client_set_connection: * @client: a #GstRTSPClient diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 5b6963f132..c0d9629362 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -36,6 +36,7 @@ typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; #include "rtsp-session-pool.h" #include "rtsp-session-media.h" #include "rtsp-auth.h" +#include "rtsp-thread-pool.h" #include "rtsp-token.h" #include "rtsp-sdp.h" @@ -163,6 +164,9 @@ gboolean gst_rtsp_client_get_use_client_settings (GstRTSPClient * c void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); +void gst_rtsp_client_set_thread_pool (GstRTSPClient *client, GstRTSPThreadPool *pool); +GstRTSPThreadPool * gst_rtsp_client_get_thread_pool (GstRTSPClient *client); + gboolean gst_rtsp_client_set_connection (GstRTSPClient *client, GstRTSPConnection *conn); GstRTSPConnection * gst_rtsp_client_get_connection (GstRTSPClient *client); From 01b921e8a6fb112558bff06e2ed939478e0741b4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Jul 2013 17:07:13 +0200 Subject: [PATCH 0717/1776] server: configure client thread pool --- gst/rtsp-server/rtsp-server.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 981df7de2c..8f63d3430e 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1144,6 +1144,8 @@ default_create_client (GstRTSPServer * server) gst_rtsp_client_set_mount_points (client, priv->mount_points); /* set authentication manager */ gst_rtsp_client_set_auth (client, priv->auth); + /* set threadpool */ + gst_rtsp_client_set_thread_pool (client, priv->thread_pool); /* check if client transport settings for multicast are allowed */ gst_rtsp_client_set_use_client_settings (client, priv->use_client_settings); GST_RTSP_SERVER_UNLOCK (server); From d1e4baab6ca1b7064b6143f85318bb59a8e892cd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Jul 2013 17:08:14 +0200 Subject: [PATCH 0718/1776] media: Accept a thread in _prepare Remove out own threadpool handling and use the provided thread and maincontext for the bus messages and the state changes. --- gst/rtsp-server/rtsp-media.c | 37 +++++++++++------------------------- gst/rtsp-server/rtsp-media.h | 8 ++------ 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c9e83f36e2..d7e4291f48 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -57,6 +57,7 @@ struct _GstRTSPMediaPrivate GstElement *fakesink; /* protected by lock */ GSource *source; guint id; + GstRTSPThread *thread; gboolean time_provider; GstNetTimeProvider *nettime; @@ -118,7 +119,6 @@ static void gst_rtsp_media_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_media_finalize (GObject * obj); -static gpointer do_loop (GstRTSPMediaClass * klass); static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message); static void finish_unprepare (GstRTSPMedia * media); @@ -208,13 +208,8 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 0, G_TYPE_INT); - klass->context = g_main_context_new (); - klass->loop = g_main_loop_new (klass->context, TRUE); - GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); - klass->thread = g_thread_new ("Bus Thread", (GThreadFunc) do_loop, klass); - klass->handle_message = default_handle_message; klass->unprepare = default_unprepare; klass->convert_range = default_convert_range; @@ -338,16 +333,6 @@ gst_rtsp_media_set_property (GObject * object, guint propid, } } -static gpointer -do_loop (GstRTSPMediaClass * klass) -{ - GST_INFO ("enter mainloop"); - g_main_loop_run (klass->loop); - GST_INFO ("exit mainloop"); - - return NULL; -} - /* must be called with state lock */ static void collect_media_stats (GstRTSPMedia * media) @@ -1638,7 +1623,7 @@ state_failed: /** * gst_rtsp_media_prepare: * @media: a #GstRTSPMedia - * @context: a #GMainContext to run the bus handler or %NULL + * @thread: a #GstRTSPThread to run the bus handler or %NULL * * Prepare @media for streaming. This function will create the objects * to manage the streaming. A pipeline must have been set on @media with @@ -1650,15 +1635,15 @@ state_failed: * Returns: %TRUE on success. */ gboolean -gst_rtsp_media_prepare (GstRTSPMedia * media, GMainContext * context) +gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) { GstRTSPMediaPrivate *priv; GstRTSPMediaStatus status; - GstRTSPMediaClass *klass; GstBus *bus; GSource *source; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + g_return_val_if_fail (GST_IS_RTSP_THREAD (thread), FALSE); priv = media->priv; @@ -1687,14 +1672,10 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GMainContext * context) priv->is_live = FALSE; priv->seekable = FALSE; priv->buffering = FALSE; + priv->thread = thread; /* we're preparing now */ priv->status = GST_RTSP_MEDIA_STATUS_PREPARING; - klass = GST_RTSP_MEDIA_GET_CLASS (media); - - if (context == NULL) - context = klass->context; - bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline)); /* add the pipeline bus to our custom mainloop */ @@ -1704,7 +1685,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GMainContext * context) g_source_set_callback (priv->source, (GSourceFunc) bus_message, g_object_ref (media), (GDestroyNotify) watch_destroyed); - priv->id = g_source_attach (priv->source, context); + priv->id = g_source_attach (priv->source, thread->context); /* add stuff to the bin */ gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin); @@ -1712,7 +1693,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GMainContext * context) /* do remainder in context */ source = g_idle_source_new (); g_source_set_callback (source, (GSourceFunc) start_prepare, media, NULL); - g_source_attach (source, context); + g_source_attach (source, thread->context); g_source_unref (source); wait_status: @@ -1829,6 +1810,10 @@ finish_unprepare (GstRTSPMedia * media) g_source_destroy (priv->source); g_source_unref (priv->source); } + if (priv->thread) { + GST_DEBUG ("stop thread"); + gst_rtsp_thread_stop (priv->thread); + } } /* called with state-lock */ diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 8158891ee2..7b64cf3007 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -42,6 +42,7 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass; typedef struct _GstRTSPMediaPrivate GstRTSPMediaPrivate; #include "rtsp-stream.h" +#include "rtsp-thread-pool.h" #include "rtsp-permissions.h" #include "rtsp-address-pool.h" @@ -92,11 +93,6 @@ struct _GstRTSPMedia { struct _GstRTSPMediaClass { GObjectClass parent_class; - /* thread for the mainloop */ - GMainContext *context; - GMainLoop *loop; - GThread *thread; - /* vmethods */ gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message); gboolean (*unprepare) (GstRTSPMedia *media); @@ -153,7 +149,7 @@ GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media, const gchar *address, guint16 port); /* prepare the media for playback */ -gboolean gst_rtsp_media_prepare (GstRTSPMedia *media, GMainContext *context); +gboolean gst_rtsp_media_prepare (GstRTSPMedia *media, GstRTSPThread *thread); gboolean gst_rtsp_media_unprepare (GstRTSPMedia *media); /* creating streams */ From 4e9c4d8bb74aac0e83ff2c3130a84d31981c5364 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Jul 2013 17:09:27 +0200 Subject: [PATCH 0719/1776] client: pass thread from pool to media _prepare Get a thread from the configured threadpool and pass it to the prepare method of the media. --- gst/rtsp-server/rtsp-client.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 886bbbe5e3..d5feb6ffe0 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -515,6 +515,8 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) path_len = strlen (path); if (!paths_are_equal (priv->path, path, path_len)) { + GstRTSPThread *thread; + /* remove any previously cached values before we try to construct a new * media for uri */ if (priv->path) @@ -530,14 +532,20 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) if (!(media = gst_rtsp_media_factory_construct (factory, state->uri))) goto no_media; + state->media = media; + + thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool, + GST_RTSP_THREAD_TYPE_MEDIA, state); + if (thread == NULL) + goto no_thread; + /* prepare the media */ - if (!(gst_rtsp_media_prepare (media, NULL))) + if (!(gst_rtsp_media_prepare (media, thread))) goto no_prepare; /* now keep track of the uri and the media */ priv->path = g_strndup (path, path_len); priv->media = media; - state->media = media; } else { /* we have seen this path before, used cached media */ media = priv->media; @@ -586,6 +594,16 @@ no_media: state->factory = NULL; return NULL; } +no_thread: + { + GST_ERROR ("client %p: can't create thread", client); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + g_object_unref (media); + state->media = NULL; + g_object_unref (factory); + state->factory = NULL; + return NULL; + } no_prepare: { GST_ERROR ("client %p: can't prepare media", client); From 8cec0f8a4690bd1146102eef6a914aa6c5830534 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Jul 2013 20:48:18 +0200 Subject: [PATCH 0720/1776] thread-pool: store thread type in thread --- gst/rtsp-server/rtsp-thread-pool.c | 13 ++++++++----- gst/rtsp-server/rtsp-thread-pool.h | 29 +++++++++++++++-------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index 5f8121340c..d22d665958 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -70,19 +70,21 @@ gst_rtsp_thread_init (GstRTSPThreadImpl * impl) /** * gst_rtsp_thread_new: + * @type: the thread type * * Create a new thread object that can run a mainloop. * * Returns: a #GstRTSPThread. */ GstRTSPThread * -gst_rtsp_thread_new (void) +gst_rtsp_thread_new (GstRTSPThreadType type) { GstRTSPThreadImpl *impl; impl = g_slice_new0 (GstRTSPThreadImpl); gst_rtsp_thread_init (impl); + impl->thread.type = type; impl->thread.context = g_main_context_new (); impl->thread.loop = g_main_loop_new (impl->thread.context, TRUE); @@ -355,14 +357,15 @@ gst_rtsp_thread_pool_get_max_threads (GstRTSPThreadPool * pool) } static GstRTSPThread * -make_thread (GstRTSPThreadPool * pool, GstRTSPClientState * state) +make_thread (GstRTSPThreadPool * pool, GstRTSPThreadType type, + GstRTSPClientState * state) { GstRTSPThreadPoolClass *klass; GstRTSPThread *thread; klass = GST_RTSP_THREAD_POOL_GET_CLASS (pool); - thread = gst_rtsp_thread_new (); + thread = gst_rtsp_thread_new (type); gst_mini_object_set_qdata (GST_MINI_OBJECT (thread), thread_pool, g_object_ref (pool), g_object_unref); @@ -401,7 +404,7 @@ default_get_thread (GstRTSPThreadPool * pool, } else { /* make more threads */ GST_DEBUG_OBJECT (pool, "make new client thread"); - thread = make_thread (pool, state); + thread = make_thread (pool, type, state); if (!g_thread_pool_push (klass->pool, thread, &error)) goto thread_error; @@ -411,7 +414,7 @@ default_get_thread (GstRTSPThreadPool * pool, break; case GST_RTSP_THREAD_TYPE_MEDIA: GST_DEBUG_OBJECT (pool, "make new media thread"); - thread = make_thread (pool, state); + thread = make_thread (pool, type, state); if (!g_thread_pool_push (klass->pool, thread, &error)) goto thread_error; diff --git a/gst/rtsp-server/rtsp-thread-pool.h b/gst/rtsp-server/rtsp-thread-pool.h index 301b8a1d9d..a9c013b376 100644 --- a/gst/rtsp-server/rtsp-thread-pool.h +++ b/gst/rtsp-server/rtsp-thread-pool.h @@ -47,6 +47,19 @@ GType gst_rtsp_thread_get_type (void); #define GST_RTSP_THREAD_CAST(obj) ((GstRTSPThread*)(obj)) #define GST_RTSP_THREAD(obj) (GST_RTSP_THREAD_CAST(obj)) +/** + * GstRTSPThreadType: + * @GST_RTSP_THREAD_TYPE_CLIENT: a thread to handle the client communication + * @GST_RTSP_THREAD_TYPE_MEDIA: a thread to handle media + * + * Different thread types + */ +typedef enum +{ + GST_RTSP_THREAD_TYPE_CLIENT, + GST_RTSP_THREAD_TYPE_MEDIA +} GstRTSPThreadType; + /** * GstRTSPThread: * @@ -55,11 +68,12 @@ GType gst_rtsp_thread_get_type (void); struct _GstRTSPThread { GstMiniObject mini_object; + GstRTSPThreadType type; GMainContext *context; GMainLoop *loop; }; -GstRTSPThread * gst_rtsp_thread_new (void); +GstRTSPThread * gst_rtsp_thread_new (GstRTSPThreadType type); void gst_rtsp_thread_reuse (GstRTSPThread * thread); void gst_rtsp_thread_stop (GstRTSPThread * thread); @@ -99,19 +113,6 @@ gst_rtsp_thread_unref (GstRTSPThread * thread) gst_mini_object_unref (GST_MINI_OBJECT_CAST (thread)); } -/** - * GstRTSPThreadType: - * @GST_RTSP_THREAD_TYPE_CLIENT: a thread to handle the client communication - * @GST_RTSP_THREAD_TYPE_MEDIA: a thread to handle media - * - * Different thread types - */ -typedef enum -{ - GST_RTSP_THREAD_TYPE_CLIENT, - GST_RTSP_THREAD_TYPE_MEDIA -} GstRTSPThreadType; - /** * GstRTSPThreadPool: * From 6f5a82aed3d6612a49f9a25e2c21cf7c3e352178 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Jul 2013 20:48:47 +0200 Subject: [PATCH 0721/1776] thread-pool: fix vmethod invocation --- gst/rtsp-server/rtsp-thread-pool.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index d22d665958..88bd792749 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -162,8 +162,7 @@ static void gst_rtsp_thread_pool_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_thread_pool_finalize (GObject * obj); -static gpointer do_loop (GstRTSPThread * thread, - GstRTSPThreadPoolClass * klass); +static gpointer do_loop (GstRTSPThread * thread); static GstRTSPThread *default_get_thread (GstRTSPThreadPool * pool, GstRTSPThreadType type, GstRTSPClientState * state); @@ -262,14 +261,17 @@ gst_rtsp_thread_pool_set_property (GObject * object, guint propid, } static gpointer -do_loop (GstRTSPThread * thread, GstRTSPThreadPoolClass * klass) +do_loop (GstRTSPThread * thread) { GstRTSPThreadPoolPrivate *priv; + GstRTSPThreadPoolClass *klass; GstRTSPThreadPool *pool; pool = gst_mini_object_get_qdata (GST_MINI_OBJECT (thread), thread_pool); priv = pool->priv; + klass = GST_RTSP_THREAD_POOL_GET_CLASS (pool); + if (klass->thread_enter) klass->thread_enter (pool, thread); From e788a9ca60fafc2bbf2b71ca9f1d9a3be92df26a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Jul 2013 20:55:03 +0200 Subject: [PATCH 0722/1776] tests: fix compilation --- tests/check/gst/rtspserver.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 5edeffd47e..f82d3f7086 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -881,7 +881,11 @@ GST_END_TEST; GST_START_TEST (test_play_multithreaded) { - gst_rtsp_server_set_max_threads (server, 2); + GstRTSPThreadPool *pool; + + pool = gst_rtsp_server_get_thread_pool (server); + gst_rtsp_thread_pool_set_max_threads (pool, 2); + g_object_unref (pool); start_server (); @@ -927,8 +931,11 @@ GST_START_TEST (test_play_multithreaded_block_in_describe) GstRTSPMessage *request; GstRTSPMessage *response; GstRTSPStatusCode code; + GstRTSPThreadPool *pool; - gst_rtsp_server_set_max_threads (server, 2); + pool = gst_rtsp_server_get_thread_pool (server); + gst_rtsp_thread_pool_set_max_threads (pool, 2); + g_object_unref (pool); mounts = gst_rtsp_server_get_mount_points (server); fail_unless (mounts != NULL); @@ -1012,8 +1019,12 @@ GST_START_TEST (test_play_multithreaded_timeout_client) GstRTSPMessage *request; GstRTSPMessage *response; GstRTSPStatusCode code; + GstRTSPThreadPool *thread_pool; + + thread_pool = gst_rtsp_server_get_thread_pool (server); + gst_rtsp_thread_pool_set_max_threads (thread_pool, 2); + g_object_unref (thread_pool); - gst_rtsp_server_set_max_threads (server, 2); pool = gst_rtsp_server_get_session_pool (server); g_signal_connect (server, "client-connected", G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one); @@ -1100,8 +1111,12 @@ GST_START_TEST (test_play_multithreaded_timeout_session) GstRTSPTransport *video_transport = NULL; GstRTSPTransport *audio_transport = NULL; GstRTSPSessionPool *pool; + GstRTSPThreadPool *thread_pool; + + thread_pool = gst_rtsp_server_get_thread_pool (server); + gst_rtsp_thread_pool_set_max_threads (thread_pool, 2); + g_object_unref (thread_pool); - gst_rtsp_server_set_max_threads (server, 2); pool = gst_rtsp_server_get_session_pool (server); g_signal_connect (server, "client-connected", G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one); From 5c6bb3052fa79f2359fa9f712917086a016f4775 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Jul 2013 20:57:12 +0200 Subject: [PATCH 0723/1776] examples: add cgroups example --- configure.ac | 4 + examples/Makefile.am | 4 +- examples/test-cgroups.c | 261 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+), 2 deletions(-) create mode 100644 examples/test-cgroups.c diff --git a/configure.ac b/configure.ac index d538367f06..aafa57f244 100644 --- a/configure.ac +++ b/configure.ac @@ -229,6 +229,10 @@ AC_SUBST([GST_OBJ_CFLAGS]) GST_OBJ_LIBS="\$(top_builddir)/gst/rtsp-server/libgstrtspserver-$GST_API_VERSION.la \$(GST_ALL_LIBS)" AC_SUBST([GST_OBJ_LIBS]) +PKG_CHECK_MODULES(LIBCGROUP, libcgroup >= 0.26, HAVE_LIBCGROUP="yes", HAVE_LIBCGROUP="no") +AC_SUBST(LIBCGROUP_CFLAGS) +AC_SUBST(LIBCGROUP_LIBS) + dnl this really should only contain flags, not libs - they get added before dnl whatevertarget_LIBS and -L flags here affect the rest of the linking diff --git a/examples/Makefile.am b/examples/Makefile.am index 4b753f6551..20b6cb9114 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,8 +1,8 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ test-launch test-sdp test-uri test-auth \ - test-multicast test-multicast2 + test-multicast test-multicast2 test-cgroups #INCLUDES = -I$(top_srcdir) -I$(srcdir) AM_CFLAGS = $(GST_OBJ_CFLAGS) -AM_LDFLAGS = $(GST_OBJ_LIBS) $(GIO_LIBS) +AM_LDFLAGS = $(GST_OBJ_LIBS) $(GIO_LIBS) $(LIBCGROUP_LIBS) diff --git a/examples/test-cgroups.c b/examples/test-cgroups.c new file mode 100644 index 0000000000..db8e339cd4 --- /dev/null +++ b/examples/test-cgroups.c @@ -0,0 +1,261 @@ +/* GStreamer + * Copyright (C) 2013 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include + +typedef struct _GstRTSPCGroupPool GstRTSPCGroupPool; +typedef struct _GstRTSPCGroupPoolClass GstRTSPCGroupPoolClass; + +#define GST_TYPE_RTSP_CGROUP_POOL (gst_rtsp_cgroup_pool_get_type ()) +#define GST_IS_RTSP_CGROUP_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_CGROUP_POOL)) +#define GST_IS_RTSP_CGROUP_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_CGROUP_POOL)) +#define GST_RTSP_CGROUP_POOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_CGROUP_POOL, GstRTSPCGroupPoolClass)) +#define GST_RTSP_CGROUP_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_CGROUP_POOL, GstRTSPCGroupPool)) +#define GST_RTSP_CGROUP_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_CGROUP_POOL, GstRTSPCGroupPoolClass)) +#define GST_RTSP_CGROUP_POOL_CAST(obj) ((GstRTSPCGroupPool*)(obj)) +#define GST_RTSP_CGROUP_POOL_CLASS_CAST(klass) ((GstRTSPCGroupPoolClass*)(klass)) + +struct _GstRTSPCGroupPool +{ + GstRTSPThreadPool parent; + + struct cgroup *user; + struct cgroup *admin; +}; + +struct _GstRTSPCGroupPoolClass +{ + GstRTSPThreadPoolClass parent_class; +}; + +static GQuark thread_cgroup; + +static void gst_rtsp_cgroup_pool_finalize (GObject * obj); + +static void default_thread_enter (GstRTSPThreadPool * pool, + GstRTSPThread * thread); +static void default_configure_thread (GstRTSPThreadPool * pool, + GstRTSPThread * thread, GstRTSPClientState * state); + +G_DEFINE_TYPE (GstRTSPCGroupPool, gst_rtsp_cgroup_pool, + GST_TYPE_RTSP_THREAD_POOL); + +static void +gst_rtsp_cgroup_pool_class_init (GstRTSPCGroupPoolClass * klass) +{ + GObjectClass *gobject_class; + GstRTSPThreadPoolClass *tpool_class; + + gobject_class = G_OBJECT_CLASS (klass); + tpool_class = GST_RTSP_THREAD_POOL_CLASS (klass); + + gobject_class->finalize = gst_rtsp_cgroup_pool_finalize; + + tpool_class->configure_thread = default_configure_thread; + tpool_class->thread_enter = default_thread_enter; + + thread_cgroup = g_quark_from_string ("cgroup.pool.thread.cgroup"); + + cgroup_init (); +} + +static void +gst_rtsp_cgroup_pool_init (GstRTSPCGroupPool * pool) +{ + pool->user = cgroup_new_cgroup ("user"); + g_assert (cgroup_add_controller (pool->user, "cpu") != NULL); + pool->admin = cgroup_new_cgroup ("admin"); + g_assert (cgroup_add_controller (pool->admin, "cpu") != NULL); +} + +static void +gst_rtsp_cgroup_pool_finalize (GObject * obj) +{ + GstRTSPCGroupPool *pool = GST_RTSP_CGROUP_POOL (obj); + + GST_INFO ("finalize pool %p", pool); + + cgroup_free (&pool->user); + cgroup_free (&pool->admin); + + G_OBJECT_CLASS (gst_rtsp_cgroup_pool_parent_class)->finalize (obj); +} + +static void +default_thread_enter (GstRTSPThreadPool * pool, GstRTSPThread * thread) +{ + struct cgroup *cgroup; + + cgroup = gst_mini_object_get_qdata (GST_MINI_OBJECT (thread), thread_cgroup); + if (cgroup) { + gint res = 0; + + res = cgroup_attach_task (cgroup); + + if (res != 0) + GST_ERROR ("error: %d (%s)", res, cgroup_strerror (res)); + } +} + +static void +default_configure_thread (GstRTSPThreadPool * pool, + GstRTSPThread * thread, GstRTSPClientState * state) +{ + GstRTSPCGroupPool *cpool = GST_RTSP_CGROUP_POOL (pool); + const gchar *cls; + struct cgroup *cgroup; + + if (state->token) + cls = gst_rtsp_token_get_string (state->token, "cgroup.pool.media.class"); + else + cls = NULL; + + GST_DEBUG ("manage cgroup %s", cls); + + if (!g_strcmp0 (cls, "admin")) + cgroup = cpool->admin; + else + cgroup = cpool->user; + + /* attach the cgroup to the thread */ + gst_mini_object_set_qdata (GST_MINI_OBJECT (thread), thread_cgroup, + cgroup, NULL); +} + +static gboolean +timeout (GstRTSPServer * server) +{ + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_cleanup (pool); + g_object_unref (pool); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + GstRTSPAuth *auth; + GstRTSPToken *token; + gchar *basic; + GstStructure *s; + GstRTSPPermissions *permissions; + GstRTSPThreadPool *thread_pool; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mounts for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mounts = gst_rtsp_server_get_mount_points (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, "( " + "videotestsrc ! video/x-raw,width=640,height=480,framerate=50/1 ! " + "x264enc ! rtph264pay name=pay0 pt=96 " + "audiotestsrc ! audio/x-raw,rate=8000 ! " + "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); + /* attach the test factory to the /test url */ + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + /* allow user and admin to access this resource */ + permissions = gst_rtsp_permissions_new (); + gst_rtsp_permissions_add_role (permissions, "user", + gst_structure_new ("user", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + gst_rtsp_permissions_add_role (permissions, "admin", + gst_structure_new ("admin", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + gst_rtsp_media_factory_set_permissions (factory, permissions); + gst_rtsp_permissions_unref (permissions); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mounts); + + /* make a new authentication manager */ + auth = gst_rtsp_auth_new (); + + /* make user token */ + token = gst_rtsp_token_new (); + s = gst_rtsp_token_writable_structure (token); + gst_structure_set (s, "cgroup.pool.media.class", G_TYPE_STRING, "user", NULL); + gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "user", NULL); + basic = gst_rtsp_auth_make_basic ("user", "password"); + gst_rtsp_auth_add_basic (auth, basic, token); + g_free (basic); + gst_rtsp_token_unref (token); + + /* make admin token */ + token = gst_rtsp_token_new (); + s = gst_rtsp_token_writable_structure (token); + gst_structure_set (s, "cgroup.pool.media.class", G_TYPE_STRING, "admin", + NULL); + gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "admin", NULL); + basic = gst_rtsp_auth_make_basic ("admin", "power"); + gst_rtsp_auth_add_basic (auth, basic, token); + g_free (basic); + gst_rtsp_token_unref (token); + + /* set as the server authentication manager */ + gst_rtsp_server_set_auth (server, auth); + g_object_unref (auth); + + thread_pool = g_object_new (GST_TYPE_RTSP_CGROUP_POOL, NULL); + gst_rtsp_server_set_thread_pool (server, thread_pool); + g_object_unref (thread_pool); + + /* attach the server to the default maincontext */ + if (gst_rtsp_server_attach (server, NULL) == 0) + goto failed; + + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + + /* start serving */ + g_print ("stream with user:password ready at rtsp://127.0.0.1:8554/test\n"); + g_print ("stream with admin:power ready at rtsp://127.0.0.1:8554/test\n"); + g_main_loop_run (loop); + + return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } +} From 2fdc6ef88ad267284fb408bdc2a44dbc85a4f1d2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 11 Jul 2013 10:28:06 +0200 Subject: [PATCH 0724/1776] configure: compile cgroup example conditionally Only compile the cgroup example when we have libcgroup --- configure.ac | 2 ++ examples/Makefile.am | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index aafa57f244..0c2ad620d6 100644 --- a/configure.ac +++ b/configure.ac @@ -232,6 +232,7 @@ AC_SUBST([GST_OBJ_LIBS]) PKG_CHECK_MODULES(LIBCGROUP, libcgroup >= 0.26, HAVE_LIBCGROUP="yes", HAVE_LIBCGROUP="no") AC_SUBST(LIBCGROUP_CFLAGS) AC_SUBST(LIBCGROUP_LIBS) +AM_CONDITIONAL(HAVE_LIBCGROUP, test "x$HAVE_LIBCGROUP" = "xyes") dnl this really should only contain flags, not libs - they get added before dnl whatevertarget_LIBS and -L flags here affect the rest of the linking @@ -265,6 +266,7 @@ Configuration Source code location : ${srcdir} Prefix : ${prefix} Compiler : ${CC} + CGroups example : ${HAVE_LIBCGROUP} gst-rtsp-server configured. Type 'make' to build. " diff --git a/examples/Makefile.am b/examples/Makefile.am index 20b6cb9114..deec57ce1e 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,8 +1,14 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ test-launch test-sdp test-uri test-auth \ - test-multicast test-multicast2 test-cgroups + test-multicast test-multicast2 #INCLUDES = -I$(top_srcdir) -I$(srcdir) AM_CFLAGS = $(GST_OBJ_CFLAGS) -AM_LDFLAGS = $(GST_OBJ_LIBS) $(GIO_LIBS) $(LIBCGROUP_LIBS) +AM_LDFLAGS = $(GST_OBJ_LIBS) $(GIO_LIBS) + +if HAVE_LIBCGROUP +noinst_PROGRAMS += test-cgroups +AM_LDFLAGS += $(LIBCGROUP_LIBS) +endif + From ccceb1de11203b42cf0cdb9ae235f54f4c54e7ff Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 11 Jul 2013 12:18:26 +0200 Subject: [PATCH 0725/1776] docs: update docs --- docs/libs/gst-rtsp-server-docs.sgml | 14 +- docs/libs/gst-rtsp-server-sections.txt | 702 +++++++++++++++--------- gst/rtsp-server/rtsp-address-pool.c | 16 +- gst/rtsp-server/rtsp-address-pool.h | 34 +- gst/rtsp-server/rtsp-auth.c | 4 +- gst/rtsp-server/rtsp-client.h | 9 +- gst/rtsp-server/rtsp-media-factory.h | 1 + gst/rtsp-server/rtsp-media.c | 3 +- gst/rtsp-server/rtsp-media.h | 1 + gst/rtsp-server/rtsp-permissions.c | 18 + gst/rtsp-server/rtsp-permissions.h | 1 - gst/rtsp-server/rtsp-server.h | 1 + gst/rtsp-server/rtsp-session-media.c | 2 +- gst/rtsp-server/rtsp-session-media.h | 1 + gst/rtsp-server/rtsp-session-pool.h | 1 + gst/rtsp-server/rtsp-session.h | 1 + gst/rtsp-server/rtsp-stream-transport.h | 19 + gst/rtsp-server/rtsp-stream.c | 1 + gst/rtsp-server/rtsp-thread-pool.h | 6 + 19 files changed, 553 insertions(+), 282 deletions(-) diff --git a/docs/libs/gst-rtsp-server-docs.sgml b/docs/libs/gst-rtsp-server-docs.sgml index 4f196973aa..716d8b216f 100644 --- a/docs/libs/gst-rtsp-server-docs.sgml +++ b/docs/libs/gst-rtsp-server-docs.sgml @@ -14,18 +14,20 @@ + + - - - - - - + + + + + + diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index e536a7ddfb..edfe53ecb7 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -1,23 +1,185 @@
-rtsp-mount-points -GstRTSPMountPoints -GstRTSPMountPoints -GstRTSPMountPointsClass -gst_rtsp_mount_points_new -gst_rtsp_mount_points_find_factory -gst_rtsp_mount_points_add_factory -gst_rtsp_mount_points_remove_factory +rtsp-address-pool +GstRTSPAddressPool +GST_RTSP_ADDRESS_POOL_ANY_IPV4 +GST_RTSP_ADDRESS_POOL_ANY_IPV6 +GstRTSPAddress +GstRTSPAddressFlags +gst_rtsp_address_copy +gst_rtsp_address_free + +GstRTSPAddressPool +GstRTSPAddressPoolClass +gst_rtsp_address_pool_new +gst_rtsp_address_pool_clear +gst_rtsp_address_pool_dump +gst_rtsp_address_pool_add_range +gst_rtsp_address_pool_add_range_unicast +gst_rtsp_address_pool_has_unicast_addresses +gst_rtsp_address_pool_acquire_address +gst_rtsp_address_pool_reserve_address -GstRTSPMountPointsPrivate -GST_RTSP_MOUNT_POINTS_CLASS -GST_RTSP_MOUNT_POINTS_CAST -GST_RTSP_MOUNT_POINTS_CLASS_CAST -GST_RTSP_MOUNT_POINTS -GST_IS_RTSP_MOUNT_POINTS -GST_TYPE_RTSP_MOUNT_POINTS -gst_rtsp_mount_points_get_type -GST_IS_RTSP_MOUNT_POINTS_CLASS -GST_RTSP_MOUNT_POINTS_GET_CLASS +GST_RTSP_ADDRESS_POOL_CAST +GST_RTSP_ADDRESS_POOL_CLASS_CAST +GST_IS_RTSP_ADDRESS_POOL +GST_IS_RTSP_ADDRESS_POOL_CLASS +GST_RTSP_ADDRESS_POOL +GST_RTSP_ADDRESS_POOL_CLASS +GST_RTSP_ADDRESS_POOL_GET_CLASS +GST_TYPE_RTSP_ADDRESS_POOL +GstRTSPAddressPoolPrivate +gst_rtsp_address_get_type +gst_rtsp_address_pool_get_type +
+ +
+rtsp-auth +GstRTSPAuth +GstRTSPAuth +GstRTSPAuthClass +gst_rtsp_auth_new + +gst_rtsp_auth_make_basic +gst_rtsp_auth_add_basic +gst_rtsp_auth_remove_basic +gst_rtsp_auth_setup +gst_rtsp_auth_check + +GST_RTSP_AUTH_CHECK_URL +GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS +GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT + +GST_RTSP_MEDIA_FACTORY_ROLE +GST_RTSP_MEDIA_FACTORY_PERM_ACCESS +GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT + +GST_RTSP_AUTH_CAST +GST_RTSP_AUTH_CLASS_CAST +GST_IS_RTSP_AUTH +GST_IS_RTSP_AUTH_CLASS +GST_RTSP_AUTH +GST_RTSP_AUTH_CLASS +GST_RTSP_AUTH_GET_CLASS +GST_TYPE_RTSP_AUTH +GstRTSPAuthPrivate +gst_rtsp_auth_get_type +
+ +
+rtsp-client +GstRTSPClient +GstRTSPClientState +gst_rtsp_client_state_get_current + +GstRTSPClient +GstRTSPClientClass + +gst_rtsp_client_new + +gst_rtsp_client_get_session_pool +gst_rtsp_client_set_session_pool + +gst_rtsp_client_get_mount_points +gst_rtsp_client_set_mount_points + +gst_rtsp_client_get_use_client_settings +gst_rtsp_client_set_use_client_settings + +gst_rtsp_client_get_auth +gst_rtsp_client_set_auth + +gst_rtsp_client_get_thread_pool +gst_rtsp_client_set_thread_pool + +gst_rtsp_client_get_connection +gst_rtsp_client_set_connection + +GstRTSPClientSendFunc +gst_rtsp_client_set_send_func + +gst_rtsp_client_handle_message +gst_rtsp_client_send_request +gst_rtsp_client_attach + +GstRTSPClientSessionFilterFunc +gst_rtsp_client_session_filter + +GST_RTSP_CLIENT_CAST +GST_RTSP_CLIENT_CLASS_CAST +GST_IS_RTSP_CLIENT +GST_IS_RTSP_CLIENT_CLASS +GST_RTSP_CLIENT +GST_RTSP_CLIENT_CLASS +GST_RTSP_CLIENT_GET_CLASS +GST_TYPE_RTSP_CLIENT +GstRTSPClientPrivate +gst_rtsp_client_get_type +
+ +
+rtsp-media +GstRTSPMedia +GstRTSPMediaStatus + +GstRTSPMedia +GstRTSPMediaClass +gst_rtsp_media_new +gst_rtsp_media_get_element +gst_rtsp_media_take_pipeline +gst_rtsp_media_get_status + +gst_rtsp_media_set_permissions +gst_rtsp_media_get_permissions + +gst_rtsp_media_set_shared +gst_rtsp_media_is_shared + +gst_rtsp_media_set_reusable +gst_rtsp_media_is_reusable + +gst_rtsp_media_set_protocols +gst_rtsp_media_get_protocols + +gst_rtsp_media_set_eos_shutdown +gst_rtsp_media_is_eos_shutdown + +gst_rtsp_media_set_address_pool +gst_rtsp_media_get_address_pool + +gst_rtsp_media_set_buffer_size +gst_rtsp_media_get_buffer_size + +gst_rtsp_media_use_time_provider +gst_rtsp_media_is_time_provider +gst_rtsp_media_get_time_provider + +gst_rtsp_media_prepare +gst_rtsp_media_unprepare + +gst_rtsp_media_collect_streams +gst_rtsp_media_create_stream + +gst_rtsp_media_get_clock +gst_rtsp_media_get_base_time +gst_rtsp_media_n_streams +gst_rtsp_media_get_stream +gst_rtsp_media_find_stream + +gst_rtsp_media_seek +gst_rtsp_media_get_range_string + +gst_rtsp_media_set_state + +GST_RTSP_MEDIA_CAST +GST_RTSP_MEDIA_CLASS_CAST +GST_IS_RTSP_MEDIA +GST_IS_RTSP_MEDIA_CLASS +GST_RTSP_MEDIA +GST_RTSP_MEDIA_CLASS +GST_RTSP_MEDIA_GET_CLASS +GST_TYPE_RTSP_MEDIA +GstRTSPMediaPrivate +gst_rtsp_media_get_type
@@ -25,35 +187,43 @@ GST_RTSP_MOUNT_POINTS_GET_CLASS GstRTSPMediaFactory GstRTSPMediaFactory GstRTSPMediaFactoryClass + gst_rtsp_media_factory_new -gst_rtsp_media_factory_set_launch -gst_rtsp_media_factory_get_launch -gst_rtsp_media_factory_set_shared -gst_rtsp_media_factory_is_shared -gst_rtsp_media_factory_set_eos_shutdown -gst_rtsp_media_factory_is_eos_shutdown -gst_rtsp_media_factory_set_protocols -gst_rtsp_media_factory_get_protocols -gst_rtsp_media_factory_set_auth -gst_rtsp_media_factory_get_auth -gst_rtsp_media_factory_set_buffer_size -gst_rtsp_media_factory_get_buffer_size + gst_rtsp_media_factory_construct gst_rtsp_media_factory_create_element + +gst_rtsp_media_factory_get_address_pool +gst_rtsp_media_factory_set_address_pool + +gst_rtsp_media_factory_get_buffer_size +gst_rtsp_media_factory_set_buffer_size + +gst_rtsp_media_factory_get_launch +gst_rtsp_media_factory_set_launch + +gst_rtsp_media_factory_get_permissions +gst_rtsp_media_factory_set_permissions + +gst_rtsp_media_factory_get_protocols +gst_rtsp_media_factory_set_protocols + +gst_rtsp_media_factory_is_eos_shutdown +gst_rtsp_media_factory_set_eos_shutdown + +gst_rtsp_media_factory_set_shared +gst_rtsp_media_factory_is_shared -GST_RTSP_MEDIA_FACTORY_GET_LOCK -GST_RTSP_MEDIA_FACTORY_LOCK -GST_RTSP_MEDIA_FACTORY_UNLOCK -GST_RTSP_MEDIA_FACTORY_CLASS GST_RTSP_MEDIA_FACTORY_CAST GST_RTSP_MEDIA_FACTORY_CLASS_CAST -GST_RTSP_MEDIA_FACTORY GST_IS_RTSP_MEDIA_FACTORY -GST_TYPE_RTSP_MEDIA_FACTORY -gst_rtsp_media_factory_get_type GST_IS_RTSP_MEDIA_FACTORY_CLASS +GST_RTSP_MEDIA_FACTORY +GST_RTSP_MEDIA_FACTORY_CLASS GST_RTSP_MEDIA_FACTORY_GET_CLASS +GST_TYPE_RTSP_MEDIA_FACTORY GstRTSPMediaFactoryPrivate +gst_rtsp_media_factory_get_type
@@ -64,73 +234,72 @@ GstRTSPMediaFactoryURIClass gst_rtsp_media_factory_uri_new gst_rtsp_media_factory_uri_set_uri gst_rtsp_media_factory_uri_get_uri -gst_rtsp_media_factory_get_address_pool -gst_rtsp_media_factory_set_address_pool +GST_RTSP_MEDIA_FACTORY_URI_CAST +GST_RTSP_MEDIA_FACTORY_URI_CLASS_CAST GST_IS_RTSP_MEDIA_FACTORY_URI GST_IS_RTSP_MEDIA_FACTORY_URI_CLASS GST_RTSP_MEDIA_FACTORY_URI -GST_RTSP_MEDIA_FACTORY_URI_CAST GST_RTSP_MEDIA_FACTORY_URI_CLASS -GST_RTSP_MEDIA_FACTORY_URI_CLASS_CAST GST_RTSP_MEDIA_FACTORY_URI_GET_CLASS GST_TYPE_RTSP_MEDIA_FACTORY_URI -gst_rtsp_media_factory_uri_get_type GstRTSPMediaFactoryURIPrivate +gst_rtsp_media_factory_uri_get_type
+
+rtsp-mount-points +GstRTSPMountPoints +GstRTSPMountPoints +GstRTSPMountPointsClass +gst_rtsp_mount_points_new +gst_rtsp_mount_points_add_factory +gst_rtsp_mount_points_remove_factory +gst_rtsp_mount_points_match + +GST_RTSP_MOUNT_POINTS_CAST +GST_RTSP_MOUNT_POINTS_CLASS_CAST +GST_IS_RTSP_MOUNT_POINTS +GST_IS_RTSP_MOUNT_POINTS_CLASS +GST_RTSP_MOUNT_POINTS +GST_RTSP_MOUNT_POINTS_CLASS +GST_RTSP_MOUNT_POINTS_GET_CLASS +GST_TYPE_RTSP_MOUNT_POINTS +GstRTSPMountPointsPrivate +gst_rtsp_mount_points_get_type +
-rtsp-media -GstRTSPMedia -GstRTSPMediaStatus -GstRTSPMedia -GstRTSPMediaClass -gst_rtsp_media_new +rtsp-params +GstRTSPParams +gst_rtsp_params_get +gst_rtsp_params_set +
-gst_rtsp_media_set_shared -gst_rtsp_media_is_shared -gst_rtsp_media_set_reusable -gst_rtsp_media_is_reusable -gst_rtsp_media_set_protocols -gst_rtsp_media_get_protocols -gst_rtsp_media_set_eos_shutdown -gst_rtsp_media_is_eos_shutdown -gst_rtsp_media_set_auth -gst_rtsp_media_get_auth -gst_rtsp_media_set_buffer_size -gst_rtsp_media_get_buffer_size - -gst_rtsp_media_prepare -gst_rtsp_media_unprepare - -gst_rtsp_media_collect_streams -gst_rtsp_media_create_stream - -gst_rtsp_media_n_streams -gst_rtsp_media_get_stream - -gst_rtsp_media_seek -gst_rtsp_media_get_range_string -gst_rtsp_media_set_state - -gst_rtsp_media_get_status - -gst_rtsp_media_get_address_pool -gst_rtsp_media_set_address_pool - -gst_rtsp_media_take_pipeline +
+rtsp-permissions +GstRTSPPermissions +GstRTSPPermissions +gst_rtsp_permissions_new +gst_rtsp_permissions_ref +gst_rtsp_permissions_unref +gst_rtsp_permissions_add_role +gst_rtsp_permissions_remove_role +gst_rtsp_permissions_get_role +gst_rtsp_permissions_is_allowed -GST_RTSP_MEDIA_CLASS -GST_RTSP_MEDIA_CAST -GST_RTSP_MEDIA_CLASS_CAST -GST_RTSP_MEDIA -GST_IS_RTSP_MEDIA -GST_TYPE_RTSP_MEDIA -gst_rtsp_media_get_type -GST_IS_RTSP_MEDIA_CLASS -GST_RTSP_MEDIA_GET_CLASS -GstRTSPMediaPrivate +GST_RTSP_PERMISSIONS_CAST +GST_IS_RTSP_PERMISSIONS +GST_RTSP_PERMISSIONS +GST_TYPE_RTSP_PERMISSIONS +gst_rtsp_permissions_get_type +
+ +
+rtsp-sdp +GstRTSPSdp +GstSDPInfo +gst_rtsp_sdp_from_media
@@ -138,73 +307,54 @@ GstRTSPMediaPrivate GstRTSPServer GstRTSPServer GstRTSPServerClass + gst_rtsp_server_new -gst_rtsp_server_set_address + gst_rtsp_server_get_address -gst_rtsp_server_set_service +gst_rtsp_server_set_address + gst_rtsp_server_get_service +gst_rtsp_server_set_service + gst_rtsp_server_get_bound_port -gst_rtsp_server_set_backlog + gst_rtsp_server_get_backlog -gst_rtsp_server_set_session_pool -gst_rtsp_server_get_session_pool -gst_rtsp_server_set_mount_points +gst_rtsp_server_set_backlog + gst_rtsp_server_get_mount_points +gst_rtsp_server_set_mount_points + +gst_rtsp_server_get_session_pool +gst_rtsp_server_set_session_pool + +gst_rtsp_server_get_thread_pool +gst_rtsp_server_set_thread_pool + gst_rtsp_server_get_auth gst_rtsp_server_set_auth + +gst_rtsp_server_get_tls_certificate +gst_rtsp_server_set_tls_certificate + +gst_rtsp_server_get_use_client_settings +gst_rtsp_server_set_use_client_settings + gst_rtsp_server_transfer_connection gst_rtsp_server_io_func gst_rtsp_server_create_socket gst_rtsp_server_create_source gst_rtsp_server_attach -gst_rtsp_server_get_max_threads -gst_rtsp_server_set_max_threads -GST_RTSP_SERVER_GET_LOCK -GST_RTSP_SERVER_LOCK -GST_RTSP_SERVER_UNLOCK -GST_RTSP_SERVER_CLASS +GST_IS_RTSP_SERVER GST_RTSP_SERVER_CAST GST_RTSP_SERVER_CLASS_CAST -GST_RTSP_SERVER -GST_IS_RTSP_SERVER -GST_TYPE_RTSP_SERVER -gst_rtsp_server_get_type GST_IS_RTSP_SERVER_CLASS +GST_RTSP_SERVER +GST_RTSP_SERVER_CLASS GST_RTSP_SERVER_GET_CLASS +GST_TYPE_RTSP_SERVER GstRTSPServerPrivate -
- -
-rtsp-session-pool -GstRTSPSessionPool -GstRTSPSessionPool -GstRTSPSessionPoolClass -GstRTSPSessionPoolFunc -GstRTSPFilterResult -GstRTSPSessionFilterFunc -gst_rtsp_session_pool_new -gst_rtsp_session_pool_set_max_sessions -gst_rtsp_session_pool_get_max_sessions -gst_rtsp_session_pool_get_n_sessions -gst_rtsp_session_pool_create -gst_rtsp_session_pool_find -gst_rtsp_session_pool_remove -gst_rtsp_session_pool_filter -gst_rtsp_session_pool_cleanup -gst_rtsp_session_pool_create_watch -GstRTSPSessionPoolFilterFunc - -GST_RTSP_SESSION_POOL_CLASS -GST_RTSP_SESSION_POOL_CAST -GST_RTSP_SESSION_POOL_CLASS_CAST -GST_RTSP_SESSION_POOL -GST_IS_RTSP_SESSION_POOL -GST_TYPE_RTSP_SESSION_POOL -gst_rtsp_session_pool_get_type -GST_IS_RTSP_SESSION_POOL_CLASS -GST_RTSP_SESSION_POOL_GET_CLASS -GstRTSPSessionPoolPrivate +gst_rtsp_server_get_type
@@ -212,31 +362,40 @@ GstRTSPSessionPoolPrivate GstRTSPSession GstRTSPSession GstRTSPSessionClass + gst_rtsp_session_new gst_rtsp_session_get_sessionid + +gst_rtsp_session_get_header + gst_rtsp_session_set_timeout gst_rtsp_session_get_timeout + gst_rtsp_session_touch gst_rtsp_session_prevent_expire gst_rtsp_session_allow_expire gst_rtsp_session_next_timeout gst_rtsp_session_is_expired + gst_rtsp_session_manage_media gst_rtsp_session_release_media + gst_rtsp_session_get_media -gst_rtsp_session_get_header + +GstRTSPFilterResult +GstRTSPSessionFilterFunc gst_rtsp_session_filter -GST_RTSP_SESSION_CLASS GST_RTSP_SESSION_CAST GST_RTSP_SESSION_CLASS_CAST -GST_RTSP_SESSION GST_IS_RTSP_SESSION -GST_TYPE_RTSP_SESSION -gst_rtsp_session_get_type GST_IS_RTSP_SESSION_CLASS +GST_RTSP_SESSION +GST_RTSP_SESSION_CLASS GST_RTSP_SESSION_GET_CLASS +GST_TYPE_RTSP_SESSION GstRTSPSessionPrivate +gst_rtsp_session_get_type
@@ -245,15 +404,20 @@ GstRTSPSessionPrivate GstRTSPSessionMedia GstRTSPSessionMediaClass gst_rtsp_session_media_new -gst_rtsp_session_media_set_state -gst_rtsp_session_media_get_transport -gst_rtsp_session_media_alloc_channels +gst_rtsp_session_media_matches gst_rtsp_session_media_get_media +gst_rtsp_session_media_get_base_time + +gst_rtsp_session_media_set_state + gst_rtsp_session_media_get_rtsp_state -gst_rtsp_session_media_matches_url gst_rtsp_session_media_set_rtsp_state + +gst_rtsp_session_media_get_transport gst_rtsp_session_media_set_transport + +gst_rtsp_session_media_alloc_channels GST_RTSP_SESSION_MEDIA_CAST GST_RTSP_SESSION_MEDIA_CLASS_CAST @@ -263,78 +427,44 @@ GST_RTSP_SESSION_MEDIA GST_RTSP_SESSION_MEDIA_CLASS GST_RTSP_SESSION_MEDIA_GET_CLASS GST_TYPE_RTSP_SESSION_MEDIA -gst_rtsp_session_media_get_type GstRTSPSessionMediaPrivate +gst_rtsp_session_media_get_type
-rtsp-auth -GstRTSPAuth -GstRTSPAuth -GstRTSPAuthClass -gst_rtsp_auth_new -gst_rtsp_auth_set_basic -gst_rtsp_auth_setup_auth -gst_rtsp_auth_check -gst_rtsp_auth_make_basic +rtsp-session-pool +GstRTSPSessionPool +GstRTSPSessionPool +GstRTSPSessionPoolClass +gst_rtsp_session_pool_new + +gst_rtsp_session_pool_get_max_sessions +gst_rtsp_session_pool_set_max_sessions + +gst_rtsp_session_pool_get_n_sessions + +gst_rtsp_session_pool_create +gst_rtsp_session_pool_find +gst_rtsp_session_pool_remove + +gst_rtsp_session_pool_cleanup + +GstRTSPSessionPoolFunc +gst_rtsp_session_pool_create_watch + +GstRTSPSessionPoolFilterFunc +gst_rtsp_session_pool_filter -GST_IS_RTSP_AUTH -GST_IS_RTSP_AUTH_CLASS -GST_RTSP_AUTH -GST_RTSP_AUTH_CAST -GST_RTSP_AUTH_CLASS -GST_RTSP_AUTH_CLASS_CAST -GST_RTSP_AUTH_GET_CLASS -GST_TYPE_RTSP_AUTH -gst_rtsp_auth_get_type -GstRTSPAuthPrivate -
- -
-rtsp-client -GstRTSPClient -GstRTSPClientState -GstRTSPClient -GstRTSPClientClass -gst_rtsp_client_new -gst_rtsp_client_set_session_pool -gst_rtsp_client_get_session_pool -gst_rtsp_client_set_mount_points -gst_rtsp_client_get_mount_points -gst_rtsp_client_set_use_client_settings -gst_rtsp_client_get_use_client_settings -gst_rtsp_client_set_auth -gst_rtsp_client_get_auth -gst_rtsp_client_accept -gst_rtsp_client_create_from_socket -gst_rtsp_client_attach -gst_rtsp_client_handle_message -gst_rtsp_client_set_send_func -GstRTSPClientSendFunc -gst_rtsp_client_use_socket - -GST_RTSP_CLIENT_CLASS -GST_RTSP_CLIENT_CAST -GST_RTSP_CLIENT_CLASS_CAST -GST_RTSP_CLIENT -GST_IS_RTSP_CLIENT -GST_TYPE_RTSP_CLIENT -gst_rtsp_client_get_type -GST_IS_RTSP_CLIENT_CLASS -GST_RTSP_CLIENT_GET_CLASS -GstRTSPClientPrivate -
- -
-rtsp-params -gst_rtsp_params_set -gst_rtsp_params_get -
- -
-rtsp-sdp -GstSDPInfo -gst_rtsp_sdp_from_media +GST_RTSP_SESSION_POOL_CAST +GST_RTSP_SESSION_POOL_CLASS_CAST +GST_IS_RTSP_SESSION_POOL +GST_IS_RTSP_SESSION_POOL_CLASS +GST_RTSP_SESSION_POOL +GST_RTSP_SESSION_POOL_CLASS +GST_RTSP_SESSION_POOL_GET_CLASS +GST_TYPE_RTSP_SESSION_POOL +GstRTSPSessionPoolPrivate +gst_rtsp_session_pool_get_type
@@ -343,23 +473,39 @@ gst_rtsp_sdp_from_media GstRTSPStream GstRTSPStreamClass gst_rtsp_stream_new + +gst_rtsp_stream_get_index +gst_rtsp_stream_get_srcpad + +gst_rtsp_stream_get_control +gst_rtsp_stream_set_control +gst_rtsp_stream_has_control + gst_rtsp_stream_get_mtu gst_rtsp_stream_set_mtu + +gst_rtsp_stream_get_dscp_qos +gst_rtsp_stream_set_dscp_qos + +gst_rtsp_stream_get_address_pool +gst_rtsp_stream_set_address_pool +gst_rtsp_stream_reserve_address + gst_rtsp_stream_join_bin gst_rtsp_stream_leave_bin + +gst_rtsp_stream_get_server_port +gst_rtsp_stream_get_multicast_address +gst_rtsp_stream_get_rtpsession +gst_rtsp_stream_get_ssrc gst_rtsp_stream_get_rtpinfo gst_rtsp_stream_get_caps + gst_rtsp_stream_recv_rtcp gst_rtsp_stream_recv_rtp + gst_rtsp_stream_add_transport gst_rtsp_stream_remove_transport -gst_rtsp_stream_set_address_pool -gst_rtsp_stream_get_address_pool -gst_rtsp_stream_get_index -gst_rtsp_stream_get_server_port -gst_rtsp_stream_get_ssrc -gst_rtsp_stream_get_address -gst_rtsp_stream_reserve_address GST_RTSP_STREAM_CAST GST_RTSP_STREAM_CLASS_CAST @@ -369,30 +515,38 @@ GST_RTSP_STREAM GST_RTSP_STREAM_CLASS GST_RTSP_STREAM_GET_CLASS GST_TYPE_RTSP_STREAM -gst_rtsp_stream_get_type GstRTSPStreamPrivate +gst_rtsp_stream_get_type
rtsp-stream-transport GstRTSPStreamTransport -GstRTSPKeepAliveFunc -GstRTSPSendFunc GstRTSPStreamTransport GstRTSPStreamTransportClass gst_rtsp_stream_transport_new -gst_rtsp_stream_transport_set_callbacks -gst_rtsp_stream_transport_set_keepalive -gst_rtsp_stream_transport_set_transport + gst_rtsp_stream_transport_get_stream + gst_rtsp_stream_transport_get_transport +gst_rtsp_stream_transport_set_transport + +GstRTSPSendFunc +gst_rtsp_stream_transport_set_callbacks + +GstRTSPKeepAliveFunc +gst_rtsp_stream_transport_set_keepalive + +gst_rtsp_stream_transport_set_active + +gst_rtsp_stream_transport_set_timed_out gst_rtsp_stream_transport_is_timed_out -gst_rtsp_stream_transport_keep_alive + gst_rtsp_stream_transport_send_rtcp gst_rtsp_stream_transport_send_rtp -gst_rtsp_stream_transport_set_active -gst_rtsp_stream_transport_set_timed_out - + +gst_rtsp_stream_transport_keep_alive + GST_RTSP_STREAM_TRANSPORT_CAST GST_RTSP_STREAM_TRANSPORT_CLASS_CAST GST_IS_RTSP_STREAM_TRANSPORT @@ -401,41 +555,63 @@ GST_RTSP_STREAM_TRANSPORT GST_RTSP_STREAM_TRANSPORT_CLASS GST_RTSP_STREAM_TRANSPORT_GET_CLASS GST_TYPE_RTSP_STREAM_TRANSPORT -gst_rtsp_stream_transport_get_type GstRTSPStreamTransportPrivate +gst_rtsp_stream_transport_get_type
-rtsp-address-pool -GstRTSPAddressPool -GstRTSPAddressPool -gst_rtsp_address_pool_new -gst_rtsp_address_pool_add_range -GST_RTSP_ADDRESS_POOL_ANY_IPV4 -GST_RTSP_ADDRESS_POOL_ANY_IPV6 -gst_rtsp_address_pool_add_range_unicast -gst_rtsp_address_pool_clear -gst_rtsp_address_pool_dump -gst_rtsp_address_pool_acquire_address -gst_rtsp_address_pool_reserve_address -gst_rtsp_address_pool_has_unicast_addresses +rtsp-thread-pool +GstRTSPThreadPool +GstRTSPThreadType +GstRTSPThread + +gst_rtsp_thread_new +gst_rtsp_thread_ref +gst_rtsp_thread_unref +gst_rtsp_thread_reuse +gst_rtsp_thread_stop + +GstRTSPThreadPool +GstRTSPThreadPoolClass +gst_rtsp_thread_pool_new + +gst_rtsp_thread_pool_get_max_threads +gst_rtsp_thread_pool_set_max_threads + +gst_rtsp_thread_pool_get_thread -GstRTSPAddressPoolClass -GstRTSPAddressPoolPrivate -gst_rtsp_address_get_type -gst_rtsp_address_pool_get_type -GST_IS_RTSP_ADDRESS_POOL -GST_IS_RTSP_ADDRESS_POOL_CLASS -GST_RTSP_ADDRESS_POOL -GST_RTSP_ADDRESS_POOL_CAST -GST_RTSP_ADDRESS_POOL_CLASS -GST_RTSP_ADDRESS_POOL_CLASS_CAST -GST_RTSP_ADDRESS_POOL_GET_CLASS -GST_TYPE_RTSP_ADDRESS_POOL - -GstRTSPAddress -GstRTSPAddressClass -GstRTSPAddressFlags -gst_rtsp_address_copy -gst_rtsp_address_free +GST_RTSP_THREAD_CAST +GST_RTSP_THREAD_POOL_CAST +GST_RTSP_THREAD_POOL_CLASS_CAST +GST_IS_RTSP_THREAD +GST_IS_RTSP_THREAD_POOL +GST_IS_RTSP_THREAD_POOL_CLASS +GST_RTSP_THREAD +GST_RTSP_THREAD_POOL +GST_RTSP_THREAD_POOL_CLASS +GST_RTSP_THREAD_POOL_GET_CLASS +GST_TYPE_RTSP_THREAD +GST_TYPE_RTSP_THREAD_POOL +GstRTSPThreadPoolPrivate +gst_rtsp_thread_get_type +gst_rtsp_thread_pool_get_type
+ +
+rtsp-token +GstRTSPToken +GstRTSPToken +gst_rtsp_token_new +gst_rtsp_token_ref +gst_rtsp_token_unref +gst_rtsp_token_get_structure +gst_rtsp_token_writable_structure +gst_rtsp_token_get_string + +GST_RTSP_TOKEN_CAST +GST_IS_RTSP_TOKEN +GST_RTSP_TOKEN +GST_TYPE_RTSP_TOKEN +gst_rtsp_token_get_type +
+ diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index b6e2711ab0..c5c0727e86 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -22,6 +22,14 @@ #include "rtsp-address-pool.h" +/** + * gst_rtsp_address_copy: + * @addr: a #GstRTSPAddress + * + * Make a copy of @addr. + * + * Returns: a copy of @addr. + */ GstRTSPAddress * gst_rtsp_address_copy (GstRTSPAddress * addr) { @@ -41,6 +49,13 @@ gst_rtsp_address_copy (GstRTSPAddress * addr) static void gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool, GstRTSPAddress * addr); +/** + * gst_rtsp_address_free: + * @addr: a #GstRTSPAddress + * + * Free @addr and releasing it back into the pool when owned by a + * pool. + */ void gst_rtsp_address_free (GstRTSPAddress * addr) { @@ -54,7 +69,6 @@ gst_rtsp_address_free (GstRTSPAddress * addr) g_slice_free (GstRTSPAddress, addr); } - G_DEFINE_BOXED_TYPE (GstRTSPAddress, gst_rtsp_address, (GBoxedCopyFunc) gst_rtsp_address_copy, (GBoxedFreeFunc) gst_rtsp_address_free); diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index 9a0cb8c8c5..6a6b2d6701 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -34,12 +34,21 @@ G_BEGIN_DECLS #define GST_RTSP_ADDRESS_POOL_CLASS_CAST(klass) ((GstRTSPAddressPoolClass*)(klass)) typedef struct _GstRTSPAddress GstRTSPAddress; -typedef struct _GstRTSPAddressClass GstRTSPAddressClass; typedef struct _GstRTSPAddressPool GstRTSPAddressPool; typedef struct _GstRTSPAddressPoolClass GstRTSPAddressPoolClass; typedef struct _GstRTSPAddressPoolPrivate GstRTSPAddressPoolPrivate; +/** + * GstRTSPAddress: + * @pool: the #GstRTSPAddressPool owner of this address + * @address: the address + * @port: the port number + * @n_ports: number of ports + * @ttl: TTL or 0 for unicast addresses + * + * An address + */ struct _GstRTSPAddress { GstRTSPAddressPool *pool; @@ -48,6 +57,7 @@ struct _GstRTSPAddress { gint n_ports; guint8 ttl; + /**/ gpointer priv; }; @@ -56,6 +66,17 @@ GType gst_rtsp_address_get_type (void); GstRTSPAddress * gst_rtsp_address_copy (GstRTSPAddress *addr); void gst_rtsp_address_free (GstRTSPAddress *addr); +/** + * GstRTSPAddressFlags: + * @GST_RTSP_ADDRESS_FLAG_NONE: no flags + * @GST_RTSP_ADDRESS_FLAG_IPV4: an IPv4 address + * @GST_RTSP_ADDRESS_FLAG_IPV6: and IPv6 address + * @GST_RTSP_ADDRESS_FLAG_EVEN_PORT: address with an even port + * @GST_RTSP_ADDRESS_FLAG_MULTICAST: a multicast address + * @GST_RTSP_ADDRESS_FLAG_UNICAST: a unicast address + * + * Flags used to control allocation of addresses + */ typedef enum { GST_RTSP_ADDRESS_FLAG_NONE = 0, GST_RTSP_ADDRESS_FLAG_IPV4 = (1 << 0), @@ -71,6 +92,7 @@ typedef enum { * Used with gst_rtsp_address_pool_add_range_unicast() to bind to all * IPv4 addresses */ +#define GST_RTSP_ADDRESS_POOL_ANY_IPV4 "0.0.0.0" /** * GST_RTSP_ADDRESS_POOL_ANY_IPV6: @@ -78,22 +100,26 @@ typedef enum { * Used with gst_rtsp_address_pool_add_range_unicast() to bind to all * IPv6 addresses */ - -#define GST_RTSP_ADDRESS_POOL_ANY_IPV4 "0.0.0.0" #define GST_RTSP_ADDRESS_POOL_ANY_IPV6 "::" /** * GstRTSPAddressPool: * @parent: the parent GObject * - * An address pool, all member are prive + * An address pool, all member are private */ struct _GstRTSPAddressPool { GObject parent; + /*< private >*/ GstRTSPAddressPoolPrivate *priv; }; +/** + * GstRTSPAddressPoolClass: + * + * Opaque Address pool class. + */ struct _GstRTSPAddressPoolClass { GObjectClass parent_class; }; diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index a2e38c30b7..628bc4457b 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -149,10 +149,10 @@ gst_rtsp_auth_new (void) * gst_rtsp_auth_add_basic: * @auth: a #GstRTSPAuth * @basic: the basic token - * @authgroup: authorisation group + * @token: authorisation token * * Add a basic token for the default authentication algorithm that - * enables the client qith privileges from @authgroup. + * enables the client with privileges listed in @token. */ void gst_rtsp_auth_add_basic (GstRTSPAuth * auth, const gchar * basic, diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index c0d9629362..cd5de87ea1 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -105,7 +105,7 @@ typedef gboolean (*GstRTSPClientSendFunc) (GstRTSPClient *client, /** * GstRTSPClient: * - * The client structure. + * The client object represents the connection and its state with a client. */ struct _GstRTSPClient { GObject parent; @@ -115,10 +115,13 @@ struct _GstRTSPClient { /** * GstRTSPClientClass: + * @create_sdp: called when the SDP needs to be created for media. + * @configure_client_transport: called when the client transport needs to be + * configured. * @params_set: set parameters. This function should also initialize the - * RTSP response(state->response) via a call to gst_rtsp_message_init_response() + * RTSP response(state->response) via a call to gst_rtsp_message_init_response() * @params_get: get parameters. This function should also initialize the - * RTSP response(state->response) via a call to gst_rtsp_message_init_response() + * RTSP response(state->response) via a call to gst_rtsp_message_init_response() * * The client class structure. */ diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 896261a13b..ca26d26320 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -53,6 +53,7 @@ typedef struct _GstRTSPMediaFactoryPrivate GstRTSPMediaFactoryPrivate; struct _GstRTSPMediaFactory { GObject parent; + /*< private >*/ GstRTSPMediaFactoryPrivate *priv; }; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d7e4291f48..46706fa6bf 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -774,8 +774,9 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) /** * gst_rtsp_media_use_time_provider: * @media: a #GstRTSPMedia + * @time_provider: if a #GstNetTimeProvider should be used * - * Set @media to provide a GstNetTimeProvider. + * Set @media to provide a #GstNetTimeProvider. */ void gst_rtsp_media_use_time_provider (GstRTSPMedia * media, gboolean time_provider) diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 7b64cf3007..ebb7b673e1 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -76,6 +76,7 @@ typedef enum { struct _GstRTSPMedia { GObject parent; + /*< private >*/ GstRTSPMediaPrivate *priv; }; diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index 4d5e1928e0..f4098676a9 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -110,6 +110,8 @@ gst_rtsp_permissions_new (void) /** * gst_rtsp_permissions_add_role: * @permissions: a #GstRTSPPermissions + * @role: a role + * @structure: the permissions structure * * Add the configuration in @structure to @permissions for @role. */ @@ -151,7 +153,9 @@ gst_rtsp_permissions_add_role (GstRTSPPermissions * permissions, /** * gst_rtsp_permissions_remove_role: * @permissions: a #GstRTSPPermissions + * @role: a role * + * Remove all permissions for @role in @permissions. */ void gst_rtsp_permissions_remove_role (GstRTSPPermissions * permissions, @@ -165,7 +169,11 @@ gst_rtsp_permissions_remove_role (GstRTSPPermissions * permissions, /** * gst_rtsp_permissions_get_role: * @permissions: a #GstRTSPPermissions + * @role: a role * + * Get all permissions for @role in @permissions. + * + * Returns: the structure with permissions for @role. */ const GstStructure * gst_rtsp_permissions_get_role (GstRTSPPermissions * permissions, @@ -187,6 +195,16 @@ gst_rtsp_permissions_get_role (GstRTSPPermissions * permissions, return NULL; } +/** + * gst_rtsp_permissions_is_allowed: + * @permissions: a #GstRTSPPermissions + * @role: a role + * @permission: a permission + * + * Check if @role in @permissions is given permission for @permission. + * + * Returns: %TRUE if @role is allowed @permission. + */ gboolean gst_rtsp_permissions_is_allowed (GstRTSPPermissions * permissions, const gchar * role, const gchar * permission) diff --git a/gst/rtsp-server/rtsp-permissions.h b/gst/rtsp-server/rtsp-permissions.h index 5e06841c23..1fe62573f8 100644 --- a/gst/rtsp-server/rtsp-permissions.h +++ b/gst/rtsp-server/rtsp-permissions.h @@ -33,7 +33,6 @@ GType gst_rtsp_permissions_get_type (void); #define GST_RTSP_PERMISSIONS_CAST(obj) ((GstRTSPPermissions*)(obj)) #define GST_RTSP_PERMISSIONS(obj) (GST_RTSP_PERMISSIONS_CAST(obj)) - /** * GstRTSPPermissions: * diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index b4e83939cc..311a01d18c 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -61,6 +61,7 @@ struct _GstRTSPServer { * object that handles the new connection on @socket. * @setup_connection: Setup the new client connection. The default * implementation will configure the TLS certificate. + * @client_connected: emited when a new client connected. * * The RTSP server class structure */ diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 57f4473d97..3f3fd15ef7 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -356,7 +356,7 @@ gst_rtsp_session_media_set_rtsp_state (GstRTSPSessionMedia * media, } /** - * gst_rtsp_session_media_set_rtsp_state: + * gst_rtsp_session_media_get_rtsp_state: * @media: a #GstRTSPSessionMedia * * Get the current RTSP state of @media. diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 2cbc60282e..65867ab1b2 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -48,6 +48,7 @@ struct _GstRTSPSessionMedia { GObject parent; + /*< private >*/ GstRTSPSessionMediaPrivate *priv; }; diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index ca490de724..ff077ebb7e 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -52,6 +52,7 @@ typedef struct _GstRTSPSessionPoolPrivate GstRTSPSessionPoolPrivate; struct _GstRTSPSessionPool { GObject parent; + /*< private >*/ GstRTSPSessionPoolPrivate *priv; }; diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index e206032735..60ed6fad4b 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -67,6 +67,7 @@ typedef enum struct _GstRTSPSession { GObject parent; + /*< private >*/ GstRTSPSessionPrivate *priv; }; diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index ed69faa632..61257f5dc0 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -42,7 +42,25 @@ typedef struct _GstRTSPStreamTransportPrivate GstRTSPStreamTransportPrivate; #include "rtsp-stream.h" +/** + * GstRTSPSendFunc: + * @buffer: a #GstBuffer + * @channel: a channel + * @user_data: user data + * + * Function registered with gst_rtsp_stream_transport_set_callbacks() and + * called when @buffer must be sent on @channel. + * + * Returns: %TRUE on success + */ typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); +/** + * GstRTSPKeepAliveFunc: + * @user_data: user data + * + * Function registered with gst_rtsp_stream_transport_set_keepalive() and called + * when the stream is active. + */ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); /** @@ -54,6 +72,7 @@ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); struct _GstRTSPStreamTransport { GObject parent; + /*< private >*/ GstRTSPStreamTransportPrivate *priv; }; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 2a91126d86..fd8038e737 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -951,6 +951,7 @@ alloc_ports (GstRTSPStream * stream) * gst_rtsp_stream_get_server_port: * @stream: a #GstRTSPStream * @server_port: (out): result server port + * @family: the port family to get * * Fill @server_port with the port pair used by the server. This function can * only be called when @stream has been joined. diff --git a/gst/rtsp-server/rtsp-thread-pool.h b/gst/rtsp-server/rtsp-thread-pool.h index a9c013b376..1637018ffa 100644 --- a/gst/rtsp-server/rtsp-thread-pool.h +++ b/gst/rtsp-server/rtsp-thread-pool.h @@ -62,6 +62,10 @@ typedef enum /** * GstRTSPThread: + * @mini_object: parent #GstMiniObject + * @type: the thread type + * @context: a #GMainContext + * @loop: a #GMainLoop * * Structure holding info about a mainloop running in a thread */ @@ -121,11 +125,13 @@ gst_rtsp_thread_unref (GstRTSPThread * thread) struct _GstRTSPThreadPool { GObject parent; + /*< private >*/ GstRTSPThreadPoolPrivate *priv; }; /** * GstRTSPThreadPoolClass: + * @pool: a #GThreadPool used internally * @get_thread: get or reuse a thread object * @configure_thread: configure a thread object * @thread_enter: called from the thread when it is entered From d357fc55af2104dac6549fe9dd3705aee813c27f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 11 Jul 2013 12:24:33 +0200 Subject: [PATCH 0726/1776] docs: more updates --- gst/rtsp-server/rtsp-auth.c | 5 ++--- gst/rtsp-server/rtsp-media-factory.h | 1 - gst/rtsp-server/rtsp-media.h | 6 +++--- gst/rtsp-server/rtsp-mount-points.h | 7 +------ gst/rtsp-server/rtsp-session-pool.h | 3 --- gst/rtsp-server/rtsp-stream.h | 2 +- 6 files changed, 7 insertions(+), 17 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 628bc4457b..06f5aeba7d 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -211,10 +211,9 @@ default_setup (GstRTSPAuth * auth, GstRTSPClientState * state) /** * gst_rtsp_auth_setup: * @auth: a #GstRTSPAuth - * @client: the client - * @state: TODO + * @state: the client state * - * Add authentication tokens to @response. + * Add authentication tokens to @response in @state. * * Returns: FALSE if something is wrong. */ diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index ca26d26320..035cbe2cb0 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -45,7 +45,6 @@ typedef struct _GstRTSPMediaFactoryPrivate GstRTSPMediaFactoryPrivate; /** * GstRTSPMediaFactory: - * @parent: the parent GObject * * The definition and logic for constructing the pipeline for a media. The media * can contain multiple streams like audio and video. diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index ebb7b673e1..d001549f9d 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -82,12 +82,12 @@ struct _GstRTSPMedia { /** * GstRTSPMediaClass: - * @context: the main context for dispatching messages - * @loop: the mainloop for message. - * @thread: the thread dispatching messages. * @handle_message: handle a message * @unprepare: the default implementation sets the pipeline's state * to GST_STATE_NULL and removes all elements. + * @convert_range: convert a range to the given unit + * @query_position: query the current posision in the pipeline + * @query_stop: query when playback will stop * * The RTSP media class */ diff --git a/gst/rtsp-server/rtsp-mount-points.h b/gst/rtsp-server/rtsp-mount-points.h index b57c041f58..3f9b5b7b2f 100644 --- a/gst/rtsp-server/rtsp-mount-points.h +++ b/gst/rtsp-server/rtsp-mount-points.h @@ -41,23 +41,18 @@ typedef struct _GstRTSPMountPointsPrivate GstRTSPMountPointsPrivate; /** * GstRTSPMountPoints: - * @parent: parent GObject - * @mounts: the mountpoints to mediafactory mapping * * Creates a #GstRTSPMediaFactory object for a given url. */ struct _GstRTSPMountPoints { GObject parent; + /*< private >*/ GstRTSPMountPointsPrivate *priv; }; /** * GstRTSPMountPointsClass: - * @parent_class: parent GObject class - * @find_factory: Create or return a previously cached #GstRTSPMediaFactory object - * for the given url. the default implementation will use the factory - * added with gst_rtsp_mount_points_add_factory(). * * The class for the media mounts object. */ diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index ff077ebb7e..51325621b4 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -42,9 +42,6 @@ typedef struct _GstRTSPSessionPoolPrivate GstRTSPSessionPoolPrivate; /** * GstRTSPSessionPool: - * @max_sessions: the maximum number of sessions. - * @lock: locking the session hashtable - * @sessions: hashtable of sessions indexed by the session id. * * An object that keeps track of the active sessions. This object is usually * attached to a #GstRTSPServer object to manage the sessions in that server. diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 8e5cbc520c..240fc480d4 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -46,13 +46,13 @@ typedef struct _GstRTSPStreamPrivate GstRTSPStreamPrivate; /** * GstRTSPStream: - * @parent: the parent instance * * The definition of a media stream. */ struct _GstRTSPStream { GObject parent; + /*< private >*/ GstRTSPStreamPrivate *priv; }; From 8b4c9570fa1dcce2e0fd0b4e0db531e1f82394a5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 11 Jul 2013 16:28:09 +0200 Subject: [PATCH 0727/1776] session-pool: make vmethod to create a session Make a vmethod to create a sessions so that subclasses can create custom session objects --- gst/rtsp-server/rtsp-session-pool.c | 14 +++++++++++++- gst/rtsp-server/rtsp-session-pool.h | 7 ++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index f0b65dc81c..393ce6568a 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -56,6 +56,8 @@ static void gst_rtsp_session_pool_set_property (GObject * object, guint propid, static void gst_rtsp_session_pool_finalize (GObject * object); static gchar *create_session_id (GstRTSPSessionPool * pool); +static GstRTSPSession *create_session (GstRTSPSessionPool * pool, + const gchar * id); G_DEFINE_TYPE (GstRTSPSessionPool, gst_rtsp_session_pool, G_TYPE_OBJECT); @@ -79,6 +81,7 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); klass->create_session_id = create_session_id; + klass->create_session = create_session; GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsessionpool", 0, "GstRTSPSessionPool"); @@ -279,6 +282,12 @@ create_session_id (GstRTSPSessionPool * pool) return g_strndup (id, 16); } +static GstRTSPSession * +create_session (GstRTSPSessionPool * pool, const gchar * id) +{ + return gst_rtsp_session_new (id); +} + /** * gst_rtsp_session_pool_create: * @pool: a #GstRTSPSessionPool @@ -330,7 +339,10 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) goto collision; } else { /* not found, create session and insert it in the pool */ - result = gst_rtsp_session_new (id); + if (klass->create_session) + result = create_session (pool, id); + if (result == NULL) + goto too_many_sessions; /* take additional ref for the pool */ g_object_ref (result); g_hash_table_insert (priv->sessions, diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 51325621b4..82468b19b2 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -22,7 +22,6 @@ #ifndef __GST_RTSP_SESSION_POOL_H__ #define __GST_RTSP_SESSION_POOL_H__ - G_BEGIN_DECLS typedef struct _GstRTSPSessionPool GstRTSPSessionPool; @@ -57,11 +56,13 @@ struct _GstRTSPSessionPool { * GstRTSPSessionPoolClass: * @create_session_id: create a new random session id. Subclasses can create * custom session ids and should not check if the session exists. + * @create_session: make a new session object. */ struct _GstRTSPSessionPoolClass { GObjectClass parent_class; - gchar * (*create_session_id) (GstRTSPSessionPool *pool); + gchar * (*create_session_id) (GstRTSPSessionPool *pool); + GstRTSPSession * (*create_session) (GstRTSPSessionPool *pool, const gchar *id); }; /** @@ -108,7 +109,7 @@ GType gst_rtsp_session_pool_get_type (void); /* creating a session pool */ GstRTSPSessionPool * gst_rtsp_session_pool_new (void); -/* counting sessionss */ +/* counting sessions */ void gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool *pool, guint max); guint gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool *pool); From 0b3644a21be28b5747acede5982b9d653dea26d9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 11 Jul 2013 16:57:14 +0200 Subject: [PATCH 0728/1776] docs: improve docs --- docs/README | 10 +++- docs/libs/gst-rtsp-server-docs.sgml | 6 ++- docs/libs/gst-rtsp-server-sections.txt | 59 ++++++++++++++---------- gst/rtsp-server/rtsp-address-pool.c | 7 +++ gst/rtsp-server/rtsp-auth.c | 7 +++ gst/rtsp-server/rtsp-client.c | 29 +++++++++++- gst/rtsp-server/rtsp-client.h | 16 +++---- gst/rtsp-server/rtsp-media-factory-uri.c | 13 ++++++ gst/rtsp-server/rtsp-media-factory.c | 19 ++++++++ gst/rtsp-server/rtsp-media-factory.h | 14 +++--- gst/rtsp-server/rtsp-media.c | 7 +++ gst/rtsp-server/rtsp-mount-points.c | 19 +++++++- gst/rtsp-server/rtsp-params.c | 8 ++++ gst/rtsp-server/rtsp-permissions.c | 8 ++++ gst/rtsp-server/rtsp-sdp.c | 8 ++++ gst/rtsp-server/rtsp-server.c | 44 ++++++++++++++++-- gst/rtsp-server/rtsp-server.h | 19 ++++---- gst/rtsp-server/rtsp-session-media.c | 8 ++++ gst/rtsp-server/rtsp-session-pool.c | 23 +++++++++ gst/rtsp-server/rtsp-session.c | 27 +++++++++++ gst/rtsp-server/rtsp-stream-transport.c | 7 +++ gst/rtsp-server/rtsp-stream.c | 7 +++ gst/rtsp-server/rtsp-thread-pool.c | 7 +++ gst/rtsp-server/rtsp-token.c | 7 +++ 24 files changed, 322 insertions(+), 57 deletions(-) diff --git a/docs/README b/docs/README index 943382e29f..f2e878bd39 100644 --- a/docs/README +++ b/docs/README @@ -93,8 +93,8 @@ can build simple server applications with it. g_main_loop_run (loop); } - The server manages two other objects: GstRTSPSessionPool and - GstRTSPMountPoints. + The server manages four other objects: GstRTSPSessionPool, + GstRTSPMountPoints, GstRTSPAuth and GstRTSPThreadPool. The GstRTSPSessionPool is an object that keeps track of all the active sessions in the server. A session will usually be kept for each client that performed a @@ -109,6 +109,12 @@ can build simple server applications with it. request URL to a specific stream and its configuration. We explain in the next topic how to configure this object. + GstRTSPAuth is an object that authenticates users and authorizes actions + performed by users. + + GstRTSPThreadPool manages the threads used for client connections and media + pipelines. + * Making url mount points diff --git a/docs/libs/gst-rtsp-server-docs.sgml b/docs/libs/gst-rtsp-server-docs.sgml index 716d8b216f..4035cc8d69 100644 --- a/docs/libs/gst-rtsp-server-docs.sgml +++ b/docs/libs/gst-rtsp-server-docs.sgml @@ -19,11 +19,15 @@ + + - + + + diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index edfe53ecb7..3e6d6be7e2 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -1,6 +1,8 @@
rtsp-address-pool GstRTSPAddressPool + + GST_RTSP_ADDRESS_POOL_ANY_IPV4 GST_RTSP_ADDRESS_POOL_ANY_IPV6 GstRTSPAddress @@ -8,6 +10,7 @@ GstRTSPAddressFlags gst_rtsp_address_copy gst_rtsp_address_free + GstRTSPAddressPool GstRTSPAddressPoolClass gst_rtsp_address_pool_new @@ -45,10 +48,12 @@ gst_rtsp_auth_remove_basic gst_rtsp_auth_setup gst_rtsp_auth_check + GST_RTSP_AUTH_CHECK_URL GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT + GST_RTSP_MEDIA_FACTORY_ROLE GST_RTSP_MEDIA_FACTORY_PERM_ACCESS GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT @@ -68,9 +73,11 @@ gst_rtsp_auth_get_type
rtsp-client GstRTSPClient + GstRTSPClientState gst_rtsp_client_state_get_current + GstRTSPClient GstRTSPClientClass @@ -82,24 +89,25 @@ gst_rtsp_client_set_session_pool gst_rtsp_client_get_mount_points gst_rtsp_client_set_mount_points -gst_rtsp_client_get_use_client_settings -gst_rtsp_client_set_use_client_settings - gst_rtsp_client_get_auth gst_rtsp_client_set_auth gst_rtsp_client_get_thread_pool gst_rtsp_client_set_thread_pool +gst_rtsp_client_get_use_client_settings +gst_rtsp_client_set_use_client_settings + gst_rtsp_client_get_connection gst_rtsp_client_set_connection +gst_rtsp_client_attach + GstRTSPClientSendFunc gst_rtsp_client_set_send_func gst_rtsp_client_handle_message gst_rtsp_client_send_request -gst_rtsp_client_attach GstRTSPClientSessionFilterFunc gst_rtsp_client_session_filter @@ -190,8 +198,20 @@ GstRTSPMediaFactoryClass gst_rtsp_media_factory_new -gst_rtsp_media_factory_construct -gst_rtsp_media_factory_create_element +gst_rtsp_media_factory_get_launch +gst_rtsp_media_factory_set_launch + +gst_rtsp_media_factory_get_permissions +gst_rtsp_media_factory_set_permissions + +gst_rtsp_media_factory_set_shared +gst_rtsp_media_factory_is_shared + +gst_rtsp_media_factory_is_eos_shutdown +gst_rtsp_media_factory_set_eos_shutdown + +gst_rtsp_media_factory_get_protocols +gst_rtsp_media_factory_set_protocols gst_rtsp_media_factory_get_address_pool gst_rtsp_media_factory_set_address_pool @@ -199,20 +219,9 @@ gst_rtsp_media_factory_set_address_pool gst_rtsp_media_factory_get_buffer_size gst_rtsp_media_factory_set_buffer_size -gst_rtsp_media_factory_get_launch -gst_rtsp_media_factory_set_launch +gst_rtsp_media_factory_construct +gst_rtsp_media_factory_create_element -gst_rtsp_media_factory_get_permissions -gst_rtsp_media_factory_set_permissions - -gst_rtsp_media_factory_get_protocols -gst_rtsp_media_factory_set_protocols - -gst_rtsp_media_factory_is_eos_shutdown -gst_rtsp_media_factory_set_eos_shutdown - -gst_rtsp_media_factory_set_shared -gst_rtsp_media_factory_is_shared GST_RTSP_MEDIA_FACTORY_CAST GST_RTSP_MEDIA_FACTORY_CLASS_CAST @@ -316,11 +325,14 @@ gst_rtsp_server_set_address gst_rtsp_server_get_service gst_rtsp_server_set_service -gst_rtsp_server_get_bound_port - gst_rtsp_server_get_backlog gst_rtsp_server_set_backlog +gst_rtsp_server_get_tls_certificate +gst_rtsp_server_set_tls_certificate + +gst_rtsp_server_get_bound_port + gst_rtsp_server_get_mount_points gst_rtsp_server_set_mount_points @@ -333,9 +345,6 @@ gst_rtsp_server_set_thread_pool gst_rtsp_server_get_auth gst_rtsp_server_set_auth -gst_rtsp_server_get_tls_certificate -gst_rtsp_server_set_tls_certificate - gst_rtsp_server_get_use_client_settings gst_rtsp_server_set_use_client_settings @@ -562,6 +571,7 @@ gst_rtsp_stream_transport_get_type
rtsp-thread-pool GstRTSPThreadPool + GstRTSPThreadType GstRTSPThread @@ -571,6 +581,7 @@ gst_rtsp_thread_unref gst_rtsp_thread_reuse gst_rtsp_thread_stop + GstRTSPThreadPool GstRTSPThreadPoolClass gst_rtsp_thread_pool_new diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index c5c0727e86..297f85cba5 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -16,6 +16,13 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-address-pool + * @short_description: A pool of network addresses + * @see_also: #GstRTSPStream, #GstRTSPStreamTransport + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include #include diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 06f5aeba7d..dc0b2e04a7 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -16,6 +16,13 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-auth + * @short_description: Authentication and authorization + * @see_also: #GstRTSPPermission, #GstRTSPtoken + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d5feb6ffe0..6df8059e51 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -16,6 +16,28 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-client + * @short_description: A client connection state + * @see_also: #GstRTSPServer, #GstRTSPThreadPool + * + * The client object handles the connection with a client for as long as a TCP + * connection is open. + * + * A #GstRTSPClient is created by #GstRTSPServer when a new connection is + * accepted and it inherits the #GstRTSPMountPoints, #GstRTSPSessionPool, + * #GstRTSPAuth and #GstRTSPThreadPool from the server. + * + * The client connection should be configured with the #GstRTSPConnection using + * gst_rtsp_client_set_connection() before it can be attached to a #GMainContext + * using gst_rtsp_client_attach(). From then on the client will handle requests + * on the connection. + * + * Use gst_rtsp_client_session_filter() to iterate or modify all the + * #GstRTSPSession objects managed by the client object. + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include #include @@ -2391,6 +2413,9 @@ gst_rtsp_client_get_connection (GstRTSPClient * client) * Set @func as the callback that will be called when a new message needs to be * sent to the client. @user_data is passed to @func and @notify is called when * @user_data is no longer in use. + * + * By default, the client will send the messages on the #GstRTSPConnection that + * was configured with gst_rtsp_client_attach() was called. */ void gst_rtsp_client_set_send_func (GstRTSPClient * client, @@ -2453,7 +2478,8 @@ gst_rtsp_client_handle_message (GstRTSPClient * client, * @session: a #GstRTSPSession to send the request to or %NULL * @request: The request #GstRTSPMessage to send * - * Send a request message to the client. + * Send a request message to the remote end. @request must be a + * #GST_RTSP_MESSAGE_REQUEST. */ GstRTSPResult gst_rtsp_client_send_request (GstRTSPClient * client, GstRTSPSession * session, @@ -2733,6 +2759,7 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0); priv = client->priv; + g_return_val_if_fail (priv->connection != NULL, 0); g_return_val_if_fail (priv->watch == NULL, 0); /* create watch for the connection and attach */ diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index cd5de87ea1..82f5eec91e 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -160,32 +160,32 @@ void gst_rtsp_client_set_mount_points (GstRTSPClient *client, GstRTSPMountPoints *mounts); GstRTSPMountPoints * gst_rtsp_client_get_mount_points (GstRTSPClient *client); -void gst_rtsp_client_set_use_client_settings (GstRTSPClient * client, - gboolean use_client_settings); -gboolean gst_rtsp_client_get_use_client_settings (GstRTSPClient * client); - void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); void gst_rtsp_client_set_thread_pool (GstRTSPClient *client, GstRTSPThreadPool *pool); GstRTSPThreadPool * gst_rtsp_client_get_thread_pool (GstRTSPClient *client); +void gst_rtsp_client_set_use_client_settings (GstRTSPClient * client, + gboolean use_client_settings); +gboolean gst_rtsp_client_get_use_client_settings (GstRTSPClient * client); + gboolean gst_rtsp_client_set_connection (GstRTSPClient *client, GstRTSPConnection *conn); GstRTSPConnection * gst_rtsp_client_get_connection (GstRTSPClient *client); +guint gst_rtsp_client_attach (GstRTSPClient *client, + GMainContext *context); + void gst_rtsp_client_set_send_func (GstRTSPClient *client, GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify); + GstRTSPResult gst_rtsp_client_handle_message (GstRTSPClient *client, GstRTSPMessage *message); - GstRTSPResult gst_rtsp_client_send_request (GstRTSPClient * client, GstRTSPSession *session, GstRTSPMessage *request); -guint gst_rtsp_client_attach (GstRTSPClient *client, - GMainContext *context); - /** * GstRTSPClientSessionFilterFunc: * @client: a #GstRTSPClient object diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index e2e80d93ef..46300a9f62 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -16,6 +16,19 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-media-factory-uri + * @short_description: A factory for URI sources + * @see_also: #GstRTSPMediaFactory, #GstRTSPMedia + * + * This specialized #GstRTSPMediaFactory constructs media pipelines from a URI, + * given with gst_rtsp_media_factory_uri_set_uri(). + * + * It will automatically demux and payload the different streams found in the + * media at URL. + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 2864f40ae3..391ea83e58 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -16,6 +16,25 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-media-factory + * @short_description: A factory for media pipelines + * @see_also: #GstRTSPMountPoints, #GstRTSPMedia + * + * The #GstRTSPMediaFactory is responsible for creating or recycling + * #GstRTSPMedia objects based on the passed URL. + * + * The default implementation of the object can create #GstRTSPMedia objects + * containing a pipeline created from a launch description set with + * gst_rtsp_media_factory_set_launch(). + * + * Media from a factory can be shared by setting the shared flag with + * gst_rtsp_media_factory_set_shared(). When a factory is shared, + * gst_rtsp_media_factory_construct() will return the same #GstRTSPMedia when + * the url matches. + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include "rtsp-media-factory.h" diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 035cbe2cb0..2815d95f1e 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -69,10 +69,10 @@ struct _GstRTSPMediaFactory { * #GstRTSPMedia for @url. The default implementation of this * function calls create_element to retrieve an element and then looks for * pay%d to create the streams. - * @configure: configure the media created with @construct. The default - * implementation will configure the 'shared' property of the media. * @create_pipeline: create a new pipeline or re-use an existing one and * add the #GstRTSPMedia's element created by @construct to the pipeline. + * @configure: configure the media created with @construct. The default + * implementation will configure the 'shared' property of the media. * @media_constructed: signal emited when a media was constructed * @media_configure: signal emited when a media should be configured * @@ -85,8 +85,8 @@ struct _GstRTSPMediaFactoryClass { GstElement * (*create_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); - void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); GstElement * (*create_pipeline) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); + void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); /* signals */ void (*media_constructed) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); @@ -99,14 +99,14 @@ GType gst_rtsp_media_factory_get_type (void); GstRTSPMediaFactory * gst_rtsp_media_factory_new (void); /* configuring the factory */ -void gst_rtsp_media_factory_set_permissions (GstRTSPMediaFactory *factory, - GstRTSPPermissions *permissions); -GstRTSPPermissions * gst_rtsp_media_factory_get_permissions (GstRTSPMediaFactory *factory); - void gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, const gchar *launch); gchar * gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_permissions (GstRTSPMediaFactory *factory, + GstRTSPPermissions *permissions); +GstRTSPPermissions * gst_rtsp_media_factory_get_permissions (GstRTSPMediaFactory *factory); + void gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory, gboolean shared); gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 46706fa6bf..78f5f853c4 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -16,6 +16,13 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-media + * @short_description: The media pipeline + * @see_also: #GstRTSPMediaFactory, #GstRTSPStream + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include #include diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 9df3c757dc..86c7a4369a 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -16,7 +16,24 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ - +/** + * SECTION:rtsp-mount-points + * @short_description: Map a path to media + * @see_also: #GstRTSPMediaFactory, #GstRTSPClient + * + * A #GstRTSPMountPoints object maintains a relation between paths + * and #GstRTSPMediaFactory objects. This object is usually given to + * #GstRTSPClient and used to find the media attached to a path. + * + * With gst_rtsp_mount_points_add_factory () and + * gst_rtsp_mount_points_remove_factory(), factories can be added and + * removed. + * + * With gst_rtsp_mount_points_match() you can find the #GstRTSPMediaFactory + * object that completely matches the given path. + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include #include "rtsp-mount-points.h" diff --git a/gst/rtsp-server/rtsp-params.c b/gst/rtsp-server/rtsp-params.c index be45e0fc66..d1f9b698c1 100644 --- a/gst/rtsp-server/rtsp-params.c +++ b/gst/rtsp-server/rtsp-params.c @@ -16,6 +16,14 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-params + * @short_description: Param get and set implementation + * @see_also: #GstRTSPClient + * + * Last reviewed on 2013-07-11 (1.0.0) + */ + #include #include "rtsp-params.h" diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index f4098676a9..eae9383be9 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -16,6 +16,14 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-permissions + * @short_description: Roles and associated permissions + * @see_also: #GstRTSPToken, #GstRTSPAuth + * + * Last reviewed on 2013-07-11 (1.0.0) + */ + #include diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 5dfec79d97..be94d19b55 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -16,6 +16,14 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-sdp + * @short_description: Make SDP messages + * @see_also: #GstRTSPMedia + * + * Last reviewed on 2013-07-11 (1.0.0) + */ + #include #include "rtsp-sdp.h" diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 8f63d3430e..f9766b61b9 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -16,7 +16,42 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ - +/** + * SECTION:rtsp-server + * @short_description: The main server object + * @see_also: #GstRTSPClient, #GstRTSPThreadPool + * + * The server object is the object listening for connections on a port and + * creating #GstRTSPClient objects to handle those connections. + * + * The server will listen on the address set with gst_rtsp_server_set_address() + * and the port or service configured with gst_rtsp_server_set_service(). + * Use gst_rtsp_server_set_backlog() to configure the amount of pending requests + * that the server will keep. By default the server listens on the current + * network (0.0.0.0) and port 8554. + * + * The server will require an SSL connection when a TLS certificate has been + * set with gst_rtsp_server_set_tls_certificate(). + * + * To start the server, use gst_rtsp_server_attach() to attach it to a + * #GMainContext. For more control, gst_rtsp_server_create_source() and + * gst_rtsp_server_create_socket() can be used to get a #GSource and #GSocket + * respectively. + * + * gst_rtsp_server_transfer_connection() can be used to transfer an existing + * socket to the RTSP server, for example from an HTTP server. + * + * Once the server socket is attached to a mainloop, it will start accepting + * connections. When a new connection is received, a new #GstRTSPClient object + * is created to handle the connection. The new client will be configured with + * the server #GstRTSPAuth, #GstRTSPMountPoints, #GstRTSPSessionPool and + * #GstRTSPThreadPool. + * + * The server uses the configured #GstRTSPThreadPool object to handle the + * remainder of the communication with this client. + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include #include @@ -99,7 +134,6 @@ GST_DEBUG_CATEGORY_STATIC (rtsp_server_debug); #define GST_CAT_DEFAULT rtsp_server_debug typedef struct _ClientContext ClientContext; -typedef struct _Loop Loop; static guint gst_rtsp_server_signals[SIGNAL_LAST] = { 0 }; @@ -165,7 +199,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) * pending connections for the server may grow. If a connection request arrives * when the queue is full, the client may receive an error with an indication of * ECONNREFUSED or, if the underlying protocol supports retransmission, the - * request may be ignored so that a later reattempt at connection succeeds. + * request may be ignored so that a later reattempt at connection succeeds. */ g_object_class_install_property (gobject_class, PROP_BACKLOG, g_param_spec_int ("backlog", "Backlog", @@ -376,6 +410,10 @@ out: * @service should be a string containing the service name (see services(5)) or * a string containing a port number between 1 and 65535. * + * When @service is set to "0", the server will listen on a random free + * port. The actual used port can be retrieved with + * gst_rtsp_server_get_bound_port(). + * * This function must be called before the server is bound. */ void diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 311a01d18c..7140bff2c4 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -56,11 +56,12 @@ struct _GstRTSPServer { /** * GstRTSPServerClass: - * * @create_client: Create, configure a new GstRTSPClient - * object that handles the new connection on @socket. + * object that handles the new connection on @socket. The default + * implementation will create a GstRTSPClient and will configure the + * mount-points, auth, session-pool and thread-pool on the client. * @setup_connection: Setup the new client connection. The default - * implementation will configure the TLS certificate. + * implementation will configure the TLS certificate when specified. * @client_connected: emited when a new client connected. * * The RTSP server class structure @@ -68,8 +69,6 @@ struct _GstRTSPServer { struct _GstRTSPServerClass { GObjectClass parent_class; - GThreadPool *pool; - GstRTSPClient * (*create_client) (GstRTSPServer *server); gboolean (*setup_connection) (GstRTSPServer *server, GstRTSPClient *client, GstRTSPConnection *conn); @@ -87,11 +86,14 @@ gchar * gst_rtsp_server_get_address (GstRTSPServer *serve void gst_rtsp_server_set_service (GstRTSPServer *server, const gchar *service); gchar * gst_rtsp_server_get_service (GstRTSPServer *server); -int gst_rtsp_server_get_bound_port (GstRTSPServer *server); - void gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog); gint gst_rtsp_server_get_backlog (GstRTSPServer *server); +void gst_rtsp_server_set_tls_certificate (GstRTSPServer *server, GTlsCertificate *cert); +GTlsCertificate * gst_rtsp_server_get_tls_certificate (GstRTSPServer *server); + +int gst_rtsp_server_get_bound_port (GstRTSPServer *server); + void gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool); GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *server); @@ -108,9 +110,6 @@ void gst_rtsp_server_set_use_client_settings (GstRTSPServer *se gboolean use_client_settings); gboolean gst_rtsp_server_get_use_client_settings (GstRTSPServer *server); -void gst_rtsp_server_set_tls_certificate (GstRTSPServer *server, GTlsCertificate *cert); -GTlsCertificate * gst_rtsp_server_get_tls_certificate (GstRTSPServer *server); - gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket *socket, const gchar * ip, gint port, const gchar *initial_buffer); diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 3f3fd15ef7..5740a0440d 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -16,6 +16,14 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-session-media + * @short_description: Media managed in a session + * @see_also: #GstRTSPMedia, #GstRTSPSession + * + * Last reviewed on 2013-07-11 (1.0.0) + */ + #include #include "rtsp-session.h" diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 393ce6568a..d18c11c14f 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -16,6 +16,29 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-session-pool + * @short_description: An object for managing sessions + * @see_also: #GstRTSPSession + * + * The #GstRTSPSessionPool object manages a list of #GstRTSPSession objects. + * + * The maximum number of sessions can be configured with + * gst_rtsp_session_pool_set_max_sessions(). The current number of sessions can + * be retrieved with gst_rtsp_session_pool_get_n_sessions(). + * + * Use gst_rtsp_session_pool_create() to create a new #GstRTSPSession object. + * The session object can be found again with its id and + * gst_rtsp_session_pool_find(). + * + * All sessions can be iterated with gst_rtsp_session_pool_filter(). + * + * Run gst_rtsp_session_pool_cleanup() periodically to remove timed out sessions + * or use gst_rtsp_session_pool_create_watch() to be notified when session + * cleanup should be performed. + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include "rtsp-session-pool.h" diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index fe93a5f260..20540ab82b 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -16,6 +16,33 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-session + * @short_description: An object to manage media + * @see_also: #GstRTSPSessionPool, #GstRTSPSessionMedia, #GstRTSPMedia + * + * The #GstRTSPSession is identified by an id, unique in the + * #GstRTSPSessionPool that created the session and manages media and its + * configuration. + * + * A #GstRTSPSession has a timeout that can be retrieved with + * gst_rtsp_session_get_timeout(). You can check if the sessions is expired with + * gst_rtsp_session_is_expired(). gst_rtsp_session_touch() will reset the + * expiration counter of the session. + * + * When a client configures a media with SETUP, a session will be created to + * keep track of the configuration of that media. With + * gst_rtsp_session_manage_media(), the media is added to the managed media + * in the session. With gst_rtsp_session_release_media() the media can be + * released again from the session. Managed media is identified in the sessions + * with a url. Use gst_rtsp_session_get_media() to get the media that matches + * (part of) the given url. + * + * The media in a session can be iterated with gst_rtsp_session_filter(). + * + * Last reviewed on 2013-07-11 (1.0.0) + */ + #include #include "rtsp-session.h" diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 0a03ad21c3..40452c27c7 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -16,6 +16,13 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-stream-transport + * @short_description: A media stream transport configuration + * @see_also: #GstRTSPStream + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include #include diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index fd8038e737..63222c4159 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -16,6 +16,13 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-stream + * @short_description: A media stream + * @see_also: #GstRTSPMedia + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include #include diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index 88bd792749..236da0de24 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -16,6 +16,13 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-thread-pool + * @short_description: A pool of threads + * @see_also: #GstRTSPMedia, #GstRTSPClient + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index 2a4d29bb51..f82e58db3c 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -16,6 +16,13 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +/** + * SECTION:rtsp-token + * @short_description: Roles and permissions for a client + * @see_also: #GstRTSPClient, #GstRTSPPermission, #GstRTSPAuth + * + * Last reviewed on 2013-07-11 (1.0.0) + */ #include From 868a7a5a93d115cb8e0bd058df6646a59d98ca9e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 11 Jul 2013 17:05:00 +0200 Subject: [PATCH 0729/1776] tests: fix client test --- tests/check/gst/client.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index e25ba480ef..f08add5a56 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -115,6 +115,7 @@ setup_client (const gchar * launch_line) GstRTSPSessionPool *session_pool; GstRTSPMountPoints *mount_points; GstRTSPMediaFactory *factory; + GstRTSPThreadPool *thread_pool; client = gst_rtsp_client_new (); @@ -132,8 +133,12 @@ setup_client (const gchar * launch_line) gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); gst_rtsp_client_set_mount_points (client, mount_points); + thread_pool = gst_rtsp_thread_pool_new (); + gst_rtsp_client_set_thread_pool (client, thread_pool); + g_object_unref (mount_points); g_object_unref (session_pool); + g_object_unref (thread_pool); return client; } @@ -359,6 +364,7 @@ setup_multicast_client (void) GstRTSPMountPoints *mount_points; GstRTSPMediaFactory *factory; GstRTSPAddressPool *address_pool; + GstRTSPThreadPool *thread_pool; client = gst_rtsp_client_new (); @@ -376,9 +382,13 @@ setup_multicast_client (void) gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); gst_rtsp_client_set_mount_points (client, mount_points); + thread_pool = gst_rtsp_thread_pool_new (); + gst_rtsp_client_set_thread_pool (client, thread_pool); + g_object_unref (mount_points); g_object_unref (session_pool); g_object_unref (address_pool); + g_object_unref (thread_pool); return client; } From c2d4b79b69fe18cc647ad9f2a68b2024f793281e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 11 Jul 2013 17:18:58 +0200 Subject: [PATCH 0730/1776] server: let context ref the server So that we don't risk losing the server object early anc crash. --- gst/rtsp-server/rtsp-server.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index f9766b61b9..631826aef9 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1093,6 +1093,7 @@ free_client_context (ClientContext * ctx) GST_RTSP_SERVER_UNLOCK (ctx->server); g_object_unref (ctx->client); + g_object_unref (ctx->server); g_slice_free (ClientContext, ctx); return G_SOURCE_REMOVE; @@ -1106,8 +1107,6 @@ unmanage_client (GstRTSPClient * client, ClientContext * ctx) GST_DEBUG_OBJECT (server, "unmanage client %p", client); - g_object_ref (server); - GST_RTSP_SERVER_LOCK (server); priv->clients = g_list_remove (priv->clients, ctx); GST_RTSP_SERVER_UNLOCK (server); @@ -1122,8 +1121,6 @@ unmanage_client (GstRTSPClient * client, ClientContext * ctx) } else { free_client_context (ctx); } - - g_object_unref (server); } /* add the client context to the active list of clients, takes ownership @@ -1139,7 +1136,7 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) GST_DEBUG_OBJECT (server, "manage client %p", client); ctx = g_slice_new0 (ClientContext); - ctx->server = server; + ctx->server = g_object_ref (server); ctx->client = client; GST_RTSP_SERVER_LOCK (server); From 7f8fdbc453be3e2e440d7d0290fe93bf35a3ce58 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 11 Jul 2013 17:28:04 +0200 Subject: [PATCH 0731/1776] thread-pool: we don't require a state --- gst/rtsp-server/rtsp-thread-pool.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index 236da0de24..dd0a3c181b 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -462,7 +462,6 @@ gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool * pool, GstRTSPThread *result = NULL; g_return_val_if_fail (GST_IS_RTSP_THREAD_POOL (pool), NULL); - g_return_val_if_fail (state != NULL, NULL); klass = GST_RTSP_THREAD_POOL_GET_CLASS (pool); From 8200efbbd0a713ab2473cb633a790653030ee2ed Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 11 Jul 2013 17:28:17 +0200 Subject: [PATCH 0732/1776] tests: fix media test --- tests/check/gst/media.c | 44 ++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 0692bcb382..c7da079d5e 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -29,6 +29,8 @@ GST_START_TEST (test_launch) GstRTSPStream *stream; GstRTSPTimeRange *range; gchar *str; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; factory = gst_rtsp_media_factory_new (); fail_if (gst_rtsp_media_factory_is_shared (factory)); @@ -53,7 +55,11 @@ GST_START_TEST (test_launch) /* fails, need to be prepared */ fail_if (gst_rtsp_media_seek (media, range)); - fail_unless (gst_rtsp_media_prepare (media, NULL)); + pool = gst_rtsp_thread_pool_new (); + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + + fail_unless (gst_rtsp_media_prepare (media, thread)); str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT); fail_unless (g_str_equal (str, "npt=0-")); @@ -119,6 +125,10 @@ GST_START_TEST (test_media_prepare) GstRTSPMediaFactory *factory; GstRTSPMedia *media; GstRTSPUrl *url; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + + pool = gst_rtsp_thread_pool_new (); /* test non-reusable media first */ factory = gst_rtsp_media_factory_new (); @@ -132,10 +142,15 @@ GST_START_TEST (test_media_prepare) fail_unless (GST_IS_RTSP_MEDIA (media)); fail_unless (gst_rtsp_media_n_streams (media) == 1); - fail_unless (gst_rtsp_media_prepare (media, NULL)); + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 1); - fail_if (gst_rtsp_media_prepare (media, NULL)); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_if (gst_rtsp_media_prepare (media, thread)); g_object_unref (media); gst_rtsp_url_free (url); @@ -155,10 +170,15 @@ GST_START_TEST (test_media_prepare) g_object_set (G_OBJECT (media), "reusable", TRUE, NULL); - fail_unless (gst_rtsp_media_prepare (media, NULL)); + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 1); - fail_unless (gst_rtsp_media_prepare (media, NULL)); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (gst_rtsp_media_unprepare (media)); g_object_unref (media); @@ -191,6 +211,8 @@ GST_START_TEST (test_media_dyn_prepare) GstElement *bin, *src, *pay; GstElement *pipeline; GstPad *srcpad; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; bin = gst_bin_new ("bin"); fail_if (bin == NULL); @@ -219,14 +241,22 @@ GST_START_TEST (test_media_dyn_prepare) g_signal_connect (srcpad, "notify::caps", (GCallback) on_notify_caps, pay); + pool = gst_rtsp_thread_pool_new (); + fail_unless (gst_rtsp_media_n_streams (media) == 0); - fail_unless (gst_rtsp_media_prepare (media, NULL)); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (gst_rtsp_media_n_streams (media) == 1); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 0); fail_unless (gst_rtsp_media_n_streams (media) == 0); - fail_unless (gst_rtsp_media_prepare (media, NULL)); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (gst_rtsp_media_n_streams (media) == 1); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 0); From f6674d5c102a2239caf51c5d1a810b755cca85ff Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 11 Jul 2013 20:45:11 +0200 Subject: [PATCH 0733/1776] mount-points: fix debug --- gst/rtsp-server/rtsp-mount-points.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 86c7a4369a..e242af29cf 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -76,7 +76,7 @@ data_item_dump (gconstpointer a, gpointer prefix) { const DataItem *item = a; - GST_DEBUG ("%s%s %p\n", (gchar *) prefix, item->path, item->factory); + GST_DEBUG ("%s%s %p", (gchar *) prefix, item->path, item->factory); } static gint From e1628a0515a37b1551258bdf9113dd63e42202ec Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 12:36:40 +0200 Subject: [PATCH 0734/1776] client: add connection to state --- gst/rtsp-server/rtsp-client.c | 1 + gst/rtsp-server/rtsp-client.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6df8059e51..b8b96a6e2e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1859,6 +1859,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) GstRTSPMessage response = { 0 }; gchar *sessid; + state.conn = priv->connection; state.client = client; state.request = request; state.response = &response; diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 82f5eec91e..8c2dd765a7 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -52,6 +52,7 @@ typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; /** * GstRTSPClientState: * @server: the server + * @conn: the connection * @client: the client * @request: the complete request * @uri: the complete url parsed from @request @@ -69,6 +70,7 @@ typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; */ struct _GstRTSPClientState { GstRTSPServer *server; + GstRTSPConnection *conn; GstRTSPClient *client; GstRTSPMessage *request; GstRTSPUrl *uri; From a1e96c226960ef5ba2a01cdcd0fddbb4591abb9f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 12:38:54 +0200 Subject: [PATCH 0735/1776] client: add state push/pop --- gst/rtsp-server/rtsp-client.c | 55 ++++++++++++++++++++++++++++++++--- gst/rtsp-server/rtsp-client.h | 3 ++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b8b96a6e2e..e451d0ad11 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1829,7 +1829,7 @@ client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) } } -static GPrivate state_key; +static GPrivate current_state; /** * gst_rtsp_client_state_get_current: @@ -1842,7 +1842,54 @@ static GPrivate state_key; GstRTSPClientState * gst_rtsp_client_state_get_current (void) { - return g_private_get (&state_key); + GSList *l; + + l = g_private_get (¤t_state); + if (l == NULL) + return NULL; + + return (GstRTSPClientState *) (l->data); + +} + +/** + * gst_rtsp_client_state_push_current: + * @state: a ##GstRTSPClientState + * + * Pushes @state onto the state stack. The current + * state can then be received using gst_rtsp_client_state_get_current(). + **/ +void +gst_rtsp_client_state_push_current (GstRTSPClientState * state) +{ + GSList *l; + + g_return_if_fail (state != NULL); + + l = g_private_get (¤t_state); + l = g_slist_prepend (l, state); + g_private_set (¤t_state, l); +} + +/** + * gst_rtsp_client_state_pop_current: + * @state: a #GstRTSPClientState + * + * Pops @state off the state stack (verifying that @state + * is on the top of the stack). + **/ +void +gst_rtsp_client_state_pop_current (GstRTSPClientState * state) +{ + GSList *l; + + l = g_private_get (¤t_state); + + g_return_if_fail (l != NULL); + g_return_if_fail (l->data == state); + + l = g_slist_delete_link (l, l); + g_private_set (¤t_state, l); } static void @@ -1864,7 +1911,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) state.request = request; state.response = &response; state.auth = priv->auth; - g_private_set (&state_key, &state); + gst_rtsp_client_state_push_current (&state); if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) { gst_rtsp_message_dump (request); @@ -1947,7 +1994,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) } done: - g_private_set (&state_key, NULL); + gst_rtsp_client_state_pop_current (&state); if (session) g_object_unref (session); if (uri) diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 8c2dd765a7..d624638a50 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -86,6 +86,9 @@ struct _GstRTSPClientState { }; GstRTSPClientState * gst_rtsp_client_state_get_current (void); +void gst_rtsp_client_state_push_current (GstRTSPClientState * state); +void gst_rtsp_client_state_pop_current (GstRTSPClientState * state); + /** * GstRTSPClientSendFunc: From 4b2e6d88b3453b1d3f571af3609740dd6a2f4b8a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 12:41:52 +0200 Subject: [PATCH 0736/1776] auth: move TLS handling to auth module Remove the TLS settings on the server and move it to the auth module because that is where security related bits go. --- examples/test-video.c | 46 ++++++++---- gst/rtsp-server/rtsp-auth.c | 78 +++++++++++++++++++- gst/rtsp-server/rtsp-auth.h | 9 +++ gst/rtsp-server/rtsp-server.c | 134 +++++++--------------------------- gst/rtsp-server/rtsp-server.h | 3 +- 5 files changed, 147 insertions(+), 123 deletions(-) diff --git a/examples/test-video.c b/examples/test-video.c index 05db5f32d8..4a8e2058b0 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -22,7 +22,7 @@ #include /* define this if you want the resource to only be available when using - * user/admin as the password */ + * user/password as the password */ #undef WITH_AUTH /* define this if you want the server to use TLS */ @@ -52,7 +52,10 @@ main (int argc, char *argv[]) GstRTSPMediaFactory *factory; #ifdef WITH_AUTH GstRTSPAuth *auth; + GstRTSPToken *token; + GstStructure *s; gchar *basic; + GstRTSPPermissions *permissions; #endif #ifdef WITH_TLS GTlsCertificate *cert; @@ -64,6 +67,11 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); + +#ifdef WITH_AUTH + /* make a new authentication manager. it can be added to control access to all + * the factories on the server or on individual factories. */ + auth = gst_rtsp_auth_new (); #ifdef WITH_TLS cert = g_tls_certificate_new_from_pem ("-----BEGIN CERTIFICATE-----" "MIICJjCCAY+gAwIBAgIBBzANBgkqhkiG9w0BAQUFADCBhjETMBEGCgmSJomT8ixk" @@ -88,25 +96,27 @@ main (int argc, char *argv[]) "DwIga8PqH5Sf5sHedy2+CiK0V4MRfoU4c3zQ6kArI+bEgSkCIQCLA1vXBiE31B5s" "bdHoYa1BXebfZVd+1Hd95IfEM5mbRwIgSkDuQwV55BBlvWph3U8wVIMIb4GStaH8" "W535W8UBbEg=" "-----END PRIVATE KEY-----", -1, NULL); - gst_rtsp_server_set_tls_certificate (server, cert); + gst_rtsp_auth_set_tls_certificate (auth, cert); g_object_unref (cert); #endif + /* make user token */ + token = gst_rtsp_token_new (); + s = gst_rtsp_token_writable_structure (token); + gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "user", NULL); + basic = gst_rtsp_auth_make_basic ("user", "password"); + gst_rtsp_auth_add_basic (auth, basic, token); + g_free (basic); + gst_rtsp_token_unref (token); + + /* configure in the server */ + gst_rtsp_server_set_auth (server, auth); +#endif + /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ mounts = gst_rtsp_server_get_mount_points (server); -#ifdef WITH_AUTH - /* make a new authentication manager. it can be added to control access to all - * the factories on the server or on individual factories. */ - auth = gst_rtsp_auth_new (); - basic = gst_rtsp_auth_make_basic ("user", "admin"); - gst_rtsp_auth_set_basic (auth, basic); - g_free (basic); - /* configure in the server */ - gst_rtsp_server_set_auth (server, auth); -#endif - /* make a media factory for a test stream. The default media factory can use * gst-launch syntax to create pipelines. * any launch line works as long as it contains elements named pay%d. Each @@ -117,6 +127,16 @@ main (int argc, char *argv[]) "x264enc ! rtph264pay name=pay0 pt=96 " "audiotestsrc ! audio/x-raw,rate=8000 ! " "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); +#ifdef WITH_AUTH + /* add permissions for the user media role */ + permissions = gst_rtsp_permissions_new (); + gst_rtsp_permissions_add_role (permissions, "user", + gst_structure_new ("user", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + gst_rtsp_media_factory_set_permissions (factory, permissions); + gst_rtsp_permissions_unref (permissions); +#endif /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test", factory); diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index dc0b2e04a7..f5afb973b0 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -34,6 +34,9 @@ struct _GstRTSPAuthPrivate { GMutex lock; + + /* the TLS certificate */ + GTlsCertificate *certificate; GHashTable *basic; /* protected by lock */ GstRTSPMethod methods; }; @@ -109,6 +112,9 @@ gst_rtsp_auth_finalize (GObject * obj) GstRTSPAuthPrivate *priv = auth->priv; GST_INFO ("finalize auth %p", auth); + + if (priv->certificate) + g_object_unref (priv->certificate); g_hash_table_unref (priv->basic); g_mutex_clear (&priv->lock); @@ -152,6 +158,64 @@ gst_rtsp_auth_new (void) return result; } +/** + * gst_rtsp_auth_set_tls_certificate: + * @auth: a #GstRTSPAuth + * @cert: (allow none): a #GTlsCertificate + * + * Set the TLS certificate for the auth. Client connections will only + * be accepted when TLS is negotiated. + */ +void +gst_rtsp_auth_set_tls_certificate (GstRTSPAuth * auth, GTlsCertificate * cert) +{ + GstRTSPAuthPrivate *priv; + GTlsCertificate *old; + + g_return_if_fail (GST_IS_RTSP_AUTH (auth)); + + priv = auth->priv; + + if (cert) + g_object_ref (cert); + + g_mutex_lock (&priv->lock); + old = priv->certificate; + priv->certificate = cert; + g_mutex_unlock (&priv->lock); + + if (old) + g_object_unref (old); +} + +/** + * gst_rtsp_auth_get_tls_certificate: + * @auth: a #GstRTSPAuth + * + * Get the #GTlsCertificate used for negotiating TLS @auth. + * + * Returns: (transfer full): the #GTlsCertificate of @auth. g_object_unref() after + * usage. + */ +GTlsCertificate * +gst_rtsp_auth_get_tls_certificate (GstRTSPAuth * auth) +{ + GstRTSPAuthPrivate *priv; + GTlsCertificate *result; + + g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), NULL); + + priv = auth->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->certificate)) + g_object_ref (result); + g_mutex_unlock (&priv->lock); + + return result; +} + + /** * gst_rtsp_auth_add_basic: * @auth: a #GstRTSPAuth @@ -321,12 +385,24 @@ default_check (GstRTSPAuth * auth, GstRTSPClientState * state, GstRTSPAuthPrivate *priv = auth->priv; gboolean res = FALSE; - if (g_str_equal (check, GST_RTSP_AUTH_CHECK_URL)) { + if (g_str_equal (check, GST_RTSP_AUTH_CHECK_CONNECT)) { + /* new connection */ + if (priv->certificate) { + GTlsConnection *tls; + + /* configure the connection */ + tls = gst_rtsp_connection_get_tls (state->conn, NULL); + g_tls_connection_set_certificate (tls, priv->certificate); + } + res = TRUE; + } else if (g_str_equal (check, GST_RTSP_AUTH_CHECK_URL)) { + /* check url and methods */ if ((state->method & priv->methods) != 0) res = ensure_authenticated (auth, state); else res = TRUE; } else if (g_str_has_prefix (check, "auth.check.media.factory.")) { + /* check access to media factory */ const gchar *role; GstRTSPPermissions *perms; diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index cb8579fae1..29044de0f1 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -80,6 +80,9 @@ GType gst_rtsp_auth_get_type (void); GstRTSPAuth * gst_rtsp_auth_new (void); +void gst_rtsp_auth_set_tls_certificate (GstRTSPAuth *auth, GTlsCertificate *cert); +GTlsCertificate * gst_rtsp_auth_get_tls_certificate (GstRTSPAuth *auth); + void gst_rtsp_auth_add_basic (GstRTSPAuth *auth, const gchar * basic, GstRTSPToken *token); void gst_rtsp_auth_remove_basic (GstRTSPAuth *auth, const gchar * basic); @@ -93,6 +96,12 @@ gboolean gst_rtsp_auth_check (const gchar *check); gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass); /* checks */ +/** + * GST_RTSP_AUTH_CHECK_CONNECT: + * + * Check a new connection + */ +#define GST_RTSP_AUTH_CHECK_CONNECT "auth.check.connect" /** * GST_RTSP_AUTH_CHECK_URL: * diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 631826aef9..49d6d514c2 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -31,7 +31,7 @@ * network (0.0.0.0) and port 8554. * * The server will require an SSL connection when a TLS certificate has been - * set with gst_rtsp_server_set_tls_certificate(). + * set in the auth object with gst_rtsp_auth_set_tls_certificate(). * * To start the server, use gst_rtsp_server_attach() to attach it to a * #GMainContext. For more control, gst_rtsp_server_create_source() and @@ -89,9 +89,6 @@ struct _GstRTSPServerPrivate /* resource manager */ GstRTSPThreadPool *thread_pool; - /* the TLS certificate */ - GTlsCertificate *certificate; - /* the clients that are connected */ GList *clients; }; @@ -144,8 +141,6 @@ static void gst_rtsp_server_set_property (GObject * object, guint propid, static void gst_rtsp_server_finalize (GObject * object); static GstRTSPClient *default_create_client (GstRTSPServer * server); -static gboolean default_setup_connection (GstRTSPServer * server, - GstRTSPClient * client, GstRTSPConnection * conn); static void gst_rtsp_server_class_init (GstRTSPServerClass * klass) @@ -248,7 +243,6 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) gst_rtsp_client_get_type ()); klass->create_client = default_create_client; - klass->setup_connection = default_setup_connection; GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer"); } @@ -295,9 +289,6 @@ gst_rtsp_server_finalize (GObject * object) if (priv->auth) g_object_unref (priv->auth); - if (priv->certificate) - g_object_unref (priv->certificate); - g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_server_parent_class)->finalize (object); @@ -784,64 +775,6 @@ gst_rtsp_server_get_use_client_settings (GstRTSPServer * server) return res; } -/** - * gst_rtsp_server_set_tls_certificate: - * @server: a #GstRTSPServer - * @cert: (allow none): a #GTlsCertificate - * - * Set the TLS certificate for the server. Client connections will only - * be accepted when TLS is negotiated. - */ -void -gst_rtsp_server_set_tls_certificate (GstRTSPServer * server, - GTlsCertificate * cert) -{ - GstRTSPServerPrivate *priv; - GTlsCertificate *old; - - g_return_if_fail (GST_IS_RTSP_SERVER (server)); - - priv = server->priv; - - if (cert) - g_object_ref (cert); - - GST_RTSP_SERVER_LOCK (server); - old = priv->certificate; - priv->certificate = cert; - GST_RTSP_SERVER_UNLOCK (server); - - if (old) - g_object_unref (old); -} - -/** - * gst_rtsp_server_get_tls_certificate: - * @server: a #GstRTSPServer - * - * Get the #GTlsCertificate used for negotiating TLS @server. - * - * Returns: (transfer full): the #GTlsCertificate of @server. g_object_unref() after - * usage. - */ -GTlsCertificate * -gst_rtsp_server_get_tls_certificate (GstRTSPServer * server) -{ - GstRTSPServerPrivate *priv; - GTlsCertificate *result; - - g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - - priv = server->priv; - - GST_RTSP_SERVER_LOCK (server); - if ((result = priv->certificate)) - g_object_ref (result); - GST_RTSP_SERVER_UNLOCK (server); - - return result; -} - static void gst_rtsp_server_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec) @@ -1188,25 +1121,6 @@ default_create_client (GstRTSPServer * server) return client; } -static gboolean -default_setup_connection (GstRTSPServer * server, GstRTSPClient * client, - GstRTSPConnection * conn) -{ - GstRTSPServerPrivate *priv = server->priv; - - GST_RTSP_SERVER_LOCK (server); - if (priv->certificate) { - GTlsConnection *tls; - - /* configure the connection */ - tls = gst_rtsp_connection_get_tls (conn, NULL); - g_tls_connection_set_certificate (tls, priv->certificate); - } - GST_RTSP_SERVER_UNLOCK (server); - - return TRUE; -} - /** * gst_rtsp_server_transfer_connection: * @server: a #GstRTSPServer @@ -1282,29 +1196,33 @@ gboolean gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, GstRTSPServer * server) { + GstRTSPServerPrivate *priv = server->priv; GstRTSPClient *client = NULL; GstRTSPServerClass *klass; GstRTSPResult res; GstRTSPConnection *conn = NULL; + GstRTSPClientState state = { NULL }; if (condition & G_IO_IN) { + /* a new client connected. */ + GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, NULL), + accept_failed); + + state.server = server; + state.conn = conn; + state.auth = priv->auth; + gst_rtsp_client_state_push_current (&state); + + if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_CONNECT)) + goto connection_refused; klass = GST_RTSP_SERVER_GET_CLASS (server); - /* a new client connected, create a client object to handle the client. */ if (klass->create_client) client = klass->create_client (server); if (client == NULL) goto client_failed; - /* a new client connected. */ - GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, NULL), - accept_failed); - - if (klass->setup_connection) - if (!klass->setup_connection (server, client, conn)) - goto setup_failed; - /* set connection on the client now */ gst_rtsp_client_set_connection (client, conn); @@ -1316,29 +1234,31 @@ gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, } else { GST_WARNING_OBJECT (server, "received unknown event %08x", condition); } +exit: + gst_rtsp_client_state_pop_current (&state); + return G_SOURCE_CONTINUE; /* ERRORS */ -client_failed: - { - GST_ERROR_OBJECT (server, "failed to create a client"); - return G_SOURCE_CONTINUE; - } accept_failed: { gchar *str = gst_rtsp_strresult (res); GST_ERROR_OBJECT (server, "Could not accept client on socket %p: %s", socket, str); g_free (str); - g_object_unref (client); - return G_SOURCE_CONTINUE; + goto exit; } -setup_failed: +connection_refused: { - GST_ERROR_OBJECT (server, "failed to setup client connection"); + GST_ERROR_OBJECT (server, "connection refused"); gst_rtsp_connection_free (conn); - g_object_unref (client); - return G_SOURCE_CONTINUE; + goto exit; + } +client_failed: + { + GST_ERROR_OBJECT (server, "failed to create a client"); + gst_rtsp_connection_free (conn); + goto exit; } } diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 7140bff2c4..b59482e631 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -70,8 +70,7 @@ struct _GstRTSPServerClass { GObjectClass parent_class; GstRTSPClient * (*create_client) (GstRTSPServer *server); - gboolean (*setup_connection) (GstRTSPServer *server, GstRTSPClient *client, - GstRTSPConnection *conn); + /* signals */ void (*client_connected) (GstRTSPServer *server, GstRTSPClient *client); }; From 9a09d98e6d4ca8ee3c24bf09d89b1e0b90842e1c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 14:10:13 +0200 Subject: [PATCH 0737/1776] docs: fix docs --- docs/libs/gst-rtsp-server-sections.txt | 6 +++--- gst/rtsp-server/rtsp-server.h | 5 ----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 3e6d6be7e2..5b202a479c 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -42,6 +42,8 @@ GstRTSPAuth GstRTSPAuthClass gst_rtsp_auth_new +gst_rtsp_auth_get_tls_certificate +gst_rtsp_auth_set_tls_certificate gst_rtsp_auth_make_basic gst_rtsp_auth_add_basic gst_rtsp_auth_remove_basic @@ -49,6 +51,7 @@ gst_rtsp_auth_setup gst_rtsp_auth_check +GST_RTSP_AUTH_CHECK_CONNECT GST_RTSP_AUTH_CHECK_URL GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT @@ -328,9 +331,6 @@ gst_rtsp_server_set_service gst_rtsp_server_get_backlog gst_rtsp_server_set_backlog -gst_rtsp_server_get_tls_certificate -gst_rtsp_server_set_tls_certificate - gst_rtsp_server_get_bound_port gst_rtsp_server_get_mount_points diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index b59482e631..5d1ae0db78 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -60,8 +60,6 @@ struct _GstRTSPServer { * object that handles the new connection on @socket. The default * implementation will create a GstRTSPClient and will configure the * mount-points, auth, session-pool and thread-pool on the client. - * @setup_connection: Setup the new client connection. The default - * implementation will configure the TLS certificate when specified. * @client_connected: emited when a new client connected. * * The RTSP server class structure @@ -88,9 +86,6 @@ gchar * gst_rtsp_server_get_service (GstRTSPServer *serve void gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog); gint gst_rtsp_server_get_backlog (GstRTSPServer *server); -void gst_rtsp_server_set_tls_certificate (GstRTSPServer *server, GTlsCertificate *cert); -GTlsCertificate * gst_rtsp_server_get_tls_certificate (GstRTSPServer *server); - int gst_rtsp_server_get_bound_port (GstRTSPServer *server); void gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool); From 7532de687a9b53062d727595f6738b04bdfac1e2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 15:13:48 +0200 Subject: [PATCH 0738/1776] client: allow for sending any message, not only requests Change the _send_request() method to _send_message() so that we can both send requests and replies. --- gst/rtsp-server/rtsp-client.c | 22 +++++++++++----------- gst/rtsp-server/rtsp-client.h | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e451d0ad11..529d7ccc6a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2521,24 +2521,24 @@ gst_rtsp_client_handle_message (GstRTSPClient * client, } /** - * gst_rtsp_client_send_request: + * gst_rtsp_client_send_message: * @client: a #GstRTSPClient - * @session: a #GstRTSPSession to send the request to or %NULL - * @request: The request #GstRTSPMessage to send + * @session: a #GstRTSPSession to send the message to or %NULL + * @message: The #GstRTSPMessage to send * - * Send a request message to the remote end. @request must be a - * #GST_RTSP_MESSAGE_REQUEST. + * Send a message message to the remote end. @message must be a + * #GST_RTSP_MESSAGE_REQUEST or a #GST_RTSP_MESSAGE_RESPONSE. */ GstRTSPResult -gst_rtsp_client_send_request (GstRTSPClient * client, GstRTSPSession * session, - GstRTSPMessage * request) +gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession * session, + GstRTSPMessage * message) { g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL); - g_return_val_if_fail (request != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (request->type == GST_RTSP_MESSAGE_REQUEST, - GST_RTSP_EINVAL); + g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL); + g_return_val_if_fail (message->type == GST_RTSP_MESSAGE_REQUEST || + message->type == GST_RTSP_MESSAGE_RESPONSE, GST_RTSP_EINVAL); - send_message (client, session, request, FALSE); + send_message (client, session, message, FALSE); return GST_RTSP_OK; } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index d624638a50..af1ef2c003 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -188,9 +188,9 @@ void gst_rtsp_client_set_send_func (GstRTSPClient *client, GstRTSPResult gst_rtsp_client_handle_message (GstRTSPClient *client, GstRTSPMessage *message); -GstRTSPResult gst_rtsp_client_send_request (GstRTSPClient * client, +GstRTSPResult gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession *session, - GstRTSPMessage *request); + GstRTSPMessage *message); /** * GstRTSPClientSessionFilterFunc: * @client: a #GstRTSPClient object From 5cf75e64af9a9d5b5e5b5cda577a75767c912ad4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 15:19:29 +0200 Subject: [PATCH 0739/1776] auth: handle unauthorized response Move handling of the unauthorized response to the auth module, it can add the appropriate headers to request authorization for the required method much better than the client. --- gst/rtsp-server/rtsp-auth.c | 186 ++++++++++++++++++++-------------- gst/rtsp-server/rtsp-auth.h | 12 +-- gst/rtsp-server/rtsp-client.c | 19 ---- 3 files changed, 111 insertions(+), 106 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index f5afb973b0..f7386a7941 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -56,7 +56,6 @@ static void gst_rtsp_auth_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_auth_finalize (GObject * obj); -static gboolean default_setup (GstRTSPAuth * auth, GstRTSPClientState * state); static gboolean default_authenticate (GstRTSPAuth * auth, GstRTSPClientState * state); static gboolean default_check (GstRTSPAuth * auth, GstRTSPClientState * state, @@ -77,7 +76,6 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) gobject_class->set_property = gst_rtsp_auth_set_property; gobject_class->finalize = gst_rtsp_auth_finalize; - klass->setup = default_setup; klass->authenticate = default_authenticate; klass->check = default_check; @@ -266,47 +264,6 @@ gst_rtsp_auth_remove_basic (GstRTSPAuth * auth, const gchar * basic) g_mutex_unlock (&priv->lock); } -static gboolean -default_setup (GstRTSPAuth * auth, GstRTSPClientState * state) -{ - if (state->response == NULL) - return FALSE; - - /* we only have Basic for now */ - gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE, - "Basic realm=\"GStreamer RTSP Server\""); - - return TRUE; -} - -/** - * gst_rtsp_auth_setup: - * @auth: a #GstRTSPAuth - * @state: the client state - * - * Add authentication tokens to @response in @state. - * - * Returns: FALSE if something is wrong. - */ -gboolean -gst_rtsp_auth_setup (GstRTSPAuth * auth, GstRTSPClientState * state) -{ - gboolean result = FALSE; - GstRTSPAuthClass *klass; - - g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE); - g_return_val_if_fail (state != NULL, FALSE); - - klass = GST_RTSP_AUTH_GET_CLASS (auth); - - GST_DEBUG_OBJECT (auth, "setup auth"); - - if (klass->setup) - result = klass->setup (auth, state); - - return result; -} - static gboolean default_authenticate (GstRTSPAuth * auth, GstRTSPClientState * state) { @@ -378,51 +335,124 @@ no_auth: } } +static void +send_response (GstRTSPAuth * auth, GstRTSPStatusCode code, + GstRTSPClientState * state) +{ + gst_rtsp_message_init_response (state->response, code, + gst_rtsp_status_as_text (code), state->request); + + if (code == GST_RTSP_STS_UNAUTHORIZED) { + /* we only have Basic for now */ + gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE, + "Basic realm=\"GStreamer RTSP Server\""); + } + gst_rtsp_client_send_message (state->client, state->session, state->response); +} + +/* new connection */ +static gboolean +check_connect (GstRTSPAuth * auth, GstRTSPClientState * state, + const gchar * check) +{ + GstRTSPAuthPrivate *priv = auth->priv; + + if (priv->certificate) { + GTlsConnection *tls; + + /* configure the connection */ + tls = gst_rtsp_connection_get_tls (state->conn, NULL); + g_tls_connection_set_certificate (tls, priv->certificate); + } + return TRUE; +} + +/* check url and methods */ +static gboolean +check_url (GstRTSPAuth * auth, GstRTSPClientState * state, const gchar * check) +{ + GstRTSPAuthPrivate *priv = auth->priv; + + if ((state->method & priv->methods) != 0) + if (!ensure_authenticated (auth, state)) + goto not_authenticated; + + return TRUE; + + /* ERRORS */ +not_authenticated: + { + send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state); + return FALSE; + } +} + +/* check access to media factory */ +static gboolean +check_factory (GstRTSPAuth * auth, GstRTSPClientState * state, + const gchar * check) +{ + const gchar *role; + GstRTSPPermissions *perms; + + if (!(role = gst_rtsp_token_get_string (state->token, + GST_RTSP_MEDIA_FACTORY_ROLE))) + goto no_media_role; + if (!(perms = gst_rtsp_media_factory_get_permissions (state->factory))) + goto no_permissions; + + if (g_str_equal (check, "auth.check.media.factory.access")) { + if (!gst_rtsp_permissions_is_allowed (perms, role, + GST_RTSP_MEDIA_FACTORY_PERM_ACCESS)) + goto no_access; + } else if (g_str_equal (check, "auth.check.media.factory.construct")) { + if (gst_rtsp_permissions_is_allowed (perms, role, + GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT)) + goto no_construct; + } + return TRUE; + + /* ERRORS */ +no_media_role: + { + GST_DEBUG_OBJECT (auth, "no media factory role found"); + send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state); + return FALSE; + } +no_permissions: + { + GST_DEBUG_OBJECT (auth, "no permissions on media factory found"); + send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state); + return FALSE; + } +no_access: + { + GST_DEBUG_OBJECT (auth, "no permissions to access media factory"); + send_response (auth, GST_RTSP_STS_NOT_FOUND, state); + return FALSE; + } +no_construct: + { + GST_DEBUG_OBJECT (auth, "no permissions to construct media factory"); + send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state); + return FALSE; + } +} + static gboolean default_check (GstRTSPAuth * auth, GstRTSPClientState * state, const gchar * check) { - GstRTSPAuthPrivate *priv = auth->priv; gboolean res = FALSE; + /* FIXME, use hastable or so */ if (g_str_equal (check, GST_RTSP_AUTH_CHECK_CONNECT)) { - /* new connection */ - if (priv->certificate) { - GTlsConnection *tls; - - /* configure the connection */ - tls = gst_rtsp_connection_get_tls (state->conn, NULL); - g_tls_connection_set_certificate (tls, priv->certificate); - } - res = TRUE; + res = check_connect (auth, state, check); } else if (g_str_equal (check, GST_RTSP_AUTH_CHECK_URL)) { - /* check url and methods */ - if ((state->method & priv->methods) != 0) - res = ensure_authenticated (auth, state); - else - res = TRUE; + res = check_url (auth, state, check); } else if (g_str_has_prefix (check, "auth.check.media.factory.")) { - /* check access to media factory */ - const gchar *role; - GstRTSPPermissions *perms; - - if (!(role = - gst_rtsp_token_get_string (state->token, - GST_RTSP_MEDIA_FACTORY_ROLE))) - goto done; - if (!(perms = gst_rtsp_media_factory_get_permissions (state->factory))) - goto done; - - if (g_str_equal (check, "auth.check.media.factory.access")) - res = - gst_rtsp_permissions_is_allowed (perms, role, - GST_RTSP_MEDIA_FACTORY_PERM_ACCESS); - else if (g_str_equal (check, "auth.check.media.factory.construct")) - res = - gst_rtsp_permissions_is_allowed (perms, role, - GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT); + res = check_factory (auth, state, check); } -done: return res; } diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 29044de0f1..b38d8d20eb 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -53,24 +53,20 @@ struct _GstRTSPAuth { /** * GstRTSPAuthClass: - * @setup: called when an unauthorized resource has been accessed and - * authentication needs to be requested to the client. The default - * implementation adds basic authentication to the response. * @authenticate: check the authentication of a client. The default implementation * checks if the authentication in the header matches one of the basic * authentication tokens. This function should set the authgroup field * in the state. * @check: check if a resource can be accessed. this function should - * call validate to authenticate the client when needed. The default - * implementation disallows unauthenticated access to all methods - * except OPTIONS. + * call authenticate to authenticate the client when needed. The method + * should also construct and send an appropriate response message on + * error. * * The authentication class. */ struct _GstRTSPAuthClass { GObjectClass parent_class; - gboolean (*setup) (GstRTSPAuth *auth, GstRTSPClientState *state); gboolean (*authenticate) (GstRTSPAuth *auth, GstRTSPClientState *state); gboolean (*check) (GstRTSPAuth *auth, GstRTSPClientState *state, const gchar *check); @@ -87,8 +83,6 @@ void gst_rtsp_auth_add_basic (GstRTSPAuth *auth, const gc GstRTSPToken *token); void gst_rtsp_auth_remove_basic (GstRTSPAuth *auth, const gchar * basic); -gboolean gst_rtsp_auth_setup (GstRTSPAuth *auth, GstRTSPClientState *state); - gboolean gst_rtsp_auth_check (const gchar *check); diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 529d7ccc6a..1424032c75 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -470,22 +470,6 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, send_message (client, NULL, state->response, FALSE); } -static void -handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth, - GstRTSPClientState * state) -{ - gst_rtsp_message_init_response (state->response, GST_RTSP_STS_UNAUTHORIZED, - gst_rtsp_status_as_text (GST_RTSP_STS_UNAUTHORIZED), state->request); - - if (auth) { - /* and let the authentication manager setup the auth tokens */ - gst_rtsp_auth_setup (auth, state); - } - - send_message (client, state->session, state->response, FALSE); -} - - static gboolean paths_are_equal (const gchar * path1, const gchar * path2, gint len2) { @@ -599,13 +583,11 @@ no_factory: no_factory_access: { GST_ERROR ("client %p: not authorized to see factory uri %s", client, path); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); return NULL; } not_authorized: { GST_ERROR ("client %p: not authorized for factory uri %s", client, path); - handle_unauthorized_request (client, priv->auth, state); return NULL; } no_media: @@ -2030,7 +2012,6 @@ session_not_found: not_authorized: { GST_ERROR ("client %p: not allowed", client); - handle_unauthorized_request (client, priv->auth, &state); goto done; } not_implemented: From a6a82935958447716f1ba54a9bae648353ad1269 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 16:01:14 +0200 Subject: [PATCH 0740/1776] auth: fix typo --- gst/rtsp-server/rtsp-auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index f7386a7941..9de8c5cf5c 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -406,7 +406,7 @@ check_factory (GstRTSPAuth * auth, GstRTSPClientState * state, GST_RTSP_MEDIA_FACTORY_PERM_ACCESS)) goto no_access; } else if (g_str_equal (check, "auth.check.media.factory.construct")) { - if (gst_rtsp_permissions_is_allowed (perms, role, + if (!gst_rtsp_permissions_is_allowed (perms, role, GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT)) goto no_construct; } From facc91a942ee216eea6c1bdbba5f2072301004ad Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 16:03:07 +0200 Subject: [PATCH 0741/1776] permissions: simplify API a little Avoid passing GstStructure in the add_role method, use varargs instead to construct the structure behind the scenes. We can then also use the structure name as the role and simplify some more logic. --- examples/test-auth.c | 20 +++---- examples/test-cgroups.c | 10 ++-- gst/rtsp-server/rtsp-permissions.c | 85 ++++++++++++++++++------------ gst/rtsp-server/rtsp-permissions.h | 21 +++++--- 4 files changed, 77 insertions(+), 59 deletions(-) diff --git a/examples/test-auth.c b/examples/test-auth.c index b4fc62a516..b72161e9ff 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -95,19 +95,16 @@ main (int argc, char *argv[]) /* allow user and admin to access this resource */ permissions = gst_rtsp_permissions_new (); gst_rtsp_permissions_add_role (permissions, "user", - gst_structure_new ("user", - "media.factory.access", G_TYPE_BOOLEAN, TRUE, - "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); gst_rtsp_permissions_add_role (permissions, "admin", - gst_structure_new ("admin", - "media.factory.access", G_TYPE_BOOLEAN, TRUE, - "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); /* admin2 can look at the media but not construct so he gets a * 401 Unauthorized */ gst_rtsp_permissions_add_role (permissions, "admin2", - gst_structure_new ("admin2", - "media.factory.access", G_TYPE_BOOLEAN, TRUE, - "media.factory.construct", G_TYPE_BOOLEAN, FALSE, NULL)); + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, FALSE, NULL); gst_rtsp_media_factory_set_permissions (factory, permissions); gst_rtsp_permissions_unref (permissions); @@ -124,9 +121,8 @@ main (int argc, char *argv[]) /* user and admin have no permissions so they can't even see the * media and get a 404 Not Found */ gst_rtsp_permissions_add_role (permissions, "admin2", - gst_structure_new ("admin2", - "media.factory.access", G_TYPE_BOOLEAN, TRUE, - "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); gst_rtsp_media_factory_set_permissions (factory, permissions); gst_rtsp_permissions_unref (permissions); diff --git a/examples/test-cgroups.c b/examples/test-cgroups.c index db8e339cd4..7669c3d188 100644 --- a/examples/test-cgroups.c +++ b/examples/test-cgroups.c @@ -194,13 +194,11 @@ main (int argc, char *argv[]) /* allow user and admin to access this resource */ permissions = gst_rtsp_permissions_new (); gst_rtsp_permissions_add_role (permissions, "user", - gst_structure_new ("user", - "media.factory.access", G_TYPE_BOOLEAN, TRUE, - "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); gst_rtsp_permissions_add_role (permissions, "admin", - gst_structure_new ("admin", - "media.factory.access", G_TYPE_BOOLEAN, TRUE, - "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); gst_rtsp_media_factory_set_permissions (factory, permissions); gst_rtsp_permissions_unref (permissions); diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index eae9383be9..33587c787d 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -33,22 +33,15 @@ typedef struct _GstRTSPPermissionsImpl { GstRTSPPermissions permissions; - /* Roles, array of RoleEntry */ - GArray *roles; + /* Roles, array of GstStructure */ + GPtrArray *roles; } GstRTSPPermissionsImpl; -typedef struct -{ - gchar *role; - GstStructure *structure; -} RoleEntry; - static void -clear_role_entry (RoleEntry * role) +free_structure (GstStructure * structure) { - g_free (role->role); - gst_structure_set_parent_refcount (role->structure, NULL); - gst_structure_free (role->structure); + gst_structure_set_parent_refcount (structure, NULL); + gst_structure_free (structure); } //GST_DEBUG_CATEGORY_STATIC (rtsp_permissions_debug); @@ -64,7 +57,7 @@ _gst_rtsp_permissions_free (GstRTSPPermissions * permissions) { GstRTSPPermissionsImpl *impl = (GstRTSPPermissionsImpl *) permissions; - g_array_free (impl->roles, TRUE); + g_ptr_array_free (impl->roles, TRUE); g_slice_free1 (sizeof (GstRTSPPermissionsImpl), permissions); } @@ -90,9 +83,8 @@ gst_rtsp_permissions_init (GstRTSPPermissionsImpl * permissions, (GstMiniObjectCopyFunction) _gst_rtsp_permissions_copy, NULL, (GstMiniObjectFreeFunction) _gst_rtsp_permissions_free); - permissions->roles = g_array_new (FALSE, TRUE, sizeof (RoleEntry)); - g_array_set_clear_func (permissions->roles, - (GDestroyNotify) clear_role_entry); + permissions->roles = + g_ptr_array_new_with_free_func ((GDestroyNotify) free_structure); } /** @@ -119,43 +111,68 @@ gst_rtsp_permissions_new (void) * gst_rtsp_permissions_add_role: * @permissions: a #GstRTSPPermissions * @role: a role - * @structure: the permissions structure + * @fielname: the first field name + * @...: additional arguments * - * Add the configuration in @structure to @permissions for @role. + * Add a new @role to @permissions with the given variables. The fields + * are the same layout as gst_structure_new(). */ void gst_rtsp_permissions_add_role (GstRTSPPermissions * permissions, - const gchar * role, GstStructure * structure) + const gchar * role, const gchar * fieldname, ...) +{ + va_list var_args; + + va_start (var_args, fieldname); + gst_rtsp_permissions_add_role_valist (permissions, role, fieldname, var_args); + va_end (var_args); +} + +/** + * gst_rtsp_permissions_add_role_valist: + * @permissions: a #GstRTSPPermissions + * @role: a role + * @fielname: the first field name + * @var_args: additional fields to add + * + * Add a new @role to @permissions with the given variables. Structure fields + * are set according to the varargs in a manner similar to gst_structure_new(). + */ +void +gst_rtsp_permissions_add_role_valist (GstRTSPPermissions * permissions, + const gchar * role, const gchar * fieldname, va_list var_args) { GstRTSPPermissionsImpl *impl = (GstRTSPPermissionsImpl *) permissions; + GstStructure *structure; gint i, len; - RoleEntry item; gboolean found; g_return_if_fail (GST_IS_RTSP_PERMISSIONS (permissions)); g_return_if_fail (gst_mini_object_is_writable (&permissions->mini_object)); g_return_if_fail (role != NULL); + g_return_if_fail (fieldname != NULL); + + structure = gst_structure_new_valist (role, fieldname, var_args); g_return_if_fail (structure != NULL); len = impl->roles->len; found = FALSE; for (i = 0; i < len; i++) { - RoleEntry *entry = &g_array_index (impl->roles, RoleEntry, i); + GstStructure *entry = g_ptr_array_index (impl->roles, i); - if (g_str_equal (entry->role, role)) { - gst_structure_free (entry->structure); - entry->structure = structure; + if (gst_structure_has_name (entry, role)) { + gst_structure_free (entry); found = TRUE; break; } } - if (!found) { - item.role = g_strdup (role); - item.structure = structure; - gst_structure_set_parent_refcount (structure, - &impl->permissions.mini_object.refcount); - g_array_append_val (impl->roles, item); - } + + gst_structure_set_parent_refcount (structure, + &impl->permissions.mini_object.refcount); + if (!found) + g_ptr_array_add (impl->roles, structure); + else + g_ptr_array_index (impl->roles, i) = structure; } /** @@ -195,10 +212,10 @@ gst_rtsp_permissions_get_role (GstRTSPPermissions * permissions, len = impl->roles->len; for (i = 0; i < len; i++) { - RoleEntry *entry = &g_array_index (impl->roles, RoleEntry, i); + GstStructure *entry = g_ptr_array_index (impl->roles, i); - if (g_str_equal (entry->role, role)) - return entry->structure; + if (gst_structure_has_name (entry, role)) + return entry; } return NULL; } diff --git a/gst/rtsp-server/rtsp-permissions.h b/gst/rtsp-server/rtsp-permissions.h index 1fe62573f8..9beab20819 100644 --- a/gst/rtsp-server/rtsp-permissions.h +++ b/gst/rtsp-server/rtsp-permissions.h @@ -79,15 +79,22 @@ gst_rtsp_permissions_unref (GstRTSPPermissions * permissions) } -GstRTSPPermissions * gst_rtsp_permissions_new (void); +GstRTSPPermissions * gst_rtsp_permissions_new (void); -void gst_rtsp_permissions_add_role (GstRTSPPermissions *permissions, const gchar *role, - GstStructure *structure); -void gst_rtsp_permissions_remove_role (GstRTSPPermissions *permissions, const gchar *role); -const GstStructure * gst_rtsp_permissions_get_role (GstRTSPPermissions *permissions, const gchar *role); +void gst_rtsp_permissions_add_role (GstRTSPPermissions *permissions, + const gchar *role, + const gchar *field_name, ...); +void gst_rtsp_permissions_add_role_valist (GstRTSPPermissions *permissions, + const gchar *role, + const gchar *field_name, + va_list var_args); +void gst_rtsp_permissions_remove_role (GstRTSPPermissions *permissions, + const gchar *role); +const GstStructure * gst_rtsp_permissions_get_role (GstRTSPPermissions *permissions, + const gchar *role); -gboolean gst_rtsp_permissions_is_allowed (GstRTSPPermissions *permissions, - const gchar *role, const gchar *permission); +gboolean gst_rtsp_permissions_is_allowed (GstRTSPPermissions *permissions, + const gchar *role, const gchar *permission); G_END_DECLS From 67d0fbc0485cdfe5c3b55773605eaff3bb1d8d37 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 16:17:57 +0200 Subject: [PATCH 0742/1776] media-factory: add convenience API for factory --- examples/test-auth.c | 15 ++++-------- examples/test-cgroups.c | 8 ++----- gst/rtsp-server/rtsp-media-factory.c | 35 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 3 +++ 4 files changed, 44 insertions(+), 17 deletions(-) diff --git a/examples/test-auth.c b/examples/test-auth.c index b72161e9ff..d491029956 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -65,7 +65,6 @@ main (int argc, char *argv[]) GstRTSPToken *token; gchar *basic; GstStructure *s; - GstRTSPPermissions *permissions; gst_init (&argc, &argv); @@ -93,20 +92,17 @@ main (int argc, char *argv[]) gst_rtsp_mount_points_add_factory (mounts, "/test", factory); /* allow user and admin to access this resource */ - permissions = gst_rtsp_permissions_new (); - gst_rtsp_permissions_add_role (permissions, "user", + gst_rtsp_media_factory_add_role (factory, "user", "media.factory.access", G_TYPE_BOOLEAN, TRUE, "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); - gst_rtsp_permissions_add_role (permissions, "admin", + gst_rtsp_media_factory_add_role (factory, "admin", "media.factory.access", G_TYPE_BOOLEAN, TRUE, "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); /* admin2 can look at the media but not construct so he gets a * 401 Unauthorized */ - gst_rtsp_permissions_add_role (permissions, "admin2", + gst_rtsp_media_factory_add_role (factory, "admin2", "media.factory.access", G_TYPE_BOOLEAN, TRUE, "media.factory.construct", G_TYPE_BOOLEAN, FALSE, NULL); - gst_rtsp_media_factory_set_permissions (factory, permissions); - gst_rtsp_permissions_unref (permissions); /* make another factory */ factory = gst_rtsp_media_factory_new (); @@ -117,14 +113,11 @@ main (int argc, char *argv[]) gst_rtsp_mount_points_add_factory (mounts, "/test2", factory); /* allow admin2 to access this resource */ - permissions = gst_rtsp_permissions_new (); /* user and admin have no permissions so they can't even see the * media and get a 404 Not Found */ - gst_rtsp_permissions_add_role (permissions, "admin2", + gst_rtsp_media_factory_add_role (factory, "admin2", "media.factory.access", G_TYPE_BOOLEAN, TRUE, "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); - gst_rtsp_media_factory_set_permissions (factory, permissions); - gst_rtsp_permissions_unref (permissions); /* don't need the ref to the mapper anymore */ g_object_unref (mounts); diff --git a/examples/test-cgroups.c b/examples/test-cgroups.c index 7669c3d188..4c7504d0ff 100644 --- a/examples/test-cgroups.c +++ b/examples/test-cgroups.c @@ -164,7 +164,6 @@ main (int argc, char *argv[]) GstRTSPToken *token; gchar *basic; GstStructure *s; - GstRTSPPermissions *permissions; GstRTSPThreadPool *thread_pool; gst_init (&argc, &argv); @@ -192,15 +191,12 @@ main (int argc, char *argv[]) gst_rtsp_mount_points_add_factory (mounts, "/test", factory); /* allow user and admin to access this resource */ - permissions = gst_rtsp_permissions_new (); - gst_rtsp_permissions_add_role (permissions, "user", + gst_rtsp_media_factory_add_role (factory, "user", "media.factory.access", G_TYPE_BOOLEAN, TRUE, "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); - gst_rtsp_permissions_add_role (permissions, "admin", + gst_rtsp_media_factory_add_role (factory, "admin", "media.factory.access", G_TYPE_BOOLEAN, TRUE, "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); - gst_rtsp_media_factory_set_permissions (factory, permissions); - gst_rtsp_permissions_unref (permissions); /* don't need the ref to the mapper anymore */ g_object_unref (mounts); diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 391ea83e58..89678dcb92 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -345,6 +345,41 @@ gst_rtsp_media_factory_get_permissions (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_add_role: + * @factory: a #GstRTSPMediaFactory + * @role: a role + * @fieldname: the first field name + * @...: additional arguments + * + * A convenience method to add @role with @fieldname and additional arguments to + * the permissions of @factory. If @factory had no permissions, new permissions + * will be created and the role will be added to it. + */ +void +gst_rtsp_media_factory_add_role (GstRTSPMediaFactory * factory, + const gchar * role, const gchar * fieldname, ...) +{ + GstRTSPMediaFactoryPrivate *priv; + va_list var_args; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + g_return_if_fail (role != NULL); + g_return_if_fail (fieldname != NULL); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + if (priv->permissions == NULL) + priv->permissions = gst_rtsp_permissions_new (); + + va_start (var_args, fieldname); + gst_rtsp_permissions_add_role_valist (priv->permissions, role, fieldname, + var_args); + va_end (var_args); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + /** * gst_rtsp_media_factory_set_launch: * @factory: a #GstRTSPMediaFactory diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 2815d95f1e..33ec5404a6 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -106,6 +106,9 @@ gchar * gst_rtsp_media_factory_get_launch (GstRTSPMediaFacto void gst_rtsp_media_factory_set_permissions (GstRTSPMediaFactory *factory, GstRTSPPermissions *permissions); GstRTSPPermissions * gst_rtsp_media_factory_get_permissions (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_add_role (GstRTSPMediaFactory *factory, + const gchar *role, + const gchar *fieldname, ...); void gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory, gboolean shared); From b8c5aa3a6bf8d7287770b3dfb5094b7fa63acdc6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 16:36:05 +0200 Subject: [PATCH 0743/1776] token: simplify token constructor Use variable arguments to make easier API. --- examples/test-auth.c | 19 +++++-------- examples/test-cgroups.c | 14 +++------- gst/rtsp-server/rtsp-token.c | 52 +++++++++++++++++++++++++++++++++--- gst/rtsp-server/rtsp-token.h | 4 ++- 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/examples/test-auth.c b/examples/test-auth.c index d491029956..27eca57f9b 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -64,7 +64,6 @@ main (int argc, char *argv[]) GstRTSPAuth *auth; GstRTSPToken *token; gchar *basic; - GstStructure *s; gst_init (&argc, &argv); @@ -126,30 +125,24 @@ main (int argc, char *argv[]) auth = gst_rtsp_auth_new (); /* make user token */ - token = gst_rtsp_token_new (); - s = gst_rtsp_token_writable_structure (token); - gst_structure_set (s, "resources.class", G_TYPE_STRING, "user", NULL); - gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "user", NULL); + token = gst_rtsp_token_new ("resources.class", G_TYPE_STRING, "user", + "media.factory.role", G_TYPE_STRING, "user", NULL); basic = gst_rtsp_auth_make_basic ("user", "password"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); gst_rtsp_token_unref (token); /* make admin token */ - token = gst_rtsp_token_new (); - s = gst_rtsp_token_writable_structure (token); - gst_structure_set (s, "resources.class", G_TYPE_STRING, "admin", NULL); - gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "admin", NULL); + token = gst_rtsp_token_new ("resources.class", G_TYPE_STRING, "admin", + "media.factory.role", G_TYPE_STRING, "admin", NULL); basic = gst_rtsp_auth_make_basic ("admin", "power"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); gst_rtsp_token_unref (token); /* make admin2 token */ - token = gst_rtsp_token_new (); - s = gst_rtsp_token_writable_structure (token); - gst_structure_set (s, "resources.class", G_TYPE_STRING, "admin", NULL); - gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "admin2", NULL); + token = gst_rtsp_token_new ("resources.class", G_TYPE_STRING, "admin", + "media.factory.role", G_TYPE_STRING, "admin2", NULL); basic = gst_rtsp_auth_make_basic ("admin2", "power2"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); diff --git a/examples/test-cgroups.c b/examples/test-cgroups.c index 4c7504d0ff..81885884f3 100644 --- a/examples/test-cgroups.c +++ b/examples/test-cgroups.c @@ -163,7 +163,6 @@ main (int argc, char *argv[]) GstRTSPAuth *auth; GstRTSPToken *token; gchar *basic; - GstStructure *s; GstRTSPThreadPool *thread_pool; gst_init (&argc, &argv); @@ -205,21 +204,16 @@ main (int argc, char *argv[]) auth = gst_rtsp_auth_new (); /* make user token */ - token = gst_rtsp_token_new (); - s = gst_rtsp_token_writable_structure (token); - gst_structure_set (s, "cgroup.pool.media.class", G_TYPE_STRING, "user", NULL); - gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "user", NULL); + token = gst_rtsp_token_new ("cgroup.pool.media.class", G_TYPE_STRING, "user", + "media.factory.role", G_TYPE_STRING, "user", NULL); basic = gst_rtsp_auth_make_basic ("user", "password"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); gst_rtsp_token_unref (token); /* make admin token */ - token = gst_rtsp_token_new (); - s = gst_rtsp_token_writable_structure (token); - gst_structure_set (s, "cgroup.pool.media.class", G_TYPE_STRING, "admin", - NULL); - gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "admin", NULL); + token = gst_rtsp_token_new ("cgroup.pool.media.class", G_TYPE_STRING, "admin", + "media.factory.role", G_TYPE_STRING, "admin", NULL); basic = gst_rtsp_auth_make_basic ("admin", "power"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index f82e58db3c..2c228f7dbf 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -84,20 +84,64 @@ gst_rtsp_token_init (GstRTSPTokenImpl * token, GstStructure * structure) } /** - * gst_rtsp_token_new: + * gst_rtsp_token_new_empty: * * Create a new empty Authorization token. * * Returns: (transfer full): a new empty authorization token. */ GstRTSPToken * -gst_rtsp_token_new (void) +gst_rtsp_token_new_empty (void) +{ + return gst_rtsp_token_new (NULL, NULL); +} + +/** + * gst_rtsp_token_new: + * @firstfield: the first fieldname + * @...: additional arguments + * + * Create a new Authorization token with the given fieldnames and values. + * Arguments are given similar to gst_structure_new(). + * + * Returns: (transfer full): a new authorization token. + */ +GstRTSPToken * +gst_rtsp_token_new (const gchar * firstfield, ...) +{ + GstRTSPToken *result; + va_list var_args; + + va_start (var_args, firstfield); + result = gst_rtsp_token_new_valist (firstfield, var_args); + va_end (var_args); + + return result; +} + +/** + * gst_rtsp_token_new: + * @firstfield: the first fieldname + * @var_args additional arguments + * + * Create a new Authorization token with the given fieldnames and values. + * Arguments are given similar to gst_structure_new_valist(). + * + * Returns: (transfer full): a new authorization token. + */ +GstRTSPToken * +gst_rtsp_token_new_valist (const gchar * firstfield, va_list var_args) { GstRTSPTokenImpl *token; + GstStructure *s; + + g_return_val_if_fail (firstfield != NULL, NULL); + + s = gst_structure_new_valist ("GstRTSPToken", firstfield, var_args); + g_return_val_if_fail (s != NULL, NULL); token = g_slice_new0 (GstRTSPTokenImpl); - - gst_rtsp_token_init (token, gst_structure_new_empty ("GstRTSPToken")); + gst_rtsp_token_init (token, s); return (GstRTSPToken *) token; } diff --git a/gst/rtsp-server/rtsp-token.h b/gst/rtsp-server/rtsp-token.h index 732a683ad7..fa6a888ceb 100644 --- a/gst/rtsp-server/rtsp-token.h +++ b/gst/rtsp-server/rtsp-token.h @@ -81,7 +81,9 @@ gst_rtsp_token_unref (GstRTSPToken * token) } -GstRTSPToken * gst_rtsp_token_new (void); +GstRTSPToken * gst_rtsp_token_new_empty (void); +GstRTSPToken * gst_rtsp_token_new (const gchar * firstfield, ...); +GstRTSPToken * gst_rtsp_token_new_valist (const gchar * firstfield, va_list var_args); const GstStructure * gst_rtsp_token_get_structure (GstRTSPToken *token); GstStructure * gst_rtsp_token_writable_structure (GstRTSPToken *token); From c4db3025597af2d8315d80e6d33c8526cdd13607 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 17:06:37 +0200 Subject: [PATCH 0744/1776] token: add method to check boolean permission --- gst/rtsp-server/rtsp-token.c | 21 +++++++++++++++++++++ gst/rtsp-server/rtsp-token.h | 2 ++ 2 files changed, 23 insertions(+) diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index 2c228f7dbf..b252ff533f 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -205,3 +205,24 @@ gst_rtsp_token_get_string (GstRTSPToken * token, const gchar * field) { return gst_structure_get_string (GST_RTSP_TOKEN_STRUCTURE (token), field); } + +/** + * gst_rtsp_token_is_allowed: + * @token: a #GstRTSPToken + * @field: a field name + * + * Check if @token has a boolean @field and if it is set to %TRUE. + * + * Returns: %TRUE if @token has a boolean field named @field set to %TRUE. + */ +gboolean +gst_rtsp_token_is_allowed (GstRTSPToken * token, const gchar * field) +{ + gboolean result; + + if (!gst_structure_get_boolean (GST_RTSP_TOKEN_STRUCTURE (token), field, + &result)) + result = FALSE; + + return result; +} diff --git a/gst/rtsp-server/rtsp-token.h b/gst/rtsp-server/rtsp-token.h index fa6a888ceb..b7c06c4cf6 100644 --- a/gst/rtsp-server/rtsp-token.h +++ b/gst/rtsp-server/rtsp-token.h @@ -90,6 +90,8 @@ GstStructure * gst_rtsp_token_writable_structure (GstRTSPToken *token); const gchar * gst_rtsp_token_get_string (GstRTSPToken *token, const gchar *field); +gboolean gst_rtsp_token_is_allowed (GstRTSPToken *token, + const gchar *field); G_END_DECLS #endif /* __GST_RTSP_TOKEN_H__ */ From 9fe107a96ae90a4cace8e608000cea804f4d5d94 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 17:07:53 +0200 Subject: [PATCH 0745/1776] auth: let the auth module check client_settings Let the auth module decide if client settings are allowed for the current client. --- gst/rtsp-server/rtsp-auth.c | 10 +++++ gst/rtsp-server/rtsp-auth.h | 19 ++++++++- gst/rtsp-server/rtsp-client.c | 73 +++------------------------------- gst/rtsp-server/rtsp-client.h | 4 -- gst/rtsp-server/rtsp-server.c | 74 ----------------------------------- gst/rtsp-server/rtsp-server.h | 4 -- 6 files changed, 34 insertions(+), 150 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 9de8c5cf5c..091b0ef6a1 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -439,6 +439,14 @@ no_construct: } } +static gboolean +check_client_settings (GstRTSPAuth * auth, GstRTSPClientState * state, + const gchar * check) +{ + return gst_rtsp_token_is_allowed (state->token, + GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS); +} + static gboolean default_check (GstRTSPAuth * auth, GstRTSPClientState * state, const gchar * check) @@ -452,6 +460,8 @@ default_check (GstRTSPAuth * auth, GstRTSPClientState * state, res = check_url (auth, state, check); } else if (g_str_has_prefix (check, "auth.check.media.factory.")) { res = check_factory (auth, state, check); + } else if (g_str_equal (check, GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS)) { + res = check_client_settings (auth, state, check); } return res; } diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index b38d8d20eb..80b6f19cb4 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -105,15 +105,25 @@ gchar * gst_rtsp_auth_make_basic (const gchar * user, const g /** * GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS: * - * Check if access is allowed to a factory + * Check if access is allowed to a factory. + * When access is not allowed an 404 Not Found is sent in the response. */ #define GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS "auth.check.media.factory.access" /** * GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT: * * Check if media can be constructed from a media factory + * The response is sent on error. */ #define GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT "auth.check.media.factory.construct" +/** + * GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS: + * + * Check if the client can specify TTL, destination and + * port pair in multicast. No response is sent when the check returns + * %FALSE. + */ +#define GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS "auth.check.transport.client-settings" /* tokens */ @@ -139,6 +149,13 @@ gchar * gst_rtsp_auth_make_basic (const gchar * user, const g * return a 404 Not Found error when trying to access the media. */ #define GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT "media.factory.construct" +/** + * GST_RTSP_MEDIA_FACTORY_PERM_CLIENT_SETTINGS: + * + * G_TYPE_BOOLEAN, %TRUE if the client can specify TTL, destination and + * port pair in multicast. + */ +#define GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS "transport.client-settings" G_END_DECLS diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1424032c75..c51c803771 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -62,7 +62,6 @@ struct _GstRTSPClientPrivate guint close_seq; gchar *server_ip; gboolean is_ipv6; - gboolean use_client_settings; GstRTSPClientSendFunc send_func; /* protected by send_lock */ gpointer send_data; /* protected by send_lock */ @@ -87,14 +86,12 @@ static GHashTable *tunnels; /* protected by tunnels_lock */ #define DEFAULT_SESSION_POOL NULL #define DEFAULT_MOUNT_POINTS NULL -#define DEFAULT_USE_CLIENT_SETTINGS FALSE enum { PROP_0, PROP_SESSION_POOL, PROP_MOUNT_POINTS, - PROP_USE_CLIENT_SETTINGS, PROP_LAST }; @@ -168,12 +165,6 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) GST_TYPE_RTSP_MOUNT_POINTS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_USE_CLIENT_SETTINGS, - g_param_spec_boolean ("use-client-settings", "Use Client Settings", - "Use client settings for ttl and destination in multicast", - DEFAULT_USE_CLIENT_SETTINGS, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - gst_rtsp_client_signals[SIGNAL_CLOSED] = g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL, @@ -248,7 +239,6 @@ gst_rtsp_client_init (GstRTSPClient * client) g_mutex_init (&priv->lock); g_mutex_init (&priv->send_lock); - priv->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS; priv->close_seq = 0; } @@ -379,10 +369,6 @@ gst_rtsp_client_get_property (GObject * object, guint propid, case PROP_MOUNT_POINTS: g_value_take_object (value, gst_rtsp_client_get_mount_points (client)); break; - case PROP_USE_CLIENT_SETTINGS: - g_value_set_boolean (value, - gst_rtsp_client_get_use_client_settings (client)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -401,10 +387,6 @@ gst_rtsp_client_set_property (GObject * object, guint propid, case PROP_MOUNT_POINTS: gst_rtsp_client_set_mount_points (client, g_value_get_object (value)); break; - case PROP_USE_CLIENT_SETTINGS: - gst_rtsp_client_set_use_client_settings (client, - g_value_get_boolean (value)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1251,7 +1233,12 @@ default_configure_client_transport (GstRTSPClient * client, /* we have a valid transport now, set the destination of the client. */ if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - if (ct->destination && priv->use_client_settings) { + gboolean use_client_settings; + + use_client_settings = + gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS); + + if (ct->destination && use_client_settings) { GstRTSPAddress *addr; addr = gst_rtsp_stream_reserve_address (state->stream, ct->destination, @@ -2188,54 +2175,6 @@ gst_rtsp_client_get_mount_points (GstRTSPClient * client) return result; } -/** - * gst_rtsp_client_set_use_client_settings: - * @client: a #GstRTSPClient - * @use_client_settings: whether to use client settings for multicast - * - * Use client transport settings (destination and ttl) for multicast. - * When @use_client_settings is %FALSE, the server settings will be - * used. - */ -void -gst_rtsp_client_set_use_client_settings (GstRTSPClient * client, - gboolean use_client_settings) -{ - GstRTSPClientPrivate *priv; - - g_return_if_fail (GST_IS_RTSP_CLIENT (client)); - - priv = client->priv; - - g_mutex_lock (&priv->lock); - priv->use_client_settings = use_client_settings; - g_mutex_unlock (&priv->lock); -} - -/** - * gst_rtsp_client_get_use_client_settings: - * @client: a #GstRTSPClient - * - * Check if client transport settings (destination and ttl) for multicast - * will be used. - */ -gboolean -gst_rtsp_client_get_use_client_settings (GstRTSPClient * client) -{ - GstRTSPClientPrivate *priv; - gboolean res; - - g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE); - - priv = client->priv; - - g_mutex_lock (&priv->lock); - res = priv->use_client_settings; - g_mutex_unlock (&priv->lock); - - return res; -} - /** * gst_rtsp_client_set_auth: * @client: a #GstRTSPClient diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index af1ef2c003..5ea6071450 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -171,10 +171,6 @@ GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); void gst_rtsp_client_set_thread_pool (GstRTSPClient *client, GstRTSPThreadPool *pool); GstRTSPThreadPool * gst_rtsp_client_get_thread_pool (GstRTSPClient *client); -void gst_rtsp_client_set_use_client_settings (GstRTSPClient * client, - gboolean use_client_settings); -gboolean gst_rtsp_client_get_use_client_settings (GstRTSPClient * client); - gboolean gst_rtsp_client_set_connection (GstRTSPClient *client, GstRTSPConnection *conn); GstRTSPConnection * gst_rtsp_client_get_connection (GstRTSPClient *client); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 49d6d514c2..3134d4d6e7 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -73,7 +73,6 @@ struct _GstRTSPServerPrivate gchar *address; gchar *service; gint backlog; - gboolean use_client_settings; GSocket *socket; @@ -98,7 +97,6 @@ struct _GstRTSPServerPrivate /* #define DEFAULT_ADDRESS "::0" */ #define DEFAULT_SERVICE "8554" #define DEFAULT_BACKLOG 5 -#define DEFAULT_USE_CLIENT_SETTINGS FALSE /* Define to use the SO_LINGER option so that the server sockets can be resused * sooner. Disabled for now because it is not very well implemented by various @@ -115,7 +113,6 @@ enum PROP_SESSION_POOL, PROP_MOUNT_POINTS, - PROP_USE_CLIENT_SETTINGS, PROP_LAST }; @@ -224,17 +221,6 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) "The mount points to use for client session", GST_TYPE_RTSP_MOUNT_POINTS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - /** - * GstRTSPServer::use-client-settings: - * - * Use client transport settings (destination, port pair and ttl for - * multicast. FALSE means that the server settings will be used. - */ - g_object_class_install_property (gobject_class, PROP_USE_CLIENT_SETTINGS, - g_param_spec_boolean ("use-client-settings", "Use Client Settings", - "Use client settings for ttl, destination and port pair in multicast", - DEFAULT_USE_CLIENT_SETTINGS, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED] = g_signal_new ("client-connected", G_TYPE_FROM_CLASS (gobject_class), @@ -262,7 +248,6 @@ gst_rtsp_server_init (GstRTSPServer * server) priv->session_pool = gst_rtsp_session_pool_new (); priv->mount_points = gst_rtsp_mount_points_new (); priv->thread_pool = gst_rtsp_thread_pool_new (); - priv->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS; } static void @@ -726,55 +711,6 @@ gst_rtsp_server_get_thread_pool (GstRTSPServer * server) return result; } -/** - * gst_rtsp_server_set_use_client_settings: - * @server: a #GstRTSPServer - * @use_client_settings: whether to use client settings for multicast - * - * Use client transport settings (destination, port pair and ttl) for - * multicast. - * When @use_client_settings is %FALSE, the server settings will be - * used. - */ -void -gst_rtsp_server_set_use_client_settings (GstRTSPServer * server, - gboolean use_client_settings) -{ - GstRTSPServerPrivate *priv; - - g_return_if_fail (GST_IS_RTSP_SERVER (server)); - - priv = server->priv; - - GST_RTSP_SERVER_LOCK (server); - priv->use_client_settings = use_client_settings; - GST_RTSP_SERVER_UNLOCK (server); -} - -/** - * gst_rtsp_server_get_use_client_settings: - * @server: a #GstRTSPServer - * - * Check if client transport settings (destination, port pair and ttl) for - * multicast will be used. - */ -gboolean -gst_rtsp_server_get_use_client_settings (GstRTSPServer * server) -{ - GstRTSPServerPrivate *priv; - gboolean res; - - g_return_val_if_fail (GST_IS_RTSP_SERVER (server), FALSE); - - priv = server->priv; - - GST_RTSP_SERVER_LOCK (server); - res = priv->use_client_settings; - GST_RTSP_SERVER_UNLOCK (server); - - return res; -} - static void gst_rtsp_server_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec) @@ -800,10 +736,6 @@ gst_rtsp_server_get_property (GObject * object, guint propid, case PROP_MOUNT_POINTS: g_value_take_object (value, gst_rtsp_server_get_mount_points (server)); break; - case PROP_USE_CLIENT_SETTINGS: - g_value_set_boolean (value, - gst_rtsp_server_get_use_client_settings (server)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -831,10 +763,6 @@ gst_rtsp_server_set_property (GObject * object, guint propid, case PROP_MOUNT_POINTS: gst_rtsp_server_set_mount_points (server, g_value_get_object (value)); break; - case PROP_USE_CLIENT_SETTINGS: - gst_rtsp_server_set_use_client_settings (server, - g_value_get_boolean (value)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1114,8 +1042,6 @@ default_create_client (GstRTSPServer * server) gst_rtsp_client_set_auth (client, priv->auth); /* set threadpool */ gst_rtsp_client_set_thread_pool (client, priv->thread_pool); - /* check if client transport settings for multicast are allowed */ - gst_rtsp_client_set_use_client_settings (client, priv->use_client_settings); GST_RTSP_SERVER_UNLOCK (server); return client; diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 5d1ae0db78..4e185610b4 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -100,10 +100,6 @@ GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *serve void gst_rtsp_server_set_thread_pool (GstRTSPServer *server, GstRTSPThreadPool *pool); GstRTSPThreadPool * gst_rtsp_server_get_thread_pool (GstRTSPServer *server); -void gst_rtsp_server_set_use_client_settings (GstRTSPServer *server, - gboolean use_client_settings); -gboolean gst_rtsp_server_get_use_client_settings (GstRTSPServer *server); - gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket *socket, const gchar * ip, gint port, const gchar *initial_buffer); From 5ce4dd7925bbd946916a24f26d755956d4198abb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jul 2013 17:26:55 +0200 Subject: [PATCH 0746/1776] tests: almost fix test --- tests/check/gst/client.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index f08add5a56..477f78918a 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -526,12 +526,21 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) GstRTSPMessage request = { 0, }; gchar *str; GstRTSPSessionPool *session_pool; + GstRTSPClientState state = { NULL }; client = setup_multicast_client (); + state.client = client; + state.auth = gst_rtsp_auth_new (); + state.token = + gst_rtsp_token_new (GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, NULL); + gst_rtsp_client_state_push_current (&state); + +#if 0 gst_rtsp_client_set_use_client_settings (client, TRUE); fail_unless (gst_rtsp_client_get_use_client_settings (client)); - +#endif /* simple SETUP with a valid URI and multicast, but an invalid ip */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, @@ -596,6 +605,9 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) g_object_unref (client); + g_object_unref (state.auth); + gst_rtsp_token_unref (state.token); + gst_rtsp_client_state_pop_current (&state); } GST_END_TEST; @@ -606,11 +618,21 @@ GST_START_TEST (test_client_multicast_transport_specific) GstRTSPMessage request = { 0, }; gchar *str; GstRTSPSessionPool *session_pool; + GstRTSPClientState state = { NULL }; client = setup_multicast_client (); + state.client = client; + state.auth = gst_rtsp_auth_new (); + state.token = + gst_rtsp_token_new (GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, NULL); + gst_rtsp_client_state_push_current (&state); + +#if 0 gst_rtsp_client_set_use_client_settings (client, TRUE); fail_unless (gst_rtsp_client_get_use_client_settings (client)); +#endif expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" "ttl=1;port=5000-5001;mode=\"PLAY\""; @@ -638,6 +660,9 @@ GST_START_TEST (test_client_multicast_transport_specific) g_object_unref (session_pool); g_object_unref (client); + g_object_unref (state.auth); + gst_rtsp_token_unref (state.token); + gst_rtsp_client_state_pop_current (&state); } GST_END_TEST; From 692cbc1364dcd6cd5a342a9445cec9219d410088 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 11:51:34 +0200 Subject: [PATCH 0747/1776] mount-points: add some debug --- gst/rtsp-server/rtsp-mount-points.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index e242af29cf..2cf09ae34e 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -284,6 +284,8 @@ gst_rtsp_mount_points_add_factory (GstRTSPMountPoints * mounts, item = data_item_new (g_strdup (path), strlen (path), factory); + GST_INFO ("adding media factory %p for path %s", factory, path); + g_mutex_lock (&priv->lock); g_sequence_append (priv->mounts, item); priv->dirty = TRUE; @@ -312,6 +314,8 @@ gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints * mounts, item.path = (gchar *) path; + GST_INFO ("removing media factory for path %s", path); + g_mutex_lock (&priv->lock); iter = g_sequence_lookup (priv->mounts, &item, data_item_compare, mounts); if (iter) { From 7db2f9f3cf84f8eaf82d156b1f4425a8ce81864c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 11:56:06 +0200 Subject: [PATCH 0748/1776] auth: don't auth on methods Don't authorize on methods anymore but on the resources that we try to access, this is more flexible. Move the authorization checks to where they are needed and let the check return the response on error. --- gst/rtsp-server/rtsp-auth.c | 46 +++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 091b0ef6a1..deea3ebe33 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -95,12 +95,7 @@ gst_rtsp_auth_init (GstRTSPAuth * auth) (GDestroyNotify) gst_rtsp_token_unref); /* bitwise or of all methods that need authentication */ - priv->methods = GST_RTSP_DESCRIBE | - GST_RTSP_ANNOUNCE | - GST_RTSP_GET_PARAMETER | - GST_RTSP_SET_PARAMETER | - GST_RTSP_PAUSE | - GST_RTSP_PLAY | GST_RTSP_RECORD | GST_RTSP_SETUP | GST_RTSP_TEARDOWN; + priv->methods = 0; } static void @@ -303,6 +298,21 @@ no_auth: } } +static void +send_response (GstRTSPAuth * auth, GstRTSPStatusCode code, + GstRTSPClientState * state) +{ + gst_rtsp_message_init_response (state->response, code, + gst_rtsp_status_as_text (code), state->request); + + if (code == GST_RTSP_STS_UNAUTHORIZED) { + /* we only have Basic for now */ + gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE, + "Basic realm=\"GStreamer RTSP Server\""); + } + gst_rtsp_client_send_message (state->client, state->session, state->response); +} + static gboolean ensure_authenticated (GstRTSPAuth * auth, GstRTSPClientState * state) { @@ -326,30 +336,17 @@ ensure_authenticated (GstRTSPAuth * auth, GstRTSPClientState * state) authenticate_failed: { GST_DEBUG_OBJECT (auth, "authenticate failed"); + send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state); return FALSE; } no_auth: { GST_DEBUG_OBJECT (auth, "no authorization token found"); + send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state); return FALSE; } } -static void -send_response (GstRTSPAuth * auth, GstRTSPStatusCode code, - GstRTSPClientState * state) -{ - gst_rtsp_message_init_response (state->response, code, - gst_rtsp_status_as_text (code), state->request); - - if (code == GST_RTSP_STS_UNAUTHORIZED) { - /* we only have Basic for now */ - gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE, - "Basic realm=\"GStreamer RTSP Server\""); - } - gst_rtsp_client_send_message (state->client, state->session, state->response); -} - /* new connection */ static gboolean check_connect (GstRTSPAuth * auth, GstRTSPClientState * state, @@ -382,7 +379,6 @@ check_url (GstRTSPAuth * auth, GstRTSPClientState * state, const gchar * check) /* ERRORS */ not_authenticated: { - send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state); return FALSE; } } @@ -395,6 +391,9 @@ check_factory (GstRTSPAuth * auth, GstRTSPClientState * state, const gchar *role; GstRTSPPermissions *perms; + if (!ensure_authenticated (auth, state)) + return FALSE; + if (!(role = gst_rtsp_token_get_string (state->token, GST_RTSP_MEDIA_FACTORY_ROLE))) goto no_media_role; @@ -443,6 +442,9 @@ static gboolean check_client_settings (GstRTSPAuth * auth, GstRTSPClientState * state, const gchar * check) { + if (!ensure_authenticated (auth, state)) + return FALSE; + return gst_rtsp_token_is_allowed (state->token, GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS); } From 38d91a2bf8942ccf5cc19d8d6f4191d8bd54c86a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 11:57:49 +0200 Subject: [PATCH 0749/1776] client: support pushed context in handle_request If we already have a pushed state, reuse it and add our own things. This makes it easier to write tests. --- gst/rtsp-server/rtsp-client.c | 53 +++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c51c803771..e67386a9fc 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1871,16 +1871,20 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) GstRTSPVersion version; GstRTSPResult res; GstRTSPSession *session = NULL; - GstRTSPClientState state = { NULL }; + GstRTSPClientState sstate = { NULL }, *state; GstRTSPMessage response = { 0 }; gchar *sessid; - state.conn = priv->connection; - state.client = client; - state.request = request; - state.response = &response; - state.auth = priv->auth; - gst_rtsp_client_state_push_current (&state); + if (!(state = gst_rtsp_client_state_get_current ())) { + state = &sstate; + state->auth = priv->auth; + gst_rtsp_client_state_push_current (state); + } + + state->conn = priv->connection; + state->client = client; + state->request = request; + state->response = &response; if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) { gst_rtsp_message_dump (request); @@ -1894,7 +1898,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) if (version != GST_RTSP_VERSION_1_0) goto not_supported; - state.method = method; + state->method = method; /* we always try to parse the url first */ if (strcmp (uristr, "*") == 0) { @@ -1921,8 +1925,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) /* sanitize the uri */ if (uri) sanitize_uri (uri); - state.uri = uri; - state.session = session; + state->uri = uri; + state->session = session; if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_URL)) goto not_authorized; @@ -1930,28 +1934,28 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: - handle_options_request (client, &state); + handle_options_request (client, state); break; case GST_RTSP_DESCRIBE: - handle_describe_request (client, &state); + handle_describe_request (client, state); break; case GST_RTSP_SETUP: - handle_setup_request (client, &state); + handle_setup_request (client, state); break; case GST_RTSP_PLAY: - handle_play_request (client, &state); + handle_play_request (client, state); break; case GST_RTSP_PAUSE: - handle_pause_request (client, &state); + handle_pause_request (client, state); break; case GST_RTSP_TEARDOWN: - handle_teardown_request (client, &state); + handle_teardown_request (client, state); break; case GST_RTSP_SET_PARAMETER: - handle_set_param_request (client, &state); + handle_set_param_request (client, state); break; case GST_RTSP_GET_PARAMETER: - handle_get_param_request (client, &state); + handle_get_param_request (client, state); break; case GST_RTSP_ANNOUNCE: case GST_RTSP_RECORD: @@ -1963,7 +1967,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) } done: - gst_rtsp_client_state_pop_current (&state); + if (state == &sstate) + gst_rtsp_client_state_pop_current (state); if (session) g_object_unref (session); if (uri) @@ -1975,25 +1980,25 @@ not_supported: { GST_ERROR ("client %p: version %d not supported", client, version); send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, - &state); + state); goto done; } bad_request: { GST_ERROR ("client %p: bad request", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); goto done; } no_pool: { GST_ERROR ("client %p: no pool configured", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); goto done; } session_not_found: { GST_ERROR ("client %p: session not found", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); goto done; } not_authorized: @@ -2004,7 +2009,7 @@ not_authorized: not_implemented: { GST_ERROR ("client %p: method %d not implemented", client, method); - send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &state); + send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, state); goto done; } } From 15db094d85091c5a4b123a5e4c7a5776b65ee472 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 11:58:58 +0200 Subject: [PATCH 0750/1776] client: fix test Add some permissions to media so we can use the auth and enable client settings. --- tests/check/gst/client.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 477f78918a..a84c352436 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -379,6 +379,9 @@ setup_multicast_client (void) fail_unless (gst_rtsp_address_pool_add_range (address_pool, "233.252.0.1", "233.252.0.1", 5000, 5010, 1)); gst_rtsp_media_factory_set_address_pool (factory, address_pool); + gst_rtsp_media_factory_add_role (factory, "user", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); gst_rtsp_client_set_mount_points (client, mount_points); @@ -465,9 +468,16 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GstRTSPClient *client; GstRTSPMessage request = { 0, }; gchar *str; + GstRTSPClientState state = { NULL }; client = setup_multicast_client (); + state.client = client; + state.auth = gst_rtsp_auth_new (); + state.token = + gst_rtsp_token_new ("media.factory.role", G_TYPE_STRING, "user", NULL); + gst_rtsp_client_state_push_current (&state); + /* simple SETUP with a valid URI and multicast and a specific dest, * but ignore it */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, @@ -487,6 +497,9 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) expected_transport = NULL; g_object_unref (client); + g_object_unref (state.auth); + gst_rtsp_token_unref (state.token); + gst_rtsp_client_state_pop_current (&state); } GST_END_TEST; @@ -534,7 +547,7 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) state.auth = gst_rtsp_auth_new (); state.token = gst_rtsp_token_new (GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS, - G_TYPE_BOOLEAN, TRUE, NULL); + G_TYPE_BOOLEAN, TRUE, "media.factory.role", G_TYPE_STRING, "user", NULL); gst_rtsp_client_state_push_current (&state); #if 0 @@ -626,7 +639,7 @@ GST_START_TEST (test_client_multicast_transport_specific) state.auth = gst_rtsp_auth_new (); state.token = gst_rtsp_token_new (GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS, - G_TYPE_BOOLEAN, TRUE, NULL); + G_TYPE_BOOLEAN, TRUE, "media.factory.role", G_TYPE_STRING, "user", NULL); gst_rtsp_client_state_push_current (&state); #if 0 From 3fe1096fd12c1ddfca5cfb7469f0d457aa17a8c2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 14:50:26 +0200 Subject: [PATCH 0751/1776] server: add small debug --- gst/rtsp-server/rtsp-server.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 3134d4d6e7..cd6161448e 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -948,6 +948,8 @@ struct _ClientContext static gboolean free_client_context (ClientContext * ctx) { + GST_DEBUG ("free context %p", ctx); + GST_RTSP_SERVER_LOCK (ctx->server); if (ctx->thread) gst_rtsp_thread_stop (ctx->thread); From 0ce4d4d5c7a433a60e9dc963179172e3ce9a620b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 14:50:38 +0200 Subject: [PATCH 0752/1776] thread-pool: fix race in thread reuse If we try to reuse a thread right after we made it stop, we end up using a stopped thread. Catch this case and only reuse threads that are not stopping. --- gst/rtsp-server/rtsp-thread-pool.c | 23 +++++++++++++++++++---- gst/rtsp-server/rtsp-thread-pool.h | 2 +- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index dd0a3c181b..fb0a7a85cf 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -103,16 +103,19 @@ gst_rtsp_thread_new (GstRTSPThreadType type) * @thread: a #GstRTSPThread * * Reuse the mainloop of @thread + * + * Returns: %TRUE if the mainloop could be reused */ -void +gboolean gst_rtsp_thread_reuse (GstRTSPThread * thread) { GstRTSPThreadImpl *impl = (GstRTSPThreadImpl *) thread; - g_return_if_fail (GST_IS_RTSP_THREAD (thread)); + g_return_val_if_fail (GST_IS_RTSP_THREAD (thread), FALSE); GST_DEBUG ("reuse thread %p", thread); - g_atomic_int_inc (&impl->reused); + + return g_atomic_int_add (&impl->reused, 1) > 0; } /** @@ -404,11 +407,22 @@ default_get_thread (GstRTSPThreadPool * pool, GST_DEBUG_OBJECT (pool, "no client threads allowed"); thread = NULL; } else { + g_mutex_lock (&priv->lock); + retry: if (priv->max_threads > 0 && g_queue_get_length (&priv->threads) >= priv->max_threads) { /* max threads reached, recycle from queue */ - GST_DEBUG_OBJECT (pool, "recycle client thread"); thread = g_queue_pop_head (&priv->threads); + GST_DEBUG_OBJECT (pool, "recycle client thread %p", thread); + if (!gst_rtsp_thread_reuse (thread)) { + GST_DEBUG_OBJECT (pool, "thread %p stopping, retry", thread); + /* this can happen if we just decremented the reuse counter of the + * thread and signaled the mainloop that it should stop. We leave + * the thread out of the queue now, there is no point to add it + * again, it will be removed from the mainloop otherwise after it + * stops. */ + goto retry; + } gst_rtsp_thread_ref (thread); } else { /* make more threads */ @@ -419,6 +433,7 @@ default_get_thread (GstRTSPThreadPool * pool, goto thread_error; } g_queue_push_tail (&priv->threads, thread); + g_mutex_unlock (&priv->lock); } break; case GST_RTSP_THREAD_TYPE_MEDIA: diff --git a/gst/rtsp-server/rtsp-thread-pool.h b/gst/rtsp-server/rtsp-thread-pool.h index 1637018ffa..1c6fb5d9a0 100644 --- a/gst/rtsp-server/rtsp-thread-pool.h +++ b/gst/rtsp-server/rtsp-thread-pool.h @@ -79,7 +79,7 @@ struct _GstRTSPThread { GstRTSPThread * gst_rtsp_thread_new (GstRTSPThreadType type); -void gst_rtsp_thread_reuse (GstRTSPThread * thread); +gboolean gst_rtsp_thread_reuse (GstRTSPThread * thread); void gst_rtsp_thread_stop (GstRTSPThread * thread); /** From 7064b9fda7a9645ac45543e088a36293d43858cf Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 15:25:00 +0200 Subject: [PATCH 0753/1776] thread-pool: add more docs --- gst/rtsp-server/rtsp-thread-pool.c | 23 +++++++++++++++++++++++ gst/rtsp-server/rtsp-thread-pool.h | 6 ++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index fb0a7a85cf..b29f20eb86 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -21,6 +21,29 @@ * @short_description: A pool of threads * @see_also: #GstRTSPMedia, #GstRTSPClient * + * A #GstRTSPThreadPool manages reusable threads for various server tasks. + * Currently the defined thread types can be found in #GstRTSPThreadType. + * + * Threads of type #GST_RTSP_THREAD_TYPE_CLIENT are used to handle requests from + * a connected client. With gst_rtsp_thread_pool_get_max_threads() a maximum + * number of threads can be set after which the pool will start to reuse the + * same thread for multiple clients. + * + * Threads of type #GST_RTSP_THREAD_TYPE_MEDIA will be used to perform the state + * changes of the media pipelines and handle its bus messages. + * + * gst_rtsp_thread_pool_get_thread() can be used to create a #GstRTSPThread + * object of the right type. The thread object contains a mainloop and context + * that run in a seperate thread and can be used to attached sources to. + * + * gst_rtsp_thread_reuse() can be used to reuse a thread for multiple purposes. + * If all gst_rtsp_thread_reuse() calls are matched with a + * gst_rtsp_thread_stop() call, the mainloop will be quit and the thread will + * stop. + * + * To configure the threads, a subclass of this object should be made and the + * virtual methods should be overriden to implement the desired functionality. + * * Last reviewed on 2013-07-11 (1.0.0) */ diff --git a/gst/rtsp-server/rtsp-thread-pool.h b/gst/rtsp-server/rtsp-thread-pool.h index 1c6fb5d9a0..74f9e0747d 100644 --- a/gst/rtsp-server/rtsp-thread-pool.h +++ b/gst/rtsp-server/rtsp-thread-pool.h @@ -132,8 +132,10 @@ struct _GstRTSPThreadPool { /** * GstRTSPThreadPoolClass: * @pool: a #GThreadPool used internally - * @get_thread: get or reuse a thread object - * @configure_thread: configure a thread object + * @get_thread: this function should make or reuse an existing thread that runs + * a mainloop. + * @configure_thread: configure a thread object. this vmethod is called when + * a new thread has been created and should be configured. * @thread_enter: called from the thread when it is entered * @thread_leave: called from the thread when it is left * From 5b77c9f406f6a06f2f013316839c2dc66cf6dfd3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 16:05:02 +0200 Subject: [PATCH 0754/1776] README: update readme --- docs/README | 109 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 23 deletions(-) diff --git a/docs/README b/docs/README index f2e878bd39..f90f4ab2b3 100644 --- a/docs/README +++ b/docs/README @@ -1,7 +1,7 @@ README ------ -(Last updated on Fri 26 oct 2012, version 0.11.89.1) +(Last updated on Mon 15 jul 2013, version 0.11.90.1) This HOWTO describes the basic usage of the GStreamer RTSP libraries and how you can build simple server applications with it. @@ -14,7 +14,7 @@ can build simple server applications with it. the RTSP message parsing and construction in the server is done using the RTSP library that comes with gst-plugins-base. - The result is that the server is rather small (a few 6000 lines of code) and easy + The result is that the server is rather small (a few 11000 lines of code) and easy to understand and extend. In its current state of development, things change fast, API and ABI are unstable. We encourage people to use it for their various use cases and participate by suggesting changes/features. @@ -23,11 +23,9 @@ can build simple server applications with it. that provide reasonable default functionality but has a fair amount of hooks to override the default behaviour. - The server currently integrates with the glib mainloop nicely. The network part - is currently single threaded but the GStreamer bits are a heavy user of multiple - threads. It's currently not meant to be used in high-load scenarios and because - no security audit has been done, you should probably not put it on a public - IP address. + The server currently integrates with the glib mainloop nicely. It's currently + not meant to be used in high-load scenarios and because no security audit has + been done, you should probably not put it on a public IP address. * Initialisation @@ -110,10 +108,12 @@ can build simple server applications with it. topic how to configure this object. GstRTSPAuth is an object that authenticates users and authorizes actions - performed by users. + performed by users. By default, a server does not have a GstRTSPAuth object and + thus does not try to perform any authentication or authorization. GstRTSPThreadPool manages the threads used for client connections and media - pipelines. + pipelines. The server has a default implementation of a threadpool that should + be sufficient in most cases. * Making url mount points @@ -216,19 +216,23 @@ can build simple server applications with it. When preparing a GstRTSPMedia, an appsink and asppsrc is also constructed for streaming the stream over TCP when requested. + Media is prepared by the server when DESCRIBE or SETUP requests are received + from the client. + * the GstRTSPClient object - When a server detects a new client connection on its port, it will call its - accept_client vmethod. The default implementation of this function will create - a new GstRTCPClient object, will configure the session pool and media mapper - objects in it and will then call the accept function of the client. + When a server detects a new client connection on its port, it will accept the + connection, check if the connection is allowed and then call the vmethod + create_client. The default implementation of this function will create + a new GstRTCPClient object, will configure the session pool, mount points, + auth and thread pool objects in it. - The default GstRTSPClient will accept the connection and will attach a watch to - the server mainloop. In RTSP it is usual to keep the connection - open between multiple RTSP requests. The client watch will be dispatched by the - server mainloop when a new GstRTSPMessage is received, which will then be - handled and a response will be sent. + The server will then attach the new client to a server mainloop to let it + handle further communication with the client. In RTSP it is usual to keep + the connection open between multiple RTSP requests. The client watch will + be dispatched by the server mainloop when a new GstRTSPMessage is received, + which will then be handled and a response will be sent. The GstRTSPClient object remains alive for as long as a client has a TCP connection open with the server. Since is possible for a client to open and close @@ -372,6 +376,44 @@ can build simple server applications with it. GstRTSPStream objects. +* Security + + The security of the server and the policy is implemented in a GstRTSPAuth + object. The object is reponsible for: + + - authenticate the user of the server. + + - check if the current user is authorized to perform an operation. + + For critical operations, the server will call gst_rtsp_auth_check() with + a string describing the operation which should be validated. The installed + GstRTSPAuth object is then responsible for checking if the operation is + allowed. + + Implementations of GstRTSPAuth objects can use the following infrastructure + bits of the rtsp server to implement these checks: + + - GstRTSPToken: a generic structure describing roles and permissions granted + to a user. + + - GstRTSPPermissions: a generic list of roles and matching permissions. These + can be attached to media and facties currently. + + An Auth implementation will usually authenticate a user, using method such as + Basic authentication or client certificates or perhaps simply use the IP address. + The result of the authentication of the user will be a GstRTSPToken that is made + current in the context of the ongoing request. + + The auth module can then implement the various checks in the server by looking + at the current token and, if needed, compare it to the required GstRTSPPermissions + of the current object. + + The security is deliberately kept generic with a default implementation of the + GstRTSPAuth object providing a usable and simple implementaion. To make more + complicated security modules, the auth object should be subclassed and new + implementations for the checks needs to be made. + + Objects ------- @@ -387,11 +429,6 @@ GstRTSPClientState - Helper structure contaning the current state of the request handled by the client. -GstRTSPAuth - - Hooks for checking authorizations, all client activity will call this - object with the GstRTSPClientState structure. By default it supports - basic authentication. - GstRTSPMountPoints - Maps a url to a GstRTSPMediaFactory implementation. The default @@ -432,4 +469,30 @@ GstRTSPStreamTransport request. +GstRTSPSDP + - helper functions for creating SDP messages from gstRTSPMedia + +GstRTSPAddressPool + - a pool of multicast and unicast addresses used in streaming + +GstRTSPThreadPool + - a pool of threads used for various server tasks such as handling clients and + managin media pipelines. + + +GstRTSPAuth + - Hooks for checking authorizations, all client activity will call this + object with the GstRTSPClientState structure. By default it supports + basic authentication. + +GstRTSPToken + - Credentials of a user. This contrains the roles that the user is allowed + to assume and other permissions or capabilities of the user. + +GstRTSPPermissions + - A list of permissions for each role. The permissions are usually attached + to objects to describe what roles have what permissions. + +GstRTSPParams + - object to handle get and set parameter requests. From f18f2619e1a91008ec683355afb41b0419e7432e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 16:47:07 +0200 Subject: [PATCH 0755/1776] auth: add default authorizations When no auth module is specified, use our table of defaults to look up the default value of the check instead of always allowing everything. This was we can disallow client settings by default. --- gst/rtsp-server/rtsp-auth.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index deea3ebe33..8b4866f0cd 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -468,6 +468,19 @@ default_check (GstRTSPAuth * auth, GstRTSPClientState * state, return res; } +static gboolean +no_auth_check (const gchar * check) +{ + gboolean res; + + if (g_str_equal (check, GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS)) + res = FALSE; + else + res = TRUE; + + return res; +} + /** * gst_rtsp_auth_check: * @check: the item to check @@ -491,7 +504,7 @@ gst_rtsp_auth_check (const gchar * check) /* no auth, we don't need to check */ if (!(auth = state->auth)) - return TRUE; + return no_auth_check (check); klass = GST_RTSP_AUTH_GET_CLASS (auth); From 95b3bd4e0cbcf21fb775763b36938d5e15d86942 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 16:48:37 +0200 Subject: [PATCH 0756/1776] tests: simplify tests Client settings are now disabled by default so we don't need an auth module to disable them. --- tests/check/gst/client.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index a84c352436..d3a180884b 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -468,16 +468,9 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GstRTSPClient *client; GstRTSPMessage request = { 0, }; gchar *str; - GstRTSPClientState state = { NULL }; client = setup_multicast_client (); - state.client = client; - state.auth = gst_rtsp_auth_new (); - state.token = - gst_rtsp_token_new ("media.factory.role", G_TYPE_STRING, "user", NULL); - gst_rtsp_client_state_push_current (&state); - /* simple SETUP with a valid URI and multicast and a specific dest, * but ignore it */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, @@ -497,9 +490,6 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) expected_transport = NULL; g_object_unref (client); - g_object_unref (state.auth); - gst_rtsp_token_unref (state.token); - gst_rtsp_client_state_pop_current (&state); } GST_END_TEST; @@ -550,11 +540,6 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) G_TYPE_BOOLEAN, TRUE, "media.factory.role", G_TYPE_STRING, "user", NULL); gst_rtsp_client_state_push_current (&state); -#if 0 - gst_rtsp_client_set_use_client_settings (client, TRUE); - fail_unless (gst_rtsp_client_get_use_client_settings (client)); -#endif - /* simple SETUP with a valid URI and multicast, but an invalid ip */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); @@ -642,11 +627,6 @@ GST_START_TEST (test_client_multicast_transport_specific) G_TYPE_BOOLEAN, TRUE, "media.factory.role", G_TYPE_STRING, "user", NULL); gst_rtsp_client_state_push_current (&state); -#if 0 - gst_rtsp_client_set_use_client_settings (client, TRUE); - fail_unless (gst_rtsp_client_get_use_client_settings (client)); -#endif - expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" "ttl=1;port=5000-5001;mode=\"PLAY\""; From 5e297ea09397832bba6a9d25008c23a4b9318e8a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 17:12:43 +0200 Subject: [PATCH 0757/1776] permissions: update docs --- gst/rtsp-server/rtsp-permissions.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index 33587c787d..eee30e01bb 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -21,10 +21,22 @@ * @short_description: Roles and associated permissions * @see_also: #GstRTSPToken, #GstRTSPAuth * - * Last reviewed on 2013-07-11 (1.0.0) + * The #GstRTSPPermission object contains an array of roles and associated + * permissions. The roles are represented with a string and the permissions with + * a generic #GstStructure. + * + * The permissions are deliberately kept generic. The possible values of the + * roles and #GstStructure keys and values are only determined by the #GstRTSPAuth + * object that performs the checks on the permissions and the current + * #GstRTSPToken. + * + * As a convenience function, gst_rtsp_permissions_is_allowed() can be used to + * check if the permissions contains a role that contains the boolean value + * %TRUE for the the given key. + * + * Last reviewed on 2013-07-15 (1.0.0) */ - #include #include "rtsp-permissions.h" From fbe0cefae1d0dcf2b701e6eb43426721b7f0baa2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 17:12:57 +0200 Subject: [PATCH 0758/1776] permissions: implement _remove_role --- gst/rtsp-server/rtsp-permissions.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index eee30e01bb..b2bfa3d908 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -156,7 +156,7 @@ gst_rtsp_permissions_add_role_valist (GstRTSPPermissions * permissions, { GstRTSPPermissionsImpl *impl = (GstRTSPPermissionsImpl *) permissions; GstStructure *structure; - gint i, len; + guint i, len; gboolean found; g_return_if_fail (GST_IS_RTSP_PERMISSIONS (permissions)); @@ -198,9 +198,23 @@ void gst_rtsp_permissions_remove_role (GstRTSPPermissions * permissions, const gchar * role) { + GstRTSPPermissionsImpl *impl = (GstRTSPPermissionsImpl *) permissions; + guint i, len; + g_return_if_fail (GST_IS_RTSP_PERMISSIONS (permissions)); g_return_if_fail (gst_mini_object_is_writable (&permissions->mini_object)); g_return_if_fail (role != NULL); + + len = impl->roles->len; + for (i = 0; i < len; i++) { + GstStructure *entry = g_ptr_array_index (impl->roles, i); + + if (gst_structure_has_name (entry, role)) { + g_ptr_array_remove_index_fast (impl->roles, i); + gst_structure_free (entry); + break; + } + } } /** @@ -217,7 +231,7 @@ gst_rtsp_permissions_get_role (GstRTSPPermissions * permissions, const gchar * role) { GstRTSPPermissionsImpl *impl = (GstRTSPPermissionsImpl *) permissions; - gint i, len; + guint i, len; g_return_val_if_fail (GST_IS_RTSP_PERMISSIONS (permissions), NULL); g_return_val_if_fail (role != NULL, NULL); From 0a8f5c8892a947ba5575940fda56ec17bfee7f37 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Jul 2013 17:31:35 +0200 Subject: [PATCH 0759/1776] docs: improve docs --- docs/libs/gst-rtsp-server-sections.txt | 22 +++++++++++++--------- gst/rtsp-server/rtsp-auth.h | 2 +- gst/rtsp-server/rtsp-permissions.c | 4 ++-- gst/rtsp-server/rtsp-permissions.h | 4 ++-- gst/rtsp-server/rtsp-token.c | 18 +++++++++++++++--- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 5b202a479c..56744e81a7 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -47,7 +47,6 @@ gst_rtsp_auth_set_tls_certificate gst_rtsp_auth_make_basic gst_rtsp_auth_add_basic gst_rtsp_auth_remove_basic -gst_rtsp_auth_setup gst_rtsp_auth_check @@ -55,11 +54,15 @@ GST_RTSP_AUTH_CHECK_CONNECT GST_RTSP_AUTH_CHECK_URL GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT +GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS + + +GST_RTSP_MEDIA_FACTORY_ROLE -GST_RTSP_MEDIA_FACTORY_ROLE GST_RTSP_MEDIA_FACTORY_PERM_ACCESS GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT +GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS GST_RTSP_AUTH_CAST GST_RTSP_AUTH_CLASS_CAST @@ -79,6 +82,8 @@ gst_rtsp_auth_get_type GstRTSPClientState gst_rtsp_client_state_get_current +gst_rtsp_client_state_pop_current +gst_rtsp_client_state_push_current GstRTSPClient @@ -98,9 +103,6 @@ gst_rtsp_client_set_auth gst_rtsp_client_get_thread_pool gst_rtsp_client_set_thread_pool -gst_rtsp_client_get_use_client_settings -gst_rtsp_client_set_use_client_settings - gst_rtsp_client_get_connection gst_rtsp_client_set_connection @@ -110,7 +112,7 @@ GstRTSPClientSendFunc gst_rtsp_client_set_send_func gst_rtsp_client_handle_message -gst_rtsp_client_send_request +gst_rtsp_client_send_message GstRTSPClientSessionFilterFunc gst_rtsp_client_session_filter @@ -206,6 +208,7 @@ gst_rtsp_media_factory_set_launch gst_rtsp_media_factory_get_permissions gst_rtsp_media_factory_set_permissions +gst_rtsp_media_factory_add_role gst_rtsp_media_factory_set_shared gst_rtsp_media_factory_is_shared @@ -296,6 +299,7 @@ gst_rtsp_permissions_new gst_rtsp_permissions_ref gst_rtsp_permissions_unref gst_rtsp_permissions_add_role +gst_rtsp_permissions_add_role_valist gst_rtsp_permissions_remove_role gst_rtsp_permissions_get_role gst_rtsp_permissions_is_allowed @@ -345,9 +349,6 @@ gst_rtsp_server_set_thread_pool gst_rtsp_server_get_auth gst_rtsp_server_set_auth -gst_rtsp_server_get_use_client_settings -gst_rtsp_server_set_use_client_settings - gst_rtsp_server_transfer_connection gst_rtsp_server_io_func gst_rtsp_server_create_socket @@ -612,12 +613,15 @@ gst_rtsp_thread_pool_get_type rtsp-token GstRTSPToken GstRTSPToken +gst_rtsp_token_new_empty gst_rtsp_token_new +gst_rtsp_token_new_valist gst_rtsp_token_ref gst_rtsp_token_unref gst_rtsp_token_get_structure gst_rtsp_token_writable_structure gst_rtsp_token_get_string +gst_rtsp_token_is_allowed GST_RTSP_TOKEN_CAST GST_IS_RTSP_TOKEN diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 80b6f19cb4..b6b10ad33e 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -150,7 +150,7 @@ gchar * gst_rtsp_auth_make_basic (const gchar * user, const g */ #define GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT "media.factory.construct" /** - * GST_RTSP_MEDIA_FACTORY_PERM_CLIENT_SETTINGS: + * GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS: * * G_TYPE_BOOLEAN, %TRUE if the client can specify TTL, destination and * port pair in multicast. diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index b2bfa3d908..c8b35d09bc 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -123,7 +123,7 @@ gst_rtsp_permissions_new (void) * gst_rtsp_permissions_add_role: * @permissions: a #GstRTSPPermissions * @role: a role - * @fielname: the first field name + * @fieldname: the first field name * @...: additional arguments * * Add a new @role to @permissions with the given variables. The fields @@ -144,7 +144,7 @@ gst_rtsp_permissions_add_role (GstRTSPPermissions * permissions, * gst_rtsp_permissions_add_role_valist: * @permissions: a #GstRTSPPermissions * @role: a role - * @fielname: the first field name + * @fieldname: the first field name * @var_args: additional fields to add * * Add a new @role to @permissions with the given variables. Structure fields diff --git a/gst/rtsp-server/rtsp-permissions.h b/gst/rtsp-server/rtsp-permissions.h index 9beab20819..9e739c79d7 100644 --- a/gst/rtsp-server/rtsp-permissions.h +++ b/gst/rtsp-server/rtsp-permissions.h @@ -83,10 +83,10 @@ GstRTSPPermissions * gst_rtsp_permissions_new (void); void gst_rtsp_permissions_add_role (GstRTSPPermissions *permissions, const gchar *role, - const gchar *field_name, ...); + const gchar *fieldname, ...); void gst_rtsp_permissions_add_role_valist (GstRTSPPermissions *permissions, const gchar *role, - const gchar *field_name, + const gchar *fieldname, va_list var_args); void gst_rtsp_permissions_remove_role (GstRTSPPermissions *permissions, const gchar *role); diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index b252ff533f..26cf54e2d3 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -21,7 +21,19 @@ * @short_description: Roles and permissions for a client * @see_also: #GstRTSPClient, #GstRTSPPermission, #GstRTSPAuth * - * Last reviewed on 2013-07-11 (1.0.0) + * A #GstRTSPToken contains the permissions and roles of the user + * performing the current request. A token is usually created when a user is + * authenticated by the #GstRTSPAuth object and is then placed as the current + * token for the current request. + * + * #GstRTSPAuth can use the token and its contents to check authorization for + * various operations by comparing the token to the #GstRTSPPermissions of the + * object. + * + * The accepted values of the token are entirely defined by the #GstRTSPAuth + * object that implements the security policy. + * + * Last reviewed on 2013-07-15 (1.0.0) */ #include @@ -120,9 +132,9 @@ gst_rtsp_token_new (const gchar * firstfield, ...) } /** - * gst_rtsp_token_new: + * gst_rtsp_token_new_valist: * @firstfield: the first fieldname - * @var_args additional arguments + * @var_args: additional arguments * * Create a new Authorization token with the given fieldnames and values. * Arguments are given similar to gst_structure_new_valist(). From d3d7df5a1efcd6cc3286e65adc56962557f7907f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Jul 2013 12:32:00 +0200 Subject: [PATCH 0760/1776] address-pool: cleanups Remove redundant method, improve docs. --- docs/libs/gst-rtsp-server-sections.txt | 1 - gst/rtsp-server/rtsp-address-pool.c | 70 +++++++++++--------------- gst/rtsp-server/rtsp-address-pool.h | 6 --- tests/check/gst/addresspool.c | 4 +- tests/check/gst/rtspserver.c | 4 +- 5 files changed, 34 insertions(+), 51 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 56744e81a7..ac36099271 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -17,7 +17,6 @@ gst_rtsp_address_pool_new gst_rtsp_address_pool_clear gst_rtsp_address_pool_dump gst_rtsp_address_pool_add_range -gst_rtsp_address_pool_add_range_unicast gst_rtsp_address_pool_has_unicast_addresses gst_rtsp_address_pool_acquire_address gst_rtsp_address_pool_reserve_address diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 297f85cba5..2407444dd5 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -247,12 +247,19 @@ get_address_string (Addr * addr) * @max_address: a maximum address to add * @min_port: the minimum port * @max_port: the maximum port - * @ttl: a TTL + * @ttl: a TTL or 0 for unicast addresses * - * Adds the multicast addresses from @min_addess to @max_address (inclusive) + * Adds the addresses from @min_addess to @max_address (inclusive) * to @pool. The valid port range for the addresses will be from @min_port to * @max_port inclusive. * + * When @ttl is 0, @min_address and @max_address should be unicast addresses. + * @min_address and @max_address can be set to + * #GST_RTSP_ADDRESS_POOL_ANY_IPV4 or #GST_RTSP_ADDRESS_POOL_ANY_IPV6 to bind + * to all available IPv4 or IPv6 addresses. + * + * When @ttl > 0, @min_address and @max_address should be multicast addresses. + * * Returns: %TRUE if the addresses could be added. */ gboolean @@ -262,17 +269,20 @@ gst_rtsp_address_pool_add_range (GstRTSPAddressPool * pool, { AddrRange *range; GstRTSPAddressPoolPrivate *priv; + gboolean is_multicast; g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), FALSE); g_return_val_if_fail (min_port <= max_port, FALSE); priv = pool->priv; + is_multicast = ttl != 0; + range = g_slice_new0 (AddrRange); - if (!fill_address (min_address, min_port, &range->min, (ttl != 0))) + if (!fill_address (min_address, min_port, &range->min, is_multicast)) goto invalid; - if (!fill_address (max_address, max_port, &range->max, (ttl != 0))) + if (!fill_address (max_address, max_port, &range->max, is_multicast)) goto invalid; if (range->min.size != range->max.size) @@ -288,7 +298,7 @@ gst_rtsp_address_pool_add_range (GstRTSPAddressPool * pool, g_mutex_lock (&priv->lock); priv->addresses = g_list_prepend (priv->addresses, range); - if (ttl == 0) + if (!is_multicast) priv->has_unicast_addresses = TRUE; g_mutex_unlock (&priv->lock); @@ -304,35 +314,6 @@ invalid: } } -/** - * gst_rtsp_address_pool_add_range_unicast: - * @pool: a #GstRTSPAddressPool - * @min_address: a minimum address to add - * @max_address: a maximum address to add - * @min_port: the minimum port - * @max_port: the maximum port - * - * Adds the unicast addresses from @min_addess to @max_address (inclusive) - * to @pool. The valid port range for the addresses will be from @min_port to - * @max_port inclusive. - * - * @min_address and @max_address can be set to - * #GST_RTSP_ADDRESS_POOL_ANY_IPV4 or #GST_RTSP_ADDRESS_POOL_ANY_IPV6 to bind - * to all available IPv4 or IPv6 addresses. - * - * Returns: %TRUE if the addresses could be added. - */ -gboolean -gst_rtsp_address_pool_add_range_unicast (GstRTSPAddressPool * pool, - const gchar * min_address, const gchar * max_address, - guint16 min_port, guint16 max_port) -{ - return gst_rtsp_address_pool_add_range (pool, min_address, max_address, - min_port, max_port, 0); -} - -/* increments the address by count */ - static void inc_address (Addr * addr, guint8 count) { @@ -605,12 +586,14 @@ gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool) * ports will be allocated of which the first one can be found in * @port. * + * If @ttl is 0, @address should be a unicast address. If @ttl > 0, @address + * should be a valid multicast address. + * * This function should only be used internally. * * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free * after use or %NULL when no address could be acquired. */ - GstRTSPAddress * gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, const gchar * address, guint port, guint n_ports, guint ttl) @@ -620,6 +603,7 @@ gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, GList *walk, *next; AddrRange *result; GstRTSPAddress *addr; + gboolean is_multicast; g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), NULL); g_return_val_if_fail (address != NULL, NULL); @@ -629,11 +613,10 @@ gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, priv = pool->priv; result = NULL; addr = NULL; + is_multicast = ttl != 0; - if (!fill_address (address, port, &input_addr, (ttl != 0))) { - GST_ERROR_OBJECT (pool, "invalid address %s", address); - return NULL; - } + if (!fill_address (address, port, &input_addr, is_multicast)) + goto invalid; g_mutex_lock (&priv->lock); /* go over available ranges */ @@ -684,8 +667,15 @@ gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, GST_DEBUG_OBJECT (pool, "reserved address %s:%u ttl %u", addr->address, addr->port, addr->ttl); } - return addr; + + /* ERRORS */ +invalid: + { + GST_ERROR_OBJECT (pool, "invalid address %s:%u/%u/%u", address, + port, n_ports, ttl); + return NULL; + } } /** diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index 6a6b2d6701..72802fc569 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -139,12 +139,6 @@ gboolean gst_rtsp_address_pool_add_range (GstRTSPAddressPool guint16 max_port, guint8 ttl); -gboolean gst_rtsp_address_pool_add_range_unicast (GstRTSPAddressPool * pool, - const gchar *min_address, - const gchar *max_address, - guint16 min_port, - guint16 max_port); - GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, GstRTSPAddressFlags flags, gint n_ports); diff --git a/tests/check/gst/addresspool.c b/tests/check/gst/addresspool.c index 2d58209496..d862929f99 100644 --- a/tests/check/gst/addresspool.c +++ b/tests/check/gst/addresspool.c @@ -188,8 +188,8 @@ GST_START_TEST (test_pool) fail_unless (gst_rtsp_address_pool_add_range (pool, "233.252.1.1", "233.252.1.1", 5000, 5001, 1)); - fail_unless (gst_rtsp_address_pool_add_range_unicast (pool, - "192.168.1.1", "192.168.1.1", 6000, 6001)); + fail_unless (gst_rtsp_address_pool_add_range (pool, + "192.168.1.1", "192.168.1.1", 6000, 6001, 0)); addr = gst_rtsp_address_pool_acquire_address (pool, GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST, 2); diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index f82d3f7086..37bace5f8c 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1268,8 +1268,8 @@ GST_START_TEST (test_play_specific_server_port) factory = gst_rtsp_media_factory_new (); pool = gst_rtsp_address_pool_new (); - gst_rtsp_address_pool_add_range_unicast (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV4, - GST_RTSP_ADDRESS_POOL_ANY_IPV4, 7770, 7780); + gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV4, + GST_RTSP_ADDRESS_POOL_ANY_IPV4, 7770, 7780, 0); gst_rtsp_media_factory_set_address_pool (factory, pool); g_object_unref (pool); gst_rtsp_media_factory_set_launch (factory, "( " VIDEO_PIPELINE " )"); From 041b1b79a15d53af42fa6e6537f445c644e15a85 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Jul 2013 12:32:51 +0200 Subject: [PATCH 0761/1776] docs: improve docs --- docs/libs/gst-rtsp-server-sections.txt | 34 ++++++++++--------- gst/rtsp-server/rtsp-auth.c | 32 +++++++++++++++--- gst/rtsp-server/rtsp-auth.h | 43 +++++++++++++------------ gst/rtsp-server/rtsp-media.c | 39 +++++++++++++++++++++- gst/rtsp-server/rtsp-session-media.c | 11 ++++++- gst/rtsp-server/rtsp-stream-transport.c | 18 +++++++++-- gst/rtsp-server/rtsp-stream-transport.h | 3 +- gst/rtsp-server/rtsp-stream.c | 22 ++++++++++++- tests/check/gst/client.c | 10 +++--- 9 files changed, 160 insertions(+), 52 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index ac36099271..978019a025 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -55,13 +55,13 @@ GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS - -GST_RTSP_MEDIA_FACTORY_ROLE + +GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE +GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS -GST_RTSP_MEDIA_FACTORY_PERM_ACCESS -GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT -GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS +GST_RTSP_PERM_MEDIA_FACTORY_ACCESS +GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT GST_RTSP_AUTH_CAST GST_RTSP_AUTH_CLASS_CAST @@ -131,14 +131,11 @@ gst_rtsp_client_get_type
rtsp-media GstRTSPMedia -GstRTSPMediaStatus - GstRTSPMedia GstRTSPMediaClass gst_rtsp_media_new gst_rtsp_media_get_element gst_rtsp_media_take_pipeline -gst_rtsp_media_get_status gst_rtsp_media_set_permissions gst_rtsp_media_get_permissions @@ -161,26 +158,31 @@ gst_rtsp_media_get_address_pool gst_rtsp_media_set_buffer_size gst_rtsp_media_get_buffer_size -gst_rtsp_media_use_time_provider -gst_rtsp_media_is_time_provider -gst_rtsp_media_get_time_provider - + gst_rtsp_media_prepare gst_rtsp_media_unprepare +GstRTSPMediaStatus +gst_rtsp_media_get_status + gst_rtsp_media_collect_streams gst_rtsp_media_create_stream - -gst_rtsp_media_get_clock -gst_rtsp_media_get_base_time gst_rtsp_media_n_streams gst_rtsp_media_get_stream gst_rtsp_media_find_stream + gst_rtsp_media_seek gst_rtsp_media_get_range_string gst_rtsp_media_set_state + + +gst_rtsp_media_get_clock +gst_rtsp_media_get_base_time +gst_rtsp_media_use_time_provider +gst_rtsp_media_is_time_provider +gst_rtsp_media_get_time_provider GST_RTSP_MEDIA_CAST GST_RTSP_MEDIA_CLASS_CAST @@ -545,6 +547,7 @@ gst_rtsp_stream_transport_set_callbacks GstRTSPKeepAliveFunc gst_rtsp_stream_transport_set_keepalive +gst_rtsp_stream_transport_keep_alive gst_rtsp_stream_transport_set_active @@ -554,7 +557,6 @@ gst_rtsp_stream_transport_is_timed_out gst_rtsp_stream_transport_send_rtcp gst_rtsp_stream_transport_send_rtp -gst_rtsp_stream_transport_keep_alive GST_RTSP_STREAM_TRANSPORT_CAST GST_RTSP_STREAM_TRANSPORT_CLASS_CAST diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 8b4866f0cd..da575eed2e 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -21,7 +21,29 @@ * @short_description: Authentication and authorization * @see_also: #GstRTSPPermission, #GstRTSPtoken * - * Last reviewed on 2013-07-11 (1.0.0) + * The #GstRTSPAuth object is responsible for checking if the current user is + * allowed to perform requested actions. The default implementation has some + * reasonable checks but subclasses can implement custom security policies. + * + * A new auth object is made with gst_rtsp_auth_new(). It is usually configured + * on the #GstRTSPServer object. + * + * The RTSP server will call gst_rtsp_auth_check() with a string describing the + * check to perform. The possible checks are prefixed with + * #GST_RTSP_AUTH_CHECK_*. Depending on the check, the default implementation + * will use the current #GstRTSPToken, #GstRTSPClientState and + * #GstRTSPPermissions on the object to check if an operation is allowed. + * + * The default #GstRTSPAuth object has support for basic authentication. With + * gst_rtsp_auth_add_basic() you can add a basic authentication string together + * with the #GstRTSPToken that will become active when successfully + * authenticated. + * + * When a TLS certificate has been set with gst_rtsp_auth_set_tls_certificate(), + * the default auth object will require the client to connect with a TLS + * connection. + * + * Last reviewed on 2013-07-16 (1.0.0) */ #include @@ -395,18 +417,18 @@ check_factory (GstRTSPAuth * auth, GstRTSPClientState * state, return FALSE; if (!(role = gst_rtsp_token_get_string (state->token, - GST_RTSP_MEDIA_FACTORY_ROLE))) + GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE))) goto no_media_role; if (!(perms = gst_rtsp_media_factory_get_permissions (state->factory))) goto no_permissions; if (g_str_equal (check, "auth.check.media.factory.access")) { if (!gst_rtsp_permissions_is_allowed (perms, role, - GST_RTSP_MEDIA_FACTORY_PERM_ACCESS)) + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS)) goto no_access; } else if (g_str_equal (check, "auth.check.media.factory.construct")) { if (!gst_rtsp_permissions_is_allowed (perms, role, - GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT)) + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT)) goto no_construct; } return TRUE; @@ -446,7 +468,7 @@ check_client_settings (GstRTSPAuth * auth, GstRTSPClientState * state, return FALSE; return gst_rtsp_token_is_allowed (state->token, - GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS); + GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS); } static gboolean diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index b6b10ad33e..54c268f21b 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -113,7 +113,7 @@ gchar * gst_rtsp_auth_make_basic (const gchar * user, const g * GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT: * * Check if media can be constructed from a media factory - * The response is sent on error. + * A response should be sent on error. */ #define GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT "auth.check.media.factory.construct" /** @@ -128,35 +128,38 @@ gchar * gst_rtsp_auth_make_basic (const gchar * user, const g /* tokens */ /** - * GST_RTSP_MEDIA_FACTORY_ROLE: + * GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE: * * G_TYPE_STRING, the role to use when dealing with media factories - */ -#define GST_RTSP_MEDIA_FACTORY_ROLE "media.factory.role" - -/* permissions */ -/** - * GST_RTSP_MEDIA_FACTORY_PERM_ACCESS: * - * G_TYPE_BOOLEAN, %TRUE if the media can be accessed, %FALSE will - * return a 404 Not Found error when trying to access the media. + * The default #GstRTSPAuth object uses this string in the token to find the + * role of the media factory. It will then retrieve the #GstRTSPPermissions of + * the media factory and retrieve the role with the same name. */ -#define GST_RTSP_MEDIA_FACTORY_PERM_ACCESS "media.factory.access" +#define GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE "media.factory.role" /** - * GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT: - * - * G_TYPE_BOOLEAN, %TRUE if the media can be constructed, %FALSE will - * return a 404 Not Found error when trying to access the media. - */ -#define GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT "media.factory.construct" -/** - * GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS: + * GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS: * * G_TYPE_BOOLEAN, %TRUE if the client can specify TTL, destination and * port pair in multicast. */ -#define GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS "transport.client-settings" +#define GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS "transport.client-settings" +/* permissions */ +/** + * GST_RTSP_PERM_MEDIA_FACTORY_ACCESS: + * + * G_TYPE_BOOLEAN, %TRUE if the media can be accessed, %FALSE will + * return a 404 Not Found error when trying to access the media. + */ +#define GST_RTSP_PERM_MEDIA_FACTORY_ACCESS "media.factory.access" +/** + * GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT: + * + * G_TYPE_BOOLEAN, %TRUE if the media can be constructed, %FALSE will + * return a 404 Not Found error when trying to access the media. + */ +#define GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT "media.factory.construct" G_END_DECLS diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 78f5f853c4..26f734f821 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -19,7 +19,44 @@ /** * SECTION:rtsp-media * @short_description: The media pipeline - * @see_also: #GstRTSPMediaFactory, #GstRTSPStream + * @see_also: #GstRTSPMediaFactory, #GstRTSPStream, #GstRTSPSession, + * #GstRTSPSessionMedia + * + * a #GstRTSPMedia contains the complete GStreamer pipeline to manage the + * streaming to the clients. The actual data transfer is done by the + * #GstRTSPStream objects that are created and exposed by the #GstRTSPMedia. + * + * The #GstRTSPMedia is usually created from a #GstRTSPMediaFactory when the + * client does a DESCRIBE or SETUP of a resource. + * + * A media is created with gst_rtsp_media_new() that takes the element that will + * provide the streaming elements. For each of the streams, a new #GstRTSPStream + * object needs to be made with the gst_rtsp_media_create_stream() which takes + * the payloader element and the source pad that produces the RTP stream. + * + * The pipeline of the media is set to PAUSED with gst_rtsp_media_prepare(). The + * prepare method will add rtpbin and sinks and sources to send and receive RTP + * and RTCP packets from the clients. Each stream srcpad is connected to an + * input into the internal rtpbin. + * + * It is also possible to dynamically create #GstRTSPStream objects during the + * prepare phase. With gst_rtsp_media_get_status() you can check the status of + * the prepare phase. + * + * After the media is prepared, it is ready for streaming. It will usually be + * managed in a session with gst_rtsp_session_manage_media(). See + * #GstRTSPSession and #GstRTSPSessionMedia. + * + * The state of the media can be controlled with gst_rtsp_media_set_state (). + * Seeking can be done with gst_rtsp_media_seek(). + * + * With gst_rtsp_media_unprepare() the pipeline is stopped and shut down. When + * gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to + * cleanly shut down. + * + * With gst_rtsp_media_set_shared(), the media can be shared between multiple + * clients. With gst_rtsp_media_set_reusable() you can control if the pipeline + * can be prepared again after an unprepare. * * Last reviewed on 2013-07-11 (1.0.0) */ diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 5740a0440d..1b8e7e2506 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -21,7 +21,16 @@ * @short_description: Media managed in a session * @see_also: #GstRTSPMedia, #GstRTSPSession * - * Last reviewed on 2013-07-11 (1.0.0) + * The #GstRTSPSessionMedia object manages a #GstRTSPMedia with a given path. + * + * With gst_rtsp_session_media_get_transport() and + * gst_rtsp_session_media_set_transport() the transports of a #GstRTSPStream of + * the managed #GstRTSPMedia can be retrieved and configured. + * + * Use gst_rtsp_session_media_set_state() to control the media state and + * transports. + * + * Last reviewed on 2013-07-16 (1.0.0) */ #include diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 40452c27c7..c71c8ea7c7 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -19,9 +19,23 @@ /** * SECTION:rtsp-stream-transport * @short_description: A media stream transport configuration - * @see_also: #GstRTSPStream + * @see_also: #GstRTSPStream, #GstRTSPSessionMedia * - * Last reviewed on 2013-07-11 (1.0.0) + * The #GstRTSPStreamTransport configures the transport used by a + * #GstRTSPStream. It is usually manages by a #GstRTSPSessionMedia object. + * + * With gst_rtsp_stream_transport_set_callbacks(), callbacks can be configured + * to handle the RTP and RTCP packets from the stream, for example when they + * need to be sent over TCP. + * + * With gst_rtsp_stream_transport_set_active() the transports are added and + * removed from the stream. + * + * A #GstRTSPStream will call gst_rtsp_stream_transport_keep_alive() when RTCP + * is received from the client. It will also call + * gst_rtsp_stream_transport_set_timed_out() when a receiver has timed out. + * + * Last reviewed on 2013-07-16 (1.0.0) */ #include diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 61257f5dc0..b73bf6ef57 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -100,6 +100,7 @@ void gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamT GstRTSPKeepAliveFunc keep_alive, gpointer user_data, GDestroyNotify notify); +void gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport *trans); gboolean gst_rtsp_stream_transport_set_active (GstRTSPStreamTransport *trans, gboolean active); @@ -115,8 +116,6 @@ gboolean gst_rtsp_stream_transport_send_rtp (GstRTSPStreamT gboolean gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport *trans, GstBuffer *buffer); -void gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport *trans); - G_END_DECLS #endif /* __GST_RTSP_STREAM_TRANSPORT_H__ */ diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 63222c4159..ba8913b215 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -21,7 +21,27 @@ * @short_description: A media stream * @see_also: #GstRTSPMedia * - * Last reviewed on 2013-07-11 (1.0.0) + * The #GstRTSPStream object manages the data transport for one stream. It + * is created from a payloader element and a source pad that produce the RTP + * packets for the stream. + * + * With gst_rtsp_stream_join_bin() the streaming elements are added to the bin + * and rtpbin. gst_rtsp_stream_leave_bin() removes the elements again. + * + * The #GstRTSPStream will use the configured addresspool, as set with + * gst_rtsp_stream_set_address_pool(), to allocate multicast addresses for the + * stream. With gst_rtsp_stream_get_multicast_address() you can get the + * configured address. + * + * With gst_rtsp_stream_get_server_port () you can get the port that the server + * will use to receive RTCP. This is the part that the clients will use to send + * RTCP to. + * + * With gst_rtsp_stream_add_transport() destinations can be added where the + * stream should be sent to. Use gst_rtsp_stream_remove_transport() to remove + * the destination again. + * + * Last reviewed on 2013-07-16 (1.0.0) */ #include diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index d3a180884b..8a442bcee4 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -536,8 +536,9 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) state.client = client; state.auth = gst_rtsp_auth_new (); state.token = - gst_rtsp_token_new (GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS, - G_TYPE_BOOLEAN, TRUE, "media.factory.role", G_TYPE_STRING, "user", NULL); + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); gst_rtsp_client_state_push_current (&state); /* simple SETUP with a valid URI and multicast, but an invalid ip */ @@ -623,8 +624,9 @@ GST_START_TEST (test_client_multicast_transport_specific) state.client = client; state.auth = gst_rtsp_auth_new (); state.token = - gst_rtsp_token_new (GST_RTSP_TRANSPORT_PERM_CLIENT_SETTINGS, - G_TYPE_BOOLEAN, TRUE, "media.factory.role", G_TYPE_STRING, "user", NULL); + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); gst_rtsp_client_state_push_current (&state); expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" From 81745b43b43a49a8783081ffd54446d34ddf1550 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Jul 2013 12:36:56 +0200 Subject: [PATCH 0762/1776] docs: small fixes --- gst/rtsp-server/rtsp-address-pool.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index 72802fc569..1cf908bbc5 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -89,7 +89,7 @@ typedef enum { /** * GST_RTSP_ADDRESS_POOL_ANY_IPV4: * - * Used with gst_rtsp_address_pool_add_range_unicast() to bind to all + * Used with gst_rtsp_address_pool_add_range() to bind to all * IPv4 addresses */ #define GST_RTSP_ADDRESS_POOL_ANY_IPV4 "0.0.0.0" @@ -97,7 +97,7 @@ typedef enum { /** * GST_RTSP_ADDRESS_POOL_ANY_IPV6: * - * Used with gst_rtsp_address_pool_add_range_unicast() to bind to all + * Used with gst_rtsp_address_pool_add_range() to bind to all * IPv6 addresses */ #define GST_RTSP_ADDRESS_POOL_ANY_IPV6 "::" From 91a32754e351ca05b0bf7bb4499dbfd6adf50007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Wed, 17 Jul 2013 19:32:09 -0400 Subject: [PATCH 0763/1776] permissions: Make it build --- gst/rtsp-server/rtsp-permissions.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index c8b35d09bc..407d21fa67 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -61,8 +61,7 @@ free_structure (GstStructure * structure) GST_DEFINE_MINI_OBJECT_TYPE (GstRTSPPermissions, gst_rtsp_permissions); -static void gst_rtsp_permissions_init (GstRTSPPermissionsImpl * permissions, - GstStructure * structure); +static void gst_rtsp_permissions_init (GstRTSPPermissionsImpl * permissions); static void _gst_rtsp_permissions_free (GstRTSPPermissions * permissions) @@ -78,17 +77,15 @@ static GstRTSPPermissions * _gst_rtsp_permissions_copy (GstRTSPPermissionsImpl * permissions) { GstRTSPPermissionsImpl *copy; - GstStructure *structure; copy = g_slice_new0 (GstRTSPPermissionsImpl); - gst_rtsp_permissions_init (copy, structure); + gst_rtsp_permissions_init (copy); return GST_RTSP_PERMISSIONS (copy); } static void -gst_rtsp_permissions_init (GstRTSPPermissionsImpl * permissions, - GstStructure * structure) +gst_rtsp_permissions_init (GstRTSPPermissionsImpl * permissions) { gst_mini_object_init (GST_MINI_OBJECT_CAST (permissions), 0, GST_TYPE_RTSP_PERMISSIONS, @@ -112,9 +109,7 @@ gst_rtsp_permissions_new (void) GstRTSPPermissionsImpl *permissions; permissions = g_slice_new0 (GstRTSPPermissionsImpl); - - gst_rtsp_permissions_init (permissions, - gst_structure_new_empty ("GstRTSPPermissions")); + gst_rtsp_permissions_init (permissions); return GST_RTSP_PERMISSIONS (permissions); } From db74d5c5594895c4137b899264418e1a9f087dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Wed, 17 Jul 2013 19:35:33 -0400 Subject: [PATCH 0764/1776] permissions: Also copy the roles --- gst/rtsp-server/rtsp-permissions.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index 407d21fa67..077ae5b63b 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -77,9 +77,18 @@ static GstRTSPPermissions * _gst_rtsp_permissions_copy (GstRTSPPermissionsImpl * permissions) { GstRTSPPermissionsImpl *copy; + guint i; - copy = g_slice_new0 (GstRTSPPermissionsImpl); - gst_rtsp_permissions_init (copy); + copy = (GstRTSPPermissionsImpl *) gst_rtsp_permissions_new (); + + for (i = 0; i < permissions->roles->len; i++) { + GstStructure *entry = g_ptr_array_index (permissions->roles, i); + GstStructure *entry_copy = gst_structure_copy (entry); + + gst_structure_set_parent_refcount (entry_copy, + ©->permissions.mini_object.refcount); + g_ptr_array_add (permissions->roles, entry_copy); + } return GST_RTSP_PERMISSIONS (copy); } From 472010666c8b1f0b18745e6fe7d8067cb0dab763 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 18 Jul 2013 12:26:45 +0200 Subject: [PATCH 0765/1776] permissions: add the role to the copy --- gst/rtsp-server/rtsp-permissions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index 077ae5b63b..25872c65c1 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -87,7 +87,7 @@ _gst_rtsp_permissions_copy (GstRTSPPermissionsImpl * permissions) gst_structure_set_parent_refcount (entry_copy, ©->permissions.mini_object.refcount); - g_ptr_array_add (permissions->roles, entry_copy); + g_ptr_array_add (copy->roles, entry_copy); } return GST_RTSP_PERMISSIONS (copy); From 3dc34af5aa5701ddfcde60b03d9b2fea97069be5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 18 Jul 2013 11:44:21 +0200 Subject: [PATCH 0766/1776] address-pool: improve docs --- gst/rtsp-server/rtsp-address-pool.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 2407444dd5..6bb0956a0e 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -21,7 +21,20 @@ * @short_description: A pool of network addresses * @see_also: #GstRTSPStream, #GstRTSPStreamTransport * - * Last reviewed on 2013-07-11 (1.0.0) + * The #GstRTSPAddressPool is an object that maintains a collection of network + * addresses. It is used to allocate server ports and server multicast addresses + * but also to reserve client provided destination addresses. + * + * A range of addresses can be added with gst_rtsp_address_pool_add_range(). + * Both multicast and unicast addresses can be added. + * + * With gst_rtsp_address_pool_acquire_address() an unused address and port range + * can be acquired from the pool. With gst_rtsp_address_pool_reserve_address() a + * specific address can be retrieved. Both methods return a boxed + * #GstRTSPAddress that should be freed with gst_rtsp_address_free() after + * usage, which brings the address back into the pool. + * + * Last reviewed on 2013-07-16 (1.0.0) */ #include @@ -412,8 +425,6 @@ split_range (GstRTSPAddressPool * pool, AddrRange * range, guint skip_addr, * allocation. @n_ports consecutive ports will be allocated of which the first * one can be found in @port. * - * This function should only be used internally. - * * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free * after use or %NULL when no address could be acquired. */ @@ -589,8 +600,6 @@ gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool) * If @ttl is 0, @address should be a unicast address. If @ttl > 0, @address * should be a valid multicast address. * - * This function should only be used internally. - * * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free * after use or %NULL when no address could be acquired. */ From 1a307c707dbad1dad95cf95723758e8521d65726 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 18 Jul 2013 11:44:50 +0200 Subject: [PATCH 0767/1776] auth: use defines when possible --- examples/test-auth.c | 31 +++++++++++++++++-------------- gst/rtsp-server/rtsp-auth.c | 4 ++-- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/examples/test-auth.c b/examples/test-auth.c index 27eca57f9b..7d0b9d260e 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -92,16 +92,16 @@ main (int argc, char *argv[]) /* allow user and admin to access this resource */ gst_rtsp_media_factory_add_role (factory, "user", - "media.factory.access", G_TYPE_BOOLEAN, TRUE, - "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL); gst_rtsp_media_factory_add_role (factory, "admin", - "media.factory.access", G_TYPE_BOOLEAN, TRUE, - "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL); /* admin2 can look at the media but not construct so he gets a * 401 Unauthorized */ gst_rtsp_media_factory_add_role (factory, "admin2", - "media.factory.access", G_TYPE_BOOLEAN, TRUE, - "media.factory.construct", G_TYPE_BOOLEAN, FALSE, NULL); + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, FALSE, NULL); /* make another factory */ factory = gst_rtsp_media_factory_new (); @@ -115,8 +115,8 @@ main (int argc, char *argv[]) /* user and admin have no permissions so they can't even see the * media and get a 404 Not Found */ gst_rtsp_media_factory_add_role (factory, "admin2", - "media.factory.access", G_TYPE_BOOLEAN, TRUE, - "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL); /* don't need the ref to the mapper anymore */ g_object_unref (mounts); @@ -125,24 +125,27 @@ main (int argc, char *argv[]) auth = gst_rtsp_auth_new (); /* make user token */ - token = gst_rtsp_token_new ("resources.class", G_TYPE_STRING, "user", - "media.factory.role", G_TYPE_STRING, "user", NULL); + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); basic = gst_rtsp_auth_make_basic ("user", "password"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); gst_rtsp_token_unref (token); /* make admin token */ - token = gst_rtsp_token_new ("resources.class", G_TYPE_STRING, "admin", - "media.factory.role", G_TYPE_STRING, "admin", NULL); + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "admin", NULL); basic = gst_rtsp_auth_make_basic ("admin", "power"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); gst_rtsp_token_unref (token); /* make admin2 token */ - token = gst_rtsp_token_new ("resources.class", G_TYPE_STRING, "admin", - "media.factory.role", G_TYPE_STRING, "admin2", NULL); + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "admin2", NULL); basic = gst_rtsp_auth_make_basic ("admin2", "power2"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index da575eed2e..dfce78472f 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -422,11 +422,11 @@ check_factory (GstRTSPAuth * auth, GstRTSPClientState * state, if (!(perms = gst_rtsp_media_factory_get_permissions (state->factory))) goto no_permissions; - if (g_str_equal (check, "auth.check.media.factory.access")) { + if (g_str_equal (check, GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS)) { if (!gst_rtsp_permissions_is_allowed (perms, role, GST_RTSP_PERM_MEDIA_FACTORY_ACCESS)) goto no_access; - } else if (g_str_equal (check, "auth.check.media.factory.construct")) { + } else if (g_str_equal (check, GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT)) { if (!gst_rtsp_permissions_is_allowed (perms, role, GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT)) goto no_construct; From 25547176beb92482bf9e21a3904915d44f3a5802 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 18 Jul 2013 12:19:25 +0200 Subject: [PATCH 0768/1776] auth: add support for default token The default token is used when the user is not authenticated and can be used to give minimal permissions. --- examples/test-auth.c | 7 ++++ gst/rtsp-server/rtsp-auth.c | 64 +++++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-auth.h | 3 ++ 3 files changed, 74 insertions(+) diff --git a/examples/test-auth.c b/examples/test-auth.c index 7d0b9d260e..eff3c749ac 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -124,6 +124,13 @@ main (int argc, char *argv[]) /* make a new authentication manager */ auth = gst_rtsp_auth_new (); + /* make default token, it has the same permissions as admin2 */ + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "admin2", NULL); + gst_rtsp_auth_set_default_token (auth, token); + gst_rtsp_token_unref (token); + /* make user token */ token = gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index dfce78472f..68ab719eda 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -60,6 +60,7 @@ struct _GstRTSPAuthPrivate /* the TLS certificate */ GTlsCertificate *certificate; GHashTable *basic; /* protected by lock */ + GstRTSPToken *default_token; GstRTSPMethod methods; }; @@ -230,6 +231,63 @@ gst_rtsp_auth_get_tls_certificate (GstRTSPAuth * auth) return result; } +/** + * gst_rtsp_auth_set_default_token: + * @auth: a #GstRTSPAuth + * @token: (allow none): a #GstRTSPToken + * + * Set the default #GstRTSPToken to @token in @auth. The default token will + * be used for unauthenticated users. + */ +void +gst_rtsp_auth_set_default_token (GstRTSPAuth * auth, GstRTSPToken * token) +{ + GstRTSPAuthPrivate *priv; + GstRTSPToken *old; + + g_return_if_fail (GST_IS_RTSP_AUTH (auth)); + + priv = auth->priv; + + if (token) + gst_rtsp_token_ref (token); + + g_mutex_lock (&priv->lock); + old = priv->default_token; + priv->default_token = token; + g_mutex_unlock (&priv->lock); + + if (old) + gst_rtsp_token_unref (old); +} + +/** + * gst_rtsp_auth_get_default_token: + * @auth: a #GstRTSPAuth + * + * Get the default token for @auth. This token will be used for unauthorized + * users. + * + * Returns: (transfer full): the #GstRTSPToken of @auth. gst_rtsp_token_unref() after + * usage. + */ +GstRTSPToken * +gst_rtsp_auth_get_default_token (GstRTSPAuth * auth) +{ + GstRTSPAuthPrivate *priv; + GstRTSPToken *result; + + g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), NULL); + + priv = auth->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->default_token)) + gst_rtsp_token_ref (result); + g_mutex_unlock (&priv->lock); + + return result; +} /** * gst_rtsp_auth_add_basic: @@ -290,6 +348,12 @@ default_authenticate (GstRTSPAuth * auth, GstRTSPClientState * state) GST_DEBUG_OBJECT (auth, "authenticate"); + g_mutex_lock (&priv->lock); + /* FIXME, need to ref but we have no way to unref when the state is + * popped */ + state->token = priv->default_token; + g_mutex_unlock (&priv->lock); + res = gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION, &authorization, 0); diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 54c268f21b..fd0da62d0d 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -79,6 +79,9 @@ GstRTSPAuth * gst_rtsp_auth_new (void); void gst_rtsp_auth_set_tls_certificate (GstRTSPAuth *auth, GTlsCertificate *cert); GTlsCertificate * gst_rtsp_auth_get_tls_certificate (GstRTSPAuth *auth); +void gst_rtsp_auth_set_default_token (GstRTSPAuth *auth, GstRTSPToken *token); +GstRTSPToken * gst_rtsp_auth_get_default_token (GstRTSPAuth *auth); + void gst_rtsp_auth_add_basic (GstRTSPAuth *auth, const gchar * basic, GstRTSPToken *token); void gst_rtsp_auth_remove_basic (GstRTSPAuth *auth, const gchar * basic); From f78a65379ce2227d714ce6315e05fbbd1aa73f9d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 22 Jul 2013 14:25:04 +0200 Subject: [PATCH 0769/1776] ClientState -> Context Rename the clientstate to context and put the code in a separate file. --- examples/test-cgroups.c | 8 +- gst/rtsp-server/Makefile.am | 2 + gst/rtsp-server/rtsp-auth.c | 99 ++++--- gst/rtsp-server/rtsp-auth.h | 6 +- gst/rtsp-server/rtsp-client.c | 411 ++++++++++++----------------- gst/rtsp-server/rtsp-client.h | 77 ++---- gst/rtsp-server/rtsp-context.c | 90 +++++++ gst/rtsp-server/rtsp-context.h | 81 ++++++ gst/rtsp-server/rtsp-params.c | 16 +- gst/rtsp-server/rtsp-params.h | 4 +- gst/rtsp-server/rtsp-server.c | 38 +-- gst/rtsp-server/rtsp-thread-pool.c | 20 +- gst/rtsp-server/rtsp-thread-pool.h | 6 +- tests/check/gst/client.c | 32 +-- 14 files changed, 472 insertions(+), 418 deletions(-) create mode 100644 gst/rtsp-server/rtsp-context.c create mode 100644 gst/rtsp-server/rtsp-context.h diff --git a/examples/test-cgroups.c b/examples/test-cgroups.c index 81885884f3..dcd700b375 100644 --- a/examples/test-cgroups.c +++ b/examples/test-cgroups.c @@ -54,7 +54,7 @@ static void gst_rtsp_cgroup_pool_finalize (GObject * obj); static void default_thread_enter (GstRTSPThreadPool * pool, GstRTSPThread * thread); static void default_configure_thread (GstRTSPThreadPool * pool, - GstRTSPThread * thread, GstRTSPClientState * state); + GstRTSPThread * thread, GstRTSPContext * ctx); G_DEFINE_TYPE (GstRTSPCGroupPool, gst_rtsp_cgroup_pool, GST_TYPE_RTSP_THREAD_POOL); @@ -118,14 +118,14 @@ default_thread_enter (GstRTSPThreadPool * pool, GstRTSPThread * thread) static void default_configure_thread (GstRTSPThreadPool * pool, - GstRTSPThread * thread, GstRTSPClientState * state) + GstRTSPThread * thread, GstRTSPContext * ctx) { GstRTSPCGroupPool *cpool = GST_RTSP_CGROUP_POOL (pool); const gchar *cls; struct cgroup *cgroup; - if (state->token) - cls = gst_rtsp_token_get_string (state->token, "cgroup.pool.media.class"); + if (ctx->token) + cls = gst_rtsp_token_get_string (ctx->token, "cgroup.pool.media.class"); else cls = NULL; diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 725537ec2a..638b2c6f97 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -1,6 +1,7 @@ public_headers = \ rtsp-auth.h \ rtsp-address-pool.h \ + rtsp-context.h \ rtsp-params.h \ rtsp-sdp.h \ rtsp-thread-pool.h \ @@ -21,6 +22,7 @@ public_headers = \ c_sources = \ rtsp-auth.c \ rtsp-address-pool.c \ + rtsp-context.c \ rtsp-params.c \ rtsp-sdp.c \ rtsp-thread-pool.c \ diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 68ab719eda..7264128530 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -31,7 +31,7 @@ * The RTSP server will call gst_rtsp_auth_check() with a string describing the * check to perform. The possible checks are prefixed with * #GST_RTSP_AUTH_CHECK_*. Depending on the check, the default implementation - * will use the current #GstRTSPToken, #GstRTSPClientState and + * will use the current #GstRTSPToken, #GstRTSPContext and * #GstRTSPPermissions on the object to check if an operation is allowed. * * The default #GstRTSPAuth object has support for basic authentication. With @@ -79,9 +79,8 @@ static void gst_rtsp_auth_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_auth_finalize (GObject * obj); -static gboolean default_authenticate (GstRTSPAuth * auth, - GstRTSPClientState * state); -static gboolean default_check (GstRTSPAuth * auth, GstRTSPClientState * state, +static gboolean default_authenticate (GstRTSPAuth * auth, GstRTSPContext * ctx); +static gboolean default_check (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check); G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT); @@ -340,7 +339,7 @@ gst_rtsp_auth_remove_basic (GstRTSPAuth * auth, const gchar * basic) } static gboolean -default_authenticate (GstRTSPAuth * auth, GstRTSPClientState * state) +default_authenticate (GstRTSPAuth * auth, GstRTSPContext * ctx) { GstRTSPAuthPrivate *priv = auth->priv; GstRTSPResult res; @@ -349,13 +348,13 @@ default_authenticate (GstRTSPAuth * auth, GstRTSPClientState * state) GST_DEBUG_OBJECT (auth, "authenticate"); g_mutex_lock (&priv->lock); - /* FIXME, need to ref but we have no way to unref when the state is + /* FIXME, need to ref but we have no way to unref when the ctx is * popped */ - state->token = priv->default_token; + ctx->token = priv->default_token; g_mutex_unlock (&priv->lock); res = - gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION, + gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_AUTHORIZATION, &authorization, 0); if (res < 0) goto no_auth; @@ -368,7 +367,7 @@ default_authenticate (GstRTSPAuth * auth, GstRTSPClientState * state) g_mutex_lock (&priv->lock); if ((token = g_hash_table_lookup (priv->basic, &authorization[6]))) { GST_DEBUG_OBJECT (auth, "setting token %p", token); - state->token = token; + ctx->token = token; } g_mutex_unlock (&priv->lock); } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) { @@ -385,35 +384,34 @@ no_auth: } static void -send_response (GstRTSPAuth * auth, GstRTSPStatusCode code, - GstRTSPClientState * state) +send_response (GstRTSPAuth * auth, GstRTSPStatusCode code, GstRTSPContext * ctx) { - gst_rtsp_message_init_response (state->response, code, - gst_rtsp_status_as_text (code), state->request); + gst_rtsp_message_init_response (ctx->response, code, + gst_rtsp_status_as_text (code), ctx->request); if (code == GST_RTSP_STS_UNAUTHORIZED) { /* we only have Basic for now */ - gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE, + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_WWW_AUTHENTICATE, "Basic realm=\"GStreamer RTSP Server\""); } - gst_rtsp_client_send_message (state->client, state->session, state->response); + gst_rtsp_client_send_message (ctx->client, ctx->session, ctx->response); } static gboolean -ensure_authenticated (GstRTSPAuth * auth, GstRTSPClientState * state) +ensure_authenticated (GstRTSPAuth * auth, GstRTSPContext * ctx) { GstRTSPAuthClass *klass; klass = GST_RTSP_AUTH_GET_CLASS (auth); /* we need a token to check */ - if (state->token == NULL) { + if (ctx->token == NULL) { if (klass->authenticate) { - if (!klass->authenticate (auth, state)) + if (!klass->authenticate (auth, ctx)) goto authenticate_failed; } } - if (state->token == NULL) + if (ctx->token == NULL) goto no_auth; return TRUE; @@ -422,21 +420,20 @@ ensure_authenticated (GstRTSPAuth * auth, GstRTSPClientState * state) authenticate_failed: { GST_DEBUG_OBJECT (auth, "authenticate failed"); - send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state); + send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx); return FALSE; } no_auth: { GST_DEBUG_OBJECT (auth, "no authorization token found"); - send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state); + send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx); return FALSE; } } /* new connection */ static gboolean -check_connect (GstRTSPAuth * auth, GstRTSPClientState * state, - const gchar * check) +check_connect (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check) { GstRTSPAuthPrivate *priv = auth->priv; @@ -444,7 +441,7 @@ check_connect (GstRTSPAuth * auth, GstRTSPClientState * state, GTlsConnection *tls; /* configure the connection */ - tls = gst_rtsp_connection_get_tls (state->conn, NULL); + tls = gst_rtsp_connection_get_tls (ctx->conn, NULL); g_tls_connection_set_certificate (tls, priv->certificate); } return TRUE; @@ -452,12 +449,12 @@ check_connect (GstRTSPAuth * auth, GstRTSPClientState * state, /* check url and methods */ static gboolean -check_url (GstRTSPAuth * auth, GstRTSPClientState * state, const gchar * check) +check_url (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check) { GstRTSPAuthPrivate *priv = auth->priv; - if ((state->method & priv->methods) != 0) - if (!ensure_authenticated (auth, state)) + if ((ctx->method & priv->methods) != 0) + if (!ensure_authenticated (auth, ctx)) goto not_authenticated; return TRUE; @@ -471,19 +468,18 @@ not_authenticated: /* check access to media factory */ static gboolean -check_factory (GstRTSPAuth * auth, GstRTSPClientState * state, - const gchar * check) +check_factory (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check) { const gchar *role; GstRTSPPermissions *perms; - if (!ensure_authenticated (auth, state)) + if (!ensure_authenticated (auth, ctx)) return FALSE; - if (!(role = gst_rtsp_token_get_string (state->token, + if (!(role = gst_rtsp_token_get_string (ctx->token, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE))) goto no_media_role; - if (!(perms = gst_rtsp_media_factory_get_permissions (state->factory))) + if (!(perms = gst_rtsp_media_factory_get_permissions (ctx->factory))) goto no_permissions; if (g_str_equal (check, GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS)) { @@ -501,55 +497,54 @@ check_factory (GstRTSPAuth * auth, GstRTSPClientState * state, no_media_role: { GST_DEBUG_OBJECT (auth, "no media factory role found"); - send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state); + send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx); return FALSE; } no_permissions: { GST_DEBUG_OBJECT (auth, "no permissions on media factory found"); - send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state); + send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx); return FALSE; } no_access: { GST_DEBUG_OBJECT (auth, "no permissions to access media factory"); - send_response (auth, GST_RTSP_STS_NOT_FOUND, state); + send_response (auth, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_construct: { GST_DEBUG_OBJECT (auth, "no permissions to construct media factory"); - send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state); + send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx); return FALSE; } } static gboolean -check_client_settings (GstRTSPAuth * auth, GstRTSPClientState * state, +check_client_settings (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check) { - if (!ensure_authenticated (auth, state)) + if (!ensure_authenticated (auth, ctx)) return FALSE; - return gst_rtsp_token_is_allowed (state->token, + return gst_rtsp_token_is_allowed (ctx->token, GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS); } static gboolean -default_check (GstRTSPAuth * auth, GstRTSPClientState * state, - const gchar * check) +default_check (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check) { gboolean res = FALSE; /* FIXME, use hastable or so */ if (g_str_equal (check, GST_RTSP_AUTH_CHECK_CONNECT)) { - res = check_connect (auth, state, check); + res = check_connect (auth, ctx, check); } else if (g_str_equal (check, GST_RTSP_AUTH_CHECK_URL)) { - res = check_url (auth, state, check); + res = check_url (auth, ctx, check); } else if (g_str_has_prefix (check, "auth.check.media.factory.")) { - res = check_factory (auth, state, check); + res = check_factory (auth, ctx, check); } else if (g_str_equal (check, GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS)) { - res = check_client_settings (auth, state, check); + res = check_client_settings (auth, ctx, check); } return res; } @@ -580,16 +575,16 @@ gst_rtsp_auth_check (const gchar * check) { gboolean result = FALSE; GstRTSPAuthClass *klass; - GstRTSPClientState *state; + GstRTSPContext *ctx; GstRTSPAuth *auth; g_return_val_if_fail (check != NULL, FALSE); - if (!(state = gst_rtsp_client_state_get_current ())) - goto no_state; + if (!(ctx = gst_rtsp_context_get_current ())) + goto no_context; /* no auth, we don't need to check */ - if (!(auth = state->auth)) + if (!(auth = ctx->auth)) return no_auth_check (check); klass = GST_RTSP_AUTH_GET_CLASS (auth); @@ -597,14 +592,14 @@ gst_rtsp_auth_check (const gchar * check) GST_DEBUG_OBJECT (auth, "check authorization '%s'", check); if (klass->check) - result = klass->check (auth, state, check); + result = klass->check (auth, ctx, check); return result; /* ERRORS */ -no_state: +no_context: { - GST_ERROR ("no clientstate found"); + GST_ERROR ("no context found"); return FALSE; } } diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index fd0da62d0d..c2dd971054 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -56,7 +56,7 @@ struct _GstRTSPAuth { * @authenticate: check the authentication of a client. The default implementation * checks if the authentication in the header matches one of the basic * authentication tokens. This function should set the authgroup field - * in the state. + * in the context. * @check: check if a resource can be accessed. this function should * call authenticate to authenticate the client when needed. The method * should also construct and send an appropriate response message on @@ -67,8 +67,8 @@ struct _GstRTSPAuth { struct _GstRTSPAuthClass { GObjectClass parent_class; - gboolean (*authenticate) (GstRTSPAuth *auth, GstRTSPClientState *state); - gboolean (*check) (GstRTSPAuth *auth, GstRTSPClientState *state, + gboolean (*authenticate) (GstRTSPAuth *auth, GstRTSPContext *ctx); + gboolean (*check) (GstRTSPAuth *auth, GstRTSPContext *ctx, const gchar *check); }; diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e67386a9fc..dcaffaa6d6 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -127,11 +127,11 @@ static void client_session_finalized (GstRTSPClient * client, static void unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, GstRTSPSessionMedia * sessmedia); static gboolean default_configure_client_transport (GstRTSPClient * client, - GstRTSPClientState * state, GstRTSPTransport * ct); + GstRTSPContext * ctx, GstRTSPTransport * ct); static GstRTSPResult default_params_set (GstRTSPClient * client, - GstRTSPClientState * state); + GstRTSPContext * ctx); static GstRTSPResult default_params_get (GstRTSPClient * client, - GstRTSPClientState * state); + GstRTSPContext * ctx); G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); @@ -444,12 +444,12 @@ send_message (GstRTSPClient * client, GstRTSPSession * session, static void send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, - GstRTSPClientState * state) + GstRTSPContext * ctx) { - gst_rtsp_message_init_response (state->response, code, - gst_rtsp_status_as_text (code), state->request); + gst_rtsp_message_init_response (ctx->response, code, + gst_rtsp_status_as_text (code), ctx->request); - send_message (client, NULL, state->response, FALSE); + send_message (client, NULL, ctx->response, FALSE); } static gboolean @@ -471,7 +471,7 @@ paths_are_equal (const gchar * path1, const gchar * path2, gint len2) * but is cached for when the same client (without breaking the connection) is * doing a setup for the exact same url. */ static GstRTSPMedia * -find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) +find_media (GstRTSPClient * client, GstRTSPContext * ctx, gint * matched) { GstRTSPClientPrivate *priv = client->priv; GstRTSPMediaFactory *factory; @@ -482,14 +482,14 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) if (!priv->mount_points) goto no_mount_points; - path = state->uri->abspath; + path = ctx->uri->abspath; /* find the longest matching factory for the uri first */ if (!(factory = gst_rtsp_mount_points_match (priv->mount_points, path, matched))) goto no_factory; - state->factory = factory; + ctx->factory = factory; if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS)) goto no_factory_access; @@ -517,13 +517,13 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) priv->media = NULL; /* prepare the media and add it to the pipeline */ - if (!(media = gst_rtsp_media_factory_construct (factory, state->uri))) + if (!(media = gst_rtsp_media_factory_construct (factory, ctx->uri))) goto no_media; - state->media = media; + ctx->media = media; thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool, - GST_RTSP_THREAD_TYPE_MEDIA, state); + GST_RTSP_THREAD_TYPE_MEDIA, ctx); if (thread == NULL) goto no_thread; @@ -537,12 +537,12 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) } else { /* we have seen this path before, used cached media */ media = priv->media; - state->media = media; + ctx->media = media; GST_INFO ("reusing cached media %p for path %s", media, priv->path); } g_object_unref (factory); - state->factory = NULL; + ctx->factory = NULL; if (media) g_object_ref (media); @@ -553,13 +553,13 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state, gint * matched) no_mount_points: { GST_ERROR ("client %p: no mount points configured", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return NULL; } no_factory: { GST_ERROR ("client %p: no factory for uri %s", client, path); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return NULL; } no_factory_access: @@ -575,29 +575,29 @@ not_authorized: no_media: { GST_ERROR ("client %p: can't create media", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (factory); - state->factory = NULL; + ctx->factory = NULL; return NULL; } no_thread: { GST_ERROR ("client %p: can't create thread", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (media); - state->media = NULL; + ctx->media = NULL; g_object_unref (factory); - state->factory = NULL; + ctx->factory = NULL; return NULL; } no_prepare: { GST_ERROR ("client %p: can't prepare media", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (media); - state->media = NULL; + ctx->media = NULL; g_object_unref (factory); - state->factory = NULL; + ctx->factory = NULL; return NULL; } } @@ -711,7 +711,7 @@ close_connection (GstRTSPClient * client) } static gboolean -handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) +handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPClientPrivate *priv = client->priv; GstRTSPSession *session; @@ -720,15 +720,15 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) const gchar *path; gint matched; - if (!state->session) + if (!ctx->session) goto no_session; - session = state->session; + session = ctx->session; - if (!state->uri) + if (!ctx->uri) goto no_uri; - path = state->uri->abspath; + path = ctx->uri->abspath; /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -739,11 +739,11 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) if (path[matched] != '\0') goto no_aggregate; - state->sessmedia = sessmedia; + ctx->sessmedia = sessmedia; /* we emit the signal before closing the connection */ g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], - 0, state); + 0, ctx); /* unlink the all TCP callbacks */ unlink_session_transports (client, session, sessmedia); @@ -761,10 +761,10 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) } /* construct the response now */ code = GST_RTSP_STS_OK; - gst_rtsp_message_init_response (state->response, code, - gst_rtsp_status_as_text (code), state->request); + gst_rtsp_message_init_response (ctx->response, code, + gst_rtsp_status_as_text (code), ctx->request); - send_message (client, session, state->response, TRUE); + send_message (client, session, ctx->response, TRUE); return TRUE; @@ -772,75 +772,75 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state) no_session: { GST_ERROR ("client %p: no session", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); return FALSE; } no_uri: { GST_ERROR ("client %p: no uri supplied", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } not_found: { GST_ERROR ("client %p: no media for uri", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); send_generic_response (client, - GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, state); + GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); return FALSE; } } static GstRTSPResult -default_params_set (GstRTSPClient * client, GstRTSPClientState * state) +default_params_set (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPResult res; - res = gst_rtsp_params_set (client, state); + res = gst_rtsp_params_set (client, ctx); return res; } static GstRTSPResult -default_params_get (GstRTSPClient * client, GstRTSPClientState * state) +default_params_get (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPResult res; - res = gst_rtsp_params_get (client, state); + res = gst_rtsp_params_get (client, ctx); return res; } static gboolean -handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state) +handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPResult res; guint8 *data; guint size; - res = gst_rtsp_message_get_body (state->request, &data, &size); + res = gst_rtsp_message_get_body (ctx->request, &data, &size); if (res != GST_RTSP_OK) goto bad_request; if (size == 0) { /* no body, keep-alive request */ - send_generic_response (client, GST_RTSP_STS_OK, state); + send_generic_response (client, GST_RTSP_STS_OK, ctx); } else { /* there is a body, handle the params */ - res = GST_RTSP_CLIENT_GET_CLASS (client)->params_get (client, state); + res = GST_RTSP_CLIENT_GET_CLASS (client)->params_get (client, ctx); if (res != GST_RTSP_OK) goto bad_request; - send_message (client, state->session, state->response, FALSE); + send_message (client, ctx->session, ctx->response, FALSE); } g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST], - 0, state); + 0, ctx); return TRUE; @@ -848,36 +848,36 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state) bad_request: { GST_ERROR ("client %p: bad request", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } } static gboolean -handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state) +handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPResult res; guint8 *data; guint size; - res = gst_rtsp_message_get_body (state->request, &data, &size); + res = gst_rtsp_message_get_body (ctx->request, &data, &size); if (res != GST_RTSP_OK) goto bad_request; if (size == 0) { /* no body, keep-alive request */ - send_generic_response (client, GST_RTSP_STS_OK, state); + send_generic_response (client, GST_RTSP_STS_OK, ctx); } else { /* there is a body, handle the params */ - res = GST_RTSP_CLIENT_GET_CLASS (client)->params_set (client, state); + res = GST_RTSP_CLIENT_GET_CLASS (client)->params_set (client, ctx); if (res != GST_RTSP_OK) goto bad_request; - send_message (client, state->session, state->response, FALSE); + send_message (client, ctx->session, ctx->response, FALSE); } g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST], - 0, state); + 0, ctx); return TRUE; @@ -885,13 +885,13 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state) bad_request: { GST_ERROR ("client %p: bad request", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } } static gboolean -handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) +handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; @@ -900,13 +900,13 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) const gchar *path; gint matched; - if (!(session = state->session)) + if (!(session = ctx->session)) goto no_session; - if (!state->uri) + if (!ctx->uri) goto no_uri; - path = state->uri->abspath; + path = ctx->uri->abspath; /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -916,7 +916,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) if (path[matched] != '\0') goto no_aggregate; - state->sessmedia = sessmedia; + ctx->sessmedia = sessmedia; rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); /* the session state must be playing or recording */ @@ -932,16 +932,15 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) /* construct the response now */ code = GST_RTSP_STS_OK; - gst_rtsp_message_init_response (state->response, code, - gst_rtsp_status_as_text (code), state->request); + gst_rtsp_message_init_response (ctx->response, code, + gst_rtsp_status_as_text (code), ctx->request); - send_message (client, session, state->response, FALSE); + send_message (client, session, ctx->response, FALSE); /* the state is now READY */ gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY); - g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST], - 0, state); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST], 0, ctx); return TRUE; @@ -949,39 +948,39 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state) no_session: { GST_ERROR ("client %p: no seesion", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); return FALSE; } no_uri: { GST_ERROR ("client %p: no uri supplied", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } not_found: { GST_ERROR ("client %p: no media for uri", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); send_generic_response (client, - GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, state); + GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); return FALSE; } invalid_state: { GST_ERROR ("client %p: not PLAYING or RECORDING", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, - state); + ctx); return FALSE; } } static gboolean -handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) +handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; @@ -997,13 +996,13 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) const gchar *path; gint matched; - if (!(session = state->session)) + if (!(session = ctx->session)) goto no_session; - if (!state->uri) + if (!ctx->uri) goto no_uri; - path = state->uri->abspath; + path = ctx->uri->abspath; /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -1013,8 +1012,8 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) if (path[matched] != '\0') goto no_aggregate; - state->sessmedia = sessmedia; - state->media = media = gst_rtsp_session_media_get_media (sessmedia); + ctx->sessmedia = sessmedia; + ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); /* the session state must be playing or ready */ rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); @@ -1022,8 +1021,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) goto invalid_state; /* parse the range header if we have one */ - res = - gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_RANGE, &str, 0); + res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0); if (res == GST_RTSP_OK) { if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) { /* we have a range, seek to the position */ @@ -1062,7 +1060,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) if (infocount > 0) g_string_append (rtpinfo, ", "); - uristr = gst_rtsp_url_get_request_uri (state->uri); + uristr = gst_rtsp_url_get_request_uri (ctx->uri); g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", uristr, i, seq, rtptime); g_free (uristr); @@ -1075,30 +1073,29 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) /* construct the response now */ code = GST_RTSP_STS_OK; - gst_rtsp_message_init_response (state->response, code, - gst_rtsp_status_as_text (code), state->request); + gst_rtsp_message_init_response (ctx->response, code, + gst_rtsp_status_as_text (code), ctx->request); /* add the RTP-Info header */ if (infocount > 0) { str = g_string_free (rtpinfo, FALSE); - gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RTP_INFO, str); + gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO, str); } else { g_string_free (rtpinfo, TRUE); } /* add the range */ str = gst_rtsp_media_get_range_string (media, TRUE, unit); - gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str); + gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RANGE, str); - send_message (client, session, state->response, FALSE); + send_message (client, session, ctx->response, FALSE); /* start playing after sending the request */ gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING); gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING); - g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST], - 0, state); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST], 0, ctx); return TRUE; @@ -1106,33 +1103,33 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state) no_session: { GST_ERROR ("client %p: no session", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); return FALSE; } no_uri: { GST_ERROR ("client %p: no uri supplied", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } not_found: { GST_ERROR ("client %p: media not found", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); send_generic_response (client, - GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, state); + GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); return FALSE; } invalid_state: { GST_ERROR ("client %p: not PLAYING or READY", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, - state); + ctx); return FALSE; } } @@ -1227,7 +1224,7 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPStream * stream, static gboolean default_configure_client_transport (GstRTSPClient * client, - GstRTSPClientState * state, GstRTSPTransport * ct) + GstRTSPContext * ctx, GstRTSPTransport * ct) { GstRTSPClientPrivate *priv = client->priv; @@ -1241,7 +1238,7 @@ default_configure_client_transport (GstRTSPClient * client, if (ct->destination && use_client_settings) { GstRTSPAddress *addr; - addr = gst_rtsp_stream_reserve_address (state->stream, ct->destination, + addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination, ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl); if (addr == NULL) @@ -1254,7 +1251,7 @@ default_configure_client_transport (GstRTSPClient * client, family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; - addr = gst_rtsp_stream_get_multicast_address (state->stream, family); + addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family); if (addr == NULL) goto no_address; @@ -1276,7 +1273,7 @@ default_configure_client_transport (GstRTSPClient * client, if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) { /* check if the client selected channels for TCP */ if (ct->interleaved.min == -1 || ct->interleaved.max == -1) { - gst_rtsp_session_media_alloc_channels (state->sessmedia, + gst_rtsp_session_media_alloc_channels (ctx->sessmedia, &ct->interleaved); } } @@ -1292,7 +1289,7 @@ no_address: } static GstRTSPTransport * -make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, +make_server_transport (GstRTSPClient * client, GstRTSPContext * ctx, GstRTSPTransport * ct) { GstRTSPTransport *st; @@ -1320,7 +1317,7 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, switch (st->lower_transport) { case GST_RTSP_LOWER_TRANS_UDP: st->client_port = ct->client_port; - gst_rtsp_stream_get_server_port (state->stream, &st->server_port, family); + gst_rtsp_stream_get_server_port (ctx->stream, &st->server_port, family); break; case GST_RTSP_LOWER_TRANS_UDP_MCAST: st->port = ct->port; @@ -1333,13 +1330,13 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state, break; } - gst_rtsp_stream_get_ssrc (state->stream, &st->ssrc); + gst_rtsp_stream_get_ssrc (ctx->stream, &st->ssrc); return st; } static gboolean -handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) +handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPClientPrivate *priv = client->priv; GstRTSPResult res; @@ -1359,15 +1356,15 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) gchar *path, *control; gint matched; - if (!state->uri) + if (!ctx->uri) goto no_uri; - uri = state->uri; + uri = ctx->uri; path = uri->abspath; /* parse the transport */ res = - gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_TRANSPORT, + gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_TRANSPORT, &transport, 0); if (res != GST_RTSP_OK) goto no_transport; @@ -1377,7 +1374,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) if (priv->session_pool == NULL) goto no_pool; - session = state->session; + session = ctx->session; if (session) { g_object_ref (session); @@ -1392,7 +1389,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) /* we have no session media, find one and manage it */ if (sessmedia == NULL) { /* get a handle to the configuration of the media in the session */ - media = find_media (client, state, &matched); + media = find_media (client, ctx, &matched); } else { if ((media = gst_rtsp_session_media_get_media (sessmedia))) g_object_ref (media); @@ -1412,8 +1409,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) goto stream_not_found; /* now we have a uri identifying a valid media and stream */ - state->stream = stream; - state->media = media; + ctx->stream = stream; + ctx->media = media; if (session == NULL) { /* create a session if this fails we probably reached our session limit or @@ -1428,7 +1425,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0, session); - state->session = session; + ctx->session = session; } if (sessmedia == NULL) { @@ -1441,10 +1438,10 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) g_object_unref (media); } - state->sessmedia = sessmedia; + ctx->sessmedia = sessmedia; /* set blocksize on this stream */ - if (!handle_blocksize (media, stream, state->request)) + if (!handle_blocksize (media, stream, ctx->request)) goto invalid_blocksize; gst_rtsp_transport_new (&ct); @@ -1459,7 +1456,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) /* update the client transport */ klass = GST_RTSP_CLIENT_GET_CLASS (client); - if (!klass->configure_client_transport (client, state, ct)) + if (!klass->configure_client_transport (client, ctx, ct)) goto unsupported_client_transport; /* set in the session media transport */ @@ -1470,20 +1467,20 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) (GstRTSPKeepAliveFunc) do_keepalive, session, NULL); /* create and serialize the server transport */ - st = make_server_transport (client, state, ct); + st = make_server_transport (client, ctx, ct); trans_str = gst_rtsp_transport_as_text (st); gst_rtsp_transport_free (st); /* construct the response now */ code = GST_RTSP_STS_OK; - gst_rtsp_message_init_response (state->response, code, - gst_rtsp_status_as_text (code), state->request); + gst_rtsp_message_init_response (ctx->response, code, + gst_rtsp_status_as_text (code), ctx->request); - gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_TRANSPORT, + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_TRANSPORT, trans_str); g_free (trans_str); - send_message (client, session, state->response, FALSE); + send_message (client, session, ctx->response, FALSE); /* update the state */ rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); @@ -1499,8 +1496,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) } g_object_unref (session); - g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], - 0, state); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], 0, ctx); return TRUE; @@ -1508,45 +1504,45 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state) no_uri: { GST_ERROR ("client %p: no uri", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } no_transport: { GST_ERROR ("client %p: no transport", client); - send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); + send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); return FALSE; } no_pool: { GST_ERROR ("client %p: no session pool configured", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); return FALSE; } media_not_found: { GST_ERROR ("client %p: media '%s' not found", client, path); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } stream_not_found: { GST_ERROR ("client %p: stream '%s' not found", client, control); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); g_object_unref (media); return FALSE; } service_unavailable: { GST_ERROR ("client %p: can't create session", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (media); return FALSE; } sessmedia_unavailable: { GST_ERROR ("client %p: can't create session media", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (media); g_object_unref (session); return FALSE; @@ -1554,14 +1550,14 @@ sessmedia_unavailable: invalid_blocksize: { GST_ERROR ("client %p: invalid blocksize", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); g_object_unref (session); return FALSE; } unsupported_transports: { GST_ERROR ("client %p: unsupported transports", client); - send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); + send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); gst_rtsp_transport_free (ct); g_object_unref (session); return FALSE; @@ -1569,7 +1565,7 @@ unsupported_transports: unsupported_client_transport: { GST_ERROR ("client %p: unsupported client transport", client); - send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state); + send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); gst_rtsp_transport_free (ct); g_object_unref (session); return FALSE; @@ -1624,7 +1620,7 @@ no_sdp: /* for the describe we must generate an SDP */ static gboolean -handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) +handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPResult res; GstSDPMessage *sdp; @@ -1635,7 +1631,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) klass = GST_RTSP_CLIENT_GET_CLASS (client); - if (!state->uri) + if (!ctx->uri) goto no_uri; /* check what kind of format is accepted, we don't really do anything with it @@ -1644,7 +1640,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) gchar *accept; res = - gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_ACCEPT, + gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_ACCEPT, &accept, i); if (res == GST_RTSP_ENOTIMPL) break; @@ -1654,7 +1650,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) } /* find the media object for the uri */ - if (!(media = find_media (client, state, NULL))) + if (!(media = find_media (client, ctx, NULL))) goto no_media; /* create an SDP for the media object on this client */ @@ -1663,14 +1659,14 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) g_object_unref (media); - gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK, - gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request); + gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK, + gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request); - gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_TYPE, + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_CONTENT_TYPE, "application/sdp"); /* content base for some clients that might screw up creating the setup uri */ - str = gst_rtsp_url_get_request_uri (state->uri); + str = gst_rtsp_url_get_request_uri (ctx->uri); str_len = strlen (str); /* check for trailing '/' and append one */ @@ -1686,19 +1682,19 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) GST_INFO ("adding content-base: %s", content_base); - gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_BASE, + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_CONTENT_BASE, content_base); g_free (content_base); /* add SDP to the response body */ str = gst_sdp_message_as_text (sdp); - gst_rtsp_message_take_body (state->response, (guint8 *) str, strlen (str)); + gst_rtsp_message_take_body (ctx->response, (guint8 *) str, strlen (str)); gst_sdp_message_free (sdp); - send_message (client, state->session, state->response, FALSE); + send_message (client, ctx->session, ctx->response, FALSE); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST], - 0, state); + 0, ctx); return TRUE; @@ -1706,7 +1702,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state) no_uri: { GST_ERROR ("client %p: no uri", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } no_media: @@ -1718,14 +1714,14 @@ no_media: no_sdp: { GST_ERROR ("client %p: can't create SDP", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (media); return FALSE; } } static gboolean -handle_options_request (GstRTSPClient * client, GstRTSPClientState * state) +handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPMethod options; gchar *str; @@ -1739,16 +1735,16 @@ handle_options_request (GstRTSPClient * client, GstRTSPClientState * state) str = gst_rtsp_options_as_text (options); - gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK, - gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request); + gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK, + gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request); - gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_PUBLIC, str); + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PUBLIC, str); g_free (str); - send_message (client, state->session, state->response, FALSE); + send_message (client, ctx->session, ctx->response, FALSE); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST], - 0, state); + 0, ctx); return TRUE; } @@ -1798,69 +1794,6 @@ client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) } } -static GPrivate current_state; - -/** - * gst_rtsp_client_state_get_current: - * - * Get the current #GstRTSPClientState. This object is retrieved from the - * current thread that is handling the request for a client. - * - * Returns: a #GstRTSPClientState - */ -GstRTSPClientState * -gst_rtsp_client_state_get_current (void) -{ - GSList *l; - - l = g_private_get (¤t_state); - if (l == NULL) - return NULL; - - return (GstRTSPClientState *) (l->data); - -} - -/** - * gst_rtsp_client_state_push_current: - * @state: a ##GstRTSPClientState - * - * Pushes @state onto the state stack. The current - * state can then be received using gst_rtsp_client_state_get_current(). - **/ -void -gst_rtsp_client_state_push_current (GstRTSPClientState * state) -{ - GSList *l; - - g_return_if_fail (state != NULL); - - l = g_private_get (¤t_state); - l = g_slist_prepend (l, state); - g_private_set (¤t_state, l); -} - -/** - * gst_rtsp_client_state_pop_current: - * @state: a #GstRTSPClientState - * - * Pops @state off the state stack (verifying that @state - * is on the top of the stack). - **/ -void -gst_rtsp_client_state_pop_current (GstRTSPClientState * state) -{ - GSList *l; - - l = g_private_get (¤t_state); - - g_return_if_fail (l != NULL); - g_return_if_fail (l->data == state); - - l = g_slist_delete_link (l, l); - g_private_set (¤t_state, l); -} - static void handle_request (GstRTSPClient * client, GstRTSPMessage * request) { @@ -1871,20 +1804,20 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) GstRTSPVersion version; GstRTSPResult res; GstRTSPSession *session = NULL; - GstRTSPClientState sstate = { NULL }, *state; + GstRTSPContext sctx = { NULL }, *ctx; GstRTSPMessage response = { 0 }; gchar *sessid; - if (!(state = gst_rtsp_client_state_get_current ())) { - state = &sstate; - state->auth = priv->auth; - gst_rtsp_client_state_push_current (state); + if (!(ctx = gst_rtsp_context_get_current ())) { + ctx = &sctx; + ctx->auth = priv->auth; + gst_rtsp_context_push_current (ctx); } - state->conn = priv->connection; - state->client = client; - state->request = request; - state->response = &response; + ctx->conn = priv->connection; + ctx->client = client; + ctx->request = request; + ctx->response = &response; if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) { gst_rtsp_message_dump (request); @@ -1898,7 +1831,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) if (version != GST_RTSP_VERSION_1_0) goto not_supported; - state->method = method; + ctx->method = method; /* we always try to parse the url first */ if (strcmp (uristr, "*") == 0) { @@ -1925,8 +1858,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) /* sanitize the uri */ if (uri) sanitize_uri (uri); - state->uri = uri; - state->session = session; + ctx->uri = uri; + ctx->session = session; if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_URL)) goto not_authorized; @@ -1934,28 +1867,28 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: - handle_options_request (client, state); + handle_options_request (client, ctx); break; case GST_RTSP_DESCRIBE: - handle_describe_request (client, state); + handle_describe_request (client, ctx); break; case GST_RTSP_SETUP: - handle_setup_request (client, state); + handle_setup_request (client, ctx); break; case GST_RTSP_PLAY: - handle_play_request (client, state); + handle_play_request (client, ctx); break; case GST_RTSP_PAUSE: - handle_pause_request (client, state); + handle_pause_request (client, ctx); break; case GST_RTSP_TEARDOWN: - handle_teardown_request (client, state); + handle_teardown_request (client, ctx); break; case GST_RTSP_SET_PARAMETER: - handle_set_param_request (client, state); + handle_set_param_request (client, ctx); break; case GST_RTSP_GET_PARAMETER: - handle_get_param_request (client, state); + handle_get_param_request (client, ctx); break; case GST_RTSP_ANNOUNCE: case GST_RTSP_RECORD: @@ -1967,8 +1900,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) } done: - if (state == &sstate) - gst_rtsp_client_state_pop_current (state); + if (ctx == &sctx) + gst_rtsp_context_pop_current (ctx); if (session) g_object_unref (session); if (uri) @@ -1980,25 +1913,25 @@ not_supported: { GST_ERROR ("client %p: version %d not supported", client, version); send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, - state); + ctx); goto done; } bad_request: { GST_ERROR ("client %p: bad request", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); goto done; } no_pool: { GST_ERROR ("client %p: no pool configured", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); goto done; } session_not_found: { GST_ERROR ("client %p: session not found", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); goto done; } not_authorized: @@ -2009,7 +1942,7 @@ not_authorized: not_implemented: { GST_ERROR ("client %p: method %d not implemented", client, method); - send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, state); + send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx); goto done; } } diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 5ea6071450..72c51875a0 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -27,18 +27,12 @@ G_BEGIN_DECLS typedef struct _GstRTSPClient GstRTSPClient; typedef struct _GstRTSPClientClass GstRTSPClientClass; -typedef struct _GstRTSPClientState GstRTSPClientState; typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; -#include "rtsp-server.h" -#include "rtsp-media.h" +#include "rtsp-context.h" #include "rtsp-mount-points.h" -#include "rtsp-session-pool.h" -#include "rtsp-session-media.h" -#include "rtsp-auth.h" -#include "rtsp-thread-pool.h" -#include "rtsp-token.h" #include "rtsp-sdp.h" +#include "rtsp-auth.h" #define GST_TYPE_RTSP_CLIENT (gst_rtsp_client_get_type ()) #define GST_IS_RTSP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_CLIENT)) @@ -49,47 +43,6 @@ typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; #define GST_RTSP_CLIENT_CAST(obj) ((GstRTSPClient*)(obj)) #define GST_RTSP_CLIENT_CLASS_CAST(klass) ((GstRTSPClientClass*)(klass)) -/** - * GstRTSPClientState: - * @server: the server - * @conn: the connection - * @client: the client - * @request: the complete request - * @uri: the complete url parsed from @request - * @method: the parsed method of @uri - * @auth: the current auth object or NULL - * @token: authorisation token - * @session: the session, can be NULL - * @sessmedia: the session media for the url can be NULL - * @factory: the media factory for the url, can be NULL. - * @media: the media for the url can be NULL - * @stream: the stream for the url can be NULL - * @response: the response - * - * Information passed around containing the client state of a request. - */ -struct _GstRTSPClientState { - GstRTSPServer *server; - GstRTSPConnection *conn; - GstRTSPClient *client; - GstRTSPMessage *request; - GstRTSPUrl *uri; - GstRTSPMethod method; - GstRTSPAuth *auth; - GstRTSPToken *token; - GstRTSPSession *session; - GstRTSPSessionMedia *sessmedia; - GstRTSPMediaFactory *factory; - GstRTSPMedia *media; - GstRTSPStream *stream; - GstRTSPMessage *response; -}; - -GstRTSPClientState * gst_rtsp_client_state_get_current (void); -void gst_rtsp_client_state_push_current (GstRTSPClientState * state); -void gst_rtsp_client_state_pop_current (GstRTSPClientState * state); - - /** * GstRTSPClientSendFunc: * @client: a #GstRTSPClient @@ -124,9 +77,9 @@ struct _GstRTSPClient { * @configure_client_transport: called when the client transport needs to be * configured. * @params_set: set parameters. This function should also initialize the - * RTSP response(state->response) via a call to gst_rtsp_message_init_response() + * RTSP response(ctx->response) via a call to gst_rtsp_message_init_response() * @params_get: get parameters. This function should also initialize the - * RTSP response(state->response) via a call to gst_rtsp_message_init_response() + * RTSP response(ctx->response) via a call to gst_rtsp_message_init_response() * * The client class structure. */ @@ -135,22 +88,22 @@ struct _GstRTSPClientClass { GstSDPMessage * (*create_sdp) (GstRTSPClient *client, GstRTSPMedia *media); gboolean (*configure_client_transport) (GstRTSPClient * client, - GstRTSPClientState * state, + GstRTSPContext * ctx, GstRTSPTransport * ct); - GstRTSPResult (*params_set) (GstRTSPClient *client, GstRTSPClientState *state); - GstRTSPResult (*params_get) (GstRTSPClient *client, GstRTSPClientState *state); + GstRTSPResult (*params_set) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPResult (*params_get) (GstRTSPClient *client, GstRTSPContext *ctx); /* signals */ void (*closed) (GstRTSPClient *client); void (*new_session) (GstRTSPClient *client, GstRTSPSession *session); - void (*options_request) (GstRTSPClient *client, GstRTSPClientState *state); - void (*describe_request) (GstRTSPClient *client, GstRTSPClientState *state); - void (*setup_request) (GstRTSPClient *client, GstRTSPClientState *state); - void (*play_request) (GstRTSPClient *client, GstRTSPClientState *state); - void (*pause_request) (GstRTSPClient *client, GstRTSPClientState *state); - void (*teardown_request) (GstRTSPClient *client, GstRTSPClientState *state); - void (*set_parameter_request) (GstRTSPClient *client, GstRTSPClientState *state); - void (*get_parameter_request) (GstRTSPClient *client, GstRTSPClientState *state); + void (*options_request) (GstRTSPClient *client, GstRTSPContext *ctx); + void (*describe_request) (GstRTSPClient *client, GstRTSPContext *ctx); + void (*setup_request) (GstRTSPClient *client, GstRTSPContext *ctx); + void (*play_request) (GstRTSPClient *client, GstRTSPContext *ctx); + void (*pause_request) (GstRTSPClient *client, GstRTSPContext *ctx); + void (*teardown_request) (GstRTSPClient *client, GstRTSPContext *ctx); + void (*set_parameter_request) (GstRTSPClient *client, GstRTSPContext *ctx); + void (*get_parameter_request) (GstRTSPClient *client, GstRTSPContext *ctx); }; GType gst_rtsp_client_get_type (void); diff --git a/gst/rtsp-server/rtsp-context.c b/gst/rtsp-server/rtsp-context.c new file mode 100644 index 0000000000..3b8c0a10ad --- /dev/null +++ b/gst/rtsp-server/rtsp-context.c @@ -0,0 +1,90 @@ +/* GStreamer + * Copyright (C) 2013 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/** + * SECTION:rtsp-context + * @short_description: A client request context + * @see_also: #GstRTSPServer, #GstRTSPClient + * + * Last reviewed on 2013-07-11 (1.0.0) + */ + +#include "rtsp-context.h" + +static GPrivate current_context; + +/** + * gst_rtsp_context_get_current: + * + * Get the current #GstRTSPContext. This object is retrieved from the + * current thread that is handling the request for a client. + * + * Returns: a #GstRTSPContext + */ +GstRTSPContext * +gst_rtsp_context_get_current (void) +{ + GSList *l; + + l = g_private_get (¤t_context); + if (l == NULL) + return NULL; + + return (GstRTSPContext *) (l->data); + +} + +/** + * gst_rtsp_context_push_current: + * @ctx: a ##GstRTSPContext + * + * Pushes @ctx onto the context stack. The current + * context can then be received using gst_rtsp_context_get_current(). + **/ +void +gst_rtsp_context_push_current (GstRTSPContext * ctx) +{ + GSList *l; + + g_return_if_fail (ctx != NULL); + + l = g_private_get (¤t_context); + l = g_slist_prepend (l, ctx); + g_private_set (¤t_context, l); +} + +/** + * gst_rtsp_context_pop_current: + * @ctx: a #GstRTSPContext + * + * Pops @ctx off the context stack (verifying that @ctx + * is on the top of the stack). + **/ +void +gst_rtsp_context_pop_current (GstRTSPContext * ctx) +{ + GSList *l; + + l = g_private_get (¤t_context); + + g_return_if_fail (l != NULL); + g_return_if_fail (l->data == ctx); + + l = g_slist_delete_link (l, l); + g_private_set (¤t_context, l); +} diff --git a/gst/rtsp-server/rtsp-context.h b/gst/rtsp-server/rtsp-context.h new file mode 100644 index 0000000000..60ff030f67 --- /dev/null +++ b/gst/rtsp-server/rtsp-context.h @@ -0,0 +1,81 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#ifndef __GST_RTSP_CONTEXT_H__ +#define __GST_RTSP_CONTEXT_H__ + +G_BEGIN_DECLS + +typedef struct _GstRTSPContext GstRTSPContext; + +#include "rtsp-server.h" +#include "rtsp-media.h" +#include "rtsp-media-factory.h" +#include "rtsp-session-media.h" +#include "rtsp-auth.h" +#include "rtsp-thread-pool.h" +#include "rtsp-token.h" + +/** + * GstRTSPContext: + * @server: the server + * @conn: the connection + * @client: the client + * @request: the complete request + * @uri: the complete url parsed from @request + * @method: the parsed method of @uri + * @auth: the current auth object or NULL + * @token: authorisation token + * @session: the session, can be NULL + * @sessmedia: the session media for the url can be NULL + * @factory: the media factory for the url, can be NULL. + * @media: the media for the url can be NULL + * @stream: the stream for the url can be NULL + * @response: the response + * + * Information passed around containing the context of a request. + */ +struct _GstRTSPContext { + GstRTSPServer *server; + GstRTSPConnection *conn; + GstRTSPClient *client; + GstRTSPMessage *request; + GstRTSPUrl *uri; + GstRTSPMethod method; + GstRTSPAuth *auth; + GstRTSPToken *token; + GstRTSPSession *session; + GstRTSPSessionMedia *sessmedia; + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPStream *stream; + GstRTSPMessage *response; +}; + +GstRTSPContext * gst_rtsp_context_get_current (void); +void gst_rtsp_context_push_current (GstRTSPContext * ctx); +void gst_rtsp_context_pop_current (GstRTSPContext * ctx); + + +G_END_DECLS + +#endif /* __GST_RTSP_CONTEXT_H__ */ diff --git a/gst/rtsp-server/rtsp-params.c b/gst/rtsp-server/rtsp-params.c index d1f9b698c1..ce18eaa11d 100644 --- a/gst/rtsp-server/rtsp-params.c +++ b/gst/rtsp-server/rtsp-params.c @@ -31,14 +31,14 @@ /** * gst_rtsp_params_set: * @client: a #GstRTSPClient - * @state: a #GstRTSPClientState + * @ctx: a #GstRTSPContext * * Set parameters (not implemented yet) * * Returns: a #GstRTSPResult */ GstRTSPResult -gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state) +gst_rtsp_params_set (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPStatusCode code; @@ -46,8 +46,8 @@ gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state) * with a list of the parameters */ code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD; - gst_rtsp_message_init_response (state->response, code, - gst_rtsp_status_as_text (code), state->request); + gst_rtsp_message_init_response (ctx->response, code, + gst_rtsp_status_as_text (code), ctx->request); return GST_RTSP_OK; } @@ -55,14 +55,14 @@ gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state) /** * gst_rtsp_params_get: * @client: a #GstRTSPClient - * @state: a #GstRTSPClientState + * @ctx: a #GstRTSPContext * * Get parameters (not implemented yet) * * Returns: a #GstRTSPResult */ GstRTSPResult -gst_rtsp_params_get (GstRTSPClient * client, GstRTSPClientState * state) +gst_rtsp_params_get (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPStatusCode code; @@ -70,8 +70,8 @@ gst_rtsp_params_get (GstRTSPClient * client, GstRTSPClientState * state) * with a list of the parameters */ code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD; - gst_rtsp_message_init_response (state->response, code, - gst_rtsp_status_as_text (code), state->request); + gst_rtsp_message_init_response (ctx->response, code, + gst_rtsp_status_as_text (code), ctx->request); return GST_RTSP_OK; } diff --git a/gst/rtsp-server/rtsp-params.h b/gst/rtsp-server/rtsp-params.h index 93fb95991b..563757dde9 100644 --- a/gst/rtsp-server/rtsp-params.h +++ b/gst/rtsp-server/rtsp-params.h @@ -30,8 +30,8 @@ G_BEGIN_DECLS -GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state); -GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPClientState * state); +GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPContext * ctx); +GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPContext * ctx); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index cd6161448e..538a2d2d1a 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -991,26 +991,26 @@ unmanage_client (GstRTSPClient * client, ClientContext * ctx) static void manage_client (GstRTSPServer * server, GstRTSPClient * client) { - ClientContext *ctx; + ClientContext *cctx; GstRTSPServerPrivate *priv = server->priv; GMainContext *mainctx = NULL; - GstRTSPClientState state = { NULL }; + GstRTSPContext ctx = { NULL }; GST_DEBUG_OBJECT (server, "manage client %p", client); - ctx = g_slice_new0 (ClientContext); - ctx->server = g_object_ref (server); - ctx->client = client; + cctx = g_slice_new0 (ClientContext); + cctx->server = g_object_ref (server); + cctx->client = client; GST_RTSP_SERVER_LOCK (server); - state.server = server; - state.client = client; + ctx.server = server; + ctx.client = client; - ctx->thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool, - GST_RTSP_THREAD_TYPE_CLIENT, &state); - if (ctx->thread) - mainctx = ctx->thread->context; + cctx->thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool, + GST_RTSP_THREAD_TYPE_CLIENT, &ctx); + if (cctx->thread) + mainctx = cctx->thread->context; else { GSource *source; /* find the context to add the watch */ @@ -1018,8 +1018,8 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) mainctx = g_source_get_context (source); } - g_signal_connect (client, "closed", (GCallback) unmanage_client, ctx); - priv->clients = g_list_prepend (priv->clients, ctx); + g_signal_connect (client, "closed", (GCallback) unmanage_client, cctx); + priv->clients = g_list_prepend (priv->clients, cctx); gst_rtsp_client_attach (client, mainctx); @@ -1129,17 +1129,17 @@ gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, GstRTSPServerClass *klass; GstRTSPResult res; GstRTSPConnection *conn = NULL; - GstRTSPClientState state = { NULL }; + GstRTSPContext ctx = { NULL }; if (condition & G_IO_IN) { /* a new client connected. */ GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, NULL), accept_failed); - state.server = server; - state.conn = conn; - state.auth = priv->auth; - gst_rtsp_client_state_push_current (&state); + ctx.server = server; + ctx.conn = conn; + ctx.auth = priv->auth; + gst_rtsp_context_push_current (&ctx); if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_CONNECT)) goto connection_refused; @@ -1163,7 +1163,7 @@ gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, GST_WARNING_OBJECT (server, "received unknown event %08x", condition); } exit: - gst_rtsp_client_state_pop_current (&state); + gst_rtsp_context_pop_current (&ctx); return G_SOURCE_CONTINUE; diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index b29f20eb86..87a035f494 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -197,7 +197,7 @@ static void gst_rtsp_thread_pool_finalize (GObject * obj); static gpointer do_loop (GstRTSPThread * thread); static GstRTSPThread *default_get_thread (GstRTSPThreadPool * pool, - GstRTSPThreadType type, GstRTSPClientState * state); + GstRTSPThreadType type, GstRTSPContext * ctx); G_DEFINE_TYPE (GstRTSPThreadPool, gst_rtsp_thread_pool, G_TYPE_OBJECT); @@ -393,7 +393,7 @@ gst_rtsp_thread_pool_get_max_threads (GstRTSPThreadPool * pool) static GstRTSPThread * make_thread (GstRTSPThreadPool * pool, GstRTSPThreadType type, - GstRTSPClientState * state) + GstRTSPContext * ctx) { GstRTSPThreadPoolClass *klass; GstRTSPThread *thread; @@ -407,14 +407,14 @@ make_thread (GstRTSPThreadPool * pool, GstRTSPThreadType type, GST_DEBUG_OBJECT (pool, "new thread %p", thread); if (klass->configure_thread) - klass->configure_thread (pool, thread, state); + klass->configure_thread (pool, thread, ctx); return thread; } static GstRTSPThread * default_get_thread (GstRTSPThreadPool * pool, - GstRTSPThreadType type, GstRTSPClientState * state) + GstRTSPThreadType type, GstRTSPContext * ctx) { GstRTSPThreadPoolPrivate *priv = pool->priv; GstRTSPThreadPoolClass *klass; @@ -450,7 +450,7 @@ default_get_thread (GstRTSPThreadPool * pool, } else { /* make more threads */ GST_DEBUG_OBJECT (pool, "make new client thread"); - thread = make_thread (pool, type, state); + thread = make_thread (pool, type, ctx); if (!g_thread_pool_push (klass->pool, thread, &error)) goto thread_error; @@ -461,7 +461,7 @@ default_get_thread (GstRTSPThreadPool * pool, break; case GST_RTSP_THREAD_TYPE_MEDIA: GST_DEBUG_OBJECT (pool, "make new media thread"); - thread = make_thread (pool, type, state); + thread = make_thread (pool, type, ctx); if (!g_thread_pool_push (klass->pool, thread, &error)) goto thread_error; @@ -486,15 +486,15 @@ thread_error: * gst_rtsp_thread_pool_get_thread: * @pool: a #GstRTSPThreadPool * @type: the #GstRTSPThreadType - * @state: a #GstRTSPClientState + * @ctx: a #GstRTSPContext * - * Get a new #GstRTSPThread for @type and @state. + * Get a new #GstRTSPThread for @type and @ctx. * * Returns: a new #GstRTSPThread, gst_rtsp_thread_stop() after usage */ GstRTSPThread * gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool * pool, - GstRTSPThreadType type, GstRTSPClientState * state) + GstRTSPThreadType type, GstRTSPContext * ctx) { GstRTSPThreadPoolClass *klass; GstRTSPThread *result = NULL; @@ -504,7 +504,7 @@ gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool * pool, klass = GST_RTSP_THREAD_POOL_GET_CLASS (pool); if (klass->get_thread) - result = klass->get_thread (pool, type, state); + result = klass->get_thread (pool, type, ctx); return result; } diff --git a/gst/rtsp-server/rtsp-thread-pool.h b/gst/rtsp-server/rtsp-thread-pool.h index 74f9e0747d..148e73f671 100644 --- a/gst/rtsp-server/rtsp-thread-pool.h +++ b/gst/rtsp-server/rtsp-thread-pool.h @@ -148,10 +148,10 @@ struct _GstRTSPThreadPoolClass { GstRTSPThread * (*get_thread) (GstRTSPThreadPool *pool, GstRTSPThreadType type, - GstRTSPClientState *state); + GstRTSPContext *ctx); void (*configure_thread) (GstRTSPThreadPool *pool, GstRTSPThread * thread, - GstRTSPClientState *state); + GstRTSPContext *ctx); void (*thread_enter) (GstRTSPThreadPool *pool, GstRTSPThread *thread); @@ -168,7 +168,7 @@ gint gst_rtsp_thread_pool_get_max_threads (GstRTSPThreadPool * po GstRTSPThread * gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool *pool, GstRTSPThreadType type, - GstRTSPClientState *state); + GstRTSPContext *ctx); G_END_DECLS #endif /* __GST_RTSP_THREAD_POOL_H__ */ diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 8a442bcee4..58d5d837b5 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -529,17 +529,17 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) GstRTSPMessage request = { 0, }; gchar *str; GstRTSPSessionPool *session_pool; - GstRTSPClientState state = { NULL }; + GstRTSPContext ctx = { NULL }; client = setup_multicast_client (); - state.client = client; - state.auth = gst_rtsp_auth_new (); - state.token = + ctx.client = client; + ctx.auth = gst_rtsp_auth_new (); + ctx.token = gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, "user", NULL); - gst_rtsp_client_state_push_current (&state); + gst_rtsp_context_push_current (&ctx); /* simple SETUP with a valid URI and multicast, but an invalid ip */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, @@ -604,9 +604,9 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) g_object_unref (client); - g_object_unref (state.auth); - gst_rtsp_token_unref (state.token); - gst_rtsp_client_state_pop_current (&state); + g_object_unref (ctx.auth); + gst_rtsp_token_unref (ctx.token); + gst_rtsp_context_pop_current (&ctx); } GST_END_TEST; @@ -617,17 +617,17 @@ GST_START_TEST (test_client_multicast_transport_specific) GstRTSPMessage request = { 0, }; gchar *str; GstRTSPSessionPool *session_pool; - GstRTSPClientState state = { NULL }; + GstRTSPContext ctx = { NULL }; client = setup_multicast_client (); - state.client = client; - state.auth = gst_rtsp_auth_new (); - state.token = + ctx.client = client; + ctx.auth = gst_rtsp_auth_new (); + ctx.token = gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, "user", NULL); - gst_rtsp_client_state_push_current (&state); + gst_rtsp_context_push_current (&ctx); expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" "ttl=1;port=5000-5001;mode=\"PLAY\""; @@ -655,9 +655,9 @@ GST_START_TEST (test_client_multicast_transport_specific) g_object_unref (session_pool); g_object_unref (client); - g_object_unref (state.auth); - gst_rtsp_token_unref (state.token); - gst_rtsp_client_state_pop_current (&state); + g_object_unref (ctx.auth); + gst_rtsp_token_unref (ctx.token); + gst_rtsp_context_pop_current (&ctx); } GST_END_TEST; From d423c25a3feeb88f25d5ec52363f990d4fc22c71 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 22 Jul 2013 17:27:27 +0200 Subject: [PATCH 0770/1776] tests: add some more docs --- examples/test-cgroups.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/examples/test-cgroups.c b/examples/test-cgroups.c index dcd700b375..0a38916685 100644 --- a/examples/test-cgroups.c +++ b/examples/test-cgroups.c @@ -17,6 +17,29 @@ * Boston, MA 02110-1301, USA. */ +/* Runs a pipeline and clasifies the media pipelines based on the + * authenticated user. + * + * This test requires 2 cpu cgroups to exist named 'user' and 'admin'. + * The rtsp server should have permission to add its threads to the + * cgroups. + * + * sudo cgcreate -t uid:gid -g cpu:/user + * sudo cgcreate -t uid:gid -g cpu:/admin + * + * With -t you can give the user and group access to the task file to + * write the thread ids. The user running the server can be used. + * + * Then you would want to change the cpu shares assigned to each group: + * + * sudo cgset -r cpu.shares=100 user + * sudo cgset -r cpu.shares=1024 admin + * + * Then start clients for 'user' until the stream is degraded because of + * lack of CPU. Then start a client for 'admin' and check that the stream + * is not degraded. + */ + #include #include From 5e642c7ef19289013c7ad349a67713f8e289969f Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Tue, 11 Jun 2013 19:09:42 -0400 Subject: [PATCH 0771/1776] Update current position/duration when gst_rtsp_media_get_range_string is called --- gst/rtsp-server/rtsp-media.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 26f734f821..1d016b41d2 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1186,6 +1186,10 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play, goto not_prepared; g_mutex_lock (&priv->lock); + + /* Update the range value with current position/duration */ + collect_media_stats (media); + /* make copy */ range = priv->range; From 050b16ad8437313a98944b8d9e4d36e1e659991d Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Tue, 2 Jul 2013 18:55:28 -0400 Subject: [PATCH 0772/1776] Add API to rtsp-media set the pipeline's state --- gst/rtsp-server/rtsp-media.c | 39 +++++++++++++++++++++--------------- gst/rtsp-server/rtsp-media.h | 2 ++ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1d016b41d2..f37258dda5 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2063,6 +2063,26 @@ gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address, return provider; } +void +gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state) +{ + GstRTSPMediaPrivate *priv = media->priv; + + if (state == GST_STATE_NULL) { + gst_rtsp_media_unprepare (media); + } else { + GST_INFO ("state %s media %p", gst_element_state_get_name (state), media); + priv->target_state = state; + /* when we are buffering, don't update the state yet, this will be done + * when buffering finishes */ + if (priv->buffering) { + GST_INFO ("Buffering busy, delay state change"); + } else { + gst_element_set_state (priv->pipeline, state); + } + } +} + /** * gst_rtsp_media_set_state: * @media: a #GstRTSPMedia @@ -2148,22 +2168,9 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, media, do_state); if (priv->target_state != state) { - if (do_state) { - if (state == GST_STATE_NULL) { - gst_rtsp_media_unprepare (media); - } else { - GST_INFO ("state %s media %p", gst_element_state_get_name (state), - media); - priv->target_state = state; - /* when we are buffering, don't update the state yet, this will be done - * when buffering finishes */ - if (priv->buffering) { - GST_INFO ("Buffering busy, delay state change"); - } else { - gst_element_set_state (priv->pipeline, state); - } - } - } + if (do_state) + gst_rtsp_media_set_pipeline_state (media, state); + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state, NULL); } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index d001549f9d..7a24fcf043 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -174,6 +174,8 @@ gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GPtrArray *transports); +void gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, + GstState state); G_END_DECLS From 6ac547cc3482ec6474d2260121410bc8d0d675b3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 2 Aug 2013 16:57:26 +0200 Subject: [PATCH 0773/1776] media: add docs for new method --- docs/libs/gst-rtsp-server-sections.txt | 1 + gst/rtsp-server/rtsp-media.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 978019a025..3c6511b155 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -176,6 +176,7 @@ gst_rtsp_media_seek gst_rtsp_media_get_range_string gst_rtsp_media_set_state +gst_rtsp_media_set_pipeline_state gst_rtsp_media_get_clock diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index f37258dda5..4b8d405d48 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2063,6 +2063,13 @@ gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address, return provider; } +/** + * gst_rtsp_media_set_pipeline_state: + * @media: a #GstRTSPMedia + * @state: the target state of the pipeline + * + * Set the state of the pipeline managed by @media to @state + */ void gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state) { From 7618800088b64cffa53778ae1865030850afcfc6 Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Thu, 11 Jul 2013 16:11:55 -0400 Subject: [PATCH 0774/1776] Do not take range header if range is invalid --- gst/rtsp-server/rtsp-client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index dcaffaa6d6..73de18b567 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1086,7 +1086,8 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) /* add the range */ str = gst_rtsp_media_get_range_string (media, TRUE, unit); - gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RANGE, str); + if (str) + gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RANGE, str); send_message (client, session, ctx->response, FALSE); From 081e6d3204121a5139fc98bc35b54d596ebb9d8d Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Thu, 11 Jul 2013 16:12:04 -0400 Subject: [PATCH 0775/1776] small documentation fix --- gst/rtsp-server/rtsp-client.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 72c51875a0..e2fb734f29 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -155,7 +155,7 @@ GstRTSPResult gst_rtsp_client_send_message (GstRTSPClient * client, * A return value of #GST_RTSP_FILTER_KEEP will leave @sess untouched in * @client. * - * A value of GST_RTSP_FILTER_REF will add @sess to the result #GList of + * A value of #GST_RTSP_FILTER_REF will add @sess to the result #GList of * gst_rtsp_client_session_filter(). * * Returns: a #GstRTSPFilterResult. From a95ab4b29e1d80bc3eb6eaaf15508e840ba00763 Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Tue, 11 Jun 2013 19:10:01 -0400 Subject: [PATCH 0776/1776] Add vmethod for rtsp-media subclass to access rtpbin --- gst/rtsp-server/rtsp-media.c | 13 +++++++++++++ gst/rtsp-server/rtsp-media.h | 1 + 2 files changed, 14 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4b8d405d48..016f700f30 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1712,6 +1712,19 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) goto is_reused; priv->rtpbin = gst_element_factory_make ("rtpbin", NULL); + if (priv->rtpbin != NULL) { + GstRTSPMediaClass *klass; + gboolean success = TRUE; + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + if (klass->setup_rtpbin) + success = klass->setup_rtpbin (media, priv->rtpbin); + + if (success == FALSE) { + gst_object_unref (priv->rtpbin); + priv->rtpbin = NULL; + } + } if (priv->rtpbin == NULL) goto no_rtpbin; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 7a24fcf043..016526dd88 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -101,6 +101,7 @@ struct _GstRTSPMediaClass { GstRTSPRangeUnit unit); gboolean (*query_position) (GstRTSPMedia *media, gint64 *position); gboolean (*query_stop) (GstRTSPMedia *media, gint64 *stop); + gboolean (*setup_rtpbin) (GstRTSPMedia *media, GstElement *rtpbin); /* signals */ void (*new_stream) (GstRTSPMedia *media, GstRTSPStream * stream); From f124d112985b6aac9c2181a5933c67dc4975102f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 2 Aug 2013 17:15:09 +0200 Subject: [PATCH 0777/1776] server: add method to iterate clients of server --- docs/libs/gst-rtsp-server-sections.txt | 4 ++ gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-server.c | 60 ++++++++++++++++++++++++++ gst/rtsp-server/rtsp-server.h | 28 ++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 3c6511b155..0178bac115 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -356,6 +356,10 @@ gst_rtsp_server_io_func gst_rtsp_server_create_socket gst_rtsp_server_create_source gst_rtsp_server_attach + +GstRTSPServerClientFilterFunc +gst_rtsp_server_client_filter + GST_IS_RTSP_SERVER GST_RTSP_SERVER_CAST diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 73de18b567..f0d629e676 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2687,7 +2687,7 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) /** * gst_rtsp_client_session_filter: - * @client: a #GstRTSPclient + * @client: a #GstRTSPClient * @func: (scope call): a callback * @user_data: user data passed to @func * diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 538a2d2d1a..0e18fabc1f 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1302,3 +1302,63 @@ no_source: return 0; } } + +/** + * gst_rtsp_server_client_filter: + * @server: a #GstRTSPServer + * @func: (scope call): a callback + * @user_data: user data passed to @func + * + * Call @func for each client managed by @server. The result value of @func + * determines what happens to the client. @func will be called with @server + * locked so no further actions on @server can be performed from @func. + * + * If @func returns #GST_RTSP_FILTER_REMOVE, the client will be removed from + * @server. + * + * If @func returns #GST_RTSP_FILTER_KEEP, the client will remain in @server. + * + * If @func returns #GST_RTSP_FILTER_REF, the client will remain in @server but + * will also be added with an additional ref to the result #GList of this + * function.. + * + * Returns: (element-type GstRTSPClient) (transfer full): a #GList with all + * clients for which @func returned #GST_RTSP_FILTER_REF. After usage, each + * element in the #GList should be unreffed before the list is freed. + */ +GList * +gst_rtsp_server_client_filter (GstRTSPServer * server, + GstRTSPServerClientFilterFunc func, gpointer user_data) +{ + GstRTSPServerPrivate *priv; + GList *result, *walk, *next; + + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); + g_return_val_if_fail (func != NULL, NULL); + + priv = server->priv; + + result = NULL; + + GST_RTSP_SERVER_LOCK (server); + for (walk = priv->clients; walk; walk = next) { + GstRTSPClient *client = walk->data; + + next = g_list_next (walk); + + switch (func (server, client, user_data)) { + case GST_RTSP_FILTER_REMOVE: + /* remove client, FIXME */ + break; + case GST_RTSP_FILTER_REF: + result = g_list_prepend (result, g_object_ref (client)); + break; + case GST_RTSP_FILTER_KEEP: + default: + break; + } + } + GST_RTSP_SERVER_UNLOCK (server); + + return result; +} diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 4e185610b4..84aa1781d2 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -116,6 +116,34 @@ GSource * gst_rtsp_server_create_source (GstRTSPServer *serve guint gst_rtsp_server_attach (GstRTSPServer *server, GMainContext *context); +/** + * GstRTSPServerClientFilterFunc: + * @server: a #GstRTSPServer object + * @sess: a #GstRTSPClient in @server + * @user_data: user data that has been given to gst_rtsp_server_client_filter() + * + * This function will be called by the gst_rtsp_server_client_filter(). An + * implementation should return a value of #GstRTSPFilterResult. + * + * When this function returns #GST_RTSP_FILTER_REMOVE, @client will be removed + * from @server. + * + * A return value of #GST_RTSP_FILTER_KEEP will leave @client untouched in + * @server. + * + * A value of #GST_RTSP_FILTER_REF will add @client to the result #GList of + * gst_rtsp_server_client_filter(). + * + * Returns: a #GstRTSPFilterResult. + */ +typedef GstRTSPFilterResult (*GstRTSPServerClientFilterFunc) (GstRTSPServer *server, + GstRTSPClient *client, + gpointer user_data); + +GList * gst_rtsp_server_client_filter (GstRTSPServer *server, + GstRTSPServerClientFilterFunc func, + gpointer user_data); + G_END_DECLS #endif /* __GST_RTSP_SERVER_H__ */ From 3b0764d54595b0cd3576198190edc3e9e7e91fd7 Mon Sep 17 00:00:00 2001 From: Lubosz Sarnecki Date: Fri, 2 Aug 2013 14:11:01 +0200 Subject: [PATCH 0778/1776] build: add subdir-objects to AM_INIT_AUTOMAKE Fixes warnings with automake 1.14 https://bugzilla.gnome.org/show_bug.cgi?id=705350 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0c2ad620d6..d662acef6a 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ AC_INIT(Gst-RTSP, 0.11.90.1, AG_GST_INIT dnl initialize automake -AM_INIT_AUTOMAKE([-Wno-portability 1.11 no-dist-gzip dist-xz tar-ustar]) +AM_INIT_AUTOMAKE([-Wno-portability 1.11 no-dist-gzip dist-xz tar-ustar subdir-objects]) dnl define PACKAGE_VERSION_* variables AS_VERSION From cdbb6bcc1562a561c98d377fdc4072ad2f8583db Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Mon, 5 Aug 2013 10:46:33 -0400 Subject: [PATCH 0779/1776] rtsp-media: send state in "new-state" signal https://bugzilla.gnome.org/show_bug.cgi?id=705110 --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 016f700f30..a28589577a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -250,7 +250,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) gst_rtsp_media_signals[SIGNAL_NEW_STATE] = g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL, - g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 0, G_TYPE_INT); + g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); From a84b71c0f01a1792fb73e67bdad7b6862d278da8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 16 Aug 2013 16:08:43 +0200 Subject: [PATCH 0780/1776] stream: add protocols property --- gst/rtsp-server/rtsp-stream.c | 65 ++++++++++++++++++++++++++++++++++- gst/rtsp-server/rtsp-stream.h | 3 ++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index ba8913b215..7d31aaa5c5 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -68,6 +68,8 @@ struct _GstRTSPStreamPrivate gboolean is_joined; gchar *control; + GstRTSPLowerTrans protocols; + /* pads on the rtpbin */ GstPad *send_rtp_sink; GstPad *recv_sink[2]; @@ -120,12 +122,14 @@ struct _GstRTSPStreamPrivate gint dscp_qos; }; -#define DEFAULT_CONTROL NULL +#define DEFAULT_CONTROL NULL +#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP enum { PROP_0, PROP_CONTROL, + PROP_PROTOCOLS, PROP_LAST }; @@ -161,6 +165,11 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) "The control string for this stream", DEFAULT_CONTROL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PROTOCOLS, + g_param_spec_flags ("protocols", "Protocols", + "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS, + DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_DEBUG_CATEGORY_INIT (rtsp_stream_debug, "rtspstream", 0, "GstRTSPStream"); ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); @@ -177,6 +186,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->dscp_qos = -1; priv->control = g_strdup (DEFAULT_CONTROL); + priv->protocols = DEFAULT_PROTOCOLS; g_mutex_init (&priv->lock); } @@ -223,6 +233,9 @@ gst_rtsp_stream_get_property (GObject * object, guint propid, case PROP_CONTROL: g_value_take_string (value, gst_rtsp_stream_get_control (stream)); break; + case PROP_PROTOCOLS: + g_value_set_flags (value, gst_rtsp_stream_get_protocols (stream)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -238,6 +251,9 @@ gst_rtsp_stream_set_property (GObject * object, guint propid, case PROP_CONTROL: gst_rtsp_stream_set_control (stream, g_value_get_string (value)); break; + case PROP_PROTOCOLS: + gst_rtsp_stream_set_protocols (stream, g_value_get_flags (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -498,6 +514,53 @@ gst_rtsp_stream_get_dscp_qos (GstRTSPStream * stream) return priv->dscp_qos; } +/** + * gst_rtsp_stream_set_protocols: + * @stream: a #GstRTSPStream + * @protocols: the new flags + * + * Configure the allowed lower transport for @stream. + */ +void +gst_rtsp_stream_set_protocols (GstRTSPStream * stream, + GstRTSPLowerTrans protocols) +{ + GstRTSPStreamPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + priv->protocols = protocols; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_stream_get_protocols: + * @stream: a #GstRTSPStream + * + * Get the allowed protocols of @stream. + * + * Returns: a #GstRTSPLowerTrans + */ +GstRTSPLowerTrans +gst_rtsp_stream_get_protocols (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + GstRTSPLowerTrans res; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), + GST_RTSP_LOWER_TRANS_UNKNOWN); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + res = priv->protocols; + g_mutex_unlock (&priv->lock); + + return res; +} /** * gst_rtsp_stream_set_address_pool: diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 240fc480d4..1832b2cb71 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -77,6 +77,9 @@ guint gst_rtsp_stream_get_mtu (GstRTSPStream *stream); void gst_rtsp_stream_set_dscp_qos (GstRTSPStream *stream, gint dscp_qos); gint gst_rtsp_stream_get_dscp_qos (GstRTSPStream *stream); +void gst_rtsp_stream_set_protocols (GstRTSPStream *stream, GstRTSPLowerTrans protocols); +GstRTSPLowerTrans gst_rtsp_stream_get_protocols (GstRTSPStream *stream); + void gst_rtsp_stream_set_address_pool (GstRTSPStream *stream, GstRTSPAddressPool *pool); GstRTSPAddressPool * gst_rtsp_stream_get_address_pool (GstRTSPStream *stream); From cf96774e6d11c3ef18b77a330b3d26d0fa05ca32 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 16 Aug 2013 16:10:43 +0200 Subject: [PATCH 0781/1776] media: configure protocols in new streams --- gst/rtsp-server/rtsp-media.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index a28589577a..e2ae5207ea 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1027,6 +1027,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, stream = gst_rtsp_stream_new (idx, payloader, srcpad); if (priv->pool) gst_rtsp_stream_set_address_pool (stream, priv->pool); + gst_rtsp_stream_set_protocols (stream, priv->protocols); g_ptr_array_add (priv->streams, stream); g_mutex_unlock (&priv->lock); From 04d2da4d0344ac3e402170c0d7e022a4f7575253 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 16 Aug 2013 16:16:00 +0200 Subject: [PATCH 0782/1776] media-factory: allow all protocols --- gst/rtsp-server/rtsp-media-factory.c | 3 ++- gst/rtsp-server/rtsp-media.c | 4 ++-- gst/rtsp-server/rtsp-stream.c | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 89678dcb92..8216f5da71 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -63,7 +63,8 @@ struct _GstRTSPMediaFactoryPrivate #define DEFAULT_LAUNCH NULL #define DEFAULT_SHARED FALSE #define DEFAULT_EOS_SHUTDOWN FALSE -#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP +#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ + GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_BUFFER_SIZE 0x80000 enum diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e2ae5207ea..de13c14fa2 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -122,8 +122,8 @@ struct _GstRTSPMediaPrivate #define DEFAULT_SHARED FALSE #define DEFAULT_REUSABLE FALSE -#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP -//#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST +#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ + GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_EOS_SHUTDOWN FALSE #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_TIME_PROVIDER FALSE diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 7d31aaa5c5..ad0be8e1a3 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -123,7 +123,8 @@ struct _GstRTSPStreamPrivate }; #define DEFAULT_CONTROL NULL -#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP +#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ + GST_RTSP_LOWER_TRANS_TCP enum { From 1a838d61797b6e057064c42bf18e5ea07f8c8af0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 16 Aug 2013 16:16:31 +0200 Subject: [PATCH 0783/1776] client: use protocols supported by stream --- gst/rtsp-server/rtsp-client.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f0d629e676..08fe9f193d 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1448,8 +1448,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_transport_new (&ct); /* our supported transports */ - supported = GST_RTSP_LOWER_TRANS_UDP | - GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP; + supported = gst_rtsp_stream_get_protocols (stream); /* parse and find a usable supported transport */ if (!parse_transport (transport, supported, ct)) From f094256addf8c0f9c8360c2cda89a49a7b60f09f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 16 Aug 2013 16:34:56 +0200 Subject: [PATCH 0784/1776] media: set protocols on streams --- gst/rtsp-server/rtsp-media.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index de13c14fa2..93f156518f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -672,6 +672,12 @@ gst_rtsp_media_is_reusable (GstRTSPMedia * media) return res; } +static void +do_set_protocols (GstRTSPStream * stream, GstRTSPLowerTrans * protocols) +{ + gst_rtsp_stream_set_protocols (stream, *protocols); +} + /** * gst_rtsp_media_set_protocols: * @media: a #GstRTSPMedia @@ -690,6 +696,7 @@ gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols) g_mutex_lock (&priv->lock); priv->protocols = protocols; + g_ptr_array_foreach (priv->streams, (GFunc) do_set_protocols, &protocols); g_mutex_unlock (&priv->lock); } From d74cbf2911e3637c75b72edf7b4b05a12beb42bf Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 16 Aug 2013 17:05:24 +0200 Subject: [PATCH 0785/1776] stream: optimize pipeline for protocols When TCP is not an allowed protocol for the stream, avoid creating the appsrc/appsink/queue and tee elements. --- gst/rtsp-server/rtsp-stream.c | 189 ++++++++++++++++++++-------------- 1 file changed, 114 insertions(+), 75 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index ad0be8e1a3..633ec55e96 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1361,7 +1361,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, gint i; guint idx; gchar *name; - GstPad *pad, *teepad, *queuepad, *selpad; + GstPad *pad, *sinkpad, *selpad; GstPadLinkReturn ret; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); @@ -1427,6 +1427,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, stream); for (i = 0; i < 2; i++) { + GstPad *teepad, *queuepad; /* For the sender we create this bit of pipeline for both * RTP and RTCP. Sync and preroll are enabled on udpsink so * we need to add a queue before appsink to make the pipeline @@ -1441,49 +1442,57 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, * | | | queue | | appsink | * | src->sink src->sink | * '-----' '---------' '---------' + * + * When only UDP is allowed, we skip the tee, queue and appsink and link the + * udpsink directly to the session. */ - /* make tee for RTP/RTCP */ - priv->tee[i] = gst_element_factory_make ("tee", NULL); - gst_bin_add (bin, priv->tee[i]); - - /* and link to rtpbin send pad */ - pad = gst_element_get_static_pad (priv->tee[i], "sink"); - gst_pad_link (priv->send_src[i], pad); - gst_object_unref (pad); - /* add udpsink */ gst_bin_add (bin, priv->udpsink[i]); + sinkpad = gst_element_get_static_pad (priv->udpsink[i], "sink"); - /* link tee to udpsink */ - teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); - pad = gst_element_get_static_pad (priv->udpsink[i], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); + if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) { + /* make tee for RTP/RTCP */ + priv->tee[i] = gst_element_factory_make ("tee", NULL); + gst_bin_add (bin, priv->tee[i]); - /* make queue */ - priv->appqueue[i] = gst_element_factory_make ("queue", NULL); - gst_bin_add (bin, priv->appqueue[i]); - /* and link to tee */ - teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); - pad = gst_element_get_static_pad (priv->appqueue[i], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); + /* and link to rtpbin send pad */ + pad = gst_element_get_static_pad (priv->tee[i], "sink"); + gst_pad_link (priv->send_src[i], pad); + gst_object_unref (pad); - /* make appsink */ - priv->appsink[i] = gst_element_factory_make ("appsink", NULL); - g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); - g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); - gst_bin_add (bin, priv->appsink[i]); - gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), - &sink_cb, stream, NULL); - /* and link to queue */ - queuepad = gst_element_get_static_pad (priv->appqueue[i], "src"); - pad = gst_element_get_static_pad (priv->appsink[i], "sink"); - gst_pad_link (queuepad, pad); - gst_object_unref (pad); - gst_object_unref (queuepad); + /* link tee to udpsink */ + teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); + gst_pad_link (teepad, sinkpad); + gst_object_unref (teepad); + + /* make queue */ + priv->appqueue[i] = gst_element_factory_make ("queue", NULL); + gst_bin_add (bin, priv->appqueue[i]); + /* and link to tee */ + teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); + pad = gst_element_get_static_pad (priv->appqueue[i], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); + + /* make appsink */ + priv->appsink[i] = gst_element_factory_make ("appsink", NULL); + g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); + g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); + gst_bin_add (bin, priv->appsink[i]); + gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), + &sink_cb, stream, NULL); + /* and link to queue */ + queuepad = gst_element_get_static_pad (priv->appqueue[i], "src"); + pad = gst_element_get_static_pad (priv->appsink[i], "sink"); + gst_pad_link (queuepad, pad); + gst_object_unref (pad); + gst_object_unref (queuepad); + } else { + /* else only udpsink needed, link it to the session */ + gst_pad_link (priv->send_src[i], sinkpad); + } + gst_object_unref (sinkpad); /* For the receiver we create this bit of pipeline for both * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc @@ -1535,24 +1544,32 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, gst_object_unref (selpad); } - /* make and add appsrc */ - priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); - gst_bin_add (bin, priv->appsrc[i]); - /* and link to the funnel */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->appsrc[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); + if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) { + /* make and add appsrc */ + priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); + gst_bin_add (bin, priv->appsrc[i]); + /* and link to the funnel */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->appsrc[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + } /* check if we need to set to a special state */ if (state != GST_STATE_NULL) { - gst_element_set_state (priv->udpsink[i], state); - gst_element_set_state (priv->appsink[i], state); - gst_element_set_state (priv->appqueue[i], state); - gst_element_set_state (priv->tee[i], state); - gst_element_set_state (priv->funnel[i], state); - gst_element_set_state (priv->appsrc[i], state); + if (priv->udpsink[i]) + gst_element_set_state (priv->udpsink[i], state); + if (priv->appsink[i]) + gst_element_set_state (priv->appsink[i], state); + if (priv->appqueue[i]) + gst_element_set_state (priv->appqueue[i], state); + if (priv->tee[i]) + gst_element_set_state (priv->tee[i], state); + if (priv->funnel[i]) + gst_element_set_state (priv->funnel[i], state); + if (priv->appsrc[i]) + gst_element_set_state (priv->appsrc[i], state); } } @@ -1626,12 +1643,18 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->send_rtp_sink = NULL; for (i = 0; i < 2; i++) { - gst_element_set_state (priv->udpsink[i], GST_STATE_NULL); - gst_element_set_state (priv->appsink[i], GST_STATE_NULL); - gst_element_set_state (priv->appqueue[i], GST_STATE_NULL); - gst_element_set_state (priv->tee[i], GST_STATE_NULL); - gst_element_set_state (priv->funnel[i], GST_STATE_NULL); - gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); + if (priv->udpsink[i]) + gst_element_set_state (priv->udpsink[i], GST_STATE_NULL); + if (priv->appsink[i]) + gst_element_set_state (priv->appsink[i], GST_STATE_NULL); + if (priv->appqueue[i]) + gst_element_set_state (priv->appqueue[i], GST_STATE_NULL); + if (priv->tee[i]) + gst_element_set_state (priv->tee[i], GST_STATE_NULL); + if (priv->funnel[i]) + gst_element_set_state (priv->funnel[i], GST_STATE_NULL); + if (priv->appsrc[i]) + gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); if (priv->udpsrc_v4[i]) { /* and set udpsrc to NULL now before removing */ gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE); @@ -1645,12 +1668,18 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); gst_bin_remove (bin, priv->udpsrc_v6[i]); } - gst_bin_remove (bin, priv->udpsink[i]); - gst_bin_remove (bin, priv->appsrc[i]); - gst_bin_remove (bin, priv->appsink[i]); - gst_bin_remove (bin, priv->appqueue[i]); - gst_bin_remove (bin, priv->tee[i]); - gst_bin_remove (bin, priv->funnel[i]); + if (priv->udpsink[i]) + gst_bin_remove (bin, priv->udpsink[i]); + if (priv->appsrc[i]) + gst_bin_remove (bin, priv->appsrc[i]); + if (priv->appsink[i]) + gst_bin_remove (bin, priv->appsink[i]); + if (priv->appqueue[i]) + gst_bin_remove (bin, priv->appqueue[i]); + if (priv->tee[i]) + gst_bin_remove (bin, priv->tee[i]); + if (priv->funnel[i]) + gst_bin_remove (bin, priv->funnel[i]); gst_element_release_request_pad (rtpbin, priv->recv_sink[i]); gst_object_unref (priv->recv_sink[i]); @@ -1776,13 +1805,18 @@ gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * buffer) g_return_val_if_fail (priv->is_joined, FALSE); g_mutex_lock (&priv->lock); - element = gst_object_ref (priv->appsrc[0]); + if (priv->appsrc[0]) + element = gst_object_ref (priv->appsrc[0]); + else + element = NULL; g_mutex_unlock (&priv->lock); - ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (element), buffer); - - gst_object_unref (element); - + if (element) { + ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (element), buffer); + gst_object_unref (element); + } else { + ret = GST_FLOW_OK; + } return ret; } @@ -1811,13 +1845,18 @@ gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer) g_return_val_if_fail (priv->is_joined, FALSE); g_mutex_lock (&priv->lock); - element = gst_object_ref (priv->appsrc[1]); + if (priv->appsrc[1]) + element = gst_object_ref (priv->appsrc[1]); + else + element = NULL; g_mutex_unlock (&priv->lock); - ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (element), buffer); - - gst_object_unref (element); - + if (element) { + ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (element), buffer); + gst_object_unref (element); + } else { + ret = GST_FLOW_OK; + } return ret; } From 3766914a184635896d05b2eda7d2addf86e86f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 22 Aug 2013 18:39:59 +0100 Subject: [PATCH 0786/1776] rtsp-media-factory-uri: check AAC properly for whether it's parsed or not For AAC we need to check for framed=true instead of parsed=true. https://bugzilla.gnome.org/show_bug.cgi?id=701384 --- gst/rtsp-server/rtsp-media-factory-uri.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 46300a9f62..702987b577 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -352,8 +352,15 @@ find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps) if (list) { GstStructure *structure = gst_caps_get_structure (caps, 0); gboolean parsed = FALSE; + gint mpegversion = 0; - gst_structure_get_boolean (structure, "parsed", &parsed); + if (!gst_structure_get_boolean (structure, "parsed", &parsed) && + gst_structure_has_name (structure, "audio/mpeg") && + gst_structure_get_int (structure, "mpegversion", &mpegversion) && + (mpegversion == 2 || mpegversion == 4)) { + /* for AAC it's framed=true instead of parsed=true */ + gst_structure_get_boolean (structure, "framed", &parsed); + } /* Avoid plugging parsers in a loop. This is not 100% correct, as some * parsers don't set parsed=true in caps. We should do something like From 76cbc7c86ca0714e87aebf919aa870eecdbb930d Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Fri, 16 Aug 2013 12:42:22 -0400 Subject: [PATCH 0787/1776] Fix gst_rtsp_server_client_filter, using wrong variable type --- gst/rtsp-server/rtsp-server.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 0e18fabc1f..efc711bbe2 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1342,16 +1342,16 @@ gst_rtsp_server_client_filter (GstRTSPServer * server, GST_RTSP_SERVER_LOCK (server); for (walk = priv->clients; walk; walk = next) { - GstRTSPClient *client = walk->data; + ClientContext *cctx = walk->data; next = g_list_next (walk); - switch (func (server, client, user_data)) { + switch (func (server, cctx->client, user_data)) { case GST_RTSP_FILTER_REMOVE: /* remove client, FIXME */ break; case GST_RTSP_FILTER_REF: - result = g_list_prepend (result, g_object_ref (client)); + result = g_list_prepend (result, g_object_ref (cctx->client)); break; case GST_RTSP_FILTER_KEEP: default: From 1f846187257f373c8c6066bf2f0288a507a61c24 Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Thu, 8 Aug 2013 10:57:42 -0400 Subject: [PATCH 0788/1776] Add handle-response signal for when we receive a GET_PARAMETER response --- gst/rtsp-server/rtsp-client.c | 86 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-client.h | 1 + 2 files changed, 87 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 08fe9f193d..5de2cb2fc9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -107,6 +107,7 @@ enum SIGNAL_TEARDOWN_REQUEST, SIGNAL_SET_PARAMETER_REQUEST, SIGNAL_GET_PARAMETER_REQUEST, + SIGNAL_HANDLE_RESPONSE, SIGNAL_LAST }; @@ -223,6 +224,12 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) get_parameter_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE] = + g_signal_new ("handle-response", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + handle_response), NULL, NULL, g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); g_mutex_init (&tunnels_lock); @@ -1947,6 +1954,84 @@ not_implemented: } } + +static void +handle_response (GstRTSPClient * client, GstRTSPMessage * response) +{ + GstRTSPClientPrivate *priv = client->priv; + GstRTSPResult res; + GstRTSPSession *session = NULL; + GstRTSPContext sctx = { NULL }, *ctx; + gchar *sessid; + + if (!(ctx = gst_rtsp_context_get_current ())) { + ctx = &sctx; + ctx->auth = priv->auth; + gst_rtsp_context_push_current (ctx); + } + + ctx->conn = priv->connection; + ctx->client = client; + ctx->request = NULL; + ctx->uri = NULL; + ctx->method = GST_RTSP_INVALID; + ctx->response = response; + + if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) { + gst_rtsp_message_dump (response); + } + + GST_INFO ("client %p: received a response", client); + + /* get the session if there is any */ + res = + gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &sessid, 0); + if (res == GST_RTSP_OK) { + if (priv->session_pool == NULL) + goto no_pool; + + /* we had a session in the request, find it again */ + if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid))) + goto session_not_found; + + /* we add the session to the client list of watched sessions. When a session + * disappears because it times out, we will be notified. If all sessions are + * gone, we will close the connection */ + client_watch_session (client, session); + } + + ctx->session = session; + + if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_URL)) + goto not_authorized; + + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE], + 0, ctx); + +done: + if (ctx == &sctx) + gst_rtsp_context_pop_current (ctx); + if (session) + g_object_unref (session); + return; + +no_pool: + { + GST_ERROR ("client %p: no pool configured", client); + goto done; + } +session_not_found: + { + GST_ERROR ("client %p: session not found", client); + goto done; + } +not_authorized: + { + GST_ERROR ("client %p: not allowed", client); + goto done; + } +} + static void handle_data (GstRTSPClient * client, GstRTSPMessage * message) { @@ -2368,6 +2453,7 @@ gst_rtsp_client_handle_message (GstRTSPClient * client, handle_request (client, message); break; case GST_RTSP_MESSAGE_RESPONSE: + handle_response (client, message); break; case GST_RTSP_MESSAGE_DATA: handle_data (client, message); diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index e2fb734f29..2f9cdf97d7 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -104,6 +104,7 @@ struct _GstRTSPClientClass { void (*teardown_request) (GstRTSPClient *client, GstRTSPContext *ctx); void (*set_parameter_request) (GstRTSPClient *client, GstRTSPContext *ctx); void (*get_parameter_request) (GstRTSPClient *client, GstRTSPContext *ctx); + void (*handle_response) (GstRTSPClient *client, GstRTSPContext *ctx); }; GType gst_rtsp_client_get_type (void); From 1287b5f7721fe9f9ba17ffb4cada511905577d70 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 23 Aug 2013 10:38:43 +0200 Subject: [PATCH 0789/1776] client: don't check url in response There is no url or method in the response to check --- gst/rtsp-server/rtsp-client.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 5de2cb2fc9..67dfe831de 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2002,9 +2002,6 @@ handle_response (GstRTSPClient * client, GstRTSPMessage * response) ctx->session = session; - if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_URL)) - goto not_authorized; - g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE], 0, ctx); @@ -2025,11 +2022,6 @@ session_not_found: GST_ERROR ("client %p: session not found", client); goto done; } -not_authorized: - { - GST_ERROR ("client %p: not allowed", client); - goto done; - } } static void From ff10d24130d7a759f38a660fb87dfa3ae772a888 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 22 Aug 2013 12:10:39 +0200 Subject: [PATCH 0790/1776] rtsp-client: remove query part from content-base string Make sure that after the control url has been resolved, it's not a part of the query-string. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=706568 --- gst/rtsp-server/rtsp-client.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 67dfe831de..18a82da039 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1632,7 +1632,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPResult res; GstSDPMessage *sdp; guint i, str_len; - gchar *str, *content_base; + gchar *str, *str_query, *content_base; GstRTSPMedia *media; GstRTSPClientClass *klass; @@ -1676,6 +1676,13 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) str = gst_rtsp_url_get_request_uri (ctx->uri); str_len = strlen (str); + /* check for query part */ + if (ctx->uri->query != NULL) { + str_query = g_strrstr (str, "?"); + *str_query = '\0'; + str_len = strlen (str); + } + /* check for trailing '/' and append one */ if (str[str_len - 1] != '/') { content_base = g_malloc (str_len + 2); From 94ed18008a8847c35707fbd366ceec8c0fb8f6e5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 23 Aug 2013 15:14:29 +0200 Subject: [PATCH 0791/1776] tests: add appsrc example Add an example on how to use appsrc to feed the server pipeline with data. --- examples/test-appsrc.c | 137 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 examples/test-appsrc.c diff --git a/examples/test-appsrc.c b/examples/test-appsrc.c new file mode 100644 index 0000000000..9d271ead87 --- /dev/null +++ b/examples/test-appsrc.c @@ -0,0 +1,137 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +typedef struct +{ + gboolean white; + GstClockTime timestamp; +} MyContext; + +/* called when we need to give data to appsrc */ +static void +need_data (GstElement * appsrc, guint unused, MyContext * ctx) +{ + GstBuffer *buffer; + guint size; + GstFlowReturn ret; + + size = 385 * 288 * 2; + + buffer = gst_buffer_new_allocate (NULL, size, NULL); + + /* this makes the image black/white */ + gst_buffer_memset (buffer, 0, ctx->white ? 0xff : 0x0, size); + + ctx->white = !ctx->white; + + /* increment the timestamp every 1/2 second */ + GST_BUFFER_PTS (buffer) = ctx->timestamp; + GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (1, GST_SECOND, 2); + ctx->timestamp += GST_BUFFER_DURATION (buffer); + + g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret); +} + +/* called when a new media pipeline is constructed. We can query the + * pipeline and configure our appsrc */ +static void +media_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media, + gpointer user_data) +{ + GstElement *element, *appsrc; + MyContext *ctx; + + /* get the element used for providing the streams of the media */ + element = gst_rtsp_media_get_element (media); + + /* get our appsrc, we named it 'mysrc' with the name property */ + appsrc = gst_bin_get_by_name_recurse_up (GST_BIN (element), "mysrc"); + + /* this instructs appsrc that we will be dealing with timed buffer */ + gst_util_set_object_arg (G_OBJECT (appsrc), "format", "time"); + /* configure the caps of the video */ + g_object_set (G_OBJECT (appsrc), "caps", + gst_caps_new_simple ("video/x-raw", + "format", G_TYPE_STRING, "RGB16", + "width", G_TYPE_INT, 384, + "height", G_TYPE_INT, 288, + "framerate", GST_TYPE_FRACTION, 0, 1, NULL), NULL); + + ctx = g_new0 (MyContext, 1); + ctx->white = FALSE; + ctx->timestamp = 0; + /* make sure ther datais freed when the media is gone */ + g_object_set_data_full (G_OBJECT (media), "my-extra-data", ctx, + (GDestroyNotify) g_free); + + /* install the callback that will be called when a buffer is needed */ + g_signal_connect (appsrc, "need-data", (GCallback) need_data, ctx); +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mount points for this server, every server has a default object + * that be used to map uri mount points to media factories */ + mounts = gst_rtsp_server_get_mount_points (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, + "( appsrc name=mysrc ! videoconvert ! x264enc ! rtph264pay name=pay0 pt=96 )"); + + /* notify when our media is ready, This is called whenever someone asks for + * the media and a new pipeline with our appsrc is created */ + g_signal_connect (factory, "media-configure", (GCallback) media_configure, + NULL); + + /* attach the test factory to the /test url */ + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + /* don't need the ref to the mounts anymore */ + g_object_unref (mounts); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + g_main_loop_run (loop); + + return 0; +} From d3776cc80b77b84a97533f549a83236ce41d6b44 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 23 Aug 2013 15:15:12 +0200 Subject: [PATCH 0792/1776] Makefile: add rule for appsrc example --- examples/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Makefile.am b/examples/Makefile.am index deec57ce1e..0fc67c3d45 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,6 +1,6 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ test-launch test-sdp test-uri test-auth \ - test-multicast test-multicast2 + test-multicast test-multicast2 test-appsrc #INCLUDES = -I$(top_srcdir) -I$(srcdir) From 19178a413c7b7cc46899e34fb72746af4b7d9560 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Thu, 5 Sep 2013 08:53:55 +0200 Subject: [PATCH 0793/1776] auth, media, media-factory: unref permissions https://bugzilla.gnome.org/show_bug.cgi?id=707638 --- gst/rtsp-server/rtsp-auth.c | 5 +++++ gst/rtsp-server/rtsp-media-factory.c | 2 ++ gst/rtsp-server/rtsp-media.c | 3 +++ 3 files changed, 10 insertions(+) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 7264128530..28adba5c99 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -491,6 +491,9 @@ check_factory (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check) GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT)) goto no_construct; } + + gst_rtsp_permissions_unref (perms); + return TRUE; /* ERRORS */ @@ -509,12 +512,14 @@ no_permissions: no_access: { GST_DEBUG_OBJECT (auth, "no permissions to access media factory"); + gst_rtsp_permissions_unref (perms); send_response (auth, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_construct: { GST_DEBUG_OBJECT (auth, "no permissions to construct media factory"); + gst_rtsp_permissions_unref (perms); send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx); return FALSE; } diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 8216f5da71..59b1b022f5 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -210,6 +210,8 @@ gst_rtsp_media_factory_finalize (GObject * obj) GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj); GstRTSPMediaFactoryPrivate *priv = factory->priv; + if (priv->permissions) + gst_rtsp_permissions_unref (priv->permissions); g_hash_table_unref (priv->medias); g_mutex_clear (&priv->medias_lock); g_free (priv->launch); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 93f156518f..2c1f53defe 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -292,6 +292,9 @@ gst_rtsp_media_finalize (GObject * obj) GST_INFO ("finalize media %p", media); + if (priv->permissions) + gst_rtsp_permissions_unref (priv->permissions); + g_ptr_array_unref (priv->streams); g_list_free_full (priv->dynamic, gst_object_unref); From c15c659b40d12fb5f6521934690cdf816a3c8e8d Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Thu, 5 Sep 2013 18:01:18 +0200 Subject: [PATCH 0794/1776] media tests: unref thread pool and caps https://bugzilla.gnome.org/show_bug.cgi?id=707638 --- tests/check/gst/media.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index c7da079d5e..6b4b2a045b 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -91,6 +91,8 @@ GST_START_TEST (test_launch) gst_rtsp_url_free (url); g_object_unref (factory); + + g_object_unref (pool); } GST_END_TEST; @@ -200,6 +202,7 @@ on_notify_caps (GstPad * pad, GParamSpec * pspec, GstElement * pay) if (caps) { g_signal_emit_by_name (pay, "pad-added", pad); g_signal_emit_by_name (pay, "no-more-pads", NULL); + gst_caps_unref (caps); } else { g_signal_emit_by_name (pay, "pad-removed", pad); } @@ -263,6 +266,7 @@ GST_START_TEST (test_media_dyn_prepare) gst_object_unref (srcpad); g_object_unref (media); + g_object_unref (pool); } GST_END_TEST; From cafdba8445bc95311e47cac7839edbbf7527a60d Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Fri, 6 Sep 2013 17:23:20 +0200 Subject: [PATCH 0795/1776] mountpoints tests: unref matched factories https://bugzilla.gnome.org/show_bug.cgi?id=707638 --- tests/check/gst/mountpoints.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/check/gst/mountpoints.c b/tests/check/gst/mountpoints.c index 7099604d30..31a223e8e5 100644 --- a/tests/check/gst/mountpoints.c +++ b/tests/check/gst/mountpoints.c @@ -87,9 +87,11 @@ GST_START_TEST (test_match) tmp = gst_rtsp_mount_points_match (mounts, "/test", &matched); fail_unless (tmp == f[0]); fail_unless (matched == 5); + g_object_unref (tmp); tmp = gst_rtsp_mount_points_match (mounts, "/test/stream=1", &matched); fail_unless (tmp == f[0]); fail_unless (matched == 5); + g_object_unref (tmp); tmp = gst_rtsp_mount_points_match (mounts, "/booz", &matched); fail_unless (tmp == NULL); tmp = gst_rtsp_mount_points_match (mounts, "/booz/foo", &matched); @@ -97,24 +99,31 @@ GST_START_TEST (test_match) tmp = gst_rtsp_mount_points_match (mounts, "/booz/fooz", &matched); fail_unless (tmp == f[1]); fail_unless (matched == 10); + g_object_unref (tmp); tmp = gst_rtsp_mount_points_match (mounts, "/booz/fooz/zoo", &matched); fail_unless (tmp == f[1]); fail_unless (matched == 10); + g_object_unref (tmp); tmp = gst_rtsp_mount_points_match (mounts, "/booz/foo/zoop", &matched); fail_unless (tmp == f[2]); fail_unless (matched == 14); + g_object_unref (tmp); tmp = gst_rtsp_mount_points_match (mounts, "/tark/bar", &matched); fail_unless (tmp == f[3]); fail_unless (matched == 9); + g_object_unref (tmp); tmp = gst_rtsp_mount_points_match (mounts, "/tark/bar/boo", &matched); fail_unless (tmp == f[3]); fail_unless (matched == 9); + g_object_unref (tmp); tmp = gst_rtsp_mount_points_match (mounts, "/tark/bar/ba", &matched); fail_unless (tmp == f[3]); fail_unless (matched == 9); + g_object_unref (tmp); tmp = gst_rtsp_mount_points_match (mounts, "/tark/bar/baz", &matched); fail_unless (tmp == f[4]); fail_unless (matched == 13); + g_object_unref (tmp); g_object_unref (mounts); } From 23b3f21595b8de261a3de3f2919c80034152ef6e Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Thu, 5 Sep 2013 08:56:02 +0200 Subject: [PATCH 0796/1776] client: free threadpool https://bugzilla.gnome.org/show_bug.cgi?id=707638 --- gst/rtsp-server/rtsp-client.c | 2 ++ tests/check/gst/client.c | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 18a82da039..4ea5289843 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -348,6 +348,8 @@ gst_rtsp_client_finalize (GObject * obj) g_object_unref (priv->mount_points); if (priv->auth) g_object_unref (priv->auth); + if (priv->thread_pool) + g_object_unref (priv->thread_pool); if (priv->path) g_free (priv->path); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 58d5d837b5..f30056d70c 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -143,6 +143,13 @@ setup_client (const gchar * launch_line) return client; } +static void +teardown_client (GstRTSPClient *client) +{ + gst_rtsp_client_set_thread_pool (client, NULL); + g_object_unref (client); +} + GST_START_TEST (test_request) { GstRTSPClient *client; @@ -282,7 +289,7 @@ GST_START_TEST (test_describe) &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - g_object_unref (client); + teardown_client (client); } GST_END_TEST; @@ -417,7 +424,7 @@ GST_START_TEST (test_client_multicast_transport_404) &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - g_object_unref (client); + teardown_client (client); } GST_END_TEST; @@ -458,7 +465,7 @@ GST_START_TEST (test_client_multicast_transport) gst_rtsp_message_unset (&request); expected_transport = NULL; expected_session_timeout = 60; - g_object_unref (client); + teardown_client (client); } GST_END_TEST; @@ -489,7 +496,7 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) gst_rtsp_message_unset (&request); expected_transport = NULL; - g_object_unref (client); + teardown_client (client); } GST_END_TEST; @@ -603,7 +610,7 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) g_object_unref (session_pool); - g_object_unref (client); + teardown_client (client); g_object_unref (ctx.auth); gst_rtsp_token_unref (ctx.token); gst_rtsp_context_pop_current (&ctx); @@ -654,7 +661,7 @@ GST_START_TEST (test_client_multicast_transport_specific) fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 1); g_object_unref (session_pool); - g_object_unref (client); + teardown_client (client); g_object_unref (ctx.auth); gst_rtsp_token_unref (ctx.token); gst_rtsp_context_pop_current (&ctx); @@ -736,8 +743,7 @@ test_client_sdp (const gchar * launch_line, guint * bandwidth_val) &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - g_object_unref (client); - + teardown_client (client); } GST_START_TEST (test_client_sdp_with_max_bitrate_tag) From 258f63b8ac9a39e313b025f014e504dd56e8bb20 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 9 Sep 2013 11:05:26 +0200 Subject: [PATCH 0797/1776] thread-pool: Add cleanup to wait for the threadpool to finish Also fix race condition if two threads are asking for the first thread from the thread pool at once. This would case two internal GThreadPools to be created. https://bugzilla.gnome.org/show_bug.cgi?id=707753 --- gst/rtsp-server/rtsp-thread-pool.c | 32 ++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-thread-pool.h | 1 + 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index 87a035f494..5907acc739 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -229,8 +229,6 @@ gst_rtsp_thread_pool_class_init (GstRTSPThreadPoolClass * klass) klass->get_thread = default_get_thread; - klass->pool = g_thread_pool_new ((GFunc) do_loop, klass, -1, FALSE, NULL); - GST_DEBUG_CATEGORY_INIT (rtsp_thread_pool_debug, "rtspthreadpool", 0, "GstRTSPThreadPool"); @@ -503,8 +501,38 @@ gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool * pool, klass = GST_RTSP_THREAD_POOL_GET_CLASS (pool); + /* We want to be thread safe as there might be 2 threads wanting to get new + * #GstRTSPThread at the same time + */ + if (G_UNLIKELY (!g_atomic_pointer_get (&klass->pool))) { + GThreadPool *t_pool; + t_pool = g_thread_pool_new ((GFunc) do_loop, klass, -1, FALSE, NULL); + if (!g_atomic_pointer_compare_and_exchange (&klass->pool, NULL, t_pool)) + g_thread_pool_free (t_pool, FALSE, TRUE); + } + if (klass->get_thread) result = klass->get_thread (pool, type, ctx); return result; } + +/** + * gst_rtsp_thread_pool_cleanup: + * + * Wait for all tasks to be stopped and free all allocated resources. This is + * mainly used in test suites to ensure proper cleanup of internal data + * structures. + */ +void +gst_rtsp_thread_pool_cleanup (void) +{ + GstRTSPThreadPoolClass *klass; + + klass = GST_RTSP_THREAD_POOL_CLASS ( + g_type_class_peek (gst_rtsp_thread_pool_get_type ())); + if (klass->pool != NULL) { + g_thread_pool_free (klass->pool, FALSE, TRUE); + klass->pool = NULL; + } +} diff --git a/gst/rtsp-server/rtsp-thread-pool.h b/gst/rtsp-server/rtsp-thread-pool.h index 148e73f671..816512534d 100644 --- a/gst/rtsp-server/rtsp-thread-pool.h +++ b/gst/rtsp-server/rtsp-thread-pool.h @@ -169,6 +169,7 @@ gint gst_rtsp_thread_pool_get_max_threads (GstRTSPThreadPool * po GstRTSPThread * gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool *pool, GstRTSPThreadType type, GstRTSPContext *ctx); +void gst_rtsp_thread_pool_cleanup (void); G_END_DECLS #endif /* __GST_RTSP_THREAD_POOL_H__ */ From 952aa309dcfc8389fc51b119d984407d7f75f34f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 16 Sep 2013 16:47:40 +0200 Subject: [PATCH 0798/1776] mount-points: make vmethod to make path from uri Make a vmethod to transform an url into a path. The path is then used to lookup the factory. This makes it possible to also use other bits of the url, such as the query parameters, to locate the factory. --- gst/rtsp-server/rtsp-client.c | 16 +++++++++++- gst/rtsp-server/rtsp-mount-points.c | 39 +++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-mount-points.h | 6 +++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4ea5289843..c82d4a2479 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -491,7 +491,8 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gint * matched) if (!priv->mount_points) goto no_mount_points; - path = ctx->uri->abspath; + if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri))) + goto no_path; /* find the longest matching factory for the uri first */ if (!(factory = gst_rtsp_mount_points_match (priv->mount_points, @@ -552,6 +553,7 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gint * matched) g_object_unref (factory); ctx->factory = NULL; + g_free (path); if (media) g_object_ref (media); @@ -565,20 +567,29 @@ no_mount_points: send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return NULL; } +no_path: + { + GST_ERROR ("client %p: can't find path for url", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return NULL; + } no_factory: { GST_ERROR ("client %p: no factory for uri %s", client, path); + g_free (path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return NULL; } no_factory_access: { GST_ERROR ("client %p: not authorized to see factory uri %s", client, path); + g_free (path); return NULL; } not_authorized: { GST_ERROR ("client %p: not authorized for factory uri %s", client, path); + g_free (path); return NULL; } no_media: @@ -587,6 +598,7 @@ no_media: send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (factory); ctx->factory = NULL; + g_free (path); return NULL; } no_thread: @@ -597,6 +609,7 @@ no_thread: ctx->media = NULL; g_object_unref (factory); ctx->factory = NULL; + g_free (path); return NULL; } no_prepare: @@ -607,6 +620,7 @@ no_prepare: ctx->media = NULL; g_object_unref (factory); ctx->factory = NULL; + g_free (path); return NULL; } } diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 2cf09ae34e..de23bc13c6 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -102,6 +102,8 @@ G_DEFINE_TYPE (GstRTSPMountPoints, gst_rtsp_mount_points, G_TYPE_OBJECT); GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug); #define GST_CAT_DEFAULT rtsp_media_debug +static gchar *default_make_path (GstRTSPMountPoints * mounts, + const GstRTSPUrl * url); static void gst_rtsp_mount_points_finalize (GObject * obj); static void @@ -115,6 +117,8 @@ gst_rtsp_mount_points_class_init (GstRTSPMountPointsClass * klass) gobject_class->finalize = gst_rtsp_mount_points_finalize; + klass->make_path = default_make_path; + GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmountpoints", 0, "GstRTSPMountPoints"); } @@ -164,6 +168,41 @@ gst_rtsp_mount_points_new (void) return result; } +static gchar * +default_make_path (GstRTSPMountPoints * mounts, const GstRTSPUrl * url) +{ + return g_strdup (url->abspath); +} + +/** + * gst_rtsp_mount_points_make_path: + * @mounts: a #GstRTSPMountPoints + * @url: a #GstRTSPUrl + * + * Make a path string from @url. + * + * Returns: a path string for @url, g_free() after usage. + */ +gchar * +gst_rtsp_mount_points_make_path (GstRTSPMountPoints * mounts, + const GstRTSPUrl * url) +{ + GstRTSPMountPointsClass *klass; + gchar *result; + + g_return_val_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts), NULL); + g_return_val_if_fail (url != NULL, NULL); + + klass = GST_RTSP_MOUNT_POINTS_GET_CLASS (mounts); + + if (klass->make_path) + result = klass->make_path (mounts, url); + else + result = NULL; + + return result; +} + static gboolean has_prefix (DataItem * str, DataItem * prefix) { diff --git a/gst/rtsp-server/rtsp-mount-points.h b/gst/rtsp-server/rtsp-mount-points.h index 3f9b5b7b2f..18a691a133 100644 --- a/gst/rtsp-server/rtsp-mount-points.h +++ b/gst/rtsp-server/rtsp-mount-points.h @@ -53,11 +53,15 @@ struct _GstRTSPMountPoints { /** * GstRTSPMountPointsClass: + * @make_path: make a path from the given url. * * The class for the media mounts object. */ struct _GstRTSPMountPointsClass { GObjectClass parent_class; + + gchar * (*make_path) (GstRTSPMountPoints *mounts, + const GstRTSPUrl *url); }; GType gst_rtsp_mount_points_get_type (void); @@ -65,6 +69,8 @@ GType gst_rtsp_mount_points_get_type (void); /* creating a mount points */ GstRTSPMountPoints * gst_rtsp_mount_points_new (void); +gchar * gst_rtsp_mount_points_make_path (GstRTSPMountPoints *mounts, + const GstRTSPUrl * url); /* finding a media factory */ GstRTSPMediaFactory * gst_rtsp_mount_points_match (GstRTSPMountPoints *mounts, const gchar *path, From e3fded2cec897a2ec003450607b916cc1601fd2d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 16 Sep 2013 17:16:49 +0200 Subject: [PATCH 0799/1776] client: map URL to path in requests --- gst/rtsp-server/rtsp-client.c | 108 ++++++++++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c82d4a2479..48061f050a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -740,18 +740,20 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; GstRTSPStatusCode code; - const gchar *path; + gchar *path; gint matched; - if (!ctx->session) + if (!(session = ctx->session)) goto no_session; - session = ctx->session; - if (!ctx->uri) goto no_uri; - path = ctx->uri->abspath; + if (!priv->mount_points) + goto no_mount_points; + + if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri))) + goto no_path; /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -762,6 +764,8 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) if (path[matched] != '\0') goto no_aggregate; + g_free (path); + ctx->sessmedia = sessmedia; /* we emit the signal before closing the connection */ @@ -804,15 +808,29 @@ no_uri: send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } +no_mount_points: + { + GST_ERROR ("client %p: no mount points configured", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } +no_path: + { + GST_ERROR ("client %p: can't find path for url", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } not_found: { GST_ERROR ("client %p: no media for uri", client); + g_free (path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); + g_free (path); send_generic_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); return FALSE; @@ -916,11 +934,12 @@ bad_request: static gboolean handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; GstRTSPStatusCode code; GstRTSPState rtspstate; - const gchar *path; + gchar *path; gint matched; if (!(session = ctx->session)) @@ -929,7 +948,11 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!ctx->uri) goto no_uri; - path = ctx->uri->abspath; + if (!priv->mount_points) + goto no_mount_points; + + if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri))) + goto no_path; /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -939,6 +962,8 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) if (path[matched] != '\0') goto no_aggregate; + g_free (path); + ctx->sessmedia = sessmedia; rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); @@ -980,15 +1005,29 @@ no_uri: send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } +no_mount_points: + { + GST_ERROR ("client %p: no mount points configured", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } +no_path: + { + GST_ERROR ("client %p: can't find path for url", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } not_found: { GST_ERROR ("client %p: no media for uri", client); + g_free (path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); + g_free (path); send_generic_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); return FALSE; @@ -1005,6 +1044,7 @@ invalid_state: static gboolean handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; GstRTSPMedia *media; @@ -1016,7 +1056,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPResult res; GstRTSPState rtspstate; GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT; - const gchar *path; + gchar *path; gint matched; if (!(session = ctx->session)) @@ -1025,7 +1065,11 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!ctx->uri) goto no_uri; - path = ctx->uri->abspath; + if (!priv->mount_points) + goto no_mount_points; + + if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri))) + goto no_path; /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -1035,6 +1079,8 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (path[matched] != '\0') goto no_aggregate; + g_free (path); + ctx->sessmedia = sessmedia; ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); @@ -1136,15 +1182,29 @@ no_uri: send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } +no_mount_points: + { + GST_ERROR ("client %p: no mount points configured", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } +no_path: + { + GST_ERROR ("client %p: can't find path for url", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } not_found: { GST_ERROR ("client %p: media not found", client); + g_free (path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); + g_free (path); send_generic_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); return FALSE; @@ -1380,11 +1440,14 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *path, *control; gint matched; - if (!ctx->uri) + if (!(uri = ctx->uri)) goto no_uri; - uri = ctx->uri; - path = uri->abspath; + if (!priv->mount_points) + goto no_mount_points; + + if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, uri))) + goto no_path; /* parse the transport */ res = @@ -1422,7 +1485,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (media == NULL) goto media_not_found; - /* path is what matched. We can modify the parsed uri in place */ + /* path is what matched */ path[matched] = '\0'; /* control is remainder */ control = &path[matched + 1]; @@ -1461,6 +1524,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) } else { g_object_unref (media); } + g_free (path); ctx->sessmedia = sessmedia; @@ -1530,27 +1594,43 @@ no_uri: send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } +no_mount_points: + { + GST_ERROR ("client %p: no mount points configured", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } +no_path: + { + GST_ERROR ("client %p: can't find path for url", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } no_transport: { GST_ERROR ("client %p: no transport", client); + g_free (path); send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); return FALSE; } no_pool: { GST_ERROR ("client %p: no session pool configured", client); + g_free (path); send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); return FALSE; } media_not_found: { GST_ERROR ("client %p: media '%s' not found", client, path); + g_free (path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } stream_not_found: { GST_ERROR ("client %p: stream '%s' not found", client, control); + g_free (path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); g_object_unref (media); return FALSE; @@ -1558,6 +1638,7 @@ stream_not_found: service_unavailable: { GST_ERROR ("client %p: can't create session", client); + g_free (path); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (media); return FALSE; @@ -1566,6 +1647,7 @@ sessmedia_unavailable: { GST_ERROR ("client %p: can't create session media", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + g_free (path); g_object_unref (media); g_object_unref (session); return FALSE; From fe3f63de7c4a6ec6f1a2a79d1bde2e23d9b2a792 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 17 Sep 2013 11:41:57 +0200 Subject: [PATCH 0800/1776] Revert "client: map URL to path in requests" This reverts commit e3fded2cec897a2ec003450607b916cc1601fd2d. This is not correct, we only remap the URL to a path in DESCRIBE, the SDP then contains the base and control urls which are used in the SETUP, PLAY, PAUSE and TEARDOWN requests. --- gst/rtsp-server/rtsp-client.c | 108 ++++------------------------------ 1 file changed, 13 insertions(+), 95 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 48061f050a..c82d4a2479 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -740,20 +740,18 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; GstRTSPStatusCode code; - gchar *path; + const gchar *path; gint matched; - if (!(session = ctx->session)) + if (!ctx->session) goto no_session; + session = ctx->session; + if (!ctx->uri) goto no_uri; - if (!priv->mount_points) - goto no_mount_points; - - if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri))) - goto no_path; + path = ctx->uri->abspath; /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -764,8 +762,6 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) if (path[matched] != '\0') goto no_aggregate; - g_free (path); - ctx->sessmedia = sessmedia; /* we emit the signal before closing the connection */ @@ -808,29 +804,15 @@ no_uri: send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } -no_mount_points: - { - GST_ERROR ("client %p: no mount points configured", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); - return FALSE; - } -no_path: - { - GST_ERROR ("client %p: can't find path for url", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); - return FALSE; - } not_found: { GST_ERROR ("client %p: no media for uri", client); - g_free (path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); - g_free (path); send_generic_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); return FALSE; @@ -934,12 +916,11 @@ bad_request: static gboolean handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) { - GstRTSPClientPrivate *priv = client->priv; GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; GstRTSPStatusCode code; GstRTSPState rtspstate; - gchar *path; + const gchar *path; gint matched; if (!(session = ctx->session)) @@ -948,11 +929,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!ctx->uri) goto no_uri; - if (!priv->mount_points) - goto no_mount_points; - - if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri))) - goto no_path; + path = ctx->uri->abspath; /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -962,8 +939,6 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) if (path[matched] != '\0') goto no_aggregate; - g_free (path); - ctx->sessmedia = sessmedia; rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); @@ -1005,29 +980,15 @@ no_uri: send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } -no_mount_points: - { - GST_ERROR ("client %p: no mount points configured", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); - return FALSE; - } -no_path: - { - GST_ERROR ("client %p: can't find path for url", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); - return FALSE; - } not_found: { GST_ERROR ("client %p: no media for uri", client); - g_free (path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); - g_free (path); send_generic_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); return FALSE; @@ -1044,7 +1005,6 @@ invalid_state: static gboolean handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) { - GstRTSPClientPrivate *priv = client->priv; GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; GstRTSPMedia *media; @@ -1056,7 +1016,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPResult res; GstRTSPState rtspstate; GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT; - gchar *path; + const gchar *path; gint matched; if (!(session = ctx->session)) @@ -1065,11 +1025,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!ctx->uri) goto no_uri; - if (!priv->mount_points) - goto no_mount_points; - - if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri))) - goto no_path; + path = ctx->uri->abspath; /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -1079,8 +1035,6 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (path[matched] != '\0') goto no_aggregate; - g_free (path); - ctx->sessmedia = sessmedia; ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); @@ -1182,29 +1136,15 @@ no_uri: send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } -no_mount_points: - { - GST_ERROR ("client %p: no mount points configured", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); - return FALSE; - } -no_path: - { - GST_ERROR ("client %p: can't find path for url", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); - return FALSE; - } not_found: { GST_ERROR ("client %p: media not found", client); - g_free (path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); - g_free (path); send_generic_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); return FALSE; @@ -1440,14 +1380,11 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *path, *control; gint matched; - if (!(uri = ctx->uri)) + if (!ctx->uri) goto no_uri; - if (!priv->mount_points) - goto no_mount_points; - - if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, uri))) - goto no_path; + uri = ctx->uri; + path = uri->abspath; /* parse the transport */ res = @@ -1485,7 +1422,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (media == NULL) goto media_not_found; - /* path is what matched */ + /* path is what matched. We can modify the parsed uri in place */ path[matched] = '\0'; /* control is remainder */ control = &path[matched + 1]; @@ -1524,7 +1461,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) } else { g_object_unref (media); } - g_free (path); ctx->sessmedia = sessmedia; @@ -1594,43 +1530,27 @@ no_uri: send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } -no_mount_points: - { - GST_ERROR ("client %p: no mount points configured", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); - return FALSE; - } -no_path: - { - GST_ERROR ("client %p: can't find path for url", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); - return FALSE; - } no_transport: { GST_ERROR ("client %p: no transport", client); - g_free (path); send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); return FALSE; } no_pool: { GST_ERROR ("client %p: no session pool configured", client); - g_free (path); send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); return FALSE; } media_not_found: { GST_ERROR ("client %p: media '%s' not found", client, path); - g_free (path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } stream_not_found: { GST_ERROR ("client %p: stream '%s' not found", client, control); - g_free (path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); g_object_unref (media); return FALSE; @@ -1638,7 +1558,6 @@ stream_not_found: service_unavailable: { GST_ERROR ("client %p: can't create session", client); - g_free (path); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (media); return FALSE; @@ -1647,7 +1566,6 @@ sessmedia_unavailable: { GST_ERROR ("client %p: can't create session media", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); - g_free (path); g_object_unref (media); g_object_unref (session); return FALSE; From 4d6c038fc713d5d20be2dc48728eaa3d325b9d9a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 17 Sep 2013 12:21:02 +0200 Subject: [PATCH 0801/1776] client: map url to path only in describe Only map the request url to a path in the DESCRIBE method. The SDP then contains the base and control urls that should be used to SETUP/PAUSE/ PLAY/TEARDOWN the media. --- gst/rtsp-server/rtsp-client.c | 64 +++++++++++++++++------------------ 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c82d4a2479..333939a240 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -480,20 +480,14 @@ paths_are_equal (const gchar * path1, const gchar * path2, gint len2) * but is cached for when the same client (without breaking the connection) is * doing a setup for the exact same url. */ static GstRTSPMedia * -find_media (GstRTSPClient * client, GstRTSPContext * ctx, gint * matched) +find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path, + gint * matched) { GstRTSPClientPrivate *priv = client->priv; GstRTSPMediaFactory *factory; GstRTSPMedia *media; - gchar *path; gint path_len; - if (!priv->mount_points) - goto no_mount_points; - - if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri))) - goto no_path; - /* find the longest matching factory for the uri first */ if (!(factory = gst_rtsp_mount_points_match (priv->mount_points, path, matched))) @@ -553,7 +547,6 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gint * matched) g_object_unref (factory); ctx->factory = NULL; - g_free (path); if (media) g_object_ref (media); @@ -561,35 +554,21 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gint * matched) return media; /* ERRORS */ -no_mount_points: - { - GST_ERROR ("client %p: no mount points configured", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); - return NULL; - } -no_path: - { - GST_ERROR ("client %p: can't find path for url", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); - return NULL; - } no_factory: { - GST_ERROR ("client %p: no factory for uri %s", client, path); - g_free (path); + GST_ERROR ("client %p: no factory for path %s", client, path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return NULL; } no_factory_access: { - GST_ERROR ("client %p: not authorized to see factory uri %s", client, path); - g_free (path); + GST_ERROR ("client %p: not authorized to see factory path %s", client, + path); return NULL; } not_authorized: { - GST_ERROR ("client %p: not authorized for factory uri %s", client, path); - g_free (path); + GST_ERROR ("client %p: not authorized for factory path %s", client, path); return NULL; } no_media: @@ -598,7 +577,6 @@ no_media: send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (factory); ctx->factory = NULL; - g_free (path); return NULL; } no_thread: @@ -609,7 +587,6 @@ no_thread: ctx->media = NULL; g_object_unref (factory); ctx->factory = NULL; - g_free (path); return NULL; } no_prepare: @@ -620,7 +597,6 @@ no_prepare: ctx->media = NULL; g_object_unref (factory); ctx->factory = NULL; - g_free (path); return NULL; } } @@ -1413,7 +1389,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) /* we have no session media, find one and manage it */ if (sessmedia == NULL) { /* get a handle to the configuration of the media in the session */ - media = find_media (client, ctx, &matched); + media = find_media (client, ctx, path, &matched); } else { if ((media = gst_rtsp_session_media_get_media (sessmedia))) g_object_ref (media); @@ -1645,10 +1621,11 @@ no_sdp: static gboolean handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPResult res; GstSDPMessage *sdp; guint i, str_len; - gchar *str, *str_query, *content_base; + gchar *path, *str, *str_query, *content_base; GstRTSPMedia *media; GstRTSPClientClass *klass; @@ -1672,10 +1649,18 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) break; } + if (!priv->mount_points) + goto no_mount_points; + + if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri))) + goto no_path; + /* find the media object for the uri */ - if (!(media = find_media (client, ctx, NULL))) + if (!(media = find_media (client, ctx, path, NULL))) goto no_media; + g_free (path); + /* create an SDP for the media object on this client */ if (!(sdp = klass->create_sdp (client, media))) goto no_sdp; @@ -1735,9 +1720,22 @@ no_uri: send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } +no_mount_points: + { + GST_ERROR ("client %p: no mount points configured", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } +no_path: + { + GST_ERROR ("client %p: can't find path for url", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } no_media: { GST_ERROR ("client %p: no media", client); + g_free (path); /* error reply is already sent */ return FALSE; } From b41422bad7fc630e8eeba3b2b53b9aad277791d0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 17 Sep 2013 14:39:44 +0200 Subject: [PATCH 0802/1776] client: Fix RTPInfo header Refactor the method to make the content_base. Use the content-base and the control url to construct the RTPInfo url. --- gst/rtsp-server/rtsp-client.c | 81 +++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 333939a240..b7f430cef5 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -978,6 +978,28 @@ invalid_state: } } +/* convert @url and @path to a URL used as a content base for the factory + * located at @path */ +static gchar * +make_base_url (GstRTSPClient * client, GstRTSPUrl * url, gchar * path) +{ + GstRTSPUrl tmp; + gchar *result, *trail; + + /* check for trailing '/' and append one */ + trail = (path[strlen (path) - 1] != '/' ? "/" : ""); + + tmp = *url; + tmp.user = NULL; + tmp.passwd = NULL; + tmp.abspath = g_strdup_printf ("%s%s", path, trail); + tmp.query = NULL; + result = gst_rtsp_url_get_request_uri (&tmp); + g_free (tmp.abspath); + + return result; +} + static gboolean handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) { @@ -985,23 +1007,24 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPSessionMedia *sessmedia; GstRTSPMedia *media; GstRTSPStatusCode code; + GstRTSPUrl *uri; GString *rtpinfo; guint n_streams, i, infocount; - gchar *str; + gchar *str, *base_url; GstRTSPTimeRange *range; GstRTSPResult res; GstRTSPState rtspstate; GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT; - const gchar *path; + gchar *path; gint matched; if (!(session = ctx->session)) goto no_session; - if (!ctx->uri) + if (!(uri = ctx->uri)) goto no_uri; - path = ctx->uri->abspath; + path = uri->abspath; /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -1033,12 +1056,13 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) /* grab RTPInfo from the payloaders now */ rtpinfo = g_string_new (""); + base_url = make_base_url (client, uri, path); + n_streams = gst_rtsp_media_n_streams (media); for (i = 0, infocount = 0; i < n_streams; i++) { GstRTSPStreamTransport *trans; GstRTSPStream *stream; const GstRTSPTransport *tr; - gchar *uristr; guint rtptime, seq; /* get the transport, if there is no transport configured, skip this stream */ @@ -1056,19 +1080,22 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) stream = gst_rtsp_stream_transport_get_stream (trans); if (gst_rtsp_stream_get_rtpinfo (stream, &rtptime, &seq)) { + gchar *control; + if (infocount > 0) g_string_append (rtpinfo, ", "); - uristr = gst_rtsp_url_get_request_uri (ctx->uri); - g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", - uristr, i, seq, rtptime); - g_free (uristr); + control = gst_rtsp_stream_get_control (stream); + g_string_append_printf (rtpinfo, "url=%s%s;seq=%u;rtptime=%u", + base_url, control, seq, rtptime); + g_free (control); infocount++; } else { GST_WARNING ("RTP-Info cannot be determined for stream %d", i); } } + g_free (base_url); /* construct the response now */ code = GST_RTSP_STS_OK; @@ -1624,8 +1651,8 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPClientPrivate *priv = client->priv; GstRTSPResult res; GstSDPMessage *sdp; - guint i, str_len; - gchar *path, *str, *str_query, *content_base; + guint i; + gchar *path, *str; GstRTSPMedia *media; GstRTSPClientClass *klass; @@ -1659,8 +1686,6 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!(media = find_media (client, ctx, path, NULL))) goto no_media; - g_free (path); - /* create an SDP for the media object on this client */ if (!(sdp = klass->create_sdp (client, media))) goto no_sdp; @@ -1674,32 +1699,11 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) "application/sdp"); /* content base for some clients that might screw up creating the setup uri */ - str = gst_rtsp_url_get_request_uri (ctx->uri); - str_len = strlen (str); + str = make_base_url (client, ctx->uri, path); + g_free (path); - /* check for query part */ - if (ctx->uri->query != NULL) { - str_query = g_strrstr (str, "?"); - *str_query = '\0'; - str_len = strlen (str); - } - - /* check for trailing '/' and append one */ - if (str[str_len - 1] != '/') { - content_base = g_malloc (str_len + 2); - memcpy (content_base, str, str_len); - content_base[str_len] = '/'; - content_base[str_len + 1] = '\0'; - g_free (str); - } else { - content_base = str; - } - - GST_INFO ("adding content-base: %s", content_base); - - gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_CONTENT_BASE, - content_base); - g_free (content_base); + GST_INFO ("adding content-base: %s", str); + gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_CONTENT_BASE, str); /* add SDP to the response body */ str = gst_sdp_message_as_text (sdp); @@ -1743,6 +1747,7 @@ no_sdp: { GST_ERROR ("client %p: can't create SDP", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + g_free (path); g_object_unref (media); return FALSE; } From e88b71aee4ad51f0a7a8af21d467211cac0d8aa6 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Thu, 19 Sep 2013 15:44:26 +0200 Subject: [PATCH 0803/1776] client: Do not read beyond end of path string If the setup was done without a control url, make sure we don't try to read the non-existing control string and crash. --- gst/rtsp-server/rtsp-client.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b7f430cef5..1d192a7193 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1425,6 +1425,9 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (media == NULL) goto media_not_found; + if (path[matched] == '\0') + goto control_not_found; + /* path is what matched. We can modify the parsed uri in place */ path[matched] = '\0'; /* control is remainder */ @@ -1551,6 +1554,13 @@ media_not_found: send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } +control_not_found: + { + GST_ERROR ("client %p: no control in path '%s'", client, path); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + g_object_unref (media); + return FALSE; + } stream_not_found: { GST_ERROR ("client %p: stream '%s' not found", client, control); From cc9f3bf8c053b07c466e3f6052eb124652d168db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 19 Sep 2013 17:39:24 +0100 Subject: [PATCH 0804/1776] Automatic update of common submodule From 01a7a46 to 74a6857 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 01a7a46e25..74a6857d26 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 01a7a46e258177ffe9cdb09c6518db749b2325d4 +Subproject commit 74a6857d26a22d1419c89b00ba5acbc8e2a2c68a From a16761a451294d24758c6ace2a11b34fb1e2e014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 19 Sep 2013 18:46:14 +0100 Subject: [PATCH 0805/1776] Automatic update of common submodule From 74a6857 to b613661 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 74a6857d26..b6136613ca 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 74a6857d26a22d1419c89b00ba5acbc8e2a2c68a +Subproject commit b6136613ca6071ab017c46d796806326bdf8f3bb From 59aedf8d632fc094dc62854c12021da9f8526f3b Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 20 Sep 2013 16:18:54 +0200 Subject: [PATCH 0806/1776] Automatic update of common submodule From b613661 to 6b03ba7 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index b6136613ca..6b03ba716b 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit b6136613ca6071ab017c46d796806326bdf8f3bb +Subproject commit 6b03ba716b9861277a435677ad9e31b3e14284e9 From c7bed54b879ed9bccc92a33b81e8dbd217e243e7 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 20 Sep 2013 16:47:56 +0200 Subject: [PATCH 0807/1776] autogen.sh: Sync behaviour with other GStreamer modules Allows building from outside of tree amongst other things --- autogen.sh | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/autogen.sh b/autogen.sh index 376fc9dd19..7bde014917 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,6 +1,13 @@ #!/bin/sh # Run this to generate all the initial makefiles, etc. + +test -n "$srcdir" || srcdir=`dirname "$0"` +test -n "$srcdir" || srcdir=. + +olddir=`pwd` +cd "$srcdir" + DIE=0 package=gst-rtsp srcfile=gst/rtsp-server/rtsp-server.c @@ -35,13 +42,13 @@ autogen_options $@ printf "+ check for build tools" if test ! -z "$NOCHECK"; then echo ": skipped version checks"; else echo; fi -version_check "autoconf" "$AUTOCONF autoconf autoconf270 autoconf269 autoconf268 autoconf267 autoconf266 autoconf265 autoconf264 autoconf263 autoconf262" \ - "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 62 || DIE=1 +version_check "autoconf" "$AUTOCONF autoconf autoconf270 autoconf269 autoconf268 " \ + "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 68 || DIE=1 version_check "automake" "$AUTOMAKE automake automake-1.11" \ "ftp://ftp.gnu.org/pub/gnu/automake/" 1 11 || DIE=1 version_check "autopoint" "autopoint" \ "ftp://ftp.gnu.org/pub/gnu/gettext/" 0 17 || DIE=1 -version_check "libtoolize" "libtoolize glibtoolize" \ +version_check "libtoolize" "$LIBTOOLIZE libtoolize glibtoolize" \ "ftp://ftp.gnu.org/pub/gnu/libtool/" 2 2 6 || DIE=1 version_check "pkg-config" "" \ "http://www.freedesktop.org/software/pkgconfig" 0 8 0 || DIE=1 @@ -54,7 +61,7 @@ autoheader_check || DIE=1 die_check $DIE # if no arguments specified then this will be printed -if test -z "$*"; then +if test -z "$*" && test -z "$NOCONFIGURE"; then echo "+ checking for autogen.sh options" echo " This autogen script will automatically run ./configure as:" echo " ./configure $CONFIGURE_DEF_OPT" @@ -90,21 +97,22 @@ debug "automake: $automake" tool_run "$automake" "--add-missing --copy" test -n "$NOCONFIGURE" && { - echo "skipping configure stage for package $package, as requested." - echo "autogen.sh done." + echo "+ skipping configure stage for package $package, as requested." + echo "+ autogen.sh done." exit 0 } +cd "$olddir" + echo "+ running configure ... " -test ! -z "$CONFIGURE_DEF_OPT" && echo " ./configure default flags: $CONFIGURE_DEF_OPT" -test ! -z "$CONFIGURE_EXT_OPT" && echo " ./configure external flags: $CONFIGURE_EXT_OPT" +test ! -z "$CONFIGURE_DEF_OPT" && echo " default flags: $CONFIGURE_DEF_OPT" +test ! -z "$CONFIGURE_EXT_OPT" && echo " external flags: $CONFIGURE_EXT_OPT" echo -echo ./configure $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT -./configure $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT || { +echo "$srcdir/configure" $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT +"$srcdir/configure" $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT || { echo " configure failed" exit 1 } echo "Now type 'make' to compile $package." - From 7b0ad7c25f7f5eaa5ef8902a4ab299d57318edfd Mon Sep 17 00:00:00 2001 From: Patrick Radizi Date: Tue, 24 Sep 2013 17:30:18 +0200 Subject: [PATCH 0808/1776] addresspool: return reason of failure Let gst_rtsp_address_pool_reserve_address() return the reason why the address could not be reserved. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=708229 --- gst/rtsp-server/rtsp-address-pool.c | 164 +++++++++++++++++----------- gst/rtsp-server/rtsp-address-pool.h | 28 ++++- gst/rtsp-server/rtsp-stream.c | 8 +- tests/check/gst/addresspool.c | 45 +++++--- 4 files changed, 160 insertions(+), 85 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 6bb0956a0e..e1e9b9199d 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -585,64 +585,26 @@ gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool) g_mutex_unlock (&priv->lock); } -/** - * gst_rtsp_address_pool_reserve_address: - * @pool: a #GstRTSPAddressPool - * @address: The IP address to reserve - * @port: The first port to reserve - * @n_ports: The number of ports - * @ttl: The requested ttl - * - * Take a specific address and ports from @pool. @n_ports consecutive - * ports will be allocated of which the first one can be found in - * @port. - * - * If @ttl is 0, @address should be a unicast address. If @ttl > 0, @address - * should be a valid multicast address. - * - * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free - * after use or %NULL when no address could be acquired. - */ -GstRTSPAddress * -gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, - const gchar * address, guint port, guint n_ports, guint ttl) +static GList * +find_address_in_ranges (GList * addresses, Addr * addr, guint port, + guint n_ports, guint ttl) { - GstRTSPAddressPoolPrivate *priv; - Addr input_addr; GList *walk, *next; - AddrRange *result; - GstRTSPAddress *addr; - gboolean is_multicast; - g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), NULL); - g_return_val_if_fail (address != NULL, NULL); - g_return_val_if_fail (port > 0, NULL); - g_return_val_if_fail (n_ports > 0, NULL); - - priv = pool->priv; - result = NULL; - addr = NULL; - is_multicast = ttl != 0; - - if (!fill_address (address, port, &input_addr, is_multicast)) - goto invalid; - - g_mutex_lock (&priv->lock); /* go over available ranges */ - for (walk = priv->addresses; walk; walk = next) { + for (walk = addresses; walk; walk = next) { AddrRange *range; - gint skip_port, skip_addr; range = walk->data; next = walk->next; /* Not the right type of address */ - if (range->min.size != input_addr.size) + if (range->min.size != addr->size) continue; /* Check that the address is in the interval */ - if (memcmp (range->min.bytes, input_addr.bytes, input_addr.size) > 0 || - memcmp (range->max.bytes, input_addr.bytes, input_addr.size) < 0) + if (memcmp (range->min.bytes, addr->bytes, addr->size) > 0 || + memcmp (range->max.bytes, addr->bytes, addr->size) < 0) continue; /* Make sure the requested ports are inside the range */ @@ -652,38 +614,112 @@ gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, if (ttl != range->ttl) continue; + break; + } + + return walk; +} + +/** + * gst_rtsp_address_pool_reserve_address: + * @pool: a #GstRTSPAddressPool + * @ip_address: The IP address to reserve + * @port: The first port to reserve + * @n_ports: The number of ports + * @ttl: The requested ttl + * @address: (out) storage for a #GstRTSPAddress + * + * Take a specific address and ports from @pool. @n_ports consecutive + * ports will be allocated of which the first one can be found in + * @port. + * + * If @ttl is 0, @address should be a unicast address. If @ttl > 0, @address + * should be a valid multicast address. + * + * Returns: #GST_RTSP_ADDRESS_POOL_OK if an address was reserved. The address + * is returned in @address and should be freed with gst_rtsp_address_free + * after use. + */ +GstRTSPAddressPoolResult +gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, + const gchar * ip_address, guint port, guint n_ports, guint ttl, + GstRTSPAddress ** address) +{ + GstRTSPAddressPoolPrivate *priv; + Addr input_addr; + GList *list; + AddrRange *addr_range; + GstRTSPAddress *addr; + gboolean is_multicast; + GstRTSPAddressPoolResult result; + + g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), + GST_RTSP_ADDRESS_POOL_EINVAL); + g_return_val_if_fail (ip_address != NULL, GST_RTSP_ADDRESS_POOL_EINVAL); + g_return_val_if_fail (port > 0, GST_RTSP_ADDRESS_POOL_EINVAL); + g_return_val_if_fail (n_ports > 0, GST_RTSP_ADDRESS_POOL_EINVAL); + g_return_val_if_fail (address != NULL, GST_RTSP_ADDRESS_POOL_EINVAL); + + priv = pool->priv; + addr_range = NULL; + addr = NULL; + is_multicast = ttl != 0; + + if (!fill_address (ip_address, port, &input_addr, is_multicast)) + goto invalid; + + g_mutex_lock (&priv->lock); + list = find_address_in_ranges (priv->addresses, &input_addr, port, n_ports, + ttl); + if (list != NULL) { + AddrRange *range = list->data; + gint skip_port, skip_addr; + skip_addr = diff_address (&input_addr, &range->min); skip_port = port - range->min.port; /* we found a range, remove from the list */ - priv->addresses = g_list_delete_link (priv->addresses, walk); + priv->addresses = g_list_delete_link (priv->addresses, list); /* now split and exit our loop */ - result = split_range (pool, range, skip_addr, skip_port, n_ports); - priv->allocated = g_list_prepend (priv->allocated, result); - break; + addr_range = split_range (pool, range, skip_addr, skip_port, n_ports); + priv->allocated = g_list_prepend (priv->allocated, addr_range); + } + + if (addr_range) { + addr = g_slice_new0 (GstRTSPAddress); + addr->pool = g_object_ref (pool); + addr->address = get_address_string (&addr_range->min); + addr->n_ports = n_ports; + addr->port = addr_range->min.port; + addr->ttl = addr_range->ttl; + addr->priv = addr_range; + + result = GST_RTSP_ADDRESS_POOL_OK; + GST_DEBUG_OBJECT (pool, "reserved address %s:%u ttl %u", addr->address, + addr->port, addr->ttl); + } else { + /* We failed to reserve the address. Check if it was because the address + * was already in use or if it wasn't in the pool to begin with */ + list = find_address_in_ranges (priv->allocated, &input_addr, port, n_ports, + ttl); + if (list != NULL) { + result = GST_RTSP_ADDRESS_POOL_ERESERVED; + } else { + result = GST_RTSP_ADDRESS_POOL_ERANGE; + } } g_mutex_unlock (&priv->lock); - if (result) { - addr = g_slice_new0 (GstRTSPAddress); - addr->pool = g_object_ref (pool); - addr->address = get_address_string (&result->min); - addr->n_ports = n_ports; - addr->port = result->min.port; - addr->ttl = result->ttl; - addr->priv = result; - - GST_DEBUG_OBJECT (pool, "reserved address %s:%u ttl %u", addr->address, - addr->port, addr->ttl); - } - return addr; + *address = addr; + return result; /* ERRORS */ invalid: { - GST_ERROR_OBJECT (pool, "invalid address %s:%u/%u/%u", address, + GST_ERROR_OBJECT (pool, "invalid address %s:%u/%u/%u", ip_address, port, n_ports, ttl); - return NULL; + *address = NULL; + return GST_RTSP_ADDRESS_POOL_EINVAL; } } diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index 1cf908bbc5..8320dd9d62 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -33,6 +33,27 @@ G_BEGIN_DECLS #define GST_RTSP_ADDRESS_POOL_CAST(obj) ((GstRTSPAddressPool*)(obj)) #define GST_RTSP_ADDRESS_POOL_CLASS_CAST(klass) ((GstRTSPAddressPoolClass*)(klass)) +/** + * GstRTSPAddressPoolResult: + * @GST_RTSP_ADDRESS_POOL_OK: no error + * @GST_RTSP_ADDRESS_POOL_EINVAL:invalid arguments were provided to a function + * @GST_RTSP_ADDRESS_POOL_ERESERVED: the addres has already been reserved + * @GST_RTSP_ADDRESS_POOL_ERANGE: the address is not in the pool + * @GST_RTSP_ADDRESS_POOL_ELAST: last error + * + * Result codes from RTSP address pool functions. + */ +typedef enum { + GST_RTSP_ADDRESS_POOL_OK = 0, + /* errors */ + GST_RTSP_ADDRESS_POOL_EINVAL = -1, + GST_RTSP_ADDRESS_POOL_ERESERVED = -2, + GST_RTSP_ADDRESS_POOL_ERANGE = -3, + + GST_RTSP_ADDRESS_POOL_ELAST = -4, +} GstRTSPAddressPoolResult; + + typedef struct _GstRTSPAddress GstRTSPAddress; typedef struct _GstRTSPAddressPool GstRTSPAddressPool; @@ -143,11 +164,12 @@ GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool GstRTSPAddressFlags flags, gint n_ports); -GstRTSPAddress * gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, - const gchar *address, +GstRTSPAddressPoolResult gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, + const gchar *ip_address, guint port, guint n_ports, - guint ttl); + guint ttl, + GstRTSPAddress ** address); gboolean gst_rtsp_address_pool_has_unicast_addresses (GstRTSPAddressPool * pool); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 633ec55e96..e5576a1131 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -730,12 +730,14 @@ gst_rtsp_stream_reserve_address (GstRTSPStream * stream, g_mutex_lock (&priv->lock); if (*addrp == NULL) { + GstRTSPAddressPoolResult res; + if (priv->pool == NULL) goto no_pool; - *addrp = gst_rtsp_address_pool_reserve_address (priv->pool, address, - port, n_ports, ttl); - if (*addrp == NULL) + res = gst_rtsp_address_pool_reserve_address (priv->pool, address, + port, n_ports, ttl, addrp); + if (res != GST_RTSP_ADDRESS_POOL_OK) goto no_address; } else { if (strcmp ((*addrp)->address, address) || diff --git a/tests/check/gst/addresspool.c b/tests/check/gst/addresspool.c index d862929f99..f1b62e9d62 100644 --- a/tests/check/gst/addresspool.c +++ b/tests/check/gst/addresspool.c @@ -25,6 +25,7 @@ GST_START_TEST (test_pool) { GstRTSPAddressPool *pool; GstRTSPAddress *addr, *addr2, *addr3; + GstRTSPAddressPoolResult res; pool = gst_rtsp_address_pool_new (); @@ -126,47 +127,61 @@ GST_START_TEST (test_pool) fail_unless (gst_rtsp_address_pool_add_range (pool, "233.252.1.1", "233.252.1.1", 5000, 5001, 1)); - addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 3, - 1); + res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 3, + 1, &addr); + fail_unless (res == GST_RTSP_ADDRESS_POOL_ERANGE); fail_unless (addr == NULL); - addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.2", 5000, 2, - 1); + res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.2", 5000, 2, + 1, &addr); + fail_unless (res == GST_RTSP_ADDRESS_POOL_ERANGE); fail_unless (addr == NULL); - addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 500, 2, 1); + res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 500, 2, 1, + &addr); + fail_unless (res == GST_RTSP_ADDRESS_POOL_ERANGE); fail_unless (addr == NULL); - addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2, - 2); + res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2, + 2, &addr); + fail_unless (res == GST_RTSP_ADDRESS_POOL_ERANGE); fail_unless (addr == NULL); - addr = gst_rtsp_address_pool_reserve_address (pool, "2000::1", 5000, 2, 2); + res = gst_rtsp_address_pool_reserve_address (pool, "2000::1", 5000, 2, 2, + &addr); + fail_unless (res == GST_RTSP_ADDRESS_POOL_EINVAL); fail_unless (addr == NULL); - addr = gst_rtsp_address_pool_reserve_address (pool, "1.1", 5000, 2, 2); + res = gst_rtsp_address_pool_reserve_address (pool, "1.1", 5000, 2, 2, &addr); + fail_unless (res == GST_RTSP_ADDRESS_POOL_EINVAL); fail_unless (addr == NULL); - addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2, - 1); + res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2, + 1, &addr); + fail_unless (res == GST_RTSP_ADDRESS_POOL_OK); fail_unless (addr != NULL); fail_unless (addr->port == 5000); fail_unless (!strcmp (addr->address, "233.252.1.1")); + res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2, + 1, &addr2); + fail_unless (res == GST_RTSP_ADDRESS_POOL_ERESERVED); + fail_unless (addr2 == NULL); + gst_rtsp_address_free (addr); gst_rtsp_address_pool_clear (pool); fail_unless (gst_rtsp_address_pool_add_range (pool, "233.252.1.1", "233.252.1.3", 5000, 5001, 1)); - addr = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2, - 1); + res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.1", 5000, 2, + 1, &addr); fail_unless (addr != NULL); fail_unless (addr->port == 5000); fail_unless (!strcmp (addr->address, "233.252.1.1")); - addr2 = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.3", 5000, 2, - 1); + res = gst_rtsp_address_pool_reserve_address (pool, "233.252.1.3", 5000, 2, + 1, &addr2); fail_unless (addr2 != NULL); fail_unless (addr2->port == 5000); fail_unless (!strcmp (addr2->address, "233.252.1.3")); From eb03b5c17281b06969fd352cb32bf68e35cf015c Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Mon, 23 Sep 2013 14:28:04 +0200 Subject: [PATCH 0809/1776] server: Emit client-connected signal earlier Emit client-connected before the client ref is given to a GSource, otherwise client-connected can be emitted after the client object has been freed. --- gst/rtsp-server/rtsp-server.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index efc711bbe2..d126ab2d31 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -998,6 +998,9 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) GST_DEBUG_OBJECT (server, "manage client %p", client); + g_signal_emit (server, gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED], 0, + client); + cctx = g_slice_new0 (ClientContext); cctx->server = g_object_ref (server); cctx->client = client; @@ -1089,9 +1092,6 @@ gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket * socket, /* manage the client connection */ manage_client (server, client); - g_signal_emit (server, gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED], 0, - client); - return TRUE; /* ERRORS */ @@ -1156,9 +1156,6 @@ gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, /* manage the client connection */ manage_client (server, client); - - g_signal_emit (server, gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED], 0, - client); } else { GST_WARNING_OBJECT (server, "received unknown event %08x", condition); } From 986bd1346383e10cd8cb1a1c8e293f8721b8b7bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 24 Sep 2013 18:35:36 +0100 Subject: [PATCH 0810/1776] Automatic update of common submodule From 6b03ba7 to 865aa20 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 6b03ba716b..865aa20fe4 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 6b03ba716b9861277a435677ad9e31b3e14284e9 +Subproject commit 865aa20fe4b63fe6da45b1ac924c27f7ca16af13 From 74b8da93969b4462ab1c534981fdbad0d7d5d304 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Thu, 26 Sep 2013 09:41:10 +0200 Subject: [PATCH 0811/1776] client: Send setup reply once only If find_media() failed in handle_setup_request() two replies was sent. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=708819 --- gst/rtsp-server/rtsp-client.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1d192a7193..f351f24c6a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -564,11 +564,13 @@ no_factory_access: { GST_ERROR ("client %p: not authorized to see factory path %s", client, path); + /* error reply is already sent */ return NULL; } not_authorized: { GST_ERROR ("client %p: not authorized for factory path %s", client, path); + /* error reply is already sent */ return NULL; } no_media: @@ -1420,10 +1422,12 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) } else { if ((media = gst_rtsp_session_media_get_media (sessmedia))) g_object_ref (media); + else + goto media_not_found; } /* no media, not found then */ if (media == NULL) - goto media_not_found; + goto media_not_found_no_reply; if (path[matched] == '\0') goto control_not_found; @@ -1548,6 +1552,12 @@ no_pool: send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); return FALSE; } +media_not_found_no_reply: + { + GST_ERROR ("client %p: media '%s' not found", client, path); + /* error reply is already sent */ + return FALSE; + } media_not_found: { GST_ERROR ("client %p: media '%s' not found", client, path); @@ -1980,6 +1990,7 @@ session_not_found: not_authorized: { GST_ERROR ("client %p: not allowed", client); + /* error reply is already sent */ goto done; } not_implemented: From 0cd24e2257fa191c609757dc61a4bc3195408c71 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Thu, 26 Sep 2013 11:20:05 +0200 Subject: [PATCH 0812/1776] client: Reply 400 if media cannot be constructed Reply 400 Bad Request instead of 503 Service Unavailable if media cannot be constructed in SETUP. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=708821 --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f351f24c6a..f4add92211 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -576,7 +576,7 @@ not_authorized: no_media: { GST_ERROR ("client %p: can't create media", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); g_object_unref (factory); ctx->factory = NULL; return NULL; From 39dceb77ff7adfdf48814faf4ff52ea905188b2e Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Thu, 26 Sep 2013 14:36:58 +0200 Subject: [PATCH 0813/1776] tests: fix unit test Fixes https://bugzilla.gnome.org/show_bug.cgi?id=708742 --- tests/check/gst/rtspserver.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 37bace5f8c..875ca68028 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1016,9 +1016,6 @@ GST_START_TEST (test_play_multithreaded_timeout_client) GstRTSPTransport *video_transport = NULL; GstRTSPTransport *audio_transport = NULL; GstRTSPSessionPool *pool; - GstRTSPMessage *request; - GstRTSPMessage *response; - GstRTSPStatusCode code; GstRTSPThreadPool *thread_pool; thread_pool = gst_rtsp_server_get_thread_pool (server); @@ -1060,28 +1057,7 @@ GST_START_TEST (test_play_multithreaded_timeout_client) sleep (7); fail_unless (gst_rtsp_session_pool_cleanup (pool) == 1); - - - /* send TEARDOWN request and check that we get 454 Session Not found */ - request = create_request (conn, GST_RTSP_TEARDOWN, NULL); - gst_rtsp_message_add_header (request, GST_RTSP_HDR_SESSION, session); - fail_unless (send_request (conn, request)); - gst_rtsp_message_free (request); - - fail_unless (gst_rtsp_message_new (&response) == GST_RTSP_OK); - fail_unless (gst_rtsp_connection_receive (conn, response, NULL) == - GST_RTSP_OK); - gst_rtsp_message_parse_response (response, &code, NULL, NULL); - fail_unless (code == GST_RTSP_STS_SESSION_NOT_FOUND); - gst_rtsp_message_free (response); - -#if 0 - fail_unless (gst_rtsp_message_new (&response) == GST_RTSP_OK); - fail_unless (gst_rtsp_connection_receive (conn, response, NULL) == - GST_RTSP_ESYS); - fail_unless (errno == ECONNRESET); - gst_rtsp_message_free (response); -#endif + fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 0); /* clean up and iterate so the clean-up can finish */ g_object_unref (pool); From d138f79da077b913343657310a4bfd69ef4e74a3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 1 Oct 2013 17:16:11 +0200 Subject: [PATCH 0814/1776] rtsp-media: don't seek accurate by default Accurate seeking is perhaps a little overkill in the most common situation and causes some formats (mp3) over slow media to seek extremely slowly. --- gst/rtsp-server/rtsp-media.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 2c1f53defe..293a4d8b6a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1270,6 +1270,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) /* depends on the current playing state of the pipeline. We might need to * queue this until we get EOS. */ flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT; + flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT; start_type = stop_type = GST_SEEK_TYPE_NONE; From 33dc78209ca01ea0bed7ba786573ccdcb528ea39 Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Mon, 9 Sep 2013 21:51:23 -0400 Subject: [PATCH 0815/1776] media: Return FALSE if seeking is not supported --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 293a4d8b6a..cfbebaf915 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1325,7 +1325,7 @@ not_seekable: { g_rec_mutex_unlock (&priv->state_lock); GST_INFO ("pipeline is not seekable"); - return TRUE; + return FALSE; } not_supported: { From 917bbfcc20a31b15709bcf1a16a3d886fa0b7de5 Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Mon, 9 Sep 2013 21:51:44 -0400 Subject: [PATCH 0816/1776] media: Check dynamically if the pipeline supports seeking We should not depend on whether or not the pipeline state change returned NO_PREROLL or not. A media could dynamically change its element and switch from seekable to non seekable so it's best to test the seekable nature of the pipeline dynamically when we try to do a seek. --- gst/rtsp-server/rtsp-media.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index cfbebaf915..7c7eb1b397 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1251,6 +1251,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) gboolean res; GstClockTime start, stop; GstSeekType start_type, stop_type; + GstQuery *query; klass = GST_RTSP_MEDIA_GET_CLASS (media); @@ -1264,6 +1265,18 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) goto not_prepared; + /* Update the seekable state of the pipeline in case it changed */ + query = gst_query_new_seeking (GST_FORMAT_TIME); + if (gst_element_query (priv->pipeline, query)) { + GstFormat format; + gboolean seekable; + gint64 start, end; + + gst_query_parse_seeking (query, &format, &seekable, &start, &end); + priv->seekable = seekable; + } + gst_query_unref (query); + if (!priv->seekable) goto not_seekable; From fcf51d34854006aaa9011c752fa1c2cfac8a7cd9 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Tue, 1 Oct 2013 13:15:19 +0200 Subject: [PATCH 0817/1776] stream: Correct control comparison https://bugzilla.gnome.org/show_bug.cgi?id=709176 --- gst/rtsp-server/rtsp-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index e5576a1131..91512bed61 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -391,7 +391,7 @@ gst_rtsp_stream_has_control (GstRTSPStream * stream, const gchar * control) g_mutex_lock (&priv->lock); if (priv->control) - res = g_strcmp0 (priv->control, control); + res = (g_strcmp0 (priv->control, control) == 0); else { guint streamid; sscanf (control, "stream=%u", &streamid); From 59b53c90c3e4bce2fbb6dd1c9fea4527dafb9608 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 4 Oct 2013 05:48:52 +0200 Subject: [PATCH 0818/1776] rtsp-media: remove old line --- gst/rtsp-server/rtsp-media.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 7c7eb1b397..2fcbf328c7 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1282,7 +1282,6 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) /* depends on the current playing state of the pipeline. We might need to * queue this until we get EOS. */ - flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT; flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT; start_type = stop_type = GST_SEEK_TYPE_NONE; From 1742399e2369eebf5744d493b8a3c9a3f8d9bf7c Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Tue, 1 Oct 2013 14:04:17 +0200 Subject: [PATCH 0819/1776] client: Add query to control path If the SETUP url contains a query it must be appended to the control path so that it matches any already created stream in the media. The query will also be appended to the session media path. --- gst/rtsp-server/rtsp-client.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f4add92211..4f1c3c9c21 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1389,7 +1389,10 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) goto no_uri; uri = ctx->uri; - path = uri->abspath; + if (uri->query) + path = g_strconcat (uri->abspath, "?", uri->query, NULL); + else + path = g_strdup (uri->abspath); /* parse the transport */ res = @@ -1528,6 +1531,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) break; } g_object_unref (session); + g_free (path); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], 0, ctx); @@ -1544,17 +1548,20 @@ no_transport: { GST_ERROR ("client %p: no transport", client); send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); + g_free (path); return FALSE; } no_pool: { GST_ERROR ("client %p: no session pool configured", client); send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); + g_free (path); return FALSE; } media_not_found_no_reply: { GST_ERROR ("client %p: media '%s' not found", client, path); + g_free (path); /* error reply is already sent */ return FALSE; } @@ -1562,6 +1569,7 @@ media_not_found: { GST_ERROR ("client %p: media '%s' not found", client, path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + g_free (path); return FALSE; } control_not_found: @@ -1569,6 +1577,7 @@ control_not_found: GST_ERROR ("client %p: no control in path '%s'", client, path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); g_object_unref (media); + g_free (path); return FALSE; } stream_not_found: @@ -1576,6 +1585,7 @@ stream_not_found: GST_ERROR ("client %p: stream '%s' not found", client, control); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); g_object_unref (media); + g_free (path); return FALSE; } service_unavailable: @@ -1583,6 +1593,7 @@ service_unavailable: GST_ERROR ("client %p: can't create session", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (media); + g_free (path); return FALSE; } sessmedia_unavailable: @@ -1591,6 +1602,7 @@ sessmedia_unavailable: send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (media); g_object_unref (session); + g_free (path); return FALSE; } invalid_blocksize: @@ -1598,6 +1610,7 @@ invalid_blocksize: GST_ERROR ("client %p: invalid blocksize", client); send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); g_object_unref (session); + g_free (path); return FALSE; } unsupported_transports: @@ -1606,6 +1619,7 @@ unsupported_transports: send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); gst_rtsp_transport_free (ct); g_object_unref (session); + g_free (path); return FALSE; } unsupported_client_transport: @@ -1614,6 +1628,7 @@ unsupported_client_transport: send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); gst_rtsp_transport_free (ct); g_object_unref (session); + g_free (path); return FALSE; } } From d4b8a8249c1826c1074bcd5b12973d442057a94b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 4 Oct 2013 06:29:30 +0200 Subject: [PATCH 0820/1776] client: append query string in PAUSE/PLAY/TEARDOWN as well --- gst/rtsp-server/rtsp-client.c | 39 +++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4f1c3c9c21..a16daaff53 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -711,6 +711,19 @@ close_connection (GstRTSPClient * client) gst_rtsp_connection_close (priv->connection); } +static gchar * +make_path_from_uri (GstRTSPClient * client, GstRTSPUrl * uri) +{ + gchar *path; + + if (uri->query) + path = g_strconcat (uri->abspath, "?", uri->query, NULL); + else + path = g_strdup (uri->abspath); + + return path; +} + static gboolean handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) { @@ -718,7 +731,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; GstRTSPStatusCode code; - const gchar *path; + gchar *path; gint matched; if (!ctx->session) @@ -729,7 +742,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!ctx->uri) goto no_uri; - path = ctx->uri->abspath; + path = make_path_from_uri (client, ctx->uri); /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -740,6 +753,8 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) if (path[matched] != '\0') goto no_aggregate; + g_free (path); + ctx->sessmedia = sessmedia; /* we emit the signal before closing the connection */ @@ -786,6 +801,7 @@ not_found: { GST_ERROR ("client %p: no media for uri", client); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + g_free (path); return FALSE; } no_aggregate: @@ -793,6 +809,7 @@ no_aggregate: GST_ERROR ("client %p: no aggregate path %s", client, path); send_generic_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); + g_free (path); return FALSE; } } @@ -898,7 +915,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPSessionMedia *sessmedia; GstRTSPStatusCode code; GstRTSPState rtspstate; - const gchar *path; + gchar *path; gint matched; if (!(session = ctx->session)) @@ -907,7 +924,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!ctx->uri) goto no_uri; - path = ctx->uri->abspath; + path = make_path_from_uri (client, ctx->uri); /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -917,6 +934,8 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) if (path[matched] != '\0') goto no_aggregate; + g_free (path); + ctx->sessmedia = sessmedia; rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); @@ -962,6 +981,7 @@ not_found: { GST_ERROR ("client %p: no media for uri", client); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + g_free (path); return FALSE; } no_aggregate: @@ -969,6 +989,7 @@ no_aggregate: GST_ERROR ("client %p: no aggregate path %s", client, path); send_generic_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); + g_free (path); return FALSE; } invalid_state: @@ -1026,7 +1047,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!(uri = ctx->uri)) goto no_uri; - path = uri->abspath; + path = make_path_from_uri (client, uri); /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -1098,6 +1119,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) } } g_free (base_url); + g_free (path); /* construct the response now */ code = GST_RTSP_STS_OK; @@ -1152,6 +1174,7 @@ no_aggregate: GST_ERROR ("client %p: no aggregate path %s", client, path); send_generic_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); + g_free (path); return FALSE; } invalid_state: @@ -1159,6 +1182,7 @@ invalid_state: GST_ERROR ("client %p: not PLAYING or READY", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx); + g_free (path); return FALSE; } } @@ -1389,10 +1413,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) goto no_uri; uri = ctx->uri; - if (uri->query) - path = g_strconcat (uri->abspath, "?", uri->query, NULL); - else - path = g_strdup (uri->abspath); + path = make_path_from_uri (client, uri); /* parse the transport */ res = From cf82d90452a12637ee2fb6d5a99d1a9253721dcd Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Mon, 14 Oct 2013 19:36:24 +0200 Subject: [PATCH 0821/1776] tests: Improve address pool unit tests Add a range with mixed IPV4 and IPV6 addresses to pool. Get an IPV4 address from an IPV6-only pool. Get an IPV6 address from an IPV4-only pool. Reserve a IPV6 address from an IPV4-only pool. Check for unicast addresses in multicast-only pool. Check for unicast addresses in uni-/multicast-mixed pool. https://bugzilla.gnome.org/show_bug.cgi?id=710128 --- tests/check/gst/addresspool.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/check/gst/addresspool.c b/tests/check/gst/addresspool.c index f1b62e9d62..b3ca24d9a6 100644 --- a/tests/check/gst/addresspool.c +++ b/tests/check/gst/addresspool.c @@ -33,6 +33,8 @@ GST_START_TEST (test_pool) "233.252.0.1", "233.252.0.0", 5000, 5010, 1)); fail_if (gst_rtsp_address_pool_add_range (pool, "233.252.0.1", "::1", 5000, 5010, 1)); + fail_if (gst_rtsp_address_pool_add_range (pool, + "233.252.0.1", "ff02::1", 5000, 5010, 1)); fail_if (gst_rtsp_address_pool_add_range (pool, "233.252.0.1.1", "233.252.0.1", 5000, 5010, 1)); fail_if (gst_rtsp_address_pool_add_range (pool, @@ -99,6 +101,10 @@ GST_START_TEST (test_pool) GST_RTSP_ADDRESS_FLAG_MULTICAST, 1); fail_unless (addr2 == NULL); + addr2 = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_IPV4 | GST_RTSP_ADDRESS_FLAG_MULTICAST, 1); + fail_unless (addr2 == NULL); + gst_rtsp_address_free (addr); gst_rtsp_address_pool_clear (pool); @@ -121,8 +127,11 @@ GST_START_TEST (test_pool) gst_rtsp_address_free (addr); gst_rtsp_address_free (addr2); - gst_rtsp_address_pool_clear (pool); + addr = gst_rtsp_address_pool_acquire_address (pool, + GST_RTSP_ADDRESS_FLAG_IPV6 | GST_RTSP_ADDRESS_FLAG_MULTICAST, 1); + fail_unless (addr == NULL); + gst_rtsp_address_pool_clear (pool); fail_unless (gst_rtsp_address_pool_add_range (pool, "233.252.1.1", "233.252.1.1", 5000, 5001, 1)); @@ -152,6 +161,11 @@ GST_START_TEST (test_pool) fail_unless (res == GST_RTSP_ADDRESS_POOL_EINVAL); fail_unless (addr == NULL); + res = gst_rtsp_address_pool_reserve_address (pool, "ff02::1", 5000, 2, 2, + &addr); + fail_unless (res == GST_RTSP_ADDRESS_POOL_ERANGE); + fail_unless (addr == NULL); + res = gst_rtsp_address_pool_reserve_address (pool, "1.1", 5000, 2, 2, &addr); fail_unless (res == GST_RTSP_ADDRESS_POOL_EINVAL); fail_unless (addr == NULL); @@ -203,8 +217,10 @@ GST_START_TEST (test_pool) fail_unless (gst_rtsp_address_pool_add_range (pool, "233.252.1.1", "233.252.1.1", 5000, 5001, 1)); + fail_if (gst_rtsp_address_pool_has_unicast_addresses (pool)); fail_unless (gst_rtsp_address_pool_add_range (pool, "192.168.1.1", "192.168.1.1", 6000, 6001, 0)); + fail_unless (gst_rtsp_address_pool_has_unicast_addresses (pool)); addr = gst_rtsp_address_pool_acquire_address (pool, GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST, 2); From de7be1c9b2fef55ad9bad38dcb508671bb504d98 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Mon, 14 Oct 2013 08:30:33 +0200 Subject: [PATCH 0822/1776] tests: fixed racy behavior in rtspserver tests https://bugzilla.gnome.org/show_bug.cgi?id=710078 --- gst/rtsp-server/rtsp-server.c | 23 ++++++++++++++ tests/check/gst/rtspserver.c | 58 ++++++++++------------------------- 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index d126ab2d31..208731eef4 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -842,6 +842,29 @@ gst_rtsp_server_create_socket (GstRTSPServer * server, } if (g_socket_bind (socket, sockaddr, TRUE, bind_error ? NULL : &bind_error)) { + /* ask what port the socket has been bound to */ + if (port == 0 || !strcmp (priv->service, "0")) { + GError *addr_error = NULL; + + g_object_unref (sockaddr); + sockaddr = g_socket_get_local_address (socket, &addr_error); + + if (addr_error != NULL) { + GST_DEBUG_OBJECT (server, + "failed to get the local address of a bound socket %s", + addr_error->message); + g_clear_error (&addr_error); + break; + } + port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (sockaddr)); + + if (port != 0) { + g_free (priv->service); + priv->service = g_strdup_printf ("%d", port); + } else { + GST_DEBUG_OBJECT (server, "failed to get the port of a bound socket"); + } + } g_object_unref (sockaddr); break; } diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 875ca68028..fb932dfcc1 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -61,38 +61,6 @@ iterate (void) } } -/* returns an unused port that can be used by the test */ -static int -get_unused_port (gint type) -{ - int sock; - struct sockaddr_in addr; - socklen_t addr_len; - gint port; - - /* create socket */ - fail_unless ((sock = socket (AF_INET, type, 0)) > 0); - - /* pass port 0 to bind, which will bind to any free port */ - memset (&addr, 0, sizeof addr); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons (0); - fail_unless (bind (sock, (struct sockaddr *) &addr, sizeof addr) == 0); - - /* ask what port was bound using getsockname */ - addr_len = sizeof addr; - memset (&addr, 0, addr_len); - fail_unless (getsockname (sock, (struct sockaddr *) &addr, &addr_len) == 0); - port = ntohs (addr.sin_port); - - /* close the socket so the port gets unbound again (and can be used by the - * test) */ - close (sock); - - return port; -} - static void get_client_ports_full (GstRTSPRange * range, GSocket ** rtp_socket, GSocket ** rtcp_socket) @@ -197,16 +165,19 @@ start_server (void) gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); g_object_unref (mounts); - /* set port */ - test_port = get_unused_port (SOCK_STREAM); - service = g_strdup_printf ("%d", test_port); - gst_rtsp_server_set_service (server, service); - g_free (service); + /* set port to any */ + gst_rtsp_server_set_service (server, "0"); /* attach to default main context */ source_id = gst_rtsp_server_attach (server, NULL); fail_if (source_id == 0); + /* get port */ + service = gst_rtsp_server_get_service (server); + test_port = atoi (service); + fail_unless (test_port != 0); + g_free (service); + GST_DEBUG ("rtsp server listening on port %d", test_port); } @@ -1252,16 +1223,19 @@ GST_START_TEST (test_play_specific_server_port) gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); g_object_unref (mounts); - /* set port */ - test_port = get_unused_port (SOCK_STREAM); - service = g_strdup_printf ("%d", test_port); - gst_rtsp_server_set_service (server, service); - g_free (service); + /* set port to any */ + gst_rtsp_server_set_service (server, "0"); /* attach to default main context */ source_id = gst_rtsp_server_attach (server, NULL); fail_if (source_id == 0); + /* get port */ + service = gst_rtsp_server_get_service (server); + test_port = atoi (service); + fail_unless (test_port != 0); + g_free (service); + GST_DEBUG ("rtsp server listening on port %d", test_port); From 78e5a9148e6ba8d80fd3f2e78043abd7a434ec23 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 9 Oct 2013 15:25:10 +0200 Subject: [PATCH 0823/1776] thread-pool: Fix thread leak when reusing threads https://bugzilla.gnome.org/show_bug.cgi?id=709730 --- gst/rtsp-server/rtsp-thread-pool.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index 5907acc739..eb82e349c7 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -143,10 +143,10 @@ gst_rtsp_thread_reuse (GstRTSPThread * thread) /** * gst_rtsp_thread_stop: - * @thread: a #GstRTSPThread + * @thread: (transfer full): a #GstRTSPThread * - * Stop @thread. When no threads are using the mainloop, the thread will be - * stopped and the final ref to @thread will be released. + * Stop and unref @thread. When no threads are using the mainloop, the thread + * will be stopped and the final ref to @thread will be released. */ void gst_rtsp_thread_stop (GstRTSPThread * thread) @@ -161,6 +161,8 @@ gst_rtsp_thread_stop (GstRTSPThread * thread) GST_DEBUG ("stop mainloop of thread %p", thread); g_main_loop_quit (thread->loop); } + + gst_rtsp_thread_unref (thread); } #define GST_RTSP_THREAD_POOL_GET_PRIVATE(obj) \ @@ -450,7 +452,8 @@ default_get_thread (GstRTSPThreadPool * pool, GST_DEBUG_OBJECT (pool, "make new client thread"); thread = make_thread (pool, type, ctx); - if (!g_thread_pool_push (klass->pool, thread, &error)) + if (!g_thread_pool_push (klass->pool, gst_rtsp_thread_ref (thread), + &error)) goto thread_error; } g_queue_push_tail (&priv->threads, thread); @@ -461,7 +464,8 @@ default_get_thread (GstRTSPThreadPool * pool, GST_DEBUG_OBJECT (pool, "make new media thread"); thread = make_thread (pool, type, ctx); - if (!g_thread_pool_push (klass->pool, thread, &error)) + if (!g_thread_pool_push (klass->pool, gst_rtsp_thread_ref (thread), + &error)) goto thread_error; break; default: @@ -475,6 +479,8 @@ thread_error: { GST_ERROR_OBJECT (pool, "failed to push thread %s", error->message); gst_rtsp_thread_unref (thread); + /* drop also the ref dedicated for the pool */ + gst_rtsp_thread_unref (thread); g_clear_error (&error); return NULL; } From fa7898b0a61bed689cff7f57285be561d7ab5028 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 9 Oct 2013 15:19:12 +0200 Subject: [PATCH 0824/1776] thread-pool: Add unit test for the thread pools https://bugzilla.gnome.org/show_bug.cgi?id=710228 --- tests/check/Makefile.am | 3 +- tests/check/gst/threadpool.c | 90 ++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 tests/check/gst/threadpool.c diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index ff17bbf2bf..54aa0df9e3 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -31,7 +31,8 @@ check_PROGRAMS = \ gst/mountpoints \ gst/mediafactory \ gst/media \ - gst/addresspool + gst/addresspool \ + gst/threadpool # these tests don't even pass noinst_PROGRAMS = diff --git a/tests/check/gst/threadpool.c b/tests/check/gst/threadpool.c new file mode 100644 index 0000000000..735584a34c --- /dev/null +++ b/tests/check/gst/threadpool.c @@ -0,0 +1,90 @@ +/* GStreamer + * unit tests for GstRTSPThreadPool + * Copyright (C) 2013 Axis Communications + * @author Ognyan Tonchev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +GST_START_TEST (test_pool_get_thread) +{ + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + + pool = gst_rtsp_thread_pool_new (); + fail_unless (pool != NULL); + + thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, + NULL); + fail_unless (thread != NULL); + + gst_rtsp_thread_stop (thread); + g_object_unref (pool); + gst_rtsp_thread_pool_cleanup (); +} + +GST_END_TEST; + +GST_START_TEST (test_pool_get_thread_reuse) +{ + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + GstRTSPThread *thread2; + + pool = gst_rtsp_thread_pool_new (); + fail_unless (pool != NULL); + + gst_rtsp_thread_pool_set_max_threads (pool, 1); + + thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, + NULL); + fail_unless (thread != NULL); + + thread2 = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, + NULL); + fail_unless (thread2 != NULL); + + fail_unless (thread == thread2); + + gst_rtsp_thread_stop (thread); + gst_rtsp_thread_stop (thread2); + g_object_unref (pool); + + gst_rtsp_thread_pool_cleanup (); +} + +GST_END_TEST; + + +static Suite * +rtspthreadpool_suite (void) +{ + Suite *s = suite_create ("rtspthreadpool"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_set_timeout (tc, 20); + tcase_add_test (tc, test_pool_get_thread); + tcase_add_test (tc, test_pool_get_thread_reuse); + + return s; +} + +GST_CHECK_MAIN (rtspthreadpool); From c96f1aaff7bc7e286275e35f526c6921881c6858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 30 Oct 2013 19:10:59 +0100 Subject: [PATCH 0825/1776] gitignore: Add new test binary --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 04c2d86a8e..d5d2e50228 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ stamp-h.in /tests/check/gst/mediafactory /tests/check/gst/mountpoints /tests/check/gst/rtspserver +/tests/check/gst/threadpool /tests/check/test-registry.reg /tests/test-reuse From fcad523dd7c4115668de6993e139e7da852364e7 Mon Sep 17 00:00:00 2001 From: Aleix Conchillo Flaque Date: Tue, 15 Oct 2013 16:37:34 -0700 Subject: [PATCH 0826/1776] examples: fix compilation when WITH_AUTH is defined https://bugzilla.gnome.org/show_bug.cgi?id=710228 --- examples/.gitignore | 1 + examples/test-video.c | 17 ++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/.gitignore b/examples/.gitignore index 6912d88c0b..82e4c5ed5e 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,3 +1,4 @@ +test-appsrc test-launch test-mp4 test-ogg diff --git a/examples/test-video.c b/examples/test-video.c index 4a8e2058b0..9bfb9d6427 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -25,7 +25,8 @@ * user/password as the password */ #undef WITH_AUTH -/* define this if you want the server to use TLS */ +/* define this if you want the server to use TLS (it will also need WITH_AUTH + * to be defined) */ #undef WITH_TLS /* this timeout is periodically run to clean up the expired sessions from the @@ -53,7 +54,6 @@ main (int argc, char *argv[]) #ifdef WITH_AUTH GstRTSPAuth *auth; GstRTSPToken *token; - GstStructure *s; gchar *basic; GstRTSPPermissions *permissions; #endif @@ -101,9 +101,9 @@ main (int argc, char *argv[]) #endif /* make user token */ - token = gst_rtsp_token_new (); - s = gst_rtsp_token_writable_structure (token); - gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "user", NULL); + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); basic = gst_rtsp_auth_make_basic ("user", "password"); gst_rtsp_auth_add_basic (auth, basic, token); g_free (basic); @@ -118,7 +118,7 @@ main (int argc, char *argv[]) mounts = gst_rtsp_server_get_mount_points (server); /* make a media factory for a test stream. The default media factory can use - * gst-launch syntax to create pipelines. + * gst-launch syntax to create pipelines. * any launch line works as long as it contains elements named pay%d. Each * element with pay%d names will be a stream */ factory = gst_rtsp_media_factory_new (); @@ -131,9 +131,8 @@ main (int argc, char *argv[]) /* add permissions for the user media role */ permissions = gst_rtsp_permissions_new (); gst_rtsp_permissions_add_role (permissions, "user", - gst_structure_new ("user", - "media.factory.access", G_TYPE_BOOLEAN, TRUE, - "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL)); + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL); gst_rtsp_media_factory_set_permissions (factory, permissions); gst_rtsp_permissions_unref (permissions); #endif From 935e8f852d050b4939f1d0f44b38e9b55a2fbe36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 30 Oct 2013 22:16:54 +0100 Subject: [PATCH 0827/1776] rtsp-session-pool: Make sure session IDs are properly URI-escaped https://bugzilla.gnome.org/show_bug.cgi?id=643812 --- gst/rtsp-server/rtsp-session-pool.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index d18c11c14f..be07820094 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -293,7 +293,7 @@ gst_rtsp_session_pool_find (GstRTSPSessionPool * pool, const gchar * sessionid) static gchar * create_session_id (GstRTSPSessionPool * pool) { - gchar id[16]; + gchar id[17]; gint i; for (i = 0; i < 16; i++) { @@ -301,8 +301,9 @@ create_session_id (GstRTSPSessionPool * pool) session_id_charset[g_random_int_range (0, G_N_ELEMENTS (session_id_charset))]; } + id[16] = 0; - return g_strndup (id, 16); + return g_uri_escape_string (id, NULL, FALSE); } static GstRTSPSession * From 7b34d1e9153cdd404fe9996dff4c4837a2865973 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 14 Oct 2013 12:03:07 +0200 Subject: [PATCH 0828/1776] rtsp-server: Fix socket leak https://bugzilla.gnome.org/show_bug.cgi?id=710088 --- gst/rtsp-server/rtsp-server.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 208731eef4..1afbba710e 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1078,7 +1078,7 @@ default_create_client (GstRTSPServer * server) /** * gst_rtsp_server_transfer_connection: * @server: a #GstRTSPServer - * @socket: a network socket + * @socket: (transfer full): a network socket * @ip: the IP address of the remote client * @port: the port used by the other end * @initial_buffer: any initial data that was already read from the socket @@ -1108,6 +1108,7 @@ gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket * socket, GST_RTSP_CHECK (gst_rtsp_connection_create_from_socket (socket, ip, port, initial_buffer, &conn), no_connection); + g_object_unref (socket); /* set connection on the client now */ gst_rtsp_client_set_connection (client, conn); @@ -1121,6 +1122,7 @@ gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket * socket, client_failed: { GST_ERROR_OBJECT (server, "failed to create a client"); + g_object_unref (socket); return FALSE; } no_connection: @@ -1128,6 +1130,7 @@ no_connection: gchar *str = gst_rtsp_strresult (res); GST_ERROR ("could not create connection from socket %p: %s", socket, str); g_free (str); + g_object_unref (socket); return FALSE; } } From 7e8f6ffc343b347812c57ec349ec6e76bb29f0d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 5 Nov 2013 11:22:51 +0000 Subject: [PATCH 0829/1776] Automatic update of common submodule From 865aa20 to dbedaa0 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 865aa20fe4..dbedaa010e 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 865aa20fe4b63fe6da45b1ac924c27f7ca16af13 +Subproject commit dbedaa010e2a19af2b27451c7c64111ea2f8dad2 From eee8b0db8835716e81e9c42c1f9ee58dbb04e2f1 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Tue, 15 Oct 2013 18:01:38 +0200 Subject: [PATCH 0830/1776] tests: Check gst_rtsp_url_parse return value See https://bugzilla.gnome.org/show_bug.cgi?id=710202 --- tests/check/gst/media.c | 12 ++++++++---- tests/check/gst/mediafactory.c | 15 ++++++++++----- tests/check/gst/rtspserver.c | 2 +- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 6b4b2a045b..ca2c324b0d 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -34,7 +34,8 @@ GST_START_TEST (test_launch) factory = gst_rtsp_media_factory_new (); fail_if (gst_rtsp_media_factory_is_shared (factory)); - gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); gst_rtsp_media_factory_set_launch (factory, "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); @@ -135,7 +136,8 @@ GST_START_TEST (test_media_prepare) /* test non-reusable media first */ factory = gst_rtsp_media_factory_new (); fail_if (gst_rtsp_media_factory_is_shared (factory)); - gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); gst_rtsp_media_factory_set_launch (factory, "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); @@ -161,7 +163,8 @@ GST_START_TEST (test_media_prepare) /* test reusable media */ factory = gst_rtsp_media_factory_new (); fail_if (gst_rtsp_media_factory_is_shared (factory)); - gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); gst_rtsp_media_factory_set_launch (factory, "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); @@ -279,7 +282,8 @@ GST_START_TEST (test_media_take_pipeline) GstElement *pipeline; factory = gst_rtsp_media_factory_new (); - gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); gst_rtsp_media_factory_set_launch (factory, "( fakesrc ! text/plain ! rtpgstpay name=pay0 )"); diff --git a/tests/check/gst/mediafactory.c b/tests/check/gst/mediafactory.c index ab791cd427..37b56aa2a3 100644 --- a/tests/check/gst/mediafactory.c +++ b/tests/check/gst/mediafactory.c @@ -29,7 +29,8 @@ GST_START_TEST (test_parse_error) factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, "foo"); - gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); ASSERT_CRITICAL (gst_rtsp_media_factory_create_element (factory, url)); ASSERT_CRITICAL (gst_rtsp_media_factory_construct (factory, url)); @@ -47,7 +48,8 @@ GST_START_TEST (test_launch) factory = gst_rtsp_media_factory_new (); fail_if (gst_rtsp_media_factory_is_shared (factory)); - gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); gst_rtsp_media_factory_set_launch (factory, "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); @@ -71,7 +73,8 @@ GST_START_TEST (test_launch_construct) factory = gst_rtsp_media_factory_new (); fail_if (gst_rtsp_media_factory_is_shared (factory)); - gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); gst_rtsp_media_factory_set_launch (factory, "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); @@ -103,7 +106,8 @@ GST_START_TEST (test_shared) gst_rtsp_media_factory_set_shared (factory, TRUE); fail_unless (gst_rtsp_media_factory_is_shared (factory)); - gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); gst_rtsp_media_factory_set_launch (factory, "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); @@ -141,7 +145,8 @@ GST_START_TEST (test_addresspool) factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_shared (factory, TRUE); - gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); gst_rtsp_media_factory_set_launch (factory, "( videotestsrc ! rtpvrawpay pt=96 name=pay0 " diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index fb932dfcc1..54effd9d62 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -203,7 +203,7 @@ connect_to_server (gint port, const gchar * mount_point) address = gst_rtsp_server_get_address (server); uri_string = g_strdup_printf ("rtsp://%s:%d%s", address, port, mount_point); g_free (address); - gst_rtsp_url_parse (uri_string, &url); + fail_unless (gst_rtsp_url_parse (uri_string, &url) == GST_RTSP_OK); g_free (uri_string); fail_unless (gst_rtsp_connection_create (url, &conn) == GST_RTSP_OK); From 4036f210af2ae6081b5c79971a9068ab43421b7a Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Sat, 19 Oct 2013 17:39:35 +0200 Subject: [PATCH 0831/1776] permissions: Fix refcounting when adding/removing roles Previously a role that was removed was unreffed twice, and when replacing an existing role the replaced role was freed while still being referenced. Both bugs are now fixed. See https://bugzilla.gnome.org/show_bug.cgi?id=710202 --- gst/rtsp-server/rtsp-permissions.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index 25872c65c1..ae60b962dd 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -161,7 +161,6 @@ gst_rtsp_permissions_add_role_valist (GstRTSPPermissions * permissions, GstRTSPPermissionsImpl *impl = (GstRTSPPermissionsImpl *) permissions; GstStructure *structure; guint i, len; - gboolean found; g_return_if_fail (GST_IS_RTSP_PERMISSIONS (permissions)); g_return_if_fail (gst_mini_object_is_writable (&permissions->mini_object)); @@ -172,23 +171,18 @@ gst_rtsp_permissions_add_role_valist (GstRTSPPermissions * permissions, g_return_if_fail (structure != NULL); len = impl->roles->len; - found = FALSE; for (i = 0; i < len; i++) { GstStructure *entry = g_ptr_array_index (impl->roles, i); if (gst_structure_has_name (entry, role)) { - gst_structure_free (entry); - found = TRUE; + g_ptr_array_remove_index_fast (impl->roles, i); break; } } gst_structure_set_parent_refcount (structure, &impl->permissions.mini_object.refcount); - if (!found) - g_ptr_array_add (impl->roles, structure); - else - g_ptr_array_index (impl->roles, i) = structure; + g_ptr_array_add (impl->roles, structure); } /** @@ -215,7 +209,6 @@ gst_rtsp_permissions_remove_role (GstRTSPPermissions * permissions, if (gst_structure_has_name (entry, role)) { g_ptr_array_remove_index_fast (impl->roles, i); - gst_structure_free (entry); break; } } From c0828a5d53648d6140fc8c37c52a92d60e9137f5 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Tue, 15 Oct 2013 18:50:47 +0200 Subject: [PATCH 0832/1776] tests: Test mediafactory permissions See https://bugzilla.gnome.org/show_bug.cgi?id=710202 --- tests/check/gst/mediafactory.c | 71 ++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/check/gst/mediafactory.c b/tests/check/gst/mediafactory.c index 37b56aa2a3..73e4883207 100644 --- a/tests/check/gst/mediafactory.c +++ b/tests/check/gst/mediafactory.c @@ -210,6 +210,76 @@ GST_START_TEST (test_addresspool) GST_END_TEST; +GST_START_TEST (test_permissions) +{ + GstRTSPMediaFactory *factory; + GstRTSPPermissions *perms; + GstRTSPMedia *media; + GstRTSPUrl *url; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + gst_rtsp_media_factory_add_role (factory, "admin", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); + + perms = gst_rtsp_media_factory_get_permissions (factory); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "admin", + "media.factory.access")); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "admin", + "media.factory.construct")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "missing", + "media.factory.access")); + gst_rtsp_permissions_unref (perms); + + perms = gst_rtsp_permissions_new (); + gst_rtsp_permissions_add_role (perms, "user", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, FALSE, NULL); + gst_rtsp_media_factory_set_permissions (factory, perms); + gst_rtsp_permissions_unref (perms); + + perms = gst_rtsp_media_factory_get_permissions (factory); + fail_if (gst_rtsp_permissions_is_allowed (perms, "admin", + "media.factory.access")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "admin", + "media.factory.construct")); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "user", + "media.factory.access")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "user", + "media.factory.construct")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "missing", + "media.factory.access")); + gst_rtsp_permissions_unref (perms); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + perms = gst_rtsp_media_get_permissions (media); + fail_if (gst_rtsp_permissions_is_allowed (perms, "admin", + "media.factory.access")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "admin", + "media.factory.construct")); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "user", + "media.factory.access")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "user", + "media.factory.construct")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "missing", + "media.factory.access")); + gst_rtsp_permissions_unref (perms); + g_object_unref (media); + + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + static Suite * rtspmediafactory_suite (void) { @@ -223,6 +293,7 @@ rtspmediafactory_suite (void) tcase_add_test (tc, test_launch_construct); tcase_add_test (tc, test_shared); tcase_add_test (tc, test_addresspool); + tcase_add_test (tc, test_permissions); return s; } From a2eb48a27c4a68e1cbadf5a57055ac15046014c3 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Sat, 19 Oct 2013 17:36:05 +0200 Subject: [PATCH 0833/1776] tests: Add unit tests for permissions Fixes https://bugzilla.gnome.org/show_bug.cgi?id=710202 --- tests/check/Makefile.am | 1 + tests/check/gst/permissions.c | 107 ++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 tests/check/gst/permissions.c diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 54aa0df9e3..49675bde6a 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -33,6 +33,7 @@ check_PROGRAMS = \ gst/media \ gst/addresspool \ gst/threadpool + gst/permissions # these tests don't even pass noinst_PROGRAMS = diff --git a/tests/check/gst/permissions.c b/tests/check/gst/permissions.c new file mode 100644 index 0000000000..0dcf7703b3 --- /dev/null +++ b/tests/check/gst/permissions.c @@ -0,0 +1,107 @@ +/* GStreamer + * Copyright (C) 2013 Sebastian Rasmussen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +GST_START_TEST (test_permissions) +{ + GstRTSPPermissions *perms; + GstRTSPPermissions *copy; + + perms = gst_rtsp_permissions_new (); + fail_if (gst_rtsp_permissions_is_allowed (perms, "missing", "permission1")); + gst_rtsp_permissions_unref (perms); + + perms = gst_rtsp_permissions_new (); + gst_rtsp_permissions_add_role (perms, "user", + "permission1", G_TYPE_BOOLEAN, TRUE, + "permission2", G_TYPE_BOOLEAN, FALSE, NULL); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "user", "permission1")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "user", "permission2")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "user", "missing")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "missing", "permission1")); + copy = GST_RTSP_PERMISSIONS (gst_mini_object_copy (GST_MINI_OBJECT (perms))); + gst_rtsp_permissions_unref (perms); + fail_unless (gst_rtsp_permissions_is_allowed (copy, "user", "permission1")); + fail_if (gst_rtsp_permissions_is_allowed (copy, "user", "permission2")); + gst_rtsp_permissions_unref (copy); + + perms = gst_rtsp_permissions_new (); + gst_rtsp_permissions_add_role (perms, "admin", + "permission1", G_TYPE_BOOLEAN, TRUE, + "permission2", G_TYPE_BOOLEAN, TRUE, NULL); + gst_rtsp_permissions_add_role (perms, "user", + "permission1", G_TYPE_BOOLEAN, TRUE, + "permission2", G_TYPE_BOOLEAN, FALSE, NULL); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "admin", "permission1")); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "admin", "permission2")); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "user", "permission1")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "user", "permission2")); + gst_rtsp_permissions_unref (perms); + + perms = gst_rtsp_permissions_new (); + gst_rtsp_permissions_add_role (perms, "user", + "permission1", G_TYPE_BOOLEAN, TRUE, + "permission2", G_TYPE_BOOLEAN, FALSE, NULL); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "user", "permission1")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "user", "permission2")); + gst_rtsp_permissions_add_role (perms, "user", + "permission1", G_TYPE_BOOLEAN, FALSE, + "permission2", G_TYPE_BOOLEAN, TRUE, NULL); + fail_if (gst_rtsp_permissions_is_allowed (perms, "user", "permission1")); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "user", "permission2")); + gst_rtsp_permissions_unref (perms); + + perms = gst_rtsp_permissions_new (); + gst_rtsp_permissions_add_role (perms, "admin", + "permission1", G_TYPE_BOOLEAN, TRUE, + "permission2", G_TYPE_BOOLEAN, TRUE, NULL); + gst_rtsp_permissions_add_role (perms, "user", + "permission1", G_TYPE_BOOLEAN, TRUE, + "permission2", G_TYPE_BOOLEAN, FALSE, NULL); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "admin", "permission1")); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "admin", "permission2")); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "user", "permission1")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "user", "permission2")); + gst_rtsp_permissions_remove_role (perms, "user"); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "admin", "permission1")); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "admin", "permission2")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "user", "permission1")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "user", "permission2")); + gst_rtsp_permissions_unref (perms); +} + +GST_END_TEST; + +static Suite * +rtsppermissions_suite (void) +{ + Suite *s = suite_create ("rtsppermissions"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_set_timeout (tc, 20); + tcase_add_test (tc, test_permissions); + + return s; +} + +GST_CHECK_MAIN (rtsppermissions); From c4ae13dbb50760d408ed027db3e4ffa009b063ac Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 12 Nov 2013 10:28:55 +0100 Subject: [PATCH 0834/1776] thread-pool: avoid race in shutdown If we call g_main_loop_quit before the thread has entered g_main_loop_run, we don't actually stop the mainloop ever. Solve this race by adding an idle source to the mainloop that calls the _quit. This way we immediately exit the mainloop if quit was called before we started it. --- gst/rtsp-server/rtsp-thread-pool.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index eb82e349c7..0a12fd136d 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -141,6 +141,14 @@ gst_rtsp_thread_reuse (GstRTSPThread * thread) return g_atomic_int_add (&impl->reused, 1) > 0; } +static gboolean +do_quit (GstRTSPThread * thread) +{ + GST_DEBUG ("stop mainloop of thread %p", thread); + g_main_loop_quit (thread->loop); + return FALSE; +} + /** * gst_rtsp_thread_stop: * @thread: (transfer full): a #GstRTSPThread @@ -158,11 +166,15 @@ gst_rtsp_thread_stop (GstRTSPThread * thread) GST_DEBUG ("stop thread %p", thread); if (g_atomic_int_dec_and_test (&impl->reused)) { - GST_DEBUG ("stop mainloop of thread %p", thread); - g_main_loop_quit (thread->loop); - } + GSource *source; - gst_rtsp_thread_unref (thread); + GST_DEBUG ("add idle source to quit mainloop of thread %p", thread); + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) do_quit, + thread, (GDestroyNotify) gst_rtsp_thread_unref); + g_source_attach (source, thread->context); + g_source_unref (source); + } } #define GST_RTSP_THREAD_POOL_GET_PRIVATE(obj) \ @@ -453,7 +465,7 @@ default_get_thread (GstRTSPThreadPool * pool, thread = make_thread (pool, type, ctx); if (!g_thread_pool_push (klass->pool, gst_rtsp_thread_ref (thread), - &error)) + &error)) goto thread_error; } g_queue_push_tail (&priv->threads, thread); @@ -465,7 +477,7 @@ default_get_thread (GstRTSPThreadPool * pool, thread = make_thread (pool, type, ctx); if (!g_thread_pool_push (klass->pool, gst_rtsp_thread_ref (thread), - &error)) + &error)) goto thread_error; break; default: @@ -535,8 +547,9 @@ gst_rtsp_thread_pool_cleanup (void) { GstRTSPThreadPoolClass *klass; - klass = GST_RTSP_THREAD_POOL_CLASS ( - g_type_class_peek (gst_rtsp_thread_pool_get_type ())); + klass = + GST_RTSP_THREAD_POOL_CLASS (g_type_class_peek + (gst_rtsp_thread_pool_get_type ())); if (klass->pool != NULL) { g_thread_pool_free (klass->pool, FALSE, TRUE); klass->pool = NULL; From c9025a58e106355a3143cad26b4e1352b6acf0c3 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Sat, 19 Oct 2013 19:21:53 +0200 Subject: [PATCH 0835/1776] token: Fix bug when creating empty token We always want to have a valid GstStructure in the token. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=710520 --- gst/rtsp-server/rtsp-token.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index 26cf54e2d3..f07f1c26d2 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -105,7 +105,16 @@ gst_rtsp_token_init (GstRTSPTokenImpl * token, GstStructure * structure) GstRTSPToken * gst_rtsp_token_new_empty (void) { - return gst_rtsp_token_new (NULL, NULL); + GstRTSPTokenImpl *token; + GstStructure *s; + + s = gst_structure_new_empty ("GstRTSPToken"); + g_return_val_if_fail (s != NULL, NULL); + + token = g_slice_new0 (GstRTSPTokenImpl); + gst_rtsp_token_init (token, s); + + return (GstRTSPToken *) token; } /** @@ -144,18 +153,16 @@ gst_rtsp_token_new (const gchar * firstfield, ...) GstRTSPToken * gst_rtsp_token_new_valist (const gchar * firstfield, va_list var_args) { - GstRTSPTokenImpl *token; + GstRTSPToken *token; GstStructure *s; g_return_val_if_fail (firstfield != NULL, NULL); - s = gst_structure_new_valist ("GstRTSPToken", firstfield, var_args); - g_return_val_if_fail (s != NULL, NULL); + token = gst_rtsp_token_new_empty (); + s = GST_RTSP_TOKEN_STRUCTURE (token); + gst_structure_set_valist (s, firstfield, var_args); - token = g_slice_new0 (GstRTSPTokenImpl); - gst_rtsp_token_init (token, s); - - return (GstRTSPToken *) token; + return token; } From e4509ed92cd38ea253a64113e0ea6f1a0907f085 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Sat, 19 Oct 2013 19:24:34 +0200 Subject: [PATCH 0836/1776] token: Validate args for gst_rtsp_token_is_allowed See https://bugzilla.gnome.org/show_bug.cgi?id=710520 --- gst/rtsp-server/rtsp-token.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index f07f1c26d2..787213d5cb 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -239,6 +239,9 @@ gst_rtsp_token_is_allowed (GstRTSPToken * token, const gchar * field) { gboolean result; + g_return_val_if_fail (GST_IS_RTSP_TOKEN (token), FALSE); + g_return_val_if_fail (field != NULL, FALSE); + if (!gst_structure_get_boolean (GST_RTSP_TOKEN_STRUCTURE (token), field, &result)) result = FALSE; From 0e1665b7c6c886dab801f1a319015b99aa3d043a Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Sat, 19 Oct 2013 19:25:27 +0200 Subject: [PATCH 0837/1776] tests: Add unit tests for token Fixes https://bugzilla.gnome.org/show_bug.cgi?id=710520 --- tests/check/Makefile.am | 5 ++- tests/check/gst/token.c | 99 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 tests/check/gst/token.c diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 49675bde6a..16ae3733d0 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -32,8 +32,9 @@ check_PROGRAMS = \ gst/mediafactory \ gst/media \ gst/addresspool \ - gst/threadpool - gst/permissions + gst/threadpool \ + gst/permissions \ + gst/token # these tests don't even pass noinst_PROGRAMS = diff --git a/tests/check/gst/token.c b/tests/check/gst/token.c new file mode 100644 index 0000000000..df5bbd5162 --- /dev/null +++ b/tests/check/gst/token.c @@ -0,0 +1,99 @@ +/* GStreamer + * Copyright (C) 2013 Sebastian Rasmussen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +GST_START_TEST (test_token) +{ + GstRTSPToken *token; + GstRTSPToken *token2; + GstRTSPToken *copy; + GstStructure *str; + + token = gst_rtsp_token_new_empty (); + fail_if (gst_rtsp_token_is_allowed (token, "missing")); + gst_rtsp_token_unref (token); + + token = gst_rtsp_token_new ("role", G_TYPE_STRING, "user", + "permission1", G_TYPE_BOOLEAN, TRUE, + "permission2", G_TYPE_BOOLEAN, FALSE, NULL); + fail_unless_equals_string (gst_rtsp_token_get_string (token, "role"), "user"); + fail_unless (gst_rtsp_token_is_allowed (token, "permission1")); + fail_if (gst_rtsp_token_is_allowed (token, "permission2")); + fail_if (gst_rtsp_token_is_allowed (token, "missing")); + copy = GST_RTSP_TOKEN (gst_mini_object_copy (GST_MINI_OBJECT (token))); + gst_rtsp_token_unref (token); + fail_unless_equals_string (gst_rtsp_token_get_string (copy, "role"), "user"); + fail_unless (gst_rtsp_token_is_allowed (copy, "permission1")); + fail_if (gst_rtsp_token_is_allowed (copy, "permission2")); + fail_if (gst_rtsp_token_is_allowed (copy, "missing")); + gst_rtsp_token_unref (copy); + + token = gst_rtsp_token_new ("role", G_TYPE_STRING, "user", + "permission1", G_TYPE_BOOLEAN, TRUE, + "permission2", G_TYPE_BOOLEAN, FALSE, NULL); + fail_unless_equals_string (gst_rtsp_token_get_string (token, "role"), "user"); + fail_unless (gst_rtsp_token_is_allowed (token, "permission1")); + fail_if (gst_rtsp_token_is_allowed (token, "permission2")); + fail_unless_equals_string (gst_rtsp_token_get_string (token, "role"), "user"); + + fail_unless (gst_mini_object_is_writable (GST_MINI_OBJECT (token))); + fail_unless (gst_rtsp_token_writable_structure (token) != NULL); + fail_unless (gst_rtsp_token_get_structure (token) != NULL); + + token2 = gst_rtsp_token_ref (token); + + fail_if (gst_mini_object_is_writable (GST_MINI_OBJECT (token))); + ASSERT_CRITICAL (fail_unless (gst_rtsp_token_writable_structure (token) == + NULL)); + fail_unless (gst_rtsp_token_get_structure (token) != NULL); + + gst_rtsp_token_unref (token2); + + fail_unless (gst_mini_object_is_writable (GST_MINI_OBJECT (token))); + fail_unless (gst_rtsp_token_writable_structure (token) != NULL); + fail_unless (gst_rtsp_token_get_structure (token) != NULL); + + str = gst_rtsp_token_writable_structure (token); + gst_structure_set (str, "permission2", G_TYPE_BOOLEAN, TRUE, NULL); + fail_unless_equals_string (gst_rtsp_token_get_string (token, "role"), "user"); + fail_unless (gst_rtsp_token_is_allowed (token, "permission1")); + fail_unless (gst_rtsp_token_is_allowed (token, "permission2")); + fail_unless_equals_string (gst_rtsp_token_get_string (token, "role"), "user"); + gst_rtsp_token_unref (token); +} + +GST_END_TEST; + +static Suite * +rtsptoken_suite (void) +{ + Suite *s = suite_create ("rtsptoken"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_set_timeout (tc, 20); + tcase_add_test (tc, test_token); + + return s; +} + +GST_CHECK_MAIN (rtsptoken); From 533d2377547669198f6b4b4471c66dd2120a619a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 12 Nov 2013 11:15:46 +0100 Subject: [PATCH 0838/1776] auth: small typos --- gst/rtsp-server/rtsp-auth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 28adba5c99..8154bab044 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -264,7 +264,7 @@ gst_rtsp_auth_set_default_token (GstRTSPAuth * auth, GstRTSPToken * token) * gst_rtsp_auth_get_default_token: * @auth: a #GstRTSPAuth * - * Get the default token for @auth. This token will be used for unauthorized + * Get the default token for @auth. This token will be used for unauthenticated * users. * * Returns: (transfer full): the #GstRTSPToken of @auth. gst_rtsp_token_unref() after @@ -321,7 +321,7 @@ gst_rtsp_auth_add_basic (GstRTSPAuth * auth, const gchar * basic, * @basic: (transfer none): the basic token * * Add a basic token for the default authentication algorithm that - * enables the client qith privileges from @authgroup. + * enables the client with privileges from @authgroup. */ void gst_rtsp_auth_remove_basic (GstRTSPAuth * auth, const gchar * basic) From e756324490490761e4027639caaa6589ab335b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= Date: Sat, 12 Oct 2013 23:56:00 +0200 Subject: [PATCH 0839/1776] Fixed several GIR warnings --- gst/rtsp-server/Makefile.am | 4 ++++ gst/rtsp-server/rtsp-auth.c | 4 ++-- gst/rtsp-server/rtsp-context.c | 2 +- gst/rtsp-server/rtsp-media.c | 9 +++++---- gst/rtsp-server/rtsp-mount-points.c | 2 +- gst/rtsp-server/rtsp-server.h | 2 +- gst/rtsp-server/rtsp-session-media.c | 2 +- gst/rtsp-server/rtsp-session.c | 2 +- gst/rtsp-server/rtsp-stream.c | 6 +++--- 9 files changed, 19 insertions(+), 14 deletions(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 638b2c6f97..7697ae845a 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -82,12 +82,15 @@ GstRtspServer-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_API_VERSION@` \ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_API_VERSION@` \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-net-@GST_API_VERSION@` \ --library=libgstrtspserver-@GST_API_VERSION@.la \ --include=Gst-@GST_API_VERSION@ \ --include=GstRtsp-@GST_API_VERSION@ \ + --include=GstNet-@GST_API_VERSION@ \ --libtool="$(top_builddir)/libtool" \ --pkg gstreamer-@GST_API_VERSION@ \ --pkg gstreamer-rtsp-@GST_API_VERSION@ \ + --pkg gstreamer-net-@GST_API_VERSION@ \ --pkg-export gstreamer-rtsp-server-@GST_API_VERSION@ \ --output $@ \ $(gir_headers) \ @@ -110,6 +113,7 @@ typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_API_VERSION@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-net-@GST_API_VERSION@` \ $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 8154bab044..694d216214 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -176,7 +176,7 @@ gst_rtsp_auth_new (void) /** * gst_rtsp_auth_set_tls_certificate: * @auth: a #GstRTSPAuth - * @cert: (allow none): a #GTlsCertificate + * @cert: (allow-none): a #GTlsCertificate * * Set the TLS certificate for the auth. Client connections will only * be accepted when TLS is negotiated. @@ -233,7 +233,7 @@ gst_rtsp_auth_get_tls_certificate (GstRTSPAuth * auth) /** * gst_rtsp_auth_set_default_token: * @auth: a #GstRTSPAuth - * @token: (allow none): a #GstRTSPToken + * @token: (allow-none): a #GstRTSPToken * * Set the default #GstRTSPToken to @token in @auth. The default token will * be used for unauthenticated users. diff --git a/gst/rtsp-server/rtsp-context.c b/gst/rtsp-server/rtsp-context.c index 3b8c0a10ad..817207dbf4 100644 --- a/gst/rtsp-server/rtsp-context.c +++ b/gst/rtsp-server/rtsp-context.c @@ -29,7 +29,7 @@ static GPrivate current_context; /** - * gst_rtsp_context_get_current: + * gst_rtsp_context_get_current: (skip) * * Get the current #GstRTSPContext. This object is retrieved from the * current thread that is handling the request for a client. diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 2fcbf328c7..e26a58837b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -483,7 +483,7 @@ gst_rtsp_media_new (GstElement * element) * * Get the element that was used when constructing @media. * - * Returns: a #GstElement. Unref after usage. + * Returns: (transfer full): a #GstElement. Unref after usage. */ GstElement * gst_rtsp_media_get_element (GstRTSPMedia * media) @@ -2000,7 +2000,7 @@ get_clock_unlocked (GstRTSPMedia * media) * * @media must be prepared before this method returns a valid clock object. * - * Returns: the #GstClock used by @media. unref after usage. + * Returns: (transfer full): the #GstClock used by @media. unref after usage. */ GstClock * gst_rtsp_media_get_clock (GstRTSPMedia * media) @@ -2066,7 +2066,7 @@ not_prepared: * Get the #GstNetTimeProvider for the clock used by @media. The time provider * will listen on @address and @port for client time requests. * - * Returns: the #GstNetTimeProvider of @media. + * Returns: (transfer full): the #GstNetTimeProvider of @media. */ GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address, @@ -2131,7 +2131,8 @@ gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state) * gst_rtsp_media_set_state: * @media: a #GstRTSPMedia * @state: the target state of the media - * @transports: a #GPtrArray of #GstRTSPStreamTransport pointers + * @transports: (element-type GstRtspServer.RTSPStreamTransport): a #GPtrArray + * of #GstRTSPStreamTransport pointers * * Set the state of @media to @state and for the transports in @transports. * diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index de23bc13c6..b89f2c464c 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -221,7 +221,7 @@ has_prefix (DataItem * str, DataItem * prefix) * gst_rtsp_mount_points_match: * @mounts: a #GstRTSPMountPoints * @path: a mount point - * @matched: the amount of @path matched + * @matched: (out): the amount of @path matched * * Find the factory in @mounts that has the longest match with @path. * diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 84aa1781d2..610c9a0a18 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -119,7 +119,7 @@ guint gst_rtsp_server_attach (GstRTSPServer *serve /** * GstRTSPServerClientFilterFunc: * @server: a #GstRTSPServer object - * @sess: a #GstRTSPClient in @server + * @client: a #GstRTSPClient in @server * @user_data: user data that has been given to gst_rtsp_server_client_filter() * * This function will be called by the gst_rtsp_server_client_filter(). An diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 1b8e7e2506..6c0a0f50bc 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -163,7 +163,7 @@ gst_rtsp_session_media_new (const gchar * path, GstRTSPMedia * media) * gst_rtsp_session_media_matches: * @media: a #GstRTSPSessionMedia * @path: a path - * @matched: the amount of matched characters of @path + * @matched: (out): the amount of matched characters of @path * * Check if the path of @media matches @path. It @path matches, the amount of * matched characters is returned in @matched. diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 20540ab82b..85b702c3fd 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -264,7 +264,7 @@ gst_rtsp_session_release_media (GstRTSPSession * sess, * gst_rtsp_session_get_media: * @sess: a #GstRTSPSession * @path: the path for the media - * @matched: the amount of matched characters + * @matched: (out): the amount of matched characters * * Get the session media for @path. @matched will contain the number of matched * characters of @path. diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 91512bed61..c4b643c86b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -312,7 +312,7 @@ gst_rtsp_stream_get_index (GstRTSPStream * stream) * * Get the srcpad associated with @stream. * - * Return: the srcpad. Unref after usage. + * Returns: (transfer full): the srcpad. Unref after usage. */ GstPad * gst_rtsp_stream_get_srcpad (GstRTSPStream * stream) @@ -328,7 +328,7 @@ gst_rtsp_stream_get_srcpad (GstRTSPStream * stream) * * Get the control string to identify this stream. * - * Return: the control string. free after usage. + * Returns: (transfer full): the control string. free after usage. */ gchar * gst_rtsp_stream_get_control (GstRTSPStream * stream) @@ -1076,7 +1076,7 @@ gst_rtsp_stream_get_server_port (GstRTSPStream * stream, * * Get the RTP session of this stream. * - * Returns: The RTP session of this stream. Unref after usage. + * Returns: (transfer full): The RTP session of this stream. Unref after usage. */ GObject * gst_rtsp_stream_get_rtpsession (GstRTSPStream * stream) From d443f8546b075f64774678ecb860b3c8eb3b5079 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 12 Nov 2013 11:21:55 +0100 Subject: [PATCH 0840/1776] context: defing a GType for the context Fixes https://bugzilla.gnome.org/show_bug.cgi?id=710018 --- gst/rtsp-server/rtsp-context.c | 4 +++- gst/rtsp-server/rtsp-context.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-context.c b/gst/rtsp-server/rtsp-context.c index 817207dbf4..919ca2dc53 100644 --- a/gst/rtsp-server/rtsp-context.c +++ b/gst/rtsp-server/rtsp-context.c @@ -26,10 +26,12 @@ #include "rtsp-context.h" +G_DEFINE_POINTER_TYPE (GstRTSPContext, gst_rtsp_context); + static GPrivate current_context; /** - * gst_rtsp_context_get_current: (skip) + * gst_rtsp_context_get_current: * * Get the current #GstRTSPContext. This object is retrieved from the * current thread that is handling the request for a client. diff --git a/gst/rtsp-server/rtsp-context.h b/gst/rtsp-server/rtsp-context.h index 60ff030f67..a43563fce0 100644 --- a/gst/rtsp-server/rtsp-context.h +++ b/gst/rtsp-server/rtsp-context.h @@ -71,6 +71,8 @@ struct _GstRTSPContext { GstRTSPMessage *response; }; +GType gst_rtsp_context_get_type (void); + GstRTSPContext * gst_rtsp_context_get_current (void); void gst_rtsp_context_push_current (GstRTSPContext * ctx); void gst_rtsp_context_pop_current (GstRTSPContext * ctx); From 8d5ce0d4ee6b99139de64372b5138ac6f8088611 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 12 Nov 2013 12:04:55 +0100 Subject: [PATCH 0841/1776] stream: Add functions to get rtp and rtcp sockets Fixes https://bugzilla.gnome.org/show_bug.cgi?id=710100 --- docs/libs/gst-rtsp-server-sections.txt | 3 + gst/rtsp-server/rtsp-stream.c | 68 ++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 5 ++ tests/check/Makefile.am | 1 + tests/check/gst/stream.c | 107 +++++++++++++++++++++++++ 5 files changed, 184 insertions(+) create mode 100644 tests/check/gst/stream.c diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 0178bac115..85d8536f4f 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -522,6 +522,9 @@ gst_rtsp_stream_recv_rtp gst_rtsp_stream_add_transport gst_rtsp_stream_remove_transport + +gst_rtsp_stream_get_rtp_socket +gst_rtsp_stream_get_rtcp_socket GST_RTSP_STREAM_CAST GST_RTSP_STREAM_CLASS_CAST diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index c4b643c86b..09dc4b4604 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1996,3 +1996,71 @@ gst_rtsp_stream_remove_transport (GstRTSPStream * stream, return res; } + +/** + * gst_rtsp_stream_get_rtp_socket: + * @stream: a #GstRTSPStream + * @family: the socket family + * + * Get the RTP socket from @stream for a @family. + * + * @stream must be joined to a bin. + * + * Returns: the RTP socket or %NULL if no socket could be allocated for @family. + * Unref after usage + */ +GSocket * +gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family) +{ + GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); + GSocket *socket; + gchar *name; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 || + family == G_SOCKET_FAMILY_IPV6, NULL); + g_return_val_if_fail (priv->udpsink[0], NULL); + + if (family == G_SOCKET_FAMILY_IPV6) + name = "socket-v6"; + else + name = "socket"; + + g_object_get (priv->udpsink[0], name, &socket, NULL); + + return socket; +} + +/** + * gst_rtsp_stream_get_rtcp_socket: + * @stream: a #GstRTSPStream + * @family: the socket family + * + * Get the RTCP socket from @stream for a @family. + * + * @stream must be joined to a bin. + * + * Returns: the RTCP socket or %NULL if no socket could be allocated for + * @family. Unref after usage + */ +GSocket * +gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) +{ + GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); + GSocket *socket; + gchar *name; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 || + family == G_SOCKET_FAMILY_IPV6, NULL); + g_return_val_if_fail (priv->udpsink[1], NULL); + + if (family == G_SOCKET_FAMILY_IPV6) + name = "socket-v6"; + else + name = "socket"; + + g_object_get (priv->udpsink[1], name, &socket, NULL); + + return socket; +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 1832b2cb71..09fffeb93d 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -122,6 +122,11 @@ gboolean gst_rtsp_stream_add_transport (GstRTSPStream *stream, gboolean gst_rtsp_stream_remove_transport (GstRTSPStream *stream, GstRTSPStreamTransport *trans); +GSocket * gst_rtsp_stream_get_rtp_socket (GstRTSPStream *stream, + GSocketFamily family); +GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream *stream, + GSocketFamily family); + G_END_DECLS #endif /* __GST_RTSP_STREAM_H__ */ diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 16ae3733d0..71d37ab16a 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -31,6 +31,7 @@ check_PROGRAMS = \ gst/mountpoints \ gst/mediafactory \ gst/media \ + gst/stream \ gst/addresspool \ gst/threadpool \ gst/permissions \ diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c new file mode 100644 index 0000000000..eb9e0b5e76 --- /dev/null +++ b/tests/check/gst/stream.c @@ -0,0 +1,107 @@ +/* GStreamer + * Copyright (C) 2013 Axis Communications AB + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +GST_START_TEST (test_get_sockets) +{ + GstPad *srcpad; + GstElement *pay; + GstRTSPStream *stream; + GstBin *bin; + GstElement *rtpbin; + GSocket *socket; + gboolean have_ipv4; + gboolean have_ipv6; + + srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); + fail_unless (srcpad != NULL); + gst_pad_set_active (srcpad, TRUE); + pay = gst_element_factory_make ("rtpgstpay", "testpayloader"); + fail_unless (pay != NULL); + stream = gst_rtsp_stream_new (0, pay, srcpad); + fail_unless (stream != NULL); + gst_object_unref (pay); + gst_object_unref (srcpad); + rtpbin = gst_element_factory_make ("rtpbin", "testrtpbin"); + fail_unless (rtpbin != NULL); + bin = GST_BIN (gst_bin_new ("testbin")); + fail_unless (bin != NULL); + fail_unless (gst_bin_add (bin, rtpbin)); + + fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + + socket = gst_rtsp_stream_get_rtp_socket (stream, G_SOCKET_FAMILY_IPV4); + have_ipv4 = (socket != NULL); + if (have_ipv4) { + fail_unless (g_socket_get_fd (socket) >= 0); + g_object_unref (socket); + } + + socket = gst_rtsp_stream_get_rtcp_socket (stream, G_SOCKET_FAMILY_IPV4); + if (have_ipv4) { + fail_unless (socket != NULL); + fail_unless (g_socket_get_fd (socket) >= 0); + g_object_unref (socket); + } else { + fail_unless (socket == NULL); + } + + socket = gst_rtsp_stream_get_rtp_socket (stream, G_SOCKET_FAMILY_IPV6); + have_ipv6 = (socket != NULL); + if (have_ipv6) { + fail_unless (g_socket_get_fd (socket) >= 0); + g_object_unref (socket); + } + + socket = gst_rtsp_stream_get_rtcp_socket (stream, G_SOCKET_FAMILY_IPV6); + if (have_ipv6) { + fail_unless (socket != NULL); + fail_unless (g_socket_get_fd (socket) >= 0); + g_object_unref (socket); + } else { + fail_unless (socket == NULL); + } + + /* check that at least one family is available */ + fail_unless (have_ipv4 || have_ipv6); + + fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); + + gst_object_unref (bin); + gst_object_unref (stream); +} + +GST_END_TEST; + +static Suite * +rtspstream_suite (void) +{ + Suite *s = suite_create ("rtspstream"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_add_test (tc, test_get_sockets); + + return s; +} + +GST_CHECK_MAIN (rtspstream); From 8ce453d97d5a986f68cf34a57b0d663539634614 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 7 Nov 2013 13:22:09 +0100 Subject: [PATCH 0842/1776] client: make make_path_from_uri a vmethod --- gst/rtsp-server/rtsp-client.c | 21 +++++++++++++++------ gst/rtsp-server/rtsp-client.h | 1 + 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a16daaff53..3a90f528c3 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -133,6 +133,8 @@ static GstRTSPResult default_params_set (GstRTSPClient * client, GstRTSPContext * ctx); static GstRTSPResult default_params_get (GstRTSPClient * client, GstRTSPContext * ctx); +static gchar * default_make_path_from_uri (GstRTSPClient *client, + const GstRTSPUrl *uri); G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); @@ -153,6 +155,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) klass->configure_client_transport = default_configure_client_transport; klass->params_set = default_params_set; klass->params_get = default_params_get; + klass->make_path_from_uri = default_make_path_from_uri; g_object_class_install_property (gobject_class, PROP_SESSION_POOL, g_param_spec_object ("session-pool", "Session Pool", @@ -712,7 +715,7 @@ close_connection (GstRTSPClient * client) } static gchar * -make_path_from_uri (GstRTSPClient * client, GstRTSPUrl * uri) +default_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri) { gchar *path; @@ -728,6 +731,7 @@ static gboolean handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPClientPrivate *priv = client->priv; + GstRTSPClientClass *klass; GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; GstRTSPStatusCode code; @@ -742,7 +746,8 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!ctx->uri) goto no_uri; - path = make_path_from_uri (client, ctx->uri); + klass = GST_RTSP_CLIENT_GET_CLASS (client); + path = klass->make_path_from_uri (client, ctx->uri); /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -912,6 +917,7 @@ static gboolean handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPSession *session; + GstRTSPClientClass *klass; GstRTSPSessionMedia *sessmedia; GstRTSPStatusCode code; GstRTSPState rtspstate; @@ -924,7 +930,8 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!ctx->uri) goto no_uri; - path = make_path_from_uri (client, ctx->uri); + klass = GST_RTSP_CLIENT_GET_CLASS (client); + path = klass->make_path_from_uri (client, ctx->uri); /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -1027,6 +1034,7 @@ static gboolean handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPSession *session; + GstRTSPClientClass *klass; GstRTSPSessionMedia *sessmedia; GstRTSPMedia *media; GstRTSPStatusCode code; @@ -1047,7 +1055,8 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!(uri = ctx->uri)) goto no_uri; - path = make_path_from_uri (client, uri); + klass = GST_RTSP_CLIENT_GET_CLASS (client); + path = klass->make_path_from_uri (client, uri); /* get a handle to the configuration of the media in the session */ sessmedia = gst_rtsp_session_get_media (session, path, &matched); @@ -1413,7 +1422,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) goto no_uri; uri = ctx->uri; - path = make_path_from_uri (client, uri); + klass = GST_RTSP_CLIENT_GET_CLASS (client); + path = klass->make_path_from_uri (client, uri); /* parse the transport */ res = @@ -1512,7 +1522,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) goto unsupported_transports; /* update the client transport */ - klass = GST_RTSP_CLIENT_GET_CLASS (client); if (!klass->configure_client_transport (client, ctx, ct)) goto unsupported_client_transport; diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 2f9cdf97d7..88d888ef5c 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -92,6 +92,7 @@ struct _GstRTSPClientClass { GstRTSPTransport * ct); GstRTSPResult (*params_set) (GstRTSPClient *client, GstRTSPContext *ctx); GstRTSPResult (*params_get) (GstRTSPClient *client, GstRTSPContext *ctx); + gchar * (*make_path_from_uri) (GstRTSPClient *client, const GstRTSPUrl *uri); /* signals */ void (*closed) (GstRTSPClient *client); From adc02db975d8bf615dda3e33efcb0feb490f5e83 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Tue, 12 Nov 2013 10:55:14 +0100 Subject: [PATCH 0843/1776] client: allow absolute path in requests Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711689 --- gst/rtsp-server/rtsp-client.c | 30 +++++++++++++++++++++++++-- tests/check/gst/client.c | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3a90f528c3..a9c7ed1e60 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1934,8 +1934,34 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) /* we always try to parse the url first */ if (strcmp (uristr, "*") == 0) { /* special case where we have * as uri, keep uri = NULL */ - } else if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) - goto bad_request; + } else if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) { + /* check if the uristr is an absolute path <=> scheme and host information + * is missing */ + gchar *scheme; + + scheme = g_uri_parse_scheme (uristr); + if (scheme == NULL && g_str_has_prefix (uristr, "/")) { + gchar *absolute_uristr = NULL; + + GST_WARNING_OBJECT (client, "request doesn't contain absolute url"); + if (priv->server_ip == NULL) { + GST_WARNING_OBJECT (client, "host information missing"); + goto bad_request; + } + + absolute_uristr = g_strdup_printf ("rtsp://%s%s", priv->server_ip, uristr); + + GST_DEBUG_OBJECT (client, "absolute url: %s", absolute_uristr); + if (gst_rtsp_url_parse (absolute_uristr, &uri) != GST_RTSP_OK) { + g_free (absolute_uristr); + goto bad_request; + } + g_free (absolute_uristr); + } else { + g_free (scheme); + goto bad_request; + } + } /* get the session if there is any */ res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index f30056d70c..da99aa8a05 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -155,6 +155,9 @@ GST_START_TEST (test_request) GstRTSPClient *client; GstRTSPMessage request = { 0, }; gchar *str; + GstRTSPConnection *conn; + GSocket *sock; + GError *error = NULL; client = gst_rtsp_client_new (); @@ -185,6 +188,41 @@ GST_START_TEST (test_request) gst_rtsp_message_unset (&request); + /* OPTIONS with an absolute path instead of an absolute url */ + /* set host information */ + sock = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_TCP, &error); + g_assert_no_error (error); + gst_rtsp_connection_create_from_socket (sock, "localhost", 444, NULL, &conn); + fail_unless (gst_rtsp_client_set_connection (client, conn)); + g_object_unref (sock); + + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, + "/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + + gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + /* OPTIONS with an absolute path instead of an absolute url with invalid + * host information */ + g_object_unref (client); + client = gst_rtsp_client_new (); + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, + "/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + + gst_rtsp_client_set_send_func (client, test_response_400, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + g_object_unref (client); } From b2bc84cdbf7d08c5cb94da435637bc1c7188c918 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 12 Nov 2013 16:52:35 +0100 Subject: [PATCH 0844/1776] address-pool: fix address increment Use a guint instead of guint8 to increment the address. It's still not completely correct because a guint might not be able to hold the complete address range, but that's an enhacement for later. Add unit test to test improved behaviour. https://bugzilla.gnome.org/show_bug.cgi?id=708237 --- gst/rtsp-server/rtsp-address-pool.c | 8 ++++---- tests/check/gst/addresspool.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index e1e9b9199d..4f433be376 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -328,7 +328,7 @@ invalid: } static void -inc_address (Addr * addr, guint8 count) +inc_address (Addr * addr, guint count) { gint i; guint carry; @@ -342,7 +342,6 @@ inc_address (Addr * addr, guint8 count) } /* tells us the number of addresses between min_addr and max_addr */ - static guint diff_address (Addr * max_addr, Addr * min_addr) { @@ -361,7 +360,6 @@ diff_address (Addr * max_addr, Addr * min_addr) return result; } - static AddrRange * split_range (GstRTSPAddressPool * pool, AddrRange * range, guint skip_addr, guint skip_port, gint n_ports) @@ -673,11 +671,13 @@ gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, ttl); if (list != NULL) { AddrRange *range = list->data; - gint skip_port, skip_addr; + guint skip_port, skip_addr; skip_addr = diff_address (&input_addr, &range->min); skip_port = port - range->min.port; + GST_DEBUG_OBJECT (pool, "diff 0x%08x/%u", skip_addr, skip_port); + /* we found a range, remove from the list */ priv->addresses = g_list_delete_link (priv->addresses, list); /* now split and exit our loop */ diff --git a/tests/check/gst/addresspool.c b/tests/check/gst/addresspool.c index b3ca24d9a6..9a0ff54f14 100644 --- a/tests/check/gst/addresspool.c +++ b/tests/check/gst/addresspool.c @@ -236,6 +236,34 @@ GST_START_TEST (test_pool) fail_unless (!strcmp (addr->address, "192.168.1.1")); gst_rtsp_address_free (addr); + fail_unless (gst_rtsp_address_pool_add_range (pool, + GST_RTSP_ADDRESS_POOL_ANY_IPV4, GST_RTSP_ADDRESS_POOL_ANY_IPV4, 5000, + 5001, 0)); + res = + gst_rtsp_address_pool_reserve_address (pool, "192.168.0.1", 5000, 1, 0, + &addr); + fail_unless (res == GST_RTSP_ADDRESS_POOL_ERANGE); + res = + gst_rtsp_address_pool_reserve_address (pool, "0.0.0.0", 5000, 1, 0, + &addr); + fail_unless (res == GST_RTSP_ADDRESS_POOL_OK); + gst_rtsp_address_free (addr); + gst_rtsp_address_pool_clear (pool); + + /* Error case 2. Using ANY as min address makes it possible to allocate the + * same address twice */ + fail_unless (gst_rtsp_address_pool_add_range (pool, + GST_RTSP_ADDRESS_POOL_ANY_IPV4, "255.255.255.255", 5000, 5001, 0)); + res = + gst_rtsp_address_pool_reserve_address (pool, "192.168.0.1", 5000, 1, 0, + &addr); + fail_unless (res == GST_RTSP_ADDRESS_POOL_OK); + res = + gst_rtsp_address_pool_reserve_address (pool, "192.168.0.1", 5000, 1, 0, + &addr2); + fail_unless (res == GST_RTSP_ADDRESS_POOL_ERESERVED); + gst_rtsp_address_free (addr); + gst_rtsp_address_pool_clear (pool); g_object_unref (pool); } From b0f609ce7f3a8744bc5e20a209ba989a457fd479 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 15 Nov 2013 16:35:05 +0100 Subject: [PATCH 0845/1776] rtsp: allow NULL func in filters Passing a null function make the filters return a list of refcounted objects. --- gst/rtsp-server/rtsp-client.c | 18 +++++++++++++----- gst/rtsp-server/rtsp-server.c | 14 +++++++++++--- gst/rtsp-server/rtsp-session-pool.c | 12 ++++++++++-- gst/rtsp-server/rtsp-session.c | 11 +++++++++-- 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a9c7ed1e60..f0731dce01 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -133,8 +133,8 @@ static GstRTSPResult default_params_set (GstRTSPClient * client, GstRTSPContext * ctx); static GstRTSPResult default_params_get (GstRTSPClient * client, GstRTSPContext * ctx); -static gchar * default_make_path_from_uri (GstRTSPClient *client, - const GstRTSPUrl *uri); +static gchar *default_make_path_from_uri (GstRTSPClient * client, + const GstRTSPUrl * uri); G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); @@ -1949,7 +1949,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) goto bad_request; } - absolute_uristr = g_strdup_printf ("rtsp://%s%s", priv->server_ip, uristr); + absolute_uristr = + g_strdup_printf ("rtsp://%s%s", priv->server_ip, uristr); GST_DEBUG_OBJECT (client, "absolute url: %s", absolute_uristr); if (gst_rtsp_url_parse (absolute_uristr, &uri) != GST_RTSP_OK) { @@ -2899,6 +2900,8 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) * will also be added with an additional ref to the result #GList of this * function.. * + * When @func is %NULL, #GST_RTSP_FILTER_REF will be assumed for each session. + * * Returns: (element-type GstRTSPSession) (transfer full): a #GList with all * sessions for which @func returned #GST_RTSP_FILTER_REF. After usage, each * element in the #GList should be unreffed before the list is freed. @@ -2911,7 +2914,6 @@ gst_rtsp_client_session_filter (GstRTSPClient * client, GList *result, *walk, *next; g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); - g_return_val_if_fail (func != NULL, NULL); priv = client->priv; @@ -2920,10 +2922,16 @@ gst_rtsp_client_session_filter (GstRTSPClient * client, g_mutex_lock (&priv->lock); for (walk = priv->sessions; walk; walk = next) { GstRTSPSession *sess = walk->data; + GstRTSPFilterResult res; next = g_list_next (walk); - switch (func (client, sess, user_data)) { + if (func) + res = func (client, sess, user_data); + else + res = GST_RTSP_FILTER_REF; + + switch (res) { case GST_RTSP_FILTER_REMOVE: /* stop watching the session and pretent it went away */ client_cleanup_session (client, sess); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 1afbba710e..ed7ba3ee22 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -856,7 +856,8 @@ gst_rtsp_server_create_socket (GstRTSPServer * server, g_clear_error (&addr_error); break; } - port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (sockaddr)); + port = + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (sockaddr)); if (port != 0) { g_free (priv->service); @@ -1345,6 +1346,8 @@ no_source: * will also be added with an additional ref to the result #GList of this * function.. * + * When @func is %NULL, #GST_RTSP_FILTER_REF will be assumed for each client. + * * Returns: (element-type GstRTSPClient) (transfer full): a #GList with all * clients for which @func returned #GST_RTSP_FILTER_REF. After usage, each * element in the #GList should be unreffed before the list is freed. @@ -1357,7 +1360,6 @@ gst_rtsp_server_client_filter (GstRTSPServer * server, GList *result, *walk, *next; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); - g_return_val_if_fail (func != NULL, NULL); priv = server->priv; @@ -1366,10 +1368,16 @@ gst_rtsp_server_client_filter (GstRTSPServer * server, GST_RTSP_SERVER_LOCK (server); for (walk = priv->clients; walk; walk = next) { ClientContext *cctx = walk->data; + GstRTSPFilterResult res; next = g_list_next (walk); - switch (func (server, cctx->client, user_data)) { + if (func) + res = func (server, cctx->client, user_data); + else + res = GST_RTSP_FILTER_REF; + + switch (res) { case GST_RTSP_FILTER_REMOVE: /* remove client, FIXME */ break; diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index be07820094..1f2b3f9210 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -483,7 +483,14 @@ typedef struct static gboolean filter_func (gchar * sessionid, GstRTSPSession * sess, FilterData * data) { - switch (data->func (data->pool, sess, data->user_data)) { + GstRTSPFilterResult res; + + if (data->func) + res = data->func (data->pool, sess, data->user_data); + else + res = GST_RTSP_FILTER_REF; + + switch (res) { case GST_RTSP_FILTER_REMOVE: return TRUE; case GST_RTSP_FILTER_REF: @@ -515,6 +522,8 @@ filter_func (gchar * sessionid, GstRTSPSession * sess, FilterData * data) * will also be added with an additional ref to the result GList of this * function.. * + * When @func is %NULL, #GST_RTSP_FILTER_REF will be assumed for all sessions. + * * Returns: (element-type GstRTSPSession) (transfer full): a GList with all * sessions for which @func returned #GST_RTSP_FILTER_REF. After usage, each * element in the GList should be unreffed before the list is freed. @@ -527,7 +536,6 @@ gst_rtsp_session_pool_filter (GstRTSPSessionPool * pool, FilterData data; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL); - g_return_val_if_fail (func != NULL, NULL); priv = pool->priv; diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 85b702c3fd..c20cf3cd0e 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -327,6 +327,8 @@ gst_rtsp_session_get_media (GstRTSPSession * sess, const gchar * path, * will also be added with an additional ref to the result #GList of this * function.. * + * When @func is %NULL, #GST_RTSP_FILTER_REF will be assumed for all media. + * * Returns: (element-type GstRTSPSessionMedia) (transfer full): a GList with all * media for which @func returned #GST_RTSP_FILTER_REF. After usage, each * element in the #GList should be unreffed before the list is freed. @@ -339,7 +341,6 @@ gst_rtsp_session_filter (GstRTSPSession * sess, GList *result, *walk, *next; g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); - g_return_val_if_fail (func != NULL, NULL); priv = sess->priv; @@ -348,10 +349,16 @@ gst_rtsp_session_filter (GstRTSPSession * sess, g_mutex_lock (&priv->lock); for (walk = priv->medias; walk; walk = next) { GstRTSPSessionMedia *media = walk->data; + GstRTSPFilterResult res; next = g_list_next (walk); - switch (func (sess, media, user_data)) { + if (func) + res = func (sess, media, user_data); + else + res = GST_RTSP_FILTER_REF; + + switch (res) { case GST_RTSP_FILTER_REMOVE: g_object_unref (media); priv->medias = g_list_delete_link (priv->medias, walk); From a106950f7089a2a4b133d70dd79f2106e4c012bd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 18 Nov 2013 11:18:15 +0100 Subject: [PATCH 0846/1776] stream: add method to filter transports Add a method to safely iterate and collect the stream transports Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711664 --- gst/rtsp-server/rtsp-stream.c | 67 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 30 ++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 09dc4b4604..6e9218df80 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2064,3 +2064,70 @@ gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) return socket; } + +/** + * gst_rtsp_stream_transport_filter: + * @stream: a #GstRTSPStream + * @func: (scope call): a callback + * @user_data: user data passed to @func + * + * Call @func for each transport managed by @stream. The result value of @func + * determines what happens to the transport. @func will be called with @stream + * locked so no further actions on @stream can be performed from @func. + * + * If @func returns #GST_RTSP_FILTER_REMOVE, the transport will be removed from + * @stream. + * + * If @func returns #GST_RTSP_FILTER_KEEP, the transport will remain in @stream. + * + * If @func returns #GST_RTSP_FILTER_REF, the transport will remain in @stream but + * will also be added with an additional ref to the result #GList of this + * function.. + * + * When @func is %NULL, #GST_RTSP_FILTER_REF will be assumed for each transport. + * + * Returns: (element-type GstRTSPStreamTransport) (transfer full): a #GList with all + * transports for which @func returned #GST_RTSP_FILTER_REF. After usage, each + * element in the #GList should be unreffed before the list is freed. + */ +GList * +gst_rtsp_stream_transport_filter (GstRTSPStream * stream, + GstRTSPStreamTransportFilterFunc func, gpointer user_data) +{ + GstRTSPStreamPrivate *priv; + GList *result, *walk, *next; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + priv = stream->priv; + + result = NULL; + + g_mutex_lock (&priv->lock); + for (walk = priv->transports; walk; walk = next) { + GstRTSPStreamTransport *trans = walk->data; + GstRTSPFilterResult res; + + next = g_list_next (walk); + + if (func) + res = func (stream, trans, user_data); + else + res = GST_RTSP_FILTER_REF; + + switch (res) { + case GST_RTSP_FILTER_REMOVE: + update_transport (stream, trans, FALSE); + break; + case GST_RTSP_FILTER_REF: + result = g_list_prepend (result, g_object_ref (trans)); + break; + case GST_RTSP_FILTER_KEEP: + default: + break; + } + } + g_mutex_unlock (&priv->lock); + + return result; +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 09fffeb93d..7bd46814cb 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -43,6 +43,7 @@ typedef struct _GstRTSPStreamPrivate GstRTSPStreamPrivate; #include "rtsp-stream-transport.h" #include "rtsp-address-pool.h" +#include "rtsp-session.h" /** * GstRTSPStream: @@ -127,6 +128,35 @@ GSocket * gst_rtsp_stream_get_rtp_socket (GstRTSPStream *stream, GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream *stream, GSocketFamily family); +/** + * GstRTSPStreamTransportFilterFunc: + * @stream: a #GstRTSPStream object + * @trans: a #GstRTSPStreamTransport in @stream + * @user_data: user data that has been given to gst_rtsp_stream_transport_filter() + * + * This function will be called by the gst_rtsp_stream_transport_filter(). An + * implementation should return a value of #GstRTSPFilterResult. + * + * When this function returns #GST_RTSP_FILTER_REMOVE, @trans will be removed + * from @stream. + * + * A return value of #GST_RTSP_FILTER_KEEP will leave @trans untouched in + * @stream. + * + * A value of #GST_RTSP_FILTER_REF will add @trans to the result #GList of + * gst_rtsp_stream_transport_filter(). + * + * Returns: a #GstRTSPFilterResult. + */ +typedef GstRTSPFilterResult (*GstRTSPStreamTransportFilterFunc) (GstRTSPStream *stream, + GstRTSPStreamTransport *trans, + gpointer user_data); + +GList * gst_rtsp_stream_transport_filter (GstRTSPStream *stream, + GstRTSPStreamTransportFilterFunc func, + gpointer user_data); + + G_END_DECLS #endif /* __GST_RTSP_STREAM_H__ */ From 33c4bdfa01c8db82e1dd50c1b43cb637dea2d103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 18 Nov 2013 10:47:04 +0000 Subject: [PATCH 0847/1776] rtsp-server: sprinkle some allow-none annotations for g-i --- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-server.c | 2 +- gst/rtsp-server/rtsp-session-pool.c | 2 +- gst/rtsp-server/rtsp-session.c | 2 +- gst/rtsp-server/rtsp-stream.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f0731dce01..ed1b663bef 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2884,7 +2884,7 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) /** * gst_rtsp_client_session_filter: * @client: a #GstRTSPClient - * @func: (scope call): a callback + * @func: (scope call) (allow-none): a callback * @user_data: user data passed to @func * * Call @func for each session managed by @client. The result value of @func diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index ed7ba3ee22..364d5dcfea 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1330,7 +1330,7 @@ no_source: /** * gst_rtsp_server_client_filter: * @server: a #GstRTSPServer - * @func: (scope call): a callback + * @func: (scope call) (allow-none): a callback * @user_data: user data passed to @func * * Call @func for each client managed by @server. The result value of @func diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 1f2b3f9210..ca4da57840 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -506,7 +506,7 @@ filter_func (gchar * sessionid, GstRTSPSession * sess, FilterData * data) /** * gst_rtsp_session_pool_filter: * @pool: a #GstRTSPSessionPool - * @func: (scope call): a callback + * @func: (scope call) (allow-none): a callback * @user_data: user data passed to @func * * Call @func for each session in @pool. The result value of @func determines diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index c20cf3cd0e..204ccf78f7 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -311,7 +311,7 @@ gst_rtsp_session_get_media (GstRTSPSession * sess, const gchar * path, /** * gst_rtsp_session_filter: * @sess: a #GstRTSPSession - * @func: (scope call): a callback + * @func: (scope call) (allow-none): a callback * @user_data: user data passed to @func * * Call @func for each media in @sess. The result value of @func determines diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 6e9218df80..7df201b19c 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2068,7 +2068,7 @@ gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) /** * gst_rtsp_stream_transport_filter: * @stream: a #GstRTSPStream - * @func: (scope call): a callback + * @func: (scope call) (allow-none): a callback * @user_data: user data passed to @func * * Call @func for each transport managed by @stream. The result value of @func From 3052b28859a0925ba05bf17bc2b5a761af005bd0 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Fri, 22 Nov 2013 00:45:17 +0100 Subject: [PATCH 0848/1776] docs: Improve documentation * Include annotation-glossary to quiet gtk-doc * Rename remaining ClientState -> Context * Rename object hierarchy file * Remove stale chapter references * Add missing function and object references * Include missing GstRTSPAddressPoolResult https://bugzilla.gnome.org/show_bug.cgi?id=714988 --- docs/README | 4 +- docs/libs/gst-rtsp-server-docs.sgml | 56 ++------------------------ docs/libs/gst-rtsp-server-sections.txt | 29 ++++++++++--- 3 files changed, 29 insertions(+), 60 deletions(-) diff --git a/docs/README b/docs/README index f90f4ab2b3..e1cdc9c3a0 100644 --- a/docs/README +++ b/docs/README @@ -425,7 +425,7 @@ GstRTSPClient - Handle RTSP Requests from connected clients. All other objects are called by this object. -GstRTSPClientState +GstRTSPContext - Helper structure contaning the current state of the request handled by the client. @@ -482,7 +482,7 @@ GstRTSPThreadPool GstRTSPAuth - Hooks for checking authorizations, all client activity will call this - object with the GstRTSPClientState structure. By default it supports + object with the GstRTSPContext structure. By default it supports basic authentication. GstRTSPToken diff --git a/docs/libs/gst-rtsp-server-docs.sgml b/docs/libs/gst-rtsp-server-docs.sgml index 4035cc8d69..06141f838c 100644 --- a/docs/libs/gst-rtsp-server-docs.sgml +++ b/docs/libs/gst-rtsp-server-docs.sgml @@ -16,6 +16,7 @@ + @@ -34,58 +35,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Object Hierarchy @@ -94,4 +44,6 @@ API Index + + diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 85d8536f4f..e43e896542 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -13,6 +13,7 @@ gst_rtsp_address_free GstRTSPAddressPool GstRTSPAddressPoolClass +GstRTSPAddressPoolResult gst_rtsp_address_pool_new gst_rtsp_address_pool_clear gst_rtsp_address_pool_dump @@ -47,6 +48,8 @@ gst_rtsp_auth_make_basic gst_rtsp_auth_add_basic gst_rtsp_auth_remove_basic gst_rtsp_auth_check +gst_rtsp_auth_get_default_token +gst_rtsp_auth_set_default_token GST_RTSP_AUTH_CHECK_CONNECT @@ -78,12 +81,6 @@ gst_rtsp_auth_get_type
rtsp-client GstRTSPClient - -GstRTSPClientState -gst_rtsp_client_state_get_current -gst_rtsp_client_state_pop_current -gst_rtsp_client_state_push_current - GstRTSPClient GstRTSPClientClass @@ -128,6 +125,17 @@ GstRTSPClientPrivate gst_rtsp_client_get_type
+
+rtsp-context +GstRTSPContext +GstRTSPContext +gst_rtsp_context_get_current +gst_rtsp_context_push_current +gst_rtsp_context_pop_current + +gst_rtsp_context_get_type +
+
rtsp-media GstRTSPMedia @@ -273,6 +281,7 @@ gst_rtsp_mount_points_new gst_rtsp_mount_points_add_factory gst_rtsp_mount_points_remove_factory gst_rtsp_mount_points_match +gst_rtsp_mount_points_make_path GST_RTSP_MOUNT_POINTS_CAST GST_RTSP_MOUNT_POINTS_CLASS_CAST @@ -503,6 +512,9 @@ gst_rtsp_stream_set_mtu gst_rtsp_stream_get_dscp_qos gst_rtsp_stream_set_dscp_qos +gst_rtsp_stream_get_protocols +gst_rtsp_stream_set_protocols + gst_rtsp_stream_get_address_pool gst_rtsp_stream_set_address_pool gst_rtsp_stream_reserve_address @@ -525,6 +537,10 @@ gst_rtsp_stream_remove_transport gst_rtsp_stream_get_rtp_socket gst_rtsp_stream_get_rtcp_socket + +GstRTSPStreamTransportFilterFunc +gst_rtsp_stream_transport_filter + GST_RTSP_STREAM_CAST GST_RTSP_STREAM_CLASS_CAST @@ -600,6 +616,7 @@ gst_rtsp_thread_pool_get_max_threads gst_rtsp_thread_pool_set_max_threads gst_rtsp_thread_pool_get_thread +gst_rtsp_thread_pool_cleanup GST_RTSP_THREAD_CAST GST_RTSP_THREAD_POOL_CAST From d1a285365951e69e542ce0fa4d391e44d74758e4 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Fri, 22 Nov 2013 03:10:01 +0100 Subject: [PATCH 0849/1776] rtsp-*: Fix type name typos in comments * rtsp-auth: Refer to GstRTSPToken, not GstRTSPtoken * rtsp-auth: Refer to part of constant name as text * rtsp-auth/-permissions/-token: Refer to Permissions not Permission * rtsp-session-media: Fix GstRTSPSessionMedia typo * rtsp-stream: Fix typo when refering to GstBin https://bugzilla.gnome.org/show_bug.cgi?id=714988 --- gst/rtsp-server/rtsp-auth.c | 4 ++-- gst/rtsp-server/rtsp-permissions.c | 2 +- gst/rtsp-server/rtsp-session-media.c | 2 +- gst/rtsp-server/rtsp-stream.c | 2 +- gst/rtsp-server/rtsp-token.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 694d216214..e987e17258 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -19,7 +19,7 @@ /** * SECTION:rtsp-auth * @short_description: Authentication and authorization - * @see_also: #GstRTSPPermission, #GstRTSPtoken + * @see_also: #GstRTSPPermissions, #GstRTSPToken * * The #GstRTSPAuth object is responsible for checking if the current user is * allowed to perform requested actions. The default implementation has some @@ -30,7 +30,7 @@ * * The RTSP server will call gst_rtsp_auth_check() with a string describing the * check to perform. The possible checks are prefixed with - * #GST_RTSP_AUTH_CHECK_*. Depending on the check, the default implementation + * GST_RTSP_AUTH_CHECK_*. Depending on the check, the default implementation * will use the current #GstRTSPToken, #GstRTSPContext and * #GstRTSPPermissions on the object to check if an operation is allowed. * diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index ae60b962dd..2893308bff 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -21,7 +21,7 @@ * @short_description: Roles and associated permissions * @see_also: #GstRTSPToken, #GstRTSPAuth * - * The #GstRTSPPermission object contains an array of roles and associated + * The #GstRTSPPermissions object contains an array of roles and associated * permissions. The roles are represented with a string and the permissions with * a generic #GstStructure. * diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 6c0a0f50bc..796da5ac6f 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -125,7 +125,7 @@ free_session_media (gpointer data) * @path: the path * @media: the #GstRTSPMedia * - * Create a new #GstRTPSessionMedia that manages the streams + * Create a new #GstRTSPSessionMedia that manages the streams * in @media for @path. @media should be prepared. * * Ownership is taken of @media. diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 7df201b19c..79471e8dbb 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1348,7 +1348,7 @@ static GstAppSinkCallbacks sink_cb = { * @rtpbin: a rtpbin element in @bin * @state: the target state of the new elements * - * Join the #Gstbin @bin that contains the element @rtpbin. + * Join the #GstBin @bin that contains the element @rtpbin. * * @stream will link to @rtpbin, which must be inside @bin. The elements * added to @bin will be set to the state given in @state. diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index 787213d5cb..dfbb1f8d24 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -19,7 +19,7 @@ /** * SECTION:rtsp-token * @short_description: Roles and permissions for a client - * @see_also: #GstRTSPClient, #GstRTSPPermission, #GstRTSPAuth + * @see_also: #GstRTSPClient, #GstRTSPPermissions, #GstRTSPAuth * * A #GstRTSPToken contains the permissions and roles of the user * performing the current request. A token is usually created when a user is From 08160e09136a09eb98a82bc63f788c22090811c2 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Fri, 22 Nov 2013 02:28:28 +0100 Subject: [PATCH 0850/1776] rtsp-*: Refer to NULL as a constant in comments Plus one typo fix. https://bugzilla.gnome.org/show_bug.cgi?id=714988 --- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-context.h | 12 ++++++------ gst/rtsp-server/rtsp-media.c | 2 +- gst/rtsp-server/rtsp-mount-points.c | 2 +- gst/rtsp-server/rtsp-server.c | 8 ++++---- gst/rtsp-server/rtsp-token.c | 4 ++-- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index ed1b663bef..76f8c8c476 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2846,7 +2846,7 @@ client_watch_notify (GstRTSPClient * client) * @context: (allow-none): a #GMainContext * * Attaches @client to @context. When the mainloop for @context is run, the - * client will be dispatched. When @context is NULL, the default context will be + * client will be dispatched. When @context is %NULL, the default context will be * used). * * This function should be called when the client properties and urls are fully diff --git a/gst/rtsp-server/rtsp-context.h b/gst/rtsp-server/rtsp-context.h index a43563fce0..9e001aae7f 100644 --- a/gst/rtsp-server/rtsp-context.h +++ b/gst/rtsp-server/rtsp-context.h @@ -43,13 +43,13 @@ typedef struct _GstRTSPContext GstRTSPContext; * @request: the complete request * @uri: the complete url parsed from @request * @method: the parsed method of @uri - * @auth: the current auth object or NULL + * @auth: the current auth object or %NULL * @token: authorisation token - * @session: the session, can be NULL - * @sessmedia: the session media for the url can be NULL - * @factory: the media factory for the url, can be NULL. - * @media: the media for the url can be NULL - * @stream: the stream for the url can be NULL + * @session: the session, can be %NULL + * @sessmedia: the session media for the url can be %NULL + * @factory: the media factory for the url, can be %NULL + * @media: the media for the url can be %NULL + * @stream: the stream for the url can be %NULL * @response: the response * * Information passed around containing the context of a request. diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e26a58837b..cfa3a25291 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2060,7 +2060,7 @@ not_prepared: /** * gst_rtsp_media_get_time_provider: * @media: a #GstRTSPMedia - * @address: an address or NULL + * @address: an address or %NULL * @port: a port or 0 * * Get the #GstNetTimeProvider for the clock used by @media. The time provider diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index b89f2c464c..49d8d3e101 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -225,7 +225,7 @@ has_prefix (DataItem * str, DataItem * prefix) * * Find the factory in @mounts that has the longest match with @path. * - * If @matched is NULL, @path willt match the factory exactly otherwise + * If @matched is %NULL, @path will match the factory exactly otherwise * the amount of characters that matched is returned in @matched. * * Returns: (transfer full): the #GstRTSPMediaFactory for @path. diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 364d5dcfea..e9b5d812e5 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -777,7 +777,7 @@ gst_rtsp_server_set_property (GObject * object, guint propid, * Create a #GSocket for @server. The socket will listen on the * configured service. * - * Returns: (transfer full): the #GSocket for @server or NULL when an error occured. + * Returns: (transfer full): the #GSocket for @server or %NULL when an error occured. */ GSocket * gst_rtsp_server_create_socket (GstRTSPServer * server, @@ -1235,12 +1235,12 @@ watch_destroyed (GstRTSPServer * server) * Create a #GSource for @server. The new source will have a default * #GSocketSourceFunc of gst_rtsp_server_io_func(). * - * @cancellable if not NULL can be used to cancel the source, which will cause + * @cancellable if not %NULL can be used to cancel the source, which will cause * the source to trigger, reporting the current condition (which is likely 0 * unless cancellation happened at the same time as a condition change). You can * check for this in the callback using g_cancellable_is_cancelled(). * - * Returns: the #GSource for @server or NULL when an error occured. Free with + * Returns: the #GSource for @server or %NULL when an error occured. Free with * g_source_unref () */ GSource * @@ -1292,7 +1292,7 @@ no_socket: * @context: (allow-none): a #GMainContext * * Attaches @server to @context. When the mainloop for @context is run, the - * server will be dispatched. When @context is NULL, the default context will be + * server will be dispatched. When @context is %NULL, the default context will be * used). * * This function should be called when the server properties and urls are fully diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index dfbb1f8d24..7e234e82ae 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -195,7 +195,7 @@ gst_rtsp_token_get_structure (GstRTSPToken * token) * Returns: The structure of the token. The structure is still * owned by the token, which means that you should not free it and * that the pointer becomes invalid when you free the token. - * This function checks if @token is writable and will never return NULL. + * This function checks if @token is writable and will never return %NULL. * * MT safe. */ @@ -216,7 +216,7 @@ gst_rtsp_token_writable_structure (GstRTSPToken * token) * * Get the string value of @field in @token. * - * Returns: the string value of @field in @token or NULL when @field is not + * Returns: the string value of @field in @token or %NULL when @field is not * defined in @token. */ const gchar * From e5332535a738d90f234710b822cfe9a8bbbb23cf Mon Sep 17 00:00:00 2001 From: Aleix Conchillo Flaque Date: Fri, 15 Nov 2013 12:14:32 -0800 Subject: [PATCH 0851/1776] rtsp-stream: add getter for payload type * gst/rtsp-server/rtsp-stream.c: add new method gst_rtsp_stream_get_pt. * gst/rtsp-server/rtsp-media.c (pad_added_cb): find real payloader element and create the stream with this one instead of the dynpay%d element. https://bugzilla.gnome.org/show_bug.cgi?id=712396 --- gst/rtsp-server/rtsp-media.c | 32 ++++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-stream.c | 23 +++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 1 + 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index cfa3a25291..09628d3541 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -67,6 +67,8 @@ #include #include +#include + #include "rtsp-media.h" #define GST_RTSP_MEDIA_GET_PRIVATE(obj) \ @@ -1529,15 +1531,41 @@ watch_destroyed (GstRTSPMedia * media) g_object_unref (media); } +static GstElement * +find_payload_element (GstElement * payloader) +{ + GValue item = { 0 }; + GstIterator *iter; + GstElement *element; + GstElement *pay = NULL; + + iter = gst_bin_iterate_recurse (GST_BIN (payloader)); + while (gst_iterator_next (iter, &item) == GST_ITERATOR_OK) { + element = (GstElement *) g_value_get_object (&item); + if (GST_IS_RTP_BASE_PAYLOAD (element)) { + pay = gst_object_ref (element); + g_value_unset (&item); + break; + } + g_value_unset (&item); + } + gst_iterator_free (iter); + + return pay; +} + /* called from streaming threads */ static void pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; GstRTSPStream *stream; + GstElement *pay; - /* FIXME, element is likely not a payloader, find the payloader here */ - stream = gst_rtsp_media_create_stream (media, element, pad); + /* find the real payload element */ + pay = find_payload_element (element); + stream = gst_rtsp_media_create_stream (media, pay, pad); + gst_object_unref (pay); g_object_set_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream", stream); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 79471e8dbb..046ca5c72f 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -306,6 +306,29 @@ gst_rtsp_stream_get_index (GstRTSPStream * stream) return stream->priv->idx; } +/** + * gst_rtsp_stream_get_pt: + * @stream: a #GstRTSPStream + * + * Get the stream payload type. + * + * Return: the stream payload type. + */ +guint +gst_rtsp_stream_get_pt (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + guint pt; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), -1); + + priv = stream->priv; + + g_object_get (G_OBJECT (priv->payloader), "pt", &pt, NULL); + + return pt; +} + /** * gst_rtsp_stream_get_srcpad: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 7bd46814cb..2aefdcf14d 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -66,6 +66,7 @@ GType gst_rtsp_stream_get_type (void); GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement *payloader, GstPad *srcpad); guint gst_rtsp_stream_get_index (GstRTSPStream *stream); +guint gst_rtsp_stream_get_pt (GstRTSPStream *stream); GstPad * gst_rtsp_stream_get_srcpad (GstRTSPStream *stream); void gst_rtsp_stream_set_control (GstRTSPStream *stream, const gchar *control); From 7b5763179a161475d176d25b39e9a51fd1eecc19 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 22 Nov 2013 11:16:20 +0100 Subject: [PATCH 0852/1776] rtsp-media: use element metadata to find payloader Use the element metadata to find the payloader instead of checking for the base class. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=712396 --- gst/rtsp-server/rtsp-media.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 09628d3541..5767ba9576 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -67,8 +67,6 @@ #include #include -#include - #include "rtsp-media.h" #define GST_RTSP_MEDIA_GET_PRIVATE(obj) \ @@ -1536,13 +1534,19 @@ find_payload_element (GstElement * payloader) { GValue item = { 0 }; GstIterator *iter; - GstElement *element; GstElement *pay = NULL; iter = gst_bin_iterate_recurse (GST_BIN (payloader)); while (gst_iterator_next (iter, &item) == GST_ITERATOR_OK) { - element = (GstElement *) g_value_get_object (&item); - if (GST_IS_RTP_BASE_PAYLOAD (element)) { + GstElement *element = (GstElement *) g_value_get_object (&item); + GstElementClass *eclass = GST_ELEMENT_GET_CLASS (element); + const gchar *klass; + + klass = gst_element_class_get_metadata (eclass, GST_ELEMENT_METADATA_KLASS); + if (klass == NULL) + continue; + + if (strstr (klass, "Payloader") && strstr (klass, "RTP")) { pay = gst_object_ref (element); g_value_unset (&item); break; From b6d4a29d75b5a7bc8debe796b4092e55664b638b Mon Sep 17 00:00:00 2001 From: Aleix Conchillo Flaque Date: Wed, 20 Nov 2013 15:51:54 -0800 Subject: [PATCH 0853/1776] rtsp-media: remove transports if media is in error status * gst/rtsp-server/rtsp-media.c (gst_rtsp_media_set_state): if we are trying to change to GST_STATE_NULL and media is in error status, we remove all transports. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=712776 --- gst/rtsp-server/rtsp-media.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 5767ba9576..a41d688d2a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2187,6 +2187,8 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, priv = media->priv; g_rec_mutex_lock (&priv->state_lock); + if (priv->status == GST_RTSP_MEDIA_STATUS_ERROR) + goto error_status; if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) goto not_prepared; @@ -2268,6 +2270,26 @@ not_prepared: g_rec_mutex_unlock (&priv->state_lock); return FALSE; } +error_status: + { + GST_WARNING ("media %p in error status while changing to state %d", + media, state); + if (state == GST_STATE_NULL) { + for (i = 0; i < transports->len; i++) { + GstRTSPStreamTransport *trans; + + /* we need a non-NULL entry in the array */ + trans = g_ptr_array_index (transports, i); + if (trans == NULL) + continue; + + gst_rtsp_stream_transport_set_active (trans, FALSE); + } + priv->n_active = 0; + } + g_rec_mutex_unlock (&priv->state_lock); + return FALSE; + } } /* called with state-lock */ From 1ebc2c703e1af0fe2254f840a9b04bfdf965b146 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Fri, 22 Nov 2013 01:30:53 +0100 Subject: [PATCH 0854/1776] rtsp-media/-factory: Fix request pad name comments These must be escaped for gtk-doc to parse the comments without warnings. --- gst/rtsp-server/rtsp-media-factory.c | 2 +- gst/rtsp-server/rtsp-media-factory.h | 4 ++-- gst/rtsp-server/rtsp-media.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 59b1b022f5..d04c6382c3 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -981,7 +981,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) * Construct and return a #GstElement that is a #GstBin containing * the elements to use for streaming the media. * - * The bin should contain payloaders pay%d for each stream. The default + * The bin should contain payloaders pay\%d for each stream. The default * implementation of this function returns the bin created from the * launch parameter. * diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 33ec5404a6..d8819b16eb 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -63,12 +63,12 @@ struct _GstRTSPMediaFactory { * including the query parameters to return a key. * @create_element: Construct and return a #GstElement that is a #GstBin containing * the elements to use for streaming the media. The bin should contain - * payloaders pay%d for each stream. The default implementation of this + * payloaders pay\%d for each stream. The default implementation of this * function returns the bin created from the launch parameter. * @construct: the vmethod that will be called when the factory has to create the * #GstRTSPMedia for @url. The default implementation of this * function calls create_element to retrieve an element and then looks for - * pay%d to create the streams. + * pay\%d to create the streams. * @create_pipeline: create a new pipeline or re-use an existing one and * add the #GstRTSPMedia's element created by @construct to the pipeline. * @configure: configure the media created with @construct. The default diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index a41d688d2a..96ce504519 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -937,10 +937,10 @@ gst_rtsp_media_get_address_pool (GstRTSPMedia * media) * gst_rtsp_media_collect_streams: * @media: a #GstRTSPMedia * - * Find all payloader elements, they should be named pay%d in the + * Find all payloader elements, they should be named pay\%d in the * element of @media, and create #GstRTSPStreams for them. * - * Collect all dynamic elements, named dynpay%d, and add them to + * Collect all dynamic elements, named dynpay\%d, and add them to * the list of dynamic elements. */ void From 9da7b5eeb51eccf329add863321c07e4b00f47c2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 26 Nov 2013 16:24:35 +0100 Subject: [PATCH 0855/1776] media: handle add-added on non-bins too Handle dynamic payloaders that are not bins, as used in the unit-test. --- gst/rtsp-server/rtsp-media.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 96ce504519..06c236336c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1532,28 +1532,34 @@ watch_destroyed (GstRTSPMedia * media) static GstElement * find_payload_element (GstElement * payloader) { - GValue item = { 0 }; - GstIterator *iter; GstElement *pay = NULL; - iter = gst_bin_iterate_recurse (GST_BIN (payloader)); - while (gst_iterator_next (iter, &item) == GST_ITERATOR_OK) { - GstElement *element = (GstElement *) g_value_get_object (&item); - GstElementClass *eclass = GST_ELEMENT_GET_CLASS (element); - const gchar *klass; + if (GST_IS_BIN (payloader)) { + GstIterator *iter; + GValue item = { 0 }; - klass = gst_element_class_get_metadata (eclass, GST_ELEMENT_METADATA_KLASS); - if (klass == NULL) - continue; + iter = gst_bin_iterate_recurse (GST_BIN (payloader)); + while (gst_iterator_next (iter, &item) == GST_ITERATOR_OK) { + GstElement *element = (GstElement *) g_value_get_object (&item); + GstElementClass *eclass = GST_ELEMENT_GET_CLASS (element); + const gchar *klass; - if (strstr (klass, "Payloader") && strstr (klass, "RTP")) { - pay = gst_object_ref (element); + klass = + gst_element_class_get_metadata (eclass, GST_ELEMENT_METADATA_KLASS); + if (klass == NULL) + continue; + + if (strstr (klass, "Payloader") && strstr (klass, "RTP")) { + pay = gst_object_ref (element); + g_value_unset (&item); + break; + } g_value_unset (&item); - break; } - g_value_unset (&item); + gst_iterator_free (iter); + } else { + pay = g_object_ref (payloader); } - gst_iterator_free (iter); return pay; } From b8ae2570d9a4807fdd7d97b000a026cddde1b5ae Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 26 Nov 2013 16:25:37 +0100 Subject: [PATCH 0856/1776] media: take the right lock in gst_rtsp_media_set_pipeline_state() We need to take the state_lock when calling this method. --- gst/rtsp-server/rtsp-media.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 06c236336c..90948c0032 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2138,15 +2138,8 @@ gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address, return provider; } -/** - * gst_rtsp_media_set_pipeline_state: - * @media: a #GstRTSPMedia - * @state: the target state of the pipeline - * - * Set the state of the pipeline managed by @media to @state - */ -void -gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state) +static void +media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) { GstRTSPMediaPrivate *priv = media->priv; @@ -2165,6 +2158,23 @@ gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state) } } +/** + * gst_rtsp_media_set_pipeline_state: + * @media: a #GstRTSPMedia + * @state: the target state of the pipeline + * + * Set the state of the pipeline managed by @media to @state + */ +void +gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state) +{ + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + g_rec_mutex_lock (&media->priv->state_lock); + media_set_pipeline_state_locked (media, state); + g_rec_mutex_unlock (&media->priv->state_lock); +} + /** * gst_rtsp_media_set_state: * @media: a #GstRTSPMedia @@ -2254,7 +2264,7 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, if (priv->target_state != state) { if (do_state) - gst_rtsp_media_set_pipeline_state (media, state); + media_set_pipeline_state_locked (media, state); g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state, NULL); From b3baa2801d53cc018a00590c24f53c11fa0ee476 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 26 Nov 2013 17:23:04 +0100 Subject: [PATCH 0857/1776] media: move default implementations to where they are used --- gst/rtsp-server/rtsp-media.c | 69 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 90948c0032..5529845a29 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -167,9 +167,8 @@ static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message); static void finish_unprepare (GstRTSPMedia * media); static gboolean default_unprepare (GstRTSPMedia * media); -static gboolean -default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range, - GstRTSPRangeUnit unit); +static gboolean default_convert_range (GstRTSPMedia * media, + GstRTSPTimeRange * range, GstRTSPRangeUnit unit); static gboolean default_query_position (GstRTSPMedia * media, gint64 * position); static gboolean default_query_stop (GstRTSPMedia * media, gint64 * stop); @@ -380,6 +379,30 @@ gst_rtsp_media_set_property (GObject * object, guint propid, } } +static gboolean +default_query_position (GstRTSPMedia * media, gint64 * position) +{ + return gst_element_query_position (media->priv->pipeline, GST_FORMAT_TIME, + position); +} + +static gboolean +default_query_stop (GstRTSPMedia * media, gint64 * stop) +{ + GstQuery *query; + gboolean res; + + query = gst_query_new_segment (GST_FORMAT_TIME); + if ((res = gst_element_query (media->priv->pipeline, query))) { + GstFormat format; + gst_query_parse_segment (query, NULL, &format, NULL, stop); + if (format != GST_FORMAT_TIME) + *stop = -1; + } + gst_query_unref (query); + return res; +} + /* must be called with state lock */ static void collect_media_stats (GstRTSPMedia * media) @@ -1166,6 +1189,14 @@ gst_rtsp_media_find_stream (GstRTSPMedia * media, const gchar * control) return res; } +/* called with state-lock */ +static gboolean +default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range, + GstRTSPRangeUnit unit) +{ + return gst_rtsp_range_convert_units (range, unit); +} + /** * gst_rtsp_media_get_range_string: * @media: a #GstRTSPMedia @@ -2307,35 +2338,3 @@ error_status: return FALSE; } } - -/* called with state-lock */ -static gboolean -default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range, - GstRTSPRangeUnit unit) -{ - return gst_rtsp_range_convert_units (range, unit); -} - -static gboolean -default_query_position (GstRTSPMedia * media, gint64 * position) -{ - return gst_element_query_position (media->priv->pipeline, GST_FORMAT_TIME, - position); -} - -static gboolean -default_query_stop (GstRTSPMedia * media, gint64 * stop) -{ - GstQuery *query; - gboolean res; - - query = gst_query_new_segment (GST_FORMAT_TIME); - if ((res = gst_element_query (media->priv->pipeline, query))) { - GstFormat format; - gst_query_parse_segment (query, NULL, &format, NULL, stop); - if (format != GST_FORMAT_TIME) - *stop = -1; - } - gst_query_unref (query); - return res; -} From 1b0bf529d59c182cd8dee85cc57e6bfcba79e845 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 27 Nov 2013 15:42:45 +0100 Subject: [PATCH 0858/1776] docs: Specify the override file Even if it's empty (for now) it avoids make distcheck complaining --- docs/libs/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/libs/Makefile.am b/docs/libs/Makefile.am index 0aadfe4b50..64b7aa5caf 100644 --- a/docs/libs/Makefile.am +++ b/docs/libs/Makefile.am @@ -101,7 +101,6 @@ GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) # If you need to override some of the declarations, place them in this file # and uncomment this line. -#DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt -DOC_OVERRIDES = +DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt include $(top_srcdir)/common/gtk-doc.mak From bdef6312182470a6ff4726c94ea66a8396bfce9f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 28 Nov 2013 13:42:21 +0100 Subject: [PATCH 0859/1776] stream: add API to block streams Add an API to block on the streams and make it post a message. Based on patch by Ognyan Tonchev See https://bugzilla.gnome.org/show_bug.cgi?id=711257 --- gst/rtsp-server/rtsp-stream.c | 90 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 5 +- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 046ca5c72f..6428150017 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -120,6 +120,10 @@ struct _GstRTSPStreamPrivate GList *transports; gint dscp_qos; + + /* stream blocking */ + gulong blocked_id; + gboolean blocking; }; #define DEFAULT_CONTROL NULL @@ -2154,3 +2158,89 @@ gst_rtsp_stream_transport_filter (GstRTSPStream * stream, return result; } + +static GstPadProbeReturn +pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) +{ + GstRTSPStreamPrivate *priv; + GstRTSPStream *stream; + + stream = user_data; + priv = stream->priv; + + GST_DEBUG_OBJECT (pad, "now blocking"); + + g_mutex_lock (&priv->lock); + priv->blocking = TRUE; + g_mutex_unlock (&priv->lock); + + gst_element_post_message (priv->payloader, + gst_message_new_element (GST_OBJECT_CAST (priv->payloader), + gst_structure_new_empty ("GstRTSPStreamBlocking"))); + + return GST_PAD_PROBE_OK; +} + +/** + * gst_rtsp_stream_set_blocked: + * @stream: a #GstRTSPStream + * @blocked: boolean indicating we should block or unblock + * + * Blocks or unblocks the dataflow on @stream. + * + * Returns: %TRUE on success + */ +gboolean +gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked) +{ + GstRTSPStreamPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if (blocked) { + priv->blocking = FALSE; + if (priv->blocked_id == 0) { + priv->blocked_id = gst_pad_add_probe (priv->srcpad, + GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER | + GST_PAD_PROBE_TYPE_BUFFER_LIST, pad_blocking, + g_object_ref (stream), g_object_unref); + } + } else { + if (priv->blocked_id != 0) { + gst_pad_remove_probe (priv->srcpad, priv->blocked_id); + priv->blocked_id = 0; + priv->blocking = FALSE; + } + } + g_mutex_unlock (&priv->lock); + + return TRUE; +} + +/** + * gst_rtsp_stream_is_blocking: + * @stream: a #GstRTSPStream + * + * Check if @stream is blocking on a #GstBuffer. + * + * Returns: %TRUE if @stream is blocking + */ +gboolean +gst_rtsp_stream_is_blocking (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + gboolean result; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + result = priv->blocking; + g_mutex_unlock (&priv->lock); + + return result; +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 2aefdcf14d..9303a62bee 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -98,6 +98,10 @@ gboolean gst_rtsp_stream_join_bin (GstRTSPStream *stream, gboolean gst_rtsp_stream_leave_bin (GstRTSPStream *stream, GstBin *bin, GstElement *rtpbin); +gboolean gst_rtsp_stream_set_blocked (GstRTSPStream * stream, + gboolean blocked); +gboolean gst_rtsp_stream_is_blocking (GstRTSPStream * stream); + void gst_rtsp_stream_get_server_port (GstRTSPStream *stream, GstRTSPRange *server_port, GSocketFamily family); @@ -157,7 +161,6 @@ GList * gst_rtsp_stream_transport_filter (GstRTSPStream *stream, GstRTSPStreamTransportFilterFunc func, gpointer user_data); - G_END_DECLS #endif /* __GST_RTSP_STREAM_H__ */ From 6ce48c51a20b0a330a1dac12341b37b0ef442545 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 28 Nov 2013 13:58:05 +0100 Subject: [PATCH 0860/1776] media: refactor starting and waiting for preroll Based on patches from Ognyan Tonchev See https://bugzilla.gnome.org/show_bug.cgi?id=711257 --- gst/rtsp-server/rtsp-media.c | 123 ++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 38 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 5529845a29..b3cff1de68 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -173,6 +173,8 @@ static gboolean default_query_position (GstRTSPMedia * media, gint64 * position); static gboolean default_query_stop (GstRTSPMedia * media, gint64 * stop); +static gboolean wait_preroll (GstRTSPMedia * media); + static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); @@ -1345,10 +1347,14 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) /* and block for the seek to complete */ GST_INFO ("done seeking %d", res); - gst_element_get_state (priv->pipeline, NULL, NULL, -1); - GST_INFO ("prerolled again"); + g_rec_mutex_unlock (&priv->state_lock); - collect_media_stats (media); + /* wait until pipeline is prerolled again, this will also collect stats */ + if (!wait_preroll (media)) + goto preroll_failed; + + g_rec_mutex_lock (&priv->state_lock); + GST_INFO ("prerolled again"); } else { GST_INFO ("no seek needed"); res = TRUE; @@ -1376,6 +1382,11 @@ not_supported: GST_WARNING ("conversion to npt not supported"); return FALSE; } +preroll_failed: + { + GST_WARNING ("failed to preroll after seek"); + return FALSE; + } } static void @@ -1684,10 +1695,74 @@ struct _DynPaySignalHandlers }; static gboolean -start_prepare (GstRTSPMedia * media) +start_preroll (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; GstStateChangeReturn ret; + + GST_INFO ("setting pipeline to PAUSED for media %p", media); + /* first go to PAUSED */ + ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); + priv->target_state = GST_STATE_PAUSED; + + switch (ret) { + case GST_STATE_CHANGE_SUCCESS: + GST_INFO ("SUCCESS state change for media %p", media); + priv->seekable = TRUE; + break; + case GST_STATE_CHANGE_ASYNC: + GST_INFO ("ASYNC state change for media %p", media); + priv->seekable = TRUE; + break; + case GST_STATE_CHANGE_NO_PREROLL: + /* we need to go to PLAYING */ + GST_INFO ("NO_PREROLL state change: live media %p", media); + /* FIXME we disable seeking for live streams for now. We should perform a + * seeking query in preroll instead */ + priv->seekable = FALSE; + priv->is_live = TRUE; + ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) + goto state_failed; + break; + case GST_STATE_CHANGE_FAILURE: + goto state_failed; + } + + return TRUE; + +state_failed: + { + GST_WARNING ("failed to preroll pipeline"); + return FALSE; + } +} + +static gboolean +wait_preroll (GstRTSPMedia * media) +{ + GstRTSPMediaStatus status; + + GST_DEBUG ("wait to preroll pipeline"); + + /* wait until pipeline is prerolled */ + status = gst_rtsp_media_get_status (media); + if (status == GST_RTSP_MEDIA_STATUS_ERROR) + goto preroll_failed; + + return TRUE; + +preroll_failed: + { + GST_WARNING ("failed to preroll pipeline"); + return FALSE; + } +} + +static gboolean +start_prepare (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; guint i; GList *walk; @@ -1723,38 +1798,12 @@ start_prepare (GstRTSPMedia * media) gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink); } - GST_INFO ("setting pipeline to PAUSED for media %p", media); - /* first go to PAUSED */ - ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); - priv->target_state = GST_STATE_PAUSED; - - switch (ret) { - case GST_STATE_CHANGE_SUCCESS: - GST_INFO ("SUCCESS state change for media %p", media); - priv->seekable = TRUE; - break; - case GST_STATE_CHANGE_ASYNC: - GST_INFO ("ASYNC state change for media %p", media); - priv->seekable = TRUE; - break; - case GST_STATE_CHANGE_NO_PREROLL: - /* we need to go to PLAYING */ - GST_INFO ("NO_PREROLL state change: live media %p", media); - /* FIXME we disable seeking for live streams for now. We should perform a - * seeking query in preroll instead */ - priv->seekable = FALSE; - priv->is_live = TRUE; - ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); - if (ret == GST_STATE_CHANGE_FAILURE) - goto state_failed; - break; - case GST_STATE_CHANGE_FAILURE: - goto state_failed; - } + if (!start_preroll (media)) + goto preroll_failed; return FALSE; -state_failed: +preroll_failed: { GST_WARNING ("failed to preroll pipeline"); gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR); @@ -1780,7 +1829,6 @@ gboolean gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) { GstRTSPMediaPrivate *priv; - GstRTSPMediaStatus status; GstBus *bus; GSource *source; @@ -1856,9 +1904,8 @@ wait_status: /* now wait for all pads to be prerolled, FIXME, we should somehow be * able to do this async so that we don't block the server thread. */ - status = gst_rtsp_media_get_status (media); - if (status == GST_RTSP_MEDIA_STATUS_ERROR) - goto state_failed; + if (!wait_preroll (media)) + goto preroll_failed; g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL); @@ -1896,7 +1943,7 @@ no_rtpbin: g_warning ("failed to create element 'rtpbin', check your installation"); return FALSE; } -state_failed: +preroll_failed: { GST_WARNING ("failed to preroll pipeline"); gst_rtsp_media_unprepare (media); From db771c5167f46cb64f7ad3b870d68f95530420d3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 28 Nov 2013 14:06:53 +0100 Subject: [PATCH 0861/1776] media: start live streams in blocked state Start live streams in the blocked state and make them preroll using the messages. This ensure that no data is played by the sink until we explicitly unblock the stream right before going to PLAYING. See https://bugzilla.gnome.org/show_bug.cgi?id=711257 --- gst/rtsp-server/rtsp-media.c | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b3cff1de68..e1dd573059 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -86,6 +86,7 @@ struct _GstRTSPMediaPrivate gboolean eos_shutdown; guint buffer_size; GstRTSPAddressPool *pool; + gboolean blocked; GstElement *element; GRecMutex state_lock; /* locking order: state lock, lock */ @@ -1265,6 +1266,22 @@ conversion_failed: } } +static void +stream_update_blocked (GstRTSPStream * stream, GstRTSPMedia * media) +{ + gst_rtsp_stream_set_blocked (stream, media->priv->blocked); +} + +static void +media_streams_set_blocked (GstRTSPMedia * media, gboolean blocked) +{ + GstRTSPMediaPrivate *priv = media->priv; + + GST_DEBUG ("media %p set blocked %d", media, blocked); + priv->blocked = blocked; + g_ptr_array_foreach (priv->streams, (GFunc) stream_update_blocked, media); +} + /** * gst_rtsp_media_seek: * @media: a #GstRTSPMedia @@ -1342,6 +1359,10 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); + priv->status = GST_RTSP_MEDIA_STATUS_PREPARING; + if (priv->blocked) + media_streams_set_blocked (media, TRUE); + res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME, flags, start_type, start, stop_type, stop); @@ -1435,6 +1456,23 @@ gst_rtsp_media_get_status (GstRTSPMedia * media) return result; } +static void +stream_collect_blocking (GstRTSPStream * stream, gboolean * blocked) +{ + *blocked &= gst_rtsp_stream_is_blocking (stream); +} + +static gboolean +media_streams_blocking (GstRTSPMedia * media) +{ + gboolean blocking = TRUE; + + g_ptr_array_foreach (media->priv->streams, (GFunc) stream_collect_blocking, + &blocking); + + return blocking; +} + /* called with state-lock */ static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message) @@ -1512,7 +1550,22 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) break; } case GST_MESSAGE_ELEMENT: + { + const GstStructure *s; + + s = gst_message_get_structure (message); + if (gst_structure_has_name (s, "GstRTSPStreamBlocking")) { + GST_DEBUG ("media received blocking message"); + if (priv->blocked && media_streams_blocking (media)) { + GST_DEBUG ("media is blocking"); + collect_media_stats (media); + + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); + } + } break; + } case GST_MESSAGE_STREAM_STATUS: break; case GST_MESSAGE_ASYNC_DONE: @@ -1721,6 +1774,8 @@ start_preroll (GstRTSPMedia * media) * seeking query in preroll instead */ priv->seekable = FALSE; priv->is_live = TRUE; + /* start blocked to make sure nothing goes to the sink */ + media_streams_set_blocked (media, TRUE); ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; @@ -2231,6 +2286,10 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) if (priv->buffering) { GST_INFO ("Buffering busy, delay state change"); } else { + if (state == GST_STATE_PLAYING) + /* make sure pads are not blocking anymore when going to PLAYING */ + media_streams_set_blocked (media, FALSE); + gst_element_set_state (priv->pipeline, state); } } From 2f17369e9d110e1a437124a3e116fd2e092363bd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 28 Nov 2013 14:10:19 +0100 Subject: [PATCH 0862/1776] media: add suspend modes Add support for different suspend modes. The stream is suspended right after producing the SDP and after PAUSE. Different suspend modes are available that affect the state of the pipeline. NONE leaves the pipeline state unchanged and is the current and old behaviour, PAUSE will set the pipeline to the PAUSED state and RESET will bring the pipeline to the NULL state. A stream is also unsuspended when it goes back to PLAYING, for RESET streams, this means that the pipeline needs to be prerolled again. Base on patches by Ognyan Tonchev See https://bugzilla.gnome.org/show_bug.cgi?id=711257 --- gst/rtsp-server/rtsp-media-factory.c | 68 ++++++++ gst/rtsp-server/rtsp-media-factory.h | 4 + gst/rtsp-server/rtsp-media.c | 240 +++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 38 ++++- gst/rtsp-server/rtsp-session-media.c | 6 +- gst/rtsp-server/rtsp-session.c | 6 +- tests/check/gst/media.c | 45 +++++ tests/check/gst/mediafactory.c | 35 ++++ 8 files changed, 432 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index d04c6382c3..590b1f7d69 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -51,6 +51,7 @@ struct _GstRTSPMediaFactoryPrivate GstRTSPPermissions *permissions; gchar *launch; gboolean shared; + GstRTSPSuspendMode suspend_mode; gboolean eos_shutdown; GstRTSPLowerTrans protocols; guint buffer_size; @@ -62,6 +63,7 @@ struct _GstRTSPMediaFactoryPrivate #define DEFAULT_LAUNCH NULL #define DEFAULT_SHARED FALSE +#define DEFAULT_SUSPEND_MODE GST_RTSP_SUSPEND_MODE_NONE #define DEFAULT_EOS_SHUTDOWN FALSE #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ GST_RTSP_LOWER_TRANS_TCP @@ -72,6 +74,7 @@ enum PROP_0, PROP_LAUNCH, PROP_SHARED, + PROP_SUSPEND_MODE, PROP_EOS_SHUTDOWN, PROP_PROTOCOLS, PROP_BUFFER_SIZE, @@ -148,6 +151,11 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "If media from this factory is shared", DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_SUSPEND_MODE, + g_param_spec_enum ("suspend-mode", "Suspend Mode", + "Control how media will be suspended", GST_TYPE_RTSP_SUSPEND_MODE, + DEFAULT_SUSPEND_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN, g_param_spec_boolean ("eos-shutdown", "EOS Shutdown", "Send EOS down the pipeline before shutting down", @@ -194,6 +202,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->launch = g_strdup (DEFAULT_LAUNCH); priv->shared = DEFAULT_SHARED; + priv->suspend_mode = DEFAULT_SUSPEND_MODE; priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN; priv->protocols = DEFAULT_PROTOCOLS; priv->buffer_size = DEFAULT_BUFFER_SIZE; @@ -235,6 +244,10 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, case PROP_SHARED: g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory)); break; + case PROP_SUSPEND_MODE: + g_value_set_enum (value, + gst_rtsp_media_factory_get_suspend_mode (factory)); + break; case PROP_EOS_SHUTDOWN: g_value_set_boolean (value, gst_rtsp_media_factory_is_eos_shutdown (factory)); @@ -264,6 +277,10 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, case PROP_SHARED: gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value)); break; + case PROP_SUSPEND_MODE: + gst_rtsp_media_factory_set_suspend_mode (factory, + g_value_get_enum (value)); + break; case PROP_EOS_SHUTDOWN: gst_rtsp_media_factory_set_eos_shutdown (factory, g_value_get_boolean (value)); @@ -442,6 +459,54 @@ gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_set_suspend_mode: + * @factory: a #GstRTSPMediaFactory + * @mode: the new #GstRTSPSuspendMode + * + * Configure how media created from this factory will be suspended. + */ +void +gst_rtsp_media_factory_set_suspend_mode (GstRTSPMediaFactory * factory, + GstRTSPSuspendMode mode) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv->suspend_mode = mode; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_suspend_mode: + * @factory: a #GstRTSPMediaFactory + * + * Get how media created from this factory will be suspended. + * + * Returns: a #GstRTSPSuspendMode. + */ +GstRTSPSuspendMode +gst_rtsp_media_factory_get_suspend_mode (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + GstRTSPSuspendMode result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), + GST_RTSP_SUSPEND_MODE_NONE); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + result = priv->suspend_mode; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} + /** * gst_rtsp_media_factory_set_shared: * @factory: a #GstRTSPMediaFactory @@ -946,18 +1011,21 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstRTSPMediaFactoryPrivate *priv = factory->priv; gboolean shared, eos_shutdown; guint size; + GstRTSPSuspendMode suspend_mode; GstRTSPLowerTrans protocols; GstRTSPAddressPool *pool; GstRTSPPermissions *perms; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); + suspend_mode = priv->suspend_mode; shared = priv->shared; eos_shutdown = priv->eos_shutdown; size = priv->buffer_size; protocols = priv->protocols; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + gst_rtsp_media_set_suspend_mode (media, suspend_mode); gst_rtsp_media_set_shared (media, shared); gst_rtsp_media_set_eos_shutdown (media, eos_shutdown); gst_rtsp_media_set_buffer_size (media, size); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index d8819b16eb..63f4d827cf 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -114,6 +114,10 @@ void gst_rtsp_media_factory_set_shared (GstRTSPMediaFacto gboolean shared); gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_suspend_mode (GstRTSPMediaFactory *factory, + GstRTSPSuspendMode mode); +GstRTSPSuspendMode gst_rtsp_media_factory_get_suspend_mode (GstRTSPMediaFactory *factory); + void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory *factory, gboolean eos_shutdown); gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e1dd573059..2c72d97205 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -80,6 +80,7 @@ struct _GstRTSPMediaPrivate /* protected by lock */ GstRTSPPermissions *permissions; gboolean shared; + gboolean suspend_mode; gboolean reusable; GstRTSPLowerTrans protocols; gboolean reused; @@ -122,6 +123,7 @@ struct _GstRTSPMediaPrivate }; #define DEFAULT_SHARED FALSE +#define DEFAULT_SUSPEND_MODE GST_RTSP_SUSPEND_MODE_NONE #define DEFAULT_REUSABLE FALSE #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ GST_RTSP_LOWER_TRANS_TCP @@ -136,6 +138,7 @@ enum { PROP_0, PROP_SHARED, + PROP_SUSPEND_MODE, PROP_REUSABLE, PROP_PROTOCOLS, PROP_EOS_SHUTDOWN, @@ -178,6 +181,29 @@ static gboolean wait_preroll (GstRTSPMedia * media); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; +#define C_ENUM(v) ((gint) v) + +#define GST_TYPE_RTSP_SUSPEND_MODE (gst_rtsp_suspend_mode_get_type()) +GType +gst_rtsp_suspend_mode_get_type (void) +{ + static gsize id = 0; + static const GEnumValue values[] = { + {C_ENUM (GST_RTSP_SUSPEND_MODE_NONE), "GST_RTSP_SUSPEND_MODE_NONE", "none"}, + {C_ENUM (GST_RTSP_SUSPEND_MODE_PAUSE), "GST_RTSP_SUSPEND_MODE_PAUSE", + "pause"}, + {C_ENUM (GST_RTSP_SUSPEND_MODE_RESET), "GST_RTSP_SUSPEND_MODE_RESET", + "reset"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&id)) { + GType tmp = g_enum_register_static ("GstRTSPSuspendMode", values); + g_once_init_leave (&id, tmp); + } + return (GType) id; +} + G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); static void @@ -198,6 +224,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "If this media pipeline can be shared", DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_SUSPEND_MODE, + g_param_spec_enum ("suspend-mode", "Suspend Mode", + "How to suspend the media in PAUSED", GST_TYPE_RTSP_SUSPEND_MODE, + DEFAULT_SUSPEND_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_REUSABLE, g_param_spec_boolean ("reusable", "Reusable", "If this media pipeline can be reused after an unprepare", @@ -276,6 +307,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) g_rec_mutex_init (&priv->state_lock); priv->shared = DEFAULT_SHARED; + priv->suspend_mode = DEFAULT_SUSPEND_MODE; priv->reusable = DEFAULT_REUSABLE; priv->protocols = DEFAULT_PROTOCOLS; priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN; @@ -328,6 +360,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_SHARED: g_value_set_boolean (value, gst_rtsp_media_is_shared (media)); break; + case PROP_SUSPEND_MODE: + g_value_set_enum (value, gst_rtsp_media_get_suspend_mode (media)); + break; case PROP_REUSABLE: g_value_set_boolean (value, gst_rtsp_media_is_reusable (media)); break; @@ -362,6 +397,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_SHARED: gst_rtsp_media_set_shared (media, g_value_get_boolean (value)); break; + case PROP_SUSPEND_MODE: + gst_rtsp_media_set_suspend_mode (media, g_value_get_enum (value)); + break; case PROP_REUSABLE: gst_rtsp_media_set_reusable (media, g_value_get_boolean (value)); break; @@ -606,6 +644,66 @@ gst_rtsp_media_get_permissions (GstRTSPMedia * media) return result; } +/** + * gst_rtsp_media_set_suspend_mode: + * @media: a #GstRTSPMedia + * @mode: the new #GstRTSPSuspendMode + * + * Control how @ media will be suspended after the SDP has been generated and + * after a PAUSE request has been performed. + * + * Media must be unprepared when setting the suspend mode. + */ +void +gst_rtsp_media_set_suspend_mode (GstRTSPMedia * media, GstRTSPSuspendMode mode) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) + goto was_prepared; + priv->suspend_mode = mode; + g_rec_mutex_unlock (&priv->state_lock); + + return; + + /* ERRORS */ +was_prepared: + { + GST_WARNING ("media %p was prepared", media); + g_rec_mutex_unlock (&priv->state_lock); + } +} + +/** + * gst_rtsp_media_get_suspend_mode: + * @media: a #GstRTSPMedia + * + * Get how @media will be suspended. + * + * Returns: #GstRTSPSuspendMode. + */ +GstRTSPSuspendMode +gst_rtsp_media_get_suspend_mode (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + GstRTSPSuspendMode res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_RTSP_SUSPEND_MODE_NONE); + + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + res = priv->suspend_mode; + g_rec_mutex_unlock (&priv->state_lock); + + return res; +} + /** * gst_rtsp_media_set_shared: * @media: a #GstRTSPMedia @@ -2271,6 +2369,144 @@ gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address, return provider; } +/** + * gst_rtsp_media_suspend: + * @media: a #GstRTSPMedia + * + * Suspend @media. The state of the pipeline managed by @media is set to + * GST_STATE_NULL but all streams are kept. @media can be prepared again + * with gst_rtsp_media_undo_reset() + * + * @media must be prepared with gst_rtsp_media_prepare(); + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_media_suspend (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + GstStateChangeReturn ret; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + GST_FIXME ("suspend for dynamic pipelines needs fixing"); + + g_rec_mutex_lock (&priv->state_lock); + if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) + goto not_prepared; + + /* don't attempt to suspend when something is busy */ + if (priv->n_active > 0) + goto done; + + switch (priv->suspend_mode) { + case GST_RTSP_SUSPEND_MODE_NONE: + GST_DEBUG ("media %p no suspend", media); + break; + case GST_RTSP_SUSPEND_MODE_PAUSE: + GST_DEBUG ("media %p suspend to PAUSED", media); + priv->target_state = GST_STATE_PAUSED; + ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); + if (ret == GST_STATE_CHANGE_FAILURE) + goto state_failed; + break; + case GST_RTSP_SUSPEND_MODE_RESET: + GST_DEBUG ("media %p suspend to NULL", media); + priv->target_state = GST_STATE_NULL; + ret = gst_element_set_state (priv->pipeline, GST_STATE_NULL); + if (ret == GST_STATE_CHANGE_FAILURE) + goto state_failed; + break; + default: + break; + } + /* let the streams do the state changes freely, if any */ + media_streams_set_blocked (media, FALSE); + priv->status = GST_RTSP_MEDIA_STATUS_SUSPENDED; +done: + g_rec_mutex_unlock (&priv->state_lock); + + return TRUE; + + /* ERRORS */ +not_prepared: + { + g_rec_mutex_unlock (&priv->state_lock); + GST_WARNING ("media %p was not prepared", media); + return FALSE; + } +state_failed: + { + g_rec_mutex_unlock (&priv->state_lock); + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR); + GST_WARNING ("failed changing pipeline's state for media %p", media); + return FALSE; + } +} + +/** + * gst_rtsp_media_unsuspend: + * @media: a #GstRTSPMedia + * + * Unsuspend @media if it was in a suspended state. This method does nothing + * when the media was not in the suspended state. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_media_unsuspend (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + g_rec_mutex_lock (&priv->state_lock); + if (priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED) + goto done; + + switch (priv->suspend_mode) { + case GST_RTSP_SUSPEND_MODE_NONE: + priv->status = GST_RTSP_MEDIA_STATUS_PREPARED; + break; + case GST_RTSP_SUSPEND_MODE_PAUSE: + priv->status = GST_RTSP_MEDIA_STATUS_PREPARED; + break; + case GST_RTSP_SUSPEND_MODE_RESET: + { + priv->status = GST_RTSP_MEDIA_STATUS_PREPARING; + if (!start_preroll (media)) + goto start_failed; + g_rec_mutex_unlock (&priv->state_lock); + + if (!wait_preroll (media)) + goto preroll_failed; + + g_rec_mutex_lock (&priv->state_lock); + } + default: + break; + } +done: + g_rec_mutex_unlock (&priv->state_lock); + + return TRUE; + + /* ERRORS */ +start_failed: + { + g_rec_mutex_unlock (&priv->state_lock); + GST_WARNING ("failed to preroll pipeline"); + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR); + return FALSE; + } +preroll_failed: + { + GST_WARNING ("failed to preroll pipeline"); + return FALSE; + } +} + +/* must be called with state-lock */ static void media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) { @@ -2291,6 +2527,10 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) media_streams_set_blocked (media, FALSE); gst_element_set_state (priv->pipeline, state); + + /* and suspend after pause */ + if (state == GST_STATE_PAUSED) + gst_rtsp_media_suspend (media); } } } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 016526dd88..735576ba6f 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -41,11 +41,6 @@ typedef struct _GstRTSPMedia GstRTSPMedia; typedef struct _GstRTSPMediaClass GstRTSPMediaClass; typedef struct _GstRTSPMediaPrivate GstRTSPMediaPrivate; -#include "rtsp-stream.h" -#include "rtsp-thread-pool.h" -#include "rtsp-permissions.h" -#include "rtsp-address-pool.h" - /** * GstRTSPMediaStatus: * @GST_RTSP_MEDIA_STATUS_UNPREPARED: media pipeline not prerolled @@ -53,6 +48,7 @@ typedef struct _GstRTSPMediaPrivate GstRTSPMediaPrivate; * shutdown. * @GST_RTSP_MEDIA_STATUS_PREPARING: media pipeline is prerolling * @GST_RTSP_MEDIA_STATUS_PREPARED: media pipeline is prerolled + * @GST_RTSP_MEDIA_STATUS_SUSPENDED: media is suspended * @GST_RTSP_MEDIA_STATUS_ERROR: media pipeline is in error * * The state of the media pipeline. @@ -62,9 +58,33 @@ typedef enum { GST_RTSP_MEDIA_STATUS_UNPREPARING = 1, GST_RTSP_MEDIA_STATUS_PREPARING = 2, GST_RTSP_MEDIA_STATUS_PREPARED = 3, - GST_RTSP_MEDIA_STATUS_ERROR = 4 + GST_RTSP_MEDIA_STATUS_SUSPENDED = 4, + GST_RTSP_MEDIA_STATUS_ERROR = 5 } GstRTSPMediaStatus; +/** + * GstRTSPSuspendMode: + * @GST_RTSP_SUSPEND_MODE_NONE: Media is not suspended + * @GST_RTSP_SUSPEND_MODE_PAUSE: Media is PAUSED in suspend + * @GST_RTSP_SUSPEND_MODE_RESET: The media is set to NULL when suspended + * + * The suspend mode of the media pipeline. A media pipeline is suspended right + * after creating the SDP and when the client preforms a PAUSED request. + */ +typedef enum { + GST_RTSP_SUSPEND_MODE_NONE = 0, + GST_RTSP_SUSPEND_MODE_PAUSE = 1, + GST_RTSP_SUSPEND_MODE_RESET = 2 +} GstRTSPSuspendMode; + +#define GST_TYPE_RTSP_SUSPEND_MODE (gst_rtsp_suspend_mode_get_type()) +GType gst_rtsp_suspend_mode_get_type (void); + +#include "rtsp-stream.h" +#include "rtsp-thread-pool.h" +#include "rtsp-permissions.h" +#include "rtsp-address-pool.h" + /** * GstRTSPMedia: * @@ -154,6 +174,12 @@ GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media, gboolean gst_rtsp_media_prepare (GstRTSPMedia *media, GstRTSPThread *thread); gboolean gst_rtsp_media_unprepare (GstRTSPMedia *media); +void gst_rtsp_media_set_suspend_mode (GstRTSPMedia *media, GstRTSPSuspendMode mode); +GstRTSPSuspendMode gst_rtsp_media_get_suspend_mode (GstRTSPMedia *media); + +gboolean gst_rtsp_media_suspend (GstRTSPMedia *media); +gboolean gst_rtsp_media_unsuspend (GstRTSPMedia *media); + /* creating streams */ void gst_rtsp_media_collect_streams (GstRTSPMedia *media); GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia *media, diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 796da5ac6f..d042ea0b7d 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -138,11 +138,13 @@ gst_rtsp_session_media_new (const gchar * path, GstRTSPMedia * media) GstRTSPSessionMediaPrivate *priv; GstRTSPSessionMedia *result; guint n_streams; + GstRTSPMediaStatus status; g_return_val_if_fail (path != NULL, NULL); g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - g_return_val_if_fail (gst_rtsp_media_get_status (media) == - GST_RTSP_MEDIA_STATUS_PREPARED, NULL); + status = gst_rtsp_media_get_status (media); + g_return_val_if_fail (status == GST_RTSP_MEDIA_STATUS_PREPARED || status == + GST_RTSP_MEDIA_STATUS_SUSPENDED, NULL); result = g_object_new (GST_TYPE_RTSP_SESSION_MEDIA, NULL); priv = result->priv; diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 204ccf78f7..b2ff36d7c6 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -205,12 +205,14 @@ gst_rtsp_session_manage_media (GstRTSPSession * sess, const gchar * path, { GstRTSPSessionPrivate *priv; GstRTSPSessionMedia *result; + GstRTSPMediaStatus status; g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); g_return_val_if_fail (path != NULL, NULL); g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); - g_return_val_if_fail (gst_rtsp_media_get_status (media) == - GST_RTSP_MEDIA_STATUS_PREPARED, NULL); + status = gst_rtsp_media_get_status (media); + g_return_val_if_fail (status == GST_RTSP_MEDIA_STATUS_PREPARED || status == + GST_RTSP_MEDIA_STATUS_SUSPENDED, NULL); priv = sess->priv; diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index ca2c324b0d..23e858626a 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -300,6 +300,50 @@ GST_START_TEST (test_media_take_pipeline) GST_END_TEST; +GST_START_TEST (test_media_reset) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + + pool = gst_rtsp_thread_pool_new (); + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (gst_rtsp_media_suspend (media)); + fail_unless (gst_rtsp_media_unprepare (media)); + g_object_unref (media); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + gst_rtsp_media_set_suspend_mode (media, GST_RTSP_SUSPEND_MODE_RESET); + fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (gst_rtsp_media_suspend (media)); + fail_unless (gst_rtsp_media_unprepare (media)); + g_object_unref (media); + + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + static Suite * rtspmedia_suite (void) { @@ -313,6 +357,7 @@ rtspmedia_suite (void) tcase_add_test (tc, test_media_prepare); tcase_add_test (tc, test_media_dyn_prepare); tcase_add_test (tc, test_media_take_pipeline); + tcase_add_test (tc, test_media_reset); return s; } diff --git a/tests/check/gst/mediafactory.c b/tests/check/gst/mediafactory.c index 73e4883207..b6b250beb7 100644 --- a/tests/check/gst/mediafactory.c +++ b/tests/check/gst/mediafactory.c @@ -280,6 +280,40 @@ GST_START_TEST (test_permissions) GST_END_TEST; +GST_START_TEST (test_reset) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + fail_if (gst_rtsp_media_get_suspend_mode (media) != + GST_RTSP_SUSPEND_MODE_NONE); + g_object_unref (media); + + gst_rtsp_media_factory_set_suspend_mode (factory, + GST_RTSP_SUSPEND_MODE_RESET); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + fail_if (gst_rtsp_media_get_suspend_mode (media) != + GST_RTSP_SUSPEND_MODE_RESET); + g_object_unref (media); + + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + static Suite * rtspmediafactory_suite (void) { @@ -294,6 +328,7 @@ rtspmediafactory_suite (void) tcase_add_test (tc, test_shared); tcase_add_test (tc, test_addresspool); tcase_add_test (tc, test_permissions); + tcase_add_test (tc, test_reset); return s; } From b1e8172ef366458eecccd5f0d3b77d87fbb30d4a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 28 Nov 2013 14:14:35 +0100 Subject: [PATCH 0863/1776] client: suspend after SDP and unsuspend before PLAYING Based on patches by Ognyan Tonchev Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711257 --- gst/rtsp-server/rtsp-client.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 76f8c8c476..162f52ce6e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1074,6 +1074,10 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY) goto invalid_state; + /* in play we first unsuspend, media could be suspended from SDP or PAUSED */ + if (!gst_rtsp_media_unsuspend (media)) + goto unsuspend_failed; + /* parse the range header if we have one */ res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0); if (res == GST_RTSP_OK) { @@ -1194,6 +1198,13 @@ invalid_state: g_free (path); return FALSE; } +unsuspend_failed: + { + GST_ERROR ("client %p: unsuspend failed", client); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + g_free (path); + return FALSE; + } } static void @@ -1755,6 +1766,8 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!(sdp = klass->create_sdp (client, media))) goto no_sdp; + /* we suspend after the describe */ + gst_rtsp_media_suspend (media); g_object_unref (media); gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK, From 568477d9b53c5dfb46b2cf1517a1885c3feb519a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 28 Nov 2013 17:35:45 +0100 Subject: [PATCH 0864/1776] stream-transport: add method to get/set url --- gst/rtsp-server/rtsp-stream-transport.c | 41 +++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream-transport.h | 4 +++ 2 files changed, 45 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index c71c8ea7c7..bade2a61d2 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -62,6 +62,7 @@ struct _GstRTSPStreamTransportPrivate gboolean timed_out; GstRTSPTransport *transport; + GstRTSPUrl *url; GObject *rtpsource; }; @@ -266,6 +267,46 @@ gst_rtsp_stream_transport_get_transport (GstRTSPStreamTransport * trans) return trans->priv->transport; } +/** + * gst_rtsp_stream_transport_set_url: + * @trans: a #GstRTSPStreamTransport + * @url: (transfer none): a client #GstRTSPUrl + * + * Set @url as the client url. + */ +void +gst_rtsp_stream_transport_set_url (GstRTSPStreamTransport * trans, + const GstRTSPUrl * url) +{ + GstRTSPStreamTransportPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); + + priv = trans->priv; + + /* keep track of the transports in the stream. */ + if (priv->url) + gst_rtsp_url_free (priv->url); + priv->url = (url ? gst_rtsp_url_copy (url) : NULL); +} + +/** + * gst_rtsp_stream_transport_get_url: + * @trans: a #GstRTSPStreamTransport + * + * Get the url configured in @trans. + * + * Returns: (transfer none): the url configured in @trans. It remains + * valid for as long as @trans is valid. + */ +const GstRTSPUrl * +gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport * trans) +{ + g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL); + + return trans->priv->url; +} + /** * gst_rtsp_stream_transport_set_active: * @trans: a #GstRTSPStreamTransport diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index b73bf6ef57..fad6911cd5 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -91,6 +91,10 @@ void gst_rtsp_stream_transport_set_transport (GstRTSPStreamT GstRTSPTransport * tr); const GstRTSPTransport * gst_rtsp_stream_transport_get_transport (GstRTSPStreamTransport *trans); +void gst_rtsp_stream_transport_set_url (GstRTSPStreamTransport *trans, + const GstRTSPUrl * url); +const GstRTSPUrl * gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport *trans); + void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans, GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, From 421499c10274201d83c143627b6b487049e1192c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 28 Nov 2013 17:47:18 +0100 Subject: [PATCH 0865/1776] client: store setup uri and use in PLAY response Store the uri used when doing the setup and use that in the PLAY response. fixes https://bugzilla.gnome.org/show_bug.cgi?id=715168 --- gst/rtsp-server/rtsp-client.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 162f52ce6e..a9ccbc2146 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1041,7 +1041,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPUrl *uri; GString *rtpinfo; guint n_streams, i, infocount; - gchar *str, *base_url; + gchar *str; GstRTSPTimeRange *range; GstRTSPResult res; GstRTSPState rtspstate; @@ -1092,8 +1092,6 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) /* grab RTPInfo from the payloaders now */ rtpinfo = g_string_new (""); - base_url = make_base_url (client, uri, path); - n_streams = gst_rtsp_media_n_streams (media); for (i = 0, infocount = 0; i < n_streams; i++) { GstRTSPStreamTransport *trans; @@ -1116,22 +1114,23 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) stream = gst_rtsp_stream_transport_get_stream (trans); if (gst_rtsp_stream_get_rtpinfo (stream, &rtptime, &seq)) { - gchar *control; + const GstRTSPUrl *url; + gchar *url_str; if (infocount > 0) g_string_append (rtpinfo, ", "); - control = gst_rtsp_stream_get_control (stream); - g_string_append_printf (rtpinfo, "url=%s%s;seq=%u;rtptime=%u", - base_url, control, seq, rtptime); - g_free (control); + url = gst_rtsp_stream_transport_get_url (trans); + url_str = gst_rtsp_url_get_request_uri (url); + g_string_append_printf (rtpinfo, "url=%s;seq=%u;rtptime=%u", + url_str, seq, rtptime); + g_free (url_str); infocount++; } else { GST_WARNING ("RTP-Info cannot be determined for stream %d", i); } } - g_free (base_url); g_free (path); /* construct the response now */ @@ -1477,7 +1476,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (path[matched] == '\0') goto control_not_found; - /* path is what matched. We can modify the parsed uri in place */ + /* path is what matched. */ path[matched] = '\0'; /* control is remainder */ control = &path[matched + 1]; @@ -1539,6 +1538,10 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) /* set in the session media transport */ trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct); + /* configure the url used to set this transport, this we will use when + * generating the response for the PLAY request */ + gst_rtsp_stream_transport_set_url (trans, uri); + /* configure keepalive for this transport */ gst_rtsp_stream_transport_set_keepalive (trans, (GstRTSPKeepAliveFunc) do_keepalive, session, NULL); From b16b47f68daccf0a939673f5246ed1d1ae88964b Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Wed, 27 Nov 2013 15:04:04 +0100 Subject: [PATCH 0866/1776] check: add test for uri in setup Added unit tests for the new functionality in GstRTSPStreamTransport. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=715168 --- tests/check/Makefile.am | 3 +- tests/check/gst/sessionmedia.c | 118 +++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 tests/check/gst/sessionmedia.c diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 71d37ab16a..765c663e4a 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -35,7 +35,8 @@ check_PROGRAMS = \ gst/addresspool \ gst/threadpool \ gst/permissions \ - gst/token + gst/token \ + gst/sessionmedia # these tests don't even pass noinst_PROGRAMS = diff --git a/tests/check/gst/sessionmedia.c b/tests/check/gst/sessionmedia.c new file mode 100644 index 0000000000..c749a566c5 --- /dev/null +++ b/tests/check/gst/sessionmedia.c @@ -0,0 +1,118 @@ +/* GStreamer + * Copyright (C) 2013 Branko Subasic + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include + +#define TEST_PATH "rtsp://localhost:8554/test" +#define SETUP_URL TEST_PATH "/stream=0" + +GST_START_TEST (test_setup_url) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url, *setup_url; + GstRTSPStream *stream; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + GstRTSPSessionMedia *sm; + GstRTSPStreamTransport *trans; + GstRTSPTransport *ct; + gint match_len; + gchar *url_str, *url_str2; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + fail_unless (gst_rtsp_url_parse (TEST_PATH, &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + fail_unless (gst_rtsp_media_n_streams (media) == 1); + + stream = gst_rtsp_media_get_stream (media, 0); + fail_unless (stream != NULL); + + pool = gst_rtsp_thread_pool_new (); + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + + fail_unless (gst_rtsp_media_prepare (media, thread)); + + /* create session media and make sure it matches test path + * note that gst_rtsp_session_media_new takes ownership of the media + * thus no need to unref it at the bottom of function */ + sm = gst_rtsp_session_media_new (TEST_PATH, media); + fail_unless (sm != NULL); + fail_unless (gst_rtsp_session_media_matches (sm, TEST_PATH, &match_len)); + fail_unless (match_len == strlen (TEST_PATH)); + + /* make a transport for the stream */ + gst_rtsp_transport_new (&ct); + trans = gst_rtsp_session_media_set_transport (sm, stream, ct); + + /* make sure there's no setup url stored initially */ + fail_unless (gst_rtsp_stream_transport_get_url (trans) == NULL); + + /* now store a setup url and make sure it can be retrieved and that it's correct */ + fail_unless (gst_rtsp_url_parse (SETUP_URL, &setup_url) == GST_RTSP_OK); + gst_rtsp_stream_transport_set_url (trans, setup_url); + + url_str = gst_rtsp_url_get_request_uri (setup_url); + url_str2 = + gst_rtsp_url_get_request_uri (gst_rtsp_stream_transport_get_url (trans)); + fail_if (g_strcmp0 (url_str, url_str2) != 0); + g_free (url_str); + g_free (url_str2); + + /* check that it's ok to try to store the same url again */ + gst_rtsp_stream_transport_set_url (trans, setup_url); + + fail_unless (gst_rtsp_media_unprepare (media)); + + gst_rtsp_url_free (setup_url); + gst_rtsp_url_free (url); + + g_object_unref (sm); + + g_object_unref (factory); + g_object_unref (pool); +} + +GST_END_TEST; + +static Suite * +rtspsessionmedia_suite (void) +{ + Suite *s = suite_create ("rtspsessionmedia"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_set_timeout (tc, 20); + tcase_add_test (tc, test_setup_url); + + return s; +} + +GST_CHECK_MAIN (rtspsessionmedia); From 53859ac34be48bc3b8210e4598e885ea04e3efa8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 29 Nov 2013 10:53:08 +0100 Subject: [PATCH 0867/1776] media: also handle prepare and range in suspended state When we are suspended, we are already prepared. We can get the range in the suspended state. --- gst/rtsp-server/rtsp-client.c | 6 ++++-- gst/rtsp-server/rtsp-media.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a9ccbc2146..3bbd64ed8a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1937,10 +1937,12 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) gst_rtsp_message_dump (request); } - GST_INFO ("client %p: received a request", client); - gst_rtsp_message_parse_request (request, &method, &uristr, &version); + GST_INFO ("client %p: received a request %s %s %s", client, + gst_rtsp_method_as_text (method), uristr, + gst_rtsp_version_as_text (version)); + /* we can only handle 1.0 requests */ if (version != GST_RTSP_VERSION_1_0) goto not_supported; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 2c72d97205..eea4035b47 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1325,7 +1325,8 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play, priv = media->priv; g_rec_mutex_lock (&priv->state_lock); - if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) + if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED && + priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED) goto not_prepared; g_mutex_lock (&priv->lock); @@ -1993,7 +1994,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) g_rec_mutex_lock (&priv->state_lock); priv->prepare_count++; - if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED || + priv->status == GST_RTSP_MEDIA_STATUS_SUSPENDED) goto was_prepared; if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) From 3b4894c4f1ea28cc317f0c53b110cf678d27bf10 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Fri, 29 Nov 2013 15:50:23 +0100 Subject: [PATCH 0868/1776] media: also do state change in suspended state --- gst/rtsp-server/rtsp-media.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index eea4035b47..d9c9e96fea 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2584,7 +2584,8 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, g_rec_mutex_lock (&priv->state_lock); if (priv->status == GST_RTSP_MEDIA_STATUS_ERROR) goto error_status; - if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) + if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED && + priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED) goto not_prepared; /* NULL and READY are the same */ From 9473fa0d2cd2db92baf318d327a94b8d3efca98b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 29 Nov 2013 15:50:52 +0100 Subject: [PATCH 0869/1776] stream-transport: free url in finalize --- gst/rtsp-server/rtsp-stream-transport.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index bade2a61d2..90e631003d 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -121,6 +121,9 @@ gst_rtsp_stream_transport_finalize (GObject * obj) if (priv->transport) gst_rtsp_transport_free (priv->transport); + if (priv->url) + gst_rtsp_url_free (priv->url); + G_OBJECT_CLASS (gst_rtsp_stream_transport_parent_class)->finalize (obj); } From 26f215ac369bf82626d37b2d1856005ad4fddef7 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Tue, 3 Dec 2013 00:34:52 +0100 Subject: [PATCH 0870/1776] tests: fix memory leak, free test's thread pool Fixes https://bugzilla.gnome.org/show_bug.cgi?id=719733 --- tests/check/gst/media.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 23e858626a..df3e1c2aad 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -189,6 +189,7 @@ GST_START_TEST (test_media_prepare) g_object_unref (media); gst_rtsp_url_free (url); g_object_unref (factory); + g_object_unref (pool); } GST_END_TEST; @@ -340,6 +341,7 @@ GST_START_TEST (test_media_reset) gst_rtsp_url_free (url); g_object_unref (factory); + g_object_unref (pool); } GST_END_TEST; From ab3651d3393d3771975e6f1180ea9adf1fde0605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Tue, 3 Dec 2013 11:54:42 -0800 Subject: [PATCH 0871/1776] media: add new create_rtpbin vmethod * gst/rtsp-server/rtsp-media.[ch]: add new create_rtpbin vmethod. https://bugzilla.gnome.org/show_bug.cgi?id=719734 --- gst/rtsp-server/rtsp-media.c | 30 +++++++++++++++++++++++++++--- gst/rtsp-server/rtsp-media.h | 1 + 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d9c9e96fea..b8f155ed13 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -176,6 +176,7 @@ static gboolean default_convert_range (GstRTSPMedia * media, static gboolean default_query_position (GstRTSPMedia * media, gint64 * position); static gboolean default_query_stop (GstRTSPMedia * media, gint64 * stop); +static GstElement *default_create_rtpbin (GstRTSPMedia * media); static gboolean wait_preroll (GstRTSPMedia * media); @@ -292,6 +293,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->convert_range = default_convert_range; klass->query_position = default_query_position; klass->query_stop = default_query_stop; + klass->create_rtpbin = default_create_rtpbin; } static void @@ -444,6 +446,16 @@ default_query_stop (GstRTSPMedia * media, gint64 * stop) return res; } +static GstElement * +default_create_rtpbin (GstRTSPMedia * media) +{ + GstElement *rtpbin; + + rtpbin = gst_element_factory_make ("rtpbin", NULL); + + return rtpbin; +} + /* must be called with state lock */ static void collect_media_stats (GstRTSPMedia * media) @@ -1985,6 +1997,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) GstRTSPMediaPrivate *priv; GstBus *bus; GSource *source; + GstRTSPMediaClass *klass; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); g_return_val_if_fail (GST_IS_RTSP_THREAD (thread), FALSE); @@ -2007,12 +2020,15 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) if (!priv->reusable && priv->reused) goto is_reused; - priv->rtpbin = gst_element_factory_make ("rtpbin", NULL); + klass = GST_RTSP_MEDIA_GET_CLASS (media); + + if (!klass->create_rtpbin) + goto no_create_rtpbin; + + priv->rtpbin = klass->create_rtpbin (media); if (priv->rtpbin != NULL) { - GstRTSPMediaClass *klass; gboolean success = TRUE; - klass = GST_RTSP_MEDIA_GET_CLASS (media); if (klass->setup_rtpbin) success = klass->setup_rtpbin (media, priv->rtpbin); @@ -2090,6 +2106,14 @@ is_reused: GST_WARNING ("can not reuse media %p", media); return FALSE; } +no_create_rtpbin: + { + priv->prepare_count--; + g_rec_mutex_unlock (&priv->state_lock); + GST_ERROR ("no create_rtpbin function"); + g_critical ("no create_rtpbin vmethod function set"); + return FALSE; + } no_rtpbin: { priv->prepare_count--; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 735576ba6f..402b7ea8cf 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -121,6 +121,7 @@ struct _GstRTSPMediaClass { GstRTSPRangeUnit unit); gboolean (*query_position) (GstRTSPMedia *media, gint64 *position); gboolean (*query_stop) (GstRTSPMedia *media, gint64 *stop); + GstElement * (*create_rtpbin) (GstRTSPMedia *media); gboolean (*setup_rtpbin) (GstRTSPMedia *media, GstElement *rtpbin); /* signals */ From 91fac8eb29f4f68ec1f44db8bca32eef1cea1182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 12 Dec 2013 00:36:07 +0000 Subject: [PATCH 0872/1776] rtsp-server: add padding to many public structures Not mini objects though, since they are not subclassable anyway, nor kept on the stack or inlined in a structure. --- gst/rtsp-server/rtsp-address-pool.h | 4 ++++ gst/rtsp-server/rtsp-auth.h | 4 ++++ gst/rtsp-server/rtsp-client.h | 5 +++++ gst/rtsp-server/rtsp-context.h | 3 +++ gst/rtsp-server/rtsp-media-factory-uri.h | 5 +++++ gst/rtsp-server/rtsp-media-factory.h | 4 ++++ gst/rtsp-server/rtsp-media.h | 4 ++++ gst/rtsp-server/rtsp-mount-points.h | 4 ++++ gst/rtsp-server/rtsp-server.h | 5 +++++ gst/rtsp-server/rtsp-session-media.h | 4 ++++ gst/rtsp-server/rtsp-session-pool.h | 4 ++++ gst/rtsp-server/rtsp-session.h | 4 ++++ gst/rtsp-server/rtsp-stream-transport.h | 4 ++++ gst/rtsp-server/rtsp-stream.h | 5 ++++- gst/rtsp-server/rtsp-thread-pool.h | 4 ++++ gst/rtsp-server/rtsp-token.h | 2 +- 16 files changed, 63 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index 8320dd9d62..a473bdfd18 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -134,6 +134,7 @@ struct _GstRTSPAddressPool { /*< private >*/ GstRTSPAddressPoolPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; /** @@ -143,6 +144,9 @@ struct _GstRTSPAddressPool { */ struct _GstRTSPAddressPoolClass { GObjectClass parent_class; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; }; GType gst_rtsp_address_pool_get_type (void); diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index c2dd971054..cb281f0cbe 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -48,7 +48,9 @@ G_BEGIN_DECLS struct _GstRTSPAuth { GObject parent; + /*< private >*/ GstRTSPAuthPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; /** @@ -70,6 +72,8 @@ struct _GstRTSPAuthClass { gboolean (*authenticate) (GstRTSPAuth *auth, GstRTSPContext *ctx); gboolean (*check) (GstRTSPAuth *auth, GstRTSPContext *ctx, const gchar *check); + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; }; GType gst_rtsp_auth_get_type (void); diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 88d888ef5c..94d52df704 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -68,7 +68,9 @@ typedef gboolean (*GstRTSPClientSendFunc) (GstRTSPClient *client, struct _GstRTSPClient { GObject parent; + /*< private >*/ GstRTSPClientPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; /** @@ -106,6 +108,9 @@ struct _GstRTSPClientClass { void (*set_parameter_request) (GstRTSPClient *client, GstRTSPContext *ctx); void (*get_parameter_request) (GstRTSPClient *client, GstRTSPContext *ctx); void (*handle_response) (GstRTSPClient *client, GstRTSPContext *ctx); + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING_LARGE]; }; GType gst_rtsp_client_get_type (void); diff --git a/gst/rtsp-server/rtsp-context.h b/gst/rtsp-server/rtsp-context.h index 9e001aae7f..2b31bdd909 100644 --- a/gst/rtsp-server/rtsp-context.h +++ b/gst/rtsp-server/rtsp-context.h @@ -69,6 +69,9 @@ struct _GstRTSPContext { GstRTSPMedia *media; GstRTSPStream *stream; GstRTSPMessage *response; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; }; GType gst_rtsp_context_get_type (void); diff --git a/gst/rtsp-server/rtsp-media-factory-uri.h b/gst/rtsp-server/rtsp-media-factory-uri.h index fd1eb98c8b..6dc3a402d3 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.h +++ b/gst/rtsp-server/rtsp-media-factory-uri.h @@ -48,7 +48,9 @@ typedef struct _GstRTSPMediaFactoryURIPrivate GstRTSPMediaFactoryURIPrivate; struct _GstRTSPMediaFactoryURI { GstRTSPMediaFactory parent; + /*< private >*/ GstRTSPMediaFactoryURIPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; /** @@ -58,6 +60,9 @@ struct _GstRTSPMediaFactoryURI { */ struct _GstRTSPMediaFactoryURIClass { GstRTSPMediaFactoryClass parent_class; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; }; GType gst_rtsp_media_factory_uri_get_type (void); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 63f4d827cf..11aaaeb81c 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -54,6 +54,7 @@ struct _GstRTSPMediaFactory { /*< private >*/ GstRTSPMediaFactoryPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; /** @@ -91,6 +92,9 @@ struct _GstRTSPMediaFactoryClass { /* signals */ void (*media_constructed) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); void (*media_configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media); + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING_LARGE]; }; GType gst_rtsp_media_factory_get_type (void); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 402b7ea8cf..bb558354cb 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -98,6 +98,7 @@ struct _GstRTSPMedia { /*< private >*/ GstRTSPMediaPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; /** @@ -132,6 +133,9 @@ struct _GstRTSPMediaClass { void (*unprepared) (GstRTSPMedia *media); void (*new_state) (GstRTSPMedia *media, GstState state); + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING_LARGE]; }; GType gst_rtsp_media_get_type (void); diff --git a/gst/rtsp-server/rtsp-mount-points.h b/gst/rtsp-server/rtsp-mount-points.h index 18a691a133..ed13d5924a 100644 --- a/gst/rtsp-server/rtsp-mount-points.h +++ b/gst/rtsp-server/rtsp-mount-points.h @@ -49,6 +49,7 @@ struct _GstRTSPMountPoints { /*< private >*/ GstRTSPMountPointsPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; /** @@ -62,6 +63,9 @@ struct _GstRTSPMountPointsClass { gchar * (*make_path) (GstRTSPMountPoints *mounts, const GstRTSPUrl *url); + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; }; GType gst_rtsp_mount_points_get_type (void); diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 610c9a0a18..afe145aa76 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -51,7 +51,9 @@ typedef struct _GstRTSPServerPrivate GstRTSPServerPrivate; struct _GstRTSPServer { GObject parent; + /*< private >*/ GstRTSPServerPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; /** @@ -71,6 +73,9 @@ struct _GstRTSPServerClass { /* signals */ void (*client_connected) (GstRTSPServer *server, GstRTSPClient *client); + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING_LARGE]; }; GType gst_rtsp_server_get_type (void); diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 65867ab1b2..0b7c8c8b6d 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -50,11 +50,15 @@ struct _GstRTSPSessionMedia /*< private >*/ GstRTSPSessionMediaPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; struct _GstRTSPSessionMediaClass { GObjectClass parent_class; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; }; GType gst_rtsp_session_media_get_type (void); diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 82468b19b2..3b0c12d5d9 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -50,6 +50,7 @@ struct _GstRTSPSessionPool { /*< private >*/ GstRTSPSessionPoolPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; /** @@ -63,6 +64,9 @@ struct _GstRTSPSessionPoolClass { gchar * (*create_session_id) (GstRTSPSessionPool *pool); GstRTSPSession * (*create_session) (GstRTSPSessionPool *pool, const gchar *id); + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING_LARGE]; }; /** diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 60ed6fad4b..d9c0f18713 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -69,10 +69,14 @@ struct _GstRTSPSession { /*< private >*/ GstRTSPSessionPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; struct _GstRTSPSessionClass { GObjectClass parent_class; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; }; GType gst_rtsp_session_get_type (void); diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index fad6911cd5..bc02df8d39 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -74,10 +74,14 @@ struct _GstRTSPStreamTransport { /*< private >*/ GstRTSPStreamTransportPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; struct _GstRTSPStreamTransportClass { GObjectClass parent_class; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; }; GType gst_rtsp_stream_transport_get_type (void); diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 9303a62bee..71efa6211d 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -55,10 +55,13 @@ struct _GstRTSPStream { /*< private >*/ GstRTSPStreamPrivate *priv; -}; + gpointer _gst_reserved[GST_PADDING];}; struct _GstRTSPStreamClass { GObjectClass parent_class; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; }; GType gst_rtsp_stream_get_type (void); diff --git a/gst/rtsp-server/rtsp-thread-pool.h b/gst/rtsp-server/rtsp-thread-pool.h index 816512534d..e360034be8 100644 --- a/gst/rtsp-server/rtsp-thread-pool.h +++ b/gst/rtsp-server/rtsp-thread-pool.h @@ -127,6 +127,7 @@ struct _GstRTSPThreadPool { /*< private >*/ GstRTSPThreadPoolPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; }; /** @@ -157,6 +158,9 @@ struct _GstRTSPThreadPoolClass { GstRTSPThread *thread); void (*thread_leave) (GstRTSPThreadPool *pool, GstRTSPThread *thread); + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; }; GType gst_rtsp_thread_pool_get_type (void); diff --git a/gst/rtsp-server/rtsp-token.h b/gst/rtsp-server/rtsp-token.h index b7c06c4cf6..265d8d30d9 100644 --- a/gst/rtsp-server/rtsp-token.h +++ b/gst/rtsp-server/rtsp-token.h @@ -39,7 +39,7 @@ GType gst_rtsp_token_get_type(void); * GstRTSPToken: * * An opaque object used for checking authorisations. - * It is generated after successfull authentication. + * It is generated after successful authentication. */ struct _GstRTSPToken { GstMiniObject mini_object; From 2c08b5b529053f6030e79c818ceb3525aefa6ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 12 Dec 2013 00:38:07 +0000 Subject: [PATCH 0873/1776] Make git ignore more unit test binaries --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index d5d2e50228..15ed6afdba 100644 --- a/.gitignore +++ b/.gitignore @@ -50,8 +50,12 @@ stamp-h.in /tests/check/gst/media /tests/check/gst/mediafactory /tests/check/gst/mountpoints +/tests/check/gst/permissions /tests/check/gst/rtspserver +/tests/check/gst/sessionmedia +/tests/check/gst/stream /tests/check/gst/threadpool +/tests/check/gst/token /tests/check/test-registry.reg /tests/test-reuse From 7a947e8dfe424664ffdfb5397d506f785397dcea Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 18 Dec 2013 15:57:03 +0100 Subject: [PATCH 0874/1776] client: add vmethod to configure media and streams Implement a vmethod that can be used to configure the media and the streams based on the current context. Handle the blocksize handling in the default handler. See https://bugzilla.gnome.org/show_bug.cgi?id=720667 --- gst/rtsp-server/rtsp-client.c | 54 +++++++++++++++++++++-------------- gst/rtsp-server/rtsp-client.h | 6 ++++ 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3bbd64ed8a..0822727f3b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -127,6 +127,8 @@ static void client_session_finalized (GstRTSPClient * client, GstRTSPSession * session); static void unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, GstRTSPSessionMedia * sessmedia); +static gboolean default_configure_client_media (GstRTSPClient * client, + GstRTSPMedia * media, GstRTSPStream * stream, GstRTSPContext * ctx); static gboolean default_configure_client_transport (GstRTSPClient * client, GstRTSPContext * ctx, GstRTSPTransport * ct); static GstRTSPResult default_params_set (GstRTSPClient * client, @@ -152,6 +154,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gobject_class->finalize = gst_rtsp_client_finalize; klass->create_sdp = create_sdp; + klass->configure_client_media = default_configure_client_media; klass->configure_client_transport = default_configure_client_transport; klass->params_set = default_params_set; klass->params_get = default_params_get; @@ -1265,11 +1268,11 @@ parse_transport (const char *transport, GstRTSPLowerTrans supported, } static gboolean -handle_blocksize (GstRTSPMedia * media, GstRTSPStream * stream, - GstRTSPMessage * request) +default_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media, + GstRTSPStream * stream, GstRTSPContext * ctx) { + GstRTSPMessage *request = ctx->request; gchar *blocksize_str; - gboolean ret = TRUE; if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_BLOCKSIZE, &blocksize_str, 0) == GST_RTSP_OK) { @@ -1277,21 +1280,29 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPStream * stream, gchar *end; blocksize = g_ascii_strtoull (blocksize_str, &end, 10); - if (end == blocksize_str) { - GST_ERROR ("failed to parse blocksize"); - ret = FALSE; - } else { - /* we don't want to change the mtu when this media - * can be shared because it impacts other clients */ - if (gst_rtsp_media_is_shared (media)) - return TRUE; + if (end == blocksize_str) + goto parse_failed; - if (blocksize > G_MAXUINT) - blocksize = G_MAXUINT; - gst_rtsp_stream_set_mtu (stream, blocksize); - } + /* we don't want to change the mtu when this media + * can be shared because it impacts other clients */ + if (gst_rtsp_media_is_shared (media)) + goto done; + + if (blocksize > G_MAXUINT) + blocksize = G_MAXUINT; + + gst_rtsp_stream_set_mtu (stream, blocksize); + } +done: + return TRUE; + + /* ERRORS */ +parse_failed: + { + GST_ERROR_OBJECT (client, "failed to parse blocksize"); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + return FALSE; } - return ret; } static gboolean @@ -1518,9 +1529,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; - /* set blocksize on this stream */ - if (!handle_blocksize (media, stream, ctx->request)) - goto invalid_blocksize; + if (!klass->configure_client_media (client, media, stream, ctx)) + goto configure_media_failed_no_reply; gst_rtsp_transport_new (&ct); @@ -1649,12 +1659,12 @@ sessmedia_unavailable: g_free (path); return FALSE; } -invalid_blocksize: +configure_media_failed_no_reply: { - GST_ERROR ("client %p: invalid blocksize", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + GST_ERROR ("client %p: configure_media failed", client); g_object_unref (session); g_free (path); + /* error reply is already sent */ return FALSE; } unsupported_transports: diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 94d52df704..17086e5c00 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -76,6 +76,9 @@ struct _GstRTSPClient { /** * GstRTSPClientClass: * @create_sdp: called when the SDP needs to be created for media. + * @configure_client_media: called when the stream in media needs to be configured. + * The default implementation will configure the blocksize on the payloader when + * spcified in the request headers. * @configure_client_transport: called when the client transport needs to be * configured. * @params_set: set parameters. This function should also initialize the @@ -89,6 +92,9 @@ struct _GstRTSPClientClass { GObjectClass parent_class; GstSDPMessage * (*create_sdp) (GstRTSPClient *client, GstRTSPMedia *media); + gboolean (*configure_client_media) (GstRTSPClient * client, + GstRTSPMedia * media, GstRTSPStream * stream, + GstRTSPContext * ctx); gboolean (*configure_client_transport) (GstRTSPClient * client, GstRTSPContext * ctx, GstRTSPTransport * ct); From d3237dc9dc897b1914891463e23335822ee10b2e Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 19 Dec 2013 14:24:54 +0100 Subject: [PATCH 0875/1776] rtsp-client: Fix iteration Wouldn't even enter the code block otherwise (i++ was used as the check and not the postfix). --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 0822727f3b..d1826cfb0c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1752,7 +1752,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) /* check what kind of format is accepted, we don't really do anything with it * and always return SDP for now. */ - for (i = 0; i++;) { + for (i = 0;; i++) { gchar *accept; res = From cdd72905af1f479cf6d3e1e7c01e8842847c18d5 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 19 Dec 2013 14:26:34 +0100 Subject: [PATCH 0876/1776] rtsp-stream: Check return value of sscanf streamid is only valid if sscanf matched something. --- gst/rtsp-server/rtsp-stream.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 6428150017..bcc8ccfe95 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -421,8 +421,11 @@ gst_rtsp_stream_has_control (GstRTSPStream * stream, const gchar * control) res = (g_strcmp0 (priv->control, control) == 0); else { guint streamid; - sscanf (control, "stream=%u", &streamid); - res = (streamid == priv->idx); + + if (sscanf (control, "stream=%u", &streamid) > 0) + res = (streamid == priv->idx); + else + res = FALSE; } g_mutex_unlock (&priv->lock); @@ -1032,10 +1035,6 @@ cleanup: gst_element_set_state (udpsink0, GST_STATE_NULL); gst_object_unref (udpsink0); } - if (udpsink1) { - gst_element_set_state (udpsink1, GST_STATE_NULL); - gst_object_unref (udpsink1); - } if (inetaddr) g_object_unref (inetaddr); g_list_free_full (rejected_addresses, From 3fdae13fb70d83a2dfdfd1e785c0635547272664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Wed, 18 Dec 2013 16:37:27 +0100 Subject: [PATCH 0877/1776] media: add setup_sdp vmethod gst/rtsp-server/rtsp-media.[ch]: added setup_sdp vmethod and public gst_rtsp_media_setup_sdp. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=720155 --- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-media.c | 57 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 5 +++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d1826cfb0c..e87a8de08a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1719,7 +1719,7 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) info.server_ip = priv->server_ip; /* create an SDP for the media object */ - if (!gst_rtsp_sdp_from_media (sdp, &info, media)) + if (!gst_rtsp_media_setup_sdp (media, sdp, &info)) goto no_sdp; return sdp; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b8f155ed13..4c361b93a1 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -177,6 +177,8 @@ static gboolean default_query_position (GstRTSPMedia * media, gint64 * position); static gboolean default_query_stop (GstRTSPMedia * media, gint64 * stop); static GstElement *default_create_rtpbin (GstRTSPMedia * media); +static gboolean default_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, + GstSDPInfo * info); static gboolean wait_preroll (GstRTSPMedia * media); @@ -294,6 +296,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->query_position = default_query_position; klass->query_stop = default_query_stop; klass->create_rtpbin = default_create_rtpbin; + klass->setup_sdp = default_setup_sdp; } static void @@ -2395,6 +2398,60 @@ gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address, return provider; } +static gboolean +default_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, GstSDPInfo * info) +{ + return gst_rtsp_sdp_from_media (sdp, info, media); +} + +/** + * gst_rtsp_media_setup_sdp: + * @sdp: a #GstSDPMessage + * @info: info + * @media: a #GstRTSPMedia + * + * Add @media specific info to @sdp. @info is used to configure the connection + * information in the SDP. + * + * Returns: TRUE on success. + */ +gboolean +gst_rtsp_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, + GstSDPInfo * info) +{ + GstRTSPMediaPrivate *priv; + GstRTSPMediaClass *klass; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + g_return_val_if_fail (sdp != NULL, FALSE); + g_return_val_if_fail (info != NULL, FALSE); + + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + + if (!klass->setup_sdp) + goto no_setup_sdp; + + res = klass->setup_sdp (media, sdp, info); + + g_rec_mutex_unlock (&priv->state_lock); + + return res; + + /* ERRORS */ +no_setup_sdp: + { + g_rec_mutex_unlock (&priv->state_lock); + GST_ERROR ("no setup_sdp function"); + g_critical ("no setup_sdp vmethod function set"); + return FALSE; + } +} + /** * gst_rtsp_media_suspend: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index bb558354cb..885960691f 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -84,6 +84,7 @@ GType gst_rtsp_suspend_mode_get_type (void); #include "rtsp-thread-pool.h" #include "rtsp-permissions.h" #include "rtsp-address-pool.h" +#include "rtsp-sdp.h" /** * GstRTSPMedia: @@ -124,6 +125,7 @@ struct _GstRTSPMediaClass { gboolean (*query_stop) (GstRTSPMedia *media, gint64 *stop); GstElement * (*create_rtpbin) (GstRTSPMedia *media); gboolean (*setup_rtpbin) (GstRTSPMedia *media, GstElement *rtpbin); + gboolean (*setup_sdp) (GstRTSPMedia *media, GstSDPMessage *sdp, GstSDPInfo *info); /* signals */ void (*new_stream) (GstRTSPMedia *media, GstRTSPStream * stream); @@ -185,6 +187,9 @@ GstRTSPSuspendMode gst_rtsp_media_get_suspend_mode (GstRTSPMedia *media); gboolean gst_rtsp_media_suspend (GstRTSPMedia *media); gboolean gst_rtsp_media_unsuspend (GstRTSPMedia *media); +gboolean gst_rtsp_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, + GstSDPInfo * info); + /* creating streams */ void gst_rtsp_media_collect_streams (GstRTSPMedia *media); GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia *media, From d2e199ed121903ae741e2fbb67e1ee04dce77bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 22 Dec 2013 22:36:06 +0000 Subject: [PATCH 0878/1776] Automatic update of common submodule From dbedaa0 to d48bed3 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index dbedaa010e..d48bed31ff 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit dbedaa010e2a19af2b27451c7c64111ea2f8dad2 +Subproject commit d48bed31ff6502de03a12ba226685608d3a3344e From de30acfd3d9655d3819348d53d3977c8e69ac5d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 22 Dec 2013 23:04:48 +0000 Subject: [PATCH 0879/1776] Fix broken gettext setup which is not used anyway --- autogen.sh | 12 +++--------- common | 2 +- configure.ac | 6 +++--- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/autogen.sh b/autogen.sh index 7bde014917..239fa5b94c 100755 --- a/autogen.sh +++ b/autogen.sh @@ -72,15 +72,9 @@ fi toplevel_check $srcfile # autopoint -# older autopoint (< 0.12) has a tendency to complain about mkinstalldirs -if test -x mkinstalldirs; then rm mkinstalldirs; fi -# first remove patch if necessary, then run autopoint, then reapply -if test -f po/Makefile.in.in; -then - patch -p0 -R --forward < common/gettext.patch -fi -tool_run "$autopoint" "--force" "patch -p0 < common/gettext.patch" -patch -p0 < common/gettext.patch +#if test -d po ; then +# tool_run "$autopoint" "--force" +#fi # aclocal # if test -f acinclude.m4; then rm acinclude.m4; fi diff --git a/common b/common index d48bed31ff..f7bc1c3ab8 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit d48bed31ff6502de03a12ba226685608d3a3344e +Subproject commit f7bc1c3ab88024eb8b8e60f1af18fbcabcd83efe diff --git a/configure.ac b/configure.ac index d662acef6a..2cee9be210 100644 --- a/configure.ac +++ b/configure.ac @@ -57,9 +57,9 @@ AC_CONFIG_MACRO_DIR([m4]) dnl set up gettext dnl the version check needs to stay here because autopoint greps for it -AM_GNU_GETTEXT_VERSION([0.17]) -AM_GNU_GETTEXT([external]) -AG_GST_GETTEXT([gstreamer-$GST_API_VERSION]) +#AM_GNU_GETTEXT_VERSION([0.17]) +#AM_GNU_GETTEXT([external]) +#AG_GST_GETTEXT([gst-rtsp-server-$GST_API_VERSION]) dnl *** check for arguments to configure *** From 45bb30d148b21e5c04de4186f18c7643e615a027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 22 Dec 2013 23:15:02 +0000 Subject: [PATCH 0880/1776] configure: bump core/base/good requirement to 1.2.0 Bump to released stable version and make implicit requirements explicit. --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 2cee9be210..56e8121573 100644 --- a/configure.ac +++ b/configure.ac @@ -42,9 +42,9 @@ AC_SUBST(GST_API_VERSION) AS_LIBTOOL(GST, 0, 0, 0) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.0.0 -GSTPB_REQ=1.1.0.1 -GSTPG_REQ=1.0.0 +GST_REQ=1.2.0 +GSTPB_REQ=1.2.0 +GSTPG_REQ=1.2.0 dnl *** autotools stuff **** From 2b8a972dae0935c19fe7469eb0bbea6ee600ee3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 22 Dec 2013 23:16:56 +0000 Subject: [PATCH 0881/1776] configure: rename package from gst-rtsp to gst-rtsp-server To match git module name and avoid confusion with the rtsp lib in gst-plugins-base and rtsp plugin in -good. --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 56e8121573..4fe59ab595 100644 --- a/configure.ac +++ b/configure.ac @@ -2,9 +2,9 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-RTSP, 0.11.90.1, - http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, - gst-rtsp) +AC_INIT([GStreamer RTSP Server Library], [0.11.90.1], + [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], + [gst-rtsp-server]) AG_GST_INIT dnl initialize automake From dd4c04f1b8f6a2d3cc0094d625ddfa86ba65ae26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Fri, 20 Dec 2013 16:39:07 -0800 Subject: [PATCH 0882/1776] mount-points: sort sequence before g_sequence_lookup * gst/rtsp-server/rtsp-mount-points.c (gst_rtsp_mount_points_remove_factory): sort sequence if dirty, otherwise lookup will fail. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=720855 --- gst/rtsp-server/rtsp-mount-points.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 49d8d3e101..dbf5473113 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -356,6 +356,10 @@ gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints * mounts, GST_INFO ("removing media factory for path %s", path); g_mutex_lock (&priv->lock); + if (priv->dirty) { + g_sequence_sort (priv->mounts, data_item_compare, mounts); + priv->dirty = FALSE; + } iter = g_sequence_lookup (priv->mounts, &item, data_item_compare, mounts); if (iter) { g_sequence_remove (iter); From 4ca0b23a3fcf1a3ecb3559bd931e162ab5921cdc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 26 Dec 2013 15:41:14 +0100 Subject: [PATCH 0883/1776] session-media: let the session-media make the RTPInfo Add method to create the RTPInfo for a stream-transport. Add method to create the RTPInfo for all stream-transports in a session-media. Use the session-media RTPInfo code in client. This allows us to refactor another method to link the TCP callbacks. --- gst/rtsp-server/rtsp-client.c | 89 ++++++++++--------------- gst/rtsp-server/rtsp-session-media.c | 68 +++++++++++++++++++ gst/rtsp-server/rtsp-session-media.h | 2 + gst/rtsp-server/rtsp-stream-transport.c | 34 ++++++++++ gst/rtsp-server/rtsp-stream-transport.h | 3 + 5 files changed, 143 insertions(+), 53 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e87a8de08a..1a1de6c539 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -657,6 +657,32 @@ link_transport (GstRTSPClient * client, GstRTSPSession * session, gst_rtsp_session_prevent_expire (session); } +static void +link_session_transports (GstRTSPClient * client, GstRTSPSession * session, + GstRTSPSessionMedia * sessmedia) +{ + guint n_streams, i; + + n_streams = + gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (sessmedia)); + for (i = 0; i < n_streams; i++) { + GstRTSPStreamTransport *trans; + const GstRTSPTransport *tr; + + /* get the transport, if there is no transport configured, skip this stream */ + trans = gst_rtsp_session_media_get_transport (sessmedia, i); + if (trans == NULL) + continue; + + tr = gst_rtsp_stream_transport_get_transport (trans); + + if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { + /* for TCP, link the stream to the TCP connection of the client */ + link_transport (client, session, trans); + } + } +} + static void unlink_transport (GstRTSPClient * client, GstRTSPSession * session, GstRTSPStreamTransport * trans) @@ -1042,14 +1068,12 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPMedia *media; GstRTSPStatusCode code; GstRTSPUrl *uri; - GString *rtpinfo; - guint n_streams, i, infocount; gchar *str; GstRTSPTimeRange *range; GstRTSPResult res; GstRTSPState rtspstate; GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT; - gchar *path; + gchar *path, *rtpinfo; gint matched; if (!(session = ctx->session)) @@ -1069,6 +1093,8 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (path[matched] != '\0') goto no_aggregate; + g_free (path); + ctx->sessmedia = sessmedia; ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); @@ -1092,49 +1118,11 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) } } - /* grab RTPInfo from the payloaders now */ - rtpinfo = g_string_new (""); + /* link the all TCP callbacks */ + link_session_transports (client, session, sessmedia); - n_streams = gst_rtsp_media_n_streams (media); - for (i = 0, infocount = 0; i < n_streams; i++) { - GstRTSPStreamTransport *trans; - GstRTSPStream *stream; - const GstRTSPTransport *tr; - guint rtptime, seq; - - /* get the transport, if there is no transport configured, skip this stream */ - trans = gst_rtsp_session_media_get_transport (sessmedia, i); - if (trans == NULL) { - GST_INFO ("stream %d is not configured", i); - continue; - } - tr = gst_rtsp_stream_transport_get_transport (trans); - - if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { - /* for TCP, link the stream to the TCP connection of the client */ - link_transport (client, session, trans); - } - - stream = gst_rtsp_stream_transport_get_stream (trans); - if (gst_rtsp_stream_get_rtpinfo (stream, &rtptime, &seq)) { - const GstRTSPUrl *url; - gchar *url_str; - - if (infocount > 0) - g_string_append (rtpinfo, ", "); - - url = gst_rtsp_stream_transport_get_url (trans); - url_str = gst_rtsp_url_get_request_uri (url); - g_string_append_printf (rtpinfo, "url=%s;seq=%u;rtptime=%u", - url_str, seq, rtptime); - g_free (url_str); - - infocount++; - } else { - GST_WARNING ("RTP-Info cannot be determined for stream %d", i); - } - } - g_free (path); + /* grab RTPInfo from the media now */ + rtpinfo = gst_rtsp_session_media_get_rtpinfo (sessmedia); /* construct the response now */ code = GST_RTSP_STS_OK; @@ -1142,12 +1130,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_status_as_text (code), ctx->request); /* add the RTP-Info header */ - if (infocount > 0) { - str = g_string_free (rtpinfo, FALSE); - gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO, str); - } else { - g_string_free (rtpinfo, TRUE); - } + if (rtpinfo) + gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO, + rtpinfo); /* add the range */ str = gst_rtsp_media_get_range_string (media, TRUE, unit); @@ -1197,14 +1182,12 @@ invalid_state: GST_ERROR ("client %p: not PLAYING or READY", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx); - g_free (path); return FALSE; } unsuspend_failed: { GST_ERROR ("client %p: unsuspend failed", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); - g_free (path); return FALSE; } } diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index d042ea0b7d..e49e4262c4 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -232,6 +232,74 @@ gst_rtsp_session_media_get_base_time (GstRTSPSessionMedia * media) return gst_rtsp_media_get_base_time (media->priv->media); } +/** + * gst_rtsp_session_media_get_rtpinfo: + * @media: a #GstRTSPSessionMedia + * + * Retrieve the RTP-Info header string for all streams in @media + * with configured transports. + * + * Returns: (transfer full): The RTP-Info as a string, g_free() + * after usage. + */ +gchar * +gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media) +{ + GstRTSPSessionMediaPrivate *priv; + GString *rtpinfo = NULL; + GstRTSPStreamTransport *transport; + guint i, n_streams; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL); + + priv = media->priv; + g_mutex_lock (&priv->lock); + + n_streams = priv->transports->len; + + GST_LOG_OBJECT (media, "collecting RTP info for %d transports", n_streams); + + for (i = 0; i < n_streams; i++) { + gchar *stream_rtpinfo; + + transport = g_ptr_array_index (priv->transports, i); + if (transport == NULL) { + GST_DEBUG_OBJECT (media, "ignoring unconfigured transport %d", i); + continue; + } + + stream_rtpinfo = gst_rtsp_stream_transport_get_rtpinfo (transport); + if (stream_rtpinfo == NULL) + goto stream_rtpinfo_missing; + + if (rtpinfo == NULL) + rtpinfo = g_string_new (""); + else + g_string_append (rtpinfo, ", "); + + g_string_append (rtpinfo, stream_rtpinfo); + g_free (stream_rtpinfo); + } + + if (rtpinfo == NULL) { + GST_INFO_OBJECT (media, "no transports configured, RTP info is empty"); + rtpinfo = g_string_new (""); + } + + g_mutex_unlock (&priv->lock); + + return g_string_free (rtpinfo, FALSE); + + /* ERRORS */ +stream_rtpinfo_missing: + { + g_mutex_unlock (&priv->lock); + g_string_free (rtpinfo, TRUE); + GST_ERROR_OBJECT (media, "could not get stream %d rtpinfo", i); + return NULL; + } +} + /** * gst_rtsp_session_media_set_transport: * @media: a #GstRTSPSessionMedia diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 0b7c8c8b6d..e2af5ad8b8 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -90,6 +90,8 @@ GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMe gboolean gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia *media, GstRTSPRange *range); +gchar * gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media); + G_END_DECLS #endif /* __GST_RTSP_SESSION_MEDIA_H__ */ diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 90e631003d..cf8eb642b5 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -310,6 +310,40 @@ gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport * trans) return trans->priv->url; } + /** + * gst_rtsp_stream_transport_get_rtpinfo: + * @trans: a #GstRTSPStreamTransport + * + * Get the RTPInfo string for @trans. + * + * Returns: the RTPInfo string for @trans. g_free() after + * usage. + */ +gchar * +gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport * trans) +{ + GstRTSPStreamTransportPrivate *priv; + gchar *url_str; + GString *rtpinfo; + guint rtptime, seq; + + g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL); + + priv = trans->priv; + + if (!gst_rtsp_stream_get_rtpinfo (priv->stream, &rtptime, &seq)) + return NULL; + + rtpinfo = g_string_new (""); + + url_str = gst_rtsp_url_get_request_uri (trans->priv->url); + g_string_append_printf (rtpinfo, "url=%s;seq=%u;rtptime=%u", + url_str, seq, rtptime); + g_free (url_str); + + return g_string_free (rtpinfo, FALSE); +} + /** * gst_rtsp_stream_transport_set_active: * @trans: a #GstRTSPStreamTransport diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index bc02df8d39..3a5e5793dd 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -99,6 +99,9 @@ void gst_rtsp_stream_transport_set_url (GstRTSPStreamT const GstRTSPUrl * url); const GstRTSPUrl * gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport *trans); + +gchar * gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport *trans); + void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans, GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, From cfdc7408b533048515f59b7cd1190c5f1f0b2797 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 26 Dec 2013 14:43:35 +0100 Subject: [PATCH 0884/1776] stream: also return the running-time Return the running-time in the rtpinfo as well. --- gst/rtsp-server/rtsp-stream-transport.c | 2 +- gst/rtsp-server/rtsp-stream.c | 25 ++++++++++++++----------- gst/rtsp-server/rtsp-stream.h | 3 ++- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index cf8eb642b5..faacc4a653 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -331,7 +331,7 @@ gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport * trans) priv = trans->priv; - if (!gst_rtsp_stream_get_rtpinfo (priv->stream, &rtptime, &seq)) + if (!gst_rtsp_stream_get_rtpinfo (priv->stream, &rtptime, &seq, NULL)) return NULL; rtpinfo = g_string_new (""); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index bcc8ccfe95..3380bd02d3 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1749,34 +1749,37 @@ was_not_joined: /** * gst_rtsp_stream_get_rtpinfo: * @stream: a #GstRTSPStream - * @rtptime: result RTP timestamp - * @seq: result RTP seqnum + * @rtptime: (allow-none): result RTP timestamp + * @seq: (allow-none): result RTP seqnum + * @running_time: (allow-none): result running-time * - * Retrieve the current rtptime and seq. This is used to + * Retrieve the current rtptime, seq and running-time. This is used to * construct a RTPInfo reply header. * - * Returns: %TRUE when rtptime and seq could be determined. + * Returns: %TRUE when rtptime, seq and running-time could be determined. */ gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, - guint * rtptime, guint * seq) + guint * rtptime, guint * seq, GstClockTime * running_time) { GstRTSPStreamPrivate *priv; GObjectClass *payobjclass; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); - g_return_val_if_fail (rtptime != NULL, FALSE); - g_return_val_if_fail (seq != NULL, FALSE); priv = stream->priv; payobjclass = G_OBJECT_GET_CLASS (priv->payloader); - if (!g_object_class_find_property (payobjclass, "seqnum") || - !g_object_class_find_property (payobjclass, "timestamp")) - return FALSE; + if (seq && g_object_class_find_property (payobjclass, "seqnum")) + g_object_get (priv->payloader, "seqnum", seq, NULL); - g_object_get (priv->payloader, "seqnum", seq, "timestamp", rtptime, NULL); + if (rtptime && g_object_class_find_property (payobjclass, "timestamp")) + g_object_get (priv->payloader, "timestamp", rtptime, NULL); + + if (running_time + && g_object_class_find_property (payobjclass, "running-time")) + g_object_get (priv->payloader, "running-time", running_time, NULL); return TRUE; } diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 71efa6211d..0eac4328ed 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -118,7 +118,8 @@ void gst_rtsp_stream_get_ssrc (GstRTSPStream *stream, guint *ssrc); gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream *stream, - guint *rtptime, guint *seq); + guint *rtptime, guint *seq, + GstClockTime *running_time); GstCaps * gst_rtsp_stream_get_caps (GstRTSPStream *stream); GstFlowReturn gst_rtsp_stream_recv_rtp (GstRTSPStream *stream, From 037e21b578d56057a205bd07422b53f3c1d1e7e8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 26 Dec 2013 16:28:59 +0100 Subject: [PATCH 0885/1776] session-media: calculate start-time --- gst/rtsp-server/rtsp-session-media.c | 45 ++++++++++++++++++++++++- gst/rtsp-server/rtsp-stream-transport.c | 8 +++-- gst/rtsp-server/rtsp-stream-transport.h | 3 +- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index e49e4262c4..78faeedfce 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -248,15 +248,51 @@ gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media) GstRTSPSessionMediaPrivate *priv; GString *rtpinfo = NULL; GstRTSPStreamTransport *transport; + GstRTSPStream *stream; guint i, n_streams; + GstClockTime earliest = GST_CLOCK_TIME_NONE; g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL); priv = media->priv; g_mutex_lock (&priv->lock); + if (gst_rtsp_media_get_status (priv->media) != GST_RTSP_MEDIA_STATUS_PREPARED) + goto not_prepared; + n_streams = priv->transports->len; + /* first step, take lowest running-time from all streams */ + GST_LOG_OBJECT (media, "determining start time among %d transports", + n_streams); + + for (i = 0; i < n_streams; i++) { + GstClockTime running_time; + + transport = g_ptr_array_index (priv->transports, i); + if (transport == NULL) { + GST_DEBUG_OBJECT (media, "ignoring unconfigured transport %d", i); + continue; + } + + stream = gst_rtsp_stream_transport_get_stream (transport); + if (!gst_rtsp_stream_get_rtpinfo (stream, NULL, NULL, &running_time)) + continue; + + GST_LOG_OBJECT (media, "running time of %d stream: %" GST_TIME_FORMAT, i, + GST_TIME_ARGS (running_time)); + + if (!GST_CLOCK_TIME_IS_VALID (earliest)) { + earliest = running_time; + } else { + earliest = MIN (earliest, running_time); + } + } + + GST_LOG_OBJECT (media, "media start time: %" GST_TIME_FORMAT, + GST_TIME_ARGS (earliest)); + + /* next step, scale all rtptime of all streams to lowest running-time */ GST_LOG_OBJECT (media, "collecting RTP info for %d transports", n_streams); for (i = 0; i < n_streams; i++) { @@ -268,7 +304,8 @@ gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media) continue; } - stream_rtpinfo = gst_rtsp_stream_transport_get_rtpinfo (transport); + stream_rtpinfo = + gst_rtsp_stream_transport_get_rtpinfo (transport, earliest); if (stream_rtpinfo == NULL) goto stream_rtpinfo_missing; @@ -291,6 +328,12 @@ gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media) return g_string_free (rtpinfo, FALSE); /* ERRORS */ +not_prepared: + { + g_mutex_unlock (&priv->lock); + GST_ERROR_OBJECT (media, "media was not prepared"); + return NULL; + } stream_rtpinfo_missing: { g_mutex_unlock (&priv->lock); diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index faacc4a653..9c1f9c21d3 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -313,14 +313,16 @@ gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport * trans) /** * gst_rtsp_stream_transport_get_rtpinfo: * @trans: a #GstRTSPStreamTransport + * @start_time: a star time * - * Get the RTPInfo string for @trans. + * Get the RTPInfo string for @trans and @start_time. * - * Returns: the RTPInfo string for @trans. g_free() after + * Returns: the RTPInfo string for @trans and @start_time. g_free() after * usage. */ gchar * -gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport * trans) +gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport * trans, + GstClockTime start_time) { GstRTSPStreamTransportPrivate *priv; gchar *url_str; diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 3a5e5793dd..7735ee718f 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -100,7 +100,8 @@ void gst_rtsp_stream_transport_set_url (GstRTSPStreamT const GstRTSPUrl * gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport *trans); -gchar * gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport *trans); +gchar * gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport *trans, + GstClockTime start_time); void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans, GstRTSPSendFunc send_rtp, From 8aaa432d5881f82abff3cf60978e8e739b70ed70 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 26 Dec 2013 17:02:50 +0100 Subject: [PATCH 0886/1776] stream: return clock-rate from get_rtpinfo And use it to correct the rtptime to the requested start-time. See https://bugzilla.gnome.org/show_bug.cgi?id=712198 --- gst/rtsp-server/rtsp-session-media.c | 2 +- gst/rtsp-server/rtsp-stream-transport.c | 24 ++++++++++++++++++++++-- gst/rtsp-server/rtsp-stream.c | 15 ++++++++++++++- gst/rtsp-server/rtsp-stream.h | 1 + 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 78faeedfce..da82167a0d 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -276,7 +276,7 @@ gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media) } stream = gst_rtsp_stream_transport_get_stream (transport); - if (!gst_rtsp_stream_get_rtpinfo (stream, NULL, NULL, &running_time)) + if (!gst_rtsp_stream_get_rtpinfo (stream, NULL, NULL, NULL, &running_time)) continue; GST_LOG_OBJECT (media, "running time of %d stream: %" GST_TIME_FORMAT, i, diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 9c1f9c21d3..ea0a04f825 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -327,15 +327,35 @@ gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport * trans, GstRTSPStreamTransportPrivate *priv; gchar *url_str; GString *rtpinfo; - guint rtptime, seq; + guint rtptime, seq, clock_rate; + GstClockTime running_time = GST_CLOCK_TIME_NONE; g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL); priv = trans->priv; - if (!gst_rtsp_stream_get_rtpinfo (priv->stream, &rtptime, &seq, NULL)) + if (!gst_rtsp_stream_get_rtpinfo (priv->stream, &rtptime, &seq, &clock_rate, + &running_time)) return NULL; + GST_DEBUG ("RTP time %u, seq %u, rate %u, running-time %" GST_TIME_FORMAT, + rtptime, seq, clock_rate, GST_TIME_ARGS (running_time)); + + if (GST_CLOCK_TIME_IS_VALID (running_time) + && GST_CLOCK_TIME_IS_VALID (start_time)) { + if (running_time > start_time) { + rtptime -= + gst_util_uint64_scale_int (running_time - start_time, clock_rate, + GST_SECOND); + } else { + rtptime += + gst_util_uint64_scale_int (start_time - running_time, clock_rate, + GST_SECOND); + } + } + GST_DEBUG ("RTP time %u, for start-time %" GST_TIME_FORMAT, + rtptime, GST_TIME_ARGS (start_time)); + rtpinfo = g_string_new (""); url_str = gst_rtsp_url_get_request_uri (trans->priv->url); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 3380bd02d3..01ed7b7b6e 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1751,6 +1751,7 @@ was_not_joined: * @stream: a #GstRTSPStream * @rtptime: (allow-none): result RTP timestamp * @seq: (allow-none): result RTP seqnum + * @clock_rate: the clock rate * @running_time: (allow-none): result running-time * * Retrieve the current rtptime, seq and running-time. This is used to @@ -1760,7 +1761,8 @@ was_not_joined: */ gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, - guint * rtptime, guint * seq, GstClockTime * running_time) + guint * rtptime, guint * seq, guint * clock_rate, + GstClockTime * running_time) { GstRTSPStreamPrivate *priv; GObjectClass *payobjclass; @@ -1771,6 +1773,7 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, payobjclass = G_OBJECT_GET_CLASS (priv->payloader); + g_mutex_lock (&priv->lock); if (seq && g_object_class_find_property (payobjclass, "seqnum")) g_object_get (priv->payloader, "seqnum", seq, NULL); @@ -1781,6 +1784,16 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, && g_object_class_find_property (payobjclass, "running-time")) g_object_get (priv->payloader, "running-time", running_time, NULL); + if (clock_rate && priv->caps) { + GstStructure *s; + + s = gst_caps_get_structure (priv->caps, 0); + if (!gst_structure_get_int (s, "clock-rate", (gint *) clock_rate)) + if (running_time) + *running_time = GST_CLOCK_TIME_NONE; + } + g_mutex_unlock (&priv->lock); + return TRUE; } diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 0eac4328ed..b665a662fa 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -119,6 +119,7 @@ void gst_rtsp_stream_get_ssrc (GstRTSPStream *stream, gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream *stream, guint *rtptime, guint *seq, + guint *clock_rate, GstClockTime *running_time); GstCaps * gst_rtsp_stream_get_caps (GstRTSPStream *stream); From 43ec4e7c786227b85aec06599c3955626e241a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 27 Dec 2013 13:11:45 +0100 Subject: [PATCH 0887/1776] configure.ac: Only check for gstreamer-check, not check We include check in gstreamer-check since quite some time now. --- configure.ac | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 4fe59ab595..979b6f913f 100644 --- a/configure.ac +++ b/configure.ac @@ -137,11 +137,7 @@ AC_SUBST(GSTPG_PLUGINS_DIR) AC_MSG_NOTICE(Using GStreamer Good Plugins in $GSTPG_PLUGINS_DIR) AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) - -dnl FIXME: get rid of this by making sure gstreamer-check brings it in -dnl check for "check", unit testing library/header -AM_PATH_CHECK(0.9.2, HAVE_CHECK=yes, HAVE_CHECK=no) -AM_CONDITIONAL(HAVE_CHECK, test "x$HAVE_CHECK" = "xyes") +AM_CONDITIONAL(HAVE_CHECK, test "x$HAVE_GST_CHECK" = "xyes") dnl *** set variables based on configure arguments *** From a1202effdaf180ec4bfb49683a1685e7451ab827 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 7 Jan 2014 12:14:15 +0100 Subject: [PATCH 0888/1776] stream: add method to check supported transport Add a method to check if a transport is supported --- gst/rtsp-server/rtsp-stream.c | 51 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 3 +++ 2 files changed, 54 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 01ed7b7b6e..a92b9854c0 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -545,6 +545,57 @@ gst_rtsp_stream_get_dscp_qos (GstRTSPStream * stream) return priv->dscp_qos; } +/** + * gst_rtsp_stream_is_transport_supported: + * @stream: a #GstRTSPStream + * @transport: a #GstRTSPTransport + * + * Check if @transport can be handled by stream + * + * Returns: %TRUE if @transport can be handled by @stream. + */ +gboolean +gst_rtsp_stream_is_transport_supported (GstRTSPStream * stream, + GstRTSPTransport * transport) +{ + GstRTSPStreamPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if (transport->trans != GST_RTSP_TRANS_RTP) + goto unsupported_transmode; + + if (transport->profile != GST_RTSP_PROFILE_AVP) + goto unsupported_profile; + + if (!(transport->lower_transport & priv->protocols)) + goto unsupported_ltrans; + + g_mutex_unlock (&priv->lock); + + return TRUE; + + /* ERRORS */ +unsupported_transmode: + { + GST_DEBUG ("unsupported transport mode %d", transport->trans); + return FALSE; + } +unsupported_profile: + { + GST_DEBUG ("unsupported profile %d", transport->profile); + return FALSE; + } +unsupported_ltrans: + { + GST_DEBUG ("unsupported lower transport %d", transport->lower_transport); + return FALSE; + } +} + /** * gst_rtsp_stream_set_protocols: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index b665a662fa..60ea876671 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -82,6 +82,9 @@ guint gst_rtsp_stream_get_mtu (GstRTSPStream *stream); void gst_rtsp_stream_set_dscp_qos (GstRTSPStream *stream, gint dscp_qos); gint gst_rtsp_stream_get_dscp_qos (GstRTSPStream *stream); +gboolean gst_rtsp_stream_is_transport_supported (GstRTSPStream *stream, + GstRTSPTransport *transport); + void gst_rtsp_stream_set_protocols (GstRTSPStream *stream, GstRTSPLowerTrans protocols); GstRTSPLowerTrans gst_rtsp_stream_get_protocols (GstRTSPStream *stream); From 78c6648c967c9f758f8c8da7fc1e9bd7e59b703c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 7 Jan 2014 12:28:47 +0100 Subject: [PATCH 0889/1776] client: let stream check supported transport Delegate the check if a transport is allowed to the stream. See https://bugzilla.gnome.org/show_bug.cgi?id=720696 --- gst/rtsp-server/rtsp-client.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1a1de6c539..8744e2c41c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1200,10 +1200,10 @@ do_keepalive (GstRTSPSession * session) } /* parse @transport and return a valid transport in @tr. only transports - * from @supported are returned. Returns FALSE if no valid transport + * supported by @stream are returned. Returns FALSE if no valid transport * was found. */ static gboolean -parse_transport (const char *transport, GstRTSPLowerTrans supported, +parse_transport (const char *transport, GstRTSPStream * stream, GstRTSPTransport * tr) { gint i; @@ -1226,13 +1226,8 @@ parse_transport (const char *transport, GstRTSPLowerTrans supported, goto next; } - /* we have a transport, see if it's RTP/AVP */ - if (tr->trans != GST_RTSP_TRANS_RTP || tr->profile != GST_RTSP_PROFILE_AVP) { - GST_WARNING ("invalid transport %s", transports[i]); - goto next; - } - - if (!(tr->lower_transport & supported)) { + /* we have a transport, see if it's supported */ + if (!gst_rtsp_stream_is_transport_supported (stream, tr)) { GST_WARNING ("unsupported transport %s", transports[i]); goto next; } @@ -1409,7 +1404,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPUrl *uri; gchar *transport; GstRTSPTransport *ct, *st; - GstRTSPLowerTrans supported; GstRTSPStatusCode code; GstRTSPSession *session; GstRTSPStreamTransport *trans; @@ -1517,11 +1511,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_transport_new (&ct); - /* our supported transports */ - supported = gst_rtsp_stream_get_protocols (stream); - /* parse and find a usable supported transport */ - if (!parse_transport (transport, supported, ct)) + if (!parse_transport (transport, stream, ct)) goto unsupported_transports; /* update the client transport */ From ae1fe21436cf77da079beb4580f5027ec71e2238 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 7 Jan 2014 12:21:09 +0100 Subject: [PATCH 0890/1776] stream: add property to configure profiles --- gst/rtsp-server/rtsp-media.c | 68 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 3 ++ gst/rtsp-server/rtsp-stream.c | 63 +++++++++++++++++++++++++++++++- gst/rtsp-server/rtsp-stream.h | 3 ++ 4 files changed, 136 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4c361b93a1..734edec4b8 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -82,6 +82,7 @@ struct _GstRTSPMediaPrivate gboolean shared; gboolean suspend_mode; gboolean reusable; + GstRTSPProfile profiles; GstRTSPLowerTrans protocols; gboolean reused; gboolean eos_shutdown; @@ -125,6 +126,7 @@ struct _GstRTSPMediaPrivate #define DEFAULT_SHARED FALSE #define DEFAULT_SUSPEND_MODE GST_RTSP_SUSPEND_MODE_NONE #define DEFAULT_REUSABLE FALSE +#define DEFAULT_PROFILES GST_RTSP_PROFILE_AVP #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_EOS_SHUTDOWN FALSE @@ -140,6 +142,7 @@ enum PROP_SHARED, PROP_SUSPEND_MODE, PROP_REUSABLE, + PROP_PROFILES, PROP_PROTOCOLS, PROP_EOS_SHUTDOWN, PROP_BUFFER_SIZE, @@ -237,6 +240,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "If this media pipeline can be reused after an unprepare", DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PROFILES, + g_param_spec_flags ("profiles", "Profiles", + "Allowed transfer profiles", GST_TYPE_RTSP_PROFILE, + DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PROTOCOLS, g_param_spec_flags ("protocols", "Protocols", "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS, @@ -314,6 +322,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->shared = DEFAULT_SHARED; priv->suspend_mode = DEFAULT_SUSPEND_MODE; priv->reusable = DEFAULT_REUSABLE; + priv->profiles = DEFAULT_PROFILES; priv->protocols = DEFAULT_PROTOCOLS; priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN; priv->buffer_size = DEFAULT_BUFFER_SIZE; @@ -371,6 +380,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_REUSABLE: g_value_set_boolean (value, gst_rtsp_media_is_reusable (media)); break; + case PROP_PROFILES: + g_value_set_flags (value, gst_rtsp_media_get_profiles (media)); + break; case PROP_PROTOCOLS: g_value_set_flags (value, gst_rtsp_media_get_protocols (media)); break; @@ -408,6 +420,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_REUSABLE: gst_rtsp_media_set_reusable (media, g_value_get_boolean (value)); break; + case PROP_PROFILES: + gst_rtsp_media_set_profiles (media, g_value_get_flags (value)); + break; case PROP_PROTOCOLS: gst_rtsp_media_set_protocols (media, g_value_get_flags (value)); break; @@ -814,6 +829,59 @@ gst_rtsp_media_is_reusable (GstRTSPMedia * media) return res; } +static void +do_set_profiles (GstRTSPStream * stream, GstRTSPProfile * profiles) +{ + gst_rtsp_stream_set_profiles (stream, *profiles); +} + +/** + * gst_rtsp_media_set_profiles: + * @media: a #GstRTSPMedia + * @profiles: the new flags + * + * Configure the allowed lower transport for @media. + */ +void +gst_rtsp_media_set_profiles (GstRTSPMedia * media, GstRTSPProfile profiles) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->profiles = profiles; + g_ptr_array_foreach (priv->streams, (GFunc) do_set_profiles, &profiles); + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_get_profiles: + * @media: a #GstRTSPMedia + * + * Get the allowed profiles of @media. + * + * Returns: a #GstRTSPProfile + */ +GstRTSPProfile +gst_rtsp_media_get_profiles (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + GstRTSPProfile res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_RTSP_PROFILE_UNKNOWN); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->profiles; + g_mutex_unlock (&priv->lock); + + return res; +} + static void do_set_protocols (GstRTSPStream * stream, GstRTSPLowerTrans * protocols) { diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 885960691f..cd38a499ad 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -160,6 +160,9 @@ gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media); void gst_rtsp_media_set_reusable (GstRTSPMedia *media, gboolean reusable); gboolean gst_rtsp_media_is_reusable (GstRTSPMedia *media); +void gst_rtsp_media_set_profiles (GstRTSPMedia *media, GstRTSPProfile profiles); +GstRTSPProfile gst_rtsp_media_get_profiles (GstRTSPMedia *media); + void gst_rtsp_media_set_protocols (GstRTSPMedia *media, GstRTSPLowerTrans protocols); GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia *media); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index a92b9854c0..ac28bd8bde 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -68,6 +68,7 @@ struct _GstRTSPStreamPrivate gboolean is_joined; gchar *control; + GstRTSPProfile profiles; GstRTSPLowerTrans protocols; /* pads on the rtpbin */ @@ -127,6 +128,7 @@ struct _GstRTSPStreamPrivate }; #define DEFAULT_CONTROL NULL +#define DEFAULT_PROFILES GST_RTSP_PROFILE_AVP #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ GST_RTSP_LOWER_TRANS_TCP @@ -134,6 +136,7 @@ enum { PROP_0, PROP_CONTROL, + PROP_PROFILES, PROP_PROTOCOLS, PROP_LAST }; @@ -170,6 +173,11 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) "The control string for this stream", DEFAULT_CONTROL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PROFILES, + g_param_spec_flags ("profiles", "Profiles", + "Allowed transfer profiles", GST_TYPE_RTSP_PROFILE, + DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PROTOCOLS, g_param_spec_flags ("protocols", "Protocols", "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS, @@ -191,6 +199,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->dscp_qos = -1; priv->control = g_strdup (DEFAULT_CONTROL); + priv->profiles = DEFAULT_PROFILES; priv->protocols = DEFAULT_PROTOCOLS; g_mutex_init (&priv->lock); @@ -238,6 +247,9 @@ gst_rtsp_stream_get_property (GObject * object, guint propid, case PROP_CONTROL: g_value_take_string (value, gst_rtsp_stream_get_control (stream)); break; + case PROP_PROFILES: + g_value_set_flags (value, gst_rtsp_stream_get_profiles (stream)); + break; case PROP_PROTOCOLS: g_value_set_flags (value, gst_rtsp_stream_get_protocols (stream)); break; @@ -256,6 +268,9 @@ gst_rtsp_stream_set_property (GObject * object, guint propid, case PROP_CONTROL: gst_rtsp_stream_set_control (stream, g_value_get_string (value)); break; + case PROP_PROFILES: + gst_rtsp_stream_set_profiles (stream, g_value_get_flags (value)); + break; case PROP_PROTOCOLS: gst_rtsp_stream_set_protocols (stream, g_value_get_flags (value)); break; @@ -568,7 +583,7 @@ gst_rtsp_stream_is_transport_supported (GstRTSPStream * stream, if (transport->trans != GST_RTSP_TRANS_RTP) goto unsupported_transmode; - if (transport->profile != GST_RTSP_PROFILE_AVP) + if (!(transport->profile & priv->profiles)) goto unsupported_profile; if (!(transport->lower_transport & priv->protocols)) @@ -596,6 +611,52 @@ unsupported_ltrans: } } +/** + * gst_rtsp_stream_set_profiles: + * @stream: a #GstRTSPStream + * @profiles: the new profiles + * + * Configure the allowed profiles for @stream. + */ +void +gst_rtsp_stream_set_profiles (GstRTSPStream * stream, GstRTSPProfile profiles) +{ + GstRTSPStreamPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + priv->profiles = profiles; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_stream_get_profiles: + * @stream: a #GstRTSPStream + * + * Get the allowed profiles of @stream. + * + * Returns: a #GstRTSPProfile + */ +GstRTSPProfile +gst_rtsp_stream_get_profiles (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + GstRTSPProfile res; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_RTSP_PROFILE_UNKNOWN); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + res = priv->profiles; + g_mutex_unlock (&priv->lock); + + return res; +} + /** * gst_rtsp_stream_set_protocols: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 60ea876671..0e465b282b 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -85,6 +85,9 @@ gint gst_rtsp_stream_get_dscp_qos (GstRTSPStream *stream); gboolean gst_rtsp_stream_is_transport_supported (GstRTSPStream *stream, GstRTSPTransport *transport); +void gst_rtsp_stream_set_profiles (GstRTSPStream *stream, GstRTSPProfile profiles); +GstRTSPProfile gst_rtsp_stream_get_profiles (GstRTSPStream *stream); + void gst_rtsp_stream_set_protocols (GstRTSPStream *stream, GstRTSPLowerTrans protocols); GstRTSPLowerTrans gst_rtsp_stream_get_protocols (GstRTSPStream *stream); From d90ce618e4463af7567dc41a061ad13ff35cb27c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 7 Jan 2014 15:28:05 +0100 Subject: [PATCH 0891/1776] stream: fix compilation --- gst/rtsp-server/rtsp-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index ac28bd8bde..8382d3e604 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -575,7 +575,7 @@ gst_rtsp_stream_is_transport_supported (GstRTSPStream * stream, { GstRTSPStreamPrivate *priv; - g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); priv = stream->priv; From 099a10f61f11413ad0ada8ee0b7b7ad1210b1b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 12 Jan 2014 16:55:21 +0000 Subject: [PATCH 0892/1776] rtsp-server: support build against last stable release Until 1.2.3 is out with the new get_type function and we can require that. --- gst/rtsp-server/rtsp-media.c | 2 ++ gst/rtsp-server/rtsp-stream.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 734edec4b8..f5ed9ab609 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -240,10 +240,12 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "If this media pipeline can be reused after an unprepare", DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#ifdef GST_TYPE_RTSP_PROFILE g_object_class_install_property (gobject_class, PROP_PROFILES, g_param_spec_flags ("profiles", "Profiles", "Allowed transfer profiles", GST_TYPE_RTSP_PROFILE, DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#endif g_object_class_install_property (gobject_class, PROP_PROTOCOLS, g_param_spec_flags ("protocols", "Protocols", diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 8382d3e604..680dbdc490 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -173,10 +173,12 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) "The control string for this stream", DEFAULT_CONTROL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#ifdef GST_TYPE_RTSP_PROFILE g_object_class_install_property (gobject_class, PROP_PROFILES, g_param_spec_flags ("profiles", "Profiles", "Allowed transfer profiles", GST_TYPE_RTSP_PROFILE, DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#endif g_object_class_install_property (gobject_class, PROP_PROTOCOLS, g_param_spec_flags ("protocols", "Protocols", From 5eca958d5ea090949091e593a83d4a24abf5c5df Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Tue, 21 Jan 2014 12:01:25 +0100 Subject: [PATCH 0893/1776] media: add signal to notify of pending state changes --- gst/rtsp-server/rtsp-media.c | 18 +++++++++++++++++- gst/rtsp-server/rtsp-media.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index f5ed9ab609..06e361b435 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -157,6 +157,7 @@ enum SIGNAL_REMOVED_STREAM, SIGNAL_PREPARED, SIGNAL_UNPREPARED, + SIGNAL_TARGET_STATE, SIGNAL_NEW_STATE, SIGNAL_LAST }; @@ -293,6 +294,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + gst_rtsp_media_signals[SIGNAL_TARGET_STATE] = + g_signal_new ("target-state", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, + NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + gst_rtsp_media_signals[SIGNAL_NEW_STATE] = g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL, @@ -1939,8 +1945,10 @@ start_preroll (GstRTSPMedia * media) GST_INFO ("setting pipeline to PAUSED for media %p", media); /* first go to PAUSED */ - ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); priv->target_state = GST_STATE_PAUSED; + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0, + priv->target_state, NULL); + ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); switch (ret) { case GST_STATE_CHANGE_SUCCESS: @@ -2320,6 +2328,8 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) GST_INFO ("unprepare media %p", media); priv->target_state = GST_STATE_NULL; + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0, + priv->target_state, NULL); success = TRUE; if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) { @@ -2559,6 +2569,8 @@ gst_rtsp_media_suspend (GstRTSPMedia * media) case GST_RTSP_SUSPEND_MODE_PAUSE: GST_DEBUG ("media %p suspend to PAUSED", media); priv->target_state = GST_STATE_PAUSED; + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0, + priv->target_state, NULL); ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; @@ -2566,6 +2578,8 @@ gst_rtsp_media_suspend (GstRTSPMedia * media) case GST_RTSP_SUSPEND_MODE_RESET: GST_DEBUG ("media %p suspend to NULL", media); priv->target_state = GST_STATE_NULL; + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0, + priv->target_state, NULL); ret = gst_element_set_state (priv->pipeline, GST_STATE_NULL); if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; @@ -2670,6 +2684,8 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) } else { GST_INFO ("state %s media %p", gst_element_state_get_name (state), media); priv->target_state = state; + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0, + priv->target_state, NULL); /* when we are buffering, don't update the state yet, this will be done * when buffering finishes */ if (priv->buffering) { diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index cd38a499ad..1ef50795c8 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -134,6 +134,7 @@ struct _GstRTSPMediaClass { void (*prepared) (GstRTSPMedia *media); void (*unprepared) (GstRTSPMedia *media); + void (*target_state) (GstRTSPMedia *media, GstState state); void (*new_state) (GstRTSPMedia *media, GstState state); /*< private >*/ From e04d9ac34d3b52fd49115c6ea0e1d1dcddeb50a7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 21 Jan 2014 14:46:47 +0100 Subject: [PATCH 0894/1776] media: refactor state change functions and signals Make functions to set the target state and the pipeline state and emit the signals from those functions. --- gst/rtsp-server/rtsp-media.c | 69 +++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 06e361b435..44fc8ea609 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1663,6 +1663,40 @@ media_streams_blocking (GstRTSPMedia * media) return blocking; } +static GstStateChangeReturn +set_state (GstRTSPMedia * media, GstState state) +{ + GstRTSPMediaPrivate *priv = media->priv; + GstStateChangeReturn ret; + + GST_INFO ("set state to %s for media %p", gst_element_state_get_name (state), + media); + ret = gst_element_set_state (priv->pipeline, state); + + return ret; +} + +static GstStateChangeReturn +set_target_state (GstRTSPMedia * media, GstState state, gboolean do_state) +{ + GstRTSPMediaPrivate *priv = media->priv; + GstStateChangeReturn ret; + + GST_INFO ("set target state to %s for media %p", + gst_element_state_get_name (state), media); + priv->target_state = state; + + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0, + priv->target_state, NULL); + + if (do_state) + ret = set_state (media, state); + else + ret = GST_STATE_CHANGE_SUCCESS; + + return ret; +} + /* called with state-lock */ static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message) @@ -1691,7 +1725,7 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) /* if the desired state is playing, go back */ if (priv->target_state == GST_STATE_PLAYING) { GST_INFO ("Buffering done, setting pipeline to PLAYING"); - gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); + set_state (media, GST_STATE_PLAYING); } else { GST_INFO ("Buffering done"); } @@ -1701,7 +1735,7 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) if (priv->target_state == GST_STATE_PLAYING) { /* we were not buffering but PLAYING, PAUSE the pipeline. */ GST_INFO ("Buffering, setting pipeline to PAUSED ..."); - gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); + set_state (media, GST_STATE_PAUSED); } else { GST_INFO ("Buffering ..."); } @@ -1945,10 +1979,7 @@ start_preroll (GstRTSPMedia * media) GST_INFO ("setting pipeline to PAUSED for media %p", media); /* first go to PAUSED */ - priv->target_state = GST_STATE_PAUSED; - g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0, - priv->target_state, NULL); - ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); + ret = set_target_state (media, GST_STATE_PAUSED, TRUE); switch (ret) { case GST_STATE_CHANGE_SUCCESS: @@ -1968,7 +1999,7 @@ start_preroll (GstRTSPMedia * media) priv->is_live = TRUE; /* start blocked to make sure nothing goes to the sink */ media_streams_set_blocked (media, TRUE); - ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); + ret = set_state (media, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; break; @@ -2221,7 +2252,7 @@ finish_unprepare (GstRTSPMedia * media) GST_DEBUG ("shutting down"); - gst_element_set_state (priv->pipeline, GST_STATE_NULL); + set_state (media, GST_STATE_NULL); remove_fakesink (priv); for (i = 0; i < priv->streams->len; i++) { @@ -2290,7 +2321,7 @@ default_unprepare (GstRTSPMedia * media) gst_element_send_event (priv->pipeline, gst_event_new_eos ()); /* we need to go to playing again for the EOS to propagate, normally in this * state, nothing is receiving data from us anymore so this is ok. */ - gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); + set_state (media, GST_STATE_PLAYING); priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARING; } else { finish_unprepare (media); @@ -2327,9 +2358,7 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) goto is_busy; GST_INFO ("unprepare media %p", media); - priv->target_state = GST_STATE_NULL; - g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0, - priv->target_state, NULL); + set_target_state (media, GST_STATE_NULL, FALSE); success = TRUE; if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) { @@ -2568,19 +2597,13 @@ gst_rtsp_media_suspend (GstRTSPMedia * media) break; case GST_RTSP_SUSPEND_MODE_PAUSE: GST_DEBUG ("media %p suspend to PAUSED", media); - priv->target_state = GST_STATE_PAUSED; - g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0, - priv->target_state, NULL); - ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); + ret = set_target_state (media, GST_STATE_PAUSED, TRUE); if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; break; case GST_RTSP_SUSPEND_MODE_RESET: GST_DEBUG ("media %p suspend to NULL", media); - priv->target_state = GST_STATE_NULL; - g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0, - priv->target_state, NULL); - ret = gst_element_set_state (priv->pipeline, GST_STATE_NULL); + ret = set_target_state (media, GST_STATE_NULL, TRUE); if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; break; @@ -2683,9 +2706,7 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) gst_rtsp_media_unprepare (media); } else { GST_INFO ("state %s media %p", gst_element_state_get_name (state), media); - priv->target_state = state; - g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_TARGET_STATE], 0, - priv->target_state, NULL); + set_target_state (media, state, FALSE); /* when we are buffering, don't update the state yet, this will be done * when buffering finishes */ if (priv->buffering) { @@ -2695,7 +2716,7 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) /* make sure pads are not blocking anymore when going to PLAYING */ media_streams_set_blocked (media, FALSE); - gst_element_set_state (priv->pipeline, state); + set_state (media, state); /* and suspend after pause */ if (state == GST_STATE_PAUSED) From 7edaa6ca201c1fb2e03a0f6ddebd3642685935a6 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Wed, 22 Jan 2014 22:03:14 +0100 Subject: [PATCH 0895/1776] stream: Get rtpinfo properties atomically from payloader Fixes https://bugzilla.gnome.org/show_bug.cgi?id=722844 --- gst/rtsp-server/rtsp-stream.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 680dbdc490..a6b949431f 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1879,33 +1879,31 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, GstClockTime * running_time) { GstRTSPStreamPrivate *priv; - GObjectClass *payobjclass; + GstStructure *stats; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); priv = stream->priv; - payobjclass = G_OBJECT_GET_CLASS (priv->payloader); - g_mutex_lock (&priv->lock); - if (seq && g_object_class_find_property (payobjclass, "seqnum")) - g_object_get (priv->payloader, "seqnum", seq, NULL); - if (rtptime && g_object_class_find_property (payobjclass, "timestamp")) - g_object_get (priv->payloader, "timestamp", rtptime, NULL); + g_object_get (priv->payloader, "stats", &stats, NULL); - if (running_time - && g_object_class_find_property (payobjclass, "running-time")) - g_object_get (priv->payloader, "running-time", running_time, NULL); + if (seq) + gst_structure_get_uint (stats, "seqnum", seq); - if (clock_rate && priv->caps) { - GstStructure *s; + if (rtptime) + gst_structure_get_uint (stats, "timestamp", rtptime); - s = gst_caps_get_structure (priv->caps, 0); - if (!gst_structure_get_int (s, "clock-rate", (gint *) clock_rate)) - if (running_time) - *running_time = GST_CLOCK_TIME_NONE; + if (running_time) + gst_structure_get_clock_time (stats, "running-time", running_time); + + if (clock_rate) { + gst_structure_get_uint (stats, "clock-rate", clock_rate); + if (*clock_rate == 0 && running_time) + *running_time = GST_CLOCK_TIME_NONE; } + g_mutex_unlock (&priv->lock); return TRUE; From 036f2760bff796c2f70ca6efef2efac7ad954a14 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 28 Jan 2014 14:51:26 +0100 Subject: [PATCH 0896/1776] stream: don't leak stats structure Don't leak the stats structure and deal with NULL stats. --- gst/rtsp-server/rtsp-stream.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index a6b949431f..dfc03498b8 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1889,6 +1889,9 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, g_object_get (priv->payloader, "stats", &stats, NULL); + if (stats == NULL) + goto no_stats; + if (seq) gst_structure_get_uint (stats, "seqnum", seq); @@ -1904,9 +1907,19 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, *running_time = GST_CLOCK_TIME_NONE; } + gst_structure_free (stats); + g_mutex_unlock (&priv->lock); return TRUE; + + /* ERRORS */ +no_stats: + { + GST_WARNING ("Could not get payloader stats"); + g_mutex_unlock (&priv->lock); + return FALSE; + } } /** From f9355e5481fbb26c61a1b4eae361499c3e2f8722 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 30 Jan 2014 10:45:56 +0100 Subject: [PATCH 0897/1776] Automatic update of common submodule From f7bc1c3 to 1a07da9 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index f7bc1c3ab8..1a07da9a64 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit f7bc1c3ab88024eb8b8e60f1af18fbcabcd83efe +Subproject commit 1a07da9a64c733842651ece62ddefebedd29c2da From 71c45fce5a50146ca799215874095679708872d3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 4 Feb 2014 10:14:45 +0100 Subject: [PATCH 0898/1776] stream: add fallback for missing stats property Use a fallback when the payloader does not have a stats property Fixes https://bugzilla.gnome.org/show_bug.cgi?id=723554 --- gst/rtsp-server/rtsp-stream.c | 41 ++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index dfc03498b8..96485df0c5 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1880,35 +1880,46 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, { GstRTSPStreamPrivate *priv; GstStructure *stats; + GObjectClass *payobjclass; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); priv = stream->priv; + payobjclass = G_OBJECT_GET_CLASS (priv->payloader); + g_mutex_lock (&priv->lock); - g_object_get (priv->payloader, "stats", &stats, NULL); + if (g_object_class_find_property (payobjclass, "stats")) { + g_object_get (priv->payloader, "stats", &stats, NULL); + if (stats == NULL) + goto no_stats; - if (stats == NULL) - goto no_stats; + if (seq) + gst_structure_get_uint (stats, "seqnum", seq); - if (seq) - gst_structure_get_uint (stats, "seqnum", seq); + if (rtptime) + gst_structure_get_uint (stats, "timestamp", rtptime); - if (rtptime) - gst_structure_get_uint (stats, "timestamp", rtptime); + if (running_time) + gst_structure_get_clock_time (stats, "running-time", running_time); - if (running_time) - gst_structure_get_clock_time (stats, "running-time", running_time); + if (clock_rate) { + gst_structure_get_uint (stats, "clock-rate", clock_rate); + if (*clock_rate == 0 && running_time) + *running_time = GST_CLOCK_TIME_NONE; + } + gst_structure_free (stats); + } else { + if (!g_object_class_find_property (payobjclass, "seqnum") || + !g_object_class_find_property (payobjclass, "timestamp")) + goto no_stats; - if (clock_rate) { - gst_structure_get_uint (stats, "clock-rate", clock_rate); - if (*clock_rate == 0 && running_time) + g_object_get (priv->payloader, "seqnum", seq, "timestamp", rtptime, NULL); + + if (running_time) *running_time = GST_CLOCK_TIME_NONE; } - - gst_structure_free (stats); - g_mutex_unlock (&priv->lock); return TRUE; From 274d4b017fe4967b616e67f8dfe40fb30bfb053e Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Fri, 31 Jan 2014 15:02:22 +0100 Subject: [PATCH 0899/1776] thread-pool: Unref reused threads in gst_rtsp_thread_stop() Fixes https://bugzilla.gnome.org/show_bug.cgi?id=723519 --- gst/rtsp-server/rtsp-thread-pool.c | 11 ++++++++--- tests/check/gst/threadpool.c | 4 ++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index 0a12fd136d..789d8ff28a 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -133,12 +133,17 @@ gboolean gst_rtsp_thread_reuse (GstRTSPThread * thread) { GstRTSPThreadImpl *impl = (GstRTSPThreadImpl *) thread; + gboolean res; g_return_val_if_fail (GST_IS_RTSP_THREAD (thread), FALSE); GST_DEBUG ("reuse thread %p", thread); - return g_atomic_int_add (&impl->reused, 1) > 0; + res = g_atomic_int_add (&impl->reused, 1) > 0; + if (res) + gst_rtsp_thread_ref (thread); + + return res; } static gboolean @@ -174,7 +179,8 @@ gst_rtsp_thread_stop (GstRTSPThread * thread) thread, (GDestroyNotify) gst_rtsp_thread_unref); g_source_attach (source, thread->context); g_source_unref (source); - } + } else + gst_rtsp_thread_unref (thread); } #define GST_RTSP_THREAD_POOL_GET_PRIVATE(obj) \ @@ -458,7 +464,6 @@ default_get_thread (GstRTSPThreadPool * pool, * stops. */ goto retry; } - gst_rtsp_thread_ref (thread); } else { /* make more threads */ GST_DEBUG_OBJECT (pool, "make new client thread"); diff --git a/tests/check/gst/threadpool.c b/tests/check/gst/threadpool.c index 735584a34c..4c6ca79a3b 100644 --- a/tests/check/gst/threadpool.c +++ b/tests/check/gst/threadpool.c @@ -34,6 +34,8 @@ GST_START_TEST (test_pool_get_thread) thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, NULL); fail_unless (thread != NULL); + /* one ref is hold by the pool */ + fail_unless (GST_MINI_OBJECT_REFCOUNT (thread) == 2); gst_rtsp_thread_stop (thread); g_object_unref (pool); @@ -62,6 +64,8 @@ GST_START_TEST (test_pool_get_thread_reuse) fail_unless (thread2 != NULL); fail_unless (thread == thread2); + /* one ref is hold by the pool */ + fail_unless (GST_MINI_OBJECT_REFCOUNT (thread) == 3); gst_rtsp_thread_stop (thread); gst_rtsp_thread_stop (thread2); From 9048d87ff44cf9e022e5e178eefd8f67b63db6a3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 4 Feb 2014 16:27:12 +0100 Subject: [PATCH 0900/1776] stream: handle NULL seqnum and rtptime arguments --- gst/rtsp-server/rtsp-stream.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 96485df0c5..dba20f4d3d 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1915,7 +1915,11 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, !g_object_class_find_property (payobjclass, "timestamp")) goto no_stats; - g_object_get (priv->payloader, "seqnum", seq, "timestamp", rtptime, NULL); + if (seq) + g_object_get (priv->payloader, "seqnum", seq, NULL); + + if (rtptime) + g_object_get (priv->payloader, "timestamp", rtptime, NULL); if (running_time) *running_time = GST_CLOCK_TIME_NONE; From b1845b0864aa0f60d81a8fef77a7b829a1e3e8f4 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Thu, 6 Feb 2014 09:03:50 +0100 Subject: [PATCH 0901/1776] thread-pool: Unref source after mainloop has quit to avoid races in GLib Fixes https://bugzilla.gnome.org/show_bug.cgi?id=723741 --- gst/rtsp-server/rtsp-thread-pool.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index 789d8ff28a..67c9782a11 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -56,6 +56,7 @@ typedef struct _GstRTSPThreadImpl GstRTSPThread thread; gint reused; + GSource *source; } GstRTSPThreadImpl; GST_DEFINE_MINI_OBJECT_TYPE (GstRTSPThread, gst_rtsp_thread); @@ -67,6 +68,7 @@ _gst_rtsp_thread_free (GstRTSPThreadImpl * impl) { GST_DEBUG ("free thread %p", impl); + g_source_unref (impl->source); g_main_loop_unref (impl->thread.loop); g_main_context_unref (impl->thread.context); g_slice_free1 (sizeof (GstRTSPThreadImpl), impl); @@ -171,14 +173,11 @@ gst_rtsp_thread_stop (GstRTSPThread * thread) GST_DEBUG ("stop thread %p", thread); if (g_atomic_int_dec_and_test (&impl->reused)) { - GSource *source; - GST_DEBUG ("add idle source to quit mainloop of thread %p", thread); - source = g_idle_source_new (); - g_source_set_callback (source, (GSourceFunc) do_quit, + impl->source = g_idle_source_new (); + g_source_set_callback (impl->source, (GSourceFunc) do_quit, thread, (GDestroyNotify) gst_rtsp_thread_unref); - g_source_attach (source, thread->context); - g_source_unref (source); + g_source_attach (impl->source, thread->context); } else gst_rtsp_thread_unref (thread); } From 450b9d0a14fa8e727c339c02e0b09a2a5969b4c7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 6 Feb 2014 09:48:05 +0100 Subject: [PATCH 0902/1776] media: only set keyframe flag when modifying start Only set the keyframe flag when we modify the start position. The keyframe flag should probably be ignored when no change is requested but until we can claim this is all documented properly and all demuxer implement this, avoid setting the flag. See also https://bugzilla.gnome.org/show_bug.cgi?id=723075 --- gst/rtsp-server/rtsp-media.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 44fc8ea609..40b31d1db9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1487,7 +1487,6 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) { GstRTSPMediaClass *klass; GstRTSPMediaPrivate *priv; - GstSeekFlags flags; gboolean res; GstClockTime start, stop; GstSeekType start_type, stop_type; @@ -1520,10 +1519,6 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) if (!priv->seekable) goto not_seekable; - /* depends on the current playing state of the pipeline. We might need to - * queue this until we get EOS. */ - flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT; - start_type = stop_type = GST_SEEK_TYPE_NONE; if (!klass->convert_range (media, range, GST_RTSP_RANGE_NPT)) @@ -1546,6 +1541,8 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) stop_type = GST_SEEK_TYPE_SET; if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) { + GstSeekFlags flags; + GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); @@ -1553,6 +1550,15 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) if (priv->blocked) media_streams_set_blocked (media, TRUE); + /* depends on the current playing state of the pipeline. We might need to + * queue this until we get EOS. */ + flags = GST_SEEK_FLAG_FLUSH; + + /* only set keyframe flag when modifying start */ + if (start_type != GST_SEEK_TYPE_NONE) + flags |= GST_SEEK_FLAG_KEY_UNIT; + + /* FIXME, we only do forwards */ res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME, flags, start_type, start, stop_type, stop); From 271f5330985fbf4b4e41028a43cc00788a0fcfff Mon Sep 17 00:00:00 2001 From: Andrey Utkin Date: Mon, 3 Feb 2014 22:41:48 +0200 Subject: [PATCH 0903/1776] Don't free rtpinfo GString when it is NULL Fixes https://bugzilla.gnome.org/show_bug.cgi?id=723554 --- gst/rtsp-server/rtsp-session-media.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index da82167a0d..9cee47700a 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -337,7 +337,8 @@ not_prepared: stream_rtpinfo_missing: { g_mutex_unlock (&priv->lock); - g_string_free (rtpinfo, TRUE); + if (rtpinfo) + g_string_free (rtpinfo, TRUE); GST_ERROR_OBJECT (media, "could not get stream %d rtpinfo", i); return NULL; } From 8bd53dcf9c02230b172cbfa82bd120a6ff9a73dd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 7 Feb 2014 16:39:49 +0100 Subject: [PATCH 0904/1776] session: improve RTP-Info Ignore streams that can't generate RTP-Info instead of failing. Don't return the empty string when all streams are unconfigured but return NULL so that we don't generate and empty RTP-Info header. Improve docs a little. --- gst/rtsp-server/rtsp-session-media.c | 28 +++++++++---------------- gst/rtsp-server/rtsp-stream-transport.c | 6 +++--- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 9cee47700a..eea6c75850 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -239,8 +239,8 @@ gst_rtsp_session_media_get_base_time (GstRTSPSessionMedia * media) * Retrieve the RTP-Info header string for all streams in @media * with configured transports. * - * Returns: (transfer full): The RTP-Info as a string, g_free() - * after usage. + * Returns: (transfer full): The RTP-Info as a string or %NULL when + * no RTP-Info could be generated, g_free() after usage. */ gchar * gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media) @@ -306,8 +306,10 @@ gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media) stream_rtpinfo = gst_rtsp_stream_transport_get_rtpinfo (transport, earliest); - if (stream_rtpinfo == NULL) - goto stream_rtpinfo_missing; + if (stream_rtpinfo == NULL) { + GST_DEBUG_OBJECT (media, "ignoring unknown RTPInfo %d", i); + continue; + } if (rtpinfo == NULL) rtpinfo = g_string_new (""); @@ -317,14 +319,12 @@ gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media) g_string_append (rtpinfo, stream_rtpinfo); g_free (stream_rtpinfo); } - - if (rtpinfo == NULL) { - GST_INFO_OBJECT (media, "no transports configured, RTP info is empty"); - rtpinfo = g_string_new (""); - } - g_mutex_unlock (&priv->lock); + if (rtpinfo == NULL) { + GST_WARNING_OBJECT (media, "RTP info is empty"); + return NULL; + } return g_string_free (rtpinfo, FALSE); /* ERRORS */ @@ -334,14 +334,6 @@ not_prepared: GST_ERROR_OBJECT (media, "media was not prepared"); return NULL; } -stream_rtpinfo_missing: - { - g_mutex_unlock (&priv->lock); - if (rtpinfo) - g_string_free (rtpinfo, TRUE); - GST_ERROR_OBJECT (media, "could not get stream %d rtpinfo", i); - return NULL; - } } /** diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index ea0a04f825..4020ee4c0e 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -315,10 +315,10 @@ gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport * trans) * @trans: a #GstRTSPStreamTransport * @start_time: a star time * - * Get the RTPInfo string for @trans and @start_time. + * Get the RTP-Info string for @trans and @start_time. * - * Returns: the RTPInfo string for @trans and @start_time. g_free() after - * usage. + * Returns: the RTPInfo string for @trans and @start_time or %NULL when + * the RTP-Info could not be determined. g_free() after usage. */ gchar * gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport * trans, From 902b59f8238b48d3f225b494c808116bd439d825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 9 Feb 2014 10:19:50 +0100 Subject: [PATCH 0905/1776] Revert "rtsp-server: support build against last stable release" This reverts commit 099a10f61f11413ad0ada8ee0b7b7ad1210b1b2f. Let us require 1.2.3 now, which is going to be released in a few minutes. --- gst/rtsp-server/rtsp-media.c | 2 -- gst/rtsp-server/rtsp-stream.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 40b31d1db9..69ecded96d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -241,12 +241,10 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "If this media pipeline can be reused after an unprepare", DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -#ifdef GST_TYPE_RTSP_PROFILE g_object_class_install_property (gobject_class, PROP_PROFILES, g_param_spec_flags ("profiles", "Profiles", "Allowed transfer profiles", GST_TYPE_RTSP_PROFILE, DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -#endif g_object_class_install_property (gobject_class, PROP_PROTOCOLS, g_param_spec_flags ("protocols", "Protocols", diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index dba20f4d3d..4bea0fdc98 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -173,12 +173,10 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) "The control string for this stream", DEFAULT_CONTROL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -#ifdef GST_TYPE_RTSP_PROFILE g_object_class_install_property (gobject_class, PROP_PROFILES, g_param_spec_flags ("profiles", "Profiles", "Allowed transfer profiles", GST_TYPE_RTSP_PROFILE, DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -#endif g_object_class_install_property (gobject_class, PROP_PROTOCOLS, g_param_spec_flags ("protocols", "Protocols", From 745424e05cb6a9f8fcbdb1a53f8db86567372116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 9 Feb 2014 10:25:44 +0100 Subject: [PATCH 0906/1776] configure: Update version to 1.3.0.1 and require GStreamer 1.3.0 --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 979b6f913f..3efe1a76ed 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [0.11.90.1], +AC_INIT([GStreamer RTSP Server Library], [1.3.0.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -39,12 +39,12 @@ dnl we override it here if we need to for the release candidate of new series GST_API_VERSION=1.0 AC_SUBST(GST_API_VERSION) -AS_LIBTOOL(GST, 0, 0, 0) +AS_LIBTOOL(GST, 300, 0, 300) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.2.0 -GSTPB_REQ=1.2.0 -GSTPG_REQ=1.2.0 +GST_REQ=1.3.0.1 +GSTPB_REQ=1.3.0.1 +GSTPG_REQ=1.3.0.1 dnl *** autotools stuff **** From 1ab8b9d48674db8103a671fa5d74f3c1b0b856fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 9 Feb 2014 10:41:14 +0100 Subject: [PATCH 0907/1776] configure: Synchronise with the configure scripts of the other modules --- configure.ac | 74 +++++++++++++++++++++++++++++++++++++++++--- gst-rtsp-server.doap | 50 ++++++++++++++++++++++++++++++ tests/Makefile.am | 5 ++- 3 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 gst-rtsp-server.doap diff --git a/configure.ac b/configure.ac index 3efe1a76ed..24a9dc8bd1 100644 --- a/configure.ac +++ b/configure.ac @@ -39,6 +39,20 @@ dnl we override it here if we need to for the release candidate of new series GST_API_VERSION=1.0 AC_SUBST(GST_API_VERSION) +dnl CURRENT, REVISION, AGE +dnl - library source changed -> increment REVISION +dnl - interfaces added/removed/changed -> increment CURRENT, REVISION = 0 +dnl - interfaces added -> increment AGE +dnl - interfaces removed -> AGE = 0 +dnl +dnl Keep CURRENT as MINOR * 100 + MICRO +dnl Ex : 1.0.0 => 0 +dnl 1.0.3 => 3 +dnl 1.1.0 => 100 +dnl 1.2.5 => 205 +dnl 1.10.9 (who knows) => 1009 +dnl +dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 300, 0, 300) dnl *** required versions of GStreamer stuff *** @@ -63,14 +77,34 @@ dnl the version check needs to stay here because autopoint greps for it dnl *** check for arguments to configure *** +AG_GST_ARG_DISABLE_FATAL_WARNINGS + AG_GST_ARG_DEBUG AG_GST_ARG_VALGRIND AG_GST_ARG_GCOV +AG_GST_ARG_WITH_PKG_CONFIG_PATH AG_GST_ARG_WITH_PACKAGE_NAME AG_GST_ARG_WITH_PACKAGE_ORIGIN AG_GST_PKG_CONFIG_PATH +AG_GST_SET_PACKAGE_RELEASE_DATETIME_WITH_NANO([$PACKAGE_VERSION_NANO], + ["${srcdir}/gst-rtsp-server.doap"], + [$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR.$PACKAGE_VERSION_MICRO]) + +dnl building of tests +AC_ARG_ENABLE(tests, + AS_HELP_STRING([--disable-tests],[disable building test apps]), + [ + case "${enableval}" in + yes) BUILD_TESTS=yes ;; + no) BUILD_TESTS=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-tests) ;; + esac + ], +[BUILD_TESTS=yes]) dnl Default value +AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes") + dnl *** checks for platform *** dnl * hardware/architecture * @@ -79,17 +113,23 @@ dnl *** checks for programs *** dnl find a compiler AC_PROG_CC +AC_PROG_CC_STDC + +dnl check if the compiler supports '-c' and '-o' options AM_PROG_CC_C_O +dnl find an assembler +AM_PROG_AS + AC_PATH_PROG(VALGRIND_PATH, valgrind, no) AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") dnl check for gobject-introspection -GOBJECT_INTROSPECTION_CHECK([0.6.3]) +GOBJECT_INTROSPECTION_CHECK([1.31.1]) dnl check for documentation tools AG_GST_DOCBOOK_CHECK -GTK_DOC_CHECK([1.3]) +GTK_DOC_CHECK([1.12]) dnl *** checks for libraries *** @@ -139,6 +179,20 @@ AC_MSG_NOTICE(Using GStreamer Good Plugins in $GSTPG_PLUGINS_DIR) AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) AM_CONDITIONAL(HAVE_CHECK, test "x$HAVE_GST_CHECK" = "xyes") +dnl Check for -Bsymbolic-functions linker flag used to avoid +dnl intra-library PLT jumps, if available. +AC_ARG_ENABLE(Bsymbolic, + [AS_HELP_STRING([--disable-Bsymbolic],[avoid linking with -Bsymbolic])],, + [SAVED_LDFLAGS="${LDFLAGS}" + AC_MSG_CHECKING([for -Bsymbolic-functions linker flag]) + LDFLAGS=-Wl,-Bsymbolic-functions + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int main (void) { return 0; }]])],[ + AC_MSG_RESULT(yes) + enable_Bsymbolic=yes],[ + AC_MSG_RESULT(no) + enable_Bsymbolic=no]) + LDFLAGS="${SAVED_LDFLAGS}"]) + dnl *** set variables based on configure arguments *** dnl set license and copyright notice @@ -155,7 +209,7 @@ NO_WARNINGS="" AG_GST_CHECK_GST_DEBUG_DISABLED([NO_WARNINGS="-Wno-unused"], [NO_WARNINGS=""]) dnl define an ERROR_CFLAGS Makefile variable -AG_GST_SET_ERROR_CFLAGS($GST_GIT, [$NO_WARNINGS]) +AG_GST_SET_ERROR_CFLAGS($FATAL_WARNINGS, [-Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wundef -Wwrite-strings -Wformat-nonliteral -Wformat-security -Wold-style-definition -Winit-self -Wmissing-include-dirs -Waddress -Waggregate-return -Wno-multichar -Wnested-externs $NO_WARNINGS]) dnl define correct level for debugging messages AG_GST_SET_LEVEL_DEFAULT($GST_GIT) @@ -179,7 +233,15 @@ if test "x$USE_DEBUG" = xyes; then fi AC_SUBST(PROFILE_CFLAGS) -DEPRECATED_CFLAGS="-DGST_DISABLE_DEPRECATED" +# GST_DISABLE_DEPRECATED: hide the visibility of deprecated +# functionality from the API that gstreamer uses +# GST_REMOVE_DEPRECATED: don't compile deprecated functionality (breaks ABI) +if test "x$PACKAGE_VERSION_NANO" = "x1"; then + dnl Define _only_ when compiling from git (not for pre-releases or releases) + DEPRECATED_CFLAGS="-DGST_DISABLE_DEPRECATED" +else + DEPRECATED_CFLAGS="" +fi AC_SUBST(DEPRECATED_CFLAGS) dnl every flag in GST_OPTION_CFLAGS can be overridden at make time @@ -209,6 +271,10 @@ AC_SUBST([GST_ALL_LIBS]) dnl LDFLAGS really should only contain flags, not libs - they get added before dnl whatevertarget_LIBS and -L flags here affect the rest of the linking GST_ALL_LDFLAGS="-no-undefined" +if test "x${enable_Bsymbolic}" = "xyes"; then + GST_ALL_LDFLAGS="$GST_ALL_LDFLAGS -Wl,-Bsymbolic-functions" +fi + AC_SUBST(GST_ALL_LDFLAGS) dnl GST_LIB_LDFLAGS diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap new file mode 100644 index 0000000000..c2e925ebc3 --- /dev/null +++ b/gst-rtsp-server.doap @@ -0,0 +1,50 @@ + + + GStreamer RTSP Server + gst-rtsp-server + + 1999-10-31 + +RTSP server library based on GStreamer + + +RTSP server library based on GStreamer + + + + + + C + + + + + + + + + + + + + 1.1.90 + 1.1 + + 2014-02-09 + + + + + + + Wim Taymans + 0d93fde052812d51a05fd86de9bdbf674423daa2 + + + + diff --git a/tests/Makefile.am b/tests/Makefile.am index 8b3c6ab669..ca2ba661e8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,13 +1,12 @@ noinst_PROGRAMS = test-cleanup test-reuse -INCLUDES = -I$(top_srcdir) -I$(srcdir) - AM_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +AM_CPPFLAGS = -I$(top_srcdir) -I$(srcdir) AM_LDFLAGS = \ $(GST_LIBS) \ $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la -if HAVE_CHECK +if BUILD_TESTS SUBDIRS_CHECK = check else SUBDIRS_CHECK = From 957a4a65c649293717634602725e21ffc2fe84ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 9 Feb 2014 10:45:28 +0100 Subject: [PATCH 0908/1776] rtsp-server: Fix lots of compiler warnings with clang --- gst/rtsp-server/rtsp-client.c | 5 +++-- gst/rtsp-server/rtsp-mount-points.c | 5 +++-- gst/rtsp-server/rtsp-stream.c | 4 ++-- tests/check/gst/client.c | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8744e2c41c..1a3fa45e0a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1040,10 +1040,11 @@ invalid_state: /* convert @url and @path to a URL used as a content base for the factory * located at @path */ static gchar * -make_base_url (GstRTSPClient * client, GstRTSPUrl * url, gchar * path) +make_base_url (GstRTSPClient * client, GstRTSPUrl * url, const gchar * path) { GstRTSPUrl tmp; - gchar *result, *trail; + gchar *result; + const gchar *trail; /* check for trailing '/' and append one */ trail = (path[strlen (path) - 1] != '/' ? "/" : ""); diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index dbf5473113..2bddb648f0 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -72,7 +72,7 @@ data_item_free (gpointer data) } static void -data_item_dump (gconstpointer a, gpointer prefix) +data_item_dump (gconstpointer a, gconstpointer prefix) { const DataItem *item = a; @@ -251,7 +251,8 @@ gst_rtsp_mount_points_match (GstRTSPMountPoints * mounts, g_mutex_lock (&priv->lock); if (priv->dirty) { g_sequence_sort (priv->mounts, data_item_compare, mounts); - g_sequence_foreach (priv->mounts, (GFunc) data_item_dump, "sort :"); + g_sequence_foreach (priv->mounts, (GFunc) data_item_dump, + (gpointer) "sort :"); priv->dirty = FALSE; } diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4bea0fdc98..8b255eb785 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2194,7 +2194,7 @@ gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family) { GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); GSocket *socket; - gchar *name; + const gchar *name; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 || @@ -2228,7 +2228,7 @@ gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) { GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); GSocket *socket; - gchar *name; + const gchar *name; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 || diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index da99aa8a05..896a6cc91a 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -144,7 +144,7 @@ setup_client (const gchar * launch_line) } static void -teardown_client (GstRTSPClient *client) +teardown_client (GstRTSPClient * client) { gst_rtsp_client_set_thread_pool (client, NULL); g_object_unref (client); @@ -332,7 +332,7 @@ GST_START_TEST (test_describe) GST_END_TEST; -gchar *expected_transport = NULL;; +static const gchar *expected_transport = NULL;; static gboolean test_setup_response_200_multicast (GstRTSPClient * client, From 04c386b72760c8737b708535a57a73b44d4c32a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 9 Feb 2014 10:47:09 +0100 Subject: [PATCH 0909/1776] tests: Fix another compiler warning with gcc --- tests/check/gst/rtspserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 54effd9d62..e9ab1dc68a 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -183,7 +183,7 @@ start_server (void) /* stop the tested rtsp server */ static void -stop_server () +stop_server (void) { g_source_remove (source_id); source_id = 0; From e631112f3333360f7986db2511bd96755a36e5fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 9 Feb 2014 10:52:29 +0100 Subject: [PATCH 0910/1776] build: Ship gst-rtsp-server.doap file --- Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index a748dbc3b8..8b4b6055c1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,7 +13,8 @@ DIST_SUBDIRS = $(SUBDIRS) EXTRA_DIST = \ ChangeLog autogen.sh depcomp \ AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \ - gst-rtsp.spec docs/design/gst-rtp-server-design + gst-rtsp.spec docs/design/gst-rtp-server-design \ + gst-rtsp-server.doap ACLOCAL_AMFLAGS = -I m4 -I common/m4 From 0bd687f2107f613d33060484fa86159c288d4a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Tue, 11 Feb 2014 14:20:39 -0800 Subject: [PATCH 0911/1776] media: stop thread if media is already prepared in gst_rtsp_media_prepare() the thread is not used if media is already prepared (e.g. media shared) so we want to stop the thread. otherwise, a leak occurs. https://bugzilla.gnome.org/show_bug.cgi?id=724182 --- gst/rtsp-server/rtsp-media.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 69ecded96d..033e973b34 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2204,6 +2204,8 @@ wait_status: was_prepared: { GST_LOG ("media %p was prepared", media); + /* we are not going to use the giving thread, so stop it. */ + gst_rtsp_thread_stop (thread); g_rec_mutex_unlock (&priv->state_lock); return TRUE; } From a7f0feff23abe57928569f79eff58006adf2b4df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Mon, 17 Feb 2014 10:43:05 +0100 Subject: [PATCH 0912/1776] stream: set ttl-mc before adding the socket Set ttl-mc before adding the socket. Otherwise the value ttl-mc will never be set on socket. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=724531 --- gst/rtsp-server/rtsp-stream.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 8b255eb785..9c83c8251d 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2071,14 +2071,14 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, } if (add) { - GST_INFO ("adding %s:%d-%d", dest, min, max); - g_signal_emit_by_name (priv->udpsink[0], "add", dest, min, NULL); - g_signal_emit_by_name (priv->udpsink[1], "add", dest, max, NULL); if (ttl > 0) { GST_INFO ("setting ttl-mc %d", ttl); g_object_set (G_OBJECT (priv->udpsink[0]), "ttl-mc", ttl, NULL); g_object_set (G_OBJECT (priv->udpsink[1]), "ttl-mc", ttl, NULL); } + GST_INFO ("adding %s:%d-%d", dest, min, max); + g_signal_emit_by_name (priv->udpsink[0], "add", dest, min, NULL); + g_signal_emit_by_name (priv->udpsink[1], "add", dest, max, NULL); priv->transports = g_list_prepend (priv->transports, trans); } else { GST_INFO ("removing %s:%d-%d", dest, min, max); From f67fc23aab59f28796bebf130504ff46ccb97b0a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 18 Feb 2014 16:38:39 +0100 Subject: [PATCH 0913/1776] media: only flush when setting a new start position Only flush the pipeline when we change the start position with a seek. See https://bugzilla.gnome.org/show_bug.cgi?id=724611 --- gst/rtsp-server/rtsp-media.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 033e973b34..ede357e499 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1548,14 +1548,14 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) if (priv->blocked) media_streams_set_blocked (media, TRUE); + flags = GST_SEEK_FLAG_NONE; + + /* only set flush and keyframe flag when modifying start */ + if (start_type != GST_SEEK_TYPE_NONE) + flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT; + /* depends on the current playing state of the pipeline. We might need to * queue this until we get EOS. */ - flags = GST_SEEK_FLAG_FLUSH; - - /* only set keyframe flag when modifying start */ - if (start_type != GST_SEEK_TYPE_NONE) - flags |= GST_SEEK_FLAG_KEY_UNIT; - /* FIXME, we only do forwards */ res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME, flags, start_type, start, stop_type, stop); From 73551543b8ace6b43801b1744c392130b63a0730 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 18 Feb 2014 16:58:45 +0100 Subject: [PATCH 0914/1776] Revert "media: only flush when setting a new start position" This reverts commit f67fc23aab59f28796bebf130504ff46ccb97b0a. We need to do the flush in all cases, demuxer block currently for non-flushing seeks. --- gst/rtsp-server/rtsp-media.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index ede357e499..033e973b34 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1548,14 +1548,14 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) if (priv->blocked) media_streams_set_blocked (media, TRUE); - flags = GST_SEEK_FLAG_NONE; - - /* only set flush and keyframe flag when modifying start */ - if (start_type != GST_SEEK_TYPE_NONE) - flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT; - /* depends on the current playing state of the pipeline. We might need to * queue this until we get EOS. */ + flags = GST_SEEK_FLAG_FLUSH; + + /* only set keyframe flag when modifying start */ + if (start_type != GST_SEEK_TYPE_NONE) + flags |= GST_SEEK_FLAG_KEY_UNIT; + /* FIXME, we only do forwards */ res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME, flags, start_type, start, stop_type, stop); From 7ed2a6ef98d75085c47053c5d4bd7ae99c44d84d Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Tue, 18 Feb 2014 09:44:34 +0100 Subject: [PATCH 0915/1776] rtsp-media: don't loose frames handling new PLAY request If client supplied a range check if the range specifies the start point. If not, then do an accurate seek to the current position. If a start point was specified do do a key unit seek to make sure the streaming starts with decodeable frames. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=724611 --- gst/rtsp-server/rtsp-media.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 033e973b34..36626da312 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1528,9 +1528,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop)); - if (priv->range_start == start) - start = GST_CLOCK_TIME_NONE; - else if (start != GST_CLOCK_TIME_NONE) + if (start != GST_CLOCK_TIME_NONE) start_type = GST_SEEK_TYPE_SET; if (priv->range_stop == stop) @@ -1552,9 +1550,30 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) * queue this until we get EOS. */ flags = GST_SEEK_FLAG_FLUSH; - /* only set keyframe flag when modifying start */ - if (start_type != GST_SEEK_TYPE_NONE) - flags |= GST_SEEK_FLAG_KEY_UNIT; + /* if range start was not supplied we must continue from current position. + * but since we're doing a flushing seek, let us query the current position + * so we end up at exactly the same position after the seek. */ + if (range->min.type == GST_RTSP_TIME_END) { /* Yepp, that's right! */ + gint64 position; + gboolean ret = FALSE; + + if (klass->query_position) + ret = klass->query_position (media, &position); + + if (!ret) { + GST_WARNING ("position query failed"); + } else { + GST_DEBUG ("doing accurate seek to %" GST_TIME_FORMAT, + GST_TIME_ARGS (position)); + start = position; + start_type = GST_SEEK_TYPE_SET; + flags |= GST_SEEK_FLAG_ACCURATE; + } + } else { + /* only set keyframe flag when modifying start */ + if (start_type != GST_SEEK_TYPE_NONE) + flags |= GST_SEEK_FLAG_KEY_UNIT; + } /* FIXME, we only do forwards */ res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME, From e6b11af24a66bfa4d2d736d5f77fce7761407601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 21 Feb 2014 16:46:45 +0000 Subject: [PATCH 0916/1776] .gitignore: ignore temp files created in the course of 'make check' --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 15ed6afdba..86dd0f4f5d 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,10 @@ stamp-h.in /examples/test-multicast /examples/test-multicast2 +/test-driver +/tests/check/gst/*.log +/tests/check/gst/*.trs +/tests/check/test-suite.log /tests/check/gst/addresspool /tests/check/gst/client /tests/check/gst/media From f68db78a1d3d33479a7f5a32b4c9d5842cf87937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 25 Feb 2014 14:06:47 +0000 Subject: [PATCH 0917/1776] examples: fix cgroup test build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes build failure caused by compiler warning: test-cgroups.c:82:35: error: no previous prototype for ‘gst_rtsp_cgroup_pool_get_type’ [-Werror=missing-prototypes] --- examples/test-cgroups.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/test-cgroups.c b/examples/test-cgroups.c index 0a38916685..0412e4d02e 100644 --- a/examples/test-cgroups.c +++ b/examples/test-cgroups.c @@ -79,6 +79,8 @@ static void default_thread_enter (GstRTSPThreadPool * pool, static void default_configure_thread (GstRTSPThreadPool * pool, GstRTSPThread * thread, GstRTSPContext * ctx); +static GType gst_rtsp_cgroup_pool_get_type (void); + G_DEFINE_TYPE (GstRTSPCGroupPool, gst_rtsp_cgroup_pool, GST_TYPE_RTSP_THREAD_POOL); From 035d95159197df995e9989661b6310905ebdaf6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 25 Feb 2014 14:07:50 +0000 Subject: [PATCH 0918/1776] examples: add cgroup test binary to .gitignore --- examples/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/.gitignore b/examples/.gitignore index 82e4c5ed5e..286c2a3b2d 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,4 +1,5 @@ test-appsrc +test-cgroups test-launch test-mp4 test-ogg From 2234b4a503ec82c028c0931f070ba8aaaa075a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 25 Feb 2014 14:11:00 +0000 Subject: [PATCH 0919/1776] examples: test-cgroups: don't put code with side effects into g_assert() The g_assert() might get compiled out with the right compiler/preprocessor flags. --- examples/test-cgroups.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/test-cgroups.c b/examples/test-cgroups.c index 0412e4d02e..600fa3c16f 100644 --- a/examples/test-cgroups.c +++ b/examples/test-cgroups.c @@ -107,9 +107,11 @@ static void gst_rtsp_cgroup_pool_init (GstRTSPCGroupPool * pool) { pool->user = cgroup_new_cgroup ("user"); - g_assert (cgroup_add_controller (pool->user, "cpu") != NULL); + if (cgroup_add_controller (pool->user, "cpu") == NULL) + g_error ("Failed to add cpu controller to user cgroup"); pool->admin = cgroup_new_cgroup ("admin"); - g_assert (cgroup_add_controller (pool->admin, "cpu") != NULL); + if (cgroup_add_controller (pool->admin, "cpu") == NULL) + g_error ("Failed to add cpu controller to admin cgroup"); } static void From ea63932bd294134f83ed0082b69937cec091605a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 25 Feb 2014 14:42:09 +0000 Subject: [PATCH 0920/1776] configure: make sure releases are in .doap file --- configure.ac | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac index 24a9dc8bd1..4b12b26900 100644 --- a/configure.ac +++ b/configure.ac @@ -203,6 +203,11 @@ AC_SUBST(GST_LICENSE) dnl set location of plugin directory AG_GST_SET_PLUGINDIR +dnl set release date/time (and check that release version is in doap file) +AG_GST_SET_PACKAGE_RELEASE_DATETIME_WITH_NANO([$PACKAGE_VERSION_NANO], + ["${srcdir}/gst-rtsp-server.doap"], + [$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR.$PACKAGE_VERSION_MICRO]) + # set by AG_GST_PARSE_SUBSYSTEM_DISABLES above dnl make sure it doesn't complain about unused variables if debugging is disabled NO_WARNINGS="" From c3896849b2d4b9feb93d98d7f75ee91570bf1ce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 25 Feb 2014 15:13:40 +0000 Subject: [PATCH 0921/1776] examples: use LDADD for libs instead of LDFLAGS --- examples/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Makefile.am b/examples/Makefile.am index 0fc67c3d45..9bf2198a05 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -5,10 +5,10 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ #INCLUDES = -I$(top_srcdir) -I$(srcdir) AM_CFLAGS = $(GST_OBJ_CFLAGS) -AM_LDFLAGS = $(GST_OBJ_LIBS) $(GIO_LIBS) +LDADD = $(GST_OBJ_LIBS) $(GIO_LIBS) if HAVE_LIBCGROUP noinst_PROGRAMS += test-cgroups -AM_LDFLAGS += $(LIBCGROUP_LIBS) +LDADD += $(LIBCGROUP_LIBS) endif From 59ae326333bd64f7c6f7aadb205ac0b1736bf85e Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 26 Feb 2014 22:15:51 +0100 Subject: [PATCH 0922/1776] Automatic update of common submodule From 1a07da9 to fe1672e --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 1a07da9a64..fe1672ec77 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 1a07da9a64c733842651ece62ddefebedd29c2da +Subproject commit fe1672ec77616f5c4e527c0e2be493a7f95b1ebf From 36970455f8429c7a16cc03b760eed533ffb5430a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 28 Feb 2014 09:36:49 +0100 Subject: [PATCH 0923/1776] Automatic update of common submodule From fe1672e to bcb1518 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index fe1672ec77..bcb1518c08 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit fe1672ec77616f5c4e527c0e2be493a7f95b1ebf +Subproject commit bcb1518c08c889dd7eda06936fc26cad85fac755 From 81a2928c89e058a27d8b830a8df77d598baf5fd9 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Sun, 2 Mar 2014 05:12:10 +0100 Subject: [PATCH 0924/1776] docs: Enable and fix gtk-doc warnings * Makefile: Enable gtk-doc warnings, like the rest of GStreamer * addresspool/mediafactory: Add missing annotation colon * stream: Annotate return value Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725528 --- gst/rtsp-server/Makefile.am | 1 + gst/rtsp-server/rtsp-address-pool.c | 2 +- gst/rtsp-server/rtsp-media-factory.c | 2 +- gst/rtsp-server/rtsp-stream.c | 8 ++++---- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 7697ae845a..bbae027de5 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -75,6 +75,7 @@ GstRtspServer-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@ $(INTROSPECTION_SCANNER) -v --namespace GstRtspServer \ --nsversion=@GST_API_VERSION@ \ --strip-prefix=Gst \ + --warn-all \ -I$(top_srcdir) \ -I$(top_builddir) \ -DIN_GOBJECT_INTROSPECTION=1 \ diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 4f433be376..c6ba13d567 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -625,7 +625,7 @@ find_address_in_ranges (GList * addresses, Addr * addr, guint port, * @port: The first port to reserve * @n_ports: The number of ports * @ttl: The requested ttl - * @address: (out) storage for a #GstRTSPAddress + * @address: (out): storage for a #GstRTSPAddress * * Take a specific address and ports from @pool. @n_ports consecutive * ports will be allocated of which the first one can be found in diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 590b1f7d69..b8a781cea5 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -1053,7 +1053,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) * implementation of this function returns the bin created from the * launch parameter. * - * Returns: (transfer floating) a new #GstElement. + * Returns: (transfer floating): a new #GstElement. */ GstElement * gst_rtsp_media_factory_create_element (GstRTSPMediaFactory * factory, diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 9c83c8251d..ec82a1f2d2 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2186,8 +2186,8 @@ gst_rtsp_stream_remove_transport (GstRTSPStream * stream, * * @stream must be joined to a bin. * - * Returns: the RTP socket or %NULL if no socket could be allocated for @family. - * Unref after usage + * Returns: (transfer full): the RTP socket or %NULL if no socket could be + * allocated for @family. Unref after usage */ GSocket * gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family) @@ -2220,8 +2220,8 @@ gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family) * * @stream must be joined to a bin. * - * Returns: the RTCP socket or %NULL if no socket could be allocated for - * @family. Unref after usage + * Returns: (transfer full): the RTCP socket or %NULL if no socket could be + * allocated for @family. Unref after usage */ GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) From 48b6b8e3e60369347972298aa96546912970ada5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 3 Mar 2014 12:17:48 +0100 Subject: [PATCH 0925/1776] stream: release some locks in error cases --- gst/rtsp-server/rtsp-stream.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index ec82a1f2d2..fb200901a7 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -597,16 +597,19 @@ gst_rtsp_stream_is_transport_supported (GstRTSPStream * stream, unsupported_transmode: { GST_DEBUG ("unsupported transport mode %d", transport->trans); + g_mutex_unlock (&priv->lock); return FALSE; } unsupported_profile: { GST_DEBUG ("unsupported profile %d", transport->profile); + g_mutex_unlock (&priv->lock); return FALSE; } unsupported_ltrans: { GST_DEBUG ("unsupported lower transport %d", transport->lower_transport); + g_mutex_unlock (&priv->lock); return FALSE; } } @@ -1854,6 +1857,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, was_not_joined: { + g_mutex_unlock (&priv->lock); return TRUE; } } From 21144cb6e262ddd53f19b25dc08c09679fa0af2d Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Sun, 2 Mar 2014 05:12:01 +0100 Subject: [PATCH 0926/1776] .gitignore: Ignore gcov intermediate files Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725484 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 86dd0f4f5d..6a74704b4a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ *.sw[po] *.tar.* *~ +*.gc?? .deps .libs ABOUT-NLS From 2bd90b539cb6446980e43e288401c06480859b37 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 3 Mar 2014 15:12:55 +0100 Subject: [PATCH 0927/1776] sdp: pass multicast connection for multicast-only stream Pass the multicast address of the stream in the connection info in the SDP so that clients try a multicast connection first. Only allow multicast connections in the test-multicast example. Also increase the TTL a little. --- examples/test-multicast.c | 5 ++++- gst/rtsp-server/rtsp-sdp.c | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/examples/test-multicast.c b/examples/test-multicast.c index 6d4234e268..c7d55fcbb4 100644 --- a/examples/test-multicast.c +++ b/examples/test-multicast.c @@ -70,8 +70,11 @@ main (int argc, char *argv[]) /* make a new address pool */ pool = gst_rtsp_address_pool_new (); gst_rtsp_address_pool_add_range (pool, - "224.3.0.0", "224.3.0.10", 5000, 5010, 1); + "224.3.0.0", "224.3.0.10", 5000, 5010, 16); gst_rtsp_media_factory_set_address_pool (factory, pool); + /* only allow multicast */ + gst_rtsp_media_factory_set_protocols (factory, + GST_RTSP_LOWER_TRANS_UDP_MCAST); g_object_unref (pool); /* attach the test factory to the /test url */ diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index be94d19b55..e2e98bc1c2 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -108,6 +108,11 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, gboolean first; GString *fmtp; GstCaps *caps; + GstRTSPLowerTrans ltrans; + GSocketFamily family; + const gchar *addrtype; + gchar *address; + guint ttl; stream = gst_rtsp_media_get_stream (media, i); caps = gst_rtsp_stream_get_caps (stream); @@ -138,13 +143,40 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, gst_sdp_media_set_port_info (smedia, 0, 1); gst_sdp_media_set_proto (smedia, "RTP/AVP"); - /* for the c= line */ if (info->is_ipv6) { - gst_sdp_media_add_connection (smedia, "IN", "IP6", "::", 16, 0); + addrtype = "IP6"; + family = G_SOCKET_FAMILY_IPV6; } else { - gst_sdp_media_add_connection (smedia, "IN", "IP4", "0.0.0.0", 16, 0); + addrtype = "IP4"; + family = G_SOCKET_FAMILY_IPV4; } + ltrans = gst_rtsp_stream_get_protocols (stream); + if (ltrans == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + GstRTSPAddress *addr; + + addr = gst_rtsp_stream_get_multicast_address (stream, family); + if (addr == NULL) { + gst_sdp_media_free (smedia); + gst_caps_unref (caps); + g_warning ("ignoring stream %d without multicast address", i); + continue; + } + address = g_strdup (addr->address); + ttl = addr->ttl; + gst_rtsp_address_free (addr); + } else { + ttl = 16; + if (info->is_ipv6) + address = g_strdup ("::"); + else + address = g_strdup ("0.0.0.0"); + } + + /* for the c= line */ + gst_sdp_media_add_connection (smedia, "IN", addrtype, address, ttl, 1); + g_free (address); + /* get clock-rate, media type and params for the rtpmap attribute */ gst_structure_get_int (s, "clock-rate", &caps_rate); caps_enc = gst_structure_get_string (s, "encoding-name"); From 4b74afcc78b25996d03f16d5b52fa0888e6e6973 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 3 Mar 2014 16:55:48 +0100 Subject: [PATCH 0928/1776] factory: add profile property and pass to media and streams --- gst/rtsp-server/rtsp-media-factory.c | 70 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 4 ++ gst/rtsp-server/rtsp-media.c | 1 + 3 files changed, 75 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index b8a781cea5..2d2800b4d6 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -53,6 +53,7 @@ struct _GstRTSPMediaFactoryPrivate gboolean shared; GstRTSPSuspendMode suspend_mode; gboolean eos_shutdown; + GstRTSPProfile profiles; GstRTSPLowerTrans protocols; guint buffer_size; GstRTSPAddressPool *pool; @@ -65,6 +66,7 @@ struct _GstRTSPMediaFactoryPrivate #define DEFAULT_SHARED FALSE #define DEFAULT_SUSPEND_MODE GST_RTSP_SUSPEND_MODE_NONE #define DEFAULT_EOS_SHUTDOWN FALSE +#define DEFAULT_PROFILES GST_RTSP_PROFILE_AVP #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_BUFFER_SIZE 0x80000 @@ -76,6 +78,7 @@ enum PROP_SHARED, PROP_SUSPEND_MODE, PROP_EOS_SHUTDOWN, + PROP_PROFILES, PROP_PROTOCOLS, PROP_BUFFER_SIZE, PROP_LAST @@ -161,6 +164,11 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "Send EOS down the pipeline before shutting down", DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PROFILES, + g_param_spec_flags ("profiles", "Profiles", + "Allowed transfer profiles", GST_TYPE_RTSP_PROFILE, + DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PROTOCOLS, g_param_spec_flags ("protocols", "Protocols", "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS, @@ -204,6 +212,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->shared = DEFAULT_SHARED; priv->suspend_mode = DEFAULT_SUSPEND_MODE; priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN; + priv->profiles = DEFAULT_PROFILES; priv->protocols = DEFAULT_PROTOCOLS; priv->buffer_size = DEFAULT_BUFFER_SIZE; @@ -252,6 +261,9 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_boolean (value, gst_rtsp_media_factory_is_eos_shutdown (factory)); break; + case PROP_PROFILES: + g_value_set_flags (value, gst_rtsp_media_factory_get_profiles (factory)); + break; case PROP_PROTOCOLS: g_value_set_flags (value, gst_rtsp_media_factory_get_protocols (factory)); break; @@ -285,6 +297,9 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_eos_shutdown (factory, g_value_get_boolean (value)); break; + case PROP_PROFILES: + gst_rtsp_media_factory_set_profiles (factory, g_value_get_flags (value)); + break; case PROP_PROTOCOLS: gst_rtsp_media_factory_set_protocols (factory, g_value_get_flags (value)); break; @@ -706,6 +721,56 @@ gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_set_profiles: + * @factory: a #GstRTSPMediaFactory + * @profiles: the new flags + * + * Configure the allowed profiles for @factory. + */ +void +gst_rtsp_media_factory_set_profiles (GstRTSPMediaFactory * factory, + GstRTSPProfile profiles) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + priv = factory->priv; + + GST_DEBUG_OBJECT (factory, "profiles %d", profiles); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv->profiles = profiles; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_profiles: + * @factory: a #GstRTSPMediaFactory + * + * Get the allowed profiles of @factory. + * + * Returns: a #GstRTSPProfile + */ +GstRTSPProfile +gst_rtsp_media_factory_get_profiles (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + GstRTSPProfile res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), + GST_RTSP_PROFILE_UNKNOWN); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + res = priv->profiles; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return res; +} + /** * gst_rtsp_media_factory_set_protocols: * @factory: a #GstRTSPMediaFactory @@ -723,6 +788,8 @@ gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * factory, priv = factory->priv; + GST_DEBUG_OBJECT (factory, "protocols %d", protocols); + GST_RTSP_MEDIA_FACTORY_LOCK (factory); priv->protocols = protocols; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); @@ -1012,6 +1079,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gboolean shared, eos_shutdown; guint size; GstRTSPSuspendMode suspend_mode; + GstRTSPProfile profiles; GstRTSPLowerTrans protocols; GstRTSPAddressPool *pool; GstRTSPPermissions *perms; @@ -1022,6 +1090,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) shared = priv->shared; eos_shutdown = priv->eos_shutdown; size = priv->buffer_size; + profiles = priv->profiles; protocols = priv->protocols; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); @@ -1029,6 +1098,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_shared (media, shared); gst_rtsp_media_set_eos_shutdown (media, eos_shutdown); gst_rtsp_media_set_buffer_size (media, size); + gst_rtsp_media_set_profiles (media, profiles); gst_rtsp_media_set_protocols (media, protocols); if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) { diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 11aaaeb81c..bb6aec34d1 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -126,6 +126,10 @@ void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFacto gboolean eos_shutdown); gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_profiles (GstRTSPMediaFactory *factory, + GstRTSPProfile profiles); +GstRTSPProfile gst_rtsp_media_factory_get_profiles (GstRTSPMediaFactory *factory); + void gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory *factory, GstRTSPLowerTrans protocols); GstRTSPLowerTrans gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory *factory); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 36626da312..c80af1dd2d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1250,6 +1250,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, stream = gst_rtsp_stream_new (idx, payloader, srcpad); if (priv->pool) gst_rtsp_stream_set_address_pool (stream, priv->pool); + gst_rtsp_stream_set_profiles (stream, priv->profiles); gst_rtsp_stream_set_protocols (stream, priv->protocols); g_ptr_array_add (priv->streams, stream); From dffdbbf0906201ec6d6711d1e80e6245182d517c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 3 Mar 2014 16:56:53 +0100 Subject: [PATCH 0929/1776] sdp: make 1 media line per profile If we have multiple profiles (AVP or AVPF) for a stream, make one m= line in the SDP for each profile. The client is then supposed to pick one of the profiles in the SETUP request. Because the m= lines have the same pt, the client also knows that only 1 option is possible. --- gst/rtsp-server/rtsp-sdp.c | 320 +++++++++++++++++++++---------------- 1 file changed, 183 insertions(+), 137 deletions(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index e2e98bc1c2..80ddf10038 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -70,6 +70,178 @@ update_sdp_from_tags (GstRTSPStream * stream, GstSDPMedia * stream_media) gst_object_unref (src_pad); } +static void +make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, + GstRTSPStream * stream, GstStructure * s, GstRTSPProfile profile) +{ + GstSDPMedia *smedia; + const gchar *caps_str, *caps_enc, *caps_params; + gchar *tmp; + gint caps_pt, caps_rate; + guint n_fields, j; + gboolean first; + GString *fmtp; + GstRTSPLowerTrans ltrans; + GSocketFamily family; + const gchar *addrtype, *proto; + gchar *address; + guint ttl; + + gst_sdp_media_new (&smedia); + + /* get media type and payload for the m= line */ + caps_str = gst_structure_get_string (s, "media"); + gst_sdp_media_set_media (smedia, caps_str); + + gst_structure_get_int (s, "payload", &caps_pt); + tmp = g_strdup_printf ("%d", caps_pt); + gst_sdp_media_add_format (smedia, tmp); + g_free (tmp); + + gst_sdp_media_set_port_info (smedia, 0, 1); + + switch (profile) { + case GST_RTSP_PROFILE_AVP: + proto = "RTP/AVP"; + break; + case GST_RTSP_PROFILE_AVPF: + proto = "RTP/AVPF"; + break; + case GST_RTSP_PROFILE_SAVP: + proto = "RTP/SAVP"; + break; + case GST_RTSP_PROFILE_SAVPF: + proto = "RTP/SAVPF"; + break; + default: + proto = "udp"; + break; + } + gst_sdp_media_set_proto (smedia, proto); + + if (info->is_ipv6) { + addrtype = "IP6"; + family = G_SOCKET_FAMILY_IPV6; + } else { + addrtype = "IP4"; + family = G_SOCKET_FAMILY_IPV4; + } + + ltrans = gst_rtsp_stream_get_protocols (stream); + if (ltrans == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + GstRTSPAddress *addr; + + addr = gst_rtsp_stream_get_multicast_address (stream, family); + if (addr == NULL) + goto no_multicast; + + address = g_strdup (addr->address); + ttl = addr->ttl; + gst_rtsp_address_free (addr); + } else { + ttl = 16; + if (info->is_ipv6) + address = g_strdup ("::"); + else + address = g_strdup ("0.0.0.0"); + } + + /* for the c= line */ + gst_sdp_media_add_connection (smedia, "IN", addrtype, address, ttl, 1); + g_free (address); + + /* get clock-rate, media type and params for the rtpmap attribute */ + gst_structure_get_int (s, "clock-rate", &caps_rate); + caps_enc = gst_structure_get_string (s, "encoding-name"); + caps_params = gst_structure_get_string (s, "encoding-params"); + + if (caps_enc) { + if (caps_params) + tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate, + caps_params); + else + tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate); + + gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); + g_free (tmp); + } + + /* the config uri */ + tmp = gst_rtsp_stream_get_control (stream); + gst_sdp_media_add_attribute (smedia, "control", tmp); + g_free (tmp); + + /* collect all other properties and add them to fmtp or attributes */ + fmtp = g_string_new (""); + g_string_append_printf (fmtp, "%d ", caps_pt); + first = TRUE; + n_fields = gst_structure_n_fields (s); + for (j = 0; j < n_fields; j++) { + const gchar *fname, *fval; + + fname = gst_structure_nth_field_name (s, j); + + /* filter out standard properties */ + if (!strcmp (fname, "media")) + continue; + if (!strcmp (fname, "payload")) + continue; + if (!strcmp (fname, "clock-rate")) + continue; + if (!strcmp (fname, "encoding-name")) + continue; + if (!strcmp (fname, "encoding-params")) + continue; + if (!strcmp (fname, "ssrc")) + continue; + if (!strcmp (fname, "clock-base")) + continue; + if (!strcmp (fname, "seqnum-base")) + continue; + + if (g_str_has_prefix (fname, "a-")) { + /* attribute */ + if ((fval = gst_structure_get_string (s, fname))) + gst_sdp_media_add_attribute (smedia, fname + 2, fval); + continue; + } + if (g_str_has_prefix (fname, "x-")) { + /* attribute */ + if ((fval = gst_structure_get_string (s, fname))) + gst_sdp_media_add_attribute (smedia, fname, fval); + continue; + } + + if ((fval = gst_structure_get_string (s, fname))) { + g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval); + first = FALSE; + } + } + if (!first) { + tmp = g_string_free (fmtp, FALSE); + gst_sdp_media_add_attribute (smedia, "fmtp", tmp); + g_free (tmp); + } else { + g_string_free (fmtp, TRUE); + } + + update_sdp_from_tags (stream, smedia); + + gst_sdp_message_add_media (sdp, smedia); + gst_sdp_media_free (smedia); + + return; + + /* ERRORS */ +no_multicast: + { + gst_sdp_media_free (smedia); + g_warning ("ignoring stream %d without multicast address", + gst_rtsp_stream_get_index (stream)); + return; + } +} + /** * gst_rtsp_sdp_from_media: * @sdp: a #GstSDPMessage @@ -99,20 +271,10 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, for (i = 0; i < n_streams; i++) { GstRTSPStream *stream; - GstSDPMedia *smedia; - GstStructure *s; - const gchar *caps_str, *caps_enc, *caps_params; - gchar *tmp; - gint caps_pt, caps_rate; - guint n_fields, j; - gboolean first; - GString *fmtp; GstCaps *caps; - GstRTSPLowerTrans ltrans; - GSocketFamily family; - const gchar *addrtype; - gchar *address; - guint ttl; + GstStructure *s; + GstRTSPProfile profiles; + guint mask; stream = gst_rtsp_media_get_stream (media, i); caps = gst_rtsp_stream_get_caps (stream); @@ -129,133 +291,17 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, continue; } - gst_sdp_media_new (&smedia); + /* make a new media for each profile */ + profiles = gst_rtsp_stream_get_profiles (stream); + mask = 1; + while (profiles >= mask) { + GstRTSPProfile prof = profiles & mask; - /* get media type and payload for the m= line */ - caps_str = gst_structure_get_string (s, "media"); - gst_sdp_media_set_media (smedia, caps_str); + if (prof) + make_media (sdp, info, media, stream, s, prof); - gst_structure_get_int (s, "payload", &caps_pt); - tmp = g_strdup_printf ("%d", caps_pt); - gst_sdp_media_add_format (smedia, tmp); - g_free (tmp); - - gst_sdp_media_set_port_info (smedia, 0, 1); - gst_sdp_media_set_proto (smedia, "RTP/AVP"); - - if (info->is_ipv6) { - addrtype = "IP6"; - family = G_SOCKET_FAMILY_IPV6; - } else { - addrtype = "IP4"; - family = G_SOCKET_FAMILY_IPV4; + mask <<= 1; } - - ltrans = gst_rtsp_stream_get_protocols (stream); - if (ltrans == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - GstRTSPAddress *addr; - - addr = gst_rtsp_stream_get_multicast_address (stream, family); - if (addr == NULL) { - gst_sdp_media_free (smedia); - gst_caps_unref (caps); - g_warning ("ignoring stream %d without multicast address", i); - continue; - } - address = g_strdup (addr->address); - ttl = addr->ttl; - gst_rtsp_address_free (addr); - } else { - ttl = 16; - if (info->is_ipv6) - address = g_strdup ("::"); - else - address = g_strdup ("0.0.0.0"); - } - - /* for the c= line */ - gst_sdp_media_add_connection (smedia, "IN", addrtype, address, ttl, 1); - g_free (address); - - /* get clock-rate, media type and params for the rtpmap attribute */ - gst_structure_get_int (s, "clock-rate", &caps_rate); - caps_enc = gst_structure_get_string (s, "encoding-name"); - caps_params = gst_structure_get_string (s, "encoding-params"); - - if (caps_enc) { - if (caps_params) - tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate, - caps_params); - else - tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate); - - gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); - g_free (tmp); - } - - /* the config uri */ - tmp = gst_rtsp_stream_get_control (stream); - gst_sdp_media_add_attribute (smedia, "control", tmp); - g_free (tmp); - - /* collect all other properties and add them to fmtp or attributes */ - fmtp = g_string_new (""); - g_string_append_printf (fmtp, "%d ", caps_pt); - first = TRUE; - n_fields = gst_structure_n_fields (s); - for (j = 0; j < n_fields; j++) { - const gchar *fname, *fval; - - fname = gst_structure_nth_field_name (s, j); - - /* filter out standard properties */ - if (!strcmp (fname, "media")) - continue; - if (!strcmp (fname, "payload")) - continue; - if (!strcmp (fname, "clock-rate")) - continue; - if (!strcmp (fname, "encoding-name")) - continue; - if (!strcmp (fname, "encoding-params")) - continue; - if (!strcmp (fname, "ssrc")) - continue; - if (!strcmp (fname, "clock-base")) - continue; - if (!strcmp (fname, "seqnum-base")) - continue; - - if (g_str_has_prefix (fname, "a-")) { - /* attribute */ - if ((fval = gst_structure_get_string (s, fname))) - gst_sdp_media_add_attribute (smedia, fname + 2, fval); - continue; - } - if (g_str_has_prefix (fname, "x-")) { - /* attribute */ - if ((fval = gst_structure_get_string (s, fname))) - gst_sdp_media_add_attribute (smedia, fname, fval); - continue; - } - - if ((fval = gst_structure_get_string (s, fname))) { - g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval); - first = FALSE; - } - } - if (!first) { - tmp = g_string_free (fmtp, FALSE); - gst_sdp_media_add_attribute (smedia, "fmtp", tmp); - g_free (tmp); - } else { - g_string_free (fmtp, TRUE); - } - - update_sdp_from_tags (stream, smedia); - - gst_sdp_message_add_media (sdp, smedia); - gst_sdp_media_free (smedia); gst_caps_unref (caps); } From faf0b31cbbdeba09217027fb9133946a3a72cf05 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Thu, 6 Mar 2014 13:52:02 +0100 Subject: [PATCH 0930/1776] rtsp-client: vmethod for modifying tunnel GET response Add a vmethod tunnel_http_response where the response to the HTTP GET for tunneled connections can be modified. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725879 --- gst/rtsp-server/rtsp-client.c | 19 ++++++++++++++++++- gst/rtsp-server/rtsp-client.h | 6 +++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1a3fa45e0a..5ccc5b4171 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2821,6 +2821,22 @@ tunnel_closed: } } +static GstRTSPResult +tunnel_http_response (GstRTSPWatch * watch, GstRTSPMessage * request, + GstRTSPMessage * response, gpointer user_data) +{ + GstRTSPClientClass *klass; + + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + klass = GST_RTSP_CLIENT_GET_CLASS (client); + + if (klass->tunnel_http_response) { + klass->tunnel_http_response (client, request, response); + } + + return GST_RTSP_OK; +} + static GstRTSPWatchFuncs watch_funcs = { message_received, message_sent, @@ -2829,7 +2845,8 @@ static GstRTSPWatchFuncs watch_funcs = { tunnel_start, tunnel_complete, error_full, - tunnel_lost + tunnel_lost, + tunnel_http_response }; static void diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 17086e5c00..01f820826d 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -85,6 +85,8 @@ struct _GstRTSPClient { * RTSP response(ctx->response) via a call to gst_rtsp_message_init_response() * @params_get: get parameters. This function should also initialize the * RTSP response(ctx->response) via a call to gst_rtsp_message_init_response() + * @tunnel_http_response: called when a response to the GET request is about to + * be sent for a tunneled connection. The response can be modified. Since 1.4 * * The client class structure. */ @@ -115,8 +117,10 @@ struct _GstRTSPClientClass { void (*get_parameter_request) (GstRTSPClient *client, GstRTSPContext *ctx); void (*handle_response) (GstRTSPClient *client, GstRTSPContext *ctx); + void (*tunnel_http_response) (GstRTSPClient * client, GstRTSPMessage * request, + GstRTSPMessage * response); /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE]; + gpointer _gst_reserved[GST_PADDING_LARGE-1]; }; GType gst_rtsp_client_get_type (void); From 50ca10e7513326d591fa88d87ac42f2bc381c762 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 13 Mar 2014 14:20:17 +0100 Subject: [PATCH 0931/1776] stream: release lock while pushing out packets Keep a cache of the transports and use this to iterate the transport while pushing packets. This allows us to release the lock early. See https://bugzilla.gnome.org/show_bug.cgi?id=725898 --- gst/rtsp-server/rtsp-stream.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index fb200901a7..be6bd158aa 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -119,6 +119,8 @@ struct _GstRTSPStreamPrivate /* transports we stream to */ guint n_active; GList *transports; + gboolean tr_changed; + GList *tr_cache; gint dscp_qos; @@ -1442,6 +1444,14 @@ on_timeout (GObject * session, GObject * source, GstRTSPStream * stream) } } +static void +clear_tr_cache (GstRTSPStreamPrivate * priv) +{ + g_list_foreach (priv->tr_cache, (GFunc) g_object_unref, NULL); + g_list_free (priv->tr_cache); + priv->tr_cache = NULL; +} + static GstFlowReturn handle_new_sample (GstAppSink * sink, gpointer user_data) { @@ -1450,6 +1460,7 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) GstSample *sample; GstBuffer *buffer; GstRTSPStream *stream; + gboolean is_rtp; sample = gst_app_sink_pull_sample (sink); if (!sample) @@ -1459,18 +1470,28 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) priv = stream->priv; buffer = gst_sample_get_buffer (sample); + is_rtp = GST_ELEMENT_CAST (sink) == priv->appsink[0]; + g_mutex_lock (&priv->lock); - for (walk = priv->transports; walk; walk = g_list_next (walk)) { + if (priv->tr_changed) { + clear_tr_cache (priv); + for (walk = priv->transports; walk; walk = g_list_next (walk)) { + GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; + priv->tr_cache = g_list_prepend (priv->tr_cache, g_object_ref (tr)); + } + priv->tr_changed = FALSE; + } + g_mutex_unlock (&priv->lock); + + for (walk = priv->tr_cache; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - if (GST_ELEMENT_CAST (sink) == priv->appsink[0]) { + if (is_rtp) { gst_rtsp_stream_transport_send_rtp (tr, buffer); } else { gst_rtsp_stream_transport_send_rtcp (tr, buffer); } } - g_mutex_unlock (&priv->lock); - gst_sample_unref (sample); return GST_FLOW_OK; @@ -1777,6 +1798,8 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, /* all transports must be removed by now */ g_return_val_if_fail (priv->transports == NULL, FALSE); + clear_tr_cache (priv); + GST_INFO ("stream %p leaving bin", stream); gst_pad_unlink (priv->srcpad, priv->send_rtp_sink); @@ -2090,6 +2113,7 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, g_signal_emit_by_name (priv->udpsink[1], "remove", dest, max, NULL); priv->transports = g_list_remove (priv->transports, trans); } + priv->tr_changed = TRUE; break; } case GST_RTSP_LOWER_TRANS_TCP: @@ -2100,6 +2124,7 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, GST_INFO ("removing TCP %s", tr->destination); priv->transports = g_list_remove (priv->transports, trans); } + priv->tr_changed = TRUE; break; default: goto unknown_transport; From 2c7ffe97ca73d573d62e64336cff1e9fa5bfbb14 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 13 Mar 2014 14:27:15 +0100 Subject: [PATCH 0932/1776] stream: take caps after the session manager Take the caps for the SDP after they leave the rtpbin so that we can also get the properties added by rtpbin elements. --- gst/rtsp-server/rtsp-stream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index be6bd158aa..d4d1dbe992 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1738,7 +1738,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, } /* be notified of caps changes */ - priv->caps_sig = g_signal_connect (priv->send_rtp_sink, "notify::caps", + priv->caps_sig = g_signal_connect (priv->send_src[0], "notify::caps", (GCallback) caps_notify, stream); priv->is_joined = TRUE; @@ -1803,7 +1803,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, GST_INFO ("stream %p leaving bin", stream); gst_pad_unlink (priv->srcpad, priv->send_rtp_sink); - g_signal_handler_disconnect (priv->send_rtp_sink, priv->caps_sig); + g_signal_handler_disconnect (priv->send_src[0], priv->caps_sig); gst_element_release_request_pad (rtpbin, priv->send_rtp_sink); gst_object_unref (priv->send_rtp_sink); priv->send_rtp_sink = NULL; From 0b617dd5bd4311c863d37defd2e5b8c3949e861c Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Fri, 14 Mar 2014 19:03:24 +0100 Subject: [PATCH 0933/1776] rtsp-stream: Don't mix IPv4 and IPv6 addresses Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726362 --- gst/rtsp-server/rtsp-stream.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index d4d1dbe992..655545eb17 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -793,10 +793,10 @@ gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, if (family == G_SOCKET_FAMILY_IPV6) { flags = GST_RTSP_ADDRESS_FLAG_IPV6; - addrp = &priv->addr_v4; + addrp = &priv->addr_v6; } else { flags = GST_RTSP_ADDRESS_FLAG_IPV4; - addrp = &priv->addr_v6; + addrp = &priv->addr_v4; } g_mutex_lock (&priv->lock); @@ -871,9 +871,9 @@ gst_rtsp_stream_reserve_address (GstRTSPStream * stream, } if (family == G_SOCKET_FAMILY_IPV6) - addrp = &priv->addr_v4; - else addrp = &priv->addr_v6; + else + addrp = &priv->addr_v4; g_mutex_lock (&priv->lock); if (*addrp == NULL) { From b1b530157709d09590790da2f439e38c46b2c047 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Sun, 23 Mar 2014 21:24:48 +0100 Subject: [PATCH 0934/1776] gobject-introspection: Add annotations to support language bindings In addition a few cosmetic changes: * Adjust the order of arguments * Fix typo: occured -> occurred * Fix indentation after Return:-clauses Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726941 --- gst/rtsp-server/rtsp-address-pool.c | 4 +-- gst/rtsp-server/rtsp-auth.c | 12 ++++---- gst/rtsp-server/rtsp-client.c | 22 +++++++-------- gst/rtsp-server/rtsp-media-factory-uri.c | 4 +-- gst/rtsp-server/rtsp-media-factory.c | 9 +++--- gst/rtsp-server/rtsp-media.c | 22 +++++++-------- gst/rtsp-server/rtsp-mount-points.c | 6 ++-- gst/rtsp-server/rtsp-params.c | 4 +-- gst/rtsp-server/rtsp-permissions.c | 3 +- gst/rtsp-server/rtsp-sdp.c | 4 +-- gst/rtsp-server/rtsp-server.c | 35 +++++++++++++----------- gst/rtsp-server/rtsp-session-media.c | 12 ++++---- gst/rtsp-server/rtsp-session-pool.c | 12 +++++--- gst/rtsp-server/rtsp-session.c | 14 ++++++---- gst/rtsp-server/rtsp-stream-transport.c | 24 ++++++++-------- gst/rtsp-server/rtsp-stream.c | 35 ++++++++++++------------ gst/rtsp-server/rtsp-thread-pool.c | 10 +++---- gst/rtsp-server/rtsp-token.c | 19 +++++++------ 18 files changed, 132 insertions(+), 119 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index c6ba13d567..92f4c42453 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -181,7 +181,7 @@ gst_rtsp_address_pool_finalize (GObject * obj) * * Make a new #GstRTSPAddressPool. * - * Returns: a new #GstRTSPAddressPool + * Returns: (transfer full): a new #GstRTSPAddressPool */ GstRTSPAddressPool * gst_rtsp_address_pool_new (void) @@ -424,7 +424,7 @@ split_range (GstRTSPAddressPool * pool, AddrRange * range, guint skip_addr, * one can be found in @port. * * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free - * after use or %NULL when no address could be acquired. + * after use or %NULL when no address could be acquired. */ GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index e987e17258..b0e924e72d 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -161,7 +161,7 @@ gst_rtsp_auth_set_property (GObject * object, guint propid, * * Create a new #GstRTSPAuth instance. * - * Returns: a new #GstRTSPAuth + * Returns: (transfer full): a new #GstRTSPAuth */ GstRTSPAuth * gst_rtsp_auth_new (void) @@ -176,7 +176,7 @@ gst_rtsp_auth_new (void) /** * gst_rtsp_auth_set_tls_certificate: * @auth: a #GstRTSPAuth - * @cert: (allow-none): a #GTlsCertificate + * @cert: (transfer none) (allow-none): a #GTlsCertificate * * Set the TLS certificate for the auth. Client connections will only * be accepted when TLS is negotiated. @@ -233,7 +233,7 @@ gst_rtsp_auth_get_tls_certificate (GstRTSPAuth * auth) /** * gst_rtsp_auth_set_default_token: * @auth: a #GstRTSPAuth - * @token: (allow-none): a #GstRTSPToken + * @token: (transfer none) (allow-none): a #GstRTSPToken * * Set the default #GstRTSPToken to @token in @auth. The default token will * be used for unauthenticated users. @@ -292,7 +292,7 @@ gst_rtsp_auth_get_default_token (GstRTSPAuth * auth) * gst_rtsp_auth_add_basic: * @auth: a #GstRTSPAuth * @basic: the basic token - * @token: authorisation token + * @token: (transfer none): authorisation token * * Add a basic token for the default authentication algorithm that * enables the client with privileges listed in @token. @@ -616,8 +616,8 @@ no_context: * * Construct a Basic authorisation token from @user and @pass. * - * Returns: the base64 encoding of the string @user:@pass. g_free() - * after usage. + * Returns: (transfer full): the base64 encoding of the string @user:@pass. + * g_free() after usage. */ gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 5ccc5b4171..99aa85abfd 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -412,7 +412,7 @@ gst_rtsp_client_set_property (GObject * object, guint propid, * * Create a new #GstRTSPClient instance. * - * Returns: a new #GstRTSPClient + * Returns: (transfer full): a new #GstRTSPClient */ GstRTSPClient * gst_rtsp_client_new (void) @@ -2199,7 +2199,7 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) /** * gst_rtsp_client_set_session_pool: * @client: a #GstRTSPClient - * @pool: a #GstRTSPSessionPool + * @pool: (transfer none): a #GstRTSPSessionPool * * Set @pool as the sessionpool for @client which it will use to find * or allocate sessions. the sessionpool is usually inherited from the server @@ -2257,7 +2257,7 @@ gst_rtsp_client_get_session_pool (GstRTSPClient * client) /** * gst_rtsp_client_set_mount_points: * @client: a #GstRTSPClient - * @mounts: a #GstRTSPMountPoints + * @mounts: (transfer none): a #GstRTSPMountPoints * * Set @mounts as the mount points for @client which it will use to map urls * to media streams. These mount points are usually inherited from the server that @@ -2315,7 +2315,7 @@ gst_rtsp_client_get_mount_points (GstRTSPClient * client) /** * gst_rtsp_client_set_auth: * @client: a #GstRTSPClient - * @auth: a #GstRTSPAuth + * @auth: (transfer none): a #GstRTSPAuth * * configure @auth to be used as the authentication manager of @client. */ @@ -2372,7 +2372,7 @@ gst_rtsp_client_get_auth (GstRTSPClient * client) /** * gst_rtsp_client_set_thread_pool: * @client: a #GstRTSPClient - * @pool: a #GstRTSPThreadPool + * @pool: (transfer none): a #GstRTSPThreadPool * * configure @pool to be used as the thread pool of @client. */ @@ -2511,9 +2511,9 @@ gst_rtsp_client_get_connection (GstRTSPClient * client) /** * gst_rtsp_client_set_send_func: * @client: a #GstRTSPClient - * @func: a #GstRTSPClientSendFunc - * @user_data: user data passed to @func - * @notify: called when @user_data is no longer in use + * @func: (scope notified): a #GstRTSPClientSendFunc + * @user_data: (closure): user data passed to @func + * @notify: (allow-none): called when @user_data is no longer in use * * Set @func as the callback that will be called when a new message needs to be * sent to the client. @user_data is passed to @func and @notify is called when @@ -2549,7 +2549,7 @@ gst_rtsp_client_set_send_func (GstRTSPClient * client, /** * gst_rtsp_client_handle_message: * @client: a #GstRTSPClient - * @message: an #GstRTSPMessage + * @message: (transfer none): an #GstRTSPMessage * * Let the client handle @message. * @@ -2581,8 +2581,8 @@ gst_rtsp_client_handle_message (GstRTSPClient * client, /** * gst_rtsp_client_send_message: * @client: a #GstRTSPClient - * @session: a #GstRTSPSession to send the message to or %NULL - * @message: The #GstRTSPMessage to send + * @session: (transfer none): a #GstRTSPSession to send the message to or %NULL + * @message: (transfer none): The #GstRTSPMessage to send * * Send a message message to the remote end. @message must be a * #GST_RTSP_MESSAGE_REQUEST or a #GST_RTSP_MESSAGE_RESPONSE. diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 702987b577..01f3f990b2 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -276,7 +276,7 @@ gst_rtsp_media_factory_uri_set_property (GObject * object, guint propid, * * Create a new #GstRTSPMediaFactoryURI instance. * - * Returns: a new #GstRTSPMediaFactoryURI object. + * Returns: (transfer full): a new #GstRTSPMediaFactoryURI object. */ GstRTSPMediaFactoryURI * gst_rtsp_media_factory_uri_new (void) @@ -318,7 +318,7 @@ gst_rtsp_media_factory_uri_set_uri (GstRTSPMediaFactoryURI * factory, * * Get the URI that will provide media for this factory. * - * Returns: the configured URI. g_free() after usage. + * Returns: (transfer full): the configured URI. g_free() after usage. */ gchar * gst_rtsp_media_factory_uri_get_uri (GstRTSPMediaFactoryURI * factory) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 2d2800b4d6..b78e44e7eb 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -317,7 +317,7 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, * * Create a new #GstRTSPMediaFactory instance. * - * Returns: a new #GstRTSPMediaFactory object. + * Returns: (transfer full): a new #GstRTSPMediaFactory object. */ GstRTSPMediaFactory * gst_rtsp_media_factory_new (void) @@ -332,7 +332,7 @@ gst_rtsp_media_factory_new (void) /** * gst_rtsp_media_factory_set_permissions: * @factory: a #GstRTSPMediaFactory - * @permissions: a #GstRTSPPermissions + * @permissions: (transfer none): a #GstRTSPPermissions * * Set @permissions on @factory. */ @@ -455,7 +455,8 @@ gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory, * Get the gst_parse_launch() pipeline description that will be used in the * default prepare vmethod. * - * Returns: the configured launch description. g_free() after usage. + * Returns: (transfer full): the configured launch description. g_free() after + * usage. */ gchar * gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory) @@ -668,7 +669,7 @@ gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory) /** * gst_rtsp_media_factory_set_address_pool: * @factory: a #GstRTSPMediaFactory - * @pool: a #GstRTSPAddressPool + * @pool: (transfer none): a #GstRTSPAddressPool * * configure @pool to be used as the address pool of @factory. */ diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c80af1dd2d..fa9821a38c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -563,7 +563,7 @@ collect_media_stats (GstRTSPMedia * media) * * Ownership is taken of @element. * - * Returns: a new #GstRTSPMedia object. + * Returns: (transfer full): a new #GstRTSPMedia object. */ GstRTSPMedia * gst_rtsp_media_new (GstElement * element) @@ -632,7 +632,7 @@ gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline) /** * gst_rtsp_media_set_permissions: * @media: a #GstRTSPMedia - * @permissions: a #GstRTSPPermissions + * @permissions: (transfer none): a #GstRTSPPermissions * * Set @permissions on @media. */ @@ -1089,7 +1089,7 @@ gst_rtsp_media_is_time_provider (GstRTSPMedia * media) /** * gst_rtsp_media_set_address_pool: * @media: a #GstRTSPMedia - * @pool: a #GstRTSPAddressPool + * @pool: (transfer none): a #GstRTSPAddressPool * * configure @pool to be used as the address pool of @media. */ @@ -1217,7 +1217,7 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) * @srcpad should be a pad of an element inside @media->element. * * Returns: (transfer none): a new #GstRTSPStream that remains valid for as long - * as @media exists. + * as @media exists. */ GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, @@ -1397,7 +1397,7 @@ default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range, * Get the current range as a string. @media must be prepared with * gst_rtsp_media_prepare (). * - * Returns: The range as a string, g_free() after usage. + * Returns: (transfer full): The range as a string, g_free() after usage. */ gchar * gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play, @@ -1474,7 +1474,7 @@ media_streams_set_blocked (GstRTSPMedia * media, gboolean blocked) /** * gst_rtsp_media_seek: * @media: a #GstRTSPMedia - * @range: a #GstRTSPTimeRange + * @range: (transfer none): a #GstRTSPTimeRange * * Seek the pipeline of @media to @range. @media must be prepared with * gst_rtsp_media_prepare(). @@ -2116,7 +2116,7 @@ preroll_failed: /** * gst_rtsp_media_prepare: * @media: a #GstRTSPMedia - * @thread: a #GstRTSPThread to run the bus handler or %NULL + * @thread: (transfer full): a #GstRTSPThread to run the bus handler or %NULL * * Prepare @media for streaming. This function will create the objects * to manage the streaming. A pipeline must have been set on @media with @@ -2541,9 +2541,9 @@ default_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, GstSDPInfo * info) /** * gst_rtsp_media_setup_sdp: - * @sdp: a #GstSDPMessage - * @info: info * @media: a #GstRTSPMedia + * @sdp: (transfer none): a #GstSDPMessage + * @info: (transfer none): a #GstSDPInfo * * Add @media specific info to @sdp. @info is used to configure the connection * information in the SDP. @@ -2772,8 +2772,8 @@ gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state) * gst_rtsp_media_set_state: * @media: a #GstRTSPMedia * @state: the target state of the media - * @transports: (element-type GstRtspServer.RTSPStreamTransport): a #GPtrArray - * of #GstRTSPStreamTransport pointers + * @transports: (transfer none) (element-type GstRtspServer.RTSPStreamTransport): + * a #GPtrArray of #GstRTSPStreamTransport pointers * * Set the state of @media to @state and for the transports in @transports. * diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 2bddb648f0..75c872b1ec 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -156,7 +156,7 @@ gst_rtsp_mount_points_finalize (GObject * obj) * * Make a new mount points object. * - * Returns: a new #GstRTSPMountPoints + * Returns: (transfer full): a new #GstRTSPMountPoints */ GstRTSPMountPoints * gst_rtsp_mount_points_new (void) @@ -181,7 +181,7 @@ default_make_path (GstRTSPMountPoints * mounts, const GstRTSPUrl * url) * * Make a path string from @url. * - * Returns: a path string for @url, g_free() after usage. + * Returns: (transfer full): a path string for @url, g_free() after usage. */ gchar * gst_rtsp_mount_points_make_path (GstRTSPMountPoints * mounts, @@ -229,7 +229,7 @@ has_prefix (DataItem * str, DataItem * prefix) * the amount of characters that matched is returned in @matched. * * Returns: (transfer full): the #GstRTSPMediaFactory for @path. - * g_object_unref() after usage. + * g_object_unref() after usage. */ GstRTSPMediaFactory * gst_rtsp_mount_points_match (GstRTSPMountPoints * mounts, diff --git a/gst/rtsp-server/rtsp-params.c b/gst/rtsp-server/rtsp-params.c index ce18eaa11d..6025722760 100644 --- a/gst/rtsp-server/rtsp-params.c +++ b/gst/rtsp-server/rtsp-params.c @@ -31,7 +31,7 @@ /** * gst_rtsp_params_set: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (transfer none): a #GstRTSPContext * * Set parameters (not implemented yet) * @@ -55,7 +55,7 @@ gst_rtsp_params_set (GstRTSPClient * client, GstRTSPContext * ctx) /** * gst_rtsp_params_get: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (transfer none): a #GstRTSPContext * * Get parameters (not implemented yet) * diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index 2893308bff..66e9e44340 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -221,7 +221,8 @@ gst_rtsp_permissions_remove_role (GstRTSPPermissions * permissions, * * Get all permissions for @role in @permissions. * - * Returns: the structure with permissions for @role. + * Returns: (transfer none): the structure with permissions for @role. It + * remains valid for as long as @permissions is valid. */ const GstStructure * gst_rtsp_permissions_get_role (GstRTSPPermissions * permissions, diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 80ddf10038..53fc22c7b2 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -245,8 +245,8 @@ no_multicast: /** * gst_rtsp_sdp_from_media: * @sdp: a #GstSDPMessage - * @info: info - * @media: a #GstRTSPMedia + * @info: (transfer none): a #GstSDPInfo + * @media: (transfer none): a #GstRTSPMedia * * Add @media specific info to @sdp. @info is used to configure the connection * information in the SDP. diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index e9b5d812e5..019e379e89 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -283,6 +283,8 @@ gst_rtsp_server_finalize (GObject * object) * gst_rtsp_server_new: * * Create a new #GstRTSPServer instance. + * + * Returns: (transfer full): a new #GstRTSPServer */ GstRTSPServer * gst_rtsp_server_new (void) @@ -325,7 +327,7 @@ gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address) * * Get the address on which the server will accept connections. * - * Returns: the server address. g_free() after usage. + * Returns: (transfer full): the server address. g_free() after usage. */ gchar * gst_rtsp_server_get_address (GstRTSPServer * server) @@ -414,7 +416,7 @@ gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service) * * Get the service on which the server will accept connections. * - * Returns: the service. use g_free() after usage. + * Returns: (transfer full): the service. use g_free() after usage. */ gchar * gst_rtsp_server_get_service (GstRTSPServer * server) @@ -485,7 +487,7 @@ gst_rtsp_server_get_backlog (GstRTSPServer * server) /** * gst_rtsp_server_set_session_pool: * @server: a #GstRTSPServer - * @pool: a #GstRTSPSessionPool + * @pool: (transfer none): a #GstRTSPSessionPool * * configure @pool to be used as the session pool of @server. */ @@ -542,7 +544,7 @@ gst_rtsp_server_get_session_pool (GstRTSPServer * server) /** * gst_rtsp_server_set_mount_points: * @server: a #GstRTSPServer - * @mounts: a #GstRTSPMountPoints + * @mounts: (transfer none): a #GstRTSPMountPoints * * configure @mounts to be used as the mount points of @server. */ @@ -600,7 +602,7 @@ gst_rtsp_server_get_mount_points (GstRTSPServer * server) /** * gst_rtsp_server_set_auth: * @server: a #GstRTSPServer - * @auth: a #GstRTSPAuth + * @auth: (transfer none): a #GstRTSPAuth * * configure @auth to be used as the authentication manager of @server. */ @@ -657,7 +659,7 @@ gst_rtsp_server_get_auth (GstRTSPServer * server) /** * gst_rtsp_server_set_thread_pool: * @server: a #GstRTSPServer - * @pool: a #GstRTSPThreadPool + * @pool: (transfer none): a #GstRTSPThreadPool * * configure @pool to be used as the thread pool of @server. */ @@ -771,13 +773,14 @@ gst_rtsp_server_set_property (GObject * object, guint propid, /** * gst_rtsp_server_create_socket: * @server: a #GstRTSPServer - * @cancellable: a #GCancellable - * @error: a #GError + * @cancellable: (allow-none): a #GCancellable + * @error: (out): a #GError * * Create a #GSocket for @server. The socket will listen on the * configured service. * - * Returns: (transfer full): the #GSocket for @server or %NULL when an error occured. + * Returns: (transfer full): the #GSocket for @server or %NULL when an error + * occurred. */ GSocket * gst_rtsp_server_create_socket (GstRTSPServer * server, @@ -1089,7 +1092,7 @@ default_create_client (GstRTSPServer * server) * as an RTSP over HTTP tunnel. The @initial_buffer contains any remaining data * that the HTTP server read from the socket while parsing the HTTP header. * - * Returns: TRUE if all was ok, FALSE if an error occured. + * Returns: TRUE if all was ok, FALSE if an error occurred. */ gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket * socket, @@ -1140,12 +1143,12 @@ no_connection: * gst_rtsp_server_io_func: * @socket: a #GSocket * @condition: the condition on @source - * @server: a #GstRTSPServer + * @server: (transfer none): a #GstRTSPServer * * A default #GSocketSourceFunc that creates a new #GstRTSPClient to accept and handle a * new connection on @socket or @server. * - * Returns: TRUE if the source could be connected, FALSE if an error occured. + * Returns: TRUE if the source could be connected, FALSE if an error occurred. */ gboolean gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, @@ -1229,8 +1232,8 @@ watch_destroyed (GstRTSPServer * server) /** * gst_rtsp_server_create_source: * @server: a #GstRTSPServer - * @cancellable: a #GCancellable or %NULL. - * @error: a #GError + * @cancellable: (allow-none): a #GCancellable or %NULL. + * @error: (out): a #GError * * Create a #GSource for @server. The new source will have a default * #GSocketSourceFunc of gst_rtsp_server_io_func(). @@ -1240,8 +1243,8 @@ watch_destroyed (GstRTSPServer * server) * unless cancellation happened at the same time as a condition change). You can * check for this in the callback using g_cancellable_is_cancelled(). * - * Returns: the #GSource for @server or %NULL when an error occured. Free with - * g_source_unref () + * Returns: (transfer full): the #GSource for @server or %NULL when an error + * occurred. Free with g_source_unref () */ GSource * gst_rtsp_server_create_source (GstRTSPServer * server, diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index eea6c75850..79004f0f39 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -123,14 +123,14 @@ free_session_media (gpointer data) /** * gst_rtsp_session_media_new: * @path: the path - * @media: the #GstRTSPMedia + * @media: (transfer full): the #GstRTSPMedia * * Create a new #GstRTSPSessionMedia that manages the streams * in @media for @path. @media should be prepared. * * Ownership is taken of @media. * - * Returns: a new #GstRTSPSessionMedia. + * Returns: (transfer full): a new #GstRTSPSessionMedia. */ GstRTSPSessionMedia * gst_rtsp_session_media_new (const gchar * path, GstRTSPMedia * media) @@ -206,7 +206,7 @@ gst_rtsp_session_media_matches (GstRTSPSessionMedia * media, * Get the #GstRTSPMedia that was used when constructing @media * * Returns: (transfer none): the #GstRTSPMedia of @media. Remains valid as long - * as @media is valid. + * as @media is valid. */ GstRTSPMedia * gst_rtsp_session_media_get_media (GstRTSPSessionMedia * media) @@ -240,7 +240,7 @@ gst_rtsp_session_media_get_base_time (GstRTSPSessionMedia * media) * with configured transports. * * Returns: (transfer full): The RTP-Info as a string or %NULL when - * no RTP-Info could be generated, g_free() after usage. + * no RTP-Info could be generated, g_free() after usage. */ gchar * gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media) @@ -340,7 +340,7 @@ not_prepared: * gst_rtsp_session_media_set_transport: * @media: a #GstRTSPSessionMedia * @stream: a #GstRTSPStream - * @tr: a #GstRTSPTransport + * @tr: (transfer full): a #GstRTSPTransport * * Configure the transport for @stream to @tr in @media. * @@ -405,7 +405,7 @@ gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx) /** * gst_rtsp_session_media_alloc_channels: * @media: a #GstRTSPSessionMedia - * @range: a #GstRTSPRange + * @range: (out): a #GstRTSPRange * * Fill @range with the next available min and max channels for * interleaved transport. diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index ca4da57840..d30d6da84b 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -172,7 +172,8 @@ gst_rtsp_session_pool_set_property (GObject * object, guint propid, * * Create a new #GstRTSPSessionPool instance. * - * Returns: A new #GstRTSPSessionPool. g_object_unref() after usage. + * Returns: (transfer full): A new #GstRTSPSessionPool. g_object_unref() after + * usage. */ GstRTSPSessionPool * gst_rtsp_session_pool_new (void) @@ -409,7 +410,7 @@ too_many_sessions: /** * gst_rtsp_session_pool_remove: * @pool: a #GstRTSPSessionPool - * @sess: a #GstRTSPSession + * @sess: (transfer none): a #GstRTSPSession * * Remove @sess from @pool, releasing the ref that the pool has on @sess. * @@ -507,7 +508,7 @@ filter_func (gchar * sessionid, GstRTSPSession * sess, FilterData * data) * gst_rtsp_session_pool_filter: * @pool: a #GstRTSPSessionPool * @func: (scope call) (allow-none): a callback - * @user_data: user data passed to @func + * @user_data: (closure): user data passed to @func * * Call @func for each session in @pool. The result value of @func determines * what happens to the session. @func will be called with the session pool @@ -645,7 +646,10 @@ static GSourceFuncs gst_pool_source_funcs = { * gst_rtsp_session_pool_create_watch: * @pool: a #GstRTSPSessionPool * - * A GSource that will be dispatched when the session should be cleaned up. + * Create a #GSource that will be dispatched when the session should be cleaned + * up. + * + * Returns: (transfer full): a #GSource */ GSource * gst_rtsp_session_pool_create_watch (GstRTSPSessionPool * pool) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index b2ff36d7c6..59463ce18d 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -230,7 +230,7 @@ gst_rtsp_session_manage_media (GstRTSPSession * sess, const gchar * path, /** * gst_rtsp_session_release_media: * @sess: a #GstRTSPSession - * @media: a #GstRTSPMedia + * @media: (transfer none): a #GstRTSPMedia * * Release the managed @media in @sess, freeing the memory allocated by it. * @@ -314,7 +314,7 @@ gst_rtsp_session_get_media (GstRTSPSession * sess, const gchar * path, * gst_rtsp_session_filter: * @sess: a #GstRTSPSession * @func: (scope call) (allow-none): a callback - * @user_data: user data passed to @func + * @user_data: (closure): user data passed to @func * * Call @func for each media in @sess. The result value of @func determines * what happens to the media. @func will be called with @sess @@ -383,6 +383,8 @@ gst_rtsp_session_filter (GstRTSPSession * sess, * @sessionid: a session id * * Create a new #GstRTSPSession instance with @sessionid. + * + * Returns: (transfer full): a new #GstRTSPSession */ GstRTSPSession * gst_rtsp_session_new (const gchar * sessionid) @@ -402,8 +404,8 @@ gst_rtsp_session_new (const gchar * sessionid) * * Get the sessionid of @session. * - * Returns: the sessionid of @session. The value remains valid as long as - * @session is alive. + * Returns: (transfer none): the sessionid of @session. The value remains valid + * as long as @session is alive. */ const gchar * gst_rtsp_session_get_sessionid (GstRTSPSession * session) @@ -538,7 +540,7 @@ gst_rtsp_session_allow_expire (GstRTSPSession * session) /** * gst_rtsp_session_next_timeout: * @session: a #GstRTSPSession - * @now: the current system time + * @now: (transfer none): the current system time * * Get the amount of milliseconds till the session will expire. * @@ -580,7 +582,7 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) /** * gst_rtsp_session_is_expired: * @session: a #GstRTSPSession - * @now: the current system time + * @now: (transfer none): the current system time * * Check if @session timeout out. * diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 4020ee4c0e..cd16626434 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -135,7 +135,7 @@ gst_rtsp_stream_transport_finalize (GObject * obj) * Create a new #GstRTSPStreamTransport that can be used to manage * @stream with transport @tr. * - * Returns: a new #GstRTSPStreamTransport + * Returns: (transfer full): a new #GstRTSPStreamTransport */ GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr) @@ -175,8 +175,8 @@ gst_rtsp_stream_transport_get_stream (GstRTSPStreamTransport * trans) * @trans: a #GstRTSPStreamTransport * @send_rtp: (scope notified): a callback called when RTP should be sent * @send_rtcp: (scope notified): a callback called when RTCP should be sent - * @user_data: user data passed to callbacks - * @notify: called with the user_data when no longer needed. + * @user_data: (closure): user data passed to callbacks + * @notify: (allow-none): called with the user_data when no longer needed. * * Install callbacks that will be called when data for a stream should be sent * to a client. This is usually used when sending RTP/RTCP over TCP. @@ -203,9 +203,9 @@ gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport * trans, /** * gst_rtsp_stream_transport_set_keepalive: * @trans: a #GstRTSPStreamTransport - * @keep_alive: a callback called when the receiver is active - * @user_data: user data passed to callback - * @notify: called with the user_data when no longer needed. + * @keep_alive: (scope notified): a callback called when the receiver is active + * @user_data: (closure): user data passed to callback + * @notify: (allow-none): called with the user_data when no longer needed. * * Install callbacks that will be called when RTCP packets are received from the * receiver of @trans. @@ -260,7 +260,7 @@ gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans, * Get the transport configured in @trans. * * Returns: (transfer none): the transport configured in @trans. It remains - * valid for as long as @trans is valid. + * valid for as long as @trans is valid. */ const GstRTSPTransport * gst_rtsp_stream_transport_get_transport (GstRTSPStreamTransport * trans) @@ -300,7 +300,7 @@ gst_rtsp_stream_transport_set_url (GstRTSPStreamTransport * trans, * Get the url configured in @trans. * * Returns: (transfer none): the url configured in @trans. It remains - * valid for as long as @trans is valid. + * valid for as long as @trans is valid. */ const GstRTSPUrl * gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport * trans) @@ -317,8 +317,8 @@ gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport * trans) * * Get the RTP-Info string for @trans and @start_time. * - * Returns: the RTPInfo string for @trans and @start_time or %NULL when - * the RTP-Info could not be determined. g_free() after usage. + * Returns: (transfer full): the RTPInfo string for @trans and @start_time or + * %NULL when the RTP-Info could not be determined. g_free() after usage. */ gchar * gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport * trans, @@ -435,7 +435,7 @@ gst_rtsp_stream_transport_is_timed_out (GstRTSPStreamTransport * trans) /** * gst_rtsp_stream_transport_send_rtp: * @trans: a #GstRTSPStreamTransport - * @buffer: a #GstBuffer + * @buffer: (transfer none): a #GstBuffer * * Send @buffer to the installed RTP callback for @trans. * @@ -461,7 +461,7 @@ gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport * trans, /** * gst_rtsp_stream_transport_send_rtcp: * @trans: a #GstRTSPStreamTransport - * @buffer: a #GstBuffer + * @buffer: (transfer none): a #GstBuffer * * Send @buffer to the installed RTCP callback for @trans. * diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 655545eb17..9ec187c838 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -290,7 +290,7 @@ gst_rtsp_stream_set_property (GObject * object, guint propid, * Create a new media stream with index @idx that handles RTP data on * @srcpad and has a payloader element @payloader. * - * Returns: a new #GstRTSPStream + * Returns: (transfer full): a new #GstRTSPStream */ GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad) @@ -372,7 +372,7 @@ gst_rtsp_stream_get_srcpad (GstRTSPStream * stream) * * Get the control string to identify this stream. * - * Returns: (transfer full): the control string. free after usage. + * Returns: (transfer full): the control string. g_free() after usage. */ gchar * gst_rtsp_stream_get_control (GstRTSPStream * stream) @@ -565,7 +565,7 @@ gst_rtsp_stream_get_dscp_qos (GstRTSPStream * stream) /** * gst_rtsp_stream_is_transport_supported: * @stream: a #GstRTSPStream - * @transport: a #GstRTSPTransport + * @transport: (transfer none): a #GstRTSPTransport * * Check if @transport can be handled by stream * @@ -713,7 +713,7 @@ gst_rtsp_stream_get_protocols (GstRTSPStream * stream) /** * gst_rtsp_stream_set_address_pool: * @stream: a #GstRTSPStream - * @pool: a #GstRTSPAddressPool + * @pool: (transfer none): a #GstRTSPAddressPool * * configure @pool to be used as the address pool of @stream. */ @@ -775,8 +775,8 @@ gst_rtsp_stream_get_address_pool (GstRTSPStream * stream) * * Get the multicast address of @stream for @family. * - * Returns: the #GstRTSPAddress of @stream or %NULL when no address could be - * allocated. gst_rtsp_address_free() after usage. + * Returns: (transfer full): the #GstRTSPAddress of @stream or %NULL when no + * address could be allocated. gst_rtsp_address_free() after usage. */ GstRTSPAddress * gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, @@ -1506,8 +1506,8 @@ static GstAppSinkCallbacks sink_cb = { /** * gst_rtsp_stream_join_bin: * @stream: a #GstRTSPStream - * @bin: a #GstBin to join - * @rtpbin: a rtpbin element in @bin + * @bin: (transfer none): a #GstBin to join + * @rtpbin: (transfer none): a rtpbin element in @bin * @state: the target state of the new elements * * Join the #GstBin @bin that contains the element @rtpbin. @@ -1771,8 +1771,8 @@ link_failed: /** * gst_rtsp_stream_leave_bin: * @stream: a #GstRTSPStream - * @bin: a #GstBin - * @rtpbin: a rtpbin #GstElement + * @bin: (transfer none): a #GstBin + * @rtpbin: (transfer none): a rtpbin #GstElement * * Remove the elements of @stream from @bin. * @@ -1890,7 +1890,7 @@ was_not_joined: * @stream: a #GstRTSPStream * @rtptime: (allow-none): result RTP timestamp * @seq: (allow-none): result RTP seqnum - * @clock_rate: the clock rate + * @clock_rate: (allow-none): the clock rate * @running_time: (allow-none): result running-time * * Retrieve the current rtptime, seq and running-time. This is used to @@ -1969,7 +1969,7 @@ no_stats: * Retrieve the current caps of @stream. * * Returns: (transfer full): the #GstCaps of @stream. use gst_caps_unref() - * after usage. + * after usage. */ GstCaps * gst_rtsp_stream_get_caps (GstRTSPStream * stream) @@ -2065,6 +2065,7 @@ gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer) gst_object_unref (element); } else { ret = GST_FLOW_OK; + gst_buffer_unref (buffer); } return ret; } @@ -2143,7 +2144,7 @@ unknown_transport: /** * gst_rtsp_stream_add_transport: * @stream: a #GstRTSPStream - * @trans: a #GstRTSPStreamTransport + * @trans: (transfer none): a #GstRTSPStreamTransport * * Add the transport in @trans to @stream. The media of @stream will * then also be send to the values configured in @trans. @@ -2176,7 +2177,7 @@ gst_rtsp_stream_add_transport (GstRTSPStream * stream, /** * gst_rtsp_stream_remove_transport: * @stream: a #GstRTSPStream - * @trans: a #GstRTSPStreamTransport + * @trans: (transfer none): a #GstRTSPStreamTransport * * Remove the transport in @trans from @stream. The media of @stream will * not be sent to the values configured in @trans. @@ -2216,7 +2217,7 @@ gst_rtsp_stream_remove_transport (GstRTSPStream * stream, * @stream must be joined to a bin. * * Returns: (transfer full): the RTP socket or %NULL if no socket could be - * allocated for @family. Unref after usage + * allocated for @family. Unref after usage */ GSocket * gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family) @@ -2250,7 +2251,7 @@ gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family) * @stream must be joined to a bin. * * Returns: (transfer full): the RTCP socket or %NULL if no socket could be - * allocated for @family. Unref after usage + * allocated for @family. Unref after usage */ GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) @@ -2278,7 +2279,7 @@ gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) * gst_rtsp_stream_transport_filter: * @stream: a #GstRTSPStream * @func: (scope call) (allow-none): a callback - * @user_data: user data passed to @func + * @user_data: (closure): user data passed to @func * * Call @func for each transport managed by @stream. The result value of @func * determines what happens to the transport. @func will be called with @stream diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index 67c9782a11..a8cce78293 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -106,7 +106,7 @@ gst_rtsp_thread_init (GstRTSPThreadImpl * impl) * * Create a new thread object that can run a mainloop. * - * Returns: a #GstRTSPThread. + * Returns: (transfer full): a #GstRTSPThread. */ GstRTSPThread * gst_rtsp_thread_new (GstRTSPThreadType type) @@ -125,7 +125,7 @@ gst_rtsp_thread_new (GstRTSPThreadType type) /** * gst_rtsp_thread_reuse: - * @thread: a #GstRTSPThread + * @thread: (transfer none): a #GstRTSPThread * * Reuse the mainloop of @thread * @@ -346,7 +346,7 @@ do_loop (GstRTSPThread * thread) * * Create a new #GstRTSPThreadPool instance. * - * Returns: a new #GstRTSPThreadPool + * Returns: (transfer full): a new #GstRTSPThreadPool */ GstRTSPThreadPool * gst_rtsp_thread_pool_new (void) @@ -506,11 +506,11 @@ thread_error: * gst_rtsp_thread_pool_get_thread: * @pool: a #GstRTSPThreadPool * @type: the #GstRTSPThreadType - * @ctx: a #GstRTSPContext + * @ctx: (transfer none): a #GstRTSPContext * * Get a new #GstRTSPThread for @type and @ctx. * - * Returns: a new #GstRTSPThread, gst_rtsp_thread_stop() after usage + * Returns: (transfer full): a new #GstRTSPThread, gst_rtsp_thread_stop() after usage */ GstRTSPThread * gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool * pool, diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index 7e234e82ae..da9e8d9777 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -172,9 +172,9 @@ gst_rtsp_token_new_valist (const gchar * firstfield, va_list var_args) * * Access the structure of the token. * - * Returns: The structure of the token. The structure is still - * owned by the token, which means that you should not free it and - * that the pointer becomes invalid when you free the token. + * Returns: (transfer none): The structure of the token. The structure is still + * owned by the token, which means that you should not free it and that the + * pointer becomes invalid when you free the token. * * MT safe. */ @@ -192,10 +192,10 @@ gst_rtsp_token_get_structure (GstRTSPToken * token) * * Get a writable version of the structure. * - * Returns: The structure of the token. The structure is still - * owned by the token, which means that you should not free it and - * that the pointer becomes invalid when you free the token. - * This function checks if @token is writable and will never return %NULL. + * Returns: (transfer none): The structure of the token. The structure is still + * owned by the token, which means that you should not free it and that the + * pointer becomes invalid when you free the token. This function checks if + * @token is writable and will never return %NULL. * * MT safe. */ @@ -216,8 +216,9 @@ gst_rtsp_token_writable_structure (GstRTSPToken * token) * * Get the string value of @field in @token. * - * Returns: the string value of @field in @token or %NULL when @field is not - * defined in @token. + * Returns: (transfer none): the string value of @field in @token or %NULL when + * @field is not defined in @token. The string becomes invalid when you free + * @token. */ const gchar * gst_rtsp_token_get_string (GstRTSPToken * token, const gchar * field) From 1cb66a0e6d96961e1e7cd2ed88d757f211e7f7aa Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Sun, 23 Mar 2014 21:26:00 +0100 Subject: [PATCH 0935/1776] tests: Improve code coverage for rtsp-session-media Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726940 --- tests/check/gst/sessionmedia.c | 288 ++++++++++++++++++++++++++++++++- 1 file changed, 284 insertions(+), 4 deletions(-) diff --git a/tests/check/gst/sessionmedia.c b/tests/check/gst/sessionmedia.c index c749a566c5..6bd9d26c45 100644 --- a/tests/check/gst/sessionmedia.c +++ b/tests/check/gst/sessionmedia.c @@ -23,7 +23,8 @@ #include #define TEST_PATH "rtsp://localhost:8554/test" -#define SETUP_URL TEST_PATH "/stream=0" +#define SETUP_URL1 TEST_PATH "/stream=0" +#define SETUP_URL2 TEST_PATH "/stream=1" GST_START_TEST (test_setup_url) { @@ -52,7 +53,7 @@ GST_START_TEST (test_setup_url) fail_unless (gst_rtsp_media_n_streams (media) == 1); stream = gst_rtsp_media_get_stream (media, 0); - fail_unless (stream != NULL); + fail_unless (GST_IS_RTSP_STREAM (stream)); pool = gst_rtsp_thread_pool_new (); thread = gst_rtsp_thread_pool_get_thread (pool, @@ -64,19 +65,21 @@ GST_START_TEST (test_setup_url) * note that gst_rtsp_session_media_new takes ownership of the media * thus no need to unref it at the bottom of function */ sm = gst_rtsp_session_media_new (TEST_PATH, media); - fail_unless (sm != NULL); + fail_unless (GST_IS_RTSP_SESSION_MEDIA (sm)); fail_unless (gst_rtsp_session_media_matches (sm, TEST_PATH, &match_len)); fail_unless (match_len == strlen (TEST_PATH)); + fail_unless (gst_rtsp_session_media_get_media (sm) == media); /* make a transport for the stream */ gst_rtsp_transport_new (&ct); trans = gst_rtsp_session_media_set_transport (sm, stream, ct); + fail_unless (gst_rtsp_session_media_get_transport (sm, 0) == trans); /* make sure there's no setup url stored initially */ fail_unless (gst_rtsp_stream_transport_get_url (trans) == NULL); /* now store a setup url and make sure it can be retrieved and that it's correct */ - fail_unless (gst_rtsp_url_parse (SETUP_URL, &setup_url) == GST_RTSP_OK); + fail_unless (gst_rtsp_url_parse (SETUP_URL1, &setup_url) == GST_RTSP_OK); gst_rtsp_stream_transport_set_url (trans, setup_url); url_str = gst_rtsp_url_get_request_uri (setup_url); @@ -102,6 +105,279 @@ GST_START_TEST (test_setup_url) GST_END_TEST; +GST_START_TEST (test_rtsp_state) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPStream *stream; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + GstRTSPSessionMedia *sm; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + fail_unless (gst_rtsp_url_parse (TEST_PATH, &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + fail_unless (gst_rtsp_media_n_streams (media) == 1); + + stream = gst_rtsp_media_get_stream (media, 0); + fail_unless (GST_IS_RTSP_STREAM (stream)); + + pool = gst_rtsp_thread_pool_new (); + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + + fail_unless (gst_rtsp_media_prepare (media, thread)); + + sm = gst_rtsp_session_media_new (TEST_PATH, media); + fail_unless (GST_IS_RTSP_SESSION_MEDIA (sm)); + fail_unless_equals_int (gst_rtsp_session_media_get_rtsp_state (sm), + GST_RTSP_STATE_INIT); + + gst_rtsp_session_media_set_rtsp_state (sm, GST_RTSP_STATE_READY); + fail_unless_equals_int (gst_rtsp_session_media_get_rtsp_state (sm), + GST_RTSP_STATE_READY); + + gst_rtsp_session_media_set_rtsp_state (sm, GST_RTSP_STATE_SEEKING); + fail_unless_equals_int (gst_rtsp_session_media_get_rtsp_state (sm), + GST_RTSP_STATE_SEEKING); + + gst_rtsp_session_media_set_rtsp_state (sm, GST_RTSP_STATE_PLAYING); + fail_unless_equals_int (gst_rtsp_session_media_get_rtsp_state (sm), + GST_RTSP_STATE_PLAYING); + + gst_rtsp_session_media_set_rtsp_state (sm, GST_RTSP_STATE_RECORDING); + fail_unless_equals_int (gst_rtsp_session_media_get_rtsp_state (sm), + GST_RTSP_STATE_RECORDING); + + fail_unless (gst_rtsp_media_unprepare (media)); + + gst_rtsp_url_free (url); + + g_object_unref (sm); + + g_object_unref (factory); + g_object_unref (pool); +} + +GST_END_TEST; + +GST_START_TEST (test_transports) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPStream *stream1, *stream2; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + GstRTSPSessionMedia *sm; + GstRTSPStreamTransport *trans; + GstRTSPTransport *ct1, *ct2, *ct3, *ct4; + gint match_len; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + fail_unless (gst_rtsp_url_parse (TEST_PATH, &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 audiotestsrc ! rtpgstpay pt=97 name=pay1 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + fail_unless (gst_rtsp_media_n_streams (media) == 2); + + stream1 = gst_rtsp_media_get_stream (media, 0); + fail_unless (GST_IS_RTSP_STREAM (stream1)); + + stream2 = gst_rtsp_media_get_stream (media, 1); + fail_unless (GST_IS_RTSP_STREAM (stream2)); + + pool = gst_rtsp_thread_pool_new (); + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + + fail_unless (gst_rtsp_media_prepare (media, thread)); + + sm = gst_rtsp_session_media_new (TEST_PATH, media); + fail_unless (GST_IS_RTSP_SESSION_MEDIA (sm)); + fail_unless (gst_rtsp_session_media_matches (sm, TEST_PATH, &match_len)); + fail_unless (match_len == strlen (TEST_PATH)); + + gst_rtsp_transport_new (&ct1); + trans = gst_rtsp_session_media_set_transport (sm, stream1, ct1); + fail_unless (gst_rtsp_session_media_get_transport (sm, 0) == trans); + + gst_rtsp_transport_new (&ct2); + trans = gst_rtsp_session_media_set_transport (sm, stream1, ct2); + fail_unless (gst_rtsp_session_media_get_transport (sm, 0) == trans); + + gst_rtsp_transport_new (&ct3); + trans = gst_rtsp_session_media_set_transport (sm, stream2, ct3); + fail_unless (gst_rtsp_session_media_get_transport (sm, 1) == trans); + + gst_rtsp_transport_new (&ct4); + trans = gst_rtsp_session_media_set_transport (sm, stream2, ct4); + fail_unless (gst_rtsp_session_media_get_transport (sm, 1) == trans); + + fail_unless (gst_rtsp_media_unprepare (media)); + + gst_rtsp_url_free (url); + + g_object_unref (sm); + + g_object_unref (factory); + g_object_unref (pool); +} + +GST_END_TEST; + +GST_START_TEST (test_time_and_rtpinfo) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPStream *stream1, *stream2; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + GstRTSPSessionMedia *sm; + GstClockTime base_time; + gchar *rtpinfo; + GstRTSPTransport *ct1; + GstRTSPStreamTransport *trans; + GstRTSPUrl *setup_url; + gchar **streaminfo; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + fail_unless (gst_rtsp_url_parse (TEST_PATH, &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc do-timestamp=true timestamp-offset=0 ! rtpvrawpay pt=96 name=pay0 " + "audiotestsrc do-timestamp=true timestamp-offset=1000000000 ! rtpgstpay pt=97 name=pay1 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + fail_unless (gst_rtsp_media_n_streams (media) == 2); + + stream1 = gst_rtsp_media_get_stream (media, 0); + fail_unless (GST_IS_RTSP_STREAM (stream1)); + + stream2 = gst_rtsp_media_get_stream (media, 1); + fail_unless (GST_IS_RTSP_STREAM (stream2)); + + pool = gst_rtsp_thread_pool_new (); + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + + fail_unless (gst_rtsp_media_prepare (media, thread)); + + sm = gst_rtsp_session_media_new (TEST_PATH, media); + fail_unless (GST_IS_RTSP_SESSION_MEDIA (sm)); + + base_time = gst_rtsp_session_media_get_base_time (sm); + fail_unless_equals_int64 (base_time, 0); + + rtpinfo = gst_rtsp_session_media_get_rtpinfo (sm); + fail_unless (rtpinfo == NULL); + + gst_rtsp_transport_new (&ct1); + trans = gst_rtsp_session_media_set_transport (sm, stream1, ct1); + fail_unless (gst_rtsp_session_media_get_transport (sm, 0) == trans); + fail_unless (gst_rtsp_url_parse (SETUP_URL1, &setup_url) == GST_RTSP_OK); + gst_rtsp_stream_transport_set_url (trans, setup_url); + + base_time = gst_rtsp_session_media_get_base_time (sm); + fail_unless_equals_int64 (base_time, 0); + + rtpinfo = gst_rtsp_session_media_get_rtpinfo (sm); + streaminfo = g_strsplit (rtpinfo, ",", 1); + g_free (rtpinfo); + + fail_unless (g_strstr_len (streaminfo[0], -1, "url=") != NULL); + fail_unless (g_strstr_len (streaminfo[0], -1, "seq=") != NULL); + fail_unless (g_strstr_len (streaminfo[0], -1, "rtptime=") != NULL); + fail_unless (g_strstr_len (streaminfo[0], -1, SETUP_URL1) != NULL); + + g_strfreev (streaminfo); + + fail_unless (gst_rtsp_media_unprepare (media)); + + rtpinfo = gst_rtsp_session_media_get_rtpinfo (sm); + fail_unless (rtpinfo == NULL); + + gst_rtsp_url_free (url); + + g_object_unref (sm); + + g_object_unref (factory); + g_object_unref (pool); +} + +GST_END_TEST; + +GST_START_TEST (test_allocate_channels) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPStream *stream; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + GstRTSPSessionMedia *sm; + GstRTSPRange range; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + fail_unless (gst_rtsp_url_parse (TEST_PATH, &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + fail_unless (gst_rtsp_media_n_streams (media) == 1); + + stream = gst_rtsp_media_get_stream (media, 0); + fail_unless (GST_IS_RTSP_STREAM (stream)); + + pool = gst_rtsp_thread_pool_new (); + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + + fail_unless (gst_rtsp_media_prepare (media, thread)); + + sm = gst_rtsp_session_media_new (TEST_PATH, media); + fail_unless (GST_IS_RTSP_SESSION_MEDIA (sm)); + + fail_unless (gst_rtsp_session_media_alloc_channels (sm, &range)); + fail_unless_equals_int (range.min, 0); + fail_unless_equals_int (range.max, 1); + + fail_unless (gst_rtsp_session_media_alloc_channels (sm, &range)); + fail_unless_equals_int (range.min, 2); + fail_unless_equals_int (range.max, 3); + + fail_unless (gst_rtsp_media_unprepare (media)); + + gst_rtsp_url_free (url); + + g_object_unref (sm); + + g_object_unref (factory); + g_object_unref (pool); +} + +GST_END_TEST; static Suite * rtspsessionmedia_suite (void) { @@ -111,6 +387,10 @@ rtspsessionmedia_suite (void) suite_add_tcase (s, tc); tcase_set_timeout (tc, 20); tcase_add_test (tc, test_setup_url); + tcase_add_test (tc, test_rtsp_state); + tcase_add_test (tc, test_transports); + tcase_add_test (tc, test_time_and_rtpinfo); + tcase_add_test (tc, test_allocate_channels); return s; } From d9cfa3677bb2b4103be2e9439eced577893eda82 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Sat, 22 Mar 2014 13:24:27 +0100 Subject: [PATCH 0936/1776] tests: Improve code coverage of rtsp-threadpool tests Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726873 --- tests/check/gst/threadpool.c | 164 ++++++++++++++++++++++++++++++++--- 1 file changed, 153 insertions(+), 11 deletions(-) diff --git a/tests/check/gst/threadpool.c b/tests/check/gst/threadpool.c index 4c6ca79a3b..c92e64f61c 100644 --- a/tests/check/gst/threadpool.c +++ b/tests/check/gst/threadpool.c @@ -29,13 +29,34 @@ GST_START_TEST (test_pool_get_thread) GstRTSPThread *thread; pool = gst_rtsp_thread_pool_new (); - fail_unless (pool != NULL); + fail_unless (GST_IS_RTSP_THREAD_POOL (pool)); thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, NULL); - fail_unless (thread != NULL); + fail_unless (GST_IS_RTSP_THREAD (thread)); /* one ref is hold by the pool */ - fail_unless (GST_MINI_OBJECT_REFCOUNT (thread) == 2); + fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT (thread), 2); + + gst_rtsp_thread_stop (thread); + g_object_unref (pool); + gst_rtsp_thread_pool_cleanup (); +} + +GST_END_TEST; + +GST_START_TEST (test_pool_get_media_thread) +{ + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + + pool = gst_rtsp_thread_pool_new (); + fail_unless (GST_IS_RTSP_THREAD_POOL (pool)); + + thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, + NULL); + fail_unless (GST_IS_RTSP_THREAD (thread)); + /* one ref is hold by the pool */ + fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT (thread), 2); gst_rtsp_thread_stop (thread); g_object_unref (pool); @@ -47,27 +68,27 @@ GST_END_TEST; GST_START_TEST (test_pool_get_thread_reuse) { GstRTSPThreadPool *pool; - GstRTSPThread *thread; + GstRTSPThread *thread1; GstRTSPThread *thread2; pool = gst_rtsp_thread_pool_new (); - fail_unless (pool != NULL); + fail_unless (GST_IS_RTSP_THREAD_POOL (pool)); gst_rtsp_thread_pool_set_max_threads (pool, 1); - thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, + thread1 = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, NULL); - fail_unless (thread != NULL); + fail_unless (GST_IS_RTSP_THREAD (thread1)); thread2 = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, NULL); - fail_unless (thread2 != NULL); + fail_unless (GST_IS_RTSP_THREAD (thread2)); - fail_unless (thread == thread2); + fail_unless (thread2 == thread1); /* one ref is hold by the pool */ - fail_unless (GST_MINI_OBJECT_REFCOUNT (thread) == 3); + fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT (thread1), 3); - gst_rtsp_thread_stop (thread); + gst_rtsp_thread_stop (thread1); gst_rtsp_thread_stop (thread2); g_object_unref (pool); @@ -76,6 +97,123 @@ GST_START_TEST (test_pool_get_thread_reuse) GST_END_TEST; +static void +do_test_pool_max_thread (gboolean use_property) +{ + GstRTSPThreadPool *pool; + GstRTSPThread *thread1; + GstRTSPThread *thread2; + GstRTSPThread *thread3; + gint max_threads; + + pool = gst_rtsp_thread_pool_new (); + fail_unless (GST_IS_RTSP_THREAD_POOL (pool)); + + if (use_property) { + g_object_get (pool, "max-threads", &max_threads, NULL); + fail_unless_equals_int (max_threads, 1); + } else { + fail_unless_equals_int (gst_rtsp_thread_pool_get_max_threads (pool), 1); + } + + thread1 = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, + NULL); + fail_unless (GST_IS_RTSP_THREAD (thread1)); + + thread2 = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, + NULL); + fail_unless (GST_IS_RTSP_THREAD (thread2)); + + fail_unless (thread1 == thread2); + + gst_rtsp_thread_stop (thread1); + gst_rtsp_thread_stop (thread2); + + if (use_property) { + g_object_set (pool, "max-threads", 2, NULL); + g_object_get (pool, "max-threads", &max_threads, NULL); + fail_unless_equals_int (max_threads, 2); + } else { + gst_rtsp_thread_pool_set_max_threads (pool, 2); + fail_unless_equals_int (gst_rtsp_thread_pool_get_max_threads (pool), 2); + } + + thread1 = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, + NULL); + fail_unless (GST_IS_RTSP_THREAD (thread1)); + + thread2 = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, + NULL); + fail_unless (GST_IS_RTSP_THREAD (thread2)); + + thread3 = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, + NULL); + fail_unless (GST_IS_RTSP_THREAD (thread3)); + + fail_unless (thread2 != thread1); + fail_unless (thread3 == thread2 || thread3 == thread1); + + gst_rtsp_thread_stop (thread1); + gst_rtsp_thread_stop (thread2); + gst_rtsp_thread_stop (thread3); + + if (use_property) { + g_object_set (pool, "max-threads", 0, NULL); + g_object_get (pool, "max-threads", &max_threads, NULL); + fail_unless_equals_int (max_threads, 0); + } else { + gst_rtsp_thread_pool_set_max_threads (pool, 0); + fail_unless_equals_int (gst_rtsp_thread_pool_get_max_threads (pool), 0); + } + + thread1 = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, + NULL); + fail_if (GST_IS_RTSP_THREAD (thread1)); + + g_object_unref (pool); + + gst_rtsp_thread_pool_cleanup (); +} + +GST_START_TEST (test_pool_max_threads) +{ + do_test_pool_max_thread (FALSE); +} + +GST_END_TEST; + +GST_START_TEST (test_pool_max_threads_property) +{ + do_test_pool_max_thread (TRUE); +} + +GST_END_TEST; + +GST_START_TEST (test_pool_thread_copy) +{ + GstRTSPThreadPool *pool; + GstRTSPThread *thread1; + GstRTSPThread *thread2; + + pool = gst_rtsp_thread_pool_new (); + fail_unless (GST_IS_RTSP_THREAD_POOL (pool)); + + thread1 = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_CLIENT, + NULL); + fail_unless (GST_IS_RTSP_THREAD (thread1)); + fail_unless (GST_IS_MINI_OBJECT_TYPE (thread1, GST_TYPE_RTSP_THREAD)); + + thread2 = GST_RTSP_THREAD (gst_mini_object_copy (GST_MINI_OBJECT (thread1))); + fail_unless (GST_IS_RTSP_THREAD (thread2)); + fail_unless (GST_IS_MINI_OBJECT_TYPE (thread2, GST_TYPE_RTSP_THREAD)); + + gst_rtsp_thread_stop (thread1); + gst_rtsp_thread_stop (thread2); + g_object_unref (pool); + gst_rtsp_thread_pool_cleanup (); +} + +GST_END_TEST; static Suite * rtspthreadpool_suite (void) @@ -86,7 +224,11 @@ rtspthreadpool_suite (void) suite_add_tcase (s, tc); tcase_set_timeout (tc, 20); tcase_add_test (tc, test_pool_get_thread); + tcase_add_test (tc, test_pool_get_media_thread); tcase_add_test (tc, test_pool_get_thread_reuse); + tcase_add_test (tc, test_pool_max_threads); + tcase_add_test (tc, test_pool_max_threads_property); + tcase_add_test (tc, test_pool_thread_copy); return s; } From bfbf393925643f1c5c9b17d9cc5331f23ba321ec Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Sun, 16 Mar 2014 19:45:26 +0100 Subject: [PATCH 0937/1776] tests: Add unit tests for sessionpool Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726470 --- tests/check/Makefile.am | 3 +- tests/check/gst/sessionpool.c | 179 ++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 tests/check/gst/sessionpool.c diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 765c663e4a..7ecc2bc11e 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -36,7 +36,8 @@ check_PROGRAMS = \ gst/threadpool \ gst/permissions \ gst/token \ - gst/sessionmedia + gst/sessionmedia \ + gst/sessionpool # these tests don't even pass noinst_PROGRAMS = diff --git a/tests/check/gst/sessionpool.c b/tests/check/gst/sessionpool.c new file mode 100644 index 0000000000..a0de375efa --- /dev/null +++ b/tests/check/gst/sessionpool.c @@ -0,0 +1,179 @@ +/* GStreamer + * Copyright (C) 2014 Sebastian Rasmussen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +typedef struct +{ + GstRTSPSession *sessions[3]; + GstRTSPFilterResult response[3]; +} Responses; + +static GstRTSPFilterResult +filter_func (GstRTSPSessionPool * pool, GstRTSPSession * session, + gpointer user_data) +{ + Responses *responses = (Responses *) user_data; + gint i; + + for (i = 0; i < 3; i++) + if (session == responses->sessions[i]) + return responses->response[i]; + + return GST_RTSP_FILTER_KEEP; +} + +GST_START_TEST (test_pool) +{ + GstRTSPSessionPool *pool; + GstRTSPSession *session1, *session2, *session3; + const gchar *session1id, *session2id, *session3id; + GList *list; + guint maxsessions; + GSource *source; + guint sourceid; + + pool = gst_rtsp_session_pool_new (); + fail_unless_equals_int (gst_rtsp_session_pool_get_n_sessions (pool), 0); + fail_unless_equals_int (gst_rtsp_session_pool_get_max_sessions (pool), 0); + + gst_rtsp_session_pool_set_max_sessions (pool, 3); + fail_unless_equals_int (gst_rtsp_session_pool_get_max_sessions (pool), 3); + + session1 = gst_rtsp_session_pool_create (pool); + fail_unless (GST_IS_RTSP_SESSION (session1)); + fail_unless_equals_int (gst_rtsp_session_pool_get_n_sessions (pool), 1); + fail_unless_equals_int (gst_rtsp_session_pool_get_max_sessions (pool), 3); + session1id = gst_rtsp_session_get_sessionid (session1); + + session2 = gst_rtsp_session_pool_create (pool); + fail_unless (GST_IS_RTSP_SESSION (session2)); + fail_unless_equals_int (gst_rtsp_session_pool_get_n_sessions (pool), 2); + fail_unless_equals_int (gst_rtsp_session_pool_get_max_sessions (pool), 3); + session2id = gst_rtsp_session_get_sessionid (session2); + + session3 = gst_rtsp_session_pool_create (pool); + fail_unless (GST_IS_RTSP_SESSION (session3)); + fail_unless_equals_int (gst_rtsp_session_pool_get_n_sessions (pool), 3); + fail_unless_equals_int (gst_rtsp_session_pool_get_max_sessions (pool), 3); + session3id = gst_rtsp_session_get_sessionid (session3); + + fail_if (GST_IS_RTSP_SESSION (gst_rtsp_session_pool_create (pool))); + + fail_unless (gst_rtsp_session_pool_find (pool, session1id) == session1); + fail_unless (gst_rtsp_session_pool_find (pool, session2id) == session2); + fail_unless (gst_rtsp_session_pool_find (pool, session3id) == session3); + fail_unless (gst_rtsp_session_pool_find (pool, "") == NULL); + + fail_unless (gst_rtsp_session_pool_remove (pool, session2)); + fail_unless_equals_int (gst_rtsp_session_pool_get_n_sessions (pool), 2); + fail_unless_equals_int (gst_rtsp_session_pool_get_max_sessions (pool), 3); + + gst_rtsp_session_pool_set_max_sessions (pool, 2); + fail_unless_equals_int (gst_rtsp_session_pool_get_n_sessions (pool), 2); + fail_unless_equals_int (gst_rtsp_session_pool_get_max_sessions (pool), 2); + + session2 = gst_rtsp_session_pool_create (pool); + fail_if (GST_IS_RTSP_SESSION (session2)); + + { + list = gst_rtsp_session_pool_filter (pool, NULL, NULL); + fail_unless_equals_int (g_list_length (list), 2); + fail_unless (g_list_find (list, session1) != NULL); + fail_unless (g_list_find (list, session3) != NULL); + g_list_foreach (list, (GFunc) g_object_unref, NULL); + } + + { + Responses responses = { + {session1, session2, session3}, + {GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_KEEP}, + }; + + list = gst_rtsp_session_pool_filter (pool, filter_func, &responses); + fail_unless (list == NULL); + } + + { + Responses responses = { + {session1, session2, session3}, + {GST_RTSP_FILTER_REF, GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_KEEP}, + }; + + list = gst_rtsp_session_pool_filter (pool, filter_func, &responses); + fail_unless_equals_int (g_list_length (list), 1); + fail_unless (g_list_nth_data (list, 0) == session1); + g_list_foreach (list, (GFunc) g_object_unref, NULL); + } + + { + Responses responses = { + {session1, session2, session3}, + {GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_REMOVE}, + }; + + list = gst_rtsp_session_pool_filter (pool, filter_func, &responses); + fail_unless_equals_int (g_list_length (list), 0); + } + + fail_unless (gst_rtsp_session_pool_find (pool, session1id) == session1); + fail_unless (gst_rtsp_session_pool_find (pool, session2id) == NULL); + fail_unless (gst_rtsp_session_pool_find (pool, session3id) == NULL); + + g_object_get (pool, "max-sessions", &maxsessions, NULL); + fail_unless_equals_int (maxsessions, 2); + + g_object_set (pool, "max-sessions", 3, NULL); + g_object_get (pool, "max-sessions", &maxsessions, NULL); + fail_unless_equals_int (maxsessions, 3); + + fail_unless_equals_int (gst_rtsp_session_pool_cleanup (pool), 0); + + gst_rtsp_session_set_timeout (session1, 1); + + source = gst_rtsp_session_pool_create_watch (pool); + fail_unless (source != NULL); + + sourceid = g_source_attach (source, NULL); + fail_unless (sourceid != 0); + + while (!g_main_context_iteration (NULL, TRUE)); + + g_source_unref (source); + + g_object_unref (pool); +} + +GST_END_TEST; + +static Suite * +rtspsessionpool_suite (void) +{ + Suite *s = suite_create ("rtspsessionpool"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_set_timeout (tc, 15); + tcase_add_test (tc, test_pool); + + return s; +} + +GST_CHECK_MAIN (rtspsessionpool); From 3d6175c745997c3126acc8c563ff18978966f245 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 13 Mar 2014 17:35:21 +0100 Subject: [PATCH 0938/1776] stream: add SRTP support Install srtp encoder and decoder elements in rtpbin Add MIKEY in SDP --- configure.ac | 6 ++ examples/test-video.c | 1 + gst/rtsp-server/rtsp-sdp.c | 93 ++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.c | 103 ++++++++++++++++++++++++++++++++++ tests/check/Makefile.am | 4 +- 5 files changed, 205 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 4b12b26900..9f61fc753b 100644 --- a/configure.ac +++ b/configure.ac @@ -59,6 +59,7 @@ dnl *** required versions of GStreamer stuff *** GST_REQ=1.3.0.1 GSTPB_REQ=1.3.0.1 GSTPG_REQ=1.3.0.1 +GSTPD_REQ=1.3.0.1 dnl *** autotools stuff **** @@ -176,6 +177,11 @@ GSTPG_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-good-$GST_API_VERSION --variabl AC_SUBST(GSTPG_PLUGINS_DIR) AC_MSG_NOTICE(Using GStreamer Good Plugins in $GSTPG_PLUGINS_DIR) +AG_GST_CHECK_GST_PLUGINS_BAD($GST_API_VERSION, [$GSTPD_REQ], [yes]) +GSTPD_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-bad-$GST_API_VERSION --variable pluginsdir` +AC_SUBST(GSTPD_PLUGINS_DIR) +AC_MSG_NOTICE(Using GStreamer Bad Plugins in $GSTPD_PLUGINS_DIR) + AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) AM_CONDITIONAL(HAVE_CHECK, test "x$HAVE_GST_CHECK" = "xyes") diff --git a/examples/test-video.c b/examples/test-video.c index 9bfb9d6427..044fbbf519 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -136,6 +136,7 @@ main (int argc, char *argv[]) gst_rtsp_media_factory_set_permissions (factory, permissions); gst_rtsp_permissions_unref (permissions); #endif + gst_rtsp_media_factory_set_profiles (factory, GST_RTSP_PROFILE_SAVP); /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test", factory); diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 53fc22c7b2..fa8bd6536e 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -26,6 +26,8 @@ #include +#include + #include "rtsp-sdp.h" static gboolean @@ -171,6 +173,93 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, gst_sdp_media_add_attribute (smedia, "control", tmp); g_free (tmp); + + /* check for srtp */ + do { + GstBuffer *srtpkey; + const GValue *val; + const gchar *srtpcipher, *srtpauth, *srtcpcipher, *srtcpauth; + GstMIKEYMessage *msg; + GstMIKEYPayload *payload; + GBytes *bytes; + GstMapInfo info; + const guint8 *data; + gsize size; + gchar *base64; + guint8 byte; + guint32 ssrc; + + val = gst_structure_get_value (s, "srtp-key"); + if (val == NULL) + break; + + srtpkey = gst_value_get_buffer (val); + if (srtpkey == NULL) + break; + + srtpcipher = gst_structure_get_string (s, "srtp-cipher"); + srtpauth = gst_structure_get_string (s, "srtp-auth"); + srtcpcipher = gst_structure_get_string (s, "srtcp-cipher"); + srtcpauth = gst_structure_get_string (s, "srtcp-auth"); + + if (srtpcipher == NULL || srtpauth == NULL || srtcpcipher == NULL || + srtcpauth == NULL) + break; + + msg = gst_mikey_message_new (); + /* unencrypted MIKEY message, we send this over TLS so this is allowed */ + gst_mikey_message_set_info (msg, GST_MIKEY_VERSION, GST_MIKEY_TYPE_PSK_INIT, + FALSE, GST_MIKEY_PRF_MIKEY_1, 0, GST_MIKEY_MAP_TYPE_SRTP); + /* add policy '0' for our SSRC */ + gst_rtsp_stream_get_ssrc (stream, &ssrc); + gst_mikey_message_add_cs_srtp (msg, 0, ssrc, 0); + /* timestamp is now */ + gst_mikey_message_add_t_now_ntp_utc (msg); + /* add some random data */ + gst_mikey_message_add_rand_len (msg, 16); + + /* the policy '0' is SRTP with the above discovered algorithms */ + payload = gst_mikey_payload_new (GST_MIKEY_PT_SP); + gst_mikey_payload_sp_set (payload, 0, GST_MIKEY_SEC_PROTO_SRTP); + + /* only AES-CM is supported */ + byte = 1; + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_ALG, 1, + &byte); + /* only HMAC-SHA1 */ + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_ALG, 1, + &byte); + /* we enable encryption on RTP and RTCP */ + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_ENC, 1, + &byte); + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTCP_ENC, 1, + &byte); + /* we enable authentication on RTP and RTCP */ + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_AUTH, 1, + &byte); + gst_mikey_message_add_payload (msg, payload); + + /* add the key in KEMAC */ + gst_buffer_map (srtpkey, &info, GST_MAP_READ); + gst_mikey_message_add_kemac (msg, GST_MIKEY_ENC_NULL, info.size, info.data, + GST_MIKEY_MAC_NULL, NULL); + gst_buffer_unmap (srtpkey, &info); + + /* now serialize this to bytes */ + bytes = gst_mikey_message_to_bytes (msg); + gst_mikey_message_free (msg); + /* and make it into base64 */ + data = g_bytes_get_data (bytes, &size); + base64 = g_base64_encode (data, size); + g_bytes_unref (bytes); + + tmp = g_strdup_printf ("mikey %s", base64); + g_free (base64); + + gst_sdp_media_add_attribute (smedia, "key-mgmt", tmp); + g_free (tmp); + } while (FALSE); + /* collect all other properties and add them to fmtp or attributes */ fmtp = g_string_new (""); g_string_append_printf (fmtp, "%d ", caps_pt); @@ -198,6 +287,10 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, continue; if (!strcmp (fname, "seqnum-base")) continue; + if (g_str_has_prefix (fname, "srtp-")) + continue; + if (g_str_has_prefix (fname, "srtcp-")) + continue; if (g_str_has_prefix (fname, "a-")) { /* attribute */ diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 9ec187c838..ef6581f0c1 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -79,6 +79,10 @@ struct _GstRTSPStreamPrivate /* the RTPSession object */ GObject *session; + /* SRTP encoder/decoder */ + GstElement *srtpenc; + GstElement *srtpdec; + /* sinks used for sending and receiving RTP and RTCP over ipv4, they share * sockets */ GstElement *udpsrc_v4[2]; @@ -1503,6 +1507,87 @@ static GstAppSinkCallbacks sink_cb = { handle_new_sample, }; +static GstElement * +get_rtp_encoder (GstRTSPStream * stream, guint session) +{ + GstRTSPStreamPrivate *priv = stream->priv; + + if (priv->srtpenc == NULL) { + gchar *name; + + name = g_strdup_printf ("srtpenc_%u", session); + priv->srtpenc = gst_element_factory_make ("srtpenc", name); + g_free (name); + + g_object_set (priv->srtpenc, "random-key", TRUE, NULL); + } + return gst_object_ref (priv->srtpenc); +} + +static GstElement * +request_rtp_encoder (GstElement * rtpbin, guint session, GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv = stream->priv; + GstElement *enc; + GstPad *pad; + gchar *name; + + if (priv->idx != session) + return NULL; + + GST_DEBUG_OBJECT (stream, "make RTP encoder for session %u", session); + + enc = get_rtp_encoder (stream, session); + name = g_strdup_printf ("rtp_sink_%d", session); + pad = gst_element_get_request_pad (enc, name); + g_free (name); + gst_object_unref (pad); + + return enc; +} + +static GstElement * +request_rtcp_encoder (GstElement * rtpbin, guint session, + GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv = stream->priv; + GstElement *enc; + GstPad *pad; + gchar *name; + + if (priv->idx != session) + return NULL; + + GST_DEBUG_OBJECT (stream, "make RTCP encoder for session %u", session); + + enc = get_rtp_encoder (stream, session); + name = g_strdup_printf ("rtcp_sink_%d", session); + pad = gst_element_get_request_pad (enc, name); + g_free (name); + gst_object_unref (pad); + + return enc; +} + +static GstElement * +request_rtcp_decoder (GstElement * rtpbin, guint session, + GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv = stream->priv; + + if (priv->idx != session) + return NULL; + + if (priv->srtpdec == NULL) { + gchar *name; + + name = g_strdup_printf ("srtpdec_%u", session); + priv->srtpdec = gst_element_factory_make ("srtpdec", name); + g_free (name); + } + return gst_object_ref (priv->srtpdec); +} + /** * gst_rtsp_stream_join_bin: * @stream: a #GstRTSPStream @@ -1549,6 +1634,21 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, /* update the dscp qos field in the sinks */ update_dscp_qos (stream); + if (priv->profiles & GST_RTSP_PROFILE_SAVP + || priv->profiles & GST_RTSP_PROFILE_SAVPF) { + /* For SRTP */ + g_signal_connect (rtpbin, "request-rtp-encoder", + (GCallback) request_rtp_encoder, stream); + g_signal_connect (rtpbin, "request-rtcp-encoder", + (GCallback) request_rtcp_encoder, stream); +#if 0 + g_signal_connect (rtpbin, "request-rtp-decoder", + (GCallback) request_rtp_decoder, stream); +#endif + g_signal_connect (rtpbin, "request-rtcp-decoder", + (GCallback) request_rtcp_decoder, stream); + } + /* get a pad for sending RTP */ name = g_strdup_printf ("send_rtp_sink_%u", idx); priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); @@ -1873,6 +1973,9 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_caps_unref (priv->caps); priv->caps = NULL; + if (priv->srtpenc) + gst_object_unref (priv->srtpenc); + priv->is_joined = FALSE; g_mutex_unlock (&priv->lock); diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 7ecc2bc11e..82e6d42081 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -11,8 +11,8 @@ TESTS_ENVIRONMENT = \ GST_STATE_IGNORE_ELEMENTS="$(STATE_IGNORE_ELEMENTS)" \ $(REGISTRY_ENVIRONMENT) \ GST_PLUGIN_SYSTEM_PATH_1_0= \ - GST_PLUGIN_PATH_1_0=$(GST_PLUGINS_DIR):$(GSTPB_PLUGINS_DIR):$(GSTPG_PLUGINS_DIR) \ - GST_PLUGIN_LOADING_WHITELIST="gstreamer:gst-plugins-base:gst-plugins-good" + GST_PLUGIN_PATH_1_0=$(GST_PLUGINS_DIR):$(GSTPB_PLUGINS_DIR):$(GSTPG_PLUGINS_DIR):$(GSTPD_PLUGINS_DIR) \ + GST_PLUGIN_LOADING_WHITELIST="gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad" # ths core dumps of some machines have PIDs appended From 131e1d6c77ccbe84bf2c351f3e04568a711956c4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 25 Mar 2014 12:41:33 +0100 Subject: [PATCH 0939/1776] test: print an error on failure --- examples/test-video.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/test-video.c b/examples/test-video.c index 044fbbf519..d6eb408587 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -59,6 +59,7 @@ main (int argc, char *argv[]) #endif #ifdef WITH_TLS GTlsCertificate *cert; + GError *error = NULL; #endif gst_init (&argc, &argv); @@ -95,7 +96,11 @@ main (int argc, char *argv[]) "tTdPbW829BoUtIeH64cCIQDggG5i48v7HPacPBIH1RaSVhXl8qHCpQD3qrIw3FMw" "DwIga8PqH5Sf5sHedy2+CiK0V4MRfoU4c3zQ6kArI+bEgSkCIQCLA1vXBiE31B5s" "bdHoYa1BXebfZVd+1Hd95IfEM5mbRwIgSkDuQwV55BBlvWph3U8wVIMIb4GStaH8" - "W535W8UBbEg=" "-----END PRIVATE KEY-----", -1, NULL); + "W535W8UBbEg=" "-----END PRIVATE KEY-----", -1, &error); + if (cert == NULL) { + g_printerr ("failed to parse PEM: %s\n", error->message); + return -1; + } gst_rtsp_auth_set_tls_certificate (auth, cert); g_object_unref (cert); #endif From 96f7c61a15da5eadb66f1575234a38fafd808655 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 25 Mar 2014 12:42:39 +0100 Subject: [PATCH 0940/1776] test: enable SRTP only on RTSPS We only want to enable SRTP when doing rtsp over TLS so that we can exchange the keys in a secure way. --- examples/test-video.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/test-video.c b/examples/test-video.c index d6eb408587..0d4a3a5a7b 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -140,8 +140,10 @@ main (int argc, char *argv[]) GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL); gst_rtsp_media_factory_set_permissions (factory, permissions); gst_rtsp_permissions_unref (permissions); -#endif +#ifdef WITH_TLS gst_rtsp_media_factory_set_profiles (factory, GST_RTSP_PROFILE_SAVP); +#endif +#endif /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test", factory); From 07ae06a595a110325615ddb7299ed960709a9ca3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 2 Apr 2014 12:27:24 +0200 Subject: [PATCH 0941/1776] media: fix docs --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index fa9821a38c..21aeaa058c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2593,7 +2593,7 @@ no_setup_sdp: * * Suspend @media. The state of the pipeline managed by @media is set to * GST_STATE_NULL but all streams are kept. @media can be prepared again - * with gst_rtsp_media_undo_reset() + * with gst_rtsp_media_unsuspend() * * @media must be prepared with gst_rtsp_media_prepare(); * From f8a6a5668d0f90bf786cc09b5a02f5e9d949b359 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 3 Apr 2014 12:57:13 +0200 Subject: [PATCH 0942/1776] client: cleanup error paths --- gst/rtsp-server/rtsp-client.c | 40 ++++++++++++++--------------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 99aa85abfd..0bee547cee 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1577,86 +1577,78 @@ no_transport: { GST_ERROR ("client %p: no transport", client); send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); - g_free (path); - return FALSE; + goto cleanup_path; } no_pool: { GST_ERROR ("client %p: no session pool configured", client); send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); - g_free (path); - return FALSE; + goto cleanup_path; } media_not_found_no_reply: { GST_ERROR ("client %p: media '%s' not found", client, path); - g_free (path); /* error reply is already sent */ - return FALSE; + goto cleanup_path; } media_not_found: { GST_ERROR ("client %p: media '%s' not found", client, path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); - g_free (path); - return FALSE; + goto cleanup_path; } control_not_found: { GST_ERROR ("client %p: no control in path '%s'", client, path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); g_object_unref (media); - g_free (path); - return FALSE; + goto cleanup_path; } stream_not_found: { GST_ERROR ("client %p: stream '%s' not found", client, control); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); g_object_unref (media); - g_free (path); - return FALSE; + goto cleanup_path; } service_unavailable: { GST_ERROR ("client %p: can't create session", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (media); - g_free (path); - return FALSE; + goto cleanup_path; } sessmedia_unavailable: { GST_ERROR ("client %p: can't create session media", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (media); - g_object_unref (session); - g_free (path); - return FALSE; + goto cleanup_session; } configure_media_failed_no_reply: { GST_ERROR ("client %p: configure_media failed", client); - g_object_unref (session); - g_free (path); /* error reply is already sent */ - return FALSE; + goto cleanup_session; } unsupported_transports: { GST_ERROR ("client %p: unsupported transports", client); send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); - gst_rtsp_transport_free (ct); - g_object_unref (session); - g_free (path); - return FALSE; + goto cleanup_transport; } unsupported_client_transport: { GST_ERROR ("client %p: unsupported client transport", client); send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); + goto cleanup_transport; + } + { + cleanup_transport: gst_rtsp_transport_free (ct); + cleanup_session: g_object_unref (session); + cleanup_path: g_free (path); return FALSE; } From 377ca6ed0f4d70a0f20ab482ab3e1c82a2d9ac74 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 2 Apr 2014 12:36:16 +0200 Subject: [PATCH 0943/1776] stream: add method to set crypto info Make a method to configure the crypto information of a stream. Set udpsrc in READY instead of PAUSED so that we can configure caps later. --- gst/rtsp-server/rtsp-stream.c | 70 ++++++++++++++++++++++++++++++++--- gst/rtsp-server/rtsp-stream.h | 3 ++ 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index ef6581f0c1..85b4ee0d76 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -82,6 +82,7 @@ struct _GstRTSPStreamPrivate /* SRTP encoder/decoder */ GstElement *srtpenc; GstElement *srtpdec; + GHashTable *keys; /* sinks used for sending and receiving RTP and RTCP over ipv4, they share * sockets */ @@ -209,6 +210,9 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->protocols = DEFAULT_PROTOCOLS; g_mutex_init (&priv->lock); + + priv->keys = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) gst_caps_unref); } static void @@ -240,6 +244,8 @@ gst_rtsp_stream_finalize (GObject * obj) g_free (priv->control); g_mutex_clear (&priv->lock); + g_hash_table_unref (priv->keys); + G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); } @@ -1057,10 +1063,10 @@ again: g_object_set (G_OBJECT (udpsrc0), "socket", rtp_socket, NULL); g_object_set (G_OBJECT (udpsrc1), "socket", rtcp_socket, NULL); - ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED); + ret = gst_element_set_state (udpsrc0, GST_STATE_READY); if (ret == GST_STATE_CHANGE_FAILURE) goto element_error; - ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED); + ret = gst_element_set_state (udpsrc1, GST_STATE_READY); if (ret == GST_STATE_CHANGE_FAILURE) goto element_error; @@ -1569,6 +1575,22 @@ request_rtcp_encoder (GstElement * rtpbin, guint session, return enc; } +static GstCaps * +request_key (GstElement * srtpdec, guint ssrc, GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv = stream->priv; + GstCaps *caps; + + GST_DEBUG ("request key %08x", ssrc); + + g_mutex_lock (&priv->lock); + if ((caps = g_hash_table_lookup (priv->keys, GINT_TO_POINTER (ssrc)))) + gst_caps_ref (caps); + g_mutex_unlock (&priv->lock); + + return caps; +} + static GstElement * request_rtcp_decoder (GstElement * rtpbin, guint session, GstRTSPStream * stream) @@ -1584,6 +1606,9 @@ request_rtcp_decoder (GstElement * rtpbin, guint session, name = g_strdup_printf ("srtpdec_%u", session); priv->srtpdec = gst_element_factory_make ("srtpdec", name); g_free (name); + + g_signal_connect (priv->srtpdec, "request-key", + (GCallback) request_key, stream); } return gst_object_ref (priv->srtpdec); } @@ -1641,10 +1666,6 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, (GCallback) request_rtp_encoder, stream); g_signal_connect (rtpbin, "request-rtcp-encoder", (GCallback) request_rtcp_encoder, stream); -#if 0 - g_signal_connect (rtpbin, "request-rtp-decoder", - (GCallback) request_rtp_decoder, stream); -#endif g_signal_connect (rtpbin, "request-rtcp-decoder", (GCallback) request_rtcp_decoder, stream); } @@ -2310,6 +2331,43 @@ gst_rtsp_stream_remove_transport (GstRTSPStream * stream, return res; } +/** + * gst_rtsp_stream_update_crypto: + * @stream: a #GstRTSPStream + * @ssrc: the SSRC + * @crypto: (transfer none) (allow none): a #GstCaps with crypto info + * + * Update the new crypto information for @ssrc in @stream. If information + * for @ssrc did not exist, it will be added. If information + * for @ssrc existed, it will be replaced. If @crypto is %NULL, it will + * be removed from @stream. + * + * Returns: %TRUE if @crypto could be updated + */ +gboolean +gst_rtsp_stream_update_crypto (GstRTSPStream * stream, + guint ssrc, GstCaps * crypto) +{ + GstRTSPStreamPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + g_return_val_if_fail (GST_IS_CAPS (crypto), FALSE); + + priv = stream->priv; + + GST_DEBUG_OBJECT (stream, "update key for %08x", ssrc); + + g_mutex_lock (&priv->lock); + if (crypto) + g_hash_table_insert (priv->keys, GINT_TO_POINTER (ssrc), + gst_caps_ref (crypto)); + else + g_hash_table_remove (priv->keys, GINT_TO_POINTER (ssrc)); + g_mutex_unlock (&priv->lock); + + return TRUE; +} + /** * gst_rtsp_stream_get_rtp_socket: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 0e465b282b..ca8be0a520 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -144,6 +144,9 @@ GSocket * gst_rtsp_stream_get_rtp_socket (GstRTSPStream *stream, GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream *stream, GSocketFamily family); +gboolean gst_rtsp_stream_update_crypto (GstRTSPStream * stream, + guint ssrc, GstCaps * crypto); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object From 0d22b798ae02dd09e9d1d679d2c74b606140b5d3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 3 Apr 2014 12:52:51 +0200 Subject: [PATCH 0944/1776] client: parse the mikey response from the client Parse the mikey response from the client and update the policy for each SSRC. --- gst/rtsp-server/rtsp-client.c | 242 +++++++++++++++++++++++++++++++++- 1 file changed, 241 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 0bee547cee..12589bef56 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -42,6 +42,8 @@ #include #include +#include + #include "rtsp-client.h" #include "rtsp-sdp.h" #include "rtsp-params.h" @@ -1397,13 +1399,238 @@ make_server_transport (GstRTSPClient * client, GstRTSPContext * ctx, return st; } +static gboolean +mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy) +{ + const gchar *srtp_cipher; + const gchar *srtp_auth; + const GstMIKEYPayload *sp; + guint i; + + /* loop over Security policy until we find one containing policy */ + for (i = 0;; i++) { + if ((sp = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, i)) == NULL) + break; + + if (((GstMIKEYPayloadSP *) sp)->policy == policy) + break; + } + + /* the default ciphers */ + srtp_cipher = "aes-128-icm"; + srtp_auth = "hmac-sha1-80"; + + /* now override the defaults with what is in the Security Policy */ + if (sp != NULL) { + guint len; + + /* collect all the params and go over them */ + len = gst_mikey_payload_sp_get_n_params (sp); + for (i = 0; i < len; i++) { + const GstMIKEYPayloadSPParam *param = + gst_mikey_payload_sp_get_param (sp, i); + + switch (param->type) { + case GST_MIKEY_SP_SRTP_ENC_ALG: + switch (param->val[0]) { + case 0: + srtp_cipher = "null"; + break; + case 2: + case 1: + srtp_cipher = "aes-128-icm"; + break; + default: + break; + } + break; + case GST_MIKEY_SP_SRTP_AUTH_ALG: + switch (param->val[0]) { + case 0: + srtp_auth = "null"; + break; + case 2: + case 1: + srtp_auth = "hmac-sha1-80"; + break; + default: + break; + } + break; + case GST_MIKEY_SP_SRTP_SRTP_ENC: + break; + case GST_MIKEY_SP_SRTP_SRTCP_ENC: + break; + default: + break; + } + } + } + /* now configure the SRTP parameters */ + gst_caps_set_simple (caps, + "srtp-cipher", G_TYPE_STRING, srtp_cipher, + "srtp-auth", G_TYPE_STRING, srtp_auth, + "srtcp-cipher", G_TYPE_STRING, srtp_cipher, + "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL); + + return TRUE; +} + +static gboolean +handle_mikey_data (GstRTSPClient * client, GstRTSPContext * ctx, + guint8 * data, gsize size) +{ + GstMIKEYMessage *msg; + guint i, n_cs; + GstCaps *caps = NULL; + GstMIKEYPayloadKEMAC *kemac; + GstBuffer *key; + + /* the MIKEY message contains a CSB or crypto session bundle. It is a + * set of Crypto Sessions protected with the same master key. + * In the context of SRTP, an RTP and its RTCP stream is part of a + * crypto session */ + if ((msg = gst_mikey_message_new_from_data (data, size)) == NULL) + goto parse_failed; + + /* we can only handle SRTP crypto sessions for now */ + if (msg->map_type != GST_MIKEY_MAP_TYPE_SRTP) + goto invalid_map_type; + + /* get the number of crypto sessions. This maps SSRC to its + * security parameters */ + n_cs = gst_mikey_message_get_n_cs (msg); + if (n_cs == 0) + goto no_crypto_sessions; + + /* we also need keys */ + if (!(kemac = (GstMIKEYPayloadKEMAC *) gst_mikey_message_find_payload + (msg, GST_MIKEY_PT_KEMAC, 0))) + goto no_keys; + + /* we don't support encrypted keys */ + if (kemac->enc_alg != GST_MIKEY_ENC_NULL + || kemac->mac_alg != GST_MIKEY_MAC_NULL) + goto unsupported_encryption; + + /* FIXME get Key data sub-payload */ + key = + gst_buffer_new_wrapped (g_memdup (kemac->enc_data, kemac->enc_len), + kemac->enc_len); + + /* go over all crypto sessions and create the security policy for each + * SSRC */ + for (i = 0; i < n_cs; i++) { + const GstMIKEYMapSRTP *map = gst_mikey_message_get_cs_srtp (msg, i); + + caps = gst_caps_new_simple ("application/x-srtp", + "ssrc", G_TYPE_UINT, map->ssrc, + "roc", G_TYPE_UINT, map->roc, "srtp-key", GST_TYPE_BUFFER, key, NULL); + mikey_apply_policy (caps, msg, map->policy); + + gst_rtsp_stream_update_crypto (ctx->stream, map->ssrc, caps); + gst_caps_unref (caps); + } + gst_mikey_message_free (msg); + + return TRUE; + + /* ERRORS */ +parse_failed: + { + GST_DEBUG_OBJECT (client, "failed to parse MIKEY message"); + return FALSE; + } +invalid_map_type: + { + GST_DEBUG_OBJECT (client, "invalid map type %d", msg->map_type); + goto cleanup_message; + } +no_crypto_sessions: + { + GST_DEBUG_OBJECT (client, "no crypto sessions"); + goto cleanup_message; + } +no_keys: + { + GST_DEBUG_OBJECT (client, "no keys found"); + goto cleanup_message; + } +unsupported_encryption: + { + GST_DEBUG_OBJECT (client, "unsupported key encryption"); + goto cleanup_message; + } + { + cleanup_message: + gst_mikey_message_free (msg); + return FALSE; + } +} + +#define IS_STRIP_CHAR(c) (g_ascii_isspace ((guchar)(c)) || ((c) == '\"')) + +static void +strip_chars (gchar * str) +{ + gchar *s; + gsize len; + + len = strlen (str); + while (len--) { + if (!IS_STRIP_CHAR (str[len])) + break; + str[len] = '\0'; + } + for (s = str; *s && IS_STRIP_CHAR (*s); s++); + memmove (str, s, len + 1); +} + +/** + * KeyMgmt = "KeyMgmt" ":" key-mgmt-spec 0*("," key-mgmt-spec) + * key-mgmt-spec = "prot" "=" KMPID ";" ["uri" "=" %x22 URI %x22 ";"] + */ +static gboolean +handle_keymgmt (GstRTSPClient * client, GstRTSPContext * ctx, gchar * keymgmt) +{ + gchar **specs; + gint i, j; + + specs = g_strsplit (keymgmt, ",", 0); + for (i = 0; specs[i]; i++) { + gchar **split; + + split = g_strsplit (specs[i], ";", 0); + for (j = 0; split[j]; j++) { + g_strstrip (split[j]); + if (g_str_has_prefix (split[j], "prot=")) { + g_strstrip (split[j] + 5); + if (!g_str_equal (split[j] + 5, "mikey")) + break; + GST_DEBUG ("found mikey"); + } else if (g_str_has_prefix (split[j], "uri=")) { + strip_chars (split[j] + 4); + GST_DEBUG ("found uri '%s'", split[j] + 4); + } else if (g_str_has_prefix (split[j], "data=")) { + guchar *data; + gsize size; + strip_chars (split[j] + 5); + GST_DEBUG ("found data '%s'", split[j] + 5); + data = g_base64_decode_inplace (split[j] + 5, &size); + handle_mikey_data (client, ctx, data, size); + } + } + } + return TRUE; +} + static gboolean handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPClientPrivate *priv = client->priv; GstRTSPResult res; GstRTSPUrl *uri; - gchar *transport; + gchar *transport, *keymgmt; GstRTSPTransport *ct, *st; GstRTSPStatusCode code; GstRTSPSession *session; @@ -1520,6 +1747,13 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!klass->configure_client_transport (client, ctx, ct)) goto unsupported_client_transport; + /* parse the keymgmt */ + if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_KEYMGMT, + &keymgmt, 0) == GST_RTSP_OK) { + if (!handle_keymgmt (client, ctx, keymgmt)) + goto keymgmt_error; + } + /* set in the session media transport */ trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct); @@ -1643,6 +1877,12 @@ unsupported_client_transport: send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); goto cleanup_transport; } +keymgmt_error: + { + GST_ERROR ("client %p: keymgmt error", client); + send_generic_response (client, GST_RTSP_STS_KEY_MANAGEMENT_FAILURE, ctx); + goto cleanup_transport; + } { cleanup_transport: gst_rtsp_transport_free (ct); From 248db047207e7a8eaf37f19a6c00e027eb350181 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 4 Apr 2014 17:39:36 +0200 Subject: [PATCH 0945/1776] rtsp: update for MIKEY API changes --- gst/rtsp-server/rtsp-client.c | 12 ++++++++---- gst/rtsp-server/rtsp-sdp.c | 19 ++++++++++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 12589bef56..30c6b4dd33 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1484,13 +1484,14 @@ handle_mikey_data (GstRTSPClient * client, GstRTSPContext * ctx, guint i, n_cs; GstCaps *caps = NULL; GstMIKEYPayloadKEMAC *kemac; + const GstMIKEYPayloadKeyData *pkd; GstBuffer *key; /* the MIKEY message contains a CSB or crypto session bundle. It is a * set of Crypto Sessions protected with the same master key. * In the context of SRTP, an RTP and its RTCP stream is part of a * crypto session */ - if ((msg = gst_mikey_message_new_from_data (data, size)) == NULL) + if ((msg = gst_mikey_message_new_from_data (data, size, NULL, NULL)) == NULL) goto parse_failed; /* we can only handle SRTP crypto sessions for now */ @@ -1513,10 +1514,13 @@ handle_mikey_data (GstRTSPClient * client, GstRTSPContext * ctx, || kemac->mac_alg != GST_MIKEY_MAC_NULL) goto unsupported_encryption; - /* FIXME get Key data sub-payload */ + /* get Key data sub-payload */ + pkd = (const GstMIKEYPayloadKeyData *) + gst_mikey_payload_kemac_get_sub (&kemac->pt, 0); + key = - gst_buffer_new_wrapped (g_memdup (kemac->enc_data, kemac->enc_len), - kemac->enc_len); + gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len), + pkd->key_len); /* go over all crypto sessions and create the security policy for each * SSRC */ diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index fa8bd6536e..13af74d4cd 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -180,7 +180,7 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, const GValue *val; const gchar *srtpcipher, *srtpauth, *srtcpcipher, *srtcpauth; GstMIKEYMessage *msg; - GstMIKEYPayload *payload; + GstMIKEYPayload *payload, *pkd; GBytes *bytes; GstMapInfo info; const guint8 *data; @@ -239,14 +239,23 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, &byte); gst_mikey_message_add_payload (msg, payload); - /* add the key in KEMAC */ + /* make unencrypted KEMAC */ + payload = gst_mikey_payload_new (GST_MIKEY_PT_KEMAC); + gst_mikey_payload_kemac_set (payload, GST_MIKEY_ENC_NULL, + GST_MIKEY_MAC_NULL); + + /* add the key in key data */ + pkd = gst_mikey_payload_new (GST_MIKEY_PT_KEY_DATA); gst_buffer_map (srtpkey, &info, GST_MAP_READ); - gst_mikey_message_add_kemac (msg, GST_MIKEY_ENC_NULL, info.size, info.data, - GST_MIKEY_MAC_NULL, NULL); + gst_mikey_payload_key_data_set_key (pkd, GST_MIKEY_KD_TEK, info.size, + info.data); gst_buffer_unmap (srtpkey, &info); + /* add key data to KEMAC */ + gst_mikey_payload_kemac_add_sub (payload, pkd); + gst_mikey_message_add_payload (msg, payload); /* now serialize this to bytes */ - bytes = gst_mikey_message_to_bytes (msg); + bytes = gst_mikey_message_to_bytes (msg, NULL, NULL); gst_mikey_message_free (msg); /* and make it into base64 */ data = g_bytes_get_data (bytes, &size); From 7f40d3d87f4a1f49a3a69f8374f56f4bde2d1918 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 8 Apr 2014 12:08:17 +0200 Subject: [PATCH 0946/1776] media: protect status with lock Make sure we only update the status with the lock. --- gst/rtsp-server/rtsp-media.c | 109 ++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 21aeaa058c..facc40fa6c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1471,6 +1471,52 @@ media_streams_set_blocked (GstRTSPMedia * media, gboolean blocked) g_ptr_array_foreach (priv->streams, (GFunc) stream_update_blocked, media); } +static void +gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status) +{ + GstRTSPMediaPrivate *priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->status = status; + GST_DEBUG ("setting new status to %d", status); + g_cond_broadcast (&priv->cond); + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_get_status: + * @media: a #GstRTSPMedia + * + * Get the status of @media. When @media is busy preparing, this function waits + * until @media is prepared or in error. + * + * Returns: the status of @media. + */ +GstRTSPMediaStatus +gst_rtsp_media_get_status (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + GstRTSPMediaStatus result; + gint64 end_time; + + g_mutex_lock (&priv->lock); + end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND; + /* while we are preparing, wait */ + while (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) { + GST_DEBUG ("waiting for status change"); + if (!g_cond_wait_until (&priv->cond, &priv->lock, end_time)) { + GST_DEBUG ("timeout, assuming error status"); + priv->status = GST_RTSP_MEDIA_STATUS_ERROR; + } + } + /* could be success or error */ + result = priv->status; + GST_DEBUG ("got status %d", result); + g_mutex_unlock (&priv->lock); + + return result; +} + /** * gst_rtsp_media_seek: * @media: a #GstRTSPMedia @@ -1543,7 +1589,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); - priv->status = GST_RTSP_MEDIA_STATUS_PREPARING; + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); if (priv->blocked) media_streams_set_blocked (media, TRUE); @@ -1624,52 +1670,6 @@ preroll_failed: } } -static void -gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status) -{ - GstRTSPMediaPrivate *priv = media->priv; - - g_mutex_lock (&priv->lock); - priv->status = status; - GST_DEBUG ("setting new status to %d", status); - g_cond_broadcast (&priv->cond); - g_mutex_unlock (&priv->lock); -} - -/** - * gst_rtsp_media_get_status: - * @media: a #GstRTSPMedia - * - * Get the status of @media. When @media is busy preparing, this function waits - * until @media is prepared or in error. - * - * Returns: the status of @media. - */ -GstRTSPMediaStatus -gst_rtsp_media_get_status (GstRTSPMedia * media) -{ - GstRTSPMediaPrivate *priv = media->priv; - GstRTSPMediaStatus result; - gint64 end_time; - - g_mutex_lock (&priv->lock); - end_time = g_get_monotonic_time () + 20 * G_TIME_SPAN_SECOND; - /* while we are preparing, wait */ - while (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) { - GST_DEBUG ("waiting for status change"); - if (!g_cond_wait_until (&priv->cond, &priv->lock, end_time)) { - GST_DEBUG ("timeout, assuming error status"); - priv->status = GST_RTSP_MEDIA_STATUS_ERROR; - } - } - /* could be success or error */ - result = priv->status; - GST_DEBUG ("got status %d", result); - g_mutex_unlock (&priv->lock); - - return result; -} - static void stream_collect_blocking (GstRTSPStream * stream, gboolean * blocked) { @@ -2184,7 +2184,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) priv->buffering = FALSE; priv->thread = thread; /* we're preparing now */ - priv->status = GST_RTSP_MEDIA_STATUS_PREPARING; + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline)); @@ -2317,7 +2317,7 @@ finish_unprepare (GstRTSPMedia * media) priv->nettime = NULL; priv->reused = TRUE; - priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARED; + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_UNPREPARED); /* when the media is not reusable, this will effectively unref the media and * recreate it */ @@ -2348,7 +2348,6 @@ default_unprepare (GstRTSPMedia * media) /* we need to go to playing again for the EOS to propagate, normally in this * state, nothing is receiving data from us anymore so this is ok. */ set_state (media, GST_STATE_PLAYING); - priv->status = GST_RTSP_MEDIA_STATUS_UNPREPARING; } else { finish_unprepare (media); } @@ -2387,6 +2386,8 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) set_target_state (media, GST_STATE_NULL, FALSE); success = TRUE; + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_UNPREPARING); + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) { GstRTSPMediaClass *klass; @@ -2638,7 +2639,7 @@ gst_rtsp_media_suspend (GstRTSPMedia * media) } /* let the streams do the state changes freely, if any */ media_streams_set_blocked (media, FALSE); - priv->status = GST_RTSP_MEDIA_STATUS_SUSPENDED; + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_SUSPENDED); done: g_rec_mutex_unlock (&priv->state_lock); @@ -2682,14 +2683,14 @@ gst_rtsp_media_unsuspend (GstRTSPMedia * media) switch (priv->suspend_mode) { case GST_RTSP_SUSPEND_MODE_NONE: - priv->status = GST_RTSP_MEDIA_STATUS_PREPARED; + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); break; case GST_RTSP_SUSPEND_MODE_PAUSE: - priv->status = GST_RTSP_MEDIA_STATUS_PREPARED; + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); break; case GST_RTSP_SUSPEND_MODE_RESET: { - priv->status = GST_RTSP_MEDIA_STATUS_PREPARING; + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); if (!start_preroll (media)) goto start_failed; g_rec_mutex_unlock (&priv->state_lock); From fd5e949169d71fe23102d6120853e28ef45f5ae4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 8 Apr 2014 14:49:41 +0200 Subject: [PATCH 0947/1776] media: release the state lock when going to NULL Set our state to UNPREPARING and release the state-lock before setting the pipeline to the NULL state. This way, any pad-added callback will be able to take the state-lock and check that we are now unpreparing instead of deadlocking. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=727102 --- gst/rtsp-server/rtsp-media.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index facc40fa6c..ff40ec8b3f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1920,11 +1920,14 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) stream = gst_rtsp_media_create_stream (media, pay, pad); gst_object_unref (pay); - g_object_set_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream", stream); - GST_INFO ("pad added %s:%s, stream %p", GST_DEBUG_PAD_NAME (pad), stream); g_rec_mutex_lock (&priv->state_lock); + if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARING) + goto not_preparing; + + g_object_set_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream", stream); + /* we will be adding elements below that will cause ASYNC_DONE to be * posted in the bus. We want to ignore those messages until the * pipeline really prerolled. */ @@ -1937,6 +1940,17 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) priv->adding = FALSE; g_rec_mutex_unlock (&priv->state_lock); + + return; + + /* ERRORS */ +not_preparing: + { + gst_rtsp_media_remove_stream (media, stream); + g_rec_mutex_unlock (&priv->state_lock); + GST_INFO ("ignore pad because we are not preparing"); + return; + } } static void @@ -2278,7 +2292,11 @@ finish_unprepare (GstRTSPMedia * media) GST_DEBUG ("shutting down"); + /* release the lock on shutdown, otherwise pad_added_cb might try to + * acquire the lock and then we deadlock */ + g_rec_mutex_unlock (&priv->state_lock); set_state (media, GST_STATE_NULL); + g_rec_mutex_lock (&priv->state_lock); remove_fakesink (priv); for (i = 0; i < priv->streams->len; i++) { From a3e6b11f11e18f2d67cffafdd65a51f47cd7b64f Mon Sep 17 00:00:00 2001 From: Linus Svensson Date: Tue, 1 Apr 2014 13:16:26 +0200 Subject: [PATCH 0948/1776] rtsp-media: Unblock blocked streams in unprepare The streams will be blocked when a live media is prepared. The streams should be unblocked in gst_rtsp_media_unprepare. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=727231 --- gst/rtsp-server/rtsp-media.c | 2 ++ tests/check/gst/media.c | 67 +++++++++++++++++++++--------------- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index ff40ec8b3f..9848171106 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2401,6 +2401,8 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) goto is_busy; GST_INFO ("unprepare media %p", media); + if (priv->blocked) + media_streams_set_blocked (media, FALSE); set_target_state (media, GST_STATE_NULL, FALSE); success = TRUE; diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index df3e1c2aad..a0261594ad 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -123,6 +123,43 @@ GST_START_TEST (test_media) GST_END_TEST; +static void +test_prepare_reusable (GstRTSPThreadPool * pool, const gchar * launch_line) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPThread *thread; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, launch_line); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 1); + + g_object_set (G_OBJECT (media), "reusable", TRUE, NULL); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (gst_rtsp_media_unprepare (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 1); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (gst_rtsp_media_unprepare (media)); + + g_object_unref (media); + gst_rtsp_url_free (url); + g_object_unref (factory); +} + GST_START_TEST (test_media_prepare) { GstRTSPMediaFactory *factory; @@ -161,34 +198,10 @@ GST_START_TEST (test_media_prepare) g_object_unref (factory); /* test reusable media */ - factory = gst_rtsp_media_factory_new (); - fail_if (gst_rtsp_media_factory_is_shared (factory)); - fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", - &url) == GST_RTSP_OK); + test_prepare_reusable (pool, "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + test_prepare_reusable (pool, + "( videotestsrc is-live=true ! rtpvrawpay pt=96 name=pay0 )"); - gst_rtsp_media_factory_set_launch (factory, - "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); - - media = gst_rtsp_media_factory_construct (factory, url); - fail_unless (GST_IS_RTSP_MEDIA (media)); - fail_unless (gst_rtsp_media_n_streams (media) == 1); - - g_object_set (G_OBJECT (media), "reusable", TRUE, NULL); - - thread = gst_rtsp_thread_pool_get_thread (pool, - GST_RTSP_THREAD_TYPE_MEDIA, NULL); - fail_unless (gst_rtsp_media_prepare (media, thread)); - fail_unless (gst_rtsp_media_unprepare (media)); - fail_unless (gst_rtsp_media_n_streams (media) == 1); - - thread = gst_rtsp_thread_pool_get_thread (pool, - GST_RTSP_THREAD_TYPE_MEDIA, NULL); - fail_unless (gst_rtsp_media_prepare (media, thread)); - fail_unless (gst_rtsp_media_unprepare (media)); - - g_object_unref (media); - gst_rtsp_url_free (url); - g_object_unref (factory); g_object_unref (pool); } From 6916875a0b31bc2484cb16613813974348ba068c Mon Sep 17 00:00:00 2001 From: Linus Svensson Date: Tue, 1 Apr 2014 16:55:13 +0200 Subject: [PATCH 0949/1776] media test: cleanup the thread pool in tests --- tests/check/gst/media.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index a0261594ad..e23fa3740b 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -94,6 +94,8 @@ GST_START_TEST (test_launch) g_object_unref (factory); g_object_unref (pool); + + gst_rtsp_thread_pool_cleanup (); } GST_END_TEST; @@ -203,6 +205,8 @@ GST_START_TEST (test_media_prepare) "( videotestsrc is-live=true ! rtpvrawpay pt=96 name=pay0 )"); g_object_unref (pool); + gst_rtsp_thread_stop (thread); + gst_rtsp_thread_pool_cleanup (); } GST_END_TEST; @@ -284,6 +288,8 @@ GST_START_TEST (test_media_dyn_prepare) gst_object_unref (srcpad); g_object_unref (media); g_object_unref (pool); + + gst_rtsp_thread_pool_cleanup (); } GST_END_TEST; @@ -355,6 +361,8 @@ GST_START_TEST (test_media_reset) gst_rtsp_url_free (url); g_object_unref (factory); g_object_unref (pool); + + gst_rtsp_thread_pool_cleanup (); } GST_END_TEST; From 9c0ef4d9f884200764400715ee7813c3f9e768ca Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 31 Mar 2014 11:00:11 +0200 Subject: [PATCH 0950/1776] media: Make media_prepare() fail if port allocation fails Fixes https://bugzilla.gnome.org/show_bug.cgi?id=727376 --- gst/rtsp-server/rtsp-media.c | 18 ++++++++++++---- tests/check/gst/media.c | 40 ++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 9848171106..de47c68f7c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1935,8 +1935,10 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) /* join the element in the PAUSED state because this callback is * called from the streaming thread and it is PAUSED */ - gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline), - priv->rtpbin, GST_STATE_PAUSED); + if (!gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline), + priv->rtpbin, GST_STATE_PAUSED)) { + GST_WARNING ("failed to join bin element"); + } priv->adding = FALSE; g_rec_mutex_unlock (&priv->state_lock); @@ -2089,8 +2091,10 @@ start_prepare (GstRTSPMedia * media) stream = g_ptr_array_index (priv->streams, i); - gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline), - priv->rtpbin, GST_STATE_NULL); + if (!gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline), + priv->rtpbin, GST_STATE_NULL)) { + goto join_bin_failed; + } } for (walk = priv->dynamic; walk; walk = g_list_next (walk)) { @@ -2119,6 +2123,12 @@ start_prepare (GstRTSPMedia * media) return FALSE; +join_bin_failed: + { + GST_WARNING ("failed to join bin element"); + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR); + return FALSE; + } preroll_failed: { GST_WARNING ("failed to preroll pipeline"); diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index e23fa3740b..307c9e12f8 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -294,6 +294,45 @@ GST_START_TEST (test_media_dyn_prepare) GST_END_TEST; +GST_START_TEST (test_media_prepare_port_alloc_fail) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + GstRTSPAddressPool *addrpool; + + pool = gst_rtsp_thread_pool_new (); + + factory = gst_rtsp_media_factory_new (); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( fakesrc is-live=true ! text/plain ! rtpgstpay name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + addrpool = gst_rtsp_address_pool_new (); + fail_unless (gst_rtsp_address_pool_add_range (addrpool, "192.168.1.1", + "192.168.1.1", 6000, 6001, 0)); + gst_rtsp_media_set_address_pool (media, addrpool); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_if (gst_rtsp_media_prepare (media, thread)); + + g_object_unref (media); + g_object_unref (addrpool); + gst_rtsp_url_free (url); + g_object_unref (factory); + g_object_unref (pool); +} + +GST_END_TEST; + GST_START_TEST (test_media_take_pipeline) { GstRTSPMediaFactory *factory; @@ -379,6 +418,7 @@ rtspmedia_suite (void) tcase_add_test (tc, test_media); tcase_add_test (tc, test_media_prepare); tcase_add_test (tc, test_media_dyn_prepare); + tcase_add_test (tc, test_media_prepare_port_alloc_fail); tcase_add_test (tc, test_media_take_pipeline); tcase_add_test (tc, test_media_reset); From 132f77751d72b9942de25aee4071ba27b9829d28 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 2 Apr 2014 12:03:32 +0200 Subject: [PATCH 0951/1776] client: remove watch of the second client after http tunnel setup The second client will be freed after the HTTP tunnel has been set up. Make sure it's RTSP watch is never dispatched again. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=727488 --- gst/rtsp-server/rtsp-client.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 30c6b4dd33..c3c34eb3a9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -3031,9 +3031,15 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data) /* merge the tunnels into the first client */ gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection); + gst_rtsp_watch_reset (priv->watch); gst_rtsp_watch_reset (opriv->watch); g_object_unref (oclient); + /* the old client owns the tunnel now, the new one will be freed */ + g_source_destroy ((GSource *) priv->watch); + priv->watch = NULL; + gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + return GST_RTSP_OK; /* ERRORS */ From 0493a63a652bec39b2db56c2c0c4c4779091c6f5 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Thu, 3 Apr 2014 12:19:51 +0200 Subject: [PATCH 0952/1776] client: support for POST before GET when setting up a tunnel --- gst/rtsp-server/rtsp-client.c | 128 ++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 61 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c3c34eb3a9..8b253fa82e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2958,28 +2958,6 @@ tunnel_existed: } } -static GstRTSPStatusCode -tunnel_start (GstRTSPWatch * watch, gpointer user_data) -{ - GstRTSPClient *client = GST_RTSP_CLIENT (user_data); - GstRTSPClientPrivate *priv = client->priv; - - GST_INFO ("client %p: tunnel start (connection %p)", client, - priv->connection); - - if (!remember_tunnel (client)) - goto tunnel_error; - - return GST_RTSP_STS_OK; - - /* ERRORS */ -tunnel_error: - { - GST_ERROR ("client %p: error starting tunnel", client); - return GST_RTSP_STS_SERVICE_UNAVAILABLE; - } -} - static GstRTSPResult tunnel_lost (GstRTSPWatch * watch, gpointer user_data) { @@ -2995,72 +2973,100 @@ tunnel_lost (GstRTSPWatch * watch, gpointer user_data) return GST_RTSP_OK; } -static GstRTSPResult -tunnel_complete (GstRTSPWatch * watch, gpointer user_data) +static gboolean +handle_tunnel (GstRTSPClient * client) { - const gchar *tunnelid; - GstRTSPClient *client = GST_RTSP_CLIENT (user_data); GstRTSPClientPrivate *priv = client->priv; GstRTSPClient *oclient; GstRTSPClientPrivate *opriv; + const gchar *tunnelid; - GST_INFO ("client %p: tunnel complete", client); - - /* find previous tunnel */ tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection); if (tunnelid == NULL) goto no_tunnelid; + /* check for previous tunnel */ g_mutex_lock (&tunnels_lock); - if (!(oclient = g_hash_table_lookup (tunnels, tunnelid))) - goto no_tunnel; + oclient = g_hash_table_lookup (tunnels, tunnelid); - /* remove the old client from the table. ref before because removing it will - * remove the ref to it. */ - g_object_ref (oclient); - g_hash_table_remove (tunnels, tunnelid); + if (oclient == NULL) { + /* no previous tunnel, remember tunnel */ + g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client)); + g_mutex_unlock (&tunnels_lock); - opriv = oclient->priv; + GST_INFO ("client %p: no previous tunnel found, remembering tunnel (%p)", + client, priv->connection); + } else { + /* merge both tunnels into the first client */ + /* remove the old client from the table. ref before because removing it will + * remove the ref to it. */ + g_object_ref (oclient); + g_hash_table_remove (tunnels, tunnelid); + g_mutex_unlock (&tunnels_lock); - if (opriv->watch == NULL) - goto tunnel_closed; - g_mutex_unlock (&tunnels_lock); + opriv = oclient->priv; - GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient, - opriv->connection, priv->connection); + if (opriv->watch == NULL) + goto tunnel_closed; - /* merge the tunnels into the first client */ - gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection); - gst_rtsp_watch_reset (priv->watch); - gst_rtsp_watch_reset (opriv->watch); - g_object_unref (oclient); + GST_INFO ("client %p: found previous tunnel %p (old %p, new %p)", client, + oclient, opriv->connection, priv->connection); - /* the old client owns the tunnel now, the new one will be freed */ - g_source_destroy ((GSource *) priv->watch); - priv->watch = NULL; - gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection); + gst_rtsp_watch_reset (priv->watch); + gst_rtsp_watch_reset (opriv->watch); + g_object_unref (oclient); - return GST_RTSP_OK; + /* the old client owns the tunnel now, the new one will be freed */ + g_source_destroy ((GSource *) priv->watch); + priv->watch = NULL; + gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + } + + return TRUE; /* ERRORS */ no_tunnelid: { GST_ERROR ("client %p: no tunnelid provided", client); - return GST_RTSP_ERROR; - } -no_tunnel: - { - g_mutex_unlock (&tunnels_lock); - GST_ERROR ("client %p: tunnel session %s not found", client, tunnelid); - return GST_RTSP_ERROR; + return FALSE; } tunnel_closed: { - g_mutex_unlock (&tunnels_lock); GST_ERROR ("client %p: tunnel session %s was closed", client, tunnelid); g_object_unref (oclient); + return FALSE; + } +} + +static GstRTSPStatusCode +tunnel_get (GstRTSPWatch * watch, gpointer user_data) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + + GST_INFO ("client %p: tunnel get (connection %p)", client, + client->priv->connection); + + if (!handle_tunnel (client)) { + return GST_RTSP_STS_SERVICE_UNAVAILABLE; + } + + return GST_RTSP_STS_OK; +} + +static GstRTSPResult +tunnel_post (GstRTSPWatch * watch, gpointer user_data) +{ + GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + + GST_INFO ("client %p: tunnel post (connection %p)", client, + client->priv->connection); + + if (!handle_tunnel (client)) { return GST_RTSP_ERROR; } + + return GST_RTSP_OK; } static GstRTSPResult @@ -3084,8 +3090,8 @@ static GstRTSPWatchFuncs watch_funcs = { message_sent, closed, error, - tunnel_start, - tunnel_complete, + tunnel_get, + tunnel_post, error_full, tunnel_lost, tunnel_http_response From 11369d38ef6bc6a054b6da521cb9e2dbe6226373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Tue, 1 Apr 2014 13:04:21 +0200 Subject: [PATCH 0953/1776] client: Add drop-backlog property When we have too many messages queued for a client (currently hardcoded to 100) we overflow and drop the messages. Add a drop-backlog property to control this behaviour. Setting this property to FALSE will retry to send the messages to the client by waiting for more room in the backlog. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725898 --- gst/rtsp-server/rtsp-client.c | 62 ++++++++++++++++++++++++++++++++--- gst/rtsp-server/rtsp-media.c | 5 ++- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8b253fa82e..f2c146e51e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -81,6 +81,8 @@ struct _GstRTSPClientPrivate GList *transports; GList *sessions; + + gboolean drop_backlog; }; static GMutex tunnels_lock; @@ -88,12 +90,14 @@ static GHashTable *tunnels; /* protected by tunnels_lock */ #define DEFAULT_SESSION_POOL NULL #define DEFAULT_MOUNT_POINTS NULL +#define DEFAULT_DROP_BACKLOG TRUE enum { PROP_0, PROP_SESSION_POOL, PROP_MOUNT_POINTS, + PROP_DROP_BACKLOG, PROP_LAST }; @@ -174,6 +178,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) GST_TYPE_RTSP_MOUNT_POINTS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DROP_BACKLOG, + g_param_spec_boolean ("drop-backlog", "Drop Backlog", + "Drop data when the backlog queue is full", + DEFAULT_DROP_BACKLOG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_client_signals[SIGNAL_CLOSED] = g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL, @@ -255,6 +264,7 @@ gst_rtsp_client_init (GstRTSPClient * client) g_mutex_init (&priv->lock); g_mutex_init (&priv->send_lock); priv->close_seq = 0; + priv->drop_backlog = DEFAULT_DROP_BACKLOG; } static GstRTSPFilterResult @@ -341,6 +351,8 @@ gst_rtsp_client_finalize (GObject * obj) GST_INFO ("finalize client %p", client); + if (priv->watch) + gst_rtsp_watch_set_flushing (priv->watch, TRUE); gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); if (priv->watch) @@ -378,6 +390,7 @@ gst_rtsp_client_get_property (GObject * object, guint propid, GValue * value, GParamSpec * pspec) { GstRTSPClient *client = GST_RTSP_CLIENT (object); + GstRTSPClientPrivate *priv = client->priv; switch (propid) { case PROP_SESSION_POOL: @@ -386,6 +399,9 @@ gst_rtsp_client_get_property (GObject * object, guint propid, case PROP_MOUNT_POINTS: g_value_take_object (value, gst_rtsp_client_get_mount_points (client)); break; + case PROP_DROP_BACKLOG: + g_value_set_boolean (value, priv->drop_backlog); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -396,6 +412,7 @@ gst_rtsp_client_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec) { GstRTSPClient *client = GST_RTSP_CLIENT (object); + GstRTSPClientPrivate *priv = client->priv; switch (propid) { case PROP_SESSION_POOL: @@ -404,6 +421,11 @@ gst_rtsp_client_set_property (GObject * object, guint propid, case PROP_MOUNT_POINTS: gst_rtsp_client_set_mount_points (client, g_value_get_object (value)); break; + case PROP_DROP_BACKLOG: + g_mutex_lock (&priv->lock); + priv->drop_backlog = g_value_get_boolean (value); + g_mutex_unlock (&priv->lock); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -2842,11 +2864,42 @@ do_send_message (GstRTSPClient * client, GstRTSPMessage * message, gboolean close, gpointer user_data) { GstRTSPClientPrivate *priv = client->priv; + GstRTSPResult ret; + GTimeVal time; - /* send the response and store the seq number so we can wait until it's - * written to the client to close the connection */ - return gst_rtsp_watch_send_message (priv->watch, message, close ? - &priv->close_seq : NULL); + time.tv_sec = 1; + time.tv_usec = 0; + + do { + /* send the response and store the seq number so we can wait until it's + * written to the client to close the connection */ + ret = + gst_rtsp_watch_send_message (priv->watch, message, + close ? &priv->close_seq : NULL); + if (ret == GST_RTSP_OK) + break; + + if (ret != GST_RTSP_ENOMEM) + goto error; + + /* drop backlog */ + if (priv->drop_backlog) + break; + + /* queue was full, wait for more space */ + GST_DEBUG_OBJECT (client, "waiting for backlog"); + ret = gst_rtsp_watch_wait_backlog (priv->watch, &time); + GST_DEBUG_OBJECT (client, "Resend due to backlog full"); + } while (ret != GST_RTSP_EINTR); + + return ret; + + /* ERRORS */ +error: + { + GST_DEBUG_OBJECT (client, "got error %d", ret); + return ret; + } } static GstRTSPResult @@ -2886,6 +2939,7 @@ closed (GstRTSPWatch * watch, gpointer user_data) g_mutex_unlock (&tunnels_lock); } + gst_rtsp_watch_set_flushing (watch, TRUE); gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); return GST_RTSP_OK; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index de47c68f7c..33c4d2c227 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1194,7 +1194,6 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) name = g_strdup_printf ("dynpay%d", i); if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { /* a stream that will dynamically create pads to provide RTP packets */ - GST_INFO ("found dynamic element %d, %p", i, elem); g_mutex_lock (&priv->lock); @@ -1936,7 +1935,7 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) /* join the element in the PAUSED state because this callback is * called from the streaming thread and it is PAUSED */ if (!gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline), - priv->rtpbin, GST_STATE_PAUSED)) { + priv->rtpbin, GST_STATE_PAUSED)) { GST_WARNING ("failed to join bin element"); } @@ -2092,7 +2091,7 @@ start_prepare (GstRTSPMedia * media) stream = g_ptr_array_index (priv->streams, i); if (!gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline), - priv->rtpbin, GST_STATE_NULL)) { + priv->rtpbin, GST_STATE_NULL)) { goto join_bin_failed; } } From adc3e8907e87235391f68f7f061321f74fb882f7 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Thu, 10 Apr 2014 16:39:11 +0100 Subject: [PATCH 0954/1776] rtsp-client: indent cleanup Coverity was moaning about unreachable code, and I think it was just confused by { being before the label. We'll see if it pops up again. Coverity 1197705 --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f2c146e51e..7158c12990 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1587,8 +1587,8 @@ unsupported_encryption: GST_DEBUG_OBJECT (client, "unsupported key encryption"); goto cleanup_message; } +cleanup_message: { - cleanup_message: gst_mikey_message_free (msg); return FALSE; } From de2a70bb10b1e0111b3cbfa5c45c374061223965 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Sat, 12 Apr 2014 05:53:15 +0200 Subject: [PATCH 0955/1776] media: allow NULL as the thread Use the default context whan passing a NULL thread. --- gst/rtsp-server/rtsp-media.c | 11 +++++++---- tests/check/gst/media.c | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 33c4d2c227..b827c7279b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2157,9 +2157,9 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) GstBus *bus; GSource *source; GstRTSPMediaClass *klass; + GMainContext *context; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - g_return_val_if_fail (GST_IS_RTSP_THREAD (thread), FALSE); priv = media->priv; @@ -2206,6 +2206,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) priv->seekable = FALSE; priv->buffering = FALSE; priv->thread = thread; + context = (thread != NULL) ? (thread->context) : NULL; + /* we're preparing now */ gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); @@ -2218,7 +2220,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) g_source_set_callback (priv->source, (GSourceFunc) bus_message, g_object_ref (media), (GDestroyNotify) watch_destroyed); - priv->id = g_source_attach (priv->source, thread->context); + priv->id = g_source_attach (priv->source, context); /* add stuff to the bin */ gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin); @@ -2226,7 +2228,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) /* do remainder in context */ source = g_idle_source_new (); g_source_set_callback (source, (GSourceFunc) start_prepare, media, NULL); - g_source_attach (source, thread->context); + g_source_attach (source, context); g_source_unref (source); wait_status: @@ -2248,7 +2250,8 @@ was_prepared: { GST_LOG ("media %p was prepared", media); /* we are not going to use the giving thread, so stop it. */ - gst_rtsp_thread_stop (thread); + if (thread) + gst_rtsp_thread_stop (thread); g_rec_mutex_unlock (&priv->state_lock); return TRUE; } diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 307c9e12f8..e06a4ddc0c 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -317,7 +317,7 @@ GST_START_TEST (test_media_prepare_port_alloc_fail) addrpool = gst_rtsp_address_pool_new (); fail_unless (gst_rtsp_address_pool_add_range (addrpool, "192.168.1.1", - "192.168.1.1", 6000, 6001, 0)); + "192.168.1.1", 6000, 6001, 0)); gst_rtsp_media_set_address_pool (media, addrpool); thread = gst_rtsp_thread_pool_get_thread (pool, From da19a3c21a5e063e0175a16d572382f88cf4714d Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Sat, 12 Apr 2014 05:57:00 +0200 Subject: [PATCH 0956/1776] media: stop the thread in more error cases --- gst/rtsp-server/rtsp-media.c | 12 ++++++++++++ tests/check/gst/media.c | 1 - 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b827c7279b..e8b1cb1dc7 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2258,6 +2258,9 @@ was_prepared: /* ERRORS */ not_unprepared: { + /* we are not going to use the giving thread, so stop it. */ + if (thread) + gst_rtsp_thread_stop (thread); GST_WARNING ("media %p was not unprepared", media); priv->prepare_count--; g_rec_mutex_unlock (&priv->state_lock); @@ -2265,6 +2268,9 @@ not_unprepared: } is_reused: { + /* we are not going to use the giving thread, so stop it. */ + if (thread) + gst_rtsp_thread_stop (thread); priv->prepare_count--; g_rec_mutex_unlock (&priv->state_lock); GST_WARNING ("can not reuse media %p", media); @@ -2272,6 +2278,9 @@ is_reused: } no_create_rtpbin: { + /* we are not going to use the giving thread, so stop it. */ + if (thread) + gst_rtsp_thread_stop (thread); priv->prepare_count--; g_rec_mutex_unlock (&priv->state_lock); GST_ERROR ("no create_rtpbin function"); @@ -2280,6 +2289,9 @@ no_create_rtpbin: } no_rtpbin: { + /* we are not going to use the giving thread, so stop it. */ + if (thread) + gst_rtsp_thread_stop (thread); priv->prepare_count--; g_rec_mutex_unlock (&priv->state_lock); GST_WARNING ("no rtpbin element"); diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index e06a4ddc0c..f2a58cedd4 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -205,7 +205,6 @@ GST_START_TEST (test_media_prepare) "( videotestsrc is-live=true ! rtpvrawpay pt=96 name=pay0 )"); g_object_unref (pool); - gst_rtsp_thread_stop (thread); gst_rtsp_thread_pool_cleanup (); } From 80474e9e5e0f17c44d553192a2281d17c4ff2015 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 9 Apr 2014 16:44:21 +0200 Subject: [PATCH 0957/1776] media: make media_prepare virtual Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728029 --- gst/rtsp-server/rtsp-media.c | 153 +++++++++++++++++++++-------------- gst/rtsp-server/rtsp-media.h | 4 + 2 files changed, 98 insertions(+), 59 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e8b1cb1dc7..a006ecec85 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -174,6 +174,7 @@ static void gst_rtsp_media_finalize (GObject * obj); static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message); static void finish_unprepare (GstRTSPMedia * media); +static gboolean default_prepare (GstRTSPMedia * media, GstRTSPThread * thread); static gboolean default_unprepare (GstRTSPMedia * media); static gboolean default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range, GstRTSPRangeUnit unit); @@ -305,6 +306,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); klass->handle_message = default_handle_message; + klass->prepare = default_prepare; klass->unprepare = default_unprepare; klass->convert_range = default_convert_range; klass->query_position = default_query_position; @@ -2136,49 +2138,17 @@ preroll_failed: } } -/** - * gst_rtsp_media_prepare: - * @media: a #GstRTSPMedia - * @thread: (transfer full): a #GstRTSPThread to run the bus handler or %NULL - * - * Prepare @media for streaming. This function will create the objects - * to manage the streaming. A pipeline must have been set on @media with - * gst_rtsp_media_take_pipeline(). - * - * It will preroll the pipeline and collect vital information about the streams - * such as the duration. - * - * Returns: %TRUE on success. - */ -gboolean -gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) +static gboolean +default_prepare (GstRTSPMedia * media, GstRTSPThread * thread) { GstRTSPMediaPrivate *priv; - GstBus *bus; - GSource *source; GstRTSPMediaClass *klass; + GstBus *bus; GMainContext *context; - - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + GSource *source; priv = media->priv; - g_rec_mutex_lock (&priv->state_lock); - priv->prepare_count++; - - if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED || - priv->status == GST_RTSP_MEDIA_STATUS_SUSPENDED) - goto was_prepared; - - if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) - goto wait_status; - - if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED) - goto not_unprepared; - - if (!priv->reusable && priv->reused) - goto is_reused; - klass = GST_RTSP_MEDIA_GET_CLASS (media); if (!klass->create_rtpbin) @@ -2199,18 +2169,9 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) if (priv->rtpbin == NULL) goto no_rtpbin; - GST_INFO ("preparing media %p", media); - - /* reset some variables */ - priv->is_live = FALSE; - priv->seekable = FALSE; - priv->buffering = FALSE; priv->thread = thread; context = (thread != NULL) ? (thread->context) : NULL; - /* we're preparing now */ - gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); - bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline)); /* add the pipeline bus to our custom mainloop */ @@ -2231,6 +2192,85 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) g_source_attach (source, context); g_source_unref (source); + return TRUE; + + /* ERRORS */ +no_create_rtpbin: + { + /* we are not going to use the giving thread, so stop it. */ + if (thread) + gst_rtsp_thread_stop (thread); + GST_ERROR ("no create_rtpbin function"); + g_critical ("no create_rtpbin vmethod function set"); + return FALSE; + } +no_rtpbin: + { + /* we are not going to use the giving thread, so stop it. */ + if (thread) + gst_rtsp_thread_stop (thread); + GST_WARNING ("no rtpbin element"); + g_warning ("failed to create element 'rtpbin', check your installation"); + return FALSE; + } +} + +/** + * gst_rtsp_media_prepare: + * @media: a #GstRTSPMedia + * @thread: (transfer full): a #GstRTSPThread to run the bus handler or %NULL + * + * Prepare @media for streaming. This function will create the objects + * to manage the streaming. A pipeline must have been set on @media with + * gst_rtsp_media_take_pipeline(). + * + * It will preroll the pipeline and collect vital information about the streams + * such as the duration. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) +{ + GstRTSPMediaPrivate *priv; + GstRTSPMediaClass *klass; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + priv->prepare_count++; + + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED || + priv->status == GST_RTSP_MEDIA_STATUS_SUSPENDED) + goto was_prepared; + + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) + goto is_preparing; + + if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARED) + goto not_unprepared; + + if (!priv->reusable && priv->reused) + goto is_reused; + + GST_INFO ("preparing media %p", media); + + /* reset some variables */ + priv->is_live = FALSE; + priv->seekable = FALSE; + priv->buffering = FALSE; + + /* we're preparing now */ + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + if (klass->prepare) { + if (!klass->prepare (media, thread)) + goto prepare_failed; + } + wait_status: g_rec_mutex_unlock (&priv->state_lock); @@ -2246,6 +2286,13 @@ wait_status: return TRUE; /* OK */ +is_preparing: + { + /* we are not going to use the giving thread, so stop it. */ + if (thread) + gst_rtsp_thread_stop (thread); + goto wait_status; + } was_prepared: { GST_LOG ("media %p was prepared", media); @@ -2276,26 +2323,14 @@ is_reused: GST_WARNING ("can not reuse media %p", media); return FALSE; } -no_create_rtpbin: +prepare_failed: { /* we are not going to use the giving thread, so stop it. */ if (thread) gst_rtsp_thread_stop (thread); priv->prepare_count--; g_rec_mutex_unlock (&priv->state_lock); - GST_ERROR ("no create_rtpbin function"); - g_critical ("no create_rtpbin vmethod function set"); - return FALSE; - } -no_rtpbin: - { - /* we are not going to use the giving thread, so stop it. */ - if (thread) - gst_rtsp_thread_stop (thread); - priv->prepare_count--; - g_rec_mutex_unlock (&priv->state_lock); - GST_WARNING ("no rtpbin element"); - g_warning ("failed to create element 'rtpbin', check your installation"); + GST_ERROR ("failed to prepare media"); return FALSE; } preroll_failed: diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 1ef50795c8..01df74dfcc 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -105,6 +105,9 @@ struct _GstRTSPMedia { /** * GstRTSPMediaClass: * @handle_message: handle a message + * @prepare: the default implementation adds all elements and sets the + * pipeline's state to GST_STATE_PAUSED (or GST_STATE_PLAYING + * in case of NO_PREROLL elements). * @unprepare: the default implementation sets the pipeline's state * to GST_STATE_NULL and removes all elements. * @convert_range: convert a range to the given unit @@ -118,6 +121,7 @@ struct _GstRTSPMediaClass { /* vmethods */ gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message); + gboolean (*prepare) (GstRTSPMedia *media, GstRTSPThread *thread); gboolean (*unprepare) (GstRTSPMedia *media); gboolean (*convert_range) (GstRTSPMedia *media, GstRTSPTimeRange *range, GstRTSPRangeUnit unit); From 9219509bcfbc84b6c9d826b60b1d88f1619f016e Mon Sep 17 00:00:00 2001 From: Linus Svensson Date: Fri, 11 Apr 2014 23:52:49 +0200 Subject: [PATCH 0958/1776] rtsp-session-pool: Fixes annotation Fixes annotation for gst_rtsp_session_pool_create() and memory leaks in the sessionpool test. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728060 --- gst/rtsp-server/rtsp-session-pool.c | 2 +- tests/check/gst/sessionpool.c | 38 +++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index d30d6da84b..5111eaa82e 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -319,7 +319,7 @@ create_session (GstRTSPSessionPool * pool, const gchar * id) * * Create a new #GstRTSPSession object in @pool. * - * Returns: (transfer none): a new #GstRTSPSession. + * Returns: (transfer full): a new #GstRTSPSession. */ GstRTSPSession * gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) diff --git a/tests/check/gst/sessionpool.c b/tests/check/gst/sessionpool.c index a0de375efa..c1cc149c96 100644 --- a/tests/check/gst/sessionpool.c +++ b/tests/check/gst/sessionpool.c @@ -44,7 +44,8 @@ GST_START_TEST (test_pool) { GstRTSPSessionPool *pool; GstRTSPSession *session1, *session2, *session3; - const gchar *session1id, *session2id, *session3id; + GstRTSPSession *compare; + gchar *session1id, *session2id, *session3id; GList *list; guint maxsessions; GSource *source; @@ -61,28 +62,35 @@ GST_START_TEST (test_pool) fail_unless (GST_IS_RTSP_SESSION (session1)); fail_unless_equals_int (gst_rtsp_session_pool_get_n_sessions (pool), 1); fail_unless_equals_int (gst_rtsp_session_pool_get_max_sessions (pool), 3); - session1id = gst_rtsp_session_get_sessionid (session1); + session1id = g_strdup (gst_rtsp_session_get_sessionid (session1)); session2 = gst_rtsp_session_pool_create (pool); fail_unless (GST_IS_RTSP_SESSION (session2)); fail_unless_equals_int (gst_rtsp_session_pool_get_n_sessions (pool), 2); fail_unless_equals_int (gst_rtsp_session_pool_get_max_sessions (pool), 3); - session2id = gst_rtsp_session_get_sessionid (session2); + session2id = g_strdup (gst_rtsp_session_get_sessionid (session2)); session3 = gst_rtsp_session_pool_create (pool); fail_unless (GST_IS_RTSP_SESSION (session3)); fail_unless_equals_int (gst_rtsp_session_pool_get_n_sessions (pool), 3); fail_unless_equals_int (gst_rtsp_session_pool_get_max_sessions (pool), 3); - session3id = gst_rtsp_session_get_sessionid (session3); + session3id = g_strdup (gst_rtsp_session_get_sessionid (session3)); fail_if (GST_IS_RTSP_SESSION (gst_rtsp_session_pool_create (pool))); - fail_unless (gst_rtsp_session_pool_find (pool, session1id) == session1); - fail_unless (gst_rtsp_session_pool_find (pool, session2id) == session2); - fail_unless (gst_rtsp_session_pool_find (pool, session3id) == session3); + compare = gst_rtsp_session_pool_find (pool, session1id); + fail_unless (compare == session1); + g_object_unref (compare); + compare = gst_rtsp_session_pool_find (pool, session2id); + fail_unless (compare == session2); + g_object_unref (compare); + compare = gst_rtsp_session_pool_find (pool, session3id); + fail_unless (compare == session3); + g_object_unref (compare); fail_unless (gst_rtsp_session_pool_find (pool, "") == NULL); fail_unless (gst_rtsp_session_pool_remove (pool, session2)); + g_object_unref (session2); fail_unless_equals_int (gst_rtsp_session_pool_get_n_sessions (pool), 2); fail_unless_equals_int (gst_rtsp_session_pool_get_max_sessions (pool), 3); @@ -98,7 +106,7 @@ GST_START_TEST (test_pool) fail_unless_equals_int (g_list_length (list), 2); fail_unless (g_list_find (list, session1) != NULL); fail_unless (g_list_find (list, session3) != NULL); - g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free_full (list, (GDestroyNotify) g_object_unref); } { @@ -120,7 +128,7 @@ GST_START_TEST (test_pool) list = gst_rtsp_session_pool_filter (pool, filter_func, &responses); fail_unless_equals_int (g_list_length (list), 1); fail_unless (g_list_nth_data (list, 0) == session1); - g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free_full (list, (GDestroyNotify) g_object_unref); } { @@ -131,9 +139,12 @@ GST_START_TEST (test_pool) list = gst_rtsp_session_pool_filter (pool, filter_func, &responses); fail_unless_equals_int (g_list_length (list), 0); + g_list_free (list); } - fail_unless (gst_rtsp_session_pool_find (pool, session1id) == session1); + compare = gst_rtsp_session_pool_find (pool, session1id); + fail_unless (compare == session1); + g_object_unref (compare); fail_unless (gst_rtsp_session_pool_find (pool, session2id) == NULL); fail_unless (gst_rtsp_session_pool_find (pool, session3id) == NULL); @@ -158,6 +169,13 @@ GST_START_TEST (test_pool) g_source_unref (source); + g_object_unref (session1); + g_object_unref (session3); + + g_free (session1id); + g_free (session2id); + g_free (session3id); + g_object_unref (pool); } From e69241ac975704cf99fa1f83cf167facbc913741 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 15 Apr 2014 16:51:17 +0200 Subject: [PATCH 0959/1776] client: set the watch to flushing before going to NULL First set the watch to flushing so that we unblock any current and future attempt to send data on the watch, Then set the pipeline to NULL. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728153 --- gst/rtsp-server/rtsp-client.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 7158c12990..8ff51d19bf 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -819,6 +819,10 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], 0, ctx); + /* make sure we unblock the backlog and don't accept new messages + * on the watch */ + gst_rtsp_watch_set_flushing (priv->watch, TRUE); + /* unlink the all TCP callbacks */ unlink_session_transports (client, session, sessmedia); @@ -827,6 +831,9 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL); + /* allow messages again so that we can send the reply */ + gst_rtsp_watch_set_flushing (priv->watch, FALSE); + /* unmanage the media in the session, returns false if all media session * are torn down. */ if (!gst_rtsp_session_release_media (session, sessmedia)) { From 7cce8e2dde79453eb4b0e30ff5b1157d75d57f62 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 14 Apr 2014 15:17:14 +0200 Subject: [PATCH 0960/1776] media: Do not stop thread twice if default_prepare() fails --- gst/rtsp-server/rtsp-media.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index a006ecec85..f1b9cb205b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2197,18 +2197,12 @@ default_prepare (GstRTSPMedia * media, GstRTSPThread * thread) /* ERRORS */ no_create_rtpbin: { - /* we are not going to use the giving thread, so stop it. */ - if (thread) - gst_rtsp_thread_stop (thread); GST_ERROR ("no create_rtpbin function"); g_critical ("no create_rtpbin vmethod function set"); return FALSE; } no_rtpbin: { - /* we are not going to use the giving thread, so stop it. */ - if (thread) - gst_rtsp_thread_stop (thread); GST_WARNING ("no rtpbin element"); g_warning ("failed to create element 'rtpbin', check your installation"); return FALSE; From a646e278d35765651413f360652053cb95b55487 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 1 May 2014 05:29:54 +0200 Subject: [PATCH 0961/1776] client: fix typo in comment --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8ff51d19bf..182474d65f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1173,7 +1173,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) send_message (client, session, ctx->response, FALSE); - /* start playing after sending the request */ + /* start playing after sending the response */ gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING); gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING); From 4c42aec6ddc06601dc2f14b1af46b01e60dabf47 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 1 May 2014 06:07:08 +0200 Subject: [PATCH 0962/1776] client: pass context to send_message Pass the current context to send_message, we will need it later. --- gst/rtsp-server/rtsp-client.c | 47 +++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 182474d65f..fc58b16c56 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -449,7 +449,7 @@ gst_rtsp_client_new (void) } static void -send_message (GstRTSPClient * client, GstRTSPSession * session, +send_message (GstRTSPClient * client, GstRTSPContext * ctx, GstRTSPMessage * message, gboolean close) { GstRTSPClientPrivate *priv = client->priv; @@ -461,9 +461,9 @@ send_message (GstRTSPClient * client, GstRTSPSession * session, gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1); /* add the new session header for new session ids */ - if (session) { + if (ctx->session) { gst_rtsp_message_take_header (message, GST_RTSP_HDR_SESSION, - gst_rtsp_session_get_header (session)); + gst_rtsp_session_get_header (ctx->session)); } if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) { @@ -488,7 +488,9 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, gst_rtsp_message_init_response (ctx->response, code, gst_rtsp_status_as_text (code), ctx->request); - send_message (client, NULL, ctx->response, FALSE); + ctx->session = NULL; + + send_message (client, ctx, ctx->response, FALSE); } static gboolean @@ -845,7 +847,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_message_init_response (ctx->response, code, gst_rtsp_status_as_text (code), ctx->request); - send_message (client, session, ctx->response, TRUE); + send_message (client, ctx, ctx->response, TRUE); return TRUE; @@ -919,7 +921,7 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx) if (res != GST_RTSP_OK) goto bad_request; - send_message (client, ctx->session, ctx->response, FALSE); + send_message (client, ctx, ctx->response, FALSE); } g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST], @@ -956,7 +958,7 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx) if (res != GST_RTSP_OK) goto bad_request; - send_message (client, ctx->session, ctx->response, FALSE); + send_message (client, ctx, ctx->response, FALSE); } g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST], @@ -1022,7 +1024,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_message_init_response (ctx->response, code, gst_rtsp_status_as_text (code), ctx->request); - send_message (client, session, ctx->response, FALSE); + send_message (client, ctx, ctx->response, FALSE); /* the state is now READY */ gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY); @@ -1171,7 +1173,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (str) gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RANGE, str); - send_message (client, session, ctx->response, FALSE); + send_message (client, ctx, ctx->response, FALSE); /* start playing after sending the response */ gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING); @@ -1812,7 +1814,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) trans_str); g_free (trans_str); - send_message (client, session, ctx->response, FALSE); + send_message (client, ctx, ctx->response, FALSE); /* update the state */ rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); @@ -2041,7 +2043,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_message_take_body (ctx->response, (guint8 *) str, strlen (str)); gst_sdp_message_free (sdp); - send_message (client, ctx->session, ctx->response, FALSE); + send_message (client, ctx, ctx->response, FALSE); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST], 0, ctx); @@ -2105,7 +2107,7 @@ handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PUBLIC, str); g_free (str); - send_message (client, ctx->session, ctx->response, FALSE); + send_message (client, ctx, ctx->response, FALSE); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST], 0, ctx); @@ -2856,12 +2858,31 @@ GstRTSPResult gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession * session, GstRTSPMessage * message) { + GstRTSPContext sctx = { NULL } + , *ctx; + GstRTSPClientPrivate *priv; + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL); g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL); g_return_val_if_fail (message->type == GST_RTSP_MESSAGE_REQUEST || message->type == GST_RTSP_MESSAGE_RESPONSE, GST_RTSP_EINVAL); - send_message (client, session, message, FALSE); + priv = client->priv; + + if (!(ctx = gst_rtsp_context_get_current ())) { + ctx = &sctx; + ctx->auth = priv->auth; + gst_rtsp_context_push_current (ctx); + } + + ctx->conn = priv->connection; + ctx->client = client; + ctx->session = session; + + send_message (client, ctx, message, FALSE); + + if (ctx == &sctx) + gst_rtsp_context_pop_current (ctx); return GST_RTSP_OK; } From ea4543efc810f9347196ece13e8c2168b82073eb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 1 May 2014 06:17:06 +0200 Subject: [PATCH 0963/1776] client: emit a signal before sending a message Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728970 --- gst/rtsp-server/rtsp-client.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index fc58b16c56..d42f9330f5 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -114,6 +114,7 @@ enum SIGNAL_SET_PARAMETER_REQUEST, SIGNAL_GET_PARAMETER_REQUEST, SIGNAL_HANDLE_RESPONSE, + SIGNAL_SEND_MESSAGE, SIGNAL_LAST }; @@ -247,6 +248,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) handle_response), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE] = + g_signal_new ("send-message", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); + tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); g_mutex_init (&tunnels_lock); @@ -473,6 +479,9 @@ send_message (GstRTSPClient * client, GstRTSPContext * ctx, if (close) gst_rtsp_message_add_header (message, GST_RTSP_HDR_CONNECTION, "close"); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE], + 0, ctx, message); + g_mutex_lock (&priv->send_lock); if (priv->send_func) priv->send_func (client, message, close, priv->send_data); From 8b8c3630b49a257b5eb7fadfd4d74262c5c87a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 2 May 2014 19:57:23 +0100 Subject: [PATCH 0964/1776] tests: fix memory leak in sessionmedia unit test --- tests/check/gst/sessionmedia.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/check/gst/sessionmedia.c b/tests/check/gst/sessionmedia.c index 6bd9d26c45..13445b488c 100644 --- a/tests/check/gst/sessionmedia.c +++ b/tests/check/gst/sessionmedia.c @@ -314,6 +314,7 @@ GST_START_TEST (test_time_and_rtpinfo) rtpinfo = gst_rtsp_session_media_get_rtpinfo (sm); fail_unless (rtpinfo == NULL); + gst_rtsp_url_free (setup_url); gst_rtsp_url_free (url); g_object_unref (sm); From 150596e79229d76867193d601ca2f27de66e71cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 2 May 2014 19:58:15 +0100 Subject: [PATCH 0965/1776] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6a74704b4a..574f6655b1 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ stamp-h.in /tests/check/gst/permissions /tests/check/gst/rtspserver /tests/check/gst/sessionmedia +/tests/check/gst/sessionpool /tests/check/gst/stream /tests/check/gst/threadpool /tests/check/gst/token From dc27833c1f0ee8b818895b4036ca5ef29cdd9017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 3 May 2014 10:18:00 +0200 Subject: [PATCH 0966/1776] Automatic update of common submodule From bcb1518 to 211fa5f --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index bcb1518c08..211fa5f2d0 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit bcb1518c08c889dd7eda06936fc26cad85fac755 +Subproject commit 211fa5f2d0930dfd6891b386d42edba6d88c2a19 From 525339790cdd60c894c0057b92fc4ade347779ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 3 May 2014 18:40:24 +0200 Subject: [PATCH 0967/1776] Release 1.3.1 --- ChangeLog | 7251 ++++++++++++++++++++++++++++++++++++++++++ NEWS | 111 +- RELEASE | 124 + configure.ac | 12 +- gst-rtsp-server.doap | 10 + 5 files changed, 7501 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index e69de29bb2..9c8ec4b4d7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -0,0 +1,7251 @@ +=== release 1.3.1 === + +2014-05-03 Sebastian Dröge + + * configure.ac: + releasing 1.3.1 + +2014-05-03 10:18:00 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From bcb1518 to 211fa5f + +2014-05-02 19:58:15 +0100 Tim-Philipp Müller + + * .gitignore: + Update .gitignore + +2014-05-02 19:57:23 +0100 Tim-Philipp Müller + + * tests/check/gst/sessionmedia.c: + tests: fix memory leak in sessionmedia unit test + +2014-05-01 06:17:06 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: emit a signal before sending a message + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728970 + +2014-05-01 06:07:08 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: pass context to send_message + Pass the current context to send_message, we will need it later. + +2014-05-01 05:29:54 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: fix typo in comment + +2014-04-14 15:17:14 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + media: Do not stop thread twice if default_prepare() fails + +2014-04-15 16:51:17 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: set the watch to flushing before going to NULL + First set the watch to flushing so that we unblock any current and + future attempt to send data on the watch, Then set the pipeline to + NULL. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728153 + +2014-04-11 23:52:49 +0200 Linus Svensson + + * gst/rtsp-server/rtsp-session-pool.c: + * tests/check/gst/sessionpool.c: + rtsp-session-pool: Fixes annotation + Fixes annotation for gst_rtsp_session_pool_create() and memory leaks + in the sessionpool test. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728060 + +2014-04-09 16:44:21 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: make media_prepare virtual + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728029 + +2014-04-12 05:57:00 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/media.c: + media: stop the thread in more error cases + +2014-04-12 05:53:15 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/media.c: + media: allow NULL as the thread + Use the default context whan passing a NULL thread. + +2014-04-10 16:39:11 +0100 Vincent Penquerc'h + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: indent cleanup + Coverity was moaning about unreachable code, and I think it was just + confused by { being before the label. We'll see if it pops up again. + Coverity 1197705 + +2014-04-01 13:04:21 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + client: Add drop-backlog property + When we have too many messages queued for a client (currently hardcoded + to 100) we overflow and drop the messages. Add a drop-backlog property + to control this behaviour. Setting this property to FALSE will retry + to send the messages to the client by waiting for more room in the + backlog. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725898 + +2014-04-03 12:19:51 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + client: support for POST before GET when setting up a tunnel + +2014-04-02 12:03:32 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + client: remove watch of the second client after http tunnel setup + The second client will be freed after the HTTP tunnel has been set up. + Make sure it's RTSP watch is never dispatched again. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=727488 + +2014-03-31 11:00:11 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/media.c: + media: Make media_prepare() fail if port allocation fails + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=727376 + +2014-04-01 16:55:13 +0200 Linus Svensson + + * tests/check/gst/media.c: + media test: cleanup the thread pool in tests + +2014-04-01 13:16:26 +0200 Linus Svensson + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/media.c: + rtsp-media: Unblock blocked streams in unprepare + The streams will be blocked when a live media is prepared. + The streams should be unblocked in gst_rtsp_media_unprepare. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=727231 + +2014-04-08 14:49:41 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: release the state lock when going to NULL + Set our state to UNPREPARING and release the state-lock before + setting the pipeline to the NULL state. This way, any pad-added + callback will be able to take the state-lock and check that we are now + unpreparing instead of deadlocking. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=727102 + +2014-04-08 12:08:17 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: protect status with lock + Make sure we only update the status with the lock. + +2014-04-04 17:39:36 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-sdp.c: + rtsp: update for MIKEY API changes + +2014-04-03 12:52:51 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: parse the mikey response from the client + Parse the mikey response from the client and update the policy for + each SSRC. + +2014-04-02 12:36:16 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: add method to set crypto info + Make a method to configure the crypto information of a stream. + Set udpsrc in READY instead of PAUSED so that we can configure caps + later. + +2014-04-03 12:57:13 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: cleanup error paths + +2014-04-02 12:27:24 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: fix docs + +2014-03-25 12:42:39 +0100 Wim Taymans + + * examples/test-video.c: + test: enable SRTP only on RTSPS + We only want to enable SRTP when doing rtsp over TLS so that we can + exchange the keys in a secure way. + +2014-03-25 12:41:33 +0100 Wim Taymans + + * examples/test-video.c: + test: print an error on failure + +2014-03-13 17:35:21 +0100 Wim Taymans + + * configure.ac: + * examples/test-video.c: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-stream.c: + * tests/check/Makefile.am: + stream: add SRTP support + Install srtp encoder and decoder elements in rtpbin + Add MIKEY in SDP + +2014-03-16 19:45:26 +0100 Sebastian Rasmussen + + * tests/check/Makefile.am: + * tests/check/gst/sessionpool.c: + tests: Add unit tests for sessionpool + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726470 + +2014-03-22 13:24:27 +0100 Sebastian Rasmussen + + * tests/check/gst/threadpool.c: + tests: Improve code coverage of rtsp-threadpool tests + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726873 + +2014-03-23 21:26:00 +0100 Sebastian Rasmussen + + * tests/check/gst/sessionmedia.c: + tests: Improve code coverage for rtsp-session-media + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726940 + +2014-03-23 21:24:48 +0100 Sebastian Rasmussen + + gobject-introspection: Add annotations to support language bindings + In addition a few cosmetic changes: + * Adjust the order of arguments + * Fix typo: occured -> occurred + * Fix indentation after Return:-clauses + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726941 + +2014-03-14 19:03:24 +0100 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Don't mix IPv4 and IPv6 addresses + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726362 + +2014-03-13 14:27:15 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: take caps after the session manager + Take the caps for the SDP after they leave the rtpbin so that we can + also get the properties added by rtpbin elements. + +2014-03-13 14:20:17 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: release lock while pushing out packets + Keep a cache of the transports and use this to iterate the transport + while pushing packets. This allows us to release the lock early. + See https://bugzilla.gnome.org/show_bug.cgi?id=725898 + +2014-03-06 13:52:02 +0100 David Svensson Fors + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + rtsp-client: vmethod for modifying tunnel GET response + Add a vmethod tunnel_http_response where the response to the HTTP GET + for tunneled connections can be modified. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725879 + +2014-03-03 16:56:53 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-sdp.c: + sdp: make 1 media line per profile + If we have multiple profiles (AVP or AVPF) for a stream, make one m= + line in the SDP for each profile. The client is then supposed to pick + one of the profiles in the SETUP request. Because the m= lines have the + same pt, the client also knows that only 1 option is possible. + +2014-03-03 16:55:48 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + factory: add profile property and pass to media and streams + +2014-03-03 15:12:55 +0100 Wim Taymans + + * examples/test-multicast.c: + * gst/rtsp-server/rtsp-sdp.c: + sdp: pass multicast connection for multicast-only stream + Pass the multicast address of the stream in the connection info in the + SDP so that clients try a multicast connection first. + Only allow multicast connections in the test-multicast example. Also + increase the TTL a little. + +2014-03-02 05:12:01 +0100 Sebastian Rasmussen + + * .gitignore: + .gitignore: Ignore gcov intermediate files + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725484 + +2014-03-03 12:17:48 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: release some locks in error cases + +2014-03-02 05:12:10 +0100 Sebastian Rasmussen + + docs: Enable and fix gtk-doc warnings + * Makefile: Enable gtk-doc warnings, like the rest of GStreamer + * addresspool/mediafactory: Add missing annotation colon + * stream: Annotate return value + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725528 + +2014-02-28 09:36:49 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From fe1672e to bcb1518 + +2014-02-26 22:15:51 +0100 Stefan Sauer + + * common: + Automatic update of common submodule + From 1a07da9 to fe1672e + +2014-02-25 15:13:40 +0000 Tim-Philipp Müller + + * examples/Makefile.am: + examples: use LDADD for libs instead of LDFLAGS + +2014-02-25 14:42:09 +0000 Tim-Philipp Müller + + * configure.ac: + configure: make sure releases are in .doap file + +2014-02-25 14:11:00 +0000 Tim-Philipp Müller + + * examples/test-cgroups.c: + examples: test-cgroups: don't put code with side effects into g_assert() + The g_assert() might get compiled out with the right + compiler/preprocessor flags. + +2014-02-25 14:07:50 +0000 Tim-Philipp Müller + + * examples/.gitignore: + examples: add cgroup test binary to .gitignore + +2014-02-25 14:06:47 +0000 Tim-Philipp Müller + + * examples/test-cgroups.c: + examples: fix cgroup test build + Fixes build failure caused by compiler warning: + test-cgroups.c:82:35: error: no previous prototype for ‘gst_rtsp_cgroup_pool_get_type’ [-Werror=missing-prototypes] + +2014-02-21 16:46:45 +0000 Tim-Philipp Müller + + * .gitignore: + .gitignore: ignore temp files created in the course of 'make check' + +2014-02-18 09:44:34 +0100 Branko Subasic + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: don't loose frames handling new PLAY request + If client supplied a range check if the range specifies the start point. + If not, then do an accurate seek to the current position. If a start + point was specified do do a key unit seek to make sure the streaming + starts with decodeable frames. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=724611 + +2014-02-18 16:58:45 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + Revert "media: only flush when setting a new start position" + This reverts commit f67fc23aab59f28796bebf130504ff46ccb97b0a. + We need to do the flush in all cases, demuxer block currently for + non-flushing seeks. + +2014-02-18 16:38:39 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: only flush when setting a new start position + Only flush the pipeline when we change the start position with + a seek. + See https://bugzilla.gnome.org/show_bug.cgi?id=724611 + +2014-02-17 10:43:05 +0100 Göran Jönsson + + * gst/rtsp-server/rtsp-stream.c: + stream: set ttl-mc before adding the socket + Set ttl-mc before adding the socket. Otherwise the value ttl-mc will + never be set on socket. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=724531 + +2014-02-11 14:20:39 -0800 Aleix Conchillo Flaqué + + * gst/rtsp-server/rtsp-media.c: + media: stop thread if media is already prepared + in gst_rtsp_media_prepare() the thread is not used if media is already + prepared (e.g. media shared) so we want to stop the thread. otherwise, a + leak occurs. + https://bugzilla.gnome.org/show_bug.cgi?id=724182 + +2014-02-09 10:52:29 +0100 Sebastian Dröge + + * Makefile.am: + build: Ship gst-rtsp-server.doap file + +2014-02-09 10:47:09 +0100 Sebastian Dröge + + * tests/check/gst/rtspserver.c: + tests: Fix another compiler warning with gcc + +2014-02-09 10:45:28 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/client.c: + rtsp-server: Fix lots of compiler warnings with clang + +2014-02-09 10:41:14 +0100 Sebastian Dröge + + * configure.ac: + * gst-rtsp-server.doap: + * tests/Makefile.am: + configure: Synchronise with the configure scripts of the other modules + +2014-02-09 10:25:44 +0100 Sebastian Dröge + + * configure.ac: + configure: Update version to 1.3.0.1 and require GStreamer 1.3.0 + +2014-02-09 10:19:50 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + Revert "rtsp-server: support build against last stable release" + This reverts commit 099a10f61f11413ad0ada8ee0b7b7ad1210b1b2f. + Let us require 1.2.3 now, which is going to be released in a few + minutes. + +2014-02-07 16:39:49 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-stream-transport.c: + session: improve RTP-Info + Ignore streams that can't generate RTP-Info instead of failing. + Don't return the empty string when all streams are unconfigured but + return NULL so that we don't generate and empty RTP-Info header. + Improve docs a little. + +2014-02-03 22:41:48 +0200 Andrey Utkin + + * gst/rtsp-server/rtsp-session-media.c: + Don't free rtpinfo GString when it is NULL + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=723554 + +2014-02-06 09:48:05 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: only set keyframe flag when modifying start + Only set the keyframe flag when we modify the start position. The + keyframe flag should probably be ignored when no change is requested but + until we can claim this is all documented properly and all demuxer + implement this, avoid setting the flag. + See also https://bugzilla.gnome.org/show_bug.cgi?id=723075 + +2014-02-06 09:03:50 +0100 Ognyan Tonchev + + * gst/rtsp-server/rtsp-thread-pool.c: + thread-pool: Unref source after mainloop has quit to avoid races in GLib + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=723741 + +2014-02-04 16:27:12 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: handle NULL seqnum and rtptime arguments + +2014-01-31 15:02:22 +0100 Ognyan Tonchev + + * gst/rtsp-server/rtsp-thread-pool.c: + * tests/check/gst/threadpool.c: + thread-pool: Unref reused threads in gst_rtsp_thread_stop() + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=723519 + +2014-02-04 10:14:45 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: add fallback for missing stats property + Use a fallback when the payloader does not have a stats property + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=723554 + +2014-01-30 10:45:56 +0100 Edward Hervey + + * common: + Automatic update of common submodule + From f7bc1c3 to 1a07da9 + +2014-01-28 14:51:26 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: don't leak stats structure + Don't leak the stats structure and deal with NULL stats. + +2014-01-22 22:03:14 +0100 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-stream.c: + stream: Get rtpinfo properties atomically from payloader + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=722844 + +2014-01-21 14:46:47 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: refactor state change functions and signals + Make functions to set the target state and the pipeline state and emit + the signals from those functions. + +2014-01-21 12:01:25 +0100 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: add signal to notify of pending state changes + +2014-01-12 16:55:21 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-server: support build against last stable release + Until 1.2.3 is out with the new get_type function and we + can require that. + +2014-01-07 15:28:05 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: fix compilation + +2014-01-07 12:21:09 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: add property to configure profiles + +2014-01-07 12:28:47 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: let stream check supported transport + Delegate the check if a transport is allowed to the stream. + See https://bugzilla.gnome.org/show_bug.cgi?id=720696 + +2014-01-07 12:14:15 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: add method to check supported transport + Add a method to check if a transport is supported + +2013-12-27 13:11:45 +0100 Sebastian Dröge + + * configure.ac: + configure.ac: Only check for gstreamer-check, not check + We include check in gstreamer-check since quite some time now. + +2013-12-26 17:02:50 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: return clock-rate from get_rtpinfo + And use it to correct the rtptime to the requested start-time. + See https://bugzilla.gnome.org/show_bug.cgi?id=712198 + +2013-12-26 16:28:59 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + session-media: calculate start-time + +2013-12-26 14:43:35 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: also return the running-time + Return the running-time in the rtpinfo as well. + +2013-12-26 15:41:14 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + session-media: let the session-media make the RTPInfo + Add method to create the RTPInfo for a stream-transport. + Add method to create the RTPInfo for all stream-transports in a + session-media. + Use the session-media RTPInfo code in client. This allows us to refactor + another method to link the TCP callbacks. + +2013-12-20 16:39:07 -0800 Aleix Conchillo Flaqué + + mount-points: sort sequence before g_sequence_lookup + * gst/rtsp-server/rtsp-mount-points.c (gst_rtsp_mount_points_remove_factory): + sort sequence if dirty, otherwise lookup will fail. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=720855 + +2013-12-22 23:16:56 +0000 Tim-Philipp Müller + + * configure.ac: + configure: rename package from gst-rtsp to gst-rtsp-server + To match git module name and avoid confusion with the + rtsp lib in gst-plugins-base and rtsp plugin in -good. + +2013-12-22 23:15:02 +0000 Tim-Philipp Müller + + * configure.ac: + configure: bump core/base/good requirement to 1.2.0 + Bump to released stable version and make implicit + requirements explicit. + +2013-12-22 23:04:48 +0000 Tim-Philipp Müller + + * autogen.sh: + * common: + * configure.ac: + Fix broken gettext setup which is not used anyway + +2013-12-22 22:36:06 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From dbedaa0 to d48bed3 + +2013-12-18 16:37:27 +0100 Aleix Conchillo Flaqué + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: add setup_sdp vmethod + gst/rtsp-server/rtsp-media.[ch]: added setup_sdp vmethod and public + gst_rtsp_media_setup_sdp. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=720155 + +2013-12-19 14:26:34 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Check return value of sscanf + streamid is only valid if sscanf matched something. + +2013-12-19 14:24:54 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Fix iteration + Wouldn't even enter the code block otherwise (i++ was used as the check + and not the postfix). + +2013-12-18 15:57:03 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: add vmethod to configure media and streams + Implement a vmethod that can be used to configure the media and the + streams based on the current context. Handle the blocksize handling in + the default handler. + See https://bugzilla.gnome.org/show_bug.cgi?id=720667 + +2013-12-12 00:38:07 +0000 Tim-Philipp Müller + + * .gitignore: + Make git ignore more unit test binaries + +2013-12-12 00:36:07 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-address-pool.h: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-context.h: + * gst/rtsp-server/rtsp-media-factory-uri.h: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-mount-points.h: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.h: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.h: + * gst/rtsp-server/rtsp-thread-pool.h: + * gst/rtsp-server/rtsp-token.h: + rtsp-server: add padding to many public structures + Not mini objects though, since they are not subclassable + anyway, nor kept on the stack or inlined in a structure. + +2013-12-03 11:54:42 -0800 Aleix Conchillo Flaqué + + media: add new create_rtpbin vmethod + * gst/rtsp-server/rtsp-media.[ch]: add new create_rtpbin vmethod. + https://bugzilla.gnome.org/show_bug.cgi?id=719734 + +2013-12-03 00:34:52 +0100 Sebastian Rasmussen + + * tests/check/gst/media.c: + tests: fix memory leak, free test's thread pool + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=719733 + +2013-11-29 15:50:52 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream-transport.c: + stream-transport: free url in finalize + +2013-11-29 15:50:23 +0100 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + media: also do state change in suspended state + +2013-11-29 10:53:08 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + media: also handle prepare and range in suspended state + When we are suspended, we are already prepared. + We can get the range in the suspended state. + +2013-11-27 15:04:04 +0100 Branko Subasic + + * tests/check/Makefile.am: + * tests/check/gst/sessionmedia.c: + check: add test for uri in setup + Added unit tests for the new functionality in GstRTSPStreamTransport. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=715168 + +2013-11-28 17:47:18 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: store setup uri and use in PLAY response + Store the uri used when doing the setup and use that in the PLAY + response. + fixes https://bugzilla.gnome.org/show_bug.cgi?id=715168 + +2013-11-28 17:35:45 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + stream-transport: add method to get/set url + +2013-11-28 14:14:35 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: suspend after SDP and unsuspend before PLAYING + Based on patches by Ognyan Tonchev + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711257 + +2013-11-28 14:10:19 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session.c: + * tests/check/gst/media.c: + * tests/check/gst/mediafactory.c: + media: add suspend modes + Add support for different suspend modes. The stream is suspended right after + producing the SDP and after PAUSE. Different suspend modes are available that + affect the state of the pipeline. NONE leaves the pipeline state unchanged and + is the current and old behaviour, PAUSE will set the pipeline to the PAUSED + state and RESET will bring the pipeline to the NULL state. + A stream is also unsuspended when it goes back to PLAYING, for RESET streams, + this means that the pipeline needs to be prerolled again. + Base on patches by Ognyan Tonchev + See https://bugzilla.gnome.org/show_bug.cgi?id=711257 + +2013-11-28 14:06:53 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: start live streams in blocked state + Start live streams in the blocked state and make them preroll using the + messages. This ensure that no data is played by the sink until we explicitly + unblock the stream right before going to PLAYING. + See https://bugzilla.gnome.org/show_bug.cgi?id=711257 + +2013-11-28 13:58:05 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: refactor starting and waiting for preroll + Based on patches from Ognyan Tonchev + See https://bugzilla.gnome.org/show_bug.cgi?id=711257 + +2013-11-28 13:42:21 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: add API to block streams + Add an API to block on the streams and make it post a message. + Based on patch by Ognyan Tonchev + See https://bugzilla.gnome.org/show_bug.cgi?id=711257 + +2013-11-27 15:42:45 +0100 Edward Hervey + + * docs/libs/Makefile.am: + docs: Specify the override file + Even if it's empty (for now) it avoids make distcheck complaining + +2013-11-26 17:23:04 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: move default implementations to where they are used + +2013-11-26 16:25:37 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: take the right lock in gst_rtsp_media_set_pipeline_state() + We need to take the state_lock when calling this method. + +2013-11-26 16:24:35 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: handle add-added on non-bins too + Handle dynamic payloaders that are not bins, as used in the unit-test. + +2013-11-22 01:30:53 +0100 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + rtsp-media/-factory: Fix request pad name comments + These must be escaped for gtk-doc to parse the comments without warnings. + +2013-11-20 15:51:54 -0800 Aleix Conchillo Flaque + + rtsp-media: remove transports if media is in error status + * gst/rtsp-server/rtsp-media.c (gst_rtsp_media_set_state): if we are + trying to change to GST_STATE_NULL and media is in error status, we + remove all transports. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=712776 + +2013-11-22 11:16:20 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: use element metadata to find payloader + Use the element metadata to find the payloader instead of checking + for the base class. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=712396 + +2013-11-15 12:14:32 -0800 Aleix Conchillo Flaque + + rtsp-stream: add getter for payload type + * gst/rtsp-server/rtsp-stream.c: add new method gst_rtsp_stream_get_pt. + * gst/rtsp-server/rtsp-media.c (pad_added_cb): find real payloader + element and create the stream with this one instead of the dynpay%d + element. + https://bugzilla.gnome.org/show_bug.cgi?id=712396 + +2013-11-22 02:28:28 +0100 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-context.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-token.c: + rtsp-*: Refer to NULL as a constant in comments + Plus one typo fix. + https://bugzilla.gnome.org/show_bug.cgi?id=714988 + +2013-11-22 03:10:01 +0100 Sebastian Rasmussen + + rtsp-*: Fix type name typos in comments + * rtsp-auth: Refer to GstRTSPToken, not GstRTSPtoken + * rtsp-auth: Refer to part of constant name as text + * rtsp-auth/-permissions/-token: Refer to Permissions not Permission + * rtsp-session-media: Fix GstRTSPSessionMedia typo + * rtsp-stream: Fix typo when refering to GstBin + https://bugzilla.gnome.org/show_bug.cgi?id=714988 + +2013-11-22 00:45:17 +0100 Sebastian Rasmussen + + * docs/README: + * docs/libs/gst-rtsp-server-docs.sgml: + * docs/libs/gst-rtsp-server-sections.txt: + docs: Improve documentation + * Include annotation-glossary to quiet gtk-doc + * Rename remaining ClientState -> Context + * Rename object hierarchy file + * Remove stale chapter references + * Add missing function and object references + * Include missing GstRTSPAddressPoolResult + https://bugzilla.gnome.org/show_bug.cgi?id=714988 + +2013-11-18 10:47:04 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-server: sprinkle some allow-none annotations for g-i + +2013-11-18 11:18:15 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: add method to filter transports + Add a method to safely iterate and collect the stream transports + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711664 + +2013-11-15 16:35:05 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + rtsp: allow NULL func in filters + Passing a null function make the filters return a list of + refcounted objects. + +2013-11-12 16:52:35 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-address-pool.c: + * tests/check/gst/addresspool.c: + address-pool: fix address increment + Use a guint instead of guint8 to increment the address. It's still not + completely correct because a guint might not be able to hold the complete + address range, but that's an enhacement for later. + Add unit test to test improved behaviour. + https://bugzilla.gnome.org/show_bug.cgi?id=708237 + +2013-11-12 10:55:14 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + * tests/check/gst/client.c: + client: allow absolute path in requests + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711689 + +2013-11-07 13:22:09 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: make make_path_from_uri a vmethod + +2013-11-12 12:04:55 +0100 Wim Taymans + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/Makefile.am: + * tests/check/gst/stream.c: + stream: Add functions to get rtp and rtcp sockets + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=710100 + +2013-11-12 11:21:55 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-context.c: + * gst/rtsp-server/rtsp-context.h: + context: defing a GType for the context + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=710018 + +2013-10-12 23:56:00 +0200 Sebastian Pölsterl + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-context.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-stream.c: + Fixed several GIR warnings + +2013-11-12 11:15:46 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + auth: small typos + +2013-10-19 19:25:27 +0200 Sebastian Rasmussen + + * tests/check/Makefile.am: + * tests/check/gst/token.c: + tests: Add unit tests for token + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=710520 + +2013-10-19 19:24:34 +0200 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-token.c: + token: Validate args for gst_rtsp_token_is_allowed + See https://bugzilla.gnome.org/show_bug.cgi?id=710520 + +2013-10-19 19:21:53 +0200 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-token.c: + token: Fix bug when creating empty token + We always want to have a valid GstStructure in the token. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=710520 + +2013-11-12 10:28:55 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-thread-pool.c: + thread-pool: avoid race in shutdown + If we call g_main_loop_quit before the thread has entered g_main_loop_run, we + don't actually stop the mainloop ever. Solve this race by adding an idle source + to the mainloop that calls the _quit. This way we immediately exit the mainloop + if quit was called before we started it. + +2013-10-19 17:36:05 +0200 Sebastian Rasmussen + + * tests/check/Makefile.am: + * tests/check/gst/permissions.c: + tests: Add unit tests for permissions + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=710202 + +2013-10-15 18:50:47 +0200 Sebastian Rasmussen + + * tests/check/gst/mediafactory.c: + tests: Test mediafactory permissions + See https://bugzilla.gnome.org/show_bug.cgi?id=710202 + +2013-10-19 17:39:35 +0200 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-permissions.c: + permissions: Fix refcounting when adding/removing roles + Previously a role that was removed was unreffed twice, and when + replacing an existing role the replaced role was freed while still being + referenced. Both bugs are now fixed. + See https://bugzilla.gnome.org/show_bug.cgi?id=710202 + +2013-10-15 18:01:38 +0200 Sebastian Rasmussen + + * tests/check/gst/media.c: + * tests/check/gst/mediafactory.c: + * tests/check/gst/rtspserver.c: + tests: Check gst_rtsp_url_parse return value + See https://bugzilla.gnome.org/show_bug.cgi?id=710202 + +2013-11-05 11:22:51 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 865aa20 to dbedaa0 + +2013-10-14 12:03:07 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-server.c: + rtsp-server: Fix socket leak + https://bugzilla.gnome.org/show_bug.cgi?id=710088 + +2013-10-30 22:16:54 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-session-pool.c: + rtsp-session-pool: Make sure session IDs are properly URI-escaped + https://bugzilla.gnome.org/show_bug.cgi?id=643812 + +2013-10-15 16:37:34 -0700 Aleix Conchillo Flaque + + * examples/.gitignore: + * examples/test-video.c: + examples: fix compilation when WITH_AUTH is defined + https://bugzilla.gnome.org/show_bug.cgi?id=710228 + +2013-10-30 19:10:59 +0100 Sebastian Dröge + + * .gitignore: + gitignore: Add new test binary + +2013-10-09 15:19:12 +0200 Ognyan Tonchev + + * tests/check/Makefile.am: + * tests/check/gst/threadpool.c: + thread-pool: Add unit test for the thread pools + https://bugzilla.gnome.org/show_bug.cgi?id=710228 + +2013-10-09 15:25:10 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-thread-pool.c: + thread-pool: Fix thread leak when reusing threads + https://bugzilla.gnome.org/show_bug.cgi?id=709730 + +2013-10-14 08:30:33 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-server.c: + * tests/check/gst/rtspserver.c: + tests: fixed racy behavior in rtspserver tests + https://bugzilla.gnome.org/show_bug.cgi?id=710078 + +2013-10-14 19:36:24 +0200 Sebastian Rasmussen + + * tests/check/gst/addresspool.c: + tests: Improve address pool unit tests + Add a range with mixed IPV4 and IPV6 addresses to pool. + Get an IPV4 address from an IPV6-only pool. + Get an IPV6 address from an IPV4-only pool. + Reserve a IPV6 address from an IPV4-only pool. + Check for unicast addresses in multicast-only pool. + Check for unicast addresses in uni-/multicast-mixed pool. + https://bugzilla.gnome.org/show_bug.cgi?id=710128 + +2013-10-04 06:29:30 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: append query string in PAUSE/PLAY/TEARDOWN as well + +2013-10-01 14:04:17 +0200 Jonas Holmberg + + * gst/rtsp-server/rtsp-client.c: + client: Add query to control path + If the SETUP url contains a query it must be appended to the control + path so that it matches any already created stream in the media. The + query will also be appended to the session media path. + +2013-10-04 05:48:52 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: remove old line + +2013-10-01 13:15:19 +0200 Jonas Holmberg + + * gst/rtsp-server/rtsp-stream.c: + stream: Correct control comparison + https://bugzilla.gnome.org/show_bug.cgi?id=709176 + +2013-09-09 21:51:44 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-media.c: + media: Check dynamically if the pipeline supports seeking + We should not depend on whether or not the pipeline state change + returned NO_PREROLL or not. A media could dynamically change its + element and switch from seekable to non seekable so it's best to test + the seekable nature of the pipeline dynamically when we try to do a seek. + +2013-09-09 21:51:23 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-media.c: + media: Return FALSE if seeking is not supported + +2013-10-01 17:16:11 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: don't seek accurate by default + Accurate seeking is perhaps a little overkill in the most common situation and + causes some formats (mp3) over slow media to seek extremely slowly. + +2013-09-26 14:36:58 +0200 Ognyan Tonchev + + * tests/check/gst/rtspserver.c: + tests: fix unit test + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=708742 + +2013-09-26 11:20:05 +0200 Jonas Holmberg + + * gst/rtsp-server/rtsp-client.c: + client: Reply 400 if media cannot be constructed + Reply 400 Bad Request instead of 503 Service Unavailable if media + cannot be constructed in SETUP. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=708821 + +2013-09-26 09:41:10 +0200 Jonas Holmberg + + * gst/rtsp-server/rtsp-client.c: + client: Send setup reply once only + If find_media() failed in handle_setup_request() two replies was sent. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=708819 + +2013-09-24 18:35:36 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 6b03ba7 to 865aa20 + +2013-09-23 14:28:04 +0200 Jonas Holmberg + + * gst/rtsp-server/rtsp-server.c: + server: Emit client-connected signal earlier + Emit client-connected before the client ref is given to a GSource, + otherwise client-connected can be emitted after the client object has + been freed. + +2013-09-24 17:30:18 +0200 Patrick Radizi + + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-address-pool.h: + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/addresspool.c: + addresspool: return reason of failure + Let gst_rtsp_address_pool_reserve_address() return the reason why + the address could not be reserved. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=708229 + +2013-09-20 16:47:56 +0200 Edward Hervey + + * autogen.sh: + autogen.sh: Sync behaviour with other GStreamer modules + Allows building from outside of tree amongst other things + +2013-09-20 16:18:54 +0200 Edward Hervey + + * common: + Automatic update of common submodule + From b613661 to 6b03ba7 + +2013-09-19 18:46:14 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 74a6857 to b613661 + +2013-09-19 17:39:24 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 01a7a46 to 74a6857 + +2013-09-19 15:44:26 +0200 Jonas Holmberg + + * gst/rtsp-server/rtsp-client.c: + client: Do not read beyond end of path string + If the setup was done without a control url, make sure we don't try to read the + non-existing control string and crash. + +2013-09-17 14:39:44 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: Fix RTPInfo header + Refactor the method to make the content_base. + Use the content-base and the control url to construct the RTPInfo + url. + +2013-09-17 12:21:02 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: map url to path only in describe + Only map the request url to a path in the DESCRIBE method. The SDP then + contains the base and control urls that should be used to SETUP/PAUSE/ + PLAY/TEARDOWN the media. + +2013-09-17 11:41:57 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + Revert "client: map URL to path in requests" + This reverts commit e3fded2cec897a2ec003450607b916cc1601fd2d. + This is not correct, we only remap the URL to a path in DESCRIBE, the SDP then + contains the base and control urls which are used in the SETUP, PLAY, + PAUSE and TEARDOWN requests. + +2013-09-16 17:16:49 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: map URL to path in requests + +2013-09-16 16:47:40 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-mount-points.h: + mount-points: make vmethod to make path from uri + Make a vmethod to transform an url into a path. The path is then used to lookup + the factory. This makes it possible to also use other bits of the url, such as + the query parameters, to locate the factory. + +2013-09-09 11:05:26 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-thread-pool.c: + * gst/rtsp-server/rtsp-thread-pool.h: + thread-pool: Add cleanup to wait for the threadpool to finish + Also fix race condition if two threads are asking for the first + thread from the thread pool at once. This would case two internal + GThreadPools to be created. + https://bugzilla.gnome.org/show_bug.cgi?id=707753 + +2013-09-05 08:56:02 +0200 Jonas Holmberg + + * gst/rtsp-server/rtsp-client.c: + * tests/check/gst/client.c: + client: free threadpool + https://bugzilla.gnome.org/show_bug.cgi?id=707638 + +2013-09-06 17:23:20 +0200 Jonas Holmberg + + * tests/check/gst/mountpoints.c: + mountpoints tests: unref matched factories + https://bugzilla.gnome.org/show_bug.cgi?id=707638 + +2013-09-05 18:01:18 +0200 Jonas Holmberg + + * tests/check/gst/media.c: + media tests: unref thread pool and caps + https://bugzilla.gnome.org/show_bug.cgi?id=707638 + +2013-09-05 08:53:55 +0200 Jonas Holmberg + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + auth, media, media-factory: unref permissions + https://bugzilla.gnome.org/show_bug.cgi?id=707638 + +2013-08-23 15:15:12 +0200 Wim Taymans + + * examples/Makefile.am: + Makefile: add rule for appsrc example + +2013-08-23 15:14:29 +0200 Wim Taymans + + * examples/test-appsrc.c: + tests: add appsrc example + Add an example on how to use appsrc to feed the server pipeline with data. + +2013-08-22 12:10:39 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: remove query part from content-base string + Make sure that after the control url has been resolved, it's + not a part of the query-string. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=706568 + +2013-08-23 10:38:43 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: don't check url in response + There is no url or method in the response to check + +2013-08-08 10:57:42 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + Add handle-response signal for when we receive a GET_PARAMETER response + +2013-08-16 12:42:22 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-server.c: + Fix gst_rtsp_server_client_filter, using wrong variable type + +2013-08-22 18:39:59 +0100 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-media-factory-uri.c: + rtsp-media-factory-uri: check AAC properly for whether it's parsed or not + For AAC we need to check for framed=true instead of parsed=true. + https://bugzilla.gnome.org/show_bug.cgi?id=701384 + +2013-08-16 17:05:24 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: optimize pipeline for protocols + When TCP is not an allowed protocol for the stream, avoid creating the + appsrc/appsink/queue and tee elements. + +2013-08-16 16:34:56 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: set protocols on streams + +2013-08-16 16:16:31 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: use protocols supported by stream + +2013-08-16 16:16:00 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + media-factory: allow all protocols + +2013-08-16 16:10:43 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: configure protocols in new streams + +2013-08-16 16:08:43 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: add protocols property + +2013-08-05 10:46:33 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: send state in "new-state" signal + https://bugzilla.gnome.org/show_bug.cgi?id=705110 + +2013-08-02 14:11:01 +0200 Lubosz Sarnecki + + * configure.ac: + build: add subdir-objects to AM_INIT_AUTOMAKE + Fixes warnings with automake 1.14 + https://bugzilla.gnome.org/show_bug.cgi?id=705350 + +2013-08-02 17:15:09 +0200 Wim Taymans + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + server: add method to iterate clients of server + +2013-06-11 19:10:01 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + Add vmethod for rtsp-media subclass to access rtpbin + +2013-07-11 16:12:04 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-client.h: + small documentation fix + +2013-07-11 16:11:55 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-client.c: + Do not take range header if range is invalid + +2013-08-02 16:57:26 +0200 Wim Taymans + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-media.c: + media: add docs for new method + +2013-07-02 18:55:28 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + Add API to rtsp-media set the pipeline's state + +2013-06-11 19:09:42 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-media.c: + Update current position/duration when gst_rtsp_media_get_range_string is called + +2013-07-22 17:27:27 +0200 Wim Taymans + + * examples/test-cgroups.c: + tests: add some more docs + +2013-07-22 14:25:04 +0200 Wim Taymans + + * examples/test-cgroups.c: + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-context.c: + * gst/rtsp-server/rtsp-context.h: + * gst/rtsp-server/rtsp-params.c: + * gst/rtsp-server/rtsp-params.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-thread-pool.c: + * gst/rtsp-server/rtsp-thread-pool.h: + * tests/check/gst/client.c: + ClientState -> Context + Rename the clientstate to context and put the code in a separate file. + +2013-07-18 12:19:25 +0200 Wim Taymans + + * examples/test-auth.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + auth: add support for default token + The default token is used when the user is not authenticated and can be used to + give minimal permissions. + +2013-07-18 11:44:50 +0200 Wim Taymans + + * examples/test-auth.c: + * gst/rtsp-server/rtsp-auth.c: + auth: use defines when possible + +2013-07-18 11:44:21 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-address-pool.c: + address-pool: improve docs + +2013-07-18 12:26:45 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-permissions.c: + permissions: add the role to the copy + +2013-07-17 19:35:33 -0400 Olivier Crête + + * gst/rtsp-server/rtsp-permissions.c: + permissions: Also copy the roles + +2013-07-17 19:32:09 -0400 Olivier Crête + + * gst/rtsp-server/rtsp-permissions.c: + permissions: Make it build + +2013-07-16 12:36:56 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-address-pool.h: + docs: small fixes + +2013-07-16 12:32:51 +0200 Wim Taymans + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/client.c: + docs: improve docs + +2013-07-16 12:32:00 +0200 Wim Taymans + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-address-pool.h: + * tests/check/gst/addresspool.c: + * tests/check/gst/rtspserver.c: + address-pool: cleanups + Remove redundant method, improve docs. + +2013-07-15 17:31:35 +0200 Wim Taymans + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-permissions.c: + * gst/rtsp-server/rtsp-permissions.h: + * gst/rtsp-server/rtsp-token.c: + docs: improve docs + +2013-07-15 17:12:57 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-permissions.c: + permissions: implement _remove_role + +2013-07-15 17:12:43 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-permissions.c: + permissions: update docs + +2013-07-15 16:48:37 +0200 Wim Taymans + + * tests/check/gst/client.c: + tests: simplify tests + Client settings are now disabled by default so we don't need an auth + module to disable them. + +2013-07-15 16:47:07 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + auth: add default authorizations + When no auth module is specified, use our table of defaults to look up the + default value of the check instead of always allowing everything. This was + we can disallow client settings by default. + +2013-07-15 16:05:02 +0200 Wim Taymans + + * docs/README: + README: update readme + +2013-07-15 15:25:00 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-thread-pool.c: + * gst/rtsp-server/rtsp-thread-pool.h: + thread-pool: add more docs + +2013-07-15 14:50:38 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-thread-pool.c: + * gst/rtsp-server/rtsp-thread-pool.h: + thread-pool: fix race in thread reuse + If we try to reuse a thread right after we made it stop, we end up using a + stopped thread. Catch this case and only reuse threads that are not stopping. + +2013-07-15 14:50:26 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: add small debug + +2013-07-15 11:58:58 +0200 Wim Taymans + + * tests/check/gst/client.c: + client: fix test + Add some permissions to media so we can use the auth and enable + client settings. + +2013-07-15 11:57:49 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: support pushed context in handle_request + If we already have a pushed state, reuse it and add our own things. This makes + it easier to write tests. + +2013-07-15 11:56:06 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + auth: don't auth on methods + Don't authorize on methods anymore but on the resources that we + try to access, this is more flexible. + Move the authorization checks to where they are needed and let the + check return the response on error. + +2013-07-15 11:51:34 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-mount-points.c: + mount-points: add some debug + +2013-07-12 17:26:55 +0200 Wim Taymans + + * tests/check/gst/client.c: + tests: almost fix test + +2013-07-12 17:07:53 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + auth: let the auth module check client_settings + Let the auth module decide if client settings are allowed for the + current client. + +2013-07-12 17:06:37 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-token.c: + * gst/rtsp-server/rtsp-token.h: + token: add method to check boolean permission + +2013-07-12 16:36:05 +0200 Wim Taymans + + * examples/test-auth.c: + * examples/test-cgroups.c: + * gst/rtsp-server/rtsp-token.c: + * gst/rtsp-server/rtsp-token.h: + token: simplify token constructor + Use variable arguments to make easier API. + +2013-07-12 16:17:57 +0200 Wim Taymans + + * examples/test-auth.c: + * examples/test-cgroups.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + media-factory: add convenience API for factory + +2013-07-12 16:03:07 +0200 Wim Taymans + + * examples/test-auth.c: + * examples/test-cgroups.c: + * gst/rtsp-server/rtsp-permissions.c: + * gst/rtsp-server/rtsp-permissions.h: + permissions: simplify API a little + Avoid passing GstStructure in the add_role method, use varargs instead + to construct the structure behind the scenes. We can then also use the + structure name as the role and simplify some more logic. + +2013-07-12 16:01:14 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + auth: fix typo + +2013-07-12 15:19:29 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + auth: handle unauthorized response + Move handling of the unauthorized response to the auth module, it can add + the appropriate headers to request authorization for the required method + much better than the client. + +2013-07-12 15:13:48 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: allow for sending any message, not only requests + Change the _send_request() method to _send_message() so that we + can both send requests and replies. + +2013-07-12 14:10:13 +0200 Wim Taymans + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-server.h: + docs: fix docs + +2013-07-12 12:41:52 +0200 Wim Taymans + + * examples/test-video.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + auth: move TLS handling to auth module + Remove the TLS settings on the server and move it to the auth module because + that is where security related bits go. + +2013-07-12 12:38:54 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: add state push/pop + +2013-07-12 12:36:40 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: add connection to state + +2013-07-11 20:45:11 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-mount-points.c: + mount-points: fix debug + +2013-07-11 17:28:17 +0200 Wim Taymans + + * tests/check/gst/media.c: + tests: fix media test + +2013-07-11 17:28:04 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-thread-pool.c: + thread-pool: we don't require a state + +2013-07-11 17:18:58 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: let context ref the server + So that we don't risk losing the server object early anc crash. + +2013-07-11 17:05:00 +0200 Wim Taymans + + * tests/check/gst/client.c: + tests: fix client test + +2013-07-11 16:57:14 +0200 Wim Taymans + + * docs/README: + * docs/libs/gst-rtsp-server-docs.sgml: + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-params.c: + * gst/rtsp-server/rtsp-permissions.c: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-thread-pool.c: + * gst/rtsp-server/rtsp-token.c: + docs: improve docs + +2013-07-11 16:28:09 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session-pool.h: + session-pool: make vmethod to create a session + Make a vmethod to create a sessions so that subclasses can create + custom session objects + +2013-07-11 12:24:33 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-mount-points.h: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-stream.h: + docs: more updates + +2013-07-11 12:18:26 +0200 Wim Taymans + + * docs/libs/gst-rtsp-server-docs.sgml: + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-address-pool.h: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-permissions.c: + * gst/rtsp-server/rtsp-permissions.h: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.h: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-thread-pool.h: + docs: update docs + +2013-07-11 10:28:06 +0200 Wim Taymans + + * configure.ac: + * examples/Makefile.am: + configure: compile cgroup example conditionally + Only compile the cgroup example when we have libcgroup + +2013-07-10 20:57:12 +0200 Wim Taymans + + * configure.ac: + * examples/Makefile.am: + * examples/test-cgroups.c: + examples: add cgroups example + +2013-07-10 20:55:03 +0200 Wim Taymans + + * tests/check/gst/rtspserver.c: + tests: fix compilation + +2013-07-10 20:48:47 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-thread-pool.c: + thread-pool: fix vmethod invocation + +2013-07-10 20:48:18 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-thread-pool.c: + * gst/rtsp-server/rtsp-thread-pool.h: + thread-pool: store thread type in thread + +2013-07-10 17:09:27 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: pass thread from pool to media _prepare + Get a thread from the configured threadpool and pass it to the prepare method of + the media. + +2013-07-10 17:08:14 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: Accept a thread in _prepare + Remove out own threadpool handling and use the provided thread and + maincontext for the bus messages and the state changes. + +2013-07-10 17:07:13 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: configure client thread pool + +2013-07-10 17:06:36 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: add method to configure thread pool + +2013-07-10 16:49:55 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + server: use thread pool + Use the thread pool instead of doing our own thing. + +2013-07-10 16:47:43 +0200 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-thread-pool.c: + * gst/rtsp-server/rtsp-thread-pool.h: + thread-pool: add object to manage threads + Add an object to manage the client and media threads. + +2013-07-10 15:28:35 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + auth: debug authorization check + +2013-07-09 20:44:51 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: start media pipeline in context + Start the media pipeline in the provided context (or our default one + when NULL). This makes sure that we run the bus thread in this context and that + all media threads are children of this context. + +2013-07-09 16:38:39 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + factory: pass permissions to media by default + +2013-07-09 16:09:07 +0200 Wim Taymans + + * examples/test-auth.c: + test: add permissions to auth test + Ass some permissions to the media factory in the test. + +2013-07-09 16:04:35 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + auth: simplify auth checks + Remove client from methods, it's now in the state + Perform the check specified by the string, use the information from the + thread local context. + +2013-07-09 16:01:29 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: add state to current thread + Add the client to the ClientState object. + Place the ClientState on the current thread. + +2013-07-09 14:33:43 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: make it possible to set permissions + Make it possible to set permissions on media and media factory objects + +2013-07-09 14:31:15 +0200 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-permissions.c: + * gst/rtsp-server/rtsp-permissions.h: + permissions: add permissions object + Add a mini object to store permissions based on a role. + +2013-07-08 16:29:01 +0200 Wim Taymans + + * examples/test-auth.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + auth: add auth checks + Add an enum with auth checks and implement the checks in the auth object. + Perform the checks from the client. + +2013-07-05 20:48:18 +0200 Wim Taymans + + * examples/test-auth.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.h: + auth: use the token after authentication + After we authenticated a user, keep the Token around in the state. + +2013-07-05 20:43:39 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * tests/check/gst/media.c: + media: add optional context for bus messages + Add an optional mainloop to _prepare that will handle the bus messages instead + of always using the shared mainloop. + +2013-07-05 20:34:40 +0200 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-token.c: + * gst/rtsp-server/rtsp-token.h: + token: add authorization token + Add a simply miniobject that contains the authorizations. The object contains a + GstStructure that hold all authorization fields. When a user is authenticated, + the auth module will create a Token for the user. The token is then used to + check what operations the user is allowed to do and various other configuration + values. + +2013-07-05 12:08:36 +0200 Wim Taymans + + * examples/test-auth.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + auth: remove auth from media and factory + Remove the auth object from media and factory. We want to have the RTSPClient + authenticate and authorize resources, there is no need to place another auth + manager on the media/factory. + +2013-07-04 14:33:59 +0200 Wim Taymans + + * examples/test-auth.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.h: + auth: add support for multiple basic auth tokens + Make it possible to add multiple basic authorisation tokens to one authorization + object. Associate with each token an authorization group that will define what + capabilities are allowed. + +2013-07-03 16:15:04 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: error out on non-aggregate control + We require aggregate control (for now) for PLAY, PAUSE and TEARDOWN. + +2013-07-03 15:55:38 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: rework setup request a little + Cache the media in DESCRIBE based on the longest matching path with the uri + that we can find in the mount points. + Rework the setup request a little to get the media from the session or from + the longest matching path, this way we can derive the control string as + everything after the path instead of hardcoding it. + Find the stream based on the control string and only open a session when all + this can be done. + +2013-07-03 15:14:39 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: add method to find a stream by control url + +2013-07-03 15:13:45 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: add method to check control url of stream + +2013-07-03 12:37:48 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + session: use path matching for session media + Use a path string instead of a uri to lookup session media in the sessions. Also + use path matching to find the largest possible path that matches. + +2013-07-03 11:04:53 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-mount-points.h: + * tests/check/gst/mountpoints.c: + mount-points: remove useless vmethod + Making lookups in the mount points should not be done with a URL, if there is a + mapping to be done from URL to mount points, we'll need to do it somewhere + else. + +2013-07-03 10:25:46 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-mount-points.h: + * tests/check/gst/mountpoints.c: + mount-points: improve mount point searching + Use a GSequence to keep track of the mount points. + Match a URL to the longest matching registered mount point. This should be the + URL to perform aggreagate control and the remainder is the stream specific + control part. + Add some unit tests for this. + +2013-07-03 10:40:33 +0200 Sebastian Dröge + + * gst/rtsp-server/Makefile.am: + rtsp-server: Allow building of static library + +2013-07-02 15:59:16 +0200 Wim Taymans + + * tests/check/gst/mediafactory.c: + tests: fix compilation + +2013-07-02 15:54:43 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-sdp.c: + sdp: get control string from stream + Use the control string as configured in the stream. + +2013-07-02 14:44:35 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: add methods and property to set control string + +2013-07-02 11:58:02 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: cleanups + Rename variables for clarity + Keep media in state when we can + +2013-07-01 16:46:07 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: add more support for IPv6 + Rename _get_address to _get_multicast_address in GstRTSPStream to + make it clear that this function only deals with multicast. + Make it possible to have both an IPv4 and IPv6 multicast address on + a stream. Give the client an IPv4 or IPv6 address depending on the + address it used to connect to the server. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702002 + +2013-07-01 15:18:43 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: fix comment + +2013-07-01 14:45:49 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: handle failed port allocation + Allow for ipv4 or ipv6 socket allocations to fail. Only report failure if we + can't allocate any family at all. Also keep track of what port families we + allocated. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=703175 + +2013-07-01 12:20:50 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: improve docs + +2013-07-01 12:04:45 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream-transport.c: + stream-transport: remove old if 0 block + +2013-06-27 11:21:42 +0200 Patricia Muscalu + + * tests/check/gst/client.c: + tests: fix tests + gst_rtsp_client_get_uri() has been removed + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=703173 + +2013-06-26 17:18:33 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: add method to filter managed sessions + Add a method to filter the sessions managed by this client connection. + See https://bugzilla.gnome.org/show_bug.cgi?id=703016 + +2013-06-26 16:32:06 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: remove _get_uri() method + Remove the get_uri() method on the client. A client has no uri, the uri + property is an internal property to manage the last cached media for + the client. + +2013-06-26 16:31:39 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.h: + media-factory: fix typo + +2013-06-26 14:42:15 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Do not leak the query in default_query_stop + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=703120 + +2013-06-25 15:46:41 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: don't unlock when conversion fails + Don't unlock the state lock when conversion fails because it was not locked. + +2013-06-10 17:32:40 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + Add query_position and query_stop vmethods to rtsp-media + +2013-06-10 17:33:01 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-media.c: + Fix typo in property install for rtsp-media's time-provider + +2013-06-25 15:09:13 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: clean some variables + Clean some variables and add some guards to _send_request() + +2013-06-10 17:32:12 -0400 Youness Alaoui + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + Add gst_rtsp_client_send_request API + This makes it possible to send arbitrary messages to a client, such as + SET_PARAMETER or GET_PARAMETER + +2013-06-24 23:56:57 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: add _get_element() method + Add method to get the element used when creating the media. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=703008 + +2013-06-24 23:51:38 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: fix docs + +2013-06-24 11:41:27 -0700 Aleix Conchillo Flaque + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: allow access to the rtp session + https://bugzilla.gnome.org/show_bug.cgi?id=703004 + +2013-06-24 10:43:59 +0200 Alexander Schrab + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + dscp qos support in gst-rtsp-stream + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702645 + +2013-06-20 17:30:49 +0200 Wim Taymans + + * tests/check/gst/rtspserver.c: + tests: fix test + Actually do what the comment says. Also keep the old code around, not sure what + should happen when you get a 454 from a TEARDOWN, does it close the connection? + it currently doesn't. + +2013-06-20 12:20:21 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: also watch newly created session + When we newly created a session, start watching it immediately instead of + on the next request. + +2013-06-20 12:18:23 +0200 Patricia Muscalu + + * tests/check/gst/client.c: + tests: add unit test for new-session + See https://bugzilla.gnome.org/show_bug.cgi?id=701587 + +2013-06-20 12:16:07 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: emit new-session when new session is created + Only emit new-session when we created a new session for a client, not when a + client picked up a previous session. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701587 + +2013-06-20 11:17:29 +0200 Alexander Schrab + + * gst/rtsp-server/rtsp-client.c: + client: handle asterisk as path in requests + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701266 + +2013-06-20 11:14:31 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: handle segment query format mismatch + It's possible that the segment query returns with a different format than what + we asked for, handle this case also. + +2013-06-11 15:28:32 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-media.c: + media: use segment stop in collect_media_stats + Use segment stop instead of duration as range end point. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701185 + +2013-06-17 16:47:56 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/media.c: + rtsp-media: Do not leak the element in take_pipeline + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702470 + +2013-06-17 16:18:37 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + rtsp-client: Make configure_client_transport virtual + This patch makes configure_client_transport virtual. The functionality is + needed to handle some weird clients sending multicast transport settings as url + options. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702173 + +2013-06-12 12:23:56 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + rtsp-client: Make param_set and param_get virtual + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702072 + +2013-06-05 15:49:45 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: convert_range replaces get_range_times + get_range_times worked for handling UTC ranges for seeks, but we also + need to convert back from NPT to the requested unit in + get_range_string. convert_range is now used for both. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702084 + +2013-06-14 16:05:59 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-sdp.h: + sdp: cleanup sdp info + We don't need to pass the proto, we can more easily check a boolean. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702063 + +2013-06-12 15:22:57 +0200 Alexander Schrab + + * gst/rtsp-server/rtsp-sdp.c: + use 0.0.0.0 or :: for c= line instead of server address + +2013-06-12 10:56:16 +0200 Alexander Schrab + + * gst/rtsp-server/rtsp-client.c: + use local address, not remote, in SDP + See https://bugzilla.gnome.org/show_bug.cgi?id=702063 + +2013-06-05 15:18:26 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 098c0d7 to 01a7a46 + +2013-05-29 13:45:00 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: possibility to override range time conversion + Make it possible to override the conversion from GstRTSPTimeRange to + GstClockTimes, that is done before seeking on the media + pipeline. Overriding can be useful for UTC ranges, where the default + conversion gives nanoseconds since 1900. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701191 + +2013-06-03 12:04:44 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + rtsp-server: Expose the use_client_settings API + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=699935 + +2013-05-30 08:07:48 +0200 Alexander Schrab + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtspstream: handle both ipv4 and ipv6 clients + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701129 + +2013-05-31 15:28:58 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-sdp.c: + Revert "rtsp-sdp: Parse width/height from caps and set SDP attribute" + This reverts commit 5fd034ff1a517db7f629ffcc3ed16839c61f5c97. + We already have a way to place extra attributes in the SDP by using a string + property with prefix x- or a- in the caps. + +2013-05-31 15:27:48 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-sdp.c: + Revert "rtsp-sdp: Parse framerate caps field and set SDP attribute" + This reverts commit d6a4dee03642a2d2c05fec4752dc3ccb60b19494. + We already have a way to place extra attributes in the SDP, just make a string + property in the payloader with a- or x- prefix. + +2013-05-31 15:41:55 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-sdp.c: + rtsp: place a- and x- properties as attributes + application/x-rtp has properties with a- and x- prefixes that should be + placed as attributes in the SDP for the media instead of being added to the + fmtp. + +2013-05-31 12:10:28 +0200 Wim Taymans + + * examples/Makefile.am: + * examples/test-video.c: + example: add TLS example + +2013-05-31 11:42:36 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + server: add support for TLS + Add methods to set and get a TLS certificate. + Add vmethod to configure a new connection. By default, configure the TLS + certificate in a new connection if needed. + +2013-05-31 11:14:17 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + server: remove accept_client vmethod + This vmethod is not very useful so remove it. + +2013-05-30 17:23:51 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: don't crash on NULL GError + +2013-05-30 10:46:33 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-session-pool.c: + rtsp-session-pool: corrected session timeout detection + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701253 + +2013-05-30 10:52:46 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: improve debug + +2013-05-30 07:18:22 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-server.c: + server: refactor connection setup + Let the server accept the socket connection and construct a GstRTSPConnection + from it. Remove the code from the client and let the client only deal with + a fully configure GstRTSPConnection object. + We will need this later when the server will configure the connection for + TLS. + +2013-05-30 06:49:20 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: keep the transport object alive + Keep the transport object alive while we have it as qdata on the + source. + +2013-05-27 12:58:07 +0200 Alexander Schrab + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-server.c: + rtsp-server: Do not crash on nmapping of server + * generate error when gst_rtsp_connection_accept fails + * do not stop accepting incoming connections because + accepting a client fails + https://bugzilla.gnome.org/show_bug.cgi?id=701072 + +2013-05-24 13:39:50 +0200 Alexander Schrab + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: ipv4 adress should not be marked ipv6 even if socket is ipv6 + https://bugzilla.gnome.org/show_bug.cgi?id=700953 + +2013-05-22 03:29:38 +0200 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-sdp.c: + rtsp-sdp: Parse framerate caps field and set SDP attribute + The SDP attribute and its format is described in RFC4566. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=700747 + +2013-05-22 03:29:30 +0200 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-sdp.c: + rtsp-sdp: Parse width/height from caps and set SDP attribute + The SDP attribute and its format is described in RFC6064. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=700747 + +2013-04-29 14:46:30 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-sdp.c: + * tests/check/gst/client.c: + rtsp-sdp: add bandwidth line + https://bugzilla.gnome.org/show_bug.cgi?id=699220 + +2013-05-15 10:55:09 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 5edcd85 to 098c0d7 + +2013-04-23 11:28:39 +0200 Ognyan Tonchev + + * tests/check/gst/media.c: + tests: add dynamic payloader prepare/unprepare check + +2013-04-23 10:27:35 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: release lock when removing fakesink + +2013-04-23 10:16:17 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: set elements to NULL before removing + When removing a stream, set the elements to NULL first. This avoids + element-is-not-in-NULL-state errors when we dispose the elements. + +2013-04-22 23:55:48 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 3cb3d3c to 5edcd85 + +2013-04-22 17:34:37 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: listen to pad-removed signals + Listen to the pad-removed signal and remove the stream associated with the + removed pad. + Add signal to be notified of the removed pad. + Remove the fakesink in unprepare() + Fix signatures of the signal methods + +2013-04-22 17:33:30 +0200 Wim Taymans + + * examples/test-sdp.c: + tests: add example of reusable pipelines + +2013-04-22 17:32:31 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: add method to get the srcpad + +2013-04-22 16:49:39 +0200 Ognyan Tonchev + + * tests/check/gst/media.c: + check: add media prepare/unprepare test + See https://bugzilla.gnome.org/show_bug.cgi?id=698376 + +2013-04-22 16:40:48 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + media: disconnect from signal handlers in unprepare() + We connected to the pad-added and no-more-pads signals in prepare() so + we need to disconnect from them in unprepare(). + See https://bugzilla.gnome.org/show_bug.cgi?id=698376 + +2013-04-22 16:25:17 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + media: don't free streams array + Don't free the streams array in the unprepare() method, they were not + added in prepare(). + See https://bugzilla.gnome.org/show_bug.cgi?id=698376 + +2013-04-22 16:19:35 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + media: don't unref the pipeline in unprepare + Unprepare() should undo what prepare() does. Because the pipeline is + not created in prepare(), we should not unref it in unprepare() + +2013-04-22 16:09:22 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-stream.c: + stream: clear session and caps for reuse + Set the session and caps to NULL after unref otherwise we might unref + them again later. + See https://bugzilla.gnome.org/show_bug.cgi?id=698376 + +2013-04-15 12:21:54 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-client.c: + client: send out teardown signal before tearing down + The advantage is that in the signal handler you get direct access to + information about what streams are about to get torn down (in the + GstRTSPClientState). + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=697686 + +2013-04-15 12:17:34 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: expose connection + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=697546 + +2013-04-14 17:58:22 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From aed87ae to 3cb3d3c + +2013-04-12 11:34:38 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-media.h: + media: add method to get the base_time of the pipeline + Together with a shared clock, this base-time could eventually be sent to + the client so that it can reconstruct the exact running-time of the clock + on the server. + +2013-04-09 22:35:28 +0200 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-sdp.c: + media: add GstNetTimeProvider support + Add a property to let the media provide a GstNetTimeProvider for its clock. + Make methods to get the clock and nettimeprovider + Add a x-gst-clock property to the SDP with the IP and port number of the nettime + provider and also the current time of the clock. This should make it possible + for (GStreamer) clients to slave their clock to the server clock. + +2013-04-09 21:02:47 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From 04c7a1e to aed87ae + +2013-04-09 20:39:58 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: wait for buffering to complete + Wait for buffering to complete before changing the state to the target state. + +2013-04-09 20:11:35 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: small cleanup + +2013-03-20 12:33:54 +0100 David Svensson Fors + + * tests/check/gst/rtspserver.c: + tests: remove extra unref in test_setup_non_existing_stream + The unref is not needed anymore, teardown runs without it. + https://bugzilla.gnome.org/show_bug.cgi?id=696542 + +2013-03-20 11:28:11 +0100 David Svensson Fors + + * tests/check/gst/rtspserver.c: + tests: GSocketService cleanup in test_bind_already_in_use + Use g_socket_service_stop so the rtspserver test stops listening for + incoming connections in test_bind_already_in_use. + https://bugzilla.gnome.org/show_bug.cgi?id=696541 + +2013-03-22 18:25:07 -0400 Olivier Crête + + * gst/rtsp-server/rtsp-media-factory.c: + rtsp-media-factory: g_signal_connect_object is not thread safe, can't use it here + Instead use a GWeakRef which is safe to use + This is a known GLib bug, see: + https://bugzilla.gnome.org/show_bug.cgi?id=667145 + +2013-02-22 14:17:29 -0500 Olivier Crête + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-sdp.c: + * tests/check/gst/media.c: + * tests/check/gst/rtspserver.c: + rtsp-media/client: Reply to PLAY request with same type of Range + Remember the type of Range from the PLAY request and use the same type for + the reply. + +2013-03-18 09:25:54 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * tests/check/gst/client.c: + rtsp-client: expose uri + +2013-03-13 17:46:58 -0400 Olivier Crête + + * tests/check/gst/mediafactory.c: + tests: Hold ref while creating second media + To test if the media aren't shared, make sure we keep the first one while creating a second + otherwise the same memory address may be reused. + +2013-03-12 00:10:18 +0000 Tim-Philipp Müller + + * configure.ac: + configure: remove out-of-date comment + +2013-03-12 00:05:49 +0000 Tim-Philipp Müller + + * .gitignore: + .gitignore: ignore more build files + +2013-03-12 00:03:36 +0000 Tim-Philipp Müller + + * tests/check/Makefile.am: + tests: use right _LIBS variable for gst-plugins-base libs + +2013-03-11 11:35:14 +0100 Wim Taymans + + * tests/check/Makefile.am: + check: add librtp to libs + +2013-02-20 19:37:51 -0500 Olivier Crête + + * tests/check/gst/rtspserver.c: + tests: Add test to check selecting a port the server will send from + +2013-02-20 18:30:01 -0500 Olivier Crête + + * tests/check/gst/rtspserver.c: + tests: Make sure packets are actually received + +2013-02-19 18:27:20 -0500 Olivier Crête + + * gst/rtsp-server/rtsp-stream.c: + stream: Select unicast address from pool if appropriate + +2013-02-19 16:43:08 -0500 Olivier Crête + + * gst/rtsp-server/rtsp-stream.c: + stream: Properties are always there in Gst 1.0 + +2013-02-19 16:36:20 -0500 Olivier Crête + + * tests/check/gst/addresspool.c: + tests: Add tests for unicast addresses in pool + +2013-02-20 14:26:03 -0500 Olivier Crête + + * gst/rtsp-server/rtsp-address-pool.c: + * tests/check/gst/addresspool.c: + address-pool: Verify that multicast addresses are used for multicast and vice-versa + +2013-02-19 16:34:16 -0500 Olivier Crête + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-address-pool.h: + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/addresspool.c: + address-pool: Add unicast addresses + +2013-02-19 13:19:41 -0500 Olivier Crête + + * configure.ac: + * gst/rtsp-server/rtsp-server.c: + * tests/check/gst/rtspserver.c: + rtsp-server: Limit the number of threads per server instance + If we exceed the maximum, just round robin the clients over the existing + threads. + +2013-02-19 12:31:23 -0500 Olivier Crête + + * gst/rtsp-server/rtsp-server.c: + rtsp-server: No need to store the GMainContext in the client context + +2013-02-18 20:22:18 -0500 Olivier Crête + + * tests/check/gst/rtspserver.c: + tests: Add test for client disconnection + +2013-02-18 20:15:41 -0500 Olivier Crête + + * tests/check/gst/rtspserver.c: + tests: Test client and session timeouts with multiple threads + +2013-02-18 14:59:58 -0500 Olivier Crête + + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + Document locking and its order + +2013-02-15 20:02:31 -0500 Olivier Crête + + * tests/check/gst/rtspserver.c: + tests: Test that slow DESCRIBE don't block other clients + +2013-02-14 19:52:09 -0500 Olivier Crête + + * tests/check/gst/client.c: + tests: Add tests for client-requested multicast address + +2013-02-14 13:44:54 -0500 Olivier Crête + + * docs/libs/gst-rtsp-server-sections.txt: + docs: Put the various functions in the right sections + +2013-02-14 13:38:07 -0500 Olivier Crête + + * docs/libs/gst-rtsp-server-docs.sgml: + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-address-pool.h: + docs: Generate docs for GstRTSPAddressPool + +2013-02-13 18:32:20 -0500 Olivier Crête + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + client: Check client provided addresses against the address pool + +2013-02-13 18:01:43 -0500 Olivier Crête + + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-address-pool.h: + * tests/check/gst/addresspool.c: + address-pool: Add API to request a specific address from the pool + Also add relevant unit tests. + +2013-02-12 19:34:24 -0500 Olivier Crête + + * tests/check/gst/mediafactory.c: + tests: Check the passing around of a RTSPAddressPool + Make sure the RTSPAddressPool is propagated from the MediaFactory all the + way down to the stream. + +2013-02-12 16:34:37 -0500 Olivier Crête + + * tests/check/gst/addresspool.c: + tests: Add more tests for the address pool + +2013-02-12 16:29:25 -0500 Olivier Crête + + * gst/rtsp-server/rtsp-address-pool.c: + address-pool: Fix off by one error + When splitting a port range, the port after a skip is not part of range. + +2013-03-07 00:04:19 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 2de221c to 04c7a1e + +2013-02-07 16:18:08 -0600 George McCollister + + * configure.ac: + configure: replace deprecated AM_CONFIG_HEADER with AC_CONFIG_HEADERS + AM_CONFIG_HEADER was removed in automake 1.13 + https://bugzilla.gnome.org/show_bug.cgi?id=693368 + +2013-01-28 20:45:44 +0100 Stefan Sauer + + * common: + Automatic update of common submodule + From a942293 to 2de221c + +2013-01-28 10:31:50 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: make sure the watch exists while sending data + Protect the send_func with a lock. This allows us to wait for sending + to complete before changing the send_func and user_data. We add an + extra ref to the watch to make sure that it remains valid during + sending. + When closing the connection, set the send_func to NULL + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=692433 + +2013-01-16 12:16:32 +0000 Tim-Philipp Müller + + * tests/check/Makefile.am: + tests: use GST_*_1_0 environment variables everywhere + The _1_0 suffixed environment variables override the + non-suffixed ones, so if we're in an environment that + sets the _1_0 suffixed ones, such as jhbuild, we need + to set those to make sure ours actually always get + used. + +2013-01-15 15:09:24 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From acb04d9 to a942293 + +2012-12-14 11:58:29 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: set the client backlog + Set the client backlog to a reasonable default + +2012-12-04 09:47:35 +0100 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Make the element a constructor parameter + https://bugzilla.gnome.org/show_bug.cgi?id=689594 + +2012-12-04 01:05:31 +0100 Sebastian Rasmussen + + * docs/libs/Makefile.am: + docs: Link with gcov library when gcov is enabled + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=689583 + +2012-11-30 15:03:15 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: match prepare with unprepare + Really unprepare when there were an equal amount of prepare calls. + +2012-11-30 14:58:46 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: media has to be unprepared in finalize + Because unprepare takes away the last ref on the media. + +2012-11-30 14:36:30 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + Revert "client: never call gst_rtsp_media_unprepare, let gst_rtsp_media_finalize do it" + This reverts commit ba5b78ff2ff223049188eb456e228c709ccd3e05. + We can't use the refcount to trigger unprepare because it is the unprepare call + that removes the last refcount after all messages are consumed. What we should + probably do is make a prepared refcount and only unprepare when the refcount + reaches 0. + +2012-11-30 13:35:05 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: let the source unref the last media ref + the last ref to the media is held by the source so we don't need to add more ref + and unrefs, we simply destroy the media when the source is gone. + +2012-11-30 12:54:10 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: improve debug + +2012-11-30 12:53:02 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: check state + Make sure we are in the right state when collecting the position and duration. + Only make ourselves PREPARED when we were previously PREPARING. + +2012-11-30 10:05:48 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: use g_object_ref/unref for GObjects + +2012-11-30 07:05:25 +0100 Alessandro Decina + + * gst/rtsp-server/rtsp-client.c: + client: never call gst_rtsp_media_unprepare, let gst_rtsp_media_finalize do it + Calling gst_rtsp_media_unprepare breaks shared medias. Just unref + GstRTSPMedia instances and let gst_rtsp_media_finalize unprepare when a media + isn't being used anymore. + +2012-11-30 06:17:46 +0100 Alessandro Decina + + * gst/rtsp-server/rtsp-media.c: + Fix compiler warning + +2012-11-30 06:14:49 +0100 Alessandro Decina + + * gst/rtsp-server/rtsp-media-factory-uri.c: + Add missing g_type_class_add_private in GstRTSPMediaFactoryURI + +2012-11-29 17:21:12 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session-media.h: + small cleanup + +2012-11-29 17:20:56 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/media.c: + media: avoid element leak + +2012-11-29 17:20:26 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: require an element in media constructor + +2012-11-29 17:07:30 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + Revert "client: TEARDOWN brings that state to Init again" + This reverts commit 4b61fdad85a3ca84752bf074fdb2fa203954b32e. + The object is already disposed, there is no point in setting the state. + +2012-11-29 12:30:20 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: TEARDOWN brings that state to Init again + +2012-11-29 11:11:05 +0100 Wim Taymans + + * docs/libs/gst-rtsp-server-sections.txt: + * examples/test-auth.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory-uri.h: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-mount-points.h: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/media.c: + rtsp: make object details private + Make all object details private + Add methods to access private bits + +2012-11-28 14:50:47 +0100 Wim Taymans + + * tests/check/Makefile.am: + * tests/check/gst/media.c: + tests: add media tests + +2012-11-28 14:45:30 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: check if prepared for some methods + Check that the media object is prepared before doing seek and getting the + current position etc. + Add some g_return checks. + +2012-11-28 12:40:46 +0100 Wim Taymans + + * tests/check/Makefile.am: + * tests/check/gst/mediafactory.c: + tests: add mediafactory test + +2012-11-28 12:40:18 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: improve debug + +2012-11-28 12:39:37 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: unref pipeline in finalize to avoid leaking it + +2012-11-28 12:10:47 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media.c: + rtsp: use gst_object_unref on GstObjects + +2012-11-28 12:10:14 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + media-factory: require an url + +2012-11-28 11:40:33 +0100 Wim Taymans + + * examples/test-uri.c: + examples: fix include + +2012-11-28 11:17:27 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.h: + server: remove unused include + +2012-11-28 11:07:57 +0100 Wim Taymans + + * tests/check/Makefile.am: + * tests/check/gst/mountpoints.c: + tests: add test for mountpoints + +2012-11-28 11:05:08 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: fix factory leak + Keep the factory in the state object only for authorization checks and make + sure we unref it on failure. Also don't keep invalid objects in the state + object. + +2012-11-28 10:40:14 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-mount-points.c: + mounts: add g_return_if guards + +2012-11-27 12:51:55 +0100 Wim Taymans + + * tests/check/gst/client.c: + tests: add more tests + +2012-11-27 12:33:02 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: improve debug + +2012-11-27 12:24:21 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: improve debug and fix leaks + Cleanup the uri and session when there is a bad request. + +2012-11-27 12:17:05 +0100 Wim Taymans + + * common: + update common + +2012-11-27 12:13:59 +0100 Wim Taymans + + * tests/check/gst/client.c: + test: add test for session in options request + +2012-11-27 12:11:41 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: use 454 when session can't be found + We should use 454 when a session can't be found because there was no session + pool configured in the server. This is not a server configuration problem + because the server on which the request is done might not be the same one that + will keep the sessions for us and so it does not need to support sessions. + +2012-11-27 11:17:45 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: only free connection when there is one + It's possible that the client doesn't have a connection when we try to free it. + +2012-11-27 11:17:31 +0100 Wim Taymans + + * tests/check/Makefile.am: + * tests/check/gst/client.c: + tests: add unit test for the client object + +2012-11-26 17:35:51 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: small cleanup + +2012-11-26 17:34:35 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.h: + client: remove unused include + +2012-11-26 17:34:24 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: fix compilation + +2012-11-26 17:28:29 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: call destroy without the lock + +2012-11-26 17:20:39 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: make the client usable without a socket + Make a method to let the client handle a message and a callback when the client + wants us to send a response message back. This makes it possible to also use the + client object without the sockets, which should make it easier to test. + +2012-11-26 16:45:04 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: small cleanup + +2012-11-26 16:39:26 +0100 Wim Taymans + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-server.c: + client: remove reference to server + We don't need to keep a ref to the server + +2012-11-26 16:30:16 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: add locking + Also add some g_return_if() + +2012-11-26 13:37:20 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: log more errors + +2012-11-26 13:35:48 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: fix compilation + +2012-11-26 13:16:59 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: add generic close-after-send support + Add a property to send_response() to close the connection after the response has + been sent to the client. + +2012-11-26 12:34:05 +0100 Wim Taymans + + * docs/README: + * docs/libs/gst-rtsp-server-docs.sgml: + * docs/libs/gst-rtsp-server-sections.txt: + * docs/libs/gst-rtsp-server.types: + * examples/test-auth.c: + * examples/test-launch.c: + * examples/test-mp4.c: + * examples/test-multicast.c: + * examples/test-multicast2.c: + * examples/test-ogg.c: + * examples/test-readme.c: + * examples/test-sdp.c: + * examples/test-uri.c: + * examples/test-video.c: + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media-mapping.c: + * gst/rtsp-server/rtsp-media-mapping.h: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-mount-points.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session-pool.h: + * tests/check/gst/rtspserver.c: + MediaMapping -> MountPoints + Describes better what the object manages. + +2012-11-26 09:36:09 +0100 Wim Taymans + + * configure.ac: + configure: bump required version of -base + +2012-11-21 17:21:28 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: fix seeking + +2012-11-21 16:41:56 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: support more Range formats + Use the new -base methods to convert the Range string into a seek start and stop + value. + +2012-11-21 16:41:37 +0100 Wim Taymans + + * examples/test-launch.c: + examples: fix whitespace + +2012-11-20 13:34:46 +0100 Wim Taymans + + * examples/test-auth.c: + test-auth: add example of how to remove sessions + Add an example of the session filter api. + +2012-11-20 12:47:49 +0100 Wim Taymans + + * examples/test-uri.c: + test-uri: remove mapping example + +2012-11-20 12:47:20 +0100 Wim Taymans + + * examples/test-uri.c: + test-uri: fix callback signature + +2012-11-20 12:29:55 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + factory: keep ref to factory while media active + While the media from a factory is alive, keep a ref to the factory. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=663555 + +2012-11-20 12:29:26 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + factory-uri: add some debug + +2012-11-20 12:24:13 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: set udp sources to PLAYING + Set the UDP sources to PLAYING and locked state before we add it to the pipeline + so that it doesn't cause our pipeline to produce ASYNC-DONE. + +2012-11-20 12:10:16 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + factory-uri: take ref to factory + Take a ref to the factory that we place in our list. + +2012-11-20 11:30:09 +0100 Wim Taymans + + * tests/Makefile.am: + * tests/test-reuse.c: + test: add test for server reuse + See https://bugzilla.gnome.org/show_bug.cgi?id=688395 + +2012-11-15 14:02:37 +0100 David Svensson Fors + + * gst/rtsp-server/rtsp-server.c: + server: start and stop multiple times + Stop listening on the RTSP port when the GSource is removed, so clients + can't connect and the server can be started again. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=688395 + +2012-11-20 11:24:35 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: fix small leak + +2012-11-20 09:42:51 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: unref source in finish_unprepare + The source is created in prepare, unref it in finish_unprepare. + See https://bugzilla.gnome.org/show_bug.cgi?id=688707 + +2012-11-19 15:47:08 +0100 David Svensson Fors + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + rtsp-media: remove bus watch before finalizing + * A GDestroyNotify function is set for the bus watch in gst_rtsp_media_prepare. + * An extra media ref is added for the bus watch. This extra ref is unreffed by + the GDestroyNotify function. + * gst_rtsp_media_unprepare destroys the source so the bus watch is removed. + * GstRTSPClient, which calls gst_rtsp_media_prepare, also calls + gst_rtsp_media_unprepare before unreffing the media. + This way, the bus watch will be removed before the media is finalized. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=688707 + +2012-11-17 14:51:52 +0100 Alessandro Decina + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: wait until the TEARDOWN response is sent to close the connection + Responses can be sent async so we need to wait until the TEARDOWN response has + been written before we close the connection to the client. This avoids the risk + of writing/polling closed sockets. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=688535 + +2012-11-19 15:44:27 +0100 David Svensson Fors + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: plug socket leak + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=688703 + +2012-11-19 11:31:12 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 6bb6951 to a72faea + +2012-11-17 00:11:27 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-media-factory-uri.c: + rtsp-server: don't use deprecated API + +2012-11-17 00:03:42 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: fix unused-but-set-variable compiler warning + rtsp-client.c:1260:21: error: variable 'protocols' set but not used + +2012-11-15 17:11:16 +0100 Wim Taymans + + * TODO: + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-client.c: + rtsp: cleanups + +2012-11-15 16:52:42 +0100 Wim Taymans + + * examples/Makefile.am: + * examples/test-multicast2.c: + examples: add another multicast example + Add an example for how to configure separate multicast ranges for each media + stream. + +2012-11-15 16:21:51 +0100 Wim Taymans + + * examples/test-multicast.c: + test: set shared + +2012-11-15 16:18:29 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + stream: use the address managed by the stream + Use the address managed by the stream for multicast. This allows us to have 1 + multicast address for each stream. + Because the address is now managed by the stream we don't have to pass it around + anymore. + Set the address pool on the streams. + +2012-11-15 16:15:20 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp: improve debug + +2012-11-15 15:41:42 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: add signal for new streams + This allows applications to listen for new streams and configure properties on + them, like the address pool. + +2012-11-15 15:41:19 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: configure address pool in new streams + +2012-11-15 15:36:21 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: add methods to deal with address pool + Add methods to get and set the address pool for the stream + Add method to allocate and get the multicast addresses for this stream. + +2012-11-15 15:32:43 +0100 Wim Taymans + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: remove MTU property + It is a stream property + +2012-11-15 15:29:35 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: set blocksize only on stream + Set the blocksize only on the current stream. + +2012-11-15 13:52:07 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: share src and sink sockets + the allocated socket is in the used-socket property, not socket. + +2012-11-15 13:25:14 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-address-pool.h: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + * tests/check/gst/addresspool.c: + rtsp: make address-pool return an address object + Return a boxed GstRTSPAddress from the GstRTSPAddressPool. This allows us to + store more info in the structure and allows us to more easily return the address + to the right pool when no longer needed. + Pass the address to the StreamTransport so that we can return it to the pool + when the stream transport is freed or changed. + +2012-11-15 13:22:54 +0100 Wim Taymans + + * examples/Makefile.am: + * examples/test-multicast.c: + examples: add multicast example + Show how to set up the multicast address pool so that media can be + server with multicast. + +2012-11-14 17:23:59 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + rtsp: use AddressPool + Remove the multicast_group property. + Use the configured addresspool to allocate multicast addresses. + +2012-11-14 16:17:33 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-address-pool.h: + address-pool: add clear method + +2012-11-14 16:10:45 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-address-pool.c: + address-pool: small cleanups + +2012-11-14 15:50:42 +0100 Wim Taymans + + * tests/check/Makefile.am: + * tests/check/gst/addresspool.c: + tests: add addresspool unit test + +2012-11-14 15:49:06 +0100 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-address-pool.h: + address-pool: add object to manage multicast addresses + Make an object that can manage a rage of multicast addresses and ports. + +2012-11-13 12:05:42 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: set default max-threads property + +2012-11-13 11:54:17 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: wait for concurrent _prepare + If a prepare is busy, wait for the result. + +2012-11-13 11:49:08 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: add lock around message handler + We don't want to dispatch messages while we are still processing the result of + the state change. + +2012-11-13 11:15:35 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: add lock to protect state changes + +2012-11-13 11:14:49 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: add locking + +2012-11-12 17:11:18 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.c: + stream-transport: add keep-alive method + +2012-11-12 17:06:42 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.c: + stream-transport: add method to handle RTP/RTCP + Call new methods instead of poking into the structures directly. + +2012-11-12 16:51:03 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-media.h: + session-media: add locking + +2012-11-12 16:42:37 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + session: add locking + +2012-11-12 16:30:16 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: free old socket + +2012-11-12 16:18:57 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-mapping.c: + * gst/rtsp-server/rtsp-media-mapping.h: + mapping: add locking + +2012-11-12 16:14:19 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + media-factory: add locking + +2012-11-12 16:03:21 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + auth: add locking + +2012-11-12 15:53:28 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + server: add max-thread property + +2012-11-12 15:29:39 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + server: use a threadpool for the mainloops + +2012-11-12 14:30:43 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: rename method + gst_rtsp_client_create_from_socket -> gst_rtsp_client_use_socket: we + don't really create the client from the socket, we use the socket for the + client. + +2012-11-12 14:09:09 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-server.c: + server: rework maincontext handling in clients + Make a separate method to attach a client to a MainContext. + Let the server decide in what GMainContext the client will operate and give this + context to the client in attach. Then the server can later decide to use a + separate thread for each client or just use the mainthread. + +2012-11-12 12:40:34 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + session: move session header code in session object + +2012-11-04 00:14:25 +0000 Tim-Philipp Müller + + * COPYING: + * COPYING.LIB: + * examples/test-auth.c: + * examples/test-launch.c: + * examples/test-mp4.c: + * examples/test-ogg.c: + * examples/test-readme.c: + * examples/test-sdp.c: + * examples/test-uri.c: + * examples/test-video.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory-uri.h: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media-mapping.c: + * gst/rtsp-server/rtsp-media-mapping.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-params.c: + * gst/rtsp-server/rtsp-params.h: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-sdp.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/rtspserver.c: + * tests/test-cleanup.c: + Fix FSF address + +2012-10-28 13:48:44 +0100 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session.c: + rtsp-server: added annotations to indicate type of ownership transfer of return values + https://bugzilla.gnome.org/show_bug.cgi?id=680777 + +2012-10-28 15:37:51 +0000 Tim-Philipp Müller + + * configure.ac: + No need to define GST_USE_UNSTABLE_API any more, 1.0 is stable now + +2012-10-28 15:09:04 +0000 Tim-Philipp Müller + + * Makefile.am: + * bindings/Makefile.am: + * bindings/vala/Makefile.am: + * bindings/vala/gst-rtsp-server-0.10.deps: + * bindings/vala/gst-rtsp-server-0.10.vapi: + * bindings/vala/packages/gst-rtsp-server-0.10.deps: + * bindings/vala/packages/gst-rtsp-server-0.10.files: + * bindings/vala/packages/gst-rtsp-server-0.10.gi: + * bindings/vala/packages/gst-rtsp-server-0.10.metadata: + * bindings/vala/packages/gst-rtsp-server-0.10.namespace: + * configure.ac: + bindings: remove vala bindings + They'll be reunited with the other GStreamer bindings + https://bugzilla.gnome.org/show_bug.cgi?id=680777 + +2012-10-28 00:23:57 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + rtsp: only create transport when needed + Only create the StreamTransport when configured. + +2012-10-27 23:53:35 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: small cleanup + +2012-10-27 23:49:24 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + rtsp: refactor configuration of transport + Move the configuration of the transport to a place where it makes + more sense. + +2012-10-27 21:26:55 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: refactor transport parsing + +2012-10-27 21:05:03 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: refuse to change the MTU on shared media + If we change the MTU of chared media, it changes for all clients. + We don't want to set the MTU to something large for clients that + stream over UDP. + +2012-10-27 11:53:51 +0200 Wim Taymans + + * examples/test-mp4.c: + * gst/rtsp-server/rtsp-media.c: + small fixes to docs and debug + +2012-10-26 17:29:30 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: transports must already have been removed + +2012-10-26 17:28:10 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: improve join and leave of the pipeline + simplify code + Do the cleanup properly + Add some docs + +2012-10-26 15:23:16 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: move unprepare below default implementation + Makes it easier to find the default implementation + +2012-10-26 15:21:50 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: signal unprepared when we actually finish + +2012-10-26 15:19:23 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: no need to unlock, unprepare does that when needed + +2012-10-26 12:33:21 +0200 Wim Taymans + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media-mapping.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-params.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.h: + docs: update docs + +2012-10-26 12:04:02 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-mapping.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp: fix MTU setting + Fix setting of the MTU. There is no need for a vmethod. + +2012-10-26 11:02:43 +0200 Wim Taymans + + * docs/README: + docs: update docs + +2012-10-26 11:24:55 +0100 Tim-Philipp Müller + + * configure.ac: + configure: bump version number after refactoring + +2012-10-25 21:29:58 +0200 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp: massive refactoring + Make GObjects from the remaining simple structures. + Remove GstRTSPSessionStream, it's not needed. + Rename GstRTSPMediaStream -> GstRTSPStream: It is shorter + Rename GstRTSPMediaTrans -> GstRTSPStreamTransport: It describes how + a GstRTSPStream should be transported to a client. + Rename GstRTSPMediaFactory::get_element -> create_element because that + more accurately describes what it does. + Make nice methods instead of poking in the structures. + Move some methods inside the relevant object source code. + Use GPtrArray to store objects instead of plain arrays, it is more + natural and allows us to more easily clean up. + Move the allocation of udp ports to the Stream object. The Stream object + contains the elements needed to stream the media to a client. + Improve the prepare and unprepare methods. Unprepare should now undo + everything prepare did. Improve also async unprepare when doing EOS on + shutdown. Make sure we always unprepare correctly. + +2012-10-23 22:11:17 +0200 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Unref server address clients connected to + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=686725 + +2012-10-22 16:09:24 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-server.c: + rtsp-server: don't ref server socket if it is NULL + Fixes test_bind_already_in_use unit test again after commit 6a497440. + https://bugzilla.gnome.org/show_bug.cgi?id=686644 + +2012-10-22 16:29:09 +0200 Sebastian Rasmussen + + * tests/check/Makefile.am: + tests: Add libgio link dependency + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=686647 + +2012-10-01 20:03:43 +0200 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-media-mapping.c: + * gst/rtsp-server/rtsp-media-mapping.h: + rtsp-media-mapping: rename find_media vfunc to find_factory + The virtual method and class method should have the same name + so it is correctly represented in GIR file + https://bugzilla.gnome.org/show_bug.cgi?id=680777 + +2012-10-01 19:46:15 +0200 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-mapping.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + rtsp-server: fixed comments and GIR annotations + https://bugzilla.gnome.org/show_bug.cgi?id=680777 + +2012-10-12 07:18:19 +0200 Alessandro Decina + + * gst/rtsp-server/rtsp-media-mapping.c: + media-mapping: fix transfer mode for gst_rtsp_media_mapping_add_factory + +2012-10-12 07:08:57 +0200 Alessandro Decina + + * gst/rtsp-server/rtsp-server.c: + rtsp-server: allow binding on port 0 (binds on a random port) + +2012-10-12 06:21:24 +0200 Alessandro Decina + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + rtsp-server: add bound-port property + bound-port can be used to retrieve the port number when the server is bound on + port 0, which binds on a random port. + +2012-10-12 06:11:36 +0200 Alessandro Decina + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + rtsp-media-factory: make ::get_element overridable by GI bindings + The way to annotate vfuncs with GI seems to be to create an invoker (GI term) + for them and to annotate the invoker. Add gst_rtsp_media_factory_get_element() + as the invoker for ::get_element(), making it overridable by GI generated + bindings. + +2012-10-12 06:07:07 +0200 Alessandro Decina + + * gst/rtsp-server/rtsp-media-factory-uri.c: + rtsp-media-factory-uri: don't autoplug parsers in a loop + Stop autoplugging parsers if caps have parsed=true set. Fixes autoplugging + h264parse forever. + +2012-10-06 15:49:07 +0200 Alessandro Decina + + * gst/rtsp-server/Makefile.am: + Explicitly link against gio. Fix link error on mac. + +2012-10-10 11:13:10 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-session.c: + session: add ttl to the transport header in SETUP + See https://bugzilla.gnome.org/show_bug.cgi?id=685561 + +2012-10-10 11:06:02 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media.c: + client: Use client transport settings for multicast if allowed. + This patch makes it possible for the client to send transport settings for + multicast (destination && ttl). Client settings must be explicitly allowed or + the server will use its own settings. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=685561 + +2012-10-06 15:02:27 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 6c0b52c to 6bb6951 + +2012-10-01 16:13:50 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: do not destroy the rtsp watch + Don't destroy the client watch while dispatching. The rtsp watch is + automatically destroyed after the rtsp watch function closed() has + been called. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=685220 + +2012-09-22 16:11:48 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 4f962f7 to 6c0b52c + +2012-09-10 16:25:57 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + media: fix check for seekability + +2012-09-07 17:14:30 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: use more GIO + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=681593 + +2012-09-07 17:14:10 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: remove obsolete includes + +2012-09-03 17:33:17 -0700 Aleix Conchillo Flaque + + rtsp-media: also initialize transports in on_ssrc_active (bug #683304) + * gst/rtsp-server/rtsp-media.c: GstRTSPMediaStream transports might not + be available in "on_new_ssrc". The transports are added in + gst_rtsp_media_set_state when going to PLAYING state. However, + "on_new_ssrc" might be called before this happens. + https://bugzilla.gnome.org/show_bug.cgi?id=683304 + +2012-09-03 10:48:14 -0700 Aleix Conchillo Flaque + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + rtsp-client: add signals for rtsp requests (fixes #683287) + +2012-08-30 12:03:27 -0700 Aleix Conchillo Flaque + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + add new-session signal to rtsp-client (fixes #683058) + +2012-08-22 13:34:55 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From 668acee to 4f962f7 + +2012-08-15 15:54:32 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-server.c: + * tests/check/gst/rtspserver.c: + rtsp-server: fixed segfault in gst_rtsp_server_create_socket + Do not assume that *error is set in g_socket_address_enumerator_next. + Added test_bind_already_in_use unit-test. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=681914 + +2012-08-05 16:43:53 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 94ccf4c to 668acee + +2012-07-18 15:54:49 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + rtsp-client: make create_sdp virtual method + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=680173 + +2012-07-23 08:48:25 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 98e386f to 94ccf4c + +2012-07-10 11:39:58 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: fix docs + +2012-07-03 18:06:00 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + rtsp-server: use an existing socket to establish HTTP tunnel + Make it possible to transfer a socket from an HTTP server to be used as + an RTSP over HTTP tunnel. + +2012-07-03 13:26:30 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + rtsp: Handle the blocksize parameter + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=679325 + +2012-06-25 14:28:10 +0200 Sebastian Rasmussen + + * tests/check/Makefile.am: + * tests/check/gst/rtspserver.c: + Have unit test get header from source dir, not installed dir + This makes compilation of unit tests work in a build directory other + than the source directory. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=678789 + +2012-06-23 15:06:11 +0100 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: update for gst_element_make_from_uri() changes + +2012-06-19 15:25:36 +0200 David Svensson Fors + + * configure.ac: + * tests/Makefile.am: + * tests/check/Makefile.am: + * tests/check/gst/rtspserver.c: + rtsp: add unit test + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=678076 + +2012-06-13 11:43:17 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: don't collect media stats when going to NULL + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=678015 + +2012-06-14 09:59:06 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: don't leak transports + +2012-06-12 14:45:39 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: free transport on no_stream in SETUP handler + +2012-06-12 14:33:35 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: changed session media iteration + In client_unlink_session: now don't iterate in session->medias + list where items are removed by gst_rtsp_session_release_media. + Instead, repeatedly remove the first item. + +2012-06-12 13:39:35 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: don't use g_object_unref on GstRTSPSessionMedia + GstRTSPSessionMedia is not a GObject type. When the + GstRTSPSession is freed, it will free the media. + +2012-06-12 13:36:57 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-media-factory.c: + factory: plug pad leak in collect_streams + In gst_rtsp_media_factory_collect_streams: unref the srcpad that + was retrieved using gst_element_get_static_pad. gst_ghost_pad_new + will take one reference, and the other reference will otherwise + give a memory leak. + +2012-05-25 16:43:38 +0200 Sebastian Rasmussen + + * configure.ac: + configure: suppress some warnings when debug is disabled + Warnings about unused variables should be suppressed if core has the + debug system disabled. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=676824 + +2012-06-09 17:41:05 +0100 Tim-Philipp Müller + + * docs/libs/Makefile.am: + docs: fix build in uninstalled setup + Include gst-plugins-base libs properly. + +2012-05-25 16:38:15 +0200 Sebastian Rasmussen + + * docs/libs/gst-rtsp-server.types: + docs: include headers defining rtsp-server object types + Fixes compiler warnings during docs build. + https://bugzilla.gnome.org/show_bug.cgi?id=676824 + +2012-05-25 17:11:53 +0200 Sebastian Rasmussen + + * configure.ac: + configure: Add warning flags for compiler when configuring + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=676824 + +2012-06-08 15:07:06 +0200 Edward Hervey + + * common: + Automatic update of common submodule + From 03a0e57 to 98e386f + +2012-06-06 18:20:49 +0200 Edward Hervey + + * common: + Automatic update of common submodule + From 1fab359 to 03a0e57 + +2012-06-06 14:49:02 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-client.c: + client: fix GSocketAddress leak in gst_rtsp_client_accept + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=677463 + +2012-06-01 10:30:58 +0200 Edward Hervey + + * common: + Automatic update of common submodule + From f1b5a96 to 1fab359 + +2012-05-31 13:11:43 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 92b7266 to f1b5a96 + +2012-05-30 12:48:51 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From ec1c4a8 to 92b7266 + +2012-05-30 11:27:31 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 3429ba6 to ec1c4a8 + +2012-05-22 15:37:25 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-server.c: + rtsp: fix compiler warnings + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=676500 + +2012-05-13 15:59:10 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From dc70203 to 3429ba6 + +2012-05-11 09:42:47 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session-pool.h: + rtsp-server: port to new thread API + +2012-04-16 09:11:54 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 6db25be to dc70203 + +2012-04-13 15:27:22 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + rtsp-server: Fix compilation and compiler warnings + +2012-04-13 13:49:08 +0200 Sebastian Dröge + + * autogen.sh: + * configure.ac: + * gst/rtsp-server/Makefile.am: + configure: Modernize autotools setup a bit + Also we now only create tar.bz2 and tar.xz tarballs. + +2012-04-13 13:39:40 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 464fe15 to 6db25be + +2012-04-05 18:45:43 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 7fda524 to 464fe15 + +2012-04-04 14:45:55 +0200 Sebastian Dröge + + * configure.ac: + * docs/libs/Makefile.am: + * docs/version.entities.in: + * gst-rtsp.spec.in: + * gst/rtsp-server/Makefile.am: + * pkgconfig/Makefile.am: + * pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in: + * pkgconfig/gstreamer-rtsp-server.pc.in: + * tests/Makefile.am: + rtsp-server: Update versioning + +2012-03-29 15:12:21 +0200 Sebastian Dröge + + Merge remote-tracking branch 'origin/0.10' + Conflicts: + gst/rtsp-server/rtsp-session-pool.c + +2012-03-27 10:13:20 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-session-pool.c: + rtsp-server: Don't use deprecated GLib API + +2012-03-26 12:23:36 +0200 Wim Taymans + + Replace master with 0.11 + +2012-03-26 12:22:05 +0200 Wim Taymans + + Merge branch 'master' into 0.11 + +2012-03-26 12:20:51 +0200 Wim Taymans + + Merge branch 'master' into 0.11 + +2012-03-19 10:48:09 +0000 Vincent Penquerc'h + + * docs/README: + A couple minor typo fixes + +2012-03-13 18:10:53 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: fix state of the appqueue + +2012-03-13 16:06:50 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + factory: use videoconvert + +2012-03-13 16:02:47 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + factory: change to new style caps + +2012-03-07 15:03:55 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-pool.c: + rtsp-server: port to GIO + Port to GIO + +2012-03-07 15:03:24 +0100 Wim Taymans + + * configure.ac: + configure: fix build + +2012-02-29 15:56:06 +0000 Tim-Philipp Müller + + * docs/README: + docs: fix for gst_rtsp_server_set_port() -> _set_service() + https://bugzilla.gnome.org/show_bug.cgi?id=666548 + +2012-02-13 11:42:51 +0000 Tim-Philipp Müller + + * configure.ac: + * examples/Makefile.am: + First rule of gst-rtsp-server club: don't talk about gst-phonon + +2012-02-13 11:40:44 +0000 Tim-Philipp Müller + + * configure.ac: + * pkgconfig/Makefile.am: + * pkgconfig/gst-rtsp-server-uninstalled.pc.in: + * pkgconfig/gst-rtsp-server.pc.in: + * pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in: + * pkgconfig/gstreamer-rtsp-server.pc.in: + pkg-config: rename gst-rtsp-server-0.11.pc to gstreamer-rtsp-server-0.11.pc + For consistency with all other modules. + +2012-02-13 11:06:33 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: update for new map API + +2012-02-13 10:37:37 +0000 Tim-Philipp Müller + + * .gitignore: + * bindings/Makefile.am: + * bindings/python/Makefile.am: + * bindings/python/arg-types.py: + * bindings/python/codegen/Makefile.am: + * bindings/python/codegen/__init__.py: + * bindings/python/codegen/argtypes.py: + * bindings/python/codegen/code-coverage.py: + * bindings/python/codegen/codegen.py: + * bindings/python/codegen/definitions.py: + * bindings/python/codegen/defsparser.py: + * bindings/python/codegen/docextract.py: + * bindings/python/codegen/docgen.py: + * bindings/python/codegen/fileprefix.override: + * bindings/python/codegen/fileprefixmodule.c: + * bindings/python/codegen/h2def.py: + * bindings/python/codegen/mergedefs.py: + * bindings/python/codegen/mkskel.py: + * bindings/python/codegen/override.py: + * bindings/python/codegen/reversewrapper.py: + * bindings/python/codegen/scmexpr.py: + * bindings/python/rtspserver-types.defs: + * bindings/python/rtspserver.defs: + * bindings/python/rtspserver.override: + * bindings/python/rtspservermodule.c: + * bindings/python/test.py: + * configure.ac: + python: remove pygst-based python bindings + pygi is the future, apparently. + +2012-01-25 14:12:41 +0100 Thomas Vander Stichele + + * common: + Automatic update of common submodule + From c463bc0 to 7fda524 + +2012-01-25 11:40:59 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From 2a59016 to c463bc0 + +2012-01-18 16:48:41 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From 0807187 to 2a59016 + +2012-01-04 19:56:02 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 11f0cd5 to 0807187 + +2011-12-09 11:00:46 +0100 Wim Taymans + + * examples/test-auth.c: + example: update for new caps + +2011-12-09 10:53:30 +0100 Wim Taymans + + * examples/test-video.c: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + rtsp-server: port some more to 0.11 + Fix caps. + Remove bufferlist stuff + Update for new API. + Add queue before appsink now that preroll-queue-len is gone. + Update for request pad changes. + +2011-11-03 16:14:03 +0100 Wim Taymans + + Merge branch 'master' into 0.11 + +2011-11-03 16:06:23 +0100 Fabian Deutsch + + * bindings/vala/packages/gst-rtsp-server-0.10.metadata: + bindings: Fix vala binding of gst_rtsp_media_mapping_add_factory to transfer ownership. + Signed-off-by: Fabian Deutsch + +2011-11-03 16:06:23 +0100 Fabian Deutsch + + * bindings/vala/packages/gst-rtsp-server-0.10.metadata: + bindings: Fix vala binding of gst_rtsp_media_mapping_add_factory to transfer ownership. + Signed-off-by: Fabian Deutsch + +2011-11-03 12:58:42 +0100 Wim Taymans + + Merge branch 'master' into 0.11 + +2011-11-03 12:55:24 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: add a seekable boolean + Maintain the seekable state with a new variable instead of reusing the + is_live variable. + +2011-09-16 11:31:17 -0400 Victor Gottardi + + * gst/rtsp-server/rtsp-media.c: + Disallow seek in live media + +2011-11-03 11:58:42 +0100 Wim Taymans + + Merge branch 'master' into 0.11 + +2011-11-03 10:48:40 +0100 mat + + * gst/rtsp-server/rtsp-server.c: + #ifdef statements for windows socket creation were missing + +2011-09-06 21:53:46 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From a39eb83 to 11f0cd5 + +2011-09-06 16:07:18 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From 605cd9a to a39eb83 + +2011-08-16 16:39:26 +0200 Wim Taymans + + Merge branch 'master' into 0.11 + +2011-08-16 16:07:04 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: use method to access property + +2011-08-16 15:15:19 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + media-factory: add protocols property + Add a property to configure the allowed protocols in the media created from the + factory. + +2011-08-16 15:03:06 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + media-factory: add media-configure signal + Add signal to allow the application to configure the media after it was created + from the factory. + +2011-08-16 16:07:04 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: use method to access property + +2011-08-16 15:15:19 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + media-factory: add protocols property + Add a property to configure the allowed protocols in the media created from the + factory. + +2011-08-16 15:03:06 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + media-factory: add media-configure signal + Add signal to allow the application to configure the media after it was created + from the factory. + +2011-08-16 14:50:50 +0200 Wim Taymans + + Merge branch 'master' into 0.11 + +2011-08-16 13:43:44 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: use media multicast group + +2011-08-16 13:37:50 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.h: + retab some .h + +2011-08-16 13:31:52 +0200 Robert Krakora + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-sdp.h: + sdp: copy and free the server ip address + Copy and free the server ip address to make memory management easier later. + +2011-08-16 13:27:39 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + media-factory: configure multicast in media + +2011-08-16 13:25:16 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: add property for multicast group + Add a property to configure the multicast group in the media. + Based on patches from Marc Leeman and Robert Krakora. + +2011-08-16 13:13:36 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + media-factory: add property for multicast group + Add a property to configure the multicast group in the media factory. + Based on patches from Marc Leeman and Robert Krakora. + +2011-08-16 12:51:44 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: do configuration of transport in one place + Move the configuration of the transport destination address to where we also + configure the other bits. + +2011-08-16 13:43:44 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: use media multicast group + +2011-08-16 13:37:50 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.h: + retab some .h + +2011-08-16 13:31:52 +0200 Robert Krakora + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-sdp.h: + sdp: copy and free the server ip address + Copy and free the server ip address to make memory management easier later. + +2011-08-16 13:27:39 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + media-factory: configure multicast in media + +2011-08-16 13:25:16 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: add property for multicast group + Add a property to configure the multicast group in the media. + Based on patches from Marc Leeman and Robert Krakora. + +2011-08-16 13:13:36 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + media-factory: add property for multicast group + Add a property to configure the multicast group in the media factory. + Based on patches from Marc Leeman and Robert Krakora. + +2011-08-16 12:51:44 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: do configuration of transport in one place + Move the configuration of the transport destination address to where we also + configure the other bits. + +2011-08-16 12:11:59 +0200 Wim Taymans + + Merge branch 'master' into 0.11 + +2011-08-16 12:09:48 +0200 Robert Krakora + + * gst/rtsp-server/rtsp-client.c: + client: destroy pipeline on client disconnect with no prior TEARDOWN. + The problem occurs when the client abruptly closes the connection without + issuing a TEARDOWN. The TEARDOWN handler in the rtsp-client.c file of the RTSP + server is where the pipeline gets torn down. Since this handler is not called, + the pipeline remains and is up and running. Subsequent clients get their own + pipelines and if the do not issue TEARDOWNs then those pipelines will also + remain up and running. This is a resource leak. + +2011-08-16 11:53:37 +0200 Wim Taymans + + Merge branch 'master' into 0.11 + +2011-06-30 10:13:59 +0200 Emmanuel Pacaud + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + media-factory: add a "media-constructed" signal to GstRTSPMediaFactory + For example, it can be used to retrieve source elements like appsrc, in a more + convenient way than subclassing get_element. + +2011-08-16 11:12:33 +0200 Wim Taymans + + Merge branch 'master' into 0.11 + +2011-08-11 18:07:08 -0700 David Schleef + + * gst/rtsp-server/rtsp-server.c: + rtsp-server: hold on to reference while using object + +2011-08-04 08:59:17 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: use new api + +2011-08-04 08:58:58 +0200 Wim Taymans + + * configure.ac: + configure: use unstable api + +2011-06-27 11:26:26 -0700 David Schleef + + * gst/rtsp-server/rtsp-client.c: + client: fix reference counting + +2011-07-20 17:16:42 +0200 Thijs Vermeir + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + fix compiler warnings about unused variables + +2011-07-19 16:10:39 +0200 Stefan Sauer + + * examples/test-launch.c: + * examples/test-readme.c: + * examples/test-uri.c: + * examples/test-video.c: + examples: tell rtsp uri when ready + +2011-06-23 11:30:14 -0700 David Schleef + + * common: + Automatic update of common submodule + From 69b981f to 605cd9a + +2011-06-13 19:05:57 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: update for buffer API change + +2011-06-07 10:54:26 +0200 Edward Hervey + + * gst/rtsp-server/Makefile.am: + Makefile.am: 0.10 => @GST_MAJORMINOR@ + +2011-06-07 10:59:16 +0200 Edward Hervey + + * gst/rtsp-server/rtsp-media-factory-uri.c: + rtsp-media-factory-uri: GST_PLUGIN_FEATURE_NAME is no longer + +2011-06-07 10:59:03 +0200 Edward Hervey + + * gst/rtsp-server/.gitignore: + .gitignore: 0.10 => 0.11 + +2011-06-07 10:54:26 +0200 Edward Hervey + + * gst/rtsp-server/Makefile.am: + Makefile.am: 0.10 => @GST_MAJORMINOR@ + +2011-05-24 18:26:06 +0200 Wim Taymans + + Merge branch 'master' into 0.11 + +2011-05-19 23:00:52 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From 9e5bbd5 to 69b981f + +2011-05-18 16:14:10 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From fd35073 to 9e5bbd5 + +2011-05-18 12:27:35 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From 46dfcea to fd35073 + +2011-05-17 09:48:13 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media.c: + media: port to new caps API + +2011-05-17 09:45:04 +0200 Wim Taymans + + Merge branch 'master' into 0.11 + +2011-05-03 21:13:15 +0200 Fabian Deutsch + + * bindings/vala/gst-rtsp-server-0.10.vapi: + Updated Vala bindings. + Signed-off-by: Fabian Deutsch + +2011-05-03 16:24:28 +0200 Fabian Deutsch + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + Add a signal for newly connected clients. + Signed-off-by: Fabian Deutsch + +2011-05-08 13:15:19 +0200 Alessandro Decina + + * bindings/python/rtspserver.override: + python: override gst_rtsp_media_mapping_add_factory to fix refcounting + +2011-04-26 19:22:50 +0200 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-funnel.c: + * gst/rtsp-server/rtsp-funnel.h: + * gst/rtsp-server/rtsp-media.c: + rtsp-server: port to 0.11 + +2011-04-26 19:14:18 +0200 Wim Taymans + + * common: + add common + +2011-04-26 19:07:13 +0200 Wim Taymans + + Merge branch 'master' into 0.11 + Conflicts: + common + configure.ac + +2011-04-24 14:07:11 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From c3cafe1 to 46dfcea + +2011-04-20 11:19:38 +0200 Alessandro Decina + + * bindings/python/Makefile.am: + * bindings/python/rtspserver.defs: + python bindings: wrap GstRTSPMediaFactoryClass vfuncs + +2011-04-20 11:13:56 +0200 Alessandro Decina + + * bindings/python/arg-types.py: + python bindings: add GstRTSPUrlParam + Needed to implement MediaFactory virtual proxies + +2011-04-20 10:19:46 +0200 Alessandro Decina + + * bindings/python/arg-types.py: + python bindings: fix returning GstRTSPUrl types + +2011-04-20 10:17:07 +0200 Alessandro Decina + + * bindings/python/arg-types.py: + python bindings: add arg type for GstRTSPUrl + +2011-04-20 10:16:08 +0200 Alessandro Decina + + * bindings/python/rtspserver.defs: + python bindings: fix the definition of MediaFactory.collect_stream + +2011-04-04 15:59:50 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From 1ccbe09 to c3cafe1 + +2011-03-25 22:38:06 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From 193b717 to 1ccbe09 + +2011-03-25 14:58:34 +0200 Stefan Kost + + * common: + Automatic update of common submodule + From b77e2bf to 193b717 + +2011-03-25 10:04:57 +0100 Sebastian Dröge + + * Makefile.am: + build: Include lcov.mak to allow test coverage report generation + +2011-03-25 09:35:15 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From d8814b6 to b77e2bf + +2011-03-25 09:11:40 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From 6aaa286 to d8814b6 + +2011-03-24 18:51:37 +0200 Stefan Kost + + * common: + Automatic update of common submodule + From 6aec6b9 to 6aaa286 + +2011-03-18 19:34:57 +0100 Luis de Bethencourt + + * autogen.sh: + autogen: wingo signed comment + +2011-03-03 20:38:03 +0100 Miguel Angel Cabrera Moya + + * gst/rtsp-server/rtsp-session-pool.c: + session: use full charset for RTSP session ID + As specified in RFC 2326 section 3.4 use full valid charset to make guessing + session ID more difficult. + https://bugzilla.gnome.org/show_bug.cgi?id=643812 + +2011-03-07 10:23:06 +0100 Sebastian Dröge + + * gst/rtsp-server/Makefile.am: + rtsp-server: Don't install the funnel header + +2011-02-28 18:35:03 +0100 Mark Nauwelaerts + + * common: + Automatic update of common submodule + From 1de7f6a to 6aec6b9 + +2011-02-26 19:58:02 +0000 Tim-Philipp Müller + + * configure.ac: + configure: require core/base 0.10.31 + Needed at least for gst_plugin_feature_rank_compare_func(). + +2011-02-14 12:56:29 +0200 Stefan Kost + + * common: + Automatic update of common submodule + From f94d739 to 1de7f6a + +2011-02-02 15:37:03 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: remove more unused code + +2011-02-02 15:30:45 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: remove duplicate filtering + Remove the duplicate filtering code now that we have a released -good version. + Give a warning instead. + +2011-01-31 17:38:47 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + media: fix default buffer size + +2011-01-31 17:37:02 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + media-factory: add property to configure the buffer-size + Add a property to configure the kernel UDP buffer size. + +2011-01-31 17:28:22 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: add property to configure kernel buffer sizes + Add a property to configure the kernel UDP buffer size. + +2011-01-26 15:52:54 +0000 Tim-Philipp Müller + + * configure.ac: + configure: set PYGOBJECT_REQ before using it + https://bugzilla.gnome.org/show_bug.cgi?id=640641 + +2011-01-24 11:59:22 +0000 Tim-Philipp Müller + + * docs/Makefile.am: + docs: recursive into sub-directories on 'make upload' + +2011-01-24 11:53:17 +0000 Tim-Philipp Müller + + * docs/libs/gst-rtsp-server-docs.sgml: + * docs/version.entities.in: + docs: mention full version these docs are for, not just major-minor + +2011-01-24 12:07:17 +0100 Wim Taymans + + * configure.ac: + back to development + +=== release 0.10.8 === + +2011-01-24 11:57:12 +0100 Wim Taymans + + * configure.ac: + release 0.10.8 + +2011-01-19 15:29:55 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + rtsp-server: clarify docs a little + +2011-01-13 18:57:15 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: init debug category before starting thread + +2011-01-13 18:40:48 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + auth: add realm to make it more spec compliant + +2011-01-12 18:57:41 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + server: add locking + +2011-01-12 18:33:49 +0100 Wim Taymans + + * examples/test-video.c: + example: improve example docs a little + +2011-01-12 18:26:57 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: ensure the watch has a ref to the server + +2011-01-12 18:24:44 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: simpify channel function + +2011-01-12 18:18:13 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + server: simplify management of channel and source + We don't need to keep around the channel and source objects. Let the mainloop + and the source manage the source and channel respectively. + +2011-01-12 18:17:26 +0100 Wim Taymans + + * Makefile.am: + * configure.ac: + build tests + +2011-01-12 18:16:46 +0100 Wim Taymans + + * tests/.gitignore: + * tests/Makefile.am: + * tests/test-cleanup.c: + tests: add tests directory and cleanup test + +2011-01-12 18:14:48 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-mapping.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + server: improve debugging in various objects + +2011-01-12 16:38:34 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: chain up to the parent finalize + +2010-09-21 17:04:02 -0300 André Dieb Martins + + * bindings/python/rtspserver-types.defs: + * bindings/python/rtspserver.defs: + * bindings/python/rtspserver.override: + * bindings/python/test.py: + gst-rtsp-server: update python bindings + +2011-01-12 15:37:39 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: use the response from the clientstate + Create the response object only once and store in the client state. + Make all methods use the state response, + +2011-01-12 15:36:22 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: use signal to keep track of clients + Keep track of all the clients that the server creates and remove them when they + fire the 'closed' signal. + +2011-01-12 15:35:51 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: emit signal when closing + +2011-01-12 13:57:09 +0100 Wim Taymans + + * examples/.gitignore: + * examples/Makefile.am: + * examples/test-auth.c: + * examples/test-video.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.h: + media: enable per factory authorisations + Allow for adding a GstRTSPAuth on the factory and media level and check + permissions when accessing the factory. + Add hints to the auth methods for future more fine grained authorisation. + Add example application for per factory authentication. + +2011-01-12 13:16:08 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-params.c: + * gst/rtsp-server/rtsp-params.h: + rtsp-server: Pass ClientState structure arround + Pass the collected information for the ongoing request in a GstRTSPClientState + structure that we can then pass around to simplify the method arguments. This + will also be handy when we implement logging functionality. + +2011-01-12 12:07:40 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + media-factory: add methods to configure authorisation + +2011-01-12 12:07:20 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: unref auth in finalize + +2011-01-12 12:07:04 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: unref auth in finalize + +2011-01-12 11:07:26 +0100 Wim Taymans + + * docs/libs/gst-rtsp-server-docs.sgml: + * docs/libs/gst-rtsp-server-sections.txt: + * docs/libs/gst-rtsp-server.types: + docs: add more docs + +2011-01-12 10:57:08 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + server: separate create and accept + Create separate create and accept methods so that subclasses can create custom + client object. + Configure the server in the client object and prepare for keeping track of + connected clients. + +2011-01-12 10:42:52 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: add support for setting the server. + Add support for keeping a ref to the server that started this client + connection. + +2011-01-12 10:41:42 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + auth: fix memleak and add some docs + Fix a memleak of the basic auth token. + Add docs for the helper function + +2011-01-12 00:35:28 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + client: delegate setup of auth to the manager + Delegate the configuration of the authentication tokens to the manager object + when configured. + +2011-01-12 00:17:54 +0100 Wim Taymans + + * examples/test-video.c: + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + auth: add authentication object + Add an object that can check the authorization of requests. + Implement basic authentication. + Add example authentication to test-video + +2011-01-12 00:20:36 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + server: move includes back + the includes are needed for sockaddr_in. + +2011-01-11 22:41:12 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + rtsp: move network includes where they are needed + +2011-01-07 23:45:32 +0200 Sreerenj Balachandran + + * gst/rtsp-server/rtsp-media.h: + rtsp-media.h: Minor corrections in comments. + Fixes #638944 + +2011-01-11 15:52:44 +0200 Stefan Kost + + * common: + Automatic update of common submodule + From e572c87 to f94d739 + +2011-01-11 13:01:44 +0100 Edward Hervey + + * .gitignore: + * docs/.gitignore: + * docs/libs/.gitignore: + * examples/.gitignore: + * gst/rtsp-server/.gitignore: + gitignore: updates + +2011-01-11 12:58:39 +0100 Edward Hervey + + * docs/libs/Makefile.am: + docs: We don't build ps/pdf for API reference docs + +2011-01-10 16:39:36 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From ccbaa85 to e572c87 + +2011-01-10 14:56:39 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 46445ad to ccbaa85 + +2011-01-10 15:10:53 +0100 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/fs-funnel.c: + * gst/rtsp-server/fs-funnel.h: + * gst/rtsp-server/rtsp-funnel.c: + * gst/rtsp-server/rtsp-funnel.h: + * gst/rtsp-server/rtsp-media.c: + funnel: rename fsfunnel to rtspfunnel + Rename the funnel to avoid conflicts with the farsight one. + +2011-01-10 13:41:43 +0100 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/fs-funnel.c: + * gst/rtsp-server/fs-funnel.h: + * gst/rtsp-server/rtsp-media.c: + rtsp-media: add and use fsfunnel + Add a copy of fsfunnel to the build because input-selector removed the (broken) + select-all property that we need. + +2011-01-08 01:58:44 +0000 Tim-Philipp Müller + + * gst/rtsp-server/Makefile.am: + gobject-introspection: use PKG_CONFIG_PATH specified at configure time + Use PKG_CONFIG_PATH specified at configure time (if any) as well + for the g-ir-compiler, rather than just assuming the env var has + been set. + +2011-01-08 01:55:06 +0000 Tim-Philipp Müller + + * .gitignore: + * Makefile.am: + * configure.ac: + * m4/Makefile.am: + * m4/codeset.m4: + build: make autotools put all .m4 cruft into m4/ rather than polluting common/m4 + +2011-01-08 01:15:35 +0000 Tim-Philipp Müller + + * configure.ac: + * gst/rtsp-server/Makefile.am: + gobject-introspection: fix g-i build for uninstalled setup + Requires gst-plugins-base git (> 0.10.31.2). + +2011-01-07 11:27:57 +0100 Wim Taymans + + * examples/test-uri.c: + examples: add some more options and comments + +2011-01-07 11:24:39 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + factory-uri: use right property type + +2011-01-05 12:07:42 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + factory-uri: attempt to configure buffer-lists + Attempt to configure buffer lists in the payloader for improved performance. + +2011-01-05 12:06:23 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: attempt to configure bigger UDP buffers + Attempt to configure bigger udp kernel send buffers to avoid overflowing the + send buffers with high bitrate streams. + +2011-01-05 11:26:30 +0100 Jonas Larsson + + * gst/rtsp-server/rtsp-client.c: + client: use the socket length from getsockname + Use the length returned by getsockname to perform the getnameinfo call because + the size can depend on the socket type and platform. + Fixes #638723 + +2010-12-30 12:41:53 +0100 Wim Taymans + + * docs/libs/gst-rtsp-server-docs.sgml: + * docs/libs/gst-rtsp-server-sections.txt: + docs: add uri factory to the docs + +2010-12-30 12:41:31 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.h: + docs: improve docs + +2010-12-29 16:26:41 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + rtsp-server: add support for buffer lists + Add support for sending bufferlists received from appsink. + Fixes #635832 + +2010-12-28 18:35:01 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-sdp.c: + media: make method to retrieve the play range + Make a method to retrieve the playback range so that we can conditionally create + a different range for the SDP and the PLAY requests. + +2010-12-28 18:34:10 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: add signal to notify of state changes + +2010-12-28 18:31:26 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.h: + client: cleanup headers + +2010-12-28 12:18:41 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: fix typo + +2010-12-23 18:53:01 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory-uri.h: + factory-uri: add support for gstpay + Add an option to prefer gstpay over decoder + raw payloader. + +2010-12-23 15:58:14 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory-uri.h: + factory-uri: rework the autoplugger. + Rewrite the autoplugger a little so that it prefers to plug demuxers and parsers + before payloaders. + +2010-12-21 17:37:26 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + factory-uri: use better factory filter + Make better payloader filter based on autoplug rank and RTP use case. + +2010-12-20 17:48:41 +0100 Edward Hervey + + * common: + Automatic update of common submodule + From 169462a to 46445ad + +2010-12-18 11:24:48 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: set SO_REUSEADDR before bind + Set the SO_REUSEADDR _before_ bind() to make it actually work. + +2010-12-13 16:58:36 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: emit prepared signal when prepared + Make a 'prepared' signal and emit it when we successfully prepared the element. + This signal can be used to configure the media object after it has been prepared + for streaming. + +2010-12-15 14:58:00 +0200 Stefan Kost + + * common: + Automatic update of common submodule + From 011bcc8 to 169462a + +2010-12-13 16:38:09 +0100 Andy Wingo + + python an optional dependency + * configure.ac: Move up valgrind and g-i checks. Make the python + dependency optional, as it was before. + +2010-12-13 11:43:13 +0100 Wim Taymans + + Merge branch 'master' into 0.11 + Conflicts: + common + configure.ac + +2010-12-12 15:48:47 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: update range when active clients changed + When we changed the number of active clients, update the current range + information because we want the second client connecting to a shared resource + continue from where the stream currently. + +2010-12-12 04:06:41 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory-uri.h: + factory-uri: add colorspace and fix pt + Rework the way we pass data to the autoplugger. + When we have raw caps, plug a converter element to make pluggin to raw + payloaders more successful. + Make sure all dynamically plugged payloaders have a unique payload types. + +2010-12-11 18:06:26 +0100 Wim Taymans + + * examples/Makefile.am: + * examples/test-uri.c: + example: add example of the uri factory + +2010-12-11 18:01:53 +0100 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory-uri.h: + * gst/rtsp-server/rtsp-server.h: + factory-uri: add a factory to stream any URI + Make a factory that uses uridecodebin to decode any uri and autoplug a payloader + when we have one. + +2010-12-11 17:31:44 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: ignore spurious ASYNC_DONE messages + When we are dynamically adding pads, the addition of the udpsrc elements will + trigger an ASYNC_DONE. We have to ignore this because we only want to react to + the real ASYNC_DONE when everything is prerolled. + +2010-12-11 13:41:24 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + media-factory: make lock macro + +2010-12-11 10:53:28 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-client.c: + rtsp-server: Remove unused variable and dead assignment + +2010-12-11 10:49:30 +0100 Edward Hervey + + * examples/test-launch.c: + * examples/test-mp4.c: + * examples/test-ogg.c: + * examples/test-readme.c: + * examples/test-sdp.c: + * examples/test-video.c: + examples: Run gst-indent + +2010-12-11 10:48:42 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-mapping.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-params.c: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + rtsp-server: Run gst-indent + Since it wasn't using the upstream common previously, there was no + indentation check before commiting. + +2010-12-11 10:48:25 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-media-mapping.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + rtsp-server: Some more doc fixups + +2010-12-07 18:56:03 +0100 Edward Hervey + + * Makefile.am: + Makefile: Add cruft-cleaning support + +2010-12-07 18:52:15 +0100 Edward Hervey + + * Makefile.am: + * configure.ac: + * docs/Makefile.am: + * docs/libs/Makefile.am: + * docs/libs/gst-rtsp-server-docs.sgml: + * docs/libs/gst-rtsp-server-sections.txt: + * docs/libs/gst-rtsp-server.types: + * docs/version.entities.in: + docs: Add gtk-doc build system + +2010-12-07 18:14:39 +0100 Edward Hervey + + * gst/rtsp-server/Makefile.am: + Makefile.am: Use standard GIR make behaviour + +2010-12-07 18:14:22 +0100 Edward Hervey + + * autogen.sh: + * configure.ac: + autogen/configure: Bring more in sync to standard gst module behaviour + +2010-12-06 19:29:53 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: warn and fail when gstrtpbin is not found + +2010-12-06 12:40:30 +0100 Wim Taymans + + * configure.ac: + configure: open 0.11 branch + +2010-12-01 20:00:22 +0100 Edward Hervey + + * .gitmodules: + * common: + Add common submodule + +2010-12-01 19:58:49 +0100 Edward Hervey + + * common/ChangeLog: + * common/Makefile.am: + * common/c-to-xml.py: + * common/check.mak: + * common/coverage/coverage-report-entry.pl: + * common/coverage/coverage-report.pl: + * common/coverage/coverage-report.xsl: + * common/coverage/lcov.mak: + * common/gettext.patch: + * common/glib-gen.mak: + * common/gst-autogen.sh: + * common/gst-xmlinspect.py: + * common/gst.supp: + * common/gstdoc-scangobj: + * common/gtk-doc-plugins.mak: + * common/gtk-doc.mak: + * common/m4/.gitignore: + * common/m4/Makefile.am: + * common/m4/README: + * common/m4/as-ac-expand.m4: + * common/m4/as-auto-alt.m4: + * common/m4/as-compiler-flag.m4: + * common/m4/as-compiler.m4: + * common/m4/as-docbook.m4: + * common/m4/as-libtool-tags.m4: + * common/m4/as-libtool.m4: + * common/m4/as-python.m4: + * common/m4/as-scrub-include.m4: + * common/m4/as-version.m4: + * common/m4/ax_create_stdint_h.m4: + * common/m4/check.m4: + * common/m4/glib-gettext.m4: + * common/m4/gst-arch.m4: + * common/m4/gst-args.m4: + * common/m4/gst-check.m4: + * common/m4/gst-debuginfo.m4: + * common/m4/gst-default.m4: + * common/m4/gst-doc.m4: + * common/m4/gst-error.m4: + * common/m4/gst-feature.m4: + * common/m4/gst-function.m4: + * common/m4/gst-gettext.m4: + * common/m4/gst-glib2.m4: + * common/m4/gst-libxml2.m4: + * common/m4/gst-plugindir.m4: + * common/m4/gst-valgrind.m4: + * common/m4/gtk-doc.m4: + * common/m4/introspection.m4: + * common/m4/pkg.m4: + * common/mangle-tmpl.py: + * common/plugins.xsl: + * common/po.mak: + * common/release.mak: + * common/scangobj-merge.py: + * common/upload.mak: + common: Remove static version + +2010-11-08 17:04:00 +0000 Bastien Nocera + + * common/m4/introspection.m4: + Update introspection.m4 to match usage + +2010-10-30 13:26:12 +0200 Wim Taymans + + * README: + README: update + Remove old stuff from the README + +2010-10-11 11:12:11 +0200 Wim Taymans + + * configure.ac: + back to development + +=== release 0.10.7 === + +2010-10-11 11:05:40 +0200 Wim Taymans + + * configure.ac: + release 0.10.7 + +2010-10-04 17:16:40 +0200 Wim Taymans + + * examples/test-ogg.c: + test-ogg: remove parsers + Remove the parsers, they are not needed anymore as oggdemux now outputs normal + buffers with timestamps. Using the parsers also seems to break things. + +2010-09-23 12:44:18 +0200 Sebastian Pölsterl + + * bindings/vala/gst-rtsp-server-0.10.vapi: + * bindings/vala/packages/gst-rtsp-server-0.10.metadata: + Updated Vala bindings + +2010-09-22 23:13:37 +0200 Sebastian Pölsterl + + * common/m4/introspection.m4: + * configure.ac: + * gst/rtsp-server/Makefile.am: + Added initial gobject-introspection support + +2010-09-23 11:32:58 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + media-factory: don't use host for shared hash key + When we generate the key to share made between connections, don't include the + host used to connect so that we can share media even if between clients that + connected with localhost and ones with the ip address. + +2010-09-22 21:16:03 +0100 Tim-Philipp Müller + + * bindings/vala/Makefile.am: + build: fix distcheck + +2010-09-22 18:24:12 +0200 Sebastian Dröge + + * bindings/vala/gst-rtsp-server-0.10.vapi: + * bindings/vala/packages/gst-rtsp-server-0.10.gi: + * bindings/vala/packages/gst-rtsp-server-0.10.metadata: + Update Vala bindings + +2010-09-22 18:12:50 +0200 Sebastian Dröge + + * bindings/vala/Makefile.am: + * configure.ac: + Fix configure checks and installation location for Vala bindings + Fixes bug #628676. + +2010-09-22 16:32:30 +0200 Wim Taymans + + * configure.ac: + back to development + +=== release 0.10.6 === + +2010-09-22 16:22:49 +0200 Wim Taymans + + * configure.ac: + configure: release 0.10.6 + +2010-09-22 16:15:56 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: help the compiler a little + +2010-08-24 16:47:30 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-session.c: + media: cleanup media transport before freeing + Cleanup the media transport data before freeing. In particular, remove the qdata + from the rtpsource object. + +2010-08-20 18:17:08 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media-factory: add eos-shutdown property + Add an eos-shutdown property that will send an EOS to the pipeline before + shutting it down. This allows for nice cleanup in case of a muxer. + Fixes #625597 + +2010-08-20 15:58:39 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: use multiudpsink send-duplicates when we can + If we have a new enough multiudpsink with the send-duplicates property, use this + instead of doing our own filtering. Our custom filtering code should eventually + be removed when we can depend on a released -good. + +2010-08-20 13:19:56 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: don't leak destinations + Refactor and cleanup the destinations array when the stream is destroyed. + +2010-08-20 13:09:12 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: don't add udp addresses multiple times + Keep track of the udp addresses we added to udpsink and never add the same udp + destination twice. This avoids duplicate packets when using multicast. + +2010-08-20 10:18:34 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: disable use of SO_LINGER + SO_LINGER cause the client to fail to receive a TEARDOWN message because the + server close()s the connection. + +2010-08-19 18:52:47 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: use 5 second linger period in SO_LINGER + Wait 5 seconds before clearing the send buffers and reseting the connection with + the client when we do a close. This should be enough time to get the message to + the client. + See #622757 + +2010-08-16 12:32:28 +0200 Robert Krakora + + * gst/rtsp-server/rtsp-server.c: + server: use SO_LINGER + SO_LINGER on the socket will make sure that any pending data on the socket is + flushed ASAP and that the socket connection is reset. This makes sure that the + socket can be reused immediately. + Fixes 622757 + +2010-08-16 12:24:50 +0200 Wim Taymans + + * docs/README: + README: add blurb about shared media factories + +2010-08-09 12:56:23 -0700 David Schleef + + * gst/rtsp-server/rtsp-media.c: + Add stdlib.h for atoi() + +2010-05-20 14:33:24 +0100 Tim-Philipp Müller + + * bindings/python/Makefile.am: + * bindings/vala/Makefile.am: + build: distcheck fixes + Fix 'make distcheck', somewhat (it still fails because it tries to + install files into /usr/share/vala/vapi/ irrespective of the + configured prefix). + +2010-05-20 14:09:18 +0100 Tim-Philipp Müller + + * configure.ac: + configure: bump core/base requirements to released version + Makes things less confusing for people. + +2010-04-25 16:35:30 +0100 Tim-Philipp Müller + + * configure.ac: + configure: fail if GStreamer core/base requirements are not met + +2010-04-06 17:08:40 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: improve client cleanups + Make sure the session does not timeout when using TCP. We need to do this + because quicktime player does not send RTCP for some reason in tunneled + mode. + Refactor some cleanup code. + Fixes #612915 + +2010-04-06 17:07:27 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + session: add support for prevent session timeouts + Add an atomix counter to prevent session timeouts when we are, for example, + streaming over TCP. + +2010-04-06 15:45:56 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: fix unlink on session timeouts + When our session times out, make sure we unlink all streams in this + session. + Remove the tunnelid when closing the connection. + +2010-04-06 15:44:45 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-session.c: + session: small cleanups + +2010-04-06 11:13:51 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: handle lost_tunnel callbacks + Handle lost_tunnel callbacks and use it to store the tunnelid back into the + hashtable so that we can reuse it for when the client reopens the POST + socket. + Close the connection after a TEARDOWN. + Make sure or watchid is cleared when the watch is removed. + Fixes #612915 + +2010-03-19 18:03:40 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-sdp.c: + rtsp-server: add more support for multicast + +2010-03-19 15:15:29 +0100 Wim Taymans + + * configure.ac: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: allow configuration of allowed lower transport + +2010-03-16 18:37:18 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-sdp.h: + * gst/rtsp-server/rtsp-server.c: + rtsp: keep track of server ip and ipv6 + Keep track of how the client connected to the server and setup the udp ports + with the same protocol. + Copy the server ip address in the SDP so that clients can send RTCP back to + us. + +2010-03-16 18:34:43 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session.c: + session: indent + +2010-03-16 18:33:23 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: use right size for malloc + +2010-03-10 11:45:30 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: comment ipv6 server listening address + +2010-03-10 11:45:06 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: allow for ipv6 sockets + +2010-03-09 13:49:00 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + server: rework server part + Allow setting a bind address, make sure we can deal with ipv6. + Remove the port property and change with the service property. + +2010-03-09 13:44:20 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.h: + media: update comments a little + +2010-03-09 13:43:29 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: make content-base better + Use the URI formatting functions to make a content-base. Also make sure that + there is a trailing / at the end. + +2010-03-09 13:42:50 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: guard against invalid paths + +2010-03-09 13:41:33 +0100 Wim Taymans + + * examples/test-video.c: + test: catch server bind errors + +2010-03-09 10:27:38 +0100 Alessandro Decina + + * gst/rtsp-server/rtsp-media.c: + rtspmedia: emit "unprepared" if _prepare fails. + Emit the unprepared signal if gst_rtsp_media_prepare fails so that the + media object is removed from its factory's cache. + +2010-03-05 19:08:08 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: collect media position when seek completes + +2010-03-05 18:37:17 +0100 Luca Ognibene + + * gst/rtsp-server/rtsp-client.c: + client: call unlink_streams in client finalize + Fixes #599027 + +2010-03-05 18:23:18 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: limit the time to wait to something huge + Avoid waiting forever but limit the timeout to 20 seconds. + +2010-03-05 17:57:08 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-sdp.c: + sdp: reindent and check for prepared status + +2010-03-05 17:51:26 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-session.c: + media: avoid doing _get_state() for state changes + When preparing, use the ASYNC_DONE and ERROR messages in the bus handler to wait + until the media is prerolled or in error. This avoids doing a blocking call of + gst_element_get_state() that can cause lockups when there is an error. + Fixes #611899 + +2010-03-05 16:20:08 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: reindent + +2010-03-05 13:34:15 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + media-factory: better error handling + Improve the error handling a bit. + +2010-03-05 13:31:37 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: rework transport parsing + Rework the transport parsing code so that we can ignore transports we don't + support instead of just picking the first one we can parse. + Configure a (for now hardcoded) destination for multicast transports. + +2010-03-05 13:28:58 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: set multicast sink parameters + Disable loop and automatic multicast join on the udpsink elements. + Add some more debug info. + Reset some state variables in the right place. + Use the right port numbers for multicast. + +2010-03-05 13:27:18 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session.c: + session: handle transport setup correctly + Handle UDP, MCAST and TCP transport negotiation more correctly. + Store the server session SSRC in the transport. + +2010-01-27 18:38:27 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: implement error_full + Implement error_full to avoid some segfaults when the rtspconnection calls it. + See #608245 + +2009-12-25 18:24:10 +0100 Wim Taymans + + * docs/README: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-server.c: + docs: update docs and comments + +2009-12-25 15:22:23 +0100 Nikolay Ivanov + + * gst/rtsp-server/rtsp-sdp.c: + sdp: make server work better when behind a proxy + +2009-11-21 01:17:25 +0100 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-client.c: + client: dump rtsp message only if debug threshold is higher than GST_LEVEL_LOG + +2009-11-21 19:20:23 +0100 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-mapping.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + Use GStreamer's debugging subsystem + +2009-11-21 01:00:39 +0100 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-media-factory.c: + server: Set ghost pad active in gst_rtsp_media_factory_collect_streams + +2009-11-05 11:22:44 +0100 Wim Taymans + + * configure.ac: + back to development + +=== release 0.10.5 === + +2009-11-05 11:20:45 +0100 Wim Taymans + + * configure.ac: + release 0.10.5 + +2009-10-14 12:11:31 +0200 Wim Taymans + + * configure.ac: + configure: bump required versions + +2009-10-11 13:57:54 +0200 Luca Ognibene + + * gst/rtsp-server/rtsp-client.c: + client: call weak-unref on client->sessions from finalize + Fixes bug #596305 + +2009-10-09 23:08:18 +0200 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-media.c: + media: Fixed crasher where caps got unref'ed too often + +2009-10-09 16:26:30 +0200 Sebastian Pölsterl + + * configure.ac: + * pkgconfig/.gitignore: + * pkgconfig/Makefile.am: + * pkgconfig/gst-rtsp-server-uninstalled.pc.in: + Added pkg-config file to use gst-rtsp-server uninstalled + +2009-09-11 13:52:27 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: add some docs + +2009-08-24 13:27:00 +0200 Peter Kjellerstedt + + * gst/rtsp-server/rtsp-client.c: + rtsp: Use gst_rtsp_watch_send_message(). + Use gst_rtsp_watch_send_message() since the old API which used + gst_rtsp_watch_queue_message() has been deprecated. + +2009-08-05 11:53:56 +0200 Wim Taymans + + * configure.ac: + back to development + +=== release 0.10.4 === + +2009-08-05 11:44:49 +0200 Wim Taymans + + * configure.ac: + Release 0.10.4 + +2009-07-27 19:42:44 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + rtsp: allocate channels in TCP mode + When the client does not provide us with channels in TCP mode, allocate channels + ourselves. + +2009-07-24 12:49:41 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: don't crash when tunnelid is missing + When a clients tries to open an HTTP tunnel but fails to provide a tunnelid, + don't crash but return an error response to the client. + Fixes #589489 + +2009-07-13 11:31:23 +0200 Sebastian Pölsterl + + * bindings/vala/gst-rtsp-server-0.10.vapi: + * bindings/vala/packages/gst-rtsp-server-0.10.gi: + * bindings/vala/packages/gst-rtsp-server-0.10.metadata: + bindings: update vala bindings with new method + +2009-06-30 21:27:53 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session-pool.h: + sessionpool: add function to filter sessions + Add generic function to retrieve/remove sessions. + +2009-06-22 18:57:25 +0100 Tim-Philipp Müller + + * configure.ac: + configure: bump core/base requirements to release + +2009-06-18 16:05:18 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: fix indentation + +2009-06-14 23:12:13 +0200 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-media.c: + Unref pipeline and set it to NULL. Set stream's caps to NULL, otherwise we unref it too often. + +2009-06-13 16:05:02 +0200 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-media.c: + set state and remove elements of media in for loop + +2009-06-13 14:38:39 +0200 Sebastian + + * bindings/vala/gst-rtsp-server-0.10.vapi: + * bindings/vala/packages/gst-rtsp-server-0.10.gi: + Added gst_rtsp_media_remove_elements function to Vala bindings + +2009-06-13 14:38:20 +0200 Sebastian + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + Added gst_rtsp_media_remove_elements function + +2009-06-12 22:22:40 +0200 Sebastian + + * gst/rtsp-server/rtsp-media.c: + Don't use name for gstrtpbin so we can add multiple instances to the pipeline + +2009-06-12 19:28:04 +0200 Sebastian Pölsterl + + * bindings/vala/gst-rtsp-server-0.10.vapi: + * bindings/vala/packages/gst-rtsp-server-0.10.gi: + * bindings/vala/packages/gst-rtsp-server-0.10.metadata: + Updated Vala bindings + +2009-06-12 18:05:30 +0200 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + Added vmethod unprepare to GstRTSPMedia + The default implementation sets the state of the pipeline to GST_STATE_NULL + +2009-06-12 17:51:44 +0200 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + Made collect_streams function public + +2009-06-12 17:45:29 +0200 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + Added vmethod create_pipeline to GstRTSPMediaFactory + The pipeline is created in this method and the GstRTSPMedia's element is added to it + +2009-06-11 11:27:47 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: use g_source_destroy() + We need to use g_source_destroy() because we might have added the source to a + different main context than the default one. + +2009-06-10 00:01:07 +0200 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-params.c: + * gst/rtsp-server/rtsp-params.h: + rtsp: prepare for handling GET/SET_PARAMETER + Add helper functions to handle GET/SET_PARAMETER. Reply with an error when there + is a body now. + Fix return codes of handlers. + +2009-06-04 19:20:26 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: don't leak session pads + +2009-06-04 18:32:15 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: clean up the messages a bit + +2009-06-03 12:13:21 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-sdp.c: + sdp: warn and skip streams without media + +2009-05-30 14:38:34 +0200 Sebastian Pölsterl + + * bindings/vala/gst-rtsp-server-0.10.vapi: + * bindings/vala/packages/gst-rtsp-server-0.10.metadata: + vala: Fixed typo in header file of RTSPMediaStream + +2009-05-27 11:15:22 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: fix message + Fix a debug message + Make dumping RTCP stats configurable + +2009-05-26 19:20:07 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: be less verbose and leak less + +2009-05-26 19:05:07 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: don't leak the destination address + +2009-05-26 19:01:10 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + rtsp: use RTCP to keep the session alive + Use the RTCP rtcp-from stats field to find the associated session and use this + to keep the session alive. + +2009-05-26 17:27:07 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-session.c: + session: add 5sec to the real session timeout + Allow the session to live 5sec longer before really timing out. This should give + clients some extra time to keep the session active. + +2009-05-26 17:25:59 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: replay OK to GET/SET_PARAMETER + Some clients (vlc) use GET/SET_PARAMETER to keep the TCP session open. Make it + so that we return OK for those requests. + +2009-05-26 11:42:41 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: keep track of active transports + Keep track of which transport is active to avoid closing the connection too + soon. + Remove the destination transport also when going to NULL. + Print some stats about the SDES and other RTCP messages we receive from the + clients. + +2009-05-24 20:00:19 +0200 Wim Taymans + + * examples/.gitignore: + * examples/Makefile.am: + * examples/test-sdp.c: + example: add SDP relay example + +2009-05-24 19:56:45 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: also count active TCP connections + +2009-05-24 19:34:52 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + rtsp: add support for dynamic elements + Add support for dynamic elements. + Don't set live pipelines back to paused. + +2009-05-24 19:33:22 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-sdp.c: + sdp: don't add encoding name when absent in caps + +2009-05-23 16:30:55 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: warn when we can't do RTP-Info + +2009-05-23 16:18:04 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + factory: factor out the stream construction + +2009-05-23 16:17:02 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: only add RTP-Info when we have the info + Only add RTP-Info for a stream when we can get the seqnum and timestamp from the + depayloader. + +2009-05-17 14:04:31 +0200 Wim Taymans + + * configure.ac: + back to development + +=== release 0.10.3 === + +2009-05-17 13:59:10 +0200 Wim Taymans + + * configure.ac: + release: 0.10.3 + - Fixes a bug where it put the wrong verion in pkgconfig + - Link RTP and RTCP sources + +2009-05-15 17:58:44 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: link the RTP udpsrc to the session manager + Link the RTP udpsrc and the appsrc to the session manager so that they don't + shut down when the client sends a packet to open firewalls. + +2009-05-15 17:10:44 +0200 Sebastian Pölsterl + + * pkgconfig/gst-rtsp-server.pc.in: + Don't use hard-coded version number in pkg-config file + +2009-05-11 10:51:47 +0200 Wim Taymans + + * configure.ac: + back to development + +=== release 0.10.2 === + +2009-05-11 10:50:31 +0200 Wim Taymans + + * configure.ac: + release 0.10.2 + +2009-05-11 10:38:44 +0200 Wim Taymans + + * .gitignore: + * common/m4/.gitignore: + * examples/.gitignore: + * pkgconfig/.gitignore: + add some .gitignore files + +2009-04-29 17:24:46 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: seek to key frames + +2009-04-21 22:44:05 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: emit the unprepared signal by id + Emit the unprepared signal by id instead of name and set the media as + reused. + +2009-04-21 22:23:54 +0200 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-media.c: + Set pipeline's state to NULL no matter if the media is reusable and emit unprepared signal in gst_rtsp_media_unprepare + +2009-04-18 16:10:59 +0200 Sebastian Pölsterl + + * gst/rtsp-server/rtsp-server.c: + Added finalize function to GstRTPSPServer to unref session pool and media mapping + +2009-04-17 21:13:07 +0200 Sebastian Pölsterl + + * bindings/vala/gst-rtsp-server-0.10.vapi: + * bindings/vala/packages/gst-rtsp-server-0.10.gi: + * bindings/vala/packages/gst-rtsp-server-0.10.metadata: + Updated vala bindings + +2009-04-14 23:38:58 +0200 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + server: use appsink and appsrc with the API + Use the appsink/appsrc API instead of the signals for higher + performance. + +2009-04-14 23:38:15 +0200 Wim Taymans + + * examples/test-ogg.c: + tests: set the payload type correctly + +2009-04-03 22:46:22 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + factory: connect to the unprepare signal + Connect to the unprepare signal for non-reusable media so that we can remove + them from the cache. + +2009-04-03 22:45:57 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: add signal to notify of unprepare + +2009-04-03 22:22:30 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: more work on making the media shared + Add a reusable flag to medias, indicating that they can be reused after a state + change to NULL. + Small cleanups. + +2009-04-03 19:47:38 +0200 Wim Taymans + + * examples/test-readme.c: + examples: mark the example as shared for testing + +2009-04-03 19:44:37 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + client: support shared media + Always perform the state actions even if the target state of the pipeline is + already correct, we still want to add/remove the transports when we are dealing + with shared media. + Keep a counter of the number of active transports for a media so that we can use + this to perform a state change when needed. + Perform a state change of the pipeline only when the first transport was added + or when there are no active transports. + +2009-04-03 09:03:59 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: fix refcounting crasher + Don't need to remove the weak refs in the finalize methods, they are already + removed in the dispose. + Don't register the callback with a DestroyNofity. + +2009-04-01 01:01:46 +0100 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-client.c: + Fix rtsp client refcount management in TCP mode. + Don't unref a client ref we never had. Fixes an unref + of an already-free client object after a client + teardown request for me. + +2009-04-01 00:45:17 +0100 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-session.c: + docs: fix typo in API docs + +2009-03-13 15:57:42 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + More seeking fixes. + Keep the udp sources in playing even if we go to paused. unlock the sources when + we shut down. + Add some more debug info. + Only seek when we need to. + Keep track of the position when we go to paused. + +2009-03-12 20:32:14 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + Add beginnings of seeking. + Parse the Range header and perform a seek on the pipeline for the requested + position. It's disabled currently until I figure out what's going wrong. + +2009-03-12 20:31:22 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + allow pause requests for now. + -- + +2009-03-11 20:03:06 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + Remove weak ref on the session in teardown + We need to remove our weakref from the session when we do a teardown because + else we close the TCP connection prematurely. + +2009-03-11 19:38:06 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-session-pool.c: + Do some more session cleanup + Make session timeout kill the TCP connection that currently watches the + session. + Remove the client timeout property. + +2009-03-11 16:45:12 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + Add TCP transports + Use appsrc and appsink to send and receive RTP/RTCP packets in the TCP + connection. + +2009-03-11 16:39:20 +0100 Wim Taymans + + * examples/Makefile.am: + * examples/test-launch.c: + Add example server that takes launch lines + Add an example server that streams any -launch line. + +2009-03-06 19:34:14 +0100 Wim Taymans + + * examples/test-readme.c: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + Add support for live streams + Add support for live streams and ranges + Start on handling TCP data transfer. + +2009-03-04 16:33:59 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + Free the pipeline before other things + --- + +2009-03-04 16:33:21 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + Only free the pending tunnel if there is one + -- + +2009-03-04 12:44:01 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media.c: + rtsp-server: Add support for tunneling + Add support for tunneling over HTTP. + Use new connection methods to retrieve the url. + Dispatch messages based on the message type instead of blindly + assuming it's always a request. + Keep track of the watch id so that we can remove it later. + Set the media pipeline to NULL before unreffing the pipeline. + +2009-02-19 15:53:50 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + Fix for channel -> watch rename in gstreamer + Rename the RTSPChannel to RTSPWatch and remove an unused variable. + +2009-02-18 18:57:31 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + Use ASYNC RTSP io + Use the async RTSP channels instead of spawning a new thread for each client. + If a sessionid is specified in a request, fail if we don't have the session. + +2009-02-18 17:49:03 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + Add better debug info + Add some better debug info. + +2009-02-13 20:00:34 +0100 Wim Taymans + + * examples/test-video.c: + Time out sessions + Add support for session timeouts in the example. + +2009-02-13 19:58:17 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session-pool.h: + Pass GTimeVal around for performance reasons + Get the current time only once and pass it around so that sessions don't have to + get the current time anymore. + Add experimental support for a GSource that dispatches when the session needs to + be cleaned up. + +2009-02-13 19:56:01 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + Add better support for session timeouts + Add a method to request the number of milliseconds when a session will timeout. + +2009-02-13 19:54:18 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + Add suport for RTP manager monitoring + Add the first stage in monitoring the rtp manager. + Make sure we don't update the state to something we don't want. + +2009-02-13 19:52:05 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + Add support for session keepalive + Get and update the session timeout for all requests. get the session as early as + possible. + +2009-02-13 16:39:36 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + Handle media bus messages + Handle media bus messages in a custom mainloop and dispatch them to the + RTSPMedia objects. Let the default implementation handle some common messages. + +2009-02-13 12:57:45 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + Some more session timeout handling + Move the session header setting code to a central place so that we always add + the timeout parameter too. + Handle timeouts by running the session cleanup code. + Stop media before cleaning up. + +2009-02-10 16:24:13 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + Add timeout property + Add a timeout property ot the client and make the other properties into GObject + properties. + +2009-02-10 16:21:17 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session-pool.c: + Use getters and setters in property code + Use the getters and setters for the timeout property instead of locking + ourselves. + +2009-02-04 20:13:32 +0100 Wim Taymans + + Merge branch 'master' of git+ssh://git.collabora.co.uk/git/gst-rtsp-server + +2009-02-04 20:10:39 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + Add more timeout stuff + Add method to check if a session is expired. + Add method to perform cleanup on a session pool. + +2009-02-04 19:52:50 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + Add beginnings of session timeouts and limits + Add the timeout value to the Session header for unusual timeout values. + Allow us to configure a limit to the amount of active sessions in a pool. Set a + limit on the amount of retry we do after a sessionid collision. + Add properties to the sessionid and the timeout of a session. Keep track of + creation time and last access time for sessions. + +2009-02-04 17:00:42 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + Cleanup of sessions and more + Fix the refcounting of media and sessions in the client. Properly clean up the + session data when the client performs a teardown. + Add Server header to responses. + Allow for multiple uri setups in one session. + Add Range header to the PLAY response and add the range attribute to the SDP + message. + Fix the session pool remove method, it used the wrong key in the hashtable. Also + give the ownership of the sessionid to the session object. + +2009-02-04 09:57:55 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + Rename a variable + Rename the 'server_port' variable to simply 'port'. + +2009-02-03 19:32:38 +0100 Wim Taymans + + * configure.ac: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + Rework the way we handle transports for streams + Make the media accept an array of transports for the streams that we have + configured for the play/pause requests. + Implement server states for a client and its media. + Require 0.10.22.1 (git HEAD) of gstreamer. + +2009-01-31 19:50:33 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + Drop const from functions dealing with urls + Drop const from GstRTSPUrl stuff because the .h files in gst-plugins-base don't + have the right const in them. + +2009-01-30 17:06:26 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-sdp.c: + Fix various leaks + Fix some leaks. + +2009-01-30 16:24:10 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + More cleanups + Don't keep a reference to the GstRTSPMedia in the stream. + Free more things when freeing the GstRTSPMedia. + +2009-01-30 14:53:28 +0100 Wim Taymans + + * docs/README: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + More docs and small cleanups + Add some more docs and update the README + Cleanup some method names. + Remove an unneeded idx field in the GstRTSPMediaStream + +2009-01-30 13:24:04 +0100 Wim Taymans + + * docs/README: + * examples/Makefile.am: + * examples/test-readme.c: + Add a README and more example code + Add a README file that contains a small introduction on how to use the server + along with the example code explained in the readme. + +2009-01-30 11:06:31 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-server.c: + Fix some leaks and change default port + Fix some memory leaks by setting the udpsrc elements to the unlocked state after + we finished the initial preroll. If we keep them locked, setting the pipeline to + NULL will not stop and clean up the sources correctly. + Change the default RTSP port to 8554 aka the official alternative RTSP port. + +2009-01-29 18:55:22 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + Cleanups to the session object + Remove some unneeded variables in the session state of a stream such as the + owner media and the server transport. + Get the configuration of a media stream in a session based on the media_stream + in the original object instead of our cached index. + Free more data in the finalize method. + +2009-01-29 18:51:02 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + Cleanups and reuse media from DESCRIBE + Handle thread create errors. + Rename some internal methods to better match what they actually do. + Handle misconfiguration of session_pool and media_mapping gracefully. + Cache the DESCRIBE media and uri in the client connection and reuse them when + we receive a SETUP request in the same connection for the same uri. + Cleanup the client connection object. + +2009-01-29 17:20:27 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + Add shared properties to media and factory + Add the shared property to media. + Implement some simple caching in the factory depending on if the media is shared + or not. + +2009-01-29 17:19:21 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + Add a little comment + Add some comment about the content-base header. + +2009-01-29 13:31:27 +0100 Wim Taymans + + * examples/Makefile.am: + * examples/main.c: + * examples/test-mp4.c: + * examples/test-ogg.c: + * examples/test-video.c: + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-sdp.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + Reorganize things, prepare for media sharing + Added various other test server examples + Move the SDP message generation to a separate helper. + Refactor common code for finding the session. + Add content-base for realplayer compatibility + Clean up request uris before processing for better vlc compatibility. + Move prerolling and pipeline construction to the RTSPMedia object. + Use multiudpsink for future pipeline reuse. + +2009-01-30 11:23:57 +0100 Wim Taymans + + * configure.ac: + Back to development + Back to 0.10.1.1 + +=== release 0.10.1 === + +2009-01-30 11:20:18 +0100 Wim Taymans + + * configure.ac: + Make 0.10.1 release + Release 0.10.1 + +2009-01-29 15:19:01 +0100 Wim Taymans + + * bindings/vala/Makefile.am: + Fix make dist + Add more directories and files to the dist. + +2009-01-24 14:34:35 +0100 Sebastian Pölsterl + + * bindings/python/Makefile.am: + * bindings/python/rtspserver.override: + Fixed compile error of python bindings + +2009-01-23 21:03:53 +0100 Sebastian Pölsterl + + * bindings/vala/gst-rtsp-server-0.10.vapi: + * bindings/vala/packages/gst-rtsp-server-0.10.metadata: + Marked values as nullable accordingly + +2009-01-23 20:31:11 +0100 Sebastian Pölsterl + + * bindings/vala/gst-rtsp-server-0.10.vapi: + * bindings/vala/packages/gst-rtsp-server-0.10.excludes: + * bindings/vala/packages/gst-rtsp-server-0.10.gi: + * bindings/vala/packages/gst-rtsp-server-0.10.metadata: + Updated Vala bindings + +2009-01-22 18:35:17 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-mapping.c: + * gst/rtsp-server/rtsp-media-mapping.h: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-session-pool.h: + Cleanups and doc updates + Add some more documentation and do some minor cleanups here and there. + +2009-01-22 17:58:19 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + More improvements + Rename GstRTSPMediaBin to GstRTSPMedia + Parse the request url into a GstRTSPUri object and pass this object to the + various handlers and methods that require the uri. + +2009-01-22 16:54:07 +0100 Wim Taymans + + * examples/main.c: + Update example + Add some more docs and remove some old code from the example. + +2009-01-22 16:53:16 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + Handle state change failures better + Handle state change failures better when changing the state of the pipeline to + determine the SDP. + +2009-01-22 16:51:08 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + Make element creation more extendible + Add get_element vmethod to the default MediaFactory so that subclasses can just + override that method and still use the default logic for making a MediaBin from + that. + +2009-01-22 15:33:29 +0100 Wim Taymans + + * examples/main.c: + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media-mapping.c: + * gst/rtsp-server/rtsp-media-mapping.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + Make the server handle arbitrary pipelines + Make GstMediaFactory an object that can instantiate GstMediaBin objects. + The GstMediaBin object has a handle to a bin with elements and to a list of + GstMediaStream objects that this bin produces. + Add GstMediaMapper that can map url mountpoints to GstMediaFactory objects along + with methods to register and remove those mappings. + Add methods and a property to GstRTSPServer to manage the GstMediaMapper object + used by the server instance. + Modify the example application so that it shows how to create custom pipelines + attached to a specific mount point. + Various misc cleanps. + +2009-01-20 19:47:07 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + Allow setting a custom media factory for a server + +2009-01-20 19:46:21 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + Allow setting a custom media factory for a client. + +2009-01-20 19:45:28 +0100 Wim Taymans + + * gst/rtsp-server/Makefile.am: + Add Makefile entry for the media factory + +2009-01-20 19:44:45 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + Add media factory to map urls to media pipeline objects. + +2009-01-20 19:43:47 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + Add comments. Remove unused field + +2009-01-20 19:41:53 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session-pool.h: + Allow custom session pools to override the session id allocation algorithms Add some comments. + +2009-01-20 19:40:42 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session.h: + Add some comments. + +2009-01-20 13:57:47 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + Move the connection code in one place Add some comments + +2009-01-20 13:19:36 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + Make vmethod to create and accept new clients. Add some docs. + +2009-01-19 19:36:23 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + Make more properties configurable in the server. Expose the GIOChannel and GSource better to allow for more customisations. + +2009-01-19 19:34:29 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + Name the parameters more appropriately. + +2009-01-19 19:32:28 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-session-pool.c: + Do some more cleanup of the session pool. + +2009-01-08 16:28:24 +0100 Wim Taymans + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-client.c: + Check if return value of gst_rtsp_session_get_media is not NULL + +2009-01-08 15:02:42 +0100 Wim Taymans + + * gst/rtsp-server/Makefile.am: + Install rtsp-session and rtsp-session-pool headers + +2009-01-08 14:57:55 +0100 Wim Taymans + + * .gitignore: + * Makefile.am: + * acinclude.m4: + * bindings/python/Makefile.am: + * bindings/python/arg-types.py: + * bindings/python/codegen/Makefile.am: + * bindings/python/codegen/__init__.py: + * bindings/python/codegen/argtypes.py: + * bindings/python/codegen/code-coverage.py: + * bindings/python/codegen/codegen.py: + * bindings/python/codegen/definitions.py: + * bindings/python/codegen/defsparser.py: + * bindings/python/codegen/docextract.py: + * bindings/python/codegen/docgen.py: + * bindings/python/codegen/fileprefix.override: + * bindings/python/codegen/fileprefixmodule.c: + * bindings/python/codegen/h2def.py: + * bindings/python/codegen/mergedefs.py: + * bindings/python/codegen/mkskel.py: + * bindings/python/codegen/override.py: + * bindings/python/codegen/reversewrapper.py: + * bindings/python/codegen/scmexpr.py: + * bindings/python/rtspserver-types.defs: + * bindings/python/rtspserver.defs: + * bindings/python/rtspserver.override: + * bindings/python/rtspservermodule.c: + * configure.ac: + Add python bindings. + +2009-01-08 14:53:47 +0100 Wim Taymans + + * bindings/Makefile.am: + * configure.ac: + Don't go into python dir when requirements for python bindings are missing + +2009-01-08 14:49:57 +0100 Wim Taymans + + * bindings/Makefile.am: + * bindings/vala/Makefile.am: + * configure.ac: + Install Vala bindings if vala is available + +2008-12-12 16:22:02 +0100 Sebastian Pölsterl + + * bindings/vala/gst-rtsp-server-0.10.deps: + * bindings/vala/gst-rtsp-server-0.10.vapi: + * bindings/vala/gst-rtsp-server.vapi: + * bindings/vala/packages/gst-rtsp-server-0.10.deps: + * bindings/vala/packages/gst-rtsp-server-0.10.excludes: + * bindings/vala/packages/gst-rtsp-server-0.10.files: + * bindings/vala/packages/gst-rtsp-server-0.10.gi: + * bindings/vala/packages/gst-rtsp-server-0.10.metadata: + * bindings/vala/packages/gst-rtsp-server-0.10.namespace: + * bindings/vala/packages/gst-rtsp-server.deps: + * bindings/vala/packages/gst-rtsp-server.excludes: + * bindings/vala/packages/gst-rtsp-server.files: + * bindings/vala/packages/gst-rtsp-server.gi: + * bindings/vala/packages/gst-rtsp-server.metadata: + * bindings/vala/packages/gst-rtsp-server.namespace: + Regenerated Vala bindings + +2008-12-08 13:19:40 +0100 Sebastian Pölsterl + + * bindings/vala/gst-rtsp-server.vapi: + * bindings/vala/packages/gst-rtsp-server.metadata: + Fixed typo in included headers for vala bindings + +2009-01-08 14:42:10 +0100 Wim Taymans + + * Makefile.am: + * configure.ac: + * pkgconfig/Makefile.am: + * pkgconfig/gst-rtsp-server.pc.in: + Added pkgconfig file + +2008-11-30 23:57:26 +0100 Sebastian Pölsterl + + * bindings/vala/gst-rtsp-server.vapi: + * bindings/vala/packages/gst-rtsp-server.excludes: + * bindings/vala/packages/gst-rtsp-server.gi: + * bindings/vala/packages/gst-rtsp-server.metadata: + Adjusted included headersfor Vala bindings. Ignore rtsp-url-compat.h + +2008-11-30 23:41:20 +0100 Sebastian Pölsterl + + * bindings/vala/gst-rtsp-server.vapi: + * bindings/vala/packages/gst-rtsp-server.deps: + * bindings/vala/packages/gst-rtsp-server.files: + * bindings/vala/packages/gst-rtsp-server.gi: + * bindings/vala/packages/gst-rtsp-server.metadata: + * bindings/vala/packages/gst-rtsp-server.namespace: + Added Vala bindings + +2008-10-25 23:36:16 +0200 Alessandro Decina + + * gst/rtsp-server/rtsp-session.c: + Change an obviously wrong return FALSE to return NULL; (cherry picked from commit 56d4fb48030db3ae45f3f0e60b29b36f3134322b) + +2008-11-13 19:43:10 +0100 Sebastian Pölsterl + + * examples/Makefile.am: + * gst/rtsp-server/Makefile.am: + Put GStreamer version in library name + +2009-01-08 13:51:26 +0100 Wim Taymans + + * examples/Makefile.am: + * gst/rtsp-server/Makefile.am: + Fix some issues to pass distcheck + +2009-01-08 13:41:33 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + Added port property to GstRTSPServer class. + +2009-01-08 13:18:55 +0100 Wim Taymans + + * Makefile.am: + * autogen.sh: + * configure.ac: + * examples/Makefile.am: + * examples/main.c: + * gst/Makefile.am: + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + * src/Makefile.am: + * src/main.c: + * src/rtsp-client.c: + * src/rtsp-client.h: + * src/rtsp-media.c: + * src/rtsp-media.h: + * src/rtsp-server.c: + * src/rtsp-server.h: + * src/rtsp-session-pool.c: + * src/rtsp-session-pool.h: + * src/rtsp-session.c: + * src/rtsp-session.h: + Split in library and example program + +2008-11-10 20:59:35 +0100 Sebastian Pölsterl + + * src/rtsp-client.h: + Removed obsolete variable + +2008-11-10 21:03:15 +0100 Sebastian Pölsterl + + * src/rtsp-client.c: + * src/rtsp-client.h: + Removed pipeline variable GstRTSPClient, because it's only used in one function + +2009-01-08 11:22:58 +0100 Wim Taymans + + * src/rtsp-media.c: + Set the payload types for the different payloaders. Maybe this shoulde be done automatically instead. + +2008-10-23 12:23:27 +0200 Wim Taymans + + * src/rtsp-session.c: + Initialize some more vars. + +2008-10-23 12:14:55 +0200 Wim Taymans + + * src/rtsp-session.c: + Initialize variable to avoid compiler warning. + +2008-10-09 13:30:47 +0100 Simon McVittie + + * .gitignore: + Add a reasonable generic .gitignore + diff --git a/NEWS b/NEWS index 6abbfaa4e2..4a7ac5719e 100644 --- a/NEWS +++ b/NEWS @@ -1 +1,110 @@ -This is GstRTSP +This is GStreamer RTSP Server 1.3.1 + +Changes since 1.2: + +New API: + • GstMessageType has GST_MESSAGE_EXTENDED added. All types before + that can be used together as a flags type as before, but from + that message onwards the types are just counted incrementally. + This was necessary to be able to add more message types. + In 2.0 GstMessageType will just become an enum and not a flags + type anymore. + • GstDeviceMonitor for device probing, e.g. to list all available + audio or video capture devices. This is the replacement for + GstPropertyProbe from 0.10. + • Events accumulate the running-time offset now when travelling + through pads, as set by the gst_pad_set_offset() function. This + allows to compensate for this in the QOS event for example. + • GstBuffer has a new flag "tag-memory" that is set automatically + when memory is added or removed to a buffer. This allows buffer + pools to detect if they can recycle a buffer or need to reset + it first. + • GstToc has new API to mark GstTocEntries as loops. + • A not-authorized resource error has been defined to notify + applications that accessing the resource has failed because + of missing authorization and to distinguish this case from others. + This change is actually already in 1.2.4. + • GstPad has a new flag "accept-intersect", that will let the default + ACCEPT_CAPS query handler do an intersection instead of subset check. + This is interesting for parser elements that can handle incomplete + caps. + • GstCollectPads has support for flushing and a default handler for + SEEK events now. + • GstSegment has new API to offset the running time by a specific + value and this is used in GstPad to allow positive and negative + offsets in gst_pad_set_offset() in all situations. + • Support for h265/HEVC and VP8 has been added to the codec utils and codec + parsers library, and was integrated into various elements. + • API for adjusting the TLS validation of RTSP connection has been added. + • The RTSP and SDP library has MIKEY (RFC 3830) support now, and + there is API to distinguish between the different RTSP profiles. + • API to access RTP time information and statistics. + • Support for auxiliary streams was added to rtpbin. + • Support for tiled, raw video formats has been added. + • GstVideoDecoder and GstAudioDecoder have API to help aggregating tag + events and merge custom tags into them consistently. + • playbin/playsink has support for application provided audio and video + filters. + • The GL library was merged from gst-plugins-gl to gst-plugins-bad, + providing a generic infrastructure for handling GL inside GStreamer + pipelines and a plugin with some elements using these, especially + a video sink. Supported platforms currently are Android, Cocoa (OS X), + DispManX (Raspberry Pi), EAGL (iOS), WGL (Windows) and generic X11, + Wayland and EGL platforms. + This replaces eglglessink and also is supposed to replace osxvideosink. + + +Major changes: + • New plugins and elements: + ∘ v4l2videodec element for accessing hardware codecs on + platforms that make them accessible via V4L2, e.g. + Samsung Exynos. This comes together with major refactoring + of the existing V4L2 elements and the corresponding + infrastructure. + The v4l2videodec element replaces the mfcdec element. + ∘ rtpstreampay and rtpstreamdepay elements for transmitting + RTP packets over a stream API (e.g. TCP) according to + RFC 4571. + ∘ rtprtx elements for standard compliant implementation of + retransmissions, integrated into the rtpmanager plugin. + ∘ audiomixer element that mixes multiple audio streams together + into a single one while keeping synchronization. This is + planned to become the replacement of the adder element. + ∘ OpenNI2 plugin for 3D cameras like the Kinect camera. + ∘ OpenEXR plugin for decoding high-dynamic-range EXR images. + ∘ curlsshsink and curlsftpsink to write files via SSH/SFTP. + ∘ videosignal, ivfparse and sndfile plugins ported from 0.10. + ∘ avfvideosrc, vtdec and other elements were ported from 0.10 and + are available on OS X and iOS now. + + • Other changes: + ∘ gst-libav now uses libav 10, and gained support for H265/HEVC. + ∘ Support for hardware codecs and special memory types has been + improved with bugfixes and feature additions in various plugins + and base classes. + ∘ Various bugfixes and improvements to buffering in queue2 and + multiqueue elements. + ∘ dvbsrc supports more delivery mechanisms and other features + now, including DVB S2 and T2 support. + ∘ The MPEGTS library has support for many more descriptors. + ∘ Major improvements to tsdemux, especially time related. + ∘ souphttpsrc now has support for keep-alive connections, + compression, configurable number of retries and configuration + for SSL certificate validation. + ∘ hlsdemux has undergone major refactoring and works more + reliable now and supports more HLS features like trick modes. + Also fragments are pushed downstream while they're downloaded + now instead of waiting for each fragment to finish. + ∘ videoflip can automatically flip based on the orientation tag. + ∘ openjpeg supports the OpenJPEG2 API. + ∘ gst-rtsp-server supports SRTP and MIKEY now. + ∘ Lots of fixes for coverity warnings all over the place. + ∘ 400+ fixed bug reports, and many other bug fixes and other + improvements everywhere that had no bug report. + +Things to look out for: + • The eglglessink element was removed and replaced by the glimagesink + element. + • The mfcdec element was removed and replaced by v4l2videodec. + • osxvideosink is only available in OS X 10.6 or newer. + diff --git a/RELEASE b/RELEASE index e69de29bb2..638d91d9fe 100644 --- a/RELEASE +++ b/RELEASE @@ -0,0 +1,124 @@ + +Release notes for GStreamer RTSP Server Library 1.3.1 + + +The GStreamer team is pleased to announce the first release of the unstable +1.3 release series. The 1.3 release series is adding new features on top of +the 1.0 and 1.2 series and is part of the API and ABI-stable 1.x release +series of the GStreamer multimedia framework. The unstable 1.3 release series +will lead to the stable 1.4 release series in the next weeks, and newly added +API can still change until that point. + + + +Binaries for Android, iOS, Mac OS X and Windows will be provided separately +during the unstable 1.3 release series. + + + +The versioning scheme that is used in general is that 1.x.y is API and +ABI backwards compatible with previous 1.x.y releases. If x is an even +number it is a stable release series and all releases in this series +will only contain important bugfixes, e.g. the 1.0 series with 1.0.7. If +x is odd it is a development release series that will lead to the next +stable release series 1.x+1 and contains new features and bigger +changes. During the development release series, new API can still +change. + + + + +Bugs fixed in this release + + * 725484 : gst-rtsp-server: Ignore gcov intermediate files + * 725528 : rtspserver: Enable and fix gtk-doc warnings + * 725879 : rtsp-client: headers in GET response not configurable for tunnels + * 726362 : rtsp-stream: fix a typo where IPv4 and IPv6 addresses were confused. + * 726470 : tests: Add unit tests for sessionpool + * 726873 : rtsp-threadpool: Improve code coverage of check tests + * 726940 : rtsp-session-media: add more tests to improve code coverage + * 726941 : docs: Add annotations to support language bindings + * 727102 : rtsp-media: deadlock with dynamic pipelines when preroll fails + * 727231 : rtsp-server: The media streams leak + * 727376 : crash if media_prepare() fails to allocate UDP ports + * 727488 : There is a race when disconnecting POST channel in tunneled mode + * 728029 : rtsp-media: Make media_prepare() virtual + * 728060 : rtsp-session-pool: Incorrect annotation and leak in unit test + * 728153 : Problem with send_lock when data in backlog and recive a teardown request. + * 728970 : rtsp-client: add signal before sending response + +==== Download ==== + +You can find source releases of gst-rtsp-server in the download +directory: http://gstreamer.freedesktop.org/src/gst-rtsp-server/ + +The git repository and details how to clone it can be found at +http://cgit.freedesktop.org/gstreamer/gst-rtsp-server/ + +==== Homepage ==== + +The project's website is http://gstreamer.freedesktop.org/ + +==== Support and Bugs ==== + +We use GNOME's bugzilla for bug reports and feature requests: +http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer + +Please submit patches via bugzilla as well. + +For help and support, please subscribe to and send questions to the +gstreamer-devel mailing list (see below for details). + +There is also a #gstreamer IRC channel on the Freenode IRC network. + +==== Developers ==== + +GStreamer is stored in Git, hosted at git.freedesktop.org, and can be cloned +from there (see link above). + +Interested developers of the core library, plugins, and applications should +subscribe to the gstreamer-devel list. + + +Applications + +Contributors to this release + + * Aleix Conchillo Flaque + * Aleix Conchillo Flaqué + * Alessandro Decina + * Alexander Schrab + * Andrey Utkin + * Branko Subasic + * David Schleef + * David Svensson Fors + * Edward Hervey + * Emmanuel Pacaud + * Fabian Deutsch + * George McCollister + * Göran Jönsson + * Jonas Holmberg + * Linus Svensson + * Lubosz Sarnecki + * Luis de Bethencourt + * Mark Nauwelaerts + * Miguel Angel Cabrera Moya + * Ognyan Tonchev + * Olivier Crête + * Patricia Muscalu + * Patrick Radizi + * Robert Krakora + * Sebastian Dröge + * Sebastian Pölsterl + * Sebastian Rasmussen + * Stefan Kost + * Stefan Sauer + * Thijs Vermeir + * Thomas Vander Stichele + * Tim-Philipp Müller + * Victor Gottardi + * Vincent Penquerc'h + * Wim Taymans + * Youness Alaoui + * mat +  \ No newline at end of file diff --git a/configure.ac b/configure.ac index 9f61fc753b..400faa6b5e 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.3.0.1], +AC_INIT([GStreamer RTSP Server Library], [1.3.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 300, 0, 300) +AS_LIBTOOL(GST, 301, 0, 301) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.3.0.1 -GSTPB_REQ=1.3.0.1 -GSTPG_REQ=1.3.0.1 -GSTPD_REQ=1.3.0.1 +GST_REQ=1.3.1 +GSTPB_REQ=1.3.1 +GSTPG_REQ=1.3.1 +GSTPD_REQ=1.3.1 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index c2e925ebc3..216748147a 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.3.1 + 1.3 + + 2014-05-03 + + + + 1.1.90 From 4e29b60048a465bc8ba049a64ecd68f8f3ba9fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 3 May 2014 20:48:43 +0200 Subject: [PATCH 0968/1776] Back to development --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 400faa6b5e..e56ba81a1a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.3.1], +AC_INIT([GStreamer RTSP Server Library], [1.3.1.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 301, 0, 301) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.3.1 -GSTPB_REQ=1.3.1 -GSTPG_REQ=1.3.1 -GSTPD_REQ=1.3.1 +GST_REQ=1.3.1.1 +GSTPB_REQ=1.3.1.1 +GSTPG_REQ=1.3.1.1 +GSTPD_REQ=1.3.1.1 dnl *** autotools stuff **** From efd079546ae736d0e20891acd126fe1ec7e116d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 2 May 2014 19:59:23 +0100 Subject: [PATCH 0969/1776] rtsp-client: handle Require headers and respond with OPTION_NOT_SUPPORTED Servers must handle Require headers and must report a failure if they don't handle any of the Required options, see RFC 2326, section 12.32: https://tools.ietf.org/html/rfc2326#page-54 https://bugzilla.gnome.org/show_bug.cgi?id=729426 --- gst/rtsp-server/rtsp-client.c | 81 +++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d42f9330f5..93d3b3fa5e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -502,6 +502,25 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, send_message (client, ctx, ctx->response, FALSE); } +static void +send_option_not_supported_response (GstRTSPClient * client, + GstRTSPContext * ctx, const gchar * unsupported_options) +{ + GstRTSPStatusCode code = GST_RTSP_STS_OPTION_NOT_SUPPORTED; + + gst_rtsp_message_init_response (ctx->response, code, + gst_rtsp_status_as_text (code), ctx->request); + + if (unsupported_options != NULL) { + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_UNSUPPORTED, + unsupported_options); + } + + ctx->session = NULL; + + send_message (client, ctx, ctx->response, FALSE); +} + static gboolean paths_are_equal (const gchar * path1, const gchar * path2, gint len2) { @@ -2169,6 +2188,55 @@ client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) } } +/* Returns TRUE if there are no Require headers, otherwise returns FALSE + * and also returns a newly-allocated string of (comma-separated) unsupported + * options in the unsupported_reqs variable . + * + * There may be multiple Require headers, but we must send one single + * Unsupported header with all the unsupported options as response. If + * an incoming Require header contained a comma-separated list of options + * GstRtspConnection will already have split that list up into multiple + * headers. + * + * TODO: allow the application to decide what features are supported + */ +static gboolean +check_request_requirements (GstRTSPMessage * msg, gchar ** unsupported_reqs) +{ + GstRTSPResult res; + GPtrArray *arr = NULL; + gchar *reqs = NULL; + gint i; + + i = 0; + do { + res = gst_rtsp_message_get_header (msg, GST_RTSP_HDR_REQUIRE, &reqs, i++); + + if (res == GST_RTSP_ENOTIMPL) + break; + + if (arr == NULL) + arr = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); + + g_ptr_array_add (arr, g_strdup (reqs)); + } + while (TRUE); + + /* if we don't have any Require headers at all, all is fine */ + if (i == 1) + return TRUE; + + /* otherwise we've now processed at all the Require headers */ + g_ptr_array_add (arr, NULL); + + /* for now we don't commit to supporting anything, so will just report + * all of the required options as unsupported */ + *unsupported_reqs = g_strjoinv (", ", (gchar **) arr->pdata); + + g_ptr_array_unref (arr); + return FALSE; +} + static void handle_request (GstRTSPClient * client, GstRTSPMessage * request) { @@ -2181,6 +2249,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) GstRTSPSession *session = NULL; GstRTSPContext sctx = { NULL }, *ctx; GstRTSPMessage response = { 0 }; + gchar *unsupported_reqs = NULL; gchar *sessid; if (!(ctx = gst_rtsp_context_get_current ())) { @@ -2268,6 +2337,10 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_URL)) goto not_authorized; + /* handle any 'Require' headers */ + if (!check_request_requirements (ctx->request, &unsupported_reqs)) + goto unsupported_requirement; + /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: @@ -2344,6 +2417,14 @@ not_authorized: /* error reply is already sent */ goto done; } +unsupported_requirement: + { + GST_ERROR ("client %p: Required option is not supported (%s)", client, + unsupported_reqs); + send_option_not_supported_response (client, ctx, unsupported_reqs); + g_free (unsupported_reqs); + goto done; + } not_implemented: { GST_ERROR ("client %p: method %d not implemented", client, method); From aec1b42c4e59ad548a3d39b561c775fc19eaa776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 2 May 2014 20:06:29 +0100 Subject: [PATCH 0970/1776] tests: add unit test for correct handling of Require headers https://bugzilla.gnome.org/show_bug.cgi?id=729426 --- tests/check/gst/rtspserver.c | 120 ++++++++++++++++++++++++++++++++--- 1 file changed, 110 insertions(+), 10 deletions(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index e9ab1dc68a..223ad6981a 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -269,11 +269,12 @@ read_response (GstRTSPConnection * conn) /* send an rtsp request and receive response. gchar** parameters are out * parameters that have to be freed by the caller */ static GstRTSPStatusCode -do_request (GstRTSPConnection * conn, GstRTSPMethod method, +do_request_full (GstRTSPConnection * conn, GstRTSPMethod method, const gchar * control, const gchar * session_in, const gchar * transport_in, - const gchar * range_in, + const gchar * range_in, const gchar * require_in, gchar ** content_type, gchar ** content_base, gchar ** body, - gchar ** session_out, gchar ** transport_out, gchar ** range_out) + gchar ** session_out, gchar ** transport_out, gchar ** range_out, + gchar ** unsupported_out) { GstRTSPMessage *request; GstRTSPMessage *response; @@ -293,6 +294,9 @@ do_request (GstRTSPConnection * conn, GstRTSPMethod method, if (range_in) { gst_rtsp_message_add_header (request, GST_RTSP_HDR_RANGE, range_in); } + if (require_in) { + gst_rtsp_message_add_header (request, GST_RTSP_HDR_REQUIRE, require_in); + } /* send request */ fail_unless (send_request (conn, request)); @@ -306,6 +310,11 @@ do_request (GstRTSPConnection * conn, GstRTSPMethod method, /* check status line */ gst_rtsp_message_parse_response (response, &code, NULL, NULL); if (code != GST_RTSP_STS_OK) { + if (unsupported_out != NULL && code == GST_RTSP_STS_OPTION_NOT_SUPPORTED) { + gst_rtsp_message_get_header (response, GST_RTSP_HDR_UNSUPPORTED, + &value, 0); + *unsupported_out = g_strdup (value); + } gst_rtsp_message_free (response); return code; } @@ -355,6 +364,20 @@ do_request (GstRTSPConnection * conn, GstRTSPMethod method, return code; } +/* send an rtsp request and receive response. gchar** parameters are out + * parameters that have to be freed by the caller */ +static GstRTSPStatusCode +do_request (GstRTSPConnection * conn, GstRTSPMethod method, + const gchar * control, const gchar * session_in, + const gchar * transport_in, const gchar * range_in, + gchar ** content_type, gchar ** content_base, gchar ** body, + gchar ** session_out, gchar ** transport_out, gchar ** range_out) +{ + return do_request_full (conn, method, control, session_in, transport_in, + range_in, NULL, content_type, content_base, body, session_out, + transport_out, range_out, NULL); +} + /* send an rtsp request with a method and a session, and receive response */ static GstRTSPStatusCode do_simple_request (GstRTSPConnection * conn, GstRTSPMethod method, @@ -408,9 +431,9 @@ do_describe (GstRTSPConnection * conn, const gchar * mount_point) * session string that must be freed by the caller. the returned * transport must be freed by the caller. */ static GstRTSPStatusCode -do_setup (GstRTSPConnection * conn, const gchar * control, - const GstRTSPRange * client_ports, gchar ** session, - GstRTSPTransport ** transport) +do_setup_full (GstRTSPConnection * conn, const gchar * control, + const GstRTSPRange * client_ports, const gchar * require, gchar ** session, + GstRTSPTransport ** transport, gchar ** unsupported) { GstRTSPStatusCode code; gchar *session_in = NULL; @@ -430,9 +453,9 @@ do_setup (GstRTSPConnection * conn, const gchar * control, g_strdup_printf (TEST_PROTO ";unicast;client_port=%d-%d", client_ports->min, client_ports->max); code = - do_request (conn, GST_RTSP_SETUP, control, session_in, - transport_string_in, NULL, NULL, NULL, NULL, session_out, - &transport_string_out, NULL); + do_request_full (conn, GST_RTSP_SETUP, control, session_in, + transport_string_in, NULL, require, NULL, NULL, NULL, session_out, + &transport_string_out, NULL, unsupported); g_free (transport_string_in); if (transport_string_out) { @@ -442,10 +465,23 @@ do_setup (GstRTSPConnection * conn, const gchar * control, *transport) == GST_RTSP_OK); g_free (transport_string_out); } - + GST_INFO ("code=%d", code); return code; } +/* send a SETUP request and receive response. if *session is not NULL, + * it is used in the request. otherwise, *session is set to a returned + * session string that must be freed by the caller. the returned + * transport must be freed by the caller. */ +static GstRTSPStatusCode +do_setup (GstRTSPConnection * conn, const gchar * control, + const GstRTSPRange * client_ports, gchar ** session, + GstRTSPTransport ** transport) +{ + return do_setup_full (conn, control, client_ports, NULL, session, transport, + NULL); +} + /* fixture setup function */ static void setup (void) @@ -621,6 +657,69 @@ GST_START_TEST (test_setup) GST_END_TEST; +GST_START_TEST (test_setup_with_require_header) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + GstRTSPRange client_ports; + gchar *session = NULL; + gchar *unsupported = NULL; + GstRTSPTransport *video_transport = NULL; + + start_server (); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports (&client_ports); + + /* send SETUP request for video, with single Require header */ + fail_unless_equals_int (do_setup_full (conn, video_control, &client_ports, + "funky-feature", &session, &video_transport, &unsupported), + GST_RTSP_STS_OPTION_NOT_SUPPORTED); + fail_unless_equals_string (unsupported, "funky-feature"); + g_free (unsupported); + unsupported = NULL; + + /* send SETUP request for video, with multiple Require headers */ + fail_unless_equals_int (do_setup_full (conn, video_control, &client_ports, + "funky-feature, foo-bar, superburst", &session, &video_transport, + &unsupported), GST_RTSP_STS_OPTION_NOT_SUPPORTED); + fail_unless_equals_string (unsupported, "funky-feature, foo-bar, superburst"); + g_free (unsupported); + unsupported = NULL; + + /* ok, just do a normal setup then (make sure that still works) */ + fail_unless_equals_int (do_setup (conn, video_control, &client_ports, + &session, &video_transport), GST_RTSP_STS_OK); + + GST_DEBUG ("set up video %s, got session '%s'", video_control, session); + + /* check response from SETUP */ + fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP); + fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP); + fail_unless (video_transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP); + fail_unless (video_transport->mode_play); + gst_rtsp_transport_free (video_transport); + + /* clean up and iterate so the clean-up can finish */ + g_free (session); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); +} + +GST_END_TEST; + GST_START_TEST (test_setup_non_existing_stream) { GstRTSPConnection *conn; @@ -1329,6 +1428,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_describe); tcase_add_test (tc, test_describe_non_existing_mount_point); tcase_add_test (tc, test_setup); + tcase_add_test (tc, test_setup_with_require_header); tcase_add_test (tc, test_setup_non_existing_stream); tcase_add_test (tc, test_play); tcase_add_test (tc, test_play_without_session); From b8165dbd6035e4bf4924e68d91b799713689411f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 9 May 2014 15:08:48 +0200 Subject: [PATCH 0971/1776] tests: add and remove pads only once In this test we simulate a dynamic pad by watching the caps event. Because of renegotiation in the base payloader now, this caps is sent multiple times but we can only deal with 1 invocation, use a variable to only 'add and remove' the pad once. --- tests/check/gst/media.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index f2a58cedd4..c7d680e7c2 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -214,17 +214,24 @@ static void on_notify_caps (GstPad * pad, GParamSpec * pspec, GstElement * pay) { GstCaps *caps; + static gboolean have_caps = FALSE; g_object_get (pad, "caps", &caps, NULL); GST_DEBUG ("notify %" GST_PTR_FORMAT, caps); if (caps) { - g_signal_emit_by_name (pay, "pad-added", pad); - g_signal_emit_by_name (pay, "no-more-pads", NULL); + if (!have_caps) { + g_signal_emit_by_name (pay, "pad-added", pad); + g_signal_emit_by_name (pay, "no-more-pads", NULL); + have_caps = TRUE; + } gst_caps_unref (caps); } else { - g_signal_emit_by_name (pay, "pad-removed", pad); + if (have_caps) { + g_signal_emit_by_name (pay, "pad-removed", pad); + have_caps = FALSE; + } } } From d01beef7c54da0022c952956ff70a81e09093f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Fri, 9 May 2014 17:25:07 -0700 Subject: [PATCH 0972/1776] client: fix send-message signal marshaller Use generic marshalling for the send-message signal. It has two POINTER arguments, not just one. https://bugzilla.gnome.org/show_bug.cgi?id=729900 --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 93d3b3fa5e..d16eee0a86 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -250,7 +250,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE] = g_signal_new ("send-message", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, + G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); tunnels = From 0fb7922e9bcb6485fa5404412846685cae216e3a Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 14 May 2014 09:31:31 +0200 Subject: [PATCH 0973/1776] media: Make suspend()/unsuspend() virtual Fixes https://bugzilla.gnome.org/show_bug.cgi?id=730109 --- gst/rtsp-server/rtsp-media.c | 147 ++++++++++++++++++++++++----------- gst/rtsp-server/rtsp-media.h | 8 ++ 2 files changed, 108 insertions(+), 47 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index f1b9cb205b..5687a72cc5 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -176,6 +176,8 @@ static gboolean default_handle_message (GstRTSPMedia * media, static void finish_unprepare (GstRTSPMedia * media); static gboolean default_prepare (GstRTSPMedia * media, GstRTSPThread * thread); static gboolean default_unprepare (GstRTSPMedia * media); +static gboolean default_suspend (GstRTSPMedia * media); +static gboolean default_unsuspend (GstRTSPMedia * media); static gboolean default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range, GstRTSPRangeUnit unit); static gboolean default_query_position (GstRTSPMedia * media, @@ -308,6 +310,8 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->handle_message = default_handle_message; klass->prepare = default_prepare; klass->unprepare = default_unprepare; + klass->suspend = default_suspend; + klass->unsuspend = default_unsuspend; klass->convert_range = default_convert_range; klass->query_position = default_query_position; klass->query_stop = default_query_stop; @@ -2661,36 +2665,13 @@ no_setup_sdp: } } -/** - * gst_rtsp_media_suspend: - * @media: a #GstRTSPMedia - * - * Suspend @media. The state of the pipeline managed by @media is set to - * GST_STATE_NULL but all streams are kept. @media can be prepared again - * with gst_rtsp_media_unsuspend() - * - * @media must be prepared with gst_rtsp_media_prepare(); - * - * Returns: %TRUE on success. - */ +/* call with state_lock */ gboolean -gst_rtsp_media_suspend (GstRTSPMedia * media) +default_suspend (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; GstStateChangeReturn ret; - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - - GST_FIXME ("suspend for dynamic pipelines needs fixing"); - - g_rec_mutex_lock (&priv->state_lock); - if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) - goto not_prepared; - - /* don't attempt to suspend when something is busy */ - if (priv->n_active > 0) - goto done; - switch (priv->suspend_mode) { case GST_RTSP_SUSPEND_MODE_NONE: GST_DEBUG ("media %p no suspend", media); @@ -2710,8 +2691,56 @@ gst_rtsp_media_suspend (GstRTSPMedia * media) default: break; } + /* let the streams do the state changes freely, if any */ media_streams_set_blocked (media, FALSE); + + return TRUE; + + /* ERRORS */ +state_failed: + { + GST_WARNING ("failed changing pipeline's state for media %p", media); + return FALSE; + } +} + +/** + * gst_rtsp_media_suspend: + * @media: a #GstRTSPMedia + * + * Suspend @media. The state of the pipeline managed by @media is set to + * GST_STATE_NULL but all streams are kept. @media can be prepared again + * with gst_rtsp_media_unsuspend() + * + * @media must be prepared with gst_rtsp_media_prepare(); + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_media_suspend (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + GstRTSPMediaClass *klass; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + GST_FIXME ("suspend for dynamic pipelines needs fixing"); + + g_rec_mutex_lock (&priv->state_lock); + if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) + goto not_prepared; + + /* don't attempt to suspend when something is busy */ + if (priv->n_active > 0) + goto done; + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + if (klass->suspend) { + if (!klass->suspend (media)) + goto suspend_failed; + } + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_SUSPENDED); done: g_rec_mutex_unlock (&priv->state_lock); @@ -2725,35 +2754,21 @@ not_prepared: GST_WARNING ("media %p was not prepared", media); return FALSE; } -state_failed: +suspend_failed: { g_rec_mutex_unlock (&priv->state_lock); gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR); - GST_WARNING ("failed changing pipeline's state for media %p", media); + GST_WARNING ("failed to suspend media %p", media); return FALSE; } } -/** - * gst_rtsp_media_unsuspend: - * @media: a #GstRTSPMedia - * - * Unsuspend @media if it was in a suspended state. This method does nothing - * when the media was not in the suspended state. - * - * Returns: %TRUE on success. - */ +/* call with state_lock */ gboolean -gst_rtsp_media_unsuspend (GstRTSPMedia * media) +default_unsuspend (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - - g_rec_mutex_lock (&priv->state_lock); - if (priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED) - goto done; - switch (priv->suspend_mode) { case GST_RTSP_SUSPEND_MODE_NONE: gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); @@ -2776,17 +2791,13 @@ gst_rtsp_media_unsuspend (GstRTSPMedia * media) default: break; } -done: - g_rec_mutex_unlock (&priv->state_lock); return TRUE; /* ERRORS */ start_failed: { - g_rec_mutex_unlock (&priv->state_lock); GST_WARNING ("failed to preroll pipeline"); - gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR); return FALSE; } preroll_failed: @@ -2796,6 +2807,48 @@ preroll_failed: } } +/** + * gst_rtsp_media_unsuspend: + * @media: a #GstRTSPMedia + * + * Unsuspend @media if it was in a suspended state. This method does nothing + * when the media was not in the suspended state. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_media_unsuspend (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + GstRTSPMediaClass *klass; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + g_rec_mutex_lock (&priv->state_lock); + if (priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED) + goto done; + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + if (klass->unsuspend) { + if (!klass->unsuspend (media)) + goto unsuspend_failed; + } + +done: + g_rec_mutex_unlock (&priv->state_lock); + + return TRUE; + + /* ERRORS */ +unsuspend_failed: + { + g_rec_mutex_unlock (&priv->state_lock); + GST_WARNING ("failed to unsuspend media %p", media); + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR); + return FALSE; + } +} + /* must be called with state-lock */ static void media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 01df74dfcc..53047595fe 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -110,6 +110,12 @@ struct _GstRTSPMedia { * in case of NO_PREROLL elements). * @unprepare: the default implementation sets the pipeline's state * to GST_STATE_NULL and removes all elements. + * @suspend: the default implementation sets the pipeline's state to + * GST_STATE_NULL GST_STATE_PAUSED depending on the selected + * suspend mode. + * @unsuspend: the default implementation reverts the suspend operation. + * The pipeline will be prerolled again if it's state was + * set to GST_STATE_NULL in suspend. * @convert_range: convert a range to the given unit * @query_position: query the current posision in the pipeline * @query_stop: query when playback will stop @@ -123,6 +129,8 @@ struct _GstRTSPMediaClass { gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message); gboolean (*prepare) (GstRTSPMedia *media, GstRTSPThread *thread); gboolean (*unprepare) (GstRTSPMedia *media); + gboolean (*suspend) (GstRTSPMedia *media); + gboolean (*unsuspend) (GstRTSPMedia *media); gboolean (*convert_range) (GstRTSPMedia *media, GstRTSPTimeRange *range, GstRTSPRangeUnit unit); gboolean (*query_position) (GstRTSPMedia *media, gint64 *position); From 17322693f66a7e2b7b37f79a12618d6eea6e12cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Thu, 15 May 2014 18:15:04 -0700 Subject: [PATCH 0974/1776] stream: add signals for new RTP/RTCP encoders New signals to allow the user to configure the dynamically created encoders. https://bugzilla.gnome.org/show_bug.cgi?id=730228 --- gst/rtsp-server/rtsp-stream.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 85b4ee0d76..7317553b37 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -148,6 +148,13 @@ enum PROP_LAST }; +enum +{ + SIGNAL_NEW_RTP_ENCODER, + SIGNAL_NEW_RTCP_ENCODER, + SIGNAL_LAST +}; + GST_DEBUG_CATEGORY_STATIC (rtsp_stream_debug); #define GST_CAT_DEFAULT rtsp_stream_debug @@ -160,6 +167,8 @@ static void gst_rtsp_stream_set_property (GObject * object, guint propid, static void gst_rtsp_stream_finalize (GObject * obj); +static guint gst_rtsp_stream_signals[SIGNAL_LAST] = { 0 }; + G_DEFINE_TYPE (GstRTSPStream, gst_rtsp_stream, G_TYPE_OBJECT); static void @@ -190,6 +199,16 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS, DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_stream_signals[SIGNAL_NEW_RTP_ENCODER] = + g_signal_new ("new-rtp-encoder", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, + G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + + gst_rtsp_stream_signals[SIGNAL_NEW_RTCP_ENCODER] = + g_signal_new ("new-rtcp-encoder", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, + G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + GST_DEBUG_CATEGORY_INIT (rtsp_stream_debug, "rtspstream", 0, "GstRTSPStream"); ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); @@ -1534,7 +1553,7 @@ static GstElement * request_rtp_encoder (GstElement * rtpbin, guint session, GstRTSPStream * stream) { GstRTSPStreamPrivate *priv = stream->priv; - GstElement *enc; + GstElement *oldenc, *enc; GstPad *pad; gchar *name; @@ -1543,12 +1562,17 @@ request_rtp_encoder (GstElement * rtpbin, guint session, GstRTSPStream * stream) GST_DEBUG_OBJECT (stream, "make RTP encoder for session %u", session); + oldenc = priv->srtpenc; enc = get_rtp_encoder (stream, session); name = g_strdup_printf ("rtp_sink_%d", session); pad = gst_element_get_request_pad (enc, name); g_free (name); gst_object_unref (pad); + if (oldenc == NULL) + g_signal_emit (stream, gst_rtsp_stream_signals[SIGNAL_NEW_RTP_ENCODER], 0, + enc); + return enc; } @@ -1557,7 +1581,7 @@ request_rtcp_encoder (GstElement * rtpbin, guint session, GstRTSPStream * stream) { GstRTSPStreamPrivate *priv = stream->priv; - GstElement *enc; + GstElement *oldenc, *enc; GstPad *pad; gchar *name; @@ -1566,12 +1590,17 @@ request_rtcp_encoder (GstElement * rtpbin, guint session, GST_DEBUG_OBJECT (stream, "make RTCP encoder for session %u", session); + oldenc = priv->srtpenc; enc = get_rtp_encoder (stream, session); name = g_strdup_printf ("rtcp_sink_%d", session); pad = gst_element_get_request_pad (enc, name); g_free (name); gst_object_unref (pad); + if (oldenc == NULL) + g_signal_emit (stream, gst_rtsp_stream_signals[SIGNAL_NEW_RTCP_ENCODER], 0, + enc); + return enc; } From 5aa06b8058423e7ecd1f656d6d420cab6d581d1e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 May 2014 15:57:30 +0200 Subject: [PATCH 0975/1776] client: store TCP ports in transport Store the TCP ports in the transport when we are doing RTSP over TCP. This way, we can easily get to the ports from the transport. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=729776 --- gst/rtsp-server/rtsp-client.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d16eee0a86..fb44a293cb 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1394,6 +1394,33 @@ default_configure_client_transport (GstRTSPClient * client, ct->destination = g_strdup (url->host); if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) { + GSocket *sock; + GSocketAddress *addr; + + sock = gst_rtsp_connection_get_read_socket (priv->connection); + if ((addr = g_socket_get_remote_address (sock, NULL))) { + /* our read port is the sender port of client */ + ct->client_port.min = + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)); + g_object_unref (addr); + } + if ((addr = g_socket_get_local_address (sock, NULL))) { + ct->server_port.max = + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)); + g_object_unref (addr); + } + sock = gst_rtsp_connection_get_write_socket (priv->connection); + if ((addr = g_socket_get_remote_address (sock, NULL))) { + /* our write port is the receiver port of client */ + ct->client_port.max = + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)); + g_object_unref (addr); + } + if ((addr = g_socket_get_local_address (sock, NULL))) { + ct->server_port.min = + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)); + g_object_unref (addr); + } /* check if the client selected channels for TCP */ if (ct->interleaved.min == -1 || ct->interleaved.max == -1) { gst_rtsp_session_media_alloc_channels (ctx->sessmedia, @@ -1449,6 +1476,8 @@ make_server_transport (GstRTSPClient * client, GstRTSPContext * ctx, break; case GST_RTSP_LOWER_TRANS_TCP: st->interleaved = ct->interleaved; + st->client_port = ct->client_port; + st->server_port = ct->server_port; default: break; } From afa3f3f48aa9f788a29af992cbe494721615b31c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 21 May 2014 10:54:05 +0200 Subject: [PATCH 0976/1776] Automatic update of common submodule From 211fa5f to 1f5d3c3 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 211fa5f2d0..1f5d3c3163 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 211fa5f2d0930dfd6891b386d42edba6d88c2a19 +Subproject commit 1f5d3c3163cc3399251827235355087c2affa790 From acbdc49c35f405c88885da8d78c91bced4a19f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 21 May 2014 13:06:36 +0200 Subject: [PATCH 0977/1776] Release 1.3.2 --- ChangeLog | 83 ++++++++++++++++++++++++++++++++++++++++++-- NEWS | 18 ++++++++-- RELEASE | 60 ++++++-------------------------- common | 2 +- configure.ac | 12 +++---- gst-rtsp-server.doap | 12 ++++++- 6 files changed, 123 insertions(+), 64 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9c8ec4b4d7..f4495d0d21 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,86 @@ -=== release 1.3.1 === +=== release 1.3.2 === -2014-05-03 Sebastian Dröge +2014-05-21 Sebastian Dröge * configure.ac: - releasing 1.3.1 + releasing 1.3.2 + +2014-05-21 10:54:05 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 211fa5f to 1f5d3c3 + +2014-05-20 15:57:30 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: store TCP ports in transport + Store the TCP ports in the transport when we are doing RTSP over TCP. + This way, we can easily get to the ports from the transport. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=729776 + +2014-05-15 18:15:04 -0700 Aleix Conchillo Flaqué + + * gst/rtsp-server/rtsp-stream.c: + stream: add signals for new RTP/RTCP encoders + New signals to allow the user to configure the dynamically created + encoders. + https://bugzilla.gnome.org/show_bug.cgi?id=730228 + +2014-05-14 09:31:31 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media: Make suspend()/unsuspend() virtual + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=730109 + +2014-05-09 17:25:07 -0700 Aleix Conchillo Flaqué + + * gst/rtsp-server/rtsp-client.c: + client: fix send-message signal marshaller + Use generic marshalling for the send-message signal. It has + two POINTER arguments, not just one. + https://bugzilla.gnome.org/show_bug.cgi?id=729900 + +2014-05-09 15:08:48 +0200 Wim Taymans + + * tests/check/gst/media.c: + tests: add and remove pads only once + In this test we simulate a dynamic pad by watching the caps event. + Because of renegotiation in the base payloader now, this caps is sent + multiple times but we can only deal with 1 invocation, use a variable to + only 'add and remove' the pad once. + +2014-05-02 20:06:29 +0100 Tim-Philipp Müller + + * tests/check/gst/rtspserver.c: + tests: add unit test for correct handling of Require headers + https://bugzilla.gnome.org/show_bug.cgi?id=729426 + +2014-05-02 19:59:23 +0100 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: handle Require headers and respond with OPTION_NOT_SUPPORTED + Servers must handle Require headers and must report a failure + if they don't handle any of the Required options, see RFC 2326, + section 12.32: https://tools.ietf.org/html/rfc2326#page-54 + https://bugzilla.gnome.org/show_bug.cgi?id=729426 + +2014-05-03 20:48:43 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.3.1 === + +2014-05-03 18:40:24 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.3.1 2014-05-03 10:18:00 +0200 Sebastian Dröge diff --git a/NEWS b/NEWS index 4a7ac5719e..1011887b7b 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -This is GStreamer RTSP Server 1.3.1 +This is GStreamer RTSP Server 1.3.2 Changes since 1.2: @@ -45,6 +45,8 @@ New API: events and merge custom tags into them consistently. • playbin/playsink has support for application provided audio and video filters. + • GstDiscoverer has new and simplified API to get details about missing + plugins and information to pass to the plugin installer. • The GL library was merged from gst-plugins-gl to gst-plugins-bad, providing a generic infrastructure for handling GL inside GStreamer pipelines and a plugin with some elements using these, especially @@ -62,6 +64,14 @@ Major changes: of the existing V4L2 elements and the corresponding infrastructure. The v4l2videodec element replaces the mfcdec element. + ∘ New downloadbuffer element that replaces the download + buffering feature of queue2. Compared to queue2's code + it is much simpler and only for this single use case. + A noteworthy new feature is that it's downloading gaps + in the already downloaded stream parts when nothing else + is to be downloaded. + This is now used by playbin when download buffering is + enabled. ∘ rtpstreampay and rtpstreamdepay elements for transmitting RTP packets over a stream API (e.g. TCP) according to RFC 4571. @@ -78,7 +88,7 @@ Major changes: are available on OS X and iOS now. • Other changes: - ∘ gst-libav now uses libav 10, and gained support for H265/HEVC. + ∘ gst-libav now uses libav 10.1, and gained support for H265/HEVC. ∘ Support for hardware codecs and special memory types has been improved with bugfixes and feature additions in various plugins and base classes. @@ -95,6 +105,9 @@ Major changes: reliable now and supports more HLS features like trick modes. Also fragments are pushed downstream while they're downloaded now instead of waiting for each fragment to finish. + ∘ dashdemux and mssdemux are now also pushing fragments downstream + while they're downloaded instead of waiting for each fragment to + finish. ∘ videoflip can automatically flip based on the orientation tag. ∘ openjpeg supports the OpenJPEG2 API. ∘ gst-rtsp-server supports SRTP and MIKEY now. @@ -107,4 +120,3 @@ Things to look out for: element. • The mfcdec element was removed and replaced by v4l2videodec. • osxvideosink is only available in OS X 10.6 or newer. - diff --git a/RELEASE b/RELEASE index 638d91d9fe..c7d8057a46 100644 --- a/RELEASE +++ b/RELEASE @@ -1,8 +1,8 @@ -Release notes for GStreamer RTSP Server Library 1.3.1 +Release notes for GStreamer RTSP Server Library 1.3.2 -The GStreamer team is pleased to announce the first release of the unstable +The GStreamer team is pleased to announce the second release of the unstable 1.3 release series. The 1.3 release series is adding new features on top of the 1.0 and 1.2 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. The unstable 1.3 release series @@ -28,24 +28,16 @@ change. +Features of this release + + Bugs fixed in this release - * 725484 : gst-rtsp-server: Ignore gcov intermediate files - * 725528 : rtspserver: Enable and fix gtk-doc warnings - * 725879 : rtsp-client: headers in GET response not configurable for tunnels - * 726362 : rtsp-stream: fix a typo where IPv4 and IPv6 addresses were confused. - * 726470 : tests: Add unit tests for sessionpool - * 726873 : rtsp-threadpool: Improve code coverage of check tests - * 726940 : rtsp-session-media: add more tests to improve code coverage - * 726941 : docs: Add annotations to support language bindings - * 727102 : rtsp-media: deadlock with dynamic pipelines when preroll fails - * 727231 : rtsp-server: The media streams leak - * 727376 : crash if media_prepare() fails to allocate UDP ports - * 727488 : There is a race when disconnecting POST channel in tunneled mode - * 728029 : rtsp-media: Make media_prepare() virtual - * 728060 : rtsp-session-pool: Incorrect annotation and leak in unit test - * 728153 : Problem with send_lock when data in backlog and recive a teardown request. - * 728970 : rtsp-client: add signal before sending response + * 729426 : Should respond " 551 Option not supported " in case a Require header is received + * 729776 : Set client port from URL + * 729900 : rtsp-client: wrong marshalling in send-message signal + * 730109 : media: Make suspend()/unsuspend() virtual + * 730228 : stream: add signals for new RTP/RTCP encoders ==== Download ==== @@ -84,41 +76,9 @@ Applications Contributors to this release - * Aleix Conchillo Flaque * Aleix Conchillo Flaqué - * Alessandro Decina - * Alexander Schrab - * Andrey Utkin - * Branko Subasic - * David Schleef - * David Svensson Fors - * Edward Hervey - * Emmanuel Pacaud - * Fabian Deutsch - * George McCollister - * Göran Jönsson - * Jonas Holmberg - * Linus Svensson - * Lubosz Sarnecki - * Luis de Bethencourt - * Mark Nauwelaerts - * Miguel Angel Cabrera Moya * Ognyan Tonchev - * Olivier Crête - * Patricia Muscalu - * Patrick Radizi - * Robert Krakora * Sebastian Dröge - * Sebastian Pölsterl - * Sebastian Rasmussen - * Stefan Kost - * Stefan Sauer - * Thijs Vermeir - * Thomas Vander Stichele * Tim-Philipp Müller - * Victor Gottardi - * Vincent Penquerc'h * Wim Taymans - * Youness Alaoui - * mat   \ No newline at end of file diff --git a/common b/common index 1f5d3c3163..211fa5f2d0 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 1f5d3c3163cc3399251827235355087c2affa790 +Subproject commit 211fa5f2d0930dfd6891b386d42edba6d88c2a19 diff --git a/configure.ac b/configure.ac index e56ba81a1a..42aea341a8 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.3.1.1], +AC_INIT([GStreamer RTSP Server Library], [1.3.2], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 301, 0, 301) +AS_LIBTOOL(GST, 302, 0, 302) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.3.1.1 -GSTPB_REQ=1.3.1.1 -GSTPG_REQ=1.3.1.1 -GSTPD_REQ=1.3.1.1 +GST_REQ=1.3.2 +GSTPB_REQ=1.3.2 +GSTPG_REQ=1.3.2 +GSTPD_REQ=1.3.2 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 216748147a..2201ab2631 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -28,7 +28,17 @@ RTSP server library based on GStreamer - + + + + + 1.3.2 + 1.3 + + 2014-05-21 + + + From 35a6c8cbcc46c188afb1215916c2390da0bc5c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 21 May 2014 13:23:40 +0200 Subject: [PATCH 0978/1776] Back to development --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 42aea341a8..1b053e7c76 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.3.2], +AC_INIT([GStreamer RTSP Server Library], [1.3.2.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 302, 0, 302) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.3.2 -GSTPB_REQ=1.3.2 -GSTPG_REQ=1.3.2 -GSTPD_REQ=1.3.2 +GST_REQ=1.3.2.1 +GSTPB_REQ=1.3.2.1 +GSTPG_REQ=1.3.2.1 +GSTPD_REQ=1.3.2.1 dnl *** autotools stuff **** From aaf921cac423a7dee34d66def9271845b8c998eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Tue, 27 May 2014 12:36:52 +0200 Subject: [PATCH 0979/1776] rtsp-session: Timeout in header. Adding the possbilty to always have timout in header. This is configurabe with setting "timeout-always-visible". Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728264 --- gst/rtsp-server/rtsp-session.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 59463ce18d..9beb8ab08e 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -56,6 +56,7 @@ struct _GstRTSPSessionPrivate gchar *sessionid; guint timeout; + gboolean timeout_always_visible; GTimeVal create_time; /* immutable */ GTimeVal last_access; gint expire_count; @@ -65,13 +66,15 @@ struct _GstRTSPSessionPrivate #undef DEBUG -#define DEFAULT_TIMEOUT 60 +#define DEFAULT_TIMEOUT 60 +#define DEFAULT_ALWAYS_VISIBLE FALSE enum { PROP_0, PROP_SESSIONID, PROP_TIMEOUT, + PROP_TIMEOUT_ALWAYS_VISIBLE, PROP_LAST }; @@ -109,6 +112,11 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass) "the timeout of the session (0 = never)", 0, G_MAXUINT, DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_TIMEOUT_ALWAYS_VISIBLE, + g_param_spec_boolean ("timeout-always-visible", "Timeout Always Visible ", + "timeout always visible in header", + DEFAULT_ALWAYS_VISIBLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0, "GstRTSPSession"); } @@ -161,6 +169,9 @@ gst_rtsp_session_get_property (GObject * object, guint propid, case PROP_TIMEOUT: g_value_set_uint (value, gst_rtsp_session_get_timeout (session)); break; + case PROP_TIMEOUT_ALWAYS_VISIBLE: + g_value_set_boolean (value, priv->timeout_always_visible); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -181,6 +192,11 @@ gst_rtsp_session_set_property (GObject * object, guint propid, case PROP_TIMEOUT: gst_rtsp_session_set_timeout (session, g_value_get_uint (value)); break; + case PROP_TIMEOUT_ALWAYS_VISIBLE: + g_mutex_lock (&priv->lock); + priv->timeout_always_visible = g_value_get_boolean (value); + g_mutex_unlock (&priv->lock); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -433,8 +449,9 @@ gst_rtsp_session_get_header (GstRTSPSession * session) priv = session->priv; + g_mutex_lock (&priv->lock); - if (priv->timeout != 60) + if (priv->timeout_always_visible || priv->timeout != 60) result = g_strdup_printf ("%s; timeout=%d", priv->sessionid, priv->timeout); else result = g_strdup (priv->sessionid); From e327af8a269fce5dc82e4365fe93263e7d68eb55 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 13 Jun 2014 16:46:06 +0200 Subject: [PATCH 0980/1776] media: fix confusing comment --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 5687a72cc5..dbcf15fbcb 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1627,7 +1627,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) flags |= GST_SEEK_FLAG_KEY_UNIT; } - /* FIXME, we only do forwards */ + /* FIXME, we only do forwards playback, no trick modes yet */ res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME, flags, start_type, start, stop_type, stop); From 97152525887e7f8d83a26c739f59e5520383be54 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Thu, 12 Jun 2014 13:48:44 +0200 Subject: [PATCH 0981/1776] client: Destroy the rtsp watch after connection close --- gst/rtsp-server/rtsp-client.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index fb44a293cb..4a8214f96f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -795,6 +795,15 @@ close_connection (GstRTSPClient * client) } gst_rtsp_connection_close (priv->connection); + + /* connection is now closed, destroy the watch which will also cause the + * closed signal to be emitted */ + if (priv->watch) { + GST_DEBUG ("client %p: destroying watch", client); + g_source_destroy ((GSource *) priv->watch); + priv->watch = NULL; + gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + } } static gchar * From f2b1aa8c817e78ff255c47d6f5637d528b7e2944 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Thu, 12 Jun 2014 13:49:17 +0200 Subject: [PATCH 0982/1776] client: ref the context until rtsp watch is alive Fixes https://bugzilla.gnome.org/show_bug.cgi?id=731569 --- gst/rtsp-server/rtsp-client.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4a8214f96f..cf79bda8a8 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -61,6 +61,7 @@ struct _GstRTSPClientPrivate GMutex send_lock; GstRTSPConnection *connection; GstRTSPWatch *watch; + GMainContext *watch_context; guint close_seq; gchar *server_ip; gboolean is_ipv6; @@ -364,6 +365,9 @@ gst_rtsp_client_finalize (GObject * obj) if (priv->watch) g_source_destroy ((GSource *) priv->watch); + if (priv->watch_context) + g_main_context_unref (priv->watch_context); + client_cleanup_sessions (client); if (priv->connection) @@ -3230,6 +3234,8 @@ handle_tunnel (GstRTSPClient * client) /* the old client owns the tunnel now, the new one will be freed */ g_source_destroy ((GSource *) priv->watch); priv->watch = NULL; + g_main_context_unref (priv->watch_context); + priv->watch_context = NULL; gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); } @@ -3314,6 +3320,8 @@ client_watch_notify (GstRTSPClient * client) GST_INFO ("client %p: watch destroyed", client); priv->watch = NULL; + g_main_context_unref (priv->watch_context); + priv->watch_context = NULL; g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL); g_object_unref (client); } @@ -3343,6 +3351,9 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) g_return_val_if_fail (priv->connection != NULL, 0); g_return_val_if_fail (priv->watch == NULL, 0); + /* make sure noone will free the context before the watch is destroyed */ + priv->watch_context = g_main_context_ref (context); + /* create watch for the connection and attach */ priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs, g_object_ref (client), (GDestroyNotify) client_watch_notify); From fc06329e87c6bf0eae0ffe49827ffac1d31c13bc Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Sun, 16 Mar 2014 17:29:48 +0100 Subject: [PATCH 0983/1776] stream tests: Make sure we get right multicast address from stream Fixes https://bugzilla.gnome.org/show_bug.cgi?id=731577 --- tests/check/gst/stream.c | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index eb9e0b5e76..582e67408f 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -20,6 +20,7 @@ #include #include +#include GST_START_TEST (test_get_sockets) { @@ -92,6 +93,69 @@ GST_START_TEST (test_get_sockets) GST_END_TEST; +GST_START_TEST (test_get_multicast_address) +{ + GstPad *srcpad; + GstElement *pay; + GstRTSPStream *stream; + GstRTSPAddressPool *pool; + GstRTSPAddress *addr1; + GstRTSPAddress *addr2; + + srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); + fail_unless (srcpad != NULL); + gst_pad_set_active (srcpad, TRUE); + pay = gst_element_factory_make ("rtpgstpay", "testpayloader"); + fail_unless (pay != NULL); + stream = gst_rtsp_stream_new (0, pay, srcpad); + fail_unless (stream != NULL); + gst_object_unref (pay); + gst_object_unref (srcpad); + + pool = gst_rtsp_address_pool_new (); + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.252.0.0", "233.252.0.0", 5000, 5001, 1)); + fail_unless (gst_rtsp_address_pool_add_range (pool, + "FF11:DB8::1", "FF11:DB8::1", 5002, 5003, 1)); + gst_rtsp_stream_set_address_pool (stream, pool); + + addr1 = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV4); + fail_unless (addr1 != NULL); + fail_unless_equals_string (addr1->address, "233.252.0.0"); + fail_unless_equals_int (addr1->port, 5000); + fail_unless_equals_int (addr1->n_ports, 2); + + addr2 = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV4); + fail_unless (addr2 != NULL); + fail_unless_equals_string (addr2->address, "233.252.0.0"); + fail_unless_equals_int (addr2->port, 5000); + fail_unless_equals_int (addr2->n_ports, 2); + + gst_rtsp_address_free (addr1); + gst_rtsp_address_free (addr2); + + addr1 = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV6); + fail_unless (addr1 != NULL); + fail_unless (!g_ascii_strcasecmp (addr1->address, "FF11:DB8::1")); + fail_unless_equals_int (addr1->port, 5002); + fail_unless_equals_int (addr1->n_ports, 2); + + addr2 = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV6); + fail_unless (addr2 != NULL); + fail_unless (!g_ascii_strcasecmp (addr2->address, "FF11:DB8::1")); + fail_unless_equals_int (addr2->port, 5002); + fail_unless_equals_int (addr2->n_ports, 2); + + gst_rtsp_address_free (addr1); + gst_rtsp_address_free (addr2); + + g_object_unref (pool); + + gst_object_unref (stream); +} + +GST_END_TEST; + static Suite * rtspstream_suite (void) { @@ -100,6 +164,7 @@ rtspstream_suite (void) suite_add_tcase (s, tc); tcase_add_test (tc, test_get_sockets); + tcase_add_test (tc, test_get_multicast_address); return s; } From 32432b5c614cbbda9e0425c01619e5c0d54d6110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Tue, 20 May 2014 14:48:37 -0700 Subject: [PATCH 0984/1776] mikey: add different key length parameters Add encryption and authentication key length parameters to MIKEY. For the encoders, the key lengths are obtained from the cipher and auth algorithms set in the caps. For the decoders, they are obtained while parsing the key management from the client. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=730472 --- gst/rtsp-server/rtsp-client.c | 24 ++++++++++++++++++++++++ gst/rtsp-server/rtsp-sdp.c | 34 ++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-sdp.h | 6 ++++++ 3 files changed, 64 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index cf79bda8a8..3cbe67e8d9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1545,6 +1545,18 @@ mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy) break; } break; + case GST_MIKEY_SP_SRTP_ENC_KEY_LEN: + switch (param->val[0]) { + case AES_128_KEY_LEN: + srtp_cipher = "aes-128-icm"; + break; + case AES_256_KEY_LEN: + srtp_cipher = "aes-256-icm"; + break; + default: + break; + } + break; case GST_MIKEY_SP_SRTP_AUTH_ALG: switch (param->val[0]) { case 0: @@ -1558,6 +1570,18 @@ mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy) break; } break; + case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN: + switch (param->val[0]) { + case HMAC_32_KEY_LEN: + srtp_auth = "hmac-sha1-32"; + break; + case HMAC_80_KEY_LEN: + srtp_auth = "hmac-sha1-80"; + break; + default: + break; + } + break; case GST_MIKEY_SP_SRTP_SRTP_ENC: break; case GST_MIKEY_SP_SRTP_SRTCP_ENC: diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 13af74d4cd..c4e74a382b 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -72,6 +72,32 @@ update_sdp_from_tags (GstRTSPStream * stream, GstSDPMedia * stream_media) gst_object_unref (src_pad); } +static guint8 +enc_key_length_from_cipher_name (const gchar * cipher) +{ + if (g_strcmp0 (cipher, "aes-128-icm") == 0) + return AES_128_KEY_LEN; + else if (g_strcmp0 (cipher, "aes-256-icm") == 0) + return AES_256_KEY_LEN; + else { + GST_ERROR ("encryption algorithm '%s' not supported", cipher); + return 0; + } +} + +static guint8 +auth_key_length_from_auth_name (const gchar * auth) +{ + if (g_strcmp0 (auth, "hmac-sha1-32") == 0) + return HMAC_32_KEY_LEN; + else if (g_strcmp0 (auth, "hmac-sha1-80") == 0) + return HMAC_80_KEY_LEN; + else { + GST_ERROR ("authentication algorithm '%s' not supported", auth); + return 0; + } +} + static void make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, GstRTSPStream * stream, GstStructure * s, GstRTSPProfile profile) @@ -226,9 +252,17 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, byte = 1; gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_ALG, 1, &byte); + /* Encryption key length */ + byte = enc_key_length_from_cipher_name (srtpcipher); + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_KEY_LEN, 1, + &byte); /* only HMAC-SHA1 */ gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_ALG, 1, &byte); + /* Authentication key length */ + byte = auth_key_length_from_auth_name (srtpauth); + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_KEY_LEN, 1, + &byte); /* we enable encryption on RTP and RTCP */ gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_ENC, 1, &byte); diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h index 7732f36d90..d0783a752f 100644 --- a/gst/rtsp-server/rtsp-sdp.h +++ b/gst/rtsp-server/rtsp-sdp.h @@ -27,6 +27,12 @@ G_BEGIN_DECLS +#define AES_128_KEY_LEN 16 +#define AES_256_KEY_LEN 32 + +#define HMAC_32_KEY_LEN 4 +#define HMAC_80_KEY_LEN 10 + typedef struct { gboolean is_ipv6; const gchar *server_ip; From 456e05f497634e73248e4b6ac566d07ff1809c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 22 Jun 2014 19:36:14 +0200 Subject: [PATCH 0985/1776] Release 1.3.3 --- ChangeLog | 65 ++++++++++++++++++++++++++++++++++++++++++-- NEWS | 25 +++++++++++++++-- RELEASE | 31 ++++++++------------- configure.ac | 12 ++++---- gst-rtsp-server.doap | 10 +++++++ 5 files changed, 111 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index f4495d0d21..1777857505 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,68 @@ -=== release 1.3.2 === +=== release 1.3.3 === -2014-05-21 Sebastian Dröge +2014-06-22 Sebastian Dröge * configure.ac: - releasing 1.3.2 + releasing 1.3.3 + +2014-05-20 14:48:37 -0700 Aleix Conchillo Flaqué + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-sdp.h: + mikey: add different key length parameters + Add encryption and authentication key length parameters to MIKEY. For + the encoders, the key lengths are obtained from the cipher and auth + algorithms set in the caps. For the decoders, they are obtained while + parsing the key management from the client. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=730472 + +2014-03-16 17:29:48 +0100 Ognyan Tonchev + + * tests/check/gst/stream.c: + stream tests: Make sure we get right multicast address from stream + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=731577 + +2014-06-12 13:49:17 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + client: ref the context until rtsp watch is alive + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=731569 + +2014-06-12 13:48:44 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + client: Destroy the rtsp watch after connection close + +2014-06-13 16:46:06 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-media.c: + media: fix confusing comment + +2014-05-27 12:36:52 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-session.c: + rtsp-session: Timeout in header. + Adding the possbilty to always have timout in header. + This is configurabe with setting "timeout-always-visible". + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728264 + +2014-05-21 13:23:40 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.3.2 === + +2014-05-21 13:06:36 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * common: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.3.2 2014-05-21 10:54:05 +0200 Sebastian Dröge diff --git a/NEWS b/NEWS index 1011887b7b..be406eea79 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -This is GStreamer RTSP Server 1.3.2 +This is GStreamer RTSP Server 1.3.3 Changes since 1.2: @@ -30,6 +30,10 @@ New API: caps. • GstCollectPads has support for flushing and a default handler for SEEK events now. + • New GstFlowAggregator helper object that simplifies handling of + flow returns in elements with multiple source pads. Additionally + GstPad now always stores the last flow return and provides an + API to retrieve it. • GstSegment has new API to offset the running time by a specific value and this is used in GstPad to allow positive and negative offsets in gst_pad_set_offset() in all situations. @@ -43,6 +47,7 @@ New API: • Support for tiled, raw video formats has been added. • GstVideoDecoder and GstAudioDecoder have API to help aggregating tag events and merge custom tags into them consistently. + • GstBufferPool has support for flushing now. • playbin/playsink has support for application provided audio and video filters. • GstDiscoverer has new and simplified API to get details about missing @@ -54,6 +59,10 @@ New API: DispManX (Raspberry Pi), EAGL (iOS), WGL (Windows) and generic X11, Wayland and EGL platforms. This replaces eglglessink and also is supposed to replace osxvideosink. + • New GstAggregator base class in gst-plugins-bad. This is supposed to + replace GstCollectPads in the future and fix long-known shortcomings + in its API. Together with the base class some elements are provided + already, like a videomixer (compositor). Major changes: @@ -97,7 +106,8 @@ Major changes: ∘ dvbsrc supports more delivery mechanisms and other features now, including DVB S2 and T2 support. ∘ The MPEGTS library has support for many more descriptors. - ∘ Major improvements to tsdemux, especially time related. + ∘ Major improvements to tsdemux and tsparse, especially time and + seeking related. ∘ souphttpsrc now has support for keep-alive connections, compression, configurable number of retries and configuration for SSL certificate validation. @@ -110,9 +120,16 @@ Major changes: finish. ∘ videoflip can automatically flip based on the orientation tag. ∘ openjpeg supports the OpenJPEG2 API. + ∘ waylandsink was refactored and should be more useful now. It also + includes a small library which most likely is going to be removed + in the future and will result in extensions to the GstVideoOverlay + interface. ∘ gst-rtsp-server supports SRTP and MIKEY now. + ∘ gst-libav encoders are now negotiating any profile/level settings + with downstream via caps. ∘ Lots of fixes for coverity warnings all over the place. - ∘ 400+ fixed bug reports, and many other bug fixes and other + ∘ Negotiation related performance improvements. + ∘ 500+ fixed bug reports, and many other bug fixes and other improvements everywhere that had no bug report. Things to look out for: @@ -120,3 +137,5 @@ Things to look out for: element. • The mfcdec element was removed and replaced by v4l2videodec. • osxvideosink is only available in OS X 10.6 or newer. + • The GstDeviceMonitor API will likely change slightly before the + 1.4.0 release. diff --git a/RELEASE b/RELEASE index c7d8057a46..341e1e8805 100644 --- a/RELEASE +++ b/RELEASE @@ -1,8 +1,7 @@ -Release notes for GStreamer RTSP Server Library 1.3.2 +Release notes for GStreamer RTSP Server Library 1.3.3 - -The GStreamer team is pleased to announce the second release of the unstable +The GStreamer team is pleased to announce the third release of the unstable 1.3 release series. The 1.3 release series is adding new features on top of the 1.0 and 1.2 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. The unstable 1.3 release series @@ -10,22 +9,15 @@ will lead to the stable 1.4 release series in the next weeks, and newly added API can still change until that point. +This is hopefully the last 1.3 development release and will be followed by +the first 1.4.0 release candidate (1.3.90) in 1-2 weeks. Which then hopefully +is followed by 1.4.0 soonish in early July. + Binaries for Android, iOS, Mac OS X and Windows will be provided separately during the unstable 1.3 release series. - -The versioning scheme that is used in general is that 1.x.y is API and -ABI backwards compatible with previous 1.x.y releases. If x is an even -number it is a stable release series and all releases in this series -will only contain important bugfixes, e.g. the 1.0 series with 1.0.7. If -x is odd it is a development release series that will lead to the next -stable release series 1.x+1 and contains new features and bigger -changes. During the development release series, new API can still -change. - - Features of this release @@ -33,11 +25,10 @@ Features of this release Bugs fixed in this release - * 729426 : Should respond " 551 Option not supported " in case a Require header is received - * 729776 : Set client port from URL - * 729900 : rtsp-client: wrong marshalling in send-message signal - * 730109 : media: Make suspend()/unsuspend() virtual - * 730228 : stream: add signals for new RTP/RTCP encoders + * 728264 : No timeout in header when timeout is 60s + * 730472 : mikey: add different key length parameters + * 731569 : Server does not free all resources if session timeout + * 731577 : new unit test for gst/stream ==== Download ==== @@ -77,8 +68,8 @@ Applications Contributors to this release * Aleix Conchillo Flaqué + * Göran Jönsson * Ognyan Tonchev * Sebastian Dröge - * Tim-Philipp Müller * Wim Taymans   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 1b053e7c76..49687d263e 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.3.2.1], +AC_INIT([GStreamer RTSP Server Library], [1.3.3], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 302, 0, 302) +AS_LIBTOOL(GST, 303, 0, 303) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.3.2.1 -GSTPB_REQ=1.3.2.1 -GSTPG_REQ=1.3.2.1 -GSTPD_REQ=1.3.2.1 +GST_REQ=1.3.3 +GSTPB_REQ=1.3.3 +GSTPG_REQ=1.3.3 +GSTPD_REQ=1.3.3 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 2201ab2631..28fb7259c4 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.3.3 + 1.3 + + 2014-06-22 + + + + 1.3.2 From bf9a3efb5905bbea4199b48f929dfa4e38b393f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 22 Jun 2014 19:37:31 +0200 Subject: [PATCH 0986/1776] Back to development --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 49687d263e..103c3f2bb8 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.3.3], +AC_INIT([GStreamer RTSP Server Library], [1.3.3.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 303, 0, 303) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.3.3 -GSTPB_REQ=1.3.3 -GSTPG_REQ=1.3.3 -GSTPD_REQ=1.3.3 +GST_REQ=1.3.3.1 +GSTPB_REQ=1.3.3.1 +GSTPG_REQ=1.3.3.1 +GSTPD_REQ=1.3.3.1 dnl *** autotools stuff **** From d676c568886b93ac53ddd4d557230735adfb0fee Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 24 Jun 2014 09:34:50 +0200 Subject: [PATCH 0987/1776] sdp: hide key length defines They don't have a namespace. --- gst/rtsp-server/rtsp-client.c | 6 ++++++ gst/rtsp-server/rtsp-sdp.c | 6 ++++++ gst/rtsp-server/rtsp-sdp.h | 6 ------ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3cbe67e8d9..8aec8fe6b1 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1500,6 +1500,12 @@ make_server_transport (GstRTSPClient * client, GstRTSPContext * ctx, return st; } +#define AES_128_KEY_LEN 16 +#define AES_256_KEY_LEN 32 + +#define HMAC_32_KEY_LEN 4 +#define HMAC_80_KEY_LEN 10 + static gboolean mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy) { diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index c4e74a382b..5734278231 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -30,6 +30,12 @@ #include "rtsp-sdp.h" +#define AES_128_KEY_LEN 16 +#define AES_256_KEY_LEN 32 + +#define HMAC_32_KEY_LEN 4 +#define HMAC_80_KEY_LEN 10 + static gboolean get_info_from_tags (GstPad * pad, GstEvent ** event, gpointer user_data) { diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h index d0783a752f..7732f36d90 100644 --- a/gst/rtsp-server/rtsp-sdp.h +++ b/gst/rtsp-server/rtsp-sdp.h @@ -27,12 +27,6 @@ G_BEGIN_DECLS -#define AES_128_KEY_LEN 16 -#define AES_256_KEY_LEN 32 - -#define HMAC_32_KEY_LEN 4 -#define HMAC_80_KEY_LEN 10 - typedef struct { gboolean is_ipv6; const gchar *server_ip; From aa44c034397e50d9fb201058416beaaa80a30809 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 24 Jun 2014 09:42:47 +0200 Subject: [PATCH 0988/1776] context: add type macro --- gst/rtsp-server/rtsp-context.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-context.h b/gst/rtsp-server/rtsp-context.h index 2b31bdd909..c2be87edc5 100644 --- a/gst/rtsp-server/rtsp-context.h +++ b/gst/rtsp-server/rtsp-context.h @@ -25,6 +25,8 @@ G_BEGIN_DECLS +#define GST_TYPE_RTSP_CONTEXT (gst_rtsp_context_get_type ()) + typedef struct _GstRTSPContext GstRTSPContext; #include "rtsp-server.h" From 661f4d928f32455bc52664fcd05ed4e8ce94e5ba Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 24 Jun 2014 09:43:44 +0200 Subject: [PATCH 0989/1776] signals: use generic marshal function Use the generic C marshal function. Use more explicit type instead of G_TYPE_POINTER --- gst/rtsp-server/rtsp-client.c | 42 ++++++++++++++-------------- gst/rtsp-server/rtsp-media-factory.c | 4 +-- gst/rtsp-server/rtsp-media.c | 8 +++--- gst/rtsp-server/rtsp-server.c | 4 +-- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8aec8fe6b1..36137a6e24 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -188,71 +188,71 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_CLOSED] = g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE); gst_rtsp_client_signals[SIGNAL_NEW_SESSION] = g_signal_new ("new-session", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, new_session), NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION); + g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION); gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST] = g_signal_new ("options-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, options_request), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, + GST_TYPE_RTSP_CONTEXT); gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST] = g_signal_new ("describe-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, describe_request), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, + GST_TYPE_RTSP_CONTEXT); gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST] = g_signal_new ("setup-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, setup_request), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, + GST_TYPE_RTSP_CONTEXT); gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST] = g_signal_new ("play-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, play_request), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, + GST_TYPE_RTSP_CONTEXT); gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST] = g_signal_new ("pause-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, pause_request), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, + GST_TYPE_RTSP_CONTEXT); gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST] = g_signal_new ("teardown-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, teardown_request), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, + GST_TYPE_RTSP_CONTEXT); gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST] = g_signal_new ("set-parameter-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - set_parameter_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); + set_parameter_request), NULL, NULL, g_cclosure_marshal_generic, + G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST] = g_signal_new ("get-parameter-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - get_parameter_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); + get_parameter_request), NULL, NULL, g_cclosure_marshal_generic, + G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE] = g_signal_new ("handle-response", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - handle_response), NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); + handle_response), NULL, NULL, g_cclosure_marshal_generic, + G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE] = g_signal_new ("send-message", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, - G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); + G_TYPE_NONE, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_POINTER); tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index b78e44e7eb..7d85dccecd 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -182,13 +182,13 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, - media_constructed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, + media_constructed), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA); gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE] = g_signal_new ("media-configure", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, - media_configure), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, + media_configure), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA); klass->gen_key = default_gen_key; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index dbcf15fbcb..1d01b4ef77 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -288,22 +288,22 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) gst_rtsp_media_signals[SIGNAL_PREPARED] = g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE); gst_rtsp_media_signals[SIGNAL_UNPREPARED] = g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE); gst_rtsp_media_signals[SIGNAL_TARGET_STATE] = g_signal_new ("target-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, - NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT); gst_rtsp_media_signals[SIGNAL_NEW_STATE] = g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL, - g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT); GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 019e379e89..a5ea95a728 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -225,8 +225,8 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED] = g_signal_new ("client-connected", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPServerClass, client_connected), - NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, - gst_rtsp_client_get_type ()); + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, + GST_TYPE_RTSP_CLIENT); klass->create_client = default_create_client; From d08b46f4b7e778c5080ac90de6a7d381bcb0a83f Mon Sep 17 00:00:00 2001 From: Evan Nemerson Date: Tue, 24 Jun 2014 09:48:45 +0200 Subject: [PATCH 0990/1776] gi: improve annotations Fixes https://bugzilla.gnome.org/show_bug.cgi?id=730953 --- gst/rtsp-server/rtsp-client.c | 9 +++++++-- gst/rtsp-server/rtsp-stream.c | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 36137a6e24..65c6230212 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -249,6 +249,12 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) handle_response), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::send-message: + * @client: The RTSP client + * @session: (type GstRtspServer.RTSPSession): The session + * @message: (type GstRtsp.RTSPMessage): The message + */ gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE] = g_signal_new ("send-message", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, @@ -1721,8 +1727,7 @@ strip_chars (gchar * str) memmove (str, s, len + 1); } -/** - * KeyMgmt = "KeyMgmt" ":" key-mgmt-spec 0*("," key-mgmt-spec) +/* KeyMgmt = "KeyMgmt" ":" key-mgmt-spec 0*("," key-mgmt-spec) * key-mgmt-spec = "prot" "=" KMPID ";" ["uri" "=" %x22 URI %x22 ";"] */ static gboolean diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 7317553b37..074f226161 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2364,7 +2364,7 @@ gst_rtsp_stream_remove_transport (GstRTSPStream * stream, * gst_rtsp_stream_update_crypto: * @stream: a #GstRTSPStream * @ssrc: the SSRC - * @crypto: (transfer none) (allow none): a #GstCaps with crypto info + * @crypto: (transfer none) (allow-none): a #GstCaps with crypto info * * Update the new crypto information for @ssrc in @stream. If information * for @ssrc did not exist, it will be added. If information From 34e6ac3b9f52f74edb2d661b48fd5a2a8751b5be Mon Sep 17 00:00:00 2001 From: Evan Nemerson Date: Wed, 11 Jun 2014 16:38:36 -0700 Subject: [PATCH 0991/1776] introspection: add (nullable) annotations to return values https://bugzilla.gnome.org/show_bug.cgi?id=730952 --- gst/rtsp-server/rtsp-address-pool.c | 5 +++-- gst/rtsp-server/rtsp-media.c | 9 +++++---- gst/rtsp-server/rtsp-session-media.c | 4 ++-- gst/rtsp-server/rtsp-session-pool.c | 4 ++-- gst/rtsp-server/rtsp-stream-transport.c | 5 +++-- gst/rtsp-server/rtsp-stream.c | 17 +++++++++-------- gst/rtsp-server/rtsp-token.c | 6 +++--- 7 files changed, 27 insertions(+), 23 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 92f4c42453..1343839f3a 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -423,8 +423,9 @@ split_range (GstRTSPAddressPool * pool, AddrRange * range, guint skip_addr, * allocation. @n_ports consecutive ports will be allocated of which the first * one can be found in @port. * - * Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free - * after use or %NULL when no address could be acquired. + * Returns: (nullable): a #GstRTSPAddress that should be freed with + * gst_rtsp_address_free after use or %NULL when no address could be + * acquired. */ GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1d01b4ef77..c76fece8e2 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1323,8 +1323,8 @@ gst_rtsp_media_n_streams (GstRTSPMedia * media) * * Retrieve the stream with index @idx from @media. * - * Returns: (transfer none): the #GstRTSPStream at index @idx or %NULL when a stream with - * that index did not exist. + * Returns: (nullable) (transfer none): the #GstRTSPStream at index + * @idx or %NULL when a stream with that index did not exist. */ GstRTSPStream * gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) @@ -1353,8 +1353,9 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx) * * Find a stream in @media with @control as the control uri. * - * Returns: (transfer none): the #GstRTSPStream with control uri @control - * or %NULL when a stream with that control did not exist. + * Returns: (nullable) (transfer none): the #GstRTSPStream with + * control uri @control or %NULL when a stream with that control did + * not exist. */ GstRTSPStream * gst_rtsp_media_find_stream (GstRTSPMedia * media, const gchar * control) diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 79004f0f39..8eb1f2879f 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -239,8 +239,8 @@ gst_rtsp_session_media_get_base_time (GstRTSPSessionMedia * media) * Retrieve the RTP-Info header string for all streams in @media * with configured transports. * - * Returns: (transfer full): The RTP-Info as a string or %NULL when - * no RTP-Info could be generated, g_free() after usage. + * Returns: (transfer full) (nullable): The RTP-Info as a string or + * %NULL when no RTP-Info could be generated, g_free() after usage. */ gchar * gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 5111eaa82e..62e7a56f80 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -266,8 +266,8 @@ gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool * pool) * Find the session with @sessionid in @pool. The access time of the session * will be updated with gst_rtsp_session_touch(). * - * Returns: (transfer full): the #GstRTSPSession with @sessionid or %NULL when the session did - * not exist. g_object_unref() after usage. + * Returns: (transfer full) (nullable): the #GstRTSPSession with @sessionid + * or %NULL when the session did not exist. g_object_unref() after usage. */ GstRTSPSession * gst_rtsp_session_pool_find (GstRTSPSessionPool * pool, const gchar * sessionid) diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index cd16626434..a99295bb35 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -317,8 +317,9 @@ gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport * trans) * * Get the RTP-Info string for @trans and @start_time. * - * Returns: (transfer full): the RTPInfo string for @trans and @start_time or - * %NULL when the RTP-Info could not be determined. g_free() after usage. + * Returns: (transfer full) (nullable): the RTPInfo string for @trans + * and @start_time or %NULL when the RTP-Info could not be + * determined. g_free() after usage. */ gchar * gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport * trans, diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 074f226161..7f12e138cb 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -804,8 +804,9 @@ gst_rtsp_stream_get_address_pool (GstRTSPStream * stream) * * Get the multicast address of @stream for @family. * - * Returns: (transfer full): the #GstRTSPAddress of @stream or %NULL when no - * address could be allocated. gst_rtsp_address_free() after usage. + * Returns: (transfer full) (nullable): the #GstRTSPAddress of @stream + * or %NULL when no address could be allocated. gst_rtsp_address_free() + * after usage. */ GstRTSPAddress * gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, @@ -869,8 +870,8 @@ no_address: * * Reserve @address and @port as the address and port of @stream. * - * Returns: the #GstRTSPAddress of @stream or %NULL when the address could be - * reserved. gst_rtsp_address_free() after usage. + * Returns: (nullable): the #GstRTSPAddress of @stream or %NULL when + * the address could be reserved. gst_rtsp_address_free() after usage. */ GstRTSPAddress * gst_rtsp_stream_reserve_address (GstRTSPStream * stream, @@ -2406,8 +2407,8 @@ gst_rtsp_stream_update_crypto (GstRTSPStream * stream, * * @stream must be joined to a bin. * - * Returns: (transfer full): the RTP socket or %NULL if no socket could be - * allocated for @family. Unref after usage + * Returns: (transfer full) (nullable): the RTP socket or %NULL if no + * socket could be allocated for @family. Unref after usage */ GSocket * gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family) @@ -2440,8 +2441,8 @@ gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family) * * @stream must be joined to a bin. * - * Returns: (transfer full): the RTCP socket or %NULL if no socket could be - * allocated for @family. Unref after usage + * Returns: (transfer full) (nullable): the RTCP socket or %NULL if no + * socket could be allocated for @family. Unref after usage */ GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index da9e8d9777..69250f9adc 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -216,9 +216,9 @@ gst_rtsp_token_writable_structure (GstRTSPToken * token) * * Get the string value of @field in @token. * - * Returns: (transfer none): the string value of @field in @token or %NULL when - * @field is not defined in @token. The string becomes invalid when you free - * @token. + * Returns: (transfer none) (nullable): the string value of @field in + * @token or %NULL when @field is not defined in @token. The string + * becomes invalid when you free @token. */ const gchar * gst_rtsp_token_get_string (GstRTSPToken * token, const gchar * field) From cecc2cb4ff0b66270da77ad1511f26591ec8947f Mon Sep 17 00:00:00 2001 From: Evan Nemerson Date: Wed, 11 Jun 2014 16:42:08 -0700 Subject: [PATCH 0992/1776] introspection: add missing allow-none annotations https://bugzilla.gnome.org/show_bug.cgi?id=730952 --- gst/rtsp-server/rtsp-client.c | 3 ++- gst/rtsp-server/rtsp-media.c | 5 +++-- gst/rtsp-server/rtsp-mount-points.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 65c6230212..78c352c2fc 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -3015,7 +3015,8 @@ gst_rtsp_client_handle_message (GstRTSPClient * client, /** * gst_rtsp_client_send_message: * @client: a #GstRTSPClient - * @session: (transfer none): a #GstRTSPSession to send the message to or %NULL + * @session: (allow-none) (transfer none): a #GstRTSPSession to send + * the message to or %NULL * @message: (transfer none): The #GstRTSPMessage to send * * Send a message message to the remote end. @message must be a diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c76fece8e2..cc35372c6c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2217,7 +2217,8 @@ no_rtpbin: /** * gst_rtsp_media_prepare: * @media: a #GstRTSPMedia - * @thread: (transfer full): a #GstRTSPThread to run the bus handler or %NULL + * @thread: (transfer full) (allow-none): a #GstRTSPThread to run the + * bus handler or %NULL * * Prepare @media for streaming. This function will create the objects * to manage the streaming. A pipeline must have been set on @media with @@ -2572,7 +2573,7 @@ not_prepared: /** * gst_rtsp_media_get_time_provider: * @media: a #GstRTSPMedia - * @address: an address or %NULL + * @address: (allow-none): an address or %NULL * @port: a port or 0 * * Get the #GstNetTimeProvider for the clock used by @media. The time provider diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 75c872b1ec..c6a8c06dce 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -221,7 +221,7 @@ has_prefix (DataItem * str, DataItem * prefix) * gst_rtsp_mount_points_match: * @mounts: a #GstRTSPMountPoints * @path: a mount point - * @matched: (out): the amount of @path matched + * @matched: (out) (allow-none): the amount of @path matched * * Find the factory in @mounts that has the longest match with @path. * From db95746f6b29432cf4fbe8b88ea0fb2dbb03fe73 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 27 Jun 2014 16:54:22 +0200 Subject: [PATCH 0993/1776] stream: crypto can be NULL --- gst/rtsp-server/rtsp-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 7f12e138cb..02c8274260 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2381,7 +2381,7 @@ gst_rtsp_stream_update_crypto (GstRTSPStream * stream, GstRTSPStreamPrivate *priv; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); - g_return_val_if_fail (GST_IS_CAPS (crypto), FALSE); + g_return_val_if_fail (crypto == NULL || GST_IS_CAPS (crypto), FALSE); priv = stream->priv; From b6f4dd4c28a5d32feaef67a74029bb13579a76b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 28 Jun 2014 11:48:29 +0200 Subject: [PATCH 0994/1776] Release 1.3.90 --- ChangeLog | 77 ++++++++++++++++++++++++++++++++++++++++++-- NEWS | 12 ++++--- RELEASE | 45 +++++++++++++------------- configure.ac | 12 +++---- gst-rtsp-server.doap | 10 ++++++ 5 files changed, 120 insertions(+), 36 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1777857505..2175c5562c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,80 @@ -=== release 1.3.3 === +=== release 1.3.90 === -2014-06-22 Sebastian Dröge +2014-06-28 Sebastian Dröge * configure.ac: - releasing 1.3.3 + releasing 1.3.90 + +2014-06-27 16:54:22 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream.c: + stream: crypto can be NULL + +2014-06-11 16:42:08 -0700 Evan Nemerson + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-mount-points.c: + introspection: add missing allow-none annotations + https://bugzilla.gnome.org/show_bug.cgi?id=730952 + +2014-06-11 16:38:36 -0700 Evan Nemerson + + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-token.c: + introspection: add (nullable) annotations to return values + https://bugzilla.gnome.org/show_bug.cgi?id=730952 + +2014-06-24 09:48:45 +0200 Evan Nemerson + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + gi: improve annotations + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=730953 + +2014-06-24 09:43:44 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-server.c: + signals: use generic marshal function + Use the generic C marshal function. + Use more explicit type instead of G_TYPE_POINTER + +2014-06-24 09:42:47 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-context.h: + context: add type macro + +2014-06-24 09:34:50 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-sdp.h: + sdp: hide key length defines + They don't have a namespace. + +2014-06-22 19:37:31 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.3.3 === + +2014-06-22 19:36:14 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.3.3 2014-05-20 14:48:37 -0700 Aleix Conchillo Flaqué diff --git a/NEWS b/NEWS index be406eea79..a89efb608d 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -This is GStreamer RTSP Server 1.3.3 +This is GStreamer RTSP Server 1.3.90 Changes since 1.2: @@ -129,7 +129,7 @@ Major changes: with downstream via caps. ∘ Lots of fixes for coverity warnings all over the place. ∘ Negotiation related performance improvements. - ∘ 500+ fixed bug reports, and many other bug fixes and other + ∘ 800+ fixed bug reports, and many other bug fixes and other improvements everywhere that had no bug report. Things to look out for: @@ -137,5 +137,9 @@ Things to look out for: element. • The mfcdec element was removed and replaced by v4l2videodec. • osxvideosink is only available in OS X 10.6 or newer. - • The GstDeviceMonitor API will likely change slightly before the - 1.4.0 release. + • On Android the namespace of the automatically generated Java class + for initialization of GStreamer has changed from com.gstreamer to + org.freedesktop.gstreamer to prevent namespace pollution. + • On iOS you have to update your gst_ios_init.h and gst_ios_init.m in + your projects from the one included in the binaries if you used the + GnuTLS GIO module before. The loading mechanism has slightly changed. diff --git a/RELEASE b/RELEASE index 341e1e8805..32be8ce299 100644 --- a/RELEASE +++ b/RELEASE @@ -1,34 +1,35 @@ -Release notes for GStreamer RTSP Server Library 1.3.3 - -The GStreamer team is pleased to announce the third release of the unstable -1.3 release series. The 1.3 release series is adding new features on top of -the 1.0 and 1.2 series and is part of the API and ABI-stable 1.x release -series of the GStreamer multimedia framework. The unstable 1.3 release series -will lead to the stable 1.4 release series in the next weeks, and newly added -API can still change until that point. +Release notes for GStreamer RTSP Server Library 1.3.90 -This is hopefully the last 1.3 development release and will be followed by -the first 1.4.0 release candidate (1.3.90) in 1-2 weeks. Which then hopefully -is followed by 1.4.0 soonish in early July. +The GStreamer team is pleased to announce the first release candidate of +the stable 1.4 release series. The 1.4 release series is adding new features +on top of the 1.0 and 1.2 series and is part of the API and ABI-stable 1.x +release series of the GStreamer multimedia framework. -Binaries for Android, iOS, Mac OS X and Windows will be provided separately -during the unstable 1.3 release series. +This release candidate will hopefully shortly be followed by the stable 1.4.0 +release if no bigger regressions or bigger issues are detected, and enough +testing of the release candidate happened. The new API that was added during +the 1.3 release series is not expected to change anymore at this point. + + +Binaries for Android, iOS, Mac OS X and Windows are provided together with this +release. + + +The stable 1.4 release series is API and ABI compatible with 1.0.x, 1.2.x and +any other 1.x release series in the future. Compared to 1.2.x it contains some +new features and more intrusive changes that were considered too risky as a +bugfix. -Features of this release - - Bugs fixed in this release - * 728264 : No timeout in header when timeout is 60s - * 730472 : mikey: add different key length parameters - * 731569 : Server does not free all resources if session timeout - * 731577 : new unit test for gst/stream + * 730952 : Missing nullability annotations + * 730953 : Missing documentation (and annotations) for GstRTSPServer ==== Download ==== @@ -67,9 +68,7 @@ Applications Contributors to this release - * Aleix Conchillo Flaqué - * Göran Jönsson - * Ognyan Tonchev + * Evan Nemerson * Sebastian Dröge * Wim Taymans   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 103c3f2bb8..e9b182cb13 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.3.3.1], +AC_INIT([GStreamer RTSP Server Library], [1.3.90], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 303, 0, 303) +AS_LIBTOOL(GST, 390, 0, 390) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.3.3.1 -GSTPB_REQ=1.3.3.1 -GSTPG_REQ=1.3.3.1 -GSTPD_REQ=1.3.3.1 +GST_REQ=1.3.90 +GSTPB_REQ=1.3.90 +GSTPG_REQ=1.3.90 +GSTPD_REQ=1.3.90 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 28fb7259c4..c289dc1667 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.3.90 + 1.3 + + 2014-06-28 + + + + 1.3.3 From 41d1ef7ed3df2471bea4894b6106020a74084f19 Mon Sep 17 00:00:00 2001 From: Evan Nemerson Date: Mon, 30 Jun 2014 00:37:59 -0700 Subject: [PATCH 0995/1776] Make rtsp-server.h a single-include header, use it for G-I https://bugzilla.gnome.org/show_bug.cgi?id=732411 --- gst/rtsp-server/Makefile.am | 3 +-- gst/rtsp-server/rtsp-server.h | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index bbae027de5..4fcd366929 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -68,7 +68,6 @@ BUILT_GIRSOURCES = GstRtspServer-@GST_API_VERSION@.gir gir_headers=$(patsubst %,$(srcdir)/%, $(libgstrtspserver_@GST_API_VERSION@include_HEADERS)) gir_sources=$(patsubst %,$(srcdir)/%, $(libgstrtspserver_@GST_API_VERSION@_la_SOURCES)) -gir_cincludes=$(patsubst %,--c-include='gst/rtsp-server/%',$(libgstrtspinclude_HEADERS)) GstRtspServer-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@GST_API_VERSION@.la $(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \ @@ -79,7 +78,7 @@ GstRtspServer-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@ -I$(top_srcdir) \ -I$(top_builddir) \ -DIN_GOBJECT_INTROSPECTION=1 \ - --c-include='gst/gst.h' \ + --c-include='gst/rtsp-server/rtsp-server.h' \ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_API_VERSION@` \ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_API_VERSION@` \ diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index afe145aa76..9a6f9d4a1f 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -29,9 +29,24 @@ typedef struct _GstRTSPServerClass GstRTSPServerClass; typedef struct _GstRTSPServerPrivate GstRTSPServerPrivate; #include "rtsp-session-pool.h" -#include "rtsp-mount-points.h" +#include "rtsp-session.h" +#include "rtsp-media.h" +#include "rtsp-stream.h" +#include "rtsp-stream-transport.h" +#include "rtsp-address-pool.h" +#include "rtsp-thread-pool.h" #include "rtsp-client.h" +#include "rtsp-context.h" +#include "rtsp-server.h" +#include "rtsp-mount-points.h" +#include "rtsp-media-factory.h" +#include "rtsp-permissions.h" #include "rtsp-auth.h" +#include "rtsp-token.h" +#include "rtsp-session-media.h" +#include "rtsp-sdp.h" +#include "rtsp-media-factory-uri.h" +#include "rtsp-params.h" #define GST_TYPE_RTSP_SERVER (gst_rtsp_server_get_type ()) #define GST_IS_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SERVER)) From 964ca3c98842c5dd7d640b81bc018c0a6687c4ef Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 30 Jun 2014 15:14:34 +0200 Subject: [PATCH 0996/1776] session-pool: add session-removed signal Add a signal to be notified when a session is removed from the pool. --- gst/rtsp-server/rtsp-session-pool.c | 62 +++++++++++++++++++++++++---- gst/rtsp-server/rtsp-session-pool.h | 7 +++- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 62e7a56f80..a7aa5b2510 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -69,6 +69,14 @@ static const gchar session_id_charset[] = '8', '9', '$', '-', '_', '.', '+' }; +enum +{ + SIGNAL_SESSION_REMOVED, + SIGNAL_LAST +}; + +static guint gst_rtsp_session_pool_signals[SIGNAL_LAST] = { 0 }; + GST_DEBUG_CATEGORY_STATIC (rtsp_session_debug); #define GST_CAT_DEFAULT rtsp_session_debug @@ -103,6 +111,12 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) 0, G_MAXUINT, DEFAULT_MAX_SESSIONS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED] = + g_signal_new ("session-removed", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPSessionPoolClass, + session_removed), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, + 1, GST_TYPE_RTSP_SESSION); + klass->create_session_id = create_session_id; klass->create_session = create_session; @@ -123,14 +137,22 @@ gst_rtsp_session_pool_init (GstRTSPSessionPool * pool) priv->max_sessions = DEFAULT_MAX_SESSIONS; } +static GstRTSPFilterResult +remove_sessions_func (GstRTSPSessionPool * pool, GstRTSPSession * session, + gpointer user_data) +{ + return GST_RTSP_FILTER_REMOVE; +} + static void gst_rtsp_session_pool_finalize (GObject * object) { GstRTSPSessionPool *pool = GST_RTSP_SESSION_POOL (object); GstRTSPSessionPoolPrivate *priv = pool->priv; - g_mutex_clear (&priv->lock); + gst_rtsp_session_pool_filter (pool, remove_sessions_func, NULL); g_hash_table_unref (priv->sessions); + g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_session_pool_parent_class)->finalize (object); } @@ -428,18 +450,38 @@ gst_rtsp_session_pool_remove (GstRTSPSessionPool * pool, GstRTSPSession * sess) priv = pool->priv; g_mutex_lock (&priv->lock); + g_object_ref (sess); found = g_hash_table_remove (priv->sessions, gst_rtsp_session_get_sessionid (sess)); + if (found) { + g_signal_emit (pool, gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED], + 0, sess); + } + g_object_unref (sess); g_mutex_unlock (&priv->lock); return found; } -static gboolean -cleanup_func (gchar * sessionid, GstRTSPSession * sess, GTimeVal * now) +typedef struct { - return gst_rtsp_session_is_expired (sess, now); + GTimeVal now; + GstRTSPSessionPool *pool; +} CleanupData; + +static gboolean +cleanup_func (gchar * sessionid, GstRTSPSession * sess, CleanupData * data) +{ + gboolean expired; + + expired = gst_rtsp_session_is_expired (sess, &data->now); + if (expired) { + GST_DEBUG ("session expired, emitting signal"); + g_signal_emit (data->pool, + gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED], 0, sess); + } + return expired; } /** @@ -456,18 +498,19 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool) { GstRTSPSessionPoolPrivate *priv; guint result; - GTimeVal now; + CleanupData data; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0); priv = pool->priv; - g_get_current_time (&now); + g_get_current_time (&data.now); + data.pool = pool; g_mutex_lock (&priv->lock); result = g_hash_table_foreach_remove (priv->sessions, (GHRFunc) cleanup_func, - &now); + &data); g_mutex_unlock (&priv->lock); return result; @@ -493,6 +536,8 @@ filter_func (gchar * sessionid, GstRTSPSession * sess, FilterData * data) switch (res) { case GST_RTSP_FILTER_REMOVE: + g_signal_emit (data->pool, + gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED], 0, sess); return TRUE; case GST_RTSP_FILTER_REF: /* keep ref */ @@ -514,7 +559,8 @@ filter_func (gchar * sessionid, GstRTSPSession * sess, FilterData * data) * what happens to the session. @func will be called with the session pool * locked so no further actions on @pool can be performed from @func. * - * If @func returns #GST_RTSP_FILTER_REMOVE, the session will be removed from + * If @func returns #GST_RTSP_FILTER_REMOVE, the session will be set to the + * expired state with gst_rtsp_session_set_expired() and removed from * @pool. * * If @func returns #GST_RTSP_FILTER_KEEP, the session will remain in @pool. diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 3b0c12d5d9..e2ba951e8f 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -58,6 +58,7 @@ struct _GstRTSPSessionPool { * @create_session_id: create a new random session id. Subclasses can create * custom session ids and should not check if the session exists. * @create_session: make a new session object. + * @session_removed: a session was removed from the pool */ struct _GstRTSPSessionPoolClass { GObjectClass parent_class; @@ -65,8 +66,12 @@ struct _GstRTSPSessionPoolClass { gchar * (*create_session_id) (GstRTSPSessionPool *pool); GstRTSPSession * (*create_session) (GstRTSPSessionPool *pool, const gchar *id); + /* signals */ + void (*session_removed) (GstRTSPSessionPool *pool, + GstRTSPSession *session); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE]; + gpointer _gst_reserved[GST_PADDING_LARGE - 1]; }; /** From fe081e73015dc269d585f4be3efbc0d93ead128b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 1 Jul 2014 12:13:47 +0200 Subject: [PATCH 0997/1776] Client: keep a ref to the session Don't just keep a weak ref to the session objects but use a hard ref. We will be notified when a session is removed from the pool (expired) with the new session-removed signal. Don't automatically close the RTSP connection when all the sessions of a client are removed, a client can continue to operate and it can create a new session if it wants. If you want to remove the client from the server, you have to use gst_rtsp_server_client_filter() now. Based on patch from Ognyan Tonchev See https://bugzilla.gnome.org/show_bug.cgi?id=732226 --- gst/rtsp-server/rtsp-client.c | 146 +++++++++++++++------------------- 1 file changed, 65 insertions(+), 81 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 78c352c2fc..0c0685c032 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -71,6 +71,7 @@ struct _GstRTSPClientPrivate GDestroyNotify send_notify; /* protected by send_lock */ GstRTSPSessionPool *session_pool; + gulong session_removed_id; GstRTSPMountPoints *mount_points; GstRTSPAuth *auth; GstRTSPThreadPool *thread_pool; @@ -131,8 +132,6 @@ static void gst_rtsp_client_set_property (GObject * object, guint propid, static void gst_rtsp_client_finalize (GObject * obj); static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media); -static void client_session_finalized (GstRTSPClient * client, - GstRTSPSession * session); static void unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, GstRTSPSessionMedia * sessmedia); static gboolean default_configure_client_media (GstRTSPClient * client, @@ -281,7 +280,7 @@ gst_rtsp_client_init (GstRTSPClient * client) } static GstRTSPFilterResult -filter_session (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia, +filter_session_media (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); @@ -293,66 +292,46 @@ filter_session (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia, return GST_RTSP_FILTER_REMOVE; } -static void -client_unlink_session (GstRTSPClient * client, GstRTSPSession * session) -{ - /* unlink all media managed in this session */ - gst_rtsp_session_filter (session, filter_session, client); -} - static void client_watch_session (GstRTSPClient * client, GstRTSPSession * session) { GstRTSPClientPrivate *priv = client->priv; - GList *walk; - for (walk = priv->sessions; walk; walk = g_list_next (walk)) { - GstRTSPSession *msession = (GstRTSPSession *) walk->data; + /* we already know about this session */ + if (g_list_find (priv->sessions, session) != NULL) + return; - /* we already know about this session */ - if (msession == session) + GST_INFO ("watching session %p", session); + priv->sessions = g_list_prepend (priv->sessions, g_object_ref (session)); +} + +static void +client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session, + GList * link) +{ + GstRTSPClientPrivate *priv = client->priv; + + GST_INFO ("client %p: unwatch session %p", client, session); + + if (link == NULL) { + link = g_list_find (priv->sessions, session); + if (link == NULL) return; } - GST_INFO ("watching session %p", session); + /* unlink all media managed in this session */ + gst_rtsp_session_filter (session, filter_session_media, client); - g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, - client); - priv->sessions = g_list_prepend (priv->sessions, session); + /* remove the session */ + priv->sessions = g_list_delete_link (priv->sessions, link); + g_object_unref (session); } -static void -client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session) +static GstRTSPFilterResult +cleanup_session (GstRTSPClient * client, GstRTSPSession * sess, + gpointer user_data) { - GstRTSPClientPrivate *priv = client->priv; - - GST_INFO ("unwatching session %p", session); - - g_object_weak_unref (G_OBJECT (session), - (GWeakNotify) client_session_finalized, client); - priv->sessions = g_list_remove (priv->sessions, session); -} - -static void -client_cleanup_session (GstRTSPClient * client, GstRTSPSession * session) -{ - g_object_weak_unref (G_OBJECT (session), - (GWeakNotify) client_session_finalized, client); - client_unlink_session (client, session); -} - -static void -client_cleanup_sessions (GstRTSPClient * client) -{ - GstRTSPClientPrivate *priv = client->priv; - GList *sessions; - - /* remove weak-ref from sessions */ - for (sessions = priv->sessions; sessions; sessions = g_list_next (sessions)) { - client_cleanup_session (client, (GstRTSPSession *) sessions->data); - } - g_list_free (priv->sessions); - priv->sessions = NULL; + return GST_RTSP_FILTER_REMOVE; } /* A client is finalized when the connection is broken */ @@ -374,12 +353,14 @@ gst_rtsp_client_finalize (GObject * obj) if (priv->watch_context) g_main_context_unref (priv->watch_context); - client_cleanup_sessions (client); + gst_rtsp_client_session_filter (client, cleanup_session, NULL); if (priv->connection) gst_rtsp_connection_free (priv->connection); - if (priv->session_pool) + if (priv->session_pool) { + g_signal_handler_disconnect (priv->session_pool, priv->session_removed_id); g_object_unref (priv->session_pool); + } if (priv->mount_points) g_object_unref (priv->mount_points); if (priv->auth) @@ -797,15 +778,16 @@ close_connection (GstRTSPClient * client) GST_DEBUG ("client %p: closing connection", client); - if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) { - g_mutex_lock (&tunnels_lock); - /* remove from tunnelids */ - g_hash_table_remove (tunnels, tunnelid); - g_mutex_unlock (&tunnels_lock); + if (priv->connection) { + if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) { + g_mutex_lock (&tunnels_lock); + /* remove from tunnelids */ + g_hash_table_remove (tunnels, tunnelid); + g_mutex_unlock (&tunnels_lock); + } + gst_rtsp_connection_close (priv->connection); } - gst_rtsp_connection_close (priv->connection); - /* connection is now closed, destroy the watch which will also cause the * closed signal to be emitted */ if (priv->watch) { @@ -839,6 +821,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPStatusCode code; gchar *path; gint matched; + gboolean keep_session; if (!ctx->session) goto no_session; @@ -875,9 +858,6 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) /* unlink the all TCP callbacks */ unlink_session_transports (client, session, sessmedia); - /* remove the session from the watched sessions */ - client_unwatch_session (client, session); - gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL); /* allow messages again so that we can send the reply */ @@ -885,10 +865,8 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) /* unmanage the media in the session, returns false if all media session * are torn down. */ - if (!gst_rtsp_session_release_media (session, sessmedia)) { - /* remove the session */ - gst_rtsp_session_pool_remove (priv->session_pool, session); - } + keep_session = gst_rtsp_session_release_media (session, sessmedia); + /* construct the response now */ code = GST_RTSP_STS_OK; gst_rtsp_message_init_response (ctx->response, code, @@ -896,6 +874,11 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) send_message (client, ctx, ctx->response, TRUE); + if (!keep_session) { + /* remove the session */ + gst_rtsp_session_pool_remove (priv->session_pool, session); + } + return TRUE; /* ERRORS */ @@ -2247,22 +2230,13 @@ sanitize_uri (GstRTSPUrl * uri) *d = '\0'; } +/* is called when the session is removed from its session pool. */ static void -client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) +client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session, + GstRTSPClient * client) { - GstRTSPClientPrivate *priv = client->priv; - - GST_INFO ("client %p: session %p finished", client, session); - - /* unlink all media managed in this session */ - client_unlink_session (client, session); - - /* remove the session */ - if (!(priv->sessions = g_list_remove (priv->sessions, session))) { - GST_INFO ("client %p: all sessions finalized, close the connection", - client); - close_connection (client); - } + GST_INFO ("client %p: session %p removed", client, session); + client_unwatch_session (client, session, NULL); } /* Returns TRUE if there are no Require headers, otherwise returns FALSE @@ -2656,8 +2630,17 @@ gst_rtsp_client_set_session_pool (GstRTSPClient * client, g_mutex_lock (&priv->lock); old = priv->session_pool; priv->session_pool = pool; + + if (priv->session_removed_id) + g_signal_handler_disconnect (old, priv->session_removed_id); + if (pool) + priv->session_removed_id = g_signal_connect (pool, "session-removed", + G_CALLBACK (client_session_removed), client); + else + priv->session_removed_id = 0; g_mutex_unlock (&priv->lock); + /* FIXME, should remove all sessions from the old pool for this client */ if (old) g_object_unref (old); } @@ -3112,6 +3095,7 @@ message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) GstRTSPClientPrivate *priv = client->priv; if (priv->close_seq && priv->close_seq == cseq) { + GST_INFO ("client %p: send close message", client); priv->close_seq = 0; close_connection (client); } @@ -3459,7 +3443,7 @@ gst_rtsp_client_session_filter (GstRTSPClient * client, switch (res) { case GST_RTSP_FILTER_REMOVE: /* stop watching the session and pretent it went away */ - client_cleanup_session (client, sess); + client_unwatch_session (client, sess, walk); break; case GST_RTSP_FILTER_REF: result = g_list_prepend (result, g_object_ref (sess)); From 5e2afcefdda5066641c01d243444c4f670054de0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 1 Jul 2014 14:41:14 +0200 Subject: [PATCH 0998/1776] client: protect sessions with lock Protect the list of sessions with the lock. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=732226 --- gst/rtsp-server/rtsp-client.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 0c0685c032..e442209bed 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -297,14 +297,18 @@ client_watch_session (GstRTSPClient * client, GstRTSPSession * session) { GstRTSPClientPrivate *priv = client->priv; - /* we already know about this session */ - if (g_list_find (priv->sessions, session) != NULL) - return; + g_mutex_lock (&priv->lock); + /* check if we already know about this session */ + if (g_list_find (priv->sessions, session) = NULL) { + GST_INFO ("watching session %p", session); + priv->sessions = g_list_prepend (priv->sessions, g_object_ref (session)); + } + g_mutex_unlock (&priv->lock); - GST_INFO ("watching session %p", session); - priv->sessions = g_list_prepend (priv->sessions, g_object_ref (session)); + return; } +/* should be called with lock */ static void client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session, GList * link) @@ -318,12 +322,12 @@ client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session, if (link == NULL) return; } + priv->sessions = g_list_delete_link (priv->sessions, link); /* unlink all media managed in this session */ gst_rtsp_session_filter (session, filter_session_media, client); /* remove the session */ - priv->sessions = g_list_delete_link (priv->sessions, link); g_object_unref (session); } @@ -2235,8 +2239,13 @@ static void client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session, GstRTSPClient * client) { + GstRTSPClientPrivate *priv = client->priv; + GST_INFO ("client %p: session %p removed", client, session); + + g_mutex_lock (&priv->lock); client_unwatch_session (client, session, NULL); + g_mutex_unlock (&priv->lock); } /* Returns TRUE if there are no Require headers, otherwise returns FALSE From 517bb78ae31551c79017915bcff6471c28b57ddf Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 1 Jul 2014 15:02:15 +0200 Subject: [PATCH 0999/1776] client: fix build --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e442209bed..57865f2c5c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -299,7 +299,7 @@ client_watch_session (GstRTSPClient * client, GstRTSPSession * session) g_mutex_lock (&priv->lock); /* check if we already know about this session */ - if (g_list_find (priv->sessions, session) = NULL) { + if (g_list_find (priv->sessions, session) == NULL) { GST_INFO ("watching session %p", session); priv->sessions = g_list_prepend (priv->sessions, g_object_ref (session)); } From 72a57e792f76ae2ade17849a9672014b3bf951fc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 1 Jul 2014 16:12:13 +0200 Subject: [PATCH 1000/1776] client: free watch context only once The watch context is freed when the source is destroyed. Avoids a CRITICAL when we try to unref the context twice. --- gst/rtsp-server/rtsp-client.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 57865f2c5c..c60ba0a4a1 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -3263,8 +3263,6 @@ handle_tunnel (GstRTSPClient * client) /* the old client owns the tunnel now, the new one will be freed */ g_source_destroy ((GSource *) priv->watch); priv->watch = NULL; - g_main_context_unref (priv->watch_context); - priv->watch_context = NULL; gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); } @@ -3393,7 +3391,7 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) * be superceeded by a cache object later */ gst_rtsp_watch_set_send_backlog (priv->watch, 0, 100); - GST_INFO ("attaching to context %p", context); + GST_INFO ("client %p: attaching to context %p", client, context); res = gst_rtsp_watch_attach (priv->watch, context); return res; From 99f670d8bcecc5286ceaeca8a3fb925d746b21ac Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 2 Jul 2014 16:04:53 +0200 Subject: [PATCH 1001/1776] rtsp: fix for MIKEY api change --- gst/rtsp-server/rtsp-client.c | 4 ++-- gst/rtsp-server/rtsp-sdp.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c60ba0a4a1..47c965712e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1659,7 +1659,7 @@ handle_mikey_data (GstRTSPClient * client, GstRTSPContext * ctx, gst_rtsp_stream_update_crypto (ctx->stream, map->ssrc, caps); gst_caps_unref (caps); } - gst_mikey_message_free (msg); + gst_mikey_message_unref (msg); return TRUE; @@ -1691,7 +1691,7 @@ unsupported_encryption: } cleanup_message: { - gst_mikey_message_free (msg); + gst_mikey_message_unref (msg); return FALSE; } } diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 5734278231..07aea903df 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -296,7 +296,7 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, /* now serialize this to bytes */ bytes = gst_mikey_message_to_bytes (msg, NULL, NULL); - gst_mikey_message_free (msg); + gst_mikey_message_unref (msg); /* and make it into base64 */ data = g_bytes_get_data (bytes, &size); base64 = g_base64_encode (data, size); From fc6fa3f16a9f98e477442dd2630602e6ddffe266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 3 Jul 2014 19:52:42 +0100 Subject: [PATCH 1002/1776] examples: print 'stream ready at url' for mp4 and ogg example --- examples/test-mp4.c | 1 + examples/test-ogg.c | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/test-mp4.c b/examples/test-mp4.c index b69c7cd295..52e082d862 100644 --- a/examples/test-mp4.c +++ b/examples/test-mp4.c @@ -69,6 +69,7 @@ main (int argc, char *argv[]) gst_rtsp_server_attach (server, NULL); /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); g_main_loop_run (loop); return 0; diff --git a/examples/test-ogg.c b/examples/test-ogg.c index 5e844ad779..f4d104cee3 100644 --- a/examples/test-ogg.c +++ b/examples/test-ogg.c @@ -69,6 +69,7 @@ main (int argc, char *argv[]) gst_rtsp_server_attach (server, NULL); /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); g_main_loop_run (loop); return 0; From 5aec4af1b96ef5bddfc02a015e9cec3488c89f4a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 8 Jul 2014 12:36:12 +0200 Subject: [PATCH 1003/1776] client: manage media in session as a last step Once we manage a media in a session, we can't unmanage it anymore without destroying it. Therefore, first check everything before we manage the media, otherwise if something is wrong we have no way to unmanage the media. If we created a new session and something went wrong, remove the session again. Fixes a leak in the unit test. --- gst/rtsp-server/rtsp-client.c | 28 ++++++++++++++++------------ gst/rtsp-server/rtsp-session.c | 2 ++ tests/check/gst/client.c | 6 +++--- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 47c965712e..46da780bcb 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1770,6 +1770,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPClientClass *klass; gchar *path, *control; gint matched; + gboolean new_session = FALSE; if (!ctx->uri) goto no_uri; @@ -1842,6 +1843,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) /* make sure this client is closed when the session is closed */ client_watch_session (client, session); + new_session = TRUE; /* signal new session */ g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0, session); @@ -1849,18 +1851,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->session = session; } - if (sessmedia == NULL) { - /* manage the media in our session now, if not done already */ - sessmedia = gst_rtsp_session_manage_media (session, path, media); - /* if we stil have no media, error */ - if (sessmedia == NULL) - goto sessmedia_unavailable; - } else { - g_object_unref (media); - } - - ctx->sessmedia = sessmedia; - if (!klass->configure_client_media (client, media, stream, ctx)) goto configure_media_failed_no_reply; @@ -1881,6 +1871,18 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) goto keymgmt_error; } + if (sessmedia == NULL) { + /* manage the media in our session now, if not done already */ + sessmedia = gst_rtsp_session_manage_media (session, path, media); + /* if we stil have no media, error */ + if (sessmedia == NULL) + goto sessmedia_unavailable; + } else { + g_object_unref (media); + } + + ctx->sessmedia = sessmedia; + /* set in the session media transport */ trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct); @@ -2014,6 +2016,8 @@ keymgmt_error: cleanup_transport: gst_rtsp_transport_free (ct); cleanup_session: + if (new_session) + gst_rtsp_session_pool_remove (priv->session_pool, session); g_object_unref (session); cleanup_path: g_free (path); diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 9beb8ab08e..3463b326f1 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -128,6 +128,8 @@ gst_rtsp_session_init (GstRTSPSession * session) session->priv = priv; + GST_INFO ("init session %p", session); + g_mutex_init (&priv->lock); priv->timeout = DEFAULT_TIMEOUT; g_get_current_time (&priv->create_time); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 896a6cc91a..6d8df97370 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -602,7 +602,7 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) session_pool = gst_rtsp_client_get_session_pool (client); fail_unless (session_pool != NULL); /* FIXME: There seems to be a leak of a session here ! */ - /* fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); */ + fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); g_object_unref (session_pool); @@ -623,7 +623,7 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) session_pool = gst_rtsp_client_get_session_pool (client); fail_unless (session_pool != NULL); /* FIXME: There seems to be a leak of a session here ! */ - /* fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); */ + fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); g_object_unref (session_pool); @@ -644,7 +644,7 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) session_pool = gst_rtsp_client_get_session_pool (client); fail_unless (session_pool != NULL); /* FIXME: There seems to be a leak of a session here ! */ - /* fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); */ + fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); g_object_unref (session_pool); From e0bc97e40cdf49de2911038c92275b6181113ba6 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 9 Jul 2014 15:01:31 +0200 Subject: [PATCH 1004/1776] client: keep ref to client for the session removed handler This extra ref will be dropped when all client sessions have been removed. A session is removed when a client sends teardown, closes its endpoint of the TCP connection or the sessions expires. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=732226 --- gst/rtsp-server/rtsp-client.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 46da780bcb..e94567cbee 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -144,6 +144,8 @@ static GstRTSPResult default_params_get (GstRTSPClient * client, GstRTSPContext * ctx); static gchar *default_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri); +static void client_session_removed (GstRTSPSessionPool * pool, + GstRTSPSession * session, GstRTSPClient * client); G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); @@ -301,7 +303,15 @@ client_watch_session (GstRTSPClient * client, GstRTSPSession * session) /* check if we already know about this session */ if (g_list_find (priv->sessions, session) == NULL) { GST_INFO ("watching session %p", session); + priv->sessions = g_list_prepend (priv->sessions, g_object_ref (session)); + + /* connect removed session handler, it will be disconnected when the last + * session gets removed */ + if (priv->session_removed_id == 0) + priv->session_removed_id = g_signal_connect_data (priv->session_pool, + "session-removed", G_CALLBACK (client_session_removed), + g_object_ref (client), (GClosureNotify) g_object_unref, 0); } g_mutex_unlock (&priv->lock); @@ -322,8 +332,17 @@ client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session, if (link == NULL) return; } + priv->sessions = g_list_delete_link (priv->sessions, link); + /* if this was the last session, disconnect the handler. + * This will also drop the extra client ref */ + if (!priv->sessions) { + g_signal_handler_disconnect (priv->session_pool, + priv->session_removed_id); + priv->session_removed_id = 0; + } + /* unlink all media managed in this session */ gst_rtsp_session_filter (session, filter_session_media, client); @@ -357,12 +376,15 @@ gst_rtsp_client_finalize (GObject * obj) if (priv->watch_context) g_main_context_unref (priv->watch_context); - gst_rtsp_client_session_filter (client, cleanup_session, NULL); + /* all sessions should have been removed by now. We keep a ref to + * the client object for the session removed handler. The ref is + * dropped when the last session is removed from the list. */ + g_assert (priv->sessions == NULL); + g_assert (priv->session_removed_id == 0); if (priv->connection) gst_rtsp_connection_free (priv->connection); if (priv->session_pool) { - g_signal_handler_disconnect (priv->session_pool, priv->session_removed_id); g_object_unref (priv->session_pool); } if (priv->mount_points) @@ -2644,13 +2666,10 @@ gst_rtsp_client_set_session_pool (GstRTSPClient * client, old = priv->session_pool; priv->session_pool = pool; - if (priv->session_removed_id) + if (priv->session_removed_id) { g_signal_handler_disconnect (old, priv->session_removed_id); - if (pool) - priv->session_removed_id = g_signal_connect (pool, "session-removed", - G_CALLBACK (client_session_removed), client); - else priv->session_removed_id = 0; + } g_mutex_unlock (&priv->lock); /* FIXME, should remove all sessions from the old pool for this client */ @@ -3353,6 +3372,8 @@ client_watch_notify (GstRTSPClient * client) priv->watch = NULL; g_main_context_unref (priv->watch_context); priv->watch_context = NULL; + /* remove all sessions and so drop the extra client ref */ + gst_rtsp_client_session_filter (client, cleanup_session, NULL); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL); g_object_unref (client); } From f78886e7cb6992a5d25098978e6edc62baeee32e Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 9 Jul 2014 14:17:46 +0200 Subject: [PATCH 1005/1776] server tests: send teardown to cleanup session --- tests/check/gst/rtspserver.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 223ad6981a..28910f7e69 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -647,6 +647,10 @@ GST_START_TEST (test_setup) fail_unless (audio_transport->mode_play); gst_rtsp_transport_free (audio_transport); + /* send TEARDOWN request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session) == GST_RTSP_STS_OK); + /* clean up and iterate so the clean-up can finish */ g_free (session); gst_sdp_message_free (sdp_message); @@ -710,6 +714,10 @@ GST_START_TEST (test_setup_with_require_header) fail_unless (video_transport->mode_play); gst_rtsp_transport_free (video_transport); + /* send TEARDOWN request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session) == GST_RTSP_STS_OK); + /* clean up and iterate so the clean-up can finish */ g_free (session); gst_sdp_message_free (sdp_message); From bfd498585a7fba9c9da91b18da8058204ce84afc Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 9 Jul 2014 14:19:10 +0200 Subject: [PATCH 1006/1776] client tests: send teardown to cleanup session --- tests/check/gst/client.c | 55 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 6d8df97370..1bbd67d80e 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -21,6 +21,7 @@ #include +static gchar * session_id; static gint cseq; static guint expected_session_timeout = 60; @@ -392,6 +393,10 @@ test_setup_response_200_multicast (GstRTSPClient * client, session = gst_rtsp_session_pool_find (session_pool, session_hdr_params[0]); g_strfreev (session_hdr_params); + /* remember session id to be able to send teardown */ + session_id = g_strdup (gst_rtsp_session_get_sessionid (session)); + fail_unless (session_id != NULL); + fail_unless (session != NULL); g_object_unref (session); @@ -401,6 +406,49 @@ test_setup_response_200_multicast (GstRTSPClient * client, return TRUE; } +static gboolean +test_teardown_response_200 (GstRTSPClient * client, + GstRTSPMessage * response, gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_OK); + fail_unless (g_str_equal (reason, "OK")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + return TRUE; +} + +static void +send_teardown (GstRTSPClient * client) +{ + GstRTSPMessage request = { 0, }; + gchar *str; + + fail_unless (session_id != NULL); + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_TEARDOWN, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, + session_id); + gst_rtsp_client_set_send_func (client, test_teardown_response_200, + NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + g_free (session_id); + session_id = NULL; +} + static GstRTSPClient * setup_multicast_client (void) { @@ -503,6 +551,9 @@ GST_START_TEST (test_client_multicast_transport) gst_rtsp_message_unset (&request); expected_transport = NULL; expected_session_timeout = 60; + + send_teardown (client); + teardown_client (client); } @@ -534,6 +585,8 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) gst_rtsp_message_unset (&request); expected_transport = NULL; + send_teardown (client); + teardown_client (client); } @@ -699,6 +752,8 @@ GST_START_TEST (test_client_multicast_transport_specific) fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 1); g_object_unref (session_pool); + send_teardown (client); + teardown_client (client); g_object_unref (ctx.auth); gst_rtsp_token_unref (ctx.token); From 6543082d2b6eb75da4bddc5b43aa24e759123fae Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 9 Jul 2014 15:16:08 +0200 Subject: [PATCH 1007/1776] client: check if watch is set in handle_teardown() The unit tests run without a watch --- gst/rtsp-server/rtsp-client.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e94567cbee..43c671af8e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -879,7 +879,8 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) /* make sure we unblock the backlog and don't accept new messages * on the watch */ - gst_rtsp_watch_set_flushing (priv->watch, TRUE); + if (priv->watch != NULL) + gst_rtsp_watch_set_flushing (priv->watch, TRUE); /* unlink the all TCP callbacks */ unlink_session_transports (client, session, sessmedia); @@ -887,7 +888,8 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL); /* allow messages again so that we can send the reply */ - gst_rtsp_watch_set_flushing (priv->watch, FALSE); + if (priv->watch != NULL) + gst_rtsp_watch_set_flushing (priv->watch, FALSE); /* unmanage the media in the session, returns false if all media session * are torn down. */ From 945c93fde09b461d4b810846e2a9443f915e6507 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 10 Jul 2014 11:32:20 +0200 Subject: [PATCH 1008/1776] filter: Release lock in filter functions Release the object lock before calling the filter functions. We need to keep a cookie to detect when the list changed during the filter callback. We also keep a hashtable to make sure we only call the filter function once for each object in case of concurrent modification. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=732950 --- gst/rtsp-server/rtsp-client.c | 40 +++++++++-- gst/rtsp-server/rtsp-server.c | 35 ++++++++-- gst/rtsp-server/rtsp-session-pool.c | 103 +++++++++++++++++----------- gst/rtsp-server/rtsp-session.c | 39 +++++++++-- gst/rtsp-server/rtsp-stream.c | 38 ++++++++-- 5 files changed, 194 insertions(+), 61 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 43c671af8e..0fd751ad7f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -83,6 +83,7 @@ struct _GstRTSPClientPrivate GList *transports; GList *sessions; + guint sessions_cookie; gboolean drop_backlog; }; @@ -305,6 +306,7 @@ client_watch_session (GstRTSPClient * client, GstRTSPSession * session) GST_INFO ("watching session %p", session); priv->sessions = g_list_prepend (priv->sessions, g_object_ref (session)); + priv->sessions_cookie++; /* connect removed session handler, it will be disconnected when the last * session gets removed */ @@ -334,12 +336,12 @@ client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session, } priv->sessions = g_list_delete_link (priv->sessions, link); + priv->sessions_cookie++; /* if this was the last session, disconnect the handler. * This will also drop the extra client ref */ if (!priv->sessions) { - g_signal_handler_disconnect (priv->session_pool, - priv->session_removed_id); + g_signal_handler_disconnect (priv->session_pool, priv->session_removed_id); priv->session_removed_id = 0; } @@ -3455,29 +3457,50 @@ gst_rtsp_client_session_filter (GstRTSPClient * client, { GstRTSPClientPrivate *priv; GList *result, *walk, *next; + GHashTable *visited; + guint cookie; g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL); priv = client->priv; result = NULL; + if (func) + visited = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL); g_mutex_lock (&priv->lock); +restart: + cookie = priv->sessions_cookie; for (walk = priv->sessions; walk; walk = next) { GstRTSPSession *sess = walk->data; GstRTSPFilterResult res; + gboolean changed; next = g_list_next (walk); - if (func) + if (func) { + /* only visit each session once */ + if (g_hash_table_contains (visited, sess)) + continue; + + g_hash_table_add (visited, g_object_ref (sess)); + g_mutex_unlock (&priv->lock); + res = func (client, sess, user_data); - else + + g_mutex_lock (&priv->lock); + } else res = GST_RTSP_FILTER_REF; + changed = (cookie != priv->sessions_cookie); + switch (res) { case GST_RTSP_FILTER_REMOVE: - /* stop watching the session and pretent it went away */ - client_unwatch_session (client, sess, walk); + /* stop watching the session and pretend it went away, if the list was + * changed, we can't use the current list position, try to see if we + * still have the session */ + client_unwatch_session (client, sess, changed ? NULL : walk); + cookie = priv->sessions_cookie; break; case GST_RTSP_FILTER_REF: result = g_list_prepend (result, g_object_ref (sess)); @@ -3486,8 +3509,13 @@ gst_rtsp_client_session_filter (GstRTSPClient * client, default: break; } + if (changed) + goto restart; } g_mutex_unlock (&priv->lock); + if (func) + g_hash_table_unref (visited); + return result; } diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index a5ea95a728..84a7d50174 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -90,6 +90,7 @@ struct _GstRTSPServerPrivate /* the clients that are connected */ GList *clients; + guint clients_cookie; }; #define DEFAULT_ADDRESS "0.0.0.0" @@ -999,6 +1000,7 @@ unmanage_client (GstRTSPClient * client, ClientContext * ctx) GST_RTSP_SERVER_LOCK (server); priv->clients = g_list_remove (priv->clients, ctx); + priv->clients_cookie++; GST_RTSP_SERVER_UNLOCK (server); if (ctx->thread) { @@ -1050,6 +1052,7 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client) g_signal_connect (client, "closed", (GCallback) unmanage_client, cctx); priv->clients = g_list_prepend (priv->clients, cctx); + priv->clients_cookie++; gst_rtsp_client_attach (client, mainctx); @@ -1361,38 +1364,62 @@ gst_rtsp_server_client_filter (GstRTSPServer * server, { GstRTSPServerPrivate *priv; GList *result, *walk, *next; + GHashTable *visited; + guint cookie; g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); priv = server->priv; result = NULL; + if (func) + visited = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL); GST_RTSP_SERVER_LOCK (server); +restart: + cookie = priv->clients_cookie; for (walk = priv->clients; walk; walk = next) { ClientContext *cctx = walk->data; + GstRTSPClient *client = cctx->client; GstRTSPFilterResult res; + gboolean changed; next = g_list_next (walk); - if (func) - res = func (server, cctx->client, user_data); - else + if (func) { + /* only visit each media once */ + if (g_hash_table_contains (visited, client)) + continue; + + g_hash_table_add (visited, g_object_ref (client)); + GST_RTSP_SERVER_UNLOCK (server); + + res = func (server, client, user_data); + + GST_RTSP_SERVER_LOCK (server); + } else res = GST_RTSP_FILTER_REF; + changed = (cookie != priv->clients_cookie); + switch (res) { case GST_RTSP_FILTER_REMOVE: /* remove client, FIXME */ break; case GST_RTSP_FILTER_REF: - result = g_list_prepend (result, g_object_ref (cctx->client)); + result = g_list_prepend (result, g_object_ref (client)); break; case GST_RTSP_FILTER_KEEP: default: break; } + if (changed) + goto restart; } GST_RTSP_SERVER_UNLOCK (server); + if (func) + g_hash_table_unref (visited); + return result; } diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index a7aa5b2510..769919615d 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -50,6 +50,7 @@ struct _GstRTSPSessionPoolPrivate GMutex lock; /* protects everything in this struct */ guint max_sessions; GHashTable *sessions; + guint sessions_cookie; }; #define DEFAULT_MAX_SESSIONS 0 @@ -394,6 +395,7 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) g_object_ref (result); g_hash_table_insert (priv->sessions, (gchar *) gst_rtsp_session_get_sessionid (result), result); + priv->sessions_cookie++; } g_mutex_unlock (&priv->lock); @@ -455,6 +457,7 @@ gst_rtsp_session_pool_remove (GstRTSPSessionPool * pool, GstRTSPSession * sess) g_hash_table_remove (priv->sessions, gst_rtsp_session_get_sessionid (sess)); if (found) { + priv->sessions_cookie++; g_signal_emit (pool, gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED], 0, sess); } @@ -511,44 +514,13 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool) result = g_hash_table_foreach_remove (priv->sessions, (GHRFunc) cleanup_func, &data); + if (result > 0) + priv->sessions_cookie++; g_mutex_unlock (&priv->lock); return result; } -typedef struct -{ - GstRTSPSessionPool *pool; - GstRTSPSessionPoolFilterFunc func; - gpointer user_data; - GList *list; -} FilterData; - -static gboolean -filter_func (gchar * sessionid, GstRTSPSession * sess, FilterData * data) -{ - GstRTSPFilterResult res; - - if (data->func) - res = data->func (data->pool, sess, data->user_data); - else - res = GST_RTSP_FILTER_REF; - - switch (res) { - case GST_RTSP_FILTER_REMOVE: - g_signal_emit (data->pool, - gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED], 0, sess); - return TRUE; - case GST_RTSP_FILTER_REF: - /* keep ref */ - data->list = g_list_prepend (data->list, g_object_ref (sess)); - /* fallthrough */ - default: - case GST_RTSP_FILTER_KEEP: - return FALSE; - } -} - /** * gst_rtsp_session_pool_filter: * @pool: a #GstRTSPSessionPool @@ -580,22 +552,73 @@ gst_rtsp_session_pool_filter (GstRTSPSessionPool * pool, GstRTSPSessionPoolFilterFunc func, gpointer user_data) { GstRTSPSessionPoolPrivate *priv; - FilterData data; + GHashTableIter iter; + gpointer key, value; + GList *result; + GHashTable *visited; + guint cookie; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), NULL); priv = pool->priv; - data.pool = pool; - data.func = func; - data.user_data = user_data; - data.list = NULL; + result = NULL; + if (func) + visited = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL); g_mutex_lock (&priv->lock); - g_hash_table_foreach_remove (priv->sessions, (GHRFunc) filter_func, &data); +restart: + g_hash_table_iter_init (&iter, priv->sessions); + cookie = priv->sessions_cookie; + while (g_hash_table_iter_next (&iter, &key, &value)) { + GstRTSPSession *session = value; + GstRTSPFilterResult res; + gboolean changed; + + if (func) { + /* only visit each session once */ + if (g_hash_table_contains (visited, session)) + continue; + + g_hash_table_add (visited, g_object_ref (session)); + g_mutex_unlock (&priv->lock); + + res = func (pool, session, user_data); + + g_mutex_lock (&priv->lock); + } else + res = GST_RTSP_FILTER_REF; + + changed = (cookie != priv->sessions_cookie); + + switch (res) { + case GST_RTSP_FILTER_REMOVE: + g_signal_emit (pool, + gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED], 0, session); + + if (changed) + g_hash_table_remove (priv->sessions, key); + else + g_hash_table_iter_remove (&iter); + cookie = ++priv->sessions_cookie; + break; + case GST_RTSP_FILTER_REF: + /* keep ref */ + result = g_list_prepend (result, g_object_ref (session)); + break; + case GST_RTSP_FILTER_KEEP: + default: + break; + } + if (changed) + goto restart; + } g_mutex_unlock (&priv->lock); - return data.list; + if (func) + g_hash_table_unref (visited); + + return result; } typedef struct diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 3463b326f1..372746ae9b 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -62,6 +62,7 @@ struct _GstRTSPSessionPrivate gint expire_count; GList *medias; + guint medias_cookie; }; #undef DEBUG @@ -238,6 +239,7 @@ gst_rtsp_session_manage_media (GstRTSPSession * sess, const gchar * path, g_mutex_lock (&priv->lock); priv->medias = g_list_prepend (priv->medias, result); + priv->medias_cookie++; g_mutex_unlock (&priv->lock); GST_INFO ("manage new media %p in session %p", media, result); @@ -269,8 +271,10 @@ gst_rtsp_session_release_media (GstRTSPSession * sess, g_mutex_lock (&priv->lock); find = g_list_find (priv->medias, media); - if (find) + if (find) { priv->medias = g_list_delete_link (priv->medias, find); + priv->medias_cookie++; + } more = (priv->medias != NULL); g_mutex_unlock (&priv->lock); @@ -359,29 +363,51 @@ gst_rtsp_session_filter (GstRTSPSession * sess, { GstRTSPSessionPrivate *priv; GList *result, *walk, *next; + GHashTable *visited; + guint cookie; g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); priv = sess->priv; result = NULL; + if (func) + visited = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL); g_mutex_lock (&priv->lock); +restart: + cookie = priv->medias_cookie; for (walk = priv->medias; walk; walk = next) { GstRTSPSessionMedia *media = walk->data; GstRTSPFilterResult res; + gboolean changed; next = g_list_next (walk); - if (func) + if (func) { + /* only visit each media once */ + if (g_hash_table_contains (visited, media)) + continue; + + g_hash_table_add (visited, g_object_ref (media)); + g_mutex_unlock (&priv->lock); + res = func (sess, media, user_data); - else + + g_mutex_lock (&priv->lock); + } else res = GST_RTSP_FILTER_REF; + changed = (cookie != priv->medias_cookie); + switch (res) { case GST_RTSP_FILTER_REMOVE: + if (changed) + priv->medias = g_list_remove (priv->medias, media); + else + priv->medias = g_list_delete_link (priv->medias, walk); + cookie = ++priv->medias_cookie; g_object_unref (media); - priv->medias = g_list_delete_link (priv->medias, walk); break; case GST_RTSP_FILTER_REF: result = g_list_prepend (result, g_object_ref (media)); @@ -390,9 +416,14 @@ gst_rtsp_session_filter (GstRTSPSession * sess, default: break; } + if (changed) + goto restart; } g_mutex_unlock (&priv->lock); + if (func) + g_hash_table_unref (visited); + return result; } diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 02c8274260..942b837c72 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -124,8 +124,9 @@ struct _GstRTSPStreamPrivate /* transports we stream to */ guint n_active; GList *transports; - gboolean tr_changed; + guint transports_cookie; GList *tr_cache; + guint tr_cache_cookie; gint dscp_qos; @@ -1503,13 +1504,13 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) is_rtp = GST_ELEMENT_CAST (sink) == priv->appsink[0]; g_mutex_lock (&priv->lock); - if (priv->tr_changed) { + if (priv->tr_cache_cookie != priv->transports_cookie) { clear_tr_cache (priv); for (walk = priv->transports; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; priv->tr_cache = g_list_prepend (priv->tr_cache, g_object_ref (tr)); } - priv->tr_changed = FALSE; + priv->tr_cache_cookie = priv->transports_cookie; } g_mutex_unlock (&priv->lock); @@ -2268,7 +2269,7 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, g_signal_emit_by_name (priv->udpsink[1], "remove", dest, max, NULL); priv->transports = g_list_remove (priv->transports, trans); } - priv->tr_changed = TRUE; + priv->transports_cookie++; break; } case GST_RTSP_LOWER_TRANS_TCP: @@ -2279,7 +2280,7 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, GST_INFO ("removing TCP %s", tr->destination); priv->transports = g_list_remove (priv->transports, trans); } - priv->tr_changed = TRUE; + priv->transports_cookie++; break; default: goto unknown_transport; @@ -2497,25 +2498,43 @@ gst_rtsp_stream_transport_filter (GstRTSPStream * stream, { GstRTSPStreamPrivate *priv; GList *result, *walk, *next; + GHashTable *visited; + guint cookie; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); priv = stream->priv; result = NULL; + if (func) + visited = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL); g_mutex_lock (&priv->lock); +restart: + cookie = priv->transports_cookie; for (walk = priv->transports; walk; walk = next) { GstRTSPStreamTransport *trans = walk->data; GstRTSPFilterResult res; + gboolean changed; next = g_list_next (walk); - if (func) + if (func) { + /* only visit each transport once */ + if (g_hash_table_contains (visited, trans)) + continue; + + g_hash_table_add (visited, g_object_ref (trans)); + g_mutex_unlock (&priv->lock); + res = func (stream, trans, user_data); - else + + g_mutex_lock (&priv->lock); + } else res = GST_RTSP_FILTER_REF; + changed = (cookie != priv->transports_cookie); + switch (res) { case GST_RTSP_FILTER_REMOVE: update_transport (stream, trans, FALSE); @@ -2527,9 +2546,14 @@ gst_rtsp_stream_transport_filter (GstRTSPStream * stream, default: break; } + if (changed) + goto restart; } g_mutex_unlock (&priv->lock); + if (func) + g_hash_table_unref (visited); + return result; } From 301585b30f7d6a604252df96a999d6e2435b1fab Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 10 Jul 2014 12:20:15 +0200 Subject: [PATCH 1009/1776] session-pool: signal session-removed outside of the lock Release the lock before emiting the session-removed signal. --- gst/rtsp-server/rtsp-session-pool.c | 50 +++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 769919615d..fad5288300 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -456,13 +456,15 @@ gst_rtsp_session_pool_remove (GstRTSPSessionPool * pool, GstRTSPSession * sess) found = g_hash_table_remove (priv->sessions, gst_rtsp_session_get_sessionid (sess)); - if (found) { + if (found) priv->sessions_cookie++; + g_mutex_unlock (&priv->lock); + + if (found) g_signal_emit (pool, gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED], 0, sess); - } + g_object_unref (sess); - g_mutex_unlock (&priv->lock); return found; } @@ -471,6 +473,7 @@ typedef struct { GTimeVal now; GstRTSPSessionPool *pool; + GList *removed; } CleanupData; static gboolean @@ -480,9 +483,8 @@ cleanup_func (gchar * sessionid, GstRTSPSession * sess, CleanupData * data) expired = gst_rtsp_session_is_expired (sess, &data->now); if (expired) { - GST_DEBUG ("session expired, emitting signal"); - g_signal_emit (data->pool, - gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED], 0, sess); + GST_DEBUG ("session expired"); + data->removed = g_list_prepend (data->removed, g_object_ref (sess)); } return expired; } @@ -502,6 +504,7 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool) GstRTSPSessionPoolPrivate *priv; guint result; CleanupData data; + GList *walk; g_return_val_if_fail (GST_IS_RTSP_SESSION_POOL (pool), 0); @@ -509,6 +512,7 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool) g_get_current_time (&data.now); data.pool = pool; + data.removed = NULL; g_mutex_lock (&priv->lock); result = @@ -518,6 +522,16 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool) priv->sessions_cookie++; g_mutex_unlock (&priv->lock); + for (walk = data.removed; walk; walk = walk->next) { + GstRTSPSession *sess = walk->data; + + g_signal_emit (pool, + gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED], 0, sess); + + g_object_unref (sess); + } + g_list_free (data.removed); + return result; } @@ -593,15 +607,31 @@ restart: switch (res) { case GST_RTSP_FILTER_REMOVE: - g_signal_emit (pool, - gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED], 0, session); + { + gboolean removed = TRUE; if (changed) - g_hash_table_remove (priv->sessions, key); + /* something changed, check if we still have the session */ + removed = g_hash_table_remove (priv->sessions, key); else g_hash_table_iter_remove (&iter); - cookie = ++priv->sessions_cookie; + + if (removed) { + /* if we managed to remove the session, update the cookie and + * signal */ + cookie = ++priv->sessions_cookie; + g_mutex_unlock (&priv->lock); + + g_signal_emit (pool, + gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED], 0, + session); + + g_mutex_lock (&priv->lock); + /* cookie could have changed again, make sure we restart */ + changed |= (cookie != priv->sessions_cookie); + } break; + } case GST_RTSP_FILTER_REF: /* keep ref */ result = g_list_prepend (result, g_object_ref (session)); From ced406cc28ef448739b6153ea80e79af102aa490 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 10 Jul 2014 17:05:13 +0200 Subject: [PATCH 1010/1776] client: expose _close() method Expose a previously internal close method to close the client connection. --- gst/rtsp-server/rtsp-client.c | 14 +++++++++++--- gst/rtsp-server/rtsp-client.h | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 0fd751ad7f..d37fb68497 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -798,8 +798,16 @@ unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, } } -static void -close_connection (GstRTSPClient * client) +/** + * gst_rtsp_client_close: + * @client: a #GstRTSPClient + * + * Close the connection of @client and remove all media it was managing. + * + * Since: 1.4 + */ +void +gst_rtsp_client_close (GstRTSPClient * client) { GstRTSPClientPrivate *priv = client->priv; const gchar *tunnelid; @@ -3133,7 +3141,7 @@ message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) if (priv->close_seq && priv->close_seq == cseq) { GST_INFO ("client %p: send close message", client); priv->close_seq = 0; - close_connection (client); + gst_rtsp_client_close (client); } return GST_RTSP_OK; diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 01f820826d..6bc9a59e6d 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -146,6 +146,7 @@ GstRTSPConnection * gst_rtsp_client_get_connection (GstRTSPClient *client); guint gst_rtsp_client_attach (GstRTSPClient *client, GMainContext *context); +void gst_rtsp_client_close (GstRTSPClient * client); void gst_rtsp_client_set_send_func (GstRTSPClient *client, GstRTSPClientSendFunc func, From ecde0051db71d97cf8e1b67a16280644c106806a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 10 Jul 2014 17:10:06 +0200 Subject: [PATCH 1011/1776] server: implement client REMOVE filter --- gst/rtsp-server/rtsp-server.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 84a7d50174..686ba03121 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1404,7 +1404,12 @@ restart: switch (res) { case GST_RTSP_FILTER_REMOVE: - /* remove client, FIXME */ + GST_RTSP_SERVER_UNLOCK (server); + + gst_rtsp_client_close (client); + + GST_RTSP_SERVER_LOCK (server); + changed |= (cookie != priv->clients_cookie); break; case GST_RTSP_FILTER_REF: result = g_list_prepend (result, g_object_ref (client)); From 0b9e72f279316a56ff2127ecd13fdcc993ee57e5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 10 Jul 2014 17:37:45 +0200 Subject: [PATCH 1012/1776] docs: update docs --- docs/libs/gst-rtsp-server-sections.txt | 41 +++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index e43e896542..e832c4e6b4 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -86,6 +86,7 @@ GstRTSPClient GstRTSPClientClass gst_rtsp_client_new +gst_rtsp_client_close gst_rtsp_client_get_session_pool gst_rtsp_client_set_session_pool @@ -133,6 +134,7 @@ gst_rtsp_context_get_current gst_rtsp_context_push_current gst_rtsp_context_pop_current +GST_TYPE_RTSP_CONTEXT gst_rtsp_context_get_type
@@ -154,6 +156,9 @@ gst_rtsp_media_is_shared gst_rtsp_media_set_reusable gst_rtsp_media_is_reusable +gst_rtsp_media_set_profiles +gst_rtsp_media_get_profiles + gst_rtsp_media_set_protocols gst_rtsp_media_get_protocols @@ -166,12 +171,22 @@ gst_rtsp_media_get_address_pool gst_rtsp_media_set_buffer_size gst_rtsp_media_get_buffer_size +gst_rtsp_media_setup_sdp + gst_rtsp_media_prepare gst_rtsp_media_unprepare GstRTSPMediaStatus gst_rtsp_media_get_status + +gst_rtsp_media_set_suspend_mode +gst_rtsp_media_get_suspend_mode + +GstRTSPSuspendMode +gst_rtsp_media_suspend +gst_rtsp_media_unsuspend + gst_rtsp_media_collect_streams gst_rtsp_media_create_stream @@ -203,6 +218,8 @@ GST_RTSP_MEDIA_GET_CLASS GST_TYPE_RTSP_MEDIA GstRTSPMediaPrivate gst_rtsp_media_get_type +GST_TYPE_RTSP_SUSPEND_MODE +gst_rtsp_suspend_mode_get_type
@@ -210,7 +227,6 @@ gst_rtsp_media_get_type GstRTSPMediaFactory GstRTSPMediaFactory GstRTSPMediaFactoryClass - gst_rtsp_media_factory_new gst_rtsp_media_factory_get_launch @@ -229,12 +245,18 @@ gst_rtsp_media_factory_set_eos_shutdown gst_rtsp_media_factory_get_protocols gst_rtsp_media_factory_set_protocols +gst_rtsp_media_factory_set_profiles +gst_rtsp_media_factory_get_profiles + gst_rtsp_media_factory_get_address_pool gst_rtsp_media_factory_set_address_pool gst_rtsp_media_factory_get_buffer_size gst_rtsp_media_factory_set_buffer_size +gst_rtsp_media_factory_get_suspend_mode +gst_rtsp_media_factory_set_suspend_mode + gst_rtsp_media_factory_construct gst_rtsp_media_factory_create_element @@ -433,6 +455,7 @@ gst_rtsp_session_media_matches gst_rtsp_session_media_get_media gst_rtsp_session_media_get_base_time +gst_rtsp_session_media_get_rtpinfo gst_rtsp_session_media_set_state @@ -512,9 +535,14 @@ gst_rtsp_stream_set_mtu gst_rtsp_stream_get_dscp_qos gst_rtsp_stream_set_dscp_qos +gst_rtsp_stream_set_profiles +gst_rtsp_stream_get_profiles + gst_rtsp_stream_get_protocols gst_rtsp_stream_set_protocols +gst_rtsp_stream_is_transport_supported + gst_rtsp_stream_get_address_pool gst_rtsp_stream_set_address_pool gst_rtsp_stream_reserve_address @@ -528,6 +556,7 @@ gst_rtsp_stream_get_rtpsession gst_rtsp_stream_get_ssrc gst_rtsp_stream_get_rtpinfo gst_rtsp_stream_get_caps +gst_rtsp_stream_get_pt gst_rtsp_stream_recv_rtcp gst_rtsp_stream_recv_rtp @@ -538,6 +567,11 @@ gst_rtsp_stream_remove_transport gst_rtsp_stream_get_rtp_socket gst_rtsp_stream_get_rtcp_socket +gst_rtsp_stream_set_blocked +gst_rtsp_stream_is_blocking + +gst_rtsp_stream_update_crypto + GstRTSPStreamTransportFilterFunc gst_rtsp_stream_transport_filter @@ -566,6 +600,11 @@ gst_rtsp_stream_transport_get_stream gst_rtsp_stream_transport_get_transport gst_rtsp_stream_transport_set_transport +gst_rtsp_stream_transport_get_url +gst_rtsp_stream_transport_set_url + +gst_rtsp_stream_transport_get_rtpinfo + GstRTSPSendFunc gst_rtsp_stream_transport_set_callbacks From 5932dc3336e3ab440d17c2560e6b8f8c606f6238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 11 Jul 2014 12:19:08 +0200 Subject: [PATCH 1013/1776] Release 1.3.91 --- ChangeLog | 152 ++++++++++++++++++++++++++++++++++++++++++- NEWS | 2 +- RELEASE | 12 ++-- configure.ac | 12 ++-- gst-rtsp-server.doap | 10 +++ 5 files changed, 173 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2175c5562c..ff942f113f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,155 @@ -=== release 1.3.90 === +=== release 1.3.91 === -2014-06-28 Sebastian Dröge +2014-07-11 Sebastian Dröge * configure.ac: - releasing 1.3.90 + releasing 1.3.91 + +2014-07-10 17:37:45 +0200 Wim Taymans + + * docs/libs/gst-rtsp-server-sections.txt: + docs: update docs + +2014-07-10 17:10:06 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-server.c: + server: implement client REMOVE filter + +2014-07-10 17:05:13 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: expose _close() method + Expose a previously internal close method to close the client + connection. + +2014-07-10 12:20:15 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-session-pool.c: + session-pool: signal session-removed outside of the lock + Release the lock before emiting the session-removed signal. + +2014-07-10 11:32:20 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-stream.c: + filter: Release lock in filter functions + Release the object lock before calling the filter functions. We need to + keep a cookie to detect when the list changed during the filter + callback. We also keep a hashtable to make sure we only call the filter + function once for each object in case of concurrent modification. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=732950 + +2014-07-09 15:16:08 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + client: check if watch is set in handle_teardown() + The unit tests run without a watch + +2014-07-09 14:19:10 +0200 Ognyan Tonchev + + * tests/check/gst/client.c: + client tests: send teardown to cleanup session + +2014-07-09 14:17:46 +0200 Ognyan Tonchev + + * tests/check/gst/rtspserver.c: + server tests: send teardown to cleanup session + +2014-07-09 15:01:31 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + client: keep ref to client for the session removed handler + This extra ref will be dropped when all client sessions have been + removed. A session is removed when a client sends teardown, closes its + endpoint of the TCP connection or the sessions expires. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=732226 + +2014-07-08 12:36:12 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-session.c: + * tests/check/gst/client.c: + client: manage media in session as a last step + Once we manage a media in a session, we can't unmanage it anymore + without destroying it. Therefore, first check everything before we + manage the media, otherwise if something is wrong we have no way to + unmanage the media. + If we created a new session and something went wrong, remove the session + again. Fixes a leak in the unit test. + +2014-07-03 19:52:42 +0100 Tim-Philipp Müller + + * examples/test-mp4.c: + * examples/test-ogg.c: + examples: print 'stream ready at url' for mp4 and ogg example + +2014-07-02 16:04:53 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-sdp.c: + rtsp: fix for MIKEY api change + +2014-07-01 16:12:13 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: free watch context only once + The watch context is freed when the source is destroyed. Avoids + a CRITICAL when we try to unref the context twice. + +2014-07-01 15:02:15 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: fix build + +2014-07-01 14:41:14 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: protect sessions with lock + Protect the list of sessions with the lock. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=732226 + +2014-07-01 12:13:47 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + Client: keep a ref to the session + Don't just keep a weak ref to the session objects but use a hard ref. We + will be notified when a session is removed from the pool (expired) with + the new session-removed signal. + Don't automatically close the RTSP connection when all the sessions of + a client are removed, a client can continue to operate and it can create + a new session if it wants. If you want to remove the client from the + server, you have to use gst_rtsp_server_client_filter() now. + Based on patch from Ognyan Tonchev + See https://bugzilla.gnome.org/show_bug.cgi?id=732226 + +2014-06-30 15:14:34 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session-pool.h: + session-pool: add session-removed signal + Add a signal to be notified when a session is removed from the pool. + +2014-06-30 00:37:59 -0700 Evan Nemerson + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-server.h: + Make rtsp-server.h a single-include header, use it for G-I + https://bugzilla.gnome.org/show_bug.cgi?id=732411 + +=== release 1.3.90 === + +2014-06-28 11:48:29 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.3.90 2014-06-27 16:54:22 +0200 Wim Taymans diff --git a/NEWS b/NEWS index a89efb608d..227344898e 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -This is GStreamer RTSP Server 1.3.90 +This is GStreamer RTSP Server 1.3.91 Changes since 1.2: diff --git a/RELEASE b/RELEASE index 32be8ce299..052f6c22f6 100644 --- a/RELEASE +++ b/RELEASE @@ -1,8 +1,8 @@ -Release notes for GStreamer RTSP Server Library 1.3.90 +Release notes for GStreamer RTSP Server Library 1.3.91 -The GStreamer team is pleased to announce the first release candidate of +The GStreamer team is pleased to announce the second release candidate of the stable 1.4 release series. The 1.4 release series is adding new features on top of the 1.0 and 1.2 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. @@ -28,8 +28,9 @@ bugfix. Bugs fixed in this release - * 730952 : Missing nullability annotations - * 730953 : Missing documentation (and annotations) for GstRTSPServer + * 732226 : Races when sessions time out + * 732411 : rtsp server GIR has wrong C include + * 732950 : deadlock after TEARDOWN ==== Download ==== @@ -69,6 +70,7 @@ Applications Contributors to this release * Evan Nemerson - * Sebastian Dröge + * Ognyan Tonchev + * Tim-Philipp Müller * Wim Taymans   \ No newline at end of file diff --git a/configure.ac b/configure.ac index e9b182cb13..4a7df6276d 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.3.90], +AC_INIT([GStreamer RTSP Server Library], [1.3.91], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 390, 0, 390) +AS_LIBTOOL(GST, 391, 0, 391) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.3.90 -GSTPB_REQ=1.3.90 -GSTPG_REQ=1.3.90 -GSTPD_REQ=1.3.90 +GST_REQ=1.3.91 +GSTPB_REQ=1.3.91 +GSTPG_REQ=1.3.91 +GSTPD_REQ=1.3.91 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index c289dc1667..4d4e42607f 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.3.91 + 1.3 + + 2014-07-11 + + + + 1.3.90 From a8e604355cc18445f1b9154abc9efb6d990c32bf Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Wed, 16 Jul 2014 20:39:42 +0900 Subject: [PATCH 1014/1776] media: correct misspelled words in description https://bugzilla.gnome.org/show_bug.cgi?id=733244 --- gst/rtsp-server/rtsp-media.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 53047595fe..a78650d9b9 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -69,7 +69,7 @@ typedef enum { * @GST_RTSP_SUSPEND_MODE_RESET: The media is set to NULL when suspended * * The suspend mode of the media pipeline. A media pipeline is suspended right - * after creating the SDP and when the client preforms a PAUSED request. + * after creating the SDP and when the client performs a PAUSED request. */ typedef enum { GST_RTSP_SUSPEND_MODE_NONE = 0, @@ -117,7 +117,7 @@ struct _GstRTSPMedia { * The pipeline will be prerolled again if it's state was * set to GST_STATE_NULL in suspend. * @convert_range: convert a range to the given unit - * @query_position: query the current posision in the pipeline + * @query_position: query the current position in the pipeline * @query_stop: query when playback will stop * * The RTSP media class From 67644cb625d1b5fe107dc59a2a7e9bd9e633cf8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 19 Jul 2014 17:56:31 +0200 Subject: [PATCH 1015/1776] Release 1.4.0 --- ChangeLog | 23 ++++++++++++++++++++--- NEWS | 4 ++-- RELEASE | 39 ++++++++++++++------------------------- configure.ac | 12 ++++++------ gst-rtsp-server.doap | 10 ++++++++++ 5 files changed, 52 insertions(+), 36 deletions(-) diff --git a/ChangeLog b/ChangeLog index ff942f113f..9367e68d32 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,26 @@ -=== release 1.3.91 === +=== release 1.4.0 === -2014-07-11 Sebastian Dröge +2014-07-19 Sebastian Dröge * configure.ac: - releasing 1.3.91 + releasing 1.4.0 + +2014-07-16 20:39:42 +0900 Hyunjun Ko + + * gst/rtsp-server/rtsp-media.h: + media: correct misspelled words in description + https://bugzilla.gnome.org/show_bug.cgi?id=733244 + +=== release 1.3.91 === + +2014-07-11 12:19:08 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.3.91 2014-07-10 17:37:45 +0200 Wim Taymans diff --git a/NEWS b/NEWS index 227344898e..1280881ba2 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -This is GStreamer RTSP Server 1.3.91 +This is GStreamer RTSP Server 1.4.0 Changes since 1.2: @@ -97,7 +97,7 @@ Major changes: are available on OS X and iOS now. • Other changes: - ∘ gst-libav now uses libav 10.1, and gained support for H265/HEVC. + ∘ gst-libav now uses libav 10.2, and gained support for H265/HEVC. ∘ Support for hardware codecs and special memory types has been improved with bugfixes and feature additions in various plugins and base classes. diff --git a/RELEASE b/RELEASE index 052f6c22f6..bcd3f9d586 100644 --- a/RELEASE +++ b/RELEASE @@ -1,36 +1,30 @@ -Release notes for GStreamer RTSP Server Library 1.3.91 +Release notes for GStreamer RTSP Server Library 1.4.0 -The GStreamer team is pleased to announce the second release candidate of -the stable 1.4 release series. The 1.4 release series is adding new features -on top of the 1.0 and 1.2 series and is part of the API and ABI-stable 1.x -release series of the GStreamer multimedia framework. +The GStreamer team is pleased to announce the first release of +the stable 1.4 release series. The 1.4 release series is adding new +features on top of the 1.0 and 1.2 series and is part of the API and +ABI-stable 1.x release series of the GStreamer multimedia framework. -This release candidate will hopefully shortly be followed by the stable 1.4.0 -release if no bigger regressions or bigger issues are detected, and enough -testing of the release candidate happened. The new API that was added during -the 1.3 release series is not expected to change anymore at this point. + +Binaries for Android, iOS, Mac OS X and Windows are provided together +with this release. -Binaries for Android, iOS, Mac OS X and Windows are provided together with this -release. - -The stable 1.4 release series is API and ABI compatible with 1.0.x, 1.2.x and -any other 1.x release series in the future. Compared to 1.2.x it contains some -new features and more intrusive changes that were considered too risky as a -bugfix. +The stable 1.4 release series is API and ABI compatible with 1.0.x, +1.2.x and any other 1.x release series in the future. Compared to 1.2.x +it contains some new features and more intrusive changes that were +considered too risky as a bugfix. Bugs fixed in this release - * 732226 : Races when sessions time out - * 732411 : rtsp server GIR has wrong C include - * 732950 : deadlock after TEARDOWN + * 733244 : Correct misspelled words ==== Download ==== @@ -65,12 +59,7 @@ Interested developers of the core library, plugins, and applications should subscribe to the gstreamer-devel list. -Applications - Contributors to this release - * Evan Nemerson - * Ognyan Tonchev - * Tim-Philipp Müller - * Wim Taymans + * Hyunjun Ko   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 4a7df6276d..04457ff021 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.3.91], +AC_INIT([GStreamer RTSP Server Library], [1.4.0], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 391, 0, 391) +AS_LIBTOOL(GST, 400, 0, 400) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.3.91 -GSTPB_REQ=1.3.91 -GSTPG_REQ=1.3.91 -GSTPD_REQ=1.3.91 +GST_REQ=1.4.0 +GSTPB_REQ=1.4.0 +GSTPG_REQ=1.4.0 +GSTPD_REQ=1.4.0 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 4d4e42607f..8668226355 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.4.0 + 1.4 + + 2014-07-19 + + + + 1.3.91 From e58eeb408d1b8415860c93ade956a8bf62f7af1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 19 Jul 2014 18:04:52 +0200 Subject: [PATCH 1016/1776] Back to development --- configure.ac | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 04457ff021..4d804ba546 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.4.0], +AC_INIT([GStreamer RTSP Server Library], [1.5.0.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 400, 0, 400) +AS_LIBTOOL(GST, 501, 0, 501) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.4.0 -GSTPB_REQ=1.4.0 -GSTPG_REQ=1.4.0 -GSTPD_REQ=1.4.0 +GST_REQ=1.5.0.1 +GSTPB_REQ=1.5.0.1 +GSTPG_REQ=1.5.0.1 +GSTPD_REQ=1.5.0.1 dnl *** autotools stuff **** From 3159b374b9d4b73d20667667f8fd843fa319e9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 25 Jun 2014 18:23:10 +0200 Subject: [PATCH 1017/1776] rtsp-stream: Listen on the multicast group for RTP/RTCP packets When a UDP multicast transport is used it is expected that the server listens for RTP and RTCP packets on the multicast group with the corresponding port. Without this we will never get RTCP packets from clients in multicast mode. https://bugzilla.gnome.org/show_bug.cgi?id=732238 --- gst/rtsp-server/rtsp-stream.c | 90 ++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 942b837c72..9ed194f7bd 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -58,6 +58,15 @@ #define GST_RTSP_STREAM_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_STREAM, GstRTSPStreamPrivate)) +typedef struct +{ + GstRTSPStreamTransport *transport; + + /* RTP and RTCP source */ + GstElement *udpsrc[2]; + GstPad *selpad[2]; +} GstRTSPMulticastTransportSource; + struct _GstRTSPStreamPrivate { GMutex lock; @@ -128,6 +137,9 @@ struct _GstRTSPStreamPrivate GList *tr_cache; guint tr_cache_cookie; + /* UDP sources for UDP multicast transports */ + GList *transport_sources; + gint dscp_qos; /* stream blocking */ @@ -1137,6 +1149,7 @@ again: udpsrc_out[1] = udpsrc1; udpsink_out[0] = udpsink0; udpsink_out[1] = udpsink1; + server_port_out->min = rtpport; server_port_out->max = rtcpport; @@ -2236,8 +2249,83 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, tr = gst_rtsp_stream_transport_get_transport (trans); switch (tr->lower_transport) { - case GST_RTSP_LOWER_TRANS_UDP: case GST_RTSP_LOWER_TRANS_UDP_MCAST: + { + GstRTSPMulticastTransportSource *source; + GstBin *bin; + + bin = GST_BIN (gst_object_get_parent (GST_OBJECT (priv->funnel[0]))); + + if (add) { + gchar *host; + gint i; + GstPad *selpad, *pad; + + source = g_slice_new0 (GstRTSPMulticastTransportSource); + source->transport = trans; + + for (i = 0; i < 2; i++) { + host = + g_strdup_printf ("udp://%s:%d", tr->destination, + (i == 0) ? tr->port.min : tr->port.max); + source->udpsrc[i] = + gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); + g_free (host); + + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values */ + gst_element_set_state (source->udpsrc[i], GST_STATE_PLAYING); + gst_element_set_locked_state (source->udpsrc[i], TRUE); + /* add udpsrc */ + gst_bin_add (bin, source->udpsrc[i]); + + /* and link to the funnel v4 */ + source->selpad[i] = selpad = + gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (source->udpsrc[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + } + gst_object_unref (bin); + + priv->transport_sources = + g_list_prepend (priv->transport_sources, source); + } else { + GList *l; + + for (l = priv->transport_sources; l; l = l->next) { + source = l->data; + + if (source->transport == trans) { + priv->transport_sources = + g_list_delete_link (priv->transport_sources, l); + break; + } + } + + if (l != NULL) { + gint i; + + for (i = 0; i < 2; i++) { + /* Will automatically unlink everything */ + gst_bin_remove (bin, + GST_ELEMENT (gst_object_ref (source->udpsrc[i]))); + + gst_element_set_state (source->udpsrc[i], GST_STATE_NULL); + gst_object_unref (source->udpsrc[i]); + + gst_element_release_request_pad (priv->funnel[i], + source->selpad[i]); + } + + g_slice_free (GstRTSPMulticastTransportSource, source); + } + } + + /* fall through for the generic case */ + } + case GST_RTSP_LOWER_TRANS_UDP: { gchar *dest; gint min, max; From bad8eca332df47d21485c4c9afb6db0a7996673f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 1 Aug 2014 10:46:44 +0200 Subject: [PATCH 1018/1776] Makefile: Add usage of build-checks step Allows building checks without running them --- Makefile.am | 4 ++++ common | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 8b4b6055c1..d331c8d3be 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,9 +31,13 @@ check-valgrind: if HAVE_CHECK check-torture: cd tests/check && make torture +build-checks: + cd tests/check && make build-checks else check-torture: true +build-checks: + true endif # cruft: plugins that have been merged or moved or renamed diff --git a/common b/common index 211fa5f2d0..36388a18d3 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 211fa5f2d0930dfd6891b386d42edba6d88c2a19 +Subproject commit 36388a18d37d72f9633bf1a8c06d18d310d215bb From e297dd1fee6228a69e7487691b5805bd17819d0d Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Wed, 2 Jul 2014 22:45:07 +0530 Subject: [PATCH 1019/1776] signals: Fix copy-pasto in target-state signal offset --- gst/rtsp-server/rtsp-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index cc35372c6c..8f2078c715 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -297,8 +297,8 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) gst_rtsp_media_signals[SIGNAL_TARGET_STATE] = g_signal_new ("target-state", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, - NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT); + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, target_state), + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT); gst_rtsp_media_signals[SIGNAL_NEW_STATE] = g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, From 486f30558a8418c5a22143083e2755a1c2375ff0 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Thu, 17 Jul 2014 01:34:17 +0200 Subject: [PATCH 1020/1776] examples: unref element after usage gst_bin_get_by_name_recurse_up() returns an element reference that must be unreffed after usage. https://bugzilla.gnome.org/show_bug.cgi?id=734546 --- examples/test-appsrc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/test-appsrc.c b/examples/test-appsrc.c index 9d271ead87..125c642f96 100644 --- a/examples/test-appsrc.c +++ b/examples/test-appsrc.c @@ -86,6 +86,7 @@ media_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media, /* install the callback that will be called when a buffer is needed */ g_signal_connect (appsrc, "need-data", (GCallback) need_data, ctx); + gst_object_unref (appsrc); } int From 04e69cf83b1c97382537032d9e39ce1b3e9cac9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 9 Aug 2014 14:41:35 +0100 Subject: [PATCH 1021/1776] examples: fix another reference leak gst_rtsp_media_get_element() returns a new ref. --- examples/test-appsrc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/test-appsrc.c b/examples/test-appsrc.c index 125c642f96..33ce15bb39 100644 --- a/examples/test-appsrc.c +++ b/examples/test-appsrc.c @@ -87,6 +87,7 @@ media_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media, /* install the callback that will be called when a buffer is needed */ g_signal_connect (appsrc, "need-data", (GCallback) need_data, ctx); gst_object_unref (appsrc); + gst_object_unref (element); } int From 6ba5ca447f40bc05ac74c2ab805d1ce9cf77797a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 5 Aug 2014 16:12:19 +0200 Subject: [PATCH 1022/1776] rtsp-media: Query position and stop time only on the RTP parts of the pipeline The RTCP parts, in specific the RTCP udpsinks, are not flushed when seeking and will always continue counting the time. This leads to the NPT after a backwards seek to be something completely different to the actual seek position. https://bugzilla.gnome.org/show_bug.cgi?id=732644 --- gst/rtsp-server/rtsp-media.c | 74 ++++++++++++++++++++++++++------- gst/rtsp-server/rtsp-stream.c | 78 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 6 +++ 3 files changed, 144 insertions(+), 14 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 8f2078c715..48868f5464 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -452,28 +452,74 @@ gst_rtsp_media_set_property (GObject * object, guint propid, } } +typedef struct +{ + gint64 position; + gboolean ret; +} DoQueryPositionData; + +static void +do_query_position (GstRTSPStream * stream, DoQueryPositionData * data) +{ + gint64 tmp; + + if (gst_rtsp_stream_query_position (stream, &tmp)) { + data->position = MAX (data->position, tmp); + data->ret = TRUE; + } +} + static gboolean default_query_position (GstRTSPMedia * media, gint64 * position) { - return gst_element_query_position (media->priv->pipeline, GST_FORMAT_TIME, - position); + GstRTSPMediaPrivate *priv; + DoQueryPositionData data; + + priv = media->priv; + + data.position = -1; + data.ret = FALSE; + + g_ptr_array_foreach (priv->streams, (GFunc) do_query_position, &data); + + *position = data.position; + + return data.ret; +} + +typedef struct +{ + gint64 stop; + gboolean ret; +} DoQueryStopData; + +static void +do_query_stop (GstRTSPStream * stream, DoQueryStopData * data) +{ + gint64 tmp; + + if (gst_rtsp_stream_query_stop (stream, &tmp)) { + data->stop = MAX (data->stop, tmp); + data->ret = TRUE; + } } static gboolean default_query_stop (GstRTSPMedia * media, gint64 * stop) { - GstQuery *query; - gboolean res; + GstRTSPMediaPrivate *priv; + DoQueryStopData data; - query = gst_query_new_segment (GST_FORMAT_TIME); - if ((res = gst_element_query (media->priv->pipeline, query))) { - GstFormat format; - gst_query_parse_segment (query, NULL, &format, NULL, stop); - if (format != GST_FORMAT_TIME) - *stop = -1; - } - gst_query_unref (query); - return res; + priv = media->priv; + + data.stop = -1; + data.ret = FALSE; + + g_ptr_array_foreach (priv->streams, (GFunc) do_query_stop, &data); + + *stop = data.stop; + + return data.ret; } static GstElement * @@ -491,7 +537,7 @@ static void collect_media_stats (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; - gint64 position, stop; + gint64 position = 0, stop = -1; if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED && priv->status != GST_RTSP_MEDIA_STATUS_PREPARING) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 9ed194f7bd..0b0257043d 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2730,3 +2730,81 @@ gst_rtsp_stream_is_blocking (GstRTSPStream * stream) return result; } + +/** + * gst_rtsp_stream_query_position: + * @stream: a #GstRTSPStream + * + * Query the position of the stream in %GST_FORMAT_TIME. This only considers + * the RTP parts of the pipeline and not the RTCP parts. + * + * Returns: %TRUE if the position could be queried + */ +gboolean +gst_rtsp_stream_query_position (GstRTSPStream * stream, gint64 * position) +{ + GstRTSPStreamPrivate *priv; + GstElement *sink; + gboolean ret; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if ((sink = priv->udpsink[0])) + gst_object_ref (sink); + g_mutex_unlock (&priv->lock); + + if (!sink) + return FALSE; + + ret = gst_element_query_position (sink, GST_FORMAT_TIME, position); + gst_object_unref (sink); + + return ret; +} + +/** + * gst_rtsp_stream_query_stop: + * @stream: a #GstRTSPStream + * + * Query the stop of the stream in %GST_FORMAT_TIME. This only considers + * the RTP parts of the pipeline and not the RTCP parts. + * + * Returns: %TRUE if the stop could be queried + */ +gboolean +gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop) +{ + GstRTSPStreamPrivate *priv; + GstElement *sink; + GstQuery *query; + gboolean ret; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if ((sink = priv->udpsink[0])) + gst_object_ref (sink); + g_mutex_unlock (&priv->lock); + + if (!sink) + return FALSE; + + query = gst_query_new_segment (GST_FORMAT_TIME); + if ((ret = gst_element_query (sink, query))) { + GstFormat format; + + gst_query_parse_segment (query, NULL, &format, NULL, stop); + if (format != GST_FORMAT_TIME) + *stop = -1; + } + gst_query_unref (query); + gst_object_unref (sink); + + return ret; + +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index ca8be0a520..1dbfdf3a4c 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -147,6 +147,12 @@ GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream *stream, gboolean gst_rtsp_stream_update_crypto (GstRTSPStream * stream, guint ssrc, GstCaps * crypto); + +gboolean gst_rtsp_stream_query_position (GstRTSPStream * stream, + gint64 * position); +gboolean gst_rtsp_stream_query_stop (GstRTSPStream * stream, + gint64 * stop); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object From 1b47b6d9b03bf93c3e5b0a2885c51851ef61d1e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 13 Aug 2014 17:22:16 +0300 Subject: [PATCH 1023/1776] rtsp-stream: Remove the multicast group udp sources when removing from the bin --- gst/rtsp-server/rtsp-stream.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 0b0257043d..68d7bec00b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1949,6 +1949,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, { GstRTSPStreamPrivate *priv; gint i; + GList *l; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); g_return_val_if_fail (GST_IS_BIN (bin), FALSE); @@ -1999,6 +2000,18 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); gst_bin_remove (bin, priv->udpsrc_v6[i]); } + + for (l = priv->transport_sources; l; l = l->next) { + GstRTSPMulticastTransportSource *s = l->data; + + if (!s->udpsrc[i]) + continue; + + gst_element_set_locked_state (s->udpsrc[i], FALSE); + gst_element_set_state (s->udpsrc[i], GST_STATE_NULL); + gst_bin_remove (bin, s->udpsrc[i]); + } + if (priv->udpsink[i]) gst_bin_remove (bin, priv->udpsink[i]); if (priv->appsrc[i]) @@ -2025,6 +2038,14 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->tee[i] = NULL; priv->funnel[i] = NULL; } + + for (l = priv->transport_sources; l; l = l->next) { + GstRTSPMulticastTransportSource *s = l->data; + g_slice_free (GstRTSPMulticastTransportSource, s); + } + g_list_free (priv->transport_sources); + priv->transport_sources = NULL; + gst_object_unref (priv->send_src[0]); priv->send_src[0] = NULL; From 09bf2025f810cdad3127162dcce80a7dc73099e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Thu, 28 Aug 2014 13:35:15 +0200 Subject: [PATCH 1024/1776] rtsp-client: Protect saved clients watch with a mutex Fixes a crash when close() is called while merging clients in handle_tunnel(). In that case close() would destroy the watch while it is still being used in handle_tunnel(). https://bugzilla.gnome.org/show_bug.cgi?id=735570 --- gst/rtsp-server/rtsp-client.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d37fb68497..77dc1d0156 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -59,6 +59,7 @@ struct _GstRTSPClientPrivate { GMutex lock; /* protects everything else */ GMutex send_lock; + GMutex watch_lock; GstRTSPConnection *connection; GstRTSPWatch *watch; GMainContext *watch_context; @@ -278,6 +279,7 @@ gst_rtsp_client_init (GstRTSPClient * client) g_mutex_init (&priv->lock); g_mutex_init (&priv->send_lock); + g_mutex_init (&priv->watch_lock); priv->close_seq = 0; priv->drop_backlog = DEFAULT_DROP_BACKLOG; } @@ -406,6 +408,7 @@ gst_rtsp_client_finalize (GObject * obj) g_free (priv->server_ip); g_mutex_clear (&priv->lock); g_mutex_clear (&priv->send_lock); + g_mutex_clear (&priv->watch_lock); G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj); } @@ -3164,7 +3167,9 @@ closed (GstRTSPWatch * watch, gpointer user_data) } gst_rtsp_watch_set_flushing (watch, TRUE); + g_mutex_lock (&priv->watch_lock); gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + g_mutex_unlock (&priv->watch_lock); return GST_RTSP_OK; } @@ -3284,6 +3289,7 @@ handle_tunnel (GstRTSPClient * client) opriv = oclient->priv; + g_mutex_lock (&opriv->watch_lock); if (opriv->watch == NULL) goto tunnel_closed; @@ -3293,6 +3299,7 @@ handle_tunnel (GstRTSPClient * client) gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection); gst_rtsp_watch_reset (priv->watch); gst_rtsp_watch_reset (opriv->watch); + g_mutex_unlock (&opriv->watch_lock); g_object_unref (oclient); /* the old client owns the tunnel now, the new one will be freed */ @@ -3312,6 +3319,7 @@ no_tunnelid: tunnel_closed: { GST_ERROR ("client %p: tunnel session %s was closed", client, tunnelid); + g_mutex_unlock (&opriv->watch_lock); g_object_unref (oclient); return FALSE; } From 376488d8c7d0a92c56065070f9003e699533c3e5 Mon Sep 17 00:00:00 2001 From: Srimanta Panda Date: Mon, 8 Sep 2014 09:26:23 +0200 Subject: [PATCH 1025/1776] rtsp-media: Make sure that sequence numbers are monotonic after pause The sequence number is not monotonic for RTP packets after pause. The reason is basepayloader generates a randon sequence number when the pipeline goes from ready to pause. With this fix generation of sequence number will be monotonic when going from pause to play request. https://bugzilla.gnome.org/show_bug.cgi?id=736017 --- gst/rtsp-server/rtsp-media.c | 14 ++++++++++++ gst/rtsp-server/rtsp-stream.c | 42 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 3 +++ 3 files changed, 59 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 48868f5464..6b81e254e5 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2713,6 +2713,14 @@ no_setup_sdp: } } +static void +do_set_seqnum (GstRTSPStream * stream) +{ + guint16 seq_num; + seq_num = gst_rtsp_stream_get_current_seqnum (stream); + gst_rtsp_stream_set_seqnum_offset (stream, seq_num + 1); +} + /* call with state_lock */ gboolean default_suspend (GstRTSPMedia * media) @@ -2735,6 +2743,12 @@ default_suspend (GstRTSPMedia * media) ret = set_target_state (media, GST_STATE_NULL, TRUE); if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; + /* Because payloader needs to set the sequence number as + * monotonic, we need to preserve the sequence number + * after pause. (otherwise going from pause to play, which + * is actually from NULL to PLAY will create a new sequence + * number. */ + g_ptr_array_foreach (priv->streams, (GFunc) do_set_seqnum, NULL); break; default: break; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 68d7bec00b..456ddd9941 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2576,6 +2576,48 @@ gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) return socket; } +/** + * gst_rtsp_stream_set_seqnum: + * @stream: a #GstRTSPStream + * @seqnum: a new sequence number + * + * Configure the sequence number in the payloader of @stream to @seqnum. + */ +void +gst_rtsp_stream_set_seqnum_offset (GstRTSPStream * stream, guint16 seqnum) +{ + GstRTSPStreamPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + priv = stream->priv; + + g_object_set (G_OBJECT (priv->payloader), "seqnum-offset", seqnum, NULL); +} + +/** + * gst_rtsp_stream_get_seqnum: + * @stream: a #GstRTSPStream + * + * Get the configured sequence number in the payloader of @stream. + * + * Returns: the sequence number of the payloader. + */ +guint16 +gst_rtsp_stream_get_current_seqnum (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + guint seqnum; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), 0); + + priv = stream->priv; + + g_object_get (G_OBJECT (priv->payloader), "seqnum", &seqnum, NULL); + + return seqnum; +} + /** * gst_rtsp_stream_transport_filter: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 1dbfdf3a4c..135689e114 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -153,6 +153,9 @@ gboolean gst_rtsp_stream_query_position (GstRTSPStream * stream, gboolean gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop); +void gst_rtsp_stream_set_seqnum_offset (GstRTSPStream *stream, guint16 seqnum); +guint16 gst_rtsp_stream_get_current_seqnum (GstRTSPStream *stream); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object From 4056897111ba9030450635ab658645fa3a69b40b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 15 Sep 2014 16:54:05 +0200 Subject: [PATCH 1026/1776] test: add example of dumping RTCP reports --- examples/test-mp4.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/examples/test-mp4.c b/examples/test-mp4.c index 52e082d862..bf88abe3f9 100644 --- a/examples/test-mp4.c +++ b/examples/test-mp4.c @@ -21,6 +21,61 @@ #include +/* called when a stream has received an RTCP packet from the client */ +static void +on_ssrc_active (GObject * session, GObject * source, GstRTSPMedia * media) +{ + GstStructure *stats; + + GST_INFO ("source %p in session %p is active", source, session); + + g_object_get (source, "stats", &stats, NULL); + if (stats) { + gchar *sstr; + + sstr = gst_structure_to_string (stats); + g_print ("structure: %s\n", sstr); + g_free (sstr); + + gst_structure_free (stats); + } +} + +/* signal callback when the media is prepared for streaming. We can get the + * session manager for each of the streams and connect to some signals. */ +static void +media_prepared_cb (GstRTSPMedia * media) +{ + guint i, n_streams; + + n_streams = gst_rtsp_media_n_streams (media); + + GST_INFO ("media %p is prepared and has %u streams", media, n_streams); + + for (i = 0; i < n_streams; i++) { + GstRTSPStream *stream; + GObject *session; + + stream = gst_rtsp_media_get_stream (media, i); + if (stream == NULL) + continue; + + session = gst_rtsp_stream_get_rtpsession (stream); + GST_INFO ("watching session %p on stream %u", session, i); + + g_signal_connect (session, "on-ssrc-active", + (GCallback) on_ssrc_active, media); + } +} + +static void +media_configure_cb (GstRTSPMediaFactory * factory, GstRTSPMedia * media) +{ + /* connect our prepared signal so that we can see when this media is + * prepared for streaming */ + g_signal_connect (media, "prepared", (GCallback) media_prepared_cb, factory); +} + int main (int argc, char *argv[]) { @@ -57,6 +112,8 @@ main (int argc, char *argv[]) * element with pay%d names will be a stream */ factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, str); + g_signal_connect (factory, "media-configure", (GCallback) media_configure_cb, + factory); g_free (str); /* attach the test factory to the /test url */ From ea5d4cfc7e29d010c0d7b6a2f606de76a6d117f4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Sep 2014 18:10:12 +0200 Subject: [PATCH 1027/1776] stream-transport: make method to handle received data Make a method to handle the data received on a channel. It sends the data to the stream of the transport on the RTP or RTCP pads based on the channel number. --- gst/rtsp-server/rtsp-stream-transport.c | 32 +++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream-transport.h | 3 +++ 2 files changed, 35 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index a99295bb35..cd0a1439b2 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -501,3 +501,35 @@ gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport * trans) if (priv->keep_alive) priv->keep_alive (priv->ka_user_data); } + +/** + * gst_rtsp_stream_transport_recv_data: + * @trans: a #GstRTSPStreamTransport + * @channel: a channel + * @buffer: (transfer full): a #GstBuffer + * + * Receive @buffer on @channel @trans. + * + * Returns: a #GstFlowReturn. Returns GST_FLOW_NOT_LINKED when @channel is not + * configured in the transport of @trans. + */ +GstFlowReturn +gst_rtsp_stream_transport_recv_data (GstRTSPStreamTransport * trans, + guint channel, GstBuffer * buffer) +{ + GstRTSPStreamTransportPrivate *priv; + const GstRTSPTransport *tr; + GstFlowReturn res; + + priv = trans->priv; + tr = priv->transport; + + if (tr->interleaved.min == channel) { + res = gst_rtsp_stream_recv_rtp (priv->stream, buffer); + } else if (tr->interleaved.max == channel) { + res = gst_rtsp_stream_recv_rtcp (priv->stream, buffer); + } else { + res = GST_FLOW_NOT_LINKED; + } + return res; +} diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 7735ee718f..c3ee257cf2 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -128,6 +128,9 @@ gboolean gst_rtsp_stream_transport_send_rtp (GstRTSPStreamT gboolean gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport *trans, GstBuffer *buffer); +GstFlowReturn gst_rtsp_stream_transport_recv_data (GstRTSPStreamTransport *trans, + guint channel, GstBuffer *buffer); + G_END_DECLS #endif /* __GST_RTSP_STREAM_TRANSPORT_H__ */ From 0292be09eaf338f16c752aee0c317b1e6b3971e2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Sep 2014 18:11:39 +0200 Subject: [PATCH 1028/1776] client: simplify session transport handling link/unlink of the transport in a session was done to keep track of all TCP transports and to send RTP/RTCP data to the streams. We can simplify that by putting all the TCP transports in a hashtable indexed with the channel number. We also don't need to link/unlink the transports when we pause/resume the streams. The same effect is already achieved when we pause/play the media. Indeed, when we pause the media, the transport is removed from the media and the callbacks will not be called anymore. See https://bugzilla.gnome.org/show_bug.cgi?id=736041 --- gst/rtsp-server/rtsp-client.c | 154 +++++----------------------------- 1 file changed, 23 insertions(+), 131 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 77dc1d0156..eb87c84d82 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -82,7 +82,7 @@ struct _GstRTSPClientPrivate gchar *path; GstRTSPMedia *media; - GList *transports; + GHashTable *transports; GList *sessions; guint sessions_cookie; @@ -134,8 +134,6 @@ static void gst_rtsp_client_set_property (GObject * object, guint propid, static void gst_rtsp_client_finalize (GObject * obj); static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media); -static void unlink_session_transports (GstRTSPClient * client, - GstRTSPSession * session, GstRTSPSessionMedia * sessmedia); static gboolean default_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media, GstRTSPStream * stream, GstRTSPContext * ctx); static gboolean default_configure_client_transport (GstRTSPClient * client, @@ -282,18 +280,15 @@ gst_rtsp_client_init (GstRTSPClient * client) g_mutex_init (&priv->watch_lock); priv->close_seq = 0; priv->drop_backlog = DEFAULT_DROP_BACKLOG; + priv->transports = g_hash_table_new (g_direct_hash, g_direct_equal); } static GstRTSPFilterResult filter_session_media (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia, gpointer user_data) { - GstRTSPClient *client = GST_RTSP_CLIENT (user_data); - gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL); - unlink_session_transports (client, sess, sessmedia); - /* unmanage the media in the session */ return GST_RTSP_FILTER_REMOVE; } @@ -386,6 +381,8 @@ gst_rtsp_client_finalize (GObject * obj) g_assert (priv->sessions == NULL); g_assert (priv->session_removed_id == 0); + g_hash_table_unref (priv->transports); + if (priv->connection) gst_rtsp_connection_free (priv->connection); if (priv->session_pool) { @@ -715,92 +712,6 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) return TRUE; } -static void -link_transport (GstRTSPClient * client, GstRTSPSession * session, - GstRTSPStreamTransport * trans) -{ - GstRTSPClientPrivate *priv = client->priv; - - GST_DEBUG ("client %p: linking transport %p", client, trans); - - gst_rtsp_stream_transport_set_callbacks (trans, - (GstRTSPSendFunc) do_send_data, - (GstRTSPSendFunc) do_send_data, client, NULL); - - priv->transports = g_list_prepend (priv->transports, trans); - - /* make sure our session can't expire */ - gst_rtsp_session_prevent_expire (session); -} - -static void -link_session_transports (GstRTSPClient * client, GstRTSPSession * session, - GstRTSPSessionMedia * sessmedia) -{ - guint n_streams, i; - - n_streams = - gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (sessmedia)); - for (i = 0; i < n_streams; i++) { - GstRTSPStreamTransport *trans; - const GstRTSPTransport *tr; - - /* get the transport, if there is no transport configured, skip this stream */ - trans = gst_rtsp_session_media_get_transport (sessmedia, i); - if (trans == NULL) - continue; - - tr = gst_rtsp_stream_transport_get_transport (trans); - - if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { - /* for TCP, link the stream to the TCP connection of the client */ - link_transport (client, session, trans); - } - } -} - -static void -unlink_transport (GstRTSPClient * client, GstRTSPSession * session, - GstRTSPStreamTransport * trans) -{ - GstRTSPClientPrivate *priv = client->priv; - - GST_DEBUG ("client %p: unlinking transport %p", client, trans); - - gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL); - - priv->transports = g_list_remove (priv->transports, trans); - - /* our session can now expire */ - gst_rtsp_session_allow_expire (session); -} - -static void -unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session, - GstRTSPSessionMedia * sessmedia) -{ - guint n_streams, i; - - n_streams = - gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (sessmedia)); - for (i = 0; i < n_streams; i++) { - GstRTSPStreamTransport *trans; - const GstRTSPTransport *tr; - - /* get the transport, if there is no transport configured, skip this stream */ - trans = gst_rtsp_session_media_get_transport (sessmedia, i); - if (trans == NULL) - continue; - - tr = gst_rtsp_stream_transport_get_transport (trans); - - if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { - /* for TCP, unlink the stream from the TCP connection of the client */ - unlink_transport (client, session, trans); - } - } -} - /** * gst_rtsp_client_close: * @client: a #GstRTSPClient @@ -895,9 +806,6 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) if (priv->watch != NULL) gst_rtsp_watch_set_flushing (priv->watch, TRUE); - /* unlink the all TCP callbacks */ - unlink_session_transports (client, session, sessmedia); - gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL); /* allow messages again so that we can send the reply */ @@ -1084,9 +992,6 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) rtspstate != GST_RTSP_STATE_RECORDING) goto invalid_state; - /* unlink the all TCP callbacks */ - unlink_session_transports (client, session, sessmedia); - /* then pause sending */ gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PAUSED); @@ -1223,9 +1128,6 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) } } - /* link the all TCP callbacks */ - link_session_transports (client, session, sessmedia); - /* grab RTPInfo from the media now */ rtpinfo = gst_rtsp_session_media_get_rtpinfo (sessmedia); @@ -1926,11 +1828,22 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) /* configure the url used to set this transport, this we will use when * generating the response for the PLAY request */ gst_rtsp_stream_transport_set_url (trans, uri); - /* configure keepalive for this transport */ gst_rtsp_stream_transport_set_keepalive (trans, (GstRTSPKeepAliveFunc) do_keepalive, session, NULL); + if (ct->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { + /* our callbacks to send data on this TCP connection */ + gst_rtsp_stream_transport_set_callbacks (trans, + (GstRTSPSendFunc) do_send_data, + (GstRTSPSendFunc) do_send_data, client, NULL); + + g_hash_table_insert (priv->transports, + GINT_TO_POINTER (ct->interleaved.min), trans); + g_hash_table_insert (priv->transports, + GINT_TO_POINTER (ct->interleaved.max), trans); + } + /* create and serialize the server transport */ st = make_server_transport (client, ctx, ct); trans_str = gst_rtsp_transport_as_text (st); @@ -2610,11 +2523,10 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) GstRTSPClientPrivate *priv = client->priv; GstRTSPResult res; guint8 channel; - GList *walk; guint8 *data; guint size; GstBuffer *buffer; - gboolean handled; + GstRTSPStreamTransport *trans; /* find the stream for this message */ res = gst_rtsp_message_parse_data (message, &channel); @@ -2625,33 +2537,13 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) buffer = gst_buffer_new_wrapped (data, size); - handled = FALSE; - for (walk = priv->transports; walk; walk = g_list_next (walk)) { - GstRTSPStreamTransport *trans; - GstRTSPStream *stream; - const GstRTSPTransport *tr; - - trans = walk->data; - - tr = gst_rtsp_stream_transport_get_transport (trans); - stream = gst_rtsp_stream_transport_get_stream (trans); - - /* check for TCP transport */ - if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { - /* dispatch to the stream based on the channel number */ - if (tr->interleaved.min == channel) { - gst_rtsp_stream_recv_rtp (stream, buffer); - handled = TRUE; - break; - } else if (tr->interleaved.max == channel) { - gst_rtsp_stream_recv_rtcp (stream, buffer); - handled = TRUE; - break; - } - } - } - if (!handled) + trans = g_hash_table_lookup (priv->transports, GINT_TO_POINTER (channel)); + if (trans) { + /* dispatch to the stream based on the channel number */ + gst_rtsp_stream_transport_recv_data (trans, channel, buffer); + } else { gst_buffer_unref (buffer); + } } /** From ebd9be59fe63b242d6c7f3c28088c73392927b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Tue, 16 Sep 2014 11:29:38 +0200 Subject: [PATCH 1029/1776] client: make define for the WATCH_BACKLOG See https://bugzilla.gnome.org/show_bug.cgi?id=736322 --- gst/rtsp-server/rtsp-client.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index eb87c84d82..d616e84ee3 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -92,6 +92,10 @@ struct _GstRTSPClientPrivate static GMutex tunnels_lock; static GHashTable *tunnels; /* protected by tunnels_lock */ +/* FIXME make this configurable. We don't want to do this yet because it will + * be superceeded by a cache object later */ +#define WATCH_BACKLOG_SIZE 100 + #define DEFAULT_SESSION_POOL NULL #define DEFAULT_MOUNT_POINTS NULL #define DEFAULT_DROP_BACKLOG TRUE @@ -3324,9 +3328,7 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) gst_rtsp_client_set_send_func (client, do_send_message, priv->watch, (GDestroyNotify) gst_rtsp_watch_unref); - /* FIXME make this configurable. We don't want to do this yet because it will - * be superceeded by a cache object later */ - gst_rtsp_watch_set_send_backlog (priv->watch, 0, 100); + gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); GST_INFO ("client %p: attaching to context %p", client, context); res = gst_rtsp_watch_attach (priv->watch, context); From 23b9d8fbb04ceff21110086528591849c728ae48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Tue, 16 Sep 2014 11:41:52 +0200 Subject: [PATCH 1030/1776] client: raise the backlog limits before pausing We need to raise the backlog limits before pausing the pipeline or else the appsink might be blocking in the render method in wait_backlog() and we would deadlock waiting for paused. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=736322 --- gst/rtsp-server/rtsp-client.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d616e84ee3..9cd69bcffd 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -961,6 +961,7 @@ bad_request: static gboolean handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) { + GstRTSPClientPrivate *priv = client->priv; GstRTSPSession *session; GstRTSPClientClass *klass; GstRTSPSessionMedia *sessmedia; @@ -996,6 +997,11 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) rtspstate != GST_RTSP_STATE_RECORDING) goto invalid_state; + /* No limit on watch queue because else we might be blocking in the appsink + * render method and the PAUSE below will hang */ + if (priv->watch != NULL) + gst_rtsp_watch_set_send_backlog (priv->watch, 0, 0); + /* then pause sending */ gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PAUSED); @@ -1006,6 +1012,9 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) send_message (client, ctx, ctx->response, FALSE); + if (priv->watch != NULL) + gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); + /* the state is now READY */ gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY); From 980553547d527fb149c6a8f8d1f9a23bd4d9c194 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 22 Sep 2014 09:30:39 +0200 Subject: [PATCH 1031/1776] rtsp-client: Make old compilers happy rtsp-client.c:2553:50: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] Just in case that guint8 doesn't fit in a pointer. Just in case ... --- gst/rtsp-server/rtsp-client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 9cd69bcffd..0e8b03dbac 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2550,7 +2550,8 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) buffer = gst_buffer_new_wrapped (data, size); - trans = g_hash_table_lookup (priv->transports, GINT_TO_POINTER (channel)); + trans = + g_hash_table_lookup (priv->transports, GINT_TO_POINTER ((gint) channel)); if (trans) { /* dispatch to the stream based on the channel number */ gst_rtsp_stream_transport_recv_data (trans, channel, buffer); From 733ef1162b78809751ccb327cbd0b07f46e6a42e Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Fri, 19 Sep 2014 18:28:30 +0200 Subject: [PATCH 1032/1776] rtsp-client: Allow backlog to grow while expiring session Allow the send backlog in the RTSP watch to grow to unlimited size while attempting to bring the media pipeline to NULL due to a session expiring. Without this change the appsink element cannot change state because it is blocked while rendering data in the new_sample callback. This callback will block until it has successfully put the data into the send backlog. There is a chance that the send backlog is full at this point which means that the callback may block for a long time, possibly forever. Therefore the media pipeline may also be prevented from changing state for a long time. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=736647 --- gst/rtsp-server/rtsp-client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 0e8b03dbac..3d4ce91134 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2211,7 +2211,11 @@ client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session, GST_INFO ("client %p: session %p removed", client, session); g_mutex_lock (&priv->lock); + if (priv->watch != NULL) + gst_rtsp_watch_set_send_backlog (priv->watch, 0, 0); client_unwatch_session (client, session, NULL); + if (priv->watch != NULL) + gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); g_mutex_unlock (&priv->lock); } From 2218510cae291dca6f27920583729f8cfaf276ff Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Fri, 19 Sep 2014 18:28:50 +0200 Subject: [PATCH 1033/1776] rtsp-*: Treat sending packets to clients as keepalive As long as gst-rtsp-server can successfully send RTP/RTCP data to clients then the client must be reading. This change makes the server timeout the connection if the client stops reading. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=736647 --- gst/rtsp-server/rtsp-client.c | 5 +++-- gst/rtsp-server/rtsp-session.c | 11 +++++++---- gst/rtsp-server/rtsp-stream-transport.c | 6 ++++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3d4ce91134..40295fe544 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -691,6 +691,7 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) { GstRTSPClientPrivate *priv = client->priv; GstRTSPMessage message = { 0 }; + GstRTSPResult res = GST_RTSP_OK; GstMapInfo map_info; guint8 *data; guint usize; @@ -705,7 +706,7 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) g_mutex_lock (&priv->send_lock); if (priv->send_func) - priv->send_func (client, &message, FALSE, priv->send_data); + res = priv->send_func (client, &message, FALSE, priv->send_data); g_mutex_unlock (&priv->send_lock); gst_rtsp_message_steal_body (&message, &data, &usize); @@ -713,7 +714,7 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) gst_rtsp_message_unset (&message); - return TRUE; + return res == GST_RTSP_OK; } /** diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 372746ae9b..1f4b650344 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -58,6 +58,7 @@ struct _GstRTSPSessionPrivate guint timeout; gboolean timeout_always_visible; GTimeVal create_time; /* immutable */ + GMutex last_access_lock; GTimeVal last_access; gint expire_count; @@ -132,6 +133,7 @@ gst_rtsp_session_init (GstRTSPSession * session) GST_INFO ("init session %p", session); g_mutex_init (&priv->lock); + g_mutex_init (&priv->last_access_lock); priv->timeout = DEFAULT_TIMEOUT; g_get_current_time (&priv->create_time); gst_rtsp_session_touch (session); @@ -153,6 +155,7 @@ gst_rtsp_session_finalize (GObject * obj) /* free session id */ g_free (priv->sessionid); + g_mutex_clear (&priv->last_access_lock); g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_session_parent_class)->finalize (obj); @@ -555,9 +558,9 @@ gst_rtsp_session_touch (GstRTSPSession * session) priv = session->priv; - g_mutex_lock (&priv->lock); + g_mutex_lock (&priv->last_access_lock); g_get_current_time (&priv->last_access); - g_mutex_unlock (&priv->lock); + g_mutex_unlock (&priv->last_access_lock); } /** @@ -608,7 +611,7 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) priv = session->priv; - g_mutex_lock (&priv->lock); + g_mutex_lock (&priv->last_access_lock); if (g_atomic_int_get (&priv->expire_count) != 0) { /* touch session when the expire count is not 0 */ g_get_current_time (&priv->last_access); @@ -617,7 +620,7 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) last_access = GST_TIMEVAL_TO_TIME (priv->last_access); /* add timeout allow for 5 seconds of extra time */ last_access += priv->timeout * GST_SECOND + (5 * GST_SECOND); - g_mutex_unlock (&priv->lock); + g_mutex_unlock (&priv->last_access_lock); now_ns = GST_TIMEVAL_TO_TIME (*now); diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index cd0a1439b2..c69de266db 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -456,6 +456,9 @@ gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport * trans, priv->send_rtp (buffer, priv->transport->interleaved.min, priv->user_data); + if (res) + gst_rtsp_stream_transport_keep_alive (trans); + return res; } @@ -482,6 +485,9 @@ gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport * trans, priv->send_rtcp (buffer, priv->transport->interleaved.max, priv->user_data); + if (res) + gst_rtsp_stream_transport_keep_alive (trans); + return res; } From 2745e6f65416de4b70e07875f00e94059c030821 Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Fri, 19 Sep 2014 18:29:00 +0200 Subject: [PATCH 1034/1776] tests: Extend unit test timeout to accomodate for valgrind Fixes https://bugzilla.gnome.org/show_bug.cgi?id=736647 --- tests/check/gst/rtspserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 28910f7e69..f95af4bf5b 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1431,7 +1431,7 @@ rtspserver_suite (void) suite_add_tcase (s, tc); tcase_add_checked_fixture (tc, setup, teardown); - tcase_set_timeout (tc, 20); + tcase_set_timeout (tc, 120); tcase_add_test (tc, test_connect); tcase_add_test (tc, test_describe); tcase_add_test (tc, test_describe_non_existing_mount_point); From 17f5785638edd7af241dc028ccb91331498b2cfb Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 22 Sep 2014 13:32:06 +0200 Subject: [PATCH 1035/1776] rtsp-client: do not free main context before rtsp watch https://bugzilla.gnome.org/show_bug.cgi?id=737110 --- gst/rtsp-server/rtsp-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 40295fe544..df02258364 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -750,6 +750,8 @@ gst_rtsp_client_close (GstRTSPClient * client) g_source_destroy ((GSource *) priv->watch); priv->watch = NULL; gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + g_main_context_unref (priv->watch_context); + priv->watch_context = NULL; } } @@ -3301,8 +3303,6 @@ client_watch_notify (GstRTSPClient * client) GST_INFO ("client %p: watch destroyed", client); priv->watch = NULL; - g_main_context_unref (priv->watch_context); - priv->watch_context = NULL; /* remove all sessions and so drop the extra client ref */ gst_rtsp_client_session_filter (client, cleanup_session, NULL); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL); From 404a80e38a508c13a9e9b7f9b1da70f3ccb2a77b Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Tue, 30 Sep 2014 01:35:02 +0200 Subject: [PATCH 1036/1776] rtsp-client: Remove backlog limit while processings requests If the backlog limit is kept two cases of deadlocks may be encountered when streaming over TCP. Without the backlog limit this deadlocks can not happen, at the expence of memory usage. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=737631 --- gst/rtsp-server/rtsp-client.c | 47 ++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index df02258364..aa0ab982fe 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -964,7 +964,6 @@ bad_request: static gboolean handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) { - GstRTSPClientPrivate *priv = client->priv; GstRTSPSession *session; GstRTSPClientClass *klass; GstRTSPSessionMedia *sessmedia; @@ -1000,11 +999,6 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) rtspstate != GST_RTSP_STATE_RECORDING) goto invalid_state; - /* No limit on watch queue because else we might be blocking in the appsink - * render method and the PAUSE below will hang */ - if (priv->watch != NULL) - gst_rtsp_watch_set_send_backlog (priv->watch, 0, 0); - /* then pause sending */ gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PAUSED); @@ -1015,9 +1009,6 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) send_message (client, ctx, ctx->response, FALSE); - if (priv->watch != NULL) - gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); - /* the state is now READY */ gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY); @@ -2375,6 +2366,37 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) if (!check_request_requirements (ctx->request, &unsupported_reqs)) goto unsupported_requirement; + /* the backlog must be unlimited while processing requests. + * the causes of this are two cases of deadlocks while streaming over TCP: + * + * 1. consider the scenario where the media pipeline's streaming thread + * is blocking in the appsink (taking the appsink's preroll lock) because + * the backlog is full. when a PAUSE request is received by the RTSP + * client thread then the the state of the session media ought to change + * to PAUSED. while most elements in the pipeline can change state this + * can never happen for the appsink since its preroll lock is taken by + * another thread. + * + * 2. consider the scenario where the media pipeline's streaming thread + * is blocking in the appsink new_sample callback (taking the send lock + * in RTSP client) because the backlog is full. when e.g. a GET request + * is received by the RTSP client thread then a response ought to be sent + * but this can never happen since it requires taking the send lock + * already taken by another thread. + * + * the reason that the backlog is never emptied is that the source used + * for dequeing messages from the backlog is never dispatched because it + * is attached to the same mainloop as the source receving RTSP requests and + * therefore run by the RTSP client thread which is alreayd blocking. + * + * without significant changes the easiest way to cope with this is to + * not block indefinitely when the backlog is full, but rather let the + * backlog grow in size. this in effect means that there can not be any + * upper boundary on its size. + */ + if (priv->watch != NULL) + gst_rtsp_watch_set_send_backlog (priv->watch, 0, 0); + /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: @@ -2404,12 +2426,19 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) case GST_RTSP_ANNOUNCE: case GST_RTSP_RECORD: case GST_RTSP_REDIRECT: + if (priv->watch != NULL) + gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); goto not_implemented; case GST_RTSP_INVALID: default: + if (priv->watch != NULL) + gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); goto bad_request; } + if (priv->watch != NULL) + gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); + done: if (ctx == &sctx) gst_rtsp_context_pop_current (ctx); From d48e022c137fea5480462f1433b9e44c113e2805 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Tue, 30 Sep 2014 19:17:04 +0200 Subject: [PATCH 1037/1776] media: set state to unpreparing when unprepare is initiated https://bugzilla.gnome.org/show_bug.cgi?id=737675 --- gst/rtsp-server/rtsp-media.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 6b81e254e5..1b80729ac9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2471,6 +2471,7 @@ default_unprepare (GstRTSPMedia * media) /* we need to go to playing again for the EOS to propagate, normally in this * state, nothing is receiving data from us anymore so this is ok. */ set_state (media, GST_STATE_PLAYING); + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_UNPREPARING); } else { finish_unprepare (media); } @@ -2511,8 +2512,6 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) set_target_state (media, GST_STATE_NULL, FALSE); success = TRUE; - gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_UNPREPARING); - if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) { GstRTSPMediaClass *klass; From 1badcd83c346391985432d51ece51ba7fa3eb09e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 30 Sep 2014 23:22:45 +0300 Subject: [PATCH 1038/1776] rtsp-media: Set state to UNPREPARING in all cases --- gst/rtsp-server/rtsp-media.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1b80729ac9..3c573897cf 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2464,6 +2464,8 @@ default_unprepare (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_UNPREPARING); + if (priv->eos_shutdown) { GST_DEBUG ("sending EOS for shutdown"); /* ref so that we don't disappear */ @@ -2471,7 +2473,6 @@ default_unprepare (GstRTSPMedia * media) /* we need to go to playing again for the EOS to propagate, normally in this * state, nothing is receiving data from us anymore so this is ok. */ set_state (media, GST_STATE_PLAYING); - gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_UNPREPARING); } else { finish_unprepare (media); } From 6c0c90c9d22a3c969e364d559f0a4174931bd08f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Tue, 30 Sep 2014 16:36:51 -0700 Subject: [PATCH 1039/1776] client: set session media to NULL without the lock We need to set session medias to NULL without the client lock otherwise we can end up in a deadlock if another thread is waiting for the lock and media unprepare is also waiting for that thread to end. https://bugzilla.gnome.org/show_bug.cgi?id=737690 --- gst/rtsp-server/rtsp-client.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index aa0ab982fe..b00993ae35 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -346,9 +346,6 @@ client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session, priv->session_removed_id = 0; } - /* unlink all media managed in this session */ - gst_rtsp_session_filter (session, filter_session_media, client); - /* remove the session */ g_object_unref (session); } @@ -357,6 +354,10 @@ static GstRTSPFilterResult cleanup_session (GstRTSPClient * client, GstRTSPSession * sess, gpointer user_data) { + /* unlink all media managed in this session. This needs to happen + * without the client lock, so we really want to do it here. */ + gst_rtsp_session_filter (sess, filter_session_media, client); + return GST_RTSP_FILTER_REMOVE; } From dde6a899287df2689473293d2174d63f64375fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 10 Oct 2014 18:43:00 -0400 Subject: [PATCH 1040/1776] rtsp-sdp: Rename clock-base and seqnum-base to timestamp-offset and seqnum-offset These were renamed in GstRTPBasePayload in 1.0 --- gst/rtsp-server/rtsp-sdp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 07aea903df..d2551c03d4 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -332,9 +332,9 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, continue; if (!strcmp (fname, "ssrc")) continue; - if (!strcmp (fname, "clock-base")) + if (!strcmp (fname, "timestamp-offset")) continue; - if (!strcmp (fname, "seqnum-base")) + if (!strcmp (fname, "seqnum-offset")) continue; if (g_str_has_prefix (fname, "srtp-")) continue; From 966065a018ee7abd3bbab6172d3a3e94abc027b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Thu, 2 Oct 2014 12:02:48 -0700 Subject: [PATCH 1041/1776] stream: release lock even not all transports have been removed We don't want to keep the lock even we return FALSE because not all the transports have been removed. This could lead into a deadlock. https://bugzilla.gnome.org/show_bug.cgi?id=737797 --- gst/rtsp-server/rtsp-stream.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 456ddd9941..be66e13466 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1962,7 +1962,8 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, goto was_not_joined; /* all transports must be removed by now */ - g_return_val_if_fail (priv->transports == NULL, FALSE); + if (priv->transports != NULL) + goto transports_not_removed; clear_tr_cache (priv); @@ -2072,6 +2073,12 @@ was_not_joined: g_mutex_unlock (&priv->lock); return TRUE; } +transports_not_removed: + { + GST_ERROR_OBJECT (stream, "can't leave bin (transports not removed)"); + g_mutex_unlock (&priv->lock); + return FALSE; + } } /** From 0aad92531d3970aa3d7d901ab885717e4e6ac485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Mon, 20 Oct 2014 15:40:59 -0700 Subject: [PATCH 1042/1776] rtsp-client: add stream transport to context We add the stream transport to the context so we can get the configured client stream transport in the setup request signal. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=738905 --- gst/rtsp-server/rtsp-client.c | 2 ++ gst/rtsp-server/rtsp-context.h | 32 +++++++++++++++++--------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b00993ae35..2b5895bb24 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1833,6 +1833,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) /* set in the session media transport */ trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct); + ctx->trans = trans; + /* configure the url used to set this transport, this we will use when * generating the response for the PLAY request */ gst_rtsp_stream_transport_set_url (trans, uri); diff --git a/gst/rtsp-server/rtsp-context.h b/gst/rtsp-server/rtsp-context.h index c2be87edc5..d21c31ae55 100644 --- a/gst/rtsp-server/rtsp-context.h +++ b/gst/rtsp-server/rtsp-context.h @@ -53,27 +53,29 @@ typedef struct _GstRTSPContext GstRTSPContext; * @media: the media for the url can be %NULL * @stream: the stream for the url can be %NULL * @response: the response + * @trans: the stream transport, can be %NULL * * Information passed around containing the context of a request. */ struct _GstRTSPContext { - GstRTSPServer *server; - GstRTSPConnection *conn; - GstRTSPClient *client; - GstRTSPMessage *request; - GstRTSPUrl *uri; - GstRTSPMethod method; - GstRTSPAuth *auth; - GstRTSPToken *token; - GstRTSPSession *session; - GstRTSPSessionMedia *sessmedia; - GstRTSPMediaFactory *factory; - GstRTSPMedia *media; - GstRTSPStream *stream; - GstRTSPMessage *response; + GstRTSPServer *server; + GstRTSPConnection *conn; + GstRTSPClient *client; + GstRTSPMessage *request; + GstRTSPUrl *uri; + GstRTSPMethod method; + GstRTSPAuth *auth; + GstRTSPToken *token; + GstRTSPSession *session; + GstRTSPSessionMedia *sessmedia; + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPStream *stream; + GstRTSPMessage *response; + GstRTSPStreamTransport *trans; /*< private >*/ - gpointer _gst_reserved[GST_PADDING]; + gpointer _gst_reserved[GST_PADDING - 1]; }; GType gst_rtsp_context_get_type (void); From f803be2dc84b3d3dc16e58582b96c4809aab3c29 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 1 Oct 2014 07:12:30 -0400 Subject: [PATCH 1043/1776] rtsp-media: deactivate media when shutting down from paused This was only done when going directly from playing. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=737829 --- gst/rtsp-server/rtsp-media.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 3c573897cf..85010dcb12 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2997,11 +2997,16 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, activate = deactivate = FALSE; - GST_INFO ("going to state %s media %p", gst_element_state_get_name (state), - media); + GST_INFO ("going to state %s media %p, target state %s", + gst_element_state_get_name (state), media, + gst_element_state_get_name (priv->target_state)); switch (state) { case GST_STATE_NULL: + /* we're going from PLAYING or PAUSED to READY or NULL, deactivate */ + if (priv->target_state >= GST_STATE_PAUSED) + deactivate = TRUE; + break; case GST_STATE_PAUSED: /* we're going from PLAYING to PAUSED, READY or NULL, deactivate */ if (priv->target_state == GST_STATE_PLAYING) @@ -3016,6 +3021,8 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, } old_active = priv->n_active; + GST_DEBUG ("%d transports, activate %d, deactivate %d", transports->len, + activate, deactivate); for (i = 0; i < transports->len; i++) { GstRTSPStreamTransport *trans; From 8caa8679e9ce9b22e8617cf9048250ea1bca1c60 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 21 Oct 2014 13:00:49 +0200 Subject: [PATCH 1044/1776] Automatic update of common submodule From 36388a1 to a8c8939 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 36388a18d3..a8c89390ae 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 36388a18d37d72f9633bf1a8c06d18d310d215bb +Subproject commit a8c89390ae462951f3f94997955d5319028f26d3 From 39c0feb83fac518ec2b4702d476d64687061de82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 21 Oct 2014 13:04:14 +0100 Subject: [PATCH 1045/1776] Automatic update of common submodule From a8c8939 to 84d06cd --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index a8c89390ae..84d06cd7a0 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit a8c89390ae462951f3f94997955d5319028f26d3 +Subproject commit 84d06cd7a0e6b0857009858574aa21bb56309efb From f57e8fc57003a7961e89174ca398cff48f5268a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 24 Oct 2014 17:48:04 +0100 Subject: [PATCH 1046/1776] Parallelise 'make check-valgrind' --- Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index d331c8d3be..43483edc54 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,13 +26,13 @@ include $(top_srcdir)/common/po.mak include $(top_srcdir)/common/coverage/lcov.mak check-valgrind: - cd tests/check && make check-valgrind + $(MAKE) -C tests/check check-valgrind if HAVE_CHECK check-torture: - cd tests/check && make torture + $(MAKE) -C tests/check torture build-checks: - cd tests/check && make build-checks + $(MAKE) -C tests/check build-checks else check-torture: true From bfc4d54404c5e2bbbe3297bb77cda2ae7f7b1369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 27 Oct 2014 18:01:35 +0100 Subject: [PATCH 1047/1776] Automatic update of common submodule From 84d06cd to 7bb2bce --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 84d06cd7a0..7bb2bcecda 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 84d06cd7a0e6b0857009858574aa21bb56309efb +Subproject commit 7bb2bcecda471a0d514a964365a78150f3ee5747 From ef9dc6c9e4fdf1b349a76ad9f39da168a1906355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Wed, 29 Oct 2014 21:01:39 -0700 Subject: [PATCH 1048/1776] rtsp-client: mikey memory leaks https://bugzilla.gnome.org/show_bug.cgi?id=739383 --- gst/rtsp-server/rtsp-client.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 2b5895bb24..934a3a7a63 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1607,6 +1607,7 @@ handle_mikey_data (GstRTSPClient * client, GstRTSPContext * ctx, gst_caps_unref (caps); } gst_mikey_message_unref (msg); + gst_buffer_unref (key); return TRUE; @@ -1694,7 +1695,9 @@ handle_keymgmt (GstRTSPClient * client, GstRTSPContext * ctx, gchar * keymgmt) handle_mikey_data (client, ctx, data, size); } } + g_strfreev (split); } + g_strfreev (specs); return TRUE; } From 7c267928ff8a74c15fe0821985c96d9fcda97f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Fri, 31 Oct 2014 23:01:53 -0700 Subject: [PATCH 1049/1776] rtsp-stream: unref srtp decoder when leaving bin https://bugzilla.gnome.org/show_bug.cgi?id=739481 --- gst/rtsp-server/rtsp-stream.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index be66e13466..2d237d11dd 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2062,6 +2062,8 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, if (priv->srtpenc) gst_object_unref (priv->srtpenc); + if (priv->srtpdec) + gst_object_unref (priv->srtpdec); priv->is_joined = FALSE; g_mutex_unlock (&priv->lock); From a455181aff9231c4a00777f456a80d6de1019f05 Mon Sep 17 00:00:00 2001 From: Linus Svensson Date: Thu, 23 Oct 2014 12:54:03 +0200 Subject: [PATCH 1050/1776] client: Stop caching media in client when doing setup If the media has been managed by a session media, it should not be cached in the client any longer. The GstRTSPSessionMedia object is now responsible for unpreparing the GstRTSPMedia object using gst_rtsp_media_unprepare(). Unprepare the media when finalizing the session media. https://bugzilla.gnome.org/show_bug.cgi?id=739112 --- gst/rtsp-server/rtsp-client.c | 8 ++++++++ gst/rtsp-server/rtsp-session-media.c | 2 ++ 2 files changed, 10 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 934a3a7a63..c26bf6c008 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1827,6 +1827,14 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) /* if we stil have no media, error */ if (sessmedia == NULL) goto sessmedia_unavailable; + + /* don't cache media anymore */ + if (priv->path) + g_free (priv->path); + priv->path = NULL; + if (priv->media) + g_object_unref (priv->media); + priv->media = NULL; } else { g_object_unref (media); } diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 8eb1f2879f..e319241aa9 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -104,6 +104,8 @@ gst_rtsp_session_media_finalize (GObject * obj) gst_rtsp_session_media_set_state (media, GST_STATE_NULL); + gst_rtsp_media_unprepare (priv->media); + g_ptr_array_unref (priv->transports); g_free (priv->path); From 088eee65900cd53135be0ee7b41068f5b919ecbd Mon Sep 17 00:00:00 2001 From: Linus Svensson Date: Fri, 24 Oct 2014 12:04:54 +0200 Subject: [PATCH 1051/1776] client: Configure transport after creating session media The default implementation of configure_client_transport() in rtsp-client uses the session media when it chooses channels for interleaved traffic. https://bugzilla.gnome.org/show_bug.cgi?id=739112 --- gst/rtsp-server/rtsp-client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c26bf6c008..c50444c6c4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1810,10 +1810,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!parse_transport (transport, stream, ct)) goto unsupported_transports; - /* update the client transport */ - if (!klass->configure_client_transport (client, ctx, ct)) - goto unsupported_client_transport; - /* parse the keymgmt */ if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_KEYMGMT, &keymgmt, 0) == GST_RTSP_OK) { @@ -1841,6 +1837,10 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; + /* update the client transport */ + if (!klass->configure_client_transport (client, ctx, ct)) + goto unsupported_client_transport; + /* set in the session media transport */ trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct); From df5850f9661a840b270feeb40c88bed244eb4225 Mon Sep 17 00:00:00 2001 From: Linus Svensson Date: Fri, 24 Oct 2014 12:05:27 +0200 Subject: [PATCH 1052/1776] tests: Test setup with tcp transport https://bugzilla.gnome.org/show_bug.cgi?id=739112 --- tests/check/gst/rtspserver.c | 103 +++++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 10 deletions(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index f95af4bf5b..b8e57531fe 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -40,6 +40,7 @@ #define TEST_MOUNT_POINT "/test" #define TEST_PROTO "RTP/AVP" +#define TEST_PROTO_TCP "RTP/AVP/TCP" #define TEST_ENCODING "X-GST" #define TEST_CLOCK_RATE "90000" @@ -432,8 +433,9 @@ do_describe (GstRTSPConnection * conn, const gchar * mount_point) * transport must be freed by the caller. */ static GstRTSPStatusCode do_setup_full (GstRTSPConnection * conn, const gchar * control, - const GstRTSPRange * client_ports, const gchar * require, gchar ** session, - GstRTSPTransport ** transport, gchar ** unsupported) + gboolean use_tcp_transport, const GstRTSPRange * client_ports, + const gchar * require, gchar ** session, GstRTSPTransport ** transport, + gchar ** unsupported) { GstRTSPStatusCode code; gchar *session_in = NULL; @@ -449,9 +451,15 @@ do_setup_full (GstRTSPConnection * conn, const gchar * control, session_out = session; } } - transport_string_in = + + if (use_tcp_transport) { + transport_string_in = + g_strdup_printf (TEST_PROTO_TCP ";unicast"); + } else { + transport_string_in = g_strdup_printf (TEST_PROTO ";unicast;client_port=%d-%d", client_ports->min, client_ports->max); + } code = do_request_full (conn, GST_RTSP_SETUP, control, session_in, transport_string_in, NULL, require, NULL, NULL, NULL, session_out, @@ -478,7 +486,19 @@ do_setup (GstRTSPConnection * conn, const gchar * control, const GstRTSPRange * client_ports, gchar ** session, GstRTSPTransport ** transport) { - return do_setup_full (conn, control, client_ports, NULL, session, transport, + return do_setup_full (conn, control, FALSE, client_ports, NULL, session, + transport, NULL); +} + +/* send a SETUP request and receive response. if *session is not NULL, + * it is used in the request. otherwise, *session is set to a returned + * session string that must be freed by the caller. the returned + * transport must be freed by the caller. */ +static GstRTSPStatusCode +do_setup_tcp (GstRTSPConnection * conn, const gchar * control, + gchar ** session, GstRTSPTransport ** transport) +{ + return do_setup_full (conn, control, TRUE, NULL, NULL, session, transport, NULL); } @@ -661,6 +681,68 @@ GST_START_TEST (test_setup) GST_END_TEST; +GST_START_TEST (test_setup_tcp) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + const gchar *audio_control; + gchar *session = NULL; + GstRTSPTransport *video_transport = NULL; + GstRTSPTransport *audio_transport = NULL; + + start_server (); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + sdp_media = gst_sdp_message_get_media (sdp_message, 1); + audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + /* send SETUP request for video */ + fail_unless (do_setup_tcp (conn, video_control, &session, + &video_transport) == GST_RTSP_STS_OK); + GST_DEBUG ("set up video %s, got session '%s'", video_control, session); + + /* check response from SETUP */ + fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP); + fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP); + fail_unless (video_transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP); + fail_unless (video_transport->mode_play); + gst_rtsp_transport_free (video_transport); + + /* send SETUP request for audio */ + fail_unless (do_setup_tcp (conn, audio_control, &session, + &audio_transport) == GST_RTSP_STS_OK); + GST_DEBUG ("set up audio %s with session '%s'", audio_control, session); + + /* check response from SETUP */ + fail_unless (audio_transport->trans == GST_RTSP_TRANS_RTP); + fail_unless (audio_transport->profile == GST_RTSP_PROFILE_AVP); + fail_unless (audio_transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP); + fail_unless (audio_transport->mode_play); + gst_rtsp_transport_free (audio_transport); + + /* send TEARDOWN request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session) == GST_RTSP_STS_OK); + + /* clean up and iterate so the clean-up can finish */ + g_free (session); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); +} + +GST_END_TEST; + GST_START_TEST (test_setup_with_require_header) { GstRTSPConnection *conn; @@ -686,17 +768,17 @@ GST_START_TEST (test_setup_with_require_header) get_client_ports (&client_ports); /* send SETUP request for video, with single Require header */ - fail_unless_equals_int (do_setup_full (conn, video_control, &client_ports, - "funky-feature", &session, &video_transport, &unsupported), - GST_RTSP_STS_OPTION_NOT_SUPPORTED); + fail_unless_equals_int (do_setup_full (conn, video_control, FALSE, + &client_ports, "funky-feature", &session, &video_transport, + &unsupported), GST_RTSP_STS_OPTION_NOT_SUPPORTED); fail_unless_equals_string (unsupported, "funky-feature"); g_free (unsupported); unsupported = NULL; /* send SETUP request for video, with multiple Require headers */ - fail_unless_equals_int (do_setup_full (conn, video_control, &client_ports, - "funky-feature, foo-bar, superburst", &session, &video_transport, - &unsupported), GST_RTSP_STS_OPTION_NOT_SUPPORTED); + fail_unless_equals_int (do_setup_full (conn, video_control, FALSE, + &client_ports, "funky-feature, foo-bar, superburst", &session, + &video_transport, &unsupported), GST_RTSP_STS_OPTION_NOT_SUPPORTED); fail_unless_equals_string (unsupported, "funky-feature, foo-bar, superburst"); g_free (unsupported); unsupported = NULL; @@ -1436,6 +1518,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_describe); tcase_add_test (tc, test_describe_non_existing_mount_point); tcase_add_test (tc, test_setup); + tcase_add_test (tc, test_setup_tcp); tcase_add_test (tc, test_setup_with_require_header); tcase_add_test (tc, test_setup_non_existing_stream); tcase_add_test (tc, test_play); From d1ea01d4c6f5621c47ba3b4acc6b4e269b47b016 Mon Sep 17 00:00:00 2001 From: Linus Svensson Date: Thu, 23 Oct 2014 17:54:37 +0200 Subject: [PATCH 1053/1776] tests: Test to setup two sessions on one connection https://bugzilla.gnome.org/show_bug.cgi?id=739112 --- tests/check/gst/rtspserver.c | 73 ++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index b8e57531fe..b6ce2235c6 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -743,6 +743,78 @@ GST_START_TEST (test_setup_tcp) GST_END_TEST; +GST_START_TEST (test_setup_twice) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message; + const GstSDPMedia *sdp_media; + const gchar *video_control; + GstRTSPRange client_ports; + GstRTSPTransport *video_transport = NULL; + gchar *session1 = NULL; + gchar *session2 = NULL; + + start_server (); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + /* we wan't more than one session for this connection */ + gst_rtsp_connection_set_remember_session_id (conn, FALSE); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get the control url */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports (&client_ports); + + /* send SETUP request for one session */ + fail_unless (do_setup (conn, video_control, &client_ports, &session1, + &video_transport) == GST_RTSP_STS_OK); + GST_DEBUG ("set up video %s, got session '%s'", video_control, session1); + + /* check response from SETUP */ + fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP); + fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP); + fail_unless (video_transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP); + fail_unless (video_transport->mode_play); + gst_rtsp_transport_free (video_transport); + + /* send SETUP request for another session */ + fail_unless (do_setup (conn, video_control, &client_ports, &session2, + &video_transport) == GST_RTSP_STS_OK); + GST_DEBUG ("set up video %s, got session '%s'", video_control, session2); + + /* check response from SETUP */ + fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP); + fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP); + fail_unless (video_transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP); + fail_unless (video_transport->mode_play); + gst_rtsp_transport_free (video_transport); + + /* session can not be the same */ + fail_unless (strcmp (session1, session2)); + + /* send TEARDOWN request for the first session*/ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session1) == GST_RTSP_STS_OK); + + /* send TEARDOWN request for the second session */ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session2) == GST_RTSP_STS_OK); + + g_free (session1); + g_free (session2); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); +} + +GST_END_TEST; + GST_START_TEST (test_setup_with_require_header) { GstRTSPConnection *conn; @@ -1519,6 +1591,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_describe_non_existing_mount_point); tcase_add_test (tc, test_setup); tcase_add_test (tc, test_setup_tcp); + tcase_add_test (tc, test_setup_twice); tcase_add_test (tc, test_setup_with_require_header); tcase_add_test (tc, test_setup_non_existing_stream); tcase_add_test (tc, test_play); From 1a004c5d4650f79638112a1bf3203d54a2454b4d Mon Sep 17 00:00:00 2001 From: Linus Svensson Date: Thu, 23 Oct 2014 13:39:10 +0200 Subject: [PATCH 1054/1776] tests: Remove FIXME The session leak is now fixed, lets remove those FIXME comments. --- tests/check/gst/client.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 1bbd67d80e..6d392a7582 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -654,7 +654,6 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) session_pool = gst_rtsp_client_get_session_pool (client); fail_unless (session_pool != NULL); - /* FIXME: There seems to be a leak of a session here ! */ fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); g_object_unref (session_pool); @@ -675,7 +674,6 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) session_pool = gst_rtsp_client_get_session_pool (client); fail_unless (session_pool != NULL); - /* FIXME: There seems to be a leak of a session here ! */ fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); g_object_unref (session_pool); @@ -696,7 +694,6 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) session_pool = gst_rtsp_client_get_session_pool (client); fail_unless (session_pool != NULL); - /* FIXME: There seems to be a leak of a session here ! */ fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); g_object_unref (session_pool); From bd8b2d3fb93961b90760dc60cf1dd4b0ddb2ecaf Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 7 Nov 2014 12:48:53 +0100 Subject: [PATCH 1055/1776] client: refactor cleanup of cached media --- gst/rtsp-server/rtsp-client.c | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c50444c6c4..f97a642ebe 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -361,6 +361,23 @@ cleanup_session (GstRTSPClient * client, GstRTSPSession * sess, return GST_RTSP_FILTER_REMOVE; } +static void +clean_cached_media (GstRTSPClient * client, gboolean unprepare) +{ + GstRTSPClientPrivate *priv = client->priv; + + if (priv->path) { + g_free (priv->path); + priv->path = NULL; + } + if (priv->media) { + if (unprepare) + gst_rtsp_media_unprepare (priv->media); + g_object_unref (priv->media); + priv->media = NULL; + } +} + /* A client is finalized when the connection is broken */ static void gst_rtsp_client_finalize (GObject * obj) @@ -400,12 +417,7 @@ gst_rtsp_client_finalize (GObject * obj) if (priv->thread_pool) g_object_unref (priv->thread_pool); - if (priv->path) - g_free (priv->path); - if (priv->media) { - gst_rtsp_media_unprepare (priv->media); - g_object_unref (priv->media); - } + clean_cached_media (client, TRUE); g_free (priv->server_ip); g_mutex_clear (&priv->lock); @@ -595,14 +607,7 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path, /* remove any previously cached values before we try to construct a new * media for uri */ - if (priv->path) - g_free (priv->path); - priv->path = NULL; - if (priv->media) { - gst_rtsp_media_unprepare (priv->media); - g_object_unref (priv->media); - } - priv->media = NULL; + clean_cached_media (client, TRUE); /* prepare the media and add it to the pipeline */ if (!(media = gst_rtsp_media_factory_construct (factory, ctx->uri))) @@ -1825,12 +1830,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) goto sessmedia_unavailable; /* don't cache media anymore */ - if (priv->path) - g_free (priv->path); - priv->path = NULL; - if (priv->media) - g_object_unref (priv->media); - priv->media = NULL; + clean_cached_media (client, FALSE); } else { g_object_unref (media); } From 6ba01ef0efc300fdf06ba877165818096959e88c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 27 Nov 2014 17:13:05 +0100 Subject: [PATCH 1056/1776] Automatic update of common submodule From 7bb2bce to ef1ffdc --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 7bb2bcecda..ef1ffdcc6e 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 7bb2bcecda471a0d514a964365a78150f3ee5747 +Subproject commit ef1ffdcc6e6fca1f512f923a94c990e3534ba9a5 From 058698c9cf07234857c0068ec483f09cc8e107fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Fri, 28 Nov 2014 12:45:14 +0100 Subject: [PATCH 1057/1776] rtsp: Ref transports in hash table. Also ref streams for transports. This solves a crash when reciving a rtcp after teardown but before client finalize. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=740845 --- gst/rtsp-server/rtsp-client.c | 6 +++++- gst/rtsp-server/rtsp-stream-transport.c | 4 ++++ gst/rtsp-server/rtsp-stream.c | 5 ++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f97a642ebe..3885ee98fd 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -284,7 +284,9 @@ gst_rtsp_client_init (GstRTSPClient * client) g_mutex_init (&priv->watch_lock); priv->close_seq = 0; priv->drop_backlog = DEFAULT_DROP_BACKLOG; - priv->transports = g_hash_table_new (g_direct_hash, g_direct_equal); + priv->transports = + g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, + g_object_unref); } static GstRTSPFilterResult @@ -1861,8 +1863,10 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) g_hash_table_insert (priv->transports, GINT_TO_POINTER (ct->interleaved.min), trans); + g_object_ref (trans); g_hash_table_insert (priv->transports, GINT_TO_POINTER (ct->interleaved.max), trans); + g_object_ref (trans); } /* create and serialize the server transport */ diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index c69de266db..0498830ea4 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -118,6 +118,9 @@ gst_rtsp_stream_transport_finalize (GObject * obj) gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL); gst_rtsp_stream_transport_set_keepalive (trans, NULL, NULL, NULL); + if (priv->stream) + g_object_unref (priv->stream); + if (priv->transport) gst_rtsp_transport_free (priv->transport); @@ -149,6 +152,7 @@ gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr) trans = g_object_new (GST_TYPE_RTSP_STREAM_TRANSPORT, NULL); priv = trans->priv; priv->stream = stream; + priv->stream = g_object_ref (priv->stream); priv->transport = tr; return trans; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 2d237d11dd..f2ac3db492 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2249,8 +2249,11 @@ gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer) g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR); priv = stream->priv; g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); - g_return_val_if_fail (priv->is_joined, FALSE); + if (!priv->is_joined) { + gst_buffer_unref (buffer); + return GST_FLOW_NOT_LINKED; + } g_mutex_lock (&priv->lock); if (priv->appsrc[1]) element = gst_object_ref (priv->appsrc[1]); From 4f40781fff4f74ca80f202b3b6e435ff9a86ee1e Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Thu, 27 Nov 2014 01:12:36 +1100 Subject: [PATCH 1058/1776] media: implement ssrc-multiplexed retransmission support based off RFC 4588 and the server-rtpaux example in -good --- docs/libs/gst-rtsp-server-sections.txt | 9 ++ gst/rtsp-server/rtsp-media-factory.c | 54 ++++++++++ gst/rtsp-server/rtsp-media-factory.h | 3 + gst/rtsp-server/rtsp-media.c | 117 ++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 3 + gst/rtsp-server/rtsp-sdp.c | 31 ++++++ gst/rtsp-server/rtsp-stream.c | 130 +++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 6 +- 8 files changed, 352 insertions(+), 1 deletion(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index e832c4e6b4..fe38081dfd 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -171,6 +171,9 @@ gst_rtsp_media_get_address_pool gst_rtsp_media_set_buffer_size gst_rtsp_media_get_buffer_size +gst_rtsp_media_set_retransmission_time +gst_rtsp_media_get_retransmission_time + gst_rtsp_media_setup_sdp @@ -257,6 +260,9 @@ gst_rtsp_media_factory_set_buffer_size gst_rtsp_media_factory_get_suspend_mode gst_rtsp_media_factory_set_suspend_mode +gst_rtsp_media_factory_set_retransmission_time +gst_rtsp_media_factory_get_retransmission_time + gst_rtsp_media_factory_construct gst_rtsp_media_factory_create_element @@ -541,6 +547,9 @@ gst_rtsp_stream_get_profiles gst_rtsp_stream_get_protocols gst_rtsp_stream_set_protocols +gst_rtsp_stream_get_retransmission_time +gst_rtsp_stream_set_retransmission_time + gst_rtsp_stream_is_transport_supported gst_rtsp_stream_get_address_pool diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 7d85dccecd..6e0da84b39 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -58,6 +58,8 @@ struct _GstRTSPMediaFactoryPrivate guint buffer_size; GstRTSPAddressPool *pool; + GstClockTime rtx_time; + GMutex medias_lock; GHashTable *medias; /* protected by medias_lock */ }; @@ -822,6 +824,55 @@ gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory) return res; } +/** + * gst_rtsp_media_factory_set_retransmission_time: + * @factory: a #GstRTSPMediaFactory + * @time: a #GstClockTime + * + * Configure the time to store for possible retransmission + */ +void +gst_rtsp_media_factory_set_retransmission_time (GstRTSPMediaFactory * factory, + GstClockTime time) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + priv = factory->priv; + + GST_DEBUG_OBJECT (factory, "retransmission time %" G_GUINT64_FORMAT, time); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv->rtx_time = time; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_retransmission_time: + * @factory: a #GstRTSPMediaFactory + * + * Get the time that is stored for retransmission purposes + * + * Returns: a #GstClockTime + */ +GstClockTime +gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + GstClockTime res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + res = priv->rtx_time; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return res; +} + static gboolean compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) { @@ -1084,6 +1135,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstRTSPLowerTrans protocols; GstRTSPAddressPool *pool; GstRTSPPermissions *perms; + GstClockTime rtx_time; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -1093,6 +1145,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) size = priv->buffer_size; profiles = priv->profiles; protocols = priv->protocols; + rtx_time = priv->rtx_time; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_suspend_mode (media, suspend_mode); @@ -1101,6 +1154,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_buffer_size (media, size); gst_rtsp_media_set_profiles (media, profiles); gst_rtsp_media_set_protocols (media, protocols); + gst_rtsp_media_set_retransmission_time (media, rtx_time); if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) { gst_rtsp_media_set_address_pool (media, pool); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index bb6aec34d1..ce069d7f79 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -141,6 +141,9 @@ GstRTSPAddressPool * gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFacto void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint size); guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory); +void gst_rtsp_media_factory_set_retransmission_time (GstRTSPMediaFactory * factory, + GstClockTime time); +GstClockTime gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory); /* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 85010dcb12..0c48c5c3da 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -121,6 +121,9 @@ struct _GstRTSPMediaPrivate GstRTSPTimeRange range; /* protected by lock */ GstClockTime range_start; GstClockTime range_stop; + + GList *payloads; /* protected by lock */ + GstClockTime rtx_time; /* protected by lock */ }; #define DEFAULT_SHARED FALSE @@ -366,6 +369,8 @@ gst_rtsp_media_finalize (GObject * obj) gst_object_unref (priv->element); if (priv->pool) g_object_unref (priv->pool); + if (priv->payloads) + g_list_free (priv->payloads); g_mutex_clear (&priv->lock); g_cond_clear (&priv->cond); g_rec_mutex_clear (&priv->state_lock); @@ -1090,6 +1095,63 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) return res; } +/** + * gst_rtsp_media_set_retransmission_time: + * @media: a #GstRTSPMedia + * @time: the new value + * + * Set the amount of time to store retransmission packets. + */ +void +gst_rtsp_media_set_retransmission_time (GstRTSPMedia * media, GstClockTime time) +{ + GstRTSPMediaPrivate *priv; + guint i; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + GST_LOG_OBJECT (media, "set retransmission time %" G_GUINT64_FORMAT, time); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->rtx_time = time; + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + + gst_rtsp_stream_set_retransmission_time (stream, time); + } + + if (priv->rtpbin) + g_object_set (priv->rtpbin, "do-retransmission", time > 0, NULL); + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_get_retransmission_time: + * @media: a #GstRTSPMedia + * + * Get the amount of time to store retransmission data. + * + * Returns: the amount of time to store retransmission data. + */ +GstClockTime +gst_rtsp_media_get_retransmission_time (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + GstClockTime res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + priv = media->priv; + + g_mutex_unlock (&priv->lock); + res = priv->rtx_time; + g_mutex_unlock (&priv->lock); + + return res; +} + /** * gst_rtsp_media_use_time_provider: * @media: a #GstRTSPMedia @@ -1198,6 +1260,37 @@ gst_rtsp_media_get_address_pool (GstRTSPMedia * media) return result; } +static GList * +_find_payload_types (GstRTSPMedia * media) +{ + GList *ret = NULL; + gint i, n; + + n = media->priv->streams->len; + for (i = 0; i < n; i++) { + GstRTSPStream *stream = g_ptr_array_index (media->priv->streams, i); + guint pt = gst_rtsp_stream_get_pt (stream); + + ret = g_list_append (ret, GUINT_TO_POINTER (pt)); + } + + return ret; +} + +static guint +_next_available_pt (GList * payloads) +{ + guint i; + + for (i = 96; i <= 127; i++) { + GList *iter = g_list_find (payloads, GINT_TO_POINTER (i)); + if (!iter) + return GPOINTER_TO_UINT (i); + } + + return 0; +} + /** * gst_rtsp_media_collect_streams: * @media: a #GstRTSPMedia @@ -1279,6 +1372,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, GstPad *srcpad; gchar *name; gint idx; + gint i, n; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL); @@ -1303,8 +1397,28 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, gst_rtsp_stream_set_address_pool (stream, priv->pool); gst_rtsp_stream_set_profiles (stream, priv->profiles); gst_rtsp_stream_set_protocols (stream, priv->protocols); + gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time); g_ptr_array_add (priv->streams, stream); + + if (priv->payloads) + g_list_free (priv->payloads); + priv->payloads = _find_payload_types (media); + + n = priv->streams->len; + for (i = 0; i < n; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + guint rtx_pt = _next_available_pt (priv->payloads); + + if (rtx_pt == 0) { + /* FIXME: ran out of space of dynamic payload types */ + break; + } + + gst_rtsp_stream_set_retransmission_pt (stream, rtx_pt); + + priv->payloads = g_list_append (priv->payloads, GUINT_TO_POINTER (rtx_pt)); + } g_mutex_unlock (&priv->lock); g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STREAM], 0, stream, @@ -2149,6 +2263,9 @@ start_prepare (GstRTSPMedia * media) } } + if (priv->rtpbin) + g_object_set (priv->rtpbin, "do-retransmission", priv->rtx_time > 0, NULL); + for (walk = priv->dynamic; walk; walk = g_list_next (walk)) { GstElement *elem = walk->data; DynPaySignalHandlers *handlers = g_slice_new (DynPaySignalHandlers); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index a78650d9b9..7c7515b62c 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -188,6 +188,9 @@ GstRTSPAddressPool * gst_rtsp_media_get_address_pool (GstRTSPMedia *media); void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size); guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media); +void gst_rtsp_media_set_retransmission_time (GstRTSPMedia *media, GstClockTime time); +GstClockTime gst_rtsp_media_get_retransmission_time (GstRTSPMedia *media); + void gst_rtsp_media_use_time_provider (GstRTSPMedia *media, gboolean time_provider); gboolean gst_rtsp_media_is_time_provider (GstRTSPMedia *media); GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media, diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index d2551c03d4..dfc54be97a 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -120,6 +120,7 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, const gchar *addrtype, *proto; gchar *address; guint ttl; + GstClockTime rtx_time; gst_sdp_media_new (&smedia); @@ -340,6 +341,9 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, continue; if (g_str_has_prefix (fname, "srtcp-")) continue; + /* handled later */ + if (g_str_has_prefix (fname, "x-gst-rtsp-server-rtx-time")) + continue; if (g_str_has_prefix (fname, "a-")) { /* attribute */ @@ -359,6 +363,7 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, first = FALSE; } } + if (!first) { tmp = g_string_free (fmtp, FALSE); gst_sdp_media_add_attribute (smedia, "fmtp", tmp); @@ -369,6 +374,32 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, update_sdp_from_tags (stream, smedia); + if ((rtx_time = gst_rtsp_stream_get_retransmission_time (stream))) { + /* ssrc multiplexed retransmit functionality */ + guint rtx_pt = gst_rtsp_stream_get_retransmission_pt (stream); + + if (rtx_pt == 0) { + g_warning ("failed to find an available dynamic payload type. " + "Not adding retransmission"); + } else { + gchar *tmp; + + tmp = g_strdup_printf ("%d", rtx_pt); + gst_sdp_media_add_format (smedia, tmp); + g_free (tmp); + + tmp = g_strdup_printf ("%d rtx/%d", rtx_pt, caps_rate); + gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); + g_free (tmp); + + tmp = + g_strdup_printf ("%d apt=%d;rtx-time=%" G_GINT64_FORMAT, rtx_pt, + caps_pt, GST_TIME_AS_MSECONDS (rtx_time)); + gst_sdp_media_add_attribute (smedia, "fmtp", tmp); + g_free (tmp); + } + } + gst_sdp_message_add_media (sdp, smedia); gst_sdp_media_free (smedia); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index f2ac3db492..24569ddcf5 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -111,6 +111,11 @@ struct _GstRTSPStreamPrivate GstElement *tee[2]; GstElement *funnel[2]; + /* retransmission */ + GstElement *rtxsend; + guint rtx_pt; + GstClockTime rtx_time; + /* server ports for sending/receiving over ipv4 */ GstRTSPRange server_port_v4; GstRTSPAddress *server_addr_v4; @@ -271,6 +276,9 @@ gst_rtsp_stream_finalize (GObject * obj) gst_rtsp_address_free (priv->server_addr_v6); if (priv->pool) g_object_unref (priv->pool); + if (priv->rtxsend) + g_object_unref (priv->rtxsend); + gst_object_unref (priv->payloader); gst_object_unref (priv->srcpad); g_free (priv->control); @@ -1306,6 +1314,82 @@ gst_rtsp_stream_get_ssrc (GstRTSPStream * stream, guint * ssrc) g_mutex_unlock (&priv->lock); } +/** + * gst_rtsp_stream_set_retransmission_time: + * @stream: a #GstRTSPStream + * @time: a #GstClockTime + * + * Set the amount of time to store retransmission packets. + */ +void +gst_rtsp_stream_set_retransmission_time (GstRTSPStream * stream, + GstClockTime time) +{ + GST_DEBUG_OBJECT (stream, "set retransmission time %" G_GUINT64_FORMAT, time); + + g_mutex_lock (&stream->priv->lock); + stream->priv->rtx_time = time; + if (stream->priv->rtxsend) + g_object_set (stream->priv->rtxsend, "max-size-time", + GST_TIME_AS_MSECONDS (time), NULL); + g_mutex_unlock (&stream->priv->lock); +} + +/** + * gst_rtsp_media_get_retransmission_time: + * @media: a #GstRTSPMedia + * + * Get the amount of time to store retransmission data. + * + * Returns: the amount of time to store retransmission data. + */ +GstClockTime +gst_rtsp_stream_get_retransmission_time (GstRTSPStream * stream) +{ + GstClockTime ret; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + g_mutex_lock (&stream->priv->lock); + ret = stream->priv->rtx_time; + g_mutex_unlock (&stream->priv->lock); + + return ret; +} + +void +gst_rtsp_stream_set_retransmission_pt (GstRTSPStream * stream, guint rtx_pt) +{ + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + GST_DEBUG_OBJECT (stream, "set retransmission pt %u", rtx_pt); + + g_mutex_lock (&stream->priv->lock); + stream->priv->rtx_pt = rtx_pt; + if (stream->priv->rtxsend) { + guint pt = gst_rtsp_stream_get_pt (stream); + gchar *pt_s = g_strdup_printf ("%d", pt); + GstStructure *rtx_pt_map = gst_structure_new ("application/x-rtp-pt-map", + pt_s, G_TYPE_UINT, rtx_pt, NULL); + g_object_set (stream->priv->rtxsend, "payload-type-map", rtx_pt_map, NULL); + } + g_mutex_unlock (&stream->priv->lock); +} + +guint +gst_rtsp_stream_get_retransmission_pt (GstRTSPStream * stream) +{ + guint rtx_pt; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + g_mutex_lock (&stream->priv->lock); + rtx_pt = stream->priv->rtx_pt; + g_mutex_unlock (&stream->priv->lock); + + return rtx_pt; +} + /* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) @@ -1657,6 +1741,46 @@ request_rtcp_decoder (GstElement * rtpbin, guint session, return gst_object_ref (priv->srtpdec); } +static GstElement * +request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPStream * stream) +{ + GstElement *bin; + GstPad *pad; + GstStructure *pt_map; + gchar *name; + guint pt, rtx_pt; + gchar *pt_s; + + pt = gst_rtsp_stream_get_pt (stream); + pt_s = g_strdup_printf ("%u", pt); + rtx_pt = stream->priv->rtx_pt; + + GST_INFO ("creating rtxsend with pt %u to %u", pt, rtx_pt); + + bin = gst_bin_new (NULL); + stream->priv->rtxsend = gst_element_factory_make ("rtprtxsend", NULL); + pt_map = gst_structure_new ("application/x-rtp-pt-map", + pt_s, G_TYPE_UINT, rtx_pt, NULL); + g_object_set (stream->priv->rtxsend, "payload-type-map", pt_map, + "max-size-time", GST_TIME_AS_MSECONDS (stream->priv->rtx_time), NULL); + gst_structure_free (pt_map); + gst_bin_add (GST_BIN (bin), gst_object_ref (stream->priv->rtxsend)); + + pad = gst_element_get_static_pad (stream->priv->rtxsend, "src"); + name = g_strdup_printf ("src_%u", sessid); + gst_element_add_pad (bin, gst_ghost_pad_new (name, pad)); + g_free (name); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (stream->priv->rtxsend, "sink"); + name = g_strdup_printf ("sink_%u", sessid); + gst_element_add_pad (bin, gst_ghost_pad_new (name, pad)); + g_free (name); + gst_object_unref (pad); + + return bin; +} + /** * gst_rtsp_stream_join_bin: * @stream: a #GstRTSPStream @@ -1714,6 +1838,12 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, (GCallback) request_rtcp_decoder, stream); } + if (priv->rtx_time > 0) { + /* enable retransmission by setting rtprtxsend as the "aux" element of rtpbin */ + g_signal_connect (rtpbin, "request-aux-sender", + (GCallback) request_aux_sender, stream); + } + /* get a pad for sending RTP */ name = g_strdup_printf ("send_rtp_sink_%u", idx); priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 135689e114..4fb41959d4 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -147,7 +147,6 @@ GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream *stream, gboolean gst_rtsp_stream_update_crypto (GstRTSPStream * stream, guint ssrc, GstCaps * crypto); - gboolean gst_rtsp_stream_query_position (GstRTSPStream * stream, gint64 * position); gboolean gst_rtsp_stream_query_stop (GstRTSPStream * stream, @@ -155,6 +154,11 @@ gboolean gst_rtsp_stream_query_stop (GstRTSPStream * stream, void gst_rtsp_stream_set_seqnum_offset (GstRTSPStream *stream, guint16 seqnum); guint16 gst_rtsp_stream_get_current_seqnum (GstRTSPStream *stream); +void gst_rtsp_stream_set_retransmission_time (GstRTSPStream *stream, GstClockTime time); +GstClockTime gst_rtsp_stream_get_retransmission_time (GstRTSPStream *stream); +guint gst_rtsp_stream_get_retransmission_pt (GstRTSPStream * stream); +void gst_rtsp_stream_set_retransmission_pt (GstRTSPStream * stream, + guint rtx_pt); /** * GstRTSPStreamTransportFilterFunc: From 06bfc0697b8fa8d7272124868706cd896b423257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 16 Dec 2014 16:42:13 +0100 Subject: [PATCH 1059/1776] rtsp-stream: Fix compiler warnings rtsp-stream.c:1351:3: error: non-void function 'gst_rtsp_stream_get_retransmission_time' should return a value [-Wreturn-type] g_return_if_fail (GST_IS_RTSP_STREAM (stream)); ^ rtsp-stream.c:1384:3: error: non-void function 'gst_rtsp_stream_get_retransmission_pt' should return a value [-Wreturn-type] g_return_if_fail (GST_IS_RTSP_STREAM (stream)); ^ --- gst/rtsp-server/rtsp-stream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 24569ddcf5..96a86cb273 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1348,7 +1348,7 @@ gst_rtsp_stream_get_retransmission_time (GstRTSPStream * stream) { GstClockTime ret; - g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), 0); g_mutex_lock (&stream->priv->lock); ret = stream->priv->rtx_time; @@ -1381,7 +1381,7 @@ gst_rtsp_stream_get_retransmission_pt (GstRTSPStream * stream) { guint rtx_pt; - g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), 0); g_mutex_lock (&stream->priv->lock); rtx_pt = stream->priv->rtx_pt; From 8ae35665911424eea52ba4a7444eb9d1dbff1d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 16 Dec 2014 16:46:06 +0100 Subject: [PATCH 1060/1776] rtsp-media: Some minor cleanup --- gst/rtsp-server/rtsp-media.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 0c48c5c3da..eddbf41a0c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1263,18 +1263,18 @@ gst_rtsp_media_get_address_pool (GstRTSPMedia * media) static GList * _find_payload_types (GstRTSPMedia * media) { - GList *ret = NULL; gint i, n; + GQueue queue = G_QUEUE_INIT; n = media->priv->streams->len; for (i = 0; i < n; i++) { GstRTSPStream *stream = g_ptr_array_index (media->priv->streams, i); guint pt = gst_rtsp_stream_get_pt (stream); - ret = g_list_append (ret, GUINT_TO_POINTER (pt)); + g_queue_push_tail (&queue, GUINT_TO_POINTER (pt)); } - return ret; + return queue.head; } static guint @@ -1411,7 +1411,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, guint rtx_pt = _next_available_pt (priv->payloads); if (rtx_pt == 0) { - /* FIXME: ran out of space of dynamic payload types */ + GST_WARNING ("Ran out of space of dynamic payload types"); break; } From a44b564f59c738f9f115df7e7995935f77d29d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 16 Dec 2014 16:46:15 +0100 Subject: [PATCH 1061/1776] rtsp-stream: Fix some minor memory leaks --- gst/rtsp-server/rtsp-stream.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 96a86cb273..10549107cf 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1372,6 +1372,8 @@ gst_rtsp_stream_set_retransmission_pt (GstRTSPStream * stream, guint rtx_pt) GstStructure *rtx_pt_map = gst_structure_new ("application/x-rtp-pt-map", pt_s, G_TYPE_UINT, rtx_pt, NULL); g_object_set (stream->priv->rtxsend, "payload-type-map", rtx_pt_map, NULL); + g_free (pt_s); + gst_structure_free (rtx_pt_map); } g_mutex_unlock (&stream->priv->lock); } @@ -1763,6 +1765,7 @@ request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPStream * stream) pt_s, G_TYPE_UINT, rtx_pt, NULL); g_object_set (stream->priv->rtxsend, "payload-type-map", pt_map, "max-size-time", GST_TIME_AS_MSECONDS (stream->priv->rtx_time), NULL); + g_free (pt_s); gst_structure_free (pt_map); gst_bin_add (GST_BIN (bin), gst_object_ref (stream->priv->rtxsend)); From fa4d8db7ea9079e3a92cdc4fcccc284e22c0df63 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 1 Dec 2014 23:42:34 +1100 Subject: [PATCH 1062/1776] examples: add a retransmisison example implementing RFC4588 Currently only SSRC-multiplexed rtx streams are supported --- examples/.gitignore | 1 + examples/Makefile.am | 3 +- examples/test-video-rtx.c | 98 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 examples/test-video-rtx.c diff --git a/examples/.gitignore b/examples/.gitignore index 286c2a3b2d..81859e7c1d 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -6,5 +6,6 @@ test-ogg test-readme test-sdp test-video +test-video-rtx test-uri test-auth diff --git a/examples/Makefile.am b/examples/Makefile.am index 9bf2198a05..6d13ed6737 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,6 +1,7 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ test-launch test-sdp test-uri test-auth \ - test-multicast test-multicast2 test-appsrc + test-multicast test-multicast2 test-appsrc \ + test-video-rtx #INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/examples/test-video-rtx.c b/examples/test-video-rtx.c new file mode 100644 index 0000000000..27763c37c2 --- /dev/null +++ b/examples/test-video-rtx.c @@ -0,0 +1,98 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +/* this timeout is periodically run to clean up the expired sessions from the + * pool. This needs to be run explicitly currently but might be done + * automatically as part of the mainloop. */ +static gboolean +timeout (GstRTSPServer * server, gboolean ignored) +{ + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_cleanup (pool); + g_object_unref (pool); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mount points for this server, every server has a default object + * that be used to map uri mount points to media factories */ + mounts = gst_rtsp_server_get_mount_points (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, "( " + "videotestsrc ! video/x-raw,width=352,height=288,framerate=15/1 ! " + "x264enc ! rtph264pay name=pay0 pt=96 " + "audiotestsrc ! audio/x-raw,rate=8000 ! " + "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); + + /* store up to 0.4 seconds of retransmission data */ + gst_rtsp_media_factory_set_retransmission_time (factory, 400 * GST_MSECOND); + + /* attach the test factory to the /test url */ + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mounts); + + /* attach the server to the default maincontext */ + if (gst_rtsp_server_attach (server, NULL) == 0) + goto failed; + + /* add a timeout for the session cleanup */ + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + + /* start serving, this never stops */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + + g_main_loop_run (loop); + + return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } +} From b6e4587afdc5291e1e6ad9e23df3282b21178b12 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Wed, 17 Dec 2014 20:02:05 +0100 Subject: [PATCH 1063/1776] configure: add --disable-examples switch https://bugzilla.gnome.org/show_bug.cgi?id=741678 --- Makefile.am | 10 ++++++++-- configure.ac | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 43483edc54..9624f7e00e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,14 +1,20 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc +if BUILD_EXAMPLES +SUBDIRS_EXAMPLES = examples +else +SUBDIRS_EXAMPLES = +endif + SUBDIRS = \ gst \ common \ pkgconfig \ docs \ - examples \ + $(SUBDIRS_EXAMPLES) tests -DIST_SUBDIRS = $(SUBDIRS) +DIST_SUBDIRS = gst common pkgconfig docs examples tests EXTRA_DIST = \ ChangeLog autogen.sh depcomp \ diff --git a/configure.ac b/configure.ac index 4d804ba546..4ac95c15b2 100644 --- a/configure.ac +++ b/configure.ac @@ -87,6 +87,8 @@ AG_GST_ARG_WITH_PKG_CONFIG_PATH AG_GST_ARG_WITH_PACKAGE_NAME AG_GST_ARG_WITH_PACKAGE_ORIGIN +AG_GST_ARG_EXAMPLES + AG_GST_PKG_CONFIG_PATH AG_GST_SET_PACKAGE_RELEASE_DATETIME_WITH_NANO([$PACKAGE_VERSION_NANO], From fc6811697c82122d22b1a6853050ac8b988c6bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 18 Dec 2014 10:56:44 +0100 Subject: [PATCH 1064/1776] Automatic update of common submodule From ef1ffdc to f2c6b95 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index ef1ffdcc6e..f2c6b95d0d 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit ef1ffdcc6e6fca1f512f923a94c990e3534ba9a5 +Subproject commit f2c6b95d0d98e97c37ffe27509709fdd41cd503c From 79e41bc2bee8223db5278fe85e14348b3a45aa40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 29 Dec 2014 12:06:50 +0100 Subject: [PATCH 1065/1776] rtsp-client: Add a send_message default signal handler This allows subclasses to easily hook into the response sending mechanism without doing everything from a signal, which seems awkward from subclasses. --- gst/rtsp-server/rtsp-client.c | 3 ++- gst/rtsp-server/rtsp-client.h | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3885ee98fd..4099b7898b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -262,7 +262,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) */ gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE] = g_signal_new ("send-message", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + send_message), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_POINTER); tunnels = diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 6bc9a59e6d..4e9519a101 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -119,8 +119,10 @@ struct _GstRTSPClientClass { void (*tunnel_http_response) (GstRTSPClient * client, GstRTSPMessage * request, GstRTSPMessage * response); + void (*send_message) (GstRTSPClient * client, GstRTSPContext *ctx, + GstRTSPMessage * response); /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE-1]; + gpointer _gst_reserved[GST_PADDING_LARGE-2]; }; GType gst_rtsp_client_get_type (void); From e0d3807cbbba6c24d24b6a9cf8e8e11005b74c51 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Tue, 30 Dec 2014 18:13:49 +0530 Subject: [PATCH 1066/1776] examples: Add command-line parsing and take a 'port' argument This allows users to run multiple servers on different ports for testing. Only done for examples that actually take arguments and hence are capable of outputting different streams for each instance on each port. https://bugzilla.gnome.org/show_bug.cgi?id=742115 --- examples/test-launch.c | 26 +++++++++++++++++++++----- examples/test-mp4.c | 23 ++++++++++++++++++++--- examples/test-ogg.c | 23 ++++++++++++++++++++--- examples/test-uri.c | 23 ++++++++++++++++++++--- 4 files changed, 81 insertions(+), 14 deletions(-) diff --git a/examples/test-launch.c b/examples/test-launch.c index 0466224146..663391c50b 100644 --- a/examples/test-launch.c +++ b/examples/test-launch.c @@ -21,6 +21,16 @@ #include +#define DEFAULT_RTSP_PORT "8554" + +static char *port = (char *) DEFAULT_RTSP_PORT; + +static GOptionEntry entries[] = { + {"port", 'p', 0, G_OPTION_ARG_STRING, &port, + "Port to listen on (default: " DEFAULT_RTSP_PORT ")", "PORT"}, + {NULL} +}; + int main (int argc, char *argv[]) { @@ -28,20 +38,26 @@ main (int argc, char *argv[]) GstRTSPServer *server; GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; + GOptionContext *optctx; + GError *error = NULL; gst_init (&argc, &argv); - if (argc < 2) { - g_print ("usage: %s \n" - "example: %s \"( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )\"\n", - argv[0], argv[0]); + optctx = g_option_context_new (" - Test RTSP Server, Launch\n\n" + "Example: \"( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )\""); + g_option_context_add_main_entries (optctx, entries, NULL); + g_option_context_add_group (optctx, gst_init_get_option_group ()); + if (!g_option_context_parse (optctx, &argc, &argv, &error)) { + g_printerr ("Error parsing options: %s\n", error->message); return -1; } + g_option_context_free (optctx); loop = g_main_loop_new (NULL, FALSE); /* create a server instance */ server = gst_rtsp_server_new (); + g_object_set (server, "service", port, NULL); /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ @@ -64,7 +80,7 @@ main (int argc, char *argv[]) gst_rtsp_server_attach (server, NULL); /* start serving */ - g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port); g_main_loop_run (loop); return 0; diff --git a/examples/test-mp4.c b/examples/test-mp4.c index bf88abe3f9..3ca0060053 100644 --- a/examples/test-mp4.c +++ b/examples/test-mp4.c @@ -21,6 +21,16 @@ #include +#define DEFAULT_RTSP_PORT "8554" + +static char *port = (char *) DEFAULT_RTSP_PORT; + +static GOptionEntry entries[] = { + {"port", 'p', 0, G_OPTION_ARG_STRING, &port, + "Port to listen on (default: " DEFAULT_RTSP_PORT ")", "PORT"}, + {NULL} +}; + /* called when a stream has received an RTCP packet from the client */ static void on_ssrc_active (GObject * session, GObject * source, GstRTSPMedia * media) @@ -83,19 +93,26 @@ main (int argc, char *argv[]) GstRTSPServer *server; GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; + GOptionContext *optctx; + GError *error = NULL; gchar *str; gst_init (&argc, &argv); - if (argc < 2) { - g_message ("usage: %s ", argv[0]); + optctx = g_option_context_new (" - Test RTSP Server, MP4"); + g_option_context_add_main_entries (optctx, entries, NULL); + g_option_context_add_group (optctx, gst_init_get_option_group ()); + if (!g_option_context_parse (optctx, &argc, &argv, &error)) { + g_printerr ("Error parsing options: %s\n", error->message); return -1; } + g_option_context_free (optctx); loop = g_main_loop_new (NULL, FALSE); /* create a server instance */ server = gst_rtsp_server_new (); + g_object_set (server, "service", port, NULL); /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ @@ -126,7 +143,7 @@ main (int argc, char *argv[]) gst_rtsp_server_attach (server, NULL); /* start serving */ - g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port); g_main_loop_run (loop); return 0; diff --git a/examples/test-ogg.c b/examples/test-ogg.c index f4d104cee3..f3e26b441e 100644 --- a/examples/test-ogg.c +++ b/examples/test-ogg.c @@ -21,6 +21,16 @@ #include +#define DEFAULT_RTSP_PORT "8554" + +static char *port = (char *) DEFAULT_RTSP_PORT; + +static GOptionEntry entries[] = { + {"port", 'p', 0, G_OPTION_ARG_STRING, &port, + "Port to listen on (default: " DEFAULT_RTSP_PORT ")", "PORT"}, + {NULL} +}; + int main (int argc, char *argv[]) { @@ -28,19 +38,26 @@ main (int argc, char *argv[]) GstRTSPServer *server; GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; + GOptionContext *optctx; + GError *error = NULL; gchar *str; gst_init (&argc, &argv); - if (argc < 2) { - g_message ("usage: %s ", argv[0]); + optctx = g_option_context_new (" - Test RTSP Server, OGG"); + g_option_context_add_main_entries (optctx, entries, NULL); + g_option_context_add_group (optctx, gst_init_get_option_group ()); + if (!g_option_context_parse (optctx, &argc, &argv, &error)) { + g_printerr ("Error parsing options: %s\n", error->message); return -1; } + g_option_context_free (optctx); loop = g_main_loop_new (NULL, FALSE); /* create a server instance */ server = gst_rtsp_server_new (); + g_object_set (server, "service", port, NULL); /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ @@ -69,7 +86,7 @@ main (int argc, char *argv[]) gst_rtsp_server_attach (server, NULL); /* start serving */ - g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port); g_main_loop_run (loop); return 0; diff --git a/examples/test-uri.c b/examples/test-uri.c index b0daebc798..fb6deb7941 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -22,6 +22,16 @@ #include #include +#define DEFAULT_RTSP_PORT "8554" + +static char *port = (char *) DEFAULT_RTSP_PORT; + +static GOptionEntry entries[] = { + {"port", 'p', 0, G_OPTION_ARG_STRING, &port, + "Port to listen on (default: " DEFAULT_RTSP_PORT ")", "PORT"}, + {NULL} +}; + static gboolean timeout (GstRTSPServer * server) @@ -55,18 +65,25 @@ main (int argc, char *argv[]) GstRTSPServer *server; GstRTSPMountPoints *mounts; GstRTSPMediaFactoryURI *factory; + GOptionContext *optctx; + GError *error = NULL; gst_init (&argc, &argv); - if (argc < 2) { - g_message ("usage: %s ", argv[0]); + optctx = g_option_context_new (" - Test RTSP Server, URI"); + g_option_context_add_main_entries (optctx, entries, NULL); + g_option_context_add_group (optctx, gst_init_get_option_group ()); + if (!g_option_context_parse (optctx, &argc, &argv, &error)) { + g_printerr ("Error parsing options: %s\n", error->message); return -1; } + g_option_context_free (optctx); loop = g_main_loop_new (NULL, FALSE); /* create a server instance */ server = gst_rtsp_server_new (); + g_object_set (server, "service", port, NULL); /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ @@ -100,7 +117,7 @@ main (int argc, char *argv[]) g_timeout_add_seconds (10, (GSourceFunc) remove_map, server); /* start serving */ - g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port); g_main_loop_run (loop); return 0; From e2b31dd9b4dd6ad93a3548327b9666b572f6a177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 31 Dec 2014 13:04:57 +0000 Subject: [PATCH 1067/1776] Fix 'make check' from top-level directory --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 9624f7e00e..dccba6e1eb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,7 +11,7 @@ SUBDIRS = \ common \ pkgconfig \ docs \ - $(SUBDIRS_EXAMPLES) + $(SUBDIRS_EXAMPLES) \ tests DIST_SUBDIRS = gst common pkgconfig docs examples tests From d535cd8cbb454ebaf031f3b1f60826b3da8d2265 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 12 Jan 2015 16:14:12 +0100 Subject: [PATCH 1068/1776] Automatic update of common submodule From f2c6b95 to bc76a8b --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index f2c6b95d0d..bc76a8b6a2 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit f2c6b95d0d98e97c37ffe27509709fdd41cd503c +Subproject commit bc76a8b6a2db1cc0605158e672b2d420b4e130d0 From 94f3e18c5bb2d8a054ab3b3d4828b9c77fd7f398 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Tue, 13 Jan 2015 15:29:29 +0100 Subject: [PATCH 1069/1776] Revert "rtsp-session-pool: Make sure session IDs are properly URI-escaped" This reverts commit 935e8f852d050b4939f1d0f44b38e9b55a2fbe36. RFC 2326 states that session IDs may consist of alphanumeric as well as the safe characters $-_.+ -- N.B. the percent character is not allowed. Previously the session ID was URI-escaped, this meant that any character which was not alphanumeric or any of the characters +-._~ would be percent encoded. While the RFC (surprisingly) mentions that linear white space in session IDs should be URI-escaped, it does not say anything about other characters. Moreover no white space is allowed in the session ID. Finally the percent character which is the result of URI-escaping is not allowed in a session ID. So there is no reason to do any URI-escaping, and now it is removed. https://bugzilla.gnome.org/show_bug.cgi?id=742869 --- gst/rtsp-server/rtsp-session-pool.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index fad5288300..772390ffc1 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -317,7 +317,7 @@ gst_rtsp_session_pool_find (GstRTSPSessionPool * pool, const gchar * sessionid) static gchar * create_session_id (GstRTSPSessionPool * pool) { - gchar id[17]; + gchar id[16]; gint i; for (i = 0; i < 16; i++) { @@ -325,9 +325,8 @@ create_session_id (GstRTSPSessionPool * pool) session_id_charset[g_random_int_range (0, G_N_ELEMENTS (session_id_charset))]; } - id[16] = 0; - return g_uri_escape_string (id, NULL, FALSE); + return g_strndup (id, 16); } static GstRTSPSession * From fe8e877dd9585ccd9a329832ce09a136fd155b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 15 Jan 2015 19:34:20 +0100 Subject: [PATCH 1070/1776] rtsp-stream: Set format=TIME on our app sources for TCP --- gst/rtsp-server/rtsp-stream.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 10549107cf..33ee7d48af 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2009,6 +2009,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) { /* make and add appsrc */ priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); + g_object_set (priv->appsrc[i], "format", GST_FORMAT_TIME, NULL); gst_bin_add (bin, priv->appsrc[i]); /* and link to the funnel */ selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); From 0d2de69db99670451bc7a39d921dc5636fd94cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Fri, 16 Jan 2015 11:10:20 +0100 Subject: [PATCH 1071/1776] rtsp-stream: Have one copy of the transports cache for RTP and RTCP each Fixes crash when two threads access handle_new_sample() at the same time, one for RTP, one for RTCP. Otherwise, when iterating over the transports cache, it might be modified by another thread at the same time if the transports cookie has changed. https://bugzilla.gnome.org/show_bug.cgi?id=742954 --- gst/rtsp-server/rtsp-stream.c | 42 ++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 33ee7d48af..d64fed4d29 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -139,7 +139,8 @@ struct _GstRTSPStreamPrivate guint n_active; GList *transports; guint transports_cookie; - GList *tr_cache; + GList *tr_cache_rtp; + GList *tr_cache_rtcp; guint tr_cache_cookie; /* UDP sources for UDP multicast transports */ @@ -1575,11 +1576,17 @@ on_timeout (GObject * session, GObject * source, GstRTSPStream * stream) } static void -clear_tr_cache (GstRTSPStreamPrivate * priv) +clear_tr_cache (GstRTSPStreamPrivate * priv, gboolean is_rtp) { - g_list_foreach (priv->tr_cache, (GFunc) g_object_unref, NULL); - g_list_free (priv->tr_cache); - priv->tr_cache = NULL; + if (is_rtp) { + g_list_foreach (priv->tr_cache_rtp, (GFunc) g_object_unref, NULL); + g_list_free (priv->tr_cache_rtp); + priv->tr_cache_rtp = NULL; + } else { + g_list_foreach (priv->tr_cache_rtcp, (GFunc) g_object_unref, NULL); + g_list_free (priv->tr_cache_rtcp); + priv->tr_cache_rtcp = NULL; + } } static GstFlowReturn @@ -1604,21 +1611,29 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) g_mutex_lock (&priv->lock); if (priv->tr_cache_cookie != priv->transports_cookie) { - clear_tr_cache (priv); + clear_tr_cache (priv, is_rtp); for (walk = priv->transports; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - priv->tr_cache = g_list_prepend (priv->tr_cache, g_object_ref (tr)); + if (is_rtp) { + priv->tr_cache_rtp = + g_list_prepend (priv->tr_cache_rtp, g_object_ref (tr)); + } else { + priv->tr_cache_rtcp = + g_list_prepend (priv->tr_cache_rtcp, g_object_ref (tr)); + } } priv->tr_cache_cookie = priv->transports_cookie; } g_mutex_unlock (&priv->lock); - for (walk = priv->tr_cache; walk; walk = g_list_next (walk)) { - GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - - if (is_rtp) { + if (is_rtp) { + for (walk = priv->tr_cache_rtp; walk; walk = g_list_next (walk)) { + GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; gst_rtsp_stream_transport_send_rtp (tr, buffer); - } else { + } + } else { + for (walk = priv->tr_cache_rtcp; walk; walk = g_list_next (walk)) { + GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; gst_rtsp_stream_transport_send_rtcp (tr, buffer); } } @@ -2099,7 +2114,8 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, if (priv->transports != NULL) goto transports_not_removed; - clear_tr_cache (priv); + clear_tr_cache (priv, TRUE); + clear_tr_cache (priv, FALSE); GST_INFO ("stream %p leaving bin", stream); From 586fe4ea4bbc97283cc1db263e0e9d21c61228e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 16 Jan 2015 20:04:01 +0100 Subject: [PATCH 1072/1776] rtsp-client: Drop trailing \0 of RTSP DATA messages We add a trailing \0 in GstRTSPConnection to make parsing of string message bodies easier (e.g. the SDP from DESCRIBE) but for actual data this means we have to drop it or otherwise create invalid data. --- gst/rtsp-server/rtsp-client.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4099b7898b..faff8b12dc 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2601,9 +2601,14 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) if (res != GST_RTSP_OK) return; + gst_rtsp_message_get_body (message, &data, &size); + if (size < 2) + goto invalid_length; + gst_rtsp_message_steal_body (message, &data, &size); - buffer = gst_buffer_new_wrapped (data, size); + /* Strip trailing \0 */ + buffer = gst_buffer_new_wrapped (data, size - 1); trans = g_hash_table_lookup (priv->transports, GINT_TO_POINTER ((gint) channel)); @@ -2613,6 +2618,11 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) } else { gst_buffer_unref (buffer); } +invalid_length: + { + GST_DEBUG ("client %p: Short message received, ignoring", client); + return; + } } /** From 634abb9906d4251d3f4efd5e31fd0d1968b1e457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 17 Jan 2015 10:29:36 +0100 Subject: [PATCH 1073/1776] examples: Don't call gst_init() and gst_get_option_group() The latter calls the former at the appropriate time. --- examples/test-launch.c | 2 -- examples/test-mp4.c | 2 -- examples/test-ogg.c | 2 -- examples/test-uri.c | 2 -- 4 files changed, 8 deletions(-) diff --git a/examples/test-launch.c b/examples/test-launch.c index 663391c50b..24e1271e61 100644 --- a/examples/test-launch.c +++ b/examples/test-launch.c @@ -41,8 +41,6 @@ main (int argc, char *argv[]) GOptionContext *optctx; GError *error = NULL; - gst_init (&argc, &argv); - optctx = g_option_context_new (" - Test RTSP Server, Launch\n\n" "Example: \"( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )\""); g_option_context_add_main_entries (optctx, entries, NULL); diff --git a/examples/test-mp4.c b/examples/test-mp4.c index 3ca0060053..263d122efc 100644 --- a/examples/test-mp4.c +++ b/examples/test-mp4.c @@ -97,8 +97,6 @@ main (int argc, char *argv[]) GError *error = NULL; gchar *str; - gst_init (&argc, &argv); - optctx = g_option_context_new (" - Test RTSP Server, MP4"); g_option_context_add_main_entries (optctx, entries, NULL); g_option_context_add_group (optctx, gst_init_get_option_group ()); diff --git a/examples/test-ogg.c b/examples/test-ogg.c index f3e26b441e..c22e638ba2 100644 --- a/examples/test-ogg.c +++ b/examples/test-ogg.c @@ -42,8 +42,6 @@ main (int argc, char *argv[]) GError *error = NULL; gchar *str; - gst_init (&argc, &argv); - optctx = g_option_context_new (" - Test RTSP Server, OGG"); g_option_context_add_main_entries (optctx, entries, NULL); g_option_context_add_group (optctx, gst_init_get_option_group ()); diff --git a/examples/test-uri.c b/examples/test-uri.c index fb6deb7941..a5a3399a0b 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -68,8 +68,6 @@ main (int argc, char *argv[]) GOptionContext *optctx; GError *error = NULL; - gst_init (&argc, &argv); - optctx = g_option_context_new (" - Test RTSP Server, URI"); g_option_context_add_main_entries (optctx, entries, NULL); g_option_context_add_group (optctx, gst_init_get_option_group ()); From 69e346419a16dbfd0a23a5e5169f606e55c31fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 18 Jan 2015 19:08:36 +0100 Subject: [PATCH 1074/1776] rtsp-client: Use a random session ID in the SDP RFC4566 Section 5.2 says that it should make the username, session id, nettype, addrtype and unicast address tuple globally unique. Always using 1188340656180883 is not going to guarantee that: https://xkcd.com/221/ Instead let's create a 64 bit random number, which at least brings us closer to the goal of global uniqueness. https://tools.ietf.org/html/rfc4566#section-5.2 --- gst/rtsp-server/rtsp-client.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index faff8b12dc..6fbb5ea833 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2008,6 +2008,8 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) GstSDPMessage *sdp; GstSDPInfo info; const gchar *proto; + guint64 session_id_tmp; + gchar session_id[21]; gst_sdp_message_new (&sdp); @@ -2019,7 +2021,11 @@ create_sdp (GstRTSPClient * client, GstRTSPMedia * media) else proto = "IP4"; - gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", proto, + session_id_tmp = (((guint64) g_random_int ()) << 32) | g_random_int (); + g_snprintf (session_id, sizeof (session_id), "%" G_GUINT64_FORMAT, + session_id_tmp); + + gst_sdp_message_set_origin (sdp, "-", session_id, "1", "IN", proto, priv->server_ip); gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer"); From fcef562f35f8377346888629a7b4a73df4be4ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 19 Jan 2015 13:09:20 +0100 Subject: [PATCH 1075/1776] rtsp-client: If we have a single-stream media and SETUP contains no control, use the one and only stream --- gst/rtsp-server/rtsp-client.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6fbb5ea833..54d1d501ba 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1726,7 +1726,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPStream *stream; GstRTSPState rtspstate; GstRTSPClientClass *klass; - gchar *path, *control; + gchar *path, *control = NULL; gint matched; gboolean new_session = FALSE; @@ -1775,16 +1775,22 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (media == NULL) goto media_not_found_no_reply; - if (path[matched] == '\0') - goto control_not_found; + if (path[matched] == '\0') { + if (gst_rtsp_media_n_streams (media) == 1) { + stream = gst_rtsp_media_get_stream (media, 0); + } else { + goto control_not_found; + } + } else { + /* path is what matched. */ + path[matched] = '\0'; + /* control is remainder */ + control = &path[matched + 1]; - /* path is what matched. */ - path[matched] = '\0'; - /* control is remainder */ - control = &path[matched + 1]; + /* find the stream now using the control part */ + stream = gst_rtsp_media_find_stream (media, control); + } - /* find the stream now using the control part */ - stream = gst_rtsp_media_find_stream (media, control); if (stream == NULL) goto stream_not_found; @@ -1945,7 +1951,8 @@ control_not_found: } stream_not_found: { - GST_ERROR ("client %p: stream '%s' not found", client, control); + GST_ERROR ("client %p: stream '%s' not found", client, + GST_STR_NULL (control)); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); g_object_unref (media); goto cleanup_path; From 47eaac5b9efa1ff8584bbafaa5a3217559a8f049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 19 Jan 2015 20:18:20 +0000 Subject: [PATCH 1076/1776] rtsp-client: fix unintentional fallthrough to debug warning when receiving interleaved data --- gst/rtsp-server/rtsp-client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 54d1d501ba..b2a528157e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2631,6 +2631,10 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) } else { gst_buffer_unref (buffer); } + + return; + +/* ERRORS */ invalid_length: { GST_DEBUG ("client %p: Short message received, ignoring", client); From cc3e0ed39b3dea045bd8f83d8a9886bdadc8d759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 19 Jan 2015 20:35:15 +0000 Subject: [PATCH 1077/1776] rtsp-client: log interleaved data received --- gst/rtsp-server/rtsp-client.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b2a528157e..c6b582c143 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2620,15 +2620,20 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) gst_rtsp_message_steal_body (message, &data, &size); - /* Strip trailing \0 */ - buffer = gst_buffer_new_wrapped (data, size - 1); + /* Strip trailing \0 (which GstRTSPConnection adds) */ + --size; + + buffer = gst_buffer_new_wrapped (data, size); trans = g_hash_table_lookup (priv->transports, GINT_TO_POINTER ((gint) channel)); if (trans) { /* dispatch to the stream based on the channel number */ + GST_LOG_OBJECT (client, "%u bytes of data on channel %u", size, channel); gst_rtsp_stream_transport_recv_data (trans, channel, buffer); } else { + GST_DEBUG_OBJECT (client, "received %u bytes of data for " + "unknown channel %u", size, channel); gst_buffer_unref (buffer); } From 6987a00fa9e3a918498a311a4069a427373a5d32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 21 Jan 2015 14:57:03 +0000 Subject: [PATCH 1078/1776] rtsp-stream: fix false compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rtsp-stream.c:3034: error: ‘visited’ may be used uninitialized in this function --- gst/rtsp-server/rtsp-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index d64fed4d29..9a7a59f246 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2811,7 +2811,7 @@ gst_rtsp_stream_transport_filter (GstRTSPStream * stream, { GstRTSPStreamPrivate *priv; GList *result, *walk, *next; - GHashTable *visited; + GHashTable *visited = NULL; guint cookie; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); From 18668bf49570b3ab75e35dd275f4761f0210cc42 Mon Sep 17 00:00:00 2001 From: Anila Balavan Date: Fri, 30 Jan 2015 12:50:20 +0100 Subject: [PATCH 1079/1776] rtsp-stream: RTCP and RTP transport cache cookies seperated RTCP packets were not sent because the same tr_cache_cookie was used for both RTP and RTCP. So only one of the tr_cache lists were populated depending on which one was sent first. If the tr_cache list is not populated then no packets can be sent. Most often this happened to be RTCP. Now seperate RTCP and RTP transport cache cookies are added which resulted in both the tr_cache_lists to be populated regardless of which one was sent first. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=743734 --- gst/rtsp-server/rtsp-stream.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 9a7a59f246..d2e043290b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -141,7 +141,9 @@ struct _GstRTSPStreamPrivate guint transports_cookie; GList *tr_cache_rtp; GList *tr_cache_rtcp; - guint tr_cache_cookie; + guint tr_cache_cookie_rtp; + guint tr_cache_cookie_rtcp; + /* UDP sources for UDP multicast transports */ GList *transport_sources; @@ -1610,19 +1612,26 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) is_rtp = GST_ELEMENT_CAST (sink) == priv->appsink[0]; g_mutex_lock (&priv->lock); - if (priv->tr_cache_cookie != priv->transports_cookie) { - clear_tr_cache (priv, is_rtp); - for (walk = priv->transports; walk; walk = g_list_next (walk)) { - GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - if (is_rtp) { + if (is_rtp) { + if (priv->tr_cache_cookie_rtp != priv->transports_cookie) { + clear_tr_cache (priv, is_rtp); + for (walk = priv->transports; walk; walk = g_list_next (walk)) { + GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; priv->tr_cache_rtp = g_list_prepend (priv->tr_cache_rtp, g_object_ref (tr)); - } else { + } + priv->tr_cache_cookie_rtp = priv->transports_cookie; + } + } else { + if (priv->tr_cache_cookie_rtcp != priv->transports_cookie) { + clear_tr_cache (priv, is_rtp); + for (walk = priv->transports; walk; walk = g_list_next (walk)) { + GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; priv->tr_cache_rtcp = g_list_prepend (priv->tr_cache_rtcp, g_object_ref (tr)); } + priv->tr_cache_cookie_rtcp = priv->transports_cookie; } - priv->tr_cache_cookie = priv->transports_cookie; } g_mutex_unlock (&priv->lock); From ccf6c6eb53cc35050a9d9b736a6714268446c550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 9 Jan 2015 12:40:47 +0100 Subject: [PATCH 1080/1776] Add initial support for RECORD We currently only support media that is RECORD or PLAY only, not both at once. https://bugzilla.gnome.org/show_bug.cgi?id=743175 --- examples/Makefile.am | 2 +- examples/test-record.c | 68 +++ gst/rtsp-server/rtsp-client.c | 372 ++++++++++++- gst/rtsp-server/rtsp-client.h | 8 +- gst/rtsp-server/rtsp-media-factory.c | 70 +++ gst/rtsp-server/rtsp-media-factory.h | 4 + gst/rtsp-server/rtsp-media.c | 776 +++++++++++++++++++++++++-- gst/rtsp-server/rtsp-media.h | 10 +- gst/rtsp-server/rtsp-session-media.c | 3 + gst/rtsp-server/rtsp-stream.c | 236 ++++++-- gst/rtsp-server/rtsp-stream.h | 5 +- 11 files changed, 1468 insertions(+), 86 deletions(-) create mode 100644 examples/test-record.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 6d13ed6737..ef33adf75b 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,7 +1,7 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ test-launch test-sdp test-uri test-auth \ test-multicast test-multicast2 test-appsrc \ - test-video-rtx + test-video-rtx test-record #INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/examples/test-record.c b/examples/test-record.c new file mode 100644 index 0000000000..676ae982e5 --- /dev/null +++ b/examples/test-record.c @@ -0,0 +1,68 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * Copyright (C) 2015 Centricular Ltd + * Author: Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mount points for this server, every server has a default object + * that be used to map uri mount points to media factories */ + mounts = gst_rtsp_server_get_mount_points (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named depay%d. Each + * element with depay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_record (factory, TRUE); + gst_rtsp_media_factory_set_launch (factory, + "( decodebin name=depay0 ! autovideosink decodebin name=depay1 ! autoaudiosink )"); + + /* attach the test factory to the /test url */ + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mounts); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + g_main_loop_run (loop); + + return 0; +} diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c6b582c143..d69ef0a34f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1,5 +1,7 @@ /* GStreamer * Copyright (C) 2008 Wim Taymans + * Copyright (C) 2015 Centricular Ltd + * Author: Sebastian Dröge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -123,6 +125,8 @@ enum SIGNAL_GET_PARAMETER_REQUEST, SIGNAL_HANDLE_RESPONSE, SIGNAL_SEND_MESSAGE, + SIGNAL_ANNOUNCE_REQUEST, + SIGNAL_RECORD_REQUEST, SIGNAL_LAST }; @@ -138,6 +142,8 @@ static void gst_rtsp_client_set_property (GObject * object, guint propid, static void gst_rtsp_client_finalize (GObject * obj); static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media); +static gboolean handle_sdp (GstRTSPClient * client, GstRTSPContext * ctx, + GstRTSPMedia * media, GstSDPMessage * sdp); static gboolean default_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media, GstRTSPStream * stream, GstRTSPContext * ctx); static gboolean default_configure_client_transport (GstRTSPClient * client, @@ -167,6 +173,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gobject_class->finalize = gst_rtsp_client_finalize; klass->create_sdp = create_sdp; + klass->handle_sdp = handle_sdp; klass->configure_client_media = default_configure_client_media; klass->configure_client_transport = default_configure_client_transport; klass->params_set = default_params_set; @@ -266,6 +273,18 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) send_message), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_POINTER); + gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST] = + g_signal_new ("announce-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, announce_request), + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, + GST_TYPE_RTSP_CONTEXT); + + gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST] = + g_signal_new ("record-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, record_request), + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, + GST_TYPE_RTSP_CONTEXT); + tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); g_mutex_init (&tunnels_lock); @@ -606,8 +625,6 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path, path_len = strlen (path); if (!paths_are_equal (priv->path, path, path_len)) { - GstRTSPThread *thread; - /* remove any previously cached values before we try to construct a new * media for uri */ clean_cached_media (client, TRUE); @@ -618,14 +635,18 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path, ctx->media = media; - thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool, - GST_RTSP_THREAD_TYPE_MEDIA, ctx); - if (thread == NULL) - goto no_thread; + if (!gst_rtsp_media_is_record (media)) { + GstRTSPThread *thread; - /* prepare the media */ - if (!(gst_rtsp_media_prepare (media, thread))) - goto no_prepare; + thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool, + GST_RTSP_THREAD_TYPE_MEDIA, ctx); + if (thread == NULL) + goto no_thread; + + /* prepare the media */ + if (!gst_rtsp_media_prepare (media, thread)) + goto no_prepare; + } /* now keep track of the uri and the media */ priv->path = g_strndup (path, path_len); @@ -1124,6 +1145,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); + if (gst_rtsp_media_is_record (media)) + goto record_media; + /* the session state must be playing or ready */ rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY) @@ -1213,6 +1237,12 @@ unsuspend_failed: send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); return FALSE; } +record_media: + { + GST_ERROR ("client %p: RECORD media does not support PLAY", client); + send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); + return FALSE; + } } static void @@ -1400,8 +1430,8 @@ no_address: } static GstRTSPTransport * -make_server_transport (GstRTSPClient * client, GstRTSPContext * ctx, - GstRTSPTransport * ct) +make_server_transport (GstRTSPClient * client, GstRTSPMedia * media, + GstRTSPContext * ctx, GstRTSPTransport * ct) { GstRTSPTransport *st; GInetAddress *addr; @@ -1413,6 +1443,8 @@ make_server_transport (GstRTSPClient * client, GstRTSPContext * ctx, st->trans = ct->trans; st->profile = ct->profile; st->lower_transport = ct->lower_transport; + st->mode_play = ct->mode_play; + st->mode_record = ct->mode_record; addr = g_inet_address_new_from_string (ct->destination); @@ -1443,7 +1475,8 @@ make_server_transport (GstRTSPClient * client, GstRTSPContext * ctx, break; } - gst_rtsp_stream_get_ssrc (ctx->stream, &st->ssrc); + if (!gst_rtsp_media_is_record (media)) + gst_rtsp_stream_get_ssrc (ctx->stream, &st->ssrc); return st; } @@ -1824,6 +1857,11 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!parse_transport (transport, stream, ct)) goto unsupported_transports; + /* TODO: Add support for PLAY,RECORD media */ + if ((ct->mode_play && gst_rtsp_media_is_record (media)) || + (ct->mode_record && !gst_rtsp_media_is_record (media))) + goto unsupported_mode; + /* parse the keymgmt */ if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_KEYMGMT, &keymgmt, 0) == GST_RTSP_OK) { @@ -1877,7 +1915,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) } /* create and serialize the server transport */ - st = make_server_transport (client, ctx, ct); + st = make_server_transport (client, media, ctx, ct); trans_str = gst_rtsp_transport_as_text (st); gst_rtsp_transport_free (st); @@ -1989,6 +2027,14 @@ unsupported_client_transport: send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); goto cleanup_transport; } +unsupported_mode: + { + GST_ERROR ("client %p: unsupported mode (media record: %d, mode play: %d" + ", mode record: %d)", client, gst_rtsp_media_is_record (media), + ct->mode_play, ct->mode_record); + send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); + goto cleanup_transport; + } keymgmt_error: { GST_ERROR ("client %p: keymgmt error", client); @@ -2102,6 +2148,9 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!(media = find_media (client, ctx, path, NULL))) goto no_media; + if (gst_rtsp_media_is_record (media)) + goto record_media; + /* create an SDP for the media object on this client */ if (!(sdp = klass->create_sdp (client, media))) goto no_sdp; @@ -2161,6 +2210,14 @@ no_media: /* error reply is already sent */ return FALSE; } +record_media: + { + GST_ERROR ("client %p: RECORD media does not support DESCRIBE", client); + send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); + g_free (path); + g_object_unref (media); + return FALSE; + } no_sdp: { GST_ERROR ("client %p: can't create SDP", client); @@ -2171,6 +2228,291 @@ no_sdp: } } +static gboolean +handle_sdp (GstRTSPClient * client, GstRTSPContext * ctx, GstRTSPMedia * media, + GstSDPMessage * sdp) +{ + GstRTSPClientPrivate *priv = client->priv; + GstRTSPThread *thread; + + /* create an SDP for the media object */ + if (!gst_rtsp_media_handle_sdp (media, sdp)) + goto unhandled_sdp; + + thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool, + GST_RTSP_THREAD_TYPE_MEDIA, ctx); + if (thread == NULL) + goto no_thread; + + /* prepare the media */ + if (!gst_rtsp_media_prepare (media, thread)) + goto no_prepare; + + return TRUE; + + /* ERRORS */ +unhandled_sdp: + { + GST_ERROR ("client %p: could not handle SDP", client); + return FALSE; + } +no_thread: + { + GST_ERROR ("client %p: can't create thread", client); + return FALSE; + } +no_prepare: + { + GST_ERROR ("client %p: can't prepare media", client); + return FALSE; + } +} + +static gboolean +handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) +{ + GstRTSPClientPrivate *priv = client->priv; + GstRTSPClientClass *klass; + GstSDPResult sres; + GstSDPMessage *sdp; + GstRTSPMedia *media; + gchar *path, *cont = NULL; + guint8 *data; + guint size; + + klass = GST_RTSP_CLIENT_GET_CLASS (client); + + if (!ctx->uri) + goto no_uri; + + if (!priv->mount_points) + goto no_mount_points; + + if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri))) + goto no_path; + + /* check if reply is SDP */ + gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_CONTENT_TYPE, &cont, + 0); + /* could not be set but since the request returned OK, we assume it + * was SDP, else check it. */ + if (cont) { + if (!g_ascii_strcasecmp (cont, "application/sdp") == 0) + goto wrong_content_type; + } + + /* get message body and parse as SDP */ + gst_rtsp_message_get_body (ctx->request, &data, &size); + if (data == NULL || size == 0) + goto no_message; + + GST_DEBUG ("client %p: parse SDP...", client); + gst_sdp_message_new (&sdp); + sres = gst_sdp_message_parse_buffer (data, size, sdp); + if (sres != GST_SDP_OK) + goto sdp_parse_failed; + + if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri))) + goto no_path; + + /* find the media object for the uri */ + if (!(media = find_media (client, ctx, path, NULL))) + goto no_media; + + if (!gst_rtsp_media_is_record (media)) + goto play_media; + + /* Tell client subclass about the media */ + if (!klass->handle_sdp (client, ctx, media, sdp)) + goto unhandled_sdp; + + /* we suspend after the announce */ + gst_rtsp_media_suspend (media); + g_object_unref (media); + + gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK, + gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request); + + send_message (client, ctx, ctx->response, FALSE); + + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST], + 0, ctx); + + return TRUE; + +no_uri: + { + GST_ERROR ("client %p: no uri", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + return FALSE; + } +no_mount_points: + { + GST_ERROR ("client %p: no mount points configured", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } +no_path: + { + GST_ERROR ("client %p: can't find path for url", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } +wrong_content_type: + { + GST_ERROR ("client %p: unknown content type", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + g_free (path); + return FALSE; + } +no_message: + { + GST_ERROR ("client %p: can't find SDP message", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + g_free (path); + return FALSE; + } +sdp_parse_failed: + { + GST_ERROR ("client %p: failed to parse SDP message", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + g_free (path); + return FALSE; + } +no_media: + { + GST_ERROR ("client %p: no media", client); + g_free (path); + /* error reply is already sent */ + return FALSE; + } +play_media: + { + GST_ERROR ("client %p: PLAY media does not support ANNOUNCE", client); + send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); + g_free (path); + g_object_unref (media); + return FALSE; + } +unhandled_sdp: + { + GST_ERROR ("client %p: can't handle SDP", client); + send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, ctx); + g_free (path); + g_object_unref (media); + return FALSE; + } +} + +static gboolean +handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx) +{ + GstRTSPSession *session; + GstRTSPClientClass *klass; + GstRTSPSessionMedia *sessmedia; + GstRTSPMedia *media; + GstRTSPUrl *uri; + GstRTSPState rtspstate; + gchar *path; + gint matched; + + if (!(session = ctx->session)) + goto no_session; + + if (!(uri = ctx->uri)) + goto no_uri; + + klass = GST_RTSP_CLIENT_GET_CLASS (client); + path = klass->make_path_from_uri (client, uri); + + /* get a handle to the configuration of the media in the session */ + sessmedia = gst_rtsp_session_get_media (session, path, &matched); + if (!sessmedia) + goto not_found; + + if (path[matched] != '\0') + goto no_aggregate; + + g_free (path); + + ctx->sessmedia = sessmedia; + ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); + + if (!gst_rtsp_media_is_record (media)) + goto play_media; + + /* the session state must be playing or ready */ + rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); + if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY) + goto invalid_state; + + /* in play we first unsuspend, media could be suspended from SDP or PAUSED */ + if (!gst_rtsp_media_unsuspend (media)) + goto unsuspend_failed; + + gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK, + gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request); + + send_message (client, ctx, ctx->response, FALSE); + + /* start playing after sending the response */ + gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING); + + gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING); + + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST], 0, + ctx); + + return TRUE; + + /* ERRORS */ +no_session: + { + GST_ERROR ("client %p: no session", client); + send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); + return FALSE; + } +no_uri: + { + GST_ERROR ("client %p: no uri supplied", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + return FALSE; + } +not_found: + { + GST_ERROR ("client %p: media not found", client); + send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + return FALSE; + } +no_aggregate: + { + GST_ERROR ("client %p: no aggregate path %s", client, path); + send_generic_response (client, + GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); + g_free (path); + return FALSE; + } +play_media: + { + GST_ERROR ("client %p: PLAY media does not support RECORD", client); + send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); + return FALSE; + } +invalid_state: + { + GST_ERROR ("client %p: not PLAYING or READY", client); + send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, + ctx); + return FALSE; + } +unsuspend_failed: + { + GST_ERROR ("client %p: unsuspend failed", client); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + return FALSE; + } +} + static gboolean handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx) { @@ -2456,7 +2798,11 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) handle_get_param_request (client, ctx); break; case GST_RTSP_ANNOUNCE: + handle_announce_request (client, ctx); + break; case GST_RTSP_RECORD: + handle_record_request (client, ctx); + break; case GST_RTSP_REDIRECT: if (priv->watch != NULL) gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 4e9519a101..5137cc62aa 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -121,8 +121,14 @@ struct _GstRTSPClientClass { GstRTSPMessage * response); void (*send_message) (GstRTSPClient * client, GstRTSPContext *ctx, GstRTSPMessage * response); + + gboolean (*handle_sdp) (GstRTSPClient *client, GstRTSPContext *ctx, GstRTSPMedia *media, GstSDPMessage *sdp); + + void (*announce_request) (GstRTSPClient *client, GstRTSPContext *ctx); + void (*record_request) (GstRTSPClient *client, GstRTSPContext *ctx); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE-2]; + gpointer _gst_reserved[GST_PADDING_LARGE-5]; }; GType gst_rtsp_client_get_type (void); diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 6e0da84b39..34a0ac84e6 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -1,5 +1,7 @@ /* GStreamer * Copyright (C) 2008 Wim Taymans + * Copyright (C) 2015 Centricular Ltd + * Author: Sebastian Dröge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -51,6 +53,7 @@ struct _GstRTSPMediaFactoryPrivate GstRTSPPermissions *permissions; gchar *launch; gboolean shared; + gboolean record; GstRTSPSuspendMode suspend_mode; gboolean eos_shutdown; GstRTSPProfile profiles; @@ -72,6 +75,7 @@ struct _GstRTSPMediaFactoryPrivate #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_BUFFER_SIZE 0x80000 +#define DEFAULT_RECORD FALSE enum { @@ -83,6 +87,7 @@ enum PROP_PROFILES, PROP_PROTOCOLS, PROP_BUFFER_SIZE, + PROP_RECORD, PROP_LAST }; @@ -181,6 +186,14 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "The kernel UDP buffer size to use", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /* FIXME: Should this be a flag property to allow RECORD and PLAY? + * Or just another boolean PLAY property that default to TRUE? + */ + g_object_class_install_property (gobject_class, PROP_RECORD, + g_param_spec_boolean ("record", "Record", + "If media from this factory is for PLAY or RECORD", DEFAULT_RECORD, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, @@ -273,6 +286,9 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_uint (value, gst_rtsp_media_factory_get_buffer_size (factory)); break; + case PROP_RECORD: + g_value_set_boolean (value, gst_rtsp_media_factory_is_record (factory)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -309,6 +325,9 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_buffer_size (factory, g_value_get_uint (value)); break; + case PROP_RECORD: + gst_rtsp_media_factory_set_record (factory, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1136,6 +1155,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstRTSPAddressPool *pool; GstRTSPPermissions *perms; GstClockTime rtx_time; + gboolean record; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -1146,6 +1166,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) profiles = priv->profiles; protocols = priv->protocols; rtx_time = priv->rtx_time; + record = priv->record; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_suspend_mode (media, suspend_mode); @@ -1155,6 +1176,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_profiles (media, profiles); gst_rtsp_media_set_protocols (media, protocols); gst_rtsp_media_set_retransmission_time (media, rtx_time); + gst_rtsp_media_set_record (media, record); if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) { gst_rtsp_media_set_address_pool (media, pool); @@ -1199,3 +1221,51 @@ gst_rtsp_media_factory_create_element (GstRTSPMediaFactory * factory, return result; } + +/** + * gst_rtsp_media_factory_set_record: + * @factory: a #GstRTSPMediaFactory + * @record: the new value + * + * Configure if this factory creates media for PLAY or RECORD methods. + */ +void +gst_rtsp_media_factory_set_record (GstRTSPMediaFactory * factory, + gboolean record) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv->record = record; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_is_record: + * @factory: a #GstRTSPMediaFactory + * + * Get if media created from this factory can be used for PLAY or RECORD + * methods. + * + * Returns: %TRUE if the media will be record between clients. + */ +gboolean +gst_rtsp_media_factory_is_record (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + gboolean result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + result = priv->record; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index ce069d7f79..288d111567 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -145,6 +145,10 @@ void gst_rtsp_media_factory_set_retransmission_time (GstRTSPMed GstClockTime time); GstClockTime gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory); +void gst_rtsp_media_factory_set_record (GstRTSPMediaFactory *factory, + gboolean record); +gboolean gst_rtsp_media_factory_is_record (GstRTSPMediaFactory *factory); + /* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index eddbf41a0c..9b64569df7 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1,5 +1,7 @@ /* GStreamer * Copyright (C) 2008 Wim Taymans + * Copyright (C) 2015 Centricular Ltd + * Author: Sebastian Dröge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -61,12 +63,22 @@ * Last reviewed on 2013-07-11 (1.0.0) */ +#include #include #include #include #include +#include +#include + +#define AES_128_KEY_LEN 16 +#define AES_256_KEY_LEN 32 + +#define HMAC_32_KEY_LEN 4 +#define HMAC_80_KEY_LEN 10 + #include "rtsp-media.h" #define GST_RTSP_MEDIA_GET_PRIVATE(obj) \ @@ -89,6 +101,7 @@ struct _GstRTSPMediaPrivate guint buffer_size; GstRTSPAddressPool *pool; gboolean blocked; + gboolean record; GstElement *element; GRecMutex state_lock; /* locking order: state lock, lock */ @@ -135,6 +148,7 @@ struct _GstRTSPMediaPrivate #define DEFAULT_EOS_SHUTDOWN FALSE #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_TIME_PROVIDER FALSE +#define DEFAULT_RECORD FALSE /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -151,6 +165,7 @@ enum PROP_BUFFER_SIZE, PROP_ELEMENT, PROP_TIME_PROVIDER, + PROP_RECORD, PROP_LAST }; @@ -189,6 +204,7 @@ static gboolean default_query_stop (GstRTSPMedia * media, gint64 * stop); static GstElement *default_create_rtpbin (GstRTSPMedia * media); static gboolean default_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, GstSDPInfo * info); +static gboolean default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp); static gboolean wait_preroll (GstRTSPMedia * media); @@ -277,6 +293,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "Use a NetTimeProvider for clients", DEFAULT_TIME_PROVIDER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_RECORD, + g_param_spec_boolean ("record", "Record", + "If this media pipeline can be used for PLAY or RECORD", + DEFAULT_RECORD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, @@ -320,6 +341,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) klass->query_stop = default_query_stop; klass->create_rtpbin = default_create_rtpbin; klass->setup_sdp = default_setup_sdp; + klass->handle_sdp = default_handle_sdp; } static void @@ -342,6 +364,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN; priv->buffer_size = DEFAULT_BUFFER_SIZE; priv->time_provider = DEFAULT_TIME_PROVIDER; + priv->record = DEFAULT_RECORD; } static void @@ -412,6 +435,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_TIME_PROVIDER: g_value_set_boolean (value, gst_rtsp_media_is_time_provider (media)); break; + case PROP_RECORD: + g_value_set_boolean (value, gst_rtsp_media_is_record (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -452,6 +478,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_TIME_PROVIDER: gst_rtsp_media_use_time_provider (media, g_value_get_boolean (value)); break; + case PROP_RECORD: + gst_rtsp_media_set_record (media, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1300,6 +1329,9 @@ _next_available_pt (GList * payloads) * * Collect all dynamic elements, named dynpay\%d, and add them to * the list of dynamic elements. + * + * Find all depayloader elements, they should be named depay\%d in the + * element of @media, and create #GstRTSPStreams for them. */ void gst_rtsp_media_collect_streams (GstRTSPMedia * media) @@ -1348,6 +1380,21 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) have_elem = TRUE; } g_free (name); + + name = g_strdup_printf ("depay%d", i); + if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { + GST_INFO ("found stream %d with depayloader %p", i, elem); + + /* take the pad of the payloader */ + pad = gst_element_get_static_pad (elem, "sink"); + /* create the stream */ + gst_rtsp_media_create_stream (media, elem, pad); + gst_object_unref (pad); + gst_object_unref (elem); + + have_elem = TRUE; + } + g_free (name); } } @@ -1355,10 +1402,10 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) * gst_rtsp_media_create_stream: * @media: a #GstRTSPMedia * @payloader: a #GstElement - * @srcpad: a source #GstPad + * @pad: a #GstPad * - * Create a new stream in @media that provides RTP data on @srcpad. - * @srcpad should be a pad of an element inside @media->element. + * Create a new stream in @media that provides RTP data on @pad. + * @pad should be a pad of an element inside @media->element. * * Returns: (transfer none): a new #GstRTSPStream that remains valid for as long * as @media exists. @@ -1369,15 +1416,13 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, { GstRTSPMediaPrivate *priv; GstRTSPStream *stream; - GstPad *srcpad; + GstPad *ghostpad; gchar *name; gint idx; - gint i, n; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL); g_return_val_if_fail (GST_IS_PAD (pad), NULL); - g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL); priv = media->priv; @@ -1386,13 +1431,17 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, GST_DEBUG ("media %p: creating stream with index %d", media, idx); - name = g_strdup_printf ("src_%u", idx); - srcpad = gst_ghost_pad_new (name, pad); - gst_pad_set_active (srcpad, TRUE); - gst_element_add_pad (priv->element, srcpad); + if (GST_PAD_IS_SRC (pad)) + name = g_strdup_printf ("src_%u", idx); + else + name = g_strdup_printf ("sink_%u", idx); + + ghostpad = gst_ghost_pad_new (name, pad); + gst_pad_set_active (ghostpad, TRUE); + gst_element_add_pad (priv->element, ghostpad); g_free (name); - stream = gst_rtsp_stream_new (idx, payloader, srcpad); + stream = gst_rtsp_stream_new (idx, payloader, ghostpad); if (priv->pool) gst_rtsp_stream_set_address_pool (stream, priv->pool); gst_rtsp_stream_set_profiles (stream, priv->profiles); @@ -1401,23 +1450,28 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, g_ptr_array_add (priv->streams, stream); - if (priv->payloads) - g_list_free (priv->payloads); - priv->payloads = _find_payload_types (media); + if (GST_PAD_IS_SRC (pad)) { + gint i, n; - n = priv->streams->len; - for (i = 0; i < n; i++) { - GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); - guint rtx_pt = _next_available_pt (priv->payloads); + if (priv->payloads) + g_list_free (priv->payloads); + priv->payloads = _find_payload_types (media); - if (rtx_pt == 0) { - GST_WARNING ("Ran out of space of dynamic payload types"); - break; + n = priv->streams->len; + for (i = 0; i < n; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + guint rtx_pt = _next_available_pt (priv->payloads); + + if (rtx_pt == 0) { + GST_WARNING ("Ran out of space of dynamic payload types"); + break; + } + + gst_rtsp_stream_set_retransmission_pt (stream, rtx_pt); + + priv->payloads = + g_list_append (priv->payloads, GUINT_TO_POINTER (rtx_pt)); } - - gst_rtsp_stream_set_retransmission_pt (stream, rtx_pt); - - priv->payloads = g_list_append (priv->payloads, GUINT_TO_POINTER (rtx_pt)); } g_mutex_unlock (&priv->lock); @@ -1716,16 +1770,21 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) goto not_prepared; /* Update the seekable state of the pipeline in case it changed */ - query = gst_query_new_seeking (GST_FORMAT_TIME); - if (gst_element_query (priv->pipeline, query)) { - GstFormat format; - gboolean seekable; - gint64 start, end; + if (gst_rtsp_media_is_record (media)) { + /* TODO: Seeking for RECORD? */ + priv->seekable = FALSE; + } else { + query = gst_query_new_seeking (GST_FORMAT_TIME); + if (gst_element_query (priv->pipeline, query)) { + GstFormat format; + gboolean seekable; + gint64 start, end; - gst_query_parse_seeking (query, &format, &seekable, &start, &end); - priv->seekable = seekable; + gst_query_parse_seeking (query, &format, &seekable, &start, &end); + priv->seekable = seekable; + } + gst_query_unref (query); } - gst_query_unref (query); if (!priv->seekable) goto not_seekable; @@ -1898,7 +1957,28 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) switch (type) { case GST_MESSAGE_STATE_CHANGED: + { + GstState old, new, pending; + + if (GST_MESSAGE_SRC (message) != GST_OBJECT (priv->pipeline)) + break; + + gst_message_parse_state_changed (message, &old, &new, &pending); + + GST_DEBUG ("%p: went from %s to %s (pending %s)", media, + gst_element_state_get_name (old), gst_element_state_get_name (new), + gst_element_state_get_name (pending)); + if (gst_rtsp_media_is_record (media) + && old == GST_STATE_READY && new == GST_STATE_PAUSED) { + GST_INFO ("%p: went to PAUSED, prepared now", media); + collect_media_stats (media); + + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); + } + break; + } case GST_MESSAGE_BUFFERING: { gint percent; @@ -2203,8 +2283,10 @@ start_preroll (GstRTSPMedia * media) * seeking query in preroll instead */ priv->seekable = FALSE; priv->is_live = TRUE; - /* start blocked to make sure nothing goes to the sink */ - media_streams_set_blocked (media, TRUE); + if (!gst_rtsp_media_is_record (media)) { + /* start blocked to make sure nothing goes to the sink */ + media_streams_set_blocked (media, TRUE); + } ret = set_state (media, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; @@ -2830,6 +2912,583 @@ no_setup_sdp: } } +static const gchar * +rtsp_get_attribute_for_pt (const GstSDPMedia * media, const gchar * name, + gint pt) +{ + guint i; + + for (i = 0;; i++) { + const gchar *attr; + gint val; + + if ((attr = gst_sdp_media_get_attribute_val_n (media, name, i)) == NULL) + break; + + if (sscanf (attr, "%d ", &val) != 1) + continue; + + if (val == pt) + return attr; + } + return NULL; +} + +#define PARSE_INT(p, del, res) \ +G_STMT_START { \ + gchar *t = p; \ + p = strstr (p, del); \ + if (p == NULL) \ + res = -1; \ + else { \ + *p = '\0'; \ + p++; \ + res = atoi (t); \ + } \ +} G_STMT_END + +#define PARSE_STRING(p, del, res) \ +G_STMT_START { \ + gchar *t = p; \ + p = strstr (p, del); \ + if (p == NULL) { \ + res = NULL; \ + p = t; \ + } \ + else { \ + *p = '\0'; \ + p++; \ + res = t; \ + } \ +} G_STMT_END + +#define SKIP_SPACES(p) \ + while (*p && g_ascii_isspace (*p)) \ + p++; + +/* rtpmap contains: + * + * /[/] + */ +static gboolean +parse_rtpmap (const gchar * rtpmap, gint * payload, gchar ** name, + gint * rate, gchar ** params) +{ + gchar *p, *t; + + p = (gchar *) rtpmap; + + PARSE_INT (p, " ", *payload); + if (*payload == -1) + return FALSE; + + SKIP_SPACES (p); + if (*p == '\0') + return FALSE; + + PARSE_STRING (p, "/", *name); + if (*name == NULL) { + GST_DEBUG ("no rate, name %s", p); + /* no rate, assume -1 then, this is not supposed to happen but RealMedia + * streams seem to omit the rate. */ + *name = p; + *rate = -1; + return TRUE; + } + + t = p; + p = strstr (p, "/"); + if (p == NULL) { + *rate = atoi (t); + return TRUE; + } + *p = '\0'; + p++; + *rate = atoi (t); + + t = p; + if (*p == '\0') + return TRUE; + *params = t; + + return TRUE; +} + +/* + * Mapping of caps to and from SDP fields: + * + * a=rtpmap: /[/] + * a=fmtp: [=];... + */ +static GstCaps * +media_to_caps (gint pt, const GstSDPMedia * media) +{ + GstCaps *caps; + const gchar *rtpmap; + const gchar *fmtp; + gchar *name = NULL; + gint rate = -1; + gchar *params = NULL; + gchar *tmp; + GstStructure *s; + gint payload = 0; + gboolean ret; + + /* get and parse rtpmap */ + rtpmap = rtsp_get_attribute_for_pt (media, "rtpmap", pt); + + if (rtpmap) { + ret = parse_rtpmap (rtpmap, &payload, &name, &rate, ¶ms); + if (!ret) { + g_warning ("error parsing rtpmap, ignoring"); + rtpmap = NULL; + } + } + /* dynamic payloads need rtpmap or we fail */ + if (rtpmap == NULL && pt >= 96) + goto no_rtpmap; + + /* check if we have a rate, if not, we need to look up the rate from the + * default rates based on the payload types. */ + if (rate == -1) { + const GstRTPPayloadInfo *info; + + if (GST_RTP_PAYLOAD_IS_DYNAMIC (pt)) { + /* dynamic types, use media and encoding_name */ + tmp = g_ascii_strdown (media->media, -1); + info = gst_rtp_payload_info_for_name (tmp, name); + g_free (tmp); + } else { + /* static types, use payload type */ + info = gst_rtp_payload_info_for_pt (pt); + } + + if (info) { + if ((rate = info->clock_rate) == 0) + rate = -1; + } + /* we fail if we cannot find one */ + if (rate == -1) + goto no_rate; + } + + tmp = g_ascii_strdown (media->media, -1); + caps = gst_caps_new_simple ("application/x-unknown", + "media", G_TYPE_STRING, tmp, "payload", G_TYPE_INT, pt, NULL); + g_free (tmp); + s = gst_caps_get_structure (caps, 0); + + gst_structure_set (s, "clock-rate", G_TYPE_INT, rate, NULL); + + /* encoding name must be upper case */ + if (name != NULL) { + tmp = g_ascii_strup (name, -1); + gst_structure_set (s, "encoding-name", G_TYPE_STRING, tmp, NULL); + g_free (tmp); + } + + /* params must be lower case */ + if (params != NULL) { + tmp = g_ascii_strdown (params, -1); + gst_structure_set (s, "encoding-params", G_TYPE_STRING, tmp, NULL); + g_free (tmp); + } + + /* parse optional fmtp: field */ + if ((fmtp = rtsp_get_attribute_for_pt (media, "fmtp", pt))) { + gchar *p; + gint payload = 0; + + p = (gchar *) fmtp; + + /* p is now of the format [=];... */ + PARSE_INT (p, " ", payload); + if (payload != -1 && payload == pt) { + gchar **pairs; + gint i; + + /* [=] are separated with ';' */ + pairs = g_strsplit (p, ";", 0); + for (i = 0; pairs[i]; i++) { + gchar *valpos; + const gchar *val, *key; + + /* the key may not have a '=', the value can have other '='s */ + valpos = strstr (pairs[i], "="); + if (valpos) { + /* we have a '=' and thus a value, remove the '=' with \0 */ + *valpos = '\0'; + /* value is everything between '=' and ';'. We split the pairs at ; + * boundaries so we can take the remainder of the value. Some servers + * put spaces around the value which we strip off here. Alternatively + * we could strip those spaces in the depayloaders should these spaces + * actually carry any meaning in the future. */ + val = g_strstrip (valpos + 1); + } else { + /* simple ;.. is translated into =1;... */ + val = "1"; + } + /* strip the key of spaces, convert key to lowercase but not the value. */ + key = g_strstrip (pairs[i]); + if (strlen (key) > 1) { + tmp = g_ascii_strdown (key, -1); + gst_structure_set (s, tmp, G_TYPE_STRING, val, NULL); + g_free (tmp); + } + } + g_strfreev (pairs); + } + } + return caps; + + /* ERRORS */ +no_rtpmap: + { + g_warning ("rtpmap type not given for dynamic payload %d", pt); + return NULL; + } +no_rate: + { + g_warning ("rate unknown for payload type %d", pt); + return NULL; + } +} + +static gboolean +parse_keymgmt (const gchar * keymgmt, GstCaps * caps) +{ + gboolean res = FALSE; + gchar *p, *kmpid; + gsize size; + guchar *data; + GstMIKEYMessage *msg; + const GstMIKEYPayload *payload; + const gchar *srtp_cipher; + const gchar *srtp_auth; + + p = (gchar *) keymgmt; + + SKIP_SPACES (p); + if (*p == '\0') + return FALSE; + + PARSE_STRING (p, " ", kmpid); + if (!g_str_equal (kmpid, "mikey")) + return FALSE; + + data = g_base64_decode (p, &size); + if (data == NULL) + return FALSE; + + msg = gst_mikey_message_new_from_data (data, size, NULL, NULL); + g_free (data); + if (msg == NULL) + return FALSE; + + srtp_cipher = "aes-128-icm"; + srtp_auth = "hmac-sha1-80"; + + /* check the Security policy if any */ + if ((payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, 0))) { + GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload; + guint len, i; + + if (p->proto != GST_MIKEY_SEC_PROTO_SRTP) + goto done; + + len = gst_mikey_payload_sp_get_n_params (payload); + for (i = 0; i < len; i++) { + const GstMIKEYPayloadSPParam *param = + gst_mikey_payload_sp_get_param (payload, i); + + switch (param->type) { + case GST_MIKEY_SP_SRTP_ENC_ALG: + switch (param->val[0]) { + case 0: + srtp_cipher = "null"; + break; + case 2: + case 1: + srtp_cipher = "aes-128-icm"; + break; + default: + break; + } + break; + case GST_MIKEY_SP_SRTP_ENC_KEY_LEN: + switch (param->val[0]) { + case AES_128_KEY_LEN: + srtp_cipher = "aes-128-icm"; + break; + case AES_256_KEY_LEN: + srtp_cipher = "aes-256-icm"; + break; + default: + break; + } + break; + case GST_MIKEY_SP_SRTP_AUTH_ALG: + switch (param->val[0]) { + case 0: + srtp_auth = "null"; + break; + case 2: + case 1: + srtp_auth = "hmac-sha1-80"; + break; + default: + break; + } + break; + case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN: + switch (param->val[0]) { + case HMAC_32_KEY_LEN: + srtp_auth = "hmac-sha1-32"; + break; + case HMAC_80_KEY_LEN: + srtp_auth = "hmac-sha1-80"; + break; + default: + break; + } + break; + case GST_MIKEY_SP_SRTP_SRTP_ENC: + break; + case GST_MIKEY_SP_SRTP_SRTCP_ENC: + break; + default: + break; + } + } + } + + if (!(payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_KEMAC, 0))) + goto done; + else { + GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload; + const GstMIKEYPayload *sub; + GstMIKEYPayloadKeyData *pkd; + GstBuffer *buf; + + if (p->enc_alg != GST_MIKEY_ENC_NULL || p->mac_alg != GST_MIKEY_MAC_NULL) + goto done; + + if (!(sub = gst_mikey_payload_kemac_get_sub (payload, 0))) + goto done; + + if (sub->type != GST_MIKEY_PT_KEY_DATA) + goto done; + + pkd = (GstMIKEYPayloadKeyData *) sub; + buf = + gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len), + pkd->key_len); + gst_caps_set_simple (caps, "srtp-key", GST_TYPE_BUFFER, buf, NULL); + } + + gst_caps_set_simple (caps, + "srtp-cipher", G_TYPE_STRING, srtp_cipher, + "srtp-auth", G_TYPE_STRING, srtp_auth, + "srtcp-cipher", G_TYPE_STRING, srtp_cipher, + "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL); + + res = TRUE; +done: + gst_mikey_message_unref (msg); + + return res; +} + +/* + * Mapping SDP attributes to caps + * + * prepend 'a-' to IANA registered sdp attributes names + * (ie: not prefixed with 'x-') in order to avoid + * collision with gstreamer standard caps properties names + */ +static void +sdp_attributes_to_caps (GArray * attributes, GstCaps * caps) +{ + if (attributes->len > 0) { + GstStructure *s; + guint i; + + s = gst_caps_get_structure (caps, 0); + + for (i = 0; i < attributes->len; i++) { + GstSDPAttribute *attr = &g_array_index (attributes, GstSDPAttribute, i); + gchar *tofree, *key; + + key = attr->key; + + /* skip some of the attribute we already handle */ + if (!strcmp (key, "fmtp")) + continue; + if (!strcmp (key, "rtpmap")) + continue; + if (!strcmp (key, "control")) + continue; + if (!strcmp (key, "range")) + continue; + if (g_str_equal (key, "key-mgmt")) { + parse_keymgmt (attr->value, caps); + continue; + } + + /* string must be valid UTF8 */ + if (!g_utf8_validate (attr->value, -1, NULL)) + continue; + + if (!g_str_has_prefix (key, "x-")) + tofree = key = g_strdup_printf ("a-%s", key); + else + tofree = NULL; + + GST_DEBUG ("adding caps: %s=%s", key, attr->value); + gst_structure_set (s, key, G_TYPE_STRING, attr->value, NULL); + g_free (tofree); + } + } +} + +static gboolean +default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp) +{ + GstRTSPMediaPrivate *priv = media->priv; + gint i, medias_len; + + medias_len = gst_sdp_message_medias_len (sdp); + if (medias_len != priv->streams->len) { + GST_ERROR ("%p: Media has more or less streams than SDP (%d /= %d)", media, + priv->streams->len, medias_len); + return FALSE; + } + + for (i = 0; i < medias_len; i++) { + const gchar *proto, *media_type; + const GstSDPMedia *sdp_media = gst_sdp_message_get_media (sdp, i); + GstRTSPStream *stream; + gint j, formats_len; + const gchar *control; + GstRTSPProfile profile, profiles; + + stream = g_ptr_array_index (priv->streams, i); + + /* TODO: Should we do something with the other SDP information? */ + + /* get proto */ + proto = gst_sdp_media_get_proto (sdp_media); + if (proto == NULL) { + GST_ERROR ("%p: SDP media %d has no proto", media, i); + return FALSE; + } + + if (g_str_equal (proto, "RTP/AVP")) { + media_type = "application/x-rtp"; + profile = GST_RTSP_PROFILE_AVP; + } else if (g_str_equal (proto, "RTP/SAVP")) { + media_type = "application/x-srtp"; + profile = GST_RTSP_PROFILE_SAVP; + } else if (g_str_equal (proto, "RTP/AVPF")) { + media_type = "application/x-rtp"; + profile = GST_RTSP_PROFILE_AVPF; + } else if (g_str_equal (proto, "RTP/SAVPF")) { + media_type = "application/x-srtp"; + profile = GST_RTSP_PROFILE_SAVPF; + } else { + GST_ERROR ("%p: unsupported profile '%s' for stream %d", media, proto, i); + return FALSE; + } + + profiles = gst_rtsp_stream_get_profiles (stream); + if ((profiles & profile) == 0) { + GST_ERROR ("%p: unsupported profile '%s' for stream %d", media, proto, i); + return FALSE; + } + + formats_len = gst_sdp_media_formats_len (sdp_media); + for (j = 0; j < formats_len; j++) { + gint pt; + GstCaps *caps; + GstStructure *s; + + pt = atoi (gst_sdp_media_get_format (sdp_media, j)); + + GST_DEBUG (" looking at %d pt: %d", j, pt); + + /* convert caps */ + caps = media_to_caps (pt, sdp_media); + if (caps == NULL) { + GST_WARNING (" skipping pt %d without caps", pt); + continue; + } + + /* do some tweaks */ + GST_DEBUG ("mapping sdp session level attributes to caps"); + sdp_attributes_to_caps (sdp->attributes, caps); + GST_DEBUG ("mapping sdp media level attributes to caps"); + sdp_attributes_to_caps (sdp_media->attributes, caps); + + s = gst_caps_get_structure (caps, 0); + gst_structure_set_name (s, media_type); + + gst_rtsp_stream_set_pt_map (stream, pt, caps); + gst_caps_unref (caps); + } + + control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + if (control) + gst_rtsp_stream_set_control (stream, control); + + } + + return TRUE; +} + +/** + * gst_rtsp_media_handle_sdp: + * @media: a #GstRTSPMedia + * @sdp: (transfer none): a #GstSDPMessage + * + * Configure an SDP on @media for receiving streams + * + * Returns: TRUE on success. + */ +gboolean +gst_rtsp_media_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp) +{ + GstRTSPMediaPrivate *priv; + GstRTSPMediaClass *klass; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + g_return_val_if_fail (sdp != NULL, FALSE); + + priv = media->priv; + + g_rec_mutex_lock (&priv->state_lock); + + klass = GST_RTSP_MEDIA_GET_CLASS (media); + + if (!klass->handle_sdp) + goto no_handle_sdp; + + res = klass->handle_sdp (media, sdp); + + g_rec_mutex_unlock (&priv->state_lock); + + return res; + + /* ERRORS */ +no_handle_sdp: + { + g_rec_mutex_unlock (&priv->state_lock); + GST_ERROR ("no handle_sdp function"); + g_critical ("no handle_sdp vmethod function set"); + return FALSE; + } +} + static void do_set_seqnum (GstRTSPStream * stream) { @@ -3214,3 +3873,50 @@ error_status: return FALSE; } } + +/** + * gst_rtsp_media_set_record: + * @media: a #GstRTSPMedia + * @record: the new value + * + * Set or unset if the pipeline for @media can be used for PLAY or RECORD + * methods. + */ +void +gst_rtsp_media_set_record (GstRTSPMedia * media, gboolean record) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->record = record; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_is_record: + * @media: a #GstRTSPMedia + * + * Check if the pipeline for @media can be used for PLAY or RECORD methods. + * + * Returns: %TRUE if the media can be record between clients. + */ +gboolean +gst_rtsp_media_is_record (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->record; + g_mutex_unlock (&priv->lock); + + return res; +} diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 7c7515b62c..6b4922b9d0 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -149,8 +149,10 @@ struct _GstRTSPMediaClass { void (*target_state) (GstRTSPMedia *media, GstState state); void (*new_state) (GstRTSPMedia *media, GstState state); + gboolean (*handle_sdp) (GstRTSPMedia *media, GstSDPMessage *sdp); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE]; + gpointer _gst_reserved[GST_PADDING_LARGE-1]; }; GType gst_rtsp_media_get_type (void); @@ -170,6 +172,9 @@ GstRTSPPermissions * gst_rtsp_media_get_permissions (GstRTSPMedia *media); void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared); gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media); +void gst_rtsp_media_set_record (GstRTSPMedia *media, gboolean record); +gboolean gst_rtsp_media_is_record (GstRTSPMedia *media); + void gst_rtsp_media_set_reusable (GstRTSPMedia *media, gboolean reusable); gboolean gst_rtsp_media_is_reusable (GstRTSPMedia *media); @@ -209,6 +214,9 @@ gboolean gst_rtsp_media_unsuspend (GstRTSPMedia *media); gboolean gst_rtsp_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, GstSDPInfo * info); +gboolean gst_rtsp_media_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp); + + /* creating streams */ void gst_rtsp_media_collect_streams (GstRTSPMedia *media); GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia *media, diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index e319241aa9..0fffbcab2e 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -1,5 +1,7 @@ /* GStreamer * Copyright (C) 2008 Wim Taymans + * Copyright (C) 2015 Centricular Ltd + * Author: Sebastian Dröge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -144,6 +146,7 @@ gst_rtsp_session_media_new (const gchar * path, GstRTSPMedia * media) g_return_val_if_fail (path != NULL, NULL); g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + status = gst_rtsp_media_get_status (media); g_return_val_if_fail (status == GST_RTSP_MEDIA_STATUS_PREPARED || status == GST_RTSP_MEDIA_STATUS_SUSPENDED, NULL); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index d2e043290b..6c7cacf8b0 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1,5 +1,7 @@ /* GStreamer * Copyright (C) 2008 Wim Taymans + * Copyright (C) 2015 Centricular Ltd + * Author: Sebastian Dröge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -71,7 +73,8 @@ struct _GstRTSPStreamPrivate { GMutex lock; guint idx; - GstPad *srcpad; + /* Only one pad is ever set */ + GstPad *srcpad, *sinkpad; GstElement *payloader; guint buffer_size; gboolean is_joined; @@ -82,6 +85,7 @@ struct _GstRTSPStreamPrivate /* pads on the rtpbin */ GstPad *send_rtp_sink; + GstPad *recv_rtp_src; GstPad *recv_sink[2]; GstPad *send_src[2]; @@ -153,6 +157,9 @@ struct _GstRTSPStreamPrivate /* stream blocking */ gulong blocked_id; gboolean blocking; + + /* pt->caps map for RECORD streams */ + GHashTable *ptmap; }; #define DEFAULT_CONTROL NULL @@ -253,6 +260,8 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->keys = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) gst_caps_unref); + priv->ptmap = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) gst_caps_unref); } static void @@ -283,11 +292,15 @@ gst_rtsp_stream_finalize (GObject * obj) g_object_unref (priv->rtxsend); gst_object_unref (priv->payloader); - gst_object_unref (priv->srcpad); + if (priv->srcpad) + gst_object_unref (priv->srcpad); + if (priv->sinkpad) + gst_object_unref (priv->sinkpad); g_free (priv->control); g_mutex_clear (&priv->lock); g_hash_table_unref (priv->keys); + g_hash_table_destroy (priv->ptmap); G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); } @@ -337,29 +350,32 @@ gst_rtsp_stream_set_property (GObject * object, guint propid, /** * gst_rtsp_stream_new: * @idx: an index - * @srcpad: a #GstPad + * @pad: a #GstPad * @payloader: a #GstElement * * Create a new media stream with index @idx that handles RTP data on - * @srcpad and has a payloader element @payloader. + * @pad and has a payloader element @payloader if @pad is a source pad + * or a depayloader element @payloader if @pad is a sink pad. * * Returns: (transfer full): a new #GstRTSPStream */ GstRTSPStream * -gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad) +gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * pad) { GstRTSPStreamPrivate *priv; GstRTSPStream *stream; g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL); - g_return_val_if_fail (GST_IS_PAD (srcpad), NULL); - g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), NULL); + g_return_val_if_fail (GST_IS_PAD (pad), NULL); stream = g_object_new (GST_TYPE_RTSP_STREAM, NULL); priv = stream->priv; priv->idx = idx; priv->payloader = gst_object_ref (payloader); - priv->srcpad = gst_object_ref (srcpad); + if (GST_PAD_IS_SRC (pad)) + priv->srcpad = gst_object_ref (pad); + else + priv->sinkpad = gst_object_ref (pad); return stream; } @@ -416,9 +432,31 @@ gst_rtsp_stream_get_srcpad (GstRTSPStream * stream) { g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + if (!stream->priv->srcpad) + return NULL; + return gst_object_ref (stream->priv->srcpad); } +/** + * gst_rtsp_stream_get_sinkpad: + * @stream: a #GstRTSPStream + * + * Get the sinkpad associated with @stream. + * + * Returns: (transfer full): the sinkpad. Unref after usage. + */ +GstPad * +gst_rtsp_stream_get_sinkpad (GstRTSPStream * stream) +{ + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + if (!stream->priv->sinkpad) + return NULL; + + return gst_object_ref (stream->priv->sinkpad); +} + /** * gst_rtsp_stream_get_control: * @stream: a #GstRTSPStream @@ -975,11 +1013,12 @@ different_address: } static gboolean -alloc_ports_one_family (GstRTSPAddressPool * pool, gint buffer_size, - GSocketFamily family, GstElement * udpsrc_out[2], +alloc_ports_one_family (GstRTSPStream * stream, GstRTSPAddressPool * pool, + gint buffer_size, GSocketFamily family, GstElement * udpsrc_out[2], GstElement * udpsink_out[2], GstRTSPRange * server_port_out, GstRTSPAddress ** server_addr_out) { + GstRTSPStreamPrivate *priv = stream->priv; GstStateChangeReturn ret; GstElement *udpsrc0, *udpsrc1; GstElement *udpsink0, *udpsink1; @@ -1148,6 +1187,11 @@ again: g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), multisink_socket, rtcp_socket, NULL); g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); + /* Needs to be async for RECORD streams, otherwise we will never go to + * PLAYING because the sinks will wait for data while the udpsrc can't + * provide data with timestamps in PAUSED. */ + if (priv->sinkpad) + g_object_set (G_OBJECT (udpsink0), "async", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL); g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL); @@ -1227,11 +1271,13 @@ alloc_ports (GstRTSPStream * stream) { GstRTSPStreamPrivate *priv = stream->priv; - priv->have_ipv4 = alloc_ports_one_family (priv->pool, priv->buffer_size, + priv->have_ipv4 = + alloc_ports_one_family (stream, priv->pool, priv->buffer_size, G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, priv->udpsink, &priv->server_port_v4, &priv->server_addr_v4); - priv->have_ipv6 = alloc_ports_one_family (priv->pool, priv->buffer_size, + priv->have_ipv6 = + alloc_ports_one_family (stream, priv->pool, priv->buffer_size, G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, priv->udpsink, &priv->server_port_v6, &priv->server_addr_v6); @@ -1746,7 +1792,7 @@ request_key (GstElement * srtpdec, guint ssrc, GstRTSPStream * stream) } static GstElement * -request_rtcp_decoder (GstElement * rtpbin, guint session, +request_rtp_rtcp_decoder (GstElement * rtpbin, guint session, GstRTSPStream * stream) { GstRTSPStreamPrivate *priv = stream->priv; @@ -1808,6 +1854,101 @@ request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPStream * stream) return bin; } +/** + * gst_rtsp_stream_set_pt_map: + * @stream: a #GstRTSPStream + * @pt: the pt + * @caps: a #GstCaps + * + * Configure a pt map between @pt and @caps. + */ +void +gst_rtsp_stream_set_pt_map (GstRTSPStream * stream, guint pt, GstCaps * caps) +{ + GstRTSPStreamPrivate *priv = stream->priv; + + g_mutex_lock (&priv->lock); + g_hash_table_insert (priv->ptmap, GINT_TO_POINTER (pt), gst_caps_ref (caps)); + g_mutex_unlock (&priv->lock); +} + +static GstCaps * +request_pt_map (GstElement * rtpbin, guint session, guint pt, + GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv = stream->priv; + GstCaps *caps = NULL; + + g_mutex_lock (&priv->lock); + + if (priv->idx == session) { + caps = g_hash_table_lookup (priv->ptmap, GINT_TO_POINTER (pt)); + if (caps) { + GST_DEBUG ("Stream %p, pt %u: caps %" GST_PTR_FORMAT, stream, pt, caps); + gst_caps_ref (caps); + } else { + GST_DEBUG ("Stream %p, pt %u: no caps", stream, pt); + } + } + + g_mutex_unlock (&priv->lock); + + return caps; +} + +static void +pad_added (GstElement * rtpbin, GstPad * pad, GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv = stream->priv; + gchar *name; + GstPadLinkReturn ret; + guint sessid; + + GST_DEBUG ("Stream %p added pad %s:%s for pad %s:%s", stream, + GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (priv->sinkpad)); + + name = gst_pad_get_name (pad); + if (sscanf (name, "recv_rtp_src_%u", &sessid) != 1) { + g_free (name); + return; + } + g_free (name); + + if (priv->idx != sessid) + return; + + if (gst_pad_is_linked (priv->sinkpad)) { + GST_WARNING ("Stream %p: Pad %s:%s is linked already", stream, + GST_DEBUG_PAD_NAME (priv->sinkpad)); + return; + } + + /* link the RTP pad to the session manager, it should not really fail unless + * this is not really an RTP pad */ + ret = gst_pad_link (pad, priv->sinkpad); + if (ret != GST_PAD_LINK_OK) + goto link_failed; + priv->recv_rtp_src = gst_object_ref (pad); + + return; + +/* ERRORS */ +link_failed: + { + GST_ERROR ("Stream %p: Failed to link pads %s:%s and %s:%s", stream, + GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (priv->sinkpad)); + } +} + +static void +on_npt_stop (GstElement * rtpbin, guint session, guint ssrc, + GstRTSPStream * stream) +{ + /* TODO: What to do here other than this? */ + GST_DEBUG ("Stream %p: Got EOS", stream); + gst_pad_send_event (stream->priv->sinkpad, gst_event_new_eos ()); +} + /** * gst_rtsp_stream_join_bin: * @stream: a #GstRTSPStream @@ -1861,37 +2002,52 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, (GCallback) request_rtp_encoder, stream); g_signal_connect (rtpbin, "request-rtcp-encoder", (GCallback) request_rtcp_encoder, stream); + g_signal_connect (rtpbin, "request-rtp-decoder", + (GCallback) request_rtp_rtcp_decoder, stream); g_signal_connect (rtpbin, "request-rtcp-decoder", - (GCallback) request_rtcp_decoder, stream); + (GCallback) request_rtp_rtcp_decoder, stream); } - if (priv->rtx_time > 0) { + if (priv->rtx_time > 0 && priv->srcpad) { /* enable retransmission by setting rtprtxsend as the "aux" element of rtpbin */ g_signal_connect (rtpbin, "request-aux-sender", (GCallback) request_aux_sender, stream); } + if (priv->sinkpad) { + g_signal_connect (rtpbin, "request-pt-map", + (GCallback) request_pt_map, stream); + } /* get a pad for sending RTP */ name = g_strdup_printf ("send_rtp_sink_%u", idx); priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); g_free (name); - /* link the RTP pad to the session manager, it should not really fail unless - * this is not really an RTP pad */ - ret = gst_pad_link (priv->srcpad, priv->send_rtp_sink); - if (ret != GST_PAD_LINK_OK) - goto link_failed; + + if (priv->srcpad) { + /* link the RTP pad to the session manager, it should not really fail unless + * this is not really an RTP pad */ + ret = gst_pad_link (priv->srcpad, priv->send_rtp_sink); + if (ret != GST_PAD_LINK_OK) + goto link_failed; + } else { + /* Need to connect our sinkpad from here */ + g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added, stream); + /* EOS */ + g_signal_connect (rtpbin, "on-npt-stop", (GCallback) on_npt_stop, stream); + } /* get pads from the RTP session element for sending and receiving * RTP/RTCP*/ name = g_strdup_printf ("send_rtp_src_%u", idx); priv->send_src[0] = gst_element_get_static_pad (rtpbin, name); g_free (name); - name = g_strdup_printf ("send_rtcp_src_%u", idx); - priv->send_src[1] = gst_element_get_request_pad (rtpbin, name); - g_free (name); name = g_strdup_printf ("recv_rtp_sink_%u", idx); priv->recv_sink[0] = gst_element_get_request_pad (rtpbin, name); g_free (name); + + name = g_strdup_printf ("send_rtcp_src_%u", idx); + priv->send_src[1] = gst_element_get_request_pad (rtpbin, name); + g_free (name); name = g_strdup_printf ("recv_rtcp_sink_%u", idx); priv->recv_sink[1] = gst_element_get_request_pad (rtpbin, name); g_free (name); @@ -2002,10 +2158,12 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, gst_object_unref (pad); if (priv->udpsrc_v4[i]) { - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values */ - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); + if (priv->srcpad) { + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values. This is only relevant for PLAY pipelines */ + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); + } /* add udpsrc */ gst_bin_add (bin, priv->udpsrc_v4[i]); @@ -2018,8 +2176,10 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, } if (priv->udpsrc_v6[i]) { - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); + if (priv->srcpad) { + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); + } gst_bin_add (bin, priv->udpsrc_v6[i]); /* and link to the funnel v6 */ @@ -2128,7 +2288,13 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, GST_INFO ("stream %p leaving bin", stream); - gst_pad_unlink (priv->srcpad, priv->send_rtp_sink); + if (priv->srcpad) { + gst_pad_unlink (priv->srcpad, priv->send_rtp_sink); + } else if (priv->recv_rtp_src) { + gst_pad_unlink (priv->recv_rtp_src, priv->sinkpad); + gst_object_unref (priv->recv_rtp_src); + priv->recv_rtp_src = NULL; + } g_signal_handler_disconnect (priv->send_src[0], priv->caps_sig); gst_element_release_request_pad (rtpbin, priv->send_rtp_sink); gst_object_unref (priv->send_rtp_sink); @@ -2464,10 +2630,12 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); g_free (host); - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values */ - gst_element_set_state (source->udpsrc[i], GST_STATE_PLAYING); - gst_element_set_locked_state (source->udpsrc[i], TRUE); + if (priv->srcpad) { + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values. This is only relevant for PLAY pipelines */ + gst_element_set_state (source->udpsrc[i], GST_STATE_PLAYING); + gst_element_set_locked_state (source->udpsrc[i], TRUE); + } /* add udpsrc */ gst_bin_add (bin, source->udpsrc[i]); diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 4fb41959d4..b71c776fdf 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -67,10 +67,11 @@ struct _GstRTSPStreamClass { GType gst_rtsp_stream_get_type (void); GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement *payloader, - GstPad *srcpad); + GstPad *pad); guint gst_rtsp_stream_get_index (GstRTSPStream *stream); guint gst_rtsp_stream_get_pt (GstRTSPStream *stream); GstPad * gst_rtsp_stream_get_srcpad (GstRTSPStream *stream); +GstPad * gst_rtsp_stream_get_sinkpad (GstRTSPStream *stream); void gst_rtsp_stream_set_control (GstRTSPStream *stream, const gchar *control); gchar * gst_rtsp_stream_get_control (GstRTSPStream *stream); @@ -160,6 +161,8 @@ guint gst_rtsp_stream_get_retransmission_pt (GstRTSPStream * s void gst_rtsp_stream_set_retransmission_pt (GstRTSPStream * stream, guint rtx_pt); +void gst_rtsp_stream_set_pt_map (GstRTSPStream * stream, guint pt, GstCaps * caps); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object From 844add610d1fe9056beddf0f9497ad875751f725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 16 Jan 2015 20:48:42 +0100 Subject: [PATCH 1081/1776] rtsp-stream: Put the timestamp of receival of the initial packet over TCP on the first buffer --- gst/rtsp-server/rtsp-stream.c | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 6c7cacf8b0..83cee2b53e 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -109,6 +109,7 @@ struct _GstRTSPStreamPrivate /* for TCP transport */ GstElement *appsrc[2]; + GstClockTime appsrc_base_time[2]; GstElement *appqueue[2]; GstElement *appsink[2]; @@ -2193,6 +2194,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) { /* make and add appsrc */ priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); + priv->appsrc_base_time[i] = -1; g_object_set (priv->appsrc[i], "format", GST_FORMAT_TIME, NULL); gst_bin_add (bin, priv->appsrc[i]); /* and link to the funnel */ @@ -2544,6 +2546,31 @@ gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * buffer) g_mutex_unlock (&priv->lock); if (element) { + if (priv->appsrc_base_time[0] == -1) { + /* Take current running_time. This timestamp will be put on + * the first buffer of each stream because we are a live source and so we + * timestamp with the running_time. When we are dealing with TCP, we also + * only timestamp the first buffer (using the DISCONT flag) because a server + * typically bursts data, for which we don't want to compensate by speeding + * up the media. The other timestamps will be interpollated from this one + * using the RTP timestamps. */ + GST_OBJECT_LOCK (element); + if (GST_ELEMENT_CLOCK (element)) { + GstClockTime now; + GstClockTime base_time; + + now = gst_clock_get_time (GST_ELEMENT_CLOCK (element)); + base_time = GST_ELEMENT_CAST (element)->base_time; + + priv->appsrc_base_time[0] = now - base_time; + GST_BUFFER_TIMESTAMP (buffer) = priv->appsrc_base_time[0]; + GST_DEBUG ("stream %p: first buffer at time %" GST_TIME_FORMAT + ", base %" GST_TIME_FORMAT, stream, GST_TIME_ARGS (now), + GST_TIME_ARGS (base_time)); + } + GST_OBJECT_UNLOCK (element); + } + ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (element), buffer); gst_object_unref (element); } else { @@ -2587,6 +2614,31 @@ gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer) g_mutex_unlock (&priv->lock); if (element) { + if (priv->appsrc_base_time[1] == -1) { + /* Take current running_time. This timestamp will be put on + * the first buffer of each stream because we are a live source and so we + * timestamp with the running_time. When we are dealing with TCP, we also + * only timestamp the first buffer (using the DISCONT flag) because a server + * typically bursts data, for which we don't want to compensate by speeding + * up the media. The other timestamps will be interpollated from this one + * using the RTP timestamps. */ + GST_OBJECT_LOCK (element); + if (GST_ELEMENT_CLOCK (element)) { + GstClockTime now; + GstClockTime base_time; + + now = gst_clock_get_time (GST_ELEMENT_CLOCK (element)); + base_time = GST_ELEMENT_CAST (element)->base_time; + + priv->appsrc_base_time[1] = now - base_time; + GST_BUFFER_TIMESTAMP (buffer) = priv->appsrc_base_time[1]; + GST_DEBUG ("stream %p: first buffer at time %" GST_TIME_FORMAT + ", base %" GST_TIME_FORMAT, stream, GST_TIME_ARGS (now), + GST_TIME_ARGS (base_time)); + } + GST_OBJECT_UNLOCK (element); + } + ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (element), buffer); gst_object_unref (element); } else { From 18d3244fd0a547d40b0791e37da8cfcbb41b9e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 17 Jan 2015 10:28:13 +0100 Subject: [PATCH 1082/1776] test-record: Use GOptionContext to parse the server port and take the pipeline from the commandline --- examples/test-record.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/examples/test-record.c b/examples/test-record.c index 676ae982e5..85d6f83243 100644 --- a/examples/test-record.c +++ b/examples/test-record.c @@ -23,6 +23,16 @@ #include +#define DEFAULT_RTSP_PORT "8554" + +static char *port = (char *) DEFAULT_RTSP_PORT; + +static GOptionEntry entries[] = { + {"port", 'p', 0, G_OPTION_ARG_STRING, &port, + "Port to listen on (default: " DEFAULT_RTSP_PORT ")", "PORT"}, + {NULL} +}; + int main (int argc, char *argv[]) { @@ -30,8 +40,18 @@ main (int argc, char *argv[]) GstRTSPServer *server; GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; + GOptionContext *optctx; + GError *error = NULL; - gst_init (&argc, &argv); + optctx = g_option_context_new (" - Test RTSP Server, Launch\n\n" + "Example: \"( decodebin name=depay0 ! autovideosink )\""); + g_option_context_add_main_entries (optctx, entries, NULL); + g_option_context_add_group (optctx, gst_init_get_option_group ()); + if (!g_option_context_parse (optctx, &argc, &argv, &error)) { + g_printerr ("Error parsing options: %s\n", error->message); + return -1; + } + g_option_context_free (optctx); loop = g_main_loop_new (NULL, FALSE); @@ -48,8 +68,7 @@ main (int argc, char *argv[]) * element with depay%d names will be a stream */ factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_record (factory, TRUE); - gst_rtsp_media_factory_set_launch (factory, - "( decodebin name=depay0 ! autovideosink decodebin name=depay1 ! autoaudiosink )"); + gst_rtsp_media_factory_set_launch (factory, argv[1]); /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test", factory); @@ -61,7 +80,7 @@ main (int argc, char *argv[]) gst_rtsp_server_attach (server, NULL); /* start serving */ - g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port); g_main_loop_run (loop); return 0; From 35b2b10cf44e30f93b9c1c6ab2cf1041d81b61d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 19 Jan 2015 13:20:39 +0100 Subject: [PATCH 1083/1776] rtsp-media: Expose latency setting for setting the rtpbin latency --- gst/rtsp-server/rtsp-media-factory.c | 67 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 4 ++ gst/rtsp-server/rtsp-media.c | 66 +++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 3 ++ 4 files changed, 140 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 34a0ac84e6..304c4a1ddb 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -62,6 +62,7 @@ struct _GstRTSPMediaFactoryPrivate GstRTSPAddressPool *pool; GstClockTime rtx_time; + guint latency; GMutex medias_lock; GHashTable *medias; /* protected by medias_lock */ @@ -75,6 +76,7 @@ struct _GstRTSPMediaFactoryPrivate #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_BUFFER_SIZE 0x80000 +#define DEFAULT_LATENCY 200 #define DEFAULT_RECORD FALSE enum @@ -87,6 +89,7 @@ enum PROP_PROFILES, PROP_PROTOCOLS, PROP_BUFFER_SIZE, + PROP_LATENCY, PROP_RECORD, PROP_LAST }; @@ -186,6 +189,11 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "The kernel UDP buffer size to use", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_LATENCY, + g_param_spec_uint ("latency", "Latency", + "Latency used for receiving media in milliseconds", 0, G_MAXUINT, + DEFAULT_LATENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /* FIXME: Should this be a flag property to allow RECORD and PLAY? * Or just another boolean PLAY property that default to TRUE? */ @@ -230,6 +238,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->profiles = DEFAULT_PROFILES; priv->protocols = DEFAULT_PROTOCOLS; priv->buffer_size = DEFAULT_BUFFER_SIZE; + priv->latency = DEFAULT_LATENCY; g_mutex_init (&priv->lock); g_mutex_init (&priv->medias_lock); @@ -286,6 +295,9 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_uint (value, gst_rtsp_media_factory_get_buffer_size (factory)); break; + case PROP_LATENCY: + g_value_set_uint (value, gst_rtsp_media_factory_get_latency (factory)); + break; case PROP_RECORD: g_value_set_boolean (value, gst_rtsp_media_factory_is_record (factory)); break; @@ -325,6 +337,9 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_buffer_size (factory, g_value_get_uint (value)); break; + case PROP_LATENCY: + gst_rtsp_media_factory_set_latency (factory, g_value_get_uint (value)); + break; case PROP_RECORD: gst_rtsp_media_factory_set_record (factory, g_value_get_boolean (value)); break; @@ -892,6 +907,55 @@ gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory) return res; } +/** + * gst_rtsp_media_factory_set_latency: + * @factory: a #GstRTSPMediaFactory + * @latency: latency in milliseconds + * + * Configure the latency used for receiving media + */ +void +gst_rtsp_media_factory_set_latency (GstRTSPMediaFactory * factory, + guint latency) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + priv = factory->priv; + + GST_DEBUG_OBJECT (factory, "latency %ums", latency); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv->latency = latency; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_latency: + * @factory: a #GstRTSPMediaFactory + * + * Get the latency that is used for receiving media + * + * Returns: latency in milliseconds + */ +guint +gst_rtsp_media_factory_get_latency (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + guint res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + res = priv->latency; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return res; +} + static gboolean compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) { @@ -1155,6 +1219,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstRTSPAddressPool *pool; GstRTSPPermissions *perms; GstClockTime rtx_time; + guint latency; gboolean record; /* configure the sharedness */ @@ -1166,6 +1231,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) profiles = priv->profiles; protocols = priv->protocols; rtx_time = priv->rtx_time; + latency = priv->latency; record = priv->record; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); @@ -1176,6 +1242,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_profiles (media, profiles); gst_rtsp_media_set_protocols (media, protocols); gst_rtsp_media_set_retransmission_time (media, rtx_time); + gst_rtsp_media_set_latency (media, latency); gst_rtsp_media_set_record (media, record); if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) { diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 288d111567..b8b54045b3 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -145,6 +145,10 @@ void gst_rtsp_media_factory_set_retransmission_time (GstRTSPMed GstClockTime time); GstClockTime gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory); +void gst_rtsp_media_factory_set_latency (GstRTSPMediaFactory * factory, + guint latency); +guint gst_rtsp_media_factory_get_latency (GstRTSPMediaFactory * factory); + void gst_rtsp_media_factory_set_record (GstRTSPMediaFactory *factory, gboolean record); gboolean gst_rtsp_media_factory_is_record (GstRTSPMediaFactory *factory); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 9b64569df7..ad2609a17b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -137,6 +137,7 @@ struct _GstRTSPMediaPrivate GList *payloads; /* protected by lock */ GstClockTime rtx_time; /* protected by lock */ + guint latency; /* protected by lock */ }; #define DEFAULT_SHARED FALSE @@ -148,6 +149,7 @@ struct _GstRTSPMediaPrivate #define DEFAULT_EOS_SHUTDOWN FALSE #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_TIME_PROVIDER FALSE +#define DEFAULT_LATENCY 200 #define DEFAULT_RECORD FALSE /* define to dump received RTCP packets */ @@ -165,6 +167,7 @@ enum PROP_BUFFER_SIZE, PROP_ELEMENT, PROP_TIME_PROVIDER, + PROP_LATENCY, PROP_RECORD, PROP_LAST }; @@ -293,6 +296,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "Use a NetTimeProvider for clients", DEFAULT_TIME_PROVIDER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_LATENCY, + g_param_spec_uint ("latency", "Latency", + "Latency used for receiving media in milliseconds", 0, G_MAXUINT, + DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_RECORD, g_param_spec_boolean ("record", "Record", "If this media pipeline can be used for PLAY or RECORD", @@ -435,6 +443,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_TIME_PROVIDER: g_value_set_boolean (value, gst_rtsp_media_is_time_provider (media)); break; + case PROP_LATENCY: + g_value_set_uint (value, gst_rtsp_media_get_latency (media)); + break; case PROP_RECORD: g_value_set_boolean (value, gst_rtsp_media_is_record (media)); break; @@ -478,6 +489,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_TIME_PROVIDER: gst_rtsp_media_use_time_provider (media, g_value_get_boolean (value)); break; + case PROP_LATENCY: + gst_rtsp_media_set_latency (media, g_value_get_uint (value)); + break; case PROP_RECORD: gst_rtsp_media_set_record (media, g_value_get_boolean (value)); break; @@ -1181,6 +1195,56 @@ gst_rtsp_media_get_retransmission_time (GstRTSPMedia * media) return res; } +/** + * gst_rtsp_media_set_latncy: + * @media: a #GstRTSPMedia + * @latency: latency in milliseconds + * + * Configure the latency used for receiving media. + */ +void +gst_rtsp_media_set_latency (GstRTSPMedia * media, guint latency) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + GST_LOG_OBJECT (media, "set latency %ums", latency); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->latency = latency; + if (priv->rtpbin) + g_object_set (priv->rtpbin, "latency", latency, NULL); + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_get_latency: + * @media: a #GstRTSPMedia + * + * Get the latency that is used for receiving media. + * + * Returns: latency in milliseconds + */ +guint +gst_rtsp_media_get_latency (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + guint res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + priv = media->priv; + + g_mutex_unlock (&priv->lock); + res = priv->latency; + g_mutex_unlock (&priv->lock); + + return res; +} + /** * gst_rtsp_media_use_time_provider: * @media: a #GstRTSPMedia @@ -2408,6 +2472,8 @@ default_prepare (GstRTSPMedia * media, GstRTSPThread * thread) if (priv->rtpbin != NULL) { gboolean success = TRUE; + g_object_set (priv->rtpbin, "latency", priv->latency, NULL); + if (klass->setup_rtpbin) success = klass->setup_rtpbin (media, priv->rtpbin); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 6b4922b9d0..4aa2415d4f 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -196,6 +196,9 @@ guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media); void gst_rtsp_media_set_retransmission_time (GstRTSPMedia *media, GstClockTime time); GstClockTime gst_rtsp_media_get_retransmission_time (GstRTSPMedia *media); +void gst_rtsp_media_set_latency (GstRTSPMedia *media, guint latency); +guint gst_rtsp_media_get_latency (GstRTSPMedia *media); + void gst_rtsp_media_use_time_provider (GstRTSPMedia *media, gboolean time_provider); gboolean gst_rtsp_media_is_time_provider (GstRTSPMedia *media); GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media, From e9ce91634cd88b08412c98fdcb24465b88241a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 21 Jan 2015 16:32:44 +0000 Subject: [PATCH 1084/1776] rtsp-client: fix a couple of leaks in handle_announce --- gst/rtsp-server/rtsp-client.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d69ef0a34f..fa1c3a0533 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2288,9 +2288,6 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!priv->mount_points) goto no_mount_points; - if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri))) - goto no_path; - /* check if reply is SDP */ gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_CONTENT_TYPE, &cont, 0); @@ -2338,6 +2335,8 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST], 0, ctx); + gst_sdp_message_free (sdp); + g_free (path); return TRUE; no_uri: @@ -2356,27 +2355,26 @@ no_path: { GST_ERROR ("client %p: can't find path for url", client); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + gst_sdp_message_free (sdp); return FALSE; } wrong_content_type: { GST_ERROR ("client %p: unknown content type", client); send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); - g_free (path); return FALSE; } no_message: { GST_ERROR ("client %p: can't find SDP message", client); send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); - g_free (path); return FALSE; } sdp_parse_failed: { GST_ERROR ("client %p: failed to parse SDP message", client); send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); - g_free (path); + gst_sdp_message_free (sdp); return FALSE; } no_media: @@ -2384,6 +2382,7 @@ no_media: GST_ERROR ("client %p: no media", client); g_free (path); /* error reply is already sent */ + gst_sdp_message_free (sdp); return FALSE; } play_media: @@ -2392,6 +2391,7 @@ play_media: send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); g_free (path); g_object_unref (media); + gst_sdp_message_free (sdp); return FALSE; } unhandled_sdp: @@ -2400,6 +2400,7 @@ unhandled_sdp: send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, ctx); g_free (path); g_object_unref (media); + gst_sdp_message_free (sdp); return FALSE; } } From 6e5b156b0d5dcf1c9c407fdb06914ad92f01e846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 21 Jan 2015 17:27:56 +0000 Subject: [PATCH 1085/1776] tests: add some unit tests for ANNOUNCE and RECORD https://bugzilla.gnome.org/show_bug.cgi?id=743175 --- tests/check/gst/rtspserver.c | 355 ++++++++++++++++++++++++++++++++++- 1 file changed, 345 insertions(+), 10 deletions(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index b6ce2235c6..d268b66420 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1,9 +1,8 @@ -/* GStreamer - * - * unit test for GstRTSPServer - * +/* GStreamer unit test for GstRTSPServer * Copyright (C) 2012 Axis Communications - * @author David Svensson Fors + * @author David Svensson Fors + * Copyright (C) 2015 Centricular Ltd + * @author Tim-Philipp Müller * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -182,6 +181,40 @@ start_server (void) GST_DEBUG ("rtsp server listening on port %d", test_port); } +/* start the testing rtsp server for RECORD mode */ +static GstRTSPMediaFactory * +start_record_server (const gchar * launch_line) +{ + GstRTSPMediaFactory *factory; + GstRTSPMountPoints *mounts; + gchar *service; + + mounts = gst_rtsp_server_get_mount_points (server); + + factory = gst_rtsp_media_factory_new (); + + gst_rtsp_media_factory_set_record (factory, TRUE); + gst_rtsp_media_factory_set_launch (factory, launch_line); + gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); + g_object_unref (mounts); + + /* set port to any */ + gst_rtsp_server_set_service (server, "0"); + + /* attach to default main context */ + source_id = gst_rtsp_server_attach (server, NULL); + fail_if (source_id == 0); + + /* get port */ + service = gst_rtsp_server_get_service (server); + test_port = atoi (service); + fail_unless (test_port != 0); + g_free (service); + + GST_DEBUG ("rtsp server listening on port %d", test_port); + return factory; +} + /* stop the tested rtsp server */ static void stop_server (void) @@ -453,12 +486,11 @@ do_setup_full (GstRTSPConnection * conn, const gchar * control, } if (use_tcp_transport) { - transport_string_in = - g_strdup_printf (TEST_PROTO_TCP ";unicast"); + transport_string_in = g_strdup_printf (TEST_PROTO_TCP ";unicast"); } else { transport_string_in = - g_strdup_printf (TEST_PROTO ";unicast;client_port=%d-%d", - client_ports->min, client_ports->max); + g_strdup_printf (TEST_PROTO ";unicast;client_port=%d-%d", + client_ports->min, client_ports->max); } code = do_request_full (conn, GST_RTSP_SETUP, control, session_in, @@ -596,6 +628,27 @@ GST_START_TEST (test_describe) GST_END_TEST; +GST_START_TEST (test_describe_record_media) +{ + GstRTSPConnection *conn; + + start_record_server ("( fakesink name=depay0 )"); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + /* send DESCRIBE request */ + fail_unless_equals_int (do_request (conn, GST_RTSP_DESCRIBE, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL), + GST_RTSP_STS_METHOD_NOT_ALLOWED); + + /* clean up and iterate so the clean-up can finish */ + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); +} + +GST_END_TEST; + GST_START_TEST (test_describe_non_existing_mount_point) { GstRTSPConnection *conn; @@ -797,7 +850,7 @@ GST_START_TEST (test_setup_twice) /* session can not be the same */ fail_unless (strcmp (session1, session2)); - /* send TEARDOWN request for the first session*/ + /* send TEARDOWN request for the first session */ fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, session1) == GST_RTSP_STS_OK); @@ -1576,6 +1629,285 @@ GST_START_TEST (test_play_smpte_range) GST_END_TEST; +GST_START_TEST (test_announce_without_sdp) +{ + GstRTSPConnection *conn; + GstRTSPStatusCode status; + GstRTSPMessage *request; + GstRTSPMessage *response; + + start_record_server ("( fakesink name=depay0 )"); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + /* create and send ANNOUNCE request */ + request = create_request (conn, GST_RTSP_ANNOUNCE, NULL); + + fail_unless (send_request (conn, request)); + + iterate (); + + response = read_response (conn); + + /* check response */ + gst_rtsp_message_parse_response (response, &status, NULL, NULL); + fail_unless_equals_int (status, GST_RTSP_STS_BAD_REQUEST); + gst_rtsp_message_free (response); + + /* try again, this type with content-type, but still no SDP */ + gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE, + "application/sdp"); + + fail_unless (send_request (conn, request)); + + iterate (); + + response = read_response (conn); + + /* check response */ + gst_rtsp_message_parse_response (response, &status, NULL, NULL); + fail_unless_equals_int (status, GST_RTSP_STS_BAD_REQUEST); + gst_rtsp_message_free (response); + + /* try again, this type with an unknown content-type */ + gst_rtsp_message_remove_header (request, GST_RTSP_HDR_CONTENT_TYPE, -1); + gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE, + "application/x-something"); + + fail_unless (send_request (conn, request)); + + iterate (); + + response = read_response (conn); + + /* check response */ + gst_rtsp_message_parse_response (response, &status, NULL, NULL); + fail_unless_equals_int (status, GST_RTSP_STS_BAD_REQUEST); + gst_rtsp_message_free (response); + + /* clean up and iterate so the clean-up can finish */ + gst_rtsp_message_free (request); + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); +} + +GST_END_TEST; + +static GstRTSPStatusCode +do_announce (GstRTSPConnection * conn, GstSDPMessage * sdp) +{ + GstRTSPMessage *request; + GstRTSPMessage *response; + GstRTSPStatusCode code; + gchar *str; + + /* create request */ + request = create_request (conn, GST_RTSP_ANNOUNCE, NULL); + + gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE, + "application/sdp"); + + /* add SDP to the response body */ + str = gst_sdp_message_as_text (sdp); + gst_rtsp_message_take_body (request, (guint8 *) str, strlen (str)); + gst_sdp_message_free (sdp); + + /* send request */ + fail_unless (send_request (conn, request)); + gst_rtsp_message_free (request); + + iterate (); + + /* read response */ + response = read_response (conn); + + /* check status line */ + gst_rtsp_message_parse_response (response, &code, NULL, NULL); + + gst_rtsp_message_free (response); + return code; +} + +static void +media_constructed_cb (GstRTSPMediaFactory * mfactory, GstRTSPMedia * media, + gpointer user_data) +{ + GstElement **p_sink = user_data; + GstElement *bin; + + bin = gst_rtsp_media_get_element (media); + *p_sink = gst_bin_get_by_name (GST_BIN (bin), "sink"); + GST_INFO ("media constructed!: %" GST_PTR_FORMAT, *p_sink); +} + +#define RECORD_N_BUFS 10 + +GST_START_TEST (test_record_tcp) +{ + GstRTSPMediaFactory *mfactory; + GstRTSPConnection *conn; + GstRTSPStatusCode status; + GstRTSPMessage *response; + GstRTSPMessage *request; + GstSDPMessage *sdp; + GstRTSPResult rres; + GSocketAddress *sa; + GInetAddress *ia; + GstElement *sink = NULL; + GSocket *conn_socket; + const gchar *proto; + gchar *client_ip, *sess_id, *session = NULL; + gint i; + + mfactory = + start_record_server ("( rtppcmadepay name=depay0 ! appsink name=sink )"); + + g_signal_connect (mfactory, "media-constructed", + G_CALLBACK (media_constructed_cb), &sink); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + conn_socket = gst_rtsp_connection_get_read_socket (conn); + + sa = g_socket_get_local_address (conn_socket, NULL); + ia = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sa)); + client_ip = g_inet_address_to_string (ia); + if (g_socket_address_get_family (sa) == G_SOCKET_FAMILY_IPV6) + proto = "IP6"; + else if (g_socket_address_get_family (sa) == G_SOCKET_FAMILY_IPV4) + proto = "IP4"; + else + g_assert_not_reached (); + g_object_unref (sa); + + gst_sdp_message_new (&sdp); + + /* some standard things first */ + gst_sdp_message_set_version (sdp, "0"); + + /* session ID doesn't have to be super-unique in this case */ + sess_id = g_strdup_printf ("%u", g_random_int ()); + gst_sdp_message_set_origin (sdp, "-", sess_id, "1", "IN", proto, client_ip); + g_free (sess_id); + g_free (client_ip); + + gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer"); + gst_sdp_message_set_information (sdp, "rtsp-server-test"); + gst_sdp_message_add_time (sdp, "0", "0", NULL); + gst_sdp_message_add_attribute (sdp, "tool", "GStreamer"); + + /* add stream 0 */ + { + GstSDPMedia *smedia; + + gst_sdp_media_new (&smedia); + gst_sdp_media_set_media (smedia, "audio"); + gst_sdp_media_add_format (smedia, "8"); /* pcma/alaw */ + gst_sdp_media_set_port_info (smedia, 0, 1); + gst_sdp_media_set_proto (smedia, "RTP/AVP"); + gst_sdp_media_add_attribute (smedia, "rtpmap", "8 PCMA/8000"); + gst_sdp_message_add_media (sdp, smedia); + gst_sdp_media_free (smedia); + } + + /* send ANNOUNCE request */ + status = do_announce (conn, sdp); + fail_unless_equals_int (status, GST_RTSP_STS_OK); + + /* create and send SETUP request */ + request = create_request (conn, GST_RTSP_SETUP, NULL); + gst_rtsp_message_add_header (request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP/TCP;interleaved=0;mode=record"); + fail_unless (send_request (conn, request)); + gst_rtsp_message_free (request); + iterate (); + response = read_response (conn); + gst_rtsp_message_parse_response (response, &status, NULL, NULL); + fail_unless_equals_int (status, GST_RTSP_STS_OK); + + rres = + gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &session, 0); + session = g_strdup (session); + fail_unless_equals_int (rres, GST_RTSP_OK); + gst_rtsp_message_free (response); + + /* send RECORD */ + request = create_request (conn, GST_RTSP_RECORD, NULL); + gst_rtsp_message_add_header (request, GST_RTSP_HDR_SESSION, session); + fail_unless (send_request (conn, request)); + gst_rtsp_message_free (request); + iterate (); + response = read_response (conn); + gst_rtsp_message_parse_response (response, &status, NULL, NULL); + fail_unless_equals_int (status, GST_RTSP_STS_OK); + gst_rtsp_message_free (response); + + /* send some data */ + { + GstElement *pipeline, *src, *enc, *pay, *sink; + + pipeline = gst_pipeline_new ("send-pipeline"); + src = gst_element_factory_make ("audiotestsrc", NULL); + g_object_set (src, "num-buffers", RECORD_N_BUFS, + "samplesperbuffer", 1000, NULL); + enc = gst_element_factory_make ("alawenc", NULL); + pay = gst_element_factory_make ("rtppcmapay", NULL); + sink = gst_element_factory_make ("appsink", NULL); + fail_unless (pipeline && src && enc && pay && sink); + gst_bin_add_many (GST_BIN (pipeline), src, enc, pay, sink, NULL); + gst_element_link_many (src, enc, pay, sink, NULL); + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + do { + GstRTSPMessage *data_msg; + GstMapInfo map = GST_MAP_INFO_INIT; + GstRTSPResult rres; + GstSample *sample = NULL; + GstBuffer *buf; + + g_signal_emit_by_name (G_OBJECT (sink), "pull-sample", &sample); + if (sample == NULL) + break; + buf = gst_sample_get_buffer (sample); + rres = gst_rtsp_message_new_data (&data_msg, 0); + fail_unless_equals_int (rres, GST_RTSP_OK); + gst_buffer_map (buf, &map, GST_MAP_READ); + GST_INFO ("sending %u bytes of data on channel 0", (guint) map.size); + GST_MEMDUMP ("data on channel 0", map.data, map.size); + rres = gst_rtsp_message_set_body (data_msg, map.data, map.size); + fail_unless_equals_int (rres, GST_RTSP_OK); + gst_buffer_unmap (buf, &map); + rres = gst_rtsp_connection_send (conn, data_msg, NULL); + fail_unless_equals_int (rres, GST_RTSP_OK); + gst_rtsp_message_free (data_msg); + gst_sample_unref (sample); + } while (TRUE); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + } + + /* check received data (we assume every buffer created by audiotestsrc and + * subsequently encoded by mulawenc results in exactly one RTP packet) */ + for (i = 0; i < RECORD_N_BUFS; ++i) { + GstSample *sample = NULL; + + g_signal_emit_by_name (G_OBJECT (sink), "pull-sample", &sample); + GST_INFO ("%2d recv sample: %p", i, sample); + gst_sample_unref (sample); + } + + fail_unless_equals_int (GST_STATE (sink), GST_STATE_PLAYING); + + /* clean up and iterate so the clean-up can finish */ + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); + g_free (session); +} + +GST_END_TEST; static Suite * rtspserver_suite (void) @@ -1589,6 +1921,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_connect); tcase_add_test (tc, test_describe); tcase_add_test (tc, test_describe_non_existing_mount_point); + tcase_add_test (tc, test_describe_record_media); tcase_add_test (tc, test_setup); tcase_add_test (tc, test_setup_tcp); tcase_add_test (tc, test_setup_twice); @@ -1604,6 +1937,8 @@ rtspserver_suite (void) tcase_add_test (tc, test_play_disconnect); tcase_add_test (tc, test_play_specific_server_port); tcase_add_test (tc, test_play_smpte_range); + tcase_add_test (tc, test_announce_without_sdp); + tcase_add_test (tc, test_record_tcp); return s; } From aa1feab8740ac305cbcfe8655590b5d8fad63572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 28 Jan 2015 17:49:16 +0100 Subject: [PATCH 1086/1776] test-record: Set latency for playback-style example to 2s instead of 200ms --- examples/test-record.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/test-record.c b/examples/test-record.c index 85d6f83243..86dcf6ea77 100644 --- a/examples/test-record.c +++ b/examples/test-record.c @@ -69,6 +69,7 @@ main (int argc, char *argv[]) factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_record (factory, TRUE); gst_rtsp_media_factory_set_launch (factory, argv[1]); + gst_rtsp_media_factory_set_latency (factory, 2000); /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test", factory); From a93ed7e5d41c6ef19dc2ac764c293efe5fe4d8f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 28 Jan 2015 18:54:01 +0100 Subject: [PATCH 1087/1776] rtsp-media: Use flags to distinguish between PLAY and RECORD media --- examples/test-record.c | 3 +- gst/rtsp-server/rtsp-client.c | 59 +++++++++++-------- gst/rtsp-server/rtsp-media-factory.c | 57 +++++++++--------- gst/rtsp-server/rtsp-media-factory.h | 6 +- gst/rtsp-server/rtsp-media.c | 86 +++++++++++++++++++--------- gst/rtsp-server/rtsp-media.h | 19 +++++- tests/check/gst/rtspserver.c | 3 +- 7 files changed, 147 insertions(+), 86 deletions(-) diff --git a/examples/test-record.c b/examples/test-record.c index 86dcf6ea77..1c6ac3f083 100644 --- a/examples/test-record.c +++ b/examples/test-record.c @@ -67,7 +67,8 @@ main (int argc, char *argv[]) * any launch line works as long as it contains elements named depay%d. Each * element with depay%d names will be a stream */ factory = gst_rtsp_media_factory_new (); - gst_rtsp_media_factory_set_record (factory, TRUE); + gst_rtsp_media_factory_set_transport_mode (factory, + GST_RTSP_TRANSPORT_MODE_RECORD); gst_rtsp_media_factory_set_launch (factory, argv[1]); gst_rtsp_media_factory_set_latency (factory, 2000); diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index fa1c3a0533..dc7ebcc6ba 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -635,7 +635,8 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path, ctx->media = media; - if (!gst_rtsp_media_is_record (media)) { + if (!(gst_rtsp_media_get_transport_mode (media) & + GST_RTSP_TRANSPORT_MODE_RECORD)) { GstRTSPThread *thread; thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool, @@ -1145,8 +1146,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); - if (gst_rtsp_media_is_record (media)) - goto record_media; + if (!(gst_rtsp_media_get_transport_mode (media) & + GST_RTSP_TRANSPORT_MODE_PLAY)) + goto unsupported_mode; /* the session state must be playing or ready */ rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); @@ -1237,9 +1239,9 @@ unsuspend_failed: send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); return FALSE; } -record_media: +unsupported_mode: { - GST_ERROR ("client %p: RECORD media does not support PLAY", client); + GST_ERROR ("client %p: media does not support PLAY", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); return FALSE; } @@ -1475,7 +1477,8 @@ make_server_transport (GstRTSPClient * client, GstRTSPMedia * media, break; } - if (!gst_rtsp_media_is_record (media)) + if ((gst_rtsp_media_get_transport_mode (media) & + GST_RTSP_TRANSPORT_MODE_PLAY)) gst_rtsp_stream_get_ssrc (ctx->stream, &st->ssrc); return st; @@ -1857,9 +1860,11 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!parse_transport (transport, stream, ct)) goto unsupported_transports; - /* TODO: Add support for PLAY,RECORD media */ - if ((ct->mode_play && gst_rtsp_media_is_record (media)) || - (ct->mode_record && !gst_rtsp_media_is_record (media))) + if ((ct->mode_play + && !(gst_rtsp_media_get_transport_mode (media) & + GST_RTSP_TRANSPORT_MODE_PLAY)) || (ct->mode_record + && !(gst_rtsp_media_get_transport_mode (media) & + GST_RTSP_TRANSPORT_MODE_RECORD))) goto unsupported_mode; /* parse the keymgmt */ @@ -2029,9 +2034,12 @@ unsupported_client_transport: } unsupported_mode: { - GST_ERROR ("client %p: unsupported mode (media record: %d, mode play: %d" - ", mode record: %d)", client, gst_rtsp_media_is_record (media), - ct->mode_play, ct->mode_record); + GST_ERROR ("client %p: unsupported mode (media play: %d, media record: %d, " + "mode play: %d, mode record: %d)", client, + ! !(gst_rtsp_media_get_transport_mode (media) & + GST_RTSP_TRANSPORT_MODE_PLAY), + ! !(gst_rtsp_media_get_transport_mode (media) & + GST_RTSP_TRANSPORT_MODE_RECORD), ct->mode_play, ct->mode_record); send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); goto cleanup_transport; } @@ -2148,8 +2156,9 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!(media = find_media (client, ctx, path, NULL))) goto no_media; - if (gst_rtsp_media_is_record (media)) - goto record_media; + if (!(gst_rtsp_media_get_transport_mode (media) & + GST_RTSP_TRANSPORT_MODE_PLAY)) + goto unsupported_mode; /* create an SDP for the media object on this client */ if (!(sdp = klass->create_sdp (client, media))) @@ -2210,9 +2219,9 @@ no_media: /* error reply is already sent */ return FALSE; } -record_media: +unsupported_mode: { - GST_ERROR ("client %p: RECORD media does not support DESCRIBE", client); + GST_ERROR ("client %p: media does not support DESCRIBE", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); g_free (path); g_object_unref (media); @@ -2316,8 +2325,9 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!(media = find_media (client, ctx, path, NULL))) goto no_media; - if (!gst_rtsp_media_is_record (media)) - goto play_media; + if (!(gst_rtsp_media_get_transport_mode (media) & + GST_RTSP_TRANSPORT_MODE_RECORD)) + goto unsupported_mode; /* Tell client subclass about the media */ if (!klass->handle_sdp (client, ctx, media, sdp)) @@ -2385,9 +2395,9 @@ no_media: gst_sdp_message_free (sdp); return FALSE; } -play_media: +unsupported_mode: { - GST_ERROR ("client %p: PLAY media does not support ANNOUNCE", client); + GST_ERROR ("client %p: media does not support ANNOUNCE", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); g_free (path); g_object_unref (media); @@ -2439,8 +2449,9 @@ handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); - if (!gst_rtsp_media_is_record (media)) - goto play_media; + if (!(gst_rtsp_media_get_transport_mode (media) & + GST_RTSP_TRANSPORT_MODE_RECORD)) + goto unsupported_mode; /* the session state must be playing or ready */ rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); @@ -2493,9 +2504,9 @@ no_aggregate: g_free (path); return FALSE; } -play_media: +unsupported_mode: { - GST_ERROR ("client %p: PLAY media does not support RECORD", client); + GST_ERROR ("client %p: media does not support RECORD", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); return FALSE; } diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 304c4a1ddb..e1e169eae9 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -53,13 +53,13 @@ struct _GstRTSPMediaFactoryPrivate GstRTSPPermissions *permissions; gchar *launch; gboolean shared; - gboolean record; GstRTSPSuspendMode suspend_mode; gboolean eos_shutdown; GstRTSPProfile profiles; GstRTSPLowerTrans protocols; guint buffer_size; GstRTSPAddressPool *pool; + GstRTSPTransportMode transport_mode; GstClockTime rtx_time; guint latency; @@ -77,7 +77,7 @@ struct _GstRTSPMediaFactoryPrivate GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_LATENCY 200 -#define DEFAULT_RECORD FALSE +#define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY enum { @@ -90,7 +90,7 @@ enum PROP_PROTOCOLS, PROP_BUFFER_SIZE, PROP_LATENCY, - PROP_RECORD, + PROP_TRANSPORT_MODE, PROP_LAST }; @@ -194,12 +194,10 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "Latency used for receiving media in milliseconds", 0, G_MAXUINT, DEFAULT_LATENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - /* FIXME: Should this be a flag property to allow RECORD and PLAY? - * Or just another boolean PLAY property that default to TRUE? - */ - g_object_class_install_property (gobject_class, PROP_RECORD, - g_param_spec_boolean ("record", "Record", - "If media from this factory is for PLAY or RECORD", DEFAULT_RECORD, + g_object_class_install_property (gobject_class, PROP_TRANSPORT_MODE, + g_param_spec_flags ("transport-mode", "Transport Mode", + "If media from this factory is for PLAY or RECORD", + GST_TYPE_RTSP_TRANSPORT_MODE, DEFAULT_TRANSPORT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = @@ -239,6 +237,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->protocols = DEFAULT_PROTOCOLS; priv->buffer_size = DEFAULT_BUFFER_SIZE; priv->latency = DEFAULT_LATENCY; + priv->transport_mode = DEFAULT_TRANSPORT_MODE; g_mutex_init (&priv->lock); g_mutex_init (&priv->medias_lock); @@ -298,8 +297,9 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, case PROP_LATENCY: g_value_set_uint (value, gst_rtsp_media_factory_get_latency (factory)); break; - case PROP_RECORD: - g_value_set_boolean (value, gst_rtsp_media_factory_is_record (factory)); + case PROP_TRANSPORT_MODE: + g_value_set_flags (value, + gst_rtsp_media_factory_get_transport_mode (factory)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -340,8 +340,9 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, case PROP_LATENCY: gst_rtsp_media_factory_set_latency (factory, g_value_get_uint (value)); break; - case PROP_RECORD: - gst_rtsp_media_factory_set_record (factory, g_value_get_boolean (value)); + case PROP_TRANSPORT_MODE: + gst_rtsp_media_factory_set_transport_mode (factory, + g_value_get_flags (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -1220,7 +1221,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstRTSPPermissions *perms; GstClockTime rtx_time; guint latency; - gboolean record; + GstRTSPTransportMode transport_mode; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -1232,7 +1233,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) protocols = priv->protocols; rtx_time = priv->rtx_time; latency = priv->latency; - record = priv->record; + transport_mode = priv->transport_mode; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_suspend_mode (media, suspend_mode); @@ -1243,7 +1244,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_protocols (media, protocols); gst_rtsp_media_set_retransmission_time (media, rtx_time); gst_rtsp_media_set_latency (media, latency); - gst_rtsp_media_set_record (media, record); + gst_rtsp_media_set_transport_mode (media, transport_mode); if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) { gst_rtsp_media_set_address_pool (media, pool); @@ -1290,15 +1291,15 @@ gst_rtsp_media_factory_create_element (GstRTSPMediaFactory * factory, } /** - * gst_rtsp_media_factory_set_record: + * gst_rtsp_media_factory_set_transport_mode: * @factory: a #GstRTSPMediaFactory - * @record: the new value + * @mode: the new value * - * Configure if this factory creates media for PLAY or RECORD methods. + * Configure if this factory creates media for PLAY or RECORD modes. */ void -gst_rtsp_media_factory_set_record (GstRTSPMediaFactory * factory, - gboolean record) +gst_rtsp_media_factory_set_transport_mode (GstRTSPMediaFactory * factory, + GstRTSPTransportMode mode) { GstRTSPMediaFactoryPrivate *priv; @@ -1307,31 +1308,31 @@ gst_rtsp_media_factory_set_record (GstRTSPMediaFactory * factory, priv = factory->priv; GST_RTSP_MEDIA_FACTORY_LOCK (factory); - priv->record = record; + priv->transport_mode = mode; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); } /** - * gst_rtsp_media_factory_is_record: + * gst_rtsp_media_factory_get_transport_mode: * @factory: a #GstRTSPMediaFactory * * Get if media created from this factory can be used for PLAY or RECORD * methods. * - * Returns: %TRUE if the media will be record between clients. + * Returns: The supported transport modes. */ -gboolean -gst_rtsp_media_factory_is_record (GstRTSPMediaFactory * factory) +GstRTSPTransportMode +gst_rtsp_media_factory_get_transport_mode (GstRTSPMediaFactory * factory) { GstRTSPMediaFactoryPrivate *priv; - gboolean result; + GstRTSPTransportMode result; g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); priv = factory->priv; GST_RTSP_MEDIA_FACTORY_LOCK (factory); - result = priv->record; + result = priv->transport_mode; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); return result; diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index b8b54045b3..fa3676665d 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -149,9 +149,9 @@ void gst_rtsp_media_factory_set_latency (GstRTSPMediaFacto guint latency); guint gst_rtsp_media_factory_get_latency (GstRTSPMediaFactory * factory); -void gst_rtsp_media_factory_set_record (GstRTSPMediaFactory *factory, - gboolean record); -gboolean gst_rtsp_media_factory_is_record (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_transport_mode (GstRTSPMediaFactory *factory, + GstRTSPTransportMode mode); +GstRTSPTransportMode gst_rtsp_media_factory_get_transport_mode (GstRTSPMediaFactory *factory); /* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index ad2609a17b..5218b93a68 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -101,7 +101,7 @@ struct _GstRTSPMediaPrivate guint buffer_size; GstRTSPAddressPool *pool; gboolean blocked; - gboolean record; + GstRTSPTransportMode transport_mode; GstElement *element; GRecMutex state_lock; /* locking order: state lock, lock */ @@ -150,7 +150,7 @@ struct _GstRTSPMediaPrivate #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_TIME_PROVIDER FALSE #define DEFAULT_LATENCY 200 -#define DEFAULT_RECORD FALSE +#define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -168,7 +168,7 @@ enum PROP_ELEMENT, PROP_TIME_PROVIDER, PROP_LATENCY, - PROP_RECORD, + PROP_TRANSPORT_MODE, PROP_LAST }; @@ -215,7 +215,6 @@ static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; #define C_ENUM(v) ((gint) v) -#define GST_TYPE_RTSP_SUSPEND_MODE (gst_rtsp_suspend_mode_get_type()) GType gst_rtsp_suspend_mode_get_type (void) { @@ -236,6 +235,27 @@ gst_rtsp_suspend_mode_get_type (void) return (GType) id; } +#define C_FLAGS(v) ((guint) v) + +GType +gst_rtsp_transport_mode_get_type (void) +{ + static gsize id = 0; + static const GFlagsValue values[] = { + {C_FLAGS (GST_RTSP_TRANSPORT_MODE_PLAY), "GST_RTSP_TRANSPORT_MODE_PLAY", + "play"}, + {C_FLAGS (GST_RTSP_TRANSPORT_MODE_RECORD), "GST_RTSP_TRANSPORT_MODE_RECORD", + "record"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&id)) { + GType tmp = g_flags_register_static ("GstRTSPTransportMode", values); + g_once_init_leave (&id, tmp); + } + return (GType) id; +} + G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); static void @@ -301,10 +321,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "Latency used for receiving media in milliseconds", 0, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_RECORD, - g_param_spec_boolean ("record", "Record", + g_object_class_install_property (gobject_class, PROP_TRANSPORT_MODE, + g_param_spec_flags ("transport-mode", "Transport Mode", "If this media pipeline can be used for PLAY or RECORD", - DEFAULT_RECORD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_TYPE_RTSP_TRANSPORT_MODE, DEFAULT_TRANSPORT_MODE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, @@ -372,7 +393,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN; priv->buffer_size = DEFAULT_BUFFER_SIZE; priv->time_provider = DEFAULT_TIME_PROVIDER; - priv->record = DEFAULT_RECORD; + priv->transport_mode = DEFAULT_TRANSPORT_MODE; } static void @@ -446,8 +467,8 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_LATENCY: g_value_set_uint (value, gst_rtsp_media_get_latency (media)); break; - case PROP_RECORD: - g_value_set_boolean (value, gst_rtsp_media_is_record (media)); + case PROP_TRANSPORT_MODE: + g_value_set_flags (value, gst_rtsp_media_get_transport_mode (media)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -492,8 +513,8 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_LATENCY: gst_rtsp_media_set_latency (media, g_value_get_uint (value)); break; - case PROP_RECORD: - gst_rtsp_media_set_record (media, g_value_get_boolean (value)); + case PROP_TRANSPORT_MODE: + gst_rtsp_media_set_transport_mode (media, g_value_get_flags (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); @@ -1405,6 +1426,7 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) GstPad *pad; gint i; gboolean have_elem; + GstRTSPTransportMode mode = 0; g_return_if_fail (GST_IS_RTSP_MEDIA (media)); @@ -1429,6 +1451,7 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) gst_object_unref (elem); have_elem = TRUE; + mode |= GST_RTSP_TRANSPORT_MODE_PLAY; } g_free (name); @@ -1442,6 +1465,7 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) g_mutex_unlock (&priv->lock); have_elem = TRUE; + mode |= GST_RTSP_TRANSPORT_MODE_PLAY; } g_free (name); @@ -1457,9 +1481,17 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) gst_object_unref (elem); have_elem = TRUE; + mode |= GST_RTSP_TRANSPORT_MODE_RECORD; } g_free (name); } + + if (have_elem) { + if (priv->transport_mode != mode) + GST_WARNING ("found different mode than expected (0x%02x != 0x%02d)", + priv->transport_mode, mode); + gst_rtsp_media_set_transport_mode (media, mode); + } } /** @@ -1834,7 +1866,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) goto not_prepared; /* Update the seekable state of the pipeline in case it changed */ - if (gst_rtsp_media_is_record (media)) { + if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) { /* TODO: Seeking for RECORD? */ priv->seekable = FALSE; } else { @@ -2032,7 +2064,7 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) GST_DEBUG ("%p: went from %s to %s (pending %s)", media, gst_element_state_get_name (old), gst_element_state_get_name (new), gst_element_state_get_name (pending)); - if (gst_rtsp_media_is_record (media) + if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD) && old == GST_STATE_READY && new == GST_STATE_PAUSED) { GST_INFO ("%p: went to PAUSED, prepared now", media); collect_media_stats (media); @@ -2347,7 +2379,7 @@ start_preroll (GstRTSPMedia * media) * seeking query in preroll instead */ priv->seekable = FALSE; priv->is_live = TRUE; - if (!gst_rtsp_media_is_record (media)) { + if (!(priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) { /* start blocked to make sure nothing goes to the sink */ media_streams_set_blocked (media, TRUE); } @@ -3941,15 +3973,15 @@ error_status: } /** - * gst_rtsp_media_set_record: + * gst_rtsp_media_set_transport_mode: * @media: a #GstRTSPMedia - * @record: the new value + * @mode: the new value * - * Set or unset if the pipeline for @media can be used for PLAY or RECORD - * methods. + * Sets if the media pipeline can work in PLAY or RECORD mode */ void -gst_rtsp_media_set_record (GstRTSPMedia * media, gboolean record) +gst_rtsp_media_set_transport_mode (GstRTSPMedia * media, + GstRTSPTransportMode mode) { GstRTSPMediaPrivate *priv; @@ -3958,30 +3990,30 @@ gst_rtsp_media_set_record (GstRTSPMedia * media, gboolean record) priv = media->priv; g_mutex_lock (&priv->lock); - priv->record = record; + priv->transport_mode = mode; g_mutex_unlock (&priv->lock); } /** - * gst_rtsp_media_is_record: + * gst_rtsp_media_get_transport_mode: * @media: a #GstRTSPMedia * * Check if the pipeline for @media can be used for PLAY or RECORD methods. * - * Returns: %TRUE if the media can be record between clients. + * Returns: The transport mode. */ -gboolean -gst_rtsp_media_is_record (GstRTSPMedia * media) +GstRTSPTransportMode +gst_rtsp_media_get_transport_mode (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv; - gboolean res; + GstRTSPTransportMode res; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); priv = media->priv; g_mutex_lock (&priv->lock); - res = priv->record; + res = priv->transport_mode; g_mutex_unlock (&priv->lock); return res; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 4aa2415d4f..07581b59a9 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -77,6 +77,21 @@ typedef enum { GST_RTSP_SUSPEND_MODE_RESET = 2 } GstRTSPSuspendMode; +/** + * GstRTSPTransportMode: + * @GST_RTSP_TRANSPORT_MODE_PLAY: Transport supports PLAY mode + * @GST_RTSP_TRANSPORT_MODE_RECORD: Transport supports RECORD mode + * + * The supported modes of the media. + */ +typedef enum { + GST_RTSP_TRANSPORT_MODE_PLAY = 1, + GST_RTSP_TRANSPORT_MODE_RECORD = 2, +} GstRTSPTransportMode; + +#define GST_TYPE_RTSP_TRANSPORT_MODE (gst_rtsp_transport_mode_get_type()) +GType gst_rtsp_transport_mode_get_type (void); + #define GST_TYPE_RTSP_SUSPEND_MODE (gst_rtsp_suspend_mode_get_type()) GType gst_rtsp_suspend_mode_get_type (void); @@ -172,8 +187,8 @@ GstRTSPPermissions * gst_rtsp_media_get_permissions (GstRTSPMedia *media); void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared); gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media); -void gst_rtsp_media_set_record (GstRTSPMedia *media, gboolean record); -gboolean gst_rtsp_media_is_record (GstRTSPMedia *media); +void gst_rtsp_media_set_transport_mode (GstRTSPMedia *media, GstRTSPTransportMode mode); +GstRTSPTransportMode gst_rtsp_media_get_transport_mode (GstRTSPMedia *media); void gst_rtsp_media_set_reusable (GstRTSPMedia *media, gboolean reusable); gboolean gst_rtsp_media_is_reusable (GstRTSPMedia *media); diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index d268b66420..726c9493f8 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -193,7 +193,8 @@ start_record_server (const gchar * launch_line) factory = gst_rtsp_media_factory_new (); - gst_rtsp_media_factory_set_record (factory, TRUE); + gst_rtsp_media_factory_set_transport_mode (factory, + GST_RTSP_TRANSPORT_MODE_RECORD); gst_rtsp_media_factory_set_launch (factory, launch_line); gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); g_object_unref (mounts); From 5377dd2b78c230c7c2a8956334d4bd2a71b84bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 21 Jan 2015 17:32:21 +0000 Subject: [PATCH 1088/1776] examples: add new test-record to .gitignore --- examples/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/.gitignore b/examples/.gitignore index 81859e7c1d..978258f205 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -4,6 +4,7 @@ test-launch test-mp4 test-ogg test-readme +test-record test-sdp test-video test-video-rtx From a862d632b72effc85f0be6a068f1e4bfb8765418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 6 Feb 2015 19:15:40 +0000 Subject: [PATCH 1089/1776] examples: test-uri: don't remove mount point after 10 seconds It's very irritating when trying to test stuff repeatedly and serves no real purpose other than showing that it can be done. --- examples/test-uri.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/test-uri.c b/examples/test-uri.c index a5a3399a0b..7bcb041c9c 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -45,6 +45,7 @@ timeout (GstRTSPServer * server) return TRUE; } +#if 0 static gboolean remove_map (GstRTSPServer * server) { @@ -57,6 +58,7 @@ remove_map (GstRTSPServer * server) return FALSE; } +#endif int main (int argc, char *argv[]) @@ -110,9 +112,12 @@ main (int argc, char *argv[]) /* do session cleanup every 2 seconds */ g_timeout_add_seconds (2, (GSourceFunc) timeout, server); - /* remove the mount point after 10 seconds, new clients won't be able to use the - * /test url anymore */ + +#if 0 + /* remove the mount point after 10 seconds, new clients won't be able to use + * the /test url anymore */ g_timeout_add_seconds (10, (GSourceFunc) remove_map, server); +#endif /* start serving */ g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port); From 6dbffce31973253307dcb92a753734f22773ab90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 6 Feb 2015 19:34:17 +0000 Subject: [PATCH 1090/1776] examples: test-uri: improve uri argument handling and accept file names Print an error if the argument passed is not a URI and can't be converted into one, or no arguments have been provided. --- examples/test-uri.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/examples/test-uri.c b/examples/test-uri.c index 7bcb041c9c..acea862c19 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -69,6 +69,7 @@ main (int argc, char *argv[]) GstRTSPMediaFactoryURI *factory; GOptionContext *optctx; GError *error = NULL; + gchar *uri; optctx = g_option_context_new (" - Test RTSP Server, URI"); g_option_context_add_main_entries (optctx, entries, NULL); @@ -79,6 +80,11 @@ main (int argc, char *argv[]) } g_option_context_free (optctx); + if (argc < 2) { + g_printerr ("Please pass an URI or file as argument!\n"); + return -1; + } + loop = g_main_loop_new (NULL, FALSE); /* create a server instance */ @@ -91,10 +97,25 @@ main (int argc, char *argv[]) /* make a URI media factory for a test stream. */ factory = gst_rtsp_media_factory_uri_new (); + /* when using GStreamer as a client, one can use the gst payloader, which is * more efficient when there is no payloader for the compressed format */ /* g_object_set (factory, "use-gstpay", TRUE, NULL); */ - gst_rtsp_media_factory_uri_set_uri (factory, argv[1]); + + /* check if URI is valid, otherwise convert filename to URI if it's a file */ + if (gst_uri_is_valid (argv[1])) { + uri = g_strdup (argv[1]); + } else if (g_file_test (argv[1], G_FILE_TEST_EXISTS)) { + uri = gst_filename_to_uri (argv[1], NULL); + } else { + g_printerr ("Unrecognised command line argument '%s'.\n" + "Please pass an URI or file as argument!\n", argv[1]); + return -1; + } + + gst_rtsp_media_factory_uri_set_uri (factory, uri); + g_free (uri); + /* if you want multiple clients to see the same video, set the shared property * to TRUE */ /* gst_rtsp_media_factory_set_shared ( GST_RTSP_MEDIA_FACTORY (factory), TRUE); */ From 57c21c8f9ebdf239697dd38039777252ea904387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 8 Feb 2015 12:08:36 +0000 Subject: [PATCH 1091/1776] rtsp-client: fix awkward if clause --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index dc7ebcc6ba..1d9610afec 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2303,7 +2303,7 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) /* could not be set but since the request returned OK, we assume it * was SDP, else check it. */ if (cont) { - if (!g_ascii_strcasecmp (cont, "application/sdp") == 0) + if (g_ascii_strcasecmp (cont, "application/sdp") != 0) goto wrong_content_type; } From a56404a45a3b170e1d563aaa4c1f92c66ab68331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 8 Feb 2015 18:05:50 +0000 Subject: [PATCH 1092/1776] tests: rtspserver: rename shadowed variable We have two different 'sink' variables here, rename one of them for clarity. --- tests/check/gst/rtspserver.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 726c9493f8..fd8b067f29 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1755,7 +1755,7 @@ GST_START_TEST (test_record_tcp) GstRTSPResult rres; GSocketAddress *sa; GInetAddress *ia; - GstElement *sink = NULL; + GstElement *server_sink = NULL; GSocket *conn_socket; const gchar *proto; gchar *client_ip, *sess_id, *session = NULL; @@ -1765,7 +1765,7 @@ GST_START_TEST (test_record_tcp) start_record_server ("( rtppcmadepay name=depay0 ! appsink name=sink )"); g_signal_connect (mfactory, "media-constructed", - G_CALLBACK (media_constructed_cb), &sink); + G_CALLBACK (media_constructed_cb), &server_sink); conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -1894,12 +1894,12 @@ GST_START_TEST (test_record_tcp) for (i = 0; i < RECORD_N_BUFS; ++i) { GstSample *sample = NULL; - g_signal_emit_by_name (G_OBJECT (sink), "pull-sample", &sample); + g_signal_emit_by_name (G_OBJECT (server_sink), "pull-sample", &sample); GST_INFO ("%2d recv sample: %p", i, sample); gst_sample_unref (sample); } - fail_unless_equals_int (GST_STATE (sink), GST_STATE_PLAYING); + fail_unless_equals_int (GST_STATE (server_sink), GST_STATE_PLAYING); /* clean up and iterate so the clean-up can finish */ gst_rtsp_connection_free (conn); From 8405cfad3ab63b56e48edc25656b931615f302ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 9 Feb 2015 10:21:50 +0100 Subject: [PATCH 1093/1776] rtsp-media: Don't set the transport mode based on what elements we find Just print a warning if the one that was set before disagrees with what elements we found. It must already be set to something before as this function is called after we received the SDP from ANNOUNCE in RECORD mode, and we would reject ANNOUNCE if the RECORD flag was not set. --- gst/rtsp-server/rtsp-media.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 5218b93a68..4ac89b11da 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1490,7 +1490,6 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) if (priv->transport_mode != mode) GST_WARNING ("found different mode than expected (0x%02x != 0x%02d)", priv->transport_mode, mode); - gst_rtsp_media_set_transport_mode (media, mode); } } From ec7bf5379ebf9fc0bf477fb9b4e1f4fbb1685cad Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 10 Feb 2015 16:39:58 +0000 Subject: [PATCH 1094/1776] rtsp-media: fix logic for collect_streams Fix the logic of gst_rtsp_media_collect_streams() so after looping collecting all streams it knows if it got any, and can check if the transport mode is OK. CID #1268400 --- gst/rtsp-server/rtsp-media.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4ac89b11da..0e94e528cd 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1426,6 +1426,7 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) GstPad *pad; gint i; gboolean have_elem; + gboolean more_elem_remaining = TRUE; GstRTSPTransportMode mode = 0; g_return_if_fail (GST_IS_RTSP_MEDIA (media)); @@ -1433,11 +1434,11 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) priv = media->priv; element = priv->element; - have_elem = TRUE; - for (i = 0; have_elem; i++) { + have_elem = FALSE; + for (i = 0; more_elem_remaining; i++) { gchar *name; - have_elem = FALSE; + more_elem_remaining = FALSE; name = g_strdup_printf ("pay%d", i); if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { @@ -1451,6 +1452,7 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) gst_object_unref (elem); have_elem = TRUE; + more_elem_remaining = TRUE; mode |= GST_RTSP_TRANSPORT_MODE_PLAY; } g_free (name); @@ -1465,6 +1467,7 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) g_mutex_unlock (&priv->lock); have_elem = TRUE; + more_elem_remaining = TRUE; mode |= GST_RTSP_TRANSPORT_MODE_PLAY; } g_free (name); @@ -1481,6 +1484,7 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) gst_object_unref (elem); have_elem = TRUE; + more_elem_remaining = TRUE; mode |= GST_RTSP_TRANSPORT_MODE_RECORD; } g_free (name); From dc43f427a91c1c6036ab61b4f2dec3ff29bd2dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 11 Feb 2015 17:24:38 +0000 Subject: [PATCH 1095/1776] rtsp-stream: minor code formatting fix --- gst/rtsp-server/rtsp-stream.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index b71c776fdf..d5f890cba6 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -55,7 +55,8 @@ struct _GstRTSPStream { /*< private >*/ GstRTSPStreamPrivate *priv; - gpointer _gst_reserved[GST_PADDING];}; + gpointer _gst_reserved[GST_PADDING]; +}; struct _GstRTSPStreamClass { GObjectClass parent_class; From 98b162f54b9168fe0745ddab98163d07109ca208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 12 Feb 2015 16:48:46 +0200 Subject: [PATCH 1096/1776] rtsp-media: If seeking fails, don't wait forever for the media to preroll again Instead error out properly the same way as if the SEEKING query already failed. --- gst/rtsp-server/rtsp-client.c | 11 ++++++++++- gst/rtsp-server/rtsp-media.c | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1d9610afec..8e8f73ad3e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1165,7 +1165,10 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) { /* we have a range, seek to the position */ unit = range->unit; - gst_rtsp_media_seek (media, range); + if (!gst_rtsp_media_seek (media, range)) { + gst_rtsp_range_free (range); + goto seek_failed; + } gst_rtsp_range_free (range); } } @@ -1239,6 +1242,12 @@ unsuspend_failed: send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); return FALSE; } +seek_failed: + { + GST_ERROR ("client %p: seek failed", client); + send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + return FALSE; + } unsupported_mode: { GST_ERROR ("client %p: media does not support PLAY", client); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 0e94e528cd..f97490b012 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1952,6 +1952,9 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) /* and block for the seek to complete */ GST_INFO ("done seeking %d", res); + if (!res) + goto seek_failed; + g_rec_mutex_unlock (&priv->state_lock); /* wait until pipeline is prerolled again, this will also collect stats */ @@ -1987,6 +1990,12 @@ not_supported: GST_WARNING ("conversion to npt not supported"); return FALSE; } +seek_failed: + { + g_rec_mutex_unlock (&priv->state_lock); + GST_INFO ("seeking failed"); + return FALSE; + } preroll_failed: { GST_WARNING ("failed to preroll after seek"); From bac59c52f18310893d906c7076bdd07a85fa9744 Mon Sep 17 00:00:00 2001 From: Andreas Frisch Date: Thu, 12 Feb 2015 10:46:28 +0100 Subject: [PATCH 1097/1776] rtsp-stream: Add necessary queues between tee and multiudpsink https://bugzilla.gnome.org/show_bug.cgi?id=744379 --- gst/rtsp-server/rtsp-stream.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 83cee2b53e..abdeeaaf2b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -105,6 +105,7 @@ struct _GstRTSPStreamPrivate * sockets */ GstElement *udpsrc_v6[2]; + GstElement *udpqueue[2]; GstElement *udpsink[2]; /* for TCP transport */ @@ -2103,11 +2104,20 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, gst_pad_link (priv->send_src[i], pad); gst_object_unref (pad); - /* link tee to udpsink */ + priv->udpqueue[i] = gst_element_factory_make ("queue", NULL); + gst_bin_add (bin, priv->udpqueue[i]); + /* link tee to udpqueue */ teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); - gst_pad_link (teepad, sinkpad); + pad = gst_element_get_static_pad (priv->udpqueue[i], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); gst_object_unref (teepad); + /* link udpqueue to udpsink */ + queuepad = gst_element_get_static_pad (priv->udpqueue[i], "src"); + gst_pad_link (queuepad, sinkpad); + gst_object_unref (queuepad); + /* make queue */ priv->appqueue[i] = gst_element_factory_make ("queue", NULL); gst_bin_add (bin, priv->appqueue[i]); @@ -2213,6 +2223,8 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, gst_element_set_state (priv->appsink[i], state); if (priv->appqueue[i]) gst_element_set_state (priv->appqueue[i], state); + if (priv->udpqueue[i]) + gst_element_set_state (priv->udpqueue[i], state); if (priv->tee[i]) gst_element_set_state (priv->tee[i], state); if (priv->funnel[i]) @@ -2309,6 +2321,8 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_element_set_state (priv->appsink[i], GST_STATE_NULL); if (priv->appqueue[i]) gst_element_set_state (priv->appqueue[i], GST_STATE_NULL); + if (priv->udpqueue[i]) + gst_element_set_state (priv->udpqueue[i], GST_STATE_NULL); if (priv->tee[i]) gst_element_set_state (priv->tee[i], GST_STATE_NULL); if (priv->funnel[i]) @@ -2348,6 +2362,8 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_bin_remove (bin, priv->appsink[i]); if (priv->appqueue[i]) gst_bin_remove (bin, priv->appqueue[i]); + if (priv->udpqueue[i]) + gst_bin_remove (bin, priv->udpqueue[i]); if (priv->tee[i]) gst_bin_remove (bin, priv->tee[i]); if (priv->funnel[i]) @@ -2363,6 +2379,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->appsrc[i] = NULL; priv->appsink[i] = NULL; priv->appqueue[i] = NULL; + priv->udpqueue[i] = NULL; priv->tee[i] = NULL; priv->funnel[i] = NULL; } From 51ed357597eec8d3ca51427f4788afada3154c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 13 Feb 2015 12:21:16 +0200 Subject: [PATCH 1098/1776] rtsp-client: Only error out in PLAY if seeking actually failed If the media was just not seekable, we continue from whatever position we are and let the client decide if that is what is wanted or not. Only if the actual seek failed, we can't really recover and should error out. --- gst/rtsp-server/rtsp-client.c | 11 +++++++---- gst/rtsp-server/rtsp-media.c | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8e8f73ad3e..bedc4642e4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1163,13 +1163,16 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0); if (res == GST_RTSP_OK) { if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) { + GstRTSPMediaStatus media_status; + /* we have a range, seek to the position */ unit = range->unit; - if (!gst_rtsp_media_seek (media, range)) { - gst_rtsp_range_free (range); - goto seek_failed; - } + gst_rtsp_media_seek (media, range); gst_rtsp_range_free (range); + + media_status = gst_rtsp_media_get_status (media); + if (media_status == GST_RTSP_MEDIA_STATUS_ERROR) + goto seek_failed; } } diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index f97490b012..65ad9ff284 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1994,6 +1994,7 @@ seek_failed: { g_rec_mutex_unlock (&priv->state_lock); GST_INFO ("seeking failed"); + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR); return FALSE; } preroll_failed: From d2f1997c4b38b9aa0c85a9c4dffdc336cddd747d Mon Sep 17 00:00:00 2001 From: Kent-Inge Ingesson Date: Thu, 19 Feb 2015 10:43:16 +0200 Subject: [PATCH 1099/1776] rtsp-session: Use monotonic time for RTSP session timeout Changed RTSP session timeout handling to monotonic time and deprecating the API for current system time. This fixes timeouts when the system time changes. https://bugzilla.gnome.org/show_bug.cgi?id=743346 --- gst/rtsp-server/rtsp-session-pool.c | 16 +++-- gst/rtsp-server/rtsp-session.c | 100 +++++++++++++++++++++++++--- gst/rtsp-server/rtsp-session.h | 4 ++ 3 files changed, 106 insertions(+), 14 deletions(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 772390ffc1..ea1ff18e4d 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -470,7 +470,7 @@ gst_rtsp_session_pool_remove (GstRTSPSessionPool * pool, GstRTSPSession * sess) typedef struct { - GTimeVal now; + gint64 now_monotonic_time; GstRTSPSessionPool *pool; GList *removed; } CleanupData; @@ -480,11 +480,13 @@ cleanup_func (gchar * sessionid, GstRTSPSession * sess, CleanupData * data) { gboolean expired; - expired = gst_rtsp_session_is_expired (sess, &data->now); + expired = gst_rtsp_session_is_expired_usec (sess, data->now_monotonic_time); + if (expired) { GST_DEBUG ("session expired"); data->removed = g_list_prepend (data->removed, g_object_ref (sess)); } + return expired; } @@ -509,7 +511,8 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool) priv = pool->priv; - g_get_current_time (&data.now); + data.now_monotonic_time = g_get_monotonic_time (); + data.pool = pool; data.removed = NULL; @@ -661,11 +664,12 @@ static void collect_timeout (gchar * sessionid, GstRTSPSession * sess, GstPoolSource * psrc) { gint timeout; - GTimeVal now; + gint64 now_monotonic_time; - g_get_current_time (&now); + now_monotonic_time = g_get_monotonic_time (); + + timeout = gst_rtsp_session_next_timeout_usec (sess, now_monotonic_time); - timeout = gst_rtsp_session_next_timeout (sess, &now); GST_INFO ("%p: next timeout: %d", sess, timeout); if (psrc->timeout == -1 || timeout < psrc->timeout) psrc->timeout = timeout; diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 1f4b650344..052537e740 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -57,9 +57,9 @@ struct _GstRTSPSessionPrivate guint timeout; gboolean timeout_always_visible; - GTimeVal create_time; /* immutable */ GMutex last_access_lock; - GTimeVal last_access; + gint64 last_access_monotonic_time; + gint64 last_access_real_time; gint expire_count; GList *medias; @@ -135,7 +135,7 @@ gst_rtsp_session_init (GstRTSPSession * session) g_mutex_init (&priv->lock); g_mutex_init (&priv->last_access_lock); priv->timeout = DEFAULT_TIMEOUT; - g_get_current_time (&priv->create_time); + gst_rtsp_session_touch (session); } @@ -559,7 +559,8 @@ gst_rtsp_session_touch (GstRTSPSession * session) priv = session->priv; g_mutex_lock (&priv->last_access_lock); - g_get_current_time (&priv->last_access); + priv->last_access_monotonic_time = g_get_monotonic_time (); + priv->last_access_real_time = g_get_real_time (); g_mutex_unlock (&priv->last_access_lock); } @@ -590,6 +591,52 @@ gst_rtsp_session_allow_expire (GstRTSPSession * session) g_atomic_int_add (&session->priv->expire_count, -1); } +/** + * gst_rtsp_session_next_timeout_usec: + * @session: a #GstRTSPSession + * @now: (transfer none): the current monotonic time + * + * Get the amount of milliseconds till the session will expire. + * + * Returns: the amount of milliseconds since the session will time out. + */ +gint +gst_rtsp_session_next_timeout_usec (GstRTSPSession * session, gint64 now) +{ + GstRTSPSessionPrivate *priv; + gint res; + GstClockTime last_access, now_ns; + + g_return_val_if_fail (GST_IS_RTSP_SESSION (session), -1); + + priv = session->priv; + + g_mutex_lock (&priv->last_access_lock); + if (g_atomic_int_get (&priv->expire_count) != 0) { + /* touch session when the expire count is not 0 */ + priv->last_access_monotonic_time = g_get_monotonic_time (); + priv->last_access_real_time = g_get_real_time (); + } + + last_access = GST_USECOND * (priv->last_access_monotonic_time); + + /* add timeout allow for 5 seconds of extra time */ + last_access += priv->timeout * GST_SECOND + (5 * GST_SECOND); + g_mutex_unlock (&priv->last_access_lock); + + now_ns = GST_USECOND * now; + + if (last_access > now_ns) { + res = GST_TIME_AS_MSECONDS (last_access - now_ns); + } else { + res = 0; + } + + return res; +} + +/****** Deprecated API *******/ + /** * gst_rtsp_session_next_timeout: * @session: a #GstRTSPSession @@ -598,7 +645,11 @@ gst_rtsp_session_allow_expire (GstRTSPSession * session) * Get the amount of milliseconds till the session will expire. * * Returns: the amount of milliseconds since the session will time out. + * + * Deprecated: Use gst_rtsp_session_next_timeout_usec() instead. */ +#ifndef GST_REMOVE_DEPRECATED +#ifndef GST_DISABLE_DEPRECATED gint gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) { @@ -614,23 +665,50 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) g_mutex_lock (&priv->last_access_lock); if (g_atomic_int_get (&priv->expire_count) != 0) { /* touch session when the expire count is not 0 */ - g_get_current_time (&priv->last_access); + priv->last_access_monotonic_time = g_get_monotonic_time (); + priv->last_access_real_time = g_get_real_time (); } - last_access = GST_TIMEVAL_TO_TIME (priv->last_access); + last_access = GST_USECOND * (priv->last_access_real_time); + /* add timeout allow for 5 seconds of extra time */ last_access += priv->timeout * GST_SECOND + (5 * GST_SECOND); g_mutex_unlock (&priv->last_access_lock); now_ns = GST_TIMEVAL_TO_TIME (*now); - if (last_access > now_ns) + if (last_access > now_ns) { res = GST_TIME_AS_MSECONDS (last_access - now_ns); - else + } else { res = 0; + } return res; } +#endif +#endif + +/** + * gst_rtsp_session_is_expired_usec: + * @session: a #GstRTSPSession + * @now: (transfer none): the current monotonic time + * + * Check if @session timeout out. + * + * Returns: %TRUE if @session timed out + */ +gboolean +gst_rtsp_session_is_expired_usec (GstRTSPSession * session, gint64 now) +{ + gboolean res; + + res = (gst_rtsp_session_next_timeout_usec (session, now) == 0); + + return res; +} + + +/****** Deprecated API *******/ /** * gst_rtsp_session_is_expired: @@ -640,7 +718,11 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) * Check if @session timeout out. * * Returns: %TRUE if @session timed out + * + * Deprecated: Use gst_rtsp_session_is_expired_usec() instead. */ +#ifndef GST_REMOVE_DEPRECATED +#ifndef GST_DISABLE_DEPRECATED gboolean gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) { @@ -650,3 +732,5 @@ gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) return res; } +#endif +#endif diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index d9c0f18713..8bd6ca954e 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -95,8 +95,12 @@ guint gst_rtsp_session_get_timeout (GstRTSPSession *se void gst_rtsp_session_touch (GstRTSPSession *session); void gst_rtsp_session_prevent_expire (GstRTSPSession *session); void gst_rtsp_session_allow_expire (GstRTSPSession *session); +gint gst_rtsp_session_next_timeout_usec (GstRTSPSession *session, gint64 now); +gboolean gst_rtsp_session_is_expired_usec (GstRTSPSession *session, gint64 now); +#ifndef GST_DISABLE_DEPRECATED gint gst_rtsp_session_next_timeout (GstRTSPSession *session, GTimeVal *now); gboolean gst_rtsp_session_is_expired (GstRTSPSession *session, GTimeVal *now); +#endif /* handle media in a session */ GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess, From bc7765eee7a23c602a71d796c66a73a43fb48073 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Fri, 27 Feb 2015 17:45:42 +0100 Subject: [PATCH 1100/1776] rtsp-media: fix double unlock in _get_buffer_size() Fixes an abort when calling gst_rtsp_media_get_buffer_size() because of double g_mutex_unlock () usage. https://bugzilla.gnome.org/show_bug.cgi?id=745434 --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 65ad9ff284..fa5f4101df 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1152,7 +1152,7 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) priv = media->priv; - g_mutex_unlock (&priv->lock); + g_mutex_lock (&priv->lock); res = priv->buffer_size; g_mutex_unlock (&priv->lock); From db42945c2c1cfce74b94dd5f024e2ecf9ac327ce Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 3 Mar 2015 01:49:42 +1100 Subject: [PATCH 1101/1776] rtsp-media-factory: Add functions to set/get the media gtype Allow specifying the GType of a GstRtspMedia subclass to create as a simpler way to get the factory to create a custom GstRtspMedia sub-class, without subclassing GstRtspMediaFactory. --- gst/rtsp-server/rtsp-media-factory.c | 58 +++++++++++++++++++++++++++- gst/rtsp-server/rtsp-media-factory.h | 4 ++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index e1e169eae9..b126339546 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -66,6 +66,8 @@ struct _GstRTSPMediaFactoryPrivate GMutex medias_lock; GHashTable *medias; /* protected by medias_lock */ + + GType media_gtype; }; #define DEFAULT_LAUNCH NULL @@ -243,6 +245,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) g_mutex_init (&priv->medias_lock); priv->medias = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + priv->media_gtype = GST_TYPE_RTSP_MEDIA; } static void @@ -1091,6 +1094,54 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, return media; } +/** + * gst_rtsp_media_factory_set_media_gtype: + * @factory: a #GstRTSPMediaFactory + * @media_gtype: the GType of the class to create + * + * Configure the GType of the GstRTSPMedia subclass to + * create (by default, overridden construct vmethods + * may of course do something different) + * + * Since: 1.6 + */ +void +gst_rtsp_media_factory_set_media_gtype (GstRTSPMediaFactory * factory, + GType media_gtype) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (g_type_is_a (media_gtype, GST_TYPE_RTSP_MEDIA)); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv = factory->priv; + priv->media_gtype = media_gtype; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_media_gtype: + * @factory: a #GstRTSPMediaFactory + * + * Return the GType of the GstRTSPMedia subclass this + * factory will create. + * + * Since: 1.6 + */ +GType +gst_rtsp_media_factory_get_media_gtype (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + GType ret; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv = factory->priv; + ret = priv->media_gtype; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return ret; +} + static gchar * default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { @@ -1157,6 +1208,7 @@ default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) GstRTSPMedia *media; GstElement *element, *pipeline; GstRTSPMediaFactoryClass *klass; + GType media_gtype; klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); @@ -1167,8 +1219,12 @@ default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) if (element == NULL) goto no_element; + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + media_gtype = factory->priv->media_gtype; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + /* create a new empty media */ - media = gst_rtsp_media_new (element); + media = g_object_new (media_gtype, "element", element, NULL); gst_rtsp_media_collect_streams (media); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index fa3676665d..1382426360 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -153,6 +153,10 @@ void gst_rtsp_media_factory_set_transport_mode (GstRTSPMediaFac GstRTSPTransportMode mode); GstRTSPTransportMode gst_rtsp_media_factory_get_transport_mode (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_media_gtype (GstRTSPMediaFactory * factory, + GType media_gtype); +GType gst_rtsp_media_factory_get_media_gtype (GstRTSPMediaFactory * factory); + /* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); From b04856f0cf7960ce8ed863bca7aa0ab5a233ff9b Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 3 Mar 2015 01:49:42 +1100 Subject: [PATCH 1102/1776] examples: Add a simple example of network synch for live streams. An example server and client that works for synchronising live streams only - as it can't support pause/play. --- examples/.gitignore | 2 + examples/Makefile.am | 11 +- examples/test-netclock-client.c | 105 ++++++++++++++++++ examples/test-netclock.c | 181 ++++++++++++++++++++++++++++++++ 4 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 examples/test-netclock-client.c create mode 100644 examples/test-netclock.c diff --git a/examples/.gitignore b/examples/.gitignore index 978258f205..b8c175aa99 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -10,3 +10,5 @@ test-video test-video-rtx test-uri test-auth +test-netclock +test-netclock-client diff --git a/examples/Makefile.am b/examples/Makefile.am index ef33adf75b..0b1495dafc 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,7 +1,8 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ test-launch test-sdp test-uri test-auth \ test-multicast test-multicast2 test-appsrc \ - test-video-rtx test-record + test-video-rtx test-record \ + test-netclock test-netclock-client #INCLUDES = -I$(top_srcdir) -I$(srcdir) @@ -13,3 +14,11 @@ noinst_PROGRAMS += test-cgroups LDADD += $(LIBCGROUP_LIBS) endif +test_netclock_LDFLAGS = \ + $(GST_LIBS) \ + -lgstnet-@GST_API_VERSION@ \ + $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la + +test_netclock_client_LDFLAGS = \ + $(GST_LIBS) \ + -lgstnet-@GST_API_VERSION@ diff --git a/examples/test-netclock-client.c b/examples/test-netclock-client.c new file mode 100644 index 0000000000..f91773eb07 --- /dev/null +++ b/examples/test-netclock-client.c @@ -0,0 +1,105 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * Copyright (C) 2014 Jan Schmidt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include + +#define PLAYBACK_DELAY_MS 40 + +static void +source_created (GstElement * pipe, GParamSpec * pspec) +{ + GstElement *source; + + g_object_get (pipe, "source", &source, NULL); + g_assert (source != NULL); + + g_object_set (source, "latency", PLAYBACK_DELAY_MS, + "use-pipeline-clock", TRUE, "buffer-mode", 1, NULL); + + gst_object_unref (source); +} + +int +main (int argc, char *argv[]) +{ + GstClock *net_clock; + gchar *server; + gint clock_port; + GstElement *pipe; + GstMessage *msg; + + gst_init (&argc, &argv); + + if (argc < 2) { + g_print ("usage: %s rtsp://URI clock-IP clock-PORT\n" + "example: %s rtsp://localhost:8554/test 127.0.0.1 8554\n", + argv[0], argv[0]); + return -1; + } + + server = argv[2]; + clock_port = atoi (argv[3]); + + net_clock = gst_net_client_clock_new ("net_clock", server, clock_port, 0); + if (net_clock == NULL) { + g_print ("Failed to create net clock client for %s:%d\n", + server, clock_port); + return 1; + } + + /* Wait 0.5 seconds for the clock to stabilise */ + g_usleep (G_USEC_PER_SEC / 2); + + pipe = gst_element_factory_make ("playbin", NULL); + g_object_set (pipe, "uri", argv[1], NULL); + g_signal_connect (pipe, "notify::source", (GCallback) source_created, NULL); + + gst_element_set_start_time (pipe, GST_CLOCK_TIME_NONE); + gst_element_set_base_time (pipe, 0); + gst_pipeline_use_clock (GST_PIPELINE (pipe), net_clock); + + if (gst_element_set_state (pipe, + GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + g_print ("Failed to set state to PLAYING\n"); + goto exit; + }; + + msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipe), + GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { + GError *err = NULL; + gchar *debug = NULL; + gst_message_parse_error (msg, &err, &debug); + g_print ("\nERROR: %s\n%s\n\n", err->message, debug); + g_error_free (err); + g_free (debug); + } + gst_message_unref (msg); + +exit: + gst_element_set_state (pipe, GST_STATE_NULL); + gst_object_unref (pipe); + + return 0; +} diff --git a/examples/test-netclock.c b/examples/test-netclock.c new file mode 100644 index 0000000000..2e53635fdb --- /dev/null +++ b/examples/test-netclock.c @@ -0,0 +1,181 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * Copyright (C) 2014 Jan Schmidt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include + +GstClock *global_clock; + +#define TEST_TYPE_RTSP_MEDIA_FACTORY (test_rtsp_media_factory_get_type ()) +#define TEST_TYPE_RTSP_MEDIA (test_rtsp_media_get_type ()) + +GType test_rtsp_media_factory_get_type (void); +GType test_rtsp_media_get_type (void); + +static GstRTSPMediaFactory *test_rtsp_media_factory_new (void); +static GstElement *create_pipeline (GstRTSPMediaFactory * factory, + GstRTSPMedia * media); + +typedef struct TestRTSPMediaFactoryClass TestRTSPMediaFactoryClass; +typedef struct TestRTSPMediaFactory TestRTSPMediaFactory; + +struct TestRTSPMediaFactoryClass +{ + GstRTSPMediaFactoryClass parent; +}; + +struct TestRTSPMediaFactory +{ + GstRTSPMediaFactory parent; +}; + +typedef struct TestRTSPMediaClass TestRTSPMediaClass; +typedef struct TestRTSPMedia TestRTSPMedia; + +struct TestRTSPMediaClass +{ + GstRTSPMediaClass parent; +}; + +struct TestRTSPMedia +{ + GstRTSPMedia parent; +}; + +GstRTSPMediaFactory * +test_rtsp_media_factory_new (void) +{ + GstRTSPMediaFactory *result; + + result = g_object_new (TEST_TYPE_RTSP_MEDIA_FACTORY, NULL); + + return result; +} + +G_DEFINE_TYPE (TestRTSPMediaFactory, test_rtsp_media_factory, + GST_TYPE_RTSP_MEDIA_FACTORY); + +static gboolean custom_setup_rtpbin (GstRTSPMedia * media, GstElement * rtpbin); + +static void +test_rtsp_media_factory_class_init (TestRTSPMediaFactoryClass * test_klass) +{ + GstRTSPMediaFactoryClass *mf_klass = + (GstRTSPMediaFactoryClass *) (test_klass); + mf_klass->create_pipeline = create_pipeline; +} + +static void +test_rtsp_media_factory_init (TestRTSPMediaFactory * factory) +{ +} + +static GstElement * +create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media) +{ + GstElement *pipeline; + + pipeline = gst_pipeline_new ("media-pipeline"); + gst_pipeline_use_clock (GST_PIPELINE (pipeline), global_clock); + gst_element_set_base_time (pipeline, 0); + gst_element_set_start_time (pipeline, GST_CLOCK_TIME_NONE); + gst_rtsp_media_take_pipeline (media, GST_PIPELINE_CAST (pipeline)); + + return pipeline; +} + +G_DEFINE_TYPE (TestRTSPMedia, test_rtsp_media, GST_TYPE_RTSP_MEDIA); + +static void +test_rtsp_media_class_init (TestRTSPMediaClass * test_klass) +{ + GstRTSPMediaClass *klass = (GstRTSPMediaClass *) (test_klass); + klass->setup_rtpbin = custom_setup_rtpbin; +} + +static void +test_rtsp_media_init (TestRTSPMedia * media) +{ +} + +static gboolean +custom_setup_rtpbin (GstRTSPMedia * media, GstElement * rtpbin) +{ + g_object_set (rtpbin, "use-pipeline-clock", TRUE, NULL); + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + + gst_init (&argc, &argv); + + if (argc < 2) { + g_print ("usage: %s \n" + "example: %s \"( videotestsrc is-live=true ! x264enc ! rtph264pay name=pay0 pt=96 )\"\n" + "Pipeline must be live for synchronisation to work properly with this method!\n", + argv[0], argv[0]); + return -1; + } + + loop = g_main_loop_new (NULL, FALSE); + + global_clock = gst_system_clock_obtain (); + gst_net_time_provider_new (global_clock, "0.0.0.0", 8554); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mount points for this server, every server has a default object + * that be used to map uri mount points to media factories */ + mounts = gst_rtsp_server_get_mount_points (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = test_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, argv[1]); + gst_rtsp_media_factory_set_shared (GST_RTSP_MEDIA_FACTORY (factory), TRUE); + gst_rtsp_media_factory_set_media_gtype (GST_RTSP_MEDIA_FACTORY (factory), + TEST_TYPE_RTSP_MEDIA); + + /* attach the test factory to the /test url */ + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mounts); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + g_main_loop_run (loop); + + return 0; +} From d92ff17026598ce6c58fb16f7a475c18f34b5b54 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 3 Mar 2015 13:51:01 +0000 Subject: [PATCH 1103/1776] examples: test-uri: fix tainted variable Insignificant but this keeps Coverity happy. CID #1268404 --- examples/test-uri.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/test-uri.c b/examples/test-uri.c index acea862c19..8a9c56c238 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -61,7 +61,7 @@ remove_map (GstRTSPServer * server) #endif int -main (int argc, char *argv[]) +main (int argc, gchar * argv[]) { GMainLoop *loop; GstRTSPServer *server; From 9dadaed2fd598a0abe146d042177086fdbeaed4a Mon Sep 17 00:00:00 2001 From: Linus Svensson Date: Wed, 26 Feb 2014 22:34:06 +0100 Subject: [PATCH 1104/1776] rtsp-sdp: add payload type to the sdp framesize attribute The sdp framesize attribute is desribed in RFC6064. It is specified for payloading of H263 and has the following form a=framesize: -. The - part should be added to the caps in a payloader and the should be added by the rtsp-server. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725334 --- gst/rtsp-server/rtsp-sdp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index dfc54be97a..421525d9e5 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -345,6 +345,16 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, if (g_str_has_prefix (fname, "x-gst-rtsp-server-rtx-time")) continue; + if (!strcmp (fname, "a-framesize")) { + /* a-framesize attribute */ + if ((fval = gst_structure_get_string (s, fname))) { + tmp = g_strdup_printf ("%d %s", caps_pt, fval); + gst_sdp_media_add_attribute (smedia, fname + 2, tmp); + g_free (tmp); + } + continue; + } + if (g_str_has_prefix (fname, "a-")) { /* attribute */ if ((fval = gst_structure_get_string (s, fname))) From 93bdbb6acdf8fdbd9e68c8906f4e96172aeed1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 9 Mar 2015 10:21:49 +0100 Subject: [PATCH 1105/1776] rtsp-media: Don't include payload type in the caps for framesize When the sdp media attribute framesize are converted to caps the should not be included. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725335 Based on the patch for rtspsrc by Linus Svensson --- gst/rtsp-server/rtsp-media.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index fa5f4101df..7932236f05 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3129,6 +3129,7 @@ parse_rtpmap (const gchar * rtpmap, gint * payload, gchar ** name, * Mapping of caps to and from SDP fields: * * a=rtpmap: /[/] + * a=framesize: - * a=fmtp: [=];... */ static GstCaps * @@ -3137,6 +3138,7 @@ media_to_caps (gint pt, const GstSDPMedia * media) GstCaps *caps; const gchar *rtpmap; const gchar *fmtp; + const gchar *framesize; gchar *name = NULL; gint rate = -1; gchar *params = NULL; @@ -3250,6 +3252,19 @@ media_to_caps (gint pt, const GstSDPMedia * media) g_strfreev (pairs); } } + + /* parse framesize: field */ + if ((framesize = gst_sdp_media_get_attribute_val (media, "framesize"))) { + gchar *p; + + /* p is now of the format - */ + p = (gchar *) framesize; + + PARSE_INT (p, " ", payload); + if (payload != -1 && payload == pt) { + gst_structure_set (s, "a-framesize", G_TYPE_STRING, p, NULL); + } + } return caps; /* ERRORS */ @@ -3441,6 +3456,8 @@ sdp_attributes_to_caps (GArray * attributes, GstCaps * caps) continue; if (!strcmp (key, "range")) continue; + if (!strcmp (key, "framesize")) + continue; if (g_str_equal (key, "key-mgmt")) { parse_keymgmt (attr->value, caps); continue; From b58af93d83221c5cc26c69fd960db8e578f84e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 9 Mar 2015 13:00:25 +0100 Subject: [PATCH 1106/1776] rtsp-media: Don't seek for PLAY if the position will not change https://bugzilla.gnome.org/show_bug.cgi?id=745704 --- gst/rtsp-server/rtsp-media.c | 60 ++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 7932236f05..8b25e07369 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1855,6 +1855,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GstClockTime start, stop; GstSeekType start_type, stop_type; GstQuery *query; + gint64 current_position; klass = GST_RTSP_MEDIA_GET_CLASS (media); @@ -1899,6 +1900,12 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop)); + current_position = -1; + if (klass->query_position) + klass->query_position (media, ¤t_position); + GST_INFO ("current media position %" GST_TIME_FORMAT, + GST_TIME_ARGS (current_position)); + if (start != GST_CLOCK_TIME_NONE) start_type = GST_SEEK_TYPE_SET; @@ -1913,10 +1920,6 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); - gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); - if (priv->blocked) - media_streams_set_blocked (media, TRUE); - /* depends on the current playing state of the pipeline. We might need to * queue this until we get EOS. */ flags = GST_SEEK_FLAG_FLUSH; @@ -1925,18 +1928,12 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) * but since we're doing a flushing seek, let us query the current position * so we end up at exactly the same position after the seek. */ if (range->min.type == GST_RTSP_TIME_END) { /* Yepp, that's right! */ - gint64 position; - gboolean ret = FALSE; - - if (klass->query_position) - ret = klass->query_position (media, &position); - - if (!ret) { - GST_WARNING ("position query failed"); + if (current_position == -1) { + GST_WARNING ("current position unknown"); } else { GST_DEBUG ("doing accurate seek to %" GST_TIME_FORMAT, - GST_TIME_ARGS (position)); - start = position; + GST_TIME_ARGS (current_position)); + start = current_position; start_type = GST_SEEK_TYPE_SET; flags |= GST_SEEK_FLAG_ACCURATE; } @@ -1946,23 +1943,32 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) flags |= GST_SEEK_FLAG_KEY_UNIT; } - /* FIXME, we only do forwards playback, no trick modes yet */ - res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME, - flags, start_type, start, stop_type, stop); + if (start == current_position && stop_type == GST_SEEK_TYPE_NONE) { + GST_DEBUG ("not seeking because no position change"); + res = TRUE; + } else { + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); + if (priv->blocked) + media_streams_set_blocked (media, TRUE); - /* and block for the seek to complete */ - GST_INFO ("done seeking %d", res); - if (!res) - goto seek_failed; + /* FIXME, we only do forwards playback, no trick modes yet */ + res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME, + flags, start_type, start, stop_type, stop); - g_rec_mutex_unlock (&priv->state_lock); + /* and block for the seek to complete */ + GST_INFO ("done seeking %d", res); + if (!res) + goto seek_failed; - /* wait until pipeline is prerolled again, this will also collect stats */ - if (!wait_preroll (media)) - goto preroll_failed; + g_rec_mutex_unlock (&priv->state_lock); - g_rec_mutex_lock (&priv->state_lock); - GST_INFO ("prerolled again"); + /* wait until pipeline is prerolled again, this will also collect stats */ + if (!wait_preroll (media)) + goto preroll_failed; + + g_rec_mutex_lock (&priv->state_lock); + GST_INFO ("prerolled again"); + } } else { GST_INFO ("no seek needed"); res = TRUE; From 852cc09f542af5cadd79ffd7fe79d6475cf57e14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 9 Mar 2015 16:00:07 +0100 Subject: [PATCH 1107/1776] rtsp-stream: Get the seqnum-base and other information from the last buffer in the sink This gives more accurate values than asking the payloader. There might be queueing happening between the payloader and the sink. https://bugzilla.gnome.org/show_bug.cgi?id=745704 --- gst/rtsp-server/rtsp-stream.c | 58 +++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index abdeeaaf2b..873ca5db73 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -55,6 +55,8 @@ #include #include +#include + #include "rtsp-stream.h" #define GST_RTSP_STREAM_GET_PRIVATE(obj) \ @@ -2457,6 +2459,60 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, g_mutex_lock (&priv->lock); + /* First try to extract the information from the last buffer on the sinks. + * This will have a more accurate sequence number and timestamp, as between + * the payloader and the sink there can be some queues + */ + if (priv->udpsink[0] || priv->appsink[0]) { + GstSample *last_sample; + + if (priv->udpsink[0]) + g_object_get (priv->udpsink[0], "last-sample", &last_sample, NULL); + else + g_object_get (priv->appsink[0], "last-sample", &last_sample, NULL); + + if (last_sample) { + GstCaps *caps; + GstBuffer *buffer; + GstSegment *segment; + GstRTPBuffer rtp_buffer = GST_RTP_BUFFER_INIT; + + caps = gst_sample_get_caps (last_sample); + buffer = gst_sample_get_buffer (last_sample); + segment = gst_sample_get_segment (last_sample); + + if (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp_buffer)) { + if (seq) { + *seq = gst_rtp_buffer_get_seq (&rtp_buffer); + gst_rtp_buffer_unmap (&rtp_buffer); + } + + if (rtptime) { + *rtptime = GST_BUFFER_TIMESTAMP (buffer); + } + + if (running_time) { + *running_time = + gst_segment_to_running_time (segment, GST_FORMAT_TIME, + GST_BUFFER_TIMESTAMP (buffer)); + } + + if (clock_rate) { + GstStructure *s = gst_caps_get_structure (caps, 0); + + gst_structure_get_uint (s, "clock-rate", clock_rate); + if (*clock_rate == 0 && running_time) + *running_time = GST_CLOCK_TIME_NONE; + } + gst_sample_unref (last_sample); + + goto done; + } else { + gst_sample_unref (last_sample); + } + } + } + if (g_object_class_find_property (payobjclass, "stats")) { g_object_get (priv->payloader, "stats", &stats, NULL); if (stats == NULL) @@ -2491,6 +2547,8 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, if (running_time) *running_time = GST_CLOCK_TIME_NONE; } + +done: g_mutex_unlock (&priv->lock); return TRUE; From 896767b0412cb5a147ec0ac9cb3cd7550148730e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 10 Mar 2015 09:39:22 +0000 Subject: [PATCH 1108/1776] Fix double semicolons --- gst/rtsp-server/rtsp-media-factory.c | 4 ++-- tests/check/gst/client.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index b126339546..fc9c880fec 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -975,7 +975,7 @@ media_unprepared (GstRTSPMedia * media, GWeakRef * ref) if (!factory) return; - priv = factory->priv;; + priv = factory->priv; g_mutex_lock (&priv->medias_lock); g_hash_table_foreach_remove (priv->medias, (GHRFunc) compare_media, media); @@ -1029,7 +1029,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); g_return_val_if_fail (url != NULL, NULL); - priv = factory->priv;; + priv = factory->priv; klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); /* convert the url to a key for the hashtable. NULL return or a NULL function diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 6d392a7582..95e86109f0 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -333,7 +333,7 @@ GST_START_TEST (test_describe) GST_END_TEST; -static const gchar *expected_transport = NULL;; +static const gchar *expected_transport = NULL; static gboolean test_setup_response_200_multicast (GstRTSPClient * client, From 01ae7c01f37284f4280cb54cb6a42767043fd71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 15 Mar 2015 12:27:39 +0000 Subject: [PATCH 1109/1776] Fix typo in README --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 23737300f3..2d5f7d06da 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -gst-rtsp-server is a library ion top of GStreamer for building an RTSP server +gst-rtsp-server is a library on top of GStreamer for building an RTSP server There are some examples in the examples/ directory and more comprehensive documentation in docs/README. From 01562286ba4d87cf928aef52e1be9c77c76a6506 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 18 Mar 2015 16:44:19 -0400 Subject: [PATCH 1110/1776] rtsp-stream: Don't leave buffer mapped If the seq is NULL, the RTP buffer was left mapped. We should always unmap the buffer. --- gst/rtsp-server/rtsp-stream.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 873ca5db73..e09f43d3bd 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2484,9 +2484,10 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, if (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp_buffer)) { if (seq) { *seq = gst_rtp_buffer_get_seq (&rtp_buffer); - gst_rtp_buffer_unmap (&rtp_buffer); } + gst_rtp_buffer_unmap (&rtp_buffer); + if (rtptime) { *rtptime = GST_BUFFER_TIMESTAMP (buffer); } From dfb053add33e6636ef473b78826e4a720cc1ed24 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sat, 21 Mar 2015 11:04:05 -0400 Subject: [PATCH 1111/1776] rtsp-media: Properly return first rtptime Instead we where returning first GstBuffer timestamp. This would result in clock skew and unwanted behaviour in RTSP playback. https://bugzilla.gnome.org/show_bug.cgi?id=746479 --- gst/rtsp-server/rtsp-stream.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index e09f43d3bd..abba72be80 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2486,12 +2486,12 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, *seq = gst_rtp_buffer_get_seq (&rtp_buffer); } - gst_rtp_buffer_unmap (&rtp_buffer); - if (rtptime) { - *rtptime = GST_BUFFER_TIMESTAMP (buffer); + *rtptime = gst_rtp_buffer_get_timestamp (&rtp_buffer); } + gst_rtp_buffer_unmap (&rtp_buffer); + if (running_time) { *running_time = gst_segment_to_running_time (segment, GST_FORMAT_TIME, From 357af7aea68956e812fcbf56728cacaafff986cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 23 Mar 2015 20:59:52 +0100 Subject: [PATCH 1112/1776] rtsp-stream: Update comment and ASCII art to the latest code We have a queue in front of the udpsink too to prevent the pipeline from locking up. --- gst/rtsp-server/rtsp-stream.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index abba72be80..948be854d1 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2076,14 +2076,14 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, GstPad *teepad, *queuepad; /* For the sender we create this bit of pipeline for both * RTP and RTCP. Sync and preroll are enabled on udpsink so - * we need to add a queue before appsink to make the pipeline - * not block. For the TCP case, we want to pump data to the - * client as fast as possible anyway. + * we need to add a queue before appsink and udpsink to make + * the pipeline not block. For the TCP case, we want to pump + * data to the client as fast as possible. * - * .--------. .-----. .---------. - * | rtpbin | | tee | | udpsink | - * | send->sink src->sink | - * '--------' | | '---------' + * .--------. .-----. .---------. .---------. + * | rtpbin | | tee | | queue | | udpsink | + * | send->sink src->sink src->sink | + * '--------' | | '---------' '---------' * | | .---------. .---------. * | | | queue | | appsink | * | src->sink src->sink | From ef3bfd757bde0c9a28f673823712a90a3d7ba1db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 23 Mar 2015 21:03:20 +0100 Subject: [PATCH 1113/1776] rtsp-stream: Limit the queues to 1 buffer We only need them to be able to pre-roll, queueing up more data here is only going to harm latency and memory usage. --- gst/rtsp-server/rtsp-stream.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 948be854d1..dfbd4a37fb 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2107,6 +2107,8 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, gst_object_unref (pad); priv->udpqueue[i] = gst_element_factory_make ("queue", NULL); + g_object_set (priv->udpqueue[i], "max-size-buffers", + 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), NULL); gst_bin_add (bin, priv->udpqueue[i]); /* link tee to udpqueue */ teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); @@ -2122,6 +2124,8 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, /* make queue */ priv->appqueue[i] = gst_element_factory_make ("queue", NULL); + g_object_set (priv->appqueue[i], "max-size-buffers", + 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), NULL); gst_bin_add (bin, priv->appqueue[i]); /* and link to tee */ teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); From a54d8733b237327f0232685c0c778150f52c2eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 3 Apr 2015 18:58:26 +0100 Subject: [PATCH 1114/1776] Automatic update of common submodule From bc76a8b to c8fb372 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index bc76a8b6a2..c8fb372b4c 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit bc76a8b6a2db1cc0605158e672b2d420b4e130d0 +Subproject commit c8fb372b4c58158d6cb4e309650eb7bc369f882c From bff66c00041b9b009f7e10f294f3ae683737bfb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 6 Apr 2015 10:32:52 +0100 Subject: [PATCH 1115/1776] Update autogen.sh to latest version from common Fixes build after aclocal_check etc. helpers have been removed. --- acinclude.m4 | 66 ---------------------------------------------------- autogen.sh | 51 ++++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 94 deletions(-) delete mode 100644 acinclude.m4 diff --git a/acinclude.m4 b/acinclude.m4 deleted file mode 100644 index 04a283be5d..0000000000 --- a/acinclude.m4 +++ /dev/null @@ -1,66 +0,0 @@ -## this one is commonly used with AM_PATH_PYTHONDIR ... -dnl AM_CHECK_PYMOD(MODNAME [,SYMBOL [,ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]]]) -dnl Check if a module containing a given symbol is visible to python. -AC_DEFUN([AM_CHECK_PYMOD], -[AC_REQUIRE([AM_PATH_PYTHON]) -py_mod_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'` -AC_MSG_CHECKING(for ifelse([$2],[],,[$2 in ])python module $1) -AC_CACHE_VAL(py_cv_mod_$py_mod_var, [ -ifelse([$2],[], [prog=" -import sys -try: - import $1 -except ImportError: - sys.exit(1) -except: - sys.exit(0) -sys.exit(0)"], [prog=" -import $1 -$1.$2"]) -if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC - then - eval "py_cv_mod_$py_mod_var=yes" - else - eval "py_cv_mod_$py_mod_var=no" - fi -]) -py_val=`eval "echo \`echo '$py_cv_mod_'$py_mod_var\`"` -if test "x$py_val" != xno; then - AC_MSG_RESULT(yes) - ifelse([$3], [],, [$3 -])dnl -else - AC_MSG_RESULT(no) - ifelse([$4], [],, [$4 -])dnl -fi -]) - -dnl a macro to check for ability to create python extensions -dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE]) -dnl function also defines PYTHON_INCLUDES -AC_DEFUN([AM_CHECK_PYTHON_HEADERS], -[AC_REQUIRE([AM_PATH_PYTHON]) -AC_MSG_CHECKING(for headers required to compile python extensions) -dnl deduce PYTHON_INCLUDES -py_prefix=`$PYTHON -c "import sys; print sys.prefix"` -py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` -if $PYTHON-config --help 2>/dev/null; then - PYTHON_INCLUDES=`$PYTHON-config --includes 2>/dev/null` -else - PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" - if test "$py_prefix" != "$py_exec_prefix"; then - PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" - fi -fi -AC_SUBST(PYTHON_INCLUDES) -dnl check if the headers exist: -save_CPPFLAGS="$CPPFLAGS" -CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" -AC_TRY_CPP([#include ],dnl -[AC_MSG_RESULT(found) -$1],dnl -[AC_MSG_RESULT(not found) -$2]) -CPPFLAGS="$save_CPPFLAGS" -]) diff --git a/autogen.sh b/autogen.sh index 239fa5b94c..5d0da72b33 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,5 +1,10 @@ #!/bin/sh +# +# gst-rtsp-server autogen.sh +# # Run this to generate all the initial makefiles, etc. +# +# This file has been generated from common/autogen.sh.in via common/update-autogen test -n "$srcdir" || srcdir=`dirname "$0"` @@ -9,8 +14,8 @@ olddir=`pwd` cd "$srcdir" DIE=0 -package=gst-rtsp -srcfile=gst/rtsp-server/rtsp-server.c +package=gst-rtsp-server +srcfile=gst-rtsp-server.doap # Make sure we have common if test ! -f common/gst-autogen.sh; @@ -36,30 +41,29 @@ then ln -s ../../common/hooks/pre-commit.hook .git/hooks/pre-commit fi +# GNU gettext automake support doesn't get along with git. +# https://bugzilla.gnome.org/show_bug.cgi?id=661128 +if test -d po ; then + touch -t 200001010000 po/gst-rtsp-server-1.0.pot +fi + CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc' +if test "x$package" = "xgstreamer"; then + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --enable-docbook --enable-failing-tests --enable-poisoning" +fi + autogen_options $@ printf "+ check for build tools" if test ! -z "$NOCHECK"; then echo ": skipped version checks"; else echo; fi -version_check "autoconf" "$AUTOCONF autoconf autoconf270 autoconf269 autoconf268 " \ +version_check "autoreconf" "autoreconf " \ "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 68 || DIE=1 -version_check "automake" "$AUTOMAKE automake automake-1.11" \ - "ftp://ftp.gnu.org/pub/gnu/automake/" 1 11 || DIE=1 -version_check "autopoint" "autopoint" \ - "ftp://ftp.gnu.org/pub/gnu/gettext/" 0 17 || DIE=1 -version_check "libtoolize" "$LIBTOOLIZE libtoolize glibtoolize" \ - "ftp://ftp.gnu.org/pub/gnu/libtool/" 2 2 6 || DIE=1 version_check "pkg-config" "" \ "http://www.freedesktop.org/software/pkgconfig" 0 8 0 || DIE=1 die_check $DIE -aclocal_check || DIE=1 -autoheader_check || DIE=1 - -die_check $DIE - # if no arguments specified then this will be printed if test -z "$*" && test -z "$NOCONFIGURE"; then echo "+ checking for autogen.sh options" @@ -72,23 +76,14 @@ fi toplevel_check $srcfile # autopoint -#if test -d po ; then -# tool_run "$autopoint" "--force" -#fi +if test -d po ; then + tool_run "autopoint" "--force" +fi # aclocal -# if test -f acinclude.m4; then rm acinclude.m4; fi +if test -f acinclude.m4; then rm acinclude.m4; fi -tool_run "$libtoolize" "--copy --force" -tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS" -tool_run "$autoheader" - -# touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode -echo timestamp > stamp-h.in 2> /dev/null - -tool_run "$autoconf" -debug "automake: $automake" -tool_run "$automake" "--add-missing --copy" +autoreconf --force --install || exit 1 test -n "$NOCONFIGURE" && { echo "+ skipping configure stage for package $package, as requested." From de590b4b2a8aa1c9de9bf263cd63e23aca4ca0ea Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Wed, 15 Apr 2015 09:45:23 +0900 Subject: [PATCH 1116/1776] rtsp-stream: fix to get valid each stream data for request-aux-sender signal Because of duplicated g_signal_connect for request-aux-sender signal, wrong stream pointer is passed to the signal handler. Instead of passing each stream, pass stream array and get the relevant stream. https://bugzilla.gnome.org/show_bug.cgi?id=747839 --- gst/rtsp-server/rtsp-media.c | 25 +++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.c | 11 ++++------- gst/rtsp-server/rtsp-stream.h | 2 +- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 8b25e07369..344ac278de 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2440,6 +2440,25 @@ preroll_failed: } } +static GstElement * +request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + GstRTSPStream *stream = NULL; + guint i; + + g_mutex_lock (&priv->lock); + for (i = 0; i < priv->streams->len; i++) { + stream = g_ptr_array_index (priv->streams, i); + + if (sessid == gst_rtsp_stream_get_index (stream)) + break; + } + g_mutex_unlock (&priv->lock); + + return gst_rtsp_stream_request_aux_sender (stream, sessid); +} + static gboolean start_prepare (GstRTSPMedia * media) { @@ -2454,6 +2473,12 @@ start_prepare (GstRTSPMedia * media) stream = g_ptr_array_index (priv->streams, i); + if (priv->rtx_time > 0) { + /* enable retransmission by setting rtprtxsend as the "aux" element of rtpbin */ + g_signal_connect (priv->rtpbin, "request-aux-sender", + (GCallback) request_aux_sender, media); + } + if (!gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin, GST_STATE_NULL)) { goto join_bin_failed; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index dfbd4a37fb..8a4abed69f 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1817,8 +1817,8 @@ request_rtp_rtcp_decoder (GstElement * rtpbin, guint session, return gst_object_ref (priv->srtpdec); } -static GstElement * -request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPStream * stream) +GstElement * +gst_rtsp_stream_request_aux_sender (GstRTSPStream * stream, guint sessid) { GstElement *bin; GstPad *pad; @@ -1827,6 +1827,8 @@ request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPStream * stream) guint pt, rtx_pt; gchar *pt_s; + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + pt = gst_rtsp_stream_get_pt (stream); pt_s = g_strdup_printf ("%u", pt); rtx_pt = stream->priv->rtx_pt; @@ -2012,11 +2014,6 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, (GCallback) request_rtp_rtcp_decoder, stream); } - if (priv->rtx_time > 0 && priv->srcpad) { - /* enable retransmission by setting rtprtxsend as the "aux" element of rtpbin */ - g_signal_connect (rtpbin, "request-aux-sender", - (GCallback) request_aux_sender, stream); - } if (priv->sinkpad) { g_signal_connect (rtpbin, "request-pt-map", (GCallback) request_pt_map, stream); diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index d5f890cba6..49771c3afc 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -163,7 +163,7 @@ void gst_rtsp_stream_set_retransmission_pt (GstRTSPStream * s guint rtx_pt); void gst_rtsp_stream_set_pt_map (GstRTSPStream * stream, guint pt, GstCaps * caps); - +GstElement * gst_rtsp_stream_request_aux_sender (GstRTSPStream * stream, guint sessid); /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object From fabde79bc3edf9b6c47a62ae274ad84b2d444813 Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Wed, 15 Apr 2015 10:06:30 +0900 Subject: [PATCH 1117/1776] test-video-rtx: set exact payload type to PCMA payloader Setting wrong payload type causes failure to do retransmission through audio stream https://bugzilla.gnome.org/show_bug.cgi?id=747839 --- examples/test-video-rtx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/test-video-rtx.c b/examples/test-video-rtx.c index 27763c37c2..89b7778b58 100644 --- a/examples/test-video-rtx.c +++ b/examples/test-video-rtx.c @@ -64,7 +64,7 @@ main (int argc, char *argv[]) "videotestsrc ! video/x-raw,width=352,height=288,framerate=15/1 ! " "x264enc ! rtph264pay name=pay0 pt=96 " "audiotestsrc ! audio/x-raw,rate=8000 ! " - "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); + "alawenc ! rtppcmapay name=pay1 pt=8 " ")"); /* store up to 0.4 seconds of retransmission data */ gst_rtsp_media_factory_set_retransmission_time (factory, 400 * GST_MSECOND); From 1545d8fef7065081079172ec264a0061039ac075 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 20 Apr 2015 08:49:57 +0100 Subject: [PATCH 1118/1776] configure.ac: uncomment gettext version setup Fixes autogen.sh. It would run autopoint, which would complain that it could not find the gettext version in configure.ac. https://bugzilla.gnome.org/show_bug.cgi?id=748058 --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 4ac95c15b2..e7ab6ad21b 100644 --- a/configure.ac +++ b/configure.ac @@ -72,9 +72,9 @@ AC_CONFIG_MACRO_DIR([m4]) dnl set up gettext dnl the version check needs to stay here because autopoint greps for it -#AM_GNU_GETTEXT_VERSION([0.17]) -#AM_GNU_GETTEXT([external]) -#AG_GST_GETTEXT([gst-rtsp-server-$GST_API_VERSION]) +AM_GNU_GETTEXT_VERSION([0.17]) +AM_GNU_GETTEXT([external]) +AG_GST_GETTEXT([gst-rtsp-server-$GST_API_VERSION]) dnl *** check for arguments to configure *** From bdbc6f24ce08aa19c2220ba11e7970a4331c2998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 23 Apr 2015 17:22:59 +0100 Subject: [PATCH 1119/1776] configure: bump automake requirement to 1.14 and autoconf to 2.69 This is only required for builds from git, people can still build tarballs if they only have older autotools. https://bugzilla.gnome.org//show_bug.cgi?id=747624 --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index e7ab6ad21b..47c11d59f1 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_PREREQ(2.62) +AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too @@ -8,7 +8,7 @@ AC_INIT([GStreamer RTSP Server Library], [1.5.0.1], AG_GST_INIT dnl initialize automake -AM_INIT_AUTOMAKE([-Wno-portability 1.11 no-dist-gzip dist-xz tar-ustar subdir-objects]) +AM_INIT_AUTOMAKE([-Wno-portability 1.14 no-dist-gzip dist-xz tar-ustar subdir-objects]) dnl define PACKAGE_VERSION_* variables AS_VERSION From 753f8a8ac932ce117fad3e993a9998be9dac323c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 23 Apr 2015 17:27:40 +0100 Subject: [PATCH 1120/1776] tests: define GST_CHECK_TEST_ENVIRONMENT_BEACON Make sure the test environment is set up. https://bugzilla.gnome.org//show_bug.cgi?id=747624 --- tests/check/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 82e6d42081..564d9307de 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -49,9 +49,11 @@ AM_CFLAGS = -I$(top_srcdir)/gst/rtsp-server \ $(GST_CFLAGS) \ $(GST_CHECK_CFLAGS) \ -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ + -DGST_CHECK_TEST_ENVIRONMENT_BEACON="\"GST_PLUGIN_LOADING_WHITELIST\"" \ -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS AM_CXXFLAGS = $(GST_CXXFLAGS) $(GST_CHECK_CFLAGS) \ -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ + -DGST_CHECK_TEST_ENVIRONMENT_BEACON="\"GST_PLUGIN_LOADING_WHITELIST\"" \ -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS LDADD = $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la \ $(GST_PLUGINS_BASE_LIBS) -lgstrtp-@GST_API_VERSION@ \ From eb7705a48d786d55d125caa9fa024c07a19becf4 Mon Sep 17 00:00:00 2001 From: Alistair Buxton Date: Thu, 23 Apr 2015 18:53:08 +0100 Subject: [PATCH 1121/1776] Fix timeout function signatures across tests and examples --- examples/test-multicast.c | 2 +- examples/test-multicast2.c | 2 +- examples/test-sdp.c | 2 +- examples/test-video-rtx.c | 2 +- examples/test-video.c | 2 +- tests/test-cleanup.c | 2 +- tests/test-reuse.c | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/test-multicast.c b/examples/test-multicast.c index c7d55fcbb4..8ac821eb15 100644 --- a/examples/test-multicast.c +++ b/examples/test-multicast.c @@ -23,7 +23,7 @@ static gboolean -timeout (GstRTSPServer * server, gboolean ignored) +timeout (GstRTSPServer * server) { GstRTSPSessionPool *pool; diff --git a/examples/test-multicast2.c b/examples/test-multicast2.c index 1d8e6f2654..ef9e3d6cc8 100644 --- a/examples/test-multicast2.c +++ b/examples/test-multicast2.c @@ -23,7 +23,7 @@ static gboolean -timeout (GstRTSPServer * server, gboolean ignored) +timeout (GstRTSPServer * server) { GstRTSPSessionPool *pool; diff --git a/examples/test-sdp.c b/examples/test-sdp.c index 98efe9e51f..894d9bd9d3 100644 --- a/examples/test-sdp.c +++ b/examples/test-sdp.c @@ -23,7 +23,7 @@ static gboolean -timeout (GstRTSPServer * server, gboolean ignored) +timeout (GstRTSPServer * server) { GstRTSPSessionPool *pool; diff --git a/examples/test-video-rtx.c b/examples/test-video-rtx.c index 89b7778b58..5022feb067 100644 --- a/examples/test-video-rtx.c +++ b/examples/test-video-rtx.c @@ -25,7 +25,7 @@ * pool. This needs to be run explicitly currently but might be done * automatically as part of the mainloop. */ static gboolean -timeout (GstRTSPServer * server, gboolean ignored) +timeout (GstRTSPServer * server) { GstRTSPSessionPool *pool; diff --git a/examples/test-video.c b/examples/test-video.c index 0d4a3a5a7b..087da08ce2 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -33,7 +33,7 @@ * pool. This needs to be run explicitly currently but might be done * automatically as part of the mainloop. */ static gboolean -timeout (GstRTSPServer * server, gboolean ignored) +timeout (GstRTSPServer * server) { GstRTSPSessionPool *pool; diff --git a/tests/test-cleanup.c b/tests/test-cleanup.c index 3b6f7f6954..aa0d3a40ee 100644 --- a/tests/test-cleanup.c +++ b/tests/test-cleanup.c @@ -22,7 +22,7 @@ #include static gboolean -timeout (GMainLoop * loop, gboolean ignored) +timeout (GMainLoop * loop) { g_main_loop_quit (loop); return FALSE; diff --git a/tests/test-reuse.c b/tests/test-reuse.c index 67063a8675..e29f5561cc 100644 --- a/tests/test-reuse.c +++ b/tests/test-reuse.c @@ -23,14 +23,14 @@ #define TIMEOUT 2 -static gboolean timeout_1 (GMainLoop * loop, gboolean ignored); +static gboolean timeout_1 (GMainLoop * loop); static guint id; static gint rounds = 3; static GstRTSPServer *server; static gboolean -timeout_2 (GMainLoop * loop, gboolean ignored) +timeout_2 (GMainLoop * loop) { rounds--; if (rounds > 0) { @@ -44,7 +44,7 @@ timeout_2 (GMainLoop * loop, gboolean ignored) } static gboolean -timeout_1 (GMainLoop * loop, gboolean ignored) +timeout_1 (GMainLoop * loop) { g_source_remove (id); g_print ("have removed\n"); From 226fbbc8f8540ee53c29366ed70c7beb0a0d7e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 26 Apr 2015 14:58:49 +0100 Subject: [PATCH 1122/1776] Revert "configure.ac: uncomment gettext version setup" This reverts commit 1545d8fef7065081079172ec264a0061039ac075. We don't need a gettext setup here and there's no po directory either, so no reason why autopoint would be run in the first place. See https://bugzilla.gnome.org/show_bug.cgi?id=748058 --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 47c11d59f1..a0c524dd86 100644 --- a/configure.ac +++ b/configure.ac @@ -72,9 +72,9 @@ AC_CONFIG_MACRO_DIR([m4]) dnl set up gettext dnl the version check needs to stay here because autopoint greps for it -AM_GNU_GETTEXT_VERSION([0.17]) -AM_GNU_GETTEXT([external]) -AG_GST_GETTEXT([gst-rtsp-server-$GST_API_VERSION]) +#AM_GNU_GETTEXT_VERSION([0.17]) +#AM_GNU_GETTEXT([external]) +#AG_GST_GETTEXT([gst-rtsp-server-$GST_API_VERSION]) dnl *** check for arguments to configure *** From f777de7d7f33b4982bdf39db59b4680482bcea3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 26 Apr 2015 15:00:05 +0100 Subject: [PATCH 1123/1776] autogen.sh: only run autopoint if gettext requested in configure.ac Not just because there happens to be a po directory. https://bugzilla.gnome.org/show_bug.cgi?id=748058 --- autogen.sh | 27 +++++++++++++++++++-------- common | 2 +- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/autogen.sh b/autogen.sh index 5d0da72b33..265d4f5505 100755 --- a/autogen.sh +++ b/autogen.sh @@ -13,7 +13,6 @@ test -n "$srcdir" || srcdir=. olddir=`pwd` cd "$srcdir" -DIE=0 package=gst-rtsp-server srcfile=gst-rtsp-server.doap @@ -56,13 +55,25 @@ fi autogen_options $@ printf "+ check for build tools" -if test ! -z "$NOCHECK"; then echo ": skipped version checks"; else echo; fi -version_check "autoreconf" "autoreconf " \ - "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 68 || DIE=1 -version_check "pkg-config" "" \ - "http://www.freedesktop.org/software/pkgconfig" 0 8 0 || DIE=1 +if test -z "$NOCHECK"; then + echo -die_check $DIE + printf " checking for autoreconf ... " + echo + which "autoreconf" 2>/dev/null || { + echo "not found! Please install the autoconf package." + exit 1 + } + + printf " checking for pkg-config ... " + echo + which "pkg-config" 2>/dev/null || { + echo "not found! Please install pkg-config." + exit 1 + } +else + echo ": skipped version checks" +fi # if no arguments specified then this will be printed if test -z "$*" && test -z "$NOCONFIGURE"; then @@ -76,7 +87,7 @@ fi toplevel_check $srcfile # autopoint -if test -d po ; then +if test -d po && grep ^AM_GNU_GETTEXT_VERSION configure.ac >/dev/null ; then tool_run "autopoint" "--force" fi diff --git a/common b/common index c8fb372b4c..44a351788c 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit c8fb372b4c58158d6cb4e309650eb7bc369f882c +Subproject commit 44a351788c83205f179b26af04f0eeaafb3b0d95 From 4ff22ef6d25ffb989ffa57b1f199afd85572e324 Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Mon, 27 Apr 2015 19:35:53 +0900 Subject: [PATCH 1124/1776] rtsp-stream: get valid clock-rate from last-sample clock-rate in last-sample's caps is integer, not unsigned. To get this value properly, variable needs to be type-casted to int. https://bugzilla.gnome.org/show_bug.cgi?id=747614 --- gst/rtsp-server/rtsp-stream.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 8a4abed69f..339971f775 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2502,7 +2502,8 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, if (clock_rate) { GstStructure *s = gst_caps_get_structure (caps, 0); - gst_structure_get_uint (s, "clock-rate", clock_rate); + gst_structure_get_int (s, "clock-rate", (gint *) clock_rate); + if (*clock_rate == 0 && running_time) *running_time = GST_CLOCK_TIME_NONE; } From ec2c500a9dc04f76970c1753f448064de62231cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 4 May 2015 16:31:20 +0200 Subject: [PATCH 1125/1776] rtsp-sdp: Only add RTX to the SDP when using a feedback profile --- gst/rtsp-server/rtsp-sdp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 421525d9e5..393b099045 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -384,7 +384,8 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, update_sdp_from_tags (stream, smedia); - if ((rtx_time = gst_rtsp_stream_get_retransmission_time (stream))) { + if ((profile == GST_RTSP_PROFILE_AVPF || profile == GST_RTSP_PROFILE_SAVPF) + && (rtx_time = gst_rtsp_stream_get_retransmission_time (stream))) { /* ssrc multiplexed retransmit functionality */ guint rtx_pt = gst_rtsp_stream_get_retransmission_pt (stream); From e4264381a5298c4f7d47fad1f1efd680c49b052e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 4 May 2015 16:33:08 +0200 Subject: [PATCH 1126/1776] examples: Use AVPF profile for the RTX example --- examples/test-video-rtx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/test-video-rtx.c b/examples/test-video-rtx.c index 5022feb067..f804b95c68 100644 --- a/examples/test-video-rtx.c +++ b/examples/test-video-rtx.c @@ -66,6 +66,8 @@ main (int argc, char *argv[]) "audiotestsrc ! audio/x-raw,rate=8000 ! " "alawenc ! rtppcmapay name=pay1 pt=8 " ")"); + gst_rtsp_media_factory_set_profiles (factory, GST_RTSP_PROFILE_AVPF); + /* store up to 0.4 seconds of retransmission data */ gst_rtsp_media_factory_set_retransmission_time (factory, 400 * GST_MSECOND); From bbdf0a47d18338459fa66ffa9aa8ab54ed527580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 5 May 2015 16:46:19 +0200 Subject: [PATCH 1127/1776] rtsp-media: Only unblock the media in suspend() when actually changing the state Otherwise we're going to lose a few packets for live streams during DESCRIBE. --- gst/rtsp-server/rtsp-media.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 344ac278de..7aabcf9bdf 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3662,6 +3662,7 @@ default_suspend (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; GstStateChangeReturn ret; + gboolean unblock = FALSE; switch (priv->suspend_mode) { case GST_RTSP_SUSPEND_MODE_NONE: @@ -3672,6 +3673,7 @@ default_suspend (GstRTSPMedia * media) ret = set_target_state (media, GST_STATE_PAUSED, TRUE); if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; + unblock = TRUE; break; case GST_RTSP_SUSPEND_MODE_RESET: GST_DEBUG ("media %p suspend to NULL", media); @@ -3684,13 +3686,15 @@ default_suspend (GstRTSPMedia * media) * is actually from NULL to PLAY will create a new sequence * number. */ g_ptr_array_foreach (priv->streams, (GFunc) do_set_seqnum, NULL); + unblock = TRUE; break; default: break; } /* let the streams do the state changes freely, if any */ - media_streams_set_blocked (media, FALSE); + if (unblock) + media_streams_set_blocked (media, FALSE); return TRUE; From 1c30c60e64989825d5a59908bc8e474b56d946b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 5 May 2015 16:46:57 +0200 Subject: [PATCH 1128/1776] rtsp-media: Mark some more functions static --- gst/rtsp-server/rtsp-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 7aabcf9bdf..d4efd5f4ea 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3657,7 +3657,7 @@ do_set_seqnum (GstRTSPStream * stream) } /* call with state_lock */ -gboolean +static gboolean default_suspend (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; @@ -3765,7 +3765,7 @@ suspend_failed: } /* call with state_lock */ -gboolean +static gboolean default_unsuspend (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; From 87004684990154a079f7789c09f0b5712840056f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 20 May 2015 17:05:47 +0300 Subject: [PATCH 1129/1776] rtsp-server: Use single-include rtsp header to make sure we get all definitions --- gst/rtsp-server/rtsp-media.h | 3 +-- gst/rtsp-server/rtsp-stream.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 07581b59a9..ac575e58f4 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -18,8 +18,7 @@ */ #include -#include -#include +#include #include #ifndef __GST_RTSP_MEDIA_H__ diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 49771c3afc..58474fa8d5 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -18,8 +18,7 @@ */ #include -#include -#include +#include #include #ifndef __GST_RTSP_STREAM_H__ From 550348738c0e096d5d3406b89e44ad892b19878a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 27 May 2015 17:04:41 +0100 Subject: [PATCH 1130/1776] tests: Use AM_TESTS_ENVIRONMENT Needed by the new automake test runner and the current version of the common submodule. --- tests/check/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 564d9307de..026a482854 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -6,7 +6,7 @@ TEST_FILES_DIRECTORY = $(top_srcdir)/tests/files REGISTRY_ENVIRONMENT = \ GST_REGISTRY_1_0=$(CHECK_REGISTRY) -TESTS_ENVIRONMENT = \ +AM_TESTS_ENVIRONMENT = \ CK_DEFAULT_TIMEOUT=120 \ GST_STATE_IGNORE_ELEMENTS="$(STATE_IGNORE_ELEMENTS)" \ $(REGISTRY_ENVIRONMENT) \ From 08e0c79cee11daf7872828c9c60e1b78b3f7d256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Mon, 25 May 2015 16:36:18 +0200 Subject: [PATCH 1131/1776] rtsp-client: No flush during Teardown. When calling gst_rtsp_watch_write_data in gstrtspconnection.c and backlog is empty it can happen that just a part of a message will be sent and rest is in backlog queue. If then flush during teardown just a part of message will be sent.This can lead to client miss teardown response since it expect to get the last part of message. The flushing during teardown was introduced to fix a deadlock that now is fixed more generally in handle_request by temporary setting backlog size to unlimited. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=749845 --- gst/rtsp-server/rtsp-client.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index bedc4642e4..c41d019523 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -839,17 +839,8 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], 0, ctx); - /* make sure we unblock the backlog and don't accept new messages - * on the watch */ - if (priv->watch != NULL) - gst_rtsp_watch_set_flushing (priv->watch, TRUE); - gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL); - /* allow messages again so that we can send the reply */ - if (priv->watch != NULL) - gst_rtsp_watch_set_flushing (priv->watch, FALSE); - /* unmanage the media in the session, returns false if all media session * are torn down. */ keep_session = gst_rtsp_session_release_media (session, sessmedia); From e86bbbb66c83d4cb501fe8f015a78135bf2b5e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 7 Jun 2015 11:20:01 +0200 Subject: [PATCH 1132/1776] Release 1.5.1 --- ChangeLog | 918 ++++++++++++++++++++++++++++++++++++++++++- NEWS | 145 +------ RELEASE | 82 +++- configure.ac | 10 +- gst-rtsp-server.doap | 10 + 5 files changed, 997 insertions(+), 168 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9367e68d32..0c991e9e94 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,921 @@ -=== release 1.4.0 === +=== release 1.5.1 === -2014-07-19 Sebastian Dröge +2015-06-07 Sebastian Dröge * configure.ac: - releasing 1.4.0 + releasing 1.5.1 + +2015-05-25 16:36:18 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: No flush during Teardown. + When calling gst_rtsp_watch_write_data in gstrtspconnection.c and + backlog is empty it can happen that just a part of a message will be + sent and rest is in backlog queue. If then flush during teardown + just a part of message will be sent.This can lead to client miss + teardown response since it expect to get the last part of message. + The flushing during teardown was introduced to fix a deadlock that now + is fixed more generally in handle_request by temporary setting backlog + size to unlimited. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=749845 + +2015-05-27 17:04:41 +0100 Tim-Philipp Müller + + * tests/check/Makefile.am: + tests: Use AM_TESTS_ENVIRONMENT + Needed by the new automake test runner and the + current version of the common submodule. + +2015-05-20 17:05:47 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-stream.h: + rtsp-server: Use single-include rtsp header to make sure we get all definitions + +2015-05-05 16:46:57 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Mark some more functions static + +2015-05-05 16:46:19 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Only unblock the media in suspend() when actually changing the state + Otherwise we're going to lose a few packets for live streams during DESCRIBE. + +2015-05-04 16:33:08 +0200 Sebastian Dröge + + * examples/test-video-rtx.c: + examples: Use AVPF profile for the RTX example + +2015-05-04 16:31:20 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-sdp.c: + rtsp-sdp: Only add RTX to the SDP when using a feedback profile + +2015-04-27 19:35:53 +0900 Hyunjun Ko + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: get valid clock-rate from last-sample + clock-rate in last-sample's caps is integer, not unsigned. + To get this value properly, variable needs to be type-casted to int. + https://bugzilla.gnome.org/show_bug.cgi?id=747614 + +2015-04-26 15:00:05 +0100 Tim-Philipp Müller + + * autogen.sh: + * common: + autogen.sh: only run autopoint if gettext requested in configure.ac + Not just because there happens to be a po directory. + https://bugzilla.gnome.org/show_bug.cgi?id=748058 + +2015-04-26 14:58:49 +0100 Tim-Philipp Müller + + * configure.ac: + Revert "configure.ac: uncomment gettext version setup" + This reverts commit 1545d8fef7065081079172ec264a0061039ac075. + We don't need a gettext setup here and there's no po + directory either, so no reason why autopoint would be + run in the first place. + See https://bugzilla.gnome.org/show_bug.cgi?id=748058 + +2015-04-23 18:53:08 +0100 Alistair Buxton + + * examples/test-multicast.c: + * examples/test-multicast2.c: + * examples/test-sdp.c: + * examples/test-video-rtx.c: + * examples/test-video.c: + * tests/test-cleanup.c: + * tests/test-reuse.c: + Fix timeout function signatures across tests and examples + +2015-04-23 17:27:40 +0100 Tim-Philipp Müller + + * tests/check/Makefile.am: + tests: define GST_CHECK_TEST_ENVIRONMENT_BEACON + Make sure the test environment is set up. + https://bugzilla.gnome.org//show_bug.cgi?id=747624 + +2015-04-23 17:22:59 +0100 Tim-Philipp Müller + + * configure.ac: + configure: bump automake requirement to 1.14 and autoconf to 2.69 + This is only required for builds from git, people can still + build tarballs if they only have older autotools. + https://bugzilla.gnome.org//show_bug.cgi?id=747624 + +2015-04-20 08:49:57 +0100 Vincent Penquerc'h + + * configure.ac: + configure.ac: uncomment gettext version setup + Fixes autogen.sh. It would run autopoint, which would complain + that it could not find the gettext version in configure.ac. + https://bugzilla.gnome.org/show_bug.cgi?id=748058 + +2015-04-15 10:06:30 +0900 Hyunjun Ko + + * examples/test-video-rtx.c: + test-video-rtx: set exact payload type to PCMA payloader + Setting wrong payload type causes failure to do retransmission through audio stream + https://bugzilla.gnome.org/show_bug.cgi?id=747839 + +2015-04-15 09:45:23 +0900 Hyunjun Ko + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-stream: fix to get valid each stream data for request-aux-sender signal + Because of duplicated g_signal_connect for request-aux-sender signal, + wrong stream pointer is passed to the signal handler. + Instead of passing each stream, pass stream array and get the relevant stream. + https://bugzilla.gnome.org/show_bug.cgi?id=747839 + +2015-04-06 10:32:52 +0100 Tim-Philipp Müller + + * acinclude.m4: + * autogen.sh: + Update autogen.sh to latest version from common + Fixes build after aclocal_check etc. helpers have been removed. + +2015-04-03 18:58:26 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From bc76a8b to c8fb372 + +2015-03-23 21:03:20 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Limit the queues to 1 buffer + We only need them to be able to pre-roll, queueing up more data here + is only going to harm latency and memory usage. + +2015-03-23 20:59:52 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Update comment and ASCII art to the latest code + We have a queue in front of the udpsink too to prevent the pipeline from + locking up. + +2015-03-21 11:04:05 -0400 Nicolas Dufresne + + * gst/rtsp-server/rtsp-stream.c: + rtsp-media: Properly return first rtptime + Instead we where returning first GstBuffer timestamp. This would result + in clock skew and unwanted behaviour in RTSP playback. + https://bugzilla.gnome.org/show_bug.cgi?id=746479 + +2015-03-18 16:44:19 -0400 Nicolas Dufresne + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Don't leave buffer mapped + If the seq is NULL, the RTP buffer was left mapped. We should always + unmap the buffer. + +2015-03-15 12:27:39 +0000 Sebastian Dröge + + * README: + Fix typo in README + +2015-03-10 09:39:22 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-media-factory.c: + * tests/check/gst/client.c: + Fix double semicolons + +2015-03-09 16:00:07 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Get the seqnum-base and other information from the last buffer in the sink + This gives more accurate values than asking the payloader. There might be + queueing happening between the payloader and the sink. + https://bugzilla.gnome.org/show_bug.cgi?id=745704 + +2015-03-09 13:00:25 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Don't seek for PLAY if the position will not change + https://bugzilla.gnome.org/show_bug.cgi?id=745704 + +2015-03-09 10:21:49 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Don't include payload type in the caps for framesize + When the sdp media attribute framesize are converted to caps + the should not be included. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725335 + Based on the patch for rtspsrc by Linus Svensson + +2014-02-26 22:34:06 +0100 Linus Svensson + + * gst/rtsp-server/rtsp-sdp.c: + rtsp-sdp: add payload type to the sdp framesize attribute + The sdp framesize attribute is desribed in RFC6064. It is specified + for payloading of H263 and has the following form + a=framesize: -. The - part + should be added to the caps in a payloader and the should + be added by the rtsp-server. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725334 + +2015-03-03 13:51:01 +0000 Luis de Bethencourt + + * examples/test-uri.c: + examples: test-uri: fix tainted variable + Insignificant but this keeps Coverity happy. + CID #1268404 + +2015-03-03 01:49:42 +1100 Jan Schmidt + + * examples/.gitignore: + * examples/Makefile.am: + * examples/test-netclock-client.c: + * examples/test-netclock.c: + examples: Add a simple example of network synch for live streams. + An example server and client that works for synchronising live streams + only - as it can't support pause/play. + +2015-03-03 01:49:42 +1100 Jan Schmidt + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + rtsp-media-factory: Add functions to set/get the media gtype + Allow specifying the GType of a GstRtspMedia subclass to create + as a simpler way to get the factory to create a custom + GstRtspMedia sub-class, without subclassing GstRtspMediaFactory. + +2015-02-27 17:45:42 +0100 Gregor Boirie + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: fix double unlock in _get_buffer_size() + Fixes an abort when calling gst_rtsp_media_get_buffer_size() + because of double g_mutex_unlock () usage. + https://bugzilla.gnome.org/show_bug.cgi?id=745434 + +2015-02-19 10:43:16 +0200 Kent-Inge Ingesson + + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + rtsp-session: Use monotonic time for RTSP session timeout + Changed RTSP session timeout handling to monotonic time + and deprecating the API for current system time. + This fixes timeouts when the system time changes. + https://bugzilla.gnome.org/show_bug.cgi?id=743346 + +2015-02-13 12:21:16 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + rtsp-client: Only error out in PLAY if seeking actually failed + If the media was just not seekable, we continue from whatever position we are + and let the client decide if that is what is wanted or not. + Only if the actual seek failed, we can't really recover and should error out. + +2015-02-12 10:46:28 +0100 Andreas Frisch + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Add necessary queues between tee and multiudpsink + https://bugzilla.gnome.org/show_bug.cgi?id=744379 + +2015-02-12 16:48:46 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + rtsp-media: If seeking fails, don't wait forever for the media to preroll again + Instead error out properly the same way as if the SEEKING query already + failed. + +2015-02-11 17:24:38 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-stream.h: + rtsp-stream: minor code formatting fix + +2015-02-10 16:39:58 +0000 Luis de Bethencourt + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: fix logic for collect_streams + Fix the logic of gst_rtsp_media_collect_streams() so after looping collecting + all streams it knows if it got any, and can check if the transport mode is OK. + CID #1268400 + +2015-02-09 10:21:50 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Don't set the transport mode based on what elements we find + Just print a warning if the one that was set before disagrees with what + elements we found. It must already be set to something before as this + function is called after we received the SDP from ANNOUNCE in RECORD mode, + and we would reject ANNOUNCE if the RECORD flag was not set. + +2015-02-08 18:05:50 +0000 Tim-Philipp Müller + + * tests/check/gst/rtspserver.c: + tests: rtspserver: rename shadowed variable + We have two different 'sink' variables here, + rename one of them for clarity. + +2015-02-08 12:08:36 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: fix awkward if clause + +2015-02-06 19:34:17 +0000 Tim-Philipp Müller + + * examples/test-uri.c: + examples: test-uri: improve uri argument handling and accept file names + Print an error if the argument passed is not a URI and can't + be converted into one, or no arguments have been provided. + +2015-02-06 19:15:40 +0000 Tim-Philipp Müller + + * examples/test-uri.c: + examples: test-uri: don't remove mount point after 10 seconds + It's very irritating when trying to test stuff repeatedly + and serves no real purpose other than showing that it can + be done. + +2015-01-21 17:32:21 +0000 Tim-Philipp Müller + + * examples/.gitignore: + examples: add new test-record to .gitignore + +2015-01-28 18:54:01 +0100 Sebastian Dröge + + * examples/test-record.c: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * tests/check/gst/rtspserver.c: + rtsp-media: Use flags to distinguish between PLAY and RECORD media + +2015-01-28 17:49:16 +0100 Sebastian Dröge + + * examples/test-record.c: + test-record: Set latency for playback-style example to 2s instead of 200ms + +2015-01-21 17:27:56 +0000 Tim-Philipp Müller + + * tests/check/gst/rtspserver.c: + tests: add some unit tests for ANNOUNCE and RECORD + https://bugzilla.gnome.org/show_bug.cgi?id=743175 + +2015-01-21 16:32:44 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: fix a couple of leaks in handle_announce + +2015-01-19 13:20:39 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + rtsp-media: Expose latency setting for setting the rtpbin latency + +2015-01-17 10:28:13 +0100 Sebastian Dröge + + * examples/test-record.c: + test-record: Use GOptionContext to parse the server port and take the pipeline from the commandline + +2015-01-16 20:48:42 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Put the timestamp of receival of the initial packet over TCP on the first buffer + +2015-01-09 12:40:47 +0100 Sebastian Dröge + + * examples/Makefile.am: + * examples/test-record.c: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + Add initial support for RECORD + We currently only support media that is RECORD or PLAY only, not both at once. + https://bugzilla.gnome.org/show_bug.cgi?id=743175 + +2015-01-30 12:50:20 +0100 Anila Balavan + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: RTCP and RTP transport cache cookies seperated + RTCP packets were not sent because the same tr_cache_cookie was used for + both RTP and RTCP. So only one of the tr_cache lists were populated + depending on which one was sent first. If the tr_cache list is not + populated then no packets can be sent. Most often this happened to be + RTCP. Now seperate RTCP and RTP transport cache cookies are added which + resulted in both the tr_cache_lists to be populated regardless of which + one was sent first. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=743734 + +2015-01-21 14:57:03 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: fix false compiler warning + rtsp-stream.c:3034: error: ‘visited’ may be used uninitialized in this function + +2015-01-19 20:35:15 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: log interleaved data received + +2015-01-19 20:18:20 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: fix unintentional fallthrough to debug warning when receiving interleaved data + +2015-01-19 13:09:20 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: If we have a single-stream media and SETUP contains no control, use the one and only stream + +2015-01-18 19:08:36 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Use a random session ID in the SDP + RFC4566 Section 5.2 says that it should make the username, session id, + nettype, addrtype and unicast address tuple globally unique. Always using + 1188340656180883 is not going to guarantee that: https://xkcd.com/221/ + Instead let's create a 64 bit random number, which at least brings us + closer to the goal of global uniqueness. + https://tools.ietf.org/html/rfc4566#section-5.2 + +2015-01-17 10:29:36 +0100 Sebastian Dröge + + * examples/test-launch.c: + * examples/test-mp4.c: + * examples/test-ogg.c: + * examples/test-uri.c: + examples: Don't call gst_init() and gst_get_option_group() + The latter calls the former at the appropriate time. + +2015-01-16 20:04:01 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Drop trailing \0 of RTSP DATA messages + We add a trailing \0 in GstRTSPConnection to make parsing of + string message bodies easier (e.g. the SDP from DESCRIBE) but + for actual data this means we have to drop it or otherwise + create invalid data. + +2015-01-16 11:10:20 +0100 Göran Jönsson + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Have one copy of the transports cache for RTP and RTCP each + Fixes crash when two threads access handle_new_sample() at the same + time, one for RTP, one for RTCP. + Otherwise, when iterating over the transports cache, it might be modified by + another thread at the same time if the transports cookie has changed. + https://bugzilla.gnome.org/show_bug.cgi?id=742954 + +2015-01-15 19:34:20 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Set format=TIME on our app sources for TCP + +2015-01-13 15:29:29 +0100 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-session-pool.c: + Revert "rtsp-session-pool: Make sure session IDs are properly URI-escaped" + This reverts commit 935e8f852d050b4939f1d0f44b38e9b55a2fbe36. + RFC 2326 states that session IDs may consist of alphanumeric as well as + the safe characters $-_.+ -- N.B. the percent character is not allowed. + Previously the session ID was URI-escaped, this meant that any character + which was not alphanumeric or any of the characters +-._~ would be + percent encoded. While the RFC (surprisingly) mentions that linear white + space in session IDs should be URI-escaped, it does not say anything + about other characters. Moreover no white space is allowed in the + session ID. Finally the percent character which is the result of + URI-escaping is not allowed in a session ID. + So there is no reason to do any URI-escaping, and now it is removed. + https://bugzilla.gnome.org/show_bug.cgi?id=742869 + +2015-01-12 16:14:12 +0100 Stefan Sauer + + * common: + Automatic update of common submodule + From f2c6b95 to bc76a8b + +2014-12-31 13:04:57 +0000 Tim-Philipp Müller + + * Makefile.am: + Fix 'make check' from top-level directory + +2014-12-30 18:13:49 +0530 Nirbheek Chauhan + + * examples/test-launch.c: + * examples/test-mp4.c: + * examples/test-ogg.c: + * examples/test-uri.c: + examples: Add command-line parsing and take a 'port' argument + This allows users to run multiple servers on different ports for testing. + Only done for examples that actually take arguments and hence are capable of + outputting different streams for each instance on each port. + https://bugzilla.gnome.org/show_bug.cgi?id=742115 + +2014-12-29 12:06:50 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + rtsp-client: Add a send_message default signal handler + This allows subclasses to easily hook into the response sending + mechanism without doing everything from a signal, which seems + awkward from subclasses. + +2014-12-18 10:56:44 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From ef1ffdc to f2c6b95 + +2014-12-17 20:02:05 +0100 Sebastian Rasmussen + + * Makefile.am: + * configure.ac: + configure: add --disable-examples switch + https://bugzilla.gnome.org/show_bug.cgi?id=741678 + +2014-12-01 23:42:34 +1100 Matthew Waters + + * examples/.gitignore: + * examples/Makefile.am: + * examples/test-video-rtx.c: + examples: add a retransmisison example implementing RFC4588 + Currently only SSRC-multiplexed rtx streams are supported + +2014-12-16 16:46:15 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Fix some minor memory leaks + +2014-12-16 16:46:06 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Some minor cleanup + +2014-12-16 16:42:13 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Fix compiler warnings + rtsp-stream.c:1351:3: error: non-void function 'gst_rtsp_stream_get_retransmission_time' should return a value [-Wreturn-type] + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + ^ + rtsp-stream.c:1384:3: error: non-void function 'gst_rtsp_stream_get_retransmission_pt' should return a value [-Wreturn-type] + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + ^ + +2014-11-27 01:12:36 +1100 Matthew Waters + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + media: implement ssrc-multiplexed retransmission support + based off RFC 4588 and the server-rtpaux example in -good + +2014-11-28 12:45:14 +0100 Göran Jönsson + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp: Ref transports in hash table. + Also ref streams for transports. + This solves a crash when reciving a rtcp after teardown but before + client finalize. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=740845 + +2014-11-27 17:13:05 +0100 Edward Hervey + + * common: + Automatic update of common submodule + From 7bb2bce to ef1ffdc + +2014-11-07 12:48:53 +0100 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: refactor cleanup of cached media + +2014-10-23 13:39:10 +0200 Linus Svensson + + * tests/check/gst/client.c: + tests: Remove FIXME + The session leak is now fixed, lets remove those FIXME comments. + +2014-10-23 17:54:37 +0200 Linus Svensson + + * tests/check/gst/rtspserver.c: + tests: Test to setup two sessions on one connection + https://bugzilla.gnome.org/show_bug.cgi?id=739112 + +2014-10-24 12:05:27 +0200 Linus Svensson + + * tests/check/gst/rtspserver.c: + tests: Test setup with tcp transport + https://bugzilla.gnome.org/show_bug.cgi?id=739112 + +2014-10-24 12:04:54 +0200 Linus Svensson + + * gst/rtsp-server/rtsp-client.c: + client: Configure transport after creating session media + The default implementation of configure_client_transport() in + rtsp-client uses the session media when it chooses channels for + interleaved traffic. + https://bugzilla.gnome.org/show_bug.cgi?id=739112 + +2014-10-23 12:54:03 +0200 Linus Svensson + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-session-media.c: + client: Stop caching media in client when doing setup + If the media has been managed by a session media, it should not be + cached in the client any longer. The GstRTSPSessionMedia object is now + responsible for unpreparing the GstRTSPMedia object using + gst_rtsp_media_unprepare(). Unprepare the media when finalizing the + session media. + https://bugzilla.gnome.org/show_bug.cgi?id=739112 + +2014-10-31 23:01:53 -0700 Aleix Conchillo Flaqué + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: unref srtp decoder when leaving bin + https://bugzilla.gnome.org/show_bug.cgi?id=739481 + +2014-10-29 21:01:39 -0700 Aleix Conchillo Flaqué + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: mikey memory leaks + https://bugzilla.gnome.org/show_bug.cgi?id=739383 + +2014-10-27 18:01:35 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From 84d06cd to 7bb2bce + +2014-10-24 17:48:04 +0100 Tim-Philipp Müller + + * Makefile.am: + Parallelise 'make check-valgrind' + +2014-10-21 13:04:14 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From a8c8939 to 84d06cd + +2014-10-21 13:00:49 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From 36388a1 to a8c8939 + +2014-10-01 07:12:30 -0400 Vincent Penquerc'h + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: deactivate media when shutting down from paused + This was only done when going directly from playing. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=737829 + +2014-10-20 15:40:59 -0700 Aleix Conchillo Flaqué + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-context.h: + rtsp-client: add stream transport to context + We add the stream transport to the context so we can get the configured + client stream transport in the setup request signal. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=738905 + +2014-10-02 12:02:48 -0700 Aleix Conchillo Flaqué + + * gst/rtsp-server/rtsp-stream.c: + stream: release lock even not all transports have been removed + We don't want to keep the lock even we return FALSE because not all the + transports have been removed. This could lead into a deadlock. + https://bugzilla.gnome.org/show_bug.cgi?id=737797 + +2014-10-10 18:43:00 -0400 Olivier Crête + + * gst/rtsp-server/rtsp-sdp.c: + rtsp-sdp: Rename clock-base and seqnum-base to timestamp-offset and seqnum-offset + These were renamed in GstRTPBasePayload in 1.0 + +2014-09-30 16:36:51 -0700 Aleix Conchillo Flaqué + + * gst/rtsp-server/rtsp-client.c: + client: set session media to NULL without the lock + We need to set session medias to NULL without the client lock otherwise + we can end up in a deadlock if another thread is waiting for the lock + and media unprepare is also waiting for that thread to end. + https://bugzilla.gnome.org/show_bug.cgi?id=737690 + +2014-09-30 23:22:45 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Set state to UNPREPARING in all cases + +2014-09-30 19:17:04 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + media: set state to unpreparing when unprepare is initiated + https://bugzilla.gnome.org/show_bug.cgi?id=737675 + +2014-09-30 01:35:02 +0200 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Remove backlog limit while processings requests + If the backlog limit is kept two cases of deadlocks may be + encountered when streaming over TCP. Without the backlog + limit this deadlocks can not happen, at the expence of + memory usage. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=737631 + +2014-09-22 13:32:06 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: do not free main context before rtsp watch + https://bugzilla.gnome.org/show_bug.cgi?id=737110 + +2014-09-19 18:29:00 +0200 Branko Subasic + + * tests/check/gst/rtspserver.c: + tests: Extend unit test timeout to accomodate for valgrind + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=736647 + +2014-09-19 18:28:50 +0200 Branko Subasic + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-stream-transport.c: + rtsp-*: Treat sending packets to clients as keepalive + As long as gst-rtsp-server can successfully send RTP/RTCP data to + clients then the client must be reading. This change makes the server + timeout the connection if the client stops reading. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=736647 + +2014-09-19 18:28:30 +0200 Branko Subasic + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Allow backlog to grow while expiring session + Allow the send backlog in the RTSP watch to grow to unlimited size while + attempting to bring the media pipeline to NULL due to a session + expiring. Without this change the appsink element cannot change state + because it is blocked while rendering data in the new_sample callback. + This callback will block until it has successfully put the data into the + send backlog. There is a chance that the send backlog is full at this + point which means that the callback may block for a long time, possibly + forever. Therefore the media pipeline may also be prevented from + changing state for a long time. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=736647 + +2014-09-22 09:30:39 +0200 Edward Hervey + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Make old compilers happy + rtsp-client.c:2553:50: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] + Just in case that guint8 doesn't fit in a pointer. Just in case ... + +2014-09-16 11:41:52 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-client.c: + client: raise the backlog limits before pausing + We need to raise the backlog limits before pausing the pipeline or else + the appsink might be blocking in the render method in wait_backlog() and + we would deadlock waiting for paused. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=736322 + +2014-09-16 11:29:38 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-client.c: + client: make define for the WATCH_BACKLOG + See https://bugzilla.gnome.org/show_bug.cgi?id=736322 + +2014-09-09 18:11:39 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-client.c: + client: simplify session transport handling + link/unlink of the transport in a session was done to keep track of all + TCP transports and to send RTP/RTCP data to the streams. We can simplify + that by putting all the TCP transports in a hashtable indexed with the + channel number. + We also don't need to link/unlink the transports when we pause/resume + the streams. The same effect is already achieved when we pause/play the + media. Indeed, when we pause the media, the transport is removed from + the media and the callbacks will not be called anymore. + See https://bugzilla.gnome.org/show_bug.cgi?id=736041 + +2014-09-09 18:10:12 +0200 Wim Taymans + + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + stream-transport: make method to handle received data + Make a method to handle the data received on a channel. It sends the + data to the stream of the transport on the RTP or RTCP pads based on + the channel number. + +2014-09-15 16:54:05 +0200 Wim Taymans + + * examples/test-mp4.c: + test: add example of dumping RTCP reports + +2014-09-08 09:26:23 +0200 Srimanta Panda + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-media: Make sure that sequence numbers are monotonic after pause + The sequence number is not monotonic for RTP packets after pause. The + reason is basepayloader generates a randon sequence number when the + pipeline goes from ready to pause. With this fix generation of sequence + number will be monotonic when going from pause to play request. + https://bugzilla.gnome.org/show_bug.cgi?id=736017 + +2014-08-28 13:35:15 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Protect saved clients watch with a mutex + Fixes a crash when close() is called while merging clients + in handle_tunnel(). In that case close() would destroy the + watch while it is still being used in handle_tunnel(). + https://bugzilla.gnome.org/show_bug.cgi?id=735570 + +2014-08-13 17:22:16 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Remove the multicast group udp sources when removing from the bin + +2014-08-05 16:12:19 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-media: Query position and stop time only on the RTP parts of the pipeline + The RTCP parts, in specific the RTCP udpsinks, are not flushed when + seeking and will always continue counting the time. This leads to + the NPT after a backwards seek to be something completely different + to the actual seek position. + https://bugzilla.gnome.org/show_bug.cgi?id=732644 + +2014-08-09 14:41:35 +0100 Tim-Philipp Müller + + * examples/test-appsrc.c: + examples: fix another reference leak + gst_rtsp_media_get_element() returns a new ref. + +2014-07-17 01:34:17 +0200 Sebastian Rasmussen + + * examples/test-appsrc.c: + examples: unref element after usage + gst_bin_get_by_name_recurse_up() returns an element + reference that must be unreffed after usage. + https://bugzilla.gnome.org/show_bug.cgi?id=734546 + +2014-07-02 22:45:07 +0530 Arun Raghavan + + * gst/rtsp-server/rtsp-media.c: + signals: Fix copy-pasto in target-state signal offset + +2014-08-01 10:46:44 +0200 Edward Hervey + + * Makefile.am: + * common: + Makefile: Add usage of build-checks step + Allows building checks without running them + +2014-06-25 18:23:10 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Listen on the multicast group for RTP/RTCP packets + When a UDP multicast transport is used it is expected that the server listens + for RTP and RTCP packets on the multicast group with the corresponding port. + Without this we will never get RTCP packets from clients in multicast mode. + https://bugzilla.gnome.org/show_bug.cgi?id=732238 + +2014-07-19 18:04:52 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.4.0 === + +2014-07-19 17:56:31 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.4.0 2014-07-16 20:39:42 +0900 Hyunjun Ko diff --git a/NEWS b/NEWS index 1280881ba2..6a3a6b771e 100644 --- a/NEWS +++ b/NEWS @@ -1,145 +1,2 @@ -This is GStreamer RTSP Server 1.4.0 +This is GStreamer RTSP Server 1.5.1 -Changes since 1.2: - -New API: - • GstMessageType has GST_MESSAGE_EXTENDED added. All types before - that can be used together as a flags type as before, but from - that message onwards the types are just counted incrementally. - This was necessary to be able to add more message types. - In 2.0 GstMessageType will just become an enum and not a flags - type anymore. - • GstDeviceMonitor for device probing, e.g. to list all available - audio or video capture devices. This is the replacement for - GstPropertyProbe from 0.10. - • Events accumulate the running-time offset now when travelling - through pads, as set by the gst_pad_set_offset() function. This - allows to compensate for this in the QOS event for example. - • GstBuffer has a new flag "tag-memory" that is set automatically - when memory is added or removed to a buffer. This allows buffer - pools to detect if they can recycle a buffer or need to reset - it first. - • GstToc has new API to mark GstTocEntries as loops. - • A not-authorized resource error has been defined to notify - applications that accessing the resource has failed because - of missing authorization and to distinguish this case from others. - This change is actually already in 1.2.4. - • GstPad has a new flag "accept-intersect", that will let the default - ACCEPT_CAPS query handler do an intersection instead of subset check. - This is interesting for parser elements that can handle incomplete - caps. - • GstCollectPads has support for flushing and a default handler for - SEEK events now. - • New GstFlowAggregator helper object that simplifies handling of - flow returns in elements with multiple source pads. Additionally - GstPad now always stores the last flow return and provides an - API to retrieve it. - • GstSegment has new API to offset the running time by a specific - value and this is used in GstPad to allow positive and negative - offsets in gst_pad_set_offset() in all situations. - • Support for h265/HEVC and VP8 has been added to the codec utils and codec - parsers library, and was integrated into various elements. - • API for adjusting the TLS validation of RTSP connection has been added. - • The RTSP and SDP library has MIKEY (RFC 3830) support now, and - there is API to distinguish between the different RTSP profiles. - • API to access RTP time information and statistics. - • Support for auxiliary streams was added to rtpbin. - • Support for tiled, raw video formats has been added. - • GstVideoDecoder and GstAudioDecoder have API to help aggregating tag - events and merge custom tags into them consistently. - • GstBufferPool has support for flushing now. - • playbin/playsink has support for application provided audio and video - filters. - • GstDiscoverer has new and simplified API to get details about missing - plugins and information to pass to the plugin installer. - • The GL library was merged from gst-plugins-gl to gst-plugins-bad, - providing a generic infrastructure for handling GL inside GStreamer - pipelines and a plugin with some elements using these, especially - a video sink. Supported platforms currently are Android, Cocoa (OS X), - DispManX (Raspberry Pi), EAGL (iOS), WGL (Windows) and generic X11, - Wayland and EGL platforms. - This replaces eglglessink and also is supposed to replace osxvideosink. - • New GstAggregator base class in gst-plugins-bad. This is supposed to - replace GstCollectPads in the future and fix long-known shortcomings - in its API. Together with the base class some elements are provided - already, like a videomixer (compositor). - - -Major changes: - • New plugins and elements: - ∘ v4l2videodec element for accessing hardware codecs on - platforms that make them accessible via V4L2, e.g. - Samsung Exynos. This comes together with major refactoring - of the existing V4L2 elements and the corresponding - infrastructure. - The v4l2videodec element replaces the mfcdec element. - ∘ New downloadbuffer element that replaces the download - buffering feature of queue2. Compared to queue2's code - it is much simpler and only for this single use case. - A noteworthy new feature is that it's downloading gaps - in the already downloaded stream parts when nothing else - is to be downloaded. - This is now used by playbin when download buffering is - enabled. - ∘ rtpstreampay and rtpstreamdepay elements for transmitting - RTP packets over a stream API (e.g. TCP) according to - RFC 4571. - ∘ rtprtx elements for standard compliant implementation of - retransmissions, integrated into the rtpmanager plugin. - ∘ audiomixer element that mixes multiple audio streams together - into a single one while keeping synchronization. This is - planned to become the replacement of the adder element. - ∘ OpenNI2 plugin for 3D cameras like the Kinect camera. - ∘ OpenEXR plugin for decoding high-dynamic-range EXR images. - ∘ curlsshsink and curlsftpsink to write files via SSH/SFTP. - ∘ videosignal, ivfparse and sndfile plugins ported from 0.10. - ∘ avfvideosrc, vtdec and other elements were ported from 0.10 and - are available on OS X and iOS now. - - • Other changes: - ∘ gst-libav now uses libav 10.2, and gained support for H265/HEVC. - ∘ Support for hardware codecs and special memory types has been - improved with bugfixes and feature additions in various plugins - and base classes. - ∘ Various bugfixes and improvements to buffering in queue2 and - multiqueue elements. - ∘ dvbsrc supports more delivery mechanisms and other features - now, including DVB S2 and T2 support. - ∘ The MPEGTS library has support for many more descriptors. - ∘ Major improvements to tsdemux and tsparse, especially time and - seeking related. - ∘ souphttpsrc now has support for keep-alive connections, - compression, configurable number of retries and configuration - for SSL certificate validation. - ∘ hlsdemux has undergone major refactoring and works more - reliable now and supports more HLS features like trick modes. - Also fragments are pushed downstream while they're downloaded - now instead of waiting for each fragment to finish. - ∘ dashdemux and mssdemux are now also pushing fragments downstream - while they're downloaded instead of waiting for each fragment to - finish. - ∘ videoflip can automatically flip based on the orientation tag. - ∘ openjpeg supports the OpenJPEG2 API. - ∘ waylandsink was refactored and should be more useful now. It also - includes a small library which most likely is going to be removed - in the future and will result in extensions to the GstVideoOverlay - interface. - ∘ gst-rtsp-server supports SRTP and MIKEY now. - ∘ gst-libav encoders are now negotiating any profile/level settings - with downstream via caps. - ∘ Lots of fixes for coverity warnings all over the place. - ∘ Negotiation related performance improvements. - ∘ 800+ fixed bug reports, and many other bug fixes and other - improvements everywhere that had no bug report. - -Things to look out for: - • The eglglessink element was removed and replaced by the glimagesink - element. - • The mfcdec element was removed and replaced by v4l2videodec. - • osxvideosink is only available in OS X 10.6 or newer. - • On Android the namespace of the automatically generated Java class - for initialization of GStreamer has changed from com.gstreamer to - org.freedesktop.gstreamer to prevent namespace pollution. - • On iOS you have to update your gst_ios_init.h and gst_ios_init.m in - your projects from the one included in the binaries if you used the - GnuTLS GIO module before. The loading mechanism has slightly changed. diff --git a/RELEASE b/RELEASE index bcd3f9d586..5b649a2f5f 100644 --- a/RELEASE +++ b/RELEASE @@ -1,30 +1,53 @@ -Release notes for GStreamer RTSP Server Library 1.4.0 +Release notes for GStreamer RTSP Server Library 1.5.1 -The GStreamer team is pleased to announce the first release of -the stable 1.4 release series. The 1.4 release series is adding new -features on top of the 1.0 and 1.2 series and is part of the API and -ABI-stable 1.x release series of the GStreamer multimedia framework. +The GStreamer team is pleased to announce the first release of the unstable +1.5 release series. The 1.5 release series is adding new features on top of +the 1.0, 1.2 and 1.4 series and is part of the API and ABI-stable 1.x release +series of the GStreamer multimedia framework. The unstable 1.5 release series +will lead to the stable 1.6 release series in the next weeks, and newly added +API can still change until that point. - -Binaries for Android, iOS, Mac OS X and Windows are provided together -with this release. - - - -The stable 1.4 release series is API and ABI compatible with 1.0.x, -1.2.x and any other 1.x release series in the future. Compared to 1.2.x -it contains some new features and more intrusive changes that were -considered too risky as a bugfix. +Binaries for Android, iOS, Mac OS X and Windows will be provided separately +during the unstable 1.5 release series. +Features of this release + + Bugs fixed in this release - * 733244 : Correct misspelled words + * 732238 : Listen on the multicast group for RTP/RTCP packets + * 734546 : tests: Unref element after usage + * 736041 : Protect rtsp transport data. + * 736647 : Tunneled RTSP sessions do not always timeout as expected + * 737110 : rtsp-client: race condition when closing client connection + * 737631 : gst-rtsp-server deadlock while sending response over TCP + * 737675 : media: media_unprepare() is kind of broken + * 737690 : rtsp-client: deadlock when setting session medias to NULL + * 737797 : rtsp-stream: lock not released when leaving bin and transports not removed + * 737829 : rtsp-server: deactivate media when shutting down from paused + * 738905 : rtsp-client: add stream transport to the context + * 739112 : rtsp-client: Can not allocate ports for interleaved traffic in setup + * 740752 : add retransmission support + * 740845 : crash when reciving a rtcp after teardown but before client finalize. + * 741678 : configure: add --disable-examples switch + * 742115 : Examples: Accept a 'port' argument for running multiple instances + * 742869 : Remove URI-escaping of RTSP session-id + * 742954 : Crash when two treads are in handle_new_sample at the same time. + * 743175 : Add support for RECORD + * 743346 : When system time is increased the ongoing RTSP sessions will time out. + * 743734 : RTCP packets not sent + * 744379 : gst-rtsp-server does not preroll when piping data into the media-pipeline + * 745704 : Losing the first packet + * 747614 : gst-rtsp-server: uninitialized clock rate causes critical warning + * 747839 : gst-rtsp-server: doesn't perform retransmission to both streams in test-video-rtx + * 748058 : autogen.sh fails due to autopoint erroring out due to missing gettext version in configure.ac + * 749845 : Client have problem to find the teardown response. ==== Download ==== @@ -59,7 +82,34 @@ Interested developers of the core library, plugins, and applications should subscribe to the gstreamer-devel list. +Applications + Contributors to this release + * Aleix Conchillo Flaqué + * Alistair Buxton + * Andreas Frisch + * Anila Balavan + * Arun Raghavan + * Branko Subasic + * Edward Hervey + * Gregor Boirie + * Göran Jönsson * Hyunjun Ko + * Jan Schmidt + * Kent-Inge Ingesson + * Linus Svensson + * Luis de Bethencourt + * Matthew Waters + * Nicolas Dufresne + * Nirbheek Chauhan + * Ognyan Tonchev + * Olivier Crête + * Sebastian Dröge + * Sebastian Rasmussen + * Srimanta Panda + * Stefan Sauer + * Tim-Philipp Müller + * Vincent Penquerc'h + * Wim Taymans   \ No newline at end of file diff --git a/configure.ac b/configure.ac index a0c524dd86..62daa7de0c 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.5.0.1], +AC_INIT([GStreamer RTSP Server Library], [1.5.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 501, 0, 501) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.5.0.1 -GSTPB_REQ=1.5.0.1 -GSTPG_REQ=1.5.0.1 -GSTPD_REQ=1.5.0.1 +GST_REQ=1.5.1 +GSTPB_REQ=1.5.1 +GSTPG_REQ=1.5.1 +GSTPD_REQ=1.5.1 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 8668226355..705191abd2 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.5.1 + 1.5 + + 2015-06-07 + + + + 1.4.0 From 9c75932b16be034e69e731ecd2585af22c64e48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 7 Jun 2015 16:44:55 +0200 Subject: [PATCH 1133/1776] Back to development --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 62daa7de0c..56a9918e7f 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.5.1], +AC_INIT([GStreamer RTSP Server Library], [1.5.1.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 501, 0, 501) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.5.1 -GSTPB_REQ=1.5.1 -GSTPG_REQ=1.5.1 -GSTPD_REQ=1.5.1 +GST_REQ=1.5.1.1 +GSTPB_REQ=1.5.1.1 +GSTPG_REQ=1.5.1.1 +GSTPD_REQ=1.5.1.1 dnl *** autotools stuff **** From 4aaab390c4c95973a759f3750873f9eb643c8c93 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 7 Jun 2015 17:16:47 +0200 Subject: [PATCH 1134/1776] Automatic update of common submodule From 44a3517 to c408583 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 44a351788c..c408583538 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 44a351788c83205f179b26af04f0eeaafb3b0d95 +Subproject commit c4085835384c8a177072dd6b38bcc3669a529b0a From 260e577b9ca16ad046a6304022261f80b0b652ee Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 7 Jun 2015 17:06:40 +0200 Subject: [PATCH 1135/1776] docs: remove variables that we define in the snippet from common This is syncing our Makefile.am with upstream gtkdoc. --- docs/libs/Makefile.am | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/libs/Makefile.am b/docs/libs/Makefile.am index 64b7aa5caf..38d8837b04 100644 --- a/docs/libs/Makefile.am +++ b/docs/libs/Makefile.am @@ -96,9 +96,6 @@ GTKDOC_CFLAGS = -I$(top_srcdir) $(GST_PLUGINS_BASE_CFLAGS) \ GTKDOC_LIBS = $(SCANOBJ_DEPS) $(GST_PLUGINS_BASE_LIBS) \ $(GST_BASE_LIBS) $(GST_LIBS) $(GCOV_LIBS) -GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC) -GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) - # If you need to override some of the declarations, place them in this file # and uncomment this line. DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt From 68dbad0967db5d0195b793a62c8ecc6341509bb8 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 7 Jun 2015 17:32:29 +0200 Subject: [PATCH 1136/1776] Automatic update of common submodule From c408583 to 21ba2e5 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index c408583538..21ba2e575a 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit c4085835384c8a177072dd6b38bcc3669a529b0a +Subproject commit 21ba2e575a0ecb8c51b46fa31d4b9cfd699da8b2 From 1541d3dd8ac9dc8e2f7a819de6d8d9043a18a4b5 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 7 Jun 2015 23:07:31 +0200 Subject: [PATCH 1137/1776] Automatic update of common submodule From 21ba2e5 to d37af32 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 21ba2e575a..d37af32e2d 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 21ba2e575a0ecb8c51b46fa31d4b9cfd699da8b2 +Subproject commit d37af32e2d6d1b546af72978f8441a84996ab3ea From 7436fee6899ebe6a4a62a11da61927d3dc7b94e7 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 8 Jun 2015 23:08:34 +0200 Subject: [PATCH 1138/1776] Automatic update of common submodule From d37af32 to d9a3353 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index d37af32e2d..d9a33530a2 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit d37af32e2d6d1b546af72978f8441a84996ab3ea +Subproject commit d9a33530a24c3ea24a6e13bd343b440c5656740e From 2c935a7884dc843c54dbb42c6fc2274a4f7e0bc5 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 9 Jun 2015 11:30:54 +0200 Subject: [PATCH 1139/1776] Automatic update of common submodule From d9a3353 to 6015d26 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index d9a33530a2..6015d26443 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit d9a33530a24c3ea24a6e13bd343b440c5656740e +Subproject commit 6015d26443b063bc71e87e979ece5511f25fd2be From 621976655535e451035b72f3aac36d25cf2c75d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 9 Jun 2015 13:51:02 +0200 Subject: [PATCH 1140/1776] test-netclock-client: Use a GMainLoop and playbin's source-setup signal A mainloop is needed to get glimagesink to display something on OSX, and the source-setup signal just makes things a little bit easier. --- examples/test-netclock-client.c | 80 ++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/examples/test-netclock-client.c b/examples/test-netclock-client.c index f91773eb07..bd0ae74371 100644 --- a/examples/test-netclock-client.c +++ b/examples/test-netclock-client.c @@ -26,17 +26,61 @@ #define PLAYBACK_DELAY_MS 40 static void -source_created (GstElement * pipe, GParamSpec * pspec) +source_created (GstElement * pipe, GstElement * source) { - GstElement *source; - - g_object_get (pipe, "source", &source, NULL); - g_assert (source != NULL); - g_object_set (source, "latency", PLAYBACK_DELAY_MS, "use-pipeline-clock", TRUE, "buffer-mode", 1, NULL); +} - gst_object_unref (source); +static gboolean +message (GstBus * bus, GstMessage * message, gpointer user_data) +{ + GMainLoop *loop = user_data; + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR:{ + GError *err = NULL; + gchar *name, *debug = NULL; + + name = gst_object_get_path_string (message->src); + gst_message_parse_error (message, &err, &debug); + + g_printerr ("ERROR: from element %s: %s\n", name, err->message); + if (debug != NULL) + g_printerr ("Additional debug info:\n%s\n", debug); + + g_error_free (err); + g_free (debug); + g_free (name); + + g_main_loop_quit (loop); + break; + } + case GST_MESSAGE_WARNING:{ + GError *err = NULL; + gchar *name, *debug = NULL; + + name = gst_object_get_path_string (message->src); + gst_message_parse_warning (message, &err, &debug); + + g_printerr ("ERROR: from element %s: %s\n", name, err->message); + if (debug != NULL) + g_printerr ("Additional debug info:\n%s\n", debug); + + g_error_free (err); + g_free (debug); + g_free (name); + break; + } + case GST_MESSAGE_EOS: + g_print ("Got EOS\n"); + g_main_loop_quit (loop); + break; + default: + break; + } + + return TRUE; } int @@ -46,7 +90,7 @@ main (int argc, char *argv[]) gchar *server; gint clock_port; GstElement *pipe; - GstMessage *msg; + GMainLoop *loop; gst_init (&argc, &argv); @@ -70,9 +114,11 @@ main (int argc, char *argv[]) /* Wait 0.5 seconds for the clock to stabilise */ g_usleep (G_USEC_PER_SEC / 2); + loop = g_main_loop_new (NULL, FALSE); + pipe = gst_element_factory_make ("playbin", NULL); g_object_set (pipe, "uri", argv[1], NULL); - g_signal_connect (pipe, "notify::source", (GCallback) source_created, NULL); + g_signal_connect (pipe, "source-setup", G_CALLBACK (source_created), NULL); gst_element_set_start_time (pipe, GST_CLOCK_TIME_NONE); gst_element_set_base_time (pipe, 0); @@ -84,22 +130,16 @@ main (int argc, char *argv[]) goto exit; }; - msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipe), - GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + gst_bus_add_signal_watch (GST_ELEMENT_BUS (pipe)); + g_signal_connect (GST_ELEMENT_BUS (pipe), "message", G_CALLBACK (message), + loop); - if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { - GError *err = NULL; - gchar *debug = NULL; - gst_message_parse_error (msg, &err, &debug); - g_print ("\nERROR: %s\n%s\n\n", err->message, debug); - g_error_free (err); - g_free (debug); - } - gst_message_unref (msg); + g_main_loop_run (loop); exit: gst_element_set_state (pipe, GST_STATE_NULL); gst_object_unref (pipe); + g_main_loop_unref (loop); return 0; } From af2cb6445ad56383478322d463fd15d0aea1b3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 9 Jun 2015 13:53:47 +0200 Subject: [PATCH 1141/1776] test-netclock-client: Use new GstClock API to wait for clock synchronization --- examples/test-netclock-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/test-netclock-client.c b/examples/test-netclock-client.c index bd0ae74371..c6c981225f 100644 --- a/examples/test-netclock-client.c +++ b/examples/test-netclock-client.c @@ -111,8 +111,8 @@ main (int argc, char *argv[]) return 1; } - /* Wait 0.5 seconds for the clock to stabilise */ - g_usleep (G_USEC_PER_SEC / 2); + /* Wait for the clock to stabilise */ + gst_clock_wait_for_sync (net_clock, GST_CLOCK_TIME_NONE); loop = g_main_loop_new (NULL, FALSE); From 6ec8fe44b2da3b61f8b2e0132eeb3a3f81cd7c95 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 5 Jun 2015 22:35:39 -0400 Subject: [PATCH 1142/1776] GstRTSPAuth: Add client certificate authentication support https://bugzilla.gnome.org/show_bug.cgi?id=750471 --- docs/libs/gst-rtsp-server-sections.txt | 4 + gst/rtsp-server/rtsp-auth.c | 176 ++++++++++++++++++++++++- gst/rtsp-server/rtsp-auth.h | 12 +- 3 files changed, 188 insertions(+), 4 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index fe38081dfd..69d87d89e5 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -44,6 +44,10 @@ gst_rtsp_auth_new gst_rtsp_auth_get_tls_certificate gst_rtsp_auth_set_tls_certificate +gst_rtsp_auth_get_tls_database +gst_rtsp_auth_set_tls_database +gst_rtsp_auth_get_tls_authentication_mode +gst_rtsp_auth_set_tls_authentication_mode gst_rtsp_auth_make_basic gst_rtsp_auth_add_basic gst_rtsp_auth_remove_basic diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index b0e924e72d..654388a6ff 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -59,6 +59,8 @@ struct _GstRTSPAuthPrivate /* the TLS certificate */ GTlsCertificate *certificate; + GTlsDatabase *database; + GTlsAuthenticationMode mode; GHashTable *basic; /* protected by lock */ GstRTSPToken *default_token; GstRTSPMethod methods; @@ -70,6 +72,14 @@ enum PROP_LAST }; +enum +{ + SIGNAL_ACCEPT_CERTIFICATE, + SIGNAL_LAST +}; + +static guint signals[SIGNAL_LAST] = { 0 }; + GST_DEBUG_CATEGORY_STATIC (rtsp_auth_debug); #define GST_CAT_DEFAULT rtsp_auth_debug @@ -102,6 +112,31 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) klass->check = default_check; GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth"); + + /** + * GstRTSPAuth::accept-certificate: + * @auth: a #GstRTSPAuth + * @connection: a #GTlsConnection + * @peer_cert: the peer's #GTlsCertificate + * @errors: the problems with @peer_cert. + * + * Emitted during the TLS handshake after the client certificate has + * been received. See also gst_rtsp_auth_set_tls_authentication_mode(). + * + * Returns: %TRUE to accept @peer_cert (which will also + * immediately end the signal emission). %FALSE to allow the signal + * emission to continue, which will cause the handshake to fail if + * no one else overrides it. + * + * Since: 1.6 + */ + signals[SIGNAL_ACCEPT_CERTIFICATE] = g_signal_new ("accept-certificate", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstRTSPAuthClass, accept_certificate), + g_signal_accumulator_true_handled, NULL, g_cclosure_marshal_generic, + G_TYPE_BOOLEAN, 3, G_TYPE_TLS_CONNECTION, G_TYPE_TLS_CERTIFICATE, + G_TYPE_TLS_CERTIFICATE_FLAGS); } static void @@ -130,6 +165,8 @@ gst_rtsp_auth_finalize (GObject * obj) if (priv->certificate) g_object_unref (priv->certificate); + if (priv->database) + g_object_unref (priv->database); g_hash_table_unref (priv->basic); g_mutex_clear (&priv->lock); @@ -230,6 +267,118 @@ gst_rtsp_auth_get_tls_certificate (GstRTSPAuth * auth) return result; } +/** + * gst_rtsp_auth_set_tls_database: + * @auth: a #GstRTSPAuth + * @database: (transfer none) (allow-none): a #GTlsDatabase + * + * Sets the certificate database that is used to verify peer certificates. + * If set to %NULL (the default), then peer certificate validation will always + * set the %G_TLS_CERTIFICATE_UNKNOWN_CA error. + * + * Since 1.6 + */ +void +gst_rtsp_auth_set_tls_database (GstRTSPAuth * auth, GTlsDatabase * database) +{ + GstRTSPAuthPrivate *priv; + GTlsDatabase *old; + + g_return_if_fail (GST_IS_RTSP_AUTH (auth)); + + priv = auth->priv; + + if (database) + g_object_ref (database); + + g_mutex_lock (&priv->lock); + old = priv->database; + priv->database = database; + g_mutex_unlock (&priv->lock); + + if (old) + g_object_unref (old); +} + +/** + * gst_rtsp_auth_get_tls_database: + * @auth: a #GstRTSPAuth + * + * Get the #GTlsDatabase used for verifying client certificate. + * + * Returns: (transfer full): the #GTlsDatabase of @auth. g_object_unref() after + * usage. + * Since: 1.6 + */ +GTlsDatabase * +gst_rtsp_auth_get_tls_database (GstRTSPAuth * auth) +{ + GstRTSPAuthPrivate *priv; + GTlsDatabase *result; + + g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), NULL); + + priv = auth->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->database)) + g_object_ref (result); + g_mutex_unlock (&priv->lock); + + return result; +} + +/** + * gst_rtsp_auth_set_tls_authentication_mode: + * @auth: a #GstRTSPAuth + * @mode: (transfer none) (allow-none): a #GTlsAuthenticationMode + * + * The #GTlsAuthenticationMode to set on the underlying GTlsServerConnection. + * When set to another value than %G_TLS_AUTHENTICATION_NONE, + * #GstRTSPAuth::accept-certificate signal will be emitted and must be handled. + * + * Since: 1.6 + */ +void +gst_rtsp_auth_set_tls_authentication_mode (GstRTSPAuth * auth, + GTlsAuthenticationMode mode) +{ + GstRTSPAuthPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_AUTH (auth)); + + priv = auth->priv; + + g_mutex_lock (&priv->lock); + priv->mode = mode; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_auth_get_tls_authentication_mode: + * @auth: a #GstRTSPAuth + * + * Get the #GTlsAuthenticationMode. + * + * Returns: (transfer full): the #GTlsAuthenticationMode. + */ +GTlsAuthenticationMode +gst_rtsp_auth_get_tls_authentication_mode (GstRTSPAuth * auth) +{ + GstRTSPAuthPrivate *priv; + GTlsAuthenticationMode result; + + g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), G_TLS_AUTHENTICATION_NONE); + + priv = auth->priv; + + g_mutex_lock (&priv->lock); + result = priv->mode; + g_mutex_unlock (&priv->lock); + + return result; +} + /** * gst_rtsp_auth_set_default_token: * @auth: a #GstRTSPAuth @@ -431,19 +580,40 @@ no_auth: } } +static gboolean +accept_certificate_cb (GTlsConnection * conn, GTlsCertificate * peer_cert, + GTlsCertificateFlags errors, GstRTSPAuth * auth) +{ + gboolean ret = FALSE; + + g_signal_emit (auth, signals[SIGNAL_ACCEPT_CERTIFICATE], 0, + conn, peer_cert, errors, &ret); + + return ret; +} + /* new connection */ static gboolean check_connect (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check) { GstRTSPAuthPrivate *priv = auth->priv; + GTlsConnection *tls; + + /* configure the connection */ if (priv->certificate) { - GTlsConnection *tls; - - /* configure the connection */ tls = gst_rtsp_connection_get_tls (ctx->conn, NULL); g_tls_connection_set_certificate (tls, priv->certificate); } + + if (priv->mode != G_TLS_AUTHENTICATION_NONE) { + tls = gst_rtsp_connection_get_tls (ctx->conn, NULL); + g_tls_connection_set_database (tls, priv->database); + g_object_set (tls, "authentication-mode", priv->mode, NULL); + g_signal_connect (tls, "accept-certificate", + G_CALLBACK (accept_certificate_cb), auth); + } + return TRUE; } diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index cb281f0cbe..ac44b28794 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -72,8 +72,12 @@ struct _GstRTSPAuthClass { gboolean (*authenticate) (GstRTSPAuth *auth, GstRTSPContext *ctx); gboolean (*check) (GstRTSPAuth *auth, GstRTSPContext *ctx, const gchar *check); + gboolean (*accept_certificate) (GstRTSPAuth *auth, + GTlsConnection *connection, + GTlsCertificate *peer_cert, + GTlsCertificateFlags errors); /*< private >*/ - gpointer _gst_reserved[GST_PADDING]; + gpointer _gst_reserved[GST_PADDING - 1]; }; GType gst_rtsp_auth_get_type (void); @@ -83,6 +87,12 @@ GstRTSPAuth * gst_rtsp_auth_new (void); void gst_rtsp_auth_set_tls_certificate (GstRTSPAuth *auth, GTlsCertificate *cert); GTlsCertificate * gst_rtsp_auth_get_tls_certificate (GstRTSPAuth *auth); +void gst_rtsp_auth_set_tls_database (GstRTSPAuth *auth, GTlsDatabase *database); +GTlsDatabase * gst_rtsp_auth_get_tls_database (GstRTSPAuth *auth); + +void gst_rtsp_auth_set_tls_authentication_mode (GstRTSPAuth *auth, GTlsAuthenticationMode mode); +GTlsAuthenticationMode gst_rtsp_auth_get_tls_authentication_mode (GstRTSPAuth *auth); + void gst_rtsp_auth_set_default_token (GstRTSPAuth *auth, GstRTSPToken *token); GstRTSPToken * gst_rtsp_auth_get_default_token (GstRTSPAuth *auth); From 5c5850b6b161f1a4f2388956c7ff6a9ced917aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 10 Jun 2015 17:14:18 +0200 Subject: [PATCH 1143/1776] test-netclock-client: Use ntp-sync=TRUE and buffer-mode=SYNC for proper synchronization --- examples/test-netclock-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/test-netclock-client.c b/examples/test-netclock-client.c index c6c981225f..c6ea9b64ee 100644 --- a/examples/test-netclock-client.c +++ b/examples/test-netclock-client.c @@ -29,7 +29,7 @@ static void source_created (GstElement * pipe, GstElement * source) { g_object_set (source, "latency", PLAYBACK_DELAY_MS, - "use-pipeline-clock", TRUE, "buffer-mode", 1, NULL); + "use-pipeline-clock", TRUE, "buffer-mode", 4, "ntp-sync", TRUE, NULL); } static gboolean From 8c1eb6fb4f509ee466d81a0e1f3233262c277403 Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Thu, 11 Jun 2015 17:37:25 +0900 Subject: [PATCH 1144/1776] docs: add missing apis https://bugzilla.gnome.org/show_bug.cgi?id=750764 --- docs/libs/gst-rtsp-server-sections.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 69d87d89e5..54df7a128a 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -178,7 +178,11 @@ gst_rtsp_media_get_buffer_size gst_rtsp_media_set_retransmission_time gst_rtsp_media_get_retransmission_time +gst_rtsp_media_set_latency +gst_rtsp_media_get_latency + gst_rtsp_media_setup_sdp +gst_rtsp_media_handle_sdp gst_rtsp_media_prepare @@ -267,6 +271,12 @@ gst_rtsp_media_factory_set_suspend_mode gst_rtsp_media_factory_set_retransmission_time gst_rtsp_media_factory_get_retransmission_time +gst_rtsp_media_factory_set_latency +gst_rtsp_media_factory_get_latency + +gst_rtsp_media_factory_set_media_gtype +gst_rtsp_media_factory_get_media_gtype + gst_rtsp_media_factory_construct gst_rtsp_media_factory_create_element @@ -554,6 +564,9 @@ gst_rtsp_stream_set_protocols gst_rtsp_stream_get_retransmission_time gst_rtsp_stream_set_retransmission_time +gst_rtsp_stream_set_seqnum_offset +gst_rtsp_stream_get_current_seqnum + gst_rtsp_stream_is_transport_supported gst_rtsp_stream_get_address_pool @@ -583,8 +596,14 @@ gst_rtsp_stream_get_rtcp_socket gst_rtsp_stream_set_blocked gst_rtsp_stream_is_blocking +gst_rtsp_stream_query_stop +gst_rtsp_stream_query_position + gst_rtsp_stream_update_crypto +gst_rtsp_stream_set_pt_map +gst_rtsp_stream_request_aux_sender + GstRTSPStreamTransportFilterFunc gst_rtsp_stream_transport_filter From 93d37df0c3971b24c686a856540171287f6be754 Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Thu, 11 Jun 2015 18:10:12 +0900 Subject: [PATCH 1145/1776] docs: add missing types https://bugzilla.gnome.org/show_bug.cgi?id=750764 --- docs/libs/gst-rtsp-server.types | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/libs/gst-rtsp-server.types b/docs/libs/gst-rtsp-server.types index f4476f2e09..9e4aa4cc10 100644 --- a/docs/libs/gst-rtsp-server.types +++ b/docs/libs/gst-rtsp-server.types @@ -23,3 +23,30 @@ gst_rtsp_session_get_type #include gst_rtsp_client_get_type + +#include +gst_rtsp_address_pool_get_type + +#include +gst_rtsp_context_get_type + +#include +gst_rtsp_media_factory_uri_get_type + +#include +gst_rtsp_permissions_get_type + +#include +gst_rtsp_session_media_get_type + +#include +gst_rtsp_stream_transport_get_type + +#include +gst_rtsp_stream_get_type + +#include +gst_rtsp_thread_pool_get_type + +#include +gst_rtsp_token_get_type From 2a3dd3d38fe51d4688dd0ac48e20d8d7e60b2630 Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Thu, 11 Jun 2015 17:38:52 +0900 Subject: [PATCH 1146/1776] rtsp-stream: add description for gst_rtsp_stream_request_aux_sender https://bugzilla.gnome.org/show_bug.cgi?id=750764 --- gst/rtsp-server/rtsp-stream.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 339971f775..194bc10053 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1817,6 +1817,17 @@ request_rtp_rtcp_decoder (GstElement * rtpbin, guint session, return gst_object_ref (priv->srtpdec); } +/** + * gst_rtsp_stream_request_aux_sender: + * @stream: a #GstRTSPStream + * @sessid: the session id + * + * Creating a rtxsend bin + * + * Returns: (transfer full): a #GstElement. + * + * Since: 1.6 + */ GstElement * gst_rtsp_stream_request_aux_sender (GstRTSPStream * stream, guint sessid) { From 028a4666fae626c2cfb7049463496f3ebf94f9f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 11 Jun 2015 20:41:31 +0200 Subject: [PATCH 1147/1776] test-netclock: Setting the same base time on sender and receiver is not necessary It's going to be fixed up by rtpbin when using ntp-sync=TRUE --- examples/test-netclock-client.c | 2 -- examples/test-netclock.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/examples/test-netclock-client.c b/examples/test-netclock-client.c index c6ea9b64ee..57c9c6ade3 100644 --- a/examples/test-netclock-client.c +++ b/examples/test-netclock-client.c @@ -120,8 +120,6 @@ main (int argc, char *argv[]) g_object_set (pipe, "uri", argv[1], NULL); g_signal_connect (pipe, "source-setup", G_CALLBACK (source_created), NULL); - gst_element_set_start_time (pipe, GST_CLOCK_TIME_NONE); - gst_element_set_base_time (pipe, 0); gst_pipeline_use_clock (GST_PIPELINE (pipe), net_clock); if (gst_element_set_state (pipe, diff --git a/examples/test-netclock.c b/examples/test-netclock.c index 2e53635fdb..2b5856a8ed 100644 --- a/examples/test-netclock.c +++ b/examples/test-netclock.c @@ -96,8 +96,6 @@ create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media) pipeline = gst_pipeline_new ("media-pipeline"); gst_pipeline_use_clock (GST_PIPELINE (pipeline), global_clock); - gst_element_set_base_time (pipeline, 0); - gst_element_set_start_time (pipeline, GST_CLOCK_TIME_NONE); gst_rtsp_media_take_pipeline (media, GST_PIPELINE_CAST (pipeline)); return pipeline; From a5044fa1f9337b68c03873e450a2f089b3ed81e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 12 Jun 2015 23:35:32 +0200 Subject: [PATCH 1148/1776] test-netclock: Use new ntp-time-source property on rtpbin Select the clock time to be used as NTP time source. This allows proper synchronization between receivers, independent of sharing base times, and just requires them to use the same clock. --- examples/test-netclock-client.c | 2 +- examples/test-netclock.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/test-netclock-client.c b/examples/test-netclock-client.c index 57c9c6ade3..2da9b73fc7 100644 --- a/examples/test-netclock-client.c +++ b/examples/test-netclock-client.c @@ -29,7 +29,7 @@ static void source_created (GstElement * pipe, GstElement * source) { g_object_set (source, "latency", PLAYBACK_DELAY_MS, - "use-pipeline-clock", TRUE, "buffer-mode", 4, "ntp-sync", TRUE, NULL); + "ntp-time-source", 3, "buffer-mode", 4, "ntp-sync", TRUE, NULL); } static gboolean diff --git a/examples/test-netclock.c b/examples/test-netclock.c index 2b5856a8ed..6fa728a173 100644 --- a/examples/test-netclock.c +++ b/examples/test-netclock.c @@ -118,7 +118,7 @@ test_rtsp_media_init (TestRTSPMedia * media) static gboolean custom_setup_rtpbin (GstRTSPMedia * media, GstElement * rtpbin) { - g_object_set (rtpbin, "use-pipeline-clock", TRUE, NULL); + g_object_set (rtpbin, "ntp-time-source", 3, NULL); return TRUE; } From fdfe97f447282c3ad9c1004516926173ba4a525d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 13 Jun 2015 17:14:43 +0200 Subject: [PATCH 1149/1776] test-netclock: Use gst_pipeline_set_latency() to set a high-enough, equal latency for all receivers --- examples/test-netclock-client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/test-netclock-client.c b/examples/test-netclock-client.c index 2da9b73fc7..e862ca9b00 100644 --- a/examples/test-netclock-client.c +++ b/examples/test-netclock-client.c @@ -122,6 +122,10 @@ main (int argc, char *argv[]) gst_pipeline_use_clock (GST_PIPELINE (pipe), net_clock); + /* Set this high enough so that it's higher than the minimum latency + * on all receivers */ + gst_pipeline_set_latency (GST_PIPELINE (pipe), 500 * GST_MSECOND); + if (gst_element_set_state (pipe, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { g_print ("Failed to set state to PLAYING\n"); From fb71b9c4e9bb66784491df81537d4865b99480f1 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Thu, 11 Jun 2015 17:39:00 +0200 Subject: [PATCH 1150/1776] rtsp-media: Always use real payloader when creating streams A bin that contains the real payloader might be used as payloader. In this case we have to get the real payloader for the various properties it provides. Example use cases for this are bins that payload some media and then have additional elements that add metadata or RTP extension headers to the stream. https://bugzilla.gnome.org/show_bug.cgi?id=750800 --- gst/rtsp-server/rtsp-media.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d4efd5f4ea..53b2cc42ac 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -211,6 +211,8 @@ static gboolean default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp); static gboolean wait_preroll (GstRTSPMedia * media); +static GstElement * find_payload_element (GstElement * payloader); + static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; #define C_ENUM(v) ((gint) v) @@ -1442,12 +1444,24 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) name = g_strdup_printf ("pay%d", i); if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) { + GstElement *pay; GST_INFO ("found stream %d with payloader %p", i, elem); /* take the pad of the payloader */ pad = gst_element_get_static_pad (elem, "src"); + + /* find the real payload element in case elem is a GstBin */ + pay = find_payload_element (elem); + /* create the stream */ - gst_rtsp_media_create_stream (media, elem, pad); + if (pay == NULL) { + GST_WARNING ("could not find real payloader, using bin"); + gst_rtsp_media_create_stream (media, elem, pad); + } else { + gst_rtsp_media_create_stream (media, pay, pad); + gst_object_unref (pay); + } + gst_object_unref (pad); gst_object_unref (elem); From d59c7981cc5ce93f17f4a7d79986c38cdb143e46 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 16 Jun 2015 17:50:26 -0400 Subject: [PATCH 1151/1776] Automatic update of common submodule From 6015d26 to f74b2df --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 6015d26443..f74b2df7a2 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 6015d26443b063bc71e87e979ece5511f25fd2be +Subproject commit f74b2df7a2e18b56c7eef9cae0810c505d2fc9e1 From 8922afb88dafa7b724a92796b2916161bf5375fc Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Thu, 18 Jun 2015 13:12:04 +0200 Subject: [PATCH 1152/1776] rtsp-client: allow application to decide what requirements are supported Add "check-requirements" signal and vfunc to allow application (and subclasses) to check the requirements. Based on patch from Hyunjun Ko https://bugzilla.gnome.org/show_bug.cgi?id=749417 --- gst/rtsp-server/rtsp-client.c | 61 ++++++++++++--- gst/rtsp-server/rtsp-client.h | 3 +- tests/check/gst/client.c | 135 ++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+), 12 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c41d019523..55f6259ee6 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -127,6 +127,7 @@ enum SIGNAL_SEND_MESSAGE, SIGNAL_ANNOUNCE_REQUEST, SIGNAL_RECORD_REQUEST, + SIGNAL_CHECK_REQUIREMENTS, SIGNAL_LAST }; @@ -285,6 +286,24 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::check-requirements: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * @arr: a NULL-terminated array of strings + * + * Returns: a newly allocated string with comma-separated list of + * unsupported options. An empty string must be returned if + * all options are supported. + * + * Since: 1.6 + */ + gst_rtsp_client_signals[SIGNAL_CHECK_REQUIREMENTS] = + g_signal_new ("check-requirements", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + check_requirements), NULL, NULL, g_cclosure_marshal_generic, + G_TYPE_STRING, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_STRV); + tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); g_mutex_init (&tunnels_lock); @@ -2602,25 +2621,29 @@ client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session, g_mutex_unlock (&priv->lock); } -/* Returns TRUE if there are no Require headers, otherwise returns FALSE - * and also returns a newly-allocated string of (comma-separated) unsupported - * options in the unsupported_reqs variable . +/* Check for Require headers. Returns TRUE if there are no Require headers, + * otherwise lets the application decide which headers are supported. + * By default all headers are unsupported. + * If there are unsupported options, FALSE will be returned together with + * a newly-allocated string of (comma-separated) unsupported options in + * the unsupported_reqs variable. * * There may be multiple Require headers, but we must send one single * Unsupported header with all the unsupported options as response. If * an incoming Require header contained a comma-separated list of options * GstRtspConnection will already have split that list up into multiple * headers. - * - * TODO: allow the application to decide what features are supported */ static gboolean -check_request_requirements (GstRTSPMessage * msg, gchar ** unsupported_reqs) +check_request_requirements (GstRTSPContext * ctx, gchar ** unsupported_reqs) { GstRTSPResult res; GPtrArray *arr = NULL; + GstRTSPMessage *msg = ctx->request; gchar *reqs = NULL; gint i; + gchar *sig_result = NULL; + gboolean result = TRUE; i = 0; do { @@ -2643,12 +2666,28 @@ check_request_requirements (GstRTSPMessage * msg, gchar ** unsupported_reqs) /* otherwise we've now processed at all the Require headers */ g_ptr_array_add (arr, NULL); - /* for now we don't commit to supporting anything, so will just report - * all of the required options as unsupported */ - *unsupported_reqs = g_strjoinv (", ", (gchar **) arr->pdata); + g_signal_emit (ctx->client, + gst_rtsp_client_signals[SIGNAL_CHECK_REQUIREMENTS], 0, ctx, + (gchar **) arr->pdata, &sig_result); + if (sig_result == NULL) { + /* no supported options, just report all of the required ones as + * unsupported */ + *unsupported_reqs = g_strjoinv (", ", (gchar **) arr->pdata); + result = FALSE; + goto done; + } + + if (strlen (sig_result) == 0) + g_free (sig_result); + else { + *unsupported_reqs = sig_result; + result = FALSE; + } + +done: g_ptr_array_unref (arr); - return FALSE; + return result; } static void @@ -2752,7 +2791,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) goto not_authorized; /* handle any 'Require' headers */ - if (!check_request_requirements (ctx->request, &unsupported_reqs)) + if (!check_request_requirements (ctx, &unsupported_reqs)) goto unsupported_requirement; /* the backlog must be unlimited while processing requests. diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 5137cc62aa..6b05448799 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -126,9 +126,10 @@ struct _GstRTSPClientClass { void (*announce_request) (GstRTSPClient *client, GstRTSPContext *ctx); void (*record_request) (GstRTSPClient *client, GstRTSPContext *ctx); + gchar* (*check_requirements) (GstRTSPClient *client, GstRTSPContext *ctx, gchar ** arr); /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE-5]; + gpointer _gst_reserved[GST_PADDING_LARGE-6]; }; GType gst_rtsp_client_get_type (void); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 95e86109f0..57d80e49fd 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -24,6 +24,7 @@ static gchar * session_id; static gint cseq; static guint expected_session_timeout = 60; +static const gchar *expected_unsupported_header; static gboolean test_response_200 (GstRTSPClient * client, GstRTSPMessage * response, @@ -109,6 +110,31 @@ test_response_454 (GstRTSPClient * client, GstRTSPMessage * response, return TRUE; } +static gboolean +test_response_551 (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + gchar *options; + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_OPTION_NOT_SUPPORTED); + fail_unless (g_str_equal (reason, "Option not supported")); + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_UNSUPPORTED, + &options, 0) == GST_RTSP_OK); + fail_unless (!g_strcmp0 (expected_unsupported_header, options)); + fail_unless (version == GST_RTSP_VERSION_1_0); + + return TRUE; +} + static GstRTSPClient * setup_client (const gchar * launch_line) { @@ -151,6 +177,114 @@ teardown_client (GstRTSPClient * client) g_object_unref (client); } +static gchar* +check_requirements_cb (GstRTSPClient * client, GstRTSPContext * ctx, + gchar ** req, gpointer user_data) +{ + int index = 0; + GString *result = g_string_new (""); + + while (req[index] != NULL) { + if (g_strcmp0 (req[index], "test-requirements")) { + if (result->len > 0) + g_string_append (result, ", "); + g_string_append (result, req[index]); + } + index++; + } + + return g_string_free (result, FALSE); +} + +GST_START_TEST (test_require) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = gst_rtsp_client_new (); + + /* require header without handler */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("test-not-supported1"); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str); + g_free (str); + + expected_unsupported_header = "test-not-supported1"; + gst_rtsp_client_set_send_func (client, test_response_551, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + g_signal_connect (G_OBJECT (client), "check-requirements", + G_CALLBACK (check_requirements_cb), NULL); + + /* one supported option */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("test-requirements"); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str); + g_free (str); + + gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + /* unsupported option */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("test-not-supported1"); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str); + g_free (str); + + expected_unsupported_header = "test-not-supported1"; + gst_rtsp_client_set_send_func (client, test_response_551, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + /* more than one unsupported options */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("test-not-supported1"); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str); + g_free (str); + str = g_strdup_printf ("test-not-supported2"); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str); + g_free (str); + + expected_unsupported_header = "test-not-supported1, test-not-supported2"; + gst_rtsp_client_set_send_func (client, test_response_551, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + /* supported and unsupported together */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("test-not-supported1"); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str); + g_free (str); + str = g_strdup_printf ("test-requirements"); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str); + g_free (str); + str = g_strdup_printf ("test-not-supported2"); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str); + g_free (str); + + expected_unsupported_header = "test-not-supported1, test-not-supported2"; + gst_rtsp_client_set_send_func (client, test_response_551, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + g_object_unref (client); +} + +GST_END_TEST; + GST_START_TEST (test_request) { GstRTSPClient *client; @@ -907,6 +1041,7 @@ rtspclient_suite (void) suite_add_tcase (s, tc); tcase_set_timeout (tc, 20); + tcase_add_test (tc, test_require); tcase_add_test (tc, test_request); tcase_add_test (tc, test_options); tcase_add_test (tc, test_describe); From d8fff9627d13daa76e325989c71b407ed27e6868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 24 Jun 2015 23:44:37 +0200 Subject: [PATCH 1153/1776] Release 1.5.2 --- ChangeLog | 149 ++++++++++++++++++++++++++++++++++++++++++- NEWS | 2 +- RELEASE | 58 ++--------------- configure.ac | 12 ++-- gst-rtsp-server.doap | 10 +++ 5 files changed, 169 insertions(+), 62 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0c991e9e94..9ec0b1113f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,152 @@ -=== release 1.5.1 === +=== release 1.5.2 === -2015-06-07 Sebastian Dröge +2015-06-24 Sebastian Dröge * configure.ac: - releasing 1.5.1 + releasing 1.5.2 + +2015-06-18 13:12:04 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * tests/check/gst/client.c: + rtsp-client: allow application to decide what requirements are supported + Add "check-requirements" signal and vfunc to allow application + (and subclasses) to check the requirements. + Based on patch from Hyunjun Ko + https://bugzilla.gnome.org/show_bug.cgi?id=749417 + +2015-06-16 17:50:26 -0400 Nicolas Dufresne + + * common: + Automatic update of common submodule + From 6015d26 to f74b2df + +2015-06-11 17:39:00 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Always use real payloader when creating streams + A bin that contains the real payloader might be used as payloader. In this + case we have to get the real payloader for the various properties it provides. + Example use cases for this are bins that payload some media and then have + additional elements that add metadata or RTP extension headers to the stream. + https://bugzilla.gnome.org/show_bug.cgi?id=750800 + +2015-06-13 17:14:43 +0200 Sebastian Dröge + + * examples/test-netclock-client.c: + test-netclock: Use gst_pipeline_set_latency() to set a high-enough, equal latency for all receivers + +2015-06-12 23:35:32 +0200 Sebastian Dröge + + * examples/test-netclock-client.c: + * examples/test-netclock.c: + test-netclock: Use new ntp-time-source property on rtpbin + Select the clock time to be used as NTP time source. This allows proper + synchronization between receivers, independent of sharing base times, and just + requires them to use the same clock. + +2015-06-11 20:41:31 +0200 Sebastian Dröge + + * examples/test-netclock-client.c: + * examples/test-netclock.c: + test-netclock: Setting the same base time on sender and receiver is not necessary + It's going to be fixed up by rtpbin when using ntp-sync=TRUE + +2015-06-11 17:38:52 +0900 Hyunjun Ko + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: add description for gst_rtsp_stream_request_aux_sender + https://bugzilla.gnome.org/show_bug.cgi?id=750764 + +2015-06-11 18:10:12 +0900 Hyunjun Ko + + * docs/libs/gst-rtsp-server.types: + docs: add missing types + https://bugzilla.gnome.org/show_bug.cgi?id=750764 + +2015-06-11 17:37:25 +0900 Hyunjun Ko + + * docs/libs/gst-rtsp-server-sections.txt: + docs: add missing apis + https://bugzilla.gnome.org/show_bug.cgi?id=750764 + +2015-06-10 17:14:18 +0200 Sebastian Dröge + + * examples/test-netclock-client.c: + test-netclock-client: Use ntp-sync=TRUE and buffer-mode=SYNC for proper synchronization + +2015-06-05 22:35:39 -0400 Xavier Claessens + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + GstRTSPAuth: Add client certificate authentication support + https://bugzilla.gnome.org/show_bug.cgi?id=750471 + +2015-06-09 13:53:47 +0200 Sebastian Dröge + + * examples/test-netclock-client.c: + test-netclock-client: Use new GstClock API to wait for clock synchronization + +2015-06-09 13:51:02 +0200 Sebastian Dröge + + * examples/test-netclock-client.c: + test-netclock-client: Use a GMainLoop and playbin's source-setup signal + A mainloop is needed to get glimagesink to display something on OSX, and + the source-setup signal just makes things a little bit easier. + +2015-06-09 11:30:54 +0200 Edward Hervey + + * common: + Automatic update of common submodule + From d9a3353 to 6015d26 + +2015-06-08 23:08:34 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From d37af32 to d9a3353 + +2015-06-07 23:07:31 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From 21ba2e5 to d37af32 + +2015-06-07 17:32:29 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From c408583 to 21ba2e5 + +2015-06-07 17:06:40 +0200 Stefan Sauer + + * docs/libs/Makefile.am: + docs: remove variables that we define in the snippet from common + This is syncing our Makefile.am with upstream gtkdoc. + +2015-06-07 17:16:47 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From 44a3517 to c408583 + +2015-06-07 16:44:55 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.5.1 === + +2015-06-07 11:20:01 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.5.1 2015-05-25 16:36:18 +0200 Göran Jönsson diff --git a/NEWS b/NEWS index 6a3a6b771e..a6d325deba 100644 --- a/NEWS +++ b/NEWS @@ -1,2 +1,2 @@ -This is GStreamer RTSP Server 1.5.1 +This is GStreamer RTSP Server 1.5.2 diff --git a/RELEASE b/RELEASE index 5b649a2f5f..fe1d80621b 100644 --- a/RELEASE +++ b/RELEASE @@ -1,8 +1,8 @@ -Release notes for GStreamer RTSP Server Library 1.5.1 +Release notes for GStreamer RTSP Server Library 1.5.2 -The GStreamer team is pleased to announce the first release of the unstable +The GStreamer team is pleased to announce the second release of the unstable 1.5 release series. The 1.5 release series is adding new features on top of the 1.0, 1.2 and 1.4 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. The unstable 1.5 release series @@ -16,38 +16,11 @@ during the unstable 1.5 release series. -Features of this release - - Bugs fixed in this release - * 732238 : Listen on the multicast group for RTP/RTCP packets - * 734546 : tests: Unref element after usage - * 736041 : Protect rtsp transport data. - * 736647 : Tunneled RTSP sessions do not always timeout as expected - * 737110 : rtsp-client: race condition when closing client connection - * 737631 : gst-rtsp-server deadlock while sending response over TCP - * 737675 : media: media_unprepare() is kind of broken - * 737690 : rtsp-client: deadlock when setting session medias to NULL - * 737797 : rtsp-stream: lock not released when leaving bin and transports not removed - * 737829 : rtsp-server: deactivate media when shutting down from paused - * 738905 : rtsp-client: add stream transport to the context - * 739112 : rtsp-client: Can not allocate ports for interleaved traffic in setup - * 740752 : add retransmission support - * 740845 : crash when reciving a rtcp after teardown but before client finalize. - * 741678 : configure: add --disable-examples switch - * 742115 : Examples: Accept a 'port' argument for running multiple instances - * 742869 : Remove URI-escaping of RTSP session-id - * 742954 : Crash when two treads are in handle_new_sample at the same time. - * 743175 : Add support for RECORD - * 743346 : When system time is increased the ongoing RTSP sessions will time out. - * 743734 : RTCP packets not sent - * 744379 : gst-rtsp-server does not preroll when piping data into the media-pipeline - * 745704 : Losing the first packet - * 747614 : gst-rtsp-server: uninitialized clock rate causes critical warning - * 747839 : gst-rtsp-server: doesn't perform retransmission to both streams in test-video-rtx - * 748058 : autogen.sh fails due to autopoint erroring out due to missing gettext version in configure.ac - * 749845 : Client have problem to find the teardown response. + * 749417 : rtsp-client: add API to allow application to decide what requirements are supported + * 750764 : gst-rtsp-server: add missing apis to doc + * 750800 : rtsp-media: always use real payloader when creating streams ==== Download ==== @@ -86,30 +59,11 @@ Applications Contributors to this release - * Aleix Conchillo Flaqué - * Alistair Buxton - * Andreas Frisch - * Anila Balavan - * Arun Raghavan - * Branko Subasic * Edward Hervey - * Gregor Boirie - * Göran Jönsson * Hyunjun Ko - * Jan Schmidt - * Kent-Inge Ingesson - * Linus Svensson - * Luis de Bethencourt - * Matthew Waters * Nicolas Dufresne - * Nirbheek Chauhan * Ognyan Tonchev - * Olivier Crête * Sebastian Dröge - * Sebastian Rasmussen - * Srimanta Panda * Stefan Sauer - * Tim-Philipp Müller - * Vincent Penquerc'h - * Wim Taymans + * Xavier Claessens   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 56a9918e7f..5aa8376a0a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.5.1.1], +AC_INIT([GStreamer RTSP Server Library], [1.5.2], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 501, 0, 501) +AS_LIBTOOL(GST, 502, 0, 502) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.5.1.1 -GSTPB_REQ=1.5.1.1 -GSTPG_REQ=1.5.1.1 -GSTPD_REQ=1.5.1.1 +GST_REQ=1.5.2 +GSTPB_REQ=1.5.2 +GSTPG_REQ=1.5.2 +GSTPD_REQ=1.5.2 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 705191abd2..e2fd1abe3c 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.5.2 + 1.5 + + 2015-06-24 + + + + 1.5.1 From dc9f11c27fe16ec75faff9b6d5d9760efa94aafe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 25 Jun 2015 00:04:28 +0200 Subject: [PATCH 1154/1776] Back to development --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 5aa8376a0a..166bdfce0f 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.5.2], +AC_INIT([GStreamer RTSP Server Library], [1.5.2.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 502, 0, 502) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.5.2 -GSTPB_REQ=1.5.2 -GSTPG_REQ=1.5.2 -GSTPD_REQ=1.5.2 +GST_REQ=1.5.2.1 +GSTPB_REQ=1.5.2.1 +GSTPG_REQ=1.5.2.1 +GSTPD_REQ=1.5.2.1 dnl *** autotools stuff **** From c809dc173567dd3e739c49bb22eaccf94a84f1e7 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 3 Jul 2015 22:00:00 +0200 Subject: [PATCH 1155/1776] Automatic update of common submodule From f74b2df to 9aed1d7 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index f74b2df7a2..9aed1d7a80 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit f74b2df7a2e18b56c7eef9cae0810c505d2fc9e1 +Subproject commit 9aed1d7a80a38b76f9441ecf181942df99f09c38 From 5585dc587831a8dbf6d563cd054a61c85992fe02 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Mon, 20 Jul 2015 16:37:44 -0400 Subject: [PATCH 1156/1776] threadpool: Fix possible warning in gst_rtsp_thread_pool_cleanup() https://bugzilla.gnome.org/show_bug.cgi?id=752640 --- gst/rtsp-server/rtsp-thread-pool.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index a8cce78293..b9ee37be0a 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -552,10 +552,11 @@ gst_rtsp_thread_pool_cleanup (void) GstRTSPThreadPoolClass *klass; klass = - GST_RTSP_THREAD_POOL_CLASS (g_type_class_peek + GST_RTSP_THREAD_POOL_CLASS (g_type_class_ref (gst_rtsp_thread_pool_get_type ())); if (klass->pool != NULL) { g_thread_pool_free (klass->pool, FALSE, TRUE); klass->pool = NULL; } + g_type_class_unref (klass); } From ae7bec97cbe79def80d95631e677145242bb9f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 29 Jul 2015 11:27:05 +0100 Subject: [PATCH 1157/1776] rtsp-media: Strip keys from the fmtp that we use internally in our caps Skip keys from the fmtp, which we already use ourselves for the caps. Some software is adding random things like clock-rate into the fmtp, and we would otherwise here set a string-typed clock-rate in the caps... and thus fail to create valid RTP caps https://bugzilla.gnome.org/show_bug.cgi?id=753009 --- gst/rtsp-server/rtsp-media.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 53b2cc42ac..31f9f35adc 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3270,6 +3270,11 @@ media_to_caps (gint pt, const GstSDPMedia * media) for (i = 0; pairs[i]; i++) { gchar *valpos; const gchar *val, *key; + gint j; + const gchar *reserved_keys[] = + { "media", "payload", "clock-rate", "encoding-name", + "encoding-params" + }; /* the key may not have a '=', the value can have other '='s */ valpos = strstr (pairs[i], "="); @@ -3288,6 +3293,19 @@ media_to_caps (gint pt, const GstSDPMedia * media) } /* strip the key of spaces, convert key to lowercase but not the value. */ key = g_strstrip (pairs[i]); + + /* skip keys from the fmtp, which we already use ourselves for the + * caps. Some software is adding random things like clock-rate into + * the fmtp, and we would otherwise here set a string-typed clock-rate + * in the caps... and thus fail to create valid RTP caps + */ + for (j = 0; j < G_N_ELEMENTS (reserved_keys); j++) { + if (g_ascii_strcasecmp (reserved_keys[i], key) == 0) { + key = ""; + break; + } + } + if (strlen (key) > 1) { tmp = g_ascii_strdown (key, -1); gst_structure_set (s, tmp, G_TYPE_STRING, val, NULL); From 3920e21cd0fcc459858b63c2fdcb603eac3b036d Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Thu, 30 Jul 2015 15:32:43 +0900 Subject: [PATCH 1158/1776] rtsp-media: assertion error due to wrong condition check In media to caps function, reserved_keys array is being used for variable i, leading to GLib-CRITICAL **: g_ascii_strcasecmp: assertion 's1 != NULL' failed changed it to variable j https://bugzilla.gnome.org/show_bug.cgi?id=753009 --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 31f9f35adc..011dae39c2 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3300,7 +3300,7 @@ media_to_caps (gint pt, const GstSDPMedia * media) * in the caps... and thus fail to create valid RTP caps */ for (j = 0; j < G_N_ELEMENTS (reserved_keys); j++) { - if (g_ascii_strcasecmp (reserved_keys[i], key) == 0) { + if (g_ascii_strcasecmp (reserved_keys[j], key) == 0) { key = ""; break; } From 22bf61f16c1210bb458fc3f53642179a0211104f Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 7 Aug 2015 09:21:36 -0400 Subject: [PATCH 1159/1776] rtsp-media: Only add 1 fakesink per pipeline There should be only one fakesink per pipeline, not per dynpay. This would lead to element naming clash. --- gst/rtsp-server/rtsp-media.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 011dae39c2..c00c703d50 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2516,13 +2516,13 @@ start_prepare (GstRTSPMedia * media) (GCallback) no_more_pads_cb, media); g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers); - - /* we add a fakesink here in order to make the state change async. We remove - * the fakesink again in the no-more-pads callback. */ - priv->fakesink = gst_element_factory_make ("fakesink", "fakesink"); - gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink); } + /* we add a fakesink here in order to make the state change async. We remove + * the fakesink again in the no-more-pads callback. */ + priv->fakesink = gst_element_factory_make ("fakesink", "fakesink"); + gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink); + if (!start_preroll (media)) goto preroll_failed; From 160b87430f876132199fd105a7de4fc08fa215ad Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sat, 8 Aug 2015 09:08:37 -0400 Subject: [PATCH 1160/1776] Revert "rtsp-media: Only add 1 fakesink per pipeline" This reverts commit 22bf61f16c1210bb458fc3f53642179a0211104f. --- gst/rtsp-server/rtsp-media.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c00c703d50..011dae39c2 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2516,12 +2516,12 @@ start_prepare (GstRTSPMedia * media) (GCallback) no_more_pads_cb, media); g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers); - } - /* we add a fakesink here in order to make the state change async. We remove - * the fakesink again in the no-more-pads callback. */ - priv->fakesink = gst_element_factory_make ("fakesink", "fakesink"); - gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink); + /* we add a fakesink here in order to make the state change async. We remove + * the fakesink again in the no-more-pads callback. */ + priv->fakesink = gst_element_factory_make ("fakesink", "fakesink"); + gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink); + } if (!start_preroll (media)) goto preroll_failed; From 707ac9c4876be900dd227a648db94fdab78f7324 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sat, 8 Aug 2015 09:40:09 -0400 Subject: [PATCH 1161/1776] media: Only add fakesink once per pipeline The intention is to prevent going PLAYING state before pads are created. If there was mutilple dynamic payload, it would leak few fakesink and actually prevent from ever reaching playing state. https://bugzilla.gnome.org/show_bug.cgi?id=753385 --- gst/rtsp-server/rtsp-media.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 011dae39c2..e623f00e38 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2517,10 +2517,12 @@ start_prepare (GstRTSPMedia * media) g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers); - /* we add a fakesink here in order to make the state change async. We remove - * the fakesink again in the no-more-pads callback. */ - priv->fakesink = gst_element_factory_make ("fakesink", "fakesink"); - gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink); + if (!priv->fakesink) { + /* we add a fakesink here in order to make the state change async. We remove + * the fakesink again in the no-more-pads callback. */ + priv->fakesink = gst_element_factory_make ("fakesink", "fakesink"); + gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink); + } } if (!start_preroll (media)) From 3667e71b2f8008fd40fdc17d62743d9d0bda3582 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sat, 8 Aug 2015 11:09:57 -0400 Subject: [PATCH 1162/1776] media-test: Test for multiple dynamic payload https://bugzilla.gnome.org/show_bug.cgi?id=753385 --- tests/check/gst/media.c | 88 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 5 deletions(-) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index c7d680e7c2..0c851350ce 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -210,27 +210,27 @@ GST_START_TEST (test_media_prepare) GST_END_TEST; +#define FLAG_HAVE_CAPS GST_ELEMENT_FLAG_LAST static void on_notify_caps (GstPad * pad, GParamSpec * pspec, GstElement * pay) { GstCaps *caps; - static gboolean have_caps = FALSE; g_object_get (pad, "caps", &caps, NULL); GST_DEBUG ("notify %" GST_PTR_FORMAT, caps); if (caps) { - if (!have_caps) { + if (!GST_OBJECT_FLAG_IS_SET (pay, FLAG_HAVE_CAPS)) { g_signal_emit_by_name (pay, "pad-added", pad); g_signal_emit_by_name (pay, "no-more-pads", NULL); - have_caps = TRUE; + GST_OBJECT_FLAG_SET (pay, FLAG_HAVE_CAPS); } gst_caps_unref (caps); } else { - if (have_caps) { + if (GST_OBJECT_FLAG_IS_SET (pay, FLAG_HAVE_CAPS)) { g_signal_emit_by_name (pay, "pad-removed", pad); - have_caps = FALSE; + GST_OBJECT_FLAG_UNSET (pay, FLAG_HAVE_CAPS); } } } @@ -412,6 +412,83 @@ GST_START_TEST (test_media_reset) GST_END_TEST; +GST_START_TEST (test_media_multidyn_prepare) +{ + GstRTSPMedia *media; + GstElement *bin, *src0, *pay0, *src1, *pay1; + GstElement *pipeline; + GstPad *srcpad0, *srcpad1; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + + bin = gst_bin_new ("bin"); + fail_if (bin == NULL); + + src0 = gst_element_factory_make ("videotestsrc", NULL); + fail_if (src0 == NULL); + + pay0 = gst_element_factory_make ("rtpvrawpay", "dynpay0"); + fail_if (pay0 == NULL); + g_object_set (pay0, "pt", 96, NULL); + + src1 = gst_element_factory_make ("videotestsrc", NULL); + fail_if (src1 == NULL); + + pay1 = gst_element_factory_make ("rtpvrawpay", "dynpay1"); + fail_if (pay1 == NULL); + g_object_set (pay1, "pt", 97, NULL); + + gst_bin_add_many (GST_BIN_CAST (bin), src0, pay0, src1, pay1, NULL); + gst_element_link_many (src0, pay0, NULL); + gst_element_link_many (src1, pay1, NULL); + + media = gst_rtsp_media_new (bin); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + g_object_set (G_OBJECT (media), "reusable", TRUE, NULL); + + pipeline = gst_pipeline_new ("media-pipeline"); + gst_rtsp_media_take_pipeline (media, GST_PIPELINE_CAST (pipeline)); + + gst_rtsp_media_collect_streams (media); + + srcpad0 = gst_element_get_static_pad (pay0, "src"); + srcpad1 = gst_element_get_static_pad (pay1, "src"); + + g_signal_connect (srcpad0, "notify::caps", (GCallback) on_notify_caps, pay0); + g_signal_connect (srcpad1, "notify::caps", (GCallback) on_notify_caps, pay1); + + pool = gst_rtsp_thread_pool_new (); + + fail_unless (gst_rtsp_media_n_streams (media) == 0); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (gst_rtsp_media_n_streams (media) == 2); + fail_unless (gst_rtsp_media_unprepare (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 0); + + fail_unless (gst_rtsp_media_n_streams (media) == 0); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (gst_rtsp_media_n_streams (media) == 2); + fail_unless (gst_rtsp_media_unprepare (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 0); + + gst_object_unref (srcpad0); + gst_object_unref (srcpad1); + g_object_unref (media); + g_object_unref (pool); + + gst_rtsp_thread_pool_cleanup (); +} + +GST_END_TEST; + + static Suite * rtspmedia_suite (void) { @@ -427,6 +504,7 @@ rtspmedia_suite (void) tcase_add_test (tc, test_media_prepare_port_alloc_fail); tcase_add_test (tc, test_media_take_pipeline); tcase_add_test (tc, test_media_reset); + tcase_add_test (tc, test_media_multidyn_prepare); return s; } From 8511ffe1788926f27978c26390619251343ae5f9 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 23 Jul 2015 14:50:30 -0400 Subject: [PATCH 1163/1776] Document that source keeps a ref on server until it's destroyed https://bugzilla.gnome.org/show_bug.cgi?id=749227 --- gst/rtsp-server/rtsp-server.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 686ba03121..45ae9dbc36 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1246,6 +1246,8 @@ watch_destroyed (GstRTSPServer * server) * unless cancellation happened at the same time as a condition change). You can * check for this in the callback using g_cancellable_is_cancelled(). * + * This takes a reference on @server until @source is destroyed. + * * Returns: (transfer full): the #GSource for @server or %NULL when an error * occurred. Free with g_source_unref () */ @@ -1304,6 +1306,12 @@ no_socket: * This function should be called when the server properties and urls are fully * configured and the server is ready to start. * + * This takes a reference on @server until the source is destroyed. Note that + * if @context is not the default main context as returned by + * g_main_context_default() (or %NULL), g_source_remove() cannot be used to + * destroy the source. In that case it is recommended to use + * gst_rtsp_server_create_source() and attach it to @context manually. + * * Returns: the ID (greater than 0) for the source within the GMainContext. */ guint From 418e1fe09001f9a4defc291d9af221d598d9cf45 Mon Sep 17 00:00:00 2001 From: Francisco Velazquez Date: Thu, 13 Aug 2015 11:24:10 +0200 Subject: [PATCH 1164/1776] media-test: Removing unnecessary assertion https://bugzilla.gnome.org/show_bug.cgi?id=753385 --- tests/check/gst/media.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 0c851350ce..c8cdf30b46 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -282,8 +282,6 @@ GST_START_TEST (test_media_dyn_prepare) fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 0); - fail_unless (gst_rtsp_media_n_streams (media) == 0); - thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); @@ -469,8 +467,6 @@ GST_START_TEST (test_media_multidyn_prepare) fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 0); - fail_unless (gst_rtsp_media_n_streams (media) == 0); - thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); From 4c6b1faa6a7ea97078e95d4614febcba7cd30604 Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Wed, 12 Aug 2015 14:33:44 +0900 Subject: [PATCH 1165/1776] media-factory: get port number through gst_rtsp_url_get_port https://bugzilla.gnome.org/show_bug.cgi?id=753473 --- gst/rtsp-server/rtsp-media-factory.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index fc9c880fec..087aa8ad35 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -1148,12 +1148,14 @@ default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) gchar *result; const gchar *pre_query; const gchar *query; + guint16 port; pre_query = url->query ? "?" : ""; query = url->query ? url->query : ""; - result = - g_strdup_printf ("%u%s%s%s", url->port, url->abspath, pre_query, query); + gst_rtsp_url_get_port (url, &port); + + result = g_strdup_printf ("%u%s%s%s", port, url->abspath, pre_query, query); return result; } From 43bac0c2d9e31b6a02384312b4ab105748545d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 19 Aug 2015 14:15:23 +0300 Subject: [PATCH 1166/1776] Release 1.5.90 --- ChangeLog | 99 ++++++++++++++++++++++++++++++++++++++++++-- NEWS | 2 +- RELEASE | 29 +++++++------ configure.ac | 12 +++--- gst-rtsp-server.doap | 10 +++++ 5 files changed, 127 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9ec0b1113f..c0bc2188c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,102 @@ -=== release 1.5.2 === +=== release 1.5.90 === -2015-06-24 Sebastian Dröge +2015-08-19 Sebastian Dröge * configure.ac: - releasing 1.5.2 + releasing 1.5.90 + +2015-08-12 14:33:44 +0900 Hyunjun Ko + + * gst/rtsp-server/rtsp-media-factory.c: + media-factory: get port number through gst_rtsp_url_get_port + https://bugzilla.gnome.org/show_bug.cgi?id=753473 + +2015-08-13 11:24:10 +0200 Francisco Velazquez + + * tests/check/gst/media.c: + media-test: Removing unnecessary assertion + https://bugzilla.gnome.org/show_bug.cgi?id=753385 + +2015-07-23 14:50:30 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-server.c: + Document that source keeps a ref on server until it's destroyed + https://bugzilla.gnome.org/show_bug.cgi?id=749227 + +2015-08-08 11:09:57 -0400 Nicolas Dufresne + + * tests/check/gst/media.c: + media-test: Test for multiple dynamic payload + https://bugzilla.gnome.org/show_bug.cgi?id=753385 + +2015-08-08 09:40:09 -0400 Nicolas Dufresne + + * gst/rtsp-server/rtsp-media.c: + media: Only add fakesink once per pipeline + The intention is to prevent going PLAYING state before pads are created. + If there was mutilple dynamic payload, it would leak few fakesink and + actually prevent from ever reaching playing state. + https://bugzilla.gnome.org/show_bug.cgi?id=753385 + +2015-08-08 09:08:37 -0400 Nicolas Dufresne + + * gst/rtsp-server/rtsp-media.c: + Revert "rtsp-media: Only add 1 fakesink per pipeline" + This reverts commit 22bf61f16c1210bb458fc3f53642179a0211104f. + +2015-08-07 09:21:36 -0400 Nicolas Dufresne + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Only add 1 fakesink per pipeline + There should be only one fakesink per pipeline, not per dynpay. This + would lead to element naming clash. + +2015-07-30 15:32:43 +0900 Vineeth TM + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: assertion error due to wrong condition check + In media to caps function, reserved_keys array is being used for variable i, + leading to GLib-CRITICAL **: g_ascii_strcasecmp: assertion 's1 != NULL' failed + changed it to variable j + https://bugzilla.gnome.org/show_bug.cgi?id=753009 + +2015-07-29 11:27:05 +0100 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Strip keys from the fmtp that we use internally in our caps + Skip keys from the fmtp, which we already use ourselves for the + caps. Some software is adding random things like clock-rate into + the fmtp, and we would otherwise here set a string-typed clock-rate + in the caps... and thus fail to create valid RTP caps + https://bugzilla.gnome.org/show_bug.cgi?id=753009 + +2015-07-20 16:37:44 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-thread-pool.c: + threadpool: Fix possible warning in gst_rtsp_thread_pool_cleanup() + https://bugzilla.gnome.org/show_bug.cgi?id=752640 + +2015-07-03 22:00:00 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From f74b2df to 9aed1d7 + +2015-06-25 00:04:28 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.5.2 === + +2015-06-24 23:44:37 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.5.2 2015-06-18 13:12:04 +0200 Ognyan Tonchev diff --git a/NEWS b/NEWS index a6d325deba..f1837f8acd 100644 --- a/NEWS +++ b/NEWS @@ -1,2 +1,2 @@ -This is GStreamer RTSP Server 1.5.2 +This is GStreamer RTSP Server 1.5.90 diff --git a/RELEASE b/RELEASE index fe1d80621b..59136ba3a8 100644 --- a/RELEASE +++ b/RELEASE @@ -1,26 +1,27 @@ -Release notes for GStreamer RTSP Server Library 1.5.2 +Release notes for GStreamer RTSP Server Library 1.5.90 -The GStreamer team is pleased to announce the second release of the unstable -1.5 release series. The 1.5 release series is adding new features on top of +The GStreamer team is pleased to announce the first release candidate for the +stable 1.6 release series. The 1.6 release series is adding new features on top of the 1.0, 1.2 and 1.4 series and is part of the API and ABI-stable 1.x release -series of the GStreamer multimedia framework. The unstable 1.5 release series -will lead to the stable 1.6 release series in the next weeks, and newly added -API can still change until that point. +series of the GStreamer multimedia framework. The final 1.6.0 release is planned +in the next few days unless any major bugs are found. -Binaries for Android, iOS, Mac OS X and Windows will be provided separately -during the unstable 1.5 release series. +Binaries for Android, iOS, Mac OS X and Windows will be provided separately by +the GStreamer project. + Bugs fixed in this release - * 749417 : rtsp-client: add API to allow application to decide what requirements are supported - * 750764 : gst-rtsp-server: add missing apis to doc - * 750800 : rtsp-media: always use real payloader when creating streams + * 749227 : rtsp-server: gst_rtsp_server_attach() is misleading + * 752640 : Warning in gst_rtsp_thread_pool_cleanup() + * 753385 : media: Adding multiple dynamic payload is broken + * 753473 : rtsp-server: shared media uri with explicit port given doesn't match same path uri without port ==== Download ==== @@ -55,15 +56,13 @@ Interested developers of the core library, plugins, and applications should subscribe to the gstreamer-devel list. -Applications - Contributors to this release - * Edward Hervey + * Francisco Velazquez * Hyunjun Ko * Nicolas Dufresne - * Ognyan Tonchev * Sebastian Dröge * Stefan Sauer + * Vineeth TM * Xavier Claessens   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 166bdfce0f..cb9ece9719 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.5.2.1], +AC_INIT([GStreamer RTSP Server Library], [1.5.90], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 502, 0, 502) +AS_LIBTOOL(GST, 590, 0, 590) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.5.2.1 -GSTPB_REQ=1.5.2.1 -GSTPG_REQ=1.5.2.1 -GSTPD_REQ=1.5.2.1 +GST_REQ=1.5.90 +GSTPB_REQ=1.5.90 +GSTPG_REQ=1.5.90 +GSTPD_REQ=1.5.90 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index e2fd1abe3c..15dab76e88 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.5.90 + 1.5 + + 2015-08-19 + + + + 1.5.2 From 9bfcdba42b2b93337c5ae7e4880dd3ff42a8c152 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 31 Aug 2015 22:47:45 +1000 Subject: [PATCH 1167/1776] rtsp-media: Fix small typo causing gtk-doc to complain --- gst/rtsp-server/rtsp-media.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index ac575e58f4..f1be13c3e4 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -238,7 +238,7 @@ gboolean gst_rtsp_media_handle_sdp (GstRTSPMedia * media, GstSDPMes void gst_rtsp_media_collect_streams (GstRTSPMedia *media); GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia *media, GstElement *payloader, - GstPad *srcpad); + GstPad *pad); /* dealing with the media */ GstClock * gst_rtsp_media_get_clock (GstRTSPMedia *media); From 27736d406ee73c5f98da9de567732224166a25e6 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 31 Aug 2015 22:48:34 +1000 Subject: [PATCH 1168/1776] rtsp-stream: Implement UDP buffer size setting. Add gst_rtsp_stream_(get|set)_buffer_size and use it to configure the UDP TX buffer size. Incorporates a patch by Hyunjun Ko Fixes https://bugzilla.gnome.org/show_bug.cgi?id=749095 --- gst/rtsp-server/rtsp-media.c | 9 +++++- gst/rtsp-server/rtsp-stream.c | 56 +++++++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-stream.h | 2 ++ 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e623f00e38..2483504a4d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -211,7 +211,7 @@ static gboolean default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp); static gboolean wait_preroll (GstRTSPMedia * media); -static GstElement * find_payload_element (GstElement * payloader); +static GstElement *find_payload_element (GstElement * payloader); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; @@ -1124,6 +1124,7 @@ void gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size) { GstRTSPMediaPrivate *priv; + guint i; g_return_if_fail (GST_IS_RTSP_MEDIA (media)); @@ -1133,6 +1134,11 @@ gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size) g_mutex_lock (&priv->lock); priv->buffer_size = size; + + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + gst_rtsp_stream_set_buffer_size (stream, size); + } g_mutex_unlock (&priv->lock); } @@ -1560,6 +1566,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, gst_rtsp_stream_set_profiles (stream, priv->profiles); gst_rtsp_stream_set_protocols (stream, priv->protocols); gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time); + gst_rtsp_stream_set_buffer_size (stream, priv->buffer_size); g_ptr_array_add (priv->streams, stream); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 194bc10053..d3f730a834 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1389,8 +1389,8 @@ gst_rtsp_stream_set_retransmission_time (GstRTSPStream * stream, } /** - * gst_rtsp_media_get_retransmission_time: - * @media: a #GstRTSPMedia + * gst_rtsp_stream_get_retransmission_time: + * @stream: a #GstRTSPStream * * Get the amount of time to store retransmission data. * @@ -1410,6 +1410,13 @@ gst_rtsp_stream_get_retransmission_time (GstRTSPStream * stream) return ret; } +/** + * gst_rtsp_stream_set_retransmission_pt: + * @stream: a #GstRTSPStream + * @rtx_pt: a #guint + * + * Set the payload type (pt) for retransmission of this stream. + */ void gst_rtsp_stream_set_retransmission_pt (GstRTSPStream * stream, guint rtx_pt) { @@ -1431,6 +1438,14 @@ gst_rtsp_stream_set_retransmission_pt (GstRTSPStream * stream, guint rtx_pt) g_mutex_unlock (&stream->priv->lock); } +/** + * gst_rtsp_stream_get_retransmission_pt: + * @stream: a #GstRTSPStream + * + * Get the payload-type used for retransmission of this stream + * + * Returns: The retransmission PT. + */ guint gst_rtsp_stream_get_retransmission_pt (GstRTSPStream * stream) { @@ -1445,6 +1460,43 @@ gst_rtsp_stream_get_retransmission_pt (GstRTSPStream * stream) return rtx_pt; } +/** + * gst_rtsp_media_get_buffer_size: + * @media: a #GstRTSPMedia + * @size: a #guint + * + * Set the size of the UDP transmission buffer (in bytes) + * Needs to be set before the stream is joined to a bin. + * + */ +void +gst_rtsp_stream_set_buffer_size (GstRTSPStream * stream, guint size) +{ + g_mutex_lock (&stream->priv->lock); + stream->priv->buffer_size = size; + g_mutex_unlock (&stream->priv->lock); +} + +/** + * gst_rtsp_media_get_buffer_size: + * @media: a #GstRTSPMedia + * + * Get the size of the UDP transmission buffer (in bytes) + * + * Returns: the size of the UDP TX buffer + */ +guint +gst_rtsp_stream_get_buffer_size (GstRTSPStream * stream) +{ + guint buffer_size; + + g_mutex_lock (&stream->priv->lock); + buffer_size = stream->priv->buffer_size; + g_mutex_unlock (&stream->priv->lock); + + return buffer_size; +} + /* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 58474fa8d5..0042f67de2 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -160,6 +160,8 @@ GstClockTime gst_rtsp_stream_get_retransmission_time (GstRTSPStream *st guint gst_rtsp_stream_get_retransmission_pt (GstRTSPStream * stream); void gst_rtsp_stream_set_retransmission_pt (GstRTSPStream * stream, guint rtx_pt); +void gst_rtsp_stream_set_buffer_size (GstRTSPStream *stream, guint size); +guint gst_rtsp_stream_get_buffer_size (GstRTSPStream *stream); void gst_rtsp_stream_set_pt_map (GstRTSPStream * stream, guint pt, GstCaps * caps); GstElement * gst_rtsp_stream_request_aux_sender (GstRTSPStream * stream, guint sessid); From 2a41502cde51f736b37791bd78fe97f0cf8c3d05 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 17 Aug 2015 02:36:31 +1000 Subject: [PATCH 1169/1776] test-record: Check parameter count and print out help If no launch pipeline was supplied, print out some help --- examples/test-record.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/test-record.c b/examples/test-record.c index 1c6ac3f083..1c375038f5 100644 --- a/examples/test-record.c +++ b/examples/test-record.c @@ -51,6 +51,11 @@ main (int argc, char *argv[]) g_printerr ("Error parsing options: %s\n", error->message); return -1; } + + if (argc < 2) { + g_print ("%s\n", g_option_context_get_help (optctx, TRUE, NULL)); + return 1; + } g_option_context_free (optctx); loop = g_main_loop_new (NULL, FALSE); From 22b618836ee332fce9fc83cfdcd9050305605ee0 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Sat, 22 Aug 2015 20:59:40 +1000 Subject: [PATCH 1170/1776] test-mp4: Support filenames with spaces in them. Error out on too few arguments --- examples/test-mp4.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/test-mp4.c b/examples/test-mp4.c index 263d122efc..9bcaab45e2 100644 --- a/examples/test-mp4.c +++ b/examples/test-mp4.c @@ -104,6 +104,11 @@ main (int argc, char *argv[]) g_printerr ("Error parsing options: %s\n", error->message); return -1; } + + if (argc < 2) { + g_print ("%s\n", g_option_context_get_help (optctx, TRUE, NULL)); + return 1; + } g_option_context_free (optctx); loop = g_main_loop_new (NULL, FALSE); @@ -117,7 +122,7 @@ main (int argc, char *argv[]) mounts = gst_rtsp_server_get_mount_points (server); str = g_strdup_printf ("( " - "filesrc location=%s ! qtdemux name=d " + "filesrc location=\"%s\" ! qtdemux name=d " "d. ! queue ! rtph264pay pt=96 name=pay0 " "d. ! queue ! rtpmp4apay pt=97 name=pay1 " ")", argv[1]); From 315c2f93bb3bd17514dd20fb269684dc2c23ee4d Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 4 Sep 2015 11:23:43 +1000 Subject: [PATCH 1171/1776] rtsp-media: Don't crash on encrypted RTX SDP In parse_keymgmt(), don't mutate the input string that's been passed as const, especially since we might need the original value again if the same key info applies to multiple streams (RTX, for example). https://bugzilla.gnome.org/show_bug.cgi?id=754753 --- gst/rtsp-server/rtsp-media.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 2483504a4d..adccff920a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3356,7 +3356,6 @@ static gboolean parse_keymgmt (const gchar * keymgmt, GstCaps * caps) { gboolean res = FALSE; - gchar *p, *kmpid; gsize size; guchar *data; GstMIKEYMessage *msg; @@ -3364,17 +3363,28 @@ parse_keymgmt (const gchar * keymgmt, GstCaps * caps) const gchar *srtp_cipher; const gchar *srtp_auth; - p = (gchar *) keymgmt; + { + gchar *orig_value; + gchar *p, *kmpid; - SKIP_SPACES (p); - if (*p == '\0') - return FALSE; + p = orig_value = g_strdup (keymgmt); - PARSE_STRING (p, " ", kmpid); - if (!g_str_equal (kmpid, "mikey")) - return FALSE; + SKIP_SPACES (p); + if (*p == '\0') { + g_free (orig_value); + return FALSE; + } + + PARSE_STRING (p, " ", kmpid); + if (kmpid == NULL || !g_str_equal (kmpid, "mikey")) { + g_free (orig_value); + return FALSE; + } + data = g_base64_decode (p, &size); + + g_free (orig_value); /* Don't need this any more */ + } - data = g_base64_decode (p, &size); if (data == NULL) return FALSE; From da8a31ac88e30b4c6126cf690d2faf943c519ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 17 Sep 2015 20:07:34 +0100 Subject: [PATCH 1172/1776] stream: fix docs for recently-added get/set_buffer_size API https://bugzilla.gnome.org/show_bug.cgi?id=749095 --- docs/libs/gst-rtsp-server-sections.txt | 3 +++ gst/rtsp-server/rtsp-stream.c | 13 ++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 54df7a128a..38e2d031a2 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -564,6 +564,9 @@ gst_rtsp_stream_set_protocols gst_rtsp_stream_get_retransmission_time gst_rtsp_stream_set_retransmission_time +gst_rtsp_stream_set_buffer_size +gst_rtsp_stream_get_buffer_size + gst_rtsp_stream_set_seqnum_offset gst_rtsp_stream_get_current_seqnum diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index d3f730a834..4417c4321a 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1461,13 +1461,14 @@ gst_rtsp_stream_get_retransmission_pt (GstRTSPStream * stream) } /** - * gst_rtsp_media_get_buffer_size: - * @media: a #GstRTSPMedia - * @size: a #guint + * gst_rtsp_stream_set_buffer_size: + * @stream: a #GstRTSPStream + * @size: the buffer size * * Set the size of the UDP transmission buffer (in bytes) * Needs to be set before the stream is joined to a bin. * + * Since: 1.6 */ void gst_rtsp_stream_set_buffer_size (GstRTSPStream * stream, guint size) @@ -1478,12 +1479,14 @@ gst_rtsp_stream_set_buffer_size (GstRTSPStream * stream, guint size) } /** - * gst_rtsp_media_get_buffer_size: - * @media: a #GstRTSPMedia + * gst_rtsp_stream_get_buffer_size: + * @stream: a #GstRTSPStream * * Get the size of the UDP transmission buffer (in bytes) * * Returns: the size of the UDP TX buffer + * + * Since: 1.6 */ guint gst_rtsp_stream_get_buffer_size (GstRTSPStream * stream) From e4edaebe8e672e17a7fe481c8e856a782c8fa0b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 18 Sep 2015 20:12:06 +0200 Subject: [PATCH 1173/1776] Release 1.5.91 --- ChangeLog | 60 +++++++++++++++++++++++++++++++++++++++++--- NEWS | 2 +- RELEASE | 22 ++++++---------- configure.ac | 12 ++++----- gst-rtsp-server.doap | 10 ++++++++ 5 files changed, 82 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index c0bc2188c7..1c60279937 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,63 @@ -=== release 1.5.90 === +=== release 1.5.91 === -2015-08-19 Sebastian Dröge +2015-09-18 Sebastian Dröge * configure.ac: - releasing 1.5.90 + releasing 1.5.91 + +2015-09-17 20:07:34 +0100 Tim-Philipp Müller + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-stream.c: + stream: fix docs for recently-added get/set_buffer_size API + https://bugzilla.gnome.org/show_bug.cgi?id=749095 + +2015-09-04 11:23:43 +1000 Jan Schmidt + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Don't crash on encrypted RTX SDP + In parse_keymgmt(), don't mutate the input string that's been passed + as const, especially since we might need the original value again if + the same key info applies to multiple streams (RTX, for example). + https://bugzilla.gnome.org/show_bug.cgi?id=754753 + +2015-08-22 20:59:40 +1000 Jan Schmidt + + * examples/test-mp4.c: + test-mp4: Support filenames with spaces in them. Error out on too few arguments + +2015-08-17 02:36:31 +1000 Jan Schmidt + + * examples/test-record.c: + test-record: Check parameter count and print out help + If no launch pipeline was supplied, print out some help + +2015-08-31 22:48:34 +1000 Jan Schmidt + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-stream: Implement UDP buffer size setting. + Add gst_rtsp_stream_(get|set)_buffer_size and use it to configure the + UDP TX buffer size. + Incorporates a patch by Hyunjun Ko + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=749095 + +2015-08-31 22:47:45 +1000 Jan Schmidt + + * gst/rtsp-server/rtsp-media.h: + rtsp-media: Fix small typo causing gtk-doc to complain + +=== release 1.5.90 === + +2015-08-19 14:15:23 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.5.90 2015-08-12 14:33:44 +0900 Hyunjun Ko diff --git a/NEWS b/NEWS index f1837f8acd..b850a06a9c 100644 --- a/NEWS +++ b/NEWS @@ -1,2 +1,2 @@ -This is GStreamer RTSP Server 1.5.90 +This is GStreamer RTSP Server 1.5.91 diff --git a/RELEASE b/RELEASE index 59136ba3a8..83f8a3b11f 100644 --- a/RELEASE +++ b/RELEASE @@ -1,8 +1,8 @@ -Release notes for GStreamer RTSP Server Library 1.5.90 +Release notes for GStreamer RTSP Server Library 1.5.91 -The GStreamer team is pleased to announce the first release candidate for the +The GStreamer team is pleased to announce the second release candidate for the stable 1.6 release series. The 1.6 release series is adding new features on top of the 1.0, 1.2 and 1.4 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. The final 1.6.0 release is planned @@ -13,15 +13,12 @@ Binaries for Android, iOS, Mac OS X and Windows will be provided separately by the GStreamer project. - Bugs fixed in this release - * 749227 : rtsp-server: gst_rtsp_server_attach() is misleading - * 752640 : Warning in gst_rtsp_thread_pool_cleanup() - * 753385 : media: Adding multiple dynamic payload is broken - * 753473 : rtsp-server: shared media uri with explicit port given doesn't match same path uri without port + * 749095 : rtsp-stream: add API to set UDP buffer size + * 754753 : rtsp-media: don't mutate original string when parsing keymgmt ==== Download ==== @@ -56,13 +53,10 @@ Interested developers of the core library, plugins, and applications should subscribe to the gstreamer-devel list. +Applications + Contributors to this release - * Francisco Velazquez - * Hyunjun Ko - * Nicolas Dufresne - * Sebastian Dröge - * Stefan Sauer - * Vineeth TM - * Xavier Claessens + * Jan Schmidt + * Tim-Philipp Müller   \ No newline at end of file diff --git a/configure.ac b/configure.ac index cb9ece9719..752bccc2f7 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.5.90], +AC_INIT([GStreamer RTSP Server Library], [1.5.91], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 590, 0, 590) +AS_LIBTOOL(GST, 591, 0, 591) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.5.90 -GSTPB_REQ=1.5.90 -GSTPG_REQ=1.5.90 -GSTPD_REQ=1.5.90 +GST_REQ=1.5.91 +GSTPB_REQ=1.5.91 +GSTPG_REQ=1.5.91 +GSTPD_REQ=1.5.91 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 15dab76e88..f17e957006 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.5.91 + 1.5 + + 2015-09-18 + + + + 1.5.90 From 8a8bb37f8d6ad839a2a080677c8f2e0c71a3bc5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 25 Sep 2015 23:32:52 +0200 Subject: [PATCH 1174/1776] Release 1.6.0 --- ChangeLog | 17 +++++++++--- NEWS | 64 +++++++++++++++++++++++++++++++++++++++++++- RELEASE | 27 +++++++++---------- configure.ac | 12 ++++----- gst-rtsp-server.doap | 10 +++++++ 5 files changed, 106 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1c60279937..62ce38fc42 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,20 @@ -=== release 1.5.91 === +=== release 1.6.0 === -2015-09-18 Sebastian Dröge +2015-09-25 Sebastian Dröge * configure.ac: - releasing 1.5.91 + releasing 1.6.0 + +=== release 1.5.91 === + +2015-09-18 20:12:06 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.5.91 2015-09-17 20:07:34 +0100 Tim-Philipp Müller diff --git a/NEWS b/NEWS index b850a06a9c..e04f318449 100644 --- a/NEWS +++ b/NEWS @@ -1,2 +1,64 @@ -This is GStreamer RTSP Server 1.5.91 +This is GStreamer 1.6.0 + +The GStreamer team is proud to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! + +This release has been in the works for more than a year and is packed with new +features, bug fixes and other improvements. + +See http://gstreamer.freedesktop.org/releases/1.6/ for the full list of +changes. + +Highlights + +- Stereoscopic 3D and multiview video support +- Trick mode API for key-frame only fast-forward/fast-reverse playback etc. +- Improved DTS (decoding timestamp) vs. PTS (presentation timestamp) handling + to account for negative DTS +- New GstVideoConverter API for more optimised and more correct conversion of + raw video frames between all supported formats, with rescaling +- v4l2src now supports renegotiation +- v4l2transform can now do scaling +- V4L2 Element now report Colorimetry properly +- Easier chunked recording of MP4, Matroska, Ogg, MPEG-TS: new splitmuxsink + and multifilesink improvements +- Content Protection signalling API and Common Encryption (CENC) support for + DASH/MP4 +- Many adaptive streaming (DASH, HLS and MSS) improvements +- New PTP and NTP network client clocks and better remote clock tracking + stability +- High-quality text subtitle overlay at display resolutions with glimagesink + or gtkglsink +- RECORD support for the GStreamer RTSP Server +- Retransmissions (RTX) support in RTSP server and client +- RTSP seeking support in client and server has been fixed +- RTCP scheduling improvements and reduced size RTCP support +- MP4/MOV muxer acquired a new "robust" mode of operation which attempts to + keep the output file in a valid state at all times +- Live mixing support in aggregator, audiomixer and compositor was improved a + lot +- compositor now supports rescaling and converting inputs streams on the fly +- New audiointerleave element with proper input synchronisation and live input + support +- Blackmagic Design DeckLink capture and playback card support was rewritten + from scratch; 2k/4k support; mode sensing +- KLV metadata support in RTP and MPEG-TS +- H.265 video encoder (x265), decoders (libav, libde265) and RTP payloader and + depayloaders +- New DTLS plugin and SRTP/DTLS support +- OpenGL3 support, multiple contexts and context propagation, 3D video, + transfer/conversion separation, subtitle blending +- New OpenGL-based QML video sink, Gtk GL video sink, CoreAnimation + CAOpenGLLayerSink video sink +- gst-libav switched to ffmpeg as libav-provider, gains support for + 3D/multiview video, trick modes, and the CAVS codec +- GstHarness API for unit tests +- gst-editing-services got a completely new ges-launch-1.0 interface, improved + mixing support and integration into gst-validate +- gnonlin has been deprecated in favor of nle (Non Linear Engine) in + gst-editing-services +- gst-validate has a new plugin system, an extensive default testsuite, + support for concurrent test runs and valgrind support +- cerbero build tool for SDK binary packages gains new 'bundle-source' command +- Various improvements to the Android, iOS, OS X and Windows platform support diff --git a/RELEASE b/RELEASE index 83f8a3b11f..0230fd55a6 100644 --- a/RELEASE +++ b/RELEASE @@ -1,24 +1,24 @@ -Release notes for GStreamer RTSP Server Library 1.5.91 +Release notes for GStreamer RTSP Server Library 1.6.0 -The GStreamer team is pleased to announce the second release candidate for the -stable 1.6 release series. The 1.6 release series is adding new features on top of -the 1.0, 1.2 and 1.4 series and is part of the API and ABI-stable 1.x release -series of the GStreamer multimedia framework. The final 1.6.0 release is planned -in the next few days unless any major bugs are found. +The GStreamer team is proud to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! -Binaries for Android, iOS, Mac OS X and Windows will be provided separately by -the GStreamer project. +This release has been in the works for more than a year and is packed with new +features, bug fixes and other improvements. + + +See +http://gstreamer.freedesktop.org/releases/1.6/ +for the full list of changes. -Bugs fixed in this release - - * 749095 : rtsp-stream: add API to set UDP buffer size - * 754753 : rtsp-media: don't mutate original string when parsing keymgmt +There were no bugs fixed in this release + ==== Download ==== @@ -53,10 +53,9 @@ Interested developers of the core library, plugins, and applications should subscribe to the gstreamer-devel list. -Applications - Contributors to this release * Jan Schmidt + * Sebastian Dröge * Tim-Philipp Müller   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 752bccc2f7..50b6128ff6 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.5.91], +AC_INIT([GStreamer RTSP Server Library], [1.6.0], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 591, 0, 591) +AS_LIBTOOL(GST, 600, 0, 600) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.5.91 -GSTPB_REQ=1.5.91 -GSTPG_REQ=1.5.91 -GSTPD_REQ=1.5.91 +GST_REQ=1.6.0 +GSTPB_REQ=1.6.0 +GSTPG_REQ=1.6.0 +GSTPD_REQ=1.6.0 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index f17e957006..88dae1f6f6 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.6.0 + 1.6 + + 2015-09-25 + + + + 1.5.91 From 9c513cc53600d599bc3a4dac8388f3eaaf871e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 25 Sep 2015 23:51:17 +0200 Subject: [PATCH 1175/1776] Back to development --- configure.ac | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 50b6128ff6..0943dbc506 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.6.0], +AC_INIT([GStreamer RTSP Server Library], [1.7.0.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 600, 0, 600) +AS_LIBTOOL(GST, 700, 0, 700) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.6.0 -GSTPB_REQ=1.6.0 -GSTPG_REQ=1.6.0 -GSTPD_REQ=1.6.0 +GST_REQ=1.7.0.1 +GSTPB_REQ=1.7.0.1 +GSTPG_REQ=1.7.0.1 +GSTPD_REQ=1.7.0.1 dnl *** autotools stuff **** From 6d20a1c9d91fb245885de11b032df975858b8151 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Thu, 20 Aug 2015 17:01:24 +0900 Subject: [PATCH 1176/1776] rtsp-server: Fix memory leaks when context parse fails When g_option_context_parse fails, context and error variables are not getting free'd which results in memory leaks. Free'ing the same. And replacing g_error_free with g_clear_error, which checks if the error being passed is not NULL and sets the variable to NULL on free'ing. https://bugzilla.gnome.org/show_bug.cgi?id=753863 --- examples/test-launch.c | 2 ++ examples/test-mp4.c | 2 ++ examples/test-ogg.c | 2 ++ examples/test-record.c | 2 ++ examples/test-uri.c | 2 ++ 5 files changed, 10 insertions(+) diff --git a/examples/test-launch.c b/examples/test-launch.c index 24e1271e61..03bcd410aa 100644 --- a/examples/test-launch.c +++ b/examples/test-launch.c @@ -47,6 +47,8 @@ main (int argc, char *argv[]) g_option_context_add_group (optctx, gst_init_get_option_group ()); if (!g_option_context_parse (optctx, &argc, &argv, &error)) { g_printerr ("Error parsing options: %s\n", error->message); + g_option_context_free (optctx); + g_clear_error (&error); return -1; } g_option_context_free (optctx); diff --git a/examples/test-mp4.c b/examples/test-mp4.c index 9bcaab45e2..34b8906aab 100644 --- a/examples/test-mp4.c +++ b/examples/test-mp4.c @@ -102,6 +102,8 @@ main (int argc, char *argv[]) g_option_context_add_group (optctx, gst_init_get_option_group ()); if (!g_option_context_parse (optctx, &argc, &argv, &error)) { g_printerr ("Error parsing options: %s\n", error->message); + g_option_context_free (optctx); + g_clear_error (&error); return -1; } diff --git a/examples/test-ogg.c b/examples/test-ogg.c index c22e638ba2..dc052b42bb 100644 --- a/examples/test-ogg.c +++ b/examples/test-ogg.c @@ -47,6 +47,8 @@ main (int argc, char *argv[]) g_option_context_add_group (optctx, gst_init_get_option_group ()); if (!g_option_context_parse (optctx, &argc, &argv, &error)) { g_printerr ("Error parsing options: %s\n", error->message); + g_option_context_free (optctx); + g_clear_error (&error); return -1; } g_option_context_free (optctx); diff --git a/examples/test-record.c b/examples/test-record.c index 1c375038f5..edd66ad586 100644 --- a/examples/test-record.c +++ b/examples/test-record.c @@ -49,6 +49,8 @@ main (int argc, char *argv[]) g_option_context_add_group (optctx, gst_init_get_option_group ()); if (!g_option_context_parse (optctx, &argc, &argv, &error)) { g_printerr ("Error parsing options: %s\n", error->message); + g_option_context_free (optctx); + g_clear_error (&error); return -1; } diff --git a/examples/test-uri.c b/examples/test-uri.c index 8a9c56c238..784bf9ad6b 100644 --- a/examples/test-uri.c +++ b/examples/test-uri.c @@ -76,6 +76,8 @@ main (int argc, gchar * argv[]) g_option_context_add_group (optctx, gst_init_get_option_group ()); if (!g_option_context_parse (optctx, &argc, &argv, &error)) { g_printerr ("Error parsing options: %s\n", error->message); + g_option_context_free (optctx); + g_clear_error (&error); return -1; } g_option_context_free (optctx); From 6f1cad9237956235e5cf326c1e6394e5ae39433a Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Mon, 28 Sep 2015 17:40:59 +0200 Subject: [PATCH 1177/1776] rtsp-media: Take reference to media that will be prepared default_prepare() takes a transfer-none reference GstRTSPMedia object. Later on a g_idle_source_new() is created and a pointer to the media object is passed as user data. If the media is freed before the idle source is dispatched the media object pointer is invalid, but the idle source callback expects it to still be valid. To fix this a reference to the media object is taken when registering the source callback function and a corresponding release of the reference is done when the souce is destroyed. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=755748 --- gst/rtsp-server/rtsp-media.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index adccff920a..5a6f758ab0 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2603,7 +2603,8 @@ default_prepare (GstRTSPMedia * media, GstRTSPThread * thread) /* do remainder in context */ source = g_idle_source_new (); - g_source_set_callback (source, (GSourceFunc) start_prepare, media, NULL); + g_source_set_callback (source, (GSourceFunc) start_prepare, + g_object_ref (media), (GDestroyNotify) g_object_unref); g_source_attach (source, context); g_source_unref (source); From 3cc2c2c22677c7f8d17c62f4db43db6ff0bbe118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 29 Sep 2015 13:00:51 +0100 Subject: [PATCH 1178/1776] common: update for new suppression Makes check-valgrind pass with glib 2.46 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 9aed1d7a80..6babecd339 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 9aed1d7a80a38b76f9441ecf181942df99f09c38 +Subproject commit 6babecd339cce45223ddb8312400811ba956a16d From a51337974cdb1aa56db5e4ef87a1bb52a7423979 Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Fri, 2 Oct 2015 16:11:05 +0900 Subject: [PATCH 1179/1776] stream: listen to sender ssrc signals https://bugzilla.gnome.org/show_bug.cgi?id=746747 --- examples/test-mp4.c | 22 ++++++++++++++++++++ gst/rtsp-server/rtsp-stream.c | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/examples/test-mp4.c b/examples/test-mp4.c index 34b8906aab..2ebe98c3ad 100644 --- a/examples/test-mp4.c +++ b/examples/test-mp4.c @@ -51,6 +51,26 @@ on_ssrc_active (GObject * session, GObject * source, GstRTSPMedia * media) } } +static void +on_sender_ssrc_active (GObject * session, GObject * source, + GstRTSPMedia * media) +{ + GstStructure *stats; + + GST_INFO ("source %p in session %p is active", source, session); + + g_object_get (source, "stats", &stats, NULL); + if (stats) { + gchar *sstr; + + sstr = gst_structure_to_string (stats); + g_print ("Sender stats:\nstructure: %s\n", sstr); + g_free (sstr); + + gst_structure_free (stats); + } +} + /* signal callback when the media is prepared for streaming. We can get the * session manager for each of the streams and connect to some signals. */ static void @@ -75,6 +95,8 @@ media_prepared_cb (GstRTSPMedia * media) g_signal_connect (session, "on-ssrc-active", (GCallback) on_ssrc_active, media); + g_signal_connect (session, "on-sender-ssrc-active", + (GCallback) on_sender_ssrc_active, media); } } diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4417c4321a..4e5f644b0e 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1682,6 +1682,38 @@ on_timeout (GObject * session, GObject * source, GstRTSPStream * stream) } } +static void +on_new_sender_ssrc (GObject * session, GObject * source, GstRTSPStream * stream) +{ + GST_INFO ("%p: new sender source %p", stream, source); +#ifndef DUMP_STATS + { + GstStructure *stats; + g_object_get (source, "stats", &stats, NULL); + if (stats) { + dump_structure (stats); + gst_structure_free (stats); + } + } +#endif +} + +static void +on_sender_ssrc_active (GObject * session, GObject * source, + GstRTSPStream * stream) +{ +#ifndef DUMP_STATS + { + GstStructure *stats; + g_object_get (source, "stats", &stats, NULL); + if (stats) { + dump_structure (stats); + gst_structure_free (stats); + } + } +#endif +} + static void clear_tr_cache (GstRTSPStreamPrivate * priv, gboolean is_rtp) { @@ -2135,6 +2167,12 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, g_signal_connect (priv->session, "on-timeout", (GCallback) on_timeout, stream); + /* signal for sender ssrc */ + g_signal_connect (priv->session, "on-new-sender-ssrc", + (GCallback) on_new_sender_ssrc, stream); + g_signal_connect (priv->session, "on-sender-ssrc-active", + (GCallback) on_sender_ssrc_active, stream); + for (i = 0; i < 2; i++) { GstPad *teepad, *queuepad; /* For the sender we create this bit of pipeline for both From deedb11ab2ef1f54bca90532f6d92fad0df6815e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 2 Oct 2015 22:25:47 +0300 Subject: [PATCH 1180/1776] Update GLib dependency to 2.40.0 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0943dbc506..e18ae704a5 100644 --- a/configure.ac +++ b/configure.ac @@ -149,7 +149,7 @@ dnl *** checks for library functions *** dnl *** checks for dependancy libraries *** dnl GLib is required -GLIB_REQ=2.32.0 +GLIB_REQ=2.40.0 AC_SUBST([GLIB_REQ]) AG_GST_GLIB_CHECK([$GLIB_REQ]) From 566cfdbbd72fa34f487bccd6dfadd993aba776c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 21 Oct 2015 14:28:47 +0300 Subject: [PATCH 1181/1776] Automatic update of common submodule From 6babecd to b99800a --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 6babecd339..b99800a301 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 6babecd339cce45223ddb8312400811ba956a16d +Subproject commit b99800a301ce85262a9e33e17d5a137610375c24 From afd9104c70bb2e136bf286e640ea10fa6909ecae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 20 Oct 2015 17:29:42 +0300 Subject: [PATCH 1182/1776] Use new GST_ENABLE_EXTRA_CHECKS #define https://bugzilla.gnome.org/show_bug.cgi?id=756870 --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index e18ae704a5..9faf5363af 100644 --- a/configure.ac +++ b/configure.ac @@ -79,6 +79,7 @@ dnl the version check needs to stay here because autopoint greps for it dnl *** check for arguments to configure *** AG_GST_ARG_DISABLE_FATAL_WARNINGS +AG_GST_ARG_ENABLE_EXTRA_CHECKS AG_GST_ARG_DEBUG AG_GST_ARG_VALGRIND From 6cc4f86e5d2a06e16c5483270a770aeb43154ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 21 Oct 2015 14:37:19 +0100 Subject: [PATCH 1183/1776] Automatic update of common submodule From b99800a to b319909 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index b99800a301..b3199090fa 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit b99800a301ce85262a9e33e17d5a137610375c24 +Subproject commit b3199090fa16a545d585a54deaa61b687ac369e1 From 81ae320383894892b4b4b53482a04c998441430d Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Thu, 22 Oct 2015 09:15:21 +0200 Subject: [PATCH 1184/1776] rtsp-stream: Always unref return value of gst_object_get_parent() Fixes a leak of a GstBin in the udp-mcast case. https://bugzilla.gnome.org/show_bug.cgi?id=756968 --- gst/rtsp-server/rtsp-stream.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4e5f644b0e..60442ad382 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2881,7 +2881,6 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, gst_object_unref (pad); gst_object_unref (selpad); } - gst_object_unref (bin); priv->transport_sources = g_list_prepend (priv->transport_sources, source); @@ -2917,6 +2916,8 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, } } + gst_object_unref (bin); + /* fall through for the generic case */ } case GST_RTSP_LOWER_TRANS_UDP: From 2178a7c8714e8bc7c7e9d39f4f8fc11089c70d9b Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Thu, 22 Oct 2015 14:32:30 +0200 Subject: [PATCH 1185/1776] rtspserver: Add udp-mcast transport SETUP test Refactor utility functions in the test file so they can handle more than UDP and TCP as lower transport. https://bugzilla.gnome.org/show_bug.cgi?id=756969 --- tests/check/gst/rtspserver.c | 193 ++++++++++++++++------------------- 1 file changed, 88 insertions(+), 105 deletions(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index fd8b067f29..ec66f99f70 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -39,7 +39,6 @@ #define TEST_MOUNT_POINT "/test" #define TEST_PROTO "RTP/AVP" -#define TEST_PROTO_TCP "RTP/AVP/TCP" #define TEST_ENCODING "X-GST" #define TEST_CLOCK_RATE "90000" @@ -155,6 +154,7 @@ start_server (void) GstRTSPMountPoints *mounts; gchar *service; GstRTSPMediaFactory *factory; + GstRTSPAddressPool *pool; mounts = gst_rtsp_server_get_mount_points (server); @@ -165,6 +165,13 @@ start_server (void) gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); g_object_unref (mounts); + /* use an address pool for multicast */ + pool = gst_rtsp_address_pool_new (); + gst_rtsp_address_pool_add_range (pool, + "224.3.0.0", "224.3.0.10", 5000, 5010, 16); + gst_rtsp_media_factory_set_address_pool (factory, pool); + gst_object_unref (pool); + /* set port to any */ gst_rtsp_server_set_service (server, "0"); @@ -428,9 +435,9 @@ static GstSDPMessage * do_describe (GstRTSPConnection * conn, const gchar * mount_point) { GstSDPMessage *sdp_message; - gchar *content_type; - gchar *content_base; - gchar *body; + gchar *content_type = NULL; + gchar *content_base = NULL; + gchar *body = NULL; gchar *address; gchar *expected_content_base; @@ -467,13 +474,13 @@ do_describe (GstRTSPConnection * conn, const gchar * mount_point) * transport must be freed by the caller. */ static GstRTSPStatusCode do_setup_full (GstRTSPConnection * conn, const gchar * control, - gboolean use_tcp_transport, const GstRTSPRange * client_ports, + GstRTSPLowerTrans lower_transport, const GstRTSPRange * client_ports, const gchar * require, gchar ** session, GstRTSPTransport ** transport, gchar ** unsupported) { GstRTSPStatusCode code; gchar *session_in = NULL; - gchar *transport_string_in = NULL; + GString *transport_string_in = NULL; gchar **session_out = NULL; gchar *transport_string_out = NULL; @@ -486,18 +493,35 @@ do_setup_full (GstRTSPConnection * conn, const gchar * control, } } - if (use_tcp_transport) { - transport_string_in = g_strdup_printf (TEST_PROTO_TCP ";unicast"); - } else { - transport_string_in = - g_strdup_printf (TEST_PROTO ";unicast;client_port=%d-%d", + transport_string_in = g_string_new (TEST_PROTO); + switch (lower_transport) { + case GST_RTSP_LOWER_TRANS_UDP: + transport_string_in = + g_string_append (transport_string_in, "/UDP;unicast"); + break; + case GST_RTSP_LOWER_TRANS_UDP_MCAST: + transport_string_in = + g_string_append (transport_string_in, "/UDP;multicast"); + break; + case GST_RTSP_LOWER_TRANS_TCP: + transport_string_in = + g_string_append (transport_string_in, "/TCP;unicast"); + break; + default: + g_assert_not_reached (); + break; + } + + if (client_ports) { + g_string_append_printf (transport_string_in, ";client_port=%d-%d", client_ports->min, client_ports->max); } + code = do_request_full (conn, GST_RTSP_SETUP, control, session_in, - transport_string_in, NULL, require, NULL, NULL, NULL, session_out, + transport_string_in->str, NULL, require, NULL, NULL, NULL, session_out, &transport_string_out, NULL, unsupported); - g_free (transport_string_in); + g_string_free (transport_string_in, TRUE); if (transport_string_out) { /* create transport */ @@ -519,20 +543,8 @@ do_setup (GstRTSPConnection * conn, const gchar * control, const GstRTSPRange * client_ports, gchar ** session, GstRTSPTransport ** transport) { - return do_setup_full (conn, control, FALSE, client_ports, NULL, session, - transport, NULL); -} - -/* send a SETUP request and receive response. if *session is not NULL, - * it is used in the request. otherwise, *session is set to a returned - * session string that must be freed by the caller. the returned - * transport must be freed by the caller. */ -static GstRTSPStatusCode -do_setup_tcp (GstRTSPConnection * conn, const gchar * control, - gchar ** session, GstRTSPTransport ** transport) -{ - return do_setup_full (conn, control, TRUE, NULL, NULL, session, transport, - NULL); + return do_setup_full (conn, control, GST_RTSP_LOWER_TRANS_UDP, client_ports, + NULL, session, transport, NULL); } /* fixture setup function */ @@ -670,14 +682,15 @@ GST_START_TEST (test_describe_non_existing_mount_point) GST_END_TEST; -GST_START_TEST (test_setup) +static void +do_test_setup (GstRTSPLowerTrans lower_transport) { GstRTSPConnection *conn; GstSDPMessage *sdp_message = NULL; const GstSDPMedia *sdp_media; const gchar *video_control; const gchar *audio_control; - GstRTSPRange client_ports; + GstRTSPRange client_ports = { 0 }; gchar *session = NULL; GstRTSPTransport *video_transport = NULL; GstRTSPTransport *audio_transport = NULL; @@ -698,26 +711,28 @@ GST_START_TEST (test_setup) get_client_ports (&client_ports); /* send SETUP request for video */ - fail_unless (do_setup (conn, video_control, &client_ports, &session, - &video_transport) == GST_RTSP_STS_OK); + fail_unless (do_setup_full (conn, video_control, lower_transport, + &client_ports, NULL, &session, &video_transport, + NULL) == GST_RTSP_STS_OK); GST_DEBUG ("set up video %s, got session '%s'", video_control, session); /* check response from SETUP */ fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP); fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP); - fail_unless (video_transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP); + fail_unless (video_transport->lower_transport == lower_transport); fail_unless (video_transport->mode_play); gst_rtsp_transport_free (video_transport); /* send SETUP request for audio */ - fail_unless (do_setup (conn, audio_control, &client_ports, &session, - &audio_transport) == GST_RTSP_STS_OK); + fail_unless (do_setup_full (conn, audio_control, lower_transport, + &client_ports, NULL, &session, &audio_transport, + NULL) == GST_RTSP_STS_OK); GST_DEBUG ("set up audio %s with session '%s'", audio_control, session); /* check response from SETUP */ fail_unless (audio_transport->trans == GST_RTSP_TRANS_RTP); fail_unless (audio_transport->profile == GST_RTSP_PROFILE_AVP); - fail_unless (audio_transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP); + fail_unless (audio_transport->lower_transport == lower_transport); fail_unless (audio_transport->mode_play); gst_rtsp_transport_free (audio_transport); @@ -733,66 +748,23 @@ GST_START_TEST (test_setup) iterate (); } +GST_START_TEST (test_setup_udp) +{ + do_test_setup (GST_RTSP_LOWER_TRANS_UDP); +} + GST_END_TEST; GST_START_TEST (test_setup_tcp) { - GstRTSPConnection *conn; - GstSDPMessage *sdp_message = NULL; - const GstSDPMedia *sdp_media; - const gchar *video_control; - const gchar *audio_control; - gchar *session = NULL; - GstRTSPTransport *video_transport = NULL; - GstRTSPTransport *audio_transport = NULL; + do_test_setup (GST_RTSP_LOWER_TRANS_TCP); +} - start_server (); +GST_END_TEST; - conn = connect_to_server (test_port, TEST_MOUNT_POINT); - - sdp_message = do_describe (conn, TEST_MOUNT_POINT); - - /* get control strings from DESCRIBE response */ - fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); - sdp_media = gst_sdp_message_get_media (sdp_message, 0); - video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); - sdp_media = gst_sdp_message_get_media (sdp_message, 1); - audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); - - /* send SETUP request for video */ - fail_unless (do_setup_tcp (conn, video_control, &session, - &video_transport) == GST_RTSP_STS_OK); - GST_DEBUG ("set up video %s, got session '%s'", video_control, session); - - /* check response from SETUP */ - fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP); - fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP); - fail_unless (video_transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP); - fail_unless (video_transport->mode_play); - gst_rtsp_transport_free (video_transport); - - /* send SETUP request for audio */ - fail_unless (do_setup_tcp (conn, audio_control, &session, - &audio_transport) == GST_RTSP_STS_OK); - GST_DEBUG ("set up audio %s with session '%s'", audio_control, session); - - /* check response from SETUP */ - fail_unless (audio_transport->trans == GST_RTSP_TRANS_RTP); - fail_unless (audio_transport->profile == GST_RTSP_PROFILE_AVP); - fail_unless (audio_transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP); - fail_unless (audio_transport->mode_play); - gst_rtsp_transport_free (audio_transport); - - /* send TEARDOWN request and check that we get 200 OK */ - fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, - session) == GST_RTSP_STS_OK); - - /* clean up and iterate so the clean-up can finish */ - g_free (session); - gst_sdp_message_free (sdp_message); - gst_rtsp_connection_free (conn); - stop_server (); - iterate (); +GST_START_TEST (test_setup_udp_mcast) +{ + do_test_setup (GST_RTSP_LOWER_TRANS_UDP_MCAST); } GST_END_TEST; @@ -894,17 +866,18 @@ GST_START_TEST (test_setup_with_require_header) get_client_ports (&client_ports); /* send SETUP request for video, with single Require header */ - fail_unless_equals_int (do_setup_full (conn, video_control, FALSE, - &client_ports, "funky-feature", &session, &video_transport, - &unsupported), GST_RTSP_STS_OPTION_NOT_SUPPORTED); + fail_unless_equals_int (do_setup_full (conn, video_control, + GST_RTSP_LOWER_TRANS_UDP, &client_ports, "funky-feature", &session, + &video_transport, &unsupported), GST_RTSP_STS_OPTION_NOT_SUPPORTED); fail_unless_equals_string (unsupported, "funky-feature"); g_free (unsupported); unsupported = NULL; /* send SETUP request for video, with multiple Require headers */ - fail_unless_equals_int (do_setup_full (conn, video_control, FALSE, - &client_ports, "funky-feature, foo-bar, superburst", &session, - &video_transport, &unsupported), GST_RTSP_STS_OPTION_NOT_SUPPORTED); + fail_unless_equals_int (do_setup_full (conn, video_control, + GST_RTSP_LOWER_TRANS_UDP, &client_ports, + "funky-feature, foo-bar, superburst", &session, &video_transport, + &unsupported), GST_RTSP_STS_OPTION_NOT_SUPPORTED); fail_unless_equals_string (unsupported, "funky-feature, foo-bar, superburst"); g_free (unsupported); unsupported = NULL; @@ -1034,7 +1007,7 @@ done: } static void -do_test_play (const gchar * range) +do_test_play_full (const gchar * range, GstRTSPLowerTrans lower_transport) { GstRTSPConnection *conn; GstSDPMessage *sdp_message = NULL; @@ -1062,10 +1035,12 @@ do_test_play (const gchar * range) get_client_ports_full (&client_port, &rtp_socket, &rtcp_socket); /* do SETUP for video and audio */ - fail_unless (do_setup (conn, video_control, &client_port, &session, - &video_transport) == GST_RTSP_STS_OK); - fail_unless (do_setup (conn, audio_control, &client_port, &session, - &audio_transport) == GST_RTSP_STS_OK); + fail_unless (do_setup_full (conn, video_control, lower_transport, + &client_port, NULL, &session, &video_transport, + NULL) == GST_RTSP_STS_OK); + fail_unless (do_setup_full (conn, audio_control, lower_transport, + &client_port, NULL, &session, &audio_transport, + NULL) == GST_RTSP_STS_OK); /* send PLAY request and check that we get 200 OK */ fail_unless (do_request (conn, GST_RTSP_PLAY, NULL, session, NULL, range, @@ -1096,6 +1071,11 @@ do_test_play (const gchar * range) gst_rtsp_connection_free (conn); } +static void +do_test_play (const gchar * range) +{ + do_test_play_full (range, GST_RTSP_LOWER_TRANS_UDP); +} GST_START_TEST (test_play) { @@ -1329,10 +1309,12 @@ GST_START_TEST (test_play_multithreaded_timeout_client) get_client_ports (&client_port); /* do SETUP for video and audio */ - fail_unless (do_setup (conn, video_control, &client_port, &session, - &video_transport) == GST_RTSP_STS_OK); - fail_unless (do_setup (conn, audio_control, &client_port, &session, - &audio_transport) == GST_RTSP_STS_OK); + fail_unless (do_setup_full (conn, video_control, GST_RTSP_LOWER_TRANS_UDP, + &client_port, NULL, &session, &video_transport, + NULL) == GST_RTSP_STS_OK); + fail_unless (do_setup_full (conn, audio_control, GST_RTSP_LOWER_TRANS_UDP, + &client_port, NULL, &session, &audio_transport, + NULL) == GST_RTSP_STS_OK); fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 1); @@ -1923,8 +1905,9 @@ rtspserver_suite (void) tcase_add_test (tc, test_describe); tcase_add_test (tc, test_describe_non_existing_mount_point); tcase_add_test (tc, test_describe_record_media); - tcase_add_test (tc, test_setup); + tcase_add_test (tc, test_setup_udp); tcase_add_test (tc, test_setup_tcp); + tcase_add_test (tc, test_setup_udp_mcast); tcase_add_test (tc, test_setup_twice); tcase_add_test (tc, test_setup_with_require_header); tcase_add_test (tc, test_setup_non_existing_stream); From b90d4ba917dc3a1ad4a080b229a55931bc8e828d Mon Sep 17 00:00:00 2001 From: Marcus Prebble Date: Wed, 11 Nov 2015 14:58:33 +0100 Subject: [PATCH 1186/1776] rtsp-server: Change the logic so we don't pop a NULL context When doing a port scan (e.g. with nmap) the call to GST_RTSP_CHECK() will sometimes fail. This call is made before any context is pushed resulting in an attempt to pop a NULL context. https://bugzilla.gnome.org/show_bug.cgi?id=757949 --- gst/rtsp-server/rtsp-server.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 45ae9dbc36..37a3b0fdf3 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -1191,9 +1191,11 @@ gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition, manage_client (server, client); } else { GST_WARNING_OBJECT (server, "received unknown event %08x", condition); + goto exit_no_ctx; } exit: gst_rtsp_context_pop_current (&ctx); +exit_no_ctx: return G_SOURCE_CONTINUE; @@ -1204,7 +1206,8 @@ accept_failed: GST_ERROR_OBJECT (server, "Could not accept client on socket %p: %s", socket, str); g_free (str); - goto exit; + /* We haven't pushed the context yet, so just return */ + goto exit_no_ctx; } connection_refused: { From 9e92a0307c92e57732a4790669d927563c8e622e Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 17 Nov 2015 01:12:28 +1100 Subject: [PATCH 1187/1776] rtsp-client: Report RECORD and ANNOUNCE as supported in the OPTIONS --- gst/rtsp-server/rtsp-client.c | 1 + tests/check/gst/client.c | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 55f6259ee6..65b04338d5 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2557,6 +2557,7 @@ handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx) GST_RTSP_OPTIONS | GST_RTSP_PAUSE | GST_RTSP_PLAY | + GST_RTSP_RECORD | GST_RTSP_ANNOUNCE | GST_RTSP_SETUP | GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN; diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 57d80e49fd..3f172d19fb 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -21,7 +21,7 @@ #include -static gchar * session_id; +static gchar *session_id; static gint cseq; static guint expected_session_timeout = 60; static const gchar *expected_unsupported_header; @@ -128,7 +128,7 @@ test_response_551 (GstRTSPClient * client, GstRTSPMessage * response, fail_unless (code == GST_RTSP_STS_OPTION_NOT_SUPPORTED); fail_unless (g_str_equal (reason, "Option not supported")); fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_UNSUPPORTED, - &options, 0) == GST_RTSP_OK); + &options, 0) == GST_RTSP_OK); fail_unless (!g_strcmp0 (expected_unsupported_header, options)); fail_unless (version == GST_RTSP_VERSION_1_0); @@ -177,7 +177,7 @@ teardown_client (GstRTSPClient * client) g_object_unref (client); } -static gchar* +static gchar * check_requirements_cb (GstRTSPClient * client, GstRTSPContext * ctx, gchar ** req, gpointer user_data) { @@ -193,7 +193,7 @@ check_requirements_cb (GstRTSPClient * client, GstRTSPContext * ctx, index++; } - return g_string_free (result, FALSE); + return g_string_free (result, FALSE); } GST_START_TEST (test_require) @@ -393,9 +393,11 @@ test_option_response_200 (GstRTSPClient * client, GstRTSPMessage * response, methods = gst_rtsp_options_from_text (str); fail_if (methods == 0); fail_unless (methods == (GST_RTSP_DESCRIBE | + GST_RTSP_ANNOUNCE | GST_RTSP_OPTIONS | GST_RTSP_PAUSE | GST_RTSP_PLAY | + GST_RTSP_RECORD | GST_RTSP_SETUP | GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN)); @@ -572,8 +574,7 @@ send_teardown (GstRTSPClient * client) "rtsp://localhost/test") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, - session_id); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); gst_rtsp_client_set_send_func (client, test_teardown_response_200, NULL, NULL); fail_unless (gst_rtsp_client_handle_message (client, From 75c3a3c095ffa5a2cdf437fb1989f58a42e9c39f Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 17 Nov 2015 01:12:28 +1100 Subject: [PATCH 1188/1776] Add test-record-auth example --- examples/.gitignore | 1 + examples/Makefile.am | 2 +- examples/test-record-auth.c | 130 ++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 examples/test-record-auth.c diff --git a/examples/.gitignore b/examples/.gitignore index b8c175aa99..0907268c82 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -5,6 +5,7 @@ test-mp4 test-ogg test-readme test-record +test-record-auth test-sdp test-video test-video-rtx diff --git a/examples/Makefile.am b/examples/Makefile.am index 0b1495dafc..ca5c913e0d 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,7 +1,7 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ test-launch test-sdp test-uri test-auth \ test-multicast test-multicast2 test-appsrc \ - test-video-rtx test-record \ + test-video-rtx test-record test-record-auth \ test-netclock test-netclock-client #INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/examples/test-record-auth.c b/examples/test-record-auth.c new file mode 100644 index 0000000000..94366ac6a9 --- /dev/null +++ b/examples/test-record-auth.c @@ -0,0 +1,130 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * Copyright (C) 2015 Centricular Ltd + * Author: Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#define DEFAULT_RTSP_PORT "8554" + +static char *port = (char *) DEFAULT_RTSP_PORT; + +static GOptionEntry entries[] = { + {"port", 'p', 0, G_OPTION_ARG_STRING, &port, + "Port to listen on (default: " DEFAULT_RTSP_PORT ")", "PORT"}, + {NULL} +}; + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + GOptionContext *optctx; + GError *error = NULL; + GstRTSPAuth *auth; + GstRTSPToken *token; + gchar *basic; + + optctx = g_option_context_new (" - Test RTSP Server, Launch\n\n" + "Example: \"( decodebin name=depay0 ! autovideosink )\""); + g_option_context_add_main_entries (optctx, entries, NULL); + g_option_context_add_group (optctx, gst_init_get_option_group ()); + if (!g_option_context_parse (optctx, &argc, &argv, &error)) { + g_printerr ("Error parsing options: %s\n", error->message); + return -1; + } + + if (argc < 2) { + g_print ("%s\n", g_option_context_get_help (optctx, TRUE, NULL)); + return 1; + } + g_option_context_free (optctx); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mount points for this server, every server has a default object + * that be used to map uri mount points to media factories */ + mounts = gst_rtsp_server_get_mount_points (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named depay%d. Each + * element with depay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_transport_mode (factory, + GST_RTSP_TRANSPORT_MODE_RECORD); + gst_rtsp_media_factory_set_launch (factory, argv[1]); + gst_rtsp_media_factory_set_latency (factory, 2000); + + /* allow user to access this resource */ + gst_rtsp_media_factory_add_role (factory, "user", + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL); + /* Anonymous users can see but not construct, so get UNAUTHORIZED */ + gst_rtsp_media_factory_add_role (factory, "anonymous", + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, FALSE, NULL); + + /* attach the test factory to the /test url */ + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mounts); + + /* Set up the auth for user account */ + /* make a new authentication manager */ + auth = gst_rtsp_auth_new (); + + /* make default token - anonymous unauthenticated access */ + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "anonymous", NULL); + gst_rtsp_auth_set_default_token (auth, token); + gst_rtsp_token_unref (token); + + /* make user token */ + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + basic = gst_rtsp_auth_make_basic ("user", "password"); + gst_rtsp_auth_add_basic (auth, basic, token); + g_free (basic); + gst_rtsp_token_unref (token); + + /* set as the server authentication manager */ + gst_rtsp_server_set_auth (server, auth); + g_object_unref (auth); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port); + g_main_loop_run (loop); + + return 0; +} From a062b9c562edd7d3456b1be1f00be50b0b27085e Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 17 Nov 2015 01:12:28 +1100 Subject: [PATCH 1189/1776] test-auth: Use an 'anonymous' user for unauthenticated default There's a comment on one of the resources that 'user' and 'admin' shouldn't even be able to see it, but they can if the default token is 'admin2', since that gives them access anyway. --- examples/test-auth.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/test-auth.c b/examples/test-auth.c index eff3c749ac..0087d8a81a 100644 --- a/examples/test-auth.c +++ b/examples/test-auth.c @@ -102,6 +102,10 @@ main (int argc, char *argv[]) gst_rtsp_media_factory_add_role (factory, "admin2", GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, FALSE, NULL); + /* Anonymous user can do the same things as admin2 on this resource */ + gst_rtsp_media_factory_add_role (factory, "anonymous", + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, FALSE, NULL); /* make another factory */ factory = gst_rtsp_media_factory_new (); @@ -124,10 +128,10 @@ main (int argc, char *argv[]) /* make a new authentication manager */ auth = gst_rtsp_auth_new (); - /* make default token, it has the same permissions as admin2 */ + /* make default token, it has no permissions */ token = gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, - "admin2", NULL); + "anonymous", NULL); gst_rtsp_auth_set_default_token (auth, token); gst_rtsp_token_unref (token); From eaf7b1488c0df47528e2933414967024297ec7d9 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 17 Nov 2015 01:12:28 +1100 Subject: [PATCH 1190/1776] test-record-auth: Add the option to build in TLS support --- examples/test-record-auth.c | 48 +++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/examples/test-record-auth.c b/examples/test-record-auth.c index 94366ac6a9..ba9bd4702f 100644 --- a/examples/test-record-auth.c +++ b/examples/test-record-auth.c @@ -23,6 +23,9 @@ #include +/* define this if you want the server to use TLS */ +//#define WITH_TLS + #define DEFAULT_RTSP_PORT "8554" static char *port = (char *) DEFAULT_RTSP_PORT; @@ -45,6 +48,9 @@ main (int argc, char *argv[]) GstRTSPAuth *auth; GstRTSPToken *token; gchar *basic; +#ifdef WITH_TLS + GTlsCertificate *cert; +#endif optctx = g_option_context_new (" - Test RTSP Server, Launch\n\n" "Example: \"( decodebin name=depay0 ! autovideosink )\""); @@ -79,6 +85,13 @@ main (int argc, char *argv[]) GST_RTSP_TRANSPORT_MODE_RECORD); gst_rtsp_media_factory_set_launch (factory, argv[1]); gst_rtsp_media_factory_set_latency (factory, 2000); +#ifdef WITH_TLS + gst_rtsp_media_factory_set_profiles (factory, + GST_RTSP_PROFILE_SAVP | GST_RTSP_PROFILE_SAVPF); +#else + gst_rtsp_media_factory_set_profiles (factory, + GST_RTSP_PROFILE_AVP | GST_RTSP_PROFILE_AVPF); +#endif /* allow user to access this resource */ gst_rtsp_media_factory_add_role (factory, "user", @@ -98,6 +111,37 @@ main (int argc, char *argv[]) /* Set up the auth for user account */ /* make a new authentication manager */ auth = gst_rtsp_auth_new (); +#ifdef WITH_TLS + cert = g_tls_certificate_new_from_pem ("-----BEGIN CERTIFICATE-----" + "MIICJjCCAY+gAwIBAgIBBzANBgkqhkiG9w0BAQUFADCBhjETMBEGCgmSJomT8ixk" + "ARkWA0NPTTEXMBUGCgmSJomT8ixkARkWB0VYQU1QTEUxHjAcBgNVBAsTFUNlcnRp" + "ZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAxMOY2EuZXhhbXBsZS5jb20xHTAbBgkq" + "hkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMB4XDTExMDExNzE5NDcxN1oXDTIxMDEx" + "NDE5NDcxN1owSzETMBEGCgmSJomT8ixkARkWA0NPTTEXMBUGCgmSJomT8ixkARkW" + "B0VYQU1QTEUxGzAZBgNVBAMTEnNlcnZlci5leGFtcGxlLmNvbTBcMA0GCSqGSIb3" + "DQEBAQUAA0sAMEgCQQDYScTxk55XBmbDM9zzwO+grVySE4rudWuzH2PpObIonqbf" + "hRoAalKVluG9jvbHI81eXxCdSObv1KBP1sbN5RzpAgMBAAGjIjAgMAkGA1UdEwQC" + "MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADgYEAYx6fMqT1" + "Gvo0jq88E8mc+bmp4LfXD4wJ7KxYeadQxt75HFRpj4FhFO3DOpVRFgzHlOEo3Fwk" + "PZOKjvkT0cbcoEq5whLH25dHoQxGoVQgFyAP5s+7Vp5AlHh8Y/vAoXeEVyy/RCIH" + "QkhUlAflfDMcrrYjsmwoOPSjhx6Mm/AopX4=" + "-----END CERTIFICATE-----" + "-----BEGIN PRIVATE KEY-----" + "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEA2EnE8ZOeVwZmwzPc" + "88DvoK1ckhOK7nVrsx9j6TmyKJ6m34UaAGpSlZbhvY72xyPNXl8QnUjm79SgT9bG" + "zeUc6QIDAQABAkBRFJZ32VbqWMP9OVwDJLiwC01AlYLnka0mIQZbT/2xq9dUc9GW" + "U3kiVw4lL8v/+sPjtTPCYYdzHHOyDen6znVhAiEA9qJT7BtQvRxCvGrAhr9MS022" + "tTdPbW829BoUtIeH64cCIQDggG5i48v7HPacPBIH1RaSVhXl8qHCpQD3qrIw3FMw" + "DwIga8PqH5Sf5sHedy2+CiK0V4MRfoU4c3zQ6kArI+bEgSkCIQCLA1vXBiE31B5s" + "bdHoYa1BXebfZVd+1Hd95IfEM5mbRwIgSkDuQwV55BBlvWph3U8wVIMIb4GStaH8" + "W535W8UBbEg=" "-----END PRIVATE KEY-----", -1, &error); + if (cert == NULL) { + g_printerr ("failed to parse PEM: %s\n", error->message); + return -1; + } + gst_rtsp_auth_set_tls_certificate (auth, cert); + g_object_unref (cert); +#endif /* make default token - anonymous unauthenticated access */ token = @@ -123,7 +167,11 @@ main (int argc, char *argv[]) gst_rtsp_server_attach (server, NULL); /* start serving */ +#ifdef WITH_TLS + g_print ("stream ready at rtsps://127.0.0.1:%s/test\n", port); +#else g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port); +#endif g_main_loop_run (loop); return 0; From 52fb304ac9a2f690c897ea406bfea40fbeeee653 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 17 Nov 2015 01:12:28 +1100 Subject: [PATCH 1191/1776] examples: Actually use the provided port in the record examples --- examples/test-record-auth.c | 1 + examples/test-record.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/examples/test-record-auth.c b/examples/test-record-auth.c index ba9bd4702f..8c6511763d 100644 --- a/examples/test-record-auth.c +++ b/examples/test-record-auth.c @@ -71,6 +71,7 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); + g_object_set (server, "service", port, NULL); /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ diff --git a/examples/test-record.c b/examples/test-record.c index edd66ad586..437eaf5e62 100644 --- a/examples/test-record.c +++ b/examples/test-record.c @@ -65,6 +65,8 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); + g_object_set (server, "service", port, NULL); + /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ mounts = gst_rtsp_server_get_mount_points (server); From cdc0849dfe74ceb0c151b374251463111f42a414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 17 Nov 2015 12:44:38 +0200 Subject: [PATCH 1192/1776] rtsp-stream: Disable multicast loopback for the multicast udp sources too On POSIX this setting is for sender sockets, on Windows for receiver sockets. Previously we were only setting this for sender sockets, which caused looped back packets to be received on Windows if a multicast transport was used. --- gst/rtsp-server/rtsp-stream.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 60442ad382..3ea6a8200a 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2863,6 +2863,7 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, source->udpsrc[i] = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); g_free (host); + g_object_set (source->udpsrc[i], "loop", FALSE, NULL); if (priv->srcpad) { /* we set and keep these to playing so that they don't cause NO_PREROLL return From 61772cb32644a077750abffcd17c43b01fb93cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 19 Nov 2015 15:01:16 +0200 Subject: [PATCH 1193/1776] rtsp-stream: Only create RTP sending/receiving rtpbin pads if needed Adding them when not needed will start some logic inside rtpbin that might be problematic. Also if e.g. for a sender media we suddenly receive RTP data, we would start up a rtpjitterbuffer and behave in weird ways. We still set up the UDP sources for RTP receiving for a sender media to be able to receive any packets sent by the client for NAT traversal. They will all go to a fakesink though. Having an rtpjitterbuffer in the media pipeline will cause the pipeline to be NO_PREROLL, which will cause deadlocks when seeking the media as it will never receive ASYNC_DONE after a seek. https://bugzilla.gnome.org/show_bug.cgi?id=758319 --- gst/rtsp-server/rtsp-stream.c | 331 ++++++++++++++++++---------------- 1 file changed, 175 insertions(+), 156 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 3ea6a8200a..399f33e707 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2117,32 +2117,33 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, (GCallback) request_pt_map, stream); } - /* get a pad for sending RTP */ - name = g_strdup_printf ("send_rtp_sink_%u", idx); - priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); - g_free (name); - + /* get pads from the RTP session element for sending and receiving + * RTP/RTCP*/ if (priv->srcpad) { + /* get a pad for sending RTP */ + name = g_strdup_printf ("send_rtp_sink_%u", idx); + priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); + g_free (name); + /* link the RTP pad to the session manager, it should not really fail unless * this is not really an RTP pad */ ret = gst_pad_link (priv->srcpad, priv->send_rtp_sink); if (ret != GST_PAD_LINK_OK) goto link_failed; + + name = g_strdup_printf ("send_rtp_src_%u", idx); + priv->send_src[0] = gst_element_get_static_pad (rtpbin, name); + g_free (name); } else { /* Need to connect our sinkpad from here */ g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added, stream); /* EOS */ g_signal_connect (rtpbin, "on-npt-stop", (GCallback) on_npt_stop, stream); - } - /* get pads from the RTP session element for sending and receiving - * RTP/RTCP*/ - name = g_strdup_printf ("send_rtp_src_%u", idx); - priv->send_src[0] = gst_element_get_static_pad (rtpbin, name); - g_free (name); - name = g_strdup_printf ("recv_rtp_sink_%u", idx); - priv->recv_sink[0] = gst_element_get_request_pad (rtpbin, name); - g_free (name); + name = g_strdup_printf ("recv_rtp_sink_%u", idx); + priv->recv_sink[0] = gst_element_get_request_pad (rtpbin, name); + g_free (name); + } name = g_strdup_printf ("send_rtcp_src_%u", idx); priv->send_src[1] = gst_element_get_request_pad (rtpbin, name); @@ -2193,157 +2194,170 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, * When only UDP is allowed, we skip the tee, queue and appsink and link the * udpsink directly to the session. */ - /* add udpsink */ - gst_bin_add (bin, priv->udpsink[i]); - sinkpad = gst_element_get_static_pad (priv->udpsink[i], "sink"); - if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) { - /* make tee for RTP/RTCP */ - priv->tee[i] = gst_element_factory_make ("tee", NULL); - gst_bin_add (bin, priv->tee[i]); + /* Only link the RTP send src if we're going to send RTP, link + * the RTCP send src always */ + if (priv->srcpad || i == 1) { + /* add udpsink */ + gst_bin_add (bin, priv->udpsink[i]); + sinkpad = gst_element_get_static_pad (priv->udpsink[i], "sink"); - /* and link to rtpbin send pad */ - pad = gst_element_get_static_pad (priv->tee[i], "sink"); - gst_pad_link (priv->send_src[i], pad); - gst_object_unref (pad); + if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) { + /* make tee for RTP/RTCP */ + priv->tee[i] = gst_element_factory_make ("tee", NULL); + gst_bin_add (bin, priv->tee[i]); - priv->udpqueue[i] = gst_element_factory_make ("queue", NULL); - g_object_set (priv->udpqueue[i], "max-size-buffers", - 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), NULL); - gst_bin_add (bin, priv->udpqueue[i]); - /* link tee to udpqueue */ - teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); - pad = gst_element_get_static_pad (priv->udpqueue[i], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); + /* and link to rtpbin send pad */ + pad = gst_element_get_static_pad (priv->tee[i], "sink"); + gst_pad_link (priv->send_src[i], pad); + gst_object_unref (pad); - /* link udpqueue to udpsink */ - queuepad = gst_element_get_static_pad (priv->udpqueue[i], "src"); - gst_pad_link (queuepad, sinkpad); - gst_object_unref (queuepad); + priv->udpqueue[i] = gst_element_factory_make ("queue", NULL); + g_object_set (priv->udpqueue[i], "max-size-buffers", + 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), + NULL); + gst_bin_add (bin, priv->udpqueue[i]); + /* link tee to udpqueue */ + teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); + pad = gst_element_get_static_pad (priv->udpqueue[i], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); - /* make queue */ - priv->appqueue[i] = gst_element_factory_make ("queue", NULL); - g_object_set (priv->appqueue[i], "max-size-buffers", - 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), NULL); - gst_bin_add (bin, priv->appqueue[i]); - /* and link to tee */ - teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); - pad = gst_element_get_static_pad (priv->appqueue[i], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); + /* link udpqueue to udpsink */ + queuepad = gst_element_get_static_pad (priv->udpqueue[i], "src"); + gst_pad_link (queuepad, sinkpad); + gst_object_unref (queuepad); - /* make appsink */ - priv->appsink[i] = gst_element_factory_make ("appsink", NULL); - g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); - g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); - gst_bin_add (bin, priv->appsink[i]); - gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), - &sink_cb, stream, NULL); - /* and link to queue */ - queuepad = gst_element_get_static_pad (priv->appqueue[i], "src"); - pad = gst_element_get_static_pad (priv->appsink[i], "sink"); - gst_pad_link (queuepad, pad); - gst_object_unref (pad); - gst_object_unref (queuepad); - } else { - /* else only udpsink needed, link it to the session */ - gst_pad_link (priv->send_src[i], sinkpad); - } - gst_object_unref (sinkpad); + /* make queue */ + priv->appqueue[i] = gst_element_factory_make ("queue", NULL); + g_object_set (priv->appqueue[i], "max-size-buffers", + 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), + NULL); + gst_bin_add (bin, priv->appqueue[i]); + /* and link to tee */ + teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); + pad = gst_element_get_static_pad (priv->appqueue[i], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); - /* For the receiver we create this bit of pipeline for both - * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc - * and it is all funneled into the rtpbin receive pad. - * - * .--------. .--------. .--------. - * | udpsrc | | funnel | | rtpbin | - * | src->sink src->sink | - * '--------' | | '--------' - * .--------. | | - * | appsrc | | | - * | src->sink | - * '--------' '--------' - */ - /* make funnel for the RTP/RTCP receivers */ - priv->funnel[i] = gst_element_factory_make ("funnel", NULL); - gst_bin_add (bin, priv->funnel[i]); - - pad = gst_element_get_static_pad (priv->funnel[i], "src"); - gst_pad_link (pad, priv->recv_sink[i]); - gst_object_unref (pad); - - if (priv->udpsrc_v4[i]) { - if (priv->srcpad) { - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values. This is only relevant for PLAY pipelines */ - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); + /* make appsink */ + priv->appsink[i] = gst_element_factory_make ("appsink", NULL); + g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); + g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); + gst_bin_add (bin, priv->appsink[i]); + gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), + &sink_cb, stream, NULL); + /* and link to queue */ + queuepad = gst_element_get_static_pad (priv->appqueue[i], "src"); + pad = gst_element_get_static_pad (priv->appsink[i], "sink"); + gst_pad_link (queuepad, pad); + gst_object_unref (pad); + gst_object_unref (queuepad); + } else { + /* else only udpsink needed, link it to the session */ + gst_pad_link (priv->send_src[i], sinkpad); } - /* add udpsrc */ - gst_bin_add (bin, priv->udpsrc_v4[i]); - - /* and link to the funnel v4 */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); + gst_object_unref (sinkpad); } - if (priv->udpsrc_v6[i]) { - if (priv->srcpad) { - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); + /* Only connect recv RTP sink if we expect to receive RTP. Connect recv + * RTCP sink always */ + if (priv->sinkpad || i == 1) { + /* For the receiver we create this bit of pipeline for both + * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc + * and it is all funneled into the rtpbin receive pad. + * + * .--------. .--------. .--------. + * | udpsrc | | funnel | | rtpbin | + * | src->sink src->sink | + * '--------' | | '--------' + * .--------. | | + * | appsrc | | | + * | src->sink | + * '--------' '--------' + */ + /* make funnel for the RTP/RTCP receivers */ + priv->funnel[i] = gst_element_factory_make ("funnel", NULL); + gst_bin_add (bin, priv->funnel[i]); + + pad = gst_element_get_static_pad (priv->funnel[i], "src"); + gst_pad_link (pad, priv->recv_sink[i]); + gst_object_unref (pad); + + if (priv->udpsrc_v4[i]) { + if (priv->srcpad) { + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values. This is only relevant for PLAY pipelines */ + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); + } + /* add udpsrc */ + gst_bin_add (bin, priv->udpsrc_v4[i]); + + /* and link to the funnel v4 */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); } - gst_bin_add (bin, priv->udpsrc_v6[i]); - /* and link to the funnel v6 */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - } + if (priv->udpsrc_v6[i]) { + if (priv->srcpad) { + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); + } + gst_bin_add (bin, priv->udpsrc_v6[i]); - if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) { - /* make and add appsrc */ - priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); - priv->appsrc_base_time[i] = -1; - g_object_set (priv->appsrc[i], "format", GST_FORMAT_TIME, NULL); - gst_bin_add (bin, priv->appsrc[i]); - /* and link to the funnel */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->appsrc[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); + /* and link to the funnel v6 */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + } + + if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) { + /* make and add appsrc */ + priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); + priv->appsrc_base_time[i] = -1; + g_object_set (priv->appsrc[i], "format", GST_FORMAT_TIME, NULL); + gst_bin_add (bin, priv->appsrc[i]); + /* and link to the funnel */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->appsrc[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + } } /* check if we need to set to a special state */ if (state != GST_STATE_NULL) { - if (priv->udpsink[i]) + if (priv->udpsink[i] && (priv->srcpad || i == 1)) gst_element_set_state (priv->udpsink[i], state); - if (priv->appsink[i]) + if (priv->appsink[i] && (priv->srcpad || i == 1)) gst_element_set_state (priv->appsink[i], state); - if (priv->appqueue[i]) + if (priv->appqueue[i] && (priv->srcpad || i == 1)) gst_element_set_state (priv->appqueue[i], state); - if (priv->udpqueue[i]) + if (priv->udpqueue[i] && (priv->srcpad || i == 1)) gst_element_set_state (priv->udpqueue[i], state); - if (priv->tee[i]) + if (priv->tee[i] && (priv->srcpad || i == 1)) gst_element_set_state (priv->tee[i], state); - if (priv->funnel[i]) + if (priv->funnel[i] && (priv->sinkpad || i == 1)) gst_element_set_state (priv->funnel[i], state); - if (priv->appsrc[i]) + if (priv->appsrc[i] && (priv->sinkpad || i == 1)) gst_element_set_state (priv->appsrc[i], state); } } - /* be notified of caps changes */ - priv->caps_sig = g_signal_connect (priv->send_src[0], "notify::caps", - (GCallback) caps_notify, stream); + if (priv->srcpad) { + /* be notified of caps changes */ + priv->caps_sig = g_signal_connect (priv->send_src[0], "notify::caps", + (GCallback) caps_notify, stream); + } priv->is_joined = TRUE; g_mutex_unlock (&priv->lock); @@ -2411,15 +2425,16 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, if (priv->srcpad) { gst_pad_unlink (priv->srcpad, priv->send_rtp_sink); + + g_signal_handler_disconnect (priv->send_src[0], priv->caps_sig); + gst_element_release_request_pad (rtpbin, priv->send_rtp_sink); + gst_object_unref (priv->send_rtp_sink); + priv->send_rtp_sink = NULL; } else if (priv->recv_rtp_src) { gst_pad_unlink (priv->recv_rtp_src, priv->sinkpad); gst_object_unref (priv->recv_rtp_src); priv->recv_rtp_src = NULL; } - g_signal_handler_disconnect (priv->send_src[0], priv->caps_sig); - gst_element_release_request_pad (rtpbin, priv->send_rtp_sink); - gst_object_unref (priv->send_rtp_sink); - priv->send_rtp_sink = NULL; for (i = 0; i < 2; i++) { if (priv->udpsink[i]) @@ -2436,7 +2451,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_element_set_state (priv->funnel[i], GST_STATE_NULL); if (priv->appsrc[i]) gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); - if (priv->udpsrc_v4[i]) { + if (priv->udpsrc_v4[i] && (priv->sinkpad || i == 1)) { /* and set udpsrc to NULL now before removing */ gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE); gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); @@ -2444,7 +2459,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, * pads when they finalize */ gst_bin_remove (bin, priv->udpsrc_v4[i]); } - if (priv->udpsrc_v6[i]) { + if (priv->udpsrc_v6[i] && (priv->sinkpad || i == 1)) { gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE); gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); gst_bin_remove (bin, priv->udpsrc_v6[i]); @@ -2461,24 +2476,26 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_bin_remove (bin, s->udpsrc[i]); } - if (priv->udpsink[i]) + if (priv->udpsink[i] && (priv->srcpad || i == 1)) gst_bin_remove (bin, priv->udpsink[i]); - if (priv->appsrc[i]) + if (priv->appsrc[i] && (priv->sinkpad || i == 1)) gst_bin_remove (bin, priv->appsrc[i]); - if (priv->appsink[i]) + if (priv->appsink[i] && (priv->srcpad || i == 1)) gst_bin_remove (bin, priv->appsink[i]); - if (priv->appqueue[i]) + if (priv->appqueue[i] && (priv->srcpad || i == 1)) gst_bin_remove (bin, priv->appqueue[i]); - if (priv->udpqueue[i]) + if (priv->udpqueue[i] && (priv->srcpad || i == 1)) gst_bin_remove (bin, priv->udpqueue[i]); - if (priv->tee[i]) + if (priv->tee[i] && (priv->srcpad || i == 1)) gst_bin_remove (bin, priv->tee[i]); - if (priv->funnel[i]) + if (priv->funnel[i] && (priv->sinkpad || i == 1)) gst_bin_remove (bin, priv->funnel[i]); - gst_element_release_request_pad (rtpbin, priv->recv_sink[i]); - gst_object_unref (priv->recv_sink[i]); - priv->recv_sink[i] = NULL; + if (priv->sinkpad || i == 1) { + gst_element_release_request_pad (rtpbin, priv->recv_sink[i]); + gst_object_unref (priv->recv_sink[i]); + priv->recv_sink[i] = NULL; + } priv->udpsrc_v4[i] = NULL; priv->udpsrc_v6[i] = NULL; @@ -2498,8 +2515,10 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, g_list_free (priv->transport_sources); priv->transport_sources = NULL; - gst_object_unref (priv->send_src[0]); - priv->send_src[0] = NULL; + if (priv->srcpad) { + gst_object_unref (priv->send_src[0]); + priv->send_src[0] = NULL; + } gst_element_release_request_pad (rtpbin, priv->send_src[1]); gst_object_unref (priv->send_src[1]); From 82dffd17b34c408ab2cf9ce3d991068f44757dd7 Mon Sep 17 00:00:00 2001 From: Srimanta Panda Date: Fri, 4 Dec 2015 08:01:37 +0100 Subject: [PATCH 1194/1776] rtsp-stream: create stream pipeline based on transport Based on the protocol, create the rtsp stream pipeline. If only TCP or only UDP is set as the transport protocol, it will not add the extra tee or queue element to the pipeline. Both these elements will be added, if it supports both TCP and UDP protocols. This improves the pipeline performance when one protocol is present. https://bugzilla.gnome.org/show_bug.cgi?id=758179 --- gst/rtsp-server/rtsp-stream.c | 103 +++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 399f33e707..b7756897c1 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2075,8 +2075,9 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, gint i; guint idx; gchar *name; - GstPad *pad, *sinkpad, *selpad; + GstPad *pad, *sinkpad = NULL, *selpad; GstPadLinkReturn ret; + gboolean is_tcp = FALSE, is_udp = FALSE; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); g_return_val_if_fail (GST_IS_BIN (bin), FALSE); @@ -2093,7 +2094,12 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, GST_INFO ("stream %p joining bin as session %u", stream, idx); - if (!alloc_ports (stream)) + is_tcp = priv->protocols & GST_RTSP_LOWER_TRANS_TCP; + + is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || + (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); + + if (is_udp && !alloc_ports (stream)) goto no_ports; /* update the dscp qos field in the sinks */ @@ -2180,7 +2186,8 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, * RTP and RTCP. Sync and preroll are enabled on udpsink so * we need to add a queue before appsink and udpsink to make * the pipeline not block. For the TCP case, we want to pump - * data to the client as fast as possible. + * client as fast as possible anyway. This pipeline is used + * when both TCP and UDP are present. * * .--------. .-----. .---------. .---------. * | rtpbin | | tee | | queue | | udpsink | @@ -2191,18 +2198,32 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, * | src->sink src->sink | * '-----' '---------' '---------' * - * When only UDP is allowed, we skip the tee, queue and appsink and link the - * udpsink directly to the session. + * When only UDP or only TCP is allowed, we skip the tee and queue + * and link the udpsink (for UDP) or appsink (for TCP) directly to + * the session. */ /* Only link the RTP send src if we're going to send RTP, link * the RTCP send src always */ if (priv->srcpad || i == 1) { - /* add udpsink */ - gst_bin_add (bin, priv->udpsink[i]); - sinkpad = gst_element_get_static_pad (priv->udpsink[i], "sink"); + if (is_udp) { + /* add udpsink */ + gst_bin_add (bin, priv->udpsink[i]); + sinkpad = gst_element_get_static_pad (priv->udpsink[i], "sink"); + } + + if (is_tcp) { + /* make appsink */ + priv->appsink[i] = gst_element_factory_make ("appsink", NULL); + g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); + gst_bin_add (bin, priv->appsink[i]); + gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), + &sink_cb, stream, NULL); + } + + if (is_udp && is_tcp) { + g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); - if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) { /* make tee for RTP/RTCP */ priv->tee[i] = gst_element_factory_make ("tee", NULL); gst_bin_add (bin, priv->tee[i]); @@ -2228,38 +2249,43 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, queuepad = gst_element_get_static_pad (priv->udpqueue[i], "src"); gst_pad_link (queuepad, sinkpad); gst_object_unref (queuepad); + gst_object_unref (sinkpad); - /* make queue */ + /* make appqueue */ priv->appqueue[i] = gst_element_factory_make ("queue", NULL); g_object_set (priv->appqueue[i], "max-size-buffers", 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), NULL); gst_bin_add (bin, priv->appqueue[i]); - /* and link to tee */ + /* and link tee to appqueue */ teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); pad = gst_element_get_static_pad (priv->appqueue[i], "sink"); gst_pad_link (teepad, pad); gst_object_unref (pad); gst_object_unref (teepad); - /* make appsink */ - priv->appsink[i] = gst_element_factory_make ("appsink", NULL); - g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); - g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); - gst_bin_add (bin, priv->appsink[i]); - gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), - &sink_cb, stream, NULL); - /* and link to queue */ + /* and link appqueue to appsink */ queuepad = gst_element_get_static_pad (priv->appqueue[i], "src"); pad = gst_element_get_static_pad (priv->appsink[i], "sink"); gst_pad_link (queuepad, pad); gst_object_unref (pad); gst_object_unref (queuepad); + } else if (is_tcp) { + /* only appsink needed, link it to the session */ + pad = gst_element_get_static_pad (priv->appsink[i], "sink"); + gst_pad_link (priv->send_src[i], pad); + gst_object_unref (pad); + + /* when its only TCP, we need to set sync and preroll to FALSE + * for the sink to avoid deadlock. And this is only needed for + * sink used for RTCP data, not the RTP data. */ + if (i == 1) + g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); } else { /* else only udpsink needed, link it to the session */ gst_pad_link (priv->send_src[i], sinkpad); + gst_object_unref (sinkpad); } - gst_object_unref (sinkpad); } /* Only connect recv RTP sink if we expect to receive RTP. Connect recv @@ -2319,7 +2345,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, gst_object_unref (selpad); } - if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) { + if (is_tcp) { /* make and add appsrc */ priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); priv->appsrc_base_time[i] = -1; @@ -2403,6 +2429,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, GstRTSPStreamPrivate *priv; gint i; GList *l; + gboolean is_tcp, is_udp; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); g_return_val_if_fail (GST_IS_BIN (bin), FALSE); @@ -2436,6 +2463,12 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->recv_rtp_src = NULL; } + is_tcp = priv->protocols & GST_RTSP_LOWER_TRANS_TCP; + + is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || + (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); + + for (i = 0; i < 2; i++) { if (priv->udpsink[i]) gst_element_set_state (priv->udpsink[i], GST_STATE_NULL); @@ -2476,17 +2509,17 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_bin_remove (bin, s->udpsrc[i]); } - if (priv->udpsink[i] && (priv->srcpad || i == 1)) + if (priv->udpsink[i] && is_udp && (priv->srcpad || i == 1)) gst_bin_remove (bin, priv->udpsink[i]); if (priv->appsrc[i] && (priv->sinkpad || i == 1)) gst_bin_remove (bin, priv->appsrc[i]); - if (priv->appsink[i] && (priv->srcpad || i == 1)) + if (priv->appsink[i] && is_tcp && (priv->srcpad || i == 1)) gst_bin_remove (bin, priv->appsink[i]); - if (priv->appqueue[i] && (priv->srcpad || i == 1)) + if (priv->appqueue[i] && is_tcp && is_udp && (priv->srcpad || i == 1)) gst_bin_remove (bin, priv->appqueue[i]); - if (priv->udpqueue[i] && (priv->srcpad || i == 1)) + if (priv->udpqueue[i] && is_tcp && is_udp && (priv->srcpad || i == 1)) gst_bin_remove (bin, priv->udpqueue[i]); - if (priv->tee[i] && (priv->srcpad || i == 1)) + if (priv->tee[i] && is_tcp && is_udp && (priv->srcpad || i == 1)) gst_bin_remove (bin, priv->tee[i]); if (priv->funnel[i] && (priv->sinkpad || i == 1)) gst_bin_remove (bin, priv->funnel[i]); @@ -3409,7 +3442,14 @@ gst_rtsp_stream_query_position (GstRTSPStream * stream, gint64 * position) priv = stream->priv; g_mutex_lock (&priv->lock); - if ((sink = priv->udpsink[0])) + /* depending on the transport type, it should query corresponding sink */ + if ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || + (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)) + sink = priv->udpsink[0]; + else + sink = priv->appsink[0]; + + if (sink) gst_object_ref (sink); g_mutex_unlock (&priv->lock); @@ -3444,7 +3484,14 @@ gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop) priv = stream->priv; g_mutex_lock (&priv->lock); - if ((sink = priv->udpsink[0])) + /* depending on the transport type, it should query corresponding sink */ + if ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || + (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)) + sink = priv->udpsink[0]; + else + sink = priv->appsink[0]; + + if (sink) gst_object_ref (sink); g_mutex_unlock (&priv->lock); From ed70572c6c0553d00add06aaf6304012bff82cb9 Mon Sep 17 00:00:00 2001 From: Srimanta Panda Date: Wed, 18 Nov 2015 11:14:39 +0100 Subject: [PATCH 1195/1776] rtsp-client: suspend media during setup request SETUP request from clients needs to suspend the media to clear the prerolled buffers. Otherwise it will not affect the prerolled buffer and the prerolled buffers will be incorrect (for example block-size from setup request will not affect the prerolled buffer unless the media is suspended). https://bugzilla.gnome.org/show_bug.cgi?id=758268 --- gst/rtsp-server/rtsp-client.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 65b04338d5..0a33e45321 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1823,6 +1823,9 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (sessmedia == NULL) { /* get a handle to the configuration of the media in the session */ media = find_media (client, ctx, path, &matched); + /* need to suspend the media, if the protocol has changed */ + if (media != NULL) + gst_rtsp_media_suspend (media); } else { if ((media = gst_rtsp_session_media_get_media (sessmedia))) g_object_ref (media); From b4bfef6162f074f70bdac8e7fc8eeb2d04ccf9f6 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Mon, 7 Dec 2015 09:11:35 -0500 Subject: [PATCH 1196/1776] Automatic update of common submodule From b319909 to 86e4663 --- autogen.sh | 6 +++++- common | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/autogen.sh b/autogen.sh index 265d4f5505..82a6ea4c62 100755 --- a/autogen.sh +++ b/autogen.sh @@ -37,7 +37,11 @@ fi if test ! \( -x .git/hooks/pre-commit -a -L .git/hooks/pre-commit \); then rm -f .git/hooks/pre-commit - ln -s ../../common/hooks/pre-commit.hook .git/hooks/pre-commit + if ! ln -s ../../common/hooks/pre-commit.hook .git/hooks/pre-commit 2> /dev/null + then + echo "Failed to create commit hook symlink, copying instead ..." + cp common/hooks/pre-commit.hook .git/hooks/pre-commit + fi fi # GNU gettext automake support doesn't get along with git. diff --git a/common b/common index b3199090fa..86e46630ed 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit b3199090fa16a545d585a54deaa61b687ac369e1 +Subproject commit 86e46630ed8af8d94796859db550a9c3d89c9f65 From f96947b350857ae41178703b6f45591857ab8ead Mon Sep 17 00:00:00 2001 From: Srimanta Panda Date: Tue, 8 Dec 2015 08:27:20 +0100 Subject: [PATCH 1197/1776] rtsp-stream: fixed valgrind error Fixed the valgrind error in unit test. The UDP source created during gst_rtsp_stream_join_bin() was not released while destroying the rtp bin. https://bugzilla.gnome.org/show_bug.cgi?id=759010 --- gst/rtsp-server/rtsp-stream.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index b7756897c1..f3299116c5 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2484,18 +2484,31 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_element_set_state (priv->funnel[i], GST_STATE_NULL); if (priv->appsrc[i]) gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); - if (priv->udpsrc_v4[i] && (priv->sinkpad || i == 1)) { - /* and set udpsrc to NULL now before removing */ - gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE); - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); - /* removing them should also nicely release the request - * pads when they finalize */ - gst_bin_remove (bin, priv->udpsrc_v4[i]); + + if (priv->udpsrc_v4[i]) { + if (priv->sinkpad || i == 1) { + /* and set udpsrc to NULL now before removing */ + gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE); + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); + /* removing them should also nicely release the request + * pads when they finalize */ + gst_bin_remove (bin, priv->udpsrc_v4[i]); + } else { + /* we need to set the state to NULL before unref */ + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_v4[i]); + } } - if (priv->udpsrc_v6[i] && (priv->sinkpad || i == 1)) { - gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE); - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); - gst_bin_remove (bin, priv->udpsrc_v6[i]); + + if (priv->udpsrc_v6[i]) { + if (priv->sinkpad || i == 1) { + gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE); + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); + gst_bin_remove (bin, priv->udpsrc_v6[i]); + } else { + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_v6[i]); + } } for (l = priv->transport_sources; l; l = l->next) { From 0ea68a1b0ff01725892b666eb8a4299a75ec39b1 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Tue, 10 Nov 2015 14:17:18 -0500 Subject: [PATCH 1198/1776] rtsp-server: Add g_autoptr() support to all types https://bugzilla.gnome.org/show_bug.cgi?id=754464 --- gst/rtsp-server/rtsp-address-pool.h | 8 ++++++++ gst/rtsp-server/rtsp-auth.h | 4 ++++ gst/rtsp-server/rtsp-client.h | 4 ++++ gst/rtsp-server/rtsp-media-factory-uri.h | 4 ++++ gst/rtsp-server/rtsp-media-factory.h | 4 ++++ gst/rtsp-server/rtsp-media.h | 4 ++++ gst/rtsp-server/rtsp-mount-points.h | 4 ++++ gst/rtsp-server/rtsp-permissions.h | 4 ++++ gst/rtsp-server/rtsp-server.h | 4 ++++ gst/rtsp-server/rtsp-session-media.h | 4 ++++ gst/rtsp-server/rtsp-session-pool.h | 4 ++++ gst/rtsp-server/rtsp-session.h | 4 ++++ gst/rtsp-server/rtsp-stream-transport.h | 4 ++++ gst/rtsp-server/rtsp-stream.h | 4 ++++ gst/rtsp-server/rtsp-thread-pool.h | 8 ++++++++ gst/rtsp-server/rtsp-token.h | 4 ++++ 16 files changed, 72 insertions(+) diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index a473bdfd18..654d10653b 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -177,6 +177,14 @@ GstRTSPAddressPoolResult gst_rtsp_address_pool_reserve_address (GstRTSPAddressP gboolean gst_rtsp_address_pool_has_unicast_addresses (GstRTSPAddressPool * pool); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPAddress, gst_rtsp_address_free) +#endif + +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPAddressPool, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_ADDRESS_POOL_H__ */ diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index ac44b28794..b5b5f4c0b1 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -178,6 +178,10 @@ gchar * gst_rtsp_auth_make_basic (const gchar * user, const g */ #define GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT "media.factory.construct" +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPAuth, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_AUTH_H__ */ diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 6b05448799..766e97dc95 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -197,6 +197,10 @@ GList * gst_rtsp_client_session_filter (GstRTSPClient *client, +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPClient, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_CLIENT_H__ */ diff --git a/gst/rtsp-server/rtsp-media-factory-uri.h b/gst/rtsp-server/rtsp-media-factory-uri.h index 6dc3a402d3..d6f68071a2 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.h +++ b/gst/rtsp-server/rtsp-media-factory-uri.h @@ -75,6 +75,10 @@ void gst_rtsp_media_factory_uri_set_uri (GstRTSPMediaFactoryUR const gchar *uri); gchar * gst_rtsp_media_factory_uri_get_uri (GstRTSPMediaFactoryURI *factory); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPMediaFactoryURI, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_MEDIA_FACTORY_URI_H__ */ diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 1382426360..0dc1067e27 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -164,6 +164,10 @@ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFacto GstElement * gst_rtsp_media_factory_create_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPMediaFactory, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_MEDIA_FACTORY_H__ */ diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index f1be13c3e4..d554afe769 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -258,6 +258,10 @@ gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstS void gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPMedia, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_MEDIA_H__ */ diff --git a/gst/rtsp-server/rtsp-mount-points.h b/gst/rtsp-server/rtsp-mount-points.h index ed13d5924a..bf89b0b63f 100644 --- a/gst/rtsp-server/rtsp-mount-points.h +++ b/gst/rtsp-server/rtsp-mount-points.h @@ -86,6 +86,10 @@ void gst_rtsp_mount_points_add_factory (GstRTSPMountPoints * void gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints *mounts, const gchar *path); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPMountPoints, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_MOUNT_POINTS_H__ */ diff --git a/gst/rtsp-server/rtsp-permissions.h b/gst/rtsp-server/rtsp-permissions.h index 9e739c79d7..5b0bcad032 100644 --- a/gst/rtsp-server/rtsp-permissions.h +++ b/gst/rtsp-server/rtsp-permissions.h @@ -96,6 +96,10 @@ const GstStructure * gst_rtsp_permissions_get_role (GstRTSPPermissions * gboolean gst_rtsp_permissions_is_allowed (GstRTSPPermissions *permissions, const gchar *role, const gchar *permission); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPPermissions, gst_rtsp_permissions_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_PERMISSIONS_H__ */ diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 9a6f9d4a1f..521c0beabd 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -164,6 +164,10 @@ GList * gst_rtsp_server_client_filter (GstRTSPServer *server, GstRTSPServerClientFilterFunc func, gpointer user_data); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPServer, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_SERVER_H__ */ diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index e2af5ad8b8..3f7208ccc3 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -92,6 +92,10 @@ gboolean gst_rtsp_session_media_alloc_channels (GstRTSPSessionMe gchar * gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPSessionMedia, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_SESSION_MEDIA_H__ */ diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index e2ba951e8f..dd833ae902 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -138,6 +138,10 @@ GList * gst_rtsp_session_pool_filter (GstRTSPSessionPoo guint gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool); GSource * gst_rtsp_session_pool_create_watch (GstRTSPSessionPool *pool); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPSessionPool, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_SESSION_POOL_H__ */ diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 8bd6ca954e..9a438fb3c1 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -142,6 +142,10 @@ GList * gst_rtsp_session_filter (GstRTSPSession *sess, gpointer user_data); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPSession, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_SESSION_H__ */ diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index c3ee257cf2..8e2d366972 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -131,6 +131,10 @@ gboolean gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamT GstFlowReturn gst_rtsp_stream_transport_recv_data (GstRTSPStreamTransport *trans, guint channel, GstBuffer *buffer); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPStreamTransport, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_STREAM_TRANSPORT_H__ */ diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 0042f67de2..c045ebd618 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -193,6 +193,10 @@ GList * gst_rtsp_stream_transport_filter (GstRTSPStream *stream, GstRTSPStreamTransportFilterFunc func, gpointer user_data); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPStream, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_STREAM_H__ */ diff --git a/gst/rtsp-server/rtsp-thread-pool.h b/gst/rtsp-server/rtsp-thread-pool.h index e360034be8..3799b58f35 100644 --- a/gst/rtsp-server/rtsp-thread-pool.h +++ b/gst/rtsp-server/rtsp-thread-pool.h @@ -174,6 +174,14 @@ GstRTSPThread * gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool *poo GstRTSPThreadType type, GstRTSPContext *ctx); void gst_rtsp_thread_pool_cleanup (void); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPThread, gst_rtsp_thread_unref) +#endif + +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPThreadPool, gst_object_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_THREAD_POOL_H__ */ diff --git a/gst/rtsp-server/rtsp-token.h b/gst/rtsp-server/rtsp-token.h index 265d8d30d9..44e725b150 100644 --- a/gst/rtsp-server/rtsp-token.h +++ b/gst/rtsp-server/rtsp-token.h @@ -92,6 +92,10 @@ const gchar * gst_rtsp_token_get_string (GstRTSPToken *token, const gchar *field); gboolean gst_rtsp_token_is_allowed (GstRTSPToken *token, const gchar *field); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPToken, gst_rtsp_token_unref) +#endif + G_END_DECLS #endif /* __GST_RTSP_TOKEN_H__ */ From ee3a7b61ef43742cb614f3083b7b34de1339f638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 17 Nov 2015 22:30:54 -0500 Subject: [PATCH 1199/1776] rtsp-session-pool: Avoid dollar sign ($) in session ids Live555 in VLC strips off dollar signs and then gets very confused, we don't loose too much entropy by just skipping it. --- gst/rtsp-server/rtsp-session-pool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index ea1ff18e4d..60aa30c49c 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -67,7 +67,7 @@ static const gchar session_id_charset[] = 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '$', '-', '_', '.', '+' + '8', '9', '-', '_', '.', '+' /* '$' Live555 in VLC strips off $ chars */ }; enum From c934fdaf3b63ed156ef4dbc73afaf59c4e30a6fa Mon Sep 17 00:00:00 2001 From: Koop Mast Date: Mon, 21 Dec 2015 00:43:49 +0100 Subject: [PATCH 1200/1776] configure: Make -Bsymbolic check work with clang. Update the -Bsymbolic check with the version glib has. This version works with clang. https://bugzilla.gnome.org/show_bug.cgi?id=759713 --- configure.ac | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 9faf5363af..57cc6dad1e 100644 --- a/configure.ac +++ b/configure.ac @@ -192,15 +192,16 @@ dnl Check for -Bsymbolic-functions linker flag used to avoid dnl intra-library PLT jumps, if available. AC_ARG_ENABLE(Bsymbolic, [AS_HELP_STRING([--disable-Bsymbolic],[avoid linking with -Bsymbolic])],, - [SAVED_LDFLAGS="${LDFLAGS}" + [SAVED_LDFLAGS="${LDFLAGS}" SAVED_LIBS="${LIBS}" AC_MSG_CHECKING([for -Bsymbolic-functions linker flag]) LDFLAGS=-Wl,-Bsymbolic-functions - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int main (void) { return 0; }]])],[ + LIBS= + AC_TRY_LINK([], [return 0], AC_MSG_RESULT(yes) - enable_Bsymbolic=yes],[ + enable_Bsymbolic=yes, AC_MSG_RESULT(no) - enable_Bsymbolic=no]) - LDFLAGS="${SAVED_LDFLAGS}"]) + enable_Bsymbolic=no) + LDFLAGS="${SAVED_LDFLAGS}" LIBS="${SAVED_LIBS}"]) dnl *** set variables based on configure arguments *** From 7374976722852c93e59c3cee2a562f947cb7f310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Dec 2015 14:54:06 +0100 Subject: [PATCH 1201/1776] Release 1.7.1 --- ChangeLog | 239 ++++++++++++++++++++++++++++++++++++++++++- NEWS | 64 +----------- RELEASE | 41 +++++--- configure.ac | 12 +-- gst-rtsp-server.doap | 30 ++++++ 5 files changed, 302 insertions(+), 84 deletions(-) diff --git a/ChangeLog b/ChangeLog index 62ce38fc42..a931568174 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,242 @@ -=== release 1.6.0 === +=== release 1.7.1 === -2015-09-25 Sebastian Dröge +2015-12-24 Sebastian Dröge * configure.ac: - releasing 1.6.0 + releasing 1.7.1 + +2015-12-21 00:43:49 +0100 Koop Mast + + * configure.ac: + configure: Make -Bsymbolic check work with clang. + Update the -Bsymbolic check with the version glib has. This version + works with clang. + https://bugzilla.gnome.org/show_bug.cgi?id=759713 + +2015-11-17 22:30:54 -0500 Olivier Crête + + * gst/rtsp-server/rtsp-session-pool.c: + rtsp-session-pool: Avoid dollar sign ($) in session ids + Live555 in VLC strips off dollar signs and then gets very confused, + we don't loose too much entropy by just skipping it. + +2015-11-10 14:17:18 -0500 Xavier Claessens + + * gst/rtsp-server/rtsp-address-pool.h: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media-factory-uri.h: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-mount-points.h: + * gst/rtsp-server/rtsp-permissions.h: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.h: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.h: + * gst/rtsp-server/rtsp-thread-pool.h: + * gst/rtsp-server/rtsp-token.h: + rtsp-server: Add g_autoptr() support to all types + https://bugzilla.gnome.org/show_bug.cgi?id=754464 + +2015-12-08 08:27:20 +0100 Srimanta Panda + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: fixed valgrind error + Fixed the valgrind error in unit test. The UDP source created during + gst_rtsp_stream_join_bin() was not released while destroying the rtp + bin. + https://bugzilla.gnome.org/show_bug.cgi?id=759010 + +2015-12-07 09:11:35 -0500 Nicolas Dufresne + + * autogen.sh: + * common: + Automatic update of common submodule + From b319909 to 86e4663 + +2015-11-18 11:14:39 +0100 Srimanta Panda + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: suspend media during setup request + SETUP request from clients needs to suspend the media to clear the + prerolled buffers. Otherwise it will not affect the prerolled buffer + and the prerolled buffers will be incorrect (for example block-size + from setup request will not affect the prerolled buffer unless the + media is suspended). + https://bugzilla.gnome.org/show_bug.cgi?id=758268 + +2015-12-04 08:01:37 +0100 Srimanta Panda + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: create stream pipeline based on transport + Based on the protocol, create the rtsp stream pipeline. If only TCP or + only UDP is set as the transport protocol, it will not add the extra tee + or queue element to the pipeline. Both these elements will be added, if + it supports both TCP and UDP protocols. This improves the pipeline + performance when one protocol is present. + https://bugzilla.gnome.org/show_bug.cgi?id=758179 + +2015-11-19 15:01:16 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Only create RTP sending/receiving rtpbin pads if needed + Adding them when not needed will start some logic inside rtpbin that might be + problematic. Also if e.g. for a sender media we suddenly receive RTP data, we + would start up a rtpjitterbuffer and behave in weird ways. + We still set up the UDP sources for RTP receiving for a sender media to be + able to receive any packets sent by the client for NAT traversal. They will + all go to a fakesink though. + Having an rtpjitterbuffer in the media pipeline will cause the pipeline to be + NO_PREROLL, which will cause deadlocks when seeking the media as it will never + receive ASYNC_DONE after a seek. + https://bugzilla.gnome.org/show_bug.cgi?id=758319 + +2015-11-17 12:44:38 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Disable multicast loopback for the multicast udp sources too + On POSIX this setting is for sender sockets, on Windows for receiver sockets. + Previously we were only setting this for sender sockets, which caused looped + back packets to be received on Windows if a multicast transport was used. + +2015-11-17 01:12:28 +1100 Jan Schmidt + + * examples/test-record-auth.c: + * examples/test-record.c: + examples: Actually use the provided port in the record examples + +2015-11-17 01:12:28 +1100 Jan Schmidt + + * examples/test-record-auth.c: + test-record-auth: Add the option to build in TLS support + +2015-11-17 01:12:28 +1100 Jan Schmidt + + * examples/test-auth.c: + test-auth: Use an 'anonymous' user for unauthenticated default + There's a comment on one of the resources that 'user' and 'admin' + shouldn't even be able to see it, but they can if the default + token is 'admin2', since that gives them access anyway. + +2015-11-17 01:12:28 +1100 Jan Schmidt + + * examples/.gitignore: + * examples/Makefile.am: + * examples/test-record-auth.c: + Add test-record-auth example + +2015-11-17 01:12:28 +1100 Jan Schmidt + + * gst/rtsp-server/rtsp-client.c: + * tests/check/gst/client.c: + rtsp-client: Report RECORD and ANNOUNCE as supported in the OPTIONS + +2015-11-11 14:58:33 +0100 Marcus Prebble + + * gst/rtsp-server/rtsp-server.c: + rtsp-server: Change the logic so we don't pop a NULL context + When doing a port scan (e.g. with nmap) the call to GST_RTSP_CHECK() + will sometimes fail. This call is made before any context is pushed + resulting in an attempt to pop a NULL context. + https://bugzilla.gnome.org/show_bug.cgi?id=757949 + +2015-10-22 14:32:30 +0200 David Svensson Fors + + * tests/check/gst/rtspserver.c: + rtspserver: Add udp-mcast transport SETUP test + Refactor utility functions in the test file so they can handle + more than UDP and TCP as lower transport. + https://bugzilla.gnome.org/show_bug.cgi?id=756969 + +2015-10-22 09:15:21 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Always unref return value of gst_object_get_parent() + Fixes a leak of a GstBin in the udp-mcast case. + https://bugzilla.gnome.org/show_bug.cgi?id=756968 + +2015-10-21 14:37:19 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From b99800a to b319909 + +2015-10-20 17:29:42 +0300 Sebastian Dröge + + * configure.ac: + Use new GST_ENABLE_EXTRA_CHECKS #define + https://bugzilla.gnome.org/show_bug.cgi?id=756870 + +2015-10-21 14:28:47 +0300 Sebastian Dröge + + * common: + Automatic update of common submodule + From 6babecd to b99800a + +2015-10-02 22:25:47 +0300 Sebastian Dröge + + * configure.ac: + Update GLib dependency to 2.40.0 + +2015-10-02 16:11:05 +0900 Hyunjun Ko + + * examples/test-mp4.c: + * gst/rtsp-server/rtsp-stream.c: + stream: listen to sender ssrc signals + https://bugzilla.gnome.org/show_bug.cgi?id=746747 + +2015-09-29 13:00:51 +0100 Tim-Philipp Müller + + * common: + common: update for new suppression + Makes check-valgrind pass with glib 2.46 + +2015-09-28 17:40:59 +0200 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Take reference to media that will be prepared + default_prepare() takes a transfer-none reference GstRTSPMedia object. + Later on a g_idle_source_new() is created and a pointer to the media + object is passed as user data. If the media is freed before the idle + source is dispatched the media object pointer is invalid, but the idle + source callback expects it to still be valid. To fix this a reference to + the media object is taken when registering the source callback function + and a corresponding release of the reference is done when the souce is + destroyed. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=755748 + +2015-08-20 17:01:24 +0900 Vineeth TM + + * examples/test-launch.c: + * examples/test-mp4.c: + * examples/test-ogg.c: + * examples/test-record.c: + * examples/test-uri.c: + rtsp-server: Fix memory leaks when context parse fails + When g_option_context_parse fails, context and error variables are not getting free'd + which results in memory leaks. Free'ing the same. + And replacing g_error_free with g_clear_error, which checks if the error being passed + is not NULL and sets the variable to NULL on free'ing. + https://bugzilla.gnome.org/show_bug.cgi?id=753863 + +2015-09-25 23:51:17 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.6.0 === + +2015-09-25 23:32:52 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.6.0 === release 1.5.91 === diff --git a/NEWS b/NEWS index e04f318449..a4bffc6a6b 100644 --- a/NEWS +++ b/NEWS @@ -1,64 +1,2 @@ -This is GStreamer 1.6.0 - -The GStreamer team is proud to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! - -This release has been in the works for more than a year and is packed with new -features, bug fixes and other improvements. - -See http://gstreamer.freedesktop.org/releases/1.6/ for the full list of -changes. - -Highlights - -- Stereoscopic 3D and multiview video support -- Trick mode API for key-frame only fast-forward/fast-reverse playback etc. -- Improved DTS (decoding timestamp) vs. PTS (presentation timestamp) handling - to account for negative DTS -- New GstVideoConverter API for more optimised and more correct conversion of - raw video frames between all supported formats, with rescaling -- v4l2src now supports renegotiation -- v4l2transform can now do scaling -- V4L2 Element now report Colorimetry properly -- Easier chunked recording of MP4, Matroska, Ogg, MPEG-TS: new splitmuxsink - and multifilesink improvements -- Content Protection signalling API and Common Encryption (CENC) support for - DASH/MP4 -- Many adaptive streaming (DASH, HLS and MSS) improvements -- New PTP and NTP network client clocks and better remote clock tracking - stability -- High-quality text subtitle overlay at display resolutions with glimagesink - or gtkglsink -- RECORD support for the GStreamer RTSP Server -- Retransmissions (RTX) support in RTSP server and client -- RTSP seeking support in client and server has been fixed -- RTCP scheduling improvements and reduced size RTCP support -- MP4/MOV muxer acquired a new "robust" mode of operation which attempts to - keep the output file in a valid state at all times -- Live mixing support in aggregator, audiomixer and compositor was improved a - lot -- compositor now supports rescaling and converting inputs streams on the fly -- New audiointerleave element with proper input synchronisation and live input - support -- Blackmagic Design DeckLink capture and playback card support was rewritten - from scratch; 2k/4k support; mode sensing -- KLV metadata support in RTP and MPEG-TS -- H.265 video encoder (x265), decoders (libav, libde265) and RTP payloader and - depayloaders -- New DTLS plugin and SRTP/DTLS support -- OpenGL3 support, multiple contexts and context propagation, 3D video, - transfer/conversion separation, subtitle blending -- New OpenGL-based QML video sink, Gtk GL video sink, CoreAnimation - CAOpenGLLayerSink video sink -- gst-libav switched to ffmpeg as libav-provider, gains support for - 3D/multiview video, trick modes, and the CAVS codec -- GstHarness API for unit tests -- gst-editing-services got a completely new ges-launch-1.0 interface, improved - mixing support and integration into gst-validate -- gnonlin has been deprecated in favor of nle (Non Linear Engine) in - gst-editing-services -- gst-validate has a new plugin system, an extensive default testsuite, - support for concurrent test runs and valgrind support -- cerbero build tool for SDK binary packages gains new 'bundle-source' command -- Various improvements to the Android, iOS, OS X and Windows platform support +This is GStreamer 1.7.1 diff --git a/RELEASE b/RELEASE index 0230fd55a6..f2322a44aa 100644 --- a/RELEASE +++ b/RELEASE @@ -1,24 +1,31 @@ -Release notes for GStreamer RTSP Server Library 1.6.0 +Release notes for GStreamer RTSP Server Library 1.7.1 -The GStreamer team is proud to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! +The GStreamer team is pleased to announce the first release of the unstable +1.7 release series. The 1.7 release series is adding new features on top of +the 1.0, 1.2, 1.4 and 1.6 series and is part of the API and ABI-stable 1.x release +series of the GStreamer multimedia framework. The unstable 1.7 release series +will lead to the stable 1.8 release series in the next weeks. Any newly added +API can still change until that point. -This release has been in the works for more than a year and is packed with new -features, bug fixes and other improvements. - - -See -http://gstreamer.freedesktop.org/releases/1.6/ -for the full list of changes. +Binaries for Android, iOS, Mac OS X and Windows will be provided separately +during the unstable 1.7 release series. -There were no bugs fixed in this release - +Bugs fixed in this release + + * 753863 : rtsp-server: examples: Fix memory leaks when context parse fails + * 756969 : rtsp-server unit tests don't test udp-mcast transport + * 757949 : gst_rtsp_server_io_func() pops a context that has not been pushed + * 758179 : GstRTSPStream : Create pipeline based on enabled transport type + * 758268 : handle_setup_request() expect the media to be suspended + * 758319 : rtsp-server: Seeking often hangs forever, waiting for prerolling to happen again + * 758364 : rtsp-session-pool: Avoid dollar sign ($) in session ids + * 759010 : Valgrind test are faling for rtsp-server for master ==== Download ==== @@ -55,7 +62,17 @@ subscribe to the gstreamer-devel list. Contributors to this release + * David Svensson Fors + * Hyunjun Ko * Jan Schmidt + * Koop Mast + * Marcus Prebble + * Nicolas Dufresne + * Olivier Crête * Sebastian Dröge + * Sebastian Rasmussen + * Srimanta Panda * Tim-Philipp Müller + * Vineeth TM + * Xavier Claessens   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 57cc6dad1e..663d457fed 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.7.0.1], +AC_INIT([GStreamer RTSP Server Library], [1.7.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 700, 0, 700) +AS_LIBTOOL(GST, 701, 0, 701) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.7.0.1 -GSTPB_REQ=1.7.0.1 -GSTPG_REQ=1.7.0.1 -GSTPD_REQ=1.7.0.1 +GST_REQ=1.7.1 +GSTPB_REQ=1.7.1 +GSTPG_REQ=1.7.1 +GSTPD_REQ=1.7.1 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 88dae1f6f6..b202efe0f1 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,36 @@ RTSP server library based on GStreamer + + + 1.7.1 + master + + 2015-12-24 + + + + + + + 1.6.2 + 1.6 + + 2015-12-14 + + + + + + + 1.6.1 + 1.6 + + 2015-10-30 + + + + 1.6.0 From 5dd1166259a466195f0950448bc679fbf9d4c020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Dec 2015 15:29:33 +0100 Subject: [PATCH 1202/1776] Back to development --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 663d457fed..c4722c3e52 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.7.1], +AC_INIT([GStreamer RTSP Server Library], [1.7.1.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 701, 0, 701) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.7.1 -GSTPB_REQ=1.7.1 -GSTPG_REQ=1.7.1 -GSTPD_REQ=1.7.1 +GST_REQ=1.7.1.1 +GSTPB_REQ=1.7.1.1 +GSTPG_REQ=1.7.1.1 +GSTPD_REQ=1.7.1.1 dnl *** autotools stuff **** From c8f179948ec18e44fe8018d8ae8f2c0833905f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 9 Dec 2015 18:24:24 +0200 Subject: [PATCH 1203/1776] rtsp-media: Add property to decide if sending media should be stopped when a client disconnects without TEARDOWN Without TEARDOWN it might be desireable to keep the media running and continue sending data to the client, even if the RTSP connection itself is disconnected. Only do this for session medias that have only UDP transports. If there's at least on TCP transport, it will stop working and cause problems when the connection is disconnected. https://bugzilla.gnome.org/show_bug.cgi?id=758999 --- gst/rtsp-server/rtsp-client.c | 50 ++++++++++++++++--- gst/rtsp-server/rtsp-media-factory.c | 73 +++++++++++++++++++++++++++- gst/rtsp-server/rtsp-media-factory.h | 4 ++ gst/rtsp-server/rtsp-media.c | 70 +++++++++++++++++++++++++- gst/rtsp-server/rtsp-media.h | 3 ++ 5 files changed, 191 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 0a33e45321..c7620a89ac 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -332,9 +332,38 @@ static GstRTSPFilterResult filter_session_media (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia, gpointer user_data) { - gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL); + gboolean *closed = user_data; + GstRTSPMedia *media; + guint i, n_streams; + gboolean is_all_udp = TRUE; - return GST_RTSP_FILTER_REMOVE; + media = gst_rtsp_session_media_get_media (sessmedia); + n_streams = gst_rtsp_media_n_streams (media); + + for (i = 0; i < n_streams; i++) { + GstRTSPStreamTransport *transport = + gst_rtsp_session_media_get_transport (sessmedia, i); + const GstRTSPTransport *rtsp_transport; + + if (!transport) + continue; + + rtsp_transport = gst_rtsp_stream_transport_get_transport (transport); + if (rtsp_transport + && rtsp_transport->lower_transport != GST_RTSP_LOWER_TRANS_UDP + && rtsp_transport->lower_transport != GST_RTSP_LOWER_TRANS_UDP_MCAST) { + is_all_udp = FALSE; + break; + } + } + + if (!is_all_udp || gst_rtsp_media_is_stop_on_disconnect (media)) { + gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL); + return GST_RTSP_FILTER_REMOVE; + } else { + *closed = FALSE; + return GST_RTSP_FILTER_KEEP; + } } static void @@ -395,11 +424,16 @@ static GstRTSPFilterResult cleanup_session (GstRTSPClient * client, GstRTSPSession * sess, gpointer user_data) { + gboolean *closed = user_data; + /* unlink all media managed in this session. This needs to happen * without the client lock, so we really want to do it here. */ - gst_rtsp_session_filter (sess, filter_session_media, client); + gst_rtsp_session_filter (sess, filter_session_media, user_data); - return GST_RTSP_FILTER_REMOVE; + if (*closed) + return GST_RTSP_FILTER_REMOVE; + else + return GST_RTSP_FILTER_KEEP; } static void @@ -3784,12 +3818,14 @@ static void client_watch_notify (GstRTSPClient * client) { GstRTSPClientPrivate *priv = client->priv; + gboolean closed = TRUE; GST_INFO ("client %p: watch destroyed", client); priv->watch = NULL; - /* remove all sessions and so drop the extra client ref */ - gst_rtsp_client_session_filter (client, cleanup_session, NULL); - g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL); + /* remove all sessions if the media says so and so drop the extra client ref */ + gst_rtsp_client_session_filter (client, cleanup_session, &closed); + if (closed) + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL); g_object_unref (client); } diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 087aa8ad35..ac6ce1f0c1 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -60,6 +60,7 @@ struct _GstRTSPMediaFactoryPrivate guint buffer_size; GstRTSPAddressPool *pool; GstRTSPTransportMode transport_mode; + gboolean stop_on_disconnect; GstClockTime rtx_time; guint latency; @@ -80,6 +81,7 @@ struct _GstRTSPMediaFactoryPrivate #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_LATENCY 200 #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY +#define DEFAULT_STOP_ON_DISCONNECT TRUE enum { @@ -93,6 +95,7 @@ enum PROP_BUFFER_SIZE, PROP_LATENCY, PROP_TRANSPORT_MODE, + PROP_STOP_ON_DISCONNECT, PROP_LAST }; @@ -202,6 +205,13 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) GST_TYPE_RTSP_TRANSPORT_MODE, DEFAULT_TRANSPORT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_STOP_ON_DISCONNECT, + g_param_spec_boolean ("stop-on-disconnect", "Stop On Disconnect", + "If media from this factory should be stopped " + "when a client disconnects without TEARDOWN", + DEFAULT_STOP_ON_DISCONNECT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, @@ -240,6 +250,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->buffer_size = DEFAULT_BUFFER_SIZE; priv->latency = DEFAULT_LATENCY; priv->transport_mode = DEFAULT_TRANSPORT_MODE; + priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; g_mutex_init (&priv->lock); g_mutex_init (&priv->medias_lock); @@ -304,6 +315,10 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_flags (value, gst_rtsp_media_factory_get_transport_mode (factory)); break; + case PROP_STOP_ON_DISCONNECT: + g_value_set_boolean (value, + gst_rtsp_media_factory_is_stop_on_disonnect (factory)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -347,6 +362,10 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_transport_mode (factory, g_value_get_flags (value)); break; + case PROP_STOP_ON_DISCONNECT: + gst_rtsp_media_factory_set_stop_on_disconnect (factory, + g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -862,6 +881,56 @@ gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory) return res; } +/** + * gst_rtsp_media_factory_set_stop_on_disconnect: + * @factory: a #GstRTSPMediaFactory + * @stop_on_disconnect: the new value + * + * Configure if media created from this factory should be stopped + * when a client disconnects without sending TEARDOWN. + */ +void +gst_rtsp_media_factory_set_stop_on_disconnect (GstRTSPMediaFactory * factory, + gboolean stop_on_disconnect) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv->stop_on_disconnect = stop_on_disconnect; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_is_stop_on_disconnect: + * @factory: a #GstRTSPMediaFactory + * + * Get if media created from this factory should be stopped when a client + * disconnects without sending TEARDOWN. + * + * Returns: %TRUE if the media will be stopped when a client disconnects + * without sending TEARDOWN. + */ +gboolean +gst_rtsp_media_factory_is_stop_on_disonnect (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + gboolean result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), TRUE); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + result = priv->stop_on_disconnect; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} + /** * gst_rtsp_media_factory_set_retransmission_time: * @factory: a #GstRTSPMediaFactory @@ -1270,7 +1339,7 @@ static void default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) { GstRTSPMediaFactoryPrivate *priv = factory->priv; - gboolean shared, eos_shutdown; + gboolean shared, eos_shutdown, stop_on_disconnect; guint size; GstRTSPSuspendMode suspend_mode; GstRTSPProfile profiles; @@ -1292,6 +1361,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) rtx_time = priv->rtx_time; latency = priv->latency; transport_mode = priv->transport_mode; + stop_on_disconnect = priv->stop_on_disconnect; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_suspend_mode (media, suspend_mode); @@ -1303,6 +1373,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_retransmission_time (media, rtx_time); gst_rtsp_media_set_latency (media, latency); gst_rtsp_media_set_transport_mode (media, transport_mode); + gst_rtsp_media_set_stop_on_disconnect (media, stop_on_disconnect); if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) { gst_rtsp_media_set_address_pool (media, pool); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 0dc1067e27..e82b64a913 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -118,6 +118,10 @@ void gst_rtsp_media_factory_set_shared (GstRTSPMediaFacto gboolean shared); gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_stop_on_disconnect (GstRTSPMediaFactory *factory, + gboolean stop_on_disconnect); +gboolean gst_rtsp_media_factory_is_stop_on_disonnect (GstRTSPMediaFactory *factory); + void gst_rtsp_media_factory_set_suspend_mode (GstRTSPMediaFactory *factory, GstRTSPSuspendMode mode); GstRTSPSuspendMode gst_rtsp_media_factory_get_suspend_mode (GstRTSPMediaFactory *factory); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 5a6f758ab0..61e68b2be9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -102,6 +102,7 @@ struct _GstRTSPMediaPrivate GstRTSPAddressPool *pool; gboolean blocked; GstRTSPTransportMode transport_mode; + gboolean stop_on_disconnect; GstElement *element; GRecMutex state_lock; /* locking order: state lock, lock */ @@ -151,6 +152,7 @@ struct _GstRTSPMediaPrivate #define DEFAULT_TIME_PROVIDER FALSE #define DEFAULT_LATENCY 200 #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY +#define DEFAULT_STOP_ON_DISCONNECT TRUE /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -169,6 +171,7 @@ enum PROP_TIME_PROVIDER, PROP_LATENCY, PROP_TRANSPORT_MODE, + PROP_STOP_ON_DISCONNECT, PROP_LAST }; @@ -329,6 +332,13 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) GST_TYPE_RTSP_TRANSPORT_MODE, DEFAULT_TRANSPORT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_STOP_ON_DISCONNECT, + g_param_spec_boolean ("stop-on-disconnect", "Stop On Disconnect", + "If this media pipeline should be stopped " + "when a client disconnects without TEARDOWN", + DEFAULT_STOP_ON_DISCONNECT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, @@ -396,6 +406,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->buffer_size = DEFAULT_BUFFER_SIZE; priv->time_provider = DEFAULT_TIME_PROVIDER; priv->transport_mode = DEFAULT_TRANSPORT_MODE; + priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; } static void @@ -472,6 +483,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_TRANSPORT_MODE: g_value_set_flags (value, gst_rtsp_media_get_transport_mode (media)); break; + case PROP_STOP_ON_DISCONNECT: + g_value_set_boolean (value, gst_rtsp_media_is_stop_on_disconnect (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -518,6 +532,10 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_TRANSPORT_MODE: gst_rtsp_media_set_transport_mode (media, g_value_get_flags (value)); break; + case PROP_STOP_ON_DISCONNECT: + gst_rtsp_media_set_stop_on_disconnect (media, + g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1167,6 +1185,56 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) return res; } +/** + * gst_rtsp_media_set_stop_on_disconnect: + * @media: a #GstRTSPMedia + * @stop_on_disconnect: the new value + * + * Set or unset if the pipeline for @media should be stopped when a + * client disconnects without sending TEARDOWN. + */ +void +gst_rtsp_media_set_stop_on_disconnect (GstRTSPMedia * media, + gboolean stop_on_disconnect) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->stop_on_disconnect = stop_on_disconnect; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_is_stop_on_disconnect: + * @media: a #GstRTSPMedia + * + * Check if the pipeline for @media will be stopped when a client disconnects + * without sending TEARDOWN. + * + * Returns: %TRUE if the media will be stopped when a client disconnects + * without sending TEARDOWN. + */ +gboolean +gst_rtsp_media_is_stop_on_disconnect (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), TRUE); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->stop_on_disconnect; + g_mutex_unlock (&priv->lock); + + return res; +} + /** * gst_rtsp_media_set_retransmission_time: * @media: a #GstRTSPMedia @@ -2604,7 +2672,7 @@ default_prepare (GstRTSPMedia * media, GstRTSPThread * thread) /* do remainder in context */ source = g_idle_source_new (); g_source_set_callback (source, (GSourceFunc) start_prepare, - g_object_ref (media), (GDestroyNotify) g_object_unref); + g_object_ref (media), (GDestroyNotify) g_object_unref); g_source_attach (source, context); g_source_unref (source); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index d554afe769..edf669f296 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -186,6 +186,9 @@ GstRTSPPermissions * gst_rtsp_media_get_permissions (GstRTSPMedia *media); void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared); gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media); +void gst_rtsp_media_set_stop_on_disconnect (GstRTSPMedia *media, gboolean stop_on_disconnect); +gboolean gst_rtsp_media_is_stop_on_disconnect (GstRTSPMedia *media); + void gst_rtsp_media_set_transport_mode (GstRTSPMedia *media, GstRTSPTransportMode mode); GstRTSPTransportMode gst_rtsp_media_get_transport_mode (GstRTSPMedia *media); From b2abb970435e618e8475c7d8060142cec4673dbe Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Tue, 22 Dec 2015 12:08:02 +0100 Subject: [PATCH 1204/1776] rtsp-media: Do not prepare media after media times out Deferred calls to start_prepare() can be deferred past the point until which wait_preroll() and by proxy gst_rtsp_media_get_status() is prepared to wait. Previously there was no lock and no check for this situation. This meant that a media could be prepared and unprepared simultaneously by two different threads. Now a lock is in place and a suitable check is done. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=759773 --- gst/rtsp-server/rtsp-media.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 61e68b2be9..951c5ac3bd 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2555,6 +2555,10 @@ start_prepare (GstRTSPMedia * media) guint i; GList *walk; + g_rec_mutex_lock (&priv->state_lock); + if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARING) + goto no_longer_preparing; + /* link streams we already have, other streams might appear when we have * dynamic elements */ for (i = 0; i < priv->streams->len; i++) { @@ -2603,18 +2607,28 @@ start_prepare (GstRTSPMedia * media) if (!start_preroll (media)) goto preroll_failed; + g_rec_mutex_unlock (&priv->state_lock); + return FALSE; +no_longer_preparing: + { + GST_INFO ("media is no longer preparing"); + g_rec_mutex_unlock (&priv->state_lock); + return FALSE; + } join_bin_failed: { GST_WARNING ("failed to join bin element"); gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR); + g_rec_mutex_unlock (&priv->state_lock); return FALSE; } preroll_failed: { GST_WARNING ("failed to preroll pipeline"); gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR); + g_rec_mutex_unlock (&priv->state_lock); return FALSE; } } From 3d6b93bcd35a32edf256c09f0f7009d407ad4e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 30 Dec 2015 16:29:45 +0200 Subject: [PATCH 1205/1776] rtsp-stream: Fix indentation --- gst/rtsp-server/rtsp-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index f3299116c5..d64b5c3748 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2493,7 +2493,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, /* removing them should also nicely release the request * pads when they finalize */ gst_bin_remove (bin, priv->udpsrc_v4[i]); - } else { + } else { /* we need to set the state to NULL before unref */ gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); gst_object_unref (priv->udpsrc_v4[i]); From 6b76c02552b2a1b0249ddac683bbd527ffea5d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 30 Dec 2015 16:30:38 +0200 Subject: [PATCH 1206/1776] rtsp-media-factory: Add FIXME for 2.0 --- gst/rtsp-server/rtsp-media-factory.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index ac6ce1f0c1..82afff56e4 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -1330,6 +1330,11 @@ default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstElement *pipeline; pipeline = gst_pipeline_new ("media-pipeline"); + + /* FIXME 2.0: This should be done by the caller, not the vfunc. Every + * implementation of the vfunc has to call it otherwise at the end. + * Also it does not allow use to add further behaviour here that could + * be reused by subclasses that chain up */ gst_rtsp_media_take_pipeline (media, GST_PIPELINE_CAST (pipeline)); return pipeline; From cbf3f3888f2e3b72777f1f291c34c84a4e8a924d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 30 Dec 2015 16:43:17 +0200 Subject: [PATCH 1207/1776] rtsp-media: Fix typo in docs gst_rtsp_media_set_latncy() -> latency() --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 951c5ac3bd..6024bab6dc 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1293,7 +1293,7 @@ gst_rtsp_media_get_retransmission_time (GstRTSPMedia * media) } /** - * gst_rtsp_media_set_latncy: + * gst_rtsp_media_set_latency: * @media: a #GstRTSPMedia * @latency: latency in milliseconds * From 7a41d396ae0ac12b7ef934981949a04b48ab491b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 30 Dec 2015 16:31:13 +0200 Subject: [PATCH 1208/1776] rtsp-media: Add API to directly configure a clock on the media pipelines --- gst/rtsp-server/rtsp-media-factory.c | 70 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 4 ++ gst/rtsp-server/rtsp-media.c | 46 ++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 2 + 4 files changed, 122 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 82afff56e4..3fd769d45b 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -69,6 +69,8 @@ struct _GstRTSPMediaFactoryPrivate GHashTable *medias; /* protected by medias_lock */ GType media_gtype; + + GstClock *clock; }; #define DEFAULT_LAUNCH NULL @@ -96,6 +98,7 @@ enum PROP_LATENCY, PROP_TRANSPORT_MODE, PROP_STOP_ON_DISCONNECT, + PROP_CLOCK, PROP_LAST }; @@ -212,6 +215,12 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) DEFAULT_STOP_ON_DISCONNECT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_CLOCK, + g_param_spec_object ("clock", "Clock", + "Clock to be used by the pipelines created for all " + "medias of this factory", GST_TYPE_CLOCK, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, @@ -319,6 +328,9 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_boolean (value, gst_rtsp_media_factory_is_stop_on_disonnect (factory)); break; + case PROP_CLOCK: + g_value_take_object (value, gst_rtsp_media_factory_get_clock (factory)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -366,6 +378,8 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_stop_on_disconnect (factory, g_value_get_boolean (value)); break; + case PROP_CLOCK: + gst_rtsp_media_factory_set_clock (factory, g_value_get_object (value)); default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1211,6 +1225,55 @@ gst_rtsp_media_factory_get_media_gtype (GstRTSPMediaFactory * factory) return ret; } +/** + * gst_rtsp_media_factory_set_clock: + * @factory: a #GstRTSPMediaFactory + * @clockd: the clock to be used by the media factory + * + * Configures a specific clock to be used by the pipelines + * of all medias created from this factory. + * + * Since: 1.8 + */ +void +gst_rtsp_media_factory_set_clock (GstRTSPMediaFactory * factory, + GstClock * clock) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_CLOCK (clock) || clock == NULL); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv = factory->priv; + priv->clock = clock ? gst_object_ref (clock) : NULL; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_clock: + * @factory: a #GstRTSPMediaFactory + * + * Returns the clock that is going to be used by the pipelines + * of all medias created from this factory. + * + * Returns: (transfer full): The GstClock + * + * Since: 1.8 + */ +GstClock * +gst_rtsp_media_factory_get_clock (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + GstClock *ret; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv = factory->priv; + ret = priv->clock ? gst_object_ref (priv->clock) : NULL; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return ret; +} + static gchar * default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { @@ -1354,6 +1417,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstClockTime rtx_time; guint latency; GstRTSPTransportMode transport_mode; + GstClock *clock; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -1367,6 +1431,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) latency = priv->latency; transport_mode = priv->transport_mode; stop_on_disconnect = priv->stop_on_disconnect; + clock = priv->clock ? gst_object_ref (priv->clock) : NULL; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_suspend_mode (media, suspend_mode); @@ -1380,6 +1445,11 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_transport_mode (media, transport_mode); gst_rtsp_media_set_stop_on_disconnect (media, stop_on_disconnect); + if (clock) { + gst_rtsp_media_set_clock (media, clock); + gst_object_unref (clock); + } + if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) { gst_rtsp_media_set_address_pool (media, pool); g_object_unref (pool); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index e82b64a913..c4e0a8e827 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -161,6 +161,10 @@ void gst_rtsp_media_factory_set_media_gtype (GstRTSPMediaFacto GType media_gtype); GType gst_rtsp_media_factory_get_media_gtype (GstRTSPMediaFactory * factory); +void gst_rtsp_media_factory_set_clock (GstRTSPMediaFactory *factory, + GstClock * clock); +GstClock * gst_rtsp_media_factory_get_clock (GstRTSPMediaFactory *factory); + /* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 6024bab6dc..ae590bbeae 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -139,6 +139,7 @@ struct _GstRTSPMediaPrivate GList *payloads; /* protected by lock */ GstClockTime rtx_time; /* protected by lock */ guint latency; /* protected by lock */ + GstClock *clock; /* protected by lock */ }; #define DEFAULT_SHARED FALSE @@ -172,6 +173,7 @@ enum PROP_LATENCY, PROP_TRANSPORT_MODE, PROP_STOP_ON_DISCONNECT, + PROP_CLOCK, PROP_LAST }; @@ -339,6 +341,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) DEFAULT_STOP_ON_DISCONNECT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_CLOCK, + g_param_spec_object ("clock", "Clock", + "Clock to be used by the media pipeline", + GST_TYPE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, @@ -486,6 +493,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_STOP_ON_DISCONNECT: g_value_set_boolean (value, gst_rtsp_media_is_stop_on_disconnect (media)); break; + case PROP_CLOCK: + g_value_take_object (value, gst_rtsp_media_get_clock (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -536,6 +546,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, gst_rtsp_media_set_stop_on_disconnect (media, g_value_get_boolean (value)); break; + case PROP_CLOCK: + gst_rtsp_media_set_clock (media, g_value_get_object (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1390,6 +1403,39 @@ gst_rtsp_media_is_time_provider (GstRTSPMedia * media) return res; } +/** + * gst_rtsp_media_set_clock: + * @media: a #GstRTSPMedia + * @clock: #GstClock to be used + * + * Configure the clock used for the media. + */ +void +gst_rtsp_media_set_clock (GstRTSPMedia * media, GstClock * clock) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + g_return_if_fail (GST_IS_CLOCK (clock) || clock == NULL); + + GST_LOG_OBJECT (media, "setting clock %" GST_PTR_FORMAT, clock); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + if (priv->clock) + gst_object_unref (priv->clock); + priv->clock = clock ? gst_object_ref (clock) : NULL; + if (priv->pipeline) { + if (clock) + gst_pipeline_use_clock (GST_PIPELINE_CAST (priv->pipeline), clock); + else + gst_pipeline_auto_clock (GST_PIPELINE_CAST (priv->pipeline)); + } + + g_mutex_unlock (&priv->lock); +} + /** * gst_rtsp_media_set_address_pool: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index edf669f296..400c12367b 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -221,6 +221,8 @@ gboolean gst_rtsp_media_is_time_provider (GstRTSPMedia *media); GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media, const gchar *address, guint16 port); +void gst_rtsp_media_set_clock (GstRTSPMedia *media, GstClock * clock); + /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media, GstRTSPThread *thread); gboolean gst_rtsp_media_unprepare (GstRTSPMedia *media); From 662d6b188f9d80ecc00c16a77e75b209d19d3b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 30 Dec 2015 16:34:30 +0200 Subject: [PATCH 1209/1776] test-netclock: Use the new API to configure a clock directly --- examples/test-netclock.c | 64 +++------------------------------------- 1 file changed, 4 insertions(+), 60 deletions(-) diff --git a/examples/test-netclock.c b/examples/test-netclock.c index 6fa728a173..c1bca63bae 100644 --- a/examples/test-netclock.c +++ b/examples/test-netclock.c @@ -28,26 +28,8 @@ GstClock *global_clock; #define TEST_TYPE_RTSP_MEDIA_FACTORY (test_rtsp_media_factory_get_type ()) #define TEST_TYPE_RTSP_MEDIA (test_rtsp_media_get_type ()) -GType test_rtsp_media_factory_get_type (void); GType test_rtsp_media_get_type (void); -static GstRTSPMediaFactory *test_rtsp_media_factory_new (void); -static GstElement *create_pipeline (GstRTSPMediaFactory * factory, - GstRTSPMedia * media); - -typedef struct TestRTSPMediaFactoryClass TestRTSPMediaFactoryClass; -typedef struct TestRTSPMediaFactory TestRTSPMediaFactory; - -struct TestRTSPMediaFactoryClass -{ - GstRTSPMediaFactoryClass parent; -}; - -struct TestRTSPMediaFactory -{ - GstRTSPMediaFactory parent; -}; - typedef struct TestRTSPMediaClass TestRTSPMediaClass; typedef struct TestRTSPMedia TestRTSPMedia; @@ -61,46 +43,8 @@ struct TestRTSPMedia GstRTSPMedia parent; }; -GstRTSPMediaFactory * -test_rtsp_media_factory_new (void) -{ - GstRTSPMediaFactory *result; - - result = g_object_new (TEST_TYPE_RTSP_MEDIA_FACTORY, NULL); - - return result; -} - -G_DEFINE_TYPE (TestRTSPMediaFactory, test_rtsp_media_factory, - GST_TYPE_RTSP_MEDIA_FACTORY); - static gboolean custom_setup_rtpbin (GstRTSPMedia * media, GstElement * rtpbin); -static void -test_rtsp_media_factory_class_init (TestRTSPMediaFactoryClass * test_klass) -{ - GstRTSPMediaFactoryClass *mf_klass = - (GstRTSPMediaFactoryClass *) (test_klass); - mf_klass->create_pipeline = create_pipeline; -} - -static void -test_rtsp_media_factory_init (TestRTSPMediaFactory * factory) -{ -} - -static GstElement * -create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media) -{ - GstElement *pipeline; - - pipeline = gst_pipeline_new ("media-pipeline"); - gst_pipeline_use_clock (GST_PIPELINE (pipeline), global_clock); - gst_rtsp_media_take_pipeline (media, GST_PIPELINE_CAST (pipeline)); - - return pipeline; -} - G_DEFINE_TYPE (TestRTSPMedia, test_rtsp_media, GST_TYPE_RTSP_MEDIA); static void @@ -156,11 +100,11 @@ main (int argc, char *argv[]) * gst-launch syntax to create pipelines. * any launch line works as long as it contains elements named pay%d. Each * element with pay%d names will be a stream */ - factory = test_rtsp_media_factory_new (); + factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, argv[1]); - gst_rtsp_media_factory_set_shared (GST_RTSP_MEDIA_FACTORY (factory), TRUE); - gst_rtsp_media_factory_set_media_gtype (GST_RTSP_MEDIA_FACTORY (factory), - TEST_TYPE_RTSP_MEDIA); + gst_rtsp_media_factory_set_shared (factory, TRUE); + gst_rtsp_media_factory_set_media_gtype (factory, TEST_TYPE_RTSP_MEDIA); + gst_rtsp_media_factory_set_clock (factory, global_clock); /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test", factory); From 924f914172795fa714725b890f773d8b2ecffda2 Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Wed, 7 Oct 2015 18:53:01 +0900 Subject: [PATCH 1210/1776] sdp: replace duplicated codes to call new base sdp apis https://bugzilla.gnome.org/show_bug.cgi?id=745880 --- gst/rtsp-server/rtsp-media.c | 490 +---------------------------------- gst/rtsp-server/rtsp-sdp.c | 275 +++----------------- 2 files changed, 38 insertions(+), 727 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index ae590bbeae..4013813b1e 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3206,490 +3206,6 @@ no_setup_sdp: } } -static const gchar * -rtsp_get_attribute_for_pt (const GstSDPMedia * media, const gchar * name, - gint pt) -{ - guint i; - - for (i = 0;; i++) { - const gchar *attr; - gint val; - - if ((attr = gst_sdp_media_get_attribute_val_n (media, name, i)) == NULL) - break; - - if (sscanf (attr, "%d ", &val) != 1) - continue; - - if (val == pt) - return attr; - } - return NULL; -} - -#define PARSE_INT(p, del, res) \ -G_STMT_START { \ - gchar *t = p; \ - p = strstr (p, del); \ - if (p == NULL) \ - res = -1; \ - else { \ - *p = '\0'; \ - p++; \ - res = atoi (t); \ - } \ -} G_STMT_END - -#define PARSE_STRING(p, del, res) \ -G_STMT_START { \ - gchar *t = p; \ - p = strstr (p, del); \ - if (p == NULL) { \ - res = NULL; \ - p = t; \ - } \ - else { \ - *p = '\0'; \ - p++; \ - res = t; \ - } \ -} G_STMT_END - -#define SKIP_SPACES(p) \ - while (*p && g_ascii_isspace (*p)) \ - p++; - -/* rtpmap contains: - * - * /[/] - */ -static gboolean -parse_rtpmap (const gchar * rtpmap, gint * payload, gchar ** name, - gint * rate, gchar ** params) -{ - gchar *p, *t; - - p = (gchar *) rtpmap; - - PARSE_INT (p, " ", *payload); - if (*payload == -1) - return FALSE; - - SKIP_SPACES (p); - if (*p == '\0') - return FALSE; - - PARSE_STRING (p, "/", *name); - if (*name == NULL) { - GST_DEBUG ("no rate, name %s", p); - /* no rate, assume -1 then, this is not supposed to happen but RealMedia - * streams seem to omit the rate. */ - *name = p; - *rate = -1; - return TRUE; - } - - t = p; - p = strstr (p, "/"); - if (p == NULL) { - *rate = atoi (t); - return TRUE; - } - *p = '\0'; - p++; - *rate = atoi (t); - - t = p; - if (*p == '\0') - return TRUE; - *params = t; - - return TRUE; -} - -/* - * Mapping of caps to and from SDP fields: - * - * a=rtpmap: /[/] - * a=framesize: - - * a=fmtp: [=];... - */ -static GstCaps * -media_to_caps (gint pt, const GstSDPMedia * media) -{ - GstCaps *caps; - const gchar *rtpmap; - const gchar *fmtp; - const gchar *framesize; - gchar *name = NULL; - gint rate = -1; - gchar *params = NULL; - gchar *tmp; - GstStructure *s; - gint payload = 0; - gboolean ret; - - /* get and parse rtpmap */ - rtpmap = rtsp_get_attribute_for_pt (media, "rtpmap", pt); - - if (rtpmap) { - ret = parse_rtpmap (rtpmap, &payload, &name, &rate, ¶ms); - if (!ret) { - g_warning ("error parsing rtpmap, ignoring"); - rtpmap = NULL; - } - } - /* dynamic payloads need rtpmap or we fail */ - if (rtpmap == NULL && pt >= 96) - goto no_rtpmap; - - /* check if we have a rate, if not, we need to look up the rate from the - * default rates based on the payload types. */ - if (rate == -1) { - const GstRTPPayloadInfo *info; - - if (GST_RTP_PAYLOAD_IS_DYNAMIC (pt)) { - /* dynamic types, use media and encoding_name */ - tmp = g_ascii_strdown (media->media, -1); - info = gst_rtp_payload_info_for_name (tmp, name); - g_free (tmp); - } else { - /* static types, use payload type */ - info = gst_rtp_payload_info_for_pt (pt); - } - - if (info) { - if ((rate = info->clock_rate) == 0) - rate = -1; - } - /* we fail if we cannot find one */ - if (rate == -1) - goto no_rate; - } - - tmp = g_ascii_strdown (media->media, -1); - caps = gst_caps_new_simple ("application/x-unknown", - "media", G_TYPE_STRING, tmp, "payload", G_TYPE_INT, pt, NULL); - g_free (tmp); - s = gst_caps_get_structure (caps, 0); - - gst_structure_set (s, "clock-rate", G_TYPE_INT, rate, NULL); - - /* encoding name must be upper case */ - if (name != NULL) { - tmp = g_ascii_strup (name, -1); - gst_structure_set (s, "encoding-name", G_TYPE_STRING, tmp, NULL); - g_free (tmp); - } - - /* params must be lower case */ - if (params != NULL) { - tmp = g_ascii_strdown (params, -1); - gst_structure_set (s, "encoding-params", G_TYPE_STRING, tmp, NULL); - g_free (tmp); - } - - /* parse optional fmtp: field */ - if ((fmtp = rtsp_get_attribute_for_pt (media, "fmtp", pt))) { - gchar *p; - gint payload = 0; - - p = (gchar *) fmtp; - - /* p is now of the format [=];... */ - PARSE_INT (p, " ", payload); - if (payload != -1 && payload == pt) { - gchar **pairs; - gint i; - - /* [=] are separated with ';' */ - pairs = g_strsplit (p, ";", 0); - for (i = 0; pairs[i]; i++) { - gchar *valpos; - const gchar *val, *key; - gint j; - const gchar *reserved_keys[] = - { "media", "payload", "clock-rate", "encoding-name", - "encoding-params" - }; - - /* the key may not have a '=', the value can have other '='s */ - valpos = strstr (pairs[i], "="); - if (valpos) { - /* we have a '=' and thus a value, remove the '=' with \0 */ - *valpos = '\0'; - /* value is everything between '=' and ';'. We split the pairs at ; - * boundaries so we can take the remainder of the value. Some servers - * put spaces around the value which we strip off here. Alternatively - * we could strip those spaces in the depayloaders should these spaces - * actually carry any meaning in the future. */ - val = g_strstrip (valpos + 1); - } else { - /* simple ;.. is translated into =1;... */ - val = "1"; - } - /* strip the key of spaces, convert key to lowercase but not the value. */ - key = g_strstrip (pairs[i]); - - /* skip keys from the fmtp, which we already use ourselves for the - * caps. Some software is adding random things like clock-rate into - * the fmtp, and we would otherwise here set a string-typed clock-rate - * in the caps... and thus fail to create valid RTP caps - */ - for (j = 0; j < G_N_ELEMENTS (reserved_keys); j++) { - if (g_ascii_strcasecmp (reserved_keys[j], key) == 0) { - key = ""; - break; - } - } - - if (strlen (key) > 1) { - tmp = g_ascii_strdown (key, -1); - gst_structure_set (s, tmp, G_TYPE_STRING, val, NULL); - g_free (tmp); - } - } - g_strfreev (pairs); - } - } - - /* parse framesize: field */ - if ((framesize = gst_sdp_media_get_attribute_val (media, "framesize"))) { - gchar *p; - - /* p is now of the format - */ - p = (gchar *) framesize; - - PARSE_INT (p, " ", payload); - if (payload != -1 && payload == pt) { - gst_structure_set (s, "a-framesize", G_TYPE_STRING, p, NULL); - } - } - return caps; - - /* ERRORS */ -no_rtpmap: - { - g_warning ("rtpmap type not given for dynamic payload %d", pt); - return NULL; - } -no_rate: - { - g_warning ("rate unknown for payload type %d", pt); - return NULL; - } -} - -static gboolean -parse_keymgmt (const gchar * keymgmt, GstCaps * caps) -{ - gboolean res = FALSE; - gsize size; - guchar *data; - GstMIKEYMessage *msg; - const GstMIKEYPayload *payload; - const gchar *srtp_cipher; - const gchar *srtp_auth; - - { - gchar *orig_value; - gchar *p, *kmpid; - - p = orig_value = g_strdup (keymgmt); - - SKIP_SPACES (p); - if (*p == '\0') { - g_free (orig_value); - return FALSE; - } - - PARSE_STRING (p, " ", kmpid); - if (kmpid == NULL || !g_str_equal (kmpid, "mikey")) { - g_free (orig_value); - return FALSE; - } - data = g_base64_decode (p, &size); - - g_free (orig_value); /* Don't need this any more */ - } - - if (data == NULL) - return FALSE; - - msg = gst_mikey_message_new_from_data (data, size, NULL, NULL); - g_free (data); - if (msg == NULL) - return FALSE; - - srtp_cipher = "aes-128-icm"; - srtp_auth = "hmac-sha1-80"; - - /* check the Security policy if any */ - if ((payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, 0))) { - GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload; - guint len, i; - - if (p->proto != GST_MIKEY_SEC_PROTO_SRTP) - goto done; - - len = gst_mikey_payload_sp_get_n_params (payload); - for (i = 0; i < len; i++) { - const GstMIKEYPayloadSPParam *param = - gst_mikey_payload_sp_get_param (payload, i); - - switch (param->type) { - case GST_MIKEY_SP_SRTP_ENC_ALG: - switch (param->val[0]) { - case 0: - srtp_cipher = "null"; - break; - case 2: - case 1: - srtp_cipher = "aes-128-icm"; - break; - default: - break; - } - break; - case GST_MIKEY_SP_SRTP_ENC_KEY_LEN: - switch (param->val[0]) { - case AES_128_KEY_LEN: - srtp_cipher = "aes-128-icm"; - break; - case AES_256_KEY_LEN: - srtp_cipher = "aes-256-icm"; - break; - default: - break; - } - break; - case GST_MIKEY_SP_SRTP_AUTH_ALG: - switch (param->val[0]) { - case 0: - srtp_auth = "null"; - break; - case 2: - case 1: - srtp_auth = "hmac-sha1-80"; - break; - default: - break; - } - break; - case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN: - switch (param->val[0]) { - case HMAC_32_KEY_LEN: - srtp_auth = "hmac-sha1-32"; - break; - case HMAC_80_KEY_LEN: - srtp_auth = "hmac-sha1-80"; - break; - default: - break; - } - break; - case GST_MIKEY_SP_SRTP_SRTP_ENC: - break; - case GST_MIKEY_SP_SRTP_SRTCP_ENC: - break; - default: - break; - } - } - } - - if (!(payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_KEMAC, 0))) - goto done; - else { - GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload; - const GstMIKEYPayload *sub; - GstMIKEYPayloadKeyData *pkd; - GstBuffer *buf; - - if (p->enc_alg != GST_MIKEY_ENC_NULL || p->mac_alg != GST_MIKEY_MAC_NULL) - goto done; - - if (!(sub = gst_mikey_payload_kemac_get_sub (payload, 0))) - goto done; - - if (sub->type != GST_MIKEY_PT_KEY_DATA) - goto done; - - pkd = (GstMIKEYPayloadKeyData *) sub; - buf = - gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len), - pkd->key_len); - gst_caps_set_simple (caps, "srtp-key", GST_TYPE_BUFFER, buf, NULL); - } - - gst_caps_set_simple (caps, - "srtp-cipher", G_TYPE_STRING, srtp_cipher, - "srtp-auth", G_TYPE_STRING, srtp_auth, - "srtcp-cipher", G_TYPE_STRING, srtp_cipher, - "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL); - - res = TRUE; -done: - gst_mikey_message_unref (msg); - - return res; -} - -/* - * Mapping SDP attributes to caps - * - * prepend 'a-' to IANA registered sdp attributes names - * (ie: not prefixed with 'x-') in order to avoid - * collision with gstreamer standard caps properties names - */ -static void -sdp_attributes_to_caps (GArray * attributes, GstCaps * caps) -{ - if (attributes->len > 0) { - GstStructure *s; - guint i; - - s = gst_caps_get_structure (caps, 0); - - for (i = 0; i < attributes->len; i++) { - GstSDPAttribute *attr = &g_array_index (attributes, GstSDPAttribute, i); - gchar *tofree, *key; - - key = attr->key; - - /* skip some of the attribute we already handle */ - if (!strcmp (key, "fmtp")) - continue; - if (!strcmp (key, "rtpmap")) - continue; - if (!strcmp (key, "control")) - continue; - if (!strcmp (key, "range")) - continue; - if (!strcmp (key, "framesize")) - continue; - if (g_str_equal (key, "key-mgmt")) { - parse_keymgmt (attr->value, caps); - continue; - } - - /* string must be valid UTF8 */ - if (!g_utf8_validate (attr->value, -1, NULL)) - continue; - - if (!g_str_has_prefix (key, "x-")) - tofree = key = g_strdup_printf ("a-%s", key); - else - tofree = NULL; - - GST_DEBUG ("adding caps: %s=%s", key, attr->value); - gst_structure_set (s, key, G_TYPE_STRING, attr->value, NULL); - g_free (tofree); - } - } -} - static gboolean default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp) { @@ -3756,7 +3272,7 @@ default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp) GST_DEBUG (" looking at %d pt: %d", j, pt); /* convert caps */ - caps = media_to_caps (pt, sdp_media); + caps = gst_sdp_media_get_caps_from_media (sdp_media, pt); if (caps == NULL) { GST_WARNING (" skipping pt %d without caps", pt); continue; @@ -3764,9 +3280,9 @@ default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp) /* do some tweaks */ GST_DEBUG ("mapping sdp session level attributes to caps"); - sdp_attributes_to_caps (sdp->attributes, caps); + gst_sdp_message_attributes_to_caps (sdp, caps); GST_DEBUG ("mapping sdp media level attributes to caps"); - sdp_attributes_to_caps (sdp_media->attributes, caps); + gst_sdp_media_attributes_to_caps (sdp_media, caps); s = gst_caps_get_structure (caps, 0); gst_structure_set_name (s, media_type); diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 393b099045..74ea340d4d 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -30,12 +30,6 @@ #include "rtsp-sdp.h" -#define AES_128_KEY_LEN 16 -#define AES_256_KEY_LEN 32 - -#define HMAC_32_KEY_LEN 4 -#define HMAC_80_KEY_LEN 10 - static gboolean get_info_from_tags (GstPad * pad, GstEvent ** event, gpointer user_data) { @@ -78,60 +72,27 @@ update_sdp_from_tags (GstRTSPStream * stream, GstSDPMedia * stream_media) gst_object_unref (src_pad); } -static guint8 -enc_key_length_from_cipher_name (const gchar * cipher) -{ - if (g_strcmp0 (cipher, "aes-128-icm") == 0) - return AES_128_KEY_LEN; - else if (g_strcmp0 (cipher, "aes-256-icm") == 0) - return AES_256_KEY_LEN; - else { - GST_ERROR ("encryption algorithm '%s' not supported", cipher); - return 0; - } -} - -static guint8 -auth_key_length_from_auth_name (const gchar * auth) -{ - if (g_strcmp0 (auth, "hmac-sha1-32") == 0) - return HMAC_32_KEY_LEN; - else if (g_strcmp0 (auth, "hmac-sha1-80") == 0) - return HMAC_80_KEY_LEN; - else { - GST_ERROR ("authentication algorithm '%s' not supported", auth); - return 0; - } -} - static void make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, - GstRTSPStream * stream, GstStructure * s, GstRTSPProfile profile) + GstRTSPStream * stream, GstCaps * caps, GstRTSPProfile profile) { GstSDPMedia *smedia; - const gchar *caps_str, *caps_enc, *caps_params; gchar *tmp; - gint caps_pt, caps_rate; - guint n_fields, j; - gboolean first; - GString *fmtp; GstRTSPLowerTrans ltrans; GSocketFamily family; const gchar *addrtype, *proto; gchar *address; guint ttl; GstClockTime rtx_time; + gchar *base64; + guint32 ssrc; + GstMIKEYMessage *mikey_msg; gst_sdp_media_new (&smedia); - /* get media type and payload for the m= line */ - caps_str = gst_structure_get_string (s, "media"); - gst_sdp_media_set_media (smedia, caps_str); - - gst_structure_get_int (s, "payload", &caps_pt); - tmp = g_strdup_printf ("%d", caps_pt); - gst_sdp_media_add_format (smedia, tmp); - g_free (tmp); + if (gst_sdp_media_set_media_from_caps (caps, smedia) != GST_SDP_OK) { + goto error; + } gst_sdp_media_set_port_info (smedia, 0, 1); @@ -185,201 +146,27 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, gst_sdp_media_add_connection (smedia, "IN", addrtype, address, ttl, 1); g_free (address); - /* get clock-rate, media type and params for the rtpmap attribute */ - gst_structure_get_int (s, "clock-rate", &caps_rate); - caps_enc = gst_structure_get_string (s, "encoding-name"); - caps_params = gst_structure_get_string (s, "encoding-params"); - - if (caps_enc) { - if (caps_params) - tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate, - caps_params); - else - tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate); - - gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); - g_free (tmp); - } - /* the config uri */ tmp = gst_rtsp_stream_get_control (stream); gst_sdp_media_add_attribute (smedia, "control", tmp); g_free (tmp); - /* check for srtp */ - do { - GstBuffer *srtpkey; - const GValue *val; - const gchar *srtpcipher, *srtpauth, *srtcpcipher, *srtcpauth; - GstMIKEYMessage *msg; - GstMIKEYPayload *payload, *pkd; - GBytes *bytes; - GstMapInfo info; - const guint8 *data; - gsize size; - gchar *base64; - guint8 byte; - guint32 ssrc; - - val = gst_structure_get_value (s, "srtp-key"); - if (val == NULL) - break; - - srtpkey = gst_value_get_buffer (val); - if (srtpkey == NULL) - break; - - srtpcipher = gst_structure_get_string (s, "srtp-cipher"); - srtpauth = gst_structure_get_string (s, "srtp-auth"); - srtcpcipher = gst_structure_get_string (s, "srtcp-cipher"); - srtcpauth = gst_structure_get_string (s, "srtcp-auth"); - - if (srtpcipher == NULL || srtpauth == NULL || srtcpcipher == NULL || - srtcpauth == NULL) - break; - - msg = gst_mikey_message_new (); - /* unencrypted MIKEY message, we send this over TLS so this is allowed */ - gst_mikey_message_set_info (msg, GST_MIKEY_VERSION, GST_MIKEY_TYPE_PSK_INIT, - FALSE, GST_MIKEY_PRF_MIKEY_1, 0, GST_MIKEY_MAP_TYPE_SRTP); - /* add policy '0' for our SSRC */ + mikey_msg = gst_mikey_message_new_from_caps (caps); + if (mikey_msg) { gst_rtsp_stream_get_ssrc (stream, &ssrc); - gst_mikey_message_add_cs_srtp (msg, 0, ssrc, 0); - /* timestamp is now */ - gst_mikey_message_add_t_now_ntp_utc (msg); - /* add some random data */ - gst_mikey_message_add_rand_len (msg, 16); + /* add policy '0' for our SSRC */ + gst_mikey_message_add_cs_srtp (mikey_msg, 0, ssrc, 0); - /* the policy '0' is SRTP with the above discovered algorithms */ - payload = gst_mikey_payload_new (GST_MIKEY_PT_SP); - gst_mikey_payload_sp_set (payload, 0, GST_MIKEY_SEC_PROTO_SRTP); - - /* only AES-CM is supported */ - byte = 1; - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_ALG, 1, - &byte); - /* Encryption key length */ - byte = enc_key_length_from_cipher_name (srtpcipher); - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_KEY_LEN, 1, - &byte); - /* only HMAC-SHA1 */ - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_ALG, 1, - &byte); - /* Authentication key length */ - byte = auth_key_length_from_auth_name (srtpauth); - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_KEY_LEN, 1, - &byte); - /* we enable encryption on RTP and RTCP */ - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_ENC, 1, - &byte); - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTCP_ENC, 1, - &byte); - /* we enable authentication on RTP and RTCP */ - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_AUTH, 1, - &byte); - gst_mikey_message_add_payload (msg, payload); - - /* make unencrypted KEMAC */ - payload = gst_mikey_payload_new (GST_MIKEY_PT_KEMAC); - gst_mikey_payload_kemac_set (payload, GST_MIKEY_ENC_NULL, - GST_MIKEY_MAC_NULL); - - /* add the key in key data */ - pkd = gst_mikey_payload_new (GST_MIKEY_PT_KEY_DATA); - gst_buffer_map (srtpkey, &info, GST_MAP_READ); - gst_mikey_payload_key_data_set_key (pkd, GST_MIKEY_KD_TEK, info.size, - info.data); - gst_buffer_unmap (srtpkey, &info); - /* add key data to KEMAC */ - gst_mikey_payload_kemac_add_sub (payload, pkd); - gst_mikey_message_add_payload (msg, payload); - - /* now serialize this to bytes */ - bytes = gst_mikey_message_to_bytes (msg, NULL, NULL); - gst_mikey_message_unref (msg); - /* and make it into base64 */ - data = g_bytes_get_data (bytes, &size); - base64 = g_base64_encode (data, size); - g_bytes_unref (bytes); - - tmp = g_strdup_printf ("mikey %s", base64); - g_free (base64); - - gst_sdp_media_add_attribute (smedia, "key-mgmt", tmp); - g_free (tmp); - } while (FALSE); - - /* collect all other properties and add them to fmtp or attributes */ - fmtp = g_string_new (""); - g_string_append_printf (fmtp, "%d ", caps_pt); - first = TRUE; - n_fields = gst_structure_n_fields (s); - for (j = 0; j < n_fields; j++) { - const gchar *fname, *fval; - - fname = gst_structure_nth_field_name (s, j); - - /* filter out standard properties */ - if (!strcmp (fname, "media")) - continue; - if (!strcmp (fname, "payload")) - continue; - if (!strcmp (fname, "clock-rate")) - continue; - if (!strcmp (fname, "encoding-name")) - continue; - if (!strcmp (fname, "encoding-params")) - continue; - if (!strcmp (fname, "ssrc")) - continue; - if (!strcmp (fname, "timestamp-offset")) - continue; - if (!strcmp (fname, "seqnum-offset")) - continue; - if (g_str_has_prefix (fname, "srtp-")) - continue; - if (g_str_has_prefix (fname, "srtcp-")) - continue; - /* handled later */ - if (g_str_has_prefix (fname, "x-gst-rtsp-server-rtx-time")) - continue; - - if (!strcmp (fname, "a-framesize")) { - /* a-framesize attribute */ - if ((fval = gst_structure_get_string (s, fname))) { - tmp = g_strdup_printf ("%d %s", caps_pt, fval); - gst_sdp_media_add_attribute (smedia, fname + 2, tmp); - g_free (tmp); - } - continue; + base64 = gst_mikey_message_base64_encode (mikey_msg); + if (base64) { + tmp = g_strdup_printf ("mikey %s", base64); + g_free (base64); + gst_sdp_media_add_attribute (smedia, "key-mgmt", tmp); + g_free (tmp); } - if (g_str_has_prefix (fname, "a-")) { - /* attribute */ - if ((fval = gst_structure_get_string (s, fname))) - gst_sdp_media_add_attribute (smedia, fname + 2, fval); - continue; - } - if (g_str_has_prefix (fname, "x-")) { - /* attribute */ - if ((fval = gst_structure_get_string (s, fname))) - gst_sdp_media_add_attribute (smedia, fname, fval); - continue; - } - - if ((fval = gst_structure_get_string (s, fname))) { - g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval); - first = FALSE; - } - } - - if (!first) { - tmp = g_string_free (fmtp, FALSE); - gst_sdp_media_add_attribute (smedia, "fmtp", tmp); - g_free (tmp); - } else { - g_string_free (fmtp, TRUE); + gst_mikey_message_unref (mikey_msg); } update_sdp_from_tags (stream, smedia); @@ -394,6 +181,16 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, "Not adding retransmission"); } else { gchar *tmp; + GstStructure *s; + gint caps_pt, caps_rate; + + s = gst_caps_get_structure (caps, 0); + if (s == NULL) + goto error; + + /* get payload type and clock rate */ + gst_structure_get_int (s, "payload", &caps_pt); + gst_structure_get_int (s, "clock-rate", &caps_rate); tmp = g_strdup_printf ("%d", rtx_pt); gst_sdp_media_add_format (smedia, tmp); @@ -424,6 +221,12 @@ no_multicast: gst_rtsp_stream_get_index (stream)); return; } +error: + { + gst_sdp_media_free (smedia); + g_warning ("ignoring stream %d", gst_rtsp_stream_get_index (stream)); + return; + } } /** @@ -456,7 +259,6 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, for (i = 0; i < n_streams; i++) { GstRTSPStream *stream; GstCaps *caps; - GstStructure *s; GstRTSPProfile profiles; guint mask; @@ -468,13 +270,6 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, continue; } - s = gst_caps_get_structure (caps, 0); - if (s == NULL) { - gst_caps_unref (caps); - g_warning ("ignoring stream %d without media type", i); - continue; - } - /* make a new media for each profile */ profiles = gst_rtsp_stream_get_profiles (stream); mask = 1; @@ -482,7 +277,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPProfile prof = profiles & mask; if (prof) - make_media (sdp, info, media, stream, s, prof); + make_media (sdp, info, media, stream, caps, prof); mask <<= 1; } From bec94861b0390bd1345dfa9f7d1aca4569d32cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 3 Jan 2016 17:26:31 +0000 Subject: [PATCH 1211/1776] docs: remove dummy function declarations with G_INLINE_FUNC for gtk-doc gtk-doc can handle static inline functions just fine these days, there's no need for this stuff any more. --- gst/rtsp-server/rtsp-permissions.h | 8 -------- gst/rtsp-server/rtsp-thread-pool.h | 9 --------- gst/rtsp-server/rtsp-token.h | 8 -------- 3 files changed, 25 deletions(-) diff --git a/gst/rtsp-server/rtsp-permissions.h b/gst/rtsp-server/rtsp-permissions.h index 5b0bcad032..1cebb90ff4 100644 --- a/gst/rtsp-server/rtsp-permissions.h +++ b/gst/rtsp-server/rtsp-permissions.h @@ -52,10 +52,6 @@ struct _GstRTSPPermissions { * * Returns: (transfer full): @permissions (for convenience when doing assignments) */ -#ifdef _FOOL_GTK_DOC_ -G_INLINE_FUNC GstRTSPPermissions * gst_rtsp_permissions_ref (GstRTSPPermissions * permissions); -#endif - static inline GstRTSPPermissions * gst_rtsp_permissions_ref (GstRTSPPermissions * permissions) { @@ -68,10 +64,6 @@ gst_rtsp_permissions_ref (GstRTSPPermissions * permissions) * * Decrease the refcount of an permissions, freeing it if the refcount reaches 0. */ -#ifdef _FOOL_GTK_DOC_ -G_INLINE_FUNC void gst_rtsp_permissions_unref (GstRTSPPermissions * permissions); -#endif - static inline void gst_rtsp_permissions_unref (GstRTSPPermissions * permissions) { diff --git a/gst/rtsp-server/rtsp-thread-pool.h b/gst/rtsp-server/rtsp-thread-pool.h index 3799b58f35..2db59c9383 100644 --- a/gst/rtsp-server/rtsp-thread-pool.h +++ b/gst/rtsp-server/rtsp-thread-pool.h @@ -90,10 +90,6 @@ void gst_rtsp_thread_stop (GstRTSPThread * thread); * * Returns: (transfer full): @thread (for convenience when doing assignments) */ -#ifdef _FOOL_GTK_DOC_ -G_INLINE_FUNC GstRTSPThread * gst_rtsp_thread_ref (GstRTSPThread * thread); -#endif - static inline GstRTSPThread * gst_rtsp_thread_ref (GstRTSPThread * thread) { @@ -106,11 +102,6 @@ gst_rtsp_thread_ref (GstRTSPThread * thread) * * Decrease the refcount of an thread, freeing it if the refcount reaches 0. */ -#ifdef _FOOL_GTK_DOC_ -G_INLINE_FUNC void gst_rtsp_thread_unref (GstRTSPPermissions * thread); -#endif - - static inline void gst_rtsp_thread_unref (GstRTSPThread * thread) { diff --git a/gst/rtsp-server/rtsp-token.h b/gst/rtsp-server/rtsp-token.h index 44e725b150..1d2a5551c5 100644 --- a/gst/rtsp-server/rtsp-token.h +++ b/gst/rtsp-server/rtsp-token.h @@ -54,10 +54,6 @@ struct _GstRTSPToken { * * Returns: (transfer full): @token (for convenience when doing assignments) */ -#ifdef _FOOL_GTK_DOC_ -G_INLINE_FUNC GstRTSPToken * gst_rtsp_token_ref (GstRTSPToken * token); -#endif - static inline GstRTSPToken * gst_rtsp_token_ref (GstRTSPToken * token) { @@ -70,10 +66,6 @@ gst_rtsp_token_ref (GstRTSPToken * token) * * Decrease the refcount of an token, freeing it if the refcount reaches 0. */ -#ifdef _FOOL_GTK_DOC_ -G_INLINE_FUNC void gst_rtsp_token_unref (GstRTSPToken * token); -#endif - static inline void gst_rtsp_token_unref (GstRTSPToken * token) { From fdbda049c65e7d1cd87098cac926ab6a5f04f5aa Mon Sep 17 00:00:00 2001 From: Srimanta Panda Date: Tue, 5 Jan 2016 13:10:36 +0100 Subject: [PATCH 1212/1776] rtsp-stream: fixed assert during update transport When RTSP server trying update transport during multicast, it throws an assert. The assert is thrown because it is trying to get the parent of an non-existing funnel element. https://bugzilla.gnome.org/show_bug.cgi?id=760150 --- gst/rtsp-server/rtsp-stream.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index d64b5c3748..883cbcfdcc 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2911,7 +2911,7 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, GstRTSPMulticastTransportSource *source; GstBin *bin; - bin = GST_BIN (gst_object_get_parent (GST_OBJECT (priv->funnel[0]))); + bin = GST_BIN (gst_object_get_parent (GST_OBJECT (priv->funnel[1]))); if (add) { gchar *host; @@ -2940,12 +2940,14 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, gst_bin_add (bin, source->udpsrc[i]); /* and link to the funnel v4 */ - source->selpad[i] = selpad = - gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (source->udpsrc[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); + if (priv->sinkpad || i == 1) { + source->selpad[i] = selpad = + gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (source->udpsrc[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + } } priv->transport_sources = @@ -2974,8 +2976,10 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, gst_element_set_state (source->udpsrc[i], GST_STATE_NULL); gst_object_unref (source->udpsrc[i]); - gst_element_release_request_pad (priv->funnel[i], - source->selpad[i]); + if (priv->sinkpad || i == 1) { + gst_element_release_request_pad (priv->funnel[i], + source->selpad[i]); + } } g_slice_free (GstRTSPMulticastTransportSource, source); From ac1d35b147ad4d7ac3bf4ce727c6957b442d0d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 15 Jan 2016 07:01:37 +0000 Subject: [PATCH 1213/1776] rtsp-media-factory: add missing break in "clock" property setter CID 1348453 --- gst/rtsp-server/rtsp-media-factory.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 3fd769d45b..cb4fe753ee 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -380,6 +380,7 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, break; case PROP_CLOCK: gst_rtsp_media_factory_set_clock (factory, g_value_get_object (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } From fefc011dfbc0f727f212baa2759434e1591e1821 Mon Sep 17 00:00:00 2001 From: Steven Hoving Date: Thu, 28 Jan 2016 09:22:18 +0100 Subject: [PATCH 1214/1776] rtsp-media: Fix mutex beeing unlocked while they should be locked https://bugzilla.gnome.org/show_bug.cgi?id=761226 --- gst/rtsp-server/rtsp-media.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4013813b1e..90a9ddb2cf 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1298,7 +1298,7 @@ gst_rtsp_media_get_retransmission_time (GstRTSPMedia * media) priv = media->priv; - g_mutex_unlock (&priv->lock); + g_mutex_lock (&priv->lock); res = priv->rtx_time; g_mutex_unlock (&priv->lock); @@ -1348,7 +1348,7 @@ gst_rtsp_media_get_latency (GstRTSPMedia * media) priv = media->priv; - g_mutex_unlock (&priv->lock); + g_mutex_lock (&priv->lock); res = priv->latency; g_mutex_unlock (&priv->lock); @@ -1396,7 +1396,7 @@ gst_rtsp_media_is_time_provider (GstRTSPMedia * media) priv = media->priv; - g_mutex_unlock (&priv->lock); + g_mutex_lock (&priv->lock); res = priv->time_provider; g_mutex_unlock (&priv->lock); From 192a1eea3458bd5d678e0511a0cc1a69d8aa74fa Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 17 Nov 2015 01:12:28 +1100 Subject: [PATCH 1215/1776] rtsp-sdp: Add gst_rtsp_sdp_from_stream() A new function that adds info from a GstRTSPStream into an SDP message. https://bugzilla.gnome.org/show_bug.cgi?id=758180 --- gst/rtsp-server/rtsp-sdp.c | 63 ++++++++++++++++++++++++-------------- gst/rtsp-server/rtsp-sdp.h | 1 + 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 74ea340d4d..950a1eba1f 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -73,7 +73,7 @@ update_sdp_from_tags (GstRTSPStream * stream, GstSDPMedia * stream_media) } static void -make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media, +make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream * stream, GstCaps * caps, GstRTSPProfile profile) { GstSDPMedia *smedia; @@ -258,30 +258,9 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, for (i = 0; i < n_streams; i++) { GstRTSPStream *stream; - GstCaps *caps; - GstRTSPProfile profiles; - guint mask; stream = gst_rtsp_media_get_stream (media, i); - caps = gst_rtsp_stream_get_caps (stream); - - if (caps == NULL) { - g_warning ("ignoring stream %d without media type", i); - continue; - } - - /* make a new media for each profile */ - profiles = gst_rtsp_stream_get_profiles (stream); - mask = 1; - while (profiles >= mask) { - GstRTSPProfile prof = profiles & mask; - - if (prof) - make_media (sdp, info, media, stream, caps, prof); - - mask <<= 1; - } - gst_caps_unref (caps); + gst_rtsp_sdp_from_stream (sdp, info, stream); } { @@ -317,3 +296,41 @@ not_prepared: return FALSE; } } + +/** + * gst_rtsp_sdp_from_stream: + * @sdp: a #GstSDPMessage + * @info: (transfer none): a #GstSDPInfo + * @stream: (transfer none): a #GstRTSPStream + * + * Add info from @stream to @sdp. + * + */ +void +gst_rtsp_sdp_from_stream (GstSDPMessage * sdp, GstSDPInfo * info, + GstRTSPStream * stream) +{ + GstCaps *caps; + GstRTSPProfile profiles; + guint mask; + + caps = gst_rtsp_stream_get_caps (stream); + + if (caps == NULL) { + g_warning ("ignoring stream without caps"); + return; + } + + /* make a new media for each profile */ + profiles = gst_rtsp_stream_get_profiles (stream); + mask = 1; + while (profiles >= mask) { + GstRTSPProfile prof = profiles & mask; + + if (prof) + make_media (sdp, info, stream, caps, prof); + + mask <<= 1; + } + gst_caps_unref (caps); +} diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h index 7732f36d90..4a47766f62 100644 --- a/gst/rtsp-server/rtsp-sdp.h +++ b/gst/rtsp-server/rtsp-sdp.h @@ -34,6 +34,7 @@ typedef struct { /* creating SDP */ gboolean gst_rtsp_sdp_from_media (GstSDPMessage *sdp, GstSDPInfo *info, GstRTSPMedia * media); +void gst_rtsp_sdp_from_stream (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream *stream); G_END_DECLS From b6ca057c720c2528c9fd557d4b84db83fa0412ee Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 17 Nov 2015 01:12:28 +1100 Subject: [PATCH 1216/1776] rtsp-stream: Add functions for using rtsp-stream from the client Add a boolean to indicate that the rtsp-stream is running on the 'client' side of an RTSP connection, for sending streams via RECORD. In that case, the roles of the client/server ports in transport setup are swapped. https://bugzilla.gnome.org/show_bug.cgi?id=758180 --- gst/rtsp-server/rtsp-stream.c | 68 +++++++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-stream.h | 3 ++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 883cbcfdcc..4034a5cc0a 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -80,6 +80,10 @@ struct _GstRTSPStreamPrivate GstElement *payloader; guint buffer_size; gboolean is_joined; + + /* TRUE if this stream is running on + * the client side of an RTSP link (for RECORD) */ + gboolean client_side; gchar *control; GstRTSPProfile profiles; @@ -1288,6 +1292,54 @@ alloc_ports (GstRTSPStream * stream) return priv->have_ipv4 || priv->have_ipv6; } +/** + * gst_rtsp_stream_set_client_side: + * @stream: a #GstRTSPStream + * @client_side: TRUE if this #GstRTSPStream is running on the 'client' side of + * an RTSP connection. + * + * Sets the #GstRTSPStream as a 'client side' stream - used for sending + * streams to an RTSP server via RECORD. This has the practical effect + * of changing which UDP port numbers are used when setting up the local + * side of the stream sending to be either the 'server' or 'client' pair + * of a configured UDP transport. + */ +void +gst_rtsp_stream_set_client_side (GstRTSPStream * stream, gboolean client_side) +{ + GstRTSPStreamPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + priv = stream->priv; + g_mutex_lock (&priv->lock); + priv->client_side = client_side; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_stream_set_client_side: + * @stream: a #GstRTSPStream + * + * See gst_rtsp_stream_set_client_side() + * + * Returns: TRUE if this #GstRTSPStream is client-side. + */ +gboolean +gst_rtsp_stream_is_client_side (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + gboolean ret; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + g_mutex_lock (&priv->lock); + ret = priv->client_side; + g_mutex_unlock (&priv->lock); + + return ret; +} + /** * gst_rtsp_stream_get_server_port: * @stream: a #GstRTSPStream @@ -1562,8 +1614,15 @@ find_transport (GstRTSPStream * stream, const gchar * rtcp_from) tr = gst_rtsp_stream_transport_get_transport (trans); - min = tr->client_port.min; - max = tr->client_port.max; + if (priv->client_side) { + /* In client side mode the 'destination' is the RTSP server, so send + * to those ports */ + min = tr->server_port.min; + max = tr->server_port.max; + } else { + min = tr->client_port.min; + max = tr->client_port.max; + } if ((strcmp (tr->destination, dest) == 0) && (min == port || max == port)) { result = trans; @@ -3001,6 +3060,11 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, min = tr->port.min; max = tr->port.max; ttl = tr->ttl; + } else if (priv->client_side) { + /* In client side mode the 'destination' is the RTSP server, so send + * to those ports */ + min = tr->server_port.min; + max = tr->server_port.max; } else { min = tr->client_port.min; max = tr->client_port.max; diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index c045ebd618..bd1d7e50fb 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -112,6 +112,9 @@ gboolean gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked); gboolean gst_rtsp_stream_is_blocking (GstRTSPStream * stream); +void gst_rtsp_stream_set_client_side (GstRTSPStream *stream, gboolean client_side); +gboolean gst_rtsp_stream_is_client_side (GstRTSPStream *stream); + void gst_rtsp_stream_get_server_port (GstRTSPStream *stream, GstRTSPRange *server_port, GSocketFamily family); From f54dd50203b4ff3f9b3e2cc06c4528defa9e2ac8 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 17 Nov 2015 01:12:28 +1100 Subject: [PATCH 1217/1776] rtspsink: Add rtspclientsink element Add an rtspclientsink element that accepts streams for which there is a registered payloader and sends them to an RTSP server using RECORD. Sending is synchronised to the pipeline clock. Payload-types are automatically selected. The 'new-payloader' signal is fired for custom configuration of payloaders when they are created. Can now stream a movie like this: receiver: ./test-record "( decodebin name=depay0 ! videoconvert ! autovideosink \ decodebin name=depay1 ! audioconvert ! autoaudiosink )" sender: gst-launch-1.0 filesrc location=file-with-aac-and-h264.mp4 ! qtdemux name=d ! \ queue ! aacparse ! rtspclientsink location=rtsp://127.0.0.1:8554/test name=s \ https://bugzilla.gnome.org/show_bug.cgi?id=758180 --- .gitignore | 1 + configure.ac | 28 + gst/Makefile.am | 2 +- gst/rtsp-sink/Makefile.am | 18 + gst/rtsp-sink/gstrtspclientsink.c | 4885 +++++++++++++++++++++++++++++ gst/rtsp-sink/gstrtspclientsink.h | 244 ++ gst/rtsp-sink/plugin.c | 26 + tests/check/Makefile.am | 7 +- tests/check/gst/rtspclientsink.c | 221 ++ 9 files changed, 5428 insertions(+), 4 deletions(-) create mode 100644 gst/rtsp-sink/Makefile.am create mode 100644 gst/rtsp-sink/gstrtspclientsink.c create mode 100644 gst/rtsp-sink/gstrtspclientsink.h create mode 100644 gst/rtsp-sink/plugin.c create mode 100644 tests/check/gst/rtspclientsink.c diff --git a/.gitignore b/.gitignore index 574f6655b1..0af63a739a 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ stamp-h.in /tests/check/gst/stream /tests/check/gst/threadpool /tests/check/gst/token +/tests/check/gst/rtspclientsink /tests/check/test-registry.reg /tests/test-reuse diff --git a/configure.ac b/configure.ac index c4722c3e52..7d49594b5e 100644 --- a/configure.ac +++ b/configure.ac @@ -170,6 +170,8 @@ AC_MSG_NOTICE(Using GStreamer Core Plugins in $GST_PLUGINS_DIR) AG_GST_CHECK_GST_BASE($GST_API_VERSION, [$GST_REQ], [yes]) +AG_GST_CHECK_GST_NET($GST_API_VERSION, [$GST_REQ], yes) + AG_GST_CHECK_GST_PLUGINS_BASE($GST_API_VERSION, [$GSTPB_REQ], [yes]) GSTPB_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-base-$GST_API_VERSION --variable pluginsdir` AC_SUBST(GSTPB_PLUGINS_DIR) @@ -218,6 +220,31 @@ AG_GST_SET_PACKAGE_RELEASE_DATETIME_WITH_NANO([$PACKAGE_VERSION_NANO], ["${srcdir}/gst-rtsp-server.doap"], [$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR.$PACKAGE_VERSION_MICRO]) +dnl build static plugins or not +AC_MSG_CHECKING([whether to build static plugins or not]) +AC_ARG_ENABLE( + static-plugins, + AC_HELP_STRING( + [--enable-static-plugins], + [build static plugins @<:@default=no@:>@]), + [AS_CASE( + [$enableval], [no], [], [yes], [], + [AC_MSG_ERROR([bad value "$enableval" for --enable-static-plugins])])], + [enable_static_plugins=no]) +AC_MSG_RESULT([$enable_static_plugins]) +if test "x$enable_static_plugins" = xyes; then + AC_DEFINE(GST_PLUGIN_BUILD_STATIC, 1, + [Define if static plugins should be built]) + GST_PLUGIN_LIBTOOLFLAGS="" +else + GST_PLUGIN_LIBTOOLFLAGS="--tag=disable-static" +fi +AC_SUBST(GST_PLUGIN_LIBTOOLFLAGS) +AM_CONDITIONAL(GST_PLUGIN_BUILD_STATIC, test "x$enable_static_plugins" = "xyes") + +GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_.*' $GST_ALL_LDFLAGS" +AC_SUBST(GST_PLUGIN_LDFLAGS) + # set by AG_GST_PARSE_SUBSYSTEM_DISABLES above dnl make sure it doesn't complain about unused variables if debugging is disabled NO_WARNINGS="" @@ -324,6 +351,7 @@ common/Makefile common/m4/Makefile gst/Makefile gst/rtsp-server/Makefile +gst/rtsp-sink/Makefile examples/Makefile tests/Makefile tests/check/Makefile diff --git a/gst/Makefile.am b/gst/Makefile.am index e37bbc66e9..a97a8b8db5 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -1 +1 @@ -SUBDIRS = rtsp-server +SUBDIRS = rtsp-server rtsp-sink diff --git a/gst/rtsp-sink/Makefile.am b/gst/rtsp-sink/Makefile.am new file mode 100644 index 0000000000..23807ce6c7 --- /dev/null +++ b/gst/rtsp-sink/Makefile.am @@ -0,0 +1,18 @@ +plugin_LTLIBRARIES = libgstrtspclientsink.la + +libgstrtspclientsink_la_SOURCES = gstrtspclientsink.c plugin.c + +libgstrtspclientsink_la_CFLAGS = -I$(top_srcdir) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS) + +# FIXME: Hack to avoid having to add GETTEXT_PACKAGE to gst-rtsp +libgstrtspclientsink_la_CFLAGS += -D"GETTEXT_PACKAGE=gst-rtsp-server-1.0" + +libgstrtspclientsink_la_LIBADD = $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + -lgstrtp-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ \ + -lgstsdp-@GST_API_VERSION@ $(GST_NET_LIBS) $(GST_LIBS) \ + $(GIO_LIBS) +libgstrtspclientsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstrtspclientsink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) + +noinst_HEADERS = gstrtspclientsink.h diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c new file mode 100644 index 0000000000..55c40463e0 --- /dev/null +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -0,0 +1,4885 @@ +/* GStreamer + * Copyright (C) <2005,2006> Wim Taymans + * <2006> Lutz Mueller + * <2015> Jan Schmidt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/* + * Unless otherwise indicated, Source Code is licensed under MIT license. + * See further explanation attached in License Statement (distributed in the file + * LICENSE). + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + * SECTION:element-rtspclientsink + * + * Makes a connection to an RTSP server and send data via RTSP RECORD. + * rtspclientsink strictly follows RFC 2326 + * + * RTSP supports transport over TCP or UDP in unicast or multicast mode. By + * default rtspclientsink will negotiate a connection in the following order: + * UDP unicast/UDP multicast/TCP. The order cannot be changed but the allowed + * protocols can be controlled with the #GstRTSPClientSink:protocols property. + * + * rtspclientsink will internally instantiate an RTP session manager element + * that will handle the RTCP messages to and from the server, jitter removal, + * and packet reordering. + * This feature is implemented using the gstrtpbin element. + * + * rtspclientsink accepts any stream for which there is an installed payloader, + * creates the payloader and manages payload-types, as well as RTX setup. + * The new-payloader signal is fired when a payloader is created, in case + * an app wants to do custom configuration (such as for MTU). + * + * + * Example launch line + * |[ + * gst-launch-1.0 videotestsrc ! jpegenc ! rtspclientsink location=rtsp://some.server/url + * ]| Establish a connection to an RTSP server and send JPEG encoded video packets + * + */ + +/* FIXMEs + * - Handle EOS properly and shutdown. The problem with EOS is we don't know + * when the server has received all data, so we don't know when to do teardown. + * At the moment, we forward EOS to the app as soon as we stop sending. Is there + * a way to know from the receiver that it's got all data? Some session timeout? + * - Implement extension support for Real / WMS if they support RECORD? + * - Add support for network clock synchronised streaming? + * - Fix crypto key nego so SAVP/SAVPF profiles work. + * - Test (&fix?) HTTP tunnel support + * - Add an address pool object for GstRTSPStreams to use for multicast + * - Test multicast UDP transport + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "gstrtspclientsink.h" + +GST_DEBUG_CATEGORY_STATIC (rtsp_client_sink_debug); +#define GST_CAT_DEFAULT (rtsp_client_sink_debug) + +static GstStaticPadTemplate rtptemplate = GST_STATIC_PAD_TEMPLATE ("stream_%u", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS_ANY); /* Actual caps come from available set of payloaders */ + +enum +{ + SIGNAL_HANDLE_REQUEST, + SIGNAL_NEW_MANAGER, + SIGNAL_NEW_PAYLOADER, + SIGNAL_REQUEST_RTCP_KEY, + LAST_SIGNAL +}; + +enum _GstRTSPClientSinkNtpTimeSource +{ + NTP_TIME_SOURCE_NTP, + NTP_TIME_SOURCE_UNIX, + NTP_TIME_SOURCE_RUNNING_TIME, + NTP_TIME_SOURCE_CLOCK_TIME +}; + +#define GST_TYPE_RTSP_CLIENT_SINK_NTP_TIME_SOURCE (gst_rtsp_client_sink_ntp_time_source_get_type()) +static GType +gst_rtsp_client_sink_ntp_time_source_get_type (void) +{ + static GType ntp_time_source_type = 0; + static const GEnumValue ntp_time_source_values[] = { + {NTP_TIME_SOURCE_NTP, "NTP time based on realtime clock", "ntp"}, + {NTP_TIME_SOURCE_UNIX, "UNIX time based on realtime clock", "unix"}, + {NTP_TIME_SOURCE_RUNNING_TIME, + "Running time based on pipeline clock", + "running-time"}, + {NTP_TIME_SOURCE_CLOCK_TIME, "Pipeline clock time", "clock-time"}, + {0, NULL, NULL}, + }; + + if (!ntp_time_source_type) { + ntp_time_source_type = + g_enum_register_static ("GstRTSPClientSinkNtpTimeSource", + ntp_time_source_values); + } + return ntp_time_source_type; +} + +#define AES_128_KEY_LEN 16 +#define AES_256_KEY_LEN 32 + +#define HMAC_32_KEY_LEN 4 +#define HMAC_80_KEY_LEN 10 + +#define DEFAULT_LOCATION NULL +#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP +#define DEFAULT_DEBUG FALSE +#define DEFAULT_RETRY 20 +#define DEFAULT_TIMEOUT 5000000 +#define DEFAULT_UDP_BUFFER_SIZE 0x80000 +#define DEFAULT_TCP_TIMEOUT 20000000 +#define DEFAULT_LATENCY_MS 2000 +#define DEFAULT_DO_RTSP_KEEP_ALIVE TRUE +#define DEFAULT_PROXY NULL +#define DEFAULT_RTP_BLOCKSIZE 0 +#define DEFAULT_USER_ID NULL +#define DEFAULT_USER_PW NULL +#define DEFAULT_PORT_RANGE NULL +#define DEFAULT_UDP_RECONNECT TRUE +#define DEFAULT_MULTICAST_IFACE NULL +#define DEFAULT_TLS_VALIDATION_FLAGS G_TLS_CERTIFICATE_VALIDATE_ALL +#define DEFAULT_TLS_DATABASE NULL +#define DEFAULT_TLS_INTERACTION NULL +#define DEFAULT_NTP_TIME_SOURCE NTP_TIME_SOURCE_NTP +#define DEFAULT_USER_AGENT "GStreamer/" PACKAGE_VERSION +#define DEFAULT_PROFILES GST_RTSP_PROFILE_AVP +#define DEFAULT_RTX_TIME_MS 500 + +enum +{ + PROP_0, + PROP_LOCATION, + PROP_PROTOCOLS, + PROP_DEBUG, + PROP_RETRY, + PROP_TIMEOUT, + PROP_TCP_TIMEOUT, + PROP_LATENCY, + PROP_RTX_TIME, + PROP_DO_RTSP_KEEP_ALIVE, + PROP_PROXY, + PROP_PROXY_ID, + PROP_PROXY_PW, + PROP_RTP_BLOCKSIZE, + PROP_USER_ID, + PROP_USER_PW, + PROP_PORT_RANGE, + PROP_UDP_BUFFER_SIZE, + PROP_UDP_RECONNECT, + PROP_MULTICAST_IFACE, + PROP_SDES, + PROP_TLS_VALIDATION_FLAGS, + PROP_TLS_DATABASE, + PROP_TLS_INTERACTION, + PROP_NTP_TIME_SOURCE, + PROP_USER_AGENT, + PROP_PROFILES +}; + +static void gst_rtsp_client_sink_finalize (GObject * object); + +static void gst_rtsp_client_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_rtsp_client_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstClock *gst_rtsp_client_sink_provide_clock (GstElement * element); + +static void gst_rtsp_client_sink_uri_handler_init (gpointer g_iface, + gpointer iface_data); + +static gboolean gst_rtsp_client_sink_set_proxy (GstRTSPClientSink * rtsp, + const gchar * proxy); +static void gst_rtsp_client_sink_set_tcp_timeout (GstRTSPClientSink * + rtsp_client_sink, guint64 timeout); + +static GstStateChangeReturn gst_rtsp_client_sink_change_state (GstElement * + element, GstStateChange transition); +static void gst_rtsp_client_sink_handle_message (GstBin * bin, + GstMessage * message); + +static gboolean gst_rtsp_client_sink_setup_auth (GstRTSPClientSink * sink, + GstRTSPMessage * response); + +static gboolean gst_rtsp_client_sink_loop_send_cmd (GstRTSPClientSink * sink, + gint cmd, gint mask); + +static GstRTSPResult gst_rtsp_client_sink_open (GstRTSPClientSink * sink, + gboolean async); +static GstRTSPResult gst_rtsp_client_sink_record (GstRTSPClientSink * sink, + gboolean async); +static GstRTSPResult gst_rtsp_client_sink_pause (GstRTSPClientSink * sink, + gboolean async); +static GstRTSPResult gst_rtsp_client_sink_close (GstRTSPClientSink * sink, + gboolean async, gboolean only_close); +static gboolean gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink); + +static gboolean gst_rtsp_client_sink_uri_set_uri (GstURIHandler * handler, + const gchar * uri, GError ** error); +static gchar *gst_rtsp_client_sink_uri_get_uri (GstURIHandler * handler); + +static gboolean gst_rtsp_client_sink_loop (GstRTSPClientSink * sink); +static void gst_rtsp_client_sink_connection_flush (GstRTSPClientSink * sink, + gboolean flush); + +static GstPad *gst_rtsp_client_sink_request_new_pad (GstElement * element, + GstPadTemplate * templ, const gchar * name, const GstCaps * caps); +static void gst_rtsp_client_sink_release_pad (GstElement * element, + GstPad * pad); + +/* commands we send to out loop to notify it of events */ +#define CMD_OPEN (1 << 0) +#define CMD_RECORD (1 << 1) +#define CMD_PAUSE (1 << 2) +#define CMD_CLOSE (1 << 3) +#define CMD_WAIT (1 << 4) +#define CMD_RECONNECT (1 << 5) +#define CMD_LOOP (1 << 6) + +/* mask for all commands */ +#define CMD_ALL ((CMD_LOOP << 1) - 1) + +#define GST_ELEMENT_PROGRESS(el, type, code, text) \ +G_STMT_START { \ + gchar *__txt = _gst_element_error_printf text; \ + gst_element_post_message (GST_ELEMENT_CAST (el), \ + gst_message_new_progress (GST_OBJECT_CAST (el), \ + GST_PROGRESS_TYPE_ ##type, code, __txt)); \ + g_free (__txt); \ +} G_STMT_END + +static guint gst_rtsp_client_sink_signals[LAST_SIGNAL] = { 0 }; + +#define gst_rtsp_client_sink_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstRTSPClientSink, gst_rtsp_client_sink, GST_TYPE_BIN, + G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, + gst_rtsp_client_sink_uri_handler_init)); + +#ifndef GST_DISABLE_GST_DEBUG +static inline const gchar * +cmd_to_string (guint cmd) +{ + switch (cmd) { + case CMD_OPEN: + return "OPEN"; + case CMD_RECORD: + return "RECORD"; + case CMD_PAUSE: + return "PAUSE"; + case CMD_CLOSE: + return "CLOSE"; + case CMD_WAIT: + return "WAIT"; + case CMD_RECONNECT: + return "RECONNECT"; + case CMD_LOOP: + return "LOOP"; + } + + return "unknown"; +} +#endif + +static void +gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBinClass *gstbin_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbin_class = (GstBinClass *) klass; + + GST_DEBUG_CATEGORY_INIT (rtsp_client_sink_debug, "rtspclientsink", 0, + "RTSP sink element"); + + gobject_class->set_property = gst_rtsp_client_sink_set_property; + gobject_class->get_property = gst_rtsp_client_sink_get_property; + + gobject_class->finalize = gst_rtsp_client_sink_finalize; + + g_object_class_install_property (gobject_class, PROP_LOCATION, + g_param_spec_string ("location", "RTSP Location", + "Location of the RTSP url to read", + DEFAULT_LOCATION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_PROTOCOLS, + g_param_spec_flags ("protocols", "Protocols", + "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS, + DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_PROFILES, + g_param_spec_flags ("profiles", "Profiles", + "Allowed RTSP profiles", GST_TYPE_RTSP_PROFILE, + DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_DEBUG, + g_param_spec_boolean ("debug", "Debug", + "Dump request and response messages to stdout", + DEFAULT_DEBUG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_RETRY, + g_param_spec_uint ("retry", "Retry", + "Max number of retries when allocating RTP ports.", + 0, G_MAXUINT16, DEFAULT_RETRY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_TIMEOUT, + g_param_spec_uint64 ("timeout", "Timeout", + "Retry TCP transport after UDP timeout microseconds (0 = disabled)", + 0, G_MAXUINT64, DEFAULT_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_TCP_TIMEOUT, + g_param_spec_uint64 ("tcp-timeout", "TCP Timeout", + "Fail after timeout microseconds on TCP connections (0 = disabled)", + 0, G_MAXUINT64, DEFAULT_TCP_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_LATENCY, + g_param_spec_uint ("latency", "Buffer latency in ms", + "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_RTX_TIME, + g_param_spec_uint ("rtx-time", "Retransmission buffer in ms", + "Amount of ms to buffer for retransmission. 0 disables retransmission", + 0, G_MAXUINT, DEFAULT_RTX_TIME_MS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstRTSPClientSink:do-rtsp-keep-alive: + * + * Enable RTSP keep alive support. Some old server don't like RTSP + * keep alive and then this property needs to be set to FALSE. + */ + g_object_class_install_property (gobject_class, PROP_DO_RTSP_KEEP_ALIVE, + g_param_spec_boolean ("do-rtsp-keep-alive", "Do RTSP Keep Alive", + "Send RTSP keep alive packets, disable for old incompatible server.", + DEFAULT_DO_RTSP_KEEP_ALIVE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstRTSPClientSink:proxy: + * + * Set the proxy parameters. This has to be a string of the format + * [http://][user:passwd@]host[:port]. + */ + g_object_class_install_property (gobject_class, PROP_PROXY, + g_param_spec_string ("proxy", "Proxy", + "Proxy settings for HTTP tunneling. Format: [http://][user:passwd@]host[:port]", + DEFAULT_PROXY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPClientSink:proxy-id: + * + * Sets the proxy URI user id for authentication. If the URI set via the + * "proxy" property contains a user-id already, that will take precedence. + * + */ + g_object_class_install_property (gobject_class, PROP_PROXY_ID, + g_param_spec_string ("proxy-id", "proxy-id", + "HTTP proxy URI user id for authentication", "", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPClientSink:proxy-pw: + * + * Sets the proxy URI password for authentication. If the URI set via the + * "proxy" property contains a password already, that will take precedence. + * + */ + g_object_class_install_property (gobject_class, PROP_PROXY_PW, + g_param_spec_string ("proxy-pw", "proxy-pw", + "HTTP proxy URI user password for authentication", "", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstRTSPClientSink:rtp-blocksize: + * + * RTP package size to suggest to server. + */ + g_object_class_install_property (gobject_class, PROP_RTP_BLOCKSIZE, + g_param_spec_uint ("rtp-blocksize", "RTP Blocksize", + "RTP package size to suggest to server (0 = disabled)", + 0, 65536, DEFAULT_RTP_BLOCKSIZE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, + PROP_USER_ID, + g_param_spec_string ("user-id", "user-id", + "RTSP location URI user id for authentication", DEFAULT_USER_ID, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_USER_PW, + g_param_spec_string ("user-pw", "user-pw", + "RTSP location URI user password for authentication", DEFAULT_USER_PW, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstRTSPClientSink:port-range: + * + * Configure the client port numbers that can be used to receive + * RTCP. + */ + g_object_class_install_property (gobject_class, PROP_PORT_RANGE, + g_param_spec_string ("port-range", "Port range", + "Client port range that can be used to receive RTCP data, " + "eg. 3000-3005 (NULL = no restrictions)", DEFAULT_PORT_RANGE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstRTSPClientSink:udp-buffer-size: + * + * Size of the kernel UDP receive buffer in bytes. + */ + g_object_class_install_property (gobject_class, PROP_UDP_BUFFER_SIZE, + g_param_spec_int ("udp-buffer-size", "UDP Buffer Size", + "Size of the kernel UDP receive buffer in bytes, 0=default", + 0, G_MAXINT, DEFAULT_UDP_BUFFER_SIZE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_UDP_RECONNECT, + g_param_spec_boolean ("udp-reconnect", "Reconnect to the server", + "Reconnect to the server if RTSP connection is closed when doing UDP", + DEFAULT_UDP_RECONNECT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_MULTICAST_IFACE, + g_param_spec_string ("multicast-iface", "Multicast Interface", + "The network interface on which to join the multicast group", + DEFAULT_MULTICAST_IFACE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_SDES, + g_param_spec_boxed ("sdes", "SDES", + "The SDES items of this session", + GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstRTSPClientSink::tls-validation-flags: + * + * TLS certificate validation flags used to validate server + * certificate. + * + */ + g_object_class_install_property (gobject_class, PROP_TLS_VALIDATION_FLAGS, + g_param_spec_flags ("tls-validation-flags", "TLS validation flags", + "TLS certificate validation flags used to validate the server certificate", + G_TYPE_TLS_CERTIFICATE_FLAGS, DEFAULT_TLS_VALIDATION_FLAGS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstRTSPClientSink::tls-database: + * + * TLS database with anchor certificate authorities used to validate + * the server certificate. + * + */ + g_object_class_install_property (gobject_class, PROP_TLS_DATABASE, + g_param_spec_object ("tls-database", "TLS database", + "TLS database with anchor certificate authorities used to validate the server certificate", + G_TYPE_TLS_DATABASE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstRTSPClientSink::tls-interaction: + * + * A #GTlsInteraction object to be used when the connection or certificate + * database need to interact with the user. This will be used to prompt the + * user for passwords where necessary. + * + */ + g_object_class_install_property (gobject_class, PROP_TLS_INTERACTION, + g_param_spec_object ("tls-interaction", "TLS interaction", + "A GTlsInteraction object to prompt the user for password or certificate", + G_TYPE_TLS_INTERACTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstRTSPClientSink::ntp-time-source: + * + * allows to select the time source that should be used + * for the NTP time in outgoing packets + * + */ + g_object_class_install_property (gobject_class, PROP_NTP_TIME_SOURCE, + g_param_spec_enum ("ntp-time-source", "NTP Time Source", + "NTP time source for RTCP packets", + GST_TYPE_RTSP_CLIENT_SINK_NTP_TIME_SOURCE, DEFAULT_NTP_TIME_SOURCE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstRTSPClientSink::user-agent: + * + * The string to set in the User-Agent header. + * + */ + g_object_class_install_property (gobject_class, PROP_USER_AGENT, + g_param_spec_string ("user-agent", "User Agent", + "The User-Agent string to send to the server", + DEFAULT_USER_AGENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstRTSPClientSink::handle-request: + * @rtsp_client_sink: a #GstRTSPClientSink + * @request: a #GstRTSPMessage + * @response: a #GstRTSPMessage + * + * Handle a server request in @request and prepare @response. + * + * This signal is called from the streaming thread, you should therefore not + * do any state changes on @rtsp_client_sink because this might deadlock. If you want + * to modify the state as a result of this signal, post a + * #GST_MESSAGE_REQUEST_STATE message on the bus or signal the main thread + * in some other way. + * + */ + gst_rtsp_client_sink_signals[SIGNAL_HANDLE_REQUEST] = + g_signal_new ("handle-request", G_TYPE_FROM_CLASS (klass), 0, + 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, + G_TYPE_POINTER, G_TYPE_POINTER); + + /** + * GstRTSPClientSink::new-manager: + * @rtsp_client_sink: a #GstRTSPClientSink + * @manager: a #GstElement + * + * Emitted after a new manager (like rtpbin) was created and the default + * properties were configured. + * + */ + gst_rtsp_client_sink_signals[SIGNAL_NEW_MANAGER] = + g_signal_new_class_handler ("new-manager", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, 0, NULL, NULL, + g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + + /** + * GstRTSPClientSink::new-payloader: + * @rtsp_client_sink: a #GstRTSPClientSink + * @payloader: a #GstElement + * + * Emitted after a new RTP payloader was created and the default + * properties were configured. + * + */ + gst_rtsp_client_sink_signals[SIGNAL_NEW_PAYLOADER] = + g_signal_new_class_handler ("new-payloader", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, 0, NULL, NULL, + g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + + /** + * GstRTSPClientSink::request-rtcp-key: + * @rtsp_client_sink: a #GstRTSPClientSink + * @num: the stream number + * + * Signal emitted to get the crypto parameters relevant to the RTCP + * stream. User should provide the key and the RTCP encryption ciphers + * and authentication, and return them wrapped in a GstCaps. + * + */ + gst_rtsp_client_sink_signals[SIGNAL_REQUEST_RTCP_KEY] = + g_signal_new ("request-rtcp-key", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, GST_TYPE_CAPS, 1, G_TYPE_UINT); + + gstelement_class->provide_clock = gst_rtsp_client_sink_provide_clock; + gstelement_class->change_state = gst_rtsp_client_sink_change_state; + gstelement_class->request_new_pad = + GST_DEBUG_FUNCPTR (gst_rtsp_client_sink_request_new_pad); + gstelement_class->release_pad = + GST_DEBUG_FUNCPTR (gst_rtsp_client_sink_release_pad); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&rtptemplate)); + + gst_element_class_set_static_metadata (gstelement_class, + "RTSP RECORD client", "Sink/Network", + "Send data over the network via RTSP RECORD(RFC 2326)", + "Jan Schmidt "); + + gstbin_class->handle_message = gst_rtsp_client_sink_handle_message; +} + +static void +gst_rtsp_client_sink_init (GstRTSPClientSink * sink) +{ + sink->conninfo.location = g_strdup (DEFAULT_LOCATION); + sink->protocols = DEFAULT_PROTOCOLS; + sink->debug = DEFAULT_DEBUG; + sink->retry = DEFAULT_RETRY; + sink->udp_timeout = DEFAULT_TIMEOUT; + gst_rtsp_client_sink_set_tcp_timeout (sink, DEFAULT_TCP_TIMEOUT); + sink->latency = DEFAULT_LATENCY_MS; + sink->rtx_time = DEFAULT_RTX_TIME_MS; + sink->do_rtsp_keep_alive = DEFAULT_DO_RTSP_KEEP_ALIVE; + gst_rtsp_client_sink_set_proxy (sink, DEFAULT_PROXY); + sink->rtp_blocksize = DEFAULT_RTP_BLOCKSIZE; + sink->user_id = g_strdup (DEFAULT_USER_ID); + sink->user_pw = g_strdup (DEFAULT_USER_PW); + sink->client_port_range.min = 0; + sink->client_port_range.max = 0; + sink->udp_buffer_size = DEFAULT_UDP_BUFFER_SIZE; + sink->udp_reconnect = DEFAULT_UDP_RECONNECT; + sink->multi_iface = g_strdup (DEFAULT_MULTICAST_IFACE); + sink->sdes = NULL; + sink->tls_validation_flags = DEFAULT_TLS_VALIDATION_FLAGS; + sink->tls_database = DEFAULT_TLS_DATABASE; + sink->tls_interaction = DEFAULT_TLS_INTERACTION; + sink->ntp_time_source = DEFAULT_NTP_TIME_SOURCE; + sink->user_agent = g_strdup (DEFAULT_USER_AGENT); + + sink->profiles = DEFAULT_PROFILES; + + /* protects the streaming thread in interleaved mode or the polling + * thread in UDP mode. */ + g_rec_mutex_init (&sink->stream_rec_lock); + + /* protects our state changes from multiple invocations */ + g_rec_mutex_init (&sink->state_rec_lock); + + g_mutex_init (&sink->send_lock); + + g_mutex_init (&sink->preroll_lock); + g_cond_init (&sink->preroll_cond); + + sink->state = GST_RTSP_STATE_INVALID; + + sink->internal_bin = (GstBin *) gst_bin_new ("rtspbin"); + gst_element_set_locked_state (GST_ELEMENT_CAST (sink->internal_bin), TRUE); + gst_bin_add (GST_BIN (sink), GST_ELEMENT_CAST (sink->internal_bin)); + + sink->next_dyn_pt = 96; + + gst_sdp_message_init (&sink->cursdp); + + GST_OBJECT_FLAG_SET (sink, GST_ELEMENT_FLAG_SINK); +} + +static void +gst_rtsp_client_sink_finalize (GObject * object) +{ + GstRTSPClientSink *rtsp_client_sink; + + rtsp_client_sink = GST_RTSP_CLIENT_SINK (object); + + gst_sdp_message_uninit (&rtsp_client_sink->cursdp); + + g_free (rtsp_client_sink->conninfo.location); + gst_rtsp_url_free (rtsp_client_sink->conninfo.url); + g_free (rtsp_client_sink->conninfo.url_str); + g_free (rtsp_client_sink->user_id); + g_free (rtsp_client_sink->user_pw); + g_free (rtsp_client_sink->multi_iface); + g_free (rtsp_client_sink->user_agent); + + if (rtsp_client_sink->uri_sdp) { + gst_sdp_message_free (rtsp_client_sink->uri_sdp); + rtsp_client_sink->uri_sdp = NULL; + } + if (rtsp_client_sink->provided_clock) + gst_object_unref (rtsp_client_sink->provided_clock); + + if (rtsp_client_sink->sdes) + gst_structure_free (rtsp_client_sink->sdes); + + if (rtsp_client_sink->tls_database) + g_object_unref (rtsp_client_sink->tls_database); + + if (rtsp_client_sink->tls_interaction) + g_object_unref (rtsp_client_sink->tls_interaction); + + /* free locks */ + g_rec_mutex_clear (&rtsp_client_sink->stream_rec_lock); + g_rec_mutex_clear (&rtsp_client_sink->state_rec_lock); + + g_mutex_clear (&rtsp_client_sink->send_lock); + + g_mutex_clear (&rtsp_client_sink->preroll_lock); + g_cond_clear (&rtsp_client_sink->preroll_cond); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +gst_rtp_payloader_filter_func (GstPluginFeature * feature, gpointer user_data) +{ + GstElementFactory *factory = NULL; + const gchar *klass; + + if (!GST_IS_ELEMENT_FACTORY (feature)) + return FALSE; + + factory = GST_ELEMENT_FACTORY (feature); + + if (gst_plugin_feature_get_rank (feature) == GST_RANK_NONE) + return FALSE; + + if (!gst_element_factory_list_is_type (factory, + GST_ELEMENT_FACTORY_TYPE_PAYLOADER)) + return FALSE; + + klass = + gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS); + if (strstr (klass, "Codec") == NULL) + return FALSE; + if (strstr (klass, "RTP") == NULL) + return FALSE; + + return TRUE; +} + +static gint +compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2) +{ + gint diff; + const gchar *rname1, *rname2; + GstRank rank1, rank2; + + rname1 = gst_plugin_feature_get_name (f1); + rname2 = gst_plugin_feature_get_name (f2); + + rank1 = gst_plugin_feature_get_rank (f1); + rank2 = gst_plugin_feature_get_rank (f2); + + /* HACK: Prefer rtpmp4apay over rtpmp4gpay */ + if (g_str_equal (rname1, "rtpmp4apay")) + rank1 = GST_RANK_SECONDARY + 1; + if (g_str_equal (rname2, "rtpmp4apay")) + rank2 = GST_RANK_SECONDARY + 1; + + diff = rank2 - rank1; + if (diff != 0) + return diff; + + diff = strcmp (rname2, rname1); + + return diff; +} + +static GList * +gst_rtsp_client_sink_get_factories (void) +{ + static GList *payloader_factories = NULL; + + if (g_once_init_enter (&payloader_factories)) { + GList *all_factories; + + all_factories = + gst_registry_feature_filter (gst_registry_get (), + gst_rtp_payloader_filter_func, FALSE, NULL); + + all_factories = g_list_sort (all_factories, (GCompareFunc) compare_ranks); + + g_once_init_leave (&payloader_factories, all_factories); + } + + return payloader_factories; +} + +static GstCaps * +gst_rtsp_client_sink_get_payloader_caps (void) +{ + /* Cached caps result */ + static GstCaps *ret; + + if (g_once_init_enter (&ret)) { + GList *factories, *cur; + GstCaps *caps = gst_caps_new_empty (); + + factories = gst_rtsp_client_sink_get_factories (); + for (cur = factories; cur != NULL; cur = g_list_next (cur)) { + GstElementFactory *factory = GST_ELEMENT_FACTORY (cur->data); + const GList *tmp; + + for (tmp = gst_element_factory_get_static_pad_templates (factory); + tmp; tmp = g_list_next (tmp)) { + GstStaticPadTemplate *template = tmp->data; + + if (template->direction == GST_PAD_SINK) { + GstCaps *static_caps = gst_static_pad_template_get_caps (template); + + GST_LOG ("Found pad template %s on factory %s", + template->name_template, gst_plugin_feature_get_name (factory)); + + if (static_caps) + caps = gst_caps_merge (caps, static_caps); + + /* Early out, any is absorbing */ + if (gst_caps_is_any (caps)) + goto out; + } + } + } + out: + g_once_init_leave (&ret, caps); + } + + /* Return cached result */ + return gst_caps_ref (ret); +} + +static GstElement * +gst_rtsp_client_sink_make_payloader (GstCaps * caps) +{ + GList *factories, *cur; + + factories = gst_rtsp_client_sink_get_factories (); + for (cur = factories; cur != NULL; cur = g_list_next (cur)) { + GstElementFactory *factory = GST_ELEMENT_FACTORY (cur->data); + const GList *tmp; + + for (tmp = gst_element_factory_get_static_pad_templates (factory); + tmp; tmp = g_list_next (tmp)) { + GstStaticPadTemplate *template = tmp->data; + + if (template->direction == GST_PAD_SINK) { + GstCaps *static_caps = gst_static_pad_template_get_caps (template); + GstElement *payloader = NULL; + + if (gst_caps_can_intersect (static_caps, caps)) { + GST_DEBUG ("caps %" GST_PTR_FORMAT " intersects with template %" + GST_PTR_FORMAT " for payloader %s", caps, static_caps, + gst_plugin_feature_get_name (factory)); + payloader = gst_element_factory_create (factory, NULL); + } + + gst_caps_unref (static_caps); + + if (payloader) + return payloader; + } + } + } + + return NULL; +} + +static GstRTSPStream * +gst_rtsp_client_sink_create_stream (GstRTSPClientSink * sink, + GstRTSPStreamContext * context, GstElement * payloader, GstPad * pad) +{ + GstRTSPStream *stream = NULL; + guint pt, aux_pt; + + GST_OBJECT_LOCK (sink); + + g_object_get (G_OBJECT (payloader), "pt", &pt, NULL); + if (pt >= 96 && pt <= sink->next_dyn_pt) { + /* Payloader has a dynamic PT, but one that's already used */ + /* FIXME: Create a caps->ptmap instead? */ + pt = sink->next_dyn_pt; + + if (pt > 127) + goto no_free_pt; + + GST_DEBUG_OBJECT (sink, "Assigning pt %u to stream %d", pt, context->index); + + sink->next_dyn_pt++; + } else { + GST_DEBUG_OBJECT (sink, "Keeping existing pt %u for stream %d", + pt, context->index); + } + + aux_pt = sink->next_dyn_pt; + if (aux_pt > 127) + goto no_free_pt; + sink->next_dyn_pt++; + + GST_OBJECT_UNLOCK (sink); + + + g_object_set (G_OBJECT (payloader), "pt", pt, NULL); + + stream = gst_rtsp_stream_new (context->index, payloader, pad); + + gst_rtsp_stream_set_client_side (stream, TRUE); + gst_rtsp_stream_set_retransmission_time (stream, + (GstClockTime) (sink->rtx_time) * GST_MSECOND); + gst_rtsp_stream_set_protocols (stream, sink->protocols); + gst_rtsp_stream_set_profiles (stream, sink->profiles); + gst_rtsp_stream_set_retransmission_pt (stream, aux_pt); + gst_rtsp_stream_set_buffer_size (stream, sink->udp_buffer_size); + if (sink->rtp_blocksize > 0) + gst_rtsp_stream_set_mtu (stream, sink->rtp_blocksize); + +#if 0 + if (priv->pool) + gst_rtsp_stream_set_address_pool (stream, priv->pool); +#endif + + return stream; +no_free_pt: + GST_OBJECT_UNLOCK (sink); + + GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL), + ("Ran out of dynamic payload types.")); + + if (stream) + g_object_unref (stream); + return NULL; +} + +static GstPadProbeReturn +handle_payloader_block (GstPad * pad, GstPadProbeInfo * info, + GstRTSPStreamContext * context) +{ + GstRTSPClientSink *sink = context->parent; + + GST_INFO_OBJECT (sink, "Block on pad %" GST_PTR_FORMAT, pad); + + g_mutex_lock (&sink->preroll_lock); + context->prerolled = TRUE; + g_cond_broadcast (&sink->preroll_cond); + g_mutex_unlock (&sink->preroll_lock); + + GST_INFO_OBJECT (sink, "Announced preroll on pad %" GST_PTR_FORMAT, pad); + + return GST_PAD_PROBE_OK; +} + +static gboolean +gst_rtsp_client_sink_setup_payloader (GstRTSPClientSink * sink, GstPad * pad, + GstCaps * caps) +{ + GstRTSPStreamContext *context; + + GstElement *payloader; + GstPad *sinkpad, *srcpad, *ghostsink; + + context = gst_pad_get_element_private (pad); + + /* Find the payloader. FIXME: Allow user to provide payloader via pad property */ + payloader = gst_rtsp_client_sink_make_payloader (caps); + if (payloader == NULL) + return FALSE; + + GST_DEBUG_OBJECT (sink, "Configuring payloader %" GST_PTR_FORMAT + " for pad %" GST_PTR_FORMAT, payloader, pad); + + sinkpad = gst_element_get_static_pad (payloader, "sink"); + if (sinkpad == NULL) + goto no_sinkpad; + + srcpad = gst_element_get_static_pad (payloader, "src"); + if (srcpad == NULL) + goto no_srcpad; + + gst_bin_add (GST_BIN (sink->internal_bin), payloader); + ghostsink = gst_ghost_pad_new (NULL, sinkpad); + gst_pad_set_active (ghostsink, TRUE); + gst_element_add_pad (GST_ELEMENT (sink->internal_bin), ghostsink); + + g_signal_emit (sink, gst_rtsp_client_sink_signals[SIGNAL_NEW_PAYLOADER], 0, + payloader); + + GST_RTSP_STATE_LOCK (sink); + context->payloader_block_id = + gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, + (GstPadProbeCallback) handle_payloader_block, context, NULL); + context->payloader = payloader; + + payloader = gst_object_ref (payloader); + + gst_ghost_pad_set_target (GST_GHOST_PAD (pad), ghostsink); + gst_object_unref (GST_OBJECT (sinkpad)); + GST_RTSP_STATE_UNLOCK (sink); + + gst_element_sync_state_with_parent (payloader); + + gst_object_unref (payloader); + gst_object_unref (GST_OBJECT (srcpad)); + + return TRUE; + +no_sinkpad: + GST_ERROR_OBJECT (sink, + "Could not find sink pad on payloader %" GST_PTR_FORMAT, payloader); + gst_object_unref (payloader); + return FALSE; + +no_srcpad: + GST_ERROR_OBJECT (sink, + "Could not find src pad on payloader %" GST_PTR_FORMAT, payloader); + gst_object_unref (GST_OBJECT (sinkpad)); + gst_object_unref (payloader); + return TRUE; +} + +static gboolean +gst_rtsp_client_sink_sinkpad_event (GstPad * pad, GstObject * parent, + GstEvent * event) +{ + if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) { + GstPad *target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); + if (target == NULL) { + GstCaps *caps; + + /* No target yet - choose a payloader and configure it */ + gst_event_parse_caps (event, &caps); + + GST_DEBUG_OBJECT (parent, + "Have set caps event on pad %" GST_PTR_FORMAT + " caps %" GST_PTR_FORMAT, pad, caps); + + if (!gst_rtsp_client_sink_setup_payloader (GST_RTSP_CLIENT_SINK (parent), + pad, caps)) { + gst_event_unref (event); + return FALSE; + } + } + } + + return gst_pad_event_default (pad, parent, event); +} + +static gboolean +gst_rtsp_client_sink_sinkpad_query (GstPad * pad, GstObject * parent, + GstQuery * query) +{ + if (GST_QUERY_TYPE (query) == GST_QUERY_CAPS) { + GstPad *target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); + if (target == NULL) { + /* No target yet - return the union of all payloader caps */ + GstCaps *caps = gst_rtsp_client_sink_get_payloader_caps (); + + GST_TRACE_OBJECT (parent, "Returning payloader caps %" GST_PTR_FORMAT, + caps); + + gst_query_set_caps_result (query, caps); + gst_caps_unref (caps); + + return TRUE; + } + } + + return gst_pad_query_default (pad, parent, query); +} + +static GstPad * +gst_rtsp_client_sink_request_new_pad (GstElement * element, + GstPadTemplate * templ, const gchar * name, const GstCaps * caps) +{ + GstRTSPClientSink *sink = GST_RTSP_CLIENT_SINK (element); + GstPad *pad; + GstRTSPStreamContext *context; + guint idx = (guint) - 1; + gchar *tmpname; + + g_mutex_lock (&sink->preroll_lock); + if (sink->streams_collected) { + GST_WARNING_OBJECT (element, "Can't add streams to a running session"); + g_mutex_unlock (&sink->preroll_lock); + return NULL; + } + g_mutex_unlock (&sink->preroll_lock); + + GST_OBJECT_LOCK (sink); + if (name) { + if (!sscanf (name, "sink_%u", &idx)) { + GST_OBJECT_UNLOCK (sink); + GST_ERROR_OBJECT (element, "Invalid sink pad name %s", name); + return NULL; + } + + if (idx >= sink->next_pad_id) + sink->next_pad_id = idx + 1; + } + if (idx == (guint) - 1) { + idx = sink->next_pad_id; + sink->next_pad_id++; + } + GST_OBJECT_UNLOCK (sink); + + tmpname = g_strdup_printf ("sink_%u", idx); + pad = gst_ghost_pad_new_no_target_from_template (tmpname, templ); + g_free (tmpname); + + GST_DEBUG_OBJECT (element, "Creating request pad %" GST_PTR_FORMAT, pad); + + gst_pad_set_event_function (pad, + GST_DEBUG_FUNCPTR (gst_rtsp_client_sink_sinkpad_event)); + gst_pad_set_query_function (pad, + GST_DEBUG_FUNCPTR (gst_rtsp_client_sink_sinkpad_query)); + + context = g_new0 (GstRTSPStreamContext, 1); + context->parent = sink; + context->index = idx; + + gst_pad_set_element_private (pad, context); + + /* The rest of the context is configured on a caps set */ + gst_pad_set_active (pad, TRUE); + gst_element_add_pad (element, pad); + + (void) gst_rtsp_client_sink_get_factories (); + + GST_RTSP_STATE_LOCK (sink); + sink->contexts = g_list_prepend (sink->contexts, context); + GST_RTSP_STATE_UNLOCK (sink); + + return pad; +} + +static void +gst_rtsp_client_sink_release_pad (GstElement * element, GstPad * pad) +{ + GstRTSPClientSink *sink = GST_RTSP_CLIENT_SINK (element); + GstRTSPStreamContext *context; + + context = gst_pad_get_element_private (pad); + + GST_RTSP_STATE_LOCK (sink); + sink->contexts = g_list_remove (sink->contexts, context); + GST_RTSP_STATE_UNLOCK (sink); + + /* FIXME: Shut down and clean up streaming on this pad, + * do teardown if needed */ + GST_LOG_OBJECT (sink, + "Cleaning up payloader and stream for released pad %" GST_PTR_FORMAT, + pad); + + if (context->stream_transport) { + gst_rtsp_stream_transport_set_active (context->stream_transport, FALSE); + gst_object_unref (context->stream_transport); + context->stream_transport = NULL; + } + if (context->stream) { + if (context->joined) { + gst_rtsp_stream_leave_bin (context->stream, + GST_BIN (sink->internal_bin), sink->rtpbin); + context->joined = FALSE; + } + gst_object_unref (context->stream); + context->stream = NULL; + } + if (context->srtcpparams) + gst_caps_unref (context->srtcpparams); + + g_free (context->conninfo.location); + context->conninfo.location = NULL; + + g_free (context); + + gst_element_remove_pad (element, pad); +} + +static GstClock * +gst_rtsp_client_sink_provide_clock (GstElement * element) +{ + GstRTSPClientSink *sink = GST_RTSP_CLIENT_SINK (element); + GstClock *clock; + + if ((clock = sink->provided_clock) != NULL) + gst_object_ref (clock); + + return clock; +} + +/* a proxy string of the format [user:passwd@]host[:port] */ +static gboolean +gst_rtsp_client_sink_set_proxy (GstRTSPClientSink * rtsp, const gchar * proxy) +{ + gchar *p, *at, *col; + + g_free (rtsp->proxy_user); + rtsp->proxy_user = NULL; + g_free (rtsp->proxy_passwd); + rtsp->proxy_passwd = NULL; + g_free (rtsp->proxy_host); + rtsp->proxy_host = NULL; + rtsp->proxy_port = 0; + + p = (gchar *) proxy; + + if (p == NULL) + return TRUE; + + /* we allow http:// in front but ignore it */ + if (g_str_has_prefix (p, "http://")) + p += 7; + + at = strchr (p, '@'); + if (at) { + /* look for user:passwd */ + col = strchr (proxy, ':'); + if (col == NULL || col > at) + return FALSE; + + rtsp->proxy_user = g_strndup (p, col - p); + col++; + rtsp->proxy_passwd = g_strndup (col, at - col); + + /* move to host */ + p = at + 1; + } else { + if (rtsp->prop_proxy_id != NULL && *rtsp->prop_proxy_id != '\0') + rtsp->proxy_user = g_strdup (rtsp->prop_proxy_id); + if (rtsp->prop_proxy_pw != NULL && *rtsp->prop_proxy_pw != '\0') + rtsp->proxy_passwd = g_strdup (rtsp->prop_proxy_pw); + if (rtsp->proxy_user != NULL || rtsp->proxy_passwd != NULL) { + GST_LOG_OBJECT (rtsp, "set proxy user/pw from properties: %s:%s", + GST_STR_NULL (rtsp->proxy_user), GST_STR_NULL (rtsp->proxy_passwd)); + } + } + col = strchr (p, ':'); + + if (col) { + /* everything before the colon is the hostname */ + rtsp->proxy_host = g_strndup (p, col - p); + p = col + 1; + rtsp->proxy_port = strtoul (p, (char **) &p, 10); + } else { + rtsp->proxy_host = g_strdup (p); + rtsp->proxy_port = 8080; + } + return TRUE; +} + +static void +gst_rtsp_client_sink_set_tcp_timeout (GstRTSPClientSink * rtsp_client_sink, + guint64 timeout) +{ + rtsp_client_sink->tcp_timeout.tv_sec = timeout / G_USEC_PER_SEC; + rtsp_client_sink->tcp_timeout.tv_usec = timeout % G_USEC_PER_SEC; + + if (timeout != 0) + rtsp_client_sink->ptcp_timeout = &rtsp_client_sink->tcp_timeout; + else + rtsp_client_sink->ptcp_timeout = NULL; +} + +static void +gst_rtsp_client_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstRTSPClientSink *rtsp_client_sink; + + rtsp_client_sink = GST_RTSP_CLIENT_SINK (object); + + switch (prop_id) { + case PROP_LOCATION: + gst_rtsp_client_sink_uri_set_uri (GST_URI_HANDLER (rtsp_client_sink), + g_value_get_string (value), NULL); + break; + case PROP_PROTOCOLS: + rtsp_client_sink->protocols = g_value_get_flags (value); + break; + case PROP_PROFILES: + rtsp_client_sink->profiles = g_value_get_flags (value); + break; + case PROP_DEBUG: + rtsp_client_sink->debug = g_value_get_boolean (value); + break; + case PROP_RETRY: + rtsp_client_sink->retry = g_value_get_uint (value); + break; + case PROP_TIMEOUT: + rtsp_client_sink->udp_timeout = g_value_get_uint64 (value); + break; + case PROP_TCP_TIMEOUT: + gst_rtsp_client_sink_set_tcp_timeout (rtsp_client_sink, + g_value_get_uint64 (value)); + break; + case PROP_LATENCY: + rtsp_client_sink->latency = g_value_get_uint (value); + break; + case PROP_RTX_TIME: + rtsp_client_sink->rtx_time = g_value_get_uint (value); + break; + case PROP_DO_RTSP_KEEP_ALIVE: + rtsp_client_sink->do_rtsp_keep_alive = g_value_get_boolean (value); + break; + case PROP_PROXY: + gst_rtsp_client_sink_set_proxy (rtsp_client_sink, + g_value_get_string (value)); + break; + case PROP_PROXY_ID: + if (rtsp_client_sink->prop_proxy_id) + g_free (rtsp_client_sink->prop_proxy_id); + rtsp_client_sink->prop_proxy_id = g_value_dup_string (value); + break; + case PROP_PROXY_PW: + if (rtsp_client_sink->prop_proxy_pw) + g_free (rtsp_client_sink->prop_proxy_pw); + rtsp_client_sink->prop_proxy_pw = g_value_dup_string (value); + break; + case PROP_RTP_BLOCKSIZE: + rtsp_client_sink->rtp_blocksize = g_value_get_uint (value); + break; + case PROP_USER_ID: + if (rtsp_client_sink->user_id) + g_free (rtsp_client_sink->user_id); + rtsp_client_sink->user_id = g_value_dup_string (value); + break; + case PROP_USER_PW: + if (rtsp_client_sink->user_pw) + g_free (rtsp_client_sink->user_pw); + rtsp_client_sink->user_pw = g_value_dup_string (value); + break; + case PROP_PORT_RANGE: + { + const gchar *str; + + str = g_value_get_string (value); + if (str) { + sscanf (str, "%u-%u", + &rtsp_client_sink->client_port_range.min, + &rtsp_client_sink->client_port_range.max); + } else { + rtsp_client_sink->client_port_range.min = 0; + rtsp_client_sink->client_port_range.max = 0; + } + break; + } + case PROP_UDP_BUFFER_SIZE: + rtsp_client_sink->udp_buffer_size = g_value_get_int (value); + break; + case PROP_UDP_RECONNECT: + rtsp_client_sink->udp_reconnect = g_value_get_boolean (value); + break; + case PROP_MULTICAST_IFACE: + g_free (rtsp_client_sink->multi_iface); + + if (g_value_get_string (value) == NULL) + rtsp_client_sink->multi_iface = g_strdup (DEFAULT_MULTICAST_IFACE); + else + rtsp_client_sink->multi_iface = g_value_dup_string (value); + break; + case PROP_SDES: + rtsp_client_sink->sdes = g_value_dup_boxed (value); + break; + case PROP_TLS_VALIDATION_FLAGS: + rtsp_client_sink->tls_validation_flags = g_value_get_flags (value); + break; + case PROP_TLS_DATABASE: + g_clear_object (&rtsp_client_sink->tls_database); + rtsp_client_sink->tls_database = g_value_dup_object (value); + break; + case PROP_TLS_INTERACTION: + g_clear_object (&rtsp_client_sink->tls_interaction); + rtsp_client_sink->tls_interaction = g_value_dup_object (value); + break; + case PROP_NTP_TIME_SOURCE: + rtsp_client_sink->ntp_time_source = g_value_get_enum (value); + break; + case PROP_USER_AGENT: + g_free (rtsp_client_sink->user_agent); + rtsp_client_sink->user_agent = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_rtsp_client_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstRTSPClientSink *rtsp_client_sink; + + rtsp_client_sink = GST_RTSP_CLIENT_SINK (object); + + switch (prop_id) { + case PROP_LOCATION: + g_value_set_string (value, rtsp_client_sink->conninfo.location); + break; + case PROP_PROTOCOLS: + g_value_set_flags (value, rtsp_client_sink->protocols); + break; + case PROP_PROFILES: + g_value_set_flags (value, rtsp_client_sink->profiles); + break; + case PROP_DEBUG: + g_value_set_boolean (value, rtsp_client_sink->debug); + break; + case PROP_RETRY: + g_value_set_uint (value, rtsp_client_sink->retry); + break; + case PROP_TIMEOUT: + g_value_set_uint64 (value, rtsp_client_sink->udp_timeout); + break; + case PROP_TCP_TIMEOUT: + { + guint64 timeout; + + timeout = rtsp_client_sink->tcp_timeout.tv_sec * G_USEC_PER_SEC + + rtsp_client_sink->tcp_timeout.tv_usec; + g_value_set_uint64 (value, timeout); + break; + } + case PROP_LATENCY: + g_value_set_uint (value, rtsp_client_sink->latency); + break; + case PROP_RTX_TIME: + g_value_set_uint (value, rtsp_client_sink->rtx_time); + break; + case PROP_DO_RTSP_KEEP_ALIVE: + g_value_set_boolean (value, rtsp_client_sink->do_rtsp_keep_alive); + break; + case PROP_PROXY: + { + gchar *str; + + if (rtsp_client_sink->proxy_host) { + str = + g_strdup_printf ("%s:%d", rtsp_client_sink->proxy_host, + rtsp_client_sink->proxy_port); + } else { + str = NULL; + } + g_value_take_string (value, str); + break; + } + case PROP_PROXY_ID: + g_value_set_string (value, rtsp_client_sink->prop_proxy_id); + break; + case PROP_PROXY_PW: + g_value_set_string (value, rtsp_client_sink->prop_proxy_pw); + break; + case PROP_RTP_BLOCKSIZE: + g_value_set_uint (value, rtsp_client_sink->rtp_blocksize); + break; + case PROP_USER_ID: + g_value_set_string (value, rtsp_client_sink->user_id); + break; + case PROP_USER_PW: + g_value_set_string (value, rtsp_client_sink->user_pw); + break; + case PROP_PORT_RANGE: + { + gchar *str; + + if (rtsp_client_sink->client_port_range.min != 0) { + str = g_strdup_printf ("%u-%u", rtsp_client_sink->client_port_range.min, + rtsp_client_sink->client_port_range.max); + } else { + str = NULL; + } + g_value_take_string (value, str); + break; + } + case PROP_UDP_BUFFER_SIZE: + g_value_set_int (value, rtsp_client_sink->udp_buffer_size); + break; + case PROP_UDP_RECONNECT: + g_value_set_boolean (value, rtsp_client_sink->udp_reconnect); + break; + case PROP_MULTICAST_IFACE: + g_value_set_string (value, rtsp_client_sink->multi_iface); + break; + case PROP_SDES: + g_value_set_boxed (value, rtsp_client_sink->sdes); + break; + case PROP_TLS_VALIDATION_FLAGS: + g_value_set_flags (value, rtsp_client_sink->tls_validation_flags); + break; + case PROP_TLS_DATABASE: + g_value_set_object (value, rtsp_client_sink->tls_database); + break; + case PROP_TLS_INTERACTION: + g_value_set_object (value, rtsp_client_sink->tls_interaction); + break; + case PROP_NTP_TIME_SOURCE: + g_value_set_enum (value, rtsp_client_sink->ntp_time_source); + break; + case PROP_USER_AGENT: + g_value_set_string (value, rtsp_client_sink->user_agent); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static const gchar * +get_aggregate_control (GstRTSPClientSink * sink) +{ + const gchar *base; + + if (sink->control) + base = sink->control; + else if (sink->content_base) + base = sink->content_base; + else if (sink->conninfo.url_str) + base = sink->conninfo.url_str; + else + base = "/"; + + return base; +} + +static void +gst_rtsp_client_sink_cleanup (GstRTSPClientSink * sink) +{ + GList *walk; + + GST_DEBUG_OBJECT (sink, "cleanup"); + + gst_element_set_state (GST_ELEMENT (sink->internal_bin), GST_STATE_NULL); + + /* Clean up any left over stream objects */ + for (walk = sink->contexts; walk; walk = g_list_next (walk)) { + GstRTSPStreamContext *context = (GstRTSPStreamContext *) (walk->data); + if (context->stream_transport) { + gst_rtsp_stream_transport_set_active (context->stream_transport, FALSE); + gst_object_unref (context->stream_transport); + context->stream_transport = NULL; + } + + if (context->stream) { + if (context->joined) { + gst_rtsp_stream_leave_bin (context->stream, + GST_BIN (sink->internal_bin), sink->rtpbin); + context->joined = FALSE; + } + gst_object_unref (context->stream); + context->stream = NULL; + } + + if (context->srtcpparams) + gst_caps_unref (context->srtcpparams); + g_free (context->conninfo.location); + context->conninfo.location = NULL; + } + + if (sink->rtpbin) { + gst_element_set_state (sink->rtpbin, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (sink->internal_bin), sink->rtpbin); + sink->rtpbin = NULL; + } + + g_free (sink->content_base); + sink->content_base = NULL; + + g_free (sink->control); + sink->control = NULL; + + if (sink->range) + gst_rtsp_range_free (sink->range); + sink->range = NULL; + + /* don't clear the SDP when it was used in the url */ + if (sink->uri_sdp && !sink->from_sdp) { + gst_sdp_message_free (sink->uri_sdp); + sink->uri_sdp = NULL; + } + + if (sink->provided_clock) { + gst_object_unref (sink->provided_clock); + sink->provided_clock = NULL; + } + + g_free (sink->server_ip); + sink->server_ip = NULL; + + sink->next_pad_id = 0; + sink->next_dyn_pt = 96; +} + +static GstRTSPResult +gst_rtsp_client_sink_connection_send (GstRTSPClientSink * sink, + GstRTSPConnection * conn, GstRTSPMessage * message, GTimeVal * timeout) +{ + GstRTSPResult ret; + + if (conn) + ret = gst_rtsp_connection_send (conn, message, timeout); + else + ret = GST_RTSP_ERROR; + + return ret; +} + +static GstRTSPResult +gst_rtsp_client_sink_connection_receive (GstRTSPClientSink * sink, + GstRTSPConnection * conn, GstRTSPMessage * message, GTimeVal * timeout) +{ + GstRTSPResult ret; + + if (conn) + ret = gst_rtsp_connection_receive (conn, message, timeout); + else + ret = GST_RTSP_ERROR; + + return ret; +} + +static GstRTSPResult +gst_rtsp_conninfo_connect (GstRTSPClientSink * sink, GstRTSPConnInfo * info, + gboolean async) +{ + GstRTSPResult res; + + if (info->connection == NULL) { + if (info->url == NULL) { + GST_DEBUG_OBJECT (sink, "parsing uri (%s)...", info->location); + if ((res = gst_rtsp_url_parse (info->location, &info->url)) < 0) + goto parse_error; + } + + /* create connection */ + GST_DEBUG_OBJECT (sink, "creating connection (%s)...", info->location); + if ((res = gst_rtsp_connection_create (info->url, &info->connection)) < 0) + goto could_not_create; + + if (info->url_str) + g_free (info->url_str); + info->url_str = gst_rtsp_url_get_request_uri (info->url); + + GST_DEBUG_OBJECT (sink, "sanitized uri %s", info->url_str); + + if (info->url->transports & GST_RTSP_LOWER_TRANS_TLS) { + if (!gst_rtsp_connection_set_tls_validation_flags (info->connection, + sink->tls_validation_flags)) + GST_WARNING_OBJECT (sink, "Unable to set TLS validation flags"); + + if (sink->tls_database) + gst_rtsp_connection_set_tls_database (info->connection, + sink->tls_database); + + if (sink->tls_interaction) + gst_rtsp_connection_set_tls_interaction (info->connection, + sink->tls_interaction); + } + + if (info->url->transports & GST_RTSP_LOWER_TRANS_HTTP) + gst_rtsp_connection_set_tunneled (info->connection, TRUE); + + if (sink->proxy_host) { + GST_DEBUG_OBJECT (sink, "setting proxy %s:%d", sink->proxy_host, + sink->proxy_port); + gst_rtsp_connection_set_proxy (info->connection, sink->proxy_host, + sink->proxy_port); + } + } + + if (!info->connected) { + /* connect */ + if (async) + GST_ELEMENT_PROGRESS (sink, CONTINUE, "connect", + ("Connecting to %s", info->location)); + GST_DEBUG_OBJECT (sink, "connecting (%s)...", info->location); + if ((res = + gst_rtsp_connection_connect (info->connection, + sink->ptcp_timeout)) < 0) + goto could_not_connect; + + info->connected = TRUE; + } + return GST_RTSP_OK; + + /* ERRORS */ +parse_error: + { + GST_ERROR_OBJECT (sink, "No valid RTSP URL was provided"); + return res; + } +could_not_create: + { + gchar *str = gst_rtsp_strresult (res); + GST_ERROR_OBJECT (sink, "Could not create connection. (%s)", str); + g_free (str); + return res; + } +could_not_connect: + { + gchar *str = gst_rtsp_strresult (res); + GST_ERROR_OBJECT (sink, "Could not connect to server. (%s)", str); + g_free (str); + return res; + } +} + +static GstRTSPResult +gst_rtsp_conninfo_close (GstRTSPClientSink * sink, GstRTSPConnInfo * info, + gboolean free) +{ + GST_RTSP_STATE_LOCK (sink); + if (info->connected) { + GST_DEBUG_OBJECT (sink, "closing connection..."); + gst_rtsp_connection_close (info->connection); + info->connected = FALSE; + } + if (free && info->connection) { + /* free connection */ + GST_DEBUG_OBJECT (sink, "freeing connection..."); + gst_rtsp_connection_free (info->connection); + info->connection = NULL; + } + GST_RTSP_STATE_UNLOCK (sink); + return GST_RTSP_OK; +} + +static GstRTSPResult +gst_rtsp_conninfo_reconnect (GstRTSPClientSink * sink, GstRTSPConnInfo * info, + gboolean async) +{ + GstRTSPResult res; + + GST_DEBUG_OBJECT (sink, "reconnecting connection..."); + gst_rtsp_conninfo_close (sink, info, FALSE); + res = gst_rtsp_conninfo_connect (sink, info, async); + + return res; +} + +static void +gst_rtsp_client_sink_connection_flush (GstRTSPClientSink * sink, gboolean flush) +{ + GList *walk; + + GST_DEBUG_OBJECT (sink, "set flushing %d", flush); + g_mutex_lock (&sink->preroll_lock); + if (sink->conninfo.connection && sink->conninfo.flushing != flush) { + GST_DEBUG_OBJECT (sink, "connection flush"); + gst_rtsp_connection_flush (sink->conninfo.connection, flush); + sink->conninfo.flushing = flush; + } + for (walk = sink->contexts; walk; walk = g_list_next (walk)) { + GstRTSPStreamContext *stream = (GstRTSPStreamContext *) walk->data; + if (stream->conninfo.connection && stream->conninfo.flushing != flush) { + GST_DEBUG_OBJECT (sink, "stream %p flush", stream); + gst_rtsp_connection_flush (stream->conninfo.connection, flush); + stream->conninfo.flushing = flush; + } + } + g_cond_broadcast (&sink->preroll_cond); + g_mutex_unlock (&sink->preroll_lock); +} + +static GstRTSPResult +gst_rtsp_client_sink_init_request (GstRTSPClientSink * sink, + GstRTSPMessage * msg, GstRTSPMethod method, const gchar * uri) +{ + GstRTSPResult res; + + res = gst_rtsp_message_init_request (msg, method, uri); + if (res < 0) + return res; + + /* set user-agent */ + if (sink->user_agent) + gst_rtsp_message_add_header (msg, GST_RTSP_HDR_USER_AGENT, + sink->user_agent); + + return res; +} + +/* FIXME, handle server request, reply with OK, for now */ +static GstRTSPResult +gst_rtsp_client_sink_handle_request (GstRTSPClientSink * sink, + GstRTSPConnection * conn, GstRTSPMessage * request) +{ + GstRTSPMessage response = { 0 }; + GstRTSPResult res; + + GST_DEBUG_OBJECT (sink, "got server request message"); + + if (sink->debug) + gst_rtsp_message_dump (request); + + /* default implementation, send OK */ + GST_DEBUG_OBJECT (sink, "prepare OK reply"); + res = + gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, "OK", + request); + if (res < 0) + goto send_error; + + /* let app parse and reply */ + g_signal_emit (sink, gst_rtsp_client_sink_signals[SIGNAL_HANDLE_REQUEST], + 0, request, &response); + + if (sink->debug) + gst_rtsp_message_dump (&response); + + res = gst_rtsp_client_sink_connection_send (sink, conn, &response, NULL); + if (res < 0) + goto send_error; + + gst_rtsp_message_unset (&response); + + return GST_RTSP_OK; + + /* ERRORS */ +send_error: + { + gst_rtsp_message_unset (&response); + return res; + } +} + +/* send server keep-alive */ +static GstRTSPResult +gst_rtsp_client_sink_send_keep_alive (GstRTSPClientSink * sink) +{ + GstRTSPMessage request = { 0 }; + GstRTSPResult res; + GstRTSPMethod method; + const gchar *control; + + if (sink->do_rtsp_keep_alive == FALSE) { + GST_DEBUG_OBJECT (sink, "do-rtsp-keep-alive is FALSE, not sending."); + gst_rtsp_connection_reset_timeout (sink->conninfo.connection); + return GST_RTSP_OK; + } + + GST_DEBUG_OBJECT (sink, "creating server keep-alive"); + + /* find a method to use for keep-alive */ + if (sink->methods & GST_RTSP_GET_PARAMETER) + method = GST_RTSP_GET_PARAMETER; + else + method = GST_RTSP_OPTIONS; + + control = get_aggregate_control (sink); + if (control == NULL) + goto no_control; + + res = gst_rtsp_client_sink_init_request (sink, &request, method, control); + if (res < 0) + goto send_error; + + if (sink->debug) + gst_rtsp_message_dump (&request); + + res = + gst_rtsp_client_sink_connection_send (sink, sink->conninfo.connection, + &request, NULL); + if (res < 0) + goto send_error; + + gst_rtsp_connection_reset_timeout (sink->conninfo.connection); + gst_rtsp_message_unset (&request); + + return GST_RTSP_OK; + + /* ERRORS */ +no_control: + { + GST_WARNING_OBJECT (sink, "no control url to send keepalive"); + return GST_RTSP_OK; + } +send_error: + { + gchar *str = gst_rtsp_strresult (res); + + gst_rtsp_message_unset (&request); + GST_ELEMENT_WARNING (sink, RESOURCE, WRITE, (NULL), + ("Could not send keep-alive. (%s)", str)); + g_free (str); + return res; + } +} + +static GstFlowReturn +gst_rtsp_client_sink_loop_rx (GstRTSPClientSink * sink) +{ + GstRTSPResult res; + GstRTSPMessage message = { 0 }; + gint retry = 0; + + while (TRUE) { + GTimeVal tv_timeout; + + /* get the next timeout interval */ + gst_rtsp_connection_next_timeout (sink->conninfo.connection, &tv_timeout); + + GST_DEBUG_OBJECT (sink, "doing receive with timeout %d seconds", + (gint) tv_timeout.tv_sec); + + gst_rtsp_message_unset (&message); + + /* we should continue reading the TCP socket because the server might + * send us requests. When the session timeout expires, we need to send a + * keep-alive request to keep the session open. */ + res = + gst_rtsp_client_sink_connection_receive (sink, + sink->conninfo.connection, &message, &tv_timeout); + + switch (res) { + case GST_RTSP_OK: + GST_DEBUG_OBJECT (sink, "we received a server message"); + break; + case GST_RTSP_EINTR: + /* we got interrupted, see what we have to do */ + goto interrupt; + case GST_RTSP_ETIMEOUT: + /* send keep-alive, ignore the result, a warning will be posted. */ + GST_DEBUG_OBJECT (sink, "timeout, sending keep-alive"); + if ((res = + gst_rtsp_client_sink_send_keep_alive (sink)) == GST_RTSP_EINTR) + goto interrupt; + continue; + case GST_RTSP_EEOF: + /* server closed the connection. not very fatal for UDP, reconnect and + * see what happens. */ + GST_ELEMENT_WARNING (sink, RESOURCE, READ, (NULL), + ("The server closed the connection.")); + if (sink->udp_reconnect) { + if ((res = + gst_rtsp_conninfo_reconnect (sink, &sink->conninfo, + FALSE)) < 0) + goto connect_error; + } else { + goto server_eof; + } + continue; + case GST_RTSP_ENET: + GST_DEBUG_OBJECT (sink, "An ethernet problem occured."); + default: + GST_ELEMENT_WARNING (sink, RESOURCE, READ, (NULL), + ("Unhandled return value %d.", res)); + goto receive_error; + } + + switch (message.type) { + case GST_RTSP_MESSAGE_REQUEST: + /* server sends us a request message, handle it */ + res = + gst_rtsp_client_sink_handle_request (sink, + sink->conninfo.connection, &message); + if (res == GST_RTSP_EEOF) + goto server_eof; + else if (res < 0) + goto handle_request_failed; + break; + case GST_RTSP_MESSAGE_RESPONSE: + /* we ignore response and data messages */ + GST_DEBUG_OBJECT (sink, "ignoring response message"); + if (sink->debug) + gst_rtsp_message_dump (&message); + if (message.type_data.response.code == GST_RTSP_STS_UNAUTHORIZED) { + GST_DEBUG_OBJECT (sink, "but is Unauthorized response ..."); + if (gst_rtsp_client_sink_setup_auth (sink, &message) && !(retry++)) { + GST_DEBUG_OBJECT (sink, "so retrying keep-alive"); + if ((res = + gst_rtsp_client_sink_send_keep_alive (sink)) == + GST_RTSP_EINTR) + goto interrupt; + } + } else { + retry = 0; + } + break; + case GST_RTSP_MESSAGE_DATA: + /* we ignore response and data messages */ + GST_DEBUG_OBJECT (sink, "ignoring data message"); + break; + default: + GST_WARNING_OBJECT (sink, "ignoring unknown message type %d", + message.type); + break; + } + } + g_assert_not_reached (); + + /* we get here when the connection got interrupted */ +interrupt: + { + gst_rtsp_message_unset (&message); + GST_DEBUG_OBJECT (sink, "got interrupted"); + return GST_FLOW_FLUSHING; + } +connect_error: + { + gchar *str = gst_rtsp_strresult (res); + GstFlowReturn ret; + + sink->conninfo.connected = FALSE; + if (res != GST_RTSP_EINTR) { + GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ_WRITE, (NULL), + ("Could not connect to server. (%s)", str)); + g_free (str); + ret = GST_FLOW_ERROR; + } else { + ret = GST_FLOW_FLUSHING; + } + return ret; + } +receive_error: + { + gchar *str = gst_rtsp_strresult (res); + + GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL), + ("Could not receive message. (%s)", str)); + g_free (str); + return GST_FLOW_ERROR; + } +handle_request_failed: + { + gchar *str = gst_rtsp_strresult (res); + GstFlowReturn ret; + + gst_rtsp_message_unset (&message); + if (res != GST_RTSP_EINTR) { + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), + ("Could not handle server message. (%s)", str)); + g_free (str); + ret = GST_FLOW_ERROR; + } else { + ret = GST_FLOW_FLUSHING; + } + return ret; + } +server_eof: + { + GST_DEBUG_OBJECT (sink, "we got an eof from the server"); + GST_ELEMENT_WARNING (sink, RESOURCE, READ, (NULL), + ("The server closed the connection.")); + sink->conninfo.connected = FALSE; + gst_rtsp_message_unset (&message); + return GST_FLOW_EOS; + } +} + +static GstRTSPResult +gst_rtsp_client_sink_reconnect (GstRTSPClientSink * sink, gboolean async) +{ + GstRTSPResult res = GST_RTSP_OK; + gboolean restart = FALSE; + + GST_DEBUG_OBJECT (sink, "doing reconnect"); + + GST_FIXME_OBJECT (sink, "Reconnection is not yet implemented"); + + /* no need to restart, we're done */ + if (!restart) + goto done; + + /* we can try only TCP now */ + sink->cur_protocols = GST_RTSP_LOWER_TRANS_TCP; + + /* close and cleanup our state */ + if ((res = gst_rtsp_client_sink_close (sink, async, FALSE)) < 0) + goto done; + + /* see if we have TCP left to try. Also don't try TCP when we were configured + * with an SDP. */ + if (!(sink->protocols & GST_RTSP_LOWER_TRANS_TCP) || sink->from_sdp) + goto no_protocols; + + /* We post a warning message now to inform the user + * that nothing happened. It's most likely a firewall thing. */ + GST_ELEMENT_WARNING (sink, RESOURCE, READ, (NULL), + ("Could not receive any UDP packets for %.4f seconds, maybe your " + "firewall is blocking it. Retrying using a TCP connection.", + gst_guint64_to_gdouble (sink->udp_timeout / 1000000.0))); + + /* open new connection using tcp */ + if (gst_rtsp_client_sink_open (sink, async) < 0) + goto open_failed; + + /* start recording */ + if (gst_rtsp_client_sink_record (sink, async) < 0) + goto play_failed; + +done: + return res; + + /* ERRORS */ +no_protocols: + { + sink->cur_protocols = 0; + /* no transport possible, post an error and stop */ + GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL), + ("Could not receive any UDP packets for %.4f seconds, maybe your " + "firewall is blocking it. No other protocols to try.", + gst_guint64_to_gdouble (sink->udp_timeout / 1000000.0))); + return GST_RTSP_ERROR; + } +open_failed: + { + GST_DEBUG_OBJECT (sink, "open failed"); + return GST_RTSP_OK; + } +play_failed: + { + GST_DEBUG_OBJECT (sink, "play failed"); + return GST_RTSP_OK; + } +} + +static void +gst_rtsp_client_sink_loop_start_cmd (GstRTSPClientSink * sink, gint cmd) +{ + switch (cmd) { + case CMD_OPEN: + GST_ELEMENT_PROGRESS (sink, START, "open", ("Opening Stream")); + break; + case CMD_RECORD: + GST_ELEMENT_PROGRESS (sink, START, "request", ("Sending RECORD request")); + break; + case CMD_PAUSE: + GST_ELEMENT_PROGRESS (sink, START, "request", ("Sending PAUSE request")); + break; + case CMD_CLOSE: + GST_ELEMENT_PROGRESS (sink, START, "close", ("Closing Stream")); + break; + default: + break; + } +} + +static void +gst_rtsp_client_sink_loop_complete_cmd (GstRTSPClientSink * sink, gint cmd) +{ + switch (cmd) { + case CMD_OPEN: + GST_ELEMENT_PROGRESS (sink, COMPLETE, "open", ("Opened Stream")); + break; + case CMD_RECORD: + GST_ELEMENT_PROGRESS (sink, COMPLETE, "request", ("Sent RECORD request")); + break; + case CMD_PAUSE: + GST_ELEMENT_PROGRESS (sink, COMPLETE, "request", ("Sent PAUSE request")); + break; + case CMD_CLOSE: + GST_ELEMENT_PROGRESS (sink, COMPLETE, "close", ("Closed Stream")); + break; + default: + break; + } +} + +static void +gst_rtsp_client_sink_loop_cancel_cmd (GstRTSPClientSink * sink, gint cmd) +{ + switch (cmd) { + case CMD_OPEN: + GST_ELEMENT_PROGRESS (sink, CANCELED, "open", ("Open canceled")); + break; + case CMD_RECORD: + GST_ELEMENT_PROGRESS (sink, CANCELED, "request", ("RECORD canceled")); + break; + case CMD_PAUSE: + GST_ELEMENT_PROGRESS (sink, CANCELED, "request", ("PAUSE canceled")); + break; + case CMD_CLOSE: + GST_ELEMENT_PROGRESS (sink, CANCELED, "close", ("Close canceled")); + break; + default: + break; + } +} + +static void +gst_rtsp_client_sink_loop_error_cmd (GstRTSPClientSink * sink, gint cmd) +{ + switch (cmd) { + case CMD_OPEN: + GST_ELEMENT_PROGRESS (sink, ERROR, "open", ("Open failed")); + break; + case CMD_RECORD: + GST_ELEMENT_PROGRESS (sink, ERROR, "request", ("RECORD failed")); + break; + case CMD_PAUSE: + GST_ELEMENT_PROGRESS (sink, ERROR, "request", ("PAUSE failed")); + break; + case CMD_CLOSE: + GST_ELEMENT_PROGRESS (sink, ERROR, "close", ("Close failed")); + break; + default: + break; + } +} + +static void +gst_rtsp_client_sink_loop_end_cmd (GstRTSPClientSink * sink, gint cmd, + GstRTSPResult ret) +{ + if (ret == GST_RTSP_OK) + gst_rtsp_client_sink_loop_complete_cmd (sink, cmd); + else if (ret == GST_RTSP_EINTR) + gst_rtsp_client_sink_loop_cancel_cmd (sink, cmd); + else + gst_rtsp_client_sink_loop_error_cmd (sink, cmd); +} + +static gboolean +gst_rtsp_client_sink_loop_send_cmd (GstRTSPClientSink * sink, gint cmd, + gint mask) +{ + gint old; + gboolean flushed = FALSE; + + /* start new request */ + gst_rtsp_client_sink_loop_start_cmd (sink, cmd); + + GST_DEBUG_OBJECT (sink, "sending cmd %s", cmd_to_string (cmd)); + + GST_OBJECT_LOCK (sink); + old = sink->pending_cmd; + if (old == CMD_RECONNECT) { + GST_DEBUG_OBJECT (sink, "ignore, we were reconnecting"); + cmd = CMD_RECONNECT; + } + if (old != CMD_WAIT) { + sink->pending_cmd = CMD_WAIT; + GST_OBJECT_UNLOCK (sink); + /* cancel previous request */ + GST_DEBUG_OBJECT (sink, "cancel previous request %s", cmd_to_string (old)); + gst_rtsp_client_sink_loop_cancel_cmd (sink, old); + GST_OBJECT_LOCK (sink); + } + sink->pending_cmd = cmd; + /* interrupt if allowed */ + if (sink->busy_cmd & mask) { + GST_DEBUG_OBJECT (sink, "connection flush busy %s", + cmd_to_string (sink->busy_cmd)); + gst_rtsp_client_sink_connection_flush (sink, TRUE); + flushed = TRUE; + } else { + GST_DEBUG_OBJECT (sink, "not interrupting busy cmd %s", + cmd_to_string (sink->busy_cmd)); + } + if (sink->task) + gst_task_start (sink->task); + GST_OBJECT_UNLOCK (sink); + + return flushed; +} + +static gboolean +gst_rtsp_client_sink_loop (GstRTSPClientSink * sink) +{ + GstFlowReturn ret; + + if (!sink->conninfo.connection || !sink->conninfo.connected) + goto no_connection; + + ret = gst_rtsp_client_sink_loop_rx (sink); + if (ret != GST_FLOW_OK) + goto pause; + + return TRUE; + + /* ERRORS */ +no_connection: + { + GST_WARNING_OBJECT (sink, "we are not connected"); + ret = GST_FLOW_FLUSHING; + goto pause; + } +pause: + { + const gchar *reason = gst_flow_get_name (ret); + + GST_DEBUG_OBJECT (sink, "pausing task, reason %s", reason); + gst_rtsp_client_sink_loop_send_cmd (sink, CMD_WAIT, CMD_LOOP); + return FALSE; + } +} + +#ifndef GST_DISABLE_GST_DEBUG +static const gchar * +gst_rtsp_auth_method_to_string (GstRTSPAuthMethod method) +{ + gint index = 0; + + while (method != 0) { + index++; + method >>= 1; + } + switch (index) { + case 0: + return "None"; + case 1: + return "Basic"; + case 2: + return "Digest"; + } + + return "Unknown"; +} +#endif + +static const gchar * +gst_rtsp_client_sink_skip_lws (const gchar * s) +{ + while (g_ascii_isspace (*s)) + s++; + return s; +} + +static const gchar * +gst_rtsp_client_sink_unskip_lws (const gchar * s, const gchar * start) +{ + while (s > start && g_ascii_isspace (*(s - 1))) + s--; + return s; +} + +static const gchar * +gst_rtsp_client_sink_skip_commas (const gchar * s) +{ + /* The grammar allows for multiple commas */ + while (g_ascii_isspace (*s) || *s == ',') + s++; + return s; +} + +static const gchar * +gst_rtsp_client_sink_skip_item (const gchar * s) +{ + gboolean quoted = FALSE; + const gchar *start = s; + + /* A list item ends at the last non-whitespace character + * before a comma which is not inside a quoted-string. Or at + * the end of the string. + */ + while (*s) { + if (*s == '"') + quoted = !quoted; + else if (quoted) { + if (*s == '\\' && *(s + 1)) + s++; + } else { + if (*s == ',') + break; + } + s++; + } + + return gst_rtsp_client_sink_unskip_lws (s, start); +} + +static void +gst_rtsp_decode_quoted_string (gchar * quoted_string) +{ + gchar *src, *dst; + + src = quoted_string + 1; + dst = quoted_string; + while (*src && *src != '"') { + if (*src == '\\' && *(src + 1)) + src++; + *dst++ = *src++; + } + *dst = '\0'; +} + +/* Extract the authentication tokens that the server provided for each method + * into an array of structures and give those to the connection object. + */ +static void +gst_rtsp_client_sink_parse_digest_challenge (GstRTSPConnection * conn, + const gchar * header, gboolean * stale) +{ + GSList *list = NULL, *iter; + const gchar *end; + gchar *item, *eq, *name_end, *value; + + g_return_if_fail (stale != NULL); + + gst_rtsp_connection_clear_auth_params (conn); + *stale = FALSE; + + /* Parse a header whose content is described by RFC2616 as + * "#something", where "something" does not itself contain commas, + * except as part of quoted-strings, into a list of allocated strings. + */ + header = gst_rtsp_client_sink_skip_commas (header); + while (*header) { + end = gst_rtsp_client_sink_skip_item (header); + list = g_slist_prepend (list, g_strndup (header, end - header)); + header = gst_rtsp_client_sink_skip_commas (end); + } + if (!list) + return; + + list = g_slist_reverse (list); + for (iter = list; iter; iter = iter->next) { + item = iter->data; + + eq = strchr (item, '='); + if (eq) { + name_end = (gchar *) gst_rtsp_client_sink_unskip_lws (eq, item); + if (name_end == item) { + /* That's no good... */ + g_free (item); + continue; + } + + *name_end = '\0'; + + value = (gchar *) gst_rtsp_client_sink_skip_lws (eq + 1); + if (*value == '"') + gst_rtsp_decode_quoted_string (value); + } else + value = NULL; + + if (value && strcmp (item, "stale") == 0 && strcmp (value, "TRUE") == 0) + *stale = TRUE; + gst_rtsp_connection_set_auth_param (conn, item, value); + g_free (item); + } + + g_slist_free (list); +} + +/* Parse a WWW-Authenticate Response header and determine the + * available authentication methods + * + * This code should also cope with the fact that each WWW-Authenticate + * header can contain multiple challenge methods + tokens + * + * At the moment, for Basic auth, we just do a minimal check and don't + * even parse out the realm */ +static void +gst_rtsp_client_sink_parse_auth_hdr (gchar * hdr, GstRTSPAuthMethod * methods, + GstRTSPConnection * conn, gboolean * stale) +{ + gchar *start; + + g_return_if_fail (hdr != NULL); + g_return_if_fail (methods != NULL); + g_return_if_fail (stale != NULL); + + /* Skip whitespace at the start of the string */ + for (start = hdr; start[0] != '\0' && g_ascii_isspace (start[0]); start++); + + if (g_ascii_strncasecmp (start, "basic", 5) == 0) + *methods |= GST_RTSP_AUTH_BASIC; + else if (g_ascii_strncasecmp (start, "digest ", 7) == 0) { + *methods |= GST_RTSP_AUTH_DIGEST; + gst_rtsp_client_sink_parse_digest_challenge (conn, &start[7], stale); + } +} + +/** + * gst_rtsp_client_sink_setup_auth: + * @src: the rtsp source + * + * Configure a username and password and auth method on the + * connection object based on a response we received from the + * peer. + * + * Currently, this requires that a username and password were supplied + * in the uri. In the future, they may be requested on demand by sending + * a message up the bus. + * + * Returns: TRUE if authentication information could be set up correctly. + */ +static gboolean +gst_rtsp_client_sink_setup_auth (GstRTSPClientSink * sink, + GstRTSPMessage * response) +{ + gchar *user = NULL; + gchar *pass = NULL; + GstRTSPAuthMethod avail_methods = GST_RTSP_AUTH_NONE; + GstRTSPAuthMethod method; + GstRTSPResult auth_result; + GstRTSPUrl *url; + GstRTSPConnection *conn; + gchar *hdr; + gboolean stale = FALSE; + + conn = sink->conninfo.connection; + + /* Identify the available auth methods and see if any are supported */ + if (gst_rtsp_message_get_header (response, GST_RTSP_HDR_WWW_AUTHENTICATE, + &hdr, 0) == GST_RTSP_OK) { + gst_rtsp_client_sink_parse_auth_hdr (hdr, &avail_methods, conn, &stale); + } + + if (avail_methods == GST_RTSP_AUTH_NONE) + goto no_auth_available; + + /* For digest auth, if the response indicates that the session + * data are stale, we just update them in the connection object and + * return TRUE to retry the request */ + if (stale) + sink->tried_url_auth = FALSE; + + url = gst_rtsp_connection_get_url (conn); + + /* Do we have username and password available? */ + if (url != NULL && !sink->tried_url_auth && url->user != NULL + && url->passwd != NULL) { + user = url->user; + pass = url->passwd; + sink->tried_url_auth = TRUE; + GST_DEBUG_OBJECT (sink, + "Attempting authentication using credentials from the URL"); + } else { + user = sink->user_id; + pass = sink->user_pw; + GST_DEBUG_OBJECT (sink, + "Attempting authentication using credentials from the properties"); + } + + /* FIXME: If the url didn't contain username and password or we tried them + * already, request a username and passwd from the application via some kind + * of credentials request message */ + + /* If we don't have a username and passwd at this point, bail out. */ + if (user == NULL || pass == NULL) + goto no_user_pass; + + /* Try to configure for each available authentication method, strongest to + * weakest */ + for (method = GST_RTSP_AUTH_MAX; method != GST_RTSP_AUTH_NONE; method >>= 1) { + /* Check if this method is available on the server */ + if ((method & avail_methods) == 0) + continue; + + /* Pass the credentials to the connection to try on the next request */ + auth_result = gst_rtsp_connection_set_auth (conn, method, user, pass); + /* INVAL indicates an invalid username/passwd were supplied, so we'll just + * ignore it and end up retrying later */ + if (auth_result == GST_RTSP_OK || auth_result == GST_RTSP_EINVAL) { + GST_DEBUG_OBJECT (sink, "Attempting %s authentication", + gst_rtsp_auth_method_to_string (method)); + break; + } + } + + if (method == GST_RTSP_AUTH_NONE) + goto no_auth_available; + + return TRUE; + +no_auth_available: + { + /* Output an error indicating that we couldn't connect because there were + * no supported authentication protocols */ + GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ, (NULL), + ("No supported authentication protocol was found")); + return FALSE; + } +no_user_pass: + { + /* We don't fire an error message, we just return FALSE and let the + * normal NOT_AUTHORIZED error be propagated */ + return FALSE; + } +} + +static GstRTSPResult +gst_rtsp_client_sink_try_send (GstRTSPClientSink * sink, + GstRTSPConnection * conn, GstRTSPMessage * request, + GstRTSPMessage * response, GstRTSPStatusCode * code) +{ + GstRTSPResult res; + GstRTSPStatusCode thecode; + gchar *content_base = NULL; + gint try = 0; + +again: + GST_DEBUG_OBJECT (sink, "sending message"); + + if (sink->debug) + gst_rtsp_message_dump (request); + + g_mutex_lock (&sink->send_lock); + + res = + gst_rtsp_client_sink_connection_send (sink, conn, request, + sink->ptcp_timeout); + if (res < 0) { + g_mutex_unlock (&sink->send_lock); + goto send_error; + } + + gst_rtsp_connection_reset_timeout (conn); + + /* See if we should handle the response */ + if (response == NULL) { + g_mutex_unlock (&sink->send_lock); + return GST_RTSP_OK; + } +next: + res = + gst_rtsp_client_sink_connection_receive (sink, conn, response, + sink->ptcp_timeout); + + g_mutex_unlock (&sink->send_lock); + + if (res < 0) + goto receive_error; + + if (sink->debug) + gst_rtsp_message_dump (response); + + + switch (response->type) { + case GST_RTSP_MESSAGE_REQUEST: + res = gst_rtsp_client_sink_handle_request (sink, conn, response); + if (res == GST_RTSP_EEOF) + goto server_eof; + else if (res < 0) + goto handle_request_failed; + g_mutex_lock (&sink->send_lock); + goto next; + case GST_RTSP_MESSAGE_RESPONSE: + /* ok, a response is good */ + GST_DEBUG_OBJECT (sink, "received response message"); + break; + case GST_RTSP_MESSAGE_DATA: + /* we ignore data messages */ + GST_DEBUG_OBJECT (sink, "ignoring data message"); + g_mutex_lock (&sink->send_lock); + goto next; + default: + GST_WARNING_OBJECT (sink, "ignoring unknown message type %d", + response->type); + g_mutex_lock (&sink->send_lock); + goto next; + } + + thecode = response->type_data.response.code; + + GST_DEBUG_OBJECT (sink, "got response message %d", thecode); + + /* if the caller wanted the result code, we store it. */ + if (code) + *code = thecode; + + /* If the request didn't succeed, bail out before doing any more */ + if (thecode != GST_RTSP_STS_OK) + return GST_RTSP_OK; + + /* store new content base if any */ + gst_rtsp_message_get_header (response, GST_RTSP_HDR_CONTENT_BASE, + &content_base, 0); + if (content_base) { + g_free (sink->content_base); + sink->content_base = g_strdup (content_base); + } + + return GST_RTSP_OK; + + /* ERRORS */ +send_error: + { + gchar *str = gst_rtsp_strresult (res); + + if (res != GST_RTSP_EINTR) { + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), + ("Could not send message. (%s)", str)); + } else { + GST_WARNING_OBJECT (sink, "send interrupted"); + } + g_free (str); + return res; + } +receive_error: + { + switch (res) { + case GST_RTSP_EEOF: + GST_WARNING_OBJECT (sink, "server closed connection"); + if ((try == 0) && !sink->interleaved && sink->udp_reconnect) { + try++; + /* if reconnect succeeds, try again */ + if ((res = + gst_rtsp_conninfo_reconnect (sink, &sink->conninfo, + FALSE)) == 0) + goto again; + } + /* only try once after reconnect, then fallthrough and error out */ + default: + { + gchar *str = gst_rtsp_strresult (res); + + if (res != GST_RTSP_EINTR) { + GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL), + ("Could not receive message. (%s)", str)); + } else { + GST_WARNING_OBJECT (sink, "receive interrupted"); + } + g_free (str); + break; + } + } + return res; + } +handle_request_failed: + { + /* ERROR was posted */ + gst_rtsp_message_unset (response); + return res; + } +server_eof: + { + GST_DEBUG_OBJECT (sink, "we got an eof from the server"); + GST_ELEMENT_WARNING (sink, RESOURCE, READ, (NULL), + ("The server closed the connection.")); + gst_rtsp_message_unset (response); + return res; + } +} + +static void +gst_rtsp_client_sink_set_state (GstRTSPClientSink * sink, GstState state) +{ + GST_DEBUG_OBJECT (sink, "Setting internal state to %s", + gst_element_state_get_name (state)); + gst_element_set_state (GST_ELEMENT (sink->internal_bin), state); +} + +/** + * gst_rtsp_client_sink_send: + * @src: the rtsp source + * @conn: the connection to send on + * @request: must point to a valid request + * @response: must point to an empty #GstRTSPMessage + * @code: an optional code result + * + * send @request and retrieve the response in @response. optionally @code can be + * non-NULL in which case it will contain the status code of the response. + * + * If This function returns #GST_RTSP_OK, @response will contain a valid response + * message that should be cleaned with gst_rtsp_message_unset() after usage. + * + * If @code is NULL, this function will return #GST_RTSP_ERROR (with an invalid + * @response message) if the response code was not 200 (OK). + * + * If the attempt results in an authentication failure, then this will attempt + * to retrieve authentication credentials via gst_rtsp_client_sink_setup_auth and retry + * the request. + * + * Returns: #GST_RTSP_OK if the processing was successful. + */ +static GstRTSPResult +gst_rtsp_client_sink_send (GstRTSPClientSink * sink, GstRTSPConnection * conn, + GstRTSPMessage * request, GstRTSPMessage * response, + GstRTSPStatusCode * code) +{ + GstRTSPStatusCode int_code = GST_RTSP_STS_OK; + GstRTSPResult res = GST_RTSP_ERROR; + gint count; + gboolean retry; + GstRTSPMethod method = GST_RTSP_INVALID; + + count = 0; + do { + retry = FALSE; + + /* make sure we don't loop forever */ + if (count++ > 8) + break; + + /* save method so we can disable it when the server complains */ + method = request->type_data.request.method; + + if ((res = + gst_rtsp_client_sink_try_send (sink, conn, request, response, + &int_code)) < 0) + goto error; + + switch (int_code) { + case GST_RTSP_STS_UNAUTHORIZED: + if (gst_rtsp_client_sink_setup_auth (sink, response)) { + /* Try the request/response again after configuring the auth info + * and loop again */ + retry = TRUE; + } + break; + default: + break; + } + } while (retry == TRUE); + + /* If the user requested the code, let them handle errors, otherwise + * post an error below */ + if (code != NULL) + *code = int_code; + else if (int_code != GST_RTSP_STS_OK) + goto error_response; + + return res; + + /* ERRORS */ +error: + { + GST_DEBUG_OBJECT (sink, "got error %d", res); + return res; + } +error_response: + { + res = GST_RTSP_ERROR; + + switch (response->type_data.response.code) { + case GST_RTSP_STS_NOT_FOUND: + GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, (NULL), ("%s", + response->type_data.response.reason)); + break; + case GST_RTSP_STS_UNAUTHORIZED: + GST_ELEMENT_ERROR (sink, RESOURCE, NOT_AUTHORIZED, (NULL), ("%s", + response->type_data.response.reason)); + break; + case GST_RTSP_STS_MOVED_PERMANENTLY: + case GST_RTSP_STS_MOVE_TEMPORARILY: + { + gchar *new_location; + GstRTSPLowerTrans transports; + + GST_DEBUG_OBJECT (sink, "got redirection"); + /* if we don't have a Location Header, we must error */ + if (gst_rtsp_message_get_header (response, GST_RTSP_HDR_LOCATION, + &new_location, 0) < 0) + break; + + /* When we receive a redirect result, we go back to the INIT state after + * parsing the new URI. The caller should do the needed steps to issue + * a new setup when it detects this state change. */ + GST_DEBUG_OBJECT (sink, "redirection to %s", new_location); + + /* save current transports */ + if (sink->conninfo.url) + transports = sink->conninfo.url->transports; + else + transports = GST_RTSP_LOWER_TRANS_UNKNOWN; + + gst_rtsp_client_sink_uri_set_uri (GST_URI_HANDLER (sink), new_location, + NULL); + + /* set old transports */ + if (sink->conninfo.url && transports != GST_RTSP_LOWER_TRANS_UNKNOWN) + sink->conninfo.url->transports = transports; + + sink->need_redirect = TRUE; + sink->state = GST_RTSP_STATE_INIT; + res = GST_RTSP_OK; + break; + } + case GST_RTSP_STS_NOT_ACCEPTABLE: + case GST_RTSP_STS_NOT_IMPLEMENTED: + case GST_RTSP_STS_METHOD_NOT_ALLOWED: + GST_WARNING_OBJECT (sink, "got NOT IMPLEMENTED, disable method %s", + gst_rtsp_method_as_text (method)); + sink->methods &= ~method; + res = GST_RTSP_OK; + break; + default: + GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL), + ("Got error response: %d (%s).", response->type_data.response.code, + response->type_data.response.reason)); + break; + } + /* if we return ERROR we should unset the response ourselves */ + if (res == GST_RTSP_ERROR) + gst_rtsp_message_unset (response); + + return res; + } +} + +/* parse the response and collect all the supported methods. We need this + * information so that we don't try to send an unsupported request to the + * server. + */ +static gboolean +gst_rtsp_client_sink_parse_methods (GstRTSPClientSink * sink, + GstRTSPMessage * response) +{ + GstRTSPHeaderField field; + gchar *respoptions; + gint indx = 0; + + /* reset supported methods */ + sink->methods = 0; + + /* Try Allow Header first */ + field = GST_RTSP_HDR_ALLOW; + while (TRUE) { + respoptions = NULL; + gst_rtsp_message_get_header (response, field, &respoptions, indx); + if (indx == 0 && !respoptions) { + /* if no Allow header was found then try the Public header... */ + field = GST_RTSP_HDR_PUBLIC; + gst_rtsp_message_get_header (response, field, &respoptions, indx); + } + if (!respoptions) + break; + + sink->methods |= gst_rtsp_options_from_text (respoptions); + + indx++; + } + + if (sink->methods == 0) { + /* neither Allow nor Public are required, assume the server supports + * at least SETUP. */ + GST_DEBUG_OBJECT (sink, "could not get OPTIONS"); + sink->methods = GST_RTSP_SETUP; + } + + /* Even if the server replied, and didn't say it supports + * RECORD|ANNOUNCE, try anyway by assuming it does */ + sink->methods |= GST_RTSP_ANNOUNCE | GST_RTSP_RECORD; + + if (!(sink->methods & GST_RTSP_SETUP)) + goto no_setup; + + return TRUE; + + /* ERRORS */ +no_setup: + { + GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ, (NULL), + ("Server does not support SETUP.")); + return FALSE; + } +} + +static GstRTSPResult +gst_rtsp_client_sink_connect_to_server (GstRTSPClientSink * sink, + gboolean async) +{ + GstRTSPResult res; + GstRTSPMessage request = { 0 }; + GstRTSPMessage response = { 0 }; + GSocket *conn_socket; + GSocketAddress *sa; + GInetAddress *ia; + + sink->need_redirect = FALSE; + + /* can't continue without a valid url */ + if (G_UNLIKELY (sink->conninfo.url == NULL)) { + res = GST_RTSP_EINVAL; + goto no_url; + } + sink->tried_url_auth = FALSE; + + if ((res = gst_rtsp_conninfo_connect (sink, &sink->conninfo, async)) < 0) + goto connect_failed; + + conn_socket = gst_rtsp_connection_get_read_socket (sink->conninfo.connection); + sa = g_socket_get_remote_address (conn_socket, NULL); + ia = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sa)); + + sink->server_ip = g_inet_address_to_string (ia); + + g_object_unref (sa); + + /* create OPTIONS */ + GST_DEBUG_OBJECT (sink, "create options..."); + res = + gst_rtsp_client_sink_init_request (sink, &request, GST_RTSP_OPTIONS, + sink->conninfo.url_str); + if (res < 0) + goto create_request_failed; + + /* send OPTIONS */ + GST_DEBUG_OBJECT (sink, "send options..."); + + if (async) + GST_ELEMENT_PROGRESS (sink, CONTINUE, "open", + ("Retrieving server options")); + + if ((res = + gst_rtsp_client_sink_send (sink, sink->conninfo.connection, &request, + &response, NULL)) < 0) + goto send_error; + + /* parse OPTIONS */ + if (!gst_rtsp_client_sink_parse_methods (sink, &response)) + goto methods_error; + + /* FIXME: Do we need to handle REDIRECT responses for OPTIONS? */ + + /* clean up any messages */ + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + + return res; + + /* ERRORS */ +no_url: + { + GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, (NULL), + ("No valid RTSP URL was provided")); + goto cleanup_error; + } +connect_failed: + { + gchar *str = gst_rtsp_strresult (res); + + if (res != GST_RTSP_EINTR) { + GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ_WRITE, (NULL), + ("Failed to connect. (%s)", str)); + } else { + GST_WARNING_OBJECT (sink, "connect interrupted"); + } + g_free (str); + goto cleanup_error; + } +create_request_failed: + { + gchar *str = gst_rtsp_strresult (res); + + GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL), + ("Could not create request. (%s)", str)); + g_free (str); + goto cleanup_error; + } +send_error: + { + /* Don't post a message - the rtsp_send method will have + * taken care of it because we passed NULL for the response code */ + goto cleanup_error; + } +methods_error: + { + /* error was posted */ + res = GST_RTSP_ERROR; + goto cleanup_error; + } +cleanup_error: + { + if (sink->conninfo.connection) { + GST_DEBUG_OBJECT (sink, "free connection"); + gst_rtsp_conninfo_close (sink, &sink->conninfo, TRUE); + } + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + return res; + } +} + +static GstRTSPResult +gst_rtsp_client_sink_open (GstRTSPClientSink * sink, gboolean async) +{ + GstRTSPResult ret; + + sink->methods = + GST_RTSP_SETUP | GST_RTSP_RECORD | GST_RTSP_PAUSE | GST_RTSP_TEARDOWN; + + if ((ret = gst_rtsp_client_sink_connect_to_server (sink, async)) < 0) + goto open_failed; + + if (async) + gst_rtsp_client_sink_loop_end_cmd (sink, CMD_OPEN, ret); + + /* Collect all our input streams and create + * stream objects before actually returning */ + gst_rtsp_client_sink_collect_streams (sink); + + return ret; + + /* ERRORS */ +open_failed: + { + GST_WARNING_OBJECT (sink, "Failed to connect to server"); + sink->open_error = TRUE; + if (async) + gst_rtsp_client_sink_loop_end_cmd (sink, CMD_OPEN, ret); + return ret; + } +} + +static GstRTSPResult +gst_rtsp_client_sink_close (GstRTSPClientSink * sink, gboolean async, + gboolean only_close) +{ + GstRTSPMessage request = { 0 }; + GstRTSPMessage response = { 0 }; + GstRTSPResult res = GST_RTSP_OK; + GList *walk; + const gchar *control; + + GST_DEBUG_OBJECT (sink, "TEARDOWN..."); + + gst_rtsp_client_sink_set_state (sink, GST_STATE_NULL); + + if (sink->state < GST_RTSP_STATE_READY) { + GST_DEBUG_OBJECT (sink, "not ready, doing cleanup"); + goto close; + } + + if (only_close) + goto close; + + /* construct a control url */ + control = get_aggregate_control (sink); + + if (!(sink->methods & (GST_RTSP_RECORD | GST_RTSP_TEARDOWN))) + goto not_supported; + + /* stop streaming */ + for (walk = sink->contexts; walk; walk = g_list_next (walk)) { + GstRTSPStreamContext *context = (GstRTSPStreamContext *) walk->data; + + if (context->stream_transport) + gst_rtsp_stream_transport_set_active (context->stream_transport, FALSE); + + if (context->joined) { + gst_rtsp_stream_leave_bin (context->stream, GST_BIN (sink->internal_bin), + sink->rtpbin); + context->joined = FALSE; + } + } + + for (walk = sink->contexts; walk; walk = g_list_next (walk)) { + GstRTSPStreamContext *context = (GstRTSPStreamContext *) walk->data; + const gchar *setup_url; + GstRTSPConnInfo *info; + + GST_DEBUG_OBJECT (sink, "Looking at stream %p for teardown", + context->stream); + + /* try aggregate control first but do non-aggregate control otherwise */ + if (control) + setup_url = control; + else if ((setup_url = context->conninfo.location) == NULL) { + GST_DEBUG_OBJECT (sink, "Skipping TEARDOWN stream %p - no setup URL", + context->stream); + continue; + } + + if (sink->conninfo.connection) { + info = &sink->conninfo; + } else if (context->conninfo.connection) { + info = &context->conninfo; + } else { + continue; + } + if (!info->connected) + goto next; + + /* do TEARDOWN */ + GST_DEBUG_OBJECT (sink, "Sending teardown for stream %p at URL %s", + context->stream, setup_url); + res = + gst_rtsp_client_sink_init_request (sink, &request, GST_RTSP_TEARDOWN, + setup_url); + if (res < 0) + goto create_request_failed; + + if (async) + GST_ELEMENT_PROGRESS (sink, CONTINUE, "close", ("Closing stream")); + + if ((res = + gst_rtsp_client_sink_send (sink, info->connection, &request, + &response, NULL)) < 0) + goto send_error; + + /* FIXME, parse result? */ + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + + next: + /* early exit when we did aggregate control */ + if (control) + break; + } + +close: + /* close connections */ + GST_DEBUG_OBJECT (sink, "closing connection..."); + gst_rtsp_conninfo_close (sink, &sink->conninfo, TRUE); + for (walk = sink->contexts; walk; walk = g_list_next (walk)) { + GstRTSPStreamContext *stream = (GstRTSPStreamContext *) walk->data; + gst_rtsp_conninfo_close (sink, &stream->conninfo, TRUE); + } + + /* cleanup */ + gst_rtsp_client_sink_cleanup (sink); + + sink->state = GST_RTSP_STATE_INVALID; + + if (async) + gst_rtsp_client_sink_loop_end_cmd (sink, CMD_CLOSE, res); + + return res; + + /* ERRORS */ +create_request_failed: + { + gchar *str = gst_rtsp_strresult (res); + + GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL), + ("Could not create request. (%s)", str)); + g_free (str); + goto close; + } +send_error: + { + gchar *str = gst_rtsp_strresult (res); + + gst_rtsp_message_unset (&request); + if (res != GST_RTSP_EINTR) { + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), + ("Could not send message. (%s)", str)); + } else { + GST_WARNING_OBJECT (sink, "TEARDOWN interrupted"); + } + g_free (str); + goto close; + } +not_supported: + { + GST_DEBUG_OBJECT (sink, + "TEARDOWN and PLAY not supported, can't do TEARDOWN"); + goto close; + } +} + +static gboolean +gst_rtsp_client_sink_configure_manager (GstRTSPClientSink * sink) +{ + GstElement *rtpbin; + GstStateChangeReturn ret; + + rtpbin = sink->rtpbin; + + if (rtpbin == NULL) { + GObjectClass *klass; + + rtpbin = gst_element_factory_make ("rtpbin", NULL); + if (rtpbin == NULL) + goto no_rtpbin; + + gst_bin_add (GST_BIN_CAST (sink->internal_bin), rtpbin); + + sink->rtpbin = rtpbin; + + /* Any more settings we should configure on rtpbin here? */ + g_object_set (sink->rtpbin, "latency", sink->latency, NULL); + + klass = G_OBJECT_GET_CLASS (G_OBJECT (rtpbin)); + + if (g_object_class_find_property (klass, "ntp-time-source")) { + g_object_set (sink->rtpbin, "ntp-time-source", sink->ntp_time_source, + NULL); + } + + if (sink->sdes && g_object_class_find_property (klass, "sdes")) { + g_object_set (sink->rtpbin, "sdes", sink->sdes, NULL); + } + + g_signal_emit (sink, gst_rtsp_client_sink_signals[SIGNAL_NEW_MANAGER], 0, + sink->rtpbin); + } + + ret = gst_element_set_state (rtpbin, GST_STATE_PAUSED); + if (ret == GST_STATE_CHANGE_FAILURE) + goto start_manager_failure; + + return TRUE; + +no_rtpbin: + { + GST_WARNING ("no rtpbin element"); + g_warning ("failed to create element 'rtpbin', check your installation"); + return FALSE; + } +start_manager_failure: + { + GST_DEBUG_OBJECT (sink, "could not start session manager"); + gst_bin_remove (GST_BIN_CAST (sink->internal_bin), rtpbin); + return FALSE; + } +} + +static GstElement * +request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPClientSink * sink) +{ + GstRTSPStream *stream = NULL; + GstElement *ret = NULL; + GList *walk; + + GST_RTSP_STATE_LOCK (sink); + for (walk = sink->contexts; walk; walk = g_list_next (walk)) { + GstRTSPStreamContext *context = (GstRTSPStreamContext *) walk->data; + + if (sessid == gst_rtsp_stream_get_index (context->stream)) { + stream = context->stream; + break; + } + } + + if (stream != NULL) { + GST_DEBUG_OBJECT (sink, "Creating aux sender for stream %u", sessid); + ret = gst_rtsp_stream_request_aux_sender (stream, sessid); + } + + GST_RTSP_STATE_UNLOCK (sink); + + return ret; +} + +static gboolean +gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink) +{ + GstRTSPStreamContext *context; + GList *walk; + const gchar *base; + gboolean has_slash; + + GST_DEBUG_OBJECT (sink, "Collecting stream information"); + + if (!gst_rtsp_client_sink_configure_manager (sink)) + return FALSE; + + base = get_aggregate_control (sink); + /* check if the base ends with / */ + has_slash = g_str_has_suffix (base, "/"); + + g_mutex_lock (&sink->preroll_lock); + while (sink->contexts == NULL && !sink->conninfo.flushing) { + g_cond_wait (&sink->preroll_cond, &sink->preroll_lock); + } + g_mutex_unlock (&sink->preroll_lock); + + /* FIXME: Need different locking - need to protect against pad releases + * and potential state changes ruining things here */ + for (walk = sink->contexts; walk; walk = g_list_next (walk)) { + GstPad *srcpad; + + context = (GstRTSPStreamContext *) walk->data; + if (context->stream) + continue; + + g_mutex_lock (&sink->preroll_lock); + while (!context->prerolled && !sink->conninfo.flushing) { + GST_DEBUG_OBJECT (sink, "Waiting for caps on stream %d", context->index); + g_cond_wait (&sink->preroll_cond, &sink->preroll_lock); + } + if (sink->conninfo.flushing) { + g_mutex_unlock (&sink->preroll_lock); + break; + } + g_mutex_unlock (&sink->preroll_lock); + + if (context->payloader == NULL) + continue; + + srcpad = gst_element_get_static_pad (context->payloader, "src"); + + GST_DEBUG_OBJECT (sink, "Creating stream object for stream %d", + context->index); + context->stream = + gst_rtsp_client_sink_create_stream (sink, context, context->payloader, + srcpad); + + /* concatenate the two strings, insert / when not present */ + g_free (context->conninfo.location); + context->conninfo.location = + g_strdup_printf ("%s%sstream=%d", base, has_slash ? "" : "/", + context->index); + + if (sink->rtx_time > 0) { + /* enable retransmission by setting rtprtxsend as the "aux" element of rtpbin */ + g_signal_connect (sink->rtpbin, "request-aux-sender", + (GCallback) request_aux_sender, sink); + } + + if (!gst_rtsp_stream_join_bin (context->stream, + GST_BIN (sink->internal_bin), sink->rtpbin, GST_STATE_PAUSED)) { + goto join_bin_failed; + } + context->joined = TRUE; + + /* Let the stream object receive data */ + gst_pad_remove_probe (srcpad, context->payloader_block_id); + + gst_object_unref (srcpad); + } + + /* Now wait for the preroll of the rtp bin */ + g_mutex_lock (&sink->preroll_lock); + while (!sink->prerolled && !sink->conninfo.flushing) { + GST_LOG_OBJECT (sink, "Waiting for preroll before continuing"); + g_cond_wait (&sink->preroll_cond, &sink->preroll_lock); + } + GST_LOG_OBJECT (sink, "Marking streams as collected"); + sink->streams_collected = TRUE; + g_mutex_unlock (&sink->preroll_lock); + + return TRUE; + +join_bin_failed: + + GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL), + ("Could not start stream %d", context->index)); + return FALSE; +} + +static GstRTSPResult +gst_rtsp_client_sink_create_transports_string (GstRTSPClientSink * sink, + GstRTSPStreamContext * context, GSocketFamily family, + GstRTSPLowerTrans protocols, GstRTSPProfile profiles, gchar ** transports) +{ + GString *result; + GstRTSPStream *stream = context->stream; + gboolean first = TRUE; + + /* the default RTSP transports */ + result = g_string_new ("RTP"); + + while (profiles != 0) { + if (!first) + g_string_append (result, ",RTP"); + + if (profiles & GST_RTSP_PROFILE_SAVPF) { + g_string_append (result, "/SAVPF"); + profiles &= ~GST_RTSP_PROFILE_SAVPF; + } else if (profiles & GST_RTSP_PROFILE_SAVP) { + g_string_append (result, "/SAVP"); + profiles &= ~GST_RTSP_PROFILE_SAVP; + } else if (profiles & GST_RTSP_PROFILE_AVPF) { + g_string_append (result, "/AVPF"); + profiles &= ~GST_RTSP_PROFILE_AVPF; + } else if (profiles & GST_RTSP_PROFILE_AVP) { + g_string_append (result, "/AVP"); + profiles &= ~GST_RTSP_PROFILE_AVP; + } else { + GST_WARNING_OBJECT (sink, "Unimplemented profile(s) 0x%x", profiles); + break; + } + + if (protocols & GST_RTSP_LOWER_TRANS_UDP) { + GstRTSPRange ports; + + GST_DEBUG_OBJECT (sink, "adding UDP unicast"); + gst_rtsp_stream_get_server_port (stream, &ports, family); + + g_string_append_printf (result, "/UDP;unicast;client_port=%d-%d", + ports.min, ports.max); + } else if (protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) { + GstRTSPAddress *addr = + gst_rtsp_stream_get_multicast_address (stream, family); + if (addr) { + GST_DEBUG_OBJECT (sink, "adding UDP multicast"); + g_string_append_printf (result, "/UDP;multicast;client_port=%d-%d", + addr->port, addr->port + addr->n_ports - 1); + gst_rtsp_address_free (addr); + } + } else if (protocols & GST_RTSP_LOWER_TRANS_TCP) { + GST_DEBUG_OBJECT (sink, "adding TCP"); + g_string_append_printf (result, "/TCP;unicast;interleaved=%d-%d", + sink->free_channel, sink->free_channel + 1); + } + + g_string_append (result, ";mode=RECORD"); + /* FIXME: Support appending too: + if (sink->append) + g_string_append (result, ";append"); + */ + + first = FALSE; + } + + if (first) { + /* No valid transport could be constructed */ + GST_ERROR_OBJECT (sink, "No supported profiles configured"); + goto fail; + } + + *transports = g_string_free (result, FALSE); + + GST_DEBUG_OBJECT (sink, "prepared transports %s", GST_STR_NULL (*transports)); + + return GST_RTSP_OK; +fail: + g_string_free (result, TRUE); + return GST_RTSP_ERROR; +} + +static guint8 +enc_key_length_from_cipher_name (const gchar * cipher) +{ + if (g_strcmp0 (cipher, "aes-128-icm") == 0) + return AES_128_KEY_LEN; + else if (g_strcmp0 (cipher, "aes-256-icm") == 0) + return AES_256_KEY_LEN; + else { + GST_ERROR ("encryption algorithm '%s' not supported", cipher); + return 0; + } +} + +static guint8 +auth_key_length_from_auth_name (const gchar * auth) +{ + if (g_strcmp0 (auth, "hmac-sha1-32") == 0) + return HMAC_32_KEY_LEN; + else if (g_strcmp0 (auth, "hmac-sha1-80") == 0) + return HMAC_80_KEY_LEN; + else { + GST_ERROR ("authentication algorithm '%s' not supported", auth); + return 0; + } +} + +static GstCaps * +signal_get_srtcp_params (GstRTSPClientSink * sink, + GstRTSPStreamContext * context) +{ + GstCaps *caps = NULL; + + g_signal_emit (sink, gst_rtsp_client_sink_signals[SIGNAL_REQUEST_RTCP_KEY], 0, + context->index, &caps); + + if (caps != NULL) + GST_DEBUG_OBJECT (sink, "SRTP parameters received"); + + return caps; +} + +static gchar * +gst_rtsp_client_sink_stream_make_keymgmt (GstRTSPClientSink * sink, + GstRTSPStreamContext * context) +{ + GBytes *bytes; + gchar *result, *base64; + const guint8 *data; + gsize size; + GstMIKEYMessage *msg; + GstMIKEYPayload *payload, *pkd; + guint8 byte; + GstStructure *s; + GstMapInfo info; + GstBuffer *srtpkey; + const GValue *val; + const gchar *srtcpcipher, *srtcpauth; + guint send_ssrc; + + context->srtcpparams = signal_get_srtcp_params (sink, context); + if (context->srtcpparams == NULL) + context->srtcpparams = gst_rtsp_stream_get_caps (context->stream); + + s = gst_caps_get_structure (context->srtcpparams, 0); + + srtcpcipher = gst_structure_get_string (s, "srtcp-cipher"); + srtcpauth = gst_structure_get_string (s, "srtcp-auth"); + val = gst_structure_get_value (s, "srtp-key"); + + if (srtcpcipher == NULL || srtcpauth == NULL || val == NULL) { + GST_ERROR_OBJECT (sink, "could not find the right SRTP parameters in caps"); + return NULL; + } + + srtpkey = gst_value_get_buffer (val); + + gst_rtsp_stream_get_ssrc (context->stream, &send_ssrc); + GST_LOG_OBJECT (sink, "Stream %p ssrc %x", context->stream, send_ssrc); + + msg = gst_mikey_message_new (); + /* unencrypted MIKEY message, we send this over TLS so this is allowed */ + gst_mikey_message_set_info (msg, GST_MIKEY_VERSION, GST_MIKEY_TYPE_PSK_INIT, + FALSE, GST_MIKEY_PRF_MIKEY_1, g_random_int (), GST_MIKEY_MAP_TYPE_SRTP); + /* add policy '0' for our SSRC */ + gst_mikey_message_add_cs_srtp (msg, 0, send_ssrc, 0); + /* timestamp is now */ + gst_mikey_message_add_t_now_ntp_utc (msg); + /* add some random data */ + gst_mikey_message_add_rand_len (msg, 16); + + /* the policy '0' is SRTP */ + payload = gst_mikey_payload_new (GST_MIKEY_PT_SP); + gst_mikey_payload_sp_set (payload, 0, GST_MIKEY_SEC_PROTO_SRTP); + + /* only AES-CM is supported */ + byte = 1; + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_ALG, 1, &byte); + /* encryption key length */ + byte = enc_key_length_from_cipher_name (srtcpcipher); + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_KEY_LEN, 1, + &byte); + /* only HMAC-SHA1 */ + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_ALG, 1, + &byte); + /* authentication key length */ + byte = auth_key_length_from_auth_name (srtcpauth); + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_KEY_LEN, 1, + &byte); + /* we enable encryption on RTP and RTCP */ + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_ENC, 1, + &byte); + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTCP_ENC, 1, + &byte); + /* we enable authentication on RTP and RTCP */ + gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_AUTH, 1, + &byte); + gst_mikey_message_add_payload (msg, payload); + + /* make unencrypted KEMAC */ + payload = gst_mikey_payload_new (GST_MIKEY_PT_KEMAC); + gst_mikey_payload_kemac_set (payload, GST_MIKEY_ENC_NULL, GST_MIKEY_MAC_NULL); + /* add the key in KEMAC */ + pkd = gst_mikey_payload_new (GST_MIKEY_PT_KEY_DATA); + gst_buffer_map (srtpkey, &info, GST_MAP_READ); + gst_mikey_payload_key_data_set_key (pkd, GST_MIKEY_KD_TEK, info.size, + info.data); + gst_buffer_unmap (srtpkey, &info); + gst_mikey_payload_kemac_add_sub (payload, pkd); + gst_mikey_message_add_payload (msg, payload); + + /* now serialize this to bytes */ + bytes = gst_mikey_message_to_bytes (msg, NULL, NULL); + gst_mikey_message_unref (msg); + /* and make it into base64 */ + data = g_bytes_get_data (bytes, &size); + base64 = g_base64_encode (data, size); + g_bytes_unref (bytes); + + result = g_strdup_printf ("prot=mikey;uri=\"%s\";data=\"%s\"", + context->conninfo.location, base64); + g_free (base64); + + return result; +} + +/* masks to be kept in sync with the hardcoded protocol order of preference + * in code below */ +static const guint protocol_masks[] = { + GST_RTSP_LOWER_TRANS_UDP, + GST_RTSP_LOWER_TRANS_UDP_MCAST, + GST_RTSP_LOWER_TRANS_TCP, + 0 +}; + +/* Same for profile_masks */ +static const guint profile_masks[] = { + GST_RTSP_PROFILE_SAVPF, + GST_RTSP_PROFILE_SAVP, + GST_RTSP_PROFILE_AVPF, + GST_RTSP_PROFILE_AVP, + 0 +}; + +static gboolean +do_send_data (GstBuffer * buffer, guint8 channel, + GstRTSPStreamContext * context) +{ + GstRTSPClientSink *sink = context->parent; + GstRTSPMessage message = { 0 }; + GstRTSPResult res = GST_RTSP_OK; + GstMapInfo map_info; + guint8 *data; + guint usize; + + gst_rtsp_message_init_data (&message, channel); + + /* FIXME, need some sort of iovec RTSPMessage here */ + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) + return FALSE; + + gst_rtsp_message_take_body (&message, map_info.data, map_info.size); + + res = + gst_rtsp_client_sink_try_send (sink, sink->conninfo.connection, &message, + NULL, NULL); + + gst_rtsp_message_steal_body (&message, &data, &usize); + gst_buffer_unmap (buffer, &map_info); + + gst_rtsp_message_unset (&message); + + return res == GST_RTSP_OK; +} + +static GstRTSPResult +gst_rtsp_client_sink_setup_streams (GstRTSPClientSink * sink, gboolean async) +{ + GstRTSPResult res = GST_RTSP_ERROR; + GstRTSPMessage request = { 0 }; + GstRTSPMessage response = { 0 }; + GstRTSPLowerTrans protocols; + GstRTSPStatusCode code; + GSocketFamily family; + GSocketAddress *sa; + GSocket *conn_socket; + GstRTSPUrl *url; + GList *walk; + gchar *hval; + + if (sink->conninfo.connection) { + url = gst_rtsp_connection_get_url (sink->conninfo.connection); + /* we initially allow all configured lower transports. based on the URL + * transports and the replies from the server we narrow them down. */ + protocols = url->transports & sink->cur_protocols; + } else { + url = NULL; + protocols = sink->cur_protocols; + } + + if (protocols == 0) + goto no_protocols; + + GST_RTSP_STATE_LOCK (sink); + + if (G_UNLIKELY (sink->contexts == NULL)) + goto no_streams; + + for (walk = sink->contexts; walk; walk = g_list_next (walk)) { + GstRTSPStreamContext *context = (GstRTSPStreamContext *) walk->data; + GstRTSPStream *stream; + + GstRTSPConnection *conn; + GstRTSPProfile profiles; + GstRTSPProfile cur_profile; + gchar *transports; + gint retry = 0; + guint profile_mask = 0; + guint mask = 0; + GstCaps *caps; + const GstSDPMedia *media; + + stream = context->stream; + profiles = gst_rtsp_stream_get_profiles (stream); + + caps = gst_rtsp_stream_get_caps (stream); + if (caps == NULL) { + GST_DEBUG_OBJECT (sink, "skipping stream %p, no caps", stream); + continue; + } + gst_caps_unref (caps); + media = gst_sdp_message_get_media (&sink->cursdp, context->sdp_index); + if (media == NULL) { + GST_DEBUG_OBJECT (sink, "skipping stream %p, no SDP info", stream); + continue; + } + + /* skip setup if we have no URL for it */ + if (context->conninfo.location == NULL) { + GST_DEBUG_OBJECT (sink, "skipping stream %p, no setup", stream); + continue; + } + + if (sink->conninfo.connection == NULL) { + if (!gst_rtsp_conninfo_connect (sink, &context->conninfo, async)) { + GST_DEBUG_OBJECT (sink, "skipping stream %p, failed to connect", + stream); + continue; + } + conn = context->conninfo.connection; + } else { + conn = sink->conninfo.connection; + } + GST_DEBUG_OBJECT (sink, "doing setup of stream %p with %s", stream, + context->conninfo.location); + + conn_socket = gst_rtsp_connection_get_read_socket (conn); + sa = g_socket_get_local_address (conn_socket, NULL); + family = g_socket_address_get_family (sa); + g_object_unref (sa); + + next_protocol: + /* first selectable profile */ + while (profile_masks[profile_mask] + && !(profiles & profile_masks[profile_mask])) + profile_mask++; + if (!profile_masks[profile_mask]) + goto no_profiles; + + /* first selectable protocol */ + while (protocol_masks[mask] && !(protocols & protocol_masks[mask])) + mask++; + if (!protocol_masks[mask]) + goto no_protocols; + + retry: + GST_DEBUG_OBJECT (sink, "protocols = 0x%x, protocol mask = 0x%x", protocols, + protocol_masks[mask]); + /* create a string with first transport in line */ + transports = NULL; + cur_profile = profiles & profile_masks[profile_mask]; + res = gst_rtsp_client_sink_create_transports_string (sink, context, family, + protocols & protocol_masks[mask], cur_profile, &transports); + if (res < 0 || transports == NULL) + goto setup_transport_failed; + + if (strlen (transports) == 0) { + g_free (transports); + GST_DEBUG_OBJECT (sink, "no transports found"); + mask++; + profile_mask = 0; + goto next_protocol; + } + + GST_DEBUG_OBJECT (sink, "transport is %s", GST_STR_NULL (transports)); + + /* create SETUP request */ + res = + gst_rtsp_client_sink_init_request (sink, &request, GST_RTSP_SETUP, + context->conninfo.location); + if (res < 0) { + g_free (transports); + goto create_request_failed; + } + + /* select transport */ + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_TRANSPORT, transports); + + /* set up keys */ + if (cur_profile == GST_RTSP_PROFILE_SAVP || + cur_profile == GST_RTSP_PROFILE_SAVPF) { + hval = gst_rtsp_client_sink_stream_make_keymgmt (sink, context); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_KEYMGMT, hval); + } + + /* if the user wants a non default RTP packet size we add the blocksize + * parameter */ + if (sink->rtp_blocksize > 0) { + hval = g_strdup_printf ("%d", sink->rtp_blocksize); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_BLOCKSIZE, hval); + } + + if (async) + GST_ELEMENT_PROGRESS (sink, CONTINUE, "request", ("SETUP stream %d", + context->index)); + + /* handle the code ourselves */ + res = gst_rtsp_client_sink_send (sink, conn, &request, &response, &code); + if (res < 0) + goto send_error; + + switch (code) { + case GST_RTSP_STS_OK: + break; + case GST_RTSP_STS_UNSUPPORTED_TRANSPORT: + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + + /* Try another profile. If no more, move to the next protocol */ + profile_mask++; + while (profile_masks[profile_mask] + && !(profiles & profile_masks[profile_mask])) + profile_mask++; + if (profile_masks[profile_mask]) + goto retry; + + /* select next available protocol, give up on this stream if none */ + /* Reset profiles to try: */ + profile_mask = 0; + + mask++; + while (protocol_masks[mask] && !(protocols & protocol_masks[mask])) + mask++; + if (!protocol_masks[mask]) + continue; + else + goto retry; + default: + goto response_error; + } + + /* parse response transport */ + { + gchar *resptrans = NULL; + GstRTSPTransport *transport; + + gst_rtsp_message_get_header (&response, GST_RTSP_HDR_TRANSPORT, + &resptrans, 0); + if (!resptrans) { + goto no_transport; + } + + gst_rtsp_transport_new (&transport); + + /* parse transport, go to next stream on parse error */ + if (gst_rtsp_transport_parse (resptrans, transport) != GST_RTSP_OK) { + GST_WARNING_OBJECT (sink, "failed to parse transport %s", resptrans); + goto next; + } + + /* update allowed transports for other streams. once the transport of + * one stream has been determined, we make sure that all other streams + * are configured in the same way */ + switch (transport->lower_transport) { + case GST_RTSP_LOWER_TRANS_TCP: + GST_DEBUG_OBJECT (sink, "stream %p as TCP interleaved", stream); + protocols = GST_RTSP_LOWER_TRANS_TCP; + sink->interleaved = TRUE; + /* update free channels */ + sink->free_channel = + MAX (transport->interleaved.min, sink->free_channel); + sink->free_channel = + MAX (transport->interleaved.max, sink->free_channel); + sink->free_channel++; + break; + case GST_RTSP_LOWER_TRANS_UDP_MCAST: + /* only allow multicast for other streams */ + GST_DEBUG_OBJECT (sink, "stream %p as UDP multicast", stream); + protocols = GST_RTSP_LOWER_TRANS_UDP_MCAST; + break; + case GST_RTSP_LOWER_TRANS_UDP: + /* only allow unicast for other streams */ + GST_DEBUG_OBJECT (sink, "stream %p as UDP unicast", stream); + protocols = GST_RTSP_LOWER_TRANS_UDP; + /* Update transport with server destination if not provided by the server */ + if (transport->destination == NULL) { + transport->destination = g_strdup (sink->server_ip); + } + break; + default: + GST_DEBUG_OBJECT (sink, "stream %p unknown transport %d", stream, + transport->lower_transport); + break; + } + + if (!retry) { + GST_DEBUG ("Configuring the stream transport for stream %d", + context->index); + if (context->stream_transport == NULL) + context->stream_transport = + gst_rtsp_stream_transport_new (stream, transport); + else + gst_rtsp_stream_transport_set_transport (context->stream_transport, + transport); + + if (transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { + /* our callbacks to send data on this TCP connection */ + gst_rtsp_stream_transport_set_callbacks (context->stream_transport, + (GstRTSPSendFunc) do_send_data, + (GstRTSPSendFunc) do_send_data, context, NULL); + } + + /* The stream_transport now owns the transport */ + transport = NULL; + + gst_rtsp_stream_transport_set_active (context->stream_transport, TRUE); + } + next: + if (transport) + gst_rtsp_transport_free (transport); + /* clean up used RTSP messages */ + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + } + } + GST_RTSP_STATE_UNLOCK (sink); + + /* store the transport protocol that was configured */ + sink->cur_protocols = protocols; + + return res; + +no_streams: + { + GST_RTSP_STATE_UNLOCK (sink); + GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL), + ("SDP contains no streams")); + return GST_RTSP_ERROR; + } +setup_transport_failed: + { + GST_RTSP_STATE_UNLOCK (sink); + GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL), + ("Could not setup transport.")); + res = GST_RTSP_ERROR; + goto cleanup_error; + } +no_profiles: + { + GST_RTSP_STATE_UNLOCK (sink); + /* no transport possible, post an error and stop */ + GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL), + ("Could not connect to server, no profiles left")); + return GST_RTSP_ERROR; + } +no_protocols: + { + GST_RTSP_STATE_UNLOCK (sink); + /* no transport possible, post an error and stop */ + GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL), + ("Could not connect to server, no protocols left")); + return GST_RTSP_ERROR; + } +no_transport: + { + GST_RTSP_STATE_UNLOCK (sink); + GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL), + ("Server did not select transport.")); + res = GST_RTSP_ERROR; + goto cleanup_error; + } +create_request_failed: + { + gchar *str = gst_rtsp_strresult (res); + + GST_RTSP_STATE_UNLOCK (sink); + GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL), + ("Could not create request. (%s)", str)); + g_free (str); + goto cleanup_error; + } +send_error: + { + gchar *str = gst_rtsp_strresult (res); + + GST_RTSP_STATE_UNLOCK (sink); + if (res != GST_RTSP_EINTR) { + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), + ("Could not send message. (%s)", str)); + } else { + GST_WARNING_OBJECT (sink, "send interrupted"); + } + g_free (str); + goto cleanup_error; + } +response_error: + { + const gchar *str = gst_rtsp_status_as_text (code); + + GST_RTSP_STATE_UNLOCK (sink); + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), + ("Error (%d): %s", code, GST_STR_NULL (str))); + res = GST_RTSP_ERROR; + goto cleanup_error; + } +cleanup_error: + { + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + return res; + } +} + +static GstRTSPResult +gst_rtsp_client_sink_ensure_open (GstRTSPClientSink * sink, gboolean async) +{ + GstRTSPResult res = GST_RTSP_OK; + + if (sink->state < GST_RTSP_STATE_READY) { + res = GST_RTSP_ERROR; + if (sink->open_error) { + GST_DEBUG_OBJECT (sink, "the stream was in error"); + goto done; + } + if (async) + gst_rtsp_client_sink_loop_start_cmd (sink, CMD_OPEN); + + if ((res = gst_rtsp_client_sink_open (sink, async)) < 0) { + GST_DEBUG_OBJECT (sink, "failed to open stream"); + goto done; + } + } + +done: + return res; +} + +static GstRTSPResult +gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async) +{ + GstRTSPMessage request = { 0 }; + GstRTSPMessage response = { 0 }; + GstRTSPResult res = GST_RTSP_OK; + GstSDPMessage *sdp; + guint sdp_index = 0; + GstSDPInfo info = { 0, }; + + const gchar *proto; + gchar *sess_id, *client_ip, *str; + GSocketAddress *sa; + GInetAddress *ia; + GSocket *conn_socket; + GList *walk; + + /* Wait for streams to preroll */ + g_mutex_lock (&sink->preroll_lock); + while (sink->in_async) { + GST_LOG_OBJECT (sink, "Waiting for ASYNC_DONE preroll"); + g_cond_wait (&sink->preroll_cond, &sink->preroll_lock); + } + g_mutex_unlock (&sink->preroll_lock); + + if (sink->state == GST_RTSP_STATE_PLAYING) { + /* Already recording, don't send another request */ + GST_LOG_OBJECT (sink, "Already in RECORD. Skipping duplicate request."); + goto done; + } + + /* Send announce, then setup for all streams */ + gst_sdp_message_init (&sink->cursdp); + sdp = &sink->cursdp; + + /* some standard things first */ + gst_sdp_message_set_version (sdp, "0"); + + /* session ID doesn't have to be super-unique in this case */ + sess_id = g_strdup_printf ("%u", g_random_int ()); + + if (sink->conninfo.connection == NULL) + return GST_RTSP_ERROR; + + conn_socket = gst_rtsp_connection_get_read_socket (sink->conninfo.connection); + + sa = g_socket_get_local_address (conn_socket, NULL); + ia = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sa)); + client_ip = g_inet_address_to_string (ia); + if (g_socket_address_get_family (sa) == G_SOCKET_FAMILY_IPV6) { + info.is_ipv6 = TRUE; + proto = "IP6"; + } else if (g_socket_address_get_family (sa) == G_SOCKET_FAMILY_IPV4) + proto = "IP4"; + else + g_assert_not_reached (); + g_object_unref (sa); + + /* FIXME: Should this actually be the server's IP or ours? */ + info.server_ip = sink->server_ip; + + gst_sdp_message_set_origin (sdp, "-", sess_id, "1", "IN", proto, client_ip); + + gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer"); + gst_sdp_message_set_information (sdp, "rtspclientsink"); + gst_sdp_message_add_time (sdp, "0", "0", NULL); + gst_sdp_message_add_attribute (sdp, "tool", "GStreamer"); + + /* add stream */ + for (walk = sink->contexts; walk; walk = g_list_next (walk)) { + GstRTSPStreamContext *context = (GstRTSPStreamContext *) walk->data; + + gst_rtsp_sdp_from_stream (sdp, &info, context->stream); + context->sdp_index = sdp_index++; + } + + g_free (sess_id); + g_free (client_ip); + + /* send ANNOUNCE request */ + GST_DEBUG_OBJECT (sink, "create ANNOUNCE request..."); + res = + gst_rtsp_client_sink_init_request (sink, &request, GST_RTSP_ANNOUNCE, + sink->conninfo.url_str); + if (res < 0) + goto create_request_failed; + + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CONTENT_TYPE, + "application/sdp"); + + /* add SDP to the request body */ + str = gst_sdp_message_as_text (sdp); + gst_rtsp_message_take_body (&request, (guint8 *) str, strlen (str)); + + /* send ANNOUNCE */ + GST_DEBUG_OBJECT (sink, "sending announce..."); + + if (async) + GST_ELEMENT_PROGRESS (sink, CONTINUE, "record", + ("Sending server stream info")); + + if ((res = + gst_rtsp_client_sink_send (sink, sink->conninfo.connection, &request, + &response, NULL)) < 0) + goto send_error; + + /* send setup for all streams */ + if ((res = gst_rtsp_client_sink_setup_streams (sink, async)) < 0) + goto setup_failed; + + res = gst_rtsp_client_sink_init_request (sink, &request, GST_RTSP_RECORD, + sink->conninfo.url_str); + + if (res < 0) + goto create_request_failed; + +#if 0 /* FIXME: Configure a range based on input segments? */ + if (src->need_range) { + hval = gen_range_header (src, segment); + + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_RANGE, hval); + } + + if (segment->rate != 1.0) { + gchar hval[G_ASCII_DTOSTR_BUF_SIZE]; + + g_ascii_dtostr (hval, sizeof (hval), segment->rate); + if (src->skip) + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SCALE, hval); + else + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SPEED, hval); + } +#endif + + if (async) + GST_ELEMENT_PROGRESS (sink, CONTINUE, "record", ("Starting recording")); + if ((res = + gst_rtsp_client_sink_send (sink, sink->conninfo.connection, &request, + &response, NULL)) < 0) + goto send_error; + +#if 0 /* FIXME: Check if servers return these for record: */ + /* parse the RTP-Info header field (if ANY) to get the base seqnum and timestamp + * for the RTP packets. If this is not present, we assume all starts from 0... + * This is info for the RTP session manager that we pass to it in caps. */ + hval_idx = 0; + while (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_RTP_INFO, + &hval, hval_idx++) == GST_RTSP_OK) + gst_rtspsrc_parse_rtpinfo (src, hval); + + /* some servers indicate RTCP parameters in PLAY response, + * rather than properly in SDP */ + if (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_RTCP_INTERVAL, + &hval, 0) == GST_RTSP_OK) + gst_rtspsrc_handle_rtcp_interval (src, hval); +#endif + + gst_rtsp_client_sink_set_state (sink, GST_STATE_PLAYING); + sink->state = GST_RTSP_STATE_PLAYING; + + /* clean up any messages */ + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + +done: + return res; + +create_request_failed: + { + gchar *str = gst_rtsp_strresult (res); + + GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL), + ("Could not create request. (%s)", str)); + g_free (str); + goto cleanup_error; + } +send_error: + { + /* Don't post a message - the rtsp_send method will have + * taken care of it because we passed NULL for the response code */ + goto cleanup_error; + } +setup_failed: + { + GST_ERROR_OBJECT (sink, "setup failed"); + goto cleanup_error; + } +cleanup_error: + { + if (sink->conninfo.connection) { + GST_DEBUG_OBJECT (sink, "free connection"); + gst_rtsp_conninfo_close (sink, &sink->conninfo, TRUE); + } + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + return res; + } +} + +static GstRTSPResult +gst_rtsp_client_sink_pause (GstRTSPClientSink * sink, gboolean async) +{ + GstRTSPResult res = GST_RTSP_OK; + GstRTSPMessage request = { 0 }; + GstRTSPMessage response = { 0 }; + GList *walk; + const gchar *control; + + GST_DEBUG_OBJECT (sink, "PAUSE..."); + + if ((res = gst_rtsp_client_sink_ensure_open (sink, async)) < 0) + goto open_failed; + + if (!(sink->methods & GST_RTSP_PAUSE)) + goto not_supported; + + if (sink->state == GST_RTSP_STATE_READY) + goto was_paused; + + if (!sink->conninfo.connection || !sink->conninfo.connected) + goto no_connection; + + /* construct a control url */ + control = get_aggregate_control (sink); + + /* loop over the streams. We might exit the loop early when we could do an + * aggregate control */ + for (walk = sink->contexts; walk; walk = g_list_next (walk)) { + GstRTSPStreamContext *stream = (GstRTSPStreamContext *) walk->data; + GstRTSPConnection *conn; + const gchar *setup_url; + + /* try aggregate control first but do non-aggregate control otherwise */ + if (control) + setup_url = control; + else if ((setup_url = stream->conninfo.location) == NULL) + continue; + + if (sink->conninfo.connection) { + conn = sink->conninfo.connection; + } else if (stream->conninfo.connection) { + conn = stream->conninfo.connection; + } else { + continue; + } + + if (async) + GST_ELEMENT_PROGRESS (sink, CONTINUE, "request", + ("Sending PAUSE request")); + + if ((res = + gst_rtsp_client_sink_init_request (sink, &request, GST_RTSP_PAUSE, + setup_url)) < 0) + goto create_request_failed; + + if ((res = + gst_rtsp_client_sink_send (sink, conn, &request, &response, + NULL)) < 0) + goto send_error; + + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + + /* exit early when we did agregate control */ + if (control) + break; + } + + /* change element states now */ + gst_rtsp_client_sink_set_state (sink, GST_STATE_PAUSED); + +no_connection: + sink->state = GST_RTSP_STATE_READY; + +done: + if (async) + gst_rtsp_client_sink_loop_end_cmd (sink, CMD_PAUSE, res); + + return res; + + /* ERRORS */ +open_failed: + { + GST_DEBUG_OBJECT (sink, "failed to open stream"); + goto done; + } +not_supported: + { + GST_DEBUG_OBJECT (sink, "PAUSE is not supported"); + goto done; + } +was_paused: + { + GST_DEBUG_OBJECT (sink, "we were already PAUSED"); + goto done; + } +create_request_failed: + { + gchar *str = gst_rtsp_strresult (res); + + GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL), + ("Could not create request. (%s)", str)); + g_free (str); + goto done; + } +send_error: + { + gchar *str = gst_rtsp_strresult (res); + + gst_rtsp_message_unset (&request); + if (res != GST_RTSP_EINTR) { + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), + ("Could not send message. (%s)", str)); + } else { + GST_WARNING_OBJECT (sink, "PAUSE interrupted"); + } + g_free (str); + goto done; + } +} + +static void +gst_rtsp_client_sink_handle_message (GstBin * bin, GstMessage * message) +{ + GstRTSPClientSink *rtsp_client_sink; + + rtsp_client_sink = GST_RTSP_CLIENT_SINK (bin); + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ELEMENT: + { + const GstStructure *s = gst_message_get_structure (message); + + if (gst_structure_has_name (s, "GstUDPSrcTimeout")) { + gboolean ignore_timeout; + + GST_DEBUG_OBJECT (bin, "timeout on UDP port"); + + GST_OBJECT_LOCK (rtsp_client_sink); + ignore_timeout = rtsp_client_sink->ignore_timeout; + rtsp_client_sink->ignore_timeout = TRUE; + GST_OBJECT_UNLOCK (rtsp_client_sink); + + /* we only act on the first udp timeout message, others are irrelevant + * and can be ignored. */ + if (!ignore_timeout) + gst_rtsp_client_sink_loop_send_cmd (rtsp_client_sink, CMD_RECONNECT, + CMD_LOOP); + /* eat and free */ + gst_message_unref (message); + return; + } else if (gst_structure_has_name (s, "GstRTSPStreamBlocking")) { + /* An RTSPStream has prerolled */ + g_cond_broadcast (&rtsp_client_sink->preroll_cond); + } + GST_BIN_CLASS (parent_class)->handle_message (bin, message); + break; + } + case GST_MESSAGE_ASYNC_START:{ + GstObject *sender; + + sender = GST_MESSAGE_SRC (message); + + GST_LOG_OBJECT (rtsp_client_sink, + "Have async-start from %" GST_PTR_FORMAT, sender); + if (sender == GST_OBJECT (rtsp_client_sink->internal_bin)) { + GST_LOG_OBJECT (rtsp_client_sink, "child bin is now ASYNC"); + } + GST_BIN_CLASS (parent_class)->handle_message (bin, message); + break; + } + case GST_MESSAGE_ASYNC_DONE: + { + GstObject *sender; + gboolean need_async_done; + + sender = GST_MESSAGE_SRC (message); + GST_LOG_OBJECT (rtsp_client_sink, "Have async-done from %" GST_PTR_FORMAT, + sender); + + g_mutex_lock (&rtsp_client_sink->preroll_lock); + if (sender == GST_OBJECT_CAST (rtsp_client_sink->internal_bin)) { + GST_LOG_OBJECT (rtsp_client_sink, "child bin is no longer ASYNC"); + } + need_async_done = rtsp_client_sink->in_async; + if (rtsp_client_sink->in_async) { + rtsp_client_sink->in_async = FALSE; + g_cond_broadcast (&rtsp_client_sink->preroll_cond); + } + g_mutex_unlock (&rtsp_client_sink->preroll_lock); + + GST_BIN_CLASS (parent_class)->handle_message (bin, message); + + if (need_async_done) { + GST_DEBUG_OBJECT (rtsp_client_sink, "Posting ASYNC-DONE"); + gst_element_post_message (GST_ELEMENT_CAST (rtsp_client_sink), + gst_message_new_async_done (GST_OBJECT_CAST (rtsp_client_sink), + GST_CLOCK_TIME_NONE)); + } + break; + } + case GST_MESSAGE_ERROR: + { + GstObject *sender; + + sender = GST_MESSAGE_SRC (message); + + GST_DEBUG_OBJECT (rtsp_client_sink, "got error from %s", + GST_ELEMENT_NAME (sender)); + + /* FIXME: Ignore errors on RTCP? */ + /* fatal but not our message, forward */ + GST_BIN_CLASS (parent_class)->handle_message (bin, message); + break; + } + case GST_MESSAGE_STATE_CHANGED: + { + if (GST_MESSAGE_SRC (message) == + (GstObject *) rtsp_client_sink->internal_bin) { + GstState newstate, pending; + gst_message_parse_state_changed (message, NULL, &newstate, &pending); + g_mutex_lock (&rtsp_client_sink->preroll_lock); + rtsp_client_sink->prerolled = (newstate >= GST_STATE_PAUSED) + && pending == GST_STATE_VOID_PENDING; + g_cond_broadcast (&rtsp_client_sink->preroll_cond); + g_mutex_unlock (&rtsp_client_sink->preroll_lock); + GST_DEBUG_OBJECT (bin, + "Internal bin changed state to %s (pending %s). Prerolled now %d", + gst_element_state_get_name (newstate), + gst_element_state_get_name (pending), rtsp_client_sink->prerolled); + } + } + default: + { + GST_BIN_CLASS (parent_class)->handle_message (bin, message); + break; + } + } +} + +/* the thread where everything happens */ +static void +gst_rtsp_client_sink_thread (GstRTSPClientSink * sink) +{ + gint cmd; + + GST_OBJECT_LOCK (sink); + cmd = sink->pending_cmd; + if (cmd == CMD_RECONNECT || cmd == CMD_RECORD || cmd == CMD_PAUSE + || cmd == CMD_LOOP || cmd == CMD_OPEN) + sink->pending_cmd = CMD_LOOP; + else + sink->pending_cmd = CMD_WAIT; + GST_DEBUG_OBJECT (sink, "got command %s", cmd_to_string (cmd)); + + /* we got the message command, so ensure communication is possible again */ + gst_rtsp_client_sink_connection_flush (sink, FALSE); + + sink->busy_cmd = cmd; + GST_OBJECT_UNLOCK (sink); + + switch (cmd) { + case CMD_OPEN: + gst_rtsp_client_sink_open (sink, TRUE); + break; + case CMD_RECORD: + gst_rtsp_client_sink_record (sink, TRUE); + break; + case CMD_PAUSE: + gst_rtsp_client_sink_pause (sink, TRUE); + break; + case CMD_CLOSE: + gst_rtsp_client_sink_close (sink, TRUE, FALSE); + break; + case CMD_LOOP: + gst_rtsp_client_sink_loop (sink); + break; + case CMD_RECONNECT: + gst_rtsp_client_sink_reconnect (sink, FALSE); + break; + default: + break; + } + + GST_OBJECT_LOCK (sink); + /* and go back to sleep */ + if (sink->pending_cmd == CMD_WAIT) { + if (sink->task) + gst_task_pause (sink->task); + } + /* reset waiting */ + sink->busy_cmd = CMD_WAIT; + GST_OBJECT_UNLOCK (sink); +} + +static gboolean +gst_rtsp_client_sink_start (GstRTSPClientSink * sink) +{ + GST_DEBUG_OBJECT (sink, "starting"); + + sink->streams_collected = FALSE; + sink->in_async = TRUE; + gst_element_set_locked_state (GST_ELEMENT (sink->internal_bin), TRUE); + + gst_rtsp_client_sink_set_state (sink, GST_STATE_READY); + + GST_OBJECT_LOCK (sink); + sink->pending_cmd = CMD_WAIT; + + if (sink->task == NULL) { + sink->task = + gst_task_new ((GstTaskFunction) gst_rtsp_client_sink_thread, sink, + NULL); + if (sink->task == NULL) + goto task_error; + + gst_task_set_lock (sink->task, GST_RTSP_STREAM_GET_LOCK (sink)); + } + GST_OBJECT_UNLOCK (sink); + + return TRUE; + + /* ERRORS */ +task_error: + { + GST_OBJECT_UNLOCK (sink); + GST_ERROR_OBJECT (sink, "failed to create task"); + return FALSE; + } +} + +static gboolean +gst_rtsp_client_sink_stop (GstRTSPClientSink * sink) +{ + GstTask *task; + + GST_DEBUG_OBJECT (sink, "stopping"); + + /* also cancels pending task */ + gst_rtsp_client_sink_loop_send_cmd (sink, CMD_WAIT, CMD_ALL & ~CMD_CLOSE); + + GST_OBJECT_LOCK (sink); + if ((task = sink->task)) { + sink->task = NULL; + GST_OBJECT_UNLOCK (sink); + + gst_task_stop (task); + + /* make sure it is not running */ + GST_RTSP_STREAM_LOCK (sink); + GST_RTSP_STREAM_UNLOCK (sink); + + /* now wait for the task to finish */ + gst_task_join (task); + + /* and free the task */ + gst_object_unref (GST_OBJECT (task)); + + GST_OBJECT_LOCK (sink); + } + GST_OBJECT_UNLOCK (sink); + + /* ensure synchronously all is closed and clean */ + gst_rtsp_client_sink_close (sink, FALSE, TRUE); + + return TRUE; +} + +static GstStateChangeReturn +gst_rtsp_client_sink_change_state (GstElement * element, + GstStateChange transition) +{ + GstRTSPClientSink *rtsp_client_sink; + GstStateChangeReturn ret; + + rtsp_client_sink = GST_RTSP_CLIENT_SINK (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!gst_rtsp_client_sink_start (rtsp_client_sink)) + goto start_failed; + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + /* init some state */ + rtsp_client_sink->cur_protocols = rtsp_client_sink->protocols; + /* first attempt, don't ignore timeouts */ + rtsp_client_sink->ignore_timeout = FALSE; + rtsp_client_sink->open_error = FALSE; + + gst_rtsp_client_sink_set_state (rtsp_client_sink, GST_STATE_PAUSED); + + g_mutex_lock (&rtsp_client_sink->preroll_lock); + if (rtsp_client_sink->in_async) { + GST_DEBUG_OBJECT (rtsp_client_sink, "Posting ASYNC-START"); + gst_element_post_message (GST_ELEMENT_CAST (rtsp_client_sink), + gst_message_new_async_start (GST_OBJECT_CAST (rtsp_client_sink))); + } + g_mutex_unlock (&rtsp_client_sink->preroll_lock); + + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + /* fall-through */ + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + /* unblock the tcp tasks and make the loop waiting */ + if (gst_rtsp_client_sink_loop_send_cmd (rtsp_client_sink, CMD_WAIT, + CMD_LOOP)) { + /* make sure it is waiting before we send PLAY below */ + GST_RTSP_STREAM_LOCK (rtsp_client_sink); + GST_RTSP_STREAM_UNLOCK (rtsp_client_sink); + } + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_rtsp_client_sink_set_state (rtsp_client_sink, GST_STATE_READY); + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + goto done; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + ret = GST_STATE_CHANGE_SUCCESS; + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + /* Return ASYNC and preroll input streams */ + g_mutex_lock (&rtsp_client_sink->preroll_lock); + if (rtsp_client_sink->in_async) + ret = GST_STATE_CHANGE_ASYNC; + g_mutex_unlock (&rtsp_client_sink->preroll_lock); + gst_rtsp_client_sink_loop_send_cmd (rtsp_client_sink, CMD_OPEN, 0); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING:{ + GST_DEBUG_OBJECT (rtsp_client_sink, + "Switching to playing -sending RECORD"); + gst_rtsp_client_sink_loop_send_cmd (rtsp_client_sink, CMD_RECORD, 0); + ret = GST_STATE_CHANGE_SUCCESS; + break; + } + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + /* send pause request and keep the idle task around */ + gst_rtsp_client_sink_loop_send_cmd (rtsp_client_sink, CMD_PAUSE, + CMD_LOOP); + ret = GST_STATE_CHANGE_NO_PREROLL; + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_rtsp_client_sink_loop_send_cmd (rtsp_client_sink, CMD_CLOSE, + CMD_PAUSE); + ret = GST_STATE_CHANGE_SUCCESS; + break; + case GST_STATE_CHANGE_READY_TO_NULL: + gst_rtsp_client_sink_stop (rtsp_client_sink); + ret = GST_STATE_CHANGE_SUCCESS; + break; + default: + break; + } + +done: + return ret; + +start_failed: + { + GST_DEBUG_OBJECT (rtsp_client_sink, "start failed"); + return GST_STATE_CHANGE_FAILURE; + } +} + +/*** GSTURIHANDLER INTERFACE *************************************************/ + +static GstURIType +gst_rtsp_client_sink_uri_get_type (GType type) +{ + return GST_URI_SINK; +} + +static const gchar *const * +gst_rtsp_client_sink_uri_get_protocols (GType type) +{ + static const gchar *protocols[] = + { "rtsp", "rtspu", "rtspt", "rtsph", "rtsp-sdp", + "rtsps", "rtspsu", "rtspst", "rtspsh", NULL + }; + + return protocols; +} + +static gchar * +gst_rtsp_client_sink_uri_get_uri (GstURIHandler * handler) +{ + GstRTSPClientSink *sink = GST_RTSP_CLIENT_SINK (handler); + + /* FIXME: make thread-safe */ + return g_strdup (sink->conninfo.location); +} + +static gboolean +gst_rtsp_client_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri, + GError ** error) +{ + GstRTSPClientSink *sink; + GstRTSPResult res; + GstSDPResult sres; + GstRTSPUrl *newurl = NULL; + GstSDPMessage *sdp = NULL; + + sink = GST_RTSP_CLIENT_SINK (handler); + + /* same URI, we're fine */ + if (sink->conninfo.location && uri && !strcmp (uri, sink->conninfo.location)) + goto was_ok; + + if (g_str_has_prefix (uri, "rtsp-sdp://")) { + sres = gst_sdp_message_new (&sdp); + if (sres < 0) + goto sdp_failed; + + GST_DEBUG_OBJECT (sink, "parsing SDP message"); + sres = gst_sdp_message_parse_uri (uri, sdp); + if (sres < 0) + goto invalid_sdp; + } else { + /* try to parse */ + GST_DEBUG_OBJECT (sink, "parsing URI"); + if ((res = gst_rtsp_url_parse (uri, &newurl)) < 0) + goto parse_error; + } + + /* if worked, free previous and store new url object along with the original + * location. */ + GST_DEBUG_OBJECT (sink, "configuring URI"); + g_free (sink->conninfo.location); + sink->conninfo.location = g_strdup (uri); + gst_rtsp_url_free (sink->conninfo.url); + sink->conninfo.url = newurl; + g_free (sink->conninfo.url_str); + if (newurl) + sink->conninfo.url_str = gst_rtsp_url_get_request_uri (sink->conninfo.url); + else + sink->conninfo.url_str = NULL; + + if (sink->uri_sdp) + gst_sdp_message_free (sink->uri_sdp); + sink->uri_sdp = sdp; + sink->from_sdp = sdp != NULL; + + GST_DEBUG_OBJECT (sink, "set uri: %s", GST_STR_NULL (uri)); + GST_DEBUG_OBJECT (sink, "request uri is: %s", + GST_STR_NULL (sink->conninfo.url_str)); + + return TRUE; + + /* Special cases */ +was_ok: + { + GST_DEBUG_OBJECT (sink, "URI was ok: '%s'", GST_STR_NULL (uri)); + return TRUE; + } +sdp_failed: + { + GST_ERROR_OBJECT (sink, "Could not create new SDP (%d)", sres); + g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, + "Could not create SDP"); + return FALSE; + } +invalid_sdp: + { + GST_ERROR_OBJECT (sink, "Not a valid SDP (%d) '%s'", sres, + GST_STR_NULL (uri)); + gst_sdp_message_free (sdp); + g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, + "Invalid SDP"); + return FALSE; + } +parse_error: + { + GST_ERROR_OBJECT (sink, "Not a valid RTSP url '%s' (%d)", + GST_STR_NULL (uri), res); + g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, + "Invalid RTSP URI"); + return FALSE; + } +} + +static void +gst_rtsp_client_sink_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_rtsp_client_sink_uri_get_type; + iface->get_protocols = gst_rtsp_client_sink_uri_get_protocols; + iface->get_uri = gst_rtsp_client_sink_uri_get_uri; + iface->set_uri = gst_rtsp_client_sink_uri_set_uri; +} diff --git a/gst/rtsp-sink/gstrtspclientsink.h b/gst/rtsp-sink/gstrtspclientsink.h new file mode 100644 index 0000000000..a8aef5ba78 --- /dev/null +++ b/gst/rtsp-sink/gstrtspclientsink.h @@ -0,0 +1,244 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * <2006> Wim Taymans + * <2015> Jan Schmidt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/* + * Unless otherwise indicated, Source Code is licensed under MIT license. + * See further explanation attached in License Statement (distributed in the file + * LICENSE). + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __GST_RTSP_CLIENT_SINK_H__ +#define __GST_RTSP_CLIENT_SINK_H__ + +#include + +G_BEGIN_DECLS + +#include +#include +#include + +#define GST_TYPE_RTSP_CLIENT_SINK \ + (gst_rtsp_client_sink_get_type()) +#define GST_RTSP_CLIENT_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTSP_CLIENT_SINK,GstRTSPClientSink)) +#define GST_RTSP_CLIENT_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTSP_CLIENT_SINK,GstRTSPClientSinkClass)) +#define GST_IS_RTSP_CLIENT_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTSP_CLIENT_SINK)) +#define GST_IS_RTSP_CLIENT_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTSP_CLIENT_SINK)) +#define GST_RTSP_CLIENT_SINK_CAST(obj) \ + ((GstRTSPClientSink *)(obj)) + +typedef struct _GstRTSPClientSink GstRTSPClientSink; +typedef struct _GstRTSPClientSinkClass GstRTSPClientSinkClass; + +#define GST_RTSP_STATE_GET_LOCK(rtsp) (&GST_RTSP_CLIENT_SINK_CAST(rtsp)->state_rec_lock) +#define GST_RTSP_STATE_LOCK(rtsp) (g_rec_mutex_lock (GST_RTSP_STATE_GET_LOCK(rtsp))) +#define GST_RTSP_STATE_UNLOCK(rtsp) (g_rec_mutex_unlock (GST_RTSP_STATE_GET_LOCK(rtsp))) + +#define GST_RTSP_STREAM_GET_LOCK(rtsp) (&GST_RTSP_CLIENT_SINK_CAST(rtsp)->stream_rec_lock) +#define GST_RTSP_STREAM_LOCK(rtsp) (g_rec_mutex_lock (GST_RTSP_STREAM_GET_LOCK(rtsp))) +#define GST_RTSP_STREAM_UNLOCK(rtsp) (g_rec_mutex_unlock (GST_RTSP_STREAM_GET_LOCK(rtsp))) + +typedef struct _GstRTSPConnInfo GstRTSPConnInfo; + +struct _GstRTSPConnInfo { + gchar *location; + GstRTSPUrl *url; + gchar *url_str; + GstRTSPConnection *connection; + gboolean connected; + gboolean flushing; +}; + +typedef struct _GstRTSPStreamInfo GstRTSPStreamInfo; +typedef struct _GstRTSPStreamContext GstRTSPStreamContext; + +struct _GstRTSPStreamContext { + GstRTSPClientSink *parent; + + guint index; + /* Index of the SDPMedia in the stored SDP */ + guint sdp_index; + + GstElement *payloader; + guint payloader_block_id; + gboolean prerolled; + + /* Stream management object */ + GstRTSPStream *stream; + gboolean joined; + + /* Secure profile key mgmt */ + GstCaps *srtcpparams; + + /* per stream connection */ + GstRTSPConnInfo conninfo; + /* For interleaved mode */ + guint8 channel[2]; + + GstRTSPStreamTransport *stream_transport; +}; + +/** + * GstRTSPNatMethod: + * @GST_RTSP_NAT_NONE: none + * @GST_RTSP_NAT_DUMMY: send dummy packets + * + * Different methods for trying to traverse firewalls. + */ +typedef enum +{ + GST_RTSP_NAT_NONE, + GST_RTSP_NAT_DUMMY +} GstRTSPNatMethod; + +struct _GstRTSPClientSink { + GstBin parent; + + /* task and mutex for interleaved mode */ + gboolean interleaved; + GstTask *task; + GRecMutex stream_rec_lock; + GstSegment segment; + gint free_channel; + + /* UDP mode loop */ + gint pending_cmd; + gint busy_cmd; + gboolean ignore_timeout; + gboolean open_error; + + /* mutex for protecting state changes */ + GRecMutex state_rec_lock; + + GstSDPMessage *uri_sdp; + gboolean from_sdp; + + /* properties */ + GstRTSPLowerTrans protocols; + gboolean debug; + guint retry; + guint64 udp_timeout; + GTimeVal tcp_timeout; + GTimeVal *ptcp_timeout; + guint latency; + gboolean do_rtsp_keep_alive; + gchar *proxy_host; + guint proxy_port; + gchar *proxy_user; /* from url or property */ + gchar *proxy_passwd; /* from url or property */ + gchar *prop_proxy_id; /* set via property */ + gchar *prop_proxy_pw; /* set via property */ + guint rtp_blocksize; + gchar *user_id; + gchar *user_pw; + GstRTSPRange client_port_range; + gint udp_buffer_size; + gboolean udp_reconnect; + gchar *multi_iface; + gboolean ntp_sync; + gboolean use_pipeline_clock; + GstStructure *sdes; + GTlsCertificateFlags tls_validation_flags; + GTlsDatabase *tls_database; + GTlsInteraction *tls_interaction; + gint ntp_time_source; + gchar *user_agent; + + /* state */ + GstRTSPState state; + gchar *content_base; + GstRTSPLowerTrans cur_protocols; + gboolean tried_url_auth; + gchar *addr; + gboolean need_redirect; + GstRTSPTimeRange *range; + gchar *control; + guint next_port_num; + GstClock *provided_clock; + + /* supported methods */ + gint methods; + + /* session management */ + GstRTSPConnInfo conninfo; + + /* Everything goes in an internal + * locked-state bin */ + GstBin *internal_bin; + /* Set to true when internal bin state + * >= PAUSED */ + gboolean prerolled; + + /* TRUE if we posted async-start */ + gboolean in_async; + + /* TRUE when stream info has been collected */ + gboolean streams_collected; + + guint next_pad_id; + gint next_dyn_pt; + + GstElement *rtpbin; + + GList *contexts; + GstSDPMessage cursdp; + + GMutex send_lock; + + GMutex preroll_lock; + GCond preroll_cond; + + GstClockTime rtx_time; + + GstRTSPProfile profiles; + gchar *server_ip; +}; + +struct _GstRTSPClientSinkClass { + GstBinClass parent_class; +}; + +GType gst_rtsp_client_sink_get_type(void); + +G_END_DECLS + +#endif /* __GST_RTSP_CLIENT_SINK_H__ */ diff --git a/gst/rtsp-sink/plugin.c b/gst/rtsp-sink/plugin.c new file mode 100644 index 0000000000..0580823521 --- /dev/null +++ b/gst/rtsp-sink/plugin.c @@ -0,0 +1,26 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstrtspclientsink.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ +#ifdef ENABLE_NLS + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); +#endif /* ENABLE_NLS */ + + if (!gst_element_register (plugin, "rtspclientsink", GST_RANK_NONE, + GST_TYPE_RTSP_CLIENT_SINK)) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + rtspclientsink, + "RTSP client sink element", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 026a482854..f3b5c82a5e 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -11,8 +11,8 @@ AM_TESTS_ENVIRONMENT = \ GST_STATE_IGNORE_ELEMENTS="$(STATE_IGNORE_ELEMENTS)" \ $(REGISTRY_ENVIRONMENT) \ GST_PLUGIN_SYSTEM_PATH_1_0= \ - GST_PLUGIN_PATH_1_0=$(GST_PLUGINS_DIR):$(GSTPB_PLUGINS_DIR):$(GSTPG_PLUGINS_DIR):$(GSTPD_PLUGINS_DIR) \ - GST_PLUGIN_LOADING_WHITELIST="gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad" + GST_PLUGIN_PATH_1_0=$(GST_PLUGINS_DIR):$(GSTPB_PLUGINS_DIR):$(GSTPG_PLUGINS_DIR):$(GSTPD_PLUGINS_DIR):$(top_builddir)/gst \ + GST_PLUGIN_LOADING_WHITELIST="gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad:gst-rtsp-server" # ths core dumps of some machines have PIDs appended @@ -37,7 +37,8 @@ check_PROGRAMS = \ gst/permissions \ gst/token \ gst/sessionmedia \ - gst/sessionpool + gst/sessionpool \ + gst/rtspclientsink # these tests don't even pass noinst_PROGRAMS = diff --git a/tests/check/gst/rtspclientsink.c b/tests/check/gst/rtspclientsink.c new file mode 100644 index 0000000000..584422bb43 --- /dev/null +++ b/tests/check/gst/rtspclientsink.c @@ -0,0 +1,221 @@ +/* GStreamer unit test for rtspclientsink + * Copyright (C) 2012 Axis Communications + * @author David Svensson Fors + * Copyright (C) 2015 Centricular Ltd + * @author Tim-Philipp Müller + * @author Jan Schmidt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include +#include + +#include "rtsp-server.h" + +#define TEST_MOUNT_POINT "/test" + +/* tested rtsp server */ +static GstRTSPServer *server = NULL; + +/* tcp port that the test server listens for rtsp requests on */ +static gint test_port = 0; + +/* id of the server's source within the GMainContext */ +static guint source_id; + +/* iterate the default main context until there are no events to dispatch */ +static void +iterate (void) +{ + while (g_main_context_iteration (NULL, FALSE)) { + GST_DEBUG ("iteration"); + } +} + +/* start the testing rtsp server for RECORD mode */ +static GstRTSPMediaFactory * +start_record_server (const gchar * launch_line) +{ + GstRTSPMediaFactory *factory; + GstRTSPMountPoints *mounts; + gchar *service; + + mounts = gst_rtsp_server_get_mount_points (server); + + factory = gst_rtsp_media_factory_new (); + + gst_rtsp_media_factory_set_transport_mode (factory, + GST_RTSP_TRANSPORT_MODE_RECORD); + gst_rtsp_media_factory_set_launch (factory, launch_line); + gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); + g_object_unref (mounts); + + /* set port to any */ + gst_rtsp_server_set_service (server, "0"); + + /* attach to default main context */ + source_id = gst_rtsp_server_attach (server, NULL); + fail_if (source_id == 0); + + /* get port */ + service = gst_rtsp_server_get_service (server); + test_port = atoi (service); + fail_unless (test_port != 0); + g_free (service); + + GST_DEBUG ("rtsp server listening on port %d", test_port); + return factory; +} + +/* stop the tested rtsp server */ +static void +stop_server (void) +{ + g_source_remove (source_id); + source_id = 0; + + GST_DEBUG ("rtsp server stopped"); +} + +/* fixture setup function */ +static void +setup (void) +{ + server = gst_rtsp_server_new (); +} + +/* fixture clean-up function */ +static void +teardown (void) +{ + if (server) { + g_object_unref (server); + server = NULL; + } + test_port = 0; +} + +/* create an rtsp connection to the server on test_port */ +static gchar * +get_server_uri (gint port, const gchar * mount_point) +{ + gchar *address; + gchar *uri_string; + GstRTSPUrl *url = NULL; + + address = gst_rtsp_server_get_address (server); + uri_string = g_strdup_printf ("rtsp://%s:%d%s", address, port, mount_point); + g_free (address); + + fail_unless (gst_rtsp_url_parse (uri_string, &url) == GST_RTSP_OK); + gst_rtsp_url_free (url); + + return uri_string; +} + +static void +media_constructed_cb (GstRTSPMediaFactory * mfactory, GstRTSPMedia * media, + gpointer user_data) +{ + GstElement **p_sink = user_data; + GstElement *bin; + + bin = gst_rtsp_media_get_element (media); + *p_sink = gst_bin_get_by_name (GST_BIN (bin), "sink"); + GST_INFO ("media constructed!: %" GST_PTR_FORMAT, *p_sink); +} + +#define AUDIO_PIPELINE "audiotestsrc num-buffers=%d ! " \ + "audio/x-raw,rate=8000 ! alawenc ! rtspclientsink name=sink location=%s" +#define RECORD_N_BUFS 10 + +GST_START_TEST (test_record) +{ + GstRTSPMediaFactory *mfactory; + GstElement *server_sink = NULL; + gint i; + + mfactory = + start_record_server ("( rtppcmadepay name=depay0 ! appsink name=sink )"); + + g_signal_connect (mfactory, "media-constructed", + G_CALLBACK (media_constructed_cb), &server_sink); + + /* Create an rtspclientsink and send some data */ + { + gchar *uri = get_server_uri (test_port, TEST_MOUNT_POINT); + gchar *pipe_str = g_strdup_printf (AUDIO_PIPELINE, + RECORD_N_BUFS, uri); + GstMessage *msg; + GstElement *pipeline; + GstBus *bus; + + pipeline = gst_parse_launch (pipe_str, NULL); + fail_unless (pipeline != NULL); + + bus = gst_element_get_bus (pipeline); + fail_if (bus == NULL); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1); + fail_if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_EOS); + gst_message_unref (msg); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + } + + iterate (); + + /* check received data (we assume every buffer created by audiotestsrc and + * subsequently encoded by mulawenc results in exactly one RTP packet) */ + for (i = 0; i < RECORD_N_BUFS; ++i) { + GstSample *sample = NULL; + + g_signal_emit_by_name (G_OBJECT (server_sink), "pull-sample", &sample); + GST_INFO ("%2d recv sample: %p", i, sample); + if (sample) + gst_sample_unref (sample); + } + + /* clean up and iterate so the clean-up can finish */ + stop_server (); + iterate (); +} + +GST_END_TEST; + +static Suite * +rtspclientsink_suite (void) +{ + Suite *s = suite_create ("rtspclientsink"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + tcase_add_checked_fixture (tc, setup, teardown); + tcase_set_timeout (tc, 120); + tcase_add_test (tc, test_record); + return s; +} + +GST_CHECK_MAIN (rtspclientsink); From b55fafdfbfd3cec792f08efc0814167bfe40bb03 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 28 Jan 2016 04:58:00 +1100 Subject: [PATCH 1218/1776] rtspclientsink: Simplify slightly using new -base API Use the new Mikey and SDP API in the base plugins libs to simplify some code. https://bugzilla.gnome.org/show_bug.cgi?id=758180 --- gst/rtsp-sink/gstrtspclientsink.c | 136 ++++-------------------------- 1 file changed, 16 insertions(+), 120 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 55c40463e0..3d5076f46b 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -150,12 +150,6 @@ gst_rtsp_client_sink_ntp_time_source_get_type (void) return ntp_time_source_type; } -#define AES_128_KEY_LEN 16 -#define AES_256_KEY_LEN 32 - -#define HMAC_32_KEY_LEN 4 -#define HMAC_80_KEY_LEN 10 - #define DEFAULT_LOCATION NULL #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_DEBUG FALSE @@ -3511,32 +3505,6 @@ fail: return GST_RTSP_ERROR; } -static guint8 -enc_key_length_from_cipher_name (const gchar * cipher) -{ - if (g_strcmp0 (cipher, "aes-128-icm") == 0) - return AES_128_KEY_LEN; - else if (g_strcmp0 (cipher, "aes-256-icm") == 0) - return AES_256_KEY_LEN; - else { - GST_ERROR ("encryption algorithm '%s' not supported", cipher); - return 0; - } -} - -static guint8 -auth_key_length_from_auth_name (const gchar * auth) -{ - if (g_strcmp0 (auth, "hmac-sha1-32") == 0) - return HMAC_32_KEY_LEN; - else if (g_strcmp0 (auth, "hmac-sha1-80") == 0) - return HMAC_80_KEY_LEN; - else { - GST_ERROR ("authentication algorithm '%s' not supported", auth); - return 0; - } -} - static GstCaps * signal_get_srtcp_params (GstRTSPClientSink * sink, GstRTSPStreamContext * context) @@ -3556,103 +3524,31 @@ static gchar * gst_rtsp_client_sink_stream_make_keymgmt (GstRTSPClientSink * sink, GstRTSPStreamContext * context) { - GBytes *bytes; - gchar *result, *base64; - const guint8 *data; - gsize size; - GstMIKEYMessage *msg; - GstMIKEYPayload *payload, *pkd; - guint8 byte; - GstStructure *s; - GstMapInfo info; - GstBuffer *srtpkey; - const GValue *val; - const gchar *srtcpcipher, *srtcpauth; - guint send_ssrc; + gchar *base64, *result = NULL; + GstMIKEYMessage *mikey_msg; context->srtcpparams = signal_get_srtcp_params (sink, context); if (context->srtcpparams == NULL) context->srtcpparams = gst_rtsp_stream_get_caps (context->stream); - s = gst_caps_get_structure (context->srtcpparams, 0); + mikey_msg = gst_mikey_message_new_from_caps (context->srtcpparams); + if (mikey_msg) { + guint send_ssrc; - srtcpcipher = gst_structure_get_string (s, "srtcp-cipher"); - srtcpauth = gst_structure_get_string (s, "srtcp-auth"); - val = gst_structure_get_value (s, "srtp-key"); + /* add policy '0' for our SSRC */ + gst_rtsp_stream_get_ssrc (context->stream, &send_ssrc); + GST_LOG_OBJECT (sink, "Stream %p ssrc %x", context->stream, send_ssrc); + gst_mikey_message_add_cs_srtp (mikey_msg, 0, send_ssrc, 0); - if (srtcpcipher == NULL || srtcpauth == NULL || val == NULL) { - GST_ERROR_OBJECT (sink, "could not find the right SRTP parameters in caps"); - return NULL; + base64 = gst_mikey_message_base64_encode (mikey_msg); + gst_mikey_message_unref (mikey_msg); + + if (base64) { + result = gst_sdp_make_keymgmt (context->conninfo.location, base64); + g_free (base64); + } } - srtpkey = gst_value_get_buffer (val); - - gst_rtsp_stream_get_ssrc (context->stream, &send_ssrc); - GST_LOG_OBJECT (sink, "Stream %p ssrc %x", context->stream, send_ssrc); - - msg = gst_mikey_message_new (); - /* unencrypted MIKEY message, we send this over TLS so this is allowed */ - gst_mikey_message_set_info (msg, GST_MIKEY_VERSION, GST_MIKEY_TYPE_PSK_INIT, - FALSE, GST_MIKEY_PRF_MIKEY_1, g_random_int (), GST_MIKEY_MAP_TYPE_SRTP); - /* add policy '0' for our SSRC */ - gst_mikey_message_add_cs_srtp (msg, 0, send_ssrc, 0); - /* timestamp is now */ - gst_mikey_message_add_t_now_ntp_utc (msg); - /* add some random data */ - gst_mikey_message_add_rand_len (msg, 16); - - /* the policy '0' is SRTP */ - payload = gst_mikey_payload_new (GST_MIKEY_PT_SP); - gst_mikey_payload_sp_set (payload, 0, GST_MIKEY_SEC_PROTO_SRTP); - - /* only AES-CM is supported */ - byte = 1; - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_ALG, 1, &byte); - /* encryption key length */ - byte = enc_key_length_from_cipher_name (srtcpcipher); - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_KEY_LEN, 1, - &byte); - /* only HMAC-SHA1 */ - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_ALG, 1, - &byte); - /* authentication key length */ - byte = auth_key_length_from_auth_name (srtcpauth); - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_KEY_LEN, 1, - &byte); - /* we enable encryption on RTP and RTCP */ - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_ENC, 1, - &byte); - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTCP_ENC, 1, - &byte); - /* we enable authentication on RTP and RTCP */ - gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_AUTH, 1, - &byte); - gst_mikey_message_add_payload (msg, payload); - - /* make unencrypted KEMAC */ - payload = gst_mikey_payload_new (GST_MIKEY_PT_KEMAC); - gst_mikey_payload_kemac_set (payload, GST_MIKEY_ENC_NULL, GST_MIKEY_MAC_NULL); - /* add the key in KEMAC */ - pkd = gst_mikey_payload_new (GST_MIKEY_PT_KEY_DATA); - gst_buffer_map (srtpkey, &info, GST_MAP_READ); - gst_mikey_payload_key_data_set_key (pkd, GST_MIKEY_KD_TEK, info.size, - info.data); - gst_buffer_unmap (srtpkey, &info); - gst_mikey_payload_kemac_add_sub (payload, pkd); - gst_mikey_message_add_payload (msg, payload); - - /* now serialize this to bytes */ - bytes = gst_mikey_message_to_bytes (msg, NULL, NULL); - gst_mikey_message_unref (msg); - /* and make it into base64 */ - data = g_bytes_get_data (bytes, &size); - base64 = g_base64_encode (data, size); - g_bytes_unref (bytes); - - result = g_strdup_printf ("prot=mikey;uri=\"%s\";data=\"%s\"", - context->conninfo.location, base64); - g_free (base64); - return result; } From 2af81aa56d1ffc1be92eaeef8dc6d56a78267ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 28 Jan 2016 22:05:56 +0100 Subject: [PATCH 1219/1776] configure: Move plugin specific flags below all the others They use some of the other flags, like $GST_ALL_LDFLAGS which is adding -no-undefined. And -no-undefined is required on Windows to build DLLs. --- configure.ac | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/configure.ac b/configure.ac index 7d49594b5e..83ac1723a0 100644 --- a/configure.ac +++ b/configure.ac @@ -220,31 +220,6 @@ AG_GST_SET_PACKAGE_RELEASE_DATETIME_WITH_NANO([$PACKAGE_VERSION_NANO], ["${srcdir}/gst-rtsp-server.doap"], [$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR.$PACKAGE_VERSION_MICRO]) -dnl build static plugins or not -AC_MSG_CHECKING([whether to build static plugins or not]) -AC_ARG_ENABLE( - static-plugins, - AC_HELP_STRING( - [--enable-static-plugins], - [build static plugins @<:@default=no@:>@]), - [AS_CASE( - [$enableval], [no], [], [yes], [], - [AC_MSG_ERROR([bad value "$enableval" for --enable-static-plugins])])], - [enable_static_plugins=no]) -AC_MSG_RESULT([$enable_static_plugins]) -if test "x$enable_static_plugins" = xyes; then - AC_DEFINE(GST_PLUGIN_BUILD_STATIC, 1, - [Define if static plugins should be built]) - GST_PLUGIN_LIBTOOLFLAGS="" -else - GST_PLUGIN_LIBTOOLFLAGS="--tag=disable-static" -fi -AC_SUBST(GST_PLUGIN_LIBTOOLFLAGS) -AM_CONDITIONAL(GST_PLUGIN_BUILD_STATIC, test "x$enable_static_plugins" = "xyes") - -GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_.*' $GST_ALL_LDFLAGS" -AC_SUBST(GST_PLUGIN_LDFLAGS) - # set by AG_GST_PARSE_SUBSYSTEM_DISABLES above dnl make sure it doesn't complain about unused variables if debugging is disabled NO_WARNINGS="" @@ -333,6 +308,31 @@ AC_SUBST([GST_OBJ_CFLAGS]) GST_OBJ_LIBS="\$(top_builddir)/gst/rtsp-server/libgstrtspserver-$GST_API_VERSION.la \$(GST_ALL_LIBS)" AC_SUBST([GST_OBJ_LIBS]) +dnl build static plugins or not +AC_MSG_CHECKING([whether to build static plugins or not]) +AC_ARG_ENABLE( + static-plugins, + AC_HELP_STRING( + [--enable-static-plugins], + [build static plugins @<:@default=no@:>@]), + [AS_CASE( + [$enableval], [no], [], [yes], [], + [AC_MSG_ERROR([bad value "$enableval" for --enable-static-plugins])])], + [enable_static_plugins=no]) +AC_MSG_RESULT([$enable_static_plugins]) +if test "x$enable_static_plugins" = xyes; then + AC_DEFINE(GST_PLUGIN_BUILD_STATIC, 1, + [Define if static plugins should be built]) + GST_PLUGIN_LIBTOOLFLAGS="" +else + GST_PLUGIN_LIBTOOLFLAGS="--tag=disable-static" +fi +AC_SUBST(GST_PLUGIN_LIBTOOLFLAGS) +AM_CONDITIONAL(GST_PLUGIN_BUILD_STATIC, test "x$enable_static_plugins" = "xyes") + +GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_.*' $GST_ALL_LDFLAGS" +AC_SUBST(GST_PLUGIN_LDFLAGS) + PKG_CHECK_MODULES(LIBCGROUP, libcgroup >= 0.26, HAVE_LIBCGROUP="yes", HAVE_LIBCGROUP="no") AC_SUBST(LIBCGROUP_CFLAGS) AC_SUBST(LIBCGROUP_LIBS) From aea624b6f8b93d506eb7b1f8a8b9086ca552856f Mon Sep 17 00:00:00 2001 From: Steven Hoving Date: Tue, 2 Feb 2016 09:01:51 +0100 Subject: [PATCH 1220/1776] rtsp-media: fix state_lock not locked again when preroll fails https://bugzilla.gnome.org/show_bug.cgi?id=761399 --- gst/rtsp-server/rtsp-media.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 90a9ddb2cf..9e49c5d357 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3465,6 +3465,7 @@ static gboolean default_unsuspend (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; + gboolean preroll_ok; switch (priv->suspend_mode) { case GST_RTSP_SUSPEND_MODE_NONE: @@ -3478,12 +3479,13 @@ default_unsuspend (GstRTSPMedia * media) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); if (!start_preroll (media)) goto start_failed; + g_rec_mutex_unlock (&priv->state_lock); - - if (!wait_preroll (media)) - goto preroll_failed; - + preroll_ok = wait_preroll (media); g_rec_mutex_lock (&priv->state_lock); + + if (!preroll_ok) + goto preroll_failed; } default: break; From f621e40efef5835b33d8bcc6a4fd93737123a04b Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 5 Feb 2016 18:11:41 -0300 Subject: [PATCH 1221/1776] Automatic update of common submodule From 86e4663 to b64f03f --- autogen.sh | 2 ++ common | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index 82a6ea4c62..aecf0e2e4a 100755 --- a/autogen.sh +++ b/autogen.sh @@ -54,6 +54,8 @@ CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc' if test "x$package" = "xgstreamer"; then CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --enable-docbook --enable-failing-tests --enable-poisoning" +elif test "x$package" = "xgst-plugins-bad"; then + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-player-tests" fi autogen_options $@ diff --git a/common b/common index 86e46630ed..b64f03f609 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 86e46630ed8af8d94796859db550a9c3d89c9f65 +Subproject commit b64f03f6090245624608beb5d2fff335e23a01c0 From 332846173848205a2c0ea72e40f060477dade8d2 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 5 Feb 2016 20:03:01 -0300 Subject: [PATCH 1222/1776] tests: extend the AM_TESTS_ENVIRONMENT from check.mak To get the CK_DEFAULT_TIMEOUT defined for all tests Also removes a 120 seconds timeout that was set as default explicitly in this module https://bugzilla.gnome.org/show_bug.cgi?id=761472 --- tests/check/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index f3b5c82a5e..88715192e1 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -6,8 +6,7 @@ TEST_FILES_DIRECTORY = $(top_srcdir)/tests/files REGISTRY_ENVIRONMENT = \ GST_REGISTRY_1_0=$(CHECK_REGISTRY) -AM_TESTS_ENVIRONMENT = \ - CK_DEFAULT_TIMEOUT=120 \ +AM_TESTS_ENVIRONMENT += \ GST_STATE_IGNORE_ELEMENTS="$(STATE_IGNORE_ELEMENTS)" \ $(REGISTRY_ENVIRONMENT) \ GST_PLUGIN_SYSTEM_PATH_1_0= \ From 4922b7f6b2c085a848e14b78a826c23f6d4767b6 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 8 Feb 2016 23:33:03 +0000 Subject: [PATCH 1223/1776] rtspclientsink: clean switch statements Coverity demands for fallthrough statements to be clearly commented, to distinguish from accidental fall throughs. And it also needs all cases to finish with a break, even if the break is never going to be executed like in the case of a continue jump. CID #1352039 CID #1352040 --- gst/rtsp-sink/gstrtspclientsink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 3d5076f46b..8c378ebbb6 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -1949,6 +1949,7 @@ gst_rtsp_client_sink_loop_rx (GstRTSPClientSink * sink) goto server_eof; } continue; + break; case GST_RTSP_ENET: GST_DEBUG_OBJECT (sink, "An ethernet problem occured."); default: @@ -4414,6 +4415,7 @@ gst_rtsp_client_sink_handle_message (GstBin * bin, GstMessage * message) gst_element_state_get_name (newstate), gst_element_state_get_name (pending), rtsp_client_sink->prerolled); } + /* fallthrough */ } default: { From fb9e957cc2e98b3e8a43da85a5c4c62b760b08cc Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 9 Feb 2016 10:34:22 +0000 Subject: [PATCH 1224/1776] rtspclientsink: remove check for impossible condition Goto error label checks stream to see if it needs to be unreferenced before returning, but this goto jumps happens before the stream is ever set, so it will always be NULL in this error label. CID #1352034 --- gst/rtsp-sink/gstrtspclientsink.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 8c378ebbb6..e7706a4b50 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -937,8 +937,6 @@ no_free_pt: GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL), ("Ran out of dynamic payload types.")); - if (stream) - g_object_unref (stream); return NULL; } From 8f1a9bff7f63d634055f90e29271861f5a33a136 Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Thu, 18 Feb 2016 15:20:05 +0000 Subject: [PATCH 1225/1776] uninstalled.pc: add support for non libtool build systems Currently the .la path is provided which requires to use libtool as mentioned in the GStreamer manual section-helloworld-compilerun.html. It is fine as long as the application is built using libtool. So currently it is not possible to compile a GStreamer application within gst-uninstalled with CMake or other build system different than autotools. This patch allows to do the following in gst-uninstalled env: gcc test.c -o test $(pkg-config --cflags --libs gstreamer-1.0 \ gstreamer-rtsp-server-1.0) Previously it required to prepend libtool --mode=link https://bugzilla.gnome.org/show_bug.cgi?id=720778 --- pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in index e45380566b..2aec3cc1a3 100644 --- a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in +++ b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in @@ -1,12 +1,12 @@ # the standard variables don't make sense for an uninstalled copy prefix= exec_prefix= -libdir=${pcfiledir}/../gst/rtsp-server +libdir=${pcfiledir}/../gst/rtsp-server/.libs includedir=${pcfiledir}/.. Name: gst-rtsp-server Description: GStreamer based RTSP server Version: @VERSION@ Requires: gstreamer-@GST_API_VERSION@ gstreamer-plugins-base-@GST_API_VERSION@ -Libs: ${libdir}/libgstrtspserver-@GST_API_VERSION@.la +Libs: -L${libdir} -lgstrtspserver-@GST_API_VERSION@ Cflags: -I${includedir} -I@srcdir@/.. From 60a2fa94b6584dea786ef35153d9d2e2e6ea3efa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 19 Feb 2016 12:03:18 +0200 Subject: [PATCH 1226/1776] Release 1.7.2 --- ChangeLog | 234 ++++++++++++++++++++++++++++++++++++++++++- NEWS | 2 +- RELEASE | 33 +++--- configure.ac | 12 +-- gst-rtsp-server.doap | 10 ++ 5 files changed, 260 insertions(+), 31 deletions(-) diff --git a/ChangeLog b/ChangeLog index a931568174..dfd82d0844 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,237 @@ -=== release 1.7.1 === +=== release 1.7.2 === -2015-12-24 Sebastian Dröge +2016-02-19 Sebastian Dröge * configure.ac: - releasing 1.7.1 + releasing 1.7.2 + +2016-02-18 15:20:05 +0000 Julien Isorce + + * pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in: + uninstalled.pc: add support for non libtool build systems + Currently the .la path is provided which requires to use libtool as + mentioned in the GStreamer manual section-helloworld-compilerun.html. + It is fine as long as the application is built using libtool. + So currently it is not possible to compile a GStreamer application + within gst-uninstalled with CMake or other build system different + than autotools. + This patch allows to do the following in gst-uninstalled env: + gcc test.c -o test $(pkg-config --cflags --libs gstreamer-1.0 \ + gstreamer-rtsp-server-1.0) + Previously it required to prepend libtool --mode=link + https://bugzilla.gnome.org/show_bug.cgi?id=720778 + +2016-02-09 10:34:22 +0000 Luis de Bethencourt + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: remove check for impossible condition + Goto error label checks stream to see if it needs to be unreferenced before + returning, but this goto jumps happens before the stream is ever set, so it + will always be NULL in this error label. + CID #1352034 + +2016-02-08 23:33:03 +0000 Luis de Bethencourt + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: clean switch statements + Coverity demands for fallthrough statements to be clearly commented, + to distinguish from accidental fall throughs. And it also needs all + cases to finish with a break, even if the break is never going to be + executed like in the case of a continue jump. + CID #1352039 + CID #1352040 + +2016-02-05 20:03:01 -0300 Thiago Santos + + * tests/check/Makefile.am: + tests: extend the AM_TESTS_ENVIRONMENT from check.mak + To get the CK_DEFAULT_TIMEOUT defined for all tests + Also removes a 120 seconds timeout that was set as default + explicitly in this module + https://bugzilla.gnome.org/show_bug.cgi?id=761472 + +2016-02-05 18:11:41 -0300 Thiago Santos + + * autogen.sh: + * common: + Automatic update of common submodule + From 86e4663 to b64f03f + +2016-02-02 09:01:51 +0100 Steven Hoving + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: fix state_lock not locked again when preroll fails + https://bugzilla.gnome.org/show_bug.cgi?id=761399 + +2016-01-28 22:05:56 +0100 Sebastian Dröge + + * configure.ac: + configure: Move plugin specific flags below all the others + They use some of the other flags, like $GST_ALL_LDFLAGS which is adding + -no-undefined. And -no-undefined is required on Windows to build DLLs. + +2016-01-28 04:58:00 +1100 Jan Schmidt + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Simplify slightly using new -base API + Use the new Mikey and SDP API in the base plugins libs + to simplify some code. + https://bugzilla.gnome.org/show_bug.cgi?id=758180 + +2015-11-17 01:12:28 +1100 Jan Schmidt + + * .gitignore: + * configure.ac: + * gst/Makefile.am: + * gst/rtsp-sink/Makefile.am: + * gst/rtsp-sink/gstrtspclientsink.c: + * gst/rtsp-sink/gstrtspclientsink.h: + * gst/rtsp-sink/plugin.c: + * tests/check/Makefile.am: + * tests/check/gst/rtspclientsink.c: + rtspsink: Add rtspclientsink element + Add an rtspclientsink element that accepts streams for which + there is a registered payloader and sends them to + an RTSP server using RECORD. + Sending is synchronised to the pipeline clock. Payload-types + are automatically selected. The 'new-payloader' signal is fired + for custom configuration of payloaders when they are created. + Can now stream a movie like this: + receiver: + ./test-record "( decodebin name=depay0 ! videoconvert ! autovideosink \ + decodebin name=depay1 ! audioconvert ! autoaudiosink )" + sender: + gst-launch-1.0 filesrc location=file-with-aac-and-h264.mp4 ! qtdemux name=d ! \ + queue ! aacparse ! rtspclientsink location=rtsp://127.0.0.1:8554/test name=s \ + https://bugzilla.gnome.org/show_bug.cgi?id=758180 + +2015-11-17 01:12:28 +1100 Jan Schmidt + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-stream: Add functions for using rtsp-stream from the client + Add a boolean to indicate that the rtsp-stream is running on the + 'client' side of an RTSP connection, for sending streams via + RECORD. In that case, the roles of the client/server ports + in transport setup are swapped. + https://bugzilla.gnome.org/show_bug.cgi?id=758180 + +2015-11-17 01:12:28 +1100 Jan Schmidt + + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-sdp.h: + rtsp-sdp: Add gst_rtsp_sdp_from_stream() + A new function that adds info from a GstRTSPStream into an SDP message. + https://bugzilla.gnome.org/show_bug.cgi?id=758180 + +2016-01-28 09:22:18 +0100 Steven Hoving + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Fix mutex beeing unlocked while they should be locked + https://bugzilla.gnome.org/show_bug.cgi?id=761226 + +2016-01-15 07:01:37 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-media-factory.c: + rtsp-media-factory: add missing break in "clock" property setter + CID 1348453 + +2016-01-05 13:10:36 +0100 Srimanta Panda + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: fixed assert during update transport + When RTSP server trying update transport during multicast, it throws an + assert. The assert is thrown because it is trying to get the parent of + an non-existing funnel element. + https://bugzilla.gnome.org/show_bug.cgi?id=760150 + +2016-01-03 17:26:31 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-permissions.h: + * gst/rtsp-server/rtsp-thread-pool.h: + * gst/rtsp-server/rtsp-token.h: + docs: remove dummy function declarations with G_INLINE_FUNC for gtk-doc + gtk-doc can handle static inline functions just fine these days, + there's no need for this stuff any more. + +2015-10-07 18:53:01 +0900 Hyunjun Ko + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-sdp.c: + sdp: replace duplicated codes to call new base sdp apis + https://bugzilla.gnome.org/show_bug.cgi?id=745880 + +2015-12-30 16:34:30 +0200 Sebastian Dröge + + * examples/test-netclock.c: + test-netclock: Use the new API to configure a clock directly + +2015-12-30 16:31:13 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + rtsp-media: Add API to directly configure a clock on the media pipelines + +2015-12-30 16:43:17 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Fix typo in docs gst_rtsp_media_set_latncy() -> latency() + +2015-12-30 16:30:38 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-media-factory.c: + rtsp-media-factory: Add FIXME for 2.0 + +2015-12-30 16:29:45 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Fix indentation + +2015-12-22 12:08:02 +0100 Sebastian Rasmussen + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Do not prepare media after media times out + Deferred calls to start_prepare() can be deferred past the point until + which wait_preroll() and by proxy gst_rtsp_media_get_status() is + prepared to wait. Previously there was no lock and no check for this + situation. This meant that a media could be prepared and unprepared + simultaneously by two different threads. Now a lock is in place and a + suitable check is done. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=759773 + +2015-12-09 18:24:24 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + rtsp-media: Add property to decide if sending media should be stopped when a client disconnects without TEARDOWN + Without TEARDOWN it might be desireable to keep the media running and continue + sending data to the client, even if the RTSP connection itself is + disconnected. + Only do this for session medias that have only UDP transports. If there's at + least on TCP transport, it will stop working and cause problems when the + connection is disconnected. + https://bugzilla.gnome.org/show_bug.cgi?id=758999 + +2015-12-24 15:29:33 +0100 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.7.1 === + +2015-12-24 14:54:06 +0100 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.7.1 2015-12-21 00:43:49 +0100 Koop Mast diff --git a/NEWS b/NEWS index a4bffc6a6b..a4a5e76ce2 100644 --- a/NEWS +++ b/NEWS @@ -1,2 +1,2 @@ -This is GStreamer 1.7.1 +This is GStreamer 1.7.2 diff --git a/RELEASE b/RELEASE index f2322a44aa..37b4315bc9 100644 --- a/RELEASE +++ b/RELEASE @@ -1,8 +1,7 @@ -Release notes for GStreamer RTSP Server Library 1.7.1 +Release notes for GStreamer RTSP Server Library 1.7.2 - -The GStreamer team is pleased to announce the first release of the unstable +The GStreamer team is pleased to announce the second release of the unstable 1.7 release series. The 1.7 release series is adding new features on top of the 1.0, 1.2, 1.4 and 1.6 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. The unstable 1.7 release series @@ -13,31 +12,26 @@ API can still change until that point. Binaries for Android, iOS, Mac OS X and Windows will be provided separately during the unstable 1.7 release series. - Bugs fixed in this release - * 753863 : rtsp-server: examples: Fix memory leaks when context parse fails - * 756969 : rtsp-server unit tests don't test udp-mcast transport - * 757949 : gst_rtsp_server_io_func() pops a context that has not been pushed - * 758179 : GstRTSPStream : Create pipeline based on enabled transport type - * 758268 : handle_setup_request() expect the media to be suspended - * 758319 : rtsp-server: Seeking often hangs forever, waiting for prerolling to happen again - * 758364 : rtsp-session-pool: Avoid dollar sign ($) in session ids - * 759010 : Valgrind test are faling for rtsp-server for master + * 758180 : Add rtspclientsink plugin + * 758999 : rtsp-media: Add property to decide if sending media should be stopped when a client disconnects without TEARDOWN + * 759773 : Prevent simultaneous prepare/unprepare of RTSP media + * 760150 : Updating transport for multicast case gives assertion ==== Download ==== You can find source releases of gst-rtsp-server in the download -directory: http://gstreamer.freedesktop.org/src/gst-rtsp-server/ +directory: https://gstreamer.freedesktop.org/src/gst-rtsp-server/ The git repository and details how to clone it can be found at http://cgit.freedesktop.org/gstreamer/gst-rtsp-server/ ==== Homepage ==== -The project's website is http://gstreamer.freedesktop.org/ +The project's website is https://gstreamer.freedesktop.org/ ==== Support and Bugs ==== @@ -62,17 +56,14 @@ subscribe to the gstreamer-devel list. Contributors to this release - * David Svensson Fors * Hyunjun Ko * Jan Schmidt - * Koop Mast - * Marcus Prebble - * Nicolas Dufresne - * Olivier Crête + * Julien Isorce + * Luis de Bethencourt * Sebastian Dröge * Sebastian Rasmussen * Srimanta Panda + * Steven Hoving + * Thiago Santos * Tim-Philipp Müller - * Vineeth TM - * Xavier Claessens   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 83ac1723a0..35e3987f63 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.7.1.1], +AC_INIT([GStreamer RTSP Server Library], [1.7.2], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 701, 0, 701) +AS_LIBTOOL(GST, 702, 0, 702) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.7.1.1 -GSTPB_REQ=1.7.1.1 -GSTPG_REQ=1.7.1.1 -GSTPD_REQ=1.7.1.1 +GST_REQ=1.7.2 +GSTPB_REQ=1.7.2 +GSTPG_REQ=1.7.2 +GSTPD_REQ=1.7.2 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index b202efe0f1..eae21a208a 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.7.2 + master + + 2016-02-19 + + + + 1.7.1 From 457c00dc0a9fcd7ea7aa271f2a2f26d977720e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 19 Feb 2016 12:38:42 +0200 Subject: [PATCH 1227/1776] Back to development --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 35e3987f63..7f57cfae41 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.7.2], +AC_INIT([GStreamer RTSP Server Library], [1.7.2.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 702, 0, 702) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.7.2 -GSTPB_REQ=1.7.2 -GSTPG_REQ=1.7.2 -GSTPD_REQ=1.7.2 +GST_REQ=1.7.2.1 +GSTPB_REQ=1.7.2.1 +GSTPG_REQ=1.7.2.1 +GSTPD_REQ=1.7.2.1 dnl *** autotools stuff **** From 89bc8009dd6b8a7e5d82d02a6794622a929268c0 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 19 Nov 2015 14:09:25 +0100 Subject: [PATCH 1228/1776] rtsp-stream: added helper function for creating the sender/receiver parts Code refactoring: introduced helper function for creating the receiver and the sender parts of the streaming pipeline. https://bugzilla.gnome.org/show_bug.cgi?id=757488 --- gst/rtsp-server/rtsp-stream.c | 293 +++++++++++++++++++--------------- 1 file changed, 166 insertions(+), 127 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4034a5cc0a..83f2256212 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2112,132 +2112,26 @@ on_npt_stop (GstElement * rtpbin, guint session, guint ssrc, gst_pad_send_event (stream->priv->sinkpad, gst_event_new_eos ()); } -/** - * gst_rtsp_stream_join_bin: - * @stream: a #GstRTSPStream - * @bin: (transfer none): a #GstBin to join - * @rtpbin: (transfer none): a rtpbin element in @bin - * @state: the target state of the new elements - * - * Join the #GstBin @bin that contains the element @rtpbin. - * - * @stream will link to @rtpbin, which must be inside @bin. The elements - * added to @bin will be set to the state given in @state. - * - * Returns: %TRUE on success. - */ -gboolean -gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, - GstElement * rtpbin, GstState state) + +/* must be called with lock */ +static void +create_sender_part (GstRTSPStream * stream, GstBin * bin, + GstState state) { GstRTSPStreamPrivate *priv; - gint i; - guint idx; - gchar *name; - GstPad *pad, *sinkpad = NULL, *selpad; - GstPadLinkReturn ret; + GstPad *pad, *sinkpad = NULL; gboolean is_tcp = FALSE, is_udp = FALSE; - - g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); - g_return_val_if_fail (GST_IS_BIN (bin), FALSE); - g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE); + gint i; priv = stream->priv; - g_mutex_lock (&priv->lock); - if (priv->is_joined) - goto was_joined; - - /* create a session with the same index as the stream */ - idx = priv->idx; - - GST_INFO ("stream %p joining bin as session %u", stream, idx); - is_tcp = priv->protocols & GST_RTSP_LOWER_TRANS_TCP; - is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); - if (is_udp && !alloc_ports (stream)) - goto no_ports; - - /* update the dscp qos field in the sinks */ - update_dscp_qos (stream); - - if (priv->profiles & GST_RTSP_PROFILE_SAVP - || priv->profiles & GST_RTSP_PROFILE_SAVPF) { - /* For SRTP */ - g_signal_connect (rtpbin, "request-rtp-encoder", - (GCallback) request_rtp_encoder, stream); - g_signal_connect (rtpbin, "request-rtcp-encoder", - (GCallback) request_rtcp_encoder, stream); - g_signal_connect (rtpbin, "request-rtp-decoder", - (GCallback) request_rtp_rtcp_decoder, stream); - g_signal_connect (rtpbin, "request-rtcp-decoder", - (GCallback) request_rtp_rtcp_decoder, stream); - } - - if (priv->sinkpad) { - g_signal_connect (rtpbin, "request-pt-map", - (GCallback) request_pt_map, stream); - } - - /* get pads from the RTP session element for sending and receiving - * RTP/RTCP*/ - if (priv->srcpad) { - /* get a pad for sending RTP */ - name = g_strdup_printf ("send_rtp_sink_%u", idx); - priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); - g_free (name); - - /* link the RTP pad to the session manager, it should not really fail unless - * this is not really an RTP pad */ - ret = gst_pad_link (priv->srcpad, priv->send_rtp_sink); - if (ret != GST_PAD_LINK_OK) - goto link_failed; - - name = g_strdup_printf ("send_rtp_src_%u", idx); - priv->send_src[0] = gst_element_get_static_pad (rtpbin, name); - g_free (name); - } else { - /* Need to connect our sinkpad from here */ - g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added, stream); - /* EOS */ - g_signal_connect (rtpbin, "on-npt-stop", (GCallback) on_npt_stop, stream); - - name = g_strdup_printf ("recv_rtp_sink_%u", idx); - priv->recv_sink[0] = gst_element_get_request_pad (rtpbin, name); - g_free (name); - } - - name = g_strdup_printf ("send_rtcp_src_%u", idx); - priv->send_src[1] = gst_element_get_request_pad (rtpbin, name); - g_free (name); - name = g_strdup_printf ("recv_rtcp_sink_%u", idx); - priv->recv_sink[1] = gst_element_get_request_pad (rtpbin, name); - g_free (name); - - /* get the session */ - g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &priv->session); - - g_signal_connect (priv->session, "on-new-ssrc", (GCallback) on_new_ssrc, - stream); - g_signal_connect (priv->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes, - stream); - g_signal_connect (priv->session, "on-ssrc-active", - (GCallback) on_ssrc_active, stream); - g_signal_connect (priv->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, - stream); - g_signal_connect (priv->session, "on-bye-timeout", - (GCallback) on_bye_timeout, stream); - g_signal_connect (priv->session, "on-timeout", (GCallback) on_timeout, - stream); - - /* signal for sender ssrc */ - g_signal_connect (priv->session, "on-new-sender-ssrc", - (GCallback) on_new_sender_ssrc, stream); - g_signal_connect (priv->session, "on-sender-ssrc-active", - (GCallback) on_sender_ssrc_active, stream); + if (is_udp) + /* update the dscp qos field in the sinks */ + update_dscp_qos (stream); for (i = 0; i < 2; i++) { GstPad *teepad, *queuepad; @@ -2261,7 +2155,6 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, * and link the udpsink (for UDP) or appsink (for TCP) directly to * the session. */ - /* Only link the RTP send src if we're going to send RTP, link * the RTCP send src always */ if (priv->srcpad || i == 1) { @@ -2347,6 +2240,37 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, } } + /* check if we need to set to a special state */ + if (state != GST_STATE_NULL) { + if (priv->udpsink[i] && (priv->srcpad || i == 1)) + gst_element_set_state (priv->udpsink[i], state); + if (priv->appsink[i] && (priv->srcpad || i == 1)) + gst_element_set_state (priv->appsink[i], state); + if (priv->appqueue[i] && (priv->srcpad || i == 1)) + gst_element_set_state (priv->appqueue[i], state); + if (priv->udpqueue[i] && (priv->srcpad || i == 1)) + gst_element_set_state (priv->udpqueue[i], state); + if (priv->tee[i] && (priv->srcpad || i == 1)) + gst_element_set_state (priv->tee[i], state); + } + } +} + +/* must be called with lock */ +static void +create_receiver_part (GstRTSPStream * stream, GstBin * bin, + GstState state) +{ + GstRTSPStreamPrivate *priv; + GstPad *pad, *selpad; + gboolean is_tcp; + gint i; + + priv = stream->priv; + + is_tcp = priv->protocols & GST_RTSP_LOWER_TRANS_TCP; + + for (i = 0; i < 2; i++) { /* Only connect recv RTP sink if we expect to receive RTP. Connect recv * RTCP sink always */ if (priv->sinkpad || i == 1) { @@ -2421,22 +2345,137 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, /* check if we need to set to a special state */ if (state != GST_STATE_NULL) { - if (priv->udpsink[i] && (priv->srcpad || i == 1)) - gst_element_set_state (priv->udpsink[i], state); - if (priv->appsink[i] && (priv->srcpad || i == 1)) - gst_element_set_state (priv->appsink[i], state); - if (priv->appqueue[i] && (priv->srcpad || i == 1)) - gst_element_set_state (priv->appqueue[i], state); - if (priv->udpqueue[i] && (priv->srcpad || i == 1)) - gst_element_set_state (priv->udpqueue[i], state); - if (priv->tee[i] && (priv->srcpad || i == 1)) - gst_element_set_state (priv->tee[i], state); if (priv->funnel[i] && (priv->sinkpad || i == 1)) gst_element_set_state (priv->funnel[i], state); if (priv->appsrc[i] && (priv->sinkpad || i == 1)) gst_element_set_state (priv->appsrc[i], state); } } +} + +/** + * gst_rtsp_stream_join_bin: + * @stream: a #GstRTSPStream + * @bin: (transfer none): a #GstBin to join + * @rtpbin: (transfer none): a rtpbin element in @bin + * @state: the target state of the new elements + * + * Join the #GstBin @bin that contains the element @rtpbin. + * + * @stream will link to @rtpbin, which must be inside @bin. The elements + * added to @bin will be set to the state given in @state. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, + GstElement * rtpbin, GstState state) +{ + GstRTSPStreamPrivate *priv; + guint idx; + gchar *name; + GstPadLinkReturn ret; + gboolean is_udp; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + g_return_val_if_fail (GST_IS_BIN (bin), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if (priv->is_joined) + goto was_joined; + + /* create a session with the same index as the stream */ + idx = priv->idx; + + GST_INFO ("stream %p joining bin as session %u", stream, idx); + + is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || + (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); + + if (is_udp && !alloc_ports (stream)) + goto no_ports; + + if (priv->profiles & GST_RTSP_PROFILE_SAVP + || priv->profiles & GST_RTSP_PROFILE_SAVPF) { + /* For SRTP */ + g_signal_connect (rtpbin, "request-rtp-encoder", + (GCallback) request_rtp_encoder, stream); + g_signal_connect (rtpbin, "request-rtcp-encoder", + (GCallback) request_rtcp_encoder, stream); + g_signal_connect (rtpbin, "request-rtp-decoder", + (GCallback) request_rtp_rtcp_decoder, stream); + g_signal_connect (rtpbin, "request-rtcp-decoder", + (GCallback) request_rtp_rtcp_decoder, stream); + } + + if (priv->sinkpad) { + g_signal_connect (rtpbin, "request-pt-map", + (GCallback) request_pt_map, stream); + } + + /* get pads from the RTP session element for sending and receiving + * RTP/RTCP*/ + if (priv->srcpad) { + /* get a pad for sending RTP */ + name = g_strdup_printf ("send_rtp_sink_%u", idx); + priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); + g_free (name); + + /* link the RTP pad to the session manager, it should not really fail unless + * this is not really an RTP pad */ + ret = gst_pad_link (priv->srcpad, priv->send_rtp_sink); + if (ret != GST_PAD_LINK_OK) + goto link_failed; + + name = g_strdup_printf ("send_rtp_src_%u", idx); + priv->send_src[0] = gst_element_get_static_pad (rtpbin, name); + g_free (name); + } else { + /* Need to connect our sinkpad from here */ + g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added, stream); + /* EOS */ + g_signal_connect (rtpbin, "on-npt-stop", (GCallback) on_npt_stop, stream); + + name = g_strdup_printf ("recv_rtp_sink_%u", idx); + priv->recv_sink[0] = gst_element_get_request_pad (rtpbin, name); + g_free (name); + } + + name = g_strdup_printf ("send_rtcp_src_%u", idx); + priv->send_src[1] = gst_element_get_request_pad (rtpbin, name); + g_free (name); + name = g_strdup_printf ("recv_rtcp_sink_%u", idx); + priv->recv_sink[1] = gst_element_get_request_pad (rtpbin, name); + g_free (name); + + /* get the session */ + g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &priv->session); + + g_signal_connect (priv->session, "on-new-ssrc", (GCallback) on_new_ssrc, + stream); + g_signal_connect (priv->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes, + stream); + g_signal_connect (priv->session, "on-ssrc-active", + (GCallback) on_ssrc_active, stream); + g_signal_connect (priv->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, + stream); + g_signal_connect (priv->session, "on-bye-timeout", + (GCallback) on_bye_timeout, stream); + g_signal_connect (priv->session, "on-timeout", (GCallback) on_timeout, + stream); + + /* signal for sender ssrc */ + g_signal_connect (priv->session, "on-new-sender-ssrc", + (GCallback) on_new_sender_ssrc, stream); + g_signal_connect (priv->session, "on-sender-ssrc-active", + (GCallback) on_sender_ssrc_active, stream); + + create_sender_part (stream, bin, state); + + create_receiver_part (stream, bin, state); if (priv->srcpad) { /* be notified of caps changes */ From 6b6970ab23dd0496bf770839b7fcddef05385914 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Fri, 20 Nov 2015 08:38:42 +0100 Subject: [PATCH 1229/1776] rtsp-stream: added function for creating and configuring UDP sinks Code refactoring: create and configure UDP sinks in a separate function. https://bugzilla.gnome.org/show_bug.cgi?id=757488 --- gst/rtsp-server/rtsp-stream.c | 149 +++++++++++++++++++--------------- 1 file changed, 85 insertions(+), 64 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 83f2256212..cfbe4ca2db 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1020,16 +1020,89 @@ different_address: } } +/* must be called with lock */ static gboolean -alloc_ports_one_family (GstRTSPStream * stream, GstRTSPAddressPool * pool, - gint buffer_size, GSocketFamily family, GstElement * udpsrc_out[2], - GstElement * udpsink_out[2], GstRTSPRange * server_port_out, +create_and_configure_udpsinks (GstRTSPStream * stream, GSocket * rtp_socket, + GSocket * rtcp_socket, GSocketFamily family) +{ + GstRTSPStreamPrivate *priv = stream->priv; + GstElement *udpsink0, *udpsink1; + const gchar *multisink_socket; + + if (family == G_SOCKET_FAMILY_IPV6) + multisink_socket = "socket-v6"; + else + multisink_socket = "socket"; + + udpsink0 = NULL; + udpsink1 = NULL; + + if (priv->udpsink[0]) + udpsink0 = priv->udpsink[0]; + else + udpsink0 = gst_element_factory_make ("multiudpsink", NULL); + + if (!udpsink0) + goto no_udp_protocol; + + if (priv->udpsink[1]) + udpsink1 = priv->udpsink[1]; + else + udpsink1 = gst_element_factory_make ("multiudpsink", NULL); + + if (!udpsink1) + goto no_udp_protocol; + + /* configure sinks */ + + g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL); + + g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); + + g_object_set (G_OBJECT (udpsink0), "buffer-size", priv->buffer_size, NULL); + + g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); + /* Needs to be async for RECORD streams, otherwise we will never go to + * PLAYING because the sinks will wait for data while the udpsrc can't + * provide data with timestamps in PAUSED. */ + if (priv->sinkpad) + g_object_set (G_OBJECT (udpsink0), "async", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); + + g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "auto-multicast", FALSE, NULL); + + g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL); + g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL); + + g_object_set (G_OBJECT (udpsink0), multisink_socket, rtp_socket, NULL); + g_object_set (G_OBJECT (udpsink1), multisink_socket, rtcp_socket, NULL); + + /* update the dscp qos field in the sinks */ + update_dscp_qos (stream); + + priv->udpsink[0] = udpsink0; + priv->udpsink[1] = udpsink1; + + return TRUE; + + /* ERRORS */ +no_udp_protocol: + { + return FALSE; + } +} + +static gboolean +alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, + GstElement * udpsrc_out[2], GstRTSPRange * server_port_out, GstRTSPAddress ** server_addr_out) { GstRTSPStreamPrivate *priv = stream->priv; GstStateChangeReturn ret; GstElement *udpsrc0, *udpsrc1; - GstElement *udpsink0, *udpsink1; GSocket *rtp_socket = NULL; GSocket *rtcp_socket; gint tmp_rtp, tmp_rtcp; @@ -1040,17 +1113,11 @@ alloc_ports_one_family (GstRTSPStream * stream, GstRTSPAddressPool * pool, GInetAddress *inetaddr = NULL; GSocketAddress *rtp_sockaddr = NULL; GSocketAddress *rtcp_sockaddr = NULL; - const gchar *multisink_socket; - - if (family == G_SOCKET_FAMILY_IPV6) - multisink_socket = "socket-v6"; - else - multisink_socket = "socket"; + GstRTSPAddressPool * pool; + pool = priv->pool; udpsrc0 = NULL; udpsrc1 = NULL; - udpsink0 = NULL; - udpsink1 = NULL; count = 0; /* Start with random port */ @@ -1169,49 +1236,14 @@ again: if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) goto port_error; - if (udpsink_out[0]) - udpsink0 = udpsink_out[0]; - else - udpsink0 = gst_element_factory_make ("multiudpsink", NULL); - - if (!udpsink0) + if (!create_and_configure_udpsinks (stream, rtp_socket, rtcp_socket, + family)) goto no_udp_protocol; - g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL); - g_object_set (G_OBJECT (udpsink0), multisink_socket, rtp_socket, NULL); - - if (udpsink_out[1]) - udpsink1 = udpsink_out[1]; - else - udpsink1 = gst_element_factory_make ("multiudpsink", NULL); - - if (!udpsink1) - goto no_udp_protocol; - - g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); - g_object_set (G_OBJECT (udpsink0), "buffer-size", buffer_size, NULL); - - g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), multisink_socket, rtcp_socket, NULL); - g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); - /* Needs to be async for RECORD streams, otherwise we will never go to - * PLAYING because the sinks will wait for data while the udpsrc can't - * provide data with timestamps in PAUSED. */ - if (priv->sinkpad) - g_object_set (G_OBJECT (udpsink0), "async", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); - g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL); - g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "auto-multicast", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL); - /* we keep these elements, we will further configure them when the * client told us to really use the UDP ports. */ udpsrc_out[0] = udpsrc0; udpsrc_out[1] = udpsrc1; - udpsink_out[0] = udpsink0; - udpsink_out[1] = udpsink1; server_port_out->min = rtpport; server_port_out->max = rtcpport; @@ -1255,10 +1287,6 @@ cleanup: gst_element_set_state (udpsrc1, GST_STATE_NULL); gst_object_unref (udpsrc1); } - if (udpsink0) { - gst_element_set_state (udpsink0, GST_STATE_NULL); - gst_object_unref (udpsink0); - } if (inetaddr) g_object_unref (inetaddr); g_list_free_full (rejected_addresses, @@ -1280,14 +1308,12 @@ alloc_ports (GstRTSPStream * stream) GstRTSPStreamPrivate *priv = stream->priv; priv->have_ipv4 = - alloc_ports_one_family (stream, priv->pool, priv->buffer_size, - G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, priv->udpsink, - &priv->server_port_v4, &priv->server_addr_v4); + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, + &priv->server_port_v4, &priv->server_addr_v4); priv->have_ipv6 = - alloc_ports_one_family (stream, priv->pool, priv->buffer_size, - G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, priv->udpsink, - &priv->server_port_v6, &priv->server_addr_v6); + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, + &priv->server_port_v6, &priv->server_addr_v6); return priv->have_ipv4 || priv->have_ipv6; } @@ -2112,7 +2138,6 @@ on_npt_stop (GstElement * rtpbin, guint session, guint ssrc, gst_pad_send_event (stream->priv->sinkpad, gst_event_new_eos ()); } - /* must be called with lock */ static void create_sender_part (GstRTSPStream * stream, GstBin * bin, @@ -2129,10 +2154,6 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); - if (is_udp) - /* update the dscp qos field in the sinks */ - update_dscp_qos (stream); - for (i = 0; i < 2; i++) { GstPad *teepad, *queuepad; /* For the sender we create this bit of pipeline for both From b26c16c82414e62f1d83209d695d411a155cf2cd Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Fri, 20 Nov 2015 14:43:38 +0100 Subject: [PATCH 1230/1776] rtsp-stream: added function for RTP/RTCP socket configuration Code refactoring: configure RTP and RTCP sockets for UDP sinks in a separate function. https://bugzilla.gnome.org/show_bug.cgi?id=757488 --- gst/rtsp-server/rtsp-stream.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index cfbe4ca2db..54ae71b529 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1021,12 +1021,11 @@ different_address: } /* must be called with lock */ -static gboolean -create_and_configure_udpsinks (GstRTSPStream * stream, GSocket * rtp_socket, +static void +set_sockets_for_udpsinks (GstRTSPStream * stream, GSocket * rtp_socket, GSocket * rtcp_socket, GSocketFamily family) { GstRTSPStreamPrivate *priv = stream->priv; - GstElement *udpsink0, *udpsink1; const gchar *multisink_socket; if (family == G_SOCKET_FAMILY_IPV6) @@ -1034,6 +1033,19 @@ create_and_configure_udpsinks (GstRTSPStream * stream, GSocket * rtp_socket, else multisink_socket = "socket"; + g_object_set (G_OBJECT (priv->udpsink[0]), multisink_socket, rtp_socket, + NULL); + g_object_set (G_OBJECT (priv->udpsink[1]), multisink_socket, rtcp_socket, + NULL); +} + +/* must be called with lock */ +static gboolean +create_and_configure_udpsinks (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv = stream->priv; + GstElement *udpsink0, *udpsink1; + udpsink0 = NULL; udpsink1 = NULL; @@ -1077,9 +1089,6 @@ create_and_configure_udpsinks (GstRTSPStream * stream, GSocket * rtp_socket, g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL); - g_object_set (G_OBJECT (udpsink0), multisink_socket, rtp_socket, NULL); - g_object_set (G_OBJECT (udpsink1), multisink_socket, rtcp_socket, NULL); - /* update the dscp qos field in the sinks */ update_dscp_qos (stream); @@ -1236,10 +1245,12 @@ again: if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) goto port_error; - if (!create_and_configure_udpsinks (stream, rtp_socket, rtcp_socket, - family)) + if (!create_and_configure_udpsinks (stream)) goto no_udp_protocol; + /* set RTP and RTCP sockets */ + set_sockets_for_udpsinks (stream, rtp_socket, rtcp_socket, family); + /* we keep these elements, we will further configure them when the * client told us to really use the UDP ports. */ udpsrc_out[0] = udpsrc0; From c0cadc6ec3a4b81506d6cc19f72cc9be1f91f064 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Fri, 20 Nov 2015 15:34:43 +0100 Subject: [PATCH 1231/1776] rtsp-stream: added function for creating and configuring UDP sources Code refactoring: create and configure UDP sources in a separate function. https://bugzilla.gnome.org/show_bug.cgi?id=757488 --- gst/rtsp-server/rtsp-stream.c | 81 +++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 54ae71b529..f305ea59dd 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1104,14 +1104,51 @@ no_udp_protocol: } } +/* must be called with lock */ +static gboolean +create_and_configure_udpsources_one_family (GstElement * udpsrc_out[2], + GSocket * rtp_socket, GSocket * rtcp_socket, GSocketFamily family) +{ + GstStateChangeReturn ret; + + /* we keep these elements, we will further configure them when the + * client told us to really use the UDP ports. */ + udpsrc_out[0] = gst_element_factory_make ("udpsrc", NULL); + udpsrc_out[1] = gst_element_factory_make ("udpsrc", NULL); + + if (udpsrc_out[0] == NULL || udpsrc_out[1] == NULL) + goto error; + + g_object_set (G_OBJECT (udpsrc_out[0]), "socket", rtp_socket, NULL); + g_object_set (G_OBJECT (udpsrc_out[1]), "socket", rtcp_socket, NULL); + + ret = gst_element_set_state (udpsrc_out[0], GST_STATE_READY); + if (ret == GST_STATE_CHANGE_FAILURE) + goto error; + ret = gst_element_set_state (udpsrc_out[1], GST_STATE_READY); + if (ret == GST_STATE_CHANGE_FAILURE) + goto error; + + return TRUE; + return TRUE; + + /* ERRORS */ +error: + { + if (udpsrc_out[0]) + gst_object_unref (udpsrc_out[0]); + if (udpsrc_out[1]) + gst_object_unref (udpsrc_out[1]); + return FALSE; + } +} + static gboolean alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GstElement * udpsrc_out[2], GstRTSPRange * server_port_out, GstRTSPAddress ** server_addr_out) { GstRTSPStreamPrivate *priv = stream->priv; - GstStateChangeReturn ret; - GstElement *udpsrc0, *udpsrc1; GSocket *rtp_socket = NULL; GSocket *rtcp_socket; gint tmp_rtp, tmp_rtcp; @@ -1125,8 +1162,6 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GstRTSPAddressPool * pool; pool = priv->pool; - udpsrc0 = NULL; - udpsrc1 = NULL; count = 0; /* Start with random port */ @@ -1221,25 +1256,12 @@ again: g_clear_object (&inetaddr); - udpsrc0 = gst_element_factory_make ("udpsrc", NULL); - udpsrc1 = gst_element_factory_make ("udpsrc", NULL); - - if (udpsrc0 == NULL || udpsrc1 == NULL) + if (!create_and_configure_udpsources_one_family (udpsrc_out, rtp_socket, + rtcp_socket, family)) goto no_udp_protocol; - g_object_set (G_OBJECT (udpsrc0), "socket", rtp_socket, NULL); - g_object_set (G_OBJECT (udpsrc1), "socket", rtcp_socket, NULL); - - ret = gst_element_set_state (udpsrc0, GST_STATE_READY); - if (ret == GST_STATE_CHANGE_FAILURE) - goto element_error; - ret = gst_element_set_state (udpsrc1, GST_STATE_READY); - if (ret == GST_STATE_CHANGE_FAILURE) - goto element_error; - - /* all fine, do port check */ - g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL); - g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL); + g_object_get (G_OBJECT (udpsrc_out[0]), "port", &rtpport, NULL); + g_object_get (G_OBJECT (udpsrc_out[1]), "port", &rtcpport, NULL); /* this should not happen... */ if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) @@ -1251,11 +1273,6 @@ again: /* set RTP and RTCP sockets */ set_sockets_for_udpsinks (stream, rtp_socket, rtcp_socket, family); - /* we keep these elements, we will further configure them when the - * client told us to really use the UDP ports. */ - udpsrc_out[0] = udpsrc0; - udpsrc_out[1] = udpsrc1; - server_port_out->min = rtpport; server_port_out->max = rtcpport; @@ -1284,20 +1301,8 @@ socket_error: { goto cleanup; } -element_error: - { - goto cleanup; - } cleanup: { - if (udpsrc0) { - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - } - if (udpsrc1) { - gst_element_set_state (udpsrc1, GST_STATE_NULL); - gst_object_unref (udpsrc1); - } if (inetaddr) g_object_unref (inetaddr); g_list_free_full (rejected_addresses, From 66389cb900d5c4c974b619ad3b5d8d23bea2b863 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Wed, 13 Jan 2016 10:55:40 +0100 Subject: [PATCH 1232/1776] rtsp-stream: added function for setting UDP sources to PLAYING state Code refactoring: Introduced a function for setting UDP sources to PLAYING state. https://bugzilla.gnome.org/show_bug.cgi?id=757488 --- gst/rtsp-server/rtsp-stream.c | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index f305ea59dd..15fca1918f 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1104,6 +1104,58 @@ no_udp_protocol: } } +/* must be called with lock */ +static void +play_udpsources_one_family (GstRTSPStream * stream, GSocketFamily family) +{ + GstRTSPStreamPrivate *priv; + GstPad *pad, *selpad; + guint i; + GstBin *bin; + + priv = stream->priv; + bin = GST_BIN (gst_object_get_parent (GST_OBJECT (priv->funnel[1]))); + + for (i = 0; i < 2; i++) { + if (priv->sinkpad || i == 1) { + if (family == G_SOCKET_FAMILY_IPV4 && priv->udpsrc_v4[i]) { + if (priv->srcpad) { + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values. This is only relevant for PLAY pipelines */ + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); + } + /* add udpsrc */ + gst_bin_add (bin, priv->udpsrc_v4[i]); + + /* and link to the funnel v4 */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + } + + if (family == G_SOCKET_FAMILY_IPV6 && priv->udpsrc_v6[i]) { + if (priv->srcpad) { + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); + } + gst_bin_add (bin, priv->udpsrc_v6[i]); + + /* and link to the funnel v6 */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + } + } + } + + gst_object_unref (bin); +} + /* must be called with lock */ static gboolean create_and_configure_udpsources_one_family (GstElement * udpsrc_out[2], @@ -2513,6 +2565,8 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, create_sender_part (stream, bin, state); create_receiver_part (stream, bin, state); + play_udpsources_one_family (stream, G_SOCKET_FAMILY_IPV4); + play_udpsources_one_family (stream, G_SOCKET_FAMILY_IPV6); if (priv->srcpad) { /* be notified of caps changes */ From d10ba734cdc28293a952cc1cb22203d8b2d93c63 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Wed, 13 Jan 2016 11:29:35 +0100 Subject: [PATCH 1233/1776] rtsp-stream: postpone the creation of the UDP sources Code refactoring: allocate the UDP ports after the sender and the reciver parts have been created. We postpone the creation of the UDP sources until the UDP ports have been allocated. https://bugzilla.gnome.org/show_bug.cgi?id=757488 --- gst/rtsp-server/rtsp-stream.c | 79 +++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 15fca1918f..86e7ef2768 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1311,6 +1311,7 @@ again: if (!create_and_configure_udpsources_one_family (udpsrc_out, rtp_socket, rtcp_socket, family)) goto no_udp_protocol; + play_udpsources_one_family (stream, family); g_object_get (G_OBJECT (udpsrc_out[0]), "port", &rtpport, NULL); g_object_get (G_OBJECT (udpsrc_out[1]), "port", &rtcpport, NULL); @@ -1319,8 +1320,6 @@ again: if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) goto port_error; - if (!create_and_configure_udpsinks (stream)) - goto no_udp_protocol; /* set RTP and RTCP sockets */ set_sockets_for_udpsinks (stream, rtp_socket, rtcp_socket, family); @@ -2207,7 +2206,7 @@ on_npt_stop (GstElement * rtpbin, guint session, guint ssrc, } /* must be called with lock */ -static void +static gboolean create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) { @@ -2222,6 +2221,9 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); + if (is_udp && !create_and_configure_udpsinks (stream)) + goto no_udp_protocol; + for (i = 0; i < 2; i++) { GstPad *teepad, *queuepad; /* For the sender we create this bit of pipeline for both @@ -2343,6 +2345,14 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, gst_element_set_state (priv->tee[i], state); } } + + return TRUE; + + /* ERRORS */ +no_udp_protocol: + { + return FALSE; + } } /* must be called with lock */ @@ -2481,12 +2491,6 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, GST_INFO ("stream %p joining bin as session %u", stream, idx); - is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || - (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); - - if (is_udp && !alloc_ports (stream)) - goto no_ports; - if (priv->profiles & GST_RTSP_PROFILE_SAVP || priv->profiles & GST_RTSP_PROFILE_SAVPF) { /* For SRTP */ @@ -2562,11 +2566,16 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, g_signal_connect (priv->session, "on-sender-ssrc-active", (GCallback) on_sender_ssrc_active, stream); - create_sender_part (stream, bin, state); + if (!create_sender_part (stream, bin, state)) + goto no_udp_protocol; create_receiver_part (stream, bin, state); - play_udpsources_one_family (stream, G_SOCKET_FAMILY_IPV4); - play_udpsources_one_family (stream, G_SOCKET_FAMILY_IPV6); + + is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || + (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); + + if (is_udp && !alloc_ports (stream)) + goto no_udp_protocol; if (priv->srcpad) { /* be notified of caps changes */ @@ -2585,12 +2594,6 @@ was_joined: g_mutex_unlock (&priv->lock); return TRUE; } -no_ports: - { - g_mutex_unlock (&priv->lock); - GST_WARNING ("failed to allocate ports %u", idx); - return FALSE; - } link_failed: { GST_WARNING ("failed to link stream %u", idx); @@ -2599,6 +2602,46 @@ link_failed: g_mutex_unlock (&priv->lock); return FALSE; } +no_udp_protocol: + { + GST_WARNING ("failed to allocate ports %u", idx); + gst_object_unref (priv->send_rtp_sink); + priv->send_rtp_sink = NULL; + gst_object_unref (priv->send_src[0]); + priv->send_src[0] = NULL; + gst_object_unref (priv->send_src[1]); + priv->send_src[1] = NULL; + gst_object_unref (priv->recv_sink[0]); + priv->recv_sink[0] = NULL; + gst_object_unref (priv->recv_sink[1]); + priv->recv_sink[1] = NULL; + if (priv->udpsink[0]) + gst_element_set_state (priv->udpsink[0], GST_STATE_NULL); + if (priv->udpsink[1]) + gst_element_set_state (priv->udpsink[1], GST_STATE_NULL); + if (priv->udpsrc_v4[0]) { + gst_element_set_state (priv->udpsrc_v4[0], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_v4[0]); + priv->udpsrc_v4[0] = NULL; + } + if (priv->udpsrc_v4[1]) { + gst_element_set_state (priv->udpsrc_v4[1], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_v4[1]); + priv->udpsrc_v4[1] = NULL; + } + if (priv->udpsrc_v6[0]) { + gst_element_set_state (priv->udpsrc_v6[0], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_v6[0]); + priv->udpsrc_v6[0] = NULL; + } + if (priv->udpsrc_v6[1]) { + gst_element_set_state (priv->udpsrc_v6[1], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_v6[1]); + priv->udpsrc_v6[1] = NULL; + } + g_mutex_unlock (&priv->lock); + return FALSE; + } } /** From f62a9a7eb9fda096fb88c013d6787c28090037a2 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Tue, 23 Feb 2016 14:59:32 +0100 Subject: [PATCH 1234/1776] rtsp-stream: postpone UDP socket allocation until SETUP Postpone the allocation of the UDP sockets until we know what transport has been chosen by the client. Both unicast and multicast UDP sources are created in one function. https://bugzilla.gnome.org/show_bug.cgi?id=757488 --- gst/rtsp-server/rtsp-client.c | 26 ++- gst/rtsp-server/rtsp-stream.c | 337 +++++++++++++++++----------------- gst/rtsp-server/rtsp-stream.h | 3 + 3 files changed, 186 insertions(+), 180 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c7620a89ac..b27f52bca9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1403,26 +1403,26 @@ default_configure_client_transport (GstRTSPClient * client, /* we have a valid transport now, set the destination of the client. */ if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { gboolean use_client_settings; + GSocketFamily family; use_client_settings = gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS); if (ct->destination && use_client_settings) { - GstRTSPAddress *addr; + family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; - addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination, - ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl); + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, TRUE)) + goto no_udp_protocol; - if (addr == NULL) - goto no_address; - - gst_rtsp_address_free (addr); } else { GstRTSPAddress *addr; - GSocketFamily family; family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, FALSE)) + goto no_udp_protocol; + + gst_rtsp_stream_get_server_port (ctx->stream, &ct->port, family); addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family); if (addr == NULL) goto no_address; @@ -1475,6 +1475,11 @@ default_configure_client_transport (GstRTSPClient * client, gst_rtsp_session_media_alloc_channels (ctx->sessmedia, &ct->interleaved); } + } else if (ct->lower_transport & GST_RTSP_LOWER_TRANS_UDP) { + GSocketFamily family; + family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, FALSE)) + goto no_udp_protocol; } } return TRUE; @@ -1485,6 +1490,11 @@ no_address: GST_ERROR_OBJECT (client, "failed to acquire address for stream"); return FALSE; } +no_udp_protocol: + { + GST_ERROR_OBJECT (client, "failed to allocate udp ports"); + return FALSE; + } } static GstRTSPTransport * diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 86e7ef2768..cf2c88f6c5 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -62,15 +62,6 @@ #define GST_RTSP_STREAM_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_STREAM, GstRTSPStreamPrivate)) -typedef struct -{ - GstRTSPStreamTransport *transport; - - /* RTP and RTCP source */ - GstElement *udpsrc[2]; - GstPad *selpad[2]; -} GstRTSPMulticastTransportSource; - struct _GstRTSPStreamPrivate { GMutex lock; @@ -106,10 +97,14 @@ struct _GstRTSPStreamPrivate /* sinks used for sending and receiving RTP and RTCP over ipv4, they share * sockets */ GstElement *udpsrc_v4[2]; + /* UDP sources for UDP multicast transports */ + GstElement *udpsrc_mcast_v4[2]; /* sinks used for sending and receiving RTP and RTCP over ipv6, they share * sockets */ GstElement *udpsrc_v6[2]; + /* UDP sources for UDP multicast transports */ + GstElement *udpsrc_mcast_v6[2]; GstElement *udpqueue[2]; GstElement *udpsink[2]; @@ -142,6 +137,8 @@ struct _GstRTSPStreamPrivate GstRTSPAddressPool *pool; GstRTSPAddress *addr_v4; GstRTSPAddress *addr_v6; + gboolean have_ipv4_mcast; + gboolean have_ipv6_mcast; /* the caps of the stream */ gulong caps_sig; @@ -157,9 +154,6 @@ struct _GstRTSPStreamPrivate guint tr_cache_cookie_rtcp; - /* UDP sources for UDP multicast transports */ - GList *transport_sources; - gint dscp_qos; /* stream blocking */ @@ -1106,7 +1100,8 @@ no_udp_protocol: /* must be called with lock */ static void -play_udpsources_one_family (GstRTSPStream * stream, GSocketFamily family) +play_udpsources_one_family (GstRTSPStream * stream, GstElement * udpsrc_out[2], + GSocketFamily family) { GstRTSPStreamPrivate *priv; GstPad *pad, *selpad; @@ -1118,38 +1113,21 @@ play_udpsources_one_family (GstRTSPStream * stream, GSocketFamily family) for (i = 0; i < 2; i++) { if (priv->sinkpad || i == 1) { - if (family == G_SOCKET_FAMILY_IPV4 && priv->udpsrc_v4[i]) { - if (priv->srcpad) { - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values. This is only relevant for PLAY pipelines */ - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); - } - /* add udpsrc */ - gst_bin_add (bin, priv->udpsrc_v4[i]); - - /* and link to the funnel v4 */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); + if (priv->srcpad) { + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values. This is only relevant for PLAY pipelines */ + gst_element_set_state (udpsrc_out[i], GST_STATE_PLAYING); + gst_element_set_locked_state (udpsrc_out[i], TRUE); } + /* add udpsrc */ + gst_bin_add (bin, udpsrc_out[i]); - if (family == G_SOCKET_FAMILY_IPV6 && priv->udpsrc_v6[i]) { - if (priv->srcpad) { - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); - } - gst_bin_add (bin, priv->udpsrc_v6[i]); - - /* and link to the funnel v6 */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - } + /* and link to the funnel */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (udpsrc_out[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); } } @@ -1159,18 +1137,27 @@ play_udpsources_one_family (GstRTSPStream * stream, GSocketFamily family) /* must be called with lock */ static gboolean create_and_configure_udpsources_one_family (GstElement * udpsrc_out[2], - GSocket * rtp_socket, GSocket * rtcp_socket, GSocketFamily family) + GSocket * rtp_socket, GSocket * rtcp_socket, GSocketFamily family, + const gchar * address, gint rtpport, gint rtcpport, + GstRTSPLowerTrans transport) { GstStateChangeReturn ret; - /* we keep these elements, we will further configure them when the - * client told us to really use the UDP ports. */ udpsrc_out[0] = gst_element_factory_make ("udpsrc", NULL); udpsrc_out[1] = gst_element_factory_make ("udpsrc", NULL); if (udpsrc_out[0] == NULL || udpsrc_out[1] == NULL) goto error; + if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + g_object_set (G_OBJECT (udpsrc_out[0]), "address", address, NULL); + g_object_set (G_OBJECT (udpsrc_out[1]), "address", address, NULL); + g_object_set (G_OBJECT (udpsrc_out[0]), "port", rtpport, NULL); + g_object_set (G_OBJECT (udpsrc_out[1]), "port", rtcpport, NULL); + g_object_set (G_OBJECT (udpsrc_out[0]), "loop", FALSE, NULL); + g_object_set (G_OBJECT (udpsrc_out[1]), "loop", FALSE, NULL); + } + g_object_set (G_OBJECT (udpsrc_out[0]), "socket", rtp_socket, NULL); g_object_set (G_OBJECT (udpsrc_out[1]), "socket", rtcp_socket, NULL); @@ -1198,7 +1185,8 @@ error: static gboolean alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GstElement * udpsrc_out[2], GstRTSPRange * server_port_out, - GstRTSPAddress ** server_addr_out) + GstRTSPTransport *ct, GstRTSPAddress ** server_addr_out, + gboolean use_client_settings) { GstRTSPStreamPrivate *priv = stream->priv; GSocket *rtp_socket = NULL; @@ -1209,12 +1197,15 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GList *rejected_addresses = NULL; GstRTSPAddress *addr = NULL; GInetAddress *inetaddr = NULL; + gchar *addr_str; GSocketAddress *rtp_sockaddr = NULL; GSocketAddress *rtcp_sockaddr = NULL; GstRTSPAddressPool * pool; + GstRTSPLowerTrans transport; pool = priv->pool; count = 0; + transport = ct->lower_transport; /* Start with random port */ tmp_rtp = 0; @@ -1238,19 +1229,30 @@ again: goto no_udp_protocol; } - if (pool && gst_rtsp_address_pool_has_unicast_addresses (pool)) { + if (pool) { GstRTSPAddressFlags flags; + if (transport == GST_RTSP_LOWER_TRANS_UDP && + gst_rtsp_address_pool_has_unicast_addresses (pool)) + flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_UNICAST; + else if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) + flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST; + else + goto no_ports; + if (addr) rejected_addresses = g_list_prepend (rejected_addresses, addr); - flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_UNICAST; if (family == G_SOCKET_FAMILY_IPV6) flags |= GST_RTSP_ADDRESS_FLAG_IPV6; else flags |= GST_RTSP_ADDRESS_FLAG_IPV4; - addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); + if (ct->destination && transport == GST_RTSP_LOWER_TRANS_UDP_MCAST && use_client_settings) + gst_rtsp_address_pool_reserve_address (pool, ct->destination, + ct->port.min, 2, ct->ttl, &addr); + else + addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); if (addr == NULL) goto no_ports; @@ -1306,12 +1308,23 @@ again: } g_object_unref (rtcp_sockaddr); + if (addr == NULL) + addr_str = g_inet_address_to_string (inetaddr); + else + addr_str = addr->address; g_clear_object (&inetaddr); if (!create_and_configure_udpsources_one_family (udpsrc_out, rtp_socket, - rtcp_socket, family)) + rtcp_socket, family, addr_str, tmp_rtp, tmp_rtcp, transport)) { + if (addr == NULL) + g_free (addr_str); goto no_udp_protocol; - play_udpsources_one_family (stream, family); + } + + if (addr == NULL) + g_free (addr_str); + + play_udpsources_one_family (stream, udpsrc_out, family); g_object_get (G_OBJECT (udpsrc_out[0]), "port", &rtpport, NULL); g_object_get (G_OBJECT (udpsrc_out[1]), "port", &rtcpport, NULL); @@ -1320,7 +1333,6 @@ again: if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) goto port_error; - /* set RTP and RTCP sockets */ set_sockets_for_udpsinks (stream, rtp_socket, rtcp_socket, family); @@ -1368,21 +1380,65 @@ cleanup: } } -/* must be called with lock */ -static gboolean -alloc_ports (GstRTSPStream * stream) +/** + * gst_rtsp_stream_allocate_udp_sockets: + * @stream: a #GstRTSPStream + * @family: protocol family + * @transport_method: transport method + * + * Allocates RTP and RTCP ports. + * + * Returns: %TRUE if the RTP and RTCP sockets have been succeccully allocated. + */ +gboolean +gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, + GSocketFamily family, GstRTSPTransport *ct, gboolean use_client_settings) { - GstRTSPStreamPrivate *priv = stream->priv; + GstRTSPStreamPrivate *priv; + gboolean result = FALSE; + GstRTSPLowerTrans transport = ct->lower_transport; - priv->have_ipv4 = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, - &priv->server_port_v4, &priv->server_addr_v4); + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + priv = stream->priv; + g_return_val_if_fail (priv->is_joined, FALSE); - priv->have_ipv6 = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, - &priv->server_port_v6, &priv->server_addr_v6); + g_mutex_lock (&priv->lock); - return priv->have_ipv4 || priv->have_ipv6; + if (family == G_SOCKET_FAMILY_IPV4) { + if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + if (priv->have_ipv4_mcast) + goto done; + priv->have_ipv4_mcast = + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_mcast_v4, + &priv->server_port_v4, ct, &priv->addr_v4, use_client_settings); + } else { + priv->have_ipv4 = + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, + &priv->server_port_v4, ct, &priv->server_addr_v4, use_client_settings); + } + } else { + if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + if (priv->have_ipv6_mcast) + goto done; + priv->have_ipv6_mcast = + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, priv->udpsrc_mcast_v6, + &priv->server_port_v6, ct, &priv->addr_v6, use_client_settings); + } else { + if (priv->have_ipv6) + goto done; + priv->have_ipv6 = + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, + &priv->server_port_v6, ct, &priv->server_addr_v6, use_client_settings); + } + } + +done: + result = priv->have_ipv4 || priv->have_ipv4_mcast || priv->have_ipv6 || + priv->have_ipv6_mcast; + + g_mutex_unlock (&priv->lock); + + return result; } /** @@ -2474,7 +2530,6 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, guint idx; gchar *name; GstPadLinkReturn ret; - gboolean is_udp; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); g_return_val_if_fail (GST_IS_BIN (bin), FALSE); @@ -2571,12 +2626,6 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, create_receiver_part (stream, bin, state); - is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || - (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); - - if (is_udp && !alloc_ports (stream)) - goto no_udp_protocol; - if (priv->srcpad) { /* be notified of caps changes */ priv->caps_sig = g_signal_connect (priv->send_src[0], "notify::caps", @@ -2629,6 +2678,16 @@ no_udp_protocol: gst_object_unref (priv->udpsrc_v4[1]); priv->udpsrc_v4[1] = NULL; } + if (priv->udpsrc_mcast_v4[0]) { + gst_element_set_state (priv->udpsrc_mcast_v4[0], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_mcast_v4[0]); + priv->udpsrc_mcast_v4[0] = NULL; + } + if (priv->udpsrc_mcast_v4[1]) { + gst_element_set_state (priv->udpsrc_mcast_v4[1], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_mcast_v4[1]); + priv->udpsrc_mcast_v4[1] = NULL; + } if (priv->udpsrc_v6[0]) { gst_element_set_state (priv->udpsrc_v6[0], GST_STATE_NULL); gst_object_unref (priv->udpsrc_v6[0]); @@ -2639,6 +2698,16 @@ no_udp_protocol: gst_object_unref (priv->udpsrc_v6[1]); priv->udpsrc_v6[1] = NULL; } + if (priv->udpsrc_mcast_v6[0]) { + gst_element_set_state (priv->udpsrc_mcast_v6[0], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_mcast_v6[0]); + priv->udpsrc_mcast_v6[0] = NULL; + } + if (priv->udpsrc_mcast_v6[1]) { + gst_element_set_state (priv->udpsrc_mcast_v6[1], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_mcast_v6[1]); + priv->udpsrc_mcast_v6[1] = NULL; + } g_mutex_unlock (&priv->lock); return FALSE; } @@ -2660,7 +2729,6 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, { GstRTSPStreamPrivate *priv; gint i; - GList *l; gboolean is_tcp, is_udp; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); @@ -2732,6 +2800,20 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, } } + if (priv->udpsrc_mcast_v4[i]) { + if (priv->sinkpad || i == 1) { + /* and set udpsrc to NULL now before removing */ + gst_element_set_locked_state (priv->udpsrc_mcast_v4[i], FALSE); + gst_element_set_state (priv->udpsrc_mcast_v4[i], GST_STATE_NULL); + /* removing them should also nicely release the request + * pads when they finalize */ + gst_bin_remove (bin, priv->udpsrc_mcast_v4[i]); + } else { + gst_element_set_state (priv->udpsrc_mcast_v4[i], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_mcast_v4[i]); + } + } + if (priv->udpsrc_v6[i]) { if (priv->sinkpad || i == 1) { gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE); @@ -2742,16 +2824,15 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_object_unref (priv->udpsrc_v6[i]); } } - - for (l = priv->transport_sources; l; l = l->next) { - GstRTSPMulticastTransportSource *s = l->data; - - if (!s->udpsrc[i]) - continue; - - gst_element_set_locked_state (s->udpsrc[i], FALSE); - gst_element_set_state (s->udpsrc[i], GST_STATE_NULL); - gst_bin_remove (bin, s->udpsrc[i]); + if (priv->udpsrc_mcast_v6[i]) { + if (priv->sinkpad || i == 1) { + gst_element_set_locked_state (priv->udpsrc_mcast_v6[i], FALSE); + gst_element_set_state (priv->udpsrc_mcast_v6[i], GST_STATE_NULL); + gst_bin_remove (bin, priv->udpsrc_mcast_v6[i]); + } else { + gst_element_set_state (priv->udpsrc_mcast_v6[i], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_mcast_v6[i]); + } } if (priv->udpsink[i] && is_udp && (priv->srcpad || i == 1)) @@ -2777,6 +2858,8 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->udpsrc_v4[i] = NULL; priv->udpsrc_v6[i] = NULL; + priv->udpsrc_mcast_v4[i] = NULL; + priv->udpsrc_mcast_v6[i] = NULL; priv->udpsink[i] = NULL; priv->appsrc[i] = NULL; priv->appsink[i] = NULL; @@ -2786,13 +2869,6 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->funnel[i] = NULL; } - for (l = priv->transport_sources; l; l = l->next) { - GstRTSPMulticastTransportSource *s = l->data; - g_slice_free (GstRTSPMulticastTransportSource, s); - } - g_list_free (priv->transport_sources); - priv->transport_sources = NULL; - if (priv->srcpad) { gst_object_unref (priv->send_src[0]); priv->send_src[0] = NULL; @@ -3139,89 +3215,6 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, switch (tr->lower_transport) { case GST_RTSP_LOWER_TRANS_UDP_MCAST: - { - GstRTSPMulticastTransportSource *source; - GstBin *bin; - - bin = GST_BIN (gst_object_get_parent (GST_OBJECT (priv->funnel[1]))); - - if (add) { - gchar *host; - gint i; - GstPad *selpad, *pad; - - source = g_slice_new0 (GstRTSPMulticastTransportSource); - source->transport = trans; - - for (i = 0; i < 2; i++) { - host = - g_strdup_printf ("udp://%s:%d", tr->destination, - (i == 0) ? tr->port.min : tr->port.max); - source->udpsrc[i] = - gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); - g_free (host); - g_object_set (source->udpsrc[i], "loop", FALSE, NULL); - - if (priv->srcpad) { - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values. This is only relevant for PLAY pipelines */ - gst_element_set_state (source->udpsrc[i], GST_STATE_PLAYING); - gst_element_set_locked_state (source->udpsrc[i], TRUE); - } - /* add udpsrc */ - gst_bin_add (bin, source->udpsrc[i]); - - /* and link to the funnel v4 */ - if (priv->sinkpad || i == 1) { - source->selpad[i] = selpad = - gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (source->udpsrc[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - } - } - - priv->transport_sources = - g_list_prepend (priv->transport_sources, source); - } else { - GList *l; - - for (l = priv->transport_sources; l; l = l->next) { - source = l->data; - - if (source->transport == trans) { - priv->transport_sources = - g_list_delete_link (priv->transport_sources, l); - break; - } - } - - if (l != NULL) { - gint i; - - for (i = 0; i < 2; i++) { - /* Will automatically unlink everything */ - gst_bin_remove (bin, - GST_ELEMENT (gst_object_ref (source->udpsrc[i]))); - - gst_element_set_state (source->udpsrc[i], GST_STATE_NULL); - gst_object_unref (source->udpsrc[i]); - - if (priv->sinkpad || i == 1) { - gst_element_release_request_pad (priv->funnel[i], - source->selpad[i]); - } - } - - g_slice_free (GstRTSPMulticastTransportSource, source); - } - } - - gst_object_unref (bin); - - /* fall through for the generic case */ - } case GST_RTSP_LOWER_TRANS_UDP: { gchar *dest; diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index bd1d7e50fb..46304ac817 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -168,6 +168,9 @@ guint gst_rtsp_stream_get_buffer_size (GstRTSPStream *stream); void gst_rtsp_stream_set_pt_map (GstRTSPStream * stream, guint pt, GstCaps * caps); GstElement * gst_rtsp_stream_request_aux_sender (GstRTSPStream * stream, guint sessid); + +gboolean gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, GSocketFamily family, + GstRTSPTransport *transport, gboolean use_client_setttings); /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object From a6367c59711cbf8811e0f4e170ca1c2ee8abf974 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Tue, 23 Feb 2016 15:01:22 +0100 Subject: [PATCH 1235/1776] tests: unit test fixes Removed port allocation test from the media suite. The port allocation failure is now in the stream suite. rtspserver: Make sure that the media is suspended after the DESCRIBE request before reconfiguring the UDP sinks. rtspclientsink: In the RECORD case we have to set async property to false for the appsink element in the test in order to make sure that the media pipeline doesn't hang in start_preroll(). https://bugzilla.gnome.org/show_bug.cgi?id=757488 --- tests/check/gst/media.c | 40 -------------------- tests/check/gst/rtspclientsink.c | 2 +- tests/check/gst/rtspserver.c | 7 +++- tests/check/gst/stream.c | 65 ++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 42 deletions(-) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index c8cdf30b46..b0ddb19967 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -298,45 +298,6 @@ GST_START_TEST (test_media_dyn_prepare) GST_END_TEST; -GST_START_TEST (test_media_prepare_port_alloc_fail) -{ - GstRTSPMediaFactory *factory; - GstRTSPMedia *media; - GstRTSPUrl *url; - GstRTSPThreadPool *pool; - GstRTSPThread *thread; - GstRTSPAddressPool *addrpool; - - pool = gst_rtsp_thread_pool_new (); - - factory = gst_rtsp_media_factory_new (); - fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", - &url) == GST_RTSP_OK); - - gst_rtsp_media_factory_set_launch (factory, - "( fakesrc is-live=true ! text/plain ! rtpgstpay name=pay0 )"); - - media = gst_rtsp_media_factory_construct (factory, url); - fail_unless (GST_IS_RTSP_MEDIA (media)); - - addrpool = gst_rtsp_address_pool_new (); - fail_unless (gst_rtsp_address_pool_add_range (addrpool, "192.168.1.1", - "192.168.1.1", 6000, 6001, 0)); - gst_rtsp_media_set_address_pool (media, addrpool); - - thread = gst_rtsp_thread_pool_get_thread (pool, - GST_RTSP_THREAD_TYPE_MEDIA, NULL); - fail_if (gst_rtsp_media_prepare (media, thread)); - - g_object_unref (media); - g_object_unref (addrpool); - gst_rtsp_url_free (url); - g_object_unref (factory); - g_object_unref (pool); -} - -GST_END_TEST; - GST_START_TEST (test_media_take_pipeline) { GstRTSPMediaFactory *factory; @@ -497,7 +458,6 @@ rtspmedia_suite (void) tcase_add_test (tc, test_media); tcase_add_test (tc, test_media_prepare); tcase_add_test (tc, test_media_dyn_prepare); - tcase_add_test (tc, test_media_prepare_port_alloc_fail); tcase_add_test (tc, test_media_take_pipeline); tcase_add_test (tc, test_media_reset); tcase_add_test (tc, test_media_multidyn_prepare); diff --git a/tests/check/gst/rtspclientsink.c b/tests/check/gst/rtspclientsink.c index 584422bb43..dd7f90f154 100644 --- a/tests/check/gst/rtspclientsink.c +++ b/tests/check/gst/rtspclientsink.c @@ -155,7 +155,7 @@ GST_START_TEST (test_record) gint i; mfactory = - start_record_server ("( rtppcmadepay name=depay0 ! appsink name=sink )"); + start_record_server ("( rtppcmadepay name=depay0 ! appsink name=sink async=false )"); g_signal_connect (mfactory, "media-constructed", G_CALLBACK (media_constructed_cb), &server_sink); diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index ec66f99f70..d21bf040db 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -169,6 +169,8 @@ start_server (void) pool = gst_rtsp_address_pool_new (); gst_rtsp_address_pool_add_range (pool, "224.3.0.0", "224.3.0.10", 5000, 5010, 16); + gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV4, + GST_RTSP_ADDRESS_POOL_ANY_IPV4, 6000, 6010, 0); gst_rtsp_media_factory_set_address_pool (factory, pool); gst_object_unref (pool); @@ -1511,6 +1513,9 @@ GST_START_TEST (test_play_specific_server_port) mounts = gst_rtsp_server_get_mount_points (server); factory = gst_rtsp_media_factory_new (); + /* we have to suspend media after SDP in order to make sure that + * we can reconfigure UDP sink with new UDP ports */ + gst_rtsp_media_factory_set_suspend_mode (factory, GST_RTSP_SUSPEND_MODE_RESET); pool = gst_rtsp_address_pool_new (); gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV4, GST_RTSP_ADDRESS_POOL_ANY_IPV4, 7770, 7780, 0); @@ -1744,7 +1749,7 @@ GST_START_TEST (test_record_tcp) gint i; mfactory = - start_record_server ("( rtppcmadepay name=depay0 ! appsink name=sink )"); + start_record_server ("( rtppcmadepay name=depay0 ! appsink name=sink async=false )"); g_signal_connect (mfactory, "media-constructed", G_CALLBACK (media_constructed_cb), &server_sink); diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index 582e67408f..26353b1f36 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -29,9 +29,11 @@ GST_START_TEST (test_get_sockets) GstRTSPStream *stream; GstBin *bin; GstElement *rtpbin; + GstRTSPAddressPool *pool; GSocket *socket; gboolean have_ipv4; gboolean have_ipv6; + GstRTSPTransport *tr; srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); fail_unless (srcpad != NULL); @@ -48,8 +50,21 @@ GST_START_TEST (test_get_sockets) fail_unless (bin != NULL); fail_unless (gst_bin_add (bin, rtpbin)); + /* configure address pool for IPv4 and IPv6 unicast addresses */ + pool = gst_rtsp_address_pool_new (); + fail_unless (gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV4, + GST_RTSP_ADDRESS_POOL_ANY_IPV4, 50000, 60000, 0)); + fail_unless (gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV6, + GST_RTSP_ADDRESS_POOL_ANY_IPV6, 50000, 60000, 0)); + gst_rtsp_stream_set_address_pool (stream, pool); + fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + gst_rtsp_transport_new (&tr); + tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP; + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, + tr, FALSE)); + socket = gst_rtsp_stream_get_rtp_socket (stream, G_SOCKET_FAMILY_IPV4); have_ipv4 = (socket != NULL); if (have_ipv4) { @@ -85,6 +100,9 @@ GST_START_TEST (test_get_sockets) /* check that at least one family is available */ fail_unless (have_ipv4 || have_ipv6); + gst_rtsp_transport_free (tr); + g_object_unref (pool); + fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); gst_object_unref (bin); @@ -93,6 +111,52 @@ GST_START_TEST (test_get_sockets) GST_END_TEST; +GST_START_TEST (test_allocate_udp_ports_fail) +{ + GstPad *srcpad; + GstElement *pay; + GstRTSPStream *stream; + GstBin *bin; + GstElement *rtpbin; + GstRTSPAddressPool *pool; + GstRTSPTransport *tr; + + srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); + fail_unless (srcpad != NULL); + gst_pad_set_active (srcpad, TRUE); + pay = gst_element_factory_make ("rtpgstpay", "testpayloader"); + fail_unless (pay != NULL); + stream = gst_rtsp_stream_new (0, pay, srcpad); + fail_unless (stream != NULL); + gst_object_unref (pay); + gst_object_unref (srcpad); + rtpbin = gst_element_factory_make ("rtpbin", "testrtpbin"); + fail_unless (rtpbin != NULL); + bin = GST_BIN (gst_bin_new ("testbin")); + fail_unless (bin != NULL); + fail_unless (gst_bin_add (bin, rtpbin)); + + pool = gst_rtsp_address_pool_new (); + fail_unless (gst_rtsp_address_pool_add_range (pool, "192.168.1.1", + "192.168.1.1", 6000, 6001, 0)); + gst_rtsp_stream_set_address_pool (stream, pool); + + fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + + gst_rtsp_transport_new (&tr); + tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP; + fail_if (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, + tr, FALSE)); + + gst_rtsp_transport_free (tr); + g_object_unref (pool); + fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); + gst_object_unref (bin); + gst_object_unref (stream); +} + +GST_END_TEST; + GST_START_TEST (test_get_multicast_address) { GstPad *srcpad; @@ -164,6 +228,7 @@ rtspstream_suite (void) suite_add_tcase (s, tc); tcase_add_test (tc, test_get_sockets); + tcase_add_test (tc, test_allocate_udp_ports_fail); tcase_add_test (tc, test_get_multicast_address); return s; From b96e4e16a74ff51dfa58994173c45c1906c92b77 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Wed, 24 Feb 2016 00:10:52 +1100 Subject: [PATCH 1236/1776] rtspsink: Fix some leaks in rtspclientsink and the unit test. https://bugzilla.gnome.org/show_bug.cgi?id=762525 --- gst/rtsp-sink/gstrtspclientsink.c | 3 +++ tests/check/gst/rtspclientsink.c | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index e7706a4b50..aeb8342fbd 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -1047,6 +1047,8 @@ gst_rtsp_client_sink_sinkpad_event (GstPad * pad, GstObject * parent, gst_event_unref (event); return FALSE; } + } else { + gst_object_unref (target); } } @@ -1071,6 +1073,7 @@ gst_rtsp_client_sink_sinkpad_query (GstPad * pad, GstObject * parent, return TRUE; } + gst_object_unref (target); } return gst_pad_query_default (pad, parent, query); diff --git a/tests/check/gst/rtspclientsink.c b/tests/check/gst/rtspclientsink.c index dd7f90f154..83c40e9cdd 100644 --- a/tests/check/gst/rtspclientsink.c +++ b/tests/check/gst/rtspclientsink.c @@ -163,13 +163,17 @@ GST_START_TEST (test_record) /* Create an rtspclientsink and send some data */ { gchar *uri = get_server_uri (test_port, TEST_MOUNT_POINT); - gchar *pipe_str = g_strdup_printf (AUDIO_PIPELINE, - RECORD_N_BUFS, uri); + gchar *pipe_str; GstMessage *msg; GstElement *pipeline; GstBus *bus; + pipe_str = g_strdup_printf (AUDIO_PIPELINE, RECORD_N_BUFS, uri); + g_free (uri); + pipeline = gst_parse_launch (pipe_str, NULL); + g_free (pipe_str); + fail_unless (pipeline != NULL); bus = gst_element_get_bus (pipeline); From 0eb3ea03d3d8af9158cb30a8cfc2569d4e0a4e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 26 Feb 2016 12:42:51 +0200 Subject: [PATCH 1237/1776] Automatic update of common submodule From b64f03f to 6f2d209 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index b64f03f609..6f2d2093e8 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit b64f03f6090245624608beb5d2fff335e23a01c0 +Subproject commit 6f2d2093e84cc0eb99b634fa281822ebb9507285 From ca1d987a9ded0ec7530b0bafd877520e6b3d0640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 1 Mar 2016 19:00:45 +0200 Subject: [PATCH 1238/1776] Release 1.7.90 --- ChangeLog | 113 +++++++++++++++++++++++++++++++++++++++++-- NEWS | 2 +- RELEASE | 27 +++-------- configure.ac | 12 ++--- gst-rtsp-server.doap | 10 ++++ 5 files changed, 135 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index dfd82d0844..97df09bded 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,116 @@ -=== release 1.7.2 === +=== release 1.7.90 === -2016-02-19 Sebastian Dröge +2016-03-01 Sebastian Dröge * configure.ac: - releasing 1.7.2 + releasing 1.7.90 + +2016-02-26 12:42:51 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From b64f03f to 6f2d209 + +2016-02-24 00:10:52 +1100 Jan Schmidt + + * gst/rtsp-sink/gstrtspclientsink.c: + * tests/check/gst/rtspclientsink.c: + rtspsink: Fix some leaks in rtspclientsink and the unit test. + https://bugzilla.gnome.org/show_bug.cgi?id=762525 + +2016-02-23 15:01:22 +0100 Patricia Muscalu + + * tests/check/gst/media.c: + * tests/check/gst/rtspclientsink.c: + * tests/check/gst/rtspserver.c: + * tests/check/gst/stream.c: + tests: unit test fixes + Removed port allocation test from the media suite. + The port allocation failure is now in the stream suite. + rtspserver: + Make sure that the media is suspended after the DESCRIBE request + before reconfiguring the UDP sinks. + rtspclientsink: + In the RECORD case we have to set async property to false + for the appsink element in the test in order to make sure + that the media pipeline doesn't hang in start_preroll(). + https://bugzilla.gnome.org/show_bug.cgi?id=757488 + +2016-02-23 14:59:32 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-stream: postpone UDP socket allocation until SETUP + Postpone the allocation of the UDP sockets until we know + what transport has been chosen by the client. + Both unicast and multicast UDP sources are created in one + function. + https://bugzilla.gnome.org/show_bug.cgi?id=757488 + +2016-01-13 11:29:35 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: postpone the creation of the UDP sources + Code refactoring: allocate the UDP ports after the sender and + the reciver parts have been created. + We postpone the creation of the UDP sources until the UDP + ports have been allocated. + https://bugzilla.gnome.org/show_bug.cgi?id=757488 + +2016-01-13 10:55:40 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: added function for setting UDP sources to PLAYING state + Code refactoring: Introduced a function for setting UDP sources + to PLAYING state. + https://bugzilla.gnome.org/show_bug.cgi?id=757488 + +2015-11-20 15:34:43 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: added function for creating and configuring UDP sources + Code refactoring: create and configure UDP sources in a separate function. + https://bugzilla.gnome.org/show_bug.cgi?id=757488 + +2015-11-20 14:43:38 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: added function for RTP/RTCP socket configuration + Code refactoring: configure RTP and RTCP sockets for UDP sinks + in a separate function. + https://bugzilla.gnome.org/show_bug.cgi?id=757488 + +2015-11-20 08:38:42 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: added function for creating and configuring UDP sinks + Code refactoring: create and configure UDP sinks in a separate function. + https://bugzilla.gnome.org/show_bug.cgi?id=757488 + +2015-11-19 14:09:25 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: added helper function for creating the sender/receiver parts + Code refactoring: introduced helper function for creating + the receiver and the sender parts of the streaming pipeline. + https://bugzilla.gnome.org/show_bug.cgi?id=757488 + +2016-02-19 12:38:42 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.7.2 === + +2016-02-19 12:03:18 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.7.2 2016-02-18 15:20:05 +0000 Julien Isorce diff --git a/NEWS b/NEWS index a4a5e76ce2..8f11fc4c19 100644 --- a/NEWS +++ b/NEWS @@ -1,2 +1,2 @@ -This is GStreamer 1.7.2 +This is GStreamer 1.7.90 diff --git a/RELEASE b/RELEASE index 37b4315bc9..6aa933c6e1 100644 --- a/RELEASE +++ b/RELEASE @@ -1,25 +1,21 @@ -Release notes for GStreamer RTSP Server Library 1.7.2 +Release notes for GStreamer RTSP Server Library 1.7.90 -The GStreamer team is pleased to announce the second release of the unstable -1.7 release series. The 1.7 release series is adding new features on top of +The GStreamer team is pleased to announce the first release candidate of the stable +1.8 release series. The 1.8 release series is adding new features on top of the 1.0, 1.2, 1.4 and 1.6 series and is part of the API and ABI-stable 1.x release -series of the GStreamer multimedia framework. The unstable 1.7 release series -will lead to the stable 1.8 release series in the next weeks. Any newly added -API can still change until that point. +series of the GStreamer multimedia framework. Binaries for Android, iOS, Mac OS X and Windows will be provided separately -during the unstable 1.7 release series. +during the stable 1.8 release series. Bugs fixed in this release - * 758180 : Add rtspclientsink plugin - * 758999 : rtsp-media: Add property to decide if sending media should be stopped when a client disconnects without TEARDOWN - * 759773 : Prevent simultaneous prepare/unprepare of RTSP media - * 760150 : Updating transport for multicast case gives assertion + * 757488 : gst-rtsp-server: multicast functionality is broken if using the same port ranges for multicast and unicast + * 762525 : rtspclientsink test: Memory leaks ==== Download ==== @@ -56,14 +52,7 @@ subscribe to the gstreamer-devel list. Contributors to this release - * Hyunjun Ko * Jan Schmidt - * Julien Isorce - * Luis de Bethencourt + * Patricia Muscalu * Sebastian Dröge - * Sebastian Rasmussen - * Srimanta Panda - * Steven Hoving - * Thiago Santos - * Tim-Philipp Müller   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 7f57cfae41..1261bc3e60 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.7.2.1], +AC_INIT([GStreamer RTSP Server Library], [1.7.90], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 702, 0, 702) +AS_LIBTOOL(GST, 790, 0, 790) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.7.2.1 -GSTPB_REQ=1.7.2.1 -GSTPG_REQ=1.7.2.1 -GSTPD_REQ=1.7.2.1 +GST_REQ=1.7.90 +GSTPB_REQ=1.7.90 +GSTPG_REQ=1.7.90 +GSTPD_REQ=1.7.90 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index eae21a208a..52eb47dfe2 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.7.90 + master + + 2016-03-01 + + + + 1.7.2 From bcee3202d3a6c8749d9a0c7158096d7009f8e337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 2 Mar 2016 11:47:47 +0200 Subject: [PATCH 1239/1776] rtsp-stream: Don't bind the sockets to multicast addresses This works on Linux but fails completely on Windows. You're supposed to bind to ANY and then join the multicast group. https://bugzilla.gnome.org/show_bug.cgi?id=757488 --- gst/rtsp-server/rtsp-stream.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index cf2c88f6c5..8cbedc36e0 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1261,6 +1261,15 @@ again: g_clear_object (&inetaddr); inetaddr = g_inet_address_new_from_string (addr->address); + + /* Don't bind to multicast addresses, this does not work on + * Windows. You're supposed to bind to ANY and then join the + * multicast group, which udpsrc/sink does for us already. + */ + if (g_inet_address_get_is_multicast (inetaddr)) { + g_object_unref (inetaddr); + inetaddr = g_inet_address_new_any (family); + } } else { if (tmp_rtp != 0) { tmp_rtp += 2; From 406ed190acdba2007f42cc12d30ce4029cd1c3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 2 Mar 2016 11:48:49 +0200 Subject: [PATCH 1240/1776] rtsp-server: Fix indentation --- gst/rtsp-server/rtsp-client.c | 6 ++++-- gst/rtsp-server/rtsp-stream.c | 39 +++++++++++++++++++---------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b27f52bca9..7258d77569 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1419,7 +1419,8 @@ default_configure_client_transport (GstRTSPClient * client, family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; - if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, FALSE)) + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, + FALSE)) goto no_udp_protocol; gst_rtsp_stream_get_server_port (ctx->stream, &ct->port, family); @@ -1478,7 +1479,8 @@ default_configure_client_transport (GstRTSPClient * client, } else if (ct->lower_transport & GST_RTSP_LOWER_TRANS_UDP) { GSocketFamily family; family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; - if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, FALSE)) + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, + FALSE)) goto no_udp_protocol; } } diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 8cbedc36e0..70abb992b8 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1185,7 +1185,7 @@ error: static gboolean alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GstElement * udpsrc_out[2], GstRTSPRange * server_port_out, - GstRTSPTransport *ct, GstRTSPAddress ** server_addr_out, + GstRTSPTransport * ct, GstRTSPAddress ** server_addr_out, gboolean use_client_settings) { GstRTSPStreamPrivate *priv = stream->priv; @@ -1200,7 +1200,7 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, gchar *addr_str; GSocketAddress *rtp_sockaddr = NULL; GSocketAddress *rtcp_sockaddr = NULL; - GstRTSPAddressPool * pool; + GstRTSPAddressPool *pool; GstRTSPLowerTrans transport; pool = priv->pool; @@ -1248,7 +1248,8 @@ again: else flags |= GST_RTSP_ADDRESS_FLAG_IPV4; - if (ct->destination && transport == GST_RTSP_LOWER_TRANS_UDP_MCAST && use_client_settings) + if (ct->destination && transport == GST_RTSP_LOWER_TRANS_UDP_MCAST + && use_client_settings) gst_rtsp_address_pool_reserve_address (pool, ct->destination, ct->port.min, 2, ct->ttl, &addr); else @@ -1324,7 +1325,7 @@ again: g_clear_object (&inetaddr); if (!create_and_configure_udpsources_one_family (udpsrc_out, rtp_socket, - rtcp_socket, family, addr_str, tmp_rtp, tmp_rtcp, transport)) { + rtcp_socket, family, addr_str, tmp_rtp, tmp_rtcp, transport)) { if (addr == NULL) g_free (addr_str); goto no_udp_protocol; @@ -1401,7 +1402,7 @@ cleanup: */ gboolean gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, - GSocketFamily family, GstRTSPTransport *ct, gboolean use_client_settings) + GSocketFamily family, GstRTSPTransport * ct, gboolean use_client_settings) { GstRTSPStreamPrivate *priv; gboolean result = FALSE; @@ -1418,32 +1419,36 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, if (priv->have_ipv4_mcast) goto done; priv->have_ipv4_mcast = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_mcast_v4, - &priv->server_port_v4, ct, &priv->addr_v4, use_client_settings); + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, + priv->udpsrc_mcast_v4, &priv->server_port_v4, ct, &priv->addr_v4, + use_client_settings); } else { priv->have_ipv4 = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, - &priv->server_port_v4, ct, &priv->server_addr_v4, use_client_settings); + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, + &priv->server_port_v4, ct, &priv->server_addr_v4, + use_client_settings); } } else { if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { if (priv->have_ipv6_mcast) goto done; priv->have_ipv6_mcast = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, priv->udpsrc_mcast_v6, - &priv->server_port_v6, ct, &priv->addr_v6, use_client_settings); + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, + priv->udpsrc_mcast_v6, &priv->server_port_v6, ct, &priv->addr_v6, + use_client_settings); } else { if (priv->have_ipv6) goto done; priv->have_ipv6 = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, - &priv->server_port_v6, ct, &priv->server_addr_v6, use_client_settings); + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, + &priv->server_port_v6, ct, &priv->server_addr_v6, + use_client_settings); } } done: result = priv->have_ipv4 || priv->have_ipv4_mcast || priv->have_ipv6 || - priv->have_ipv6_mcast; + priv->have_ipv6_mcast; g_mutex_unlock (&priv->lock); @@ -2272,8 +2277,7 @@ on_npt_stop (GstElement * rtpbin, guint session, guint ssrc, /* must be called with lock */ static gboolean -create_sender_part (GstRTSPStream * stream, GstBin * bin, - GstState state) +create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) { GstRTSPStreamPrivate *priv; GstPad *pad, *sinkpad = NULL; @@ -2422,8 +2426,7 @@ no_udp_protocol: /* must be called with lock */ static void -create_receiver_part (GstRTSPStream * stream, GstBin * bin, - GstState state) +create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) { GstRTSPStreamPrivate *priv; GstPad *pad, *selpad; From a7ced98346c6d49c4569d1b609a773a042c46796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 3 Mar 2016 10:41:51 +0200 Subject: [PATCH 1241/1776] rtsp-stream: Only use the address pool for unicast UDP if it contains unicast addresses Otherwise we fail to allocate UDP ports if the pool only contains multicast addresses, which is something that used to work before. For unicast addresses if the pool contains none, we just allocate them as if there is no pool at all. https://bugzilla.gnome.org/show_bug.cgi?id=757488 --- gst/rtsp-server/rtsp-stream.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 70abb992b8..272fbc94de 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1229,16 +1229,15 @@ again: goto no_udp_protocol; } - if (pool) { - GstRTSPAddressFlags flags; + if (pool && ((transport == GST_RTSP_LOWER_TRANS_UDP && + gst_rtsp_address_pool_has_unicast_addresses (pool)) + || transport == GST_RTSP_LOWER_TRANS_UDP_MCAST)) { + GstRTSPAddressFlags flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT; - if (transport == GST_RTSP_LOWER_TRANS_UDP && - gst_rtsp_address_pool_has_unicast_addresses (pool)) - flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_UNICAST; - else if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) - flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_MULTICAST; + if (transport == GST_RTSP_LOWER_TRANS_UDP) + flags |= GST_RTSP_ADDRESS_FLAG_UNICAST; else - goto no_ports; + flags |= GST_RTSP_ADDRESS_FLAG_MULTICAST; if (addr) rejected_addresses = g_list_prepend (rejected_addresses, addr); From 97948225499b37ceff773d77e345a2a0b7cb4593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 4 Mar 2016 13:51:12 +0200 Subject: [PATCH 1242/1776] rtsp-stream: Only bind multicast sockets to ANY on Windows On Linux it is still needed to bind to the multicast address to filter out random other packets, while on Windows binding to multicast addresses just fails. --- gst/rtsp-server/rtsp-stream.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 272fbc94de..fb71469d1a 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1262,14 +1262,21 @@ again: g_clear_object (&inetaddr); inetaddr = g_inet_address_new_from_string (addr->address); - /* Don't bind to multicast addresses, this does not work on - * Windows. You're supposed to bind to ANY and then join the - * multicast group, which udpsrc/sink does for us already. + /* On Windows it's not possible to bind to a multicast address + * but the OS will make sure to filter out all packets that + * arrive not for the multicast address the socket joined. + * + * On Linux and others it is necessary to bind to a multicast + * address to let the OS filter out all packets that are received + * on the same port but for different addresses than the multicast + * address */ +#ifdef G_OS_WIN32 if (g_inet_address_get_is_multicast (inetaddr)) { g_object_unref (inetaddr); inetaddr = g_inet_address_new_any (family); } +#endif } else { if (tmp_rtp != 0) { tmp_rtp += 2; From 422d3a300216df5388d00eb1908562a9665b992a Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 3 Mar 2016 15:07:06 +0100 Subject: [PATCH 1243/1776] stream tests: added new tests Test a case when the address pool only contains multicast addresses and the client is requesting unicast udp. Added tests for multicast ports allocation. https://bugzilla.gnome.org/show_bug.cgi?id=757488 --- tests/check/gst/stream.c | 209 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index 26353b1f36..0fb7e59c4f 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -220,6 +220,212 @@ GST_START_TEST (test_get_multicast_address) GST_END_TEST; +/* test case: address pool only contains multicast addresses, + * but the client is requesting unicast udp */ +GST_START_TEST (test_multicast_address_and_unicast_udp) +{ + GstPad *srcpad; + GstElement *pay; + GstRTSPStream *stream; + GstBin *bin; + GstElement *rtpbin; + GstRTSPAddressPool *pool; + GstRTSPTransport *tr; + + srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); + fail_unless (srcpad != NULL); + gst_pad_set_active (srcpad, TRUE); + pay = gst_element_factory_make ("rtpgstpay", "testpayloader"); + fail_unless (pay != NULL); + stream = gst_rtsp_stream_new (0, pay, srcpad); + fail_unless (stream != NULL); + gst_object_unref (pay); + gst_object_unref (srcpad); + rtpbin = gst_element_factory_make ("rtpbin", "testrtpbin"); + fail_unless (rtpbin != NULL); + bin = GST_BIN (gst_bin_new ("testbin")); + fail_unless (bin != NULL); + fail_unless (gst_bin_add (bin, rtpbin)); + + pool = gst_rtsp_address_pool_new (); + /* add a multicast addres to the address pool */ + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.252.0.0", "233.252.0.0", 5000, 5001, 1)); + gst_rtsp_stream_set_address_pool (stream, pool); + + fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + + gst_rtsp_transport_new (&tr); + /* unicast udp */ + tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP; + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, + tr, FALSE)); + + gst_rtsp_transport_free (tr); + g_object_unref (pool); + fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); + gst_object_unref (bin); + gst_object_unref (stream); +} + +GST_END_TEST; + +GST_START_TEST (test_allocate_udp_ports_multicast) +{ + GstPad *srcpad; + GstElement *pay; + GstRTSPStream *stream; + GstBin *bin; + GstElement *rtpbin; + GstRTSPAddressPool *pool; + GstRTSPTransport *tr; + GstRTSPAddress *addr; + + srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); + fail_unless (srcpad != NULL); + gst_pad_set_active (srcpad, TRUE); + pay = gst_element_factory_make ("rtpgstpay", "testpayloader"); + fail_unless (pay != NULL); + stream = gst_rtsp_stream_new (0, pay, srcpad); + fail_unless (stream != NULL); + gst_object_unref (pay); + gst_object_unref (srcpad); + rtpbin = gst_element_factory_make ("rtpbin", "testrtpbin"); + fail_unless (rtpbin != NULL); + bin = GST_BIN (gst_bin_new ("testbin")); + fail_unless (bin != NULL); + fail_unless (gst_bin_add (bin, rtpbin)); + + pool = gst_rtsp_address_pool_new (); + /* add multicast addresses to the address pool */ + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.252.0.1", "233.252.0.1", 6000, 6001, 1)); + fail_unless (gst_rtsp_address_pool_add_range (pool, + "FF11:DB8::1", "FF11:DB8::1", 6002, 6003, 1)); + gst_rtsp_stream_set_address_pool (stream, pool); + + fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + + /* allocate udp multicast ports for IPv4 */ + gst_rtsp_transport_new (&tr); + tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST; + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, + tr, FALSE)); + + /* check the multicast address and ports for IPv4 */ + addr = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV4); + fail_unless (addr != NULL); + fail_unless_equals_string (addr->address, "233.252.0.1"); + fail_unless_equals_int (addr->port, 6000); + fail_unless_equals_int (addr->n_ports, 2); + gst_rtsp_address_free (addr); + + /* allocate upd multicast ports for IPv6 */ + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV6, + tr, FALSE)); + + /* check the multicast address and ports for IPv6 */ + addr = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV6); + fail_unless (addr != NULL); + fail_unless (!g_ascii_strcasecmp (addr->address, "FF11:DB8::1")); + fail_unless_equals_int (addr->port, 6002); + fail_unless_equals_int (addr->n_ports, 2); + gst_rtsp_address_free (addr); + + gst_rtsp_transport_free (tr); + g_object_unref (pool); + fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); + gst_object_unref (bin); + gst_object_unref (stream); +} + +GST_END_TEST; + +GST_START_TEST (test_allocate_udp_ports_client_settings) +{ + GstPad *srcpad; + GstElement *pay; + GstRTSPStream *stream; + GstBin *bin; + GstElement *rtpbin; + GstRTSPAddressPool *pool; + GstRTSPTransport *tr; + GstRTSPAddress *addr; + + srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); + fail_unless (srcpad != NULL); + gst_pad_set_active (srcpad, TRUE); + pay = gst_element_factory_make ("rtpgstpay", "testpayloader"); + fail_unless (pay != NULL); + stream = gst_rtsp_stream_new (0, pay, srcpad); + fail_unless (stream != NULL); + gst_object_unref (pay); + gst_object_unref (srcpad); + rtpbin = gst_element_factory_make ("rtpbin", "testrtpbin"); + fail_unless (rtpbin != NULL); + bin = GST_BIN (gst_bin_new ("testbin")); + fail_unless (bin != NULL); + fail_unless (gst_bin_add (bin, rtpbin)); + + pool = gst_rtsp_address_pool_new (); + /* add multicast addresses to the address pool */ + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.252.0.1", "233.252.0.1", 6000, 6001, 1)); + fail_unless (gst_rtsp_address_pool_add_range (pool, + "FF11:DB7::1", "FF11:DB7::1", 6004, 6005, 1)); + /* multicast address specified by the client */ + fail_unless (gst_rtsp_address_pool_add_range (pool, + "233.252.0.2", "233.252.0.2", 6002, 6003, 1)); + fail_unless (gst_rtsp_address_pool_add_range (pool, + "FF11:DB8::1", "FF11:DB8::1", 6006, 6007, 1)); + gst_rtsp_stream_set_address_pool (stream, pool); + + fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + + /* client transport settings for IPv4 */ + gst_rtsp_transport_new (&tr); + tr->destination = g_strdup ("233.252.0.2"); + tr->port.min = 6002; + tr->port.max = 6003; + tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST; + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, + tr, FALSE)); + + /* verify that the multicast address and ports correspond to the requested client + * transport information for IPv4 */ + addr = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV4); + fail_unless (addr != NULL); + fail_unless_equals_string (addr->address, "233.252.0.2"); + fail_unless_equals_int (addr->port, 6002); + fail_unless_equals_int (addr->n_ports, 2); + gst_rtsp_address_free (addr); + + /* client transport settings for IPv6 */ + g_free (tr->destination); + tr->destination = g_strdup ("FF11:DB8::1"); + tr->port.min = 6006; + tr->port.max = 6007; + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV6, + tr, FALSE)); + + /* verify that the multicast address and ports correspond to the requested client + * transport information for IPv6 */ + addr = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV6); + fail_unless (addr != NULL); + fail_unless (!g_ascii_strcasecmp (addr->address, "FF11:DB8::1")); + fail_unless_equals_int (addr->port, 6006); + fail_unless_equals_int (addr->n_ports, 2); + gst_rtsp_address_free (addr); + + gst_rtsp_transport_free (tr); + g_object_unref (pool); + fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); + gst_object_unref (bin); + gst_object_unref (stream); +} + +GST_END_TEST; + static Suite * rtspstream_suite (void) { @@ -230,6 +436,9 @@ rtspstream_suite (void) tcase_add_test (tc, test_get_sockets); tcase_add_test (tc, test_allocate_udp_ports_fail); tcase_add_test (tc, test_get_multicast_address); + tcase_add_test (tc, test_multicast_address_and_unicast_udp); + tcase_add_test (tc, test_allocate_udp_ports_multicast); + tcase_add_test (tc, test_allocate_udp_ports_client_settings); return s; } From 206d2ded099e49d8d6e03fdc6158eb6ed96d6276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 5 Mar 2016 10:52:11 +0200 Subject: [PATCH 1244/1776] rtsp-stream: Disable multicast loopback for all our sockets On Windows this is a receiver-side setting, on Linux a sender-side setting. As we provide a socket ourselves to udpsrc, udpsrc is never setting the multicast loopback setting on the socket... while udpsink does which unfortunately has no effect here on Windows but on Linux. https://bugzilla.gnome.org/show_bug.cgi?id=757488 --- gst/rtsp-server/rtsp-stream.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index fb71469d1a..550ef50486 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1214,6 +1214,7 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, G_SOCKET_PROTOCOL_UDP, NULL); if (!rtcp_socket) goto no_udp_protocol; + g_socket_set_multicast_loopback (rtcp_socket, FALSE); if (*server_addr_out) gst_rtsp_address_free (*server_addr_out); @@ -1227,6 +1228,7 @@ again: G_SOCKET_PROTOCOL_UDP, NULL); if (!rtp_socket) goto no_udp_protocol; + g_socket_set_multicast_loopback (rtp_socket, FALSE); } if (pool && ((transport == GST_RTSP_LOWER_TRANS_UDP && From 4a6f63ad031ea540fa1e266d034763cde52344e6 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 11 Mar 2016 01:22:54 +1100 Subject: [PATCH 1245/1776] rtsp-stream: Fix typo in the docstring gst_rtsp_stream_set_client_side -> gst_rtsp_stream_is_client_side --- gst/rtsp-server/rtsp-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 550ef50486..a8cc815525 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1488,7 +1488,7 @@ gst_rtsp_stream_set_client_side (GstRTSPStream * stream, gboolean client_side) } /** - * gst_rtsp_stream_set_client_side: + * gst_rtsp_stream_is_client_side: * @stream: a #GstRTSPStream * * See gst_rtsp_stream_set_client_side() From 8b68edd138ec78437279ac9ec482aabe59f123dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 10 Mar 2016 13:54:38 +0200 Subject: [PATCH 1246/1776] rtsp-stream: Ensure that the pipeline is live and later-added udpsrcs are syncing the state with the parent bin Without this, RECORD pipelines are broken because a) we wait for ASYNC_DONE which never happens anymore because udpsrc would be added later. Previously it was there earlier and due to NO_PREROLL caused the pipeline to preroll immediately b) the udpsrc for the pipeline is added later and never set to PLAYING state, as the corresponding code previously was only for PLAY pipelines. https://bugzilla.gnome.org/show_bug.cgi?id=763281 --- gst/rtsp-server/rtsp-stream.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index a8cc815525..9fffeecc45 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1128,6 +1128,12 @@ play_udpsources_one_family (GstRTSPStream * stream, GstElement * udpsrc_out[2], gst_pad_link (pad, selpad); gst_object_unref (pad); gst_object_unref (selpad); + + /* otherwise sync state with parent in case it's running already + * at this point */ + if (!priv->srcpad) { + gst_element_sync_state_with_parent (udpsrc_out[i]); + } } } @@ -2507,7 +2513,12 @@ create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) /* make and add appsrc */ priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); priv->appsrc_base_time[i] = -1; - g_object_set (priv->appsrc[i], "format", GST_FORMAT_TIME, NULL); + if (priv->srcpad) { + gst_element_set_state (priv->appsrc[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->appsrc[i], TRUE); + } + g_object_set (priv->appsrc[i], "format", GST_FORMAT_TIME, "is-live", + TRUE, NULL); gst_bin_add (bin, priv->appsrc[i]); /* and link to the funnel */ selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); @@ -2857,8 +2868,16 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, if (priv->udpsink[i] && is_udp && (priv->srcpad || i == 1)) gst_bin_remove (bin, priv->udpsink[i]); - if (priv->appsrc[i] && (priv->sinkpad || i == 1)) - gst_bin_remove (bin, priv->appsrc[i]); + if (priv->appsrc[i]) { + if (priv->sinkpad || i == 1) { + gst_element_set_locked_state (priv->appsrc[i], FALSE); + gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); + gst_bin_remove (bin, priv->appsrc[i]); + } else { + gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); + gst_object_unref (priv->appsrc[i]); + } + } if (priv->appsink[i] && is_tcp && (priv->srcpad || i == 1)) gst_bin_remove (bin, priv->appsink[i]); if (priv->appqueue[i] && is_tcp && is_udp && (priv->srcpad || i == 1)) From ad7fcf7a2f1681a0c298640f91822ec3696d7d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 15 Mar 2016 12:26:13 +0200 Subject: [PATCH 1247/1776] Release 1.7.91 --- ChangeLog | 86 ++++++++++++++++++++++++++++++++++++++++++-- NEWS | 2 +- RELEASE | 8 ++--- configure.ac | 12 +++---- gst-rtsp-server.doap | 10 ++++++ 5 files changed, 104 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 97df09bded..7e2ac4d791 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,89 @@ -=== release 1.7.90 === +=== release 1.7.91 === -2016-03-01 Sebastian Dröge +2016-03-15 Sebastian Dröge * configure.ac: - releasing 1.7.90 + releasing 1.7.91 + +2016-03-10 13:54:38 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Ensure that the pipeline is live and later-added udpsrcs are syncing the state with the parent bin + Without this, RECORD pipelines are broken because + a) we wait for ASYNC_DONE which never happens anymore because udpsrc would be + added later. Previously it was there earlier and due to NO_PREROLL caused the + pipeline to preroll immediately + b) the udpsrc for the pipeline is added later and never set to PLAYING state, + as the corresponding code previously was only for PLAY pipelines. + https://bugzilla.gnome.org/show_bug.cgi?id=763281 + +2016-03-11 01:22:54 +1100 Jan Schmidt + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Fix typo in the docstring + gst_rtsp_stream_set_client_side -> gst_rtsp_stream_is_client_side + +2016-03-05 10:52:11 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Disable multicast loopback for all our sockets + On Windows this is a receiver-side setting, on Linux a sender-side setting. As + we provide a socket ourselves to udpsrc, udpsrc is never setting the multicast + loopback setting on the socket... while udpsink does which unfortunately has + no effect here on Windows but on Linux. + https://bugzilla.gnome.org/show_bug.cgi?id=757488 + +2016-03-03 15:07:06 +0100 Patricia Muscalu + + * tests/check/gst/stream.c: + stream tests: added new tests + Test a case when the address pool only contains multicast addresses + and the client is requesting unicast udp. + Added tests for multicast ports allocation. + https://bugzilla.gnome.org/show_bug.cgi?id=757488 + +2016-03-04 13:51:12 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Only bind multicast sockets to ANY on Windows + On Linux it is still needed to bind to the multicast address + to filter out random other packets, while on Windows binding + to multicast addresses just fails. + +2016-03-03 10:41:51 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Only use the address pool for unicast UDP if it contains unicast addresses + Otherwise we fail to allocate UDP ports if the pool only contains multicast + addresses, which is something that used to work before. For unicast addresses + if the pool contains none, we just allocate them as if there is no pool at + all. + https://bugzilla.gnome.org/show_bug.cgi?id=757488 + +2016-03-02 11:48:49 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-server: Fix indentation + +2016-03-02 11:47:47 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Don't bind the sockets to multicast addresses + This works on Linux but fails completely on Windows. You're supposed + to bind to ANY and then join the multicast group. + https://bugzilla.gnome.org/show_bug.cgi?id=757488 + +=== release 1.7.90 === + +2016-03-01 19:00:45 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.7.90 2016-02-26 12:42:51 +0200 Sebastian Dröge diff --git a/NEWS b/NEWS index 8f11fc4c19..dec122b59e 100644 --- a/NEWS +++ b/NEWS @@ -1,2 +1,2 @@ -This is GStreamer 1.7.90 +This is GStreamer 1.7.91 diff --git a/RELEASE b/RELEASE index 6aa933c6e1..1be853d391 100644 --- a/RELEASE +++ b/RELEASE @@ -1,7 +1,7 @@ -Release notes for GStreamer RTSP Server Library 1.7.90 +Release notes for GStreamer RTSP Server Library 1.7.91 -The GStreamer team is pleased to announce the first release candidate of the stable +The GStreamer team is pleased to announce the second release candidate of the stable 1.8 release series. The 1.8 release series is adding new features on top of the 1.0, 1.2, 1.4 and 1.6 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. @@ -10,12 +10,12 @@ series of the GStreamer multimedia framework. Binaries for Android, iOS, Mac OS X and Windows will be provided separately during the stable 1.8 release series. + Bugs fixed in this release - * 757488 : gst-rtsp-server: multicast functionality is broken if using the same port ranges for multicast and unicast - * 762525 : rtspclientsink test: Memory leaks + * 763281 : RTSP RECORD: pipeline never prerolls ==== Download ==== diff --git a/configure.ac b/configure.ac index 1261bc3e60..11e273969f 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.7.90], +AC_INIT([GStreamer RTSP Server Library], [1.7.91], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 790, 0, 790) +AS_LIBTOOL(GST, 791, 0, 791) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.7.90 -GSTPB_REQ=1.7.90 -GSTPG_REQ=1.7.90 -GSTPD_REQ=1.7.90 +GST_REQ=1.7.91 +GSTPB_REQ=1.7.91 +GSTPG_REQ=1.7.91 +GSTPD_REQ=1.7.91 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 52eb47dfe2..4f113ee687 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.7.91 + master + + 2016-03-15 + + + + 1.7.90 From 8e72e69eecaf388ff9efe4b136c3d749a18e96d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 16 Mar 2016 23:35:09 +0200 Subject: [PATCH 1248/1776] rtsp-stream: Don't set the state of the appsrc from PLAYING to PAUSED again during setup This would get us NO_PREROLL in the bin again and break seeking. Thanks to Carlos Rafael Giani for helping to debug this! https://bugzilla.gnome.org/show_bug.cgi?id=740509 --- gst/rtsp-server/rtsp-stream.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 9fffeecc45..faa76fe900 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2533,8 +2533,6 @@ create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) if (state != GST_STATE_NULL) { if (priv->funnel[i] && (priv->sinkpad || i == 1)) gst_element_set_state (priv->funnel[i], state); - if (priv->appsrc[i] && (priv->sinkpad || i == 1)) - gst_element_set_state (priv->appsrc[i], state); } } } From 9e29992026396a22fe73efa91c5b1092205a6d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Mar 2016 13:00:35 +0200 Subject: [PATCH 1249/1776] Release 1.8.0 --- ChangeLog | 25 +- NEWS | 786 ++++++++++++++++++++++++++++++++++++++++++- RELEASE | 18 +- configure.ac | 12 +- gst-rtsp-server.doap | 10 + 5 files changed, 831 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7e2ac4d791..c88dbf679f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,28 @@ -=== release 1.7.91 === +=== release 1.8.0 === -2016-03-15 Sebastian Dröge +2016-03-24 Sebastian Dröge * configure.ac: - releasing 1.7.91 + releasing 1.8.0 + +2016-03-16 23:35:09 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Don't set the state of the appsrc from PLAYING to PAUSED again during setup + This would get us NO_PREROLL in the bin again and break seeking. + Thanks to Carlos Rafael Giani for helping to debug this! + https://bugzilla.gnome.org/show_bug.cgi?id=740509 + +=== release 1.7.91 === + +2016-03-15 12:26:13 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.7.91 2016-03-10 13:54:38 +0200 Sebastian Dröge diff --git a/NEWS b/NEWS index dec122b59e..ee7f213e57 100644 --- a/NEWS +++ b/NEWS @@ -1,2 +1,786 @@ -This is GStreamer 1.7.91 +# GStreamer 1.8 Release Notes +**GStreamer 1.8.0 was released on 24 March 2016.** + +The GStreamer team is proud to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! + +As always, this release is again packed with new features, bug fixes and other +improvements. + +See [https://gstreamer.freedesktop.org/releases/1.8/][latest] for the latest +version of this document. + +*Last updated: Thursday 24 March 2016, 10:00 UTC [(log)][gitlog]* + +[latest]: https://gstreamer.freedesktop.org/releases/1.8/ +[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.8/release-notes-1.8.md + +## Highlights + +- **Hardware-accelerated zero-copy video decoding on Android** + +- **New video capture source for Android using the android.hardware.Camera API** + +- **Windows Media reverse playback** support (ASF/WMV/WMA) + +- **New tracing system** provides support for more sophisticated debugging tools + +- **New high-level GstPlayer playback convenience API** + +- **Initial support for the new [Vulkan][vulkan] API**, see + [Matthew Waters' blog post][vulkan-in-gstreamer] for more details + +- **Improved Opus audio codec support**: Support for more than two channels; MPEG-TS demuxer/muxer can now handle Opus; + [sample-accurate][opus-sample-accurate] encoding/decoding/transmuxing with + Ogg, Matroska, ISOBMFF (Quicktime/MP4), and MPEG-TS as container; + [new codec utility functions for Opus header and caps handling][opus-codec-utils] + in pbutils library. The Opus encoder/decoder elements were also moved to + gst-plugins-base (from -bad), and the opus RTP depayloader/payloader to -good. + + [opus-sample-accurate]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiometa.html#GstAudioClippingMeta + [opus-codec-utils]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstpbutilscodecutils.html + +- **GStreamer VAAPI module now released and maintained as part of the GStreamer project** + + [vulkan]: https://www.khronos.org/vulkan + [vulkan-in-gstreamer]: http://ystreet00.blogspot.co.uk/2016/02/vulkan-in-gstreamer.html + +## Major new features and changes + +### Noteworthy new API, features and other changes + +- New GstVideoAffineTransformationMeta meta for adding a simple 4x4 affine + transformation matrix to video buffers + +- [g\_autoptr()](https://developer.gnome.org/glib/stable/glib-Miscellaneous-Macros.html#g-autoptr) + support for all types is exposed in GStreamer headers now, in combination + with a sufficiently-new GLib version (i.e. 2.44 or later). This is primarily + for the benefit of application developers who would like to make use of + this, the GStreamer codebase itself will not be using g_autoptr() for + the time being due to portability issues. + +- GstContexts are now automatically propagated to elements added to a bin + or pipeline, and elements now maintain a list of contexts set on them. + The list of contexts set on an element can now be queried using the new functions + [gst\_element\_get\_context()](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-context) + and [gst\_element\_get\_contexts()](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-contexts). GstContexts are used to share context-specific configuration objects + between elements and can also be used by applications to set context-specific + configuration objects on elements, e.g. for OpenGL or Hardware-accelerated + video decoding. + +- New [GST\_BUFFER\_DTS\_OR\_PTS()](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#GST-BUFFER-DTS-OR-PTS:CAPS) + convenience macro that returns the decode timestamp if one is set and + otherwise returns the presentation timestamp + +- New GstPadEventFullFunc that returns a GstFlowReturn instead of a gboolean. + This new API is mostly for internal use and was added to fix a race condition + where occasionally internal flow error messages were posted on the bus when + sticky events were propagated at just the wrong moment whilst the pipeline + was shutting down. This happened primarily when the pipeline was shut down + immediately after starting it up. GStreamer would not know that the reason + the events could not be propagated was because the pipeline was shutting down + and not some other problem, and now the flow error allows GStreamer to know + the reason for the failure (and that there's no reason to post an error + message). This is particularly useful for queue-like elements which may need + to asynchronously propagate a previous flow return from downstream. + +- Pipeline dumps in form of "dot files" now also show pad properties that + differ from their default value, the same as it does for elements. This is + useful for elements with pad subclasses that provide additional properties, + e.g. videomixer or compositor. + +- Pad probes are now guaranteed to be called in the order they were added + (before they were called in reverse order, but no particular order was + documented or guaranteed) + +- Plugins can now have dependencies on device nodes (not just regular files) + and also have a prefix filter. This is useful for plugins that expose + features (elements) based on available devices, such as the video4linux + plugin does with video decoders on certain embedded systems. + +- gst\_segment\_to\_position() has been deprecated and been replaced by the + better-named gst\_segment\_position\_from\_running\_time(). At the same time + gst\_segment\_position\_from\_stream\_time() was added, as well as \_full() + variants of both to deal with negative stream time. + +- GstController: the interpolation control source gained a new monotonic cubic + interpolation mode that, unlike the existing cubic mode, will never overshoot + the min/max y values set. + +- GstNetAddressMeta: can now be read from buffers in language bindings as well, + via the new gst\_buffer\_get\_net\_address\_meta() function + +- ID3 tag PRIV frames are now extraced into a new GST\_TAG\_PRIVATE\_DATA tag + +- gst-launch-1.0 and gst\_parse\_launch() now warn in the most common case if + a dynamic pad link could not be resolved, instead of just silently + waiting to see if a suitable pad appears later, which is often perceived + by users as hanging -- they are now notified when this happens and can check + their pipeline. + +- GstRTSPConnection now also parses custom RTSP message headers and retains + them for the application instead of just ignoring them + +- rtspsrc handling of authentication over tunneled connections (e.g. RTSP over HTTP) + was fixed + +- gst\_video\_convert\_sample() now crops if there is a crop meta on the input buffer + +- The debugging system printf functions are now exposed for general use, which + supports special printf format specifiers such as GST\_PTR\_FORMAT and + GST\_SEGMENT\_FORMAT to print GStreamer-related objects. This is handy for + systems that want to prepare some debug log information to be output at a + later point in time. The GStreamer-OpenGL subsystem is making use of these + new functions, which are [gst\_info\_vasprintf()][gst_info_vasprintf], + [gst\_info\_strdup\_vprintf()][gst_info_strdup_vprintf] and + [gst\_info\_strdup\_printf()][gst_info_strdup_printf]. + +- videoparse: "strides", "offsets" and "framesize" properties have been added to + allow parsing raw data with strides and padding that do not match GStreamer + defaults. + +- GstPreset reads presets from the directories given in GST\_PRESET\_PATH now. + Presets are read from there after presets in the system path, but before + application and user paths. + +[gst_info_vasprintf]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-info-vasprintf +[gst_info_strdup_vprintf]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-info-strdup-vprintf +[gst_info_strdup_printf]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-info-strdup-printf + +### New Elements + +- [netsim](): a new (resurrected) element to simulate network jitter and + packet dropping / duplication. + +- New VP9 RTP payloader/depayloader elements: rtpvp9pay/rtpvp9depay + +- New [videoframe_audiolevel]() element, a video frame synchronized audio level element + +- New spandsp-based tone generator source + +- New NVIDIA NVENC-based H.264 encoder for GPU-accelerated video encoding on + suitable NVIDIA hardware + +- [rtspclientsink](), a new RTSP RECORD sink element, was added to gst-rtsp-server + +- [alsamidisrc](), a new ALSA MIDI sequencer source element + +### Noteworthy element features and additions + +- *identity*: new ["drop-buffer-flags"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-identity.html#GstIdentity--drop-buffer-flags) + property to drop buffers based on buffer flags. This can be used to drop all + non-keyframe buffers, for example. + +- *multiqueue*: various fixes and improvements, in particular special handling + for sparse streams such as substitle streams, to make sure we don't overread + them any more. For sparse streams it can be normal that there's no buffer for + a long period of time, so having no buffer queued is perfectly normal. Before + we would often unnecessarily try to fill the subtitle stream queue, which + could lead to much more data being queued in multiqueue than necessary. + +- *multiqueue*/*queue*: When dealing with time limits, these elements now use the + new ["GST_BUFFER_DTS_OR_PTS"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#GST-BUFFER-DTS-OR-PTS:CAPS) + and ["gst_segment_to_running_time_full()"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstSegment.html#gst-segment-to-running-time-full) + API, resulting in more accurate levels, especially when dealing with non-raw + streams (where reordering happens, and we want to use the increasing DTS as + opposed to the non-continuously increasing PTS) and out-of-segment input/output. + Previously all encoded buffers before the segment start, which can happen when + doing ACCURATE seeks, were not taken into account in the queue level calculation. + +- *multiqueue*: New ["use-interleave"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-multiqueue.html#GstMultiQueue--use-interleave) + property which allows the size of the queues to be optimized based on the input + streams interleave. This should only be used with input streams which are properly + timestamped. It will be used in the future decodebin3 element. + +- *queue2*: new ["avg-in-rate"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-queue2.html#GstQueue2--avg-in-rate) + property that returns the average input rate in bytes per second + +- audiotestsrc now supports all audio formats and is no longer artificially + limited with regard to the number of channels or sample rate + +- gst-libav (ffmpeg codec wrapper): map and enable JPEG2000 decoder + +- multisocketsink can, on request, send a custom GstNetworkMessage event + upstream whenever data is received from a client on a socket. Similarly, + socketsrc will, on request, pick up GstNetworkMessage events from downstream + and send any data contained within them via the socket. This allows for + simple bidirectional communication. + +- matroska muxer and demuxer now support the ProRes video format + +- Improved VP8/VP9 decoding performance on multi-core systems by enabling + multi-threaded decoding in the libvpx-based decoders on such systems + +- appsink has a new ["wait-on-eos"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-appsink.html#GstAppSink--wait-on-eos) + property, so in cases where it is uncertain if an appsink will have a consumer for + its buffers when it receives an EOS this can be set to FALSE to ensure that the + appsink will not hang. + +- rtph264pay and rtph265pay have a new "config-interval" mode -1 that will + re-send the setup data (SPS/PPS/VPS) before every keyframe to ensure + optimal coverage and the shortest possibly start-up time for a new client + +- mpegtsmux can now mux H.265/HEVC video as well + +- The MXF muxer was ported to 1.x and produces more standard conformant files now + that can be handled by more other software; The MXF demuxer got improved + support for seek tables (IndexTableSegments). + +### Plugin moves + +- The rtph265pay/depay RTP payloader/depayloader elements for H.265/HEVC video + from the rtph265 plugin in -bad have been moved into the existing rtp plugin + in gst-plugins-good. + +- The mpg123 plugin containing a libmpg123 based audio decoder element has + been moved from -bad to -ugly. + +- The Opus encoder/decoder elements have been moved to gst-plugins-base and + the RTP payloader to gst-plugins-good, both coming from gst-plugins-bad. + +### New tracing tools for developers + +A new tracing subsystem API has been added to GStreamer, which provides +external tracers with the possibility to strategically hook into GStreamer +internals and collect data that can be evaluated later. These tracers are a +new type of plugin features, and GStreamer core ships with a few example +tracers (latency, stats, rusage, log) to start with. Tracers can be loaded +and configured at start-up via an environment variable (GST\_TRACER\_PLUGINS). + +Background: While GStreamer provides plenty of data on what's going on in a +pipeline via its debug log, that data is not necessarily structured enough to +be generally useful, and the overhead to enable logging output for all data +required might be too high in many cases. The new tracing system allows tracers +to just obtain the data needed at the right spot with as little overhead as +possible, which will be particularly useful on embedded systems. + +Of course it has always been possible to do performance benchmarks and debug +memory leaks, memory consumption and invalid memory access using standard +operating system tools, but there are some things that are difficult to track +with the standard tools, and the new tracing system helps with that. Examples +are things such as latency handling, buffer flow, ownership transfer of +events and buffers from element to element, caps negotiation, etc. + +For some background on the new tracing system, watch Stefan Sauer's +GStreamer Conference talk ["A new tracing subsystem for GStreamer"][tracer-0] +and for a more specific example how it can be useful have a look at +Thiago Santos's lightning talk ["Analyzing caps negotiation using GstTracer"][tracer-1] +and his ["GstTracer experiments"][tracer-2] blog post. There was also a Google +Summer of Code project in 2015 that used tracing system for a graphical +GStreamer debugging tool ["gst-debugger"][tracer-3]. + +This is all still very much work in progress, but we hope this will provide the +foundation for a whole suite of new debugging tools for GStreamer pipelines. + +[tracer-0]: https://gstconf.ubicast.tv/videos/a-new-tracing-subsystem-for-gstreamer/ +[tracer-1]: https://gstconf.ubicast.tv/videos/analyzing-caps-negotiation-using-gsttracer/ +[tracer-2]: http://blog.thiagoss.com/2015/07/23/gsttracer-experiments/ +[tracer-3]: https://git.gnome.org/browse/gst-debugger + +### GstPlayer: a new high-level API for cross-platform multimedia playback + +GStreamer has had reasonably high-level API for multimedia playback +in the form of the playbin element for a long time. This allowed application +developers to just configure a URI to play, and playbin would take care of +everything else. This works well, but there is still way too much to do on +the application-side to implement a fully-featured playback application, and +too much general GStreamer pipeline API exposed, making it less accessible +to application developers. + +Enter GstPlayer. GstPlayer's aim is to provide an even higher-level abstraction +of a fully-featured playback API but specialised for its specific use case. It +also provides easy integration with and examples for Gtk+, Qt, Android, OS/X, +iOS and Windows. Watch Sebastian's [GstPlayer talk at the GStreamer Conference][gstplayer-talk] +for more information, or check out the [GstPlayer API reference][gstplayer-api] +and [GstPlayer examples][gstplayer-examples]. + +[gstplayer-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/player.html +[gstplayer-talk]: https://gstconf.ubicast.tv/videos/gstplayer-a-simple-cross-platform-api-for-all-your-media-playback-needs-part-1/ +[gstplayer-examples]: https://github.com/sdroege/gst-player/ + +### Adaptive streaming: DASH, HLS and MSS improvements + +- dashdemux now supports loading external xml nodes pointed from its MPD. + +- Content protection nodes parsing support for PlayReady WRM in mssdemux. + +- Reverse playback was improved to respect seek start and stop positions. + +- Adaptive demuxers (hlsdemux, dashdemux, mssdemux) now support the SNAP_AFTER + and SNAP_BEFORE seek flags which will jump to the nearest fragment boundary + when executing a seek, which means playback resumes more quickly after a seek. + +### Audio library improvements + +- audio conversion, quantization and channel up/downmixing functionality + has been moved from the audioconvert element into the audio library and + is now available as public API in form of [GstAudioConverter][audio-0], + [GstAudioQuantize][audio-1] and [GstAudioChannelMixer][audio-2]. + Audio resampling will follow in future releases. + +- [gst\_audio\_channel\_get\_fallback\_mask()][audio-3] can be used + to retrieve a default channel mask for a given number of channels as last + resort if the layout is unknown + +- A new [GstAudioClippingMeta][audio-4] meta was added for specifying clipping + on encoded audio buffers + +- A new GstAudioVisualizer base class for audio visualisation elements; + most of the existing visualisers have been ported over to the new base class. + This new base class lives in the pbutils library rather than the audio library, + since we'd have had to make libgstaudio depend on libgstvideo otherwise, + which was deemed undesirable. + +[audio-0]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-GstAudioConverter.html +[audio-1]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-GstAudioQuantize.html +[audio-2]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiochannels.html#gst-audio-channel-mix-new +[audio-3]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiochannels.html#gst-audio-channel-get-fallback-mask +[audio-4]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiometa.html#GstAudioClippingMeta + +### GStreamer OpenGL support improvements + +#### Better OpenGL Shader support + +[GstGLShader][shader] has been revamped to allow more OpenGL shader types +by utilizing a new GstGLSLStage object. Each stage holds an OpenGL pipeline +stage such as a vertex, fragment or a geometry shader that are all compiled +separately into a program that is executed. + +The glshader element has also received a revamp as a result of the changes in +the library. It does not take file locations for the vertex and fragment +shaders anymore. Instead it takes the strings directly leaving the file +management to the application. + +A new [example][liveshader-example] was added utilizing the new shader +infrastructure showcasing live shader edits. + +[shader]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstglshader.html +[liveshader-example]: https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/tests/examples/gtk/glliveshader.c + +#### OpenGL GLMemory rework + +[GstGLMemory] was extensively reworked to support the addition of multiple +texture targets required for zero-copy integration with the Android +MediaCodec elements. This work was also used to provide IOSurface based +GLMemory on OS X for zero-copy with OS X's VideoToolbox decoder (vtdec) and +AV Foundation video source (avfvideosrc). There are also patches in bugzilla +for GstGLMemoryEGL specifically aimed at improving the decoding performance on +the Raspberry Pi. + +[GstGLMemory]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstglmemory.html + +A texture-target field was added to video/x-raw(memory:GLMemory) caps to signal +the texture target contained in the GLMemory. Its values can be 2D, rectangle +or external-oes. glcolorconvert can convert between the different formats as +required and different elements will accept or produce different targets. e.g. +glimagesink can take and render external-oes textures directly as required for +effecient zero-copy on android. + +A generic GL allocation framework was also implemented to support the generic +allocation of OpenGL buffers and textures which is used extensively by +GstGLBufferPool. + +#### OpenGL DMABuf import uploader + +There is now a DMABuf uploader available for automatic selection that will +attempt to import the upstream provided DMABuf. The uploader will import into +2D textures with the necesarry format. YUV to RGB conversion is still provided +by glcolorconvert to avoid the laxer restrictions with external-oes textures. + +#### OpenGL queries + +Queries of various aspects of the OpenGL runtime such as timers, number of +samples or the current timestamp are not possible. The GstGLQuery object uses a +delayed debug system to delay the debug output to later to avoid expensive calls +to the glGet\* family of functions directly after finishing a query. It is +currently used to output the time taken to perform various operations of texture +uploads and downloads in GstGLMemory. + +#### New OpenGL elements + +glcolorbalance has been created mirroring the videobalance elements. +glcolorbalance provides the exact same interface as videobalance so can be used +as a GPU accelerated replacement. glcolorbalance has been added to glsinkbin so +usage with playsink/playbin will use it automatically instead of videobalance +where possible. + +glvideoflip, which is the OpenGL equiavalant of videoflip, implements the exact +same interface and functionality as videoflip. + +#### EGL implementation now selects OpenGL 3.x + +The EGL implementation can now select OpenGL 3.x contexts. + +#### OpenGL API removal + +The GstGLDownload library object was removed as it was not used by anything. +Everything is performed by GstGLMemory or in the gldownloadelement. + +The GstGLUploadMeta library object was removed as it was not being used and we +don't want to promote the use of GstVideoGLTextureUploadMeta. + +#### OpenGL: Other miscellaneous changes + +- The EGL implementation can now select OpenGL 3.x contexts. This brings + OpenGL 3.x to e.g. wayland and other EGL systems. + +- glstereomix/glstereosplit are now built and are usable on OpenGL ES systems + +- The UYVY/YUY2 to RGBA and RGBA to UYVY/YUY2 shaders were fixed removing the + sawtooth pattern and luma bleeding. + +- We now utilize the GL\_APPLE\_sync extension on iOS devices which improves + performance of OpenGL applications, especially with multiple OpenGL + contexts. + +- glcolorconvert now uses a bufferpool to avoid costly + glGenTextures/glDeleteTextures for every frame. + +- glvideomixer now has full glBlendFunc and glBlendEquation support per input. + +- gltransformation now support navigation events so your weird transformations + also work with DVD menus. + +- qmlglsink can now run on iOS, OS X and Android in addition to the already + supported Linux platform. + +- glimagesink now posts unhandled keyboard and mouse events (on backends that + support user input, current only X11) on the bus for the application. + +### Initial GStreamer Vulkan support + +Some new elements, vulkansink and vulkanupload have been implemented utilizing +the new Vulkan API. The implementation is currently limited to X11 platforms +(via xcb) and does not perform any scaling of the stream's contents to the size +of the available output. + +A lot of infrasctructure work has been undertaken to support using Vulkan in +GStreamer in the future. A number of GstMemory subclasses have been created for +integrating Vulkan's GPU memory handling along with VkBuffer's and VkImage's +that can be passed between elements. Some GStreamer refcounted wrappers for +global objects such as VkInstance, VkDevice, VkQueue, etc have also been +implemented along with GstContext integration for sharing these objects with the +application. + +### GStreamer VAAPI support for hardware-accelerated video decoding and encoding on Intel (and other) platforms + +#### GStreamer VAAPI is now part of upstream GStreamer + +The GStreamer-VAAPI module which provides support for hardware-accelerated +video decoding, encoding and post-processing on Intel graphics hardware +on Linux has moved from its previous home at the [Intel Open Source Technology Center][iostc] +to the upstream GStreamer repositories, where it will in future be maintained +as part of the upstream GStreamer project and released in lockstep with the +other GStreamer modules. The current maintainers will continue to spearhead +the development at the new location: + +[http://cgit.freedesktop.org/gstreamer/gstreamer-vaapi/][gst-vaapi-git] + +[gst-vaapi-git]: http://cgit.freedesktop.org/gstreamer/gstreamer-vaapi/ + +GStreamer-VAAPI relies heavily on certain GStreamer infrastructure API that +is still in flux such as the OpenGL integration API or the codec parser +libraries, and one of the goals of the move was to be able to leverage +new developments early and provide tighter integration with the latest +developments of those APIs and other graphics-related APIs provided by +GStreamer, which should hopefully improve performance even further and in +some cases might also provide better stability. + +Thanks to everyone involved in making this move happen! + +#### GStreamer VAAPI: Bug tracking + +Bugs had already been tracked on [GNOME bugzilla](bgo) but will be moved +from the gstreamer-vaapi product into a new gstreamer-vaapi component of +the GStreamer product in bugzilla. Please file new bugs against the new +component in the GStreamer product from now on. + +#### GStreamer VAAPI: Pending patches + +The code base has been re-indented to the GStreamer code style, which +affected some files more than others. This means that some of the patches +in bugzilla might not apply any longer, so if you have any unmerged patches +sitting in bugzilla please consider checking if they still apply cleany and +refresh them if not. Sorry for any inconvenience this may cause. + +#### GStreamer VAAPI: New versioning scheme and supported GStreamer versions + +The version numbering has been changed to match the GStreamer version +numbering to avoid confusion: there is a new gstreamer-vaapi 1.6.0 release +and a 1.6 branch that is roughly equivalent to the previous 0.7.0 version. +Future releases 1.7.x and 1.8.x will be made alongside GStreamer releases. + +While it was possible and supported by previous releases to build against +a whole range of different GStreamer versions (such as 1.2, 1.4, 1.6 or 1.7/1.8), +in the future there will only be one target branch, so that git master will +track GStreamer git master, 1.8.x will target GStreamer 1.8, and +1.6.x will target the 1.6 series. + +[iostc]: http://01.org +[bgo]: http://bugzilla.gnome.og + +#### GStreamer VAAPI: Miscellaneous changes + +All GStreamer-VAAPI functionality is now provided solely by its GStreamer +elements. There is no more public library exposing GstVaapi API, this API +was only ever meant for private use by the elements. Parts of it may be +resurrected again in future if needed, but for now it has all been made +private. + +GStreamer-VAAPI now unconditionally uses the codecparser library in +gst-plugins-bad instead of shipping its own internal copy. Similarly, +it no longer ships its own codec parsers but relies on the upstream +codec parser elements. + +The GStreamer-VAAPI encoder elements have been renamed from vaapiencode_foo +to vaapifooenc, so encoders are now called vaapih264enc, vaapih265enc, +vaapimpeg2enc, vaapijpegenc, and vaapivp8enc. With this change we now follow +the standard names in GStreamer, and the plugin documentation is generated +correctly. + +In the case of the decoders, only the jpeg decoder has been split from the +general decoding element vaapidecode: vaapijpegdec. This is the first step to +split per codec each decoding element. The vaapijpegdec has also been given +marginal rank for the time being. + +#### GStreamer VAAPI: New features in 1.8: 10-bit H.265/HEVC decoding support + +Support for decoding 10-bit H.265/HEVC has been added. For the time being +this only works in combination with vaapisink though, until support for the +P010 video format used internally is added to GStreamer and to the +vaGetImage()/vaPutimage() API in the vaapi-intel-driver. + +Several fixes for memory leaks, build errors, and in the internal +video parsing. + +Finally, vaapisink now posts the unhandled keyboard and mouse events to the +application. + +### GStreamer Video 4 Linux Support + +Colorimetry support has been enhanced even more. It will now properly select +default values when not specified by the driver. The range of color formats +supported by GStreamer has been greatly improved. Notably, support for +multi-planar I420 has been added along with all the new and non-ambiguous RGB +formats that got added in recent kernels. + +The device provider now exposes a variety of properties as found in the udev +database. + +The video decoder is now able to negotiate the downstream format. + +Elements that are dynamically created from /dev/video\* now track changes on +these devices to ensure the registry stay up to date. + +All this and various bug fixes that improve both stability and correctness. + +### GStreamer Editing Services + +Added APIs to handle asset proxying support. Proxy creation is not the +responsibility of GES itself, but GES provides all the needed features +for it to be cleanly handled at a higher level. + +Added support for changing playback rate. This means that now, whenever a +user adds a 'pitch' element (as it is the only known element to change playback +rate through properties), GES will handle everything internally. This change +introduced a new media-duration-factor property in NleObject which will +lead to tweaking of seek events so they have the proper playback range to be +requested upstream. + +Construction of NLE objects has been reworked making copy/pasting fully +functional and allowing users to set properties on effects right after +creating them. + +Rework of the title source to add more flexibility in text positioning, +and letting the user get feedback about rendered text positioning. + +Report nlecomposition structural issues (coming from user programing mistakes) +into ERROR messages on the bus. + +Add GI/pythyon testsuite in GES itself, making sure the API is working as expected +in python, and allowing writing tests faster. + +### GstValidate + +Added support to run tests inside gdb. + +Added a 'smart' reporting mode where we give as much information as possible about +critical errors. + +Uses GstTracer now instead of a LD\_PRELOAD library. + +## Miscellaneous + +- encodebin now works with "encoder-muxers" such as wavenc + +- gst-play-1.0 acquired a new keyboard shortcut: '0' seeks back to the start + +- gst-play-1.0 supports two new command line switches: -v for verbose output + and --flags to configure the playbin flags to use. + +## Build and Dependencies + +- The GLib dependency requirement was bumped to 2.40 + +- The -Bsymbolic configure check now works with clang as well + +- ffmpeg is now required as libav provider, incompatible changes were + introduced that make it no longer viable to support both FFmpeg and Libav + as libav providers. Most major distros have switched to FFmpeg or are in + the process of switching to it anyway, so we don't expect this to be a + problem, and there is still an internal copy of ffmpeg that can be used + as fallback if needed. + +- The internal ffmpeg snapshot is now FFMpeg 3.0, but it should be possible + to build against 2.8 as well for the time being. + +## Platform-specific improvements + +### Android + +- Zero-copy video decoding on Android using the hardware-accelerated decoders + has been implemented, and is fully integrated with the GStreamer OpenGL stack + +- ahcsrc, a new camera source element, has been merged and can be used to + capture video on android devices. It uses the android.hardware.Camera Java + API to capture from the system's cameras. + +- The OpenGL-based QML video sink can now also be used on Android + +- New tinyalsasink element, which is mainly useful for Android but can also + be used on other platforms. + +### OS/X and iOS + +- The system clock now uses mach\_absolute\_time() on OSX/iOS, which is + the preferred high-resolution monotonic clock to be used on Apple platforms + +- The OpenGL-based QML video sink can now also be used on OS X and iOS (with + some Qt build system massaging) + +- New IOSurface based memory implementation in avfvideosrc and vtdec on OS X + for zerocopy with OpenGL. The previously used OpenGL extension + GL_APPLE_ycbcr_422 is not compatible with GL 3.x core contexts. + +- New GstAppleCoreVideoMemory wrapping CVPixelBuffer's + +- avfvideosrc now supports renegotiation. + +### Windows + +- Various bugs with UDP and multicast were fixed on Windows, mostly related to + gst-rtsp-server. + +- A few bugs in directsoundsrc and directsoundsink were fixed that could cause + the element to lock up. Also the "mute" property on the sink was fixed, and + a new "device" property for device selection was added to the source. + +## Known Issues + +- Building GStreamer applications with the Android NDK r11 is currently not + supported due to incompatible changes in the NDK. This is expected to be + fixed for 1.8.1. + [Bugzilla #763999](https://bugzilla.gnome.org/show_bug.cgi?id=763999) + +- vp8enc crashes on 32 bit Windows, but was working fine in 1.6. 64 bit + Windows is unaffected. + [Bugzilla #763663](https://bugzilla.gnome.org/show_bug.cgi?id=763663) + +## Contributors + +Adam Miartus, Alban Bedel, Aleix Conchillo Flaqué, Aleksander Wabik, +Alessandro Decina, Alex Ashley, Alex Dizengof, Alex Henrie, Alistair Buxton, +Andreas Cadhalpun, Andreas Frisch, André Draszik, Anthony G. Basile, +Antoine Jacoutot, Anton Bondarenko, Antonio Ospite, Arjen Veenhuizen, +Arnaud Vrac, Arun Raghavan, Athanasios Oikonomou, Aurélien Zanelli, Ben Iofel, +Bob Holcomb, Branko Subasic, Carlos Rafael Giani, Chris Bass, Csaba Toth, +Daniel Kamil Kozar, Danilo Cesar Lemes de Paula, Dave Craig, David Fernandez, +David Schleef, David Svensson Fors, David Waring, David Wu, Duncan Palmer, +Edward Hervey, Egor Zaharov, Etienne Peron, Eunhae Choi, Evan Callaway, +Evan Nemerson, Fabian Orccon, Florent Thiéry, Florin Apostol, Frédéric Wang, +George Kiagiadakis, George Yunaev, Göran Jönsson, Graham Leggett, +Guillaume Desmottes, Guillaume Marquebielle, Haihua Hu, Havard Graff, +Heinrich Fink, Holger Kaelberer, HoonHee Lee, Hugues Fruchet, Hyunil Park, +Hyunjun Ko, Ilya Konstantinov, James Stevenson, Jan Alexander Steffens (heftig), +Jan Schmidt, Jason Litzinger, Jens Georg, Jimmy Ohn, Joan Pau Beltran, +Joe Gorse, John Chang, John Slade, Jose Antonio Santos Cadenas, Josep Torra, +Julian Bouzas, Julien Isorce, Julien Moutte, Justin Kim, Kazunori Kobayashi, +Koop Mast, Lim Siew Hoon, Linus Svensson, Lubosz Sarnecki, Luis de Bethencourt, +Lukasz Forynski, Manasa Athreya, Marcel Holtmann, Marcin Kolny, Marcus Prebble, +Mark Nauwelaerts, Maroš Ondrášek, Martin Kelly, Matej Knopp, Mathias Hasselmann, +Mathieu Duponchelle, Matt Crane, Matthew Marsh, Matthew Waters, Matthieu Bouron, +Mersad Jelacic, Michael Olbrich, Miguel París Díaz, Mikhail Fludkov, +Mischa Spiegelmock, Nicola Murino, Nicolas Dufresne, Nicolas Huet, +Nirbheek Chauhan, Ognyan Tonchev, Olivier Crête, Pablo Anton, Pankaj Darak, +Paolo Pettinato, Patricia Muscalu, Paul Arzelier, Pavel Bludov, Perry Hung, +Peter Korsgaard, Peter Seiderer, Petr Viktorin, Philippe Normand, +Philippe Renon, Philipp Zabel, Philip Van Hoof, Philip Withnall, Piotr Drąg, +plamot, Polochon\_street, Prashant Gotarne, Rajat Verma, Ramiro Polla, +Ravi Kiran K N, Reynaldo H. Verdejo Pinochet, Robert Swain, Romain Picard, +Roman Nowicki, Ross Burton, Ryan Hendrickson, Santiago Carot-Nemesio, +Scott D Phillips, Sebastian Dröge, Sebastian Rasmussen, Sergey Borovkov, +Seungha Yang, Sjors Gielen, Song Bing, Sreerenj Balachandran, Srimanta Panda, +Stavros Vagionitis, Stefan Sauer, Steven Hoving, Stian Selnes, Suhwang Kim, +Thiago Santos, Thibault Saunier, Thijs Vermeir, Thomas Bluemel, Thomas Roos, +Thomas Vander Stichele, Tim-Philipp Müller, Tim Sheridan, Ting-Wei Lan, +Tom Deseyn, Vanessa Chipirrás Navalón, Víctor Manuel Jáquez Leal, +Vincent Dehors, Vincent Penquerc'h, Vineeth T M, Vivia Nikolaidou, +Wang Xin-yu (王昕宇), William Manley, Wim Taymans, Wonchul Lee, Xavi Artigas, +Xavier Claessens, Youness Alaoui, + +... and many others who have contributed bug reports, translations, sent +suggestions or helped testing. + +## Bugs fixed in 1.8 + +More than [~700 bugs][bugs-fixed-in-1.8] have been fixed during +the development of 1.8. + +This list does not include issues that have been cherry-picked into the +stable 1.6 branch and fixed there as well, all fixes that ended up in the +1.6 branch are also included in 1.8. + +This list also does not include issues that have been fixed without a bug +report in bugzilla, so the actual number of fixes is much higher. + +[bugs-fixed-in-1.8]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=107311&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.6.1&target_milestone=1.6.2&target_milestone=1.6.3&target_milestone=1.7.0&target_milestone=1.7.1&target_milestone=1.7.2&target_milestone=1.7.3&target_milestone=1.7.4&target_milestone=1.7.90&target_milestone=1.7.91&target_milestone=1.7.92&target_milestone=1.7.x&target_milestone=1.8.0 + +## Stable 1.8 branch + +After the 1.8.0 release there will be several 1.8.x bug-fix releases which +will contain bug fixes which have been deemed suitable for a stable branch, +but no new features or intrusive changes will be added to a bug-fix release +usually. The 1.8.x bug-fix releases will be made from the git 1.8 branch, which +is a stable branch. + +### 1.8.0 + +1.8.0 was released on 24 March 2016. + +### 1.8.1 + +The first 1.8 bug-fix release (1.8.1) is planned for April 2016. + +## Schedule for 1.10 + +Our next major feature release will be 1.10, and 1.9 will be the unstable +development version leading up to the stable 1.10 release. The development +of 1.9/1.10 will happen in the git master branch. + +The plan for the 1.10 development cycle is yet to be confirmed, but it is +expected that feature freeze will be around late July or early August, +followed by several 1.9 pre-releases and the new 1.10 stable release +in September. + +1.10 will be backwards-compatible to the stable 1.8, 1.6, 1.4, 1.2 and 1.0 +release series. + +- - - + +*These release notes have been prepared by Tim-Philipp Müller with +contributions from Sebastian Dröge, Nicolas Dufresne, Edward Hervey, Víctor +Manuel Jáquez Leal, Arun Raghavan, Thiago Santos, Thibault Saunier, Jan +Schmidt and Matthew Waters.* + +*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* diff --git a/RELEASE b/RELEASE index 1be853d391..eccb206202 100644 --- a/RELEASE +++ b/RELEASE @@ -1,21 +1,21 @@ -Release notes for GStreamer RTSP Server Library 1.7.91 +Release notes for GStreamer RTSP Server Library 1.8.0 -The GStreamer team is pleased to announce the second release candidate of the stable +The GStreamer team is pleased to announce the first release of the new stable 1.8 release series. The 1.8 release series is adding new features on top of -the 1.0, 1.2, 1.4 and 1.6 series and is part of the API and ABI-stable 1.x release -series of the GStreamer multimedia framework. +the 1.0, 1.2, 1.4 and 1.6 series and is part of the API and ABI-stable 1.x +release series of the GStreamer multimedia framework. -Binaries for Android, iOS, Mac OS X and Windows will be provided separately -during the stable 1.8 release series. - +Binaries for Android, iOS, Mac OS X and Windows will be provided shortly after +the source release by the GStreamer project during the stable 1.8 release +series. Bugs fixed in this release - * 763281 : RTSP RECORD: pipeline never prerolls + * 740509 : Seek fail with test-uri ==== Download ==== @@ -52,7 +52,5 @@ subscribe to the gstreamer-devel list. Contributors to this release - * Jan Schmidt - * Patricia Muscalu * Sebastian Dröge   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 11e273969f..20ceb0ac12 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.7.91], +AC_INIT([GStreamer RTSP Server Library], [1.8.0], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 791, 0, 791) +AS_LIBTOOL(GST, 800, 0, 800) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.7.91 -GSTPB_REQ=1.7.91 -GSTPG_REQ=1.7.91 -GSTPD_REQ=1.7.91 +GST_REQ=1.8.0 +GSTPB_REQ=1.8.0 +GSTPG_REQ=1.8.0 +GSTPD_REQ=1.8.0 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 4f113ee687..09f4cec823 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.8.0 + master + + 2016-03-24 + + + + 1.7.91 From 37a1ed5d1649fb17154d91bef7bf6176b9f471fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Mar 2016 13:33:43 +0200 Subject: [PATCH 1250/1776] Back to development --- configure.ac | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 20ceb0ac12..bdd96b0838 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.8.0], +AC_INIT([GStreamer RTSP Server Library], [1.9.0.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 800, 0, 800) +AS_LIBTOOL(GST, 900, 0, 900) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.8.0 -GSTPB_REQ=1.8.0 -GSTPG_REQ=1.8.0 -GSTPD_REQ=1.8.0 +GST_REQ=1.9.0.1 +GSTPB_REQ=1.9.0.1 +GSTPG_REQ=1.9.0.1 +GSTPD_REQ=1.9.0.1 dnl *** autotools stuff **** From 1796ce2f03f54f417ac72de8e8fdc6c0f02c11e5 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Mon, 7 Mar 2016 08:50:01 +0900 Subject: [PATCH 1251/1776] rtspclientsink: use new gst_element_class_add_static_pad_template() https://bugzilla.gnome.org/show_bug.cgi?id=763196 --- gst/rtsp-sink/gstrtspclientsink.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index aeb8342fbd..52d2f78e27 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -612,8 +612,7 @@ gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtsp_client_sink_release_pad); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&rtptemplate)); + gst_element_class_add_static_pad_template (gstelement_class, &rtptemplate); gst_element_class_set_static_metadata (gstelement_class, "RTSP RECORD client", "Sink/Network", From 69d04f383809c190ce1383e6ec2ccea3d48b22dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 2 Mar 2016 19:42:13 +0200 Subject: [PATCH 1252/1776] rtsp-media: Add support for setting the multicast interface https://bugzilla.gnome.org/show_bug.cgi?id=763000 --- gst/rtsp-server/rtsp-media-factory.c | 65 +++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 3 ++ gst/rtsp-server/rtsp-media.c | 63 ++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 3 ++ gst/rtsp-server/rtsp-stream.c | 73 +++++++++++++++++++++++++++- gst/rtsp-server/rtsp-stream.h | 3 ++ 6 files changed, 208 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index cb4fe753ee..8bfc422d8f 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -61,6 +61,7 @@ struct _GstRTSPMediaFactoryPrivate GstRTSPAddressPool *pool; GstRTSPTransportMode transport_mode; gboolean stop_on_disconnect; + gchar *multicast_iface; GstClockTime rtx_time; guint latency; @@ -282,6 +283,7 @@ gst_rtsp_media_factory_finalize (GObject * obj) g_mutex_clear (&priv->lock); if (priv->pool) g_object_unref (priv->pool); + g_free (priv->multicast_iface); G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj); } @@ -796,6 +798,64 @@ gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_set_multicast_iface: + * @media_factory: a #GstRTSPMediaFactory + * @multicast_iface: (transfer none): a multicast interface + * + * configure @multicast_iface to be used for @media_factory. + */ +void +gst_rtsp_media_factory_set_multicast_iface (GstRTSPMediaFactory * media_factory, + const gchar * multicast_iface) +{ + GstRTSPMediaFactoryPrivate *priv; + gchar *old; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (media_factory)); + + priv = media_factory->priv; + + GST_LOG_OBJECT (media_factory, "set multicast interface %s", multicast_iface); + + g_mutex_lock (&priv->lock); + if ((old = priv->multicast_iface) != multicast_iface) + priv->multicast_iface = multicast_iface ? g_strdup (multicast_iface) : NULL; + else + old = NULL; + g_mutex_unlock (&priv->lock); + + if (old) + g_object_unref (old); +} + +/** + * gst_rtsp_media_factory_get_multicast_iface: + * @media_factory: a #GstRTSPMediaFactory + * + * Get the multicast interface used for @media_factory. + * + * Returns: (transfer full): the multicast interface for @media_factory. g_free() after + * usage. + */ +gchar * +gst_rtsp_media_factory_get_multicast_iface (GstRTSPMediaFactory * media_factory) +{ + GstRTSPMediaFactoryPrivate *priv; + gchar *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (media_factory), NULL); + + priv = media_factory->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->multicast_iface)) + result = g_strdup (result); + g_mutex_unlock (&priv->lock); + + return result; +} + /** * gst_rtsp_media_factory_set_profiles: * @factory: a #GstRTSPMediaFactory @@ -1419,6 +1479,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) guint latency; GstRTSPTransportMode transport_mode; GstClock *clock; + gchar *multicast_iface; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -1455,6 +1516,10 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_address_pool (media, pool); g_object_unref (pool); } + if ((multicast_iface = gst_rtsp_media_factory_get_multicast_iface (factory))) { + gst_rtsp_media_set_multicast_iface (media, multicast_iface); + g_free (multicast_iface); + } if ((perms = gst_rtsp_media_factory_get_permissions (factory))) { gst_rtsp_media_set_permissions (media, perms); gst_rtsp_permissions_unref (perms); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index c4e0a8e827..f0b6bd57ee 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -142,6 +142,9 @@ void gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFacto GstRTSPAddressPool * pool); GstRTSPAddressPool * gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory); +void gst_rtsp_media_factory_set_multicast_iface (GstRTSPMediaFactory *factory, const gchar *multicast_iface); +gchar * gst_rtsp_media_factory_get_multicast_iface (GstRTSPMediaFactory *factory); + void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint size); guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 9e49c5d357..4fb6d5127b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -100,6 +100,7 @@ struct _GstRTSPMediaPrivate gboolean eos_shutdown; guint buffer_size; GstRTSPAddressPool *pool; + gchar *multicast_iface; gboolean blocked; GstRTSPTransportMode transport_mode; gboolean stop_on_disconnect; @@ -443,6 +444,7 @@ gst_rtsp_media_finalize (GObject * obj) g_object_unref (priv->pool); if (priv->payloads) g_list_free (priv->payloads); + g_free (priv->multicast_iface); g_mutex_clear (&priv->lock); g_cond_clear (&priv->cond); g_rec_mutex_clear (&priv->state_lock); @@ -1496,6 +1498,66 @@ gst_rtsp_media_get_address_pool (GstRTSPMedia * media) return result; } +/** + * gst_rtsp_media_set_multicast_iface: + * @media: a #GstRTSPMedia + * @multicast_iface: (transfer none): a multicast interface + * + * configure @multicast_iface to be used for @media. + */ +void +gst_rtsp_media_set_multicast_iface (GstRTSPMedia * media, + const gchar * multicast_iface) +{ + GstRTSPMediaPrivate *priv; + gchar *old; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + GST_LOG_OBJECT (media, "set multicast interface %s", multicast_iface); + + g_mutex_lock (&priv->lock); + if ((old = priv->multicast_iface) != multicast_iface) + priv->multicast_iface = multicast_iface ? g_strdup (multicast_iface) : NULL; + else + old = NULL; + g_ptr_array_foreach (priv->streams, + (GFunc) gst_rtsp_stream_set_multicast_iface, (gchar *) multicast_iface); + g_mutex_unlock (&priv->lock); + + if (old) + g_object_unref (old); +} + +/** + * gst_rtsp_media_get_multicast_iface: + * @media: a #GstRTSPMedia + * + * Get the multicast interface used for @media. + * + * Returns: (transfer full): the multicast interface for @media. g_free() after + * usage. + */ +gchar * +gst_rtsp_media_get_multicast_iface (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + gchar *result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->multicast_iface)) + result = g_strdup (result); + g_mutex_unlock (&priv->lock); + + return result; +} + static GList * _find_payload_types (GstRTSPMedia * media) { @@ -1677,6 +1739,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, stream = gst_rtsp_stream_new (idx, payloader, ghostpad); if (priv->pool) gst_rtsp_stream_set_address_pool (stream, priv->pool); + gst_rtsp_stream_set_multicast_iface (stream, priv->multicast_iface); gst_rtsp_stream_set_profiles (stream, priv->profiles); gst_rtsp_stream_set_protocols (stream, priv->protocols); gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 400c12367b..c0de06c7c7 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -207,6 +207,9 @@ gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media); void gst_rtsp_media_set_address_pool (GstRTSPMedia *media, GstRTSPAddressPool *pool); GstRTSPAddressPool * gst_rtsp_media_get_address_pool (GstRTSPMedia *media); +void gst_rtsp_media_set_multicast_iface (GstRTSPMedia *media, const gchar *multicast_iface); +gchar * gst_rtsp_media_get_multicast_iface (GstRTSPMedia *media); + void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size); guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index faa76fe900..999718148b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -140,6 +140,8 @@ struct _GstRTSPStreamPrivate gboolean have_ipv4_mcast; gboolean have_ipv6_mcast; + gchar *multicast_iface; + /* the caps of the stream */ gulong caps_sig; GstCaps *caps; @@ -293,6 +295,8 @@ gst_rtsp_stream_finalize (GObject * obj) if (priv->rtxsend) g_object_unref (priv->rtxsend); + g_free (priv->multicast_iface); + gst_object_unref (priv->payloader); if (priv->srcpad) gst_object_unref (priv->srcpad); @@ -861,6 +865,65 @@ gst_rtsp_stream_get_address_pool (GstRTSPStream * stream) return result; } +/** + * gst_rtsp_stream_set_multicast_iface: + * @stream: a #GstRTSPStream + * @multicast_iface: (transfer none): a multicast interface + * + * configure @multicast_iface to be used for @stream. + */ +void +gst_rtsp_stream_set_multicast_iface (GstRTSPStream * stream, + const gchar * multicast_iface) +{ + GstRTSPStreamPrivate *priv; + gchar *old; + + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + priv = stream->priv; + + GST_LOG_OBJECT (stream, "set multicast iface %s", + GST_STR_NULL (multicast_iface)); + + g_mutex_lock (&priv->lock); + if ((old = priv->multicast_iface) != multicast_iface) + priv->multicast_iface = multicast_iface ? g_strdup (multicast_iface) : NULL; + else + old = NULL; + g_mutex_unlock (&priv->lock); + + if (old) + g_free (old); +} + +/** + * gst_rtsp_stream_get_multicast_iface: + * @stream: a #GstRTSPStream + * + * Get the multicast interface used for @stream. + * + * Returns: (transfer full): the multicast interface for @stream. g_free() after + * usage. + */ +gchar * +gst_rtsp_stream_get_multicast_iface (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + gchar *result; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if ((result = priv->multicast_iface)) + result = g_strdup (result); + g_mutex_unlock (&priv->lock); + + return result; +} + /** * gst_rtsp_stream_get_multicast_address: * @stream: a #GstRTSPStream @@ -1145,7 +1208,7 @@ static gboolean create_and_configure_udpsources_one_family (GstElement * udpsrc_out[2], GSocket * rtp_socket, GSocket * rtcp_socket, GSocketFamily family, const gchar * address, gint rtpport, gint rtcpport, - GstRTSPLowerTrans transport) + const gchar * multicast_iface, GstRTSPLowerTrans transport) { GstStateChangeReturn ret; @@ -1160,6 +1223,10 @@ create_and_configure_udpsources_one_family (GstElement * udpsrc_out[2], g_object_set (G_OBJECT (udpsrc_out[1]), "address", address, NULL); g_object_set (G_OBJECT (udpsrc_out[0]), "port", rtpport, NULL); g_object_set (G_OBJECT (udpsrc_out[1]), "port", rtcpport, NULL); + g_object_set (G_OBJECT (udpsrc_out[0]), "multicast-iface", multicast_iface, + NULL); + g_object_set (G_OBJECT (udpsrc_out[1]), "multicast-iface", multicast_iface, + NULL); g_object_set (G_OBJECT (udpsrc_out[0]), "loop", FALSE, NULL); g_object_set (G_OBJECT (udpsrc_out[1]), "loop", FALSE, NULL); } @@ -1208,6 +1275,7 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GSocketAddress *rtcp_sockaddr = NULL; GstRTSPAddressPool *pool; GstRTSPLowerTrans transport; + const gchar *multicast_iface = priv->multicast_iface; pool = priv->pool; count = 0; @@ -1339,7 +1407,8 @@ again: g_clear_object (&inetaddr); if (!create_and_configure_udpsources_one_family (udpsrc_out, rtp_socket, - rtcp_socket, family, addr_str, tmp_rtp, tmp_rtcp, transport)) { + rtcp_socket, family, addr_str, tmp_rtp, tmp_rtcp, multicast_iface, + transport)) { if (addr == NULL) g_free (addr_str); goto no_udp_protocol; diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 46304ac817..c347cb8346 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -96,6 +96,9 @@ void gst_rtsp_stream_set_address_pool (GstRTSPStream *stream, GstRT GstRTSPAddressPool * gst_rtsp_stream_get_address_pool (GstRTSPStream *stream); +void gst_rtsp_stream_set_multicast_iface (GstRTSPStream *stream, const gchar * multicast_iface); +gchar * gst_rtsp_stream_get_multicast_iface (GstRTSPStream *stream); + GstRTSPAddress * gst_rtsp_stream_reserve_address (GstRTSPStream *stream, const gchar * address, guint port, From b63a6f029f478a859ac6dc6ac1d422072fdc70a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 2 Mar 2016 19:42:58 +0200 Subject: [PATCH 1253/1776] rtspclientsink: Add support for setting the multicast interface https://bugzilla.gnome.org/show_bug.cgi?id=763000 --- gst/rtsp-sink/gstrtspclientsink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 52d2f78e27..63cdbc396a 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -923,6 +923,7 @@ gst_rtsp_client_sink_create_stream (GstRTSPClientSink * sink, gst_rtsp_stream_set_buffer_size (stream, sink->udp_buffer_size); if (sink->rtp_blocksize > 0) gst_rtsp_stream_set_mtu (stream, sink->rtp_blocksize); + gst_rtsp_stream_set_multicast_iface (stream, sink->multi_iface); #if 0 if (priv->pool) From 9fab555cc598d701b8911926193f8005471e2ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 30 Dec 2015 18:39:05 +0200 Subject: [PATCH 1254/1776] rtsp-server: Implement clock signalling according to RFC7273 For NTP and PTP clocks we signal the actual clock that is used and signal the direct media clock offset. For all other clocks we at least signal that it's the local sender clock. This allows receivers to know which clock was used to generate the media and its RTP timestamps. Receivers can then implement network synchronization, either absolute or at least relative by getting the sender clock rate directly via NTP/PTP instead of estimating it from RTP timestamps and packet receive times. https://bugzilla.gnome.org/show_bug.cgi?id=760005 --- gst/rtsp-server/rtsp-client.c | 18 ++++++ gst/rtsp-server/rtsp-media-factory.c | 51 +++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 3 + gst/rtsp-server/rtsp-media.c | 92 +++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 21 ++++++ gst/rtsp-server/rtsp-sdp.c | 95 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.c | 77 ++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 6 ++ 8 files changed, 363 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 7258d77569..c77e3598d4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1042,10 +1042,12 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPSession *session; GstRTSPClientClass *klass; GstRTSPSessionMedia *sessmedia; + GstRTSPMedia *media; GstRTSPStatusCode code; GstRTSPState rtspstate; gchar *path; gint matched; + guint i, n; if (!(session = ctx->session)) goto no_session; @@ -1066,6 +1068,16 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) g_free (path); + media = gst_rtsp_session_media_get_media (sessmedia); + n = gst_rtsp_media_n_streams (media); + for (i = 0; i < n; i++) { + GstRTSPStream *stream = gst_rtsp_media_get_stream (media, i); + + if (gst_rtsp_stream_get_publish_clock_mode (stream) == + GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET) + goto not_supported; + } + ctx->sessmedia = sessmedia; rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); @@ -1126,6 +1138,12 @@ invalid_state: ctx); return FALSE; } +not_supported: + { + GST_ERROR ("client %p: pausing not supported", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + return FALSE; + } } /* convert @url and @path to a URL used as a content base for the factory diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 8bfc422d8f..8665c47cdf 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -72,6 +72,8 @@ struct _GstRTSPMediaFactoryPrivate GType media_gtype; GstClock *clock; + + GstRTSPPublishClockMode publish_clock_mode; }; #define DEFAULT_LAUNCH NULL @@ -261,6 +263,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->latency = DEFAULT_LATENCY; priv->transport_mode = DEFAULT_TRANSPORT_MODE; priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; + priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; g_mutex_init (&priv->lock); g_mutex_init (&priv->medias_lock); @@ -1335,6 +1338,51 @@ gst_rtsp_media_factory_get_clock (GstRTSPMediaFactory * factory) return ret; } +/** + * gst_rtsp_media_factory_set_publish_clock_mode: + * @factory: a #GstRTSPMediaFactory + * @mode: the clock publish mode + * + * Sets if and how the media clock should be published according to RFC7273. + * + * Since: 1.8 + */ +void +gst_rtsp_media_factory_set_publish_clock_mode (GstRTSPMediaFactory * factory, + GstRTSPPublishClockMode mode) +{ + GstRTSPMediaFactoryPrivate *priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv = factory->priv; + priv->publish_clock_mode = mode; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_publish_clock_mode: + * @factory: a #GstRTSPMediaFactory + * + * Gets if and how the media clock should be published according to RFC7273. + * + * Returns: The GstRTSPPublishClockMode + * + * Since: 1.8 + */ +GstRTSPPublishClockMode +gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + GstRTSPPublishClockMode ret; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv = factory->priv; + ret = priv->publish_clock_mode; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return ret; +} + static gchar * default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { @@ -1480,6 +1528,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstRTSPTransportMode transport_mode; GstClock *clock; gchar *multicast_iface; + GstRTSPPublishClockMode publish_clock_mode; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -1494,6 +1543,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) transport_mode = priv->transport_mode; stop_on_disconnect = priv->stop_on_disconnect; clock = priv->clock ? gst_object_ref (priv->clock) : NULL; + publish_clock_mode = priv->publish_clock_mode; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_suspend_mode (media, suspend_mode); @@ -1506,6 +1556,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_latency (media, latency); gst_rtsp_media_set_transport_mode (media, transport_mode); gst_rtsp_media_set_stop_on_disconnect (media, stop_on_disconnect); + gst_rtsp_media_set_publish_clock_mode (media, publish_clock_mode); if (clock) { gst_rtsp_media_set_clock (media, clock); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index f0b6bd57ee..3e8adbc12f 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -168,6 +168,9 @@ void gst_rtsp_media_factory_set_clock (GstRTSPMediaFacto GstClock * clock); GstClock * gst_rtsp_media_factory_get_clock (GstRTSPMediaFactory *factory); +void gst_rtsp_media_factory_set_publish_clock_mode (GstRTSPMediaFactory * factory, GstRTSPPublishClockMode mode); +GstRTSPPublishClockMode gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory); + /* creating the media from the factory and a url */ GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4fb6d5127b..c08b2a9d91 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -141,6 +141,7 @@ struct _GstRTSPMediaPrivate GstClockTime rtx_time; /* protected by lock */ guint latency; /* protected by lock */ GstClock *clock; /* protected by lock */ + GstRTSPPublishClockMode publish_clock_mode; }; #define DEFAULT_SHARED FALSE @@ -264,6 +265,29 @@ gst_rtsp_transport_mode_get_type (void) return (GType) id; } +GType +gst_rtsp_publish_clock_mode_get_type (void) +{ + static gsize id = 0; + static const GEnumValue values[] = { + {C_ENUM (GST_RTSP_PUBLISH_CLOCK_MODE_NONE), + "GST_RTSP_PUBLISH_CLOCK_MODE_NONE", "none"}, + {C_ENUM (GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK), + "GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK", + "clock"}, + {C_ENUM (GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET), + "GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET", + "clock-and-offset"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&id)) { + GType tmp = g_enum_register_static ("GstRTSPPublishClockMode", values); + g_once_init_leave (&id, tmp); + } + return (GType) id; +} + G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); static void @@ -415,6 +439,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->time_provider = DEFAULT_TIME_PROVIDER; priv->transport_mode = DEFAULT_TRANSPORT_MODE; priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; + priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; } static void @@ -1438,6 +1463,59 @@ gst_rtsp_media_set_clock (GstRTSPMedia * media, GstClock * clock) g_mutex_unlock (&priv->lock); } +/** + * gst_rtsp_media_set_publish_clock_mode: + * @media: a #GstRTSPMedia + * @mode: the clock publish mode + * + * Sets if and how the media clock should be published according to RFC7273. + * + * Since: 1.8 + */ +void +gst_rtsp_media_set_publish_clock_mode (GstRTSPMedia * media, + GstRTSPPublishClockMode mode) +{ + GstRTSPMediaPrivate *priv; + guint i, n; + + priv = media->priv; + g_mutex_lock (&priv->lock); + priv->publish_clock_mode = mode; + + n = priv->streams->len; + for (i = 0; i < n; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + + gst_rtsp_stream_set_publish_clock_mode (stream, mode); + } + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_get_publish_clock_mode: + * @factory: a #GstRTSPMedia + * + * Gets if and how the media clock should be published according to RFC7273. + * + * Returns: The GstRTSPPublishClockMode + * + * Since: 1.8 + */ +GstRTSPPublishClockMode +gst_rtsp_media_get_publish_clock_mode (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + GstRTSPPublishClockMode ret; + + priv = media->priv; + g_mutex_lock (&priv->lock); + ret = priv->publish_clock_mode; + g_mutex_unlock (&priv->lock); + + return ret; +} + /** * gst_rtsp_media_set_address_pool: * @media: a #GstRTSPMedia @@ -1744,6 +1822,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, gst_rtsp_stream_set_protocols (stream, priv->protocols); gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time); gst_rtsp_stream_set_buffer_size (stream, priv->buffer_size); + gst_rtsp_stream_set_publish_clock_mode (stream, priv->publish_clock_mode); g_ptr_array_add (priv->streams, stream); @@ -2072,6 +2151,18 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) /* TODO: Seeking for RECORD? */ priv->seekable = FALSE; } else { + guint i, n = priv->streams->len; + + for (i = 0; i < n; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + + if (gst_rtsp_stream_get_publish_clock_mode (stream) == + GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET) { + priv->seekable = FALSE; + goto not_seekable; + } + } + query = gst_query_new_seeking (GST_FORMAT_TIME); if (gst_element_query (priv->pipeline, query)) { GstFormat format; @@ -2081,6 +2172,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) gst_query_parse_seeking (query, &format, &seekable, &start, &end); priv->seekable = seekable; } + gst_query_unref (query); } diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index c0de06c7c7..d004b5e52e 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -88,12 +88,29 @@ typedef enum { GST_RTSP_TRANSPORT_MODE_RECORD = 2, } GstRTSPTransportMode; +/** + * GstRTSPPublishClockMode: + * @GST_RTSP_PUBLISH_CLOCK_MODE_NONE: Publish nothing + * @GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK: Publish the clock but not the offset + * @GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET: Publish the clock and offset + * + * Whether the clock and possibly RTP/clock offset should be published according to RFC7273. + */ +typedef enum { + GST_RTSP_PUBLISH_CLOCK_MODE_NONE, + GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK, + GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET +} GstRTSPPublishClockMode; + #define GST_TYPE_RTSP_TRANSPORT_MODE (gst_rtsp_transport_mode_get_type()) GType gst_rtsp_transport_mode_get_type (void); #define GST_TYPE_RTSP_SUSPEND_MODE (gst_rtsp_suspend_mode_get_type()) GType gst_rtsp_suspend_mode_get_type (void); +#define GST_TYPE_RTSP_PUBLISH_CLOCK_MODE (gst_rtsp_publish_clock_mode_get_type()) +GType gst_rtsp_publish_clock_mode_get_type (void); + #include "rtsp-stream.h" #include "rtsp-thread-pool.h" #include "rtsp-permissions.h" @@ -226,6 +243,10 @@ GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media, void gst_rtsp_media_set_clock (GstRTSPMedia *media, GstClock * clock); + +void gst_rtsp_media_set_publish_clock_mode (GstRTSPMedia * media, GstRTSPPublishClockMode mode); +GstRTSPPublishClockMode gst_rtsp_media_get_publish_clock_mode (GstRTSPMedia * media); + /* prepare the media for playback */ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media, GstRTSPThread *thread); gboolean gst_rtsp_media_unprepare (GstRTSPMedia *media); diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 950a1eba1f..348cab3310 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -26,6 +26,7 @@ #include +#include #include #include "rtsp-sdp.h" @@ -169,6 +170,100 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, gst_mikey_message_unref (mikey_msg); } + /* RFC 7273 clock signalling */ + { + GstBin *joined_bin = gst_rtsp_stream_get_joined_bin (stream); + GstClock *clock = gst_element_get_clock (GST_ELEMENT_CAST (joined_bin)); + gchar *ts_refclk = NULL; + gchar *mediaclk = NULL; + guint rtptime, clock_rate; + GstClockTime running_time, base_time, clock_time; + GstRTSPPublishClockMode publish_clock_mode = + gst_rtsp_stream_get_publish_clock_mode (stream); + + gst_rtsp_stream_get_rtpinfo (stream, &rtptime, NULL, &clock_rate, + &running_time); + base_time = gst_element_get_base_time (GST_ELEMENT_CAST (joined_bin)); + g_assert (base_time != GST_CLOCK_TIME_NONE); + clock_time = running_time + base_time; + + if (publish_clock_mode != GST_RTSP_PUBLISH_CLOCK_MODE_NONE && clock) { + if (GST_IS_NTP_CLOCK (clock) || GST_IS_PTP_CLOCK (clock)) { + if (publish_clock_mode == GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET) { + guint32 mediaclk_offset; + + /* Calculate RTP time at the clock's epoch. That's the direct offset */ + clock_time = + gst_util_uint64_scale (clock_time, clock_rate, GST_SECOND); + + clock_time &= 0xffffffff; + mediaclk_offset = + G_GUINT64_CONSTANT (0xffffffff) + rtptime - clock_time; + mediaclk = g_strdup_printf ("direct=%u", (guint32) mediaclk_offset); + } + + if (GST_IS_NTP_CLOCK (clock)) { + gchar *ntp_address; + guint ntp_port; + + g_object_get (clock, "address", &ntp_address, "port", &ntp_port, + NULL); + + if (ntp_port == 123) + ts_refclk = g_strdup_printf ("ntp=%s", ntp_address); + else + ts_refclk = g_strdup_printf ("ntp=%s:%u", ntp_address, ntp_port); + + g_free (ntp_address); + } else { + guint64 ptp_clock_id; + guint ptp_domain; + + g_object_get (clock, "grandmaster-clock-id", &ptp_clock_id, "domain", + &ptp_domain, NULL); + + if (ptp_domain != 0) + ts_refclk = + g_strdup_printf + ("ptp=IEEE1588-2008:%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X:%u", + (guint) (ptp_clock_id >> 56) & 0xff, + (guint) (ptp_clock_id >> 48) & 0xff, + (guint) (ptp_clock_id >> 40) & 0xff, + (guint) (ptp_clock_id >> 32) & 0xff, + (guint) (ptp_clock_id >> 24) & 0xff, + (guint) (ptp_clock_id >> 16) & 0xff, + (guint) (ptp_clock_id >> 8) & 0xff, + (guint) (ptp_clock_id >> 0) & 0xff, ptp_domain); + else + ts_refclk = + g_strdup_printf + ("ptp=IEEE1588-2008:%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", + (guint) (ptp_clock_id >> 56) & 0xff, + (guint) (ptp_clock_id >> 48) & 0xff, + (guint) (ptp_clock_id >> 40) & 0xff, + (guint) (ptp_clock_id >> 32) & 0xff, + (guint) (ptp_clock_id >> 24) & 0xff, + (guint) (ptp_clock_id >> 16) & 0xff, + (guint) (ptp_clock_id >> 8) & 0xff, + (guint) (ptp_clock_id >> 0) & 0xff); + } + } + } + if (clock) + gst_object_unref (clock); + + if (!ts_refclk) + ts_refclk = g_strdup ("local"); + if (!mediaclk) + mediaclk = g_strdup ("sender"); + + gst_sdp_media_add_attribute (smedia, "ts-refclk", ts_refclk); + gst_sdp_media_add_attribute (smedia, "mediaclk", mediaclk); + g_free (ts_refclk); + g_free (mediaclk); + gst_object_unref (joined_bin); + } + update_sdp_from_tags (stream, smedia); if ((profile == GST_RTSP_PROFILE_AVPF || profile == GST_RTSP_PROFILE_SAVPF) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 999718148b..a847935c38 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -71,6 +71,7 @@ struct _GstRTSPStreamPrivate GstElement *payloader; guint buffer_size; gboolean is_joined; + GstBin *joined_bin; /* TRUE if this stream is running on * the client side of an RTSP link (for RECORD) */ @@ -164,6 +165,8 @@ struct _GstRTSPStreamPrivate /* pt->caps map for RECORD streams */ GHashTable *ptmap; + + GstRTSPPublishClockMode publish_clock_mode; }; #define DEFAULT_CONTROL NULL @@ -259,6 +262,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->control = g_strdup (DEFAULT_CONTROL); priv->profiles = DEFAULT_PROFILES; priv->protocols = DEFAULT_PROTOCOLS; + priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; g_mutex_init (&priv->lock); @@ -2281,6 +2285,51 @@ gst_rtsp_stream_set_pt_map (GstRTSPStream * stream, guint pt, GstCaps * caps) g_mutex_unlock (&priv->lock); } +/** + * gst_rtsp_stream_set_publish_clock_mode: + * @stream: a #GstRTSPStream + * @mode: the clock publish mode + * + * Sets if and how the stream clock should be published according to RFC7273. + * + * Since: 1.8 + */ +void +gst_rtsp_stream_set_publish_clock_mode (GstRTSPStream * stream, + GstRTSPPublishClockMode mode) +{ + GstRTSPStreamPrivate *priv; + + priv = stream->priv; + g_mutex_lock (&priv->lock); + priv->publish_clock_mode = mode; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_stream_get_publish_clock_mode: + * @factory: a #GstRTSPStream + * + * Gets if and how the stream clock should be published according to RFC7273. + * + * Returns: The GstRTSPPublishClockMode + * + * Since: 1.8 + */ +GstRTSPPublishClockMode +gst_rtsp_stream_get_publish_clock_mode (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + GstRTSPPublishClockMode ret; + + priv = stream->priv; + g_mutex_lock (&priv->lock); + ret = priv->publish_clock_mode; + g_mutex_unlock (&priv->lock); + + return ret; +} + static GstCaps * request_pt_map (GstElement * rtpbin, guint session, guint pt, GstRTSPStream * stream) @@ -2730,6 +2779,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, (GCallback) caps_notify, stream); } + priv->joined_bin = bin; priv->is_joined = TRUE; g_mutex_unlock (&priv->lock); @@ -2839,6 +2889,8 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, if (!priv->is_joined) goto was_not_joined; + priv->joined_bin = NULL; + /* all transports must be removed by now */ if (priv->transports != NULL) goto transports_not_removed; @@ -3013,6 +3065,31 @@ transports_not_removed: } } +/** + * gst_rtsp_stream_get_joined_bin: + * @stream: a #GstRTSPStream + * + * Get the previous joined bin with gst_rtsp_stream_join_bin() or NULL. + * + * Return: (transfer full): the joined bin or NULL. + */ +GstBin * +gst_rtsp_stream_get_joined_bin (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + GstBin *bin = NULL; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + bin = priv->joined_bin ? gst_object_ref (priv->joined_bin) : NULL; + g_mutex_unlock (&priv->lock); + + return bin; +} + /** * gst_rtsp_stream_get_rtpinfo: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index c347cb8346..a6ab1ff278 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -43,6 +43,7 @@ typedef struct _GstRTSPStreamPrivate GstRTSPStreamPrivate; #include "rtsp-stream-transport.h" #include "rtsp-address-pool.h" #include "rtsp-session.h" +#include "rtsp-media.h" /** * GstRTSPStream: @@ -110,6 +111,7 @@ gboolean gst_rtsp_stream_join_bin (GstRTSPStream *stream, GstState state); gboolean gst_rtsp_stream_leave_bin (GstRTSPStream *stream, GstBin *bin, GstElement *rtpbin); +GstBin * gst_rtsp_stream_get_joined_bin (GstRTSPStream *stream); gboolean gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked); @@ -174,6 +176,10 @@ GstElement * gst_rtsp_stream_request_aux_sender (GstRTSPStream * st gboolean gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, GSocketFamily family, GstRTSPTransport *transport, gboolean use_client_setttings); + +void gst_rtsp_stream_set_publish_clock_mode (GstRTSPStream * stream, GstRTSPPublishClockMode mode); +GstRTSPPublishClockMode gst_rtsp_stream_get_publish_clock_mode (GstRTSPStream * stream); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object From 60dd95849fccc35e9e676eebbbbe920811017079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 3 Apr 2016 12:06:29 +0300 Subject: [PATCH 1255/1776] rtsp-server: Use $(GST_NET_LIBS) / $(GST_NET_CFLAGS) --- gst/rtsp-server/Makefile.am | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 4fcd366929..4f6ea8ff33 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -48,12 +48,13 @@ lib_LTLIBRARIES = \ libgstrtspserver_@GST_API_VERSION@_la_SOURCES = \ $(c_sources) -libgstrtspserver_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstrtspserver_@GST_API_VERSION@_la_CFLAGS = \ + $(GST_PLUGINS_BASE_CFLAGS) $(GST_NET_CFLAGS) \ + $(GST_BASE_CFLAGS) $(GST_CFLAGS) libgstrtspserver_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) libgstrtspserver_@GST_API_VERSION@_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(GST_PLUGINS_BASE_LIBS) $(GST_NET_LIBS) $(GST_BASE_LIBS) \ -lgstrtp-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ \ - -lgstnet-@GST_API_VERSION@ \ -lgstsdp-@GST_API_VERSION@ \ -lgstapp-@GST_API_VERSION@ \ $(GST_LIBS) $(GIO_LIBS) $(LIBM) From cf064134eeb672d47bc75f0682e688f5d9ae46b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 4 Apr 2016 12:39:39 +0300 Subject: [PATCH 1256/1776] examples: Clean up CFLAGS/LDADD to link with the correct versions of all libraries --- examples/Makefile.am | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/examples/Makefile.am b/examples/Makefile.am index ca5c913e0d..f27a5ed158 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -14,11 +14,21 @@ noinst_PROGRAMS += test-cgroups LDADD += $(LIBCGROUP_LIBS) endif -test_netclock_LDFLAGS = \ +test_netclock_CFLAGS = \ + $(GST_NET_CFAGS) \ + $(GST_CFLAGS) \ + $(AM_CFLAGS) +test_netclock_LDADD = \ + $(GST_NET_LIBS) \ $(GST_LIBS) \ - -lgstnet-@GST_API_VERSION@ \ - $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la + $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la \ + $(LDADD) -test_netclock_client_LDFLAGS = \ +test_netclock_client_CFLAGS = \ + $(GST_NET_CFAGS) \ + $(GST_CFLAGS) \ + $(AM_CFLAGS) +test_netclock_client_LDADD = \ + $(GST_NET_LIBS) \ $(GST_LIBS) \ - -lgstnet-@GST_API_VERSION@ + $(LDADD) From bfe08411a994030ff0876af94f8155911d420fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 4 Apr 2016 12:58:38 +0300 Subject: [PATCH 1257/1776] examples: Clean up CFLAGS/LDADD even more The internal .la should come first and is part of LDADD, as is GST_CFLAGS/LIBS. --- examples/Makefile.am | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/examples/Makefile.am b/examples/Makefile.am index f27a5ed158..d98d1be421 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -15,20 +15,16 @@ LDADD += $(LIBCGROUP_LIBS) endif test_netclock_CFLAGS = \ - $(GST_NET_CFAGS) \ - $(GST_CFLAGS) \ - $(AM_CFLAGS) + $(AM_CFLAGS) \ + $(GST_NET_CFLAGS) test_netclock_LDADD = \ - $(GST_NET_LIBS) \ - $(GST_LIBS) \ - $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la \ - $(LDADD) + $(LDADD) \ + $(GST_NET_LIBS) test_netclock_client_CFLAGS = \ - $(GST_NET_CFAGS) \ - $(GST_CFLAGS) \ - $(AM_CFLAGS) + $(AM_CFLAGS) \ + $(GST_NET_CFLAGS) test_netclock_client_LDADD = \ - $(GST_NET_LIBS) \ - $(GST_LIBS) \ - $(LDADD) + $(LDADD) \ + $(GST_NET_LIBS) + From f0891e2cdf32489d9a3393188e4782d9f8f91d09 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Wed, 6 Apr 2016 10:09:46 +0200 Subject: [PATCH 1258/1776] rtsp-thread-pool: explained why GSource is a part of ThreadImpl Clarified why it is necessary to add source information to GstRTSPThreadImpl. See the reported bug in GLib: https://bugzilla.gnome.org/show_bug.cgi?id=720186 for more information. https://bugzilla.gnome.org/show_bug.cgi?id=761702 --- gst/rtsp-server/rtsp-thread-pool.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index b9ee37be0a..6c12ac8e66 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -57,6 +57,8 @@ typedef struct _GstRTSPThreadImpl gint reused; GSource *source; + /* FIXME, the source has to be part of GstRTSPThreadImpl, due to a bug in GLib: + * https://bugzilla.gnome.org/show_bug.cgi?id=720186 */ } GstRTSPThreadImpl; GST_DEFINE_MINI_OBJECT_TYPE (GstRTSPThread, gst_rtsp_thread); From 99e6d9c6ccbc07f486a492a0babe5ae6210f3977 Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Thu, 14 Apr 2016 10:05:02 +0100 Subject: [PATCH 1259/1776] Automatic update of common submodule From 6f2d209 to ac2f647 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 6f2d2093e8..ac2f647695 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 6f2d2093e84cc0eb99b634fa281822ebb9507285 +Subproject commit ac2f647695e7bd4b433ea108ee1d0e23901797d4 From aa9a2443a1d303727167b5b253e09e31fea6f09b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 11 Apr 2016 10:55:23 +0300 Subject: [PATCH 1260/1776] rtsp-stream: Always bind to ANY when address is a multicast address and not only on Windows For IPv6 addresses, binding to a multicast group does not work on Linux either. Always bind to ANY and then later join the multicast group. https://bugzilla.gnome.org/show_bug.cgi?id=764679 --- gst/rtsp-server/rtsp-stream.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index a847935c38..810ee1c7cd 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1342,21 +1342,13 @@ again: g_clear_object (&inetaddr); inetaddr = g_inet_address_new_from_string (addr->address); - /* On Windows it's not possible to bind to a multicast address - * but the OS will make sure to filter out all packets that - * arrive not for the multicast address the socket joined. - * - * On Linux and others it is necessary to bind to a multicast - * address to let the OS filter out all packets that are received - * on the same port but for different addresses than the multicast - * address + /* If we're supposed to bind to a multicast address, instead bind + * to ANY and let udpsrc later join the relevant multicast group */ -#ifdef G_OS_WIN32 if (g_inet_address_get_is_multicast (inetaddr)) { g_object_unref (inetaddr); inetaddr = g_inet_address_new_any (family); } -#endif } else { if (tmp_rtp != 0) { tmp_rtp += 2; From fe5f8077c1523206147c746cc40364ea16da669f Mon Sep 17 00:00:00 2001 From: Jake Foytik Date: Mon, 25 Apr 2016 08:55:25 -0400 Subject: [PATCH 1261/1776] rtsp-stream: Fix crash on cleanup with shared media and multiple udpsrc - Unicast udpsrcs are now managed in a hash table. This allows for proper cleanup in with shared streams and fixes a memory leak. - Unicast udpsrcs are now properly cleaned up when shared connections exit. See the update_transport() function. - Create unit test for shared media. https://bugzilla.gnome.org/show_bug.cgi?id=764744 --- gst/rtsp-server/rtsp-stream.c | 301 +++++++++++++++++++--------------- tests/check/gst/rtspserver.c | 120 +++++++++++--- tests/check/gst/stream.c | 40 ++--- 3 files changed, 288 insertions(+), 173 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 810ee1c7cd..27ad5acd0d 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -62,6 +62,18 @@ #define GST_RTSP_STREAM_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_STREAM, GstRTSPStreamPrivate)) +/* Container for udpsrc elements created for a specific RTSPTransport. */ +typedef struct +{ + GstElement *udpsrc[2]; +} GstRTSPStreamUDPSrcs; + +static void +destroy_udp_srcs_func (gpointer data) +{ + g_slice_free (GstRTSPStreamUDPSrcs, (GstRTSPStreamUDPSrcs *) data); +} + struct _GstRTSPStreamPrivate { GMutex lock; @@ -95,16 +107,11 @@ struct _GstRTSPStreamPrivate GstElement *srtpdec; GHashTable *keys; - /* sinks used for sending and receiving RTP and RTCP over ipv4, they share - * sockets */ - GstElement *udpsrc_v4[2]; - /* UDP sources for UDP multicast transports */ - GstElement *udpsrc_mcast_v4[2]; + /* Unicast UDP sources associated with RTSPTransports */ + GHashTable *udpsrcs; - /* sinks used for sending and receiving RTP and RTCP over ipv6, they share - * sockets */ - GstElement *udpsrc_v6[2]; - /* UDP sources for UDP multicast transports */ + /* Only allow one set of IPV4 and IPV6 multicast udpsrcs */ + GstElement *udpsrc_mcast_v4[2]; GstElement *udpsrc_mcast_v6[2]; GstElement *udpqueue[2]; @@ -127,12 +134,10 @@ struct _GstRTSPStreamPrivate /* server ports for sending/receiving over ipv4 */ GstRTSPRange server_port_v4; GstRTSPAddress *server_addr_v4; - gboolean have_ipv4; /* server ports for sending/receiving over ipv6 */ GstRTSPRange server_port_v6; GstRTSPAddress *server_addr_v6; - gboolean have_ipv6; /* multicast addresses */ GstRTSPAddressPool *pool; @@ -270,6 +275,8 @@ gst_rtsp_stream_init (GstRTSPStream * stream) NULL, (GDestroyNotify) gst_caps_unref); priv->ptmap = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) gst_caps_unref); + priv->udpsrcs = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) destroy_udp_srcs_func); } static void @@ -312,6 +319,11 @@ gst_rtsp_stream_finalize (GObject * obj) g_hash_table_unref (priv->keys); g_hash_table_destroy (priv->ptmap); + /* We expect all udpsrcs to be cleaned up by this point. */ + if (g_hash_table_size (priv->udpsrcs) > 0) + g_critical ("Unreffing udpsrcs hash table that contains elements."); + g_hash_table_unref (priv->udpsrcs); + G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); } @@ -1493,42 +1505,63 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, g_mutex_lock (&priv->lock); - if (family == G_SOCKET_FAMILY_IPV4) { - if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - if (priv->have_ipv4_mcast) + if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + if (family == G_SOCKET_FAMILY_IPV4) { + /* Multicast IPV4 */ + if (priv->have_ipv4_mcast) { + result = TRUE; goto done; + } + priv->have_ipv4_mcast = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_mcast_v4, &priv->server_port_v4, ct, &priv->addr_v4, use_client_settings); + result = priv->have_ipv4_mcast; + } else { - priv->have_ipv4 = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, - &priv->server_port_v4, ct, &priv->server_addr_v4, - use_client_settings); - } - } else { - if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - if (priv->have_ipv6_mcast) + /* Multicast IPV6 */ + if (priv->have_ipv6_mcast) { + result = TRUE; goto done; + } + priv->have_ipv6_mcast = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, priv->udpsrc_mcast_v6, &priv->server_port_v6, ct, &priv->addr_v6, use_client_settings); - } else { - if (priv->have_ipv6) - goto done; - priv->have_ipv6 = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, - &priv->server_port_v6, ct, &priv->server_addr_v6, - use_client_settings); + result = priv->have_ipv6_mcast; } + } else { + /* We allow multiple unicast transports, so we must maintain a table of the + * udpsrcs created for them. */ + GstRTSPStreamUDPSrcs *transport_udpsrcs = + g_slice_new0 (GstRTSPStreamUDPSrcs); + + if (family == G_SOCKET_FAMILY_IPV4) { + /* Unicast IPV4 */ + result = + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, + transport_udpsrcs->udpsrc, &priv->server_port_v4, ct, + &priv->server_addr_v4, use_client_settings); + } else { + /* Unicast IPV6 */ + result = + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, + transport_udpsrcs->udpsrc, &priv->server_port_v6, ct, + &priv->server_addr_v6, use_client_settings); + } + + /* If we didn't create any unicast udpsrcs, free the transport_udpsrcs struct. + * Otherwise, add it to the hash table */ + if (transport_udpsrcs->udpsrc[0] == NULL + && transport_udpsrcs->udpsrc[1] == NULL) + g_slice_free (GstRTSPStreamUDPSrcs, transport_udpsrcs); + else + g_hash_table_insert (priv->udpsrcs, ct, transport_udpsrcs); } done: - result = priv->have_ipv4 || priv->have_ipv4_mcast || priv->have_ipv6 || - priv->have_ipv6_mcast; - g_mutex_unlock (&priv->lock); return result; @@ -2586,39 +2619,6 @@ create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) gst_pad_link (pad, priv->recv_sink[i]); gst_object_unref (pad); - if (priv->udpsrc_v4[i]) { - if (priv->srcpad) { - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values. This is only relevant for PLAY pipelines */ - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); - } - /* add udpsrc */ - gst_bin_add (bin, priv->udpsrc_v4[i]); - - /* and link to the funnel v4 */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - } - - if (priv->udpsrc_v6[i]) { - if (priv->srcpad) { - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); - } - gst_bin_add (bin, priv->udpsrc_v6[i]); - - /* and link to the funnel v6 */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - } - if (is_tcp) { /* make and add appsrc */ priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); @@ -2808,51 +2808,50 @@ no_udp_protocol: gst_element_set_state (priv->udpsink[0], GST_STATE_NULL); if (priv->udpsink[1]) gst_element_set_state (priv->udpsink[1], GST_STATE_NULL); - if (priv->udpsrc_v4[0]) { - gst_element_set_state (priv->udpsrc_v4[0], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_v4[0]); - priv->udpsrc_v4[0] = NULL; - } - if (priv->udpsrc_v4[1]) { - gst_element_set_state (priv->udpsrc_v4[1], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_v4[1]); - priv->udpsrc_v4[1] = NULL; - } - if (priv->udpsrc_mcast_v4[0]) { - gst_element_set_state (priv->udpsrc_mcast_v4[0], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_mcast_v4[0]); - priv->udpsrc_mcast_v4[0] = NULL; - } - if (priv->udpsrc_mcast_v4[1]) { - gst_element_set_state (priv->udpsrc_mcast_v4[1], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_mcast_v4[1]); - priv->udpsrc_mcast_v4[1] = NULL; - } - if (priv->udpsrc_v6[0]) { - gst_element_set_state (priv->udpsrc_v6[0], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_v6[0]); - priv->udpsrc_v6[0] = NULL; - } - if (priv->udpsrc_v6[1]) { - gst_element_set_state (priv->udpsrc_v6[1], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_v6[1]); - priv->udpsrc_v6[1] = NULL; - } - if (priv->udpsrc_mcast_v6[0]) { - gst_element_set_state (priv->udpsrc_mcast_v6[0], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_mcast_v6[0]); - priv->udpsrc_mcast_v6[0] = NULL; - } - if (priv->udpsrc_mcast_v6[1]) { - gst_element_set_state (priv->udpsrc_mcast_v6[1], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_mcast_v6[1]); - priv->udpsrc_mcast_v6[1] = NULL; - } + g_mutex_unlock (&priv->lock); return FALSE; } } +/* Must be called with priv->lock. */ +static void +remove_all_unicast_udpsrcs (GstRTSPStream * stream, GstBin * bin) +{ + GstRTSPStreamPrivate *priv; + GHashTableIter iter; + gpointer iter_key, iter_value; + + priv = stream->priv; + + /* Remove all of the unicast udpsrcs */ + g_hash_table_iter_init (&iter, priv->udpsrcs); + while (g_hash_table_iter_next (&iter, &iter_key, &iter_value)) { + GstRTSPStreamUDPSrcs *transport_udpsrcs = + (GstRTSPStreamUDPSrcs *) iter_value; + + for (int i = 0; i < 2; i++) { + if (transport_udpsrcs->udpsrc[i]) { + if (priv->sinkpad || i == 1) { + /* Set udpsrc to NULL now before removing */ + gst_element_set_locked_state (transport_udpsrcs->udpsrc[i], FALSE); + gst_element_set_state (transport_udpsrcs->udpsrc[i], GST_STATE_NULL); + + /* removing them should also nicely release the request + * pads when they finalize */ + gst_bin_remove (bin, transport_udpsrcs->udpsrc[i]); + } else { + /* we need to set the state to NULL before unref */ + gst_element_set_state (transport_udpsrcs->udpsrc[i], GST_STATE_NULL); + gst_object_unref (transport_udpsrcs->udpsrc[i]); + } + } + } + } + + g_hash_table_remove_all (priv->udpsrcs); +} + /** * gst_rtsp_stream_leave_bin: * @stream: a #GstRTSPStream @@ -2910,6 +2909,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); + remove_all_unicast_udpsrcs (stream, bin); for (i = 0; i < 2; i++) { if (priv->udpsink[i]) @@ -2927,21 +2927,6 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, if (priv->appsrc[i]) gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); - if (priv->udpsrc_v4[i]) { - if (priv->sinkpad || i == 1) { - /* and set udpsrc to NULL now before removing */ - gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE); - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); - /* removing them should also nicely release the request - * pads when they finalize */ - gst_bin_remove (bin, priv->udpsrc_v4[i]); - } else { - /* we need to set the state to NULL before unref */ - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_v4[i]); - } - } - if (priv->udpsrc_mcast_v4[i]) { if (priv->sinkpad || i == 1) { /* and set udpsrc to NULL now before removing */ @@ -2956,16 +2941,6 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, } } - if (priv->udpsrc_v6[i]) { - if (priv->sinkpad || i == 1) { - gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE); - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); - gst_bin_remove (bin, priv->udpsrc_v6[i]); - } else { - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_v6[i]); - } - } if (priv->udpsrc_mcast_v6[i]) { if (priv->sinkpad || i == 1) { gst_element_set_locked_state (priv->udpsrc_mcast_v6[i], FALSE); @@ -3006,8 +2981,6 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->recv_sink[i] = NULL; } - priv->udpsrc_v4[i] = NULL; - priv->udpsrc_v6[i] = NULL; priv->udpsrc_mcast_v4[i] = NULL; priv->udpsrc_mcast_v6[i] = NULL; priv->udpsink[i] = NULL; @@ -3378,6 +3351,68 @@ gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer) return ret; } +/* Properly dispose udpsrcs that were created for a given transport. */ +/* Must be called with priv->lock. */ +static void +remove_transport_udpsrcs (GstRTSPStreamPrivate * priv, + const GstRTSPTransport * tr) +{ + /* Remove the udpsrcs associated with this transport. */ + GstRTSPStreamUDPSrcs *transport_udpsrcs = + g_hash_table_lookup (priv->udpsrcs, tr); + if (transport_udpsrcs != NULL) { + for (int i = 0; i < 2; i++) { + if (transport_udpsrcs->udpsrc[i]) { + if (priv->sinkpad || i == 1) { + GstBin *bin; + GstPad *udpsrc_srcpad, *funnel_sinkpad; + + /* We know these udpsrcs are all linked to funnels. Explicitely + * get the funnel src pads so we can properly release them. */ + udpsrc_srcpad = + gst_element_get_static_pad (transport_udpsrcs->udpsrc[i], "src"); + funnel_sinkpad = gst_pad_get_peer (udpsrc_srcpad); + + if (funnel_sinkpad != NULL) { + /* Unlink pads and release funnel's request pad. */ + gst_pad_unlink (udpsrc_srcpad, funnel_sinkpad); + gst_element_release_request_pad (priv->funnel[i], funnel_sinkpad); + gst_object_unref (funnel_sinkpad); + } + gst_object_unref (udpsrc_srcpad); + + /* Set udpsrc to NULL now before removing */ + gst_element_set_locked_state (transport_udpsrcs->udpsrc[i], FALSE); + gst_element_set_state (transport_udpsrcs->udpsrc[i], GST_STATE_NULL); + + /* This udpsrc is expected to be owned by a bin. Get the bin and + * remove our element. */ + bin = GST_BIN (gst_element_get_parent (transport_udpsrcs->udpsrc[i])); + if (bin != NULL) { + gst_bin_remove (bin, transport_udpsrcs->udpsrc[i]); + gst_object_unref (bin); + } else { + GST_ERROR ("Expected this udpsrc element to be part of a bin."); + gst_object_unref (transport_udpsrcs->udpsrc[i]); + } + + } else { + /* we need to set the state to NULL before unref */ + gst_element_set_state (transport_udpsrcs->udpsrc[i], GST_STATE_NULL); + gst_object_unref (transport_udpsrcs->udpsrc[i]); + } + } + } + + /* The udpsrcs are now properly cleaned up. Remove them from the table */ + g_hash_table_remove (priv->udpsrcs, tr); + + } else { + /* This can happen if we're dealing with a multicast transport. */ + GST_INFO ("Could not find udpsrcs associated with this transport."); + } +} + /* must be called with lock */ static gboolean update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, @@ -3426,6 +3461,8 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, g_signal_emit_by_name (priv->udpsink[0], "remove", dest, min, NULL); g_signal_emit_by_name (priv->udpsink[1], "remove", dest, max, NULL); priv->transports = g_list_remove (priv->transports, trans); + + remove_transport_udpsrcs (priv, tr); } priv->transports_cookie++; break; diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index d21bf040db..805b177d0e 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -149,7 +149,7 @@ get_client_ports (GstRTSPRange * range) /* start the tested rtsp server */ static void -start_server (void) +start_server (gboolean set_shared_factory) { GstRTSPMountPoints *mounts; gchar *service; @@ -172,6 +172,7 @@ start_server (void) gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV4, GST_RTSP_ADDRESS_POOL_ANY_IPV4, 6000, 6010, 0); gst_rtsp_media_factory_set_address_pool (factory, pool); + gst_rtsp_media_factory_set_shared (factory, set_shared_factory); gst_object_unref (pool); /* set port to any */ @@ -571,7 +572,7 @@ GST_START_TEST (test_connect) { GstRTSPConnection *conn; - start_server (); + start_server (FALSE); /* connect to server */ conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -597,7 +598,7 @@ GST_START_TEST (test_describe) const gchar *control_video; const gchar *control_audio; - start_server (); + start_server (FALSE); conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -668,7 +669,7 @@ GST_START_TEST (test_describe_non_existing_mount_point) { GstRTSPConnection *conn; - start_server (); + start_server (FALSE); /* send DESCRIBE request for a non-existing mount point * and check that we get a 404 Not Found */ @@ -697,7 +698,7 @@ do_test_setup (GstRTSPLowerTrans lower_transport) GstRTSPTransport *video_transport = NULL; GstRTSPTransport *audio_transport = NULL; - start_server (); + start_server (FALSE); conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -782,7 +783,7 @@ GST_START_TEST (test_setup_twice) gchar *session1 = NULL; gchar *session2 = NULL; - start_server (); + start_server (FALSE); conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -854,7 +855,7 @@ GST_START_TEST (test_setup_with_require_header) gchar *unsupported = NULL; GstRTSPTransport *video_transport = NULL; - start_server (); + start_server (FALSE); conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -916,7 +917,7 @@ GST_START_TEST (test_setup_non_existing_stream) GstRTSPConnection *conn; GstRTSPRange client_ports; - start_server (); + start_server (FALSE); conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -1009,7 +1010,8 @@ done: } static void -do_test_play_full (const gchar * range, GstRTSPLowerTrans lower_transport) +do_test_play_full (const gchar * range, GstRTSPLowerTrans lower_transport, + GMutex * lock) { GstRTSPConnection *conn; GstSDPMessage *sdp_message = NULL; @@ -1051,8 +1053,20 @@ do_test_play_full (const gchar * range, GstRTSPLowerTrans lower_transport) fail_unless_equals_string (range, range_out); g_free (range_out); - receive_rtp (rtp_socket, NULL); - receive_rtcp (rtcp_socket, NULL, 0); + for (;;) { + receive_rtp (rtp_socket, NULL); + receive_rtcp (rtcp_socket, NULL, 0); + + if (lock != NULL) { + if (g_mutex_trylock (lock) == TRUE) { + g_mutex_unlock (lock); + break; + } + } else { + break; + } + + } /* send TEARDOWN request and check that we get 200 OK */ fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, @@ -1076,12 +1090,12 @@ do_test_play_full (const gchar * range, GstRTSPLowerTrans lower_transport) static void do_test_play (const gchar * range) { - do_test_play_full (range, GST_RTSP_LOWER_TRANS_UDP); + do_test_play_full (range, GST_RTSP_LOWER_TRANS_UDP, NULL); } GST_START_TEST (test_play) { - start_server (); + start_server (FALSE); do_test_play (NULL); @@ -1095,7 +1109,7 @@ GST_START_TEST (test_play_without_session) { GstRTSPConnection *conn; - start_server (); + start_server (FALSE); conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -1155,7 +1169,7 @@ GST_START_TEST (test_play_multithreaded) gst_rtsp_thread_pool_set_max_threads (pool, 2); g_object_unref (pool); - start_server (); + start_server (FALSE); do_test_play (NULL); @@ -1215,7 +1229,7 @@ GST_START_TEST (test_play_multithreaded_block_in_describe) gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT "2", factory); g_object_unref (mounts); - start_server (); + start_server (FALSE); conn = connect_to_server (test_port, TEST_MOUNT_POINT "2"); iterate (); @@ -1294,7 +1308,7 @@ GST_START_TEST (test_play_multithreaded_timeout_client) g_signal_connect (server, "client-connected", G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one); - start_server (); + start_server (FALSE); conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -1367,7 +1381,7 @@ GST_START_TEST (test_play_multithreaded_timeout_session) g_signal_connect (server, "client-connected", G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one); - start_server (); + start_server (FALSE); conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -1443,7 +1457,7 @@ GST_START_TEST (test_play_disconnect) g_signal_connect (server, "client-connected", G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one); - start_server (); + start_server (FALSE); conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -1515,7 +1529,8 @@ GST_START_TEST (test_play_specific_server_port) factory = gst_rtsp_media_factory_new (); /* we have to suspend media after SDP in order to make sure that * we can reconfigure UDP sink with new UDP ports */ - gst_rtsp_media_factory_set_suspend_mode (factory, GST_RTSP_SUSPEND_MODE_RESET); + gst_rtsp_media_factory_set_suspend_mode (factory, + GST_RTSP_SUSPEND_MODE_RESET); pool = gst_rtsp_address_pool_new (); gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV4, GST_RTSP_ADDRESS_POOL_ANY_IPV4, 7770, 7780, 0); @@ -1603,7 +1618,7 @@ GST_END_TEST; GST_START_TEST (test_play_smpte_range) { - start_server (); + start_server (FALSE); do_test_play ("npt=5-"); do_test_play ("smpte=0:00:00-"); @@ -1617,6 +1632,65 @@ GST_START_TEST (test_play_smpte_range) GST_END_TEST; +static gpointer +thread_func (gpointer data) +{ + do_test_play_full (NULL, GST_RTSP_LOWER_TRANS_UDP, (GMutex *) data); + return NULL; +} + +/* Test adding and removing clients to a 'Shared' media. */ +GST_START_TEST (test_shared) +{ + GMutex lock1, lock2, lock3, lock4; + GThread *thread1, *thread2, *thread3, *thread4; + + /* Locks for each thread. Each thread will keep reading data as long as the + * thread is locked. */ + g_mutex_init (&lock1); + g_mutex_init (&lock2); + g_mutex_init (&lock3); + g_mutex_init (&lock4); + + start_server (TRUE); + + /* Start the first receiver thread. */ + g_mutex_lock (&lock1); + thread1 = g_thread_new ("thread1", thread_func, &lock1); + + /* Connect and disconnect another client. */ + g_mutex_lock (&lock2); + thread2 = g_thread_new ("thread2", thread_func, &lock2); + g_mutex_unlock (&lock2); + g_mutex_clear (&lock2); + g_thread_join (thread2); + + /* Do it again. */ + g_mutex_lock (&lock3); + thread3 = g_thread_new ("thread3", thread_func, &lock3); + g_mutex_unlock (&lock3); + g_mutex_clear (&lock3); + g_thread_join (thread3); + + /* Disconnect the last client. This will clean up the media. */ + g_mutex_unlock (&lock1); + g_mutex_clear (&lock1); + g_thread_join (thread1); + + /* Connect and disconnect another client. This will create and clean up the + * media. */ + g_mutex_lock (&lock4); + thread4 = g_thread_new ("thread4", thread_func, &lock4); + g_mutex_unlock (&lock4); + g_mutex_clear (&lock4); + g_thread_join (thread4); + + stop_server (); + iterate (); +} + +GST_END_TEST; + GST_START_TEST (test_announce_without_sdp) { GstRTSPConnection *conn; @@ -1749,7 +1823,8 @@ GST_START_TEST (test_record_tcp) gint i; mfactory = - start_record_server ("( rtppcmadepay name=depay0 ! appsink name=sink async=false )"); + start_record_server + ("( rtppcmadepay name=depay0 ! appsink name=sink async=false )"); g_signal_connect (mfactory, "media-constructed", G_CALLBACK (media_constructed_cb), &server_sink); @@ -1926,6 +2001,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_play_disconnect); tcase_add_test (tc, test_play_specific_server_port); tcase_add_test (tc, test_play_smpte_range); + tcase_add_test (tc, test_shared); tcase_add_test (tc, test_announce_without_sdp); tcase_add_test (tc, test_record_tcp); return s; diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index 0fb7e59c4f..26c291582c 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -52,18 +52,20 @@ GST_START_TEST (test_get_sockets) /* configure address pool for IPv4 and IPv6 unicast addresses */ pool = gst_rtsp_address_pool_new (); - fail_unless (gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV4, - GST_RTSP_ADDRESS_POOL_ANY_IPV4, 50000, 60000, 0)); - fail_unless (gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV6, - GST_RTSP_ADDRESS_POOL_ANY_IPV6, 50000, 60000, 0)); + fail_unless (gst_rtsp_address_pool_add_range (pool, + GST_RTSP_ADDRESS_POOL_ANY_IPV4, GST_RTSP_ADDRESS_POOL_ANY_IPV4, 50000, + 60000, 0)); + fail_unless (gst_rtsp_address_pool_add_range (pool, + GST_RTSP_ADDRESS_POOL_ANY_IPV6, GST_RTSP_ADDRESS_POOL_ANY_IPV6, 50000, + 60000, 0)); gst_rtsp_stream_set_address_pool (stream, pool); fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); gst_rtsp_transport_new (&tr); tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP; - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, - tr, FALSE)); + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, + G_SOCKET_FAMILY_IPV4, tr, FALSE)); socket = gst_rtsp_stream_get_rtp_socket (stream, G_SOCKET_FAMILY_IPV4); have_ipv4 = (socket != NULL); @@ -138,7 +140,7 @@ GST_START_TEST (test_allocate_udp_ports_fail) pool = gst_rtsp_address_pool_new (); fail_unless (gst_rtsp_address_pool_add_range (pool, "192.168.1.1", - "192.168.1.1", 6000, 6001, 0)); + "192.168.1.1", 6000, 6001, 0)); gst_rtsp_stream_set_address_pool (stream, pool); fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); @@ -146,7 +148,7 @@ GST_START_TEST (test_allocate_udp_ports_fail) gst_rtsp_transport_new (&tr); tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP; fail_if (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, - tr, FALSE)); + tr, FALSE)); gst_rtsp_transport_free (tr); g_object_unref (pool); @@ -258,8 +260,8 @@ GST_START_TEST (test_multicast_address_and_unicast_udp) gst_rtsp_transport_new (&tr); /* unicast udp */ tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP; - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, - tr, FALSE)); + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, + G_SOCKET_FAMILY_IPV4, tr, FALSE)); gst_rtsp_transport_free (tr); g_object_unref (pool); @@ -309,8 +311,8 @@ GST_START_TEST (test_allocate_udp_ports_multicast) /* allocate udp multicast ports for IPv4 */ gst_rtsp_transport_new (&tr); tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST; - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, - tr, FALSE)); + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, + G_SOCKET_FAMILY_IPV4, tr, FALSE)); /* check the multicast address and ports for IPv4 */ addr = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV4); @@ -320,9 +322,9 @@ GST_START_TEST (test_allocate_udp_ports_multicast) fail_unless_equals_int (addr->n_ports, 2); gst_rtsp_address_free (addr); - /* allocate upd multicast ports for IPv6 */ - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV6, - tr, FALSE)); + /* allocate udp multicast ports for IPv6 */ + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, + G_SOCKET_FAMILY_IPV6, tr, FALSE)); /* check the multicast address and ports for IPv6 */ addr = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV6); @@ -388,8 +390,8 @@ GST_START_TEST (test_allocate_udp_ports_client_settings) tr->port.min = 6002; tr->port.max = 6003; tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST; - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, - tr, FALSE)); + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, + G_SOCKET_FAMILY_IPV4, tr, FALSE)); /* verify that the multicast address and ports correspond to the requested client * transport information for IPv4 */ @@ -405,8 +407,8 @@ GST_START_TEST (test_allocate_udp_ports_client_settings) tr->destination = g_strdup ("FF11:DB8::1"); tr->port.min = 6006; tr->port.max = 6007; - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV6, - tr, FALSE)); + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, + G_SOCKET_FAMILY_IPV6, tr, FALSE)); /* verify that the multicast address and ports correspond to the requested client * transport information for IPv6 */ From 2639fbdb7fa8894eb1c1a0c0f0ddde3e4d2c95b0 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 7 Mar 2016 14:48:38 +0100 Subject: [PATCH 1262/1776] rtspclientsink: Check return value of sscanf And just make sure we always have 0/0 if we have an error CID #1352031 --- gst/rtsp-sink/gstrtspclientsink.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 63cdbc396a..cc3aa96166 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -1345,11 +1345,9 @@ gst_rtsp_client_sink_set_property (GObject * object, guint prop_id, const gchar *str; str = g_value_get_string (value); - if (str) { - sscanf (str, "%u-%u", - &rtsp_client_sink->client_port_range.min, - &rtsp_client_sink->client_port_range.max); - } else { + if (!str || !sscanf (str, "%u-%u", + &rtsp_client_sink->client_port_range.min, + &rtsp_client_sink->client_port_range.max)) { rtsp_client_sink->client_port_range.min = 0; rtsp_client_sink->client_port_range.max = 0; } From 178f2d6fe56668ccd5abdc749c79e04caaff2cfc Mon Sep 17 00:00:00 2001 From: Ian Date: Wed, 18 May 2016 16:48:44 +0100 Subject: [PATCH 1263/1776] rtsp-session: RFC2326 does not allow a space between ; and timeout in the Session header This works with rtspsrc and live555, but fails with e.g. ffmpeg. https://bugzilla.gnome.org/show_bug.cgi?id=766619 --- gst/rtsp-server/rtsp-session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 052537e740..10f5648020 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -488,7 +488,7 @@ gst_rtsp_session_get_header (GstRTSPSession * session) g_mutex_lock (&priv->lock); if (priv->timeout_always_visible || priv->timeout != 60) - result = g_strdup_printf ("%s; timeout=%d", priv->sessionid, priv->timeout); + result = g_strdup_printf ("%s;timeout=%d", priv->sessionid, priv->timeout); else result = g_strdup (priv->sessionid); g_mutex_unlock (&priv->lock); From 7de0d6580a15c18e337278fc8cc8a126919731a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 25 May 2016 10:28:43 +0100 Subject: [PATCH 1264/1776] g-i: pass compiler env to g-ir-scanner It's what introspection.mak does as well. Should fix spurious build failures on gnome-continuous (caused by g-ir-scanner getting compiler details via python which is broken in some environments so passing the compiler details bypasses that). --- gst/rtsp-server/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 4f6ea8ff33..224b48bcb3 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -72,6 +72,7 @@ gir_sources=$(patsubst %,$(srcdir)/%, $(libgstrtspserver_@GST_API_VERSION@_la_SO GstRtspServer-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@GST_API_VERSION@.la $(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \ + CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" CC="$(CC)" PKG_CONFIG="$(PKG_CONFIG)" DLLTOOL="$(DLLTOOL)" \ $(INTROSPECTION_SCANNER) -v --namespace GstRtspServer \ --nsversion=@GST_API_VERSION@ \ --strip-prefix=Gst \ From fc2554404b98df11fb6b498c9ff6875f02580ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 7 Jun 2016 20:44:42 +0100 Subject: [PATCH 1265/1776] docs: fix some typos --- gst/rtsp-server/rtsp-media-factory.h | 4 ++-- gst/rtsp-server/rtsp-server.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 3e8adbc12f..2a6099799f 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -74,8 +74,8 @@ struct _GstRTSPMediaFactory { * add the #GstRTSPMedia's element created by @construct to the pipeline. * @configure: configure the media created with @construct. The default * implementation will configure the 'shared' property of the media. - * @media_constructed: signal emited when a media was constructed - * @media_configure: signal emited when a media should be configured + * @media_constructed: signal emitted when a media was constructed + * @media_configure: signal emitted when a media should be configured * * The #GstRTSPMediaFactory class structure. */ diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 521c0beabd..efb18e4efd 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -77,7 +77,7 @@ struct _GstRTSPServer { * object that handles the new connection on @socket. The default * implementation will create a GstRTSPClient and will configure the * mount-points, auth, session-pool and thread-pool on the client. - * @client_connected: emited when a new client connected. + * @client_connected: emitted when a new client connected. * * The RTSP server class structure */ From 85c52e194bcb81928b96614be0ae47d59eccb1ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Thu, 14 Apr 2016 22:56:11 -0700 Subject: [PATCH 1266/1776] sdp: add rollover counters for all sender SSRC We add different crypto sessions in MIKEY, one for each sender SSRC. Currently, all of them will have the same security policy, 0. The rollover counters are obtained from the srtpenc element using the "stats" property. https://bugzilla.gnome.org/show_bug.cgi?id=730539 --- gst/rtsp-server/rtsp-sdp.c | 177 ++++++++++++++++++++++++++++++---- gst/rtsp-server/rtsp-sdp.h | 4 +- gst/rtsp-server/rtsp-stream.c | 26 +++++ gst/rtsp-server/rtsp-stream.h | 2 + 4 files changed, 186 insertions(+), 23 deletions(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 348cab3310..5e49259d80 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -16,6 +16,9 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ + +#define GLIB_DISABLE_DEPRECATION_WARNINGS + /** * SECTION:rtsp-sdp * @short_description: Make SDP messages @@ -73,7 +76,109 @@ update_sdp_from_tags (GstRTSPStream * stream, GstSDPMedia * stream_media) gst_object_unref (src_pad); } -static void +static guint +get_roc_from_stats (GstStructure * stats, guint ssrc) +{ + const GValue *va, *v; + guint i, len; + /* initialize roc to something different than 0, so if we don't get + the proper ROC from the encoder, streaming should fail initially. */ + guint roc = -1; + + va = gst_structure_get_value (stats, "streams"); + if (!va || !G_VALUE_HOLDS (va, GST_TYPE_ARRAY)) { + GST_WARNING ("stats doesn't have a valid 'streams' field"); + return 0; + } + + len = gst_value_array_get_size (va); + + /* look if there's any SSRC that matches. */ + for (i = 0; i < len; i++) { + GstStructure *stream; + v = gst_value_array_get_value (va, i); + if (v && (stream = g_value_get_boxed (v))) { + guint stream_ssrc; + gst_structure_get_uint (stream, "ssrc", &stream_ssrc); + if (stream_ssrc == ssrc) { + gst_structure_get_uint (stream, "roc", &roc); + break; + } + } + } + + return roc; +} + +static gboolean +mikey_add_crypto_sessions (GstRTSPStream * stream, GstMIKEYMessage * msg) +{ + guint i; + GObject *session; + GstElement *encoder; + GValueArray *sources; + gboolean roc_found; + + encoder = gst_rtsp_stream_get_srtp_encoder (stream); + if (encoder == NULL) { + GST_ERROR ("unable to get SRTP encoder from stream %p", stream); + return FALSE; + } + + session = gst_rtsp_stream_get_rtpsession (stream); + if (session == NULL) { + GST_ERROR ("unable to get RTP session from stream %p", stream); + return FALSE; + } + + roc_found = FALSE; + g_object_get (session, "sources", &sources, NULL); + for (i = 0; sources && (i < sources->n_values); i++) { + GValue *val; + GObject *source; + guint32 ssrc; + gboolean is_sender; + + val = g_value_array_get_nth (sources, i); + source = (GObject *) g_value_get_object (val); + + g_object_get (source, "ssrc", &ssrc, "is-sender", &is_sender, NULL); + + if (is_sender) { + guint32 roc = -1; + GstStructure *stats; + + g_object_get (encoder, "stats", &stats, NULL); + + if (stats) { + roc = get_roc_from_stats (stats, ssrc); + gst_structure_free (stats); + } + + roc_found = !!(roc != -1); + if (!roc_found) { + GST_ERROR ("unable to obtain ROC for stream %p with SSRC %u", + stream, ssrc); + goto cleanup; + } + + GST_INFO ("stream %p with SSRC %u has a ROC of %u", stream, ssrc, roc); + + gst_mikey_message_add_cs_srtp (msg, 0, ssrc, roc); + } + } + +cleanup: + { + g_value_array_free (sources); + + gst_object_unref (encoder); + g_object_unref (session); + return roc_found; + } +} + +static gboolean make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream * stream, GstCaps * caps, GstRTSPProfile profile) { @@ -86,13 +191,12 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, guint ttl; GstClockTime rtx_time; gchar *base64; - guint32 ssrc; GstMIKEYMessage *mikey_msg; gst_sdp_media_new (&smedia); if (gst_sdp_media_set_media_from_caps (caps, smedia) != GST_SDP_OK) { - goto error; + goto caps_error; } gst_sdp_media_set_port_info (smedia, 0, 1); @@ -155,9 +259,9 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, /* check for srtp */ mikey_msg = gst_mikey_message_new_from_caps (caps); if (mikey_msg) { - gst_rtsp_stream_get_ssrc (stream, &ssrc); - /* add policy '0' for our SSRC */ - gst_mikey_message_add_cs_srtp (mikey_msg, 0, ssrc, 0); + /* add policy '0' for all sending SSRC */ + if (!mikey_add_crypto_sessions (stream, mikey_msg)) + goto crypto_sessions_error; base64 = gst_mikey_message_base64_encode (mikey_msg); if (base64) { @@ -281,7 +385,7 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, s = gst_caps_get_structure (caps, 0); if (s == NULL) - goto error; + goto no_caps_info; /* get payload type and clock rate */ gst_structure_get_int (s, "payload", &caps_pt); @@ -306,21 +410,36 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, gst_sdp_message_add_media (sdp, smedia); gst_sdp_media_free (smedia); - return; + return TRUE; /* ERRORS */ +caps_error: + { + gst_sdp_media_free (smedia); + GST_ERROR ("unable to set media from caps for stream %d", + gst_rtsp_stream_get_index (stream)); + return FALSE; + } no_multicast: { gst_sdp_media_free (smedia); - g_warning ("ignoring stream %d without multicast address", + GST_ERROR ("stream %d has no multicast address", gst_rtsp_stream_get_index (stream)); - return; + return FALSE; } -error: +no_caps_info: { gst_sdp_media_free (smedia); - g_warning ("ignoring stream %d", gst_rtsp_stream_get_index (stream)); - return; + GST_ERROR ("caps for stream %d have no structure", + gst_rtsp_stream_get_index (stream)); + return FALSE; + } +crypto_sessions_error: + { + gst_sdp_media_free (smedia); + GST_ERROR ("unable to add MIKEY crypto sessions for stream %d", + gst_rtsp_stream_get_index (stream)); + return FALSE; } } @@ -341,6 +460,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, { guint i, n_streams; gchar *rangestr; + gboolean res; n_streams = gst_rtsp_media_n_streams (media); @@ -351,11 +471,16 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, gst_sdp_message_add_attribute (sdp, "range", rangestr); g_free (rangestr); - for (i = 0; i < n_streams; i++) { + res = TRUE; + for (i = 0; res && (i < n_streams); i++) { GstRTSPStream *stream; stream = gst_rtsp_media_get_stream (media, i); - gst_rtsp_sdp_from_stream (sdp, info, stream); + res = gst_rtsp_sdp_from_stream (sdp, info, stream); + if (!res) { + GST_ERROR ("could not get SDP from stream %p", stream); + goto sdp_error; + } } { @@ -382,7 +507,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info, } } - return TRUE; + return res; /* ERRORS */ not_prepared: @@ -390,6 +515,11 @@ not_prepared: GST_ERROR ("media %p is not prepared", media); return FALSE; } +sdp_error: + { + GST_ERROR ("could not get SDP from media %p", media); + return FALSE; + } } /** @@ -400,32 +530,37 @@ not_prepared: * * Add info from @stream to @sdp. * + * Returns: TRUE on success. */ -void +gboolean gst_rtsp_sdp_from_stream (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream * stream) { GstCaps *caps; GstRTSPProfile profiles; guint mask; + gboolean res; caps = gst_rtsp_stream_get_caps (stream); if (caps == NULL) { - g_warning ("ignoring stream without caps"); - return; + GST_ERROR ("stream %p has no caps", stream); + return FALSE; } /* make a new media for each profile */ profiles = gst_rtsp_stream_get_profiles (stream); mask = 1; - while (profiles >= mask) { + res = TRUE; + while (res && (profiles >= mask)) { GstRTSPProfile prof = profiles & mask; if (prof) - make_media (sdp, info, stream, caps, prof); + res = make_media (sdp, info, stream, caps, prof); mask <<= 1; } gst_caps_unref (caps); + + return res; } diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h index 4a47766f62..b56eb82dc6 100644 --- a/gst/rtsp-server/rtsp-sdp.h +++ b/gst/rtsp-server/rtsp-sdp.h @@ -33,8 +33,8 @@ typedef struct { } GstSDPInfo; /* creating SDP */ -gboolean gst_rtsp_sdp_from_media (GstSDPMessage *sdp, GstSDPInfo *info, GstRTSPMedia * media); -void gst_rtsp_sdp_from_stream (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream *stream); +gboolean gst_rtsp_sdp_from_media (GstSDPMessage *sdp, GstSDPInfo *info, GstRTSPMedia * media); +gboolean gst_rtsp_sdp_from_stream (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream *stream); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 27ad5acd0d..53894562c5 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1671,6 +1671,32 @@ gst_rtsp_stream_get_rtpsession (GstRTSPStream * stream) return session; } +/** + * gst_rtsp_stream_get_encoder: + * @stream: a #GstRTSPStream + * + * Get the SRTP encoder for this stream. + * + * Returns: (transfer full): The SRTP encoder for this stream. Unref after usage. + */ +GstElement * +gst_rtsp_stream_get_srtp_encoder (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + GstElement *encoder; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if ((encoder = priv->srtpenc)) + g_object_ref (encoder); + g_mutex_unlock (&priv->lock); + + return encoder; +} + /** * gst_rtsp_stream_get_ssrc: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index a6ab1ff278..9ef887aa9f 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -129,6 +129,8 @@ GstRTSPAddress * gst_rtsp_stream_get_multicast_address (GstRTSPStream *stream, GObject * gst_rtsp_stream_get_rtpsession (GstRTSPStream *stream); +GstElement * gst_rtsp_stream_get_srtp_encoder (GstRTSPStream *stream); + void gst_rtsp_stream_get_ssrc (GstRTSPStream *stream, guint *ssrc); From 51918ebacbee8ec9d9a20c32b246f5737b79b4b9 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 21 Jun 2016 11:49:02 -0400 Subject: [PATCH 1267/1776] Automatic update of common submodule From ac2f647 to f363b32 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index ac2f647695..f363b32056 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit ac2f647695e7bd4b433ea108ee1d0e23901797d4 +Subproject commit f363b3205658a38e84fa77f19dee218cd4445275 From fc4f171f0fdfbbd164137dfd0ed687809fafa757 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Fri, 24 Jun 2016 02:02:20 +0530 Subject: [PATCH 1268/1776] configure: Need to add -DGST_STATIC_COMPILATION when building only statically https://bugzilla.gnome.org/show_bug.cgi?id=767463 --- configure.ac | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index bdd96b0838..f79c974da5 100644 --- a/configure.ac +++ b/configure.ac @@ -268,7 +268,7 @@ AC_SUBST(GST_OPTION_CFLAGS) dnl FIXME: do we want to rename to GST_ALL_* ? dnl prefer internal headers to already installed ones dnl add GST_OPTION_CFLAGS, but overridable -GST_CFLAGS="$GST_CFLAGS \$(GST_OPTION_CFLAGS)" +GST_CFLAGS="$GST_CFLAGS \$(GST_STATIC_CFLAGS) \$(GST_OPTION_CFLAGS)" AC_SUBST(GST_CFLAGS) AC_SUBST(GST_LIBS) @@ -330,6 +330,13 @@ fi AC_SUBST(GST_PLUGIN_LIBTOOLFLAGS) AM_CONDITIONAL(GST_PLUGIN_BUILD_STATIC, test "x$enable_static_plugins" = "xyes") +dnl If only building static libraries, define GST_STATIC_COMPILATION. This is +dnl needed only on Windows, but it doesn't hurt to have it everywhere. +if test x$enable_static = xyes -a x$enable_shared = xno; then + GST_STATIC_CFLAGS="-DGST_STATIC_COMPILATION" +fi +AC_SUBST(GST_STATIC_CFLAGS) + GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_.*' $GST_ALL_LDFLAGS" AC_SUBST(GST_PLUGIN_LDFLAGS) From 7d4dc8055351dbc2f96bfb97060cbada66e1a896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 6 Jul 2016 13:28:12 +0300 Subject: [PATCH 1269/1776] Release 1.9.1 --- ChangeLog | 173 +++++++++- NEWS | 787 +------------------------------------------ RELEASE | 32 +- configure.ac | 12 +- gst-rtsp-server.doap | 10 + 5 files changed, 210 insertions(+), 804 deletions(-) diff --git a/ChangeLog b/ChangeLog index c88dbf679f..11c0514034 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,176 @@ -=== release 1.8.0 === +=== release 1.9.1 === -2016-03-24 Sebastian Dröge +2016-07-06 Sebastian Dröge * configure.ac: - releasing 1.8.0 + releasing 1.9.1 + +2016-06-24 02:02:20 +0530 Nirbheek Chauhan + + * configure.ac: + configure: Need to add -DGST_STATIC_COMPILATION when building only statically + https://bugzilla.gnome.org/show_bug.cgi?id=767463 + +2016-06-21 11:49:02 -0400 Nicolas Dufresne + + * common: + Automatic update of common submodule + From ac2f647 to f363b32 + +2016-04-14 22:56:11 -0700 Aleix Conchillo Flaqué + + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-sdp.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + sdp: add rollover counters for all sender SSRC + We add different crypto sessions in MIKEY, one for each sender + SSRC. Currently, all of them will have the same security policy, 0. + The rollover counters are obtained from the srtpenc element using the + "stats" property. + https://bugzilla.gnome.org/show_bug.cgi?id=730539 + +2016-06-07 20:44:42 +0100 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-server.h: + docs: fix some typos + +2016-05-25 10:28:43 +0100 Tim-Philipp Müller + + * gst/rtsp-server/Makefile.am: + g-i: pass compiler env to g-ir-scanner + It's what introspection.mak does as well. Should + fix spurious build failures on gnome-continuous + (caused by g-ir-scanner getting compiler details + via python which is broken in some environments + so passing the compiler details bypasses that). + +2016-05-18 16:48:44 +0100 Ian + + * gst/rtsp-server/rtsp-session.c: + rtsp-session: RFC2326 does not allow a space between ; and timeout in the Session header + This works with rtspsrc and live555, but fails with e.g. ffmpeg. + https://bugzilla.gnome.org/show_bug.cgi?id=766619 + +2016-03-07 14:48:38 +0100 Edward Hervey + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Check return value of sscanf + And just make sure we always have 0/0 if we have an error + CID #1352031 + +2016-04-25 08:55:25 -0400 Jake Foytik + + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/rtspserver.c: + * tests/check/gst/stream.c: + rtsp-stream: Fix crash on cleanup with shared media and multiple udpsrc + - Unicast udpsrcs are now managed in a hash table. This allows for proper cleanup in with shared streams and fixes a memory leak. + - Unicast udpsrcs are now properly cleaned up when shared connections exit. See the update_transport() function. + - Create unit test for shared media. + https://bugzilla.gnome.org/show_bug.cgi?id=764744 + +2016-04-11 10:55:23 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Always bind to ANY when address is a multicast address and not only on Windows + For IPv6 addresses, binding to a multicast group does not work on Linux + either. Always bind to ANY and then later join the multicast group. + https://bugzilla.gnome.org/show_bug.cgi?id=764679 + +2016-04-14 10:05:02 +0100 Julien Isorce + + * common: + Automatic update of common submodule + From 6f2d209 to ac2f647 + +2016-04-06 10:09:46 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-thread-pool.c: + rtsp-thread-pool: explained why GSource is a part of ThreadImpl + Clarified why it is necessary to add source information to + GstRTSPThreadImpl. See the reported bug in GLib: + https://bugzilla.gnome.org/show_bug.cgi?id=720186 + for more information. + https://bugzilla.gnome.org/show_bug.cgi?id=761702 + +2016-04-04 12:58:38 +0300 Sebastian Dröge + + * examples/Makefile.am: + examples: Clean up CFLAGS/LDADD even more + The internal .la should come first and is part of LDADD, as is + GST_CFLAGS/LIBS. + +2016-04-04 12:39:39 +0300 Sebastian Dröge + + * examples/Makefile.am: + examples: Clean up CFLAGS/LDADD to link with the correct versions of all libraries + +2016-04-03 12:06:29 +0300 Sebastian Dröge + + * gst/rtsp-server/Makefile.am: + rtsp-server: Use $(GST_NET_LIBS) / $(GST_NET_CFLAGS) + +2015-12-30 18:39:05 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-server: Implement clock signalling according to RFC7273 + For NTP and PTP clocks we signal the actual clock that is used and signal + the direct media clock offset. + For all other clocks we at least signal that it's the local sender clock. + This allows receivers to know which clock was used to generate the media and + its RTP timestamps. Receivers can then implement network synchronization, + either absolute or at least relative by getting the sender clock rate directly + via NTP/PTP instead of estimating it from RTP timestamps and packet receive + times. + https://bugzilla.gnome.org/show_bug.cgi?id=760005 + +2016-03-02 19:42:58 +0200 Sebastian Dröge + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Add support for setting the multicast interface + https://bugzilla.gnome.org/show_bug.cgi?id=763000 + +2016-03-02 19:42:13 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-media: Add support for setting the multicast interface + https://bugzilla.gnome.org/show_bug.cgi?id=763000 + +2016-03-07 08:50:01 +0900 Vineeth TM + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: use new gst_element_class_add_static_pad_template() + https://bugzilla.gnome.org/show_bug.cgi?id=763196 + +2016-03-24 13:33:43 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.8.0 === + +2016-03-24 13:00:35 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.8.0 2016-03-16 23:35:09 +0200 Sebastian Dröge diff --git a/NEWS b/NEWS index ee7f213e57..4c3baabdc2 100644 --- a/NEWS +++ b/NEWS @@ -1,786 +1 @@ -# GStreamer 1.8 Release Notes - -**GStreamer 1.8.0 was released on 24 March 2016.** - -The GStreamer team is proud to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! - -As always, this release is again packed with new features, bug fixes and other -improvements. - -See [https://gstreamer.freedesktop.org/releases/1.8/][latest] for the latest -version of this document. - -*Last updated: Thursday 24 March 2016, 10:00 UTC [(log)][gitlog]* - -[latest]: https://gstreamer.freedesktop.org/releases/1.8/ -[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.8/release-notes-1.8.md - -## Highlights - -- **Hardware-accelerated zero-copy video decoding on Android** - -- **New video capture source for Android using the android.hardware.Camera API** - -- **Windows Media reverse playback** support (ASF/WMV/WMA) - -- **New tracing system** provides support for more sophisticated debugging tools - -- **New high-level GstPlayer playback convenience API** - -- **Initial support for the new [Vulkan][vulkan] API**, see - [Matthew Waters' blog post][vulkan-in-gstreamer] for more details - -- **Improved Opus audio codec support**: Support for more than two channels; MPEG-TS demuxer/muxer can now handle Opus; - [sample-accurate][opus-sample-accurate] encoding/decoding/transmuxing with - Ogg, Matroska, ISOBMFF (Quicktime/MP4), and MPEG-TS as container; - [new codec utility functions for Opus header and caps handling][opus-codec-utils] - in pbutils library. The Opus encoder/decoder elements were also moved to - gst-plugins-base (from -bad), and the opus RTP depayloader/payloader to -good. - - [opus-sample-accurate]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiometa.html#GstAudioClippingMeta - [opus-codec-utils]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstpbutilscodecutils.html - -- **GStreamer VAAPI module now released and maintained as part of the GStreamer project** - - [vulkan]: https://www.khronos.org/vulkan - [vulkan-in-gstreamer]: http://ystreet00.blogspot.co.uk/2016/02/vulkan-in-gstreamer.html - -## Major new features and changes - -### Noteworthy new API, features and other changes - -- New GstVideoAffineTransformationMeta meta for adding a simple 4x4 affine - transformation matrix to video buffers - -- [g\_autoptr()](https://developer.gnome.org/glib/stable/glib-Miscellaneous-Macros.html#g-autoptr) - support for all types is exposed in GStreamer headers now, in combination - with a sufficiently-new GLib version (i.e. 2.44 or later). This is primarily - for the benefit of application developers who would like to make use of - this, the GStreamer codebase itself will not be using g_autoptr() for - the time being due to portability issues. - -- GstContexts are now automatically propagated to elements added to a bin - or pipeline, and elements now maintain a list of contexts set on them. - The list of contexts set on an element can now be queried using the new functions - [gst\_element\_get\_context()](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-context) - and [gst\_element\_get\_contexts()](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-contexts). GstContexts are used to share context-specific configuration objects - between elements and can also be used by applications to set context-specific - configuration objects on elements, e.g. for OpenGL or Hardware-accelerated - video decoding. - -- New [GST\_BUFFER\_DTS\_OR\_PTS()](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#GST-BUFFER-DTS-OR-PTS:CAPS) - convenience macro that returns the decode timestamp if one is set and - otherwise returns the presentation timestamp - -- New GstPadEventFullFunc that returns a GstFlowReturn instead of a gboolean. - This new API is mostly for internal use and was added to fix a race condition - where occasionally internal flow error messages were posted on the bus when - sticky events were propagated at just the wrong moment whilst the pipeline - was shutting down. This happened primarily when the pipeline was shut down - immediately after starting it up. GStreamer would not know that the reason - the events could not be propagated was because the pipeline was shutting down - and not some other problem, and now the flow error allows GStreamer to know - the reason for the failure (and that there's no reason to post an error - message). This is particularly useful for queue-like elements which may need - to asynchronously propagate a previous flow return from downstream. - -- Pipeline dumps in form of "dot files" now also show pad properties that - differ from their default value, the same as it does for elements. This is - useful for elements with pad subclasses that provide additional properties, - e.g. videomixer or compositor. - -- Pad probes are now guaranteed to be called in the order they were added - (before they were called in reverse order, but no particular order was - documented or guaranteed) - -- Plugins can now have dependencies on device nodes (not just regular files) - and also have a prefix filter. This is useful for plugins that expose - features (elements) based on available devices, such as the video4linux - plugin does with video decoders on certain embedded systems. - -- gst\_segment\_to\_position() has been deprecated and been replaced by the - better-named gst\_segment\_position\_from\_running\_time(). At the same time - gst\_segment\_position\_from\_stream\_time() was added, as well as \_full() - variants of both to deal with negative stream time. - -- GstController: the interpolation control source gained a new monotonic cubic - interpolation mode that, unlike the existing cubic mode, will never overshoot - the min/max y values set. - -- GstNetAddressMeta: can now be read from buffers in language bindings as well, - via the new gst\_buffer\_get\_net\_address\_meta() function - -- ID3 tag PRIV frames are now extraced into a new GST\_TAG\_PRIVATE\_DATA tag - -- gst-launch-1.0 and gst\_parse\_launch() now warn in the most common case if - a dynamic pad link could not be resolved, instead of just silently - waiting to see if a suitable pad appears later, which is often perceived - by users as hanging -- they are now notified when this happens and can check - their pipeline. - -- GstRTSPConnection now also parses custom RTSP message headers and retains - them for the application instead of just ignoring them - -- rtspsrc handling of authentication over tunneled connections (e.g. RTSP over HTTP) - was fixed - -- gst\_video\_convert\_sample() now crops if there is a crop meta on the input buffer - -- The debugging system printf functions are now exposed for general use, which - supports special printf format specifiers such as GST\_PTR\_FORMAT and - GST\_SEGMENT\_FORMAT to print GStreamer-related objects. This is handy for - systems that want to prepare some debug log information to be output at a - later point in time. The GStreamer-OpenGL subsystem is making use of these - new functions, which are [gst\_info\_vasprintf()][gst_info_vasprintf], - [gst\_info\_strdup\_vprintf()][gst_info_strdup_vprintf] and - [gst\_info\_strdup\_printf()][gst_info_strdup_printf]. - -- videoparse: "strides", "offsets" and "framesize" properties have been added to - allow parsing raw data with strides and padding that do not match GStreamer - defaults. - -- GstPreset reads presets from the directories given in GST\_PRESET\_PATH now. - Presets are read from there after presets in the system path, but before - application and user paths. - -[gst_info_vasprintf]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-info-vasprintf -[gst_info_strdup_vprintf]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-info-strdup-vprintf -[gst_info_strdup_printf]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-info-strdup-printf - -### New Elements - -- [netsim](): a new (resurrected) element to simulate network jitter and - packet dropping / duplication. - -- New VP9 RTP payloader/depayloader elements: rtpvp9pay/rtpvp9depay - -- New [videoframe_audiolevel]() element, a video frame synchronized audio level element - -- New spandsp-based tone generator source - -- New NVIDIA NVENC-based H.264 encoder for GPU-accelerated video encoding on - suitable NVIDIA hardware - -- [rtspclientsink](), a new RTSP RECORD sink element, was added to gst-rtsp-server - -- [alsamidisrc](), a new ALSA MIDI sequencer source element - -### Noteworthy element features and additions - -- *identity*: new ["drop-buffer-flags"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-identity.html#GstIdentity--drop-buffer-flags) - property to drop buffers based on buffer flags. This can be used to drop all - non-keyframe buffers, for example. - -- *multiqueue*: various fixes and improvements, in particular special handling - for sparse streams such as substitle streams, to make sure we don't overread - them any more. For sparse streams it can be normal that there's no buffer for - a long period of time, so having no buffer queued is perfectly normal. Before - we would often unnecessarily try to fill the subtitle stream queue, which - could lead to much more data being queued in multiqueue than necessary. - -- *multiqueue*/*queue*: When dealing with time limits, these elements now use the - new ["GST_BUFFER_DTS_OR_PTS"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#GST-BUFFER-DTS-OR-PTS:CAPS) - and ["gst_segment_to_running_time_full()"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstSegment.html#gst-segment-to-running-time-full) - API, resulting in more accurate levels, especially when dealing with non-raw - streams (where reordering happens, and we want to use the increasing DTS as - opposed to the non-continuously increasing PTS) and out-of-segment input/output. - Previously all encoded buffers before the segment start, which can happen when - doing ACCURATE seeks, were not taken into account in the queue level calculation. - -- *multiqueue*: New ["use-interleave"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-multiqueue.html#GstMultiQueue--use-interleave) - property which allows the size of the queues to be optimized based on the input - streams interleave. This should only be used with input streams which are properly - timestamped. It will be used in the future decodebin3 element. - -- *queue2*: new ["avg-in-rate"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-queue2.html#GstQueue2--avg-in-rate) - property that returns the average input rate in bytes per second - -- audiotestsrc now supports all audio formats and is no longer artificially - limited with regard to the number of channels or sample rate - -- gst-libav (ffmpeg codec wrapper): map and enable JPEG2000 decoder - -- multisocketsink can, on request, send a custom GstNetworkMessage event - upstream whenever data is received from a client on a socket. Similarly, - socketsrc will, on request, pick up GstNetworkMessage events from downstream - and send any data contained within them via the socket. This allows for - simple bidirectional communication. - -- matroska muxer and demuxer now support the ProRes video format - -- Improved VP8/VP9 decoding performance on multi-core systems by enabling - multi-threaded decoding in the libvpx-based decoders on such systems - -- appsink has a new ["wait-on-eos"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-appsink.html#GstAppSink--wait-on-eos) - property, so in cases where it is uncertain if an appsink will have a consumer for - its buffers when it receives an EOS this can be set to FALSE to ensure that the - appsink will not hang. - -- rtph264pay and rtph265pay have a new "config-interval" mode -1 that will - re-send the setup data (SPS/PPS/VPS) before every keyframe to ensure - optimal coverage and the shortest possibly start-up time for a new client - -- mpegtsmux can now mux H.265/HEVC video as well - -- The MXF muxer was ported to 1.x and produces more standard conformant files now - that can be handled by more other software; The MXF demuxer got improved - support for seek tables (IndexTableSegments). - -### Plugin moves - -- The rtph265pay/depay RTP payloader/depayloader elements for H.265/HEVC video - from the rtph265 plugin in -bad have been moved into the existing rtp plugin - in gst-plugins-good. - -- The mpg123 plugin containing a libmpg123 based audio decoder element has - been moved from -bad to -ugly. - -- The Opus encoder/decoder elements have been moved to gst-plugins-base and - the RTP payloader to gst-plugins-good, both coming from gst-plugins-bad. - -### New tracing tools for developers - -A new tracing subsystem API has been added to GStreamer, which provides -external tracers with the possibility to strategically hook into GStreamer -internals and collect data that can be evaluated later. These tracers are a -new type of plugin features, and GStreamer core ships with a few example -tracers (latency, stats, rusage, log) to start with. Tracers can be loaded -and configured at start-up via an environment variable (GST\_TRACER\_PLUGINS). - -Background: While GStreamer provides plenty of data on what's going on in a -pipeline via its debug log, that data is not necessarily structured enough to -be generally useful, and the overhead to enable logging output for all data -required might be too high in many cases. The new tracing system allows tracers -to just obtain the data needed at the right spot with as little overhead as -possible, which will be particularly useful on embedded systems. - -Of course it has always been possible to do performance benchmarks and debug -memory leaks, memory consumption and invalid memory access using standard -operating system tools, but there are some things that are difficult to track -with the standard tools, and the new tracing system helps with that. Examples -are things such as latency handling, buffer flow, ownership transfer of -events and buffers from element to element, caps negotiation, etc. - -For some background on the new tracing system, watch Stefan Sauer's -GStreamer Conference talk ["A new tracing subsystem for GStreamer"][tracer-0] -and for a more specific example how it can be useful have a look at -Thiago Santos's lightning talk ["Analyzing caps negotiation using GstTracer"][tracer-1] -and his ["GstTracer experiments"][tracer-2] blog post. There was also a Google -Summer of Code project in 2015 that used tracing system for a graphical -GStreamer debugging tool ["gst-debugger"][tracer-3]. - -This is all still very much work in progress, but we hope this will provide the -foundation for a whole suite of new debugging tools for GStreamer pipelines. - -[tracer-0]: https://gstconf.ubicast.tv/videos/a-new-tracing-subsystem-for-gstreamer/ -[tracer-1]: https://gstconf.ubicast.tv/videos/analyzing-caps-negotiation-using-gsttracer/ -[tracer-2]: http://blog.thiagoss.com/2015/07/23/gsttracer-experiments/ -[tracer-3]: https://git.gnome.org/browse/gst-debugger - -### GstPlayer: a new high-level API for cross-platform multimedia playback - -GStreamer has had reasonably high-level API for multimedia playback -in the form of the playbin element for a long time. This allowed application -developers to just configure a URI to play, and playbin would take care of -everything else. This works well, but there is still way too much to do on -the application-side to implement a fully-featured playback application, and -too much general GStreamer pipeline API exposed, making it less accessible -to application developers. - -Enter GstPlayer. GstPlayer's aim is to provide an even higher-level abstraction -of a fully-featured playback API but specialised for its specific use case. It -also provides easy integration with and examples for Gtk+, Qt, Android, OS/X, -iOS and Windows. Watch Sebastian's [GstPlayer talk at the GStreamer Conference][gstplayer-talk] -for more information, or check out the [GstPlayer API reference][gstplayer-api] -and [GstPlayer examples][gstplayer-examples]. - -[gstplayer-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/player.html -[gstplayer-talk]: https://gstconf.ubicast.tv/videos/gstplayer-a-simple-cross-platform-api-for-all-your-media-playback-needs-part-1/ -[gstplayer-examples]: https://github.com/sdroege/gst-player/ - -### Adaptive streaming: DASH, HLS and MSS improvements - -- dashdemux now supports loading external xml nodes pointed from its MPD. - -- Content protection nodes parsing support for PlayReady WRM in mssdemux. - -- Reverse playback was improved to respect seek start and stop positions. - -- Adaptive demuxers (hlsdemux, dashdemux, mssdemux) now support the SNAP_AFTER - and SNAP_BEFORE seek flags which will jump to the nearest fragment boundary - when executing a seek, which means playback resumes more quickly after a seek. - -### Audio library improvements - -- audio conversion, quantization and channel up/downmixing functionality - has been moved from the audioconvert element into the audio library and - is now available as public API in form of [GstAudioConverter][audio-0], - [GstAudioQuantize][audio-1] and [GstAudioChannelMixer][audio-2]. - Audio resampling will follow in future releases. - -- [gst\_audio\_channel\_get\_fallback\_mask()][audio-3] can be used - to retrieve a default channel mask for a given number of channels as last - resort if the layout is unknown - -- A new [GstAudioClippingMeta][audio-4] meta was added for specifying clipping - on encoded audio buffers - -- A new GstAudioVisualizer base class for audio visualisation elements; - most of the existing visualisers have been ported over to the new base class. - This new base class lives in the pbutils library rather than the audio library, - since we'd have had to make libgstaudio depend on libgstvideo otherwise, - which was deemed undesirable. - -[audio-0]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-GstAudioConverter.html -[audio-1]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-GstAudioQuantize.html -[audio-2]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiochannels.html#gst-audio-channel-mix-new -[audio-3]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiochannels.html#gst-audio-channel-get-fallback-mask -[audio-4]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiometa.html#GstAudioClippingMeta - -### GStreamer OpenGL support improvements - -#### Better OpenGL Shader support - -[GstGLShader][shader] has been revamped to allow more OpenGL shader types -by utilizing a new GstGLSLStage object. Each stage holds an OpenGL pipeline -stage such as a vertex, fragment or a geometry shader that are all compiled -separately into a program that is executed. - -The glshader element has also received a revamp as a result of the changes in -the library. It does not take file locations for the vertex and fragment -shaders anymore. Instead it takes the strings directly leaving the file -management to the application. - -A new [example][liveshader-example] was added utilizing the new shader -infrastructure showcasing live shader edits. - -[shader]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstglshader.html -[liveshader-example]: https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/tests/examples/gtk/glliveshader.c - -#### OpenGL GLMemory rework - -[GstGLMemory] was extensively reworked to support the addition of multiple -texture targets required for zero-copy integration with the Android -MediaCodec elements. This work was also used to provide IOSurface based -GLMemory on OS X for zero-copy with OS X's VideoToolbox decoder (vtdec) and -AV Foundation video source (avfvideosrc). There are also patches in bugzilla -for GstGLMemoryEGL specifically aimed at improving the decoding performance on -the Raspberry Pi. - -[GstGLMemory]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstglmemory.html - -A texture-target field was added to video/x-raw(memory:GLMemory) caps to signal -the texture target contained in the GLMemory. Its values can be 2D, rectangle -or external-oes. glcolorconvert can convert between the different formats as -required and different elements will accept or produce different targets. e.g. -glimagesink can take and render external-oes textures directly as required for -effecient zero-copy on android. - -A generic GL allocation framework was also implemented to support the generic -allocation of OpenGL buffers and textures which is used extensively by -GstGLBufferPool. - -#### OpenGL DMABuf import uploader - -There is now a DMABuf uploader available for automatic selection that will -attempt to import the upstream provided DMABuf. The uploader will import into -2D textures with the necesarry format. YUV to RGB conversion is still provided -by glcolorconvert to avoid the laxer restrictions with external-oes textures. - -#### OpenGL queries - -Queries of various aspects of the OpenGL runtime such as timers, number of -samples or the current timestamp are not possible. The GstGLQuery object uses a -delayed debug system to delay the debug output to later to avoid expensive calls -to the glGet\* family of functions directly after finishing a query. It is -currently used to output the time taken to perform various operations of texture -uploads and downloads in GstGLMemory. - -#### New OpenGL elements - -glcolorbalance has been created mirroring the videobalance elements. -glcolorbalance provides the exact same interface as videobalance so can be used -as a GPU accelerated replacement. glcolorbalance has been added to glsinkbin so -usage with playsink/playbin will use it automatically instead of videobalance -where possible. - -glvideoflip, which is the OpenGL equiavalant of videoflip, implements the exact -same interface and functionality as videoflip. - -#### EGL implementation now selects OpenGL 3.x - -The EGL implementation can now select OpenGL 3.x contexts. - -#### OpenGL API removal - -The GstGLDownload library object was removed as it was not used by anything. -Everything is performed by GstGLMemory or in the gldownloadelement. - -The GstGLUploadMeta library object was removed as it was not being used and we -don't want to promote the use of GstVideoGLTextureUploadMeta. - -#### OpenGL: Other miscellaneous changes - -- The EGL implementation can now select OpenGL 3.x contexts. This brings - OpenGL 3.x to e.g. wayland and other EGL systems. - -- glstereomix/glstereosplit are now built and are usable on OpenGL ES systems - -- The UYVY/YUY2 to RGBA and RGBA to UYVY/YUY2 shaders were fixed removing the - sawtooth pattern and luma bleeding. - -- We now utilize the GL\_APPLE\_sync extension on iOS devices which improves - performance of OpenGL applications, especially with multiple OpenGL - contexts. - -- glcolorconvert now uses a bufferpool to avoid costly - glGenTextures/glDeleteTextures for every frame. - -- glvideomixer now has full glBlendFunc and glBlendEquation support per input. - -- gltransformation now support navigation events so your weird transformations - also work with DVD menus. - -- qmlglsink can now run on iOS, OS X and Android in addition to the already - supported Linux platform. - -- glimagesink now posts unhandled keyboard and mouse events (on backends that - support user input, current only X11) on the bus for the application. - -### Initial GStreamer Vulkan support - -Some new elements, vulkansink and vulkanupload have been implemented utilizing -the new Vulkan API. The implementation is currently limited to X11 platforms -(via xcb) and does not perform any scaling of the stream's contents to the size -of the available output. - -A lot of infrasctructure work has been undertaken to support using Vulkan in -GStreamer in the future. A number of GstMemory subclasses have been created for -integrating Vulkan's GPU memory handling along with VkBuffer's and VkImage's -that can be passed between elements. Some GStreamer refcounted wrappers for -global objects such as VkInstance, VkDevice, VkQueue, etc have also been -implemented along with GstContext integration for sharing these objects with the -application. - -### GStreamer VAAPI support for hardware-accelerated video decoding and encoding on Intel (and other) platforms - -#### GStreamer VAAPI is now part of upstream GStreamer - -The GStreamer-VAAPI module which provides support for hardware-accelerated -video decoding, encoding and post-processing on Intel graphics hardware -on Linux has moved from its previous home at the [Intel Open Source Technology Center][iostc] -to the upstream GStreamer repositories, where it will in future be maintained -as part of the upstream GStreamer project and released in lockstep with the -other GStreamer modules. The current maintainers will continue to spearhead -the development at the new location: - -[http://cgit.freedesktop.org/gstreamer/gstreamer-vaapi/][gst-vaapi-git] - -[gst-vaapi-git]: http://cgit.freedesktop.org/gstreamer/gstreamer-vaapi/ - -GStreamer-VAAPI relies heavily on certain GStreamer infrastructure API that -is still in flux such as the OpenGL integration API or the codec parser -libraries, and one of the goals of the move was to be able to leverage -new developments early and provide tighter integration with the latest -developments of those APIs and other graphics-related APIs provided by -GStreamer, which should hopefully improve performance even further and in -some cases might also provide better stability. - -Thanks to everyone involved in making this move happen! - -#### GStreamer VAAPI: Bug tracking - -Bugs had already been tracked on [GNOME bugzilla](bgo) but will be moved -from the gstreamer-vaapi product into a new gstreamer-vaapi component of -the GStreamer product in bugzilla. Please file new bugs against the new -component in the GStreamer product from now on. - -#### GStreamer VAAPI: Pending patches - -The code base has been re-indented to the GStreamer code style, which -affected some files more than others. This means that some of the patches -in bugzilla might not apply any longer, so if you have any unmerged patches -sitting in bugzilla please consider checking if they still apply cleany and -refresh them if not. Sorry for any inconvenience this may cause. - -#### GStreamer VAAPI: New versioning scheme and supported GStreamer versions - -The version numbering has been changed to match the GStreamer version -numbering to avoid confusion: there is a new gstreamer-vaapi 1.6.0 release -and a 1.6 branch that is roughly equivalent to the previous 0.7.0 version. -Future releases 1.7.x and 1.8.x will be made alongside GStreamer releases. - -While it was possible and supported by previous releases to build against -a whole range of different GStreamer versions (such as 1.2, 1.4, 1.6 or 1.7/1.8), -in the future there will only be one target branch, so that git master will -track GStreamer git master, 1.8.x will target GStreamer 1.8, and -1.6.x will target the 1.6 series. - -[iostc]: http://01.org -[bgo]: http://bugzilla.gnome.og - -#### GStreamer VAAPI: Miscellaneous changes - -All GStreamer-VAAPI functionality is now provided solely by its GStreamer -elements. There is no more public library exposing GstVaapi API, this API -was only ever meant for private use by the elements. Parts of it may be -resurrected again in future if needed, but for now it has all been made -private. - -GStreamer-VAAPI now unconditionally uses the codecparser library in -gst-plugins-bad instead of shipping its own internal copy. Similarly, -it no longer ships its own codec parsers but relies on the upstream -codec parser elements. - -The GStreamer-VAAPI encoder elements have been renamed from vaapiencode_foo -to vaapifooenc, so encoders are now called vaapih264enc, vaapih265enc, -vaapimpeg2enc, vaapijpegenc, and vaapivp8enc. With this change we now follow -the standard names in GStreamer, and the plugin documentation is generated -correctly. - -In the case of the decoders, only the jpeg decoder has been split from the -general decoding element vaapidecode: vaapijpegdec. This is the first step to -split per codec each decoding element. The vaapijpegdec has also been given -marginal rank for the time being. - -#### GStreamer VAAPI: New features in 1.8: 10-bit H.265/HEVC decoding support - -Support for decoding 10-bit H.265/HEVC has been added. For the time being -this only works in combination with vaapisink though, until support for the -P010 video format used internally is added to GStreamer and to the -vaGetImage()/vaPutimage() API in the vaapi-intel-driver. - -Several fixes for memory leaks, build errors, and in the internal -video parsing. - -Finally, vaapisink now posts the unhandled keyboard and mouse events to the -application. - -### GStreamer Video 4 Linux Support - -Colorimetry support has been enhanced even more. It will now properly select -default values when not specified by the driver. The range of color formats -supported by GStreamer has been greatly improved. Notably, support for -multi-planar I420 has been added along with all the new and non-ambiguous RGB -formats that got added in recent kernels. - -The device provider now exposes a variety of properties as found in the udev -database. - -The video decoder is now able to negotiate the downstream format. - -Elements that are dynamically created from /dev/video\* now track changes on -these devices to ensure the registry stay up to date. - -All this and various bug fixes that improve both stability and correctness. - -### GStreamer Editing Services - -Added APIs to handle asset proxying support. Proxy creation is not the -responsibility of GES itself, but GES provides all the needed features -for it to be cleanly handled at a higher level. - -Added support for changing playback rate. This means that now, whenever a -user adds a 'pitch' element (as it is the only known element to change playback -rate through properties), GES will handle everything internally. This change -introduced a new media-duration-factor property in NleObject which will -lead to tweaking of seek events so they have the proper playback range to be -requested upstream. - -Construction of NLE objects has been reworked making copy/pasting fully -functional and allowing users to set properties on effects right after -creating them. - -Rework of the title source to add more flexibility in text positioning, -and letting the user get feedback about rendered text positioning. - -Report nlecomposition structural issues (coming from user programing mistakes) -into ERROR messages on the bus. - -Add GI/pythyon testsuite in GES itself, making sure the API is working as expected -in python, and allowing writing tests faster. - -### GstValidate - -Added support to run tests inside gdb. - -Added a 'smart' reporting mode where we give as much information as possible about -critical errors. - -Uses GstTracer now instead of a LD\_PRELOAD library. - -## Miscellaneous - -- encodebin now works with "encoder-muxers" such as wavenc - -- gst-play-1.0 acquired a new keyboard shortcut: '0' seeks back to the start - -- gst-play-1.0 supports two new command line switches: -v for verbose output - and --flags to configure the playbin flags to use. - -## Build and Dependencies - -- The GLib dependency requirement was bumped to 2.40 - -- The -Bsymbolic configure check now works with clang as well - -- ffmpeg is now required as libav provider, incompatible changes were - introduced that make it no longer viable to support both FFmpeg and Libav - as libav providers. Most major distros have switched to FFmpeg or are in - the process of switching to it anyway, so we don't expect this to be a - problem, and there is still an internal copy of ffmpeg that can be used - as fallback if needed. - -- The internal ffmpeg snapshot is now FFMpeg 3.0, but it should be possible - to build against 2.8 as well for the time being. - -## Platform-specific improvements - -### Android - -- Zero-copy video decoding on Android using the hardware-accelerated decoders - has been implemented, and is fully integrated with the GStreamer OpenGL stack - -- ahcsrc, a new camera source element, has been merged and can be used to - capture video on android devices. It uses the android.hardware.Camera Java - API to capture from the system's cameras. - -- The OpenGL-based QML video sink can now also be used on Android - -- New tinyalsasink element, which is mainly useful for Android but can also - be used on other platforms. - -### OS/X and iOS - -- The system clock now uses mach\_absolute\_time() on OSX/iOS, which is - the preferred high-resolution monotonic clock to be used on Apple platforms - -- The OpenGL-based QML video sink can now also be used on OS X and iOS (with - some Qt build system massaging) - -- New IOSurface based memory implementation in avfvideosrc and vtdec on OS X - for zerocopy with OpenGL. The previously used OpenGL extension - GL_APPLE_ycbcr_422 is not compatible with GL 3.x core contexts. - -- New GstAppleCoreVideoMemory wrapping CVPixelBuffer's - -- avfvideosrc now supports renegotiation. - -### Windows - -- Various bugs with UDP and multicast were fixed on Windows, mostly related to - gst-rtsp-server. - -- A few bugs in directsoundsrc and directsoundsink were fixed that could cause - the element to lock up. Also the "mute" property on the sink was fixed, and - a new "device" property for device selection was added to the source. - -## Known Issues - -- Building GStreamer applications with the Android NDK r11 is currently not - supported due to incompatible changes in the NDK. This is expected to be - fixed for 1.8.1. - [Bugzilla #763999](https://bugzilla.gnome.org/show_bug.cgi?id=763999) - -- vp8enc crashes on 32 bit Windows, but was working fine in 1.6. 64 bit - Windows is unaffected. - [Bugzilla #763663](https://bugzilla.gnome.org/show_bug.cgi?id=763663) - -## Contributors - -Adam Miartus, Alban Bedel, Aleix Conchillo Flaqué, Aleksander Wabik, -Alessandro Decina, Alex Ashley, Alex Dizengof, Alex Henrie, Alistair Buxton, -Andreas Cadhalpun, Andreas Frisch, André Draszik, Anthony G. Basile, -Antoine Jacoutot, Anton Bondarenko, Antonio Ospite, Arjen Veenhuizen, -Arnaud Vrac, Arun Raghavan, Athanasios Oikonomou, Aurélien Zanelli, Ben Iofel, -Bob Holcomb, Branko Subasic, Carlos Rafael Giani, Chris Bass, Csaba Toth, -Daniel Kamil Kozar, Danilo Cesar Lemes de Paula, Dave Craig, David Fernandez, -David Schleef, David Svensson Fors, David Waring, David Wu, Duncan Palmer, -Edward Hervey, Egor Zaharov, Etienne Peron, Eunhae Choi, Evan Callaway, -Evan Nemerson, Fabian Orccon, Florent Thiéry, Florin Apostol, Frédéric Wang, -George Kiagiadakis, George Yunaev, Göran Jönsson, Graham Leggett, -Guillaume Desmottes, Guillaume Marquebielle, Haihua Hu, Havard Graff, -Heinrich Fink, Holger Kaelberer, HoonHee Lee, Hugues Fruchet, Hyunil Park, -Hyunjun Ko, Ilya Konstantinov, James Stevenson, Jan Alexander Steffens (heftig), -Jan Schmidt, Jason Litzinger, Jens Georg, Jimmy Ohn, Joan Pau Beltran, -Joe Gorse, John Chang, John Slade, Jose Antonio Santos Cadenas, Josep Torra, -Julian Bouzas, Julien Isorce, Julien Moutte, Justin Kim, Kazunori Kobayashi, -Koop Mast, Lim Siew Hoon, Linus Svensson, Lubosz Sarnecki, Luis de Bethencourt, -Lukasz Forynski, Manasa Athreya, Marcel Holtmann, Marcin Kolny, Marcus Prebble, -Mark Nauwelaerts, Maroš Ondrášek, Martin Kelly, Matej Knopp, Mathias Hasselmann, -Mathieu Duponchelle, Matt Crane, Matthew Marsh, Matthew Waters, Matthieu Bouron, -Mersad Jelacic, Michael Olbrich, Miguel París Díaz, Mikhail Fludkov, -Mischa Spiegelmock, Nicola Murino, Nicolas Dufresne, Nicolas Huet, -Nirbheek Chauhan, Ognyan Tonchev, Olivier Crête, Pablo Anton, Pankaj Darak, -Paolo Pettinato, Patricia Muscalu, Paul Arzelier, Pavel Bludov, Perry Hung, -Peter Korsgaard, Peter Seiderer, Petr Viktorin, Philippe Normand, -Philippe Renon, Philipp Zabel, Philip Van Hoof, Philip Withnall, Piotr Drąg, -plamot, Polochon\_street, Prashant Gotarne, Rajat Verma, Ramiro Polla, -Ravi Kiran K N, Reynaldo H. Verdejo Pinochet, Robert Swain, Romain Picard, -Roman Nowicki, Ross Burton, Ryan Hendrickson, Santiago Carot-Nemesio, -Scott D Phillips, Sebastian Dröge, Sebastian Rasmussen, Sergey Borovkov, -Seungha Yang, Sjors Gielen, Song Bing, Sreerenj Balachandran, Srimanta Panda, -Stavros Vagionitis, Stefan Sauer, Steven Hoving, Stian Selnes, Suhwang Kim, -Thiago Santos, Thibault Saunier, Thijs Vermeir, Thomas Bluemel, Thomas Roos, -Thomas Vander Stichele, Tim-Philipp Müller, Tim Sheridan, Ting-Wei Lan, -Tom Deseyn, Vanessa Chipirrás Navalón, Víctor Manuel Jáquez Leal, -Vincent Dehors, Vincent Penquerc'h, Vineeth T M, Vivia Nikolaidou, -Wang Xin-yu (王昕宇), William Manley, Wim Taymans, Wonchul Lee, Xavi Artigas, -Xavier Claessens, Youness Alaoui, - -... and many others who have contributed bug reports, translations, sent -suggestions or helped testing. - -## Bugs fixed in 1.8 - -More than [~700 bugs][bugs-fixed-in-1.8] have been fixed during -the development of 1.8. - -This list does not include issues that have been cherry-picked into the -stable 1.6 branch and fixed there as well, all fixes that ended up in the -1.6 branch are also included in 1.8. - -This list also does not include issues that have been fixed without a bug -report in bugzilla, so the actual number of fixes is much higher. - -[bugs-fixed-in-1.8]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=107311&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.6.1&target_milestone=1.6.2&target_milestone=1.6.3&target_milestone=1.7.0&target_milestone=1.7.1&target_milestone=1.7.2&target_milestone=1.7.3&target_milestone=1.7.4&target_milestone=1.7.90&target_milestone=1.7.91&target_milestone=1.7.92&target_milestone=1.7.x&target_milestone=1.8.0 - -## Stable 1.8 branch - -After the 1.8.0 release there will be several 1.8.x bug-fix releases which -will contain bug fixes which have been deemed suitable for a stable branch, -but no new features or intrusive changes will be added to a bug-fix release -usually. The 1.8.x bug-fix releases will be made from the git 1.8 branch, which -is a stable branch. - -### 1.8.0 - -1.8.0 was released on 24 March 2016. - -### 1.8.1 - -The first 1.8 bug-fix release (1.8.1) is planned for April 2016. - -## Schedule for 1.10 - -Our next major feature release will be 1.10, and 1.9 will be the unstable -development version leading up to the stable 1.10 release. The development -of 1.9/1.10 will happen in the git master branch. - -The plan for the 1.10 development cycle is yet to be confirmed, but it is -expected that feature freeze will be around late July or early August, -followed by several 1.9 pre-releases and the new 1.10 stable release -in September. - -1.10 will be backwards-compatible to the stable 1.8, 1.6, 1.4, 1.2 and 1.0 -release series. - -- - - - -*These release notes have been prepared by Tim-Philipp Müller with -contributions from Sebastian Dröge, Nicolas Dufresne, Edward Hervey, Víctor -Manuel Jáquez Leal, Arun Raghavan, Thiago Santos, Thibault Saunier, Jan -Schmidt and Matthew Waters.* - -*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* +This is GStreamer 1.9.1 diff --git a/RELEASE b/RELEASE index eccb206202..7df862c35e 100644 --- a/RELEASE +++ b/RELEASE @@ -1,21 +1,25 @@ -Release notes for GStreamer RTSP Server Library 1.8.0 +Release notes for GStreamer RTSP Server Library 1.9.1 -The GStreamer team is pleased to announce the first release of the new stable -1.8 release series. The 1.8 release series is adding new features on top of -the 1.0, 1.2, 1.4 and 1.6 series and is part of the API and ABI-stable 1.x -release series of the GStreamer multimedia framework. +The GStreamer team is pleased to announce the first release of the unstable +1.9 release series. The 1.9 release series is adding new features on top of +the 1.0, 1.2, 1.4, 1.6 and 1.8 series and is part of the API and ABI-stable 1.x release +series of the GStreamer multimedia framework. The unstable 1.9 release series +will lead to the stable 1.10 release series in the next weeks. Any newly added +API can still change until that point. -Binaries for Android, iOS, Mac OS X and Windows will be provided shortly after -the source release by the GStreamer project during the stable 1.8 release -series. +Binaries for Android, iOS, Mac OS X and Windows will be provided in the next days. Bugs fixed in this release - * 740509 : Seek fail with test-uri + * 760005 : rtsp-sdp: Implement clock signalling according to RFC7273 + * 761702 : rtsp-thread-pool: explain why GSource is a part of GstRTSPThreadImpl + * 763000 : Add support for setting multicast interface + * 763196 : rtspclientsink: use new gst_element_class_add_static_pad_template() + * 730539 : sdp: add support for multiple crypto sessions ==== Download ==== @@ -52,5 +56,15 @@ subscribe to the gstreamer-devel list. Contributors to this release + * Aleix Conchillo Flaqué + * Edward Hervey + * Ian + * Jake Foytik + * Julien Isorce + * Nicolas Dufresne + * Nirbheek Chauhan + * Patricia Muscalu * Sebastian Dröge + * Tim-Philipp Müller + * Vineeth TM   \ No newline at end of file diff --git a/configure.ac b/configure.ac index f79c974da5..c466dc7523 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.9.0.1], +AC_INIT([GStreamer RTSP Server Library], [1.9.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 900, 0, 900) +AS_LIBTOOL(GST, 901, 0, 901) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.9.0.1 -GSTPB_REQ=1.9.0.1 -GSTPG_REQ=1.9.0.1 -GSTPD_REQ=1.9.0.1 +GST_REQ=1.9.1 +GSTPB_REQ=1.9.1 +GSTPG_REQ=1.9.1 +GSTPD_REQ=1.9.1 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 09f4cec823..a116a154dc 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.9.1 + master + + 2016-06-06 + + + + 1.8.0 From 3ceb89f41eaf1da063652e4a64eaf1acbc85e822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 6 Jul 2016 13:51:15 +0300 Subject: [PATCH 1270/1776] Back to development --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index c466dc7523..c021ee4196 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.9.1], +AC_INIT([GStreamer RTSP Server Library], [1.9.1.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 901, 0, 901) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.9.1 -GSTPB_REQ=1.9.1 -GSTPG_REQ=1.9.1 -GSTPD_REQ=1.9.1 +GST_REQ=1.9.1.1 +GSTPB_REQ=1.9.1.1 +GSTPG_REQ=1.9.1.1 +GSTPD_REQ=1.9.1.1 dnl *** autotools stuff **** From 63653a1ebea12350e08d03e2ca9bd82ff51f55e8 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 11 Jul 2016 21:16:04 +0200 Subject: [PATCH 1271/1776] Automatic update of common submodule From f363b32 to f49c55e --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index f363b32056..f49c55ecd3 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit f363b3205658a38e84fa77f19dee218cd4445275 +Subproject commit f49c55ecd35a7436194d28297f6d6f20eb6a66fa From 687301af867b99070ec8e3c35540d41d019fdcba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 2 Aug 2016 15:08:22 +0300 Subject: [PATCH 1272/1776] rtsp-client: Fix leaking of session in error cases https://bugzilla.gnome.org/show_bug.cgi?id=755632 --- gst/rtsp-server/rtsp-client.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c77e3598d4..1f53d67b10 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2066,20 +2066,20 @@ media_not_found_no_reply: { GST_ERROR ("client %p: media '%s' not found", client, path); /* error reply is already sent */ - goto cleanup_path; + goto cleanup_session; } media_not_found: { GST_ERROR ("client %p: media '%s' not found", client, path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); - goto cleanup_path; + goto cleanup_session; } control_not_found: { GST_ERROR ("client %p: no control in path '%s'", client, path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); g_object_unref (media); - goto cleanup_path; + goto cleanup_session; } stream_not_found: { @@ -2087,14 +2087,14 @@ stream_not_found: GST_STR_NULL (control)); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); g_object_unref (media); - goto cleanup_path; + goto cleanup_session; } service_unavailable: { GST_ERROR ("client %p: can't create session", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_object_unref (media); - goto cleanup_path; + goto cleanup_session; } sessmedia_unavailable: { @@ -2144,7 +2144,8 @@ keymgmt_error: cleanup_session: if (new_session) gst_rtsp_session_pool_remove (priv->session_pool, session); - g_object_unref (session); + if (session) + g_object_unref (session); cleanup_path: g_free (path); return FALSE; From de3d0c4522fb4b29887f43c2f274c27b1d0d2209 Mon Sep 17 00:00:00 2001 From: Nikita Bobkov Date: Fri, 25 Sep 2015 15:04:00 +0000 Subject: [PATCH 1273/1776] rtsp-client: Fix leaking of media in error cases With additional fixes by Kseniya Vasilchuk and myself to make the media refcounting a bit easier to follow. https://bugzilla.gnome.org/show_bug.cgi?id=755632 --- gst/rtsp-server/rtsp-client.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1f53d67b10..7af7701d86 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1965,15 +1965,14 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (sessmedia == NULL) { /* manage the media in our session now, if not done already */ - sessmedia = gst_rtsp_session_manage_media (session, path, media); + sessmedia = + gst_rtsp_session_manage_media (session, path, g_object_ref (media)); /* if we stil have no media, error */ if (sessmedia == NULL) goto sessmedia_unavailable; /* don't cache media anymore */ clean_cached_media (client, FALSE); - } else { - g_object_unref (media); } ctx->sessmedia = sessmedia; @@ -2036,6 +2035,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY); break; } + g_object_unref (media); g_object_unref (session); g_free (path); @@ -2100,12 +2100,12 @@ sessmedia_unavailable: { GST_ERROR ("client %p: can't create session media", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); - g_object_unref (media); - goto cleanup_session; + goto cleanup_transport; } configure_media_failed_no_reply: { GST_ERROR ("client %p: configure_media failed", client); + g_object_unref (media); /* error reply is already sent */ goto cleanup_session; } @@ -2141,6 +2141,8 @@ keymgmt_error: { cleanup_transport: gst_rtsp_transport_free (ct); + if (media) + g_object_unref (media); cleanup_session: if (new_session) gst_rtsp_session_pool_remove (priv->session_pool, session); From e9cab27226ea1cdb4c65726fefccd591ecc7f0a9 Mon Sep 17 00:00:00 2001 From: Josep Torra Date: Fri, 26 Aug 2016 21:56:13 +0200 Subject: [PATCH 1274/1776] build: silence error about pthread for 'make check' in osx Fixes "clang: error: argument unused during compilation: '-pthread'" --- configure.ac | 3 +++ tests/check/Makefile.am | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c021ee4196..7622a06ee8 100644 --- a/configure.ac +++ b/configure.ac @@ -137,6 +137,9 @@ GTK_DOC_CHECK([1.12]) dnl *** checks for libraries *** +dnl check for pthreads +AX_PTHREAD + dnl *** checks for header files *** dnl *** checks for types/defines *** diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 88715192e1..d4bdf7227e 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -50,7 +50,7 @@ AM_CFLAGS = -I$(top_srcdir)/gst/rtsp-server \ $(GST_CHECK_CFLAGS) \ -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ -DGST_CHECK_TEST_ENVIRONMENT_BEACON="\"GST_PLUGIN_LOADING_WHITELIST\"" \ - -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS + -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS $(PTHREAD_CFLAGS) AM_CXXFLAGS = $(GST_CXXFLAGS) $(GST_CHECK_CFLAGS) \ -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ -DGST_CHECK_TEST_ENVIRONMENT_BEACON="\"GST_PLUGIN_LOADING_WHITELIST\"" \ From a353e5074790c92858cf443fa80d35f4e8cb6468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 27 Jan 2016 01:03:52 +0000 Subject: [PATCH 1275/1776] Add support for Meson as alternative/parallel build system https://github.com/mesonbuild/meson --- config.h.meson | 16 +++++++++ examples/meson.build | 35 ++++++++++++++++++ gst/meson.build | 2 ++ gst/rtsp-server/meson.build | 58 ++++++++++++++++++++++++++++++ gst/rtsp-sink/meson.build | 12 +++++++ meson.build | 58 ++++++++++++++++++++++++++++++ pkgconfig/meson.build | 17 +++++++++ tests/check/meson.build | 72 +++++++++++++++++++++++++++++++++++++ tests/meson.build | 1 + 9 files changed, 271 insertions(+) create mode 100644 config.h.meson create mode 100644 examples/meson.build create mode 100644 gst/meson.build create mode 100644 gst/rtsp-server/meson.build create mode 100644 gst/rtsp-sink/meson.build create mode 100644 meson.build create mode 100644 pkgconfig/meson.build create mode 100644 tests/check/meson.build create mode 100644 tests/meson.build diff --git a/config.h.meson b/config.h.meson new file mode 100644 index 0000000000..c7709c8bd7 --- /dev/null +++ b/config.h.meson @@ -0,0 +1,16 @@ +#mesondefine ENABLE_NLS +#mesondefine GETTEXT_PACKAGE +#mesondefine GST_API_VERSION +#mesondefine GST_LICENSE +#mesondefine GST_PACKAGE_NAME +#mesondefine GST_PACKAGE_ORIGIN +#mesondefine GST_PACKAGE_RELEASE_DATETIME +#mesondefine LOCALEDIR +#mesondefine PACKAGE +#mesondefine PACKAGE_BUGREPORT +#mesondefine PACKAGE_NAME +#mesondefine PACKAGE_STRING +#mesondefine PACKAGE_TARNAME +#mesondefine PACKAGE_URL +#mesondefine PACKAGE_VERSION +#mesondefine VERSION diff --git a/examples/meson.build b/examples/meson.build new file mode 100644 index 0000000000..0a504470f3 --- /dev/null +++ b/examples/meson.build @@ -0,0 +1,35 @@ +examples = [ + 'test-appsrc', + 'test-auth', + 'test-launch', + 'test-mp4', + 'test-multicast2', + 'test-multicast', + 'test-netclock', + 'test-netclock-client', + 'test-ogg', + 'test-readme', + 'test-record-auth', + 'test-record', + 'test-sdp', + 'test-uri', + 'test-video', + 'test-video-rtx', +] + +foreach example : examples + executable(example, '@0@.c'.format(example), + c_args : rtspserver_args, + include_directories : rtspserver_incs, + dependencies : [glib_dep, gst_dep, gstnet_dep, gst_rtsp_server_dep], + install: false) +endforeach + +cgroup_dep = dependency('libcgroup', version : '>= 0.26', required : false) +if cgroup_dep.found() + executable('test-cgroups', 'test-cgroups.c', + c_args : rtspserver_args, + include_directories : rtspserver_incs, + dependencies : [glib_dep, gst_dep, gstnet_dep, gst_rtsp_server_dep, cgroup_dep], + install: false) +endif diff --git a/gst/meson.build b/gst/meson.build new file mode 100644 index 0000000000..229c861eed --- /dev/null +++ b/gst/meson.build @@ -0,0 +1,2 @@ +subdir('rtsp-server') +subdir('rtsp-sink') diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build new file mode 100644 index 0000000000..ef47015ae5 --- /dev/null +++ b/gst/rtsp-server/meson.build @@ -0,0 +1,58 @@ +rtsp_server_sources = [ + 'rtsp-address-pool.c', + 'rtsp-auth.c', + 'rtsp-client.c', + 'rtsp-context.c', + 'rtsp-media.c', + 'rtsp-media-factory.c', + 'rtsp-media-factory-uri.c', + 'rtsp-mount-points.c', + 'rtsp-params.c', + 'rtsp-permissions.c', + 'rtsp-sdp.c', + 'rtsp-server.c', + 'rtsp-session.c', + 'rtsp-session-media.c', + 'rtsp-session-pool.c', + 'rtsp-stream.c', + 'rtsp-stream-transport.c', + 'rtsp-thread-pool.c', + 'rtsp-token.c', +] + +rtsp_server_headers = [ + 'rtsp-auth.h', + 'rtsp-address-pool.h', + 'rtsp-context.h', + 'rtsp-params.h', + 'rtsp-sdp.h', + 'rtsp-thread-pool.h', + 'rtsp-media.h', + 'rtsp-media-factory.h', + 'rtsp-media-factory-uri.h', + 'rtsp-mount-points.h', + 'rtsp-permissions.h', + 'rtsp-stream.h', + 'rtsp-stream-transport.h', + 'rtsp-session.h', + 'rtsp-session-media.h', + 'rtsp-session-pool.h', + 'rtsp-token.h', + 'rtsp-client.h', + 'rtsp-server.h', +] +install_headers(rtsp_server_headers, subdir : 'gstreamer-1.0/gst/rtsp-server') + +gst_rtsp_server = library('gstrtspserver-@0@'.format(api_version), + rtsp_server_sources, + include_directories : rtspserver_incs, + c_args: rtspserver_args, + version : libversion, + soversion : soversion, + install : true, + dependencies : [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_dep], +) + +gst_rtsp_server_dep = declare_dependency(link_with : gst_rtsp_server, + include_directories : rtspserver_incs, + dependencies : [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_dep]) diff --git a/gst/rtsp-sink/meson.build b/gst/rtsp-sink/meson.build new file mode 100644 index 0000000000..b8fe2f0c64 --- /dev/null +++ b/gst/rtsp-sink/meson.build @@ -0,0 +1,12 @@ +rtspsink_sources = [ + 'gstrtspclientsink.c', + 'plugin.c', +] + +rtspsink = library('gstrtspclientsink', + rtspsink_sources, + c_args : rtspserver_args, + include_directories : rtspserver_incs, + dependencies : [gstrtsp_dep, gstsdp_dep, gst_rtsp_server_dep], + install : true, + install_dir : plugins_install_dir) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000000..d861ffef0e --- /dev/null +++ b/meson.build @@ -0,0 +1,58 @@ +project('gst-rtsp-server', 'c', + version : '1.9.1.1', + meson_version : '>= 0.33.0', + default_options : ['warning_level=1', 'buildtype=debugoptimized']) + +gst_version = meson.project_version() +version_arr = gst_version.split('.') +gst_version_major = version_arr[0] +gst_version_minor = version_arr[1] +gst_version_micro = version_arr[2] +if version_arr.length() == 4 + gst_version_nano = version_arr[3] +else + gst_version_nano = 0 +endif + +glib_req = '>= 2.40.0' +gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor) + +api_version = '1.0' +soversion = 0 +# maintaining compatibility with the previous libtool versioning +# current = minor * 100 + micro +libversion = '@0@.@1@.0'.format(soversion, gst_version_minor.to_int() * 100 + gst_version_micro.to_int()) + +plugins_install_dir = '@0@/gstreamer-1.0'.format(get_option('libdir')) + +cdata = configuration_data() +cdata.set('GETTEXT_PACKAGE', '"gst-rtsp-server-1.0"') +cdata.set('PACKAGE', '"gst-rtsp-server"') +cdata.set('VERSION', '"@0@"'.format(gst_version)) +cdata.set('PACKAGE_VERSION', '"@0@"'.format(gst_version)) +cdata.set('GST_PACKAGE_NAME', '"GStreamer RTSP Server Library"') +cdata.set('GST_PACKAGE_ORIGIN', '"Unknown package origin"') +#cdata.set('GST_API_VERSION', '"@0@"'.format(api_version)) +cdata.set('GST_LICENSE', '"LGPL"') + +configure_file(input : 'config.h.meson', + output : 'config.h', + configuration : cdata) + +rtspserver_args = ['-DHAVE_CONFIG_H'] + +rtspserver_incs = include_directories('gst/rtsp-server', '.') + +glib_dep = dependency('glib-2.0', version : glib_req) +gst_dep = dependency('gstreamer-1.0', version : gst_req) +gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req) +gstrtsp_dep = dependency('gstreamer-rtsp-1.0', version : gst_req) +gstrtp_dep = dependency('gstreamer-rtp-1.0', version : gst_req) +gstsdp_dep = dependency('gstreamer-sdp-1.0', version : gst_req) +gstapp_dep = dependency('gstreamer-app-1.0', version : gst_req) +gstnet_dep = dependency('gstreamer-net-1.0', version : gst_req) + +subdir('gst') +subdir('tests') +subdir('examples') +subdir('pkgconfig') diff --git a/pkgconfig/meson.build b/pkgconfig/meson.build new file mode 100644 index 0000000000..c4b7179f1f --- /dev/null +++ b/pkgconfig/meson.build @@ -0,0 +1,17 @@ +pkgconf = configuration_data() + +pkgconf.set('prefix', get_option('prefix')) +pkgconf.set('exec_prefix', '${prefix}') +pkgconf.set('libdir', '${prefix}/@0@'.format(get_option('libdir'))) +pkgconf.set('includedir', '${prefix}/@0@'.format(get_option('includedir'))) +pkgconf.set('GST_API_VERSION', api_version) +pkgconf.set('VERSION', gst_version) + +pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir')) + +# FIXME: -uninstalled.pc files (if still needed?) +configure_file(input : 'gstreamer-rtsp-server.pc.in', + output : 'gstreamer-rtsp-server-1.0.pc', + configuration : pkgconf, + install_dir : pkg_install_dir, +) diff --git a/tests/check/meson.build b/tests/check/meson.build new file mode 100644 index 0000000000..622c6c5606 --- /dev/null +++ b/tests/check/meson.build @@ -0,0 +1,72 @@ +# FIXME: something is wrong with plugin paths / whitelisting here + +test_plugins_modules = [ + ['gstreamer-1.0', true], + ['gstreamer-plugins-base-1.0', true], + ['gstreamer-plugins-good-1.0', false], + ['gstreamer-plugins-bad-1.0', false], +] +test_plugin_path = '' +foreach m : test_plugins_modules + m_name = m[0] + m_required = m[1] + runcmd = run_command('pkg-config', '--variable=pluginsdir', m_name + ' ' + gst_req) + if runcmd.returncode() == 0 + module_plugin_path = runcmd.stdout().strip() + message('Using '+ m_name + ' plugins in ' + module_plugin_path) + if test_plugin_path == '' + test_plugin_path = module_plugin_path + elif module_plugin_path != test_plugin_path + test_plugin_path = test_plugin_path + ':' + module_plugin_path + endif + elif m_required + error('Could not determine ' + m_name + ' plugins directory for unit tests.') + endif +endforeach + +test_c_args = [ + '-UG_DISABLE_ASSERT', + '-UG_DISABLE_CAST_CHECKS', + '-DGST_CHECK_TEST_ENVIRONMENT_BEACON="GST_PLUGIN_LOADING_WHITELIST"', +] + +test_env = [ + 'GST_PLUGIN_SYSTEM_PATH_1_0=', + 'GST_PLUGIN_PATH_1_0=' + meson.build_root() + '/gst/rtsp-sink:' + test_plugin_path, + 'GST_PLUGIN_LOADING_WHITELIST=gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad:gst-rtsp-server', + 'CK_DEFAULT_TIMEOUT=120', +] + +rtsp_server_tests = [ + 'gst/addresspool', + 'gst/client', + 'gst/mountpoints', + 'gst/mediafactory', + 'gst/media', + 'gst/permissions', + 'gst/rtspserver', + 'gst/rtspclientsink', + 'gst/sessionmedia', + 'gst/sessionpool', + 'gst/stream', + 'gst/threadpool', + 'gst/token', +] + +all_env = '' +foreach e : test_env + all_env = all_env + ' ' + e +endforeach +message('test env:' + all_env) + +foreach test_name : rtsp_server_tests + exe = executable(test_name, '@0@.c'.format(test_name), + include_directories : rtspserver_incs, + c_args : rtspserver_args + test_c_args, + dependencies : [gstcheck_dep, gstrtsp_dep, gstrtp_dep, gst_rtsp_server_dep] + ) + test(test_name, exe, + env : test_env + [ 'GST_REGISTRY=@0@/@1@.registry'.format(meson.current_build_dir(), test_name) ], + timeout : 120, + ) +endforeach diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000000..5f1c1c96c8 --- /dev/null +++ b/tests/meson.build @@ -0,0 +1 @@ +#subdir('check') # FIXME From c55ffc387921780f2e99951d68ea5274de33a5b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 1 Sep 2016 12:32:51 +0300 Subject: [PATCH 1276/1776] Release 1.9.2 --- ChangeLog | 86 ++++++++++++++++++++++++++++++-------------- NEWS | 2 +- RELEASE | 33 +++++++---------- configure.ac | 12 +++---- gst-rtsp-server.doap | 10 ++++++ 5 files changed, 89 insertions(+), 54 deletions(-) diff --git a/ChangeLog b/ChangeLog index 11c0514034..ebf0e05f3d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,66 @@ -=== release 1.9.1 === +=== release 1.9.2 === -2016-07-06 Sebastian Dröge +2016-09-01 Sebastian Dröge * configure.ac: - releasing 1.9.1 + releasing 1.9.2 + +2016-01-27 01:03:52 +0000 Tim-Philipp Müller + + * config.h.meson: + * examples/meson.build: + * gst/meson.build: + * gst/rtsp-server/meson.build: + * gst/rtsp-sink/meson.build: + * meson.build: + * pkgconfig/meson.build: + * tests/check/meson.build: + * tests/meson.build: + Add support for Meson as alternative/parallel build system + https://github.com/mesonbuild/meson + +2016-08-26 21:56:13 +0200 Josep Torra + + * configure.ac: + * tests/check/Makefile.am: + build: silence error about pthread for 'make check' in osx + Fixes "clang: error: argument unused during compilation: '-pthread'" + +2015-09-25 15:04:00 +0000 Nikita Bobkov + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Fix leaking of media in error cases + With additional fixes by Kseniya Vasilchuk + and myself to make the media refcounting a bit easier to follow. + https://bugzilla.gnome.org/show_bug.cgi?id=755632 + +2016-08-02 15:08:22 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Fix leaking of session in error cases + https://bugzilla.gnome.org/show_bug.cgi?id=755632 + +2016-07-11 21:16:04 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From f363b32 to f49c55e + +2016-07-06 13:51:15 +0300 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.9.1 === + +2016-07-06 13:28:12 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.9.1 2016-06-24 02:02:20 +0530 Nirbheek Chauhan @@ -6777,8 +6834,6 @@ * configure.ac: * pkgconfig/Makefile.am: - * pkgconfig/gst-rtsp-server-uninstalled.pc.in: - * pkgconfig/gst-rtsp-server.pc.in: * pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in: * pkgconfig/gstreamer-rtsp-server.pc.in: pkg-config: rename gst-rtsp-server-0.11.pc to gstreamer-rtsp-server-0.11.pc @@ -7666,8 +7721,6 @@ 2011-01-10 15:10:53 +0100 Wim Taymans * gst/rtsp-server/Makefile.am: - * gst/rtsp-server/fs-funnel.c: - * gst/rtsp-server/fs-funnel.h: * gst/rtsp-server/rtsp-funnel.c: * gst/rtsp-server/rtsp-funnel.h: * gst/rtsp-server/rtsp-media.c: @@ -9265,7 +9318,6 @@ 2009-01-29 13:31:27 +0100 Wim Taymans * examples/Makefile.am: - * examples/main.c: * examples/test-mp4.c: * examples/test-ogg.c: * examples/test-video.c: @@ -9533,19 +9585,12 @@ * bindings/vala/gst-rtsp-server-0.10.deps: * bindings/vala/gst-rtsp-server-0.10.vapi: - * bindings/vala/gst-rtsp-server.vapi: * bindings/vala/packages/gst-rtsp-server-0.10.deps: * bindings/vala/packages/gst-rtsp-server-0.10.excludes: * bindings/vala/packages/gst-rtsp-server-0.10.files: * bindings/vala/packages/gst-rtsp-server-0.10.gi: * bindings/vala/packages/gst-rtsp-server-0.10.metadata: * bindings/vala/packages/gst-rtsp-server-0.10.namespace: - * bindings/vala/packages/gst-rtsp-server.deps: - * bindings/vala/packages/gst-rtsp-server.excludes: - * bindings/vala/packages/gst-rtsp-server.files: - * bindings/vala/packages/gst-rtsp-server.gi: - * bindings/vala/packages/gst-rtsp-server.metadata: - * bindings/vala/packages/gst-rtsp-server.namespace: Regenerated Vala bindings 2008-12-08 13:19:40 +0100 Sebastian Pölsterl @@ -9622,17 +9667,6 @@ * gst/rtsp-server/rtsp-session.c: * gst/rtsp-server/rtsp-session.h: * src/Makefile.am: - * src/main.c: - * src/rtsp-client.c: - * src/rtsp-client.h: - * src/rtsp-media.c: - * src/rtsp-media.h: - * src/rtsp-server.c: - * src/rtsp-server.h: - * src/rtsp-session-pool.c: - * src/rtsp-session-pool.h: - * src/rtsp-session.c: - * src/rtsp-session.h: Split in library and example program 2008-11-10 20:59:35 +0100 Sebastian Pölsterl diff --git a/NEWS b/NEWS index 4c3baabdc2..027c01804e 100644 --- a/NEWS +++ b/NEWS @@ -1 +1 @@ -This is GStreamer 1.9.1 +This is GStreamer 1.9.2 diff --git a/RELEASE b/RELEASE index 7df862c35e..87b5eaf171 100644 --- a/RELEASE +++ b/RELEASE @@ -1,12 +1,13 @@ -Release notes for GStreamer RTSP Server Library 1.9.1 +Release notes for GStreamer RTSP Server Library 1.9.2 -The GStreamer team is pleased to announce the first release of the unstable -1.9 release series. The 1.9 release series is adding new features on top of -the 1.0, 1.2, 1.4, 1.6 and 1.8 series and is part of the API and ABI-stable 1.x release -series of the GStreamer multimedia framework. The unstable 1.9 release series -will lead to the stable 1.10 release series in the next weeks. Any newly added -API can still change until that point. +The GStreamer team is pleased to announce the second release of the unstable +1.9 release series, which marks the feature freeze for 1.10. The 1.9 release +series is adding new features on top of the 1.0, 1.2, 1.4, 1.6 and 1.8 series +and is part of the API and ABI-stable 1.x release series of the GStreamer +multimedia framework. The unstable 1.9 release series will lead to the stable +1.10 release series in the next weeks. Any newly added API can still change +until that point. Binaries for Android, iOS, Mac OS X and Windows will be provided in the next days. @@ -15,11 +16,7 @@ Binaries for Android, iOS, Mac OS X and Windows will be provided in the next day Bugs fixed in this release - * 760005 : rtsp-sdp: Implement clock signalling according to RFC7273 - * 761702 : rtsp-thread-pool: explain why GSource is a part of GstRTSPThreadImpl - * 763000 : Add support for setting multicast interface - * 763196 : rtspclientsink: use new gst_element_class_add_static_pad_template() - * 730539 : sdp: add support for multiple crypto sessions + * 755632 : Memory leak in handle_setup_request ==== Download ==== @@ -56,15 +53,9 @@ subscribe to the gstreamer-devel list. Contributors to this release - * Aleix Conchillo Flaqué - * Edward Hervey - * Ian - * Jake Foytik - * Julien Isorce - * Nicolas Dufresne - * Nirbheek Chauhan - * Patricia Muscalu + * Josep Torra + * Nikita Bobkov * Sebastian Dröge + * Stefan Sauer * Tim-Philipp Müller - * Vineeth TM   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 7622a06ee8..5fe11f3d39 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.9.1.1], +AC_INIT([GStreamer RTSP Server Library], [1.9.2], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 901, 0, 901) +AS_LIBTOOL(GST, 902, 0, 902) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.9.1.1 -GSTPB_REQ=1.9.1.1 -GSTPG_REQ=1.9.1.1 -GSTPD_REQ=1.9.1.1 +GST_REQ=1.9.2 +GSTPB_REQ=1.9.2 +GSTPG_REQ=1.9.2 +GSTPD_REQ=1.9.2 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index a116a154dc..78090d0c8f 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.9.2 + master + + 2016-09-01 + + + + 1.9.1 From 2ec0e567a923362004a3b031d852a28ca95397e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 1 Sep 2016 12:33:00 +0300 Subject: [PATCH 1277/1776] Back to development --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5fe11f3d39..5f62d0898a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.9.2], +AC_INIT([GStreamer RTSP Server Library], [1.9.2.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT From 07f17c2cce2d2cd8bc28db4ed30033b73009cb7b Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 20 Jul 2016 20:09:57 -0400 Subject: [PATCH 1278/1776] Revert "rtsp-stream: Fix crash on cleanup with shared media and multiple udpsrc" This partly reverts commit cba045e1b19fad6e689e10206f57903e15f1229a, but keeps unit tests. https://bugzilla.gnome.org/show_bug.cgi?id=766612 --- gst/rtsp-server/rtsp-stream.c | 299 +++++++++++++++------------------- 1 file changed, 131 insertions(+), 168 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 53894562c5..b72a2b2311 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -62,18 +62,6 @@ #define GST_RTSP_STREAM_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_STREAM, GstRTSPStreamPrivate)) -/* Container for udpsrc elements created for a specific RTSPTransport. */ -typedef struct -{ - GstElement *udpsrc[2]; -} GstRTSPStreamUDPSrcs; - -static void -destroy_udp_srcs_func (gpointer data) -{ - g_slice_free (GstRTSPStreamUDPSrcs, (GstRTSPStreamUDPSrcs *) data); -} - struct _GstRTSPStreamPrivate { GMutex lock; @@ -107,11 +95,16 @@ struct _GstRTSPStreamPrivate GstElement *srtpdec; GHashTable *keys; - /* Unicast UDP sources associated with RTSPTransports */ - GHashTable *udpsrcs; - - /* Only allow one set of IPV4 and IPV6 multicast udpsrcs */ + /* sinks used for sending and receiving RTP and RTCP over ipv4, they share + * sockets */ + GstElement *udpsrc_v4[2]; + /* UDP sources for UDP multicast transports */ GstElement *udpsrc_mcast_v4[2]; + + /* sinks used for sending and receiving RTP and RTCP over ipv6, they share + * sockets */ + GstElement *udpsrc_v6[2]; + /* UDP sources for UDP multicast transports */ GstElement *udpsrc_mcast_v6[2]; GstElement *udpqueue[2]; @@ -134,10 +127,12 @@ struct _GstRTSPStreamPrivate /* server ports for sending/receiving over ipv4 */ GstRTSPRange server_port_v4; GstRTSPAddress *server_addr_v4; + gboolean have_ipv4; /* server ports for sending/receiving over ipv6 */ GstRTSPRange server_port_v6; GstRTSPAddress *server_addr_v6; + gboolean have_ipv6; /* multicast addresses */ GstRTSPAddressPool *pool; @@ -275,8 +270,6 @@ gst_rtsp_stream_init (GstRTSPStream * stream) NULL, (GDestroyNotify) gst_caps_unref); priv->ptmap = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) gst_caps_unref); - priv->udpsrcs = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) destroy_udp_srcs_func); } static void @@ -319,11 +312,6 @@ gst_rtsp_stream_finalize (GObject * obj) g_hash_table_unref (priv->keys); g_hash_table_destroy (priv->ptmap); - /* We expect all udpsrcs to be cleaned up by this point. */ - if (g_hash_table_size (priv->udpsrcs) > 0) - g_critical ("Unreffing udpsrcs hash table that contains elements."); - g_hash_table_unref (priv->udpsrcs); - G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); } @@ -1505,63 +1493,42 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, g_mutex_lock (&priv->lock); - if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - if (family == G_SOCKET_FAMILY_IPV4) { - /* Multicast IPV4 */ - if (priv->have_ipv4_mcast) { - result = TRUE; + if (family == G_SOCKET_FAMILY_IPV4) { + if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + if (priv->have_ipv4_mcast) goto done; - } - priv->have_ipv4_mcast = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_mcast_v4, &priv->server_port_v4, ct, &priv->addr_v4, use_client_settings); - result = priv->have_ipv4_mcast; - } else { - /* Multicast IPV6 */ - if (priv->have_ipv6_mcast) { - result = TRUE; + priv->have_ipv4 = + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, + &priv->server_port_v4, ct, &priv->server_addr_v4, + use_client_settings); + } + } else { + if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + if (priv->have_ipv6_mcast) goto done; - } - priv->have_ipv6_mcast = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, priv->udpsrc_mcast_v6, &priv->server_port_v6, ct, &priv->addr_v6, use_client_settings); - result = priv->have_ipv6_mcast; - } - } else { - /* We allow multiple unicast transports, so we must maintain a table of the - * udpsrcs created for them. */ - GstRTSPStreamUDPSrcs *transport_udpsrcs = - g_slice_new0 (GstRTSPStreamUDPSrcs); - - if (family == G_SOCKET_FAMILY_IPV4) { - /* Unicast IPV4 */ - result = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, - transport_udpsrcs->udpsrc, &priv->server_port_v4, ct, - &priv->server_addr_v4, use_client_settings); } else { - /* Unicast IPV6 */ - result = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, - transport_udpsrcs->udpsrc, &priv->server_port_v6, ct, - &priv->server_addr_v6, use_client_settings); + if (priv->have_ipv6) + goto done; + priv->have_ipv6 = + alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, + &priv->server_port_v6, ct, &priv->server_addr_v6, + use_client_settings); } - - /* If we didn't create any unicast udpsrcs, free the transport_udpsrcs struct. - * Otherwise, add it to the hash table */ - if (transport_udpsrcs->udpsrc[0] == NULL - && transport_udpsrcs->udpsrc[1] == NULL) - g_slice_free (GstRTSPStreamUDPSrcs, transport_udpsrcs); - else - g_hash_table_insert (priv->udpsrcs, ct, transport_udpsrcs); } done: + result = priv->have_ipv4 || priv->have_ipv4_mcast || priv->have_ipv6 || + priv->have_ipv6_mcast; + g_mutex_unlock (&priv->lock); return result; @@ -2645,6 +2612,39 @@ create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) gst_pad_link (pad, priv->recv_sink[i]); gst_object_unref (pad); + if (priv->udpsrc_v4[i]) { + if (priv->srcpad) { + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values. This is only relevant for PLAY pipelines */ + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); + } + /* add udpsrc */ + gst_bin_add (bin, priv->udpsrc_v4[i]); + + /* and link to the funnel v4 */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + } + + if (priv->udpsrc_v6[i]) { + if (priv->srcpad) { + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); + } + gst_bin_add (bin, priv->udpsrc_v6[i]); + + /* and link to the funnel v6 */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + } + if (is_tcp) { /* make and add appsrc */ priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); @@ -2834,50 +2834,51 @@ no_udp_protocol: gst_element_set_state (priv->udpsink[0], GST_STATE_NULL); if (priv->udpsink[1]) gst_element_set_state (priv->udpsink[1], GST_STATE_NULL); - + if (priv->udpsrc_v4[0]) { + gst_element_set_state (priv->udpsrc_v4[0], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_v4[0]); + priv->udpsrc_v4[0] = NULL; + } + if (priv->udpsrc_v4[1]) { + gst_element_set_state (priv->udpsrc_v4[1], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_v4[1]); + priv->udpsrc_v4[1] = NULL; + } + if (priv->udpsrc_mcast_v4[0]) { + gst_element_set_state (priv->udpsrc_mcast_v4[0], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_mcast_v4[0]); + priv->udpsrc_mcast_v4[0] = NULL; + } + if (priv->udpsrc_mcast_v4[1]) { + gst_element_set_state (priv->udpsrc_mcast_v4[1], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_mcast_v4[1]); + priv->udpsrc_mcast_v4[1] = NULL; + } + if (priv->udpsrc_v6[0]) { + gst_element_set_state (priv->udpsrc_v6[0], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_v6[0]); + priv->udpsrc_v6[0] = NULL; + } + if (priv->udpsrc_v6[1]) { + gst_element_set_state (priv->udpsrc_v6[1], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_v6[1]); + priv->udpsrc_v6[1] = NULL; + } + if (priv->udpsrc_mcast_v6[0]) { + gst_element_set_state (priv->udpsrc_mcast_v6[0], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_mcast_v6[0]); + priv->udpsrc_mcast_v6[0] = NULL; + } + if (priv->udpsrc_mcast_v6[1]) { + gst_element_set_state (priv->udpsrc_mcast_v6[1], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_mcast_v6[1]); + priv->udpsrc_mcast_v6[1] = NULL; + } g_mutex_unlock (&priv->lock); return FALSE; } } -/* Must be called with priv->lock. */ -static void -remove_all_unicast_udpsrcs (GstRTSPStream * stream, GstBin * bin) -{ - GstRTSPStreamPrivate *priv; - GHashTableIter iter; - gpointer iter_key, iter_value; - - priv = stream->priv; - - /* Remove all of the unicast udpsrcs */ - g_hash_table_iter_init (&iter, priv->udpsrcs); - while (g_hash_table_iter_next (&iter, &iter_key, &iter_value)) { - GstRTSPStreamUDPSrcs *transport_udpsrcs = - (GstRTSPStreamUDPSrcs *) iter_value; - - for (int i = 0; i < 2; i++) { - if (transport_udpsrcs->udpsrc[i]) { - if (priv->sinkpad || i == 1) { - /* Set udpsrc to NULL now before removing */ - gst_element_set_locked_state (transport_udpsrcs->udpsrc[i], FALSE); - gst_element_set_state (transport_udpsrcs->udpsrc[i], GST_STATE_NULL); - - /* removing them should also nicely release the request - * pads when they finalize */ - gst_bin_remove (bin, transport_udpsrcs->udpsrc[i]); - } else { - /* we need to set the state to NULL before unref */ - gst_element_set_state (transport_udpsrcs->udpsrc[i], GST_STATE_NULL); - gst_object_unref (transport_udpsrcs->udpsrc[i]); - } - } - } - } - - g_hash_table_remove_all (priv->udpsrcs); -} - /** * gst_rtsp_stream_leave_bin: * @stream: a #GstRTSPStream @@ -2935,7 +2936,6 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); - remove_all_unicast_udpsrcs (stream, bin); for (i = 0; i < 2; i++) { if (priv->udpsink[i]) @@ -2953,6 +2953,21 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, if (priv->appsrc[i]) gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); + if (priv->udpsrc_v4[i]) { + if (priv->sinkpad || i == 1) { + /* and set udpsrc to NULL now before removing */ + gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE); + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); + /* removing them should also nicely release the request + * pads when they finalize */ + gst_bin_remove (bin, priv->udpsrc_v4[i]); + } else { + /* we need to set the state to NULL before unref */ + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_v4[i]); + } + } + if (priv->udpsrc_mcast_v4[i]) { if (priv->sinkpad || i == 1) { /* and set udpsrc to NULL now before removing */ @@ -2967,6 +2982,16 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, } } + if (priv->udpsrc_v6[i]) { + if (priv->sinkpad || i == 1) { + gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE); + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); + gst_bin_remove (bin, priv->udpsrc_v6[i]); + } else { + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); + gst_object_unref (priv->udpsrc_v6[i]); + } + } if (priv->udpsrc_mcast_v6[i]) { if (priv->sinkpad || i == 1) { gst_element_set_locked_state (priv->udpsrc_mcast_v6[i], FALSE); @@ -3007,6 +3032,8 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->recv_sink[i] = NULL; } + priv->udpsrc_v4[i] = NULL; + priv->udpsrc_v6[i] = NULL; priv->udpsrc_mcast_v4[i] = NULL; priv->udpsrc_mcast_v6[i] = NULL; priv->udpsink[i] = NULL; @@ -3377,68 +3404,6 @@ gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer) return ret; } -/* Properly dispose udpsrcs that were created for a given transport. */ -/* Must be called with priv->lock. */ -static void -remove_transport_udpsrcs (GstRTSPStreamPrivate * priv, - const GstRTSPTransport * tr) -{ - /* Remove the udpsrcs associated with this transport. */ - GstRTSPStreamUDPSrcs *transport_udpsrcs = - g_hash_table_lookup (priv->udpsrcs, tr); - if (transport_udpsrcs != NULL) { - for (int i = 0; i < 2; i++) { - if (transport_udpsrcs->udpsrc[i]) { - if (priv->sinkpad || i == 1) { - GstBin *bin; - GstPad *udpsrc_srcpad, *funnel_sinkpad; - - /* We know these udpsrcs are all linked to funnels. Explicitely - * get the funnel src pads so we can properly release them. */ - udpsrc_srcpad = - gst_element_get_static_pad (transport_udpsrcs->udpsrc[i], "src"); - funnel_sinkpad = gst_pad_get_peer (udpsrc_srcpad); - - if (funnel_sinkpad != NULL) { - /* Unlink pads and release funnel's request pad. */ - gst_pad_unlink (udpsrc_srcpad, funnel_sinkpad); - gst_element_release_request_pad (priv->funnel[i], funnel_sinkpad); - gst_object_unref (funnel_sinkpad); - } - gst_object_unref (udpsrc_srcpad); - - /* Set udpsrc to NULL now before removing */ - gst_element_set_locked_state (transport_udpsrcs->udpsrc[i], FALSE); - gst_element_set_state (transport_udpsrcs->udpsrc[i], GST_STATE_NULL); - - /* This udpsrc is expected to be owned by a bin. Get the bin and - * remove our element. */ - bin = GST_BIN (gst_element_get_parent (transport_udpsrcs->udpsrc[i])); - if (bin != NULL) { - gst_bin_remove (bin, transport_udpsrcs->udpsrc[i]); - gst_object_unref (bin); - } else { - GST_ERROR ("Expected this udpsrc element to be part of a bin."); - gst_object_unref (transport_udpsrcs->udpsrc[i]); - } - - } else { - /* we need to set the state to NULL before unref */ - gst_element_set_state (transport_udpsrcs->udpsrc[i], GST_STATE_NULL); - gst_object_unref (transport_udpsrcs->udpsrc[i]); - } - } - } - - /* The udpsrcs are now properly cleaned up. Remove them from the table */ - g_hash_table_remove (priv->udpsrcs, tr); - - } else { - /* This can happen if we're dealing with a multicast transport. */ - GST_INFO ("Could not find udpsrcs associated with this transport."); - } -} - /* must be called with lock */ static gboolean update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, @@ -3487,8 +3452,6 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, g_signal_emit_by_name (priv->udpsink[0], "remove", dest, min, NULL); g_signal_emit_by_name (priv->udpsink[1], "remove", dest, max, NULL); priv->transports = g_list_remove (priv->transports, trans); - - remove_transport_udpsrcs (priv, tr); } priv->transports_cookie++; break; From 2b223af7923a9dd16a6d1009f9902e1df3721470 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 20 Jul 2016 23:18:23 -0400 Subject: [PATCH 1279/1776] stream: small fix in error code path https://bugzilla.gnome.org/show_bug.cgi?id=766612 --- gst/rtsp-server/rtsp-stream.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index b72a2b2311..f3ad1ad99f 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1251,10 +1251,14 @@ create_and_configure_udpsources_one_family (GstElement * udpsrc_out[2], /* ERRORS */ error: { - if (udpsrc_out[0]) - gst_object_unref (udpsrc_out[0]); - if (udpsrc_out[1]) - gst_object_unref (udpsrc_out[1]); + if (udpsrc_out[0]) { + gst_element_set_state (udpsrc_out[0], GST_STATE_NULL); + g_clear_object (&udpsrc_out[0]); + } + if (udpsrc_out[1]) { + gst_element_set_state (udpsrc_out[1], GST_STATE_NULL); + g_clear_object (&udpsrc_out[1]); + } return FALSE; } } From 3ff4529a925c7da181c6602920fa5445533a72c5 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 20 Jul 2016 15:11:32 -0400 Subject: [PATCH 1280/1776] stream: code cleanup https://bugzilla.gnome.org/show_bug.cgi?id=766612 --- gst/rtsp-server/rtsp-stream.c | 485 ++++++++++++++-------------------- 1 file changed, 205 insertions(+), 280 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index f3ad1ad99f..533cbb9b43 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1179,28 +1179,33 @@ play_udpsources_one_family (GstRTSPStream * stream, GstElement * udpsrc_out[2], bin = GST_BIN (gst_object_get_parent (GST_OBJECT (priv->funnel[1]))); for (i = 0; i < 2; i++) { - if (priv->sinkpad || i == 1) { - if (priv->srcpad) { - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values. This is only relevant for PLAY pipelines */ - gst_element_set_state (udpsrc_out[i], GST_STATE_PLAYING); - gst_element_set_locked_state (udpsrc_out[i], TRUE); - } - /* add udpsrc */ - gst_bin_add (bin, udpsrc_out[i]); + if (!priv->sinkpad && i == 0) { + /* Only connect recv RTP sink if we expect to receive RTP. Connect recv + * RTCP sink always */ + continue; + } - /* and link to the funnel */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (udpsrc_out[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); + if (priv->srcpad) { + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values. This is only relevant for PLAY pipelines */ + gst_element_set_state (udpsrc_out[i], GST_STATE_PLAYING); + gst_element_set_locked_state (udpsrc_out[i], TRUE); + } - /* otherwise sync state with parent in case it's running already - * at this point */ - if (!priv->srcpad) { - gst_element_sync_state_with_parent (udpsrc_out[i]); - } + /* add udpsrc */ + gst_bin_add (bin, udpsrc_out[i]); + + /* and link to the funnel */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (udpsrc_out[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + + /* otherwise sync state with parent in case it's running already + * at this point */ + if (!priv->srcpad) { + gst_element_sync_state_with_parent (udpsrc_out[i]); } } @@ -1246,7 +1251,6 @@ create_and_configure_udpsources_one_family (GstElement * udpsrc_out[2], goto error; return TRUE; - return TRUE; /* ERRORS */ error: @@ -2469,102 +2473,102 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) * and link the udpsink (for UDP) or appsink (for TCP) directly to * the session. */ + /* Only link the RTP send src if we're going to send RTP, link * the RTCP send src always */ - if (priv->srcpad || i == 1) { - if (is_udp) { - /* add udpsink */ - gst_bin_add (bin, priv->udpsink[i]); - sinkpad = gst_element_get_static_pad (priv->udpsink[i], "sink"); - } + if (!priv->srcpad && i == 0) + continue; - if (is_tcp) { - /* make appsink */ - priv->appsink[i] = gst_element_factory_make ("appsink", NULL); - g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); - gst_bin_add (bin, priv->appsink[i]); - gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), - &sink_cb, stream, NULL); - } + if (is_udp) { + /* add udpsink */ + gst_bin_add (bin, priv->udpsink[i]); + sinkpad = gst_element_get_static_pad (priv->udpsink[i], "sink"); + } - if (is_udp && is_tcp) { + if (is_tcp) { + /* make appsink */ + priv->appsink[i] = gst_element_factory_make ("appsink", NULL); + g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); + gst_bin_add (bin, priv->appsink[i]); + gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), + &sink_cb, stream, NULL); + } + + if (is_udp && is_tcp) { + g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); + + /* make tee for RTP/RTCP */ + priv->tee[i] = gst_element_factory_make ("tee", NULL); + gst_bin_add (bin, priv->tee[i]); + + /* and link to rtpbin send pad */ + pad = gst_element_get_static_pad (priv->tee[i], "sink"); + gst_pad_link (priv->send_src[i], pad); + gst_object_unref (pad); + + priv->udpqueue[i] = gst_element_factory_make ("queue", NULL); + g_object_set (priv->udpqueue[i], "max-size-buffers", + 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), NULL); + gst_bin_add (bin, priv->udpqueue[i]); + /* link tee to udpqueue */ + teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); + pad = gst_element_get_static_pad (priv->udpqueue[i], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); + + /* link udpqueue to udpsink */ + queuepad = gst_element_get_static_pad (priv->udpqueue[i], "src"); + gst_pad_link (queuepad, sinkpad); + gst_object_unref (queuepad); + gst_object_unref (sinkpad); + + /* make appqueue */ + priv->appqueue[i] = gst_element_factory_make ("queue", NULL); + g_object_set (priv->appqueue[i], "max-size-buffers", + 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), NULL); + gst_bin_add (bin, priv->appqueue[i]); + /* and link tee to appqueue */ + teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); + pad = gst_element_get_static_pad (priv->appqueue[i], "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); + + /* and link appqueue to appsink */ + queuepad = gst_element_get_static_pad (priv->appqueue[i], "src"); + pad = gst_element_get_static_pad (priv->appsink[i], "sink"); + gst_pad_link (queuepad, pad); + gst_object_unref (pad); + gst_object_unref (queuepad); + } else if (is_tcp) { + /* only appsink needed, link it to the session */ + pad = gst_element_get_static_pad (priv->appsink[i], "sink"); + gst_pad_link (priv->send_src[i], pad); + gst_object_unref (pad); + + /* when its only TCP, we need to set sync and preroll to FALSE + * for the sink to avoid deadlock. And this is only needed for + * sink used for RTCP data, not the RTP data. */ + if (i == 1) g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); - - /* make tee for RTP/RTCP */ - priv->tee[i] = gst_element_factory_make ("tee", NULL); - gst_bin_add (bin, priv->tee[i]); - - /* and link to rtpbin send pad */ - pad = gst_element_get_static_pad (priv->tee[i], "sink"); - gst_pad_link (priv->send_src[i], pad); - gst_object_unref (pad); - - priv->udpqueue[i] = gst_element_factory_make ("queue", NULL); - g_object_set (priv->udpqueue[i], "max-size-buffers", - 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), - NULL); - gst_bin_add (bin, priv->udpqueue[i]); - /* link tee to udpqueue */ - teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); - pad = gst_element_get_static_pad (priv->udpqueue[i], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); - - /* link udpqueue to udpsink */ - queuepad = gst_element_get_static_pad (priv->udpqueue[i], "src"); - gst_pad_link (queuepad, sinkpad); - gst_object_unref (queuepad); - gst_object_unref (sinkpad); - - /* make appqueue */ - priv->appqueue[i] = gst_element_factory_make ("queue", NULL); - g_object_set (priv->appqueue[i], "max-size-buffers", - 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), - NULL); - gst_bin_add (bin, priv->appqueue[i]); - /* and link tee to appqueue */ - teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); - pad = gst_element_get_static_pad (priv->appqueue[i], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); - - /* and link appqueue to appsink */ - queuepad = gst_element_get_static_pad (priv->appqueue[i], "src"); - pad = gst_element_get_static_pad (priv->appsink[i], "sink"); - gst_pad_link (queuepad, pad); - gst_object_unref (pad); - gst_object_unref (queuepad); - } else if (is_tcp) { - /* only appsink needed, link it to the session */ - pad = gst_element_get_static_pad (priv->appsink[i], "sink"); - gst_pad_link (priv->send_src[i], pad); - gst_object_unref (pad); - - /* when its only TCP, we need to set sync and preroll to FALSE - * for the sink to avoid deadlock. And this is only needed for - * sink used for RTCP data, not the RTP data. */ - if (i == 1) - g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); - } else { - /* else only udpsink needed, link it to the session */ - gst_pad_link (priv->send_src[i], sinkpad); - gst_object_unref (sinkpad); - } + } else { + /* else only udpsink needed, link it to the session */ + gst_pad_link (priv->send_src[i], sinkpad); + gst_object_unref (sinkpad); } /* check if we need to set to a special state */ if (state != GST_STATE_NULL) { - if (priv->udpsink[i] && (priv->srcpad || i == 1)) + if (priv->udpsink[i]) gst_element_set_state (priv->udpsink[i], state); - if (priv->appsink[i] && (priv->srcpad || i == 1)) + if (priv->appsink[i]) gst_element_set_state (priv->appsink[i], state); - if (priv->appqueue[i] && (priv->srcpad || i == 1)) + if (priv->appqueue[i]) gst_element_set_state (priv->appqueue[i], state); - if (priv->udpqueue[i] && (priv->srcpad || i == 1)) + if (priv->udpqueue[i]) gst_element_set_state (priv->udpqueue[i], state); - if (priv->tee[i] && (priv->srcpad || i == 1)) + if (priv->tee[i]) gst_element_set_state (priv->tee[i], state); } } @@ -2592,87 +2596,89 @@ create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) is_tcp = priv->protocols & GST_RTSP_LOWER_TRANS_TCP; for (i = 0; i < 2; i++) { - /* Only connect recv RTP sink if we expect to receive RTP. Connect recv - * RTCP sink always */ - if (priv->sinkpad || i == 1) { - /* For the receiver we create this bit of pipeline for both - * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc - * and it is all funneled into the rtpbin receive pad. - * - * .--------. .--------. .--------. - * | udpsrc | | funnel | | rtpbin | - * | src->sink src->sink | - * '--------' | | '--------' - * .--------. | | - * | appsrc | | | - * | src->sink | - * '--------' '--------' - */ - /* make funnel for the RTP/RTCP receivers */ - priv->funnel[i] = gst_element_factory_make ("funnel", NULL); - gst_bin_add (bin, priv->funnel[i]); + /* For the receiver we create this bit of pipeline for both + * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc + * and it is all funneled into the rtpbin receive pad. + * + * .--------. .--------. .--------. + * | udpsrc | | funnel | | rtpbin | + * | src->sink src->sink | + * '--------' | | '--------' + * .--------. | | + * | appsrc | | | + * | src->sink | + * '--------' '--------' + */ - pad = gst_element_get_static_pad (priv->funnel[i], "src"); - gst_pad_link (pad, priv->recv_sink[i]); + if (!priv->sinkpad && i == 0) { + /* Only connect recv RTP sink if we expect to receive RTP. Connect recv + * RTCP sink always */ + continue; + } + + /* make funnel for the RTP/RTCP receivers */ + priv->funnel[i] = gst_element_factory_make ("funnel", NULL); + gst_bin_add (bin, priv->funnel[i]); + + pad = gst_element_get_static_pad (priv->funnel[i], "src"); + gst_pad_link (pad, priv->recv_sink[i]); + gst_object_unref (pad); + + if (priv->udpsrc_v4[i]) { + if (priv->srcpad) { + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values. This is only relevant for PLAY pipelines */ + gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); + } + /* add udpsrc */ + gst_bin_add (bin, priv->udpsrc_v4[i]); + + /* and link to the funnel v4 */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src"); + gst_pad_link (pad, selpad); gst_object_unref (pad); + gst_object_unref (selpad); + } - if (priv->udpsrc_v4[i]) { - if (priv->srcpad) { - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values. This is only relevant for PLAY pipelines */ - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); - } - /* add udpsrc */ - gst_bin_add (bin, priv->udpsrc_v4[i]); - - /* and link to the funnel v4 */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); + if (priv->udpsrc_v6[i]) { + if (priv->srcpad) { + gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); } + gst_bin_add (bin, priv->udpsrc_v6[i]); - if (priv->udpsrc_v6[i]) { - if (priv->srcpad) { - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); - } - gst_bin_add (bin, priv->udpsrc_v6[i]); + /* and link to the funnel v6 */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); + } - /* and link to the funnel v6 */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - } - - if (is_tcp) { - /* make and add appsrc */ - priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); - priv->appsrc_base_time[i] = -1; - if (priv->srcpad) { - gst_element_set_state (priv->appsrc[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->appsrc[i], TRUE); - } - g_object_set (priv->appsrc[i], "format", GST_FORMAT_TIME, "is-live", - TRUE, NULL); - gst_bin_add (bin, priv->appsrc[i]); - /* and link to the funnel */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->appsrc[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); + if (is_tcp) { + /* make and add appsrc */ + priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); + priv->appsrc_base_time[i] = -1; + if (priv->srcpad) { + gst_element_set_state (priv->appsrc[i], GST_STATE_PLAYING); + gst_element_set_locked_state (priv->appsrc[i], TRUE); } + g_object_set (priv->appsrc[i], "format", GST_FORMAT_TIME, "is-live", + TRUE, NULL); + gst_bin_add (bin, priv->appsrc[i]); + /* and link to the funnel */ + selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); + pad = gst_element_get_static_pad (priv->appsrc[i], "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); } /* check if we need to set to a special state */ if (state != GST_STATE_NULL) { - if (priv->funnel[i] && (priv->sinkpad || i == 1)) - gst_element_set_state (priv->funnel[i], state); + gst_element_set_state (priv->funnel[i], state); } } } @@ -2883,6 +2889,20 @@ no_udp_protocol: } } +static void +clear_element (GstBin * bin, GstElement ** elementptr) +{ + if (*elementptr) { + gst_element_set_locked_state (*elementptr, FALSE); + gst_element_set_state (*elementptr, GST_STATE_NULL); + if (GST_ELEMENT_PARENT (*elementptr)) + gst_bin_remove (bin, *elementptr); + else + gst_object_unref (*elementptr); + *elementptr = NULL; + } +} + /** * gst_rtsp_stream_leave_bin: * @stream: a #GstRTSPStream @@ -2899,7 +2919,6 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, { GstRTSPStreamPrivate *priv; gint i; - gboolean is_tcp, is_udp; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); g_return_val_if_fail (GST_IS_BIN (bin), FALSE); @@ -2935,118 +2954,24 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->recv_rtp_src = NULL; } - is_tcp = priv->protocols & GST_RTSP_LOWER_TRANS_TCP; - - is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || - (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); - - for (i = 0; i < 2; i++) { - if (priv->udpsink[i]) - gst_element_set_state (priv->udpsink[i], GST_STATE_NULL); - if (priv->appsink[i]) - gst_element_set_state (priv->appsink[i], GST_STATE_NULL); - if (priv->appqueue[i]) - gst_element_set_state (priv->appqueue[i], GST_STATE_NULL); - if (priv->udpqueue[i]) - gst_element_set_state (priv->udpqueue[i], GST_STATE_NULL); - if (priv->tee[i]) - gst_element_set_state (priv->tee[i], GST_STATE_NULL); - if (priv->funnel[i]) - gst_element_set_state (priv->funnel[i], GST_STATE_NULL); - if (priv->appsrc[i]) - gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); - - if (priv->udpsrc_v4[i]) { - if (priv->sinkpad || i == 1) { - /* and set udpsrc to NULL now before removing */ - gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE); - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); - /* removing them should also nicely release the request - * pads when they finalize */ - gst_bin_remove (bin, priv->udpsrc_v4[i]); - } else { - /* we need to set the state to NULL before unref */ - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_v4[i]); - } - } - - if (priv->udpsrc_mcast_v4[i]) { - if (priv->sinkpad || i == 1) { - /* and set udpsrc to NULL now before removing */ - gst_element_set_locked_state (priv->udpsrc_mcast_v4[i], FALSE); - gst_element_set_state (priv->udpsrc_mcast_v4[i], GST_STATE_NULL); - /* removing them should also nicely release the request - * pads when they finalize */ - gst_bin_remove (bin, priv->udpsrc_mcast_v4[i]); - } else { - gst_element_set_state (priv->udpsrc_mcast_v4[i], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_mcast_v4[i]); - } - } - - if (priv->udpsrc_v6[i]) { - if (priv->sinkpad || i == 1) { - gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE); - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); - gst_bin_remove (bin, priv->udpsrc_v6[i]); - } else { - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_v6[i]); - } - } - if (priv->udpsrc_mcast_v6[i]) { - if (priv->sinkpad || i == 1) { - gst_element_set_locked_state (priv->udpsrc_mcast_v6[i], FALSE); - gst_element_set_state (priv->udpsrc_mcast_v6[i], GST_STATE_NULL); - gst_bin_remove (bin, priv->udpsrc_mcast_v6[i]); - } else { - gst_element_set_state (priv->udpsrc_mcast_v6[i], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_mcast_v6[i]); - } - } - - if (priv->udpsink[i] && is_udp && (priv->srcpad || i == 1)) - gst_bin_remove (bin, priv->udpsink[i]); - if (priv->appsrc[i]) { - if (priv->sinkpad || i == 1) { - gst_element_set_locked_state (priv->appsrc[i], FALSE); - gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); - gst_bin_remove (bin, priv->appsrc[i]); - } else { - gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); - gst_object_unref (priv->appsrc[i]); - } - } - if (priv->appsink[i] && is_tcp && (priv->srcpad || i == 1)) - gst_bin_remove (bin, priv->appsink[i]); - if (priv->appqueue[i] && is_tcp && is_udp && (priv->srcpad || i == 1)) - gst_bin_remove (bin, priv->appqueue[i]); - if (priv->udpqueue[i] && is_tcp && is_udp && (priv->srcpad || i == 1)) - gst_bin_remove (bin, priv->udpqueue[i]); - if (priv->tee[i] && is_tcp && is_udp && (priv->srcpad || i == 1)) - gst_bin_remove (bin, priv->tee[i]); - if (priv->funnel[i] && (priv->sinkpad || i == 1)) - gst_bin_remove (bin, priv->funnel[i]); + clear_element (bin, &priv->udpsink[i]); + clear_element (bin, &priv->appsink[i]); + clear_element (bin, &priv->appqueue[i]); + clear_element (bin, &priv->udpqueue[i]); + clear_element (bin, &priv->tee[i]); + clear_element (bin, &priv->funnel[i]); + clear_element (bin, &priv->appsrc[i]); + clear_element (bin, &priv->udpsrc_v4[i]); + clear_element (bin, &priv->udpsrc_v6[i]); + clear_element (bin, &priv->udpsrc_mcast_v4[i]); + clear_element (bin, &priv->udpsrc_mcast_v6[i]); if (priv->sinkpad || i == 1) { gst_element_release_request_pad (rtpbin, priv->recv_sink[i]); gst_object_unref (priv->recv_sink[i]); priv->recv_sink[i] = NULL; } - - priv->udpsrc_v4[i] = NULL; - priv->udpsrc_v6[i] = NULL; - priv->udpsrc_mcast_v4[i] = NULL; - priv->udpsrc_mcast_v6[i] = NULL; - priv->udpsink[i] = NULL; - priv->appsrc[i] = NULL; - priv->appsink[i] = NULL; - priv->appqueue[i] = NULL; - priv->udpqueue[i] = NULL; - priv->tee[i] = NULL; - priv->funnel[i] = NULL; } if (priv->srcpad) { From 55a1df5724bc523ab985e42111dd0d90479339a0 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 14 Jul 2016 11:10:31 -0400 Subject: [PATCH 1281/1776] stream: Keep a ref on joined bin https://bugzilla.gnome.org/show_bug.cgi?id=766612 --- gst/rtsp-server/rtsp-stream.c | 40 ++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 533cbb9b43..5a564c6b33 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -70,7 +70,6 @@ struct _GstRTSPStreamPrivate GstPad *srcpad, *sinkpad; GstElement *payloader; guint buffer_size; - gboolean is_joined; GstBin *joined_bin; /* TRUE if this stream is running on @@ -284,7 +283,7 @@ gst_rtsp_stream_finalize (GObject * obj) GST_DEBUG ("finalize stream %p", stream); /* we really need to be unjoined now */ - g_return_if_fail (!priv->is_joined); + g_return_if_fail (priv->joined_bin == NULL); if (priv->addr_v4) gst_rtsp_address_free (priv->addr_v4); @@ -1173,10 +1172,8 @@ play_udpsources_one_family (GstRTSPStream * stream, GstElement * udpsrc_out[2], GstRTSPStreamPrivate *priv; GstPad *pad, *selpad; guint i; - GstBin *bin; priv = stream->priv; - bin = GST_BIN (gst_object_get_parent (GST_OBJECT (priv->funnel[1]))); for (i = 0; i < 2; i++) { if (!priv->sinkpad && i == 0) { @@ -1193,7 +1190,7 @@ play_udpsources_one_family (GstRTSPStream * stream, GstElement * udpsrc_out[2], } /* add udpsrc */ - gst_bin_add (bin, udpsrc_out[i]); + gst_bin_add (priv->joined_bin, udpsrc_out[i]); /* and link to the funnel */ selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); @@ -1208,8 +1205,6 @@ play_udpsources_one_family (GstRTSPStream * stream, GstElement * udpsrc_out[2], gst_element_sync_state_with_parent (udpsrc_out[i]); } } - - gst_object_unref (bin); } /* must be called with lock */ @@ -1497,7 +1492,7 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); priv = stream->priv; - g_return_val_if_fail (priv->is_joined, FALSE); + g_return_val_if_fail (priv->joined_bin != NULL, FALSE); g_mutex_lock (&priv->lock); @@ -1607,7 +1602,7 @@ gst_rtsp_stream_get_server_port (GstRTSPStream * stream, g_return_if_fail (GST_IS_RTSP_STREAM (stream)); priv = stream->priv; - g_return_if_fail (priv->is_joined); + g_return_if_fail (priv->joined_bin != NULL); g_mutex_lock (&priv->lock); if (family == G_SOCKET_FAMILY_IPV4) { @@ -1687,7 +1682,7 @@ gst_rtsp_stream_get_ssrc (GstRTSPStream * stream, guint * ssrc) g_return_if_fail (GST_IS_RTSP_STREAM (stream)); priv = stream->priv; - g_return_if_fail (priv->is_joined); + g_return_if_fail (priv->joined_bin != NULL); g_mutex_lock (&priv->lock); if (ssrc && priv->session) @@ -2713,7 +2708,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, priv = stream->priv; g_mutex_lock (&priv->lock); - if (priv->is_joined) + if (priv->joined_bin != NULL) goto was_joined; /* create a session with the same index as the stream */ @@ -2807,8 +2802,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, (GCallback) caps_notify, stream); } - priv->joined_bin = bin; - priv->is_joined = TRUE; + priv->joined_bin = gst_object_ref (bin); g_mutex_unlock (&priv->lock); return TRUE; @@ -2927,8 +2921,10 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv = stream->priv; g_mutex_lock (&priv->lock); - if (!priv->is_joined) + if (priv->joined_bin == NULL) goto was_not_joined; + if (priv->joined_bin != bin) + goto wrong_bin; priv->joined_bin = NULL; @@ -2994,7 +2990,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, if (priv->srtpdec) gst_object_unref (priv->srtpdec); - priv->is_joined = FALSE; + g_clear_object (&priv->joined_bin); g_mutex_unlock (&priv->lock); return TRUE; @@ -3010,6 +3006,12 @@ transports_not_removed: g_mutex_unlock (&priv->lock); return FALSE; } +wrong_bin: + { + GST_ERROR_OBJECT (stream, "leaving the wrong bin"); + g_mutex_unlock (&priv->lock); + return FALSE; + } } /** @@ -3221,7 +3223,7 @@ gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * buffer) g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR); priv = stream->priv; g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); - g_return_val_if_fail (priv->is_joined, FALSE); + g_return_val_if_fail (priv->joined_bin != NULL, FALSE); g_mutex_lock (&priv->lock); if (priv->appsrc[0]) @@ -3287,7 +3289,7 @@ gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer) priv = stream->priv; g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); - if (!priv->is_joined) { + if (priv->joined_bin == NULL) { gst_buffer_unref (buffer); return GST_FLOW_NOT_LINKED; } @@ -3433,7 +3435,7 @@ gst_rtsp_stream_add_transport (GstRTSPStream * stream, g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); priv = stream->priv; g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE); - g_return_val_if_fail (priv->is_joined, FALSE); + g_return_val_if_fail (priv->joined_bin != NULL, FALSE); g_mutex_lock (&priv->lock); res = update_transport (stream, trans, TRUE); @@ -3466,7 +3468,7 @@ gst_rtsp_stream_remove_transport (GstRTSPStream * stream, g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); priv = stream->priv; g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE); - g_return_val_if_fail (priv->is_joined, FALSE); + g_return_val_if_fail (priv->joined_bin != NULL, FALSE); g_mutex_lock (&priv->lock); res = update_transport (stream, trans, FALSE); From 82a618c2e6a8297b573cf3dfba0a32010784f594 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 20 Jul 2016 15:35:44 -0400 Subject: [PATCH 1282/1776] stream: rename addr_v4/6 to mcast_addr_v4/6 for clarity https://bugzilla.gnome.org/show_bug.cgi?id=766612 --- gst/rtsp-server/rtsp-stream.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 5a564c6b33..081fc14f6b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -135,8 +135,8 @@ struct _GstRTSPStreamPrivate /* multicast addresses */ GstRTSPAddressPool *pool; - GstRTSPAddress *addr_v4; - GstRTSPAddress *addr_v6; + GstRTSPAddress *mcast_addr_v4; + GstRTSPAddress *mcast_addr_v6; gboolean have_ipv4_mcast; gboolean have_ipv6_mcast; @@ -285,10 +285,10 @@ gst_rtsp_stream_finalize (GObject * obj) /* we really need to be unjoined now */ g_return_if_fail (priv->joined_bin == NULL); - if (priv->addr_v4) - gst_rtsp_address_free (priv->addr_v4); - if (priv->addr_v6) - gst_rtsp_address_free (priv->addr_v6); + if (priv->mcast_addr_v4) + gst_rtsp_address_free (priv->mcast_addr_v4); + if (priv->mcast_addr_v6) + gst_rtsp_address_free (priv->mcast_addr_v6); if (priv->server_addr_v4) gst_rtsp_address_free (priv->server_addr_v4); if (priv->server_addr_v6) @@ -953,10 +953,10 @@ gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, if (family == G_SOCKET_FAMILY_IPV6) { flags = GST_RTSP_ADDRESS_FLAG_IPV6; - addrp = &priv->addr_v6; + addrp = &priv->mcast_addr_v6; } else { flags = GST_RTSP_ADDRESS_FLAG_IPV4; - addrp = &priv->addr_v4; + addrp = &priv->mcast_addr_v4; } g_mutex_lock (&priv->lock); @@ -1031,9 +1031,9 @@ gst_rtsp_stream_reserve_address (GstRTSPStream * stream, } if (family == G_SOCKET_FAMILY_IPV6) - addrp = &priv->addr_v6; + addrp = &priv->mcast_addr_v6; else - addrp = &priv->addr_v4; + addrp = &priv->mcast_addr_v4; g_mutex_lock (&priv->lock); if (*addrp == NULL) { @@ -1502,8 +1502,8 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, goto done; priv->have_ipv4_mcast = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, - priv->udpsrc_mcast_v4, &priv->server_port_v4, ct, &priv->addr_v4, - use_client_settings); + priv->udpsrc_mcast_v4, &priv->server_port_v4, ct, + &priv->mcast_addr_v4, use_client_settings); } else { priv->have_ipv4 = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, @@ -1516,8 +1516,8 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, goto done; priv->have_ipv6_mcast = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, - priv->udpsrc_mcast_v6, &priv->server_port_v6, ct, &priv->addr_v6, - use_client_settings); + priv->udpsrc_mcast_v6, &priv->server_port_v6, ct, + &priv->mcast_addr_v6, use_client_settings); } else { if (priv->have_ipv6) goto done; From a44f198ffc2363aa58da36d8884d30358bd3d1ea Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 20 Jul 2016 23:05:09 -0400 Subject: [PATCH 1283/1776] stream: small documentation clarification https://bugzilla.gnome.org/show_bug.cgi?id=766612 --- gst/rtsp-server/rtsp-stream.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 081fc14f6b..33242a437d 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -932,7 +932,9 @@ gst_rtsp_stream_get_multicast_iface (GstRTSPStream * stream) * @stream: a #GstRTSPStream * @family: the #GSocketFamily * - * Get the multicast address of @stream for @family. + * Get the multicast address of @stream for @family. The original + * #GstRTSPAddress is cached and copy is returned, so freeing the return value + * won't release the address from the pool. * * Returns: (transfer full) (nullable): the #GstRTSPAddress of @stream * or %NULL when no address could be allocated. gst_rtsp_address_free() @@ -998,7 +1000,9 @@ no_address: * @n_ports: n_ports * @ttl: a TTL * - * Reserve @address and @port as the address and port of @stream. + * Reserve @address and @port as the address and port of @stream. The original + * #GstRTSPAddress is cached and copy is returned, so freeing the return value + * won't release the address from the pool. * * Returns: (nullable): the #GstRTSPAddress of @stream or %NULL when * the address could be reserved. gst_rtsp_address_free() after usage. From 47a3956b48de01feecdc7389c4442617269c6e4f Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 21 Jul 2016 21:46:16 -0400 Subject: [PATCH 1284/1776] stream: factor out plug_sink function https://bugzilla.gnome.org/show_bug.cgi?id=766612 --- gst/rtsp-server/rtsp-stream.c | 82 +++++++++++++++-------------------- 1 file changed, 36 insertions(+), 46 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 33242a437d..4554414a6e 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2432,12 +2432,42 @@ on_npt_stop (GstElement * rtpbin, guint session, guint ssrc, gst_pad_send_event (stream->priv->sinkpad, gst_event_new_eos ()); } +static void +plug_sink (GstBin * bin, GstElement * tee, GstElement * sink, + GstElement ** queue_out) +{ + GstPad *pad; + GstPad *teepad; + GstPad *queuepad; + + gst_bin_add (bin, sink); + + *queue_out = gst_element_factory_make ("queue", NULL); + g_object_set (*queue_out, "max-size-buffers", 1, "max-size-bytes", 0, + "max-size-time", G_GINT64_CONSTANT (0), NULL); + gst_bin_add (bin, *queue_out); + + /* link tee to queue */ + teepad = gst_element_get_request_pad (tee, "src_%u"); + pad = gst_element_get_static_pad (*queue_out, "sink"); + gst_pad_link (teepad, pad); + gst_object_unref (pad); + gst_object_unref (teepad); + + /* link queue to sink */ + queuepad = gst_element_get_static_pad (*queue_out, "src"); + pad = gst_element_get_static_pad (sink, "sink"); + gst_pad_link (queuepad, pad); + gst_object_unref (queuepad); + gst_object_unref (pad); +} + /* must be called with lock */ static gboolean create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) { GstRTSPStreamPrivate *priv; - GstPad *pad, *sinkpad = NULL; + GstPad *pad; gboolean is_tcp = FALSE, is_udp = FALSE; gint i; @@ -2451,7 +2481,6 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) goto no_udp_protocol; for (i = 0; i < 2; i++) { - GstPad *teepad, *queuepad; /* For the sender we create this bit of pipeline for both * RTP and RTCP. Sync and preroll are enabled on udpsink so * we need to add a queue before appsink and udpsink to make @@ -2478,17 +2507,10 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) if (!priv->srcpad && i == 0) continue; - if (is_udp) { - /* add udpsink */ - gst_bin_add (bin, priv->udpsink[i]); - sinkpad = gst_element_get_static_pad (priv->udpsink[i], "sink"); - } - if (is_tcp) { /* make appsink */ priv->appsink[i] = gst_element_factory_make ("appsink", NULL); g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); - gst_bin_add (bin, priv->appsink[i]); gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), &sink_cb, stream, NULL); } @@ -2505,41 +2527,8 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) gst_pad_link (priv->send_src[i], pad); gst_object_unref (pad); - priv->udpqueue[i] = gst_element_factory_make ("queue", NULL); - g_object_set (priv->udpqueue[i], "max-size-buffers", - 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), NULL); - gst_bin_add (bin, priv->udpqueue[i]); - /* link tee to udpqueue */ - teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); - pad = gst_element_get_static_pad (priv->udpqueue[i], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); - - /* link udpqueue to udpsink */ - queuepad = gst_element_get_static_pad (priv->udpqueue[i], "src"); - gst_pad_link (queuepad, sinkpad); - gst_object_unref (queuepad); - gst_object_unref (sinkpad); - - /* make appqueue */ - priv->appqueue[i] = gst_element_factory_make ("queue", NULL); - g_object_set (priv->appqueue[i], "max-size-buffers", - 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), NULL); - gst_bin_add (bin, priv->appqueue[i]); - /* and link tee to appqueue */ - teepad = gst_element_get_request_pad (priv->tee[i], "src_%u"); - pad = gst_element_get_static_pad (priv->appqueue[i], "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); - - /* and link appqueue to appsink */ - queuepad = gst_element_get_static_pad (priv->appqueue[i], "src"); - pad = gst_element_get_static_pad (priv->appsink[i], "sink"); - gst_pad_link (queuepad, pad); - gst_object_unref (pad); - gst_object_unref (queuepad); + plug_sink (bin, priv->tee[i], priv->udpsink[i], &priv->udpqueue[i]); + plug_sink (bin, priv->tee[i], priv->appsink[i], &priv->appqueue[i]); } else if (is_tcp) { /* only appsink needed, link it to the session */ pad = gst_element_get_static_pad (priv->appsink[i], "sink"); @@ -2553,8 +2542,9 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); } else { /* else only udpsink needed, link it to the session */ - gst_pad_link (priv->send_src[i], sinkpad); - gst_object_unref (sinkpad); + pad = gst_element_get_static_pad (priv->udpsink[i], "sink"); + gst_pad_link (priv->send_src[i], pad); + gst_object_unref (pad); } /* check if we need to set to a special state */ From aa0e60445d0e9e9843a5162d5a1334e0a8c7f932 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 28 Jul 2016 15:20:31 -0400 Subject: [PATCH 1285/1776] stream: factor our plug_src function https://bugzilla.gnome.org/show_bug.cgi?id=766612 --- gst/rtsp-server/rtsp-stream.c | 77 ++++++++++++++++------------------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4554414a6e..0088e21702 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2573,10 +2573,38 @@ no_udp_protocol: /* must be called with lock */ static void -create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) +plug_src (GstRTSPStream * stream, GstBin * bin, GstElement * src, + GstElement * funnel) { GstRTSPStreamPrivate *priv; GstPad *pad, *selpad; + + priv = stream->priv; + + if (priv->srcpad) { + /* we set and keep these to playing so that they don't cause NO_PREROLL return + * values. This is only relevant for PLAY pipelines */ + gst_element_set_state (src, GST_STATE_PLAYING); + gst_element_set_locked_state (src, TRUE); + } + + /* add src */ + gst_bin_add (bin, src); + + /* and link to the funnel */ + selpad = gst_element_get_request_pad (funnel, "sink_%u"); + pad = gst_element_get_static_pad (src, "src"); + gst_pad_link (pad, selpad); + gst_object_unref (pad); + gst_object_unref (selpad); +} + +/* must be called with lock */ +static void +create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) +{ + GstRTSPStreamPrivate *priv; + GstPad *pad; gboolean is_tcp; gint i; @@ -2613,56 +2641,19 @@ create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) gst_pad_link (pad, priv->recv_sink[i]); gst_object_unref (pad); - if (priv->udpsrc_v4[i]) { - if (priv->srcpad) { - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values. This is only relevant for PLAY pipelines */ - gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE); - } - /* add udpsrc */ - gst_bin_add (bin, priv->udpsrc_v4[i]); + if (priv->udpsrc_v4[i]) + plug_src (stream, bin, priv->udpsrc_v4[i], priv->funnel[i]); - /* and link to the funnel v4 */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - } - - if (priv->udpsrc_v6[i]) { - if (priv->srcpad) { - gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE); - } - gst_bin_add (bin, priv->udpsrc_v6[i]); - - /* and link to the funnel v6 */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - } + if (priv->udpsrc_v6[i]) + plug_src (stream, bin, priv->udpsrc_v6[i], priv->funnel[i]); if (is_tcp) { /* make and add appsrc */ priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); priv->appsrc_base_time[i] = -1; - if (priv->srcpad) { - gst_element_set_state (priv->appsrc[i], GST_STATE_PLAYING); - gst_element_set_locked_state (priv->appsrc[i], TRUE); - } g_object_set (priv->appsrc[i], "format", GST_FORMAT_TIME, "is-live", TRUE, NULL); - gst_bin_add (bin, priv->appsrc[i]); - /* and link to the funnel */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (priv->appsrc[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); + plug_src (stream, bin, priv->appsrc[i], priv->funnel[i]); } /* check if we need to set to a special state */ From 8495c47a9d1fff390aaac1f3bb5c22f760786644 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 28 Jul 2016 15:33:05 -0400 Subject: [PATCH 1286/1776] stream: revert back to create udpsrc/udpsink on DESCRIBE for unicast This is basically reverting changes introduced in commit f62a9a7, because it was introducing various regressions: - It introduces a leak of udpsrc elements that got wrongly fixed by adding an hash table in commit cba045e. We should have at most 4 udpsrc for unicast: ipv4/ipv6, rtp/rtcp. They can be reused for all unicast clients. - If a mcast client connects, it creates a new socket in SETUP to try to respect the destination/port given by the client in the transport, and overrides the socket already set on the udpsink element. That means that if we already had a client connected, the source address on the udp packets it receives suddenly changes. - If a 2nd mcast client connects, the destination/port in its transport is ignored but its transport wasn't updated. What this patch does: - Revert back to create udpsrc/udpsink for unicast clients on DESCRIBE. - Always have a tee+queue when udp is enabled. This could be optimized again in a later patch, but is more complicated. If no unicast clients connects then those elements are useless, this could be also optimized in a later patch. - When mcast transport is added, it creates a new set of udpsrc/udpsink, seperated from those for unicast clients. Since we already support only one mcast address, we also create only one set of elements. https://bugzilla.gnome.org/show_bug.cgi?id=766612 --- gst/rtsp-server/rtsp-client.c | 34 +- gst/rtsp-server/rtsp-stream.c | 601 +++++++++++++++++----------------- tests/check/gst/stream.c | 60 +--- 3 files changed, 319 insertions(+), 376 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 7af7701d86..956a9eb7a5 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1421,27 +1421,26 @@ default_configure_client_transport (GstRTSPClient * client, /* we have a valid transport now, set the destination of the client. */ if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { gboolean use_client_settings; - GSocketFamily family; use_client_settings = gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS); if (ct->destination && use_client_settings) { - family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; - - if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, TRUE)) - goto no_udp_protocol; - - } else { GstRTSPAddress *addr; + addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination, + ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl); + + if (addr == NULL) + goto no_address; + + gst_rtsp_address_free (addr); + } else { + GstRTSPAddress *addr; + GSocketFamily family; + family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; - if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, - FALSE)) - goto no_udp_protocol; - - gst_rtsp_stream_get_server_port (ctx->stream, &ct->port, family); addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family); if (addr == NULL) goto no_address; @@ -1494,12 +1493,6 @@ default_configure_client_transport (GstRTSPClient * client, gst_rtsp_session_media_alloc_channels (ctx->sessmedia, &ct->interleaved); } - } else if (ct->lower_transport & GST_RTSP_LOWER_TRANS_UDP) { - GSocketFamily family; - family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; - if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, - FALSE)) - goto no_udp_protocol; } } return TRUE; @@ -1510,11 +1503,6 @@ no_address: GST_ERROR_OBJECT (client, "failed to acquire address for stream"); return FALSE; } -no_udp_protocol: - { - GST_ERROR_OBJECT (client, "failed to allocate udp ports"); - return FALSE; - } } static GstRTSPTransport * diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 0088e21702..e1fbc39489 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -94,21 +94,18 @@ struct _GstRTSPStreamPrivate GstElement *srtpdec; GHashTable *keys; - /* sinks used for sending and receiving RTP and RTCP over ipv4, they share - * sockets */ + /* for UDP unicast */ GstElement *udpsrc_v4[2]; - /* UDP sources for UDP multicast transports */ - GstElement *udpsrc_mcast_v4[2]; - - /* sinks used for sending and receiving RTP and RTCP over ipv6, they share - * sockets */ GstElement *udpsrc_v6[2]; - /* UDP sources for UDP multicast transports */ - GstElement *udpsrc_mcast_v6[2]; - GstElement *udpqueue[2]; GstElement *udpsink[2]; + /* for UDP multicast */ + GstElement *mcast_udpsrc_v4[2]; + GstElement *mcast_udpsrc_v6[2]; + GstElement *mcast_udpqueue[2]; + GstElement *mcast_udpsink[2]; + /* for TCP transport */ GstElement *appsrc[2]; GstClockTime appsrc_base_time[2]; @@ -123,22 +120,18 @@ struct _GstRTSPStreamPrivate guint rtx_pt; GstClockTime rtx_time; - /* server ports for sending/receiving over ipv4 */ - GstRTSPRange server_port_v4; - GstRTSPAddress *server_addr_v4; - gboolean have_ipv4; + /* pool used to manage unicast and multicast addresses */ + GstRTSPAddressPool *pool; - /* server ports for sending/receiving over ipv6 */ + /* unicast server addr/port */ + GstRTSPRange server_port_v4; GstRTSPRange server_port_v6; + GstRTSPAddress *server_addr_v4; GstRTSPAddress *server_addr_v6; - gboolean have_ipv6; /* multicast addresses */ - GstRTSPAddressPool *pool; GstRTSPAddress *mcast_addr_v4; GstRTSPAddress *mcast_addr_v6; - gboolean have_ipv4_mcast; - gboolean have_ipv6_mcast; gchar *multicast_iface; @@ -155,7 +148,6 @@ struct _GstRTSPStreamPrivate guint tr_cache_cookie_rtp; guint tr_cache_cookie_rtcp; - gint dscp_qos; /* stream blocking */ @@ -595,22 +587,18 @@ gst_rtsp_stream_get_mtu (GstRTSPStream * stream) /* Update the dscp qos property on the udp sinks */ static void -update_dscp_qos (GstRTSPStream * stream) +update_dscp_qos (GstRTSPStream * stream, GstElement * udpsink[2]) { GstRTSPStreamPrivate *priv; - g_return_if_fail (GST_IS_RTSP_STREAM (stream)); - priv = stream->priv; - if (priv->udpsink[0]) { - g_object_set (G_OBJECT (priv->udpsink[0]), "qos-dscp", priv->dscp_qos, - NULL); + if (udpsink[0]) { + g_object_set (G_OBJECT (udpsink[0]), "qos-dscp", priv->dscp_qos, NULL); } - if (priv->udpsink[1]) { - g_object_set (G_OBJECT (priv->udpsink[1]), "qos-dscp", priv->dscp_qos, - NULL); + if (udpsink[1]) { + g_object_set (G_OBJECT (udpsink[1]), "qos-dscp", priv->dscp_qos, NULL); } } @@ -639,7 +627,7 @@ gst_rtsp_stream_set_dscp_qos (GstRTSPStream * stream, gint dscp_qos) priv->dscp_qos = dscp_qos; - update_dscp_qos (stream); + update_dscp_qos (stream, priv->udpsink); } /** @@ -971,6 +959,12 @@ gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, *addrp = gst_rtsp_address_pool_acquire_address (priv->pool, flags, 2); if (*addrp == NULL) goto no_address; + + /* FIXME: Also reserve the same port with unicast ANY address, since that's + * where we are going to bind our socket. Probably loop until we find a port + * available in both mcast and unicast pools. Maybe GstRTSPAddressPool + * should do it for us when both GST_RTSP_ADDRESS_FLAG_MULTICAST and + * GST_RTSP_ADDRESS_FLAG_UNICAST are givent. */ } result = gst_rtsp_address_copy (*addrp); g_mutex_unlock (&priv->lock); @@ -1050,6 +1044,9 @@ gst_rtsp_stream_reserve_address (GstRTSPStream * stream, port, n_ports, ttl, addrp); if (res != GST_RTSP_ADDRESS_POOL_OK) goto no_address; + + /* FIXME: Also reserve the same port with unicast ANY address, since that's + * where we are going to bind our socket. */ } else { if (strcmp ((*addrp)->address, address) || (*addrp)->port != port || (*addrp)->n_ports != n_ports || @@ -1086,10 +1083,9 @@ different_address: /* must be called with lock */ static void -set_sockets_for_udpsinks (GstRTSPStream * stream, GSocket * rtp_socket, +set_sockets_for_udpsinks (GstElement * udpsink[2], GSocket * rtp_socket, GSocket * rtcp_socket, GSocketFamily family) { - GstRTSPStreamPrivate *priv = stream->priv; const gchar *multisink_socket; if (family == G_SOCKET_FAMILY_IPV6) @@ -1097,36 +1093,21 @@ set_sockets_for_udpsinks (GstRTSPStream * stream, GSocket * rtp_socket, else multisink_socket = "socket"; - g_object_set (G_OBJECT (priv->udpsink[0]), multisink_socket, rtp_socket, - NULL); - g_object_set (G_OBJECT (priv->udpsink[1]), multisink_socket, rtcp_socket, - NULL); + g_object_set (G_OBJECT (udpsink[0]), multisink_socket, rtp_socket, NULL); + g_object_set (G_OBJECT (udpsink[1]), multisink_socket, rtcp_socket, NULL); } -/* must be called with lock */ static gboolean -create_and_configure_udpsinks (GstRTSPStream * stream) +create_and_configure_udpsinks (GstRTSPStream * stream, GstElement * udpsink[2], + const gchar * multicast_iface) { GstRTSPStreamPrivate *priv = stream->priv; GstElement *udpsink0, *udpsink1; - udpsink0 = NULL; - udpsink1 = NULL; + udpsink0 = gst_element_factory_make ("multiudpsink", NULL); + udpsink1 = gst_element_factory_make ("multiudpsink", NULL); - if (priv->udpsink[0]) - udpsink0 = priv->udpsink[0]; - else - udpsink0 = gst_element_factory_make ("multiudpsink", NULL); - - if (!udpsink0) - goto no_udp_protocol; - - if (priv->udpsink[1]) - udpsink1 = priv->udpsink[1]; - else - udpsink1 = gst_element_factory_make ("multiudpsink", NULL); - - if (!udpsink1) + if (!udpsink0 || !udpsink1) goto no_udp_protocol; /* configure sinks */ @@ -1147,17 +1128,23 @@ create_and_configure_udpsinks (GstRTSPStream * stream) g_object_set (G_OBJECT (udpsink0), "async", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); - g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "auto-multicast", FALSE, NULL); + /* join multicast group when adding clients, so we'll start receiving from it. + * We cannot rely on the udpsrc to join the group since its socket is always a + * local unicast one. */ + g_object_set (G_OBJECT (udpsink0), "auto-multicast", TRUE, NULL); + g_object_set (G_OBJECT (udpsink1), "auto-multicast", TRUE, NULL); + + g_object_set (G_OBJECT (udpsink0), "multicast-iface", multicast_iface, NULL); + g_object_set (G_OBJECT (udpsink1), "multicast-iface", multicast_iface, NULL); g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL); - /* update the dscp qos field in the sinks */ - update_dscp_qos (stream); + udpsink[0] = udpsink0; + udpsink[1] = udpsink1; - priv->udpsink[0] = udpsink0; - priv->udpsink[1] = udpsink1; + /* update the dscp qos field in the sinks */ + update_dscp_qos (stream, udpsink); return TRUE; @@ -1168,55 +1155,10 @@ no_udp_protocol: } } -/* must be called with lock */ -static void -play_udpsources_one_family (GstRTSPStream * stream, GstElement * udpsrc_out[2], - GSocketFamily family) -{ - GstRTSPStreamPrivate *priv; - GstPad *pad, *selpad; - guint i; - - priv = stream->priv; - - for (i = 0; i < 2; i++) { - if (!priv->sinkpad && i == 0) { - /* Only connect recv RTP sink if we expect to receive RTP. Connect recv - * RTCP sink always */ - continue; - } - - if (priv->srcpad) { - /* we set and keep these to playing so that they don't cause NO_PREROLL return - * values. This is only relevant for PLAY pipelines */ - gst_element_set_state (udpsrc_out[i], GST_STATE_PLAYING); - gst_element_set_locked_state (udpsrc_out[i], TRUE); - } - - /* add udpsrc */ - gst_bin_add (priv->joined_bin, udpsrc_out[i]); - - /* and link to the funnel */ - selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); - pad = gst_element_get_static_pad (udpsrc_out[i], "src"); - gst_pad_link (pad, selpad); - gst_object_unref (pad); - gst_object_unref (selpad); - - /* otherwise sync state with parent in case it's running already - * at this point */ - if (!priv->srcpad) { - gst_element_sync_state_with_parent (udpsrc_out[i]); - } - } -} - /* must be called with lock */ static gboolean -create_and_configure_udpsources_one_family (GstElement * udpsrc_out[2], - GSocket * rtp_socket, GSocket * rtcp_socket, GSocketFamily family, - const gchar * address, gint rtpport, gint rtcpport, - const gchar * multicast_iface, GstRTSPLowerTrans transport) +create_and_configure_udpsources (GstElement * udpsrc_out[2], + GSocket * rtp_socket, GSocket * rtcp_socket) { GstStateChangeReturn ret; @@ -1226,22 +1168,17 @@ create_and_configure_udpsources_one_family (GstElement * udpsrc_out[2], if (udpsrc_out[0] == NULL || udpsrc_out[1] == NULL) goto error; - if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - g_object_set (G_OBJECT (udpsrc_out[0]), "address", address, NULL); - g_object_set (G_OBJECT (udpsrc_out[1]), "address", address, NULL); - g_object_set (G_OBJECT (udpsrc_out[0]), "port", rtpport, NULL); - g_object_set (G_OBJECT (udpsrc_out[1]), "port", rtcpport, NULL); - g_object_set (G_OBJECT (udpsrc_out[0]), "multicast-iface", multicast_iface, - NULL); - g_object_set (G_OBJECT (udpsrc_out[1]), "multicast-iface", multicast_iface, - NULL); - g_object_set (G_OBJECT (udpsrc_out[0]), "loop", FALSE, NULL); - g_object_set (G_OBJECT (udpsrc_out[1]), "loop", FALSE, NULL); - } - g_object_set (G_OBJECT (udpsrc_out[0]), "socket", rtp_socket, NULL); g_object_set (G_OBJECT (udpsrc_out[1]), "socket", rtcp_socket, NULL); + /* The udpsrc cannot do the join because its socket is always a local unicast + * one. The udpsink sharing the same socket will do it for us. */ + g_object_set (G_OBJECT (udpsrc_out[0]), "auto-multicast", FALSE, NULL); + g_object_set (G_OBJECT (udpsrc_out[1]), "auto-multicast", FALSE, NULL); + + g_object_set (G_OBJECT (udpsrc_out[0]), "loop", FALSE, NULL); + g_object_set (G_OBJECT (udpsrc_out[1]), "loop", FALSE, NULL); + ret = gst_element_set_state (udpsrc_out[0], GST_STATE_READY); if (ret == GST_STATE_CHANGE_FAILURE) goto error; @@ -1268,9 +1205,8 @@ error: static gboolean alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, - GstElement * udpsrc_out[2], GstRTSPRange * server_port_out, - GstRTSPTransport * ct, GstRTSPAddress ** server_addr_out, - gboolean use_client_settings) + GstElement * udpsrc_out[2], GstElement * udpsink_out[2], + GstRTSPRange * server_port_out, GstRTSPAddress ** server_addr_out) { GstRTSPStreamPrivate *priv = stream->priv; GSocket *rtp_socket = NULL; @@ -1285,12 +1221,15 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GSocketAddress *rtp_sockaddr = NULL; GSocketAddress *rtcp_sockaddr = NULL; GstRTSPAddressPool *pool; - GstRTSPLowerTrans transport; - const gchar *multicast_iface = priv->multicast_iface; + + g_assert (!udpsrc_out[0]); + g_assert (!udpsrc_out[1]); + g_assert ((!udpsink_out[0] && !udpsink_out[1]) || + (udpsink_out[0] && udpsink_out[1])); + g_assert (*server_addr_out == NULL); pool = priv->pool; count = 0; - transport = ct->lower_transport; /* Start with random port */ tmp_rtp = 0; @@ -1301,9 +1240,6 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, goto no_udp_protocol; g_socket_set_multicast_loopback (rtcp_socket, FALSE); - if (*server_addr_out) - gst_rtsp_address_free (*server_addr_out); - /* try to allocate 2 UDP ports, the RTP port should be an even * number and the RTCP port should be the next (uneven) port */ again: @@ -1316,30 +1252,19 @@ again: g_socket_set_multicast_loopback (rtp_socket, FALSE); } - if (pool && ((transport == GST_RTSP_LOWER_TRANS_UDP && - gst_rtsp_address_pool_has_unicast_addresses (pool)) - || transport == GST_RTSP_LOWER_TRANS_UDP_MCAST)) { - GstRTSPAddressFlags flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT; - - if (transport == GST_RTSP_LOWER_TRANS_UDP) - flags |= GST_RTSP_ADDRESS_FLAG_UNICAST; - else - flags |= GST_RTSP_ADDRESS_FLAG_MULTICAST; + if (pool && gst_rtsp_address_pool_has_unicast_addresses (pool)) { + GstRTSPAddressFlags flags; if (addr) rejected_addresses = g_list_prepend (rejected_addresses, addr); + flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_UNICAST; if (family == G_SOCKET_FAMILY_IPV6) flags |= GST_RTSP_ADDRESS_FLAG_IPV6; else flags |= GST_RTSP_ADDRESS_FLAG_IPV4; - if (ct->destination && transport == GST_RTSP_LOWER_TRANS_UDP_MCAST - && use_client_settings) - gst_rtsp_address_pool_reserve_address (pool, ct->destination, - ct->port.min, 2, ct->ttl, &addr); - else - addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); + addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); if (addr == NULL) goto no_ports; @@ -1348,14 +1273,6 @@ again: g_clear_object (&inetaddr); inetaddr = g_inet_address_new_from_string (addr->address); - - /* If we're supposed to bind to a multicast address, instead bind - * to ANY and let udpsrc later join the relevant multicast group - */ - if (g_inet_address_get_is_multicast (inetaddr)) { - g_object_unref (inetaddr); - inetaddr = g_inet_address_new_any (family); - } } else { if (tmp_rtp != 0) { tmp_rtp += 2; @@ -1409,9 +1326,7 @@ again: addr_str = addr->address; g_clear_object (&inetaddr); - if (!create_and_configure_udpsources_one_family (udpsrc_out, rtp_socket, - rtcp_socket, family, addr_str, tmp_rtp, tmp_rtcp, multicast_iface, - transport)) { + if (!create_and_configure_udpsources (udpsrc_out, rtp_socket, rtcp_socket)) { if (addr == NULL) g_free (addr_str); goto no_udp_protocol; @@ -1420,8 +1335,6 @@ again: if (addr == NULL) g_free (addr_str); - play_udpsources_one_family (stream, udpsrc_out, family); - g_object_get (G_OBJECT (udpsrc_out[0]), "port", &rtpport, NULL); g_object_get (G_OBJECT (udpsrc_out[1]), "port", &rtcpport, NULL); @@ -1429,12 +1342,17 @@ again: if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) goto port_error; - /* set RTP and RTCP sockets */ - set_sockets_for_udpsinks (stream, rtp_socket, rtcp_socket, family); - server_port_out->min = rtpport; server_port_out->max = rtcpport; + /* This function is called twice (for v4 and v6) but we create only one pair + * of udpsinks. */ + if (!udpsink_out[0] + && !create_and_configure_udpsinks (stream, udpsink_out, NULL)) + goto no_udp_protocol; + + set_sockets_for_udpsinks (udpsink_out, rtp_socket, rtcp_socket, family); + *server_addr_out = addr; g_list_free_full (rejected_addresses, (GDestroyNotify) gst_rtsp_address_free); @@ -1485,60 +1403,14 @@ cleanup: * Allocates RTP and RTCP ports. * * Returns: %TRUE if the RTP and RTCP sockets have been succeccully allocated. + * Deprecated: This function shouldn't have been made public */ gboolean gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, GSocketFamily family, GstRTSPTransport * ct, gboolean use_client_settings) { - GstRTSPStreamPrivate *priv; - gboolean result = FALSE; - GstRTSPLowerTrans transport = ct->lower_transport; - - g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); - priv = stream->priv; - g_return_val_if_fail (priv->joined_bin != NULL, FALSE); - - g_mutex_lock (&priv->lock); - - if (family == G_SOCKET_FAMILY_IPV4) { - if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - if (priv->have_ipv4_mcast) - goto done; - priv->have_ipv4_mcast = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, - priv->udpsrc_mcast_v4, &priv->server_port_v4, ct, - &priv->mcast_addr_v4, use_client_settings); - } else { - priv->have_ipv4 = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, - &priv->server_port_v4, ct, &priv->server_addr_v4, - use_client_settings); - } - } else { - if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - if (priv->have_ipv6_mcast) - goto done; - priv->have_ipv6_mcast = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, - priv->udpsrc_mcast_v6, &priv->server_port_v6, ct, - &priv->mcast_addr_v6, use_client_settings); - } else { - if (priv->have_ipv6) - goto done; - priv->have_ipv6 = - alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, - &priv->server_port_v6, ct, &priv->server_addr_v6, - use_client_settings); - } - } - -done: - result = priv->have_ipv4 || priv->have_ipv4_mcast || priv->have_ipv6 || - priv->have_ipv6_mcast; - - g_mutex_unlock (&priv->lock); - - return result; + g_warn_if_reached (); + return FALSE; } /** @@ -1589,6 +1461,27 @@ gst_rtsp_stream_is_client_side (GstRTSPStream * stream) return ret; } +/* must be called with lock */ +static gboolean +alloc_ports (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv = stream->priv; + gboolean ret = TRUE; + + if ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || + (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)) { + ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, + priv->udpsrc_v4, priv->udpsink, + &priv->server_port_v4, &priv->server_addr_v4); + + ret |= alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, + priv->udpsrc_v6, priv->udpsink, + &priv->server_port_v6, &priv->server_addr_v6); + } + + return ret; +} + /** * gst_rtsp_stream_get_server_port: * @stream: a #GstRTSPStream @@ -2463,7 +2356,7 @@ plug_sink (GstBin * bin, GstElement * tee, GstElement * sink, } /* must be called with lock */ -static gboolean +static void create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) { GstRTSPStreamPrivate *priv; @@ -2477,9 +2370,6 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); - if (is_udp && !create_and_configure_udpsinks (stream)) - goto no_udp_protocol; - for (i = 0; i < 2; i++) { /* For the sender we create this bit of pipeline for both * RTP and RTCP. Sync and preroll are enabled on udpsink so @@ -2515,9 +2405,10 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) &sink_cb, stream, NULL); } - if (is_udp && is_tcp) { - g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); - + /* If we have udp always use a tee because we could have mcast clients + * requesting different ports, in which case we'll have to plug more + * udpsinks. */ + if (is_udp) { /* make tee for RTP/RTCP */ priv->tee[i] = gst_element_factory_make ("tee", NULL); gst_bin_add (bin, priv->tee[i]); @@ -2528,7 +2419,11 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) gst_object_unref (pad); plug_sink (bin, priv->tee[i], priv->udpsink[i], &priv->udpqueue[i]); - plug_sink (bin, priv->tee[i], priv->appsink[i], &priv->appqueue[i]); + + if (is_tcp) { + g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); + plug_sink (bin, priv->tee[i], priv->appsink[i], &priv->appqueue[i]); + } } else if (is_tcp) { /* only appsink needed, link it to the session */ pad = gst_element_get_static_pad (priv->appsink[i], "sink"); @@ -2540,11 +2435,6 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) * sink used for RTCP data, not the RTP data. */ if (i == 1) g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); - } else { - /* else only udpsink needed, link it to the session */ - pad = gst_element_get_static_pad (priv->udpsink[i], "sink"); - gst_pad_link (priv->send_src[i], pad); - gst_object_unref (pad); } /* check if we need to set to a special state */ @@ -2561,14 +2451,6 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) gst_element_set_state (priv->tee[i], state); } } - - return TRUE; - - /* ERRORS */ -no_udp_protocol: - { - return FALSE; - } } /* must be called with lock */ @@ -2663,6 +2545,153 @@ create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) } } +static gboolean +create_mcast_part_for_transport (GstRTSPStream * stream, + const GstRTSPTransport * tr) +{ + GstRTSPStreamPrivate *priv = stream->priv; + GInetAddress *inetaddr; + GSocketFamily family; + GstRTSPAddress *mcast_addr; + GstElement **mcast_udpsrc; + GSocket *rtp_socket = NULL; + GSocket *rtcp_socket = NULL; + GSocketAddress *rtp_sockaddr = NULL; + GSocketAddress *rtcp_sockaddr = NULL; + GError *error = NULL; + const gchar *multicast_iface = priv->multicast_iface; + + /* Check if it's a ipv4 or ipv6 transport */ + inetaddr = g_inet_address_new_from_string (tr->destination); + family = g_inet_address_get_family (inetaddr); + g_object_unref (inetaddr); + + /* Select fields corresponding to the family */ + if (family == G_SOCKET_FAMILY_IPV4) { + mcast_addr = priv->mcast_addr_v4; + mcast_udpsrc = priv->mcast_udpsrc_v4; + } else { + mcast_addr = priv->mcast_addr_v6; + mcast_udpsrc = priv->mcast_udpsrc_v6; + } + + /* We support only one mcast group per family, make sure this transport + * matches it. */ + if (!mcast_addr) + goto no_addr; + + if (!g_str_equal (tr->destination, mcast_addr->address) || + tr->port.min != mcast_addr->port || + tr->port.max != mcast_addr->port + mcast_addr->n_ports - 1 || + tr->ttl != mcast_addr->ttl) + goto wrong_addr; + + if (mcast_udpsrc[0]) { + /* We already created elements for this family. Since we support only one + * mcast group per family, there is nothing more to do here. */ + g_assert (mcast_udpsrc[1]); + g_assert (priv->mcast_udpqueue[0]); + g_assert (priv->mcast_udpqueue[1]); + g_assert (priv->mcast_udpsink[0]); + g_assert (priv->mcast_udpsink[1]); + return TRUE; + } + + g_assert (!mcast_udpsrc[1]); + + /* Create RTP/RTCP sockets and bind them on ANY with mcast ports */ + rtp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, + G_SOCKET_PROTOCOL_UDP, &error); + if (!rtp_socket) + goto socket_error; + g_socket_set_multicast_loopback (rtp_socket, FALSE); + + rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, + G_SOCKET_PROTOCOL_UDP, &error); + if (!rtcp_socket) + goto socket_error; + g_socket_set_multicast_loopback (rtcp_socket, FALSE); + + inetaddr = g_inet_address_new_any (family); + rtp_sockaddr = g_inet_socket_address_new (inetaddr, mcast_addr->port); + rtcp_sockaddr = g_inet_socket_address_new (inetaddr, mcast_addr->port + 1); + g_object_unref (inetaddr); + + if (!g_socket_bind (rtp_socket, rtp_sockaddr, FALSE, &error)) + goto socket_error; + + if (!g_socket_bind (rtcp_socket, rtcp_sockaddr, FALSE, &error)) + goto socket_error; + + g_object_unref (rtp_sockaddr); + g_object_unref (rtcp_sockaddr); + + /* Add receiver part */ + create_and_configure_udpsources (mcast_udpsrc, rtp_socket, rtcp_socket); + if (priv->srcpad) { + plug_src (stream, priv->joined_bin, mcast_udpsrc[0], priv->funnel[0]); + gst_element_sync_state_with_parent (mcast_udpsrc[0]); + } + plug_src (stream, priv->joined_bin, mcast_udpsrc[1], priv->funnel[1]); + gst_element_sync_state_with_parent (mcast_udpsrc[1]); + + /* Add sender part, could already have been created for the other family. */ + if (!priv->mcast_udpsink[0]) { + g_assert (!priv->mcast_udpsink[1]); + g_assert (!priv->mcast_udpqueue[0]); + g_assert (!priv->mcast_udpqueue[1]); + + create_and_configure_udpsinks (stream, priv->mcast_udpsink, + multicast_iface); + set_sockets_for_udpsinks (priv->mcast_udpsink, rtp_socket, rtcp_socket, + family); + + if (priv->sinkpad) { + plug_sink (priv->joined_bin, priv->tee[0], priv->mcast_udpsink[0], + &priv->mcast_udpqueue[0]); + gst_element_sync_state_with_parent (priv->mcast_udpsink[0]); + gst_element_sync_state_with_parent (priv->mcast_udpqueue[0]); + } + plug_sink (priv->joined_bin, priv->tee[1], priv->mcast_udpsink[1], + &priv->mcast_udpqueue[1]); + gst_element_sync_state_with_parent (priv->mcast_udpsink[1]); + gst_element_sync_state_with_parent (priv->mcast_udpqueue[1]); + } else { + g_assert (priv->mcast_udpsink[1]); + g_assert (priv->mcast_udpqueue[0]); + g_assert (priv->mcast_udpqueue[1]); + + set_sockets_for_udpsinks (priv->mcast_udpsink, rtp_socket, rtcp_socket, + family); + } + + return TRUE; + +no_addr: + { + GST_WARNING_OBJECT (stream, "Adding mcast transport, but no mcast address " + "has been reserved"); + return FALSE; + } +wrong_addr: + { + GST_WARNING_OBJECT (stream, "Adding mcast transport, but it doesn't match " + "the reserved address"); + return FALSE; + } +socket_error: + { + GST_ERROR_OBJECT (stream, "Error creating and binding mcast socket: %s", + error->message); + g_clear_object (&rtp_socket); + g_clear_object (&rtcp_socket); + g_clear_object (&rtp_sockaddr); + g_clear_object (&rtcp_sockaddr); + g_clear_error (&error); + return FALSE; + } +} + /** * gst_rtsp_stream_join_bin: * @stream: a #GstRTSPStream @@ -2701,6 +2730,9 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, GST_INFO ("stream %p joining bin as session %u", stream, idx); + if (!alloc_ports (stream)) + goto no_ports; + if (priv->profiles & GST_RTSP_PROFILE_SAVP || priv->profiles & GST_RTSP_PROFILE_SAVPF) { /* For SRTP */ @@ -2776,9 +2808,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, g_signal_connect (priv->session, "on-sender-ssrc-active", (GCallback) on_sender_ssrc_active, stream); - if (!create_sender_part (stream, bin, state)) - goto no_udp_protocol; - + create_sender_part (stream, bin, state); create_receiver_part (stream, bin, state); if (priv->srcpad) { @@ -2798,6 +2828,12 @@ was_joined: g_mutex_unlock (&priv->lock); return TRUE; } +no_ports: + { + g_mutex_unlock (&priv->lock); + GST_WARNING ("failed to allocate ports %u", idx); + return FALSE; + } link_failed: { GST_WARNING ("failed to link stream %u", idx); @@ -2806,66 +2842,6 @@ link_failed: g_mutex_unlock (&priv->lock); return FALSE; } -no_udp_protocol: - { - GST_WARNING ("failed to allocate ports %u", idx); - gst_object_unref (priv->send_rtp_sink); - priv->send_rtp_sink = NULL; - gst_object_unref (priv->send_src[0]); - priv->send_src[0] = NULL; - gst_object_unref (priv->send_src[1]); - priv->send_src[1] = NULL; - gst_object_unref (priv->recv_sink[0]); - priv->recv_sink[0] = NULL; - gst_object_unref (priv->recv_sink[1]); - priv->recv_sink[1] = NULL; - if (priv->udpsink[0]) - gst_element_set_state (priv->udpsink[0], GST_STATE_NULL); - if (priv->udpsink[1]) - gst_element_set_state (priv->udpsink[1], GST_STATE_NULL); - if (priv->udpsrc_v4[0]) { - gst_element_set_state (priv->udpsrc_v4[0], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_v4[0]); - priv->udpsrc_v4[0] = NULL; - } - if (priv->udpsrc_v4[1]) { - gst_element_set_state (priv->udpsrc_v4[1], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_v4[1]); - priv->udpsrc_v4[1] = NULL; - } - if (priv->udpsrc_mcast_v4[0]) { - gst_element_set_state (priv->udpsrc_mcast_v4[0], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_mcast_v4[0]); - priv->udpsrc_mcast_v4[0] = NULL; - } - if (priv->udpsrc_mcast_v4[1]) { - gst_element_set_state (priv->udpsrc_mcast_v4[1], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_mcast_v4[1]); - priv->udpsrc_mcast_v4[1] = NULL; - } - if (priv->udpsrc_v6[0]) { - gst_element_set_state (priv->udpsrc_v6[0], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_v6[0]); - priv->udpsrc_v6[0] = NULL; - } - if (priv->udpsrc_v6[1]) { - gst_element_set_state (priv->udpsrc_v6[1], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_v6[1]); - priv->udpsrc_v6[1] = NULL; - } - if (priv->udpsrc_mcast_v6[0]) { - gst_element_set_state (priv->udpsrc_mcast_v6[0], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_mcast_v6[0]); - priv->udpsrc_mcast_v6[0] = NULL; - } - if (priv->udpsrc_mcast_v6[1]) { - gst_element_set_state (priv->udpsrc_mcast_v6[1], GST_STATE_NULL); - gst_object_unref (priv->udpsrc_mcast_v6[1]); - priv->udpsrc_mcast_v6[1] = NULL; - } - g_mutex_unlock (&priv->lock); - return FALSE; - } } static void @@ -2936,17 +2912,22 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, } for (i = 0; i < 2; i++) { - clear_element (bin, &priv->udpsink[i]); - clear_element (bin, &priv->appsink[i]); - clear_element (bin, &priv->appqueue[i]); - clear_element (bin, &priv->udpqueue[i]); - clear_element (bin, &priv->tee[i]); - clear_element (bin, &priv->funnel[i]); - clear_element (bin, &priv->appsrc[i]); clear_element (bin, &priv->udpsrc_v4[i]); clear_element (bin, &priv->udpsrc_v6[i]); - clear_element (bin, &priv->udpsrc_mcast_v4[i]); - clear_element (bin, &priv->udpsrc_mcast_v6[i]); + clear_element (bin, &priv->udpqueue[i]); + clear_element (bin, &priv->udpsink[i]); + + clear_element (bin, &priv->mcast_udpsrc_v4[i]); + clear_element (bin, &priv->mcast_udpsrc_v6[i]); + clear_element (bin, &priv->mcast_udpqueue[i]); + clear_element (bin, &priv->mcast_udpsink[i]); + + clear_element (bin, &priv->appsrc[i]); + clear_element (bin, &priv->appqueue[i]); + clear_element (bin, &priv->appsink[i]); + + clear_element (bin, &priv->tee[i]); + clear_element (bin, &priv->funnel[i]); if (priv->sinkpad || i == 1) { gst_element_release_request_pad (rtpbin, priv->recv_sink[i]); @@ -3332,6 +3313,18 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, switch (tr->lower_transport) { case GST_RTSP_LOWER_TRANS_UDP_MCAST: + { + if (add) { + if (!create_mcast_part_for_transport (stream, tr)) + goto mcast_error; + priv->transports = g_list_prepend (priv->transports, trans); + } else { + priv->transports = g_list_remove (priv->transports, trans); + /* FIXME: Check if there are remaining mcast transports, and destroy + * mcast part if its now unused */ + } + break; + } case GST_RTSP_LOWER_TRANS_UDP: { gchar *dest; @@ -3393,6 +3386,10 @@ unknown_transport: GST_INFO ("Unknown transport %d", tr->lower_transport); return FALSE; } +mcast_error: + { + return FALSE; + } } diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index 26c291582c..5a21ba4f78 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -33,7 +33,6 @@ GST_START_TEST (test_get_sockets) GSocket *socket; gboolean have_ipv4; gboolean have_ipv6; - GstRTSPTransport *tr; srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); fail_unless (srcpad != NULL); @@ -62,11 +61,6 @@ GST_START_TEST (test_get_sockets) fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); - gst_rtsp_transport_new (&tr); - tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP; - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, - G_SOCKET_FAMILY_IPV4, tr, FALSE)); - socket = gst_rtsp_stream_get_rtp_socket (stream, G_SOCKET_FAMILY_IPV4); have_ipv4 = (socket != NULL); if (have_ipv4) { @@ -102,7 +96,6 @@ GST_START_TEST (test_get_sockets) /* check that at least one family is available */ fail_unless (have_ipv4 || have_ipv6); - gst_rtsp_transport_free (tr); g_object_unref (pool); fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); @@ -121,7 +114,6 @@ GST_START_TEST (test_allocate_udp_ports_fail) GstBin *bin; GstElement *rtpbin; GstRTSPAddressPool *pool; - GstRTSPTransport *tr; srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); fail_unless (srcpad != NULL); @@ -143,14 +135,8 @@ GST_START_TEST (test_allocate_udp_ports_fail) "192.168.1.1", 6000, 6001, 0)); gst_rtsp_stream_set_address_pool (stream, pool); - fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + fail_if (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); - gst_rtsp_transport_new (&tr); - tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP; - fail_if (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, - tr, FALSE)); - - gst_rtsp_transport_free (tr); g_object_unref (pool); fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); gst_object_unref (bin); @@ -257,13 +243,6 @@ GST_START_TEST (test_multicast_address_and_unicast_udp) fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); - gst_rtsp_transport_new (&tr); - /* unicast udp */ - tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP; - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, - G_SOCKET_FAMILY_IPV4, tr, FALSE)); - - gst_rtsp_transport_free (tr); g_object_unref (pool); fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); gst_object_unref (bin); @@ -280,7 +259,6 @@ GST_START_TEST (test_allocate_udp_ports_multicast) GstBin *bin; GstElement *rtpbin; GstRTSPAddressPool *pool; - GstRTSPTransport *tr; GstRTSPAddress *addr; srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); @@ -308,12 +286,6 @@ GST_START_TEST (test_allocate_udp_ports_multicast) fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); - /* allocate udp multicast ports for IPv4 */ - gst_rtsp_transport_new (&tr); - tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST; - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, - G_SOCKET_FAMILY_IPV4, tr, FALSE)); - /* check the multicast address and ports for IPv4 */ addr = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV4); fail_unless (addr != NULL); @@ -322,10 +294,6 @@ GST_START_TEST (test_allocate_udp_ports_multicast) fail_unless_equals_int (addr->n_ports, 2); gst_rtsp_address_free (addr); - /* allocate udp multicast ports for IPv6 */ - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, - G_SOCKET_FAMILY_IPV6, tr, FALSE)); - /* check the multicast address and ports for IPv6 */ addr = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV6); fail_unless (addr != NULL); @@ -334,7 +302,6 @@ GST_START_TEST (test_allocate_udp_ports_multicast) fail_unless_equals_int (addr->n_ports, 2); gst_rtsp_address_free (addr); - gst_rtsp_transport_free (tr); g_object_unref (pool); fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); gst_object_unref (bin); @@ -351,7 +318,6 @@ GST_START_TEST (test_allocate_udp_ports_client_settings) GstBin *bin; GstElement *rtpbin; GstRTSPAddressPool *pool; - GstRTSPTransport *tr; GstRTSPAddress *addr; srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); @@ -384,14 +350,10 @@ GST_START_TEST (test_allocate_udp_ports_client_settings) fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); - /* client transport settings for IPv4 */ - gst_rtsp_transport_new (&tr); - tr->destination = g_strdup ("233.252.0.2"); - tr->port.min = 6002; - tr->port.max = 6003; - tr->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST; - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, - G_SOCKET_FAMILY_IPV4, tr, FALSE)); + /* Reserve IPV4 mcast address */ + addr = gst_rtsp_stream_reserve_address (stream, "233.252.0.2", 6002, 2, 1); + fail_unless (addr != NULL); + gst_rtsp_address_free (addr); /* verify that the multicast address and ports correspond to the requested client * transport information for IPv4 */ @@ -402,13 +364,10 @@ GST_START_TEST (test_allocate_udp_ports_client_settings) fail_unless_equals_int (addr->n_ports, 2); gst_rtsp_address_free (addr); - /* client transport settings for IPv6 */ - g_free (tr->destination); - tr->destination = g_strdup ("FF11:DB8::1"); - tr->port.min = 6006; - tr->port.max = 6007; - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, - G_SOCKET_FAMILY_IPV6, tr, FALSE)); + /* Reserve IPV6 mcast address */ + addr = gst_rtsp_stream_reserve_address (stream, "FF11:DB8::1", 6006, 2, 1); + fail_unless (addr != NULL); + gst_rtsp_address_free (addr); /* verify that the multicast address and ports correspond to the requested client * transport information for IPv6 */ @@ -419,7 +378,6 @@ GST_START_TEST (test_allocate_udp_ports_client_settings) fail_unless_equals_int (addr->n_ports, 2); gst_rtsp_address_free (addr); - gst_rtsp_transport_free (tr); g_object_unref (pool); fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); gst_object_unref (bin); From 958f4a47ec09bbc95ff2c997e485e4cfde3d54d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 5 Sep 2016 13:40:59 +0300 Subject: [PATCH 1287/1776] tests: Fix compilation --- tests/check/gst/stream.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index 5a21ba4f78..4a0ee789e2 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -218,7 +218,6 @@ GST_START_TEST (test_multicast_address_and_unicast_udp) GstBin *bin; GstElement *rtpbin; GstRTSPAddressPool *pool; - GstRTSPTransport *tr; srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); fail_unless (srcpad != NULL); From be4b9718e33ce376c691b9b0f8c61350054cd2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 5 Sep 2016 16:32:57 +0300 Subject: [PATCH 1288/1776] rtsp-stream: Fix up various multicast related issues --- gst/rtsp-server/rtsp-stream.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index e1fbc39489..1d5f58e947 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1098,8 +1098,7 @@ set_sockets_for_udpsinks (GstElement * udpsink[2], GSocket * rtp_socket, } static gboolean -create_and_configure_udpsinks (GstRTSPStream * stream, GstElement * udpsink[2], - const gchar * multicast_iface) +create_and_configure_udpsinks (GstRTSPStream * stream, GstElement * udpsink[2]) { GstRTSPStreamPrivate *priv = stream->priv; GstElement *udpsink0, *udpsink1; @@ -1134,9 +1133,6 @@ create_and_configure_udpsinks (GstRTSPStream * stream, GstElement * udpsink[2], g_object_set (G_OBJECT (udpsink0), "auto-multicast", TRUE, NULL); g_object_set (G_OBJECT (udpsink1), "auto-multicast", TRUE, NULL); - g_object_set (G_OBJECT (udpsink0), "multicast-iface", multicast_iface, NULL); - g_object_set (G_OBJECT (udpsink1), "multicast-iface", multicast_iface, NULL); - g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL); @@ -1348,7 +1344,7 @@ again: /* This function is called twice (for v4 and v6) but we create only one pair * of udpsinks. */ if (!udpsink_out[0] - && !create_and_configure_udpsinks (stream, udpsink_out, NULL)) + && !create_and_configure_udpsinks (stream, udpsink_out)) goto no_udp_protocol; set_sockets_for_udpsinks (udpsink_out, rtp_socket, rtcp_socket, family); @@ -2628,7 +2624,7 @@ create_mcast_part_for_transport (GstRTSPStream * stream, /* Add receiver part */ create_and_configure_udpsources (mcast_udpsrc, rtp_socket, rtcp_socket); - if (priv->srcpad) { + if (priv->sinkpad) { plug_src (stream, priv->joined_bin, mcast_udpsrc[0], priv->funnel[0]); gst_element_sync_state_with_parent (mcast_udpsrc[0]); } @@ -2641,12 +2637,22 @@ create_mcast_part_for_transport (GstRTSPStream * stream, g_assert (!priv->mcast_udpqueue[0]); g_assert (!priv->mcast_udpqueue[1]); - create_and_configure_udpsinks (stream, priv->mcast_udpsink, - multicast_iface); + create_and_configure_udpsinks (stream, priv->mcast_udpsink); + + g_object_set (G_OBJECT (priv->mcast_udpsink[0]), "multicast-iface", + multicast_iface, NULL); + g_object_set (G_OBJECT (priv->mcast_udpsink[1]), "multicast-iface", + multicast_iface, NULL); + + g_signal_emit_by_name (priv->mcast_udpsink[0], "add", mcast_addr->address, + mcast_addr->port, NULL); + g_signal_emit_by_name (priv->mcast_udpsink[1], "add", mcast_addr->address, + mcast_addr->port + 1, NULL); + set_sockets_for_udpsinks (priv->mcast_udpsink, rtp_socket, rtcp_socket, family); - if (priv->sinkpad) { + if (priv->srcpad) { plug_sink (priv->joined_bin, priv->tee[0], priv->mcast_udpsink[0], &priv->mcast_udpqueue[0]); gst_element_sync_state_with_parent (priv->mcast_udpsink[0]); From ca855abae1a38c4278f85b93f84bf2b0c6a8a4d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 5 Sep 2016 18:04:50 +0300 Subject: [PATCH 1289/1776] rtsp-stream: Always create multicast UDP elements if the protocol flag is set Adding them later will cause deadlocks due to 1) pre-rolling and staying in PAUSED with the unicast/TCP sinks 2) adding the multicast sink 3) waiting for it to get data to preroll again 3) never happens because the queues after the tee are full. --- gst/rtsp-server/rtsp-stream.c | 278 ++++++++++++++-------------------- 1 file changed, 115 insertions(+), 163 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 1d5f58e947..5773fa60c9 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -124,8 +124,6 @@ struct _GstRTSPStreamPrivate GstRTSPAddressPool *pool; /* unicast server addr/port */ - GstRTSPRange server_port_v4; - GstRTSPRange server_port_v6; GstRTSPAddress *server_addr_v4; GstRTSPAddress *server_addr_v6; @@ -915,21 +913,9 @@ gst_rtsp_stream_get_multicast_iface (GstRTSPStream * stream) return result; } -/** - * gst_rtsp_stream_get_multicast_address: - * @stream: a #GstRTSPStream - * @family: the #GSocketFamily - * - * Get the multicast address of @stream for @family. The original - * #GstRTSPAddress is cached and copy is returned, so freeing the return value - * won't release the address from the pool. - * - * Returns: (transfer full) (nullable): the #GstRTSPAddress of @stream - * or %NULL when no address could be allocated. gst_rtsp_address_free() - * after usage. - */ -GstRTSPAddress * -gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, + +static GstRTSPAddress * +gst_rtsp_stream_get_multicast_address_locked (GstRTSPStream * stream, GSocketFamily family) { GstRTSPStreamPrivate *priv; @@ -937,8 +923,6 @@ gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, GstRTSPAddress **addrp; GstRTSPAddressFlags flags; - g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); - priv = stream->priv; if (family == G_SOCKET_FAMILY_IPV6) { @@ -949,7 +933,6 @@ gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, addrp = &priv->mcast_addr_v4; } - g_mutex_lock (&priv->lock); if (*addrp == NULL) { if (priv->pool == NULL) goto no_pool; @@ -967,7 +950,6 @@ gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, * GST_RTSP_ADDRESS_FLAG_UNICAST are givent. */ } result = gst_rtsp_address_copy (*addrp); - g_mutex_unlock (&priv->lock); return result; @@ -975,17 +957,43 @@ gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, no_pool: { GST_ERROR_OBJECT (stream, "no address pool specified"); - g_mutex_unlock (&priv->lock); return NULL; } no_address: { GST_ERROR_OBJECT (stream, "failed to acquire address from pool"); - g_mutex_unlock (&priv->lock); return NULL; } } +/** + * gst_rtsp_stream_get_multicast_address: + * @stream: a #GstRTSPStream + * @family: the #GSocketFamily + * + * Get the multicast address of @stream for @family. The original + * #GstRTSPAddress is cached and copy is returned, so freeing the return value + * won't release the address from the pool. + * + * Returns: (transfer full) (nullable): the #GstRTSPAddress of @stream + * or %NULL when no address could be allocated. gst_rtsp_address_free() + * after usage. + */ +GstRTSPAddress * +gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, + GSocketFamily family) +{ + GstRTSPAddress *result; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + g_mutex_lock (&stream->priv->lock); + result = gst_rtsp_stream_get_multicast_address_locked (stream, family); + g_mutex_unlock (&stream->priv->lock); + + return result; +} + /** * gst_rtsp_stream_reserve_address: * @stream: a #GstRTSPStream @@ -1202,7 +1210,7 @@ error: static gboolean alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GstElement * udpsrc_out[2], GstElement * udpsink_out[2], - GstRTSPRange * server_port_out, GstRTSPAddress ** server_addr_out) + GstRTSPAddress ** server_addr_out, gboolean multicast) { GstRTSPStreamPrivate *priv = stream->priv; GSocket *rtp_socket = NULL; @@ -1248,13 +1256,21 @@ again: g_socket_set_multicast_loopback (rtp_socket, FALSE); } - if (pool && gst_rtsp_address_pool_has_unicast_addresses (pool)) { + if ((pool && gst_rtsp_address_pool_has_unicast_addresses (pool)) || multicast) { GstRTSPAddressFlags flags; if (addr) rejected_addresses = g_list_prepend (rejected_addresses, addr); - flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_UNICAST; + if (!pool) + goto no_ports; + + flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT; + if (multicast) + flags |= GST_RTSP_ADDRESS_FLAG_MULTICAST; + else + flags |= GST_RTSP_ADDRESS_FLAG_UNICAST; + if (family == G_SOCKET_FAMILY_IPV6) flags |= GST_RTSP_ADDRESS_FLAG_IPV6; else @@ -1316,21 +1332,20 @@ again: } g_object_unref (rtcp_sockaddr); - if (addr == NULL) - addr_str = g_inet_address_to_string (inetaddr); - else - addr_str = addr->address; + if (!addr) { + addr = g_slice_new0 (GstRTSPAddress); + addr->address = g_inet_address_to_string (inetaddr); + addr->port = tmp_rtp; + addr->n_ports = 2; + } + + addr_str = addr->address; g_clear_object (&inetaddr); if (!create_and_configure_udpsources (udpsrc_out, rtp_socket, rtcp_socket)) { - if (addr == NULL) - g_free (addr_str); goto no_udp_protocol; } - if (addr == NULL) - g_free (addr_str); - g_object_get (G_OBJECT (udpsrc_out[0]), "port", &rtpport, NULL); g_object_get (G_OBJECT (udpsrc_out[1]), "port", &rtcpport, NULL); @@ -1338,18 +1353,26 @@ again: if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) goto port_error; - server_port_out->min = rtpport; - server_port_out->max = rtcpport; - /* This function is called twice (for v4 and v6) but we create only one pair * of udpsinks. */ if (!udpsink_out[0] && !create_and_configure_udpsinks (stream, udpsink_out)) goto no_udp_protocol; + if (multicast) { + g_object_set (G_OBJECT (udpsink_out[0]), "multicast-iface", + priv->multicast_iface, NULL); + g_object_set (G_OBJECT (udpsink_out[1]), "multicast-iface", + priv->multicast_iface, NULL); + + g_signal_emit_by_name (udpsink_out[0], "add", addr_str, rtpport, NULL); + g_signal_emit_by_name (udpsink_out[1], "add", addr_str, rtcpport, NULL); + } + set_sockets_for_udpsinks (udpsink_out, rtp_socket, rtcp_socket, family); *server_addr_out = addr; + g_list_free_full (rejected_addresses, (GDestroyNotify) gst_rtsp_address_free); g_object_unref (rtp_socket); @@ -1464,15 +1487,21 @@ alloc_ports (GstRTSPStream * stream) GstRTSPStreamPrivate *priv = stream->priv; gboolean ret = TRUE; - if ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || - (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)) { + if (priv->protocols & GST_RTSP_LOWER_TRANS_UDP) { ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, - priv->udpsrc_v4, priv->udpsink, - &priv->server_port_v4, &priv->server_addr_v4); + priv->udpsrc_v4, priv->udpsink, &priv->server_addr_v4, FALSE); ret |= alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, - priv->udpsrc_v6, priv->udpsink, - &priv->server_port_v6, &priv->server_addr_v6); + priv->udpsrc_v6, priv->udpsink, &priv->server_addr_v6, FALSE); + } + + /* FIXME: Maybe actually consider the return values? */ + if (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) { + ret |= alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, + priv->mcast_udpsrc_v4, priv->mcast_udpsink, &priv->mcast_addr_v4, TRUE); + + ret |= alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, + priv->mcast_udpsrc_v6, priv->mcast_udpsink, &priv->mcast_addr_v6, TRUE); } return ret; @@ -1499,11 +1528,17 @@ gst_rtsp_stream_get_server_port (GstRTSPStream * stream, g_mutex_lock (&priv->lock); if (family == G_SOCKET_FAMILY_IPV4) { - if (server_port) - *server_port = priv->server_port_v4; + if (server_port) { + server_port->min = priv->server_addr_v4->port; + server_port->max = + priv->server_addr_v4->port + priv->server_addr_v4->n_ports - 1; + } } else { - if (server_port) - *server_port = priv->server_port_v6; + if (server_port) { + server_port->min = priv->server_addr_v6->port; + server_port->max = + priv->server_addr_v6->port + priv->server_addr_v6->n_ports - 1; + } } g_mutex_unlock (&priv->lock); } @@ -2357,7 +2392,7 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) { GstRTSPStreamPrivate *priv; GstPad *pad; - gboolean is_tcp = FALSE, is_udp = FALSE; + gboolean is_tcp, is_udp; gint i; priv = stream->priv; @@ -2414,7 +2449,12 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) gst_pad_link (priv->send_src[i], pad); gst_object_unref (pad); - plug_sink (bin, priv->tee[i], priv->udpsink[i], &priv->udpqueue[i]); + if (priv->udpsink[i]) + plug_sink (bin, priv->tee[i], priv->udpsink[i], &priv->udpqueue[i]); + + if (priv->mcast_udpsink[i]) + plug_sink (bin, priv->tee[i], priv->mcast_udpsink[i], + &priv->mcast_udpqueue[i]); if (is_tcp) { g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); @@ -2437,12 +2477,16 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) if (state != GST_STATE_NULL) { if (priv->udpsink[i]) gst_element_set_state (priv->udpsink[i], state); + if (priv->mcast_udpsink[i]) + gst_element_set_state (priv->mcast_udpsink[i], state); if (priv->appsink[i]) gst_element_set_state (priv->appsink[i], state); if (priv->appqueue[i]) gst_element_set_state (priv->appqueue[i], state); if (priv->udpqueue[i]) gst_element_set_state (priv->udpqueue[i], state); + if (priv->mcast_udpqueue[i]) + gst_element_set_state (priv->mcast_udpqueue[i], state); if (priv->tee[i]) gst_element_set_state (priv->tee[i], state); } @@ -2525,6 +2569,12 @@ create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) if (priv->udpsrc_v6[i]) plug_src (stream, bin, priv->udpsrc_v6[i], priv->funnel[i]); + if (priv->mcast_udpsrc_v4[i]) + plug_src (stream, bin, priv->mcast_udpsrc_v4[i], priv->funnel[i]); + + if (priv->mcast_udpsrc_v6[i]) + plug_src (stream, bin, priv->mcast_udpsrc_v6[i], priv->funnel[i]); + if (is_tcp) { /* make and add appsrc */ priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); @@ -2542,20 +2592,13 @@ create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) } static gboolean -create_mcast_part_for_transport (GstRTSPStream * stream, +check_mcast_part_for_transport (GstRTSPStream * stream, const GstRTSPTransport * tr) { GstRTSPStreamPrivate *priv = stream->priv; GInetAddress *inetaddr; GSocketFamily family; GstRTSPAddress *mcast_addr; - GstElement **mcast_udpsrc; - GSocket *rtp_socket = NULL; - GSocket *rtcp_socket = NULL; - GSocketAddress *rtp_sockaddr = NULL; - GSocketAddress *rtcp_sockaddr = NULL; - GError *error = NULL; - const gchar *multicast_iface = priv->multicast_iface; /* Check if it's a ipv4 or ipv6 transport */ inetaddr = g_inet_address_new_from_string (tr->destination); @@ -2565,10 +2608,8 @@ create_mcast_part_for_transport (GstRTSPStream * stream, /* Select fields corresponding to the family */ if (family == G_SOCKET_FAMILY_IPV4) { mcast_addr = priv->mcast_addr_v4; - mcast_udpsrc = priv->mcast_udpsrc_v4; } else { mcast_addr = priv->mcast_addr_v6; - mcast_udpsrc = priv->mcast_udpsrc_v6; } /* We support only one mcast group per family, make sure this transport @@ -2582,95 +2623,6 @@ create_mcast_part_for_transport (GstRTSPStream * stream, tr->ttl != mcast_addr->ttl) goto wrong_addr; - if (mcast_udpsrc[0]) { - /* We already created elements for this family. Since we support only one - * mcast group per family, there is nothing more to do here. */ - g_assert (mcast_udpsrc[1]); - g_assert (priv->mcast_udpqueue[0]); - g_assert (priv->mcast_udpqueue[1]); - g_assert (priv->mcast_udpsink[0]); - g_assert (priv->mcast_udpsink[1]); - return TRUE; - } - - g_assert (!mcast_udpsrc[1]); - - /* Create RTP/RTCP sockets and bind them on ANY with mcast ports */ - rtp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, - G_SOCKET_PROTOCOL_UDP, &error); - if (!rtp_socket) - goto socket_error; - g_socket_set_multicast_loopback (rtp_socket, FALSE); - - rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, - G_SOCKET_PROTOCOL_UDP, &error); - if (!rtcp_socket) - goto socket_error; - g_socket_set_multicast_loopback (rtcp_socket, FALSE); - - inetaddr = g_inet_address_new_any (family); - rtp_sockaddr = g_inet_socket_address_new (inetaddr, mcast_addr->port); - rtcp_sockaddr = g_inet_socket_address_new (inetaddr, mcast_addr->port + 1); - g_object_unref (inetaddr); - - if (!g_socket_bind (rtp_socket, rtp_sockaddr, FALSE, &error)) - goto socket_error; - - if (!g_socket_bind (rtcp_socket, rtcp_sockaddr, FALSE, &error)) - goto socket_error; - - g_object_unref (rtp_sockaddr); - g_object_unref (rtcp_sockaddr); - - /* Add receiver part */ - create_and_configure_udpsources (mcast_udpsrc, rtp_socket, rtcp_socket); - if (priv->sinkpad) { - plug_src (stream, priv->joined_bin, mcast_udpsrc[0], priv->funnel[0]); - gst_element_sync_state_with_parent (mcast_udpsrc[0]); - } - plug_src (stream, priv->joined_bin, mcast_udpsrc[1], priv->funnel[1]); - gst_element_sync_state_with_parent (mcast_udpsrc[1]); - - /* Add sender part, could already have been created for the other family. */ - if (!priv->mcast_udpsink[0]) { - g_assert (!priv->mcast_udpsink[1]); - g_assert (!priv->mcast_udpqueue[0]); - g_assert (!priv->mcast_udpqueue[1]); - - create_and_configure_udpsinks (stream, priv->mcast_udpsink); - - g_object_set (G_OBJECT (priv->mcast_udpsink[0]), "multicast-iface", - multicast_iface, NULL); - g_object_set (G_OBJECT (priv->mcast_udpsink[1]), "multicast-iface", - multicast_iface, NULL); - - g_signal_emit_by_name (priv->mcast_udpsink[0], "add", mcast_addr->address, - mcast_addr->port, NULL); - g_signal_emit_by_name (priv->mcast_udpsink[1], "add", mcast_addr->address, - mcast_addr->port + 1, NULL); - - set_sockets_for_udpsinks (priv->mcast_udpsink, rtp_socket, rtcp_socket, - family); - - if (priv->srcpad) { - plug_sink (priv->joined_bin, priv->tee[0], priv->mcast_udpsink[0], - &priv->mcast_udpqueue[0]); - gst_element_sync_state_with_parent (priv->mcast_udpsink[0]); - gst_element_sync_state_with_parent (priv->mcast_udpqueue[0]); - } - plug_sink (priv->joined_bin, priv->tee[1], priv->mcast_udpsink[1], - &priv->mcast_udpqueue[1]); - gst_element_sync_state_with_parent (priv->mcast_udpsink[1]); - gst_element_sync_state_with_parent (priv->mcast_udpqueue[1]); - } else { - g_assert (priv->mcast_udpsink[1]); - g_assert (priv->mcast_udpqueue[0]); - g_assert (priv->mcast_udpqueue[1]); - - set_sockets_for_udpsinks (priv->mcast_udpsink, rtp_socket, rtcp_socket, - family); - } - return TRUE; no_addr: @@ -2685,17 +2637,6 @@ wrong_addr: "the reserved address"); return FALSE; } -socket_error: - { - GST_ERROR_OBJECT (stream, "Error creating and binding mcast socket: %s", - error->message); - g_clear_object (&rtp_socket); - g_clear_object (&rtcp_socket); - g_clear_object (&rtp_sockaddr); - g_clear_object (&rtcp_sockaddr); - g_clear_error (&error); - return FALSE; - } } /** @@ -2962,6 +2903,19 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, if (priv->srtpdec) gst_object_unref (priv->srtpdec); + if (priv->mcast_addr_v4) + gst_rtsp_address_free (priv->mcast_addr_v4); + priv->mcast_addr_v4 = NULL; + if (priv->mcast_addr_v6) + gst_rtsp_address_free (priv->mcast_addr_v6); + priv->mcast_addr_v6 = NULL; + if (priv->server_addr_v4) + gst_rtsp_address_free (priv->server_addr_v4); + priv->server_addr_v4 = NULL; + if (priv->server_addr_v6) + gst_rtsp_address_free (priv->server_addr_v6); + priv->server_addr_v6 = NULL; + g_clear_object (&priv->joined_bin); g_mutex_unlock (&priv->lock); @@ -3321,13 +3275,11 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, case GST_RTSP_LOWER_TRANS_UDP_MCAST: { if (add) { - if (!create_mcast_part_for_transport (stream, tr)) + if (!check_mcast_part_for_transport (stream, tr)) goto mcast_error; priv->transports = g_list_prepend (priv->transports, trans); } else { priv->transports = g_list_remove (priv->transports, trans); - /* FIXME: Check if there are remaining mcast transports, and destroy - * mcast part if its now unused */ } break; } From 6136ef66d4333cc8cf17eb3b28f3746a0cf9346c Mon Sep 17 00:00:00 2001 From: Kseniia Date: Mon, 5 Sep 2016 18:31:36 +0300 Subject: [PATCH 1290/1776] rtsp-session: Fix segfault when doing keep-alive after removing the session If keep-alive happens after removing the session but before finalizing the stream transport, we would segfault. https://bugzilla.gnome.org/show_bug.cgi?id=750544 --- gst/rtsp-server/rtsp-session.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 10f5648020..8c664e2858 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -250,6 +250,26 @@ gst_rtsp_session_manage_media (GstRTSPSession * sess, const gchar * path, return result; } +static void +gst_rtsp_session_unset_transport_keepalive (GstRTSPSessionMedia * sessmedia) +{ + GstRTSPMedia *media; + guint i, n_streams; + + media = gst_rtsp_session_media_get_media (sessmedia); + n_streams = gst_rtsp_media_n_streams (media); + + for (i = 0; i < n_streams; i++) { + GstRTSPStreamTransport *transport = + gst_rtsp_session_media_get_transport (sessmedia, i); + + if (!transport) + continue; + + gst_rtsp_stream_transport_set_keepalive (transport, NULL, NULL, NULL); + } +} + /** * gst_rtsp_session_release_media: * @sess: a #GstRTSPSession @@ -281,6 +301,9 @@ gst_rtsp_session_release_media (GstRTSPSession * sess, more = (priv->medias != NULL); g_mutex_unlock (&priv->lock); + if (find && !more) + gst_rtsp_session_unset_transport_keepalive (media); + if (find) g_object_unref (media); From e5a49efa7ffce2ca2eeefb1a8bad97edfc96649f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 6 Sep 2016 19:10:21 +0300 Subject: [PATCH 1291/1776] rtsp-stream: Bind multicast sockets to ANY as before https://bugzilla.gnome.org/show_bug.cgi?id=766612#c48 --- gst/rtsp-server/rtsp-stream.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 5773fa60c9..9bef965780 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1284,7 +1284,10 @@ again: tmp_rtp = addr->port; g_clear_object (&inetaddr); - inetaddr = g_inet_address_new_from_string (addr->address); + if (multicast) + inetaddr = g_inet_address_new_any (family); + else + inetaddr = g_inet_address_new_from_string (addr->address); } else { if (tmp_rtp != 0) { tmp_rtp += 2; From d33eca6156fde0dbc303615da278c098cdb1d0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 6 Sep 2016 19:15:23 +0300 Subject: [PATCH 1292/1776] rtsp-stream: Compare IP address strings case insensitive Otherwise IPv6 addresses might fail this comparision. --- gst/rtsp-server/rtsp-stream.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 9bef965780..c57d13dd6a 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1056,7 +1056,7 @@ gst_rtsp_stream_reserve_address (GstRTSPStream * stream, /* FIXME: Also reserve the same port with unicast ANY address, since that's * where we are going to bind our socket. */ } else { - if (strcmp ((*addrp)->address, address) || + if (g_ascii_strcasecmp ((*addrp)->address, address) || (*addrp)->port != port || (*addrp)->n_ports != n_ports || (*addrp)->ttl != ttl) goto different_address; @@ -1082,8 +1082,9 @@ no_address: } different_address: { - GST_ERROR_OBJECT (stream, "address %s is not the same that was already" - " reserved", address); + GST_ERROR_OBJECT (stream, + "address %s is not the same as %s that was already" " reserved", + address, (*addrp)->address); g_mutex_unlock (&priv->lock); return NULL; } From f90ab92547dcc2034744ed2abab2077be804b5c6 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 7 Sep 2016 10:12:18 -0400 Subject: [PATCH 1293/1776] stream: Fix leaked joined_bin There is no need to keep a strong ref on it, and _leave_bin() was setting it to NULL before calling g_clear_object() so it was leaked. https://bugzilla.gnome.org/show_bug.cgi?id=766612 --- common | 2 +- gst/rtsp-server/rtsp-stream.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/common b/common index f49c55ecd3..6f2d2093e8 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit f49c55ecd35a7436194d28297f6d6f20eb6a66fa +Subproject commit 6f2d2093e84cc0eb99b634fa281822ebb9507285 diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index c57d13dd6a..61ffa3e27f 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2768,7 +2768,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, (GCallback) caps_notify, stream); } - priv->joined_bin = gst_object_ref (bin); + priv->joined_bin = bin; g_mutex_unlock (&priv->lock); return TRUE; @@ -2920,7 +2920,6 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, gst_rtsp_address_free (priv->server_addr_v6); priv->server_addr_v6 = NULL; - g_clear_object (&priv->joined_bin); g_mutex_unlock (&priv->lock); return TRUE; From f5f350645ae348951b6785f18a5abb0afc55c689 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 7 Sep 2016 10:16:19 -0400 Subject: [PATCH 1294/1776] stream: Compare IP addresses case insensitive in more places https://bugzilla.gnome.org/show_bug.cgi?id=766612 --- gst/rtsp-server/rtsp-stream.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 61ffa3e27f..c5722cd39b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1827,7 +1827,8 @@ find_transport (GstRTSPStream * stream, const gchar * rtcp_from) max = tr->client_port.max; } - if ((strcmp (tr->destination, dest) == 0) && (min == port || max == port)) { + if ((g_ascii_strcasecmp (tr->destination, dest) == 0) && + (min == port || max == port)) { result = trans; break; } @@ -2621,7 +2622,7 @@ check_mcast_part_for_transport (GstRTSPStream * stream, if (!mcast_addr) goto no_addr; - if (!g_str_equal (tr->destination, mcast_addr->address) || + if (g_ascii_strcasecmp (tr->destination, mcast_addr->address) != 0 || tr->port.min != mcast_addr->port || tr->port.max != mcast_addr->port + mcast_addr->n_ports - 1 || tr->ttl != mcast_addr->ttl) From e882fe9e060cf3b98651064d3ce9776086d380da Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 7 Sep 2016 10:21:09 -0400 Subject: [PATCH 1295/1776] stream: cosmetic cleanup https://bugzilla.gnome.org/show_bug.cgi?id=766612 --- gst/rtsp-server/rtsp-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index c5722cd39b..0ca31f99df 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1083,7 +1083,7 @@ no_address: different_address: { GST_ERROR_OBJECT (stream, - "address %s is not the same as %s that was already" " reserved", + "address %s is not the same as %s that was already reserved", address, (*addrp)->address); g_mutex_unlock (&priv->lock); return NULL; From 74c8a9f4cff34c99fe8e2dc1c7aec4749f9a1fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 7 Sep 2016 18:44:34 +0300 Subject: [PATCH 1296/1776] rtsp-stream: Remove unused _locked() variant of a function It was added during refactoring. --- gst/rtsp-server/rtsp-stream.c | 54 +++++++++++++++-------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 0ca31f99df..2d3997c5f0 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -913,9 +913,21 @@ gst_rtsp_stream_get_multicast_iface (GstRTSPStream * stream) return result; } - -static GstRTSPAddress * -gst_rtsp_stream_get_multicast_address_locked (GstRTSPStream * stream, +/** + * gst_rtsp_stream_get_multicast_address: + * @stream: a #GstRTSPStream + * @family: the #GSocketFamily + * + * Get the multicast address of @stream for @family. The original + * #GstRTSPAddress is cached and copy is returned, so freeing the return value + * won't release the address from the pool. + * + * Returns: (transfer full) (nullable): the #GstRTSPAddress of @stream + * or %NULL when no address could be allocated. gst_rtsp_address_free() + * after usage. + */ +GstRTSPAddress * +gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, GSocketFamily family) { GstRTSPStreamPrivate *priv; @@ -923,8 +935,12 @@ gst_rtsp_stream_get_multicast_address_locked (GstRTSPStream * stream, GstRTSPAddress **addrp; GstRTSPAddressFlags flags; + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + priv = stream->priv; + g_mutex_lock (&stream->priv->lock); + if (family == G_SOCKET_FAMILY_IPV6) { flags = GST_RTSP_ADDRESS_FLAG_IPV6; addrp = &priv->mcast_addr_v6; @@ -951,49 +967,25 @@ gst_rtsp_stream_get_multicast_address_locked (GstRTSPStream * stream, } result = gst_rtsp_address_copy (*addrp); + g_mutex_unlock (&stream->priv->lock); + return result; /* ERRORS */ no_pool: { GST_ERROR_OBJECT (stream, "no address pool specified"); + g_mutex_unlock (&stream->priv->lock); return NULL; } no_address: { GST_ERROR_OBJECT (stream, "failed to acquire address from pool"); + g_mutex_unlock (&stream->priv->lock); return NULL; } } -/** - * gst_rtsp_stream_get_multicast_address: - * @stream: a #GstRTSPStream - * @family: the #GSocketFamily - * - * Get the multicast address of @stream for @family. The original - * #GstRTSPAddress is cached and copy is returned, so freeing the return value - * won't release the address from the pool. - * - * Returns: (transfer full) (nullable): the #GstRTSPAddress of @stream - * or %NULL when no address could be allocated. gst_rtsp_address_free() - * after usage. - */ -GstRTSPAddress * -gst_rtsp_stream_get_multicast_address (GstRTSPStream * stream, - GSocketFamily family) -{ - GstRTSPAddress *result; - - g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); - - g_mutex_lock (&stream->priv->lock); - result = gst_rtsp_stream_get_multicast_address_locked (stream, family); - g_mutex_unlock (&stream->priv->lock); - - return result; -} - /** * gst_rtsp_stream_reserve_address: * @stream: a #GstRTSPStream From 02bc6fa8ca19ee857b9f34f2641bdfc50523b240 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Sat, 10 Sep 2016 09:58:31 +1000 Subject: [PATCH 1297/1776] Automatic update of common submodule From 6f2d209 to b18d820 --- autogen.sh | 2 +- common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/autogen.sh b/autogen.sh index aecf0e2e4a..2fa6ac0f67 100755 --- a/autogen.sh +++ b/autogen.sh @@ -58,7 +58,7 @@ elif test "x$package" = "xgst-plugins-bad"; then CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-player-tests" fi -autogen_options $@ +autogen_options "$@" printf "+ check for build tools" if test -z "$NOCHECK"; then diff --git a/common b/common index 6f2d2093e8..b18d820635 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 6f2d2093e84cc0eb99b634fa281822ebb9507285 +Subproject commit b18d820635185eb549530af1ce406937141b2dd9 From 90a05f5ce5cb79950dfa0beec9b25b0ee04e2181 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Sat, 10 Sep 2016 20:52:31 +1000 Subject: [PATCH 1298/1776] Automatic update of common submodule From b18d820 to f980fd9 --- autogen.sh | 2 +- common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/autogen.sh b/autogen.sh index 2fa6ac0f67..aecf0e2e4a 100755 --- a/autogen.sh +++ b/autogen.sh @@ -58,7 +58,7 @@ elif test "x$package" = "xgst-plugins-bad"; then CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-player-tests" fi -autogen_options "$@" +autogen_options $@ printf "+ check for build tools" if test -z "$NOCHECK"; then diff --git a/common b/common index b18d820635..f980fd91c1 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit b18d820635185eb549530af1ce406937141b2dd9 +Subproject commit f980fd91c1c1fd01333966041a4a535366e897bd From 0121cbc50075fccfa308808b116bd27eef02728f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 14 Sep 2016 11:31:15 +0200 Subject: [PATCH 1299/1776] configure: Depend on gstreamer 1.9.2.1 --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 5f62d0898a..226cca9f49 100644 --- a/configure.ac +++ b/configure.ac @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 902, 0, 902) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.9.2 -GSTPB_REQ=1.9.2 -GSTPG_REQ=1.9.2 -GSTPD_REQ=1.9.2 +GST_REQ=1.9.2.1 +GSTPB_REQ=1.9.2.1 +GSTPG_REQ=1.9.2.1 +GSTPD_REQ=1.9.2.1 dnl *** autotools stuff **** From 800bed8c9c933562a9d642714f21b8af804122e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 18 Sep 2016 09:58:55 -0400 Subject: [PATCH 1300/1776] rtsp-media: Call g_free() instead of g_object_unref() on multicast-iface strings https://bugzilla.gnome.org/show_bug.cgi?id=763000#c5 --- gst/rtsp-server/rtsp-media-factory.c | 2 +- gst/rtsp-server/rtsp-media.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 8665c47cdf..5569f62dff 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -829,7 +829,7 @@ gst_rtsp_media_factory_set_multicast_iface (GstRTSPMediaFactory * media_factory, g_mutex_unlock (&priv->lock); if (old) - g_object_unref (old); + g_free (old); } /** diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c08b2a9d91..c17e85a6bc 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1606,7 +1606,7 @@ gst_rtsp_media_set_multicast_iface (GstRTSPMedia * media, g_mutex_unlock (&priv->lock); if (old) - g_object_unref (old); + g_free (old); } /** From 34389831cb18e41be002314c524e4010e2ab8e8f Mon Sep 17 00:00:00 2001 From: Ian Jamison Date: Sat, 17 Sep 2016 13:17:19 +0100 Subject: [PATCH 1301/1776] rtsp-server: Hint that set_multicast_iface expects the name of the interface To prevent any possibly confusion with IPs or anything else. https://bugzilla.gnome.org/show_bug.cgi?id=771530 --- gst/rtsp-server/rtsp-media-factory.c | 2 +- gst/rtsp-server/rtsp-media.c | 2 +- gst/rtsp-server/rtsp-stream.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 5569f62dff..09e5160423 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -804,7 +804,7 @@ gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory) /** * gst_rtsp_media_factory_set_multicast_iface: * @media_factory: a #GstRTSPMediaFactory - * @multicast_iface: (transfer none): a multicast interface + * @multicast_iface: (transfer none): a multicast interface name * * configure @multicast_iface to be used for @media_factory. */ diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c17e85a6bc..349311aced 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1579,7 +1579,7 @@ gst_rtsp_media_get_address_pool (GstRTSPMedia * media) /** * gst_rtsp_media_set_multicast_iface: * @media: a #GstRTSPMedia - * @multicast_iface: (transfer none): a multicast interface + * @multicast_iface: (transfer none): a multicast interface name * * configure @multicast_iface to be used for @media. */ diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 2d3997c5f0..9125314d34 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -857,7 +857,7 @@ gst_rtsp_stream_get_address_pool (GstRTSPStream * stream) /** * gst_rtsp_stream_set_multicast_iface: * @stream: a #GstRTSPStream - * @multicast_iface: (transfer none): a multicast interface + * @multicast_iface: (transfer none): a multicast interface name * * configure @multicast_iface to be used for @stream. */ From 11f5797cce4c4566d047982173eeeb10f087d2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 30 Sep 2016 13:04:12 +0300 Subject: [PATCH 1302/1776] Release 1.9.90 --- ChangeLog | 203 ++++++++++++++++++++++++++++++++++++++++++- NEWS | 2 +- RELEASE | 25 +++--- configure.ac | 12 +-- gst-rtsp-server.doap | 10 +++ 5 files changed, 229 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index ebf0e05f3d..c5a04b1ccb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,206 @@ -=== release 1.9.2 === +=== release 1.9.90 === -2016-09-01 Sebastian Dröge +2016-09-30 Sebastian Dröge * configure.ac: - releasing 1.9.2 + releasing 1.9.90 + +2016-09-17 13:17:19 +0100 Ian Jamison + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-server: Hint that set_multicast_iface expects the name of the interface + To prevent any possibly confusion with IPs or anything else. + https://bugzilla.gnome.org/show_bug.cgi?id=771530 + +2016-09-18 09:58:55 -0400 Sebastian Dröge + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Call g_free() instead of g_object_unref() on multicast-iface strings + https://bugzilla.gnome.org/show_bug.cgi?id=763000#c5 + +2016-09-14 11:31:15 +0200 Sebastian Dröge + + * configure.ac: + configure: Depend on gstreamer 1.9.2.1 + +2016-09-10 20:52:31 +1000 Jan Schmidt + + * autogen.sh: + * common: + Automatic update of common submodule + From b18d820 to f980fd9 + +2016-09-10 09:58:31 +1000 Jan Schmidt + + * autogen.sh: + * common: + Automatic update of common submodule + From 6f2d209 to b18d820 + +2016-09-07 18:44:34 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Remove unused _locked() variant of a function + It was added during refactoring. + +2016-09-07 10:21:09 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-stream.c: + stream: cosmetic cleanup + https://bugzilla.gnome.org/show_bug.cgi?id=766612 + +2016-09-07 10:16:19 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-stream.c: + stream: Compare IP addresses case insensitive in more places + https://bugzilla.gnome.org/show_bug.cgi?id=766612 + +2016-09-07 10:12:18 -0400 Xavier Claessens + + * common: + * gst/rtsp-server/rtsp-stream.c: + stream: Fix leaked joined_bin + There is no need to keep a strong ref on it, and _leave_bin() was + setting it to NULL before calling g_clear_object() so it was leaked. + https://bugzilla.gnome.org/show_bug.cgi?id=766612 + +2016-09-06 19:15:23 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Compare IP address strings case insensitive + Otherwise IPv6 addresses might fail this comparision. + +2016-09-06 19:10:21 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Bind multicast sockets to ANY as before + https://bugzilla.gnome.org/show_bug.cgi?id=766612#c48 + +2016-09-05 18:31:36 +0300 Kseniia + + * gst/rtsp-server/rtsp-session.c: + rtsp-session: Fix segfault when doing keep-alive after removing the session + If keep-alive happens after removing the session but before finalizing the + stream transport, we would segfault. + https://bugzilla.gnome.org/show_bug.cgi?id=750544 + +2016-09-05 18:04:50 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Always create multicast UDP elements if the protocol flag is set + Adding them later will cause deadlocks due to + 1) pre-rolling and staying in PAUSED with the unicast/TCP sinks + 2) adding the multicast sink + 3) waiting for it to get data to preroll again + 3) never happens because the queues after the tee are full. + +2016-09-05 16:32:57 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Fix up various multicast related issues + +2016-09-05 13:40:59 +0300 Sebastian Dröge + + * tests/check/gst/stream.c: + tests: Fix compilation + +2016-07-28 15:33:05 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/stream.c: + stream: revert back to create udpsrc/udpsink on DESCRIBE for unicast + This is basically reverting changes introduced in commit f62a9a7, + because it was introducing various regressions: + - It introduces a leak of udpsrc elements that got wrongly fixed by adding + an hash table in commit cba045e. We should have at most 4 udpsrc for unicast: + ipv4/ipv6, rtp/rtcp. They can be reused for all unicast clients. + - If a mcast client connects, it creates a new socket in SETUP to try to respect + the destination/port given by the client in the transport, and overrides the + socket already set on the udpsink element. That means that if we already had a + client connected, the source address on the udp packets it receives suddenly + changes. + - If a 2nd mcast client connects, the destination/port in its transport is + ignored but its transport wasn't updated. + What this patch does: + - Revert back to create udpsrc/udpsink for unicast clients on DESCRIBE. + - Always have a tee+queue when udp is enabled. This could be optimized + again in a later patch, but is more complicated. If no unicast clients + connects then those elements are useless, this could be also optimized + in a later patch. + - When mcast transport is added, it creates a new set of udpsrc/udpsink, + seperated from those for unicast clients. Since we already support only + one mcast address, we also create only one set of elements. + https://bugzilla.gnome.org/show_bug.cgi?id=766612 + +2016-07-28 15:20:31 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-stream.c: + stream: factor our plug_src function + https://bugzilla.gnome.org/show_bug.cgi?id=766612 + +2016-07-21 21:46:16 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-stream.c: + stream: factor out plug_sink function + https://bugzilla.gnome.org/show_bug.cgi?id=766612 + +2016-07-20 23:05:09 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-stream.c: + stream: small documentation clarification + https://bugzilla.gnome.org/show_bug.cgi?id=766612 + +2016-07-20 15:35:44 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-stream.c: + stream: rename addr_v4/6 to mcast_addr_v4/6 for clarity + https://bugzilla.gnome.org/show_bug.cgi?id=766612 + +2016-07-14 11:10:31 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-stream.c: + stream: Keep a ref on joined bin + https://bugzilla.gnome.org/show_bug.cgi?id=766612 + +2016-07-20 15:11:32 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-stream.c: + stream: code cleanup + https://bugzilla.gnome.org/show_bug.cgi?id=766612 + +2016-07-20 23:18:23 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-stream.c: + stream: small fix in error code path + https://bugzilla.gnome.org/show_bug.cgi?id=766612 + +2016-07-20 20:09:57 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-stream.c: + Revert "rtsp-stream: Fix crash on cleanup with shared media and multiple udpsrc" + This partly reverts commit cba045e1b19fad6e689e10206f57903e15f1229a, + but keeps unit tests. + https://bugzilla.gnome.org/show_bug.cgi?id=766612 + +2016-09-01 12:33:00 +0300 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.9.2 === + +2016-09-01 12:32:51 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.9.2 2016-01-27 01:03:52 +0000 Tim-Philipp Müller diff --git a/NEWS b/NEWS index 027c01804e..072b2dfb35 100644 --- a/NEWS +++ b/NEWS @@ -1 +1 @@ -This is GStreamer 1.9.2 +This is GStreamer 1.9.90 diff --git a/RELEASE b/RELEASE index 87b5eaf171..5aaba97b69 100644 --- a/RELEASE +++ b/RELEASE @@ -1,22 +1,21 @@ -Release notes for GStreamer RTSP Server Library 1.9.2 +Release notes for GStreamer RTSP Server Library 1.9.90 -The GStreamer team is pleased to announce the second release of the unstable -1.9 release series, which marks the feature freeze for 1.10. The 1.9 release -series is adding new features on top of the 1.0, 1.2, 1.4, 1.6 and 1.8 series -and is part of the API and ABI-stable 1.x release series of the GStreamer -multimedia framework. The unstable 1.9 release series will lead to the stable -1.10 release series in the next weeks. Any newly added API can still change -until that point. +The GStreamer team is pleased to announce the first release candidate of the +stable 1.10 release series. The 1.10 release series is adding new features on +top of the 1.0, 1.2, 1.4, 1.6 and 1.8 series and is part of the API and +ABI-stable 1.x release series of the GStreamer multimedia framework. Binaries for Android, iOS, Mac OS X and Windows will be provided in the next days. + Bugs fixed in this release - * 755632 : Memory leak in handle_setup_request + * 750544 : RTSP server: crashes when accessing freed session in keep alive callback on shutdown + * 766612 : Does not take address pool configuration into account for sending unicast UDP ==== Download ==== @@ -53,9 +52,9 @@ subscribe to the gstreamer-devel list. Contributors to this release - * Josep Torra - * Nikita Bobkov + * Ian Jamison + * Jan Schmidt + * Kseniia * Sebastian Dröge - * Stefan Sauer - * Tim-Philipp Müller + * Xavier Claessens   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 226cca9f49..4a23a85bbc 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.9.2.1], +AC_INIT([GStreamer RTSP Server Library], [1.9.90], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 902, 0, 902) +AS_LIBTOOL(GST, 990, 0, 990) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.9.2.1 -GSTPB_REQ=1.9.2.1 -GSTPG_REQ=1.9.2.1 -GSTPD_REQ=1.9.2.1 +GST_REQ=1.9.90 +GSTPB_REQ=1.9.90 +GSTPG_REQ=1.9.90 +GSTPD_REQ=1.9.90 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 78090d0c8f..45f421ac5f 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.9.90 + master + + 2016-09-30 + + + + 1.9.2 From 87f8eed5a73e1018077bef14750e10d0ec337450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 30 Sep 2016 11:42:08 +0100 Subject: [PATCH 1303/1776] meson: update version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index d861ffef0e..19f0d9f3ef 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.9.1.1', + version : '1.9.90', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From c0f24fea8381c0d35a4f255edbfd5d53463338bf Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 6 Oct 2016 11:47:50 -0400 Subject: [PATCH 1304/1776] stream: Fix randomly missing streams from SDP with dynamic elements When using dynamic elements, gst_rtsp_stream_join_bin() is called from "pad-added" signal. In that case priv->srcpad could already have its caps, and they'll be sent to priv->send_src[0] pad. That means that when it connects "notify::caps" signal, that pad could already have received its caps and the signal won't be emitted anymore. In that case priv->caps stay to NULL and when building the SDP that stream gets ignored. Leading to missing video or audio when playing in client side. https://bugzilla.gnome.org/show_bug.cgi?id=772478 --- gst/rtsp-server/rtsp-stream.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 9125314d34..9fd3e0037b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2759,6 +2759,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, /* be notified of caps changes */ priv->caps_sig = g_signal_connect (priv->send_src[0], "notify::caps", (GCallback) caps_notify, stream); + priv->caps = gst_pad_get_current_caps (priv->send_src[0]); } priv->joined_bin = bin; From ff657322707a91e84ba368356f06247daaa28243 Mon Sep 17 00:00:00 2001 From: Nikita Bobkov Date: Wed, 14 Sep 2016 17:48:39 +0300 Subject: [PATCH 1305/1776] rtsp-client: Fix factory leaking in find_media() in error cases https://bugzilla.gnome.org/show_bug.cgi?id=771488 --- gst/rtsp-server/rtsp-client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 956a9eb7a5..e1e5338cc1 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -729,6 +729,8 @@ no_factory: } no_factory_access: { + g_object_unref (factory); + ctx->factory = NULL; GST_ERROR ("client %p: not authorized to see factory path %s", client, path); /* error reply is already sent */ @@ -736,6 +738,8 @@ no_factory_access: } not_authorized: { + g_object_unref (factory); + ctx->factory = NULL; GST_ERROR ("client %p: not authorized for factory path %s", client, path); /* error reply is already sent */ return NULL; From 34ed1d0bea92691a9aa06d9973a26534fb539cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 20 Oct 2016 21:40:18 +0100 Subject: [PATCH 1306/1776] meson: add fallbacks for gst modules For gst-all. --- meson.build | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index 19f0d9f3ef..a8d9f9e365 100644 --- a/meson.build +++ b/meson.build @@ -44,13 +44,20 @@ rtspserver_args = ['-DHAVE_CONFIG_H'] rtspserver_incs = include_directories('gst/rtsp-server', '.') glib_dep = dependency('glib-2.0', version : glib_req) -gst_dep = dependency('gstreamer-1.0', version : gst_req) -gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req) -gstrtsp_dep = dependency('gstreamer-rtsp-1.0', version : gst_req) -gstrtp_dep = dependency('gstreamer-rtp-1.0', version : gst_req) -gstsdp_dep = dependency('gstreamer-sdp-1.0', version : gst_req) -gstapp_dep = dependency('gstreamer-app-1.0', version : gst_req) -gstnet_dep = dependency('gstreamer-net-1.0', version : gst_req) +gst_dep = dependency('gstreamer-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_dep']) +gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_check_dep']) +gstrtsp_dep = dependency('gstreamer-rtsp-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'rtsp_dep']) +gstrtp_dep = dependency('gstreamer-rtp-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'rtp_dep']) +gstsdp_dep = dependency('gstreamer-sdp-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'sdp_dep']) +gstapp_dep = dependency('gstreamer-app-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'app_dep']) +gstnet_dep = dependency('gstreamer-net-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_net_dep']) subdir('gst') subdir('tests') From dbf91ab231ad793646c6de540f105b4b24db9f25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Mon, 26 Sep 2016 11:16:04 +0200 Subject: [PATCH 1307/1776] rtsp-client: Session filter in unwatch session Call session filter with filter_session_media as paramer in client_unwatch_session if using drop_backlog = FALSE. In client_unwatch_session its allowed to grow the watchs backlog. If using drop_backlog = FALSE and the backlog is full it will cause a deadlock when setting session media state to NULL if the backlog is not allowed to grow. https://bugzilla.gnome.org/show_bug.cgi?id=771983 --- gst/rtsp-server/rtsp-client.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e1e5338cc1..deb2ab3403 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -416,6 +416,11 @@ client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session, priv->session_removed_id = 0; } + if (!priv->drop_backlog) { + /* unlink all media managed in this session */ + gst_rtsp_session_filter (session, filter_session_media, client); + } + /* remove the session */ g_object_unref (session); } @@ -425,10 +430,13 @@ cleanup_session (GstRTSPClient * client, GstRTSPSession * sess, gpointer user_data) { gboolean *closed = user_data; + GstRTSPClientPrivate *priv = client->priv; - /* unlink all media managed in this session. This needs to happen - * without the client lock, so we really want to do it here. */ - gst_rtsp_session_filter (sess, filter_session_media, user_data); + if (priv->drop_backlog) { + /* unlink all media managed in this session. This needs to happen + * without the client lock, so we really want to do it here. */ + gst_rtsp_session_filter (sess, filter_session_media, user_data); + } if (*closed) return GST_RTSP_FILTER_REMOVE; From fd6beb871aadf18e2dcef4749f726114a6e6ad2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 28 Oct 2016 17:50:59 +0100 Subject: [PATCH 1308/1776] tests: client: use fail_unless_equals_foo() for better failure reporting --- tests/check/gst/client.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 3f172d19fb..7779664c42 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -485,15 +485,15 @@ test_setup_response_200_multicast (GstRTSPClient * client, fail_unless (expected_transport != NULL); - fail_unless (gst_rtsp_message_get_type (response) == + fail_unless_equals_int (gst_rtsp_message_get_type (response), GST_RTSP_MESSAGE_RESPONSE); fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, &version) == GST_RTSP_OK); - fail_unless (code == GST_RTSP_STS_OK); - fail_unless (g_str_equal (reason, "OK")); - fail_unless (version == GST_RTSP_VERSION_1_0); + fail_unless_equals_int (code, GST_RTSP_STS_OK); + fail_unless_equals_string (reason, "OK"); + fail_unless_equals_int (version, GST_RTSP_VERSION_1_0); fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, 0) == GST_RTSP_OK); @@ -502,7 +502,7 @@ test_setup_response_200_multicast (GstRTSPClient * client, fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_TRANSPORT, &str, 0) == GST_RTSP_OK); - fail_unless (!strcmp (str, expected_transport)); + fail_unless_equals_string (str, expected_transport); fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &str, 0) == GST_RTSP_OK); From 75084422925ef762060e03ad8150e1670d1bf7e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 28 Oct 2016 18:38:01 +0100 Subject: [PATCH 1309/1776] tests: try to avoid using the same ports in different tests Causes problems with client multicast tests otherwise if tests are run in parallel. https://bugzilla.gnome.org/show_bug.cgi?id=773640 --- tests/check/gst/rtspserver.c | 2 +- tests/check/gst/stream.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 805b177d0e..9a9f58f94f 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -168,7 +168,7 @@ start_server (gboolean set_shared_factory) /* use an address pool for multicast */ pool = gst_rtsp_address_pool_new (); gst_rtsp_address_pool_add_range (pool, - "224.3.0.0", "224.3.0.10", 5000, 5010, 16); + "224.3.0.0", "224.3.0.10", 5500, 5510, 16); gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV4, GST_RTSP_ADDRESS_POOL_ANY_IPV4, 6000, 6010, 0); gst_rtsp_media_factory_set_address_pool (factory, pool); diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index 4a0ee789e2..0447acc2b2 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -166,21 +166,21 @@ GST_START_TEST (test_get_multicast_address) pool = gst_rtsp_address_pool_new (); fail_unless (gst_rtsp_address_pool_add_range (pool, - "233.252.0.0", "233.252.0.0", 5000, 5001, 1)); + "233.252.0.0", "233.252.0.0", 5100, 5101, 1)); fail_unless (gst_rtsp_address_pool_add_range (pool, - "FF11:DB8::1", "FF11:DB8::1", 5002, 5003, 1)); + "FF11:DB8::1", "FF11:DB8::1", 5102, 5103, 1)); gst_rtsp_stream_set_address_pool (stream, pool); addr1 = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV4); fail_unless (addr1 != NULL); fail_unless_equals_string (addr1->address, "233.252.0.0"); - fail_unless_equals_int (addr1->port, 5000); + fail_unless_equals_int (addr1->port, 5100); fail_unless_equals_int (addr1->n_ports, 2); addr2 = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV4); fail_unless (addr2 != NULL); fail_unless_equals_string (addr2->address, "233.252.0.0"); - fail_unless_equals_int (addr2->port, 5000); + fail_unless_equals_int (addr2->port, 5100); fail_unless_equals_int (addr2->n_ports, 2); gst_rtsp_address_free (addr1); @@ -189,13 +189,13 @@ GST_START_TEST (test_get_multicast_address) addr1 = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV6); fail_unless (addr1 != NULL); fail_unless (!g_ascii_strcasecmp (addr1->address, "FF11:DB8::1")); - fail_unless_equals_int (addr1->port, 5002); + fail_unless_equals_int (addr1->port, 5102); fail_unless_equals_int (addr1->n_ports, 2); addr2 = gst_rtsp_stream_get_multicast_address (stream, G_SOCKET_FAMILY_IPV6); fail_unless (addr2 != NULL); fail_unless (!g_ascii_strcasecmp (addr2->address, "FF11:DB8::1")); - fail_unless_equals_int (addr2->port, 5002); + fail_unless_equals_int (addr2->port, 5102); fail_unless_equals_int (addr2->n_ports, 2); gst_rtsp_address_free (addr1); @@ -237,7 +237,7 @@ GST_START_TEST (test_multicast_address_and_unicast_udp) pool = gst_rtsp_address_pool_new (); /* add a multicast addres to the address pool */ fail_unless (gst_rtsp_address_pool_add_range (pool, - "233.252.0.0", "233.252.0.0", 5000, 5001, 1)); + "233.252.0.0", "233.252.0.0", 5200, 5201, 1)); gst_rtsp_stream_set_address_pool (stream, pool); fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); From 3af697e777c1daa7d1a0698ca2d264550d3069e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 1 Nov 2016 18:06:46 +0200 Subject: [PATCH 1310/1776] Release 1.10.0 --- ChangeLog | 73 ++- NEWS | 1115 +++++++++++++++++++++++++++++++++++++++++- RELEASE | 27 +- configure.ac | 12 +- gst-rtsp-server.doap | 10 + 5 files changed, 1214 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index c5a04b1ccb..9e5143486c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,76 @@ -=== release 1.9.90 === +=== release 1.10.0 === -2016-09-30 Sebastian Dröge +2016-11-01 Sebastian Dröge * configure.ac: - releasing 1.9.90 + releasing 1.10.0 + +2016-10-28 18:38:01 +0100 Tim-Philipp Müller + + * tests/check/gst/rtspserver.c: + * tests/check/gst/stream.c: + tests: try to avoid using the same ports in different tests + Causes problems with client multicast tests otherwise if + tests are run in parallel. + https://bugzilla.gnome.org/show_bug.cgi?id=773640 + +2016-10-28 17:50:59 +0100 Tim-Philipp Müller + + * tests/check/gst/client.c: + tests: client: use fail_unless_equals_foo() for better failure reporting + +2016-09-26 11:16:04 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Session filter in unwatch session + Call session filter with filter_session_media as paramer in + client_unwatch_session if using drop_backlog = FALSE. + In client_unwatch_session its allowed to grow the watchs backlog. + If using drop_backlog = FALSE and the backlog is full it will cause + a deadlock when setting session media state to NULL + if the backlog is not allowed to grow. + https://bugzilla.gnome.org/show_bug.cgi?id=771983 + +2016-10-20 21:40:18 +0100 Tim-Philipp Müller + + * meson.build: + meson: add fallbacks for gst modules + For gst-all. + +2016-09-14 17:48:39 +0300 Nikita Bobkov + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Fix factory leaking in find_media() in error cases + https://bugzilla.gnome.org/show_bug.cgi?id=771488 + +2016-10-06 11:47:50 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-stream.c: + stream: Fix randomly missing streams from SDP with dynamic elements + When using dynamic elements, gst_rtsp_stream_join_bin() is called from + "pad-added" signal. In that case priv->srcpad could already have its caps, + and they'll be sent to priv->send_src[0] pad. That means that when it + connects "notify::caps" signal, that pad could already have received its + caps and the signal won't be emitted anymore. + In that case priv->caps stay to NULL and when building the SDP that stream + gets ignored. Leading to missing video or audio when playing in client side. + https://bugzilla.gnome.org/show_bug.cgi?id=772478 + +2016-09-30 11:42:08 +0100 Tim-Philipp Müller + + * meson.build: + meson: update version + +=== release 1.9.90 === + +2016-09-30 13:04:12 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.9.90 2016-09-17 13:17:19 +0100 Ian Jamison diff --git a/NEWS b/NEWS index 072b2dfb35..547de7f3f9 100644 --- a/NEWS +++ b/NEWS @@ -1 +1,1114 @@ -This is GStreamer 1.9.90 +# GStreamer 1.10 Release Notes + +**GStreamer 1.10.0 was released on 1st November 2016.** + +The GStreamer team is proud to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! + +As always, this release is again packed with new features, bug fixes and other +improvements. + +See [https://gstreamer.freedesktop.org/releases/1.10/][latest] for the latest +version of this document. + +*Last updated: Tuesday 1 Nov 2016, 15:00 UTC [(log)][gitlog]* + +[latest]: https://gstreamer.freedesktop.org/releases/1.10/ +[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.10/release-notes-1.10.md + +## Introduction + +The GStreamer team is proud to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! + +As always, this release is again packed with new features, bug fixes and other +improvements. + +## Highlights + +- Several convenience APIs have been added to make developers' lives easier +- A new `GstStream` API provides applications a more meaningful view of the + structure of streams, simplifying the process of dealing with media in + complex container formats +- Experimental `decodebin3` and `playbin3` elements which bring a number of + improvements which were hard to implement within `decodebin` and `playbin` +- A new `parsebin` element to automatically unpack and parse a stream, stopping + just short of decoding +- Experimental new `meson`-based build system, bringing faster build and much + better Windows support (including for building with Visual Studio) +- A new `gst-docs` module has been created, and we are in the process of moving + our documentation to a markdown-based format for easier maintenance and + updates +- A new `gst-examples` module has been create, which contains example + GStreamer applications and is expected to grow with many more examples in + the future +- Various OpenGL and OpenGL|ES-related fixes and improvements for greater + efficiency on desktop and mobile platforms, and Vulkan support on Wayland was + also added +- Extensive improvements to the VAAPI plugins for improved robustness and + efficiency +- Lots of fixes and improvements across the board, spanning RTP/RTSP, V4L2, + Bluetooth, audio conversion, echo cancellation, and more! + +## Major new features and changes + +### Noteworthy new API, features and other changes + +#### Core API additions + +##### Receive property change notifications via bus messages + +New API was added to receive element property change notifications via +bus messages. So far, applications had to connect a callback to an element's +`notify::property-name` signal via the GObject API, which was inconvenient for +at least two reasons: one had to implement a signal callback function, and that +callback function would usually be called from one of the streaming threads, so +one had to marshal (send) any information gathered or pending requests to the +main application thread which was tedious and error-prone. + +Enter [`gst_element_add_property_notify_watch()`][notify-watch] and +[`gst_element_add_property_deep_notify_watch()`][deep-notify-watch] which will +watch for changes of a property on the specified element, either only for this +element or recursively for a whole bin or pipeline. Whenever such a +property change happens, a `GST_MESSAGE_PROPERTY_NOTIFY` message will be posted +on the pipeline bus with details of the element, the property and the new +property value, all of which can be retrieved later from the message in the +application via [`gst_message_parse_property_notify()`][parse-notify]. Unlike +the GstBus watch functions, this API does not rely on a running GLib main loop. + +The above can be used to be notified asynchronously of caps changes in the +pipeline, or volume changes on an audio sink element, for example. + +[notify-watch]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-add-property-notify-watch +[deep-notify-watch]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-add-property-deep-notify-watch +[parse-notify]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-parse-property-notify + +##### GstBin "deep" element-added and element-removed signals + +GstBin has gained `"deep-element-added"` and `"deep-element-removed"` signals +which makes it easier for applications and higher-level plugins to track when +elements are added or removed from a complex pipeline with multiple sub-bins. + +`playbin` makes use of this to implement the new `"element-setup"` signal which +can be used to configure elements as they are added to `playbin`, just like the +existing `"source-setup"` signal which can be used to configure the source +element created. + +##### Error messages can contain additional structured details + +It is often useful to provide additional, structured information in error, +warning or info messages for applications (or higher-level elements) to make +intelligent decisions based on them. To allow this, error, warning and info +messages now have API for adding arbitrary additional information to them +using a `GstStructure`: +[`GST_ELEMENT_ERROR_WITH_DETAILS`][element-error-with-details] and +corresponding API for the other message types. + +This is now used e.g. by the new [`GST_ELEMENT_FLOW_ERROR`][element-flow-error] +API to include the actual flow error in the error message, and the +[souphttpsrc element][souphttpsrc-detailed-errors] to provide the HTTP +status code, and the URL (if any) to which a redirection has happened. + +[element-error-with-details]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#GST-ELEMENT-ERROR-WITH-DETAILS:CAPS +[element-flow-error]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#GST-ELEMENT-FLOW-ERROR:CAPS +[souphttpsrc-detailed-errors]: https://cgit.freedesktop.org/gstreamer/gst-plugins-good/tree/ext/soup/gstsouphttpsrc.c?id=60d30db912a1aedd743e66b9dcd2e21d71fbb24f#n1318 + +##### Redirect messages have official API now + +Sometimes, elements need to redirect the current stream URL and tell the +application to proceed with this new URL, possibly using a different +protocol too (thus changing the pipeline configuration). Until now, this was +informally implemented using `ELEMENT` messages on the bus. + +Now this has been formalized in the form of a new `GST_MESSAGE_REDIRECT` message. +A new redirect message can be created using [`gst_message_new_redirect()`][new-redirect]. +If needed, multiple redirect locations can be specified by calling +[`gst_message_add_redirect_entry()`][add-redirect] to add further redirect +entries, all with metadata, so the application can decide which is +most suitable (e.g. depending on the bitrate tags). + +[new-redirect]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-new-redirect +[add-redirect]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-add-redirect-entry + +##### New pad linking convenience functions that automatically create ghost pads + +New pad linking convenience functions were added: +[`gst_pad_link_maybe_ghosting()`][pad-maybe-ghost] and +[`gst_pad_link_maybe_ghosting_full()`][pad-maybe-ghost-full] which were +previously internal to GStreamer have now been exposed for general use. + +The existing pad link functions will refuse to link pads or elements at +different levels in the pipeline hierarchy, requiring the developer to +create ghost pads where necessary. These new utility functions will +automatically create ghostpads as needed when linking pads at different +levels of the hierarchy (e.g. from an element inside a bin to one that's at +the same level in the hierarchy as the bin, or in another bin). + +[pad-maybe-ghost]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-link-maybe-ghosting +[pad-maybe-ghost-full]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-link-maybe-ghosting-full + +##### Miscellaneous + +Pad probes: IDLE and BLOCK probes now work slightly differently in pull mode, +so that push and pull mode have opposite scenarios for idle and blocking probes. +In push mode, it will block with some data type and IDLE won't have any data. +In pull mode, it will block _before_ getting a buffer and will be IDLE once some +data has been obtained. ([commit][commit-pad-probes], [bug][bug-pad-probes]) + +[commit-pad-probes]: https://cgit.freedesktop.org/gstreamer/gstreamer/commit/gst/gstpad.c?id=368ee8a336d0c868d81fdace54b24431a8b48cbf +[bug-pad-probes]: https://bugzilla.gnome.org/show_bug.cgi?id=761211 + +[`gst_parse_launch_full()`][parse-launch-full] can now be made to return a +`GstBin` instead of a top-level pipeline by passing the new +`GST_PARSE_FLAG_PLACE_IN_BIN` flag. + +[parse-launch-full]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstParse.html#gst-parse-launch-full + +The default GStreamer debug log handler can now be removed before +calling `gst_init()`, so that it will never get installed and won't be active +during initialization. + +A new [`STREAM_GROUP_DONE` event][stream-group-done-event] was added. In some +ways it works similar to the `EOS` event in that it can be used to unblock +downstream elements which may be waiting for further data, such as for example +`input-selector`. Unlike `EOS`, further data flow may happen after the +`STREAM_GROUP_DONE` event though (and without the need to flush the pipeline). +This is used to unblock input-selector when switching between streams in +adaptive streaming scenarios (e.g. HLS). + +[stream-group-done-event]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-new-stream-group-done + +The `gst-launch-1.0` command line tool will now print unescaped caps in verbose +mode (enabled by the -v switch). + +[`gst_element_call_async()`][call-async] has been added as convenience API for +plugin developers. It is useful for one-shot operations that need to be done +from a thread other than the current streaming thread. It is backed by a +thread-pool that is shared by all elements. + +[call-async]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-call-async + +Various race conditions have been fixed around the `GstPoll` API used by e.g. +`GstBus` and `GstBufferPool`. Some of these manifested themselves primarily +on Windows. + +`GstAdapter` can now keep track of discontinuities signalled via the `DISCONT` +buffer flag, and has gained [new API][new-adapter-api] to track PTS, DTS and +offset at the last discont. This is useful for plugins implementing advanced +trick mode scenarios. + +[new-adapter-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstAdapter.html#gst-adapter-pts-at-discont + +`GstTestClock` gained a new [`"clock-type"` property][clock-type-prop]. + +[clock-type-prop]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstTestClock.html#GstTestClock--clock-type + +#### GstStream API for stream announcement and stream selection + +New stream listing and stream selection API: new API has been added to +provide high-level abstractions for streams ([`GstStream`][stream-api]) +and collections of streams ([`GstStreamCollections`][stream-collection-api]). + +##### Stream listing + +A [`GstStream`][stream-api] contains all the information pertinent to a stream, +such as stream id, caps, tags, flags and stream type(s); it can represent a +single elementary stream (e.g. audio, video, subtitles, etc.) or a container +stream. This will depend on the context. In a decodebin3/playbin3 one +it will typically be elementary streams that can be selected and unselected. + +A [`GstStreamCollection`][stream-collection-api] represents a group of streams +and is used to announce or publish all available streams. A GstStreamCollection +is immutable - once created it won't change. If the available streams change, +e.g. because a new stream appeared or some streams disappeared, a new stream +collection will be published. This new stream collection may contain streams +from the previous collection if those streams persist, or completely new ones. +Stream collections do not yet list all theoretically available streams, +e.g. other available DVD angles or alternative resolutions/bitrate of the same +stream in case of adaptive streaming. + +New events and messages have been added to notify or update other elements and +the application about which streams are currently available and/or selected. +This way, we can easily and seamlessly let the application know whenever the +available streams change, as happens frequently with digital television streams +for example. The new system is also more flexible. For example, it is now also +possible for the application to select multiple streams of the same type +(e.g. in a transcoding/transmuxing scenario). + +A [`STREAM_COLLECTION` message][stream-collection-msg] is posted on the bus +to inform the parent bin (e.g. `playbin3`, `decodebin3`) and/or the application +about what streams are available, so you no longer have to hunt for this +information at different places. The available information includes number of +streams of each type, caps, tags etc. Bins and/or the application can intercept +the message synchronously to select and deselect streams before any data is +produced - for the case where elements such as the demuxers support the new +stream API, not necessarily in the parsebin compatibility fallback case. + +Similarly, there is also a [`STREAM_COLLECTION` event][stream-collection-event] +to inform downstream elements of the available streams. This event can be used +by elements to aggregate streams from multiple inputs into one single collection. + +The `STREAM_START` event was extended so that it can also contain a GstStream +object with all information about the current stream, see +[`gst_event_set_stream()`][event-set-stream] and +[`gst_event_parse_stream()`][event-parse-stream]. +[`gst_pad_get_stream()`][pad-get-stream] is a new utility function that can be +used to look up the GstStream from the `STREAM_START` sticky event on a pad. + +[stream-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstStream.html +[stream-collection-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstStreamCollection.html +[stream-collection-msg]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-new-stream-collection +[stream-collection-event]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-new-stream-collection +[event-set-stream]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-set-stream +[event-parse-stream]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-parse-stream +[pad-get-stream]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-get-stream + +##### Stream selection + +Once the available streams have been published, streams can be selected via +their stream ID using the new `SELECT_STREAMS` event, which can be created +with [`gst_event_new_select_streams()`][event-select-streams]. The new API +supports selecting multiple streams per stream type. In the future, we may also +implement explicit deselection of streams that will never be used, so +elements can skip these and never expose them or output data for them in the +first place. + +The application is then notified of the currently selected streams via the +new `STREAMS_SELECTED` message on the pipeline bus, containing both the current +stream collection as well as the selected streams. This might be posted in +response to the application sending a `SELECT_STREAMS` event or when +`decodebin3` or `playbin3` decide on the streams to be initially selected without +application input. + +[event-select-streams]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-new-select-streams + +##### Further reading + +See further below for some notes on the new elements supporting this new +stream API, namely: `decodebin3`, `playbin3` and `parsebin`. + +More information about the new API and the new elements can also be found here: + +- GStreamer [stream selection design docs][streams-design] +- Edward Hervey's talk ["The new streams API: Design and usage"][streams-talk] ([slides][streams-slides]) +- Edward Hervey's talk ["Decodebin3: Dealing with modern playback use cases"][db3-talk] ([slides][db3-slides]) + +[streams-design]: https://cgit.freedesktop.org/gstreamer/gstreamer/tree/docs/design/part-stream-selection.txt +[streams-talk]: https://gstconf.ubicast.tv/videos/the-new-gststream-api-design-and-usage/ +[streams-slides]: https://gstreamer.freedesktop.org/data/events/gstreamer-conference/2016/Edward%20Hervey%20-%20The%20New%20Streams%20API%20Design%20and%20Usage.pdf +[db3-talk]: https://gstconf.ubicast.tv/videos/decodebin3-or-dealing-with-modern-playback-use-cases/ +[db3-slides]: https://gstreamer.freedesktop.org/data/events/gstreamer-conference/2015/Edward%20Hervey%20-%20decodebin3.pdf + +#### Audio conversion and resampling API + +The audio conversion library received a completely new and rewritten audio +resampler, complementing the audio conversion routines moved into the audio +library in the [previous release][release-notes-1.8]. Integrating the resampler +with the other audio conversion library allows us to implement generic +conversion much more efficiently, as format conversion and resampling can now +be done in the same processing loop instead of having to do it in separate +steps (our element implementations do not make use of this yet though). + +The new audio resampler library is a combination of some of the best features +of other samplers such as ffmpeg, speex and SRC. It natively supports S16, S32, +F32 and F64 formats and uses optimized x86 and neon assembly for most of its +processing. It also has support for dynamically changing sample rates by incrementally +updating the filter tables using linear or cubic interpolation. According to +some benchmarks, it's one of the fastest and most accurate resamplers around. + +The `audioresample` plugin has been ported to the new audio library functions +to make use of the new resampler. + +[release-notes-1.8]: https://gstreamer.freedesktop.org/releases/1.8/ + +#### Support for SMPTE timecodes + +Support for SMPTE timecodes was added to the GStreamer video library. This +comes with an abstraction for timecodes, [`GstVideoTimeCode`][video-timecode] +and a [`GstMeta`][video-timecode-meta] that can be placed on video buffers for +carrying the timecode information for each frame. Additionally there is +various API for making handling of timecodes easy and to do various +calculations with them. + +A new plugin called [`timecode`][timecode-plugin] was added, that contains an +element called `timecodestamper` for putting the timecode meta on video frames +based on counting the frames and another element called `timecodewait` that +drops all video (and audio) until a specific timecode is reached. + +Additionally support was added to the Decklink plugin for including the +timecode information when sending video out or capturing it via SDI, the +`qtmux` element is able to write timecode information into the MOV container, +and the `timeoverlay` element can overlay timecodes on top of the video. + +More information can be found in the [talk about timecodes][timecode-talk] at +the GStreamer Conference 2016. + +[video-timecode]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#GstVideoTimeCode +[video-timecode-meta]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideometa.html#gst-buffer-add-video-time-code-meta +[timecode-plugin]: https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/gst/timecode +[timecode-talk]: https://gstconf.ubicast.tv/videos/smpte-timecodes-in-gstreamer/ + +#### GStreamer OpenMAX IL plugin + +The last gst-omx release, 1.2.0, was in July 2014. It was about time to get +a new one out with all the improvements that have happened in the meantime. +From now on, we will try to release gst-omx together with all other modules. + +This release features a lot of bugfixes, improved support for the Raspberry Pi +and in general improved support for zerocopy rendering via EGL and a few minor +new features. + +At this point, gst-omx is known to work best on the Raspberry Pi platform but +it is also known to work on various other platforms. Unfortunately, we are +not including configurations for any other platforms, so if you happen to use +gst-omx: please send us patches with your configuration and code changes! + +### New Elements + +#### decodebin3, playbin3, parsebin (experimental) + +This release features new decoding and playback elements as experimental +technology previews: `decodebin3` and `playbin3` will soon supersede the +existing `decodebin` and `playbin` elements. We skipped the number 2 because +it was already used back in the 0.10 days, which might cause confusion. +Experimental technology preview means that everything should work fine already, +but we can't guarantee there won't be minor behavioural changes in the +next cycle. In any case, please test and report any problems back. + +Before we go into detail about what these new elements improve, let's look at +the new [`parsebin`][parsebin] element. It works similarly to `decodebin` and +`decodebin3`, only that it stops one step short and does not plug any actual +decoder elements. It will only plug parsers, tag readers, demuxers and +depayloaders. Also note that parsebin does not contain any queueing element. + +[`decodebin3`'s][decodebin3] internal architecture is slightly different from +the existing `decodebin` element and fixes many long-standing issues with our +decoding engine. For one, data is now fed into the internal `multiqueue` element +*after* it has been parsed and timestamped, which means that the `multiqueue` +element now has more knowledge and is able to calculate the interleaving of the +various streams, thus minimizing memory requirements and doing away with magic +values for buffering limits that were conceived when videos were 240p or 360p. +Anyone who has tried to play back 4k video streams with decodebin2 +will have noticed the limitations of that approach. The improved timestamp +tracking also enables `multiqueue` to keep streams of the same type (audio, +video) aligned better, making sure switching between streams of the same type +is very fast. + +Another major improvement in `decodebin3` is that it will no longer decode +streams that are not being used. With the old `decodebin` and `playbin`, when +there were 8 audio streams we would always decode all 8 streams even +if 7 were not actually used. This caused a lot of CPU overhead, which was +particularly problematic on embedded devices. When switching between streams +`decodebin3` will try hard to re-use existing decoders. This is useful when +switching between multiple streams of the same type if they are encoded in the +same format. + +Re-using decoders is also useful when the available streams change on the fly, +as might happen with radio streams (chained Oggs), digital television +broadcasts, when adaptive streaming streams change bitrate, or when switching +gaplessly to the next title. In order to guarantee a seamless transition, the +old `decodebin2` would plug a second decoder for the new stream while finishing +up the old stream. With `decodebin3`, this is no longer needed - at least not +when the new and old format are the same. This will be particularly useful +on embedded systems where it is often not possible to run multiple decoders +at the same time, or when tearing down and setting up decoders is fairly +expensive. + +`decodebin3` also allows for multiple input streams, not just a single one. +This will be useful, in the future, for gapless playback, or for feeding +multiple external subtitle streams to decodebin/playbin. + +`playbin3` uses `decodebin3` internally, and will supercede `playbin`. +It was decided that it would be too risky to make the old `playbin` use the +new `decodebin3` in a backwards-compatible way. The new architecture +makes it awkward, if not impossible, to maintain perfect backwards compatibility +in some aspects, hence `playbin3` was born, and developers can migrate to the +new element and new API at their own pace. + +All of these new elements make use of the new `GstStream` API for listing and +selecting streams, as described above. `parsebin` provides backwards +compatibility for demuxers and parsers which do not advertise their streams +using the new API yet (which is most). + +The new elements are not entirely feature-complete yet: `playbin3` does not +support so-called decodersinks yet where the data is not decoded inside +GStreamer but passed directly for decoding to the sink. `decodebin3` is missing +the various `autoplug-*` signals to influence which decoders get autoplugged +in which order. We're looking to add back this functionality, but it will probably +be in a different way, with a single unified signal and using GstStream perhaps. + +For more information on these new elements, check out Edward Hervey's talk +[*decodebin3 - dealing with modern playback use cases*][db3-talk] + +[parsebin]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-parsebin.html +[decodebin3]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-decodebin3.html +[db3-talk]: https://gstconf.ubicast.tv/videos/decodebin3-or-dealing-with-modern-playback-use-cases/ + +#### LV2 ported from 0.10 and switched from slv2 to lilv2 + +The LV2 wrapper plugin has been ported to 1.0 and moved from using the +deprecated slv2 library to its replacement liblv2. We support sources and +filter elements. lv2 is short for *Linux Audio Developer's Simple Plugin API +(LADSPA) version 2* and is an open standard for audio plugins which includes +support for audio synthesis (generation), digital signal processing of digital +audio, and MIDI. The new lv2 plugin supersedes the existing LADSPA plugin. + +#### WebRTC DSP Plugin for echo-cancellation, gain control and noise suppression + +A set of new elements ([webrtcdsp][webrtcdsp], [webrtcechoprobe][webrtcechoprobe]) +based on the WebRTC DSP software stack can now be used to improve your audio +voice communication pipelines. They support echo cancellation, gain control, +noise suppression and more. For more details you may read +[Nicolas' blog post][webrtc-blog-post]. + +[webrtcdsp]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-webrtcdsp.html +[webrtcechoprobe]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-webrtcechoprobe.html +[webrtc-blog-post]: https://ndufresne.ca/2016/06/gstreamer-echo-canceller/ + +#### Fraunhofer FDK AAC encoder and decoder + +New encoder and decoder elements wrapping the Fraunhofer FDK AAC library have +been added (`fdkaacdec`, `fdkaacdec`). The Fraunhofer FDK AAC encoder is +generally considered to be a very high-quality AAC encoder, but unfortunately +it comes under a non-free license with the option to obtain a paid, commercial +license. + +### Noteworthy element features and additions + +#### Major RTP and RTSP improvements + +- The RTSP server and source element, as well as the RTP jitterbuffer now support + remote clock synchronization according to [RFC7273][https://tools.ietf.org/html/rfc7273]. +- Support for application and profile specific RTCP packets was added. +- The H265/HEVC payloader/depayloader is again in sync with the final RFC. +- Seeking stability of the RTSP source and server was improved a lot and + runs stably now, even when doing scrub-seeking. +- The RTSP server received various major bugfixes, including for regressions that + caused the IP/port address pool to not be considered, or NAT hole punching + to not work anymore. [Bugzilla #766612][https://bugzilla.gnome.org/show_bug.cgi?id=766612] +- Various other bugfixes that improve the stability of RTP and RTSP, including + many new unit / integration tests. + +#### Improvements to splitmuxsrc and splitmuxsink + +- The splitmux element received reliability and error handling improvements, + removing at least one deadlock case. `splitmuxsrc` now stops cleanly at the end + of the segment when handling seeks with a stop time. We fixed a bug with large + amounts of downstream buffering causing incorrect out-of-sequence playback. + +- `splitmuxsrc` now has a `"format-location"` signal to directly specify the list + of files to play from. + +- `splitmuxsink` can now optionally send force-keyunit events to upstream + elements to allow splitting files more accurately instead of having to wait + for upstream to provide a new keyframe by itself. + +#### OpenGL/GLES improvements + +##### iOS and macOS (OS/X) + +- We now create OpenGL|ES 3.x contexts on iOS by default with a fallback to + OpenGL|ES 2.x if that fails. +- Various zerocopy decoding fixes and enhancements with the + encoding/decoding/capturing elements. +- libdispatch is now used on all Apple platforms instead of GMainLoop, removing + the expensive poll()/pthread_*() overhead. + +##### New API + +- `GstGLFramebuffer` - for wrapping OpenGL frame buffer objects. It provides + facilities for attaching `GstGLMemory` objects to the necessary attachment + points, binding and unbinding and running a user-supplied function with the + framebuffer bound. +- `GstGLRenderbuffer` (a `GstGLBaseMemory` subclass) - for wrapping OpenGL + render buffer objects that are typically used for depth/stencil buffers or + for color buffers where we don't care about the output. +- `GstGLMemoryEGL` (a `GstGLMemory` subclass) - for combining `EGLImage`s with a GL + texture that replaces `GstEGLImageMemory` bringing the improvements made to the + other `GstGLMemory` implementations. This fixes a performance regression in + zerocopy decoding on the Raspberry Pi when used with an updated gst-omx. + +##### Miscellaneous improvements + +- `gltestsrc` is now usable on devices/platforms with OpenGL 3.x and OpenGL|ES + and has completed or gained support for new patterns in line with the + existing ones in `videotestsrc`. +- `gldeinterlace` is now available on devices/platforms with OpenGL|ES + implementations. +- The dispmanx backend (used on the Raspberry Pi) now supports the + `gst_video_overlay_set_window_handle()` and + `gst_video_overlay_set_render_rectangle()` functions. +- The `gltransformation` element now correctly transforms mouse coordinates (in + window space) to stream coordinates for both perspective and orthographic + projections. +- The `gltransformation` element now detects if the + `GstVideoAffineTransformationMeta` is supported downstream and will efficiently + pass its transformation downstream. This is a performance improvement as it + results in less processing being required. +- The wayland implementation now uses the multi-threaded safe event-loop API + allowing correct usage in applications that call wayland functions from + multiple threads. +- Support for native 90 degree rotations and horizontal/vertical flips + in `glimagesink`. + +#### Vulkan + +- The Vulkan elements now work under Wayland and have received numerous + bugfixes. + +#### QML elements + +- `qmlglsink` video sink now works on more platforms, notably, Windows, Wayland, + and Qt's eglfs (for embedded devices with an OpenGL implementation) including + the Raspberry Pi. +- New element `qmlglsrc` to record a QML scene into a GStreamer pipeline. + +#### KMS video sink + +- New element `kmssink` to render video using Direct Rendering Manager + (DRM) and Kernel Mode Setting (KMS) subsystems in the Linux + kernel. It is oriented to be used mostly in embedded systems. + +#### Wayland video sink + +- `waylandsink` now supports the wl_viewporter extension allowing + video scaling and cropping to be delegated to the Wayland + compositor. This extension is also been made optional, so that it can + also work on current compositors that don't support it. It also now has + support for the video meta, allowing zero-copy operations in more + cases. + +#### DVB improvements + +- `dvbsrc` now has better delivery-system autodetection and several + new parameter sanity-checks to improve its resilience to configuration + omissions and errors. Superfluous polling continues to be trimmed down, + and the debugging output has been made more consistent and precise. + Additionally, the channel-configuration parser now supports the new dvbv5 + format, enabling `dvbbasebin` to automatically playback content transmitted + on delivery systems that previously required manual description, like ISDB-T. + +#### DASH, HLS and adaptivedemux + +- HLS now has support for Alternate Rendition audio and video tracks. Full + support for Alternate Rendition subtitle tracks will be in an upcoming release. +- DASH received support for keyframe-only trick modes if the + `GST_SEEK_FLAG_TRICKMODE_KEY_UNITS` flag is given when seeking. It will + only download keyframes then, which should help with high-speed playback. + Changes to skip over multiple frames based on bandwidth and other metrics + will be added in the near future. +- Lots of reliability fixes around seek handling and bitrate switching. + +#### Bluetooth improvements + +- The `avdtpsrc` element now supports metadata such as track title, artist + name, and more, which devices can send via AVRCP. These are published as + tags on the pipeline. +- The `a2dpsink` element received some love and was cleaned up so that it + actually works after the initial GStreamer 1.0 port. + +#### GStreamer VAAPI + +- All the decoders have been split, one plugin feature per codec. So + far, the available ones, depending on the driver, are: + `vaapimpeg2dec`, `vaapih264dec`, `vaapih265dec`, `vaapivc1dec`, `vaapivp8dec`, + `vaapivp9dec` and `vaapijpegdec` (which already was split). +- Improvements when mapping VA surfaces into memory. It now differentiates + between negotiation caps and allocations caps, since the allocation + memory for surfaces may be bigger than one that is going to be + mapped. +- `vaapih265enc` now supports constant bitrate mode (CBR). +- Since several VA drivers are unmaintained, we decide to keep a whitelist + with the va drivers we actually test, which is mostly the i915 and to a lesser + degree gallium from the mesa project. Exporting the environment variable + `GST_VAAPI_ALL_DRIVERS` disables the whitelist. +- Plugin features are registered at run-time, according to their support by + the loaded VA driver. So only the decoders and encoder supported by the + system are registered. Since the driver can change, some dependencies are + tracked to invalidate the GStreamer registry and reload the plugin. +- `dmabuf` importation from upstream has been improved, gaining performance. +- `vaapipostproc` now can negotiate buffer transformations via caps. +- Decoders now can do I-frame only reverse playback. This decodes I-frames + only because the surface pool is smaller than the required by the GOP to show all the + frames. +- The upload of frames onto native GL textures has been optimized too, keeping + a cache of the internal structures for the offered textures by the sink. + +#### V4L2 changes + +- More pixels formats are now supported +- Decoder is now using `G_SELECTION` instead of the deprecated `G_CROP` +- Decoder now uses the `STOP` command to handle EOS +- Transform element can now scale the pixel aspect ratio +- Colorimetry support has been improved even more +- We now support the `OUTPUT_OVERLAY` type of video node in v4l2sink + +#### Miscellaneous + +- `multiqueue`'s input pads gained a new `"group-id"` property which + can be used to group input streams. Typically one will assign + different id numbers to audio, video and subtitle streams for + example. This way `multiqueue` can make sure streams of the same + type advance in lockstep if some of the streams are unlinked and the + `"sync-by-running-time"` property is set. This is used in + decodebin3/playbin3 to implement almost-instantaneous stream + switching. The grouping is required because different downstream + paths (audio, video, etc.) may have different buffering/latency + etc. so might be consuming data from multiqueue with a slightly + different phase, and if we track different stream groups separately + we minimize stream switching delays and buffering inside the + `multiqueue`. +- `alsasrc` now supports ALSA drivers without a position for each + channel, this is common in some professional or industrial hardware. +- `libvpx` based decoders (`vp8dec` and `vp9dec`) now create multiple threads on + computers with multiple CPUs automatically. +- `rfbsrc` - used for capturing from a VNC server - has seen a lot of + debugging. It now supports the latest version of the RFB + protocol and uses GIO everywhere. +- `tsdemux` can now read ATSC E-AC-3 streams. +- New `GstVideoDirection` video orientation interface for rotating, flipping + and mirroring video in 90° steps. It is implemented by the `videoflip` and + `glvideoflip` elements currently. +- It is now possible to give `appsrc` a duration in time, and there is now a + non-blocking try-pull API for `appsink` that returns NULL if nothing is + available right now. +- `x264enc` has support now for chroma-site and colorimetry settings +- A new JPEG2000 parser element was added, and the JPEG2000 caps were cleaned + up and gained more information needed in combination with RTP and various + container formats. +- Reverse playback support for `videorate` and `deinterlace` was implemented +- Various improvements everywhere for reverse playback and `KEY_UNITS` trick mode +- New cleaned up `rawaudioparse` and `rawvideoparse` elements that replace the + old `audioparse` and `videoparse` elements. There are compatibility element + factories registered with the old names to allow existing code to continue + to work. +- The Decklink plugin gained support for 10 bit video SMPTE timecodes, and + generally got many bugfixes for various issues. +- New API in `GstPlayer` for setting the multiview mode for stereoscopic + video, setting an HTTP/RTSP user agent and a time offset between audio and + video. In addition to that, there were various bugfixes and the new + gst-examples module contains Android, iOS, GTK+ and Qt example applications. +- `GstBin` has new API for suppressing various `GstElement` or `GstObject` + flags that would otherwise be affected by added/removed child elements. This + new API allows `GstBin` subclasses to handle for themselves if they + should be considered a sink or source element, for example. +- The `subparse` element can handle WebVTT streams now. +- A new `sdpsrc` element was added that can read an SDP from a file, or get it + as a string as property and then sets up an RTP pipeline accordingly. + +### Plugin moves + +No plugins were moved this cycle. We'll make up for it next cycle, promise! + +### Rewritten memory leak tracer + +GStreamer has had basic functionality to trace allocation and freeing of +both mini-objects (buffers, events, caps, etc.) and objects in the form of the +internal `GstAllocTrace` tracing system. This API was never exposed in the +1.x API series though. When requested, this would dump a list of objects and +mini-objects at exit time which had still not been freed at that point, +enabled with an environment variable. This subsystem has now been removed +in favour of a new implementation based on the recently-added tracing framework. + +Tracing hooks have been added to trace the creation and destruction of +GstObjects and mini-objects, and a new tracer plugin has been written using +those new hooks to track which objects are still live and which are not. If +GStreamer has been compiled against the libunwind library, the new leaks tracer +will remember where objects were allocated from as well. By default the leaks +tracer will simply output a warning if leaks have been detected on `gst_deinit()`. + +If the `GST_LEAKS_TRACER_SIG` environment variable is set, the leaks tracer +will also handle the following UNIX signals: + + - `SIGUSR1`: log alive objects + - `SIGUSR2`: create a checkpoint and print a list of objects created and + destroyed since the previous checkpoint. + +Unfortunately this will not work on Windows due to no signals, however. + +If the `GST_LEAKS_TRACER_STACK_TRACE` environment variable is set, the leaks +tracer will also log the creation stack trace of leaked objects. This may +significantly increase memory consumption however. + +New `MAY_BE_LEAKED` flags have been added to GstObject and GstMiniObject, so +that objects and mini-objects that are likely to stay around forever can be +flagged and blacklisted from the leak output. + +To give the new leak tracer a spin, simply call any GStreamer application such +as `gst-launch-1.0` or `gst-play-1.0` like this: + + GST_TRACERS=leaks gst-launch-1.0 videotestsrc num-buffers=10 ! fakesink + +If there are any leaks, a warning will be raised at the end. + +It is also possible to trace only certain types of objects or mini-objects: + + GST_TRACERS="leaks(GstEvent,GstMessage)" gst-launch-1.0 videotestsrc num-buffers=10 ! fakesink + +This dedicated leaks tracer is much much faster than valgrind since all code is +executed natively instead of being instrumented. This makes it very suitable +for use on slow machines or embedded devices. It is however limited to certain +types of leaks and won't catch memory leaks when the allocation has been made +via plain old `malloc()` or `g_malloc()` or other means. It will also not trace +non-GstObject GObjects. + +The goal is to enable leak tracing on GStreamer's Continuous-Integration and +testing system, both for the regular unit tests (make check) and media tests +(gst-validate), so that accidental leaks in common code paths can be detected +and fixed quickly. + +For more information about the new tracer, check out Guillaume Desmottes's +["Tracking Memory Leaks"][leaks-talk] talk or his [blog post][leaks-blog] about +the topic. + +[leaks-talk]: https://gstconf.ubicast.tv/videos/tracking-memory-leaks/ +[leaks-blog]: https://blog.desmottes.be/?post/2016/06/20/GStreamer-leaks-tracer + +### GES and NLE changes + +- Clip priorities are now handled by the layers, and the GESTimelineElement + priority property is now deprecated and unused +- Enhanced (de)interlacing support to always use the `deinterlace` element + and expose needed properties to users +- Allow reusing clips children after removing the clip from a layer +- We are now testing many more rendering formats in the gst-validate + test suite, and failures have been fixed. +- Also many bugs have been fixed in this cycle! + +### GStreamer validate changes + +This cycle has been focused on making GstValidate more than just a validating +tool, but also a tool to help developers debug their GStreamer issues. When +reporting issues, we try to gather as much information as possible and expose +it to end users in a useful way. For an example of such enhancements, check out +Thibault Saunier's [blog post](improving-debugging-gstreamer-validate) about +the new Not Negotiated Error reporting mechanism. + +Playbin3 support has been added so we can run validate tests with `playbin3` +instead of playbin. + +We are now able to properly communicate between `gst-validate-launcher` and +launched subprocesses with actual IPC between them. That has enabled the test +launcher to handle failing tests specifying the exact expected issue(s). + +[improving-debugging-gstreamer-validate]: https://blogs.s-osg.org/improving-debugging-gstreamer-validate/ + +### gst-libav changes + +gst-libav uses the recently released ffmpeg 3.2 now, which brings a lot of +improvements and bugfixes from the ffmpeg team in addition to various new +codec mappings on the GStreamer side and quite a few bugfixes to the GStreamer +integration to make it more robust. + +## Build and Dependencies + +### Experimental support for Meson as build system + +#### Overview + +We have have added support for building GStreamer using the +[Meson build system][meson]. This is currently experimental, but should work +fine at least on Linux using the gcc or clang toolchains and on Windows using +the MingW or MSVC toolchains. + +Autotools remains the primary build system for the time being, but we hope to +someday replace it and will steadily work towards that goal. + +More information about the background and implications of all this and where +we're hoping to go in future with this can be found in [Tim's mail][meson-mail] +to the gstreamer-devel mailing list. + +For more information on Meson check out [these videos][meson-videos] and also +the [Meson talk][meson-gstconf] at the GStreamer Conference. + +Immediate benefits for Linux users are faster builds and rebuilds. At the time +of writing the Meson build of GStreamer is used by default in GNOME's jhbuild +system. + +The Meson build currently still lacks many of the fine-grained configuration +options to enable/disable specific plugins. These will be added back in due +course. + +Note: The meson build files are not distributed in the source tarballs, you will +need to get GStreamer from git if you want try it out. + +[meson]: http://mesonbuild.com/ +[meson-mail]: https://lists.freedesktop.org/archives/gstreamer-devel/2016-September/060231.html +[meson-videos]: http://mesonbuild.com/videos.html +[meson-gstconf]: https://gstconf.ubicast.tv/videos/gstreamer-development-on-windows-ans-faster-builds-everywhere-with-meson/ + +#### Windows Visual Studio toolchain support + +Windows users might appreciate being able to build GStreamer using the MSVC +toolchain, which is not possible using autotools. This means that it will be +possible to debug GStreamer and applications in Visual Studio, for example. +We require VS2015 or newer for this at the moment. + +There are two ways to build GStreamer using the MSVC toolchain: + +1. Using the MSVC command-line tools (`cl.exe` etc.) via Meson's "ninja" backend. +2. Letting Meson's "vs2015" backend generate Visual Studio project files that + can be opened in Visual Studio and compiled from there. + +This is currently only for adventurous souls though. All the bits are in place, +but support for all of this has not been merged into GStreamer's cerbero build +tool yet at the time of writing. This will hopefully happen in the next cycle, +but for now this means that those wishing to compile GStreamer with MSVC will +have to get their hands dirty. + +There are also no binary SDK builds using the MSVC toolchain yet. + +For more information on GStreamer builds using Meson and the Windows toolchain +check out Nirbheek Chauhan's blog post ["Building and developing GStreamer using Visual Studio"][msvc-blog]. + +[msvc-blog]: http://blog.nirbheek.in/2016/07/building-and-developing-gstreamer-using.html + +### Dependencies + +#### gstreamer + +libunwind was added as an optional dependency. It is used only for debugging +and tracing purposes. + +The `opencv` plugin in gst-plugins-bad can now be built against OpenCV +version 3.1, previously only 2.3-2.5 were supported. + +#### gst-plugins-ugly + +- `mpeg2dec` now requires at least libmpeg2 0.5.1 (from 2008). + +#### gst-plugins-bad + +- `gltransformation` now requires at least graphene 1.4.0. + +- `lv2` now plugin requires at least lilv 0.16 instead of slv2. + +### Packaging notes + +Packagers please note that the `gst/gstconfig.h` public header file in the +GStreamer core library moved back from being an architecture dependent include +to being architecture independent, and thus it is no longer installed into +`$(libdir)/gstreamer-1.0/include/gst` but into the normal include directory +where it lives happily ever after with all the other public header files. The +reason for this is that we now check whether the target supports unaligned +memory access based on predefined compiler macros at compile time instead of +checking it at configure time. + +## Platform-specific improvements + +### Android + +#### New universal binaries for all supported ABIs + +We now provide a "universal" tarball to allow building apps against all the +architectures currently supported (x86, x86-64, armeabi, armeabi-v7a, +armeabi-v8a). This is needed for building with recent versions of the Android +NDK which defaults to building against all supported ABIs. Use [the Android +player example][android-player-example-build] as a reference for the required +changes. + +[android-player-example-build]: https://cgit.freedesktop.org/gstreamer/gst-examples/commit/playback/player/android?id=a5cdde9119f038a1eb365aca20faa9741a38e788 + +#### Miscellaneous + +- New `ahssrc` element that allows reading the hardware sensors, e.g. compass + or accelerometer. + +### macOS (OS/X) and iOS + +- Support for querying available devices on OS/X via the GstDeviceProvider + API was added. +- It is now possible to create OpenGL|ES 3.x contexts on iOS and use them in + combination with the VideoToolbox based decoder element. +- many OpenGL/GLES improvements, see OpenGL section above + +### Windows + +- gstconfig.h: Always use dllexport/import on Windows with MSVC +- Miscellaneous fixes to make libs and plugins compile with the MVSC toolchain +- MSVC toolchain support (see Meson section above for more details) + +## New Modules for Documentation, Examples, Meson Build + +Three new git modules have been added recently: + +### gst-docs + +This is a new module where we will maintain documentation in the markdown +format. + +It contains the former gstreamer.com SDK tutorials which have kindly been made +available by Fluendo under a Creative Commons license. The tutorials have been +reviewed and updated for GStreamer 1.x and will be available as part of the +[official GStreamer documentation][doc] going forward. The old gstreamer.com +site will then be shut down with redirects pointing to the updated tutorials. + +Some of the existing docbook XML-formatted documentation from the GStreamer +core module such as the *Application Development Manual* and the *Plugin +Writer's Guide* have been converted to markdown as well and will be maintained +in the gst-docs module in future. They will be removed from the GStreamer core +module in the next cycle. + +This is just the beginning. Our goal is to provide a more cohesive documentation +experience for our users going forward, and easier to create and maintain +documentation for developers. There is a lot more work to do, get in touch if +you want to help out. + +If you encounter any problems or spot any omissions or outdated content in the +new documentation, please [file a bug in bugzilla][doc-bug] to let us know. + +We will probably release gst-docs as a separate tarball for distributions to +package in the next cycle. + +[doc]: http://gstreamer.freedesktop.org/documentation/ +[doc-bug]: https://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer&component=documentation + +### gst-examples + +A new [module][examples-git] has been added for examples. It does not contain +much yet, currently it only contains a small [http-launch][http-launch] utility +that serves a pipeline over http as well as various [GstPlayer playback frontends][puis] +for Android, iOS, Gtk+ and Qt. + +More examples will be added over time. The examples in this repository should +be more useful and more substantial than most of the examples we ship as part +of our other modules, and also written in a way that makes them good example +code. If you have ideas for examples, let us know. + +No decision has been made yet if this module will be released and/or packaged. +It probably makes sense to do so though. + +[examples-git]: https://cgit.freedesktop.org/gstreamer/gst-examples/tree/ +[http-launch]: https://cgit.freedesktop.org/gstreamer/gst-examples/tree/network/http-launch/ +[puis]: https://cgit.freedesktop.org/gstreamer/gst-examples/tree/playback/player + +### gst-build + +[gst-build][gst-build-git] is a new meta module to build GStreamer using the +new Meson build system. This module is not required to build GStreamer with +Meson, it is merely for convenience and aims to provide a development setup +similar to the existing `gst-uninstalled` setup. + +gst-build makes use of Meson's [subproject feature][meson-subprojects] and sets +up the various GStreamer modules as subprojects, so they can all be updated and +built in parallel. + +This module is still very new and highly experimental. It should work at least +on Linux and Windows (OS/X needs some build fixes). Let us know of any issues +you encounter by popping into the `#gstreamer` IRC channel or by +[filing a bug][gst-build-bug]. + +This module will probably not be released or packaged (does not really make sense). + +[gst-build-git]: https://cgit.freedesktop.org/gstreamer/gst-build/tree/ +[gst-build-bug]: https://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer&component=gst-build +[meson-subprojects]: https://github.com/mesonbuild/meson/wiki/Subprojects + +## Contributors + +Aaron Boxer, Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, Alex +Ashley, Alex-P. Natsios, Alistair Buxton, Allen Zhang, Andreas Naumann, Andrew +Eikum, Andy Devar, Anthony G. Basile, Arjen Veenhuizen, Arnaud Vrac, Artem +Martynovich, Arun Raghavan, Aurélien Zanelli, Barun Kumar Singh, Bernhard +Miller, Brad Lackey, Branko Subasic, Carlos Garcia Campos, Carlos Rafael +Giani, Christoffer Stengren, Daiki Ueno, Damian Ziobro, Danilo Cesar Lemes de +Paula, David Buchmann, Dimitrios Katsaros, Duncan Palmer, Edward Hervey, +Emmanuel Poitier, Enrico Jorns, Enrique Ocaña González, Fabrice Bellet, +Florian Zwoch, Florin Apostol, Francisco Velazquez, Frédéric Bertolus, Fredrik +Fornwall, Gaurav Gupta, George Kiagiadakis, Georg Lippitsch, Göran Jönsson, +Graham Leggett, Gregoire Gentil, Guillaume Desmottes, Gwang Yoon Hwang, Haakon +Sporsheim, Haihua Hu, Havard Graff, Heinrich Fink, Hoonhee Lee, Hyunjun Ko, +Iain Lane, Ian, Ian Jamison, Jagyum Koo, Jake Foytik, Jakub Adam, Jan +Alexander Steffens (heftig), Jan Schmidt, Javier Martinez Canillas, Jerome +Laheurte, Jesper Larsen, Jie Jiang, Jihae Yi, Jimmy Ohn, Jinwoo Ahn, Joakim +Johansson, Joan Pau Beltran, Jonas Holmberg, Jonathan Matthew, Jonathan Roy, +Josep Torra, Julien Isorce, Jun Ji, Jürgen Slowack, Justin Kim, Kazunori +Kobayashi, Kieran Bingham, Kipp Cannon, Koop Mast, Kouhei Sutou, Kseniia, Kyle +Schwarz, Kyungyong Kim, Linus Svensson, Luis de Bethencourt, Marcin Kolny, +Marcin Lewandowski, Marianna Smidth Buschle, Mario Sanchez Prada, Mark +Combellack, Mark Nauwelaerts, Martin Kelly, Matej Knopp, Mathieu Duponchelle, +Mats Lindestam, Matthew Gruenke, Matthew Waters, Michael Olbrich, Michal Lazo, +Miguel París Díaz, Mikhail Fludkov, Minjae Kim, Mohan R, Munez, Nicola Murino, +Nicolas Dufresne, Nicolas Huet, Nikita Bobkov, Nirbheek Chauhan, Olivier +Crête, Paolo Pettinato, Patricia Muscalu, Paulo Neves, Peng Liu, Peter +Seiderer, Philippe Normand, Philippe Renon, Philipp Zabel, Pierre Lamot, Piotr +Drąg, Prashant Gotarne, Raffaele Rossi, Ray Strode, Reynaldo H. Verdejo +Pinochet, Santiago Carot-Nemesio, Scott D Phillips, Sebastian Dröge, Sebastian +Rasmussen, Sergei Saveliev, Sergey Borovkov, Sergey Mamonov, Sergio Torres +Soldado, Seungha Yang, sezero, Song Bing, Sreerenj Balachandran, Stefan Sauer, +Stephen, Steven Hoving, Stian Selnes, Thiago Santos, Thibault Saunier, Thijs +Vermeir, Thomas Bluemel, Thomas Jones, Thomas Klausner, Thomas Scheuermann, +Tim-Philipp Müller, Ting-Wei Lan, Tom Schoonjans, Ursula Maplehurst, Vanessa +Chipirras Navalon, Víctor Manuel Jáquez Leal, Vincent Penquerc'h, Vineeth TM, +Vivia Nikolaidou, Vootele Vesterblom, Wang Xin-yu (王昕宇), William Manley, +Wim Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier Claessens, xlazom00, +Yann Jouanin, Zaheer Abbas Merali + +... and many others who have contributed bug reports, translations, sent +suggestions or helped testing. + +## Bugs fixed in 1.10 + +More than [750 bugs][bugs-fixed-in-1.10] have been fixed during +the development of 1.10. + +This list does not include issues that have been cherry-picked into the +stable 1.8 branch and fixed there as well, all fixes that ended up in the +1.8 branch are also included in 1.10. + +This list also does not include issues that have been fixed without a bug +report in bugzilla, so the actual number of fixes is much higher. + +[bugs-fixed-in-1.10]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=164074&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.8.1&target_milestone=1.8.2&target_milestone=1.8.3&target_milestone=1.8.4&target_milestone=1.9.1&target_milestone=1.9.2&target_milestone=1.9.90&target_milestone=1.10.0 + +## Stable 1.10 branch + +After the 1.10.0 release there will be several 1.10.x bug-fix releases which +will contain bug fixes which have been deemed suitable for a stable branch, +but no new features or intrusive changes will be added to a bug-fix release +usually. The 1.10.x bug-fix releases will be made from the git 1.10 branch, +which is a stable branch. + +### 1.10.0 + +1.10.0 was released on 1st November 2016. + +## Known Issues + +- iOS builds with iOS 6 SDK and old C++ STL. You need to select iOS 6 instead + of 7 or 8 in your projects settings to be able to link applications. + [Bug #766366](https://bugzilla.gnome.org/show_bug.cgi?id=766366) +- Code signing for Apple platforms has some problems currently, requiring + manual work to get your application signed. [Bug #771860](https://bugzilla.gnome.org/show_bug.cgi?id=771860) +- Building applications with Android NDK r13 on Windows does not work. Other + platforms and earlier/later versions of the NDK are not affected. + [Bug #772842](https://bugzilla.gnome.org/show_bug.cgi?id=772842) +- The new leaks tracer may deadlock the application (or exhibit other undefined + behaviour) when `SIGUSR` handling is enabled via the `GST_LEAKS_TRACER_SIG` + environment variable. [Bug #770373](https://bugzilla.gnome.org/show_bug.cgi?id=770373) +- vp8enc crashes on 32 bit Windows, but was working fine in 1.6. 64 bit Windows is unaffected. + [Bug #763663](https://bugzilla.gnome.org/show_bug.cgi?id=763663) + +## Schedule for 1.12 + +Our next major feature release will be 1.12, and 1.11 will be the unstable +development version leading up to the stable 1.12 release. The development +of 1.11/1.12 will happen in the git master branch. + +The plan for the 1.12 development cycle is yet to be confirmed, but it is +expected that feature freeze will be around early/mid-January, +followed by several 1.11 pre-releases and the new 1.12 stable release +in March. + +1.12 will be backwards-compatible to the stable 1.10, 1.8, 1.6, 1.4, 1.2 and +1.0 release series. + +- - - + +*These release notes have been prepared by Olivier Crête, Sebastian Dröge, +Nicolas Dufresne, Edward Hervey, Víctor Manuel Jáquez Leal, Tim-Philipp +Müller, Reynaldo H. Verdejo Pinochet, Arun Raghavan, Thibault Saunier, +Jan Schmidt, Wim Taymans, Matthew Waters* + +*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* + diff --git a/RELEASE b/RELEASE index 5aaba97b69..8b76e38d94 100644 --- a/RELEASE +++ b/RELEASE @@ -1,21 +1,23 @@ -Release notes for GStreamer RTSP Server Library 1.9.90 +Release notes for GStreamer RTSP Server Library 1.10.0 -The GStreamer team is pleased to announce the first release candidate of the -stable 1.10 release series. The 1.10 release series is adding new features on -top of the 1.0, 1.2, 1.4, 1.6 and 1.8 series and is part of the API and -ABI-stable 1.x release series of the GStreamer multimedia framework. +The GStreamer team is pleased to announce the first release of the new stable +1.10 release series. The 1.10 release series is adding new features on top of +the 1.0, 1.2, 1.4, 1.6 and 1.8 series and is part of the API and ABI-stable 1.x +release series of the GStreamer multimedia framework. -Binaries for Android, iOS, Mac OS X and Windows will be provided in the next days. - +Binaries for Android, iOS, Mac OS X and Windows will be provided shortly after +the source release by the GStreamer project during the stable 1.10 release +series. Bugs fixed in this release - * 750544 : RTSP server: crashes when accessing freed session in keep alive callback on shutdown - * 766612 : Does not take address pool configuration into account for sending unicast UDP + * 771983 : Deadlock when closing session and backlog is full. + * 772478 : Missing video stream from SDP + * 773640 : rtspclient unit test failures ==== Download ==== @@ -52,9 +54,8 @@ subscribe to the gstreamer-devel list. Contributors to this release - * Ian Jamison - * Jan Schmidt - * Kseniia - * Sebastian Dröge + * Göran Jönsson + * Nikita Bobkov + * Tim-Philipp Müller * Xavier Claessens   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 4a23a85bbc..4c12b25f28 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.9.90], +AC_INIT([GStreamer RTSP Server Library], [1.10.0], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 990, 0, 990) +AS_LIBTOOL(GST, 1000, 0, 1000) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.9.90 -GSTPB_REQ=1.9.90 -GSTPG_REQ=1.9.90 -GSTPD_REQ=1.9.90 +GST_REQ=1.10.0 +GSTPB_REQ=1.10.0 +GSTPG_REQ=1.10.0 +GSTPD_REQ=1.10.0 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 45f421ac5f..27bb2baaba 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.10.0 + master + + 2016-11-01 + + + + 1.9.90 From cfca152b156f0cde5c30ba122e7347214ffd7a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 1 Nov 2016 18:53:15 +0200 Subject: [PATCH 1311/1776] Back to development --- configure.ac | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 4c12b25f28..4f85610e69 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.10.0], +AC_INIT([GStreamer RTSP Server Library], [1.11.0.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1000, 0, 1000) +AS_LIBTOOL(GST, 1100, 0, 1100) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.10.0 -GSTPB_REQ=1.10.0 -GSTPG_REQ=1.10.0 -GSTPD_REQ=1.10.0 +GST_REQ=1.11.0.1 +GSTPB_REQ=1.11.0.1 +GSTPG_REQ=1.11.0.1 +GSTPD_REQ=1.11.0.1 dnl *** autotools stuff **** From 0922951c26f53af17fc96923117dc710661245f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 1 Nov 2016 18:10:35 +0000 Subject: [PATCH 1312/1776] meson: update version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a8d9f9e365..3e38eadca4 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.9.90', + version : '1.11.0.1', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 8425ea696928971333a71ebf8f76e399cf13be5c Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Wed, 24 Aug 2016 11:39:13 +0200 Subject: [PATCH 1313/1776] client: emit signal in the beginning of each rtsp request These signals let the application validate the requests, configure the media/stream in a certain way and also generate error status code in case of error or bad request. https://bugzilla.gnome.org/show_bug.cgi?id=758062 --- gst/rtsp-server/rtsp-client.c | 386 ++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-client.h | 13 +- 2 files changed, 398 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index deb2ab3403..90d624b03a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -45,6 +45,7 @@ #include #include +#include #include "rtsp-client.h" #include "rtsp-sdp.h" @@ -115,17 +116,27 @@ enum { SIGNAL_CLOSED, SIGNAL_NEW_SESSION, + SIGNAL_PRE_OPTIONS_REQUEST, SIGNAL_OPTIONS_REQUEST, + SIGNAL_PRE_DESCRIBE_REQUEST, SIGNAL_DESCRIBE_REQUEST, + SIGNAL_PRE_SETUP_REQUEST, SIGNAL_SETUP_REQUEST, + SIGNAL_PRE_PLAY_REQUEST, SIGNAL_PLAY_REQUEST, + SIGNAL_PRE_PAUSE_REQUEST, SIGNAL_PAUSE_REQUEST, + SIGNAL_PRE_TEARDOWN_REQUEST, SIGNAL_TEARDOWN_REQUEST, + SIGNAL_PRE_SET_PARAMETER_REQUEST, SIGNAL_SET_PARAMETER_REQUEST, + SIGNAL_PRE_GET_PARAMETER_REQUEST, SIGNAL_GET_PARAMETER_REQUEST, SIGNAL_HANDLE_RESPONSE, SIGNAL_SEND_MESSAGE, + SIGNAL_PRE_ANNOUNCE_REQUEST, SIGNAL_ANNOUNCE_REQUEST, + SIGNAL_PRE_RECORD_REQUEST, SIGNAL_RECORD_REQUEST, SIGNAL_CHECK_REQUIREMENTS, SIGNAL_LAST @@ -157,6 +168,10 @@ static gchar *default_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri); static void client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session, GstRTSPClient * client); +static GstRTSPStatusCode default_pre_signal_handler (GstRTSPClient * client, + GstRTSPContext * ctx); +static gboolean pre_signal_accumulator (GSignalInvocationHint * ihint, + GValue * return_accu, const GValue * handler_return, gpointer data); G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); @@ -181,6 +196,17 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) klass->params_get = default_params_get; klass->make_path_from_uri = default_make_path_from_uri; + klass->pre_options_request = default_pre_signal_handler; + klass->pre_describe_request = default_pre_signal_handler; + klass->pre_setup_request = default_pre_signal_handler; + klass->pre_play_request = default_pre_signal_handler; + klass->pre_pause_request = default_pre_signal_handler; + klass->pre_teardown_request = default_pre_signal_handler; + klass->pre_set_parameter_request = default_pre_signal_handler; + klass->pre_get_parameter_request = default_pre_signal_handler; + klass->pre_announce_request = default_pre_signal_handler; + klass->pre_record_request = default_pre_signal_handler; + g_object_class_install_property (gobject_class, PROP_SESSION_POOL, g_param_spec_object ("session-pool", "Session Pool", "The session pool to use for client session", @@ -208,48 +234,184 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) G_STRUCT_OFFSET (GstRTSPClientClass, new_session), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION); + /** + * GstRTSPClient::pre-options-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_OPTIONS_REQUEST] = + g_signal_new ("pre-options-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_options_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST] = g_signal_new ("options-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, options_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-describe-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_DESCRIBE_REQUEST] = + g_signal_new ("pre-describe-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_describe_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST] = g_signal_new ("describe-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, describe_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-setup-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_SETUP_REQUEST] = + g_signal_new ("pre-setup-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_setup_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST] = g_signal_new ("setup-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, setup_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-play-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_PLAY_REQUEST] = + g_signal_new ("pre-play-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_play_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST] = g_signal_new ("play-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, play_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-pause-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_PAUSE_REQUEST] = + g_signal_new ("pre-pause-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_pause_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST] = g_signal_new ("pause-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, pause_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-teardown-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_TEARDOWN_REQUEST] = + g_signal_new ("pre-teardown-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_teardown_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST] = g_signal_new ("teardown-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, teardown_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-set-parameter-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_SET_PARAMETER_REQUEST] = + g_signal_new ("pre-set-parameter-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_set_parameter_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, + GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST] = g_signal_new ("set-parameter-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, set_parameter_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-get-parameter-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_GET_PARAMETER_REQUEST] = + g_signal_new ("pre-get-parameter-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_get_parameter_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST] = g_signal_new ("get-parameter-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, @@ -274,12 +436,46 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) send_message), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_POINTER); + /** + * GstRTSPClient::pre-announce-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_ANNOUNCE_REQUEST] = + g_signal_new ("pre-announce-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_announce_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST] = g_signal_new ("announce-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, announce_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-record-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_RECORD_REQUEST] = + g_signal_new ("pre-record-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_record_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST] = g_signal_new ("record-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, record_request), @@ -864,6 +1060,47 @@ default_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri) return path; } +/* Default signal handler function for all "pre-command" signals, like + * pre-options-request. It just returns the RTSP return code 200. + * Subclasses can override this to get another default behaviour. + */ +static GstRTSPStatusCode +default_pre_signal_handler (GstRTSPClient * client, GstRTSPContext * ctx) +{ + GST_LOG_OBJECT (client, "returning GST_RTSP_STS_OK"); + return GST_RTSP_STS_OK; +} + +/* The pre-signal accumulator function checks the return value of the signal + * handlers. If any of them returns an RTSP status code that does not start + * with 2 it will return FALSE, no more signal handlers will be called, and + * this last RTSP status code will be the result of the signal emission. + */ +static gboolean +pre_signal_accumulator (GSignalInvocationHint * ihint, GValue * return_accu, + const GValue * handler_return, gpointer data) +{ + GstRTSPStatusCode handler_value = g_value_get_enum (handler_return); + GstRTSPStatusCode accumulated_value = g_value_get_enum (return_accu); + + if (handler_value < 200 || handler_value > 299) { + GST_DEBUG ("handler_value : %d, returning FALSE", handler_value); + g_value_set_enum (return_accu, handler_value); + return FALSE; + } + + /* the accumulated value is initiated to 0 by GLib. if current handler value is + * bigger then use that instead + * + * FIXME: Should we prioritize the 2xx codes in a smarter way? + * Like, "201 Created" > "250 Low On Storage Space" > "200 OK"? + */ + if (handler_value > accumulated_value) + g_value_set_enum (return_accu, handler_value); + + return TRUE; +} + static gboolean handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) { @@ -875,6 +1112,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *path; gint matched; gboolean keep_session; + GstRTSPStatusCode sig_result; if (!ctx->session) goto no_session; @@ -900,6 +1138,12 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_TEARDOWN_REQUEST], + 0, ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + /* we emit the signal before closing the connection */ g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], 0, ctx); @@ -952,6 +1196,13 @@ no_aggregate: g_free (path); return FALSE; } +sig_failed: + { + GST_ERROR ("client %p: pre signal returned error: %s", client, + gst_rtsp_status_as_text (sig_result)); + send_generic_response (client, sig_result, ctx); + return FALSE; + } } static GstRTSPResult @@ -980,6 +1231,14 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPResult res; guint8 *data; guint size; + GstRTSPStatusCode sig_result; + + g_signal_emit (client, + gst_rtsp_client_signals[SIGNAL_PRE_GET_PARAMETER_REQUEST], 0, ctx, + &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } res = gst_rtsp_message_get_body (ctx->request, &data, &size); if (res != GST_RTSP_OK) @@ -1003,6 +1262,13 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx) return TRUE; /* ERRORS */ +sig_failed: + { + GST_ERROR ("client %p: pre signal returned error: %s", client, + gst_rtsp_status_as_text (sig_result)); + send_generic_response (client, sig_result, ctx); + return FALSE; + } bad_request: { GST_ERROR ("client %p: bad request", client); @@ -1017,6 +1283,14 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPResult res; guint8 *data; guint size; + GstRTSPStatusCode sig_result; + + g_signal_emit (client, + gst_rtsp_client_signals[SIGNAL_PRE_SET_PARAMETER_REQUEST], 0, ctx, + &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } res = gst_rtsp_message_get_body (ctx->request, &data, &size); if (res != GST_RTSP_OK) @@ -1040,6 +1314,13 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx) return TRUE; /* ERRORS */ +sig_failed: + { + GST_ERROR ("client %p: pre signal returned error: %s", client, + gst_rtsp_status_as_text (sig_result)); + send_generic_response (client, sig_result, ctx); + return FALSE; + } bad_request: { GST_ERROR ("client %p: bad request", client); @@ -1059,6 +1340,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPState rtspstate; gchar *path; gint matched; + GstRTSPStatusCode sig_result; guint i, n; if (!(session = ctx->session)) @@ -1092,6 +1374,12 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_PAUSE_REQUEST], 0, + ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); /* the session state must be playing or recording */ if (rtspstate != GST_RTSP_STATE_PLAYING && @@ -1143,6 +1431,13 @@ no_aggregate: g_free (path); return FALSE; } +sig_failed: + { + GST_ERROR ("client %p: pre signal returned error: %s", client, + gst_rtsp_status_as_text (sig_result)); + send_generic_response (client, sig_result, ctx); + return FALSE; + } invalid_state: { GST_ERROR ("client %p: not PLAYING or RECORDING", client); @@ -1197,6 +1492,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT; gchar *path, *rtpinfo; gint matched; + GstRTSPStatusCode sig_result; if (!(session = ctx->session)) goto no_session; @@ -1220,6 +1516,12 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_PLAY_REQUEST], 0, + ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + if (!(gst_rtsp_media_get_transport_mode (media) & GST_RTSP_TRANSPORT_MODE_PLAY)) goto unsupported_mode; @@ -1306,6 +1608,13 @@ no_aggregate: g_free (path); return FALSE; } +sig_failed: + { + GST_ERROR ("client %p: pre signal returned error: %s", client, + gst_rtsp_status_as_text (sig_result)); + send_generic_response (client, sig_result, ctx); + return FALSE; + } invalid_state: { GST_ERROR ("client %p: not PLAYING or READY", client); @@ -1851,6 +2160,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *path, *control = NULL; gint matched; gboolean new_session = FALSE; + GstRTSPStatusCode sig_result; if (!ctx->uri) goto no_uri; @@ -1923,6 +2233,12 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->stream = stream; ctx->media = media; + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_SETUP_REQUEST], 0, + ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + if (session == NULL) { /* create a session if this fails we probably reached our session limit or * something. */ @@ -2089,6 +2405,14 @@ stream_not_found: g_object_unref (media); goto cleanup_session; } +sig_failed: + { + GST_ERROR ("client %p: pre signal returned error: %s", client, + gst_rtsp_status_as_text (sig_result)); + send_generic_response (client, sig_result, ctx); + g_object_unref (media); + goto cleanup_path; + } service_unavailable: { GST_ERROR ("client %p: can't create session", client); @@ -2217,12 +2541,19 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *path, *str; GstRTSPMedia *media; GstRTSPClientClass *klass; + GstRTSPStatusCode sig_result; klass = GST_RTSP_CLIENT_GET_CLASS (client); if (!ctx->uri) goto no_uri; + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_DESCRIBE_REQUEST], + 0, ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + /* check what kind of format is accepted, we don't really do anything with it * and always return SDP for now. */ for (i = 0;; i++) { @@ -2286,6 +2617,13 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) return TRUE; /* ERRORS */ +sig_failed: + { + GST_ERROR ("client %p: pre signal returned error: %s", client, + gst_rtsp_status_as_text (sig_result)); + send_generic_response (client, sig_result, ctx); + return FALSE; + } no_uri: { GST_ERROR ("client %p: no uri", client); @@ -2380,6 +2718,7 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *path, *cont = NULL; guint8 *data; guint size; + GstRTSPStatusCode sig_result; klass = GST_RTSP_CLIENT_GET_CLASS (client); @@ -2417,6 +2756,14 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!(media = find_media (client, ctx, path, NULL))) goto no_media; + ctx->media = media; + + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_ANNOUNCE_REQUEST], + 0, ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + if (!(gst_rtsp_media_get_transport_mode (media) & GST_RTSP_TRANSPORT_MODE_RECORD)) goto unsupported_mode; @@ -2487,6 +2834,14 @@ no_media: gst_sdp_message_free (sdp); return FALSE; } +sig_failed: + { + GST_ERROR ("client %p: pre signal returned error: %s", client, + gst_rtsp_status_as_text (sig_result)); + send_generic_response (client, sig_result, ctx); + gst_sdp_message_free (sdp); + return FALSE; + } unsupported_mode: { GST_ERROR ("client %p: media does not support ANNOUNCE", client); @@ -2518,6 +2873,7 @@ handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPState rtspstate; gchar *path; gint matched; + GstRTSPStatusCode sig_result; if (!(session = ctx->session)) goto no_session; @@ -2541,6 +2897,12 @@ handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_RECORD_REQUEST], 0, + ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + if (!(gst_rtsp_media_get_transport_mode (media) & GST_RTSP_TRANSPORT_MODE_RECORD)) goto unsupported_mode; @@ -2596,6 +2958,13 @@ no_aggregate: g_free (path); return FALSE; } +sig_failed: + { + GST_ERROR ("client %p: pre signal returned error: %s", client, + gst_rtsp_status_as_text (sig_result)); + send_generic_response (client, sig_result, ctx); + return FALSE; + } unsupported_mode: { GST_ERROR ("client %p: media does not support RECORD", client); @@ -2622,6 +2991,7 @@ handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPMethod options; gchar *str; + GstRTSPStatusCode sig_result; options = GST_RTSP_DESCRIBE | GST_RTSP_OPTIONS | @@ -2639,12 +3009,28 @@ handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PUBLIC, str); g_free (str); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_OPTIONS_REQUEST], 0, + ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + send_message (client, ctx, ctx->response, FALSE); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST], 0, ctx); return TRUE; + +/* ERRORS */ +sig_failed: + { + GST_ERROR ("client %p: pre signal returned error: %s", client, + gst_rtsp_status_as_text (sig_result)); + send_generic_response (client, sig_result, ctx); + gst_rtsp_message_free (ctx->response); + return FALSE; + } } /* remove duplicate and trailing '/' */ diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 766e97dc95..3daef070d2 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -128,8 +128,19 @@ struct _GstRTSPClientClass { void (*record_request) (GstRTSPClient *client, GstRTSPContext *ctx); gchar* (*check_requirements) (GstRTSPClient *client, GstRTSPContext *ctx, gchar ** arr); + GstRTSPStatusCode (*pre_options_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_describe_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_setup_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_play_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_pause_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_teardown_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_set_parameter_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_get_parameter_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_announce_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_record_request) (GstRTSPClient *client, GstRTSPContext *ctx); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE-6]; + gpointer _gst_reserved[GST_PADDING_LARGE-16]; }; GType gst_rtsp_client_get_type (void); From 166a90359470eecfcbefbb64c118ce46eb34e72b Mon Sep 17 00:00:00 2001 From: Neha Arora Date: Thu, 10 Nov 2016 05:16:00 +0000 Subject: [PATCH 1314/1776] rtsp-media: Only signal "new-state" if the state has actually changed https://bugzilla.gnome.org/show_bug.cgi?id=774173 --- gst/rtsp-server/rtsp-media.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 349311aced..52e6757ee7 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3845,11 +3845,11 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, media, do_state); if (priv->target_state != state) { - if (do_state) + if (do_state) { media_set_pipeline_state_locked (media, state); - - g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state, - NULL); + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state, + NULL); + } } /* remember where we are */ From 179eb9ae894b04ee63e5351ff347733b08c213aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 11 Nov 2016 14:42:08 +0200 Subject: [PATCH 1315/1776] rtsp-sdp: Fix indentation --- gst/rtsp-server/rtsp-sdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 5e49259d80..0380f3e2ad 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -155,7 +155,7 @@ mikey_add_crypto_sessions (GstRTSPStream * stream, GstMIKEYMessage * msg) gst_structure_free (stats); } - roc_found = !!(roc != -1); + roc_found = ! !(roc != -1); if (!roc_found) { GST_ERROR ("unable to obtain ROC for stream %p with SSRC %u", stream, ssrc); From 01ef7f32b6a36e9f74943ad54d8db923d7282f48 Mon Sep 17 00:00:00 2001 From: Scott D Phillips Date: Thu, 17 Nov 2016 09:43:37 -0800 Subject: [PATCH 1316/1776] client: update do_send_message to match type GstRTSPClientSendFunc This type mismatch fails building with MSVC https://bugzilla.gnome.org/show_bug.cgi?id=774640 --- gst/rtsp-server/rtsp-client.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 90d624b03a..ab6e8650c5 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -3935,7 +3935,7 @@ gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession * session, return GST_RTSP_OK; } -static GstRTSPResult +static gboolean do_send_message (GstRTSPClient * client, GstRTSPMessage * message, gboolean close, gpointer user_data) { @@ -3968,13 +3968,13 @@ do_send_message (GstRTSPClient * client, GstRTSPMessage * message, GST_DEBUG_OBJECT (client, "Resend due to backlog full"); } while (ret != GST_RTSP_EINTR); - return ret; + return ret == GST_RTSP_OK; /* ERRORS */ error: { GST_DEBUG_OBJECT (client, "got error %d", ret); - return ret; + return ret == GST_RTSP_OK; } } From 2ad8b13cb09737319aa177d97be22ae9f8497d50 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 18 Nov 2016 20:23:14 -0300 Subject: [PATCH 1317/1776] meson: gstreamer gst_check_dep does not exist on windows --- meson.build | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 3e38eadca4..7c5010fe84 100644 --- a/meson.build +++ b/meson.build @@ -46,8 +46,10 @@ rtspserver_incs = include_directories('gst/rtsp-server', '.') glib_dep = dependency('glib-2.0', version : glib_req) gst_dep = dependency('gstreamer-1.0', version : gst_req, fallback : ['gstreamer', 'gst_dep']) -gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, - fallback : ['gstreamer', 'gst_check_dep']) +if host_machine.system() != 'windows' + gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_check_dep']) +endif gstrtsp_dep = dependency('gstreamer-rtsp-1.0', version : gst_req, fallback : ['gst-plugins-base', 'rtsp_dep']) gstrtp_dep = dependency('gstreamer-rtp-1.0', version : gst_req, From d7676bfba3ea33e13283787dc641e97cc0241cd9 Mon Sep 17 00:00:00 2001 From: Scott D Phillips Date: Thu, 17 Nov 2016 09:41:53 -0800 Subject: [PATCH 1318/1776] Enable building with MSVC https://bugzilla.gnome.org/show_bug.cgi?id=774640 --- Makefile.am | 6 +- gst/rtsp-server/meson.build | 1 + meson.build | 6 +- tests/check/meson.build | 2 + win32/MANIFEST | 2 + win32/common/libgstrtspserver.def | 323 ++++++++++++++++++++++++++++++ 6 files changed, 335 insertions(+), 5 deletions(-) create mode 100644 win32/MANIFEST create mode 100644 win32/common/libgstrtspserver.def diff --git a/Makefile.am b/Makefile.am index dccba6e1eb..7ece053671 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,11 +16,15 @@ SUBDIRS = \ DIST_SUBDIRS = gst common pkgconfig docs examples tests +# include before EXTRA_DIST for win32 assignment +include $(top_srcdir)/common/win32.mak + EXTRA_DIST = \ ChangeLog autogen.sh depcomp \ AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \ gst-rtsp.spec docs/design/gst-rtp-server-design \ - gst-rtsp-server.doap + gst-rtsp-server.doap \ + $(win32) ACLOCAL_AMFLAGS = -I m4 -I common/m4 diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index ef47015ae5..d65a078abe 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -51,6 +51,7 @@ gst_rtsp_server = library('gstrtspserver-@0@'.format(api_version), soversion : soversion, install : true, dependencies : [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_dep], + vs_module_defs: vs_module_defs_dir + 'libgstrtspserver.def' ) gst_rtsp_server_dep = declare_dependency(link_with : gst_rtsp_server, diff --git a/meson.build b/meson.build index 7c5010fe84..fdd340c345 100644 --- a/meson.build +++ b/meson.build @@ -46,10 +46,6 @@ rtspserver_incs = include_directories('gst/rtsp-server', '.') glib_dep = dependency('glib-2.0', version : glib_req) gst_dep = dependency('gstreamer-1.0', version : gst_req, fallback : ['gstreamer', 'gst_dep']) -if host_machine.system() != 'windows' - gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, - fallback : ['gstreamer', 'gst_check_dep']) -endif gstrtsp_dep = dependency('gstreamer-rtsp-1.0', version : gst_req, fallback : ['gst-plugins-base', 'rtsp_dep']) gstrtp_dep = dependency('gstreamer-rtp-1.0', version : gst_req, @@ -61,6 +57,8 @@ gstapp_dep = dependency('gstreamer-app-1.0', version : gst_req, gstnet_dep = dependency('gstreamer-net-1.0', version : gst_req, fallback : ['gstreamer', 'gst_net_dep']) +vs_module_defs_dir = meson.current_source_dir() + '/win32/common/' + subdir('gst') subdir('tests') subdir('examples') diff --git a/tests/check/meson.build b/tests/check/meson.build index 622c6c5606..f93bf631b1 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -1,4 +1,6 @@ # FIXME: something is wrong with plugin paths / whitelisting here +gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_check_dep']) test_plugins_modules = [ ['gstreamer-1.0', true], diff --git a/win32/MANIFEST b/win32/MANIFEST new file mode 100644 index 0000000000..8cdea81e53 --- /dev/null +++ b/win32/MANIFEST @@ -0,0 +1,2 @@ +win32/MANIFEST +win32/common/libgstrtspserver.def diff --git a/win32/common/libgstrtspserver.def b/win32/common/libgstrtspserver.def new file mode 100644 index 0000000000..b238a77f6f --- /dev/null +++ b/win32/common/libgstrtspserver.def @@ -0,0 +1,323 @@ +EXPORTS + gst_rtsp_address_copy + gst_rtsp_address_free + gst_rtsp_address_get_type + gst_rtsp_address_pool_acquire_address + gst_rtsp_address_pool_add_range + gst_rtsp_address_pool_clear + gst_rtsp_address_pool_dump + gst_rtsp_address_pool_get_type + gst_rtsp_address_pool_has_unicast_addresses + gst_rtsp_address_pool_new + gst_rtsp_address_pool_reserve_address + gst_rtsp_auth_add_basic + gst_rtsp_auth_check + gst_rtsp_auth_get_default_token + gst_rtsp_auth_get_tls_authentication_mode + gst_rtsp_auth_get_tls_certificate + gst_rtsp_auth_get_tls_database + gst_rtsp_auth_get_type + gst_rtsp_auth_make_basic + gst_rtsp_auth_new + gst_rtsp_auth_remove_basic + gst_rtsp_auth_set_default_token + gst_rtsp_auth_set_tls_authentication_mode + gst_rtsp_auth_set_tls_certificate + gst_rtsp_auth_set_tls_database + gst_rtsp_client_attach + gst_rtsp_client_close + gst_rtsp_client_get_auth + gst_rtsp_client_get_connection + gst_rtsp_client_get_mount_points + gst_rtsp_client_get_session_pool + gst_rtsp_client_get_thread_pool + gst_rtsp_client_get_type + gst_rtsp_client_handle_message + gst_rtsp_client_new + gst_rtsp_client_send_message + gst_rtsp_client_session_filter + gst_rtsp_client_set_auth + gst_rtsp_client_set_connection + gst_rtsp_client_set_mount_points + gst_rtsp_client_set_send_func + gst_rtsp_client_set_session_pool + gst_rtsp_client_set_thread_pool + gst_rtsp_context_get_current + gst_rtsp_context_get_type + gst_rtsp_context_pop_current + gst_rtsp_context_push_current + gst_rtsp_media_collect_streams + gst_rtsp_media_create_stream + gst_rtsp_media_factory_add_role + gst_rtsp_media_factory_construct + gst_rtsp_media_factory_create_element + gst_rtsp_media_factory_get_address_pool + gst_rtsp_media_factory_get_buffer_size + gst_rtsp_media_factory_get_clock + gst_rtsp_media_factory_get_latency + gst_rtsp_media_factory_get_launch + gst_rtsp_media_factory_get_media_gtype + gst_rtsp_media_factory_get_multicast_iface + gst_rtsp_media_factory_get_permissions + gst_rtsp_media_factory_get_profiles + gst_rtsp_media_factory_get_protocols + gst_rtsp_media_factory_get_publish_clock_mode + gst_rtsp_media_factory_get_retransmission_time + gst_rtsp_media_factory_get_suspend_mode + gst_rtsp_media_factory_get_transport_mode + gst_rtsp_media_factory_get_type + gst_rtsp_media_factory_is_eos_shutdown + gst_rtsp_media_factory_is_shared + gst_rtsp_media_factory_is_stop_on_disonnect + gst_rtsp_media_factory_new + gst_rtsp_media_factory_set_address_pool + gst_rtsp_media_factory_set_buffer_size + gst_rtsp_media_factory_set_clock + gst_rtsp_media_factory_set_eos_shutdown + gst_rtsp_media_factory_set_latency + gst_rtsp_media_factory_set_launch + gst_rtsp_media_factory_set_media_gtype + gst_rtsp_media_factory_set_multicast_iface + gst_rtsp_media_factory_set_permissions + gst_rtsp_media_factory_set_profiles + gst_rtsp_media_factory_set_protocols + gst_rtsp_media_factory_set_publish_clock_mode + gst_rtsp_media_factory_set_retransmission_time + gst_rtsp_media_factory_set_shared + gst_rtsp_media_factory_set_stop_on_disconnect + gst_rtsp_media_factory_set_suspend_mode + gst_rtsp_media_factory_set_transport_mode + gst_rtsp_media_factory_uri_get_type + gst_rtsp_media_factory_uri_get_uri + gst_rtsp_media_factory_uri_new + gst_rtsp_media_factory_uri_set_uri + gst_rtsp_media_find_stream + gst_rtsp_media_get_address_pool + gst_rtsp_media_get_base_time + gst_rtsp_media_get_buffer_size + gst_rtsp_media_get_clock + gst_rtsp_media_get_element + gst_rtsp_media_get_latency + gst_rtsp_media_get_multicast_iface + gst_rtsp_media_get_permissions + gst_rtsp_media_get_profiles + gst_rtsp_media_get_protocols + gst_rtsp_media_get_publish_clock_mode + gst_rtsp_media_get_range_string + gst_rtsp_media_get_retransmission_time + gst_rtsp_media_get_status + gst_rtsp_media_get_stream + gst_rtsp_media_get_suspend_mode + gst_rtsp_media_get_time_provider + gst_rtsp_media_get_transport_mode + gst_rtsp_media_get_type + gst_rtsp_media_handle_sdp + gst_rtsp_media_is_eos_shutdown + gst_rtsp_media_is_reusable + gst_rtsp_media_is_shared + gst_rtsp_media_is_stop_on_disconnect + gst_rtsp_media_is_time_provider + gst_rtsp_media_n_streams + gst_rtsp_media_new + gst_rtsp_media_prepare + gst_rtsp_media_seek + gst_rtsp_media_set_address_pool + gst_rtsp_media_set_buffer_size + gst_rtsp_media_set_clock + gst_rtsp_media_set_eos_shutdown + gst_rtsp_media_set_latency + gst_rtsp_media_set_multicast_iface + gst_rtsp_media_set_permissions + gst_rtsp_media_set_pipeline_state + gst_rtsp_media_set_profiles + gst_rtsp_media_set_protocols + gst_rtsp_media_set_publish_clock_mode + gst_rtsp_media_set_retransmission_time + gst_rtsp_media_set_reusable + gst_rtsp_media_set_shared + gst_rtsp_media_set_state + gst_rtsp_media_set_stop_on_disconnect + gst_rtsp_media_set_suspend_mode + gst_rtsp_media_set_transport_mode + gst_rtsp_media_setup_sdp + gst_rtsp_media_suspend + gst_rtsp_media_take_pipeline + gst_rtsp_media_unprepare + gst_rtsp_media_unsuspend + gst_rtsp_media_use_time_provider + gst_rtsp_mount_points_add_factory + gst_rtsp_mount_points_get_type + gst_rtsp_mount_points_make_path + gst_rtsp_mount_points_match + gst_rtsp_mount_points_new + gst_rtsp_mount_points_remove_factory + gst_rtsp_params_get + gst_rtsp_params_set + gst_rtsp_permissions_add_role + gst_rtsp_permissions_add_role_valist + gst_rtsp_permissions_get_role + gst_rtsp_permissions_get_type + gst_rtsp_permissions_is_allowed + gst_rtsp_permissions_new + gst_rtsp_permissions_remove_role + gst_rtsp_publish_clock_mode_get_type + gst_rtsp_sdp_from_media + gst_rtsp_sdp_from_stream + gst_rtsp_server_attach + gst_rtsp_server_client_filter + gst_rtsp_server_create_socket + gst_rtsp_server_create_source + gst_rtsp_server_get_address + gst_rtsp_server_get_auth + gst_rtsp_server_get_backlog + gst_rtsp_server_get_bound_port + gst_rtsp_server_get_mount_points + gst_rtsp_server_get_service + gst_rtsp_server_get_session_pool + gst_rtsp_server_get_thread_pool + gst_rtsp_server_get_type + gst_rtsp_server_io_func + gst_rtsp_server_new + gst_rtsp_server_set_address + gst_rtsp_server_set_auth + gst_rtsp_server_set_backlog + gst_rtsp_server_set_mount_points + gst_rtsp_server_set_service + gst_rtsp_server_set_session_pool + gst_rtsp_server_set_thread_pool + gst_rtsp_server_transfer_connection + gst_rtsp_session_allow_expire + gst_rtsp_session_filter + gst_rtsp_session_get_header + gst_rtsp_session_get_media + gst_rtsp_session_get_sessionid + gst_rtsp_session_get_timeout + gst_rtsp_session_get_type + gst_rtsp_session_is_expired_usec + gst_rtsp_session_manage_media + gst_rtsp_session_media_alloc_channels + gst_rtsp_session_media_get_base_time + gst_rtsp_session_media_get_media + gst_rtsp_session_media_get_rtpinfo + gst_rtsp_session_media_get_rtsp_state + gst_rtsp_session_media_get_transport + gst_rtsp_session_media_get_type + gst_rtsp_session_media_matches + gst_rtsp_session_media_new + gst_rtsp_session_media_set_rtsp_state + gst_rtsp_session_media_set_state + gst_rtsp_session_media_set_transport + gst_rtsp_session_new + gst_rtsp_session_next_timeout_usec + gst_rtsp_session_pool_cleanup + gst_rtsp_session_pool_create + gst_rtsp_session_pool_create_watch + gst_rtsp_session_pool_filter + gst_rtsp_session_pool_find + gst_rtsp_session_pool_get_max_sessions + gst_rtsp_session_pool_get_n_sessions + gst_rtsp_session_pool_get_type + gst_rtsp_session_pool_new + gst_rtsp_session_pool_remove + gst_rtsp_session_pool_set_max_sessions + gst_rtsp_session_prevent_expire + gst_rtsp_session_release_media + gst_rtsp_session_set_timeout + gst_rtsp_session_touch + gst_rtsp_stream_add_transport + gst_rtsp_stream_allocate_udp_sockets + gst_rtsp_stream_get_address_pool + gst_rtsp_stream_get_buffer_size + gst_rtsp_stream_get_caps + gst_rtsp_stream_get_control + gst_rtsp_stream_get_current_seqnum + gst_rtsp_stream_get_dscp_qos + gst_rtsp_stream_get_index + gst_rtsp_stream_get_joined_bin + gst_rtsp_stream_get_mtu + gst_rtsp_stream_get_multicast_address + gst_rtsp_stream_get_multicast_iface + gst_rtsp_stream_get_profiles + gst_rtsp_stream_get_protocols + gst_rtsp_stream_get_pt + gst_rtsp_stream_get_publish_clock_mode + gst_rtsp_stream_get_retransmission_pt + gst_rtsp_stream_get_retransmission_time + gst_rtsp_stream_get_rtcp_socket + gst_rtsp_stream_get_rtp_socket + gst_rtsp_stream_get_rtpinfo + gst_rtsp_stream_get_rtpsession + gst_rtsp_stream_get_server_port + gst_rtsp_stream_get_sinkpad + gst_rtsp_stream_get_srcpad + gst_rtsp_stream_get_srtp_encoder + gst_rtsp_stream_get_ssrc + gst_rtsp_stream_get_type + gst_rtsp_stream_has_control + gst_rtsp_stream_is_blocking + gst_rtsp_stream_is_client_side + gst_rtsp_stream_is_transport_supported + gst_rtsp_stream_join_bin + gst_rtsp_stream_leave_bin + gst_rtsp_stream_new + gst_rtsp_stream_query_position + gst_rtsp_stream_query_stop + gst_rtsp_stream_recv_rtcp + gst_rtsp_stream_recv_rtp + gst_rtsp_stream_remove_transport + gst_rtsp_stream_request_aux_sender + gst_rtsp_stream_reserve_address + gst_rtsp_stream_set_address_pool + gst_rtsp_stream_set_blocked + gst_rtsp_stream_set_buffer_size + gst_rtsp_stream_set_client_side + gst_rtsp_stream_set_control + gst_rtsp_stream_set_dscp_qos + gst_rtsp_stream_set_mtu + gst_rtsp_stream_set_multicast_iface + gst_rtsp_stream_set_profiles + gst_rtsp_stream_set_protocols + gst_rtsp_stream_set_pt_map + gst_rtsp_stream_set_publish_clock_mode + gst_rtsp_stream_set_retransmission_pt + gst_rtsp_stream_set_retransmission_time + gst_rtsp_stream_set_seqnum_offset + gst_rtsp_stream_transport_filter + gst_rtsp_stream_transport_get_rtpinfo + gst_rtsp_stream_transport_get_stream + gst_rtsp_stream_transport_get_transport + gst_rtsp_stream_transport_get_type + gst_rtsp_stream_transport_get_url + gst_rtsp_stream_transport_is_timed_out + gst_rtsp_stream_transport_keep_alive + gst_rtsp_stream_transport_new + gst_rtsp_stream_transport_recv_data + gst_rtsp_stream_transport_send_rtcp + gst_rtsp_stream_transport_send_rtp + gst_rtsp_stream_transport_set_active + gst_rtsp_stream_transport_set_callbacks + gst_rtsp_stream_transport_set_keepalive + gst_rtsp_stream_transport_set_timed_out + gst_rtsp_stream_transport_set_transport + gst_rtsp_stream_transport_set_url + gst_rtsp_stream_update_crypto + gst_rtsp_suspend_mode_get_type + gst_rtsp_thread_get_type + gst_rtsp_thread_new + gst_rtsp_thread_pool_cleanup + gst_rtsp_thread_pool_get_max_threads + gst_rtsp_thread_pool_get_thread + gst_rtsp_thread_pool_get_type + gst_rtsp_thread_pool_new + gst_rtsp_thread_pool_set_max_threads + gst_rtsp_thread_reuse + gst_rtsp_thread_stop + gst_rtsp_token_get_string + gst_rtsp_token_get_structure + gst_rtsp_token_get_type + gst_rtsp_token_is_allowed + gst_rtsp_token_new + gst_rtsp_token_new_empty + gst_rtsp_token_new_valist + gst_rtsp_token_writable_structure + gst_rtsp_transport_mode_get_type From 927a44c55bcd8188e199d0573dc31527fecdf34f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 16 Nov 2016 08:42:24 +0200 Subject: [PATCH 1319/1776] rtsp-auth: Add support for Digest authentication https://bugzilla.gnome.org/show_bug.cgi?id=774416 --- examples/Makefile.am | 2 +- examples/test-auth-digest.c | 184 +++++++++++++++ gst/rtsp-server/rtsp-auth.c | 356 ++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-auth.h | 8 + win32/common/libgstrtspserver.def | 4 + 5 files changed, 531 insertions(+), 23 deletions(-) create mode 100644 examples/test-auth-digest.c diff --git a/examples/Makefile.am b/examples/Makefile.am index d98d1be421..a76f909127 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ - test-launch test-sdp test-uri test-auth \ + test-launch test-sdp test-uri test-auth test-auth-digest \ test-multicast test-multicast2 test-appsrc \ test-video-rtx test-record test-record-auth \ test-netclock test-netclock-client diff --git a/examples/test-auth-digest.c b/examples/test-auth-digest.c new file mode 100644 index 0000000000..6384da3d0c --- /dev/null +++ b/examples/test-auth-digest.c @@ -0,0 +1,184 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +static gboolean +remove_func (GstRTSPSessionPool * pool, GstRTSPSession * session, + GstRTSPServer * server) +{ + return GST_RTSP_FILTER_REMOVE; +} + +static gboolean +remove_sessions (GstRTSPServer * server) +{ + GstRTSPSessionPool *pool; + + g_print ("removing all sessions\n"); + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_filter (pool, + (GstRTSPSessionPoolFilterFunc) remove_func, server); + g_object_unref (pool); + + return FALSE; +} + +static gboolean +timeout (GstRTSPServer * server) +{ + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_cleanup (pool); + g_object_unref (pool); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + GstRTSPAuth *auth; + GstRTSPToken *token; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mounts for this server, every server has a default mapper object + * that be used to map uri mount points to media factories */ + mounts = gst_rtsp_server_get_mount_points (server); + + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, "( " + "videotestsrc ! video/x-raw,width=352,height=288,framerate=15/1 ! " + "x264enc ! rtph264pay name=pay0 pt=96 " + "audiotestsrc ! audio/x-raw,rate=8000 ! " + "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); + /* attach the test factory to the /test url */ + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + /* allow user and admin to access this resource */ + gst_rtsp_media_factory_add_role (factory, "user", + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL); + gst_rtsp_media_factory_add_role (factory, "admin", + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL); + /* admin2 can look at the media but not construct so he gets a + * 401 Unauthorized */ + gst_rtsp_media_factory_add_role (factory, "admin2", + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, FALSE, NULL); + /* Anonymous user can do the same things as admin2 on this resource */ + gst_rtsp_media_factory_add_role (factory, "anonymous", + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, FALSE, NULL); + + /* make another factory */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, "( " + "videotestsrc ! video/x-raw,width=352,height=288,framerate=30/1 ! " + "x264enc ! rtph264pay name=pay0 pt=96 )"); + /* attach the test factory to the /test url */ + gst_rtsp_mount_points_add_factory (mounts, "/test2", factory); + + /* allow admin2 to access this resource */ + /* user and admin have no permissions so they can't even see the + * media and get a 404 Not Found */ + gst_rtsp_media_factory_add_role (factory, "admin2", + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mounts); + + /* make a new authentication manager */ + auth = gst_rtsp_auth_new (); + gst_rtsp_auth_set_supported_methods (auth, GST_RTSP_AUTH_DIGEST); + + /* make default token, it has no permissions */ + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "anonymous", NULL); + gst_rtsp_auth_set_default_token (auth, token); + gst_rtsp_token_unref (token); + + /* make user token */ + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_auth_add_digest (auth, "user", "password", token); + gst_rtsp_token_unref (token); + + /* make admin token */ + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "admin", NULL); + gst_rtsp_auth_add_digest (auth, "admin", "power", token); + gst_rtsp_token_unref (token); + + /* make admin2 token */ + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "admin2", NULL); + gst_rtsp_auth_add_digest (auth, "admin2", "power2", token); + gst_rtsp_token_unref (token); + + /* set as the server authentication manager */ + gst_rtsp_server_set_auth (server, auth); + g_object_unref (auth); + + /* attach the server to the default maincontext */ + if (gst_rtsp_server_attach (server, NULL) == 0) + goto failed; + + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + g_timeout_add_seconds (10, (GSourceFunc) remove_sessions, server); + + /* start serving */ + g_print ("stream with user:password ready at rtsp://127.0.0.1:8554/test\n"); + g_print ("stream with admin:power ready at rtsp://127.0.0.1:8554/test\n"); + g_print ("stream with admin2:power2 ready at rtsp://127.0.0.1:8554/test2\n"); + g_main_loop_run (loop); + + return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } +} diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 654388a6ff..5bca6f6f24 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -62,10 +62,43 @@ struct _GstRTSPAuthPrivate GTlsDatabase *database; GTlsAuthenticationMode mode; GHashTable *basic; /* protected by lock */ + GHashTable *digest, *nonces; /* protected by lock */ + guint64 last_nonce_check; GstRTSPToken *default_token; GstRTSPMethod methods; + GstRTSPAuthMethod auth_methods; }; +typedef struct +{ + GstRTSPToken *token; + gchar *pass; +} GstRTSPDigestEntry; + +typedef struct +{ + gchar *nonce; + gchar *ip; + guint64 timestamp; + gpointer client; +} GstRTSPDigestNonce; + +static void +gst_rtsp_digest_entry_free (GstRTSPDigestEntry * entry) +{ + gst_rtsp_token_unref (entry->token); + g_free (entry->pass); + g_free (entry); +} + +static void +gst_rtsp_digest_nonce_free (GstRTSPDigestNonce * nonce) +{ + g_free (nonce->nonce); + g_free (nonce->ip); + g_free (nonce); +} + enum { PROP_0, @@ -92,6 +125,9 @@ static void gst_rtsp_auth_finalize (GObject * obj); static gboolean default_authenticate (GstRTSPAuth * auth, GstRTSPContext * ctx); static gboolean default_check (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check); +static void default_generate_authenticate_header (GstRTSPAuth * auth, + GstRTSPContext * ctx); + G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT); @@ -110,6 +146,7 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) klass->authenticate = default_authenticate; klass->check = default_check; + klass->generate_authenticate_header = default_generate_authenticate_header; GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth"); @@ -150,9 +187,14 @@ gst_rtsp_auth_init (GstRTSPAuth * auth) priv->basic = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gst_rtsp_token_unref); + priv->digest = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) gst_rtsp_digest_entry_free); + priv->nonces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) gst_rtsp_digest_nonce_free); /* bitwise or of all methods that need authentication */ priv->methods = 0; + priv->auth_methods = GST_RTSP_AUTH_BASIC; } static void @@ -168,6 +210,8 @@ gst_rtsp_auth_finalize (GObject * obj) if (priv->database) g_object_unref (priv->database); g_hash_table_unref (priv->basic); + g_hash_table_unref (priv->digest); + g_hash_table_unref (priv->nonces); g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj); @@ -469,8 +513,7 @@ gst_rtsp_auth_add_basic (GstRTSPAuth * auth, const gchar * basic, * @auth: a #GstRTSPAuth * @basic: (transfer none): the basic token * - * Add a basic token for the default authentication algorithm that - * enables the client with privileges from @authgroup. + * Removes @basic authentication token. */ void gst_rtsp_auth_remove_basic (GstRTSPAuth * auth, const gchar * basic) @@ -487,12 +530,216 @@ gst_rtsp_auth_remove_basic (GstRTSPAuth * auth, const gchar * basic) g_mutex_unlock (&priv->lock); } +/** + * gst_rtsp_auth_add_digest: + * @auth: a #GstRTSPAuth + * @user: the digest user name + * @pass: the digest password + * @token: (transfer none): authorisation token + * + * Add a digest @user and @pass for the default authentication algorithm that + * enables the client with privileges listed in @token. + * + * Since: 1.12 + */ +void +gst_rtsp_auth_add_digest (GstRTSPAuth * auth, const gchar * user, + const gchar * pass, GstRTSPToken * token) +{ + GstRTSPAuthPrivate *priv; + GstRTSPDigestEntry *entry; + + g_return_if_fail (GST_IS_RTSP_AUTH (auth)); + g_return_if_fail (user != NULL); + g_return_if_fail (pass != NULL); + g_return_if_fail (GST_IS_RTSP_TOKEN (token)); + + priv = auth->priv; + + entry = g_new0 (GstRTSPDigestEntry, 1); + entry->token = gst_rtsp_token_ref (token); + entry->pass = g_strdup (pass); + + g_mutex_lock (&priv->lock); + g_hash_table_replace (priv->digest, g_strdup (user), entry); + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_auth_remove_digest: + * @auth: a #GstRTSPAuth + * @user: (transfer none): the digest user name + * + * Removes a digest user. + * + * Since: 1.12 + */ +void +gst_rtsp_auth_remove_digest (GstRTSPAuth * auth, const gchar * user) +{ + GstRTSPAuthPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_AUTH (auth)); + g_return_if_fail (user != NULL); + + priv = auth->priv; + + g_mutex_lock (&priv->lock); + g_hash_table_remove (priv->digest, user); + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_auth_set_supported_methods: + * @auth: a #GstRTSPAuth + * @methods: supported methods + * + * Sets the supported authentication @methods for @auth. + * + * Since: 1.12 + */ +void +gst_rtsp_auth_set_supported_methods (GstRTSPAuth * auth, + GstRTSPAuthMethod methods) +{ + GstRTSPAuthPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_AUTH (auth)); + + priv = auth->priv; + + g_mutex_lock (&priv->lock); + priv->auth_methods = methods; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_auth_get_supported_methods: + * @auth: a #GstRTSPAuth + * + * Gets the supported authentication methods of @auth. + * + * Returns: The supported authentication methods + * + * Since: 1.12 + */ +GstRTSPAuthMethod +gst_rtsp_auth_get_supported_methods (GstRTSPAuth * auth) +{ + GstRTSPAuthPrivate *priv; + GstRTSPAuthMethod methods; + + g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), 0); + + priv = auth->priv; + + g_mutex_lock (&priv->lock); + methods = priv->auth_methods; + g_mutex_unlock (&priv->lock); + + return methods; +} + +typedef struct +{ + GstRTSPAuth *auth; + GstRTSPDigestNonce *nonce; +} RemoveNonceData; + +static void +remove_nonce (gpointer data, GObject * object) +{ + RemoveNonceData *remove_nonce_data = data; + + g_mutex_lock (&remove_nonce_data->auth->priv->lock); + g_hash_table_remove (remove_nonce_data->auth->priv->nonces, + remove_nonce_data->nonce->nonce); + g_mutex_unlock (&remove_nonce_data->auth->priv->lock); + + g_object_unref (remove_nonce_data->auth); + g_free (remove_nonce_data); +} + +static gboolean +default_digest_auth (GstRTSPAuth * auth, GstRTSPContext * ctx, + GstRTSPAuthParam ** param) +{ + const gchar *realm = NULL, *user = NULL, *nonce = NULL; + const gchar *response = NULL, *uri = NULL; + GstRTSPDigestNonce *nonce_entry = NULL; + GstRTSPDigestEntry *digest_entry; + gchar *expected_response = NULL; + gboolean ret = FALSE; + + GST_DEBUG_OBJECT (auth, "check Digest auth"); + + if (!param) + return ret; + + while (*param) { + if (!realm && strcmp ((*param)->name, "realm") == 0 && (*param)->value) + realm = (*param)->value; + else if (!user && strcmp ((*param)->name, "username") == 0 + && (*param)->value) + user = (*param)->value; + else if (!nonce && strcmp ((*param)->name, "nonce") == 0 && (*param)->value) + nonce = (*param)->value; + else if (!response && strcmp ((*param)->name, "response") == 0 + && (*param)->value) + response = (*param)->value; + else if (!uri && strcmp ((*param)->name, "uri") == 0 && (*param)->value) + uri = (*param)->value; + + param++; + } + + if (!realm || !user || !nonce || !response || !uri) + return FALSE; + + g_mutex_lock (&auth->priv->lock); + digest_entry = g_hash_table_lookup (auth->priv->digest, user); + if (!digest_entry) + goto out; + nonce_entry = g_hash_table_lookup (auth->priv->nonces, nonce); + if (!nonce_entry) + goto out; + + if (strcmp (nonce_entry->ip, gst_rtsp_connection_get_ip (ctx->conn)) != 0) + goto out; + if (nonce_entry->client && nonce_entry->client != ctx->client) + goto out; + + expected_response = + gst_rtsp_generate_digest_auth_response (NULL, + gst_rtsp_method_as_text (ctx->method), "GStreamer RTSP Server", user, + digest_entry->pass, uri, nonce); + if (!expected_response || strcmp (response, expected_response) != 0) + goto out; + + ctx->token = digest_entry->token; + ret = TRUE; + +out: + if (nonce_entry && !nonce_entry->client) { + RemoveNonceData *remove_nonce_data = g_new (RemoveNonceData, 1); + + nonce_entry->client = ctx->client; + remove_nonce_data->nonce = nonce_entry; + remove_nonce_data->auth = g_object_ref (auth); + g_object_weak_ref (G_OBJECT (ctx->client), remove_nonce, remove_nonce_data); + } + g_mutex_unlock (&auth->priv->lock); + + g_free (expected_response); + + return ret; +} + static gboolean default_authenticate (GstRTSPAuth * auth, GstRTSPContext * ctx) { GstRTSPAuthPrivate *priv = auth->priv; - GstRTSPResult res; - gchar *authorization; + GstRTSPAuthCredential **credentials, **credential; GST_DEBUG_OBJECT (auth, "authenticate"); @@ -502,27 +749,38 @@ default_authenticate (GstRTSPAuth * auth, GstRTSPContext * ctx) ctx->token = priv->default_token; g_mutex_unlock (&priv->lock); - res = - gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_AUTHORIZATION, - &authorization, 0); - if (res < 0) + credentials = + gst_rtsp_message_parse_auth_credentials (ctx->request, + GST_RTSP_HDR_AUTHORIZATION); + if (!credentials) goto no_auth; /* parse type */ - if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) { - GstRTSPToken *token; + credential = credentials; + while (*credential) { + if ((*credential)->scheme == GST_RTSP_AUTH_BASIC) { + GstRTSPToken *token; - GST_DEBUG_OBJECT (auth, "check Basic auth"); - g_mutex_lock (&priv->lock); - if ((token = g_hash_table_lookup (priv->basic, &authorization[6]))) { - GST_DEBUG_OBJECT (auth, "setting token %p", token); - ctx->token = token; + GST_DEBUG_OBJECT (auth, "check Basic auth"); + g_mutex_lock (&priv->lock); + if ((token = + g_hash_table_lookup (priv->basic, + (*credential)->authorization))) { + GST_DEBUG_OBJECT (auth, "setting token %p", token); + ctx->token = token; + g_mutex_unlock (&priv->lock); + break; + } + g_mutex_unlock (&priv->lock); + } else if ((*credential)->scheme == GST_RTSP_AUTH_DIGEST) { + if (default_digest_auth (auth, ctx, (*credential)->params)) + break; } - g_mutex_unlock (&priv->lock); - } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) { - GST_DEBUG_OBJECT (auth, "check Digest auth"); - /* not implemented yet */ + + credential++; } + + gst_rtsp_auth_credentials_free (credentials); return TRUE; no_auth: @@ -532,6 +790,57 @@ no_auth: } } +static void +default_generate_authenticate_header (GstRTSPAuth * auth, GstRTSPContext * ctx) +{ + if (auth->priv->auth_methods & GST_RTSP_AUTH_BASIC) { + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_WWW_AUTHENTICATE, + "Basic realm=\"GStreamer RTSP Server\""); + } + + if (auth->priv->auth_methods & GST_RTSP_AUTH_DIGEST) { + GstRTSPDigestNonce *nonce; + gchar *nonce_value, *auth_header; + + nonce_value = + g_strdup_printf ("%08x%08x", g_random_int (), g_random_int ()); + + auth_header = + g_strdup_printf + ("Digest realm=\"GStreamer RTSP Server\", nonce=\"%s\"", nonce_value); + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_WWW_AUTHENTICATE, + auth_header); + g_free (auth_header); + + nonce = g_new0 (GstRTSPDigestNonce, 1); + nonce->nonce = g_strdup (nonce_value); + nonce->timestamp = g_get_monotonic_time (); + nonce->ip = g_strdup (gst_rtsp_connection_get_ip (ctx->conn)); + g_mutex_lock (&auth->priv->lock); + g_hash_table_replace (auth->priv->nonces, nonce_value, nonce); + + if (auth->priv->last_nonce_check == 0) + auth->priv->last_nonce_check = nonce->timestamp; + + /* 30 second nonce timeout */ + if (nonce->timestamp - auth->priv->last_nonce_check >= 30 * G_USEC_PER_SEC) { + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init (&iter, auth->priv->nonces); + while (g_hash_table_iter_next (&iter, &key, &value)) { + GstRTSPDigestNonce *tmp = value; + + if (nonce->timestamp - tmp->timestamp >= 30 * G_USEC_PER_SEC) + g_hash_table_iter_remove (&iter); + } + auth->priv->last_nonce_check = nonce->timestamp; + } + + g_mutex_unlock (&auth->priv->lock); + } +} + static void send_response (GstRTSPAuth * auth, GstRTSPStatusCode code, GstRTSPContext * ctx) { @@ -539,9 +848,12 @@ send_response (GstRTSPAuth * auth, GstRTSPStatusCode code, GstRTSPContext * ctx) gst_rtsp_status_as_text (code), ctx->request); if (code == GST_RTSP_STS_UNAUTHORIZED) { - /* we only have Basic for now */ - gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_WWW_AUTHENTICATE, - "Basic realm=\"GStreamer RTSP Server\""); + GstRTSPAuthClass *klass; + + klass = GST_RTSP_AUTH_GET_CLASS (auth); + + if (klass->generate_authenticate_header) + klass->generate_authenticate_header (auth, ctx); } gst_rtsp_client_send_message (ctx->client, ctx->session, ctx->response); } diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index b5b5f4c0b1..dc65bc7770 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -72,6 +72,7 @@ struct _GstRTSPAuthClass { gboolean (*authenticate) (GstRTSPAuth *auth, GstRTSPContext *ctx); gboolean (*check) (GstRTSPAuth *auth, GstRTSPContext *ctx, const gchar *check); + void (*generate_authenticate_header) (GstRTSPAuth *auth, GstRTSPContext *ctx); gboolean (*accept_certificate) (GstRTSPAuth *auth, GTlsConnection *connection, GTlsCertificate *peer_cert, @@ -100,6 +101,13 @@ void gst_rtsp_auth_add_basic (GstRTSPAuth *auth, const gc GstRTSPToken *token); void gst_rtsp_auth_remove_basic (GstRTSPAuth *auth, const gchar * basic); +void gst_rtsp_auth_add_digest (GstRTSPAuth *auth, const gchar *user, + const gchar *pass, GstRTSPToken *token); +void gst_rtsp_auth_remove_digest (GstRTSPAuth *auth, const gchar *user); + +void gst_rtsp_auth_set_supported_methods (GstRTSPAuth *auth, GstRTSPAuthMethod methods); +GstRTSPAuthMethod gst_rtsp_auth_get_supported_methods (GstRTSPAuth *auth); + gboolean gst_rtsp_auth_check (const gchar *check); diff --git a/win32/common/libgstrtspserver.def b/win32/common/libgstrtspserver.def index b238a77f6f..18318e3f05 100644 --- a/win32/common/libgstrtspserver.def +++ b/win32/common/libgstrtspserver.def @@ -11,8 +11,10 @@ EXPORTS gst_rtsp_address_pool_new gst_rtsp_address_pool_reserve_address gst_rtsp_auth_add_basic + gst_rtsp_auth_add_digest gst_rtsp_auth_check gst_rtsp_auth_get_default_token + gst_rtsp_auth_get_supported_methods gst_rtsp_auth_get_tls_authentication_mode gst_rtsp_auth_get_tls_certificate gst_rtsp_auth_get_tls_database @@ -20,7 +22,9 @@ EXPORTS gst_rtsp_auth_make_basic gst_rtsp_auth_new gst_rtsp_auth_remove_basic + gst_rtsp_auth_remove_digest gst_rtsp_auth_set_default_token + gst_rtsp_auth_set_supported_methods gst_rtsp_auth_set_tls_authentication_mode gst_rtsp_auth_set_tls_certificate gst_rtsp_auth_set_tls_database From 6622b5be14c1a094358c0dbbd497c84f1a11aef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 18 Nov 2016 17:47:13 +0200 Subject: [PATCH 1320/1776] rtspclientsink: Move to new helper function to parse authentication responses https://bugzilla.gnome.org/show_bug.cgi?id=774416 --- gst/rtsp-sink/gstrtspclientsink.c | 176 ++++++------------------------ 1 file changed, 35 insertions(+), 141 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index cc3aa96166..88a59644dc 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -2318,131 +2318,6 @@ gst_rtsp_auth_method_to_string (GstRTSPAuthMethod method) } #endif -static const gchar * -gst_rtsp_client_sink_skip_lws (const gchar * s) -{ - while (g_ascii_isspace (*s)) - s++; - return s; -} - -static const gchar * -gst_rtsp_client_sink_unskip_lws (const gchar * s, const gchar * start) -{ - while (s > start && g_ascii_isspace (*(s - 1))) - s--; - return s; -} - -static const gchar * -gst_rtsp_client_sink_skip_commas (const gchar * s) -{ - /* The grammar allows for multiple commas */ - while (g_ascii_isspace (*s) || *s == ',') - s++; - return s; -} - -static const gchar * -gst_rtsp_client_sink_skip_item (const gchar * s) -{ - gboolean quoted = FALSE; - const gchar *start = s; - - /* A list item ends at the last non-whitespace character - * before a comma which is not inside a quoted-string. Or at - * the end of the string. - */ - while (*s) { - if (*s == '"') - quoted = !quoted; - else if (quoted) { - if (*s == '\\' && *(s + 1)) - s++; - } else { - if (*s == ',') - break; - } - s++; - } - - return gst_rtsp_client_sink_unskip_lws (s, start); -} - -static void -gst_rtsp_decode_quoted_string (gchar * quoted_string) -{ - gchar *src, *dst; - - src = quoted_string + 1; - dst = quoted_string; - while (*src && *src != '"') { - if (*src == '\\' && *(src + 1)) - src++; - *dst++ = *src++; - } - *dst = '\0'; -} - -/* Extract the authentication tokens that the server provided for each method - * into an array of structures and give those to the connection object. - */ -static void -gst_rtsp_client_sink_parse_digest_challenge (GstRTSPConnection * conn, - const gchar * header, gboolean * stale) -{ - GSList *list = NULL, *iter; - const gchar *end; - gchar *item, *eq, *name_end, *value; - - g_return_if_fail (stale != NULL); - - gst_rtsp_connection_clear_auth_params (conn); - *stale = FALSE; - - /* Parse a header whose content is described by RFC2616 as - * "#something", where "something" does not itself contain commas, - * except as part of quoted-strings, into a list of allocated strings. - */ - header = gst_rtsp_client_sink_skip_commas (header); - while (*header) { - end = gst_rtsp_client_sink_skip_item (header); - list = g_slist_prepend (list, g_strndup (header, end - header)); - header = gst_rtsp_client_sink_skip_commas (end); - } - if (!list) - return; - - list = g_slist_reverse (list); - for (iter = list; iter; iter = iter->next) { - item = iter->data; - - eq = strchr (item, '='); - if (eq) { - name_end = (gchar *) gst_rtsp_client_sink_unskip_lws (eq, item); - if (name_end == item) { - /* That's no good... */ - g_free (item); - continue; - } - - *name_end = '\0'; - - value = (gchar *) gst_rtsp_client_sink_skip_lws (eq + 1); - if (*value == '"') - gst_rtsp_decode_quoted_string (value); - } else - value = NULL; - - if (value && strcmp (item, "stale") == 0 && strcmp (value, "TRUE") == 0) - *stale = TRUE; - gst_rtsp_connection_set_auth_param (conn, item, value); - g_free (item); - } - - g_slist_free (list); -} - /* Parse a WWW-Authenticate Response header and determine the * available authentication methods * @@ -2452,24 +2327,47 @@ gst_rtsp_client_sink_parse_digest_challenge (GstRTSPConnection * conn, * At the moment, for Basic auth, we just do a minimal check and don't * even parse out the realm */ static void -gst_rtsp_client_sink_parse_auth_hdr (gchar * hdr, GstRTSPAuthMethod * methods, - GstRTSPConnection * conn, gboolean * stale) +gst_rtsp_client_sink_parse_auth_hdr (GstRTSPMessage * response, + GstRTSPAuthMethod * methods, GstRTSPConnection * conn, gboolean * stale) { - gchar *start; + GstRTSPAuthCredential **credentials, **credential; - g_return_if_fail (hdr != NULL); + g_return_if_fail (response != NULL); g_return_if_fail (methods != NULL); g_return_if_fail (stale != NULL); - /* Skip whitespace at the start of the string */ - for (start = hdr; start[0] != '\0' && g_ascii_isspace (start[0]); start++); + credentials = + gst_rtsp_message_parse_auth_credentials (response, + GST_RTSP_HDR_WWW_AUTHENTICATE); + if (!credentials) + return; - if (g_ascii_strncasecmp (start, "basic", 5) == 0) - *methods |= GST_RTSP_AUTH_BASIC; - else if (g_ascii_strncasecmp (start, "digest ", 7) == 0) { - *methods |= GST_RTSP_AUTH_DIGEST; - gst_rtsp_client_sink_parse_digest_challenge (conn, &start[7], stale); + credential = credentials; + while (*credential) { + if ((*credential)->scheme == GST_RTSP_AUTH_BASIC) { + *methods |= GST_RTSP_AUTH_BASIC; + } else if ((*credential)->scheme == GST_RTSP_AUTH_DIGEST) { + GstRTSPAuthParam **param = (*credential)->params; + + *methods |= GST_RTSP_AUTH_DIGEST; + + gst_rtsp_connection_clear_auth_params (conn); + *stale = FALSE; + + while (*param) { + if (strcmp ((*param)->name, "stale") == 0 + && g_ascii_strcasecmp ((*param)->value, "TRUE") == 0) + *stale = TRUE; + gst_rtsp_connection_set_auth_param (conn, (*param)->name, + (*param)->value); + param++; + } + } + + credential++; } + + gst_rtsp_auth_credentials_free (credentials); } /** @@ -2497,16 +2395,12 @@ gst_rtsp_client_sink_setup_auth (GstRTSPClientSink * sink, GstRTSPResult auth_result; GstRTSPUrl *url; GstRTSPConnection *conn; - gchar *hdr; gboolean stale = FALSE; conn = sink->conninfo.connection; /* Identify the available auth methods and see if any are supported */ - if (gst_rtsp_message_get_header (response, GST_RTSP_HDR_WWW_AUTHENTICATE, - &hdr, 0) == GST_RTSP_OK) { - gst_rtsp_client_sink_parse_auth_hdr (hdr, &avail_methods, conn, &stale); - } + gst_rtsp_client_sink_parse_auth_hdr (response, &avail_methods, conn, &stale); if (avail_methods == GST_RTSP_AUTH_NONE) goto no_auth_available; From 335d279a96bc91fda43ee3e1028ee3c327e542ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Mon, 21 Nov 2016 13:05:50 +0100 Subject: [PATCH 1321/1776] rtsp-stream: Set close-socket FALSE on UDP src:es With this RTSP server can use the sockets independent on the udpsrc state. When the udp src is finalized it will unref socket and when g_socket is finalized the socket will be closed. https://bugzilla.gnome.org/show_bug.cgi?id=765673 --- gst/rtsp-server/rtsp-stream.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 9fd3e0037b..f5b5cf2d45 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1176,6 +1176,9 @@ create_and_configure_udpsources (GstElement * udpsrc_out[2], g_object_set (G_OBJECT (udpsrc_out[0]), "loop", FALSE, NULL); g_object_set (G_OBJECT (udpsrc_out[1]), "loop", FALSE, NULL); + g_object_set (G_OBJECT (udpsrc_out[0]), "close-socket", FALSE, NULL); + g_object_set (G_OBJECT (udpsrc_out[1]), "close-socket", FALSE, NULL); + ret = gst_element_set_state (udpsrc_out[0], GST_STATE_READY); if (ret == GST_STATE_CHANGE_FAILURE) goto error; From 9777e4dcd67396dcd88c648e5b930e68101c9705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 23 Nov 2016 09:45:08 +0000 Subject: [PATCH 1322/1776] .gitignore more --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0af63a739a..82aec05c40 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ stamp-h.in /examples/test-multicast /examples/test-multicast2 +/examples/test-auth-digest /test-driver /tests/check/gst/*.log From f00ac2daf244fecf59272bfd841685cc0af7d512 Mon Sep 17 00:00:00 2001 From: Dag Gullberg Date: Mon, 21 Nov 2016 16:02:39 +0100 Subject: [PATCH 1323/1776] rtsp-client: add IDLE timeout, before session exists The RTSP server will not timeout an idle RTSP connection (note this is different from doing timeout on a RTSP session). At least for Apache this is a problem when running RTSP over HTTPS since it uses one of the threads (there is a rather limited number) that are available for handling requests. https://bugzilla.gnome.org/show_bug.cgi?id=771830 --- gst/rtsp-server/rtsp-client.c | 65 +++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index ab6e8650c5..6f59c5e43d 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -90,6 +90,9 @@ struct _GstRTSPClientPrivate guint sessions_cookie; gboolean drop_backlog; + + guint rtsp_ctrl_timeout_id; + guint rtsp_ctrl_timeout_cnt; }; static GMutex tunnels_lock; @@ -103,6 +106,9 @@ static GHashTable *tunnels; /* protected by tunnels_lock */ #define DEFAULT_MOUNT_POINTS NULL #define DEFAULT_DROP_BACKLOG TRUE +#define RTSP_CTRL_CB_INTERVAL 1 +#define RTSP_CTRL_TIMEOUT_VALUE 60 + enum { PROP_0, @@ -2140,6 +2146,47 @@ handle_keymgmt (GstRTSPClient * client, GstRTSPContext * ctx, gchar * keymgmt) return TRUE; } +static gboolean +rtsp_ctrl_timeout_cb (gpointer user_data) +{ + gboolean res = G_SOURCE_CONTINUE; + GstRTSPClient *client = (GstRTSPClient *) user_data; + GstRTSPClientPrivate *priv = client->priv; + + priv->rtsp_ctrl_timeout_cnt += RTSP_CTRL_CB_INTERVAL; + + if (priv->rtsp_ctrl_timeout_cnt > RTSP_CTRL_TIMEOUT_VALUE) { + GST_DEBUG ("rtsp control session timeout id=%u expired, closing client.", + priv->rtsp_ctrl_timeout_id); + g_mutex_lock (&priv->lock); + priv->rtsp_ctrl_timeout_id = 0; + priv->rtsp_ctrl_timeout_cnt = 0; + g_mutex_unlock (&priv->lock); + gst_rtsp_client_close (client); + + res = G_SOURCE_REMOVE; + } + + return res; +} + +static void +rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv) +{ + g_mutex_lock (&priv->lock); + + if (priv->rtsp_ctrl_timeout_id != 0) { + g_source_destroy (g_main_context_find_source_by_id (priv->watch_context, + priv->rtsp_ctrl_timeout_id)); + GST_DEBUG ("rtsp control session removed timeout id=%u.", + priv->rtsp_ctrl_timeout_id); + priv->rtsp_ctrl_timeout_id = 0; + priv->rtsp_ctrl_timeout_cnt = 0; + } + + g_mutex_unlock (&priv->lock); +} + static gboolean handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) { @@ -2256,6 +2303,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->session = session; } + rtsp_ctrl_timeout_remove (priv); + if (!klass->configure_client_media (client, media, stream, ctx)) goto configure_media_failed_no_reply; @@ -4242,6 +4291,7 @@ client_watch_notify (GstRTSPClient * client) GST_INFO ("client %p: watch destroyed", client); priv->watch = NULL; /* remove all sessions if the media says so and so drop the extra client ref */ + rtsp_ctrl_timeout_remove (priv); gst_rtsp_client_session_filter (client, cleanup_session, &closed); if (closed) g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL); @@ -4266,6 +4316,7 @@ guint gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) { GstRTSPClientPrivate *priv; + GSource *timer_src; guint res; g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0); @@ -4287,6 +4338,20 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) GST_INFO ("client %p: attaching to context %p", client, context); res = gst_rtsp_watch_attach (priv->watch, context); + /* Setting up a timeout for the RTSP control channel until a session + * is up where it is handling timeouts. */ + rtsp_ctrl_timeout_remove (priv); /* removing old if any */ + g_mutex_lock (&priv->lock); + + timer_src = g_timeout_source_new_seconds (RTSP_CTRL_CB_INTERVAL); + g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client, NULL); + priv->rtsp_ctrl_timeout_id = g_source_attach (timer_src, priv->watch_context); + g_source_unref (timer_src); + GST_DEBUG ("rtsp control setting up session timeout id=%u.", + priv->rtsp_ctrl_timeout_id); + + g_mutex_unlock (&priv->lock); + return res; } From b38eb8e99efe0147b15ed443d2481d3786d9e1df Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 21 Nov 2016 23:29:56 +1100 Subject: [PATCH 1324/1776] stream: block the output of rtpbin instead of the source pipeline 85c52e194bcb81928b96614be0ae47d59eccb1ce introduced a more correct detection of the srtp rollover counter to add to the SDP. Unfortunately, it was incomplete for live pipelines where the logic blocks the source bin before creating the SDP and thus would never have the necessary informaiton to create a correct SDP with srtp encryption. Move the pad blocks to rtpbin's output pads instead so that the necessary information can be created before we need the information for the SDP. https://bugzilla.gnome.org/show_bug.cgi?id=770239 --- gst/rtsp-server/rtsp-stream.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index f5b5cf2d45..d10b1392b8 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -149,7 +149,7 @@ struct _GstRTSPStreamPrivate gint dscp_qos; /* stream blocking */ - gulong blocked_id; + gulong blocked_id[2]; gboolean blocking; /* pt->caps map for RECORD streams */ @@ -3689,6 +3689,7 @@ gboolean gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked) { GstRTSPStreamPrivate *priv; + int i; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); @@ -3697,18 +3698,22 @@ gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked) g_mutex_lock (&priv->lock); if (blocked) { priv->blocking = FALSE; - if (priv->blocked_id == 0) { - priv->blocked_id = gst_pad_add_probe (priv->srcpad, - GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER | - GST_PAD_PROBE_TYPE_BUFFER_LIST, pad_blocking, - g_object_ref (stream), g_object_unref); + for (i = 0; i < 2; i++) { + if (priv->blocked_id[i] == 0) { + priv->blocked_id[i] = gst_pad_add_probe (priv->send_src[i], + GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER | + GST_PAD_PROBE_TYPE_BUFFER_LIST, pad_blocking, + g_object_ref (stream), g_object_unref); + } } } else { - if (priv->blocked_id != 0) { - gst_pad_remove_probe (priv->srcpad, priv->blocked_id); - priv->blocked_id = 0; - priv->blocking = FALSE; + for (i = 0; i < 2; i++) { + if (priv->blocked_id[i] != 0) { + gst_pad_remove_probe (priv->send_src[i], priv->blocked_id[i]); + priv->blocked_id[i] = 0; + } } + priv->blocking = FALSE; } g_mutex_unlock (&priv->lock); From 628c613a0ae8a2c0d49d1944cae6bee82ae38fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 26 Nov 2016 11:24:50 +0000 Subject: [PATCH 1325/1776] common: use https protocol for common submodule https://bugzilla.gnome.org/show_bug.cgi?id=775110 --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index a6b1edac4c..3ff9d95ea0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "common"] path = common - url = git://anongit.freedesktop.org/gstreamer/common + url = https://anongit.freedesktop.org/git/gstreamer/common.git From cc59abc8246749662e28737c0c7ecab289aeb9fc Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Wed, 30 Nov 2016 14:06:36 +1100 Subject: [PATCH 1326/1776] rtspclientsink: Don't leave stale pointer after unref Fix a warning on shutdown - don't keep a pointer to an alread-unreffed object. --- gst/rtsp-sink/gstrtspclientsink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 88a59644dc..b2aaec882e 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -1559,8 +1559,10 @@ gst_rtsp_client_sink_cleanup (GstRTSPClientSink * sink) context->stream = NULL; } - if (context->srtcpparams) + if (context->srtcpparams) { gst_caps_unref (context->srtcpparams); + context->srtcpparams = NULL; + } g_free (context->conninfo.location); context->conninfo.location = NULL; } From 09e499387d3ffce24a09bf31c365fabb4354013f Mon Sep 17 00:00:00 2001 From: Kseniia Vasilchuk Date: Tue, 25 Oct 2016 15:41:28 +0300 Subject: [PATCH 1327/1776] media: Fix race condition around finish_unprepare() if called multiple time https://bugzilla.gnome.org/show_bug.cgi?id=755329 --- gst/rtsp-server/rtsp-media.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 52e6757ee7..4858b13a05 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3050,6 +3050,10 @@ finish_unprepare (GstRTSPMedia * media) g_rec_mutex_unlock (&priv->state_lock); set_state (media, GST_STATE_NULL); g_rec_mutex_lock (&priv->state_lock); + + if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARING) + return; + remove_fakesink (priv); for (i = 0; i < priv->streams->len; i++) { @@ -3168,6 +3172,7 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) if (klass->unprepare) success = klass->unprepare (media); } else { + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_UNPREPARING); finish_unprepare (media); } g_rec_mutex_unlock (&priv->state_lock); From 708fd3c325573b294e1c9a5ebc96ca4194e3e505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 1 Dec 2016 18:04:34 +0200 Subject: [PATCH 1328/1776] rtsp-media-factory: Don't create a pipeline for the media pipeline string We're going to put a pipeline into a pipeline otherwise, which is not exactly ideal. --- gst/rtsp-server/rtsp-media-factory.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 09e5160423..9cea6ca962 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -1414,7 +1414,9 @@ default_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) goto no_launch; /* parse the user provided launch line */ - element = gst_parse_launch (priv->launch, &error); + element = + gst_parse_launch_full (priv->launch, NULL, GST_PARSE_FLAG_PLACE_IN_BIN, + &error); if (element == NULL) goto parse_error; From d633c0103a3c1b92b76f5e5b469642a660527ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 2 Dec 2016 14:36:50 +0200 Subject: [PATCH 1329/1776] rtsp-auth: Don't remove digest-auth nonces that already/still have a client connected --- gst/rtsp-server/rtsp-auth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 5bca6f6f24..85758c4cb9 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -831,7 +831,8 @@ default_generate_authenticate_header (GstRTSPAuth * auth, GstRTSPContext * ctx) while (g_hash_table_iter_next (&iter, &key, &value)) { GstRTSPDigestNonce *tmp = value; - if (nonce->timestamp - tmp->timestamp >= 30 * G_USEC_PER_SEC) + if (!tmp->client + && nonce->timestamp - tmp->timestamp >= 30 * G_USEC_PER_SEC) g_hash_table_iter_remove (&iter); } auth->priv->last_nonce_check = nonce->timestamp; From 8317139121888c43a9745beb29b0e71a9a6d0881 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 2 Dec 2016 15:38:04 +0100 Subject: [PATCH 1330/1776] media-factory: Create media objects with the proper transport mode The function called immediately afterwards (collect_streams()) will need it to work properly --- gst/rtsp-server/rtsp-media-factory.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 9cea6ca962..191480f8ba 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -1469,7 +1469,9 @@ default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); /* create a new empty media */ - media = g_object_new (media_gtype, "element", element, NULL); + media = + g_object_new (media_gtype, "element", element, "transport-mode", + factory->priv->transport_mode, NULL); gst_rtsp_media_collect_streams (media); From dea000f2e3057109b390e94a1b6e389b4ac8b96c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 2 Dec 2016 15:40:09 +0100 Subject: [PATCH 1331/1776] media: Fix pt map caps Since decryption is handled within rtpbin, all outcoming stream caps will be application/x-rtp (i.e. regular rtp) Fixes RECORD with SRTP streams --- gst/rtsp-server/rtsp-media.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4858b13a05..a7f3460032 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3380,7 +3380,7 @@ default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp) } for (i = 0; i < medias_len; i++) { - const gchar *proto, *media_type; + const gchar *proto; const GstSDPMedia *sdp_media = gst_sdp_message_get_media (sdp, i); GstRTSPStream *stream; gint j, formats_len; @@ -3399,16 +3399,12 @@ default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp) } if (g_str_equal (proto, "RTP/AVP")) { - media_type = "application/x-rtp"; profile = GST_RTSP_PROFILE_AVP; } else if (g_str_equal (proto, "RTP/SAVP")) { - media_type = "application/x-srtp"; profile = GST_RTSP_PROFILE_SAVP; } else if (g_str_equal (proto, "RTP/AVPF")) { - media_type = "application/x-rtp"; profile = GST_RTSP_PROFILE_AVPF; } else if (g_str_equal (proto, "RTP/SAVPF")) { - media_type = "application/x-srtp"; profile = GST_RTSP_PROFILE_SAVPF; } else { GST_ERROR ("%p: unsupported profile '%s' for stream %d", media, proto, i); @@ -3445,7 +3441,7 @@ default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp) gst_sdp_media_attributes_to_caps (sdp_media, caps); s = gst_caps_get_structure (caps, 0); - gst_structure_set_name (s, media_type); + gst_structure_set_name (s, "application/x-rtp"); gst_rtsp_stream_set_pt_map (stream, pt, caps); gst_caps_unref (caps); From b7769a6dee19bbb26d713dad80f685971c163b68 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 3 Dec 2016 08:21:02 +0100 Subject: [PATCH 1332/1776] Automatic update of common submodule From f980fd9 to 39ac2f5 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index f980fd91c1..39ac2f563e 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit f980fd91c1c1fd01333966041a4a535366e897bd +Subproject commit 39ac2f563e12d22100e320c95aaab8d8e5812ca9 From 143063a68f2676a0bb1b70bd49a093031193f276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 16 Dec 2016 17:26:04 +0000 Subject: [PATCH 1333/1776] Remove generated .spec file Likely extremely bitrotten, and we should not ship this anyway. --- .gitignore | 1 - Makefile.am | 5 +++-- configure.ac | 1 - gst-rtsp.spec.in | 54 ------------------------------------------------ 4 files changed, 3 insertions(+), 58 deletions(-) delete mode 100644 gst-rtsp.spec.in diff --git a/.gitignore b/.gitignore index 82aec05c40..2d4d543b41 100644 --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,6 @@ ltmain.sh missing stamp-h1 tags -gst-rtsp.spec stamp-h.in .dirstamp diff --git a/Makefile.am b/Makefile.am index 7ece053671..eb01c6a53d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,13 +22,13 @@ include $(top_srcdir)/common/win32.mak EXTRA_DIST = \ ChangeLog autogen.sh depcomp \ AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \ - gst-rtsp.spec docs/design/gst-rtp-server-design \ + docs/design/gst-rtp-server-design \ gst-rtsp-server.doap \ $(win32) ACLOCAL_AMFLAGS = -I m4 -I common/m4 -DISTCLEANFILES = _stdint.h gst-rtsp.spec +DISTCLEANFILES = _stdint.h include $(top_srcdir)/common/release.mak include $(top_srcdir)/common/po.mak @@ -52,6 +52,7 @@ endif # cruft: plugins that have been merged or moved or renamed CRUFT_FILES = \ + $(top_builddir)/gst-rtsp.spec \ $(top_builddir)/common/shave \ $(top_builddir)/common/shave-libtool \ $(top_builddir)/common/m4/codeset.m4 \ diff --git a/configure.ac b/configure.ac index 4f85610e69..8167ff9fdd 100644 --- a/configure.ac +++ b/configure.ac @@ -356,7 +356,6 @@ dnl *** output files *** dnl keep this alphabetic per directory, please AC_CONFIG_FILES([ Makefile -gst-rtsp.spec common/Makefile common/m4/Makefile gst/Makefile diff --git a/gst-rtsp.spec.in b/gst-rtsp.spec.in deleted file mode 100644 index 12224f8bab..0000000000 --- a/gst-rtsp.spec.in +++ /dev/null @@ -1,54 +0,0 @@ -%define gst_majorminor @GST_API_VERSION@ - -Name: gstreamer-rtsp-server -Version: @VERSION@ -Release: 1%{?dist} -Summary: GStreamer based RTSP server -Vendor: Collabora Multimedia -Group: Applications/Multimedia -License: LGPLv2+ -Source0: gst-rtsp-%{version}.tar.bz2 -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: gstreamer-devel >= 0.10.11 - - -%description -This is a RTSP server using the GStreamer framework. - - -%prep -%setup -q -n gst-rtsp-%{version} - - -%build -%configure - -make - -%install -%makeinstall - -# Clean out files that should not be part of the rpm. -rm -f $RPM_BUILD_ROOT%{_libdir}/gstreamer-%{majorminor}/*.a -rm -f $RPM_BUILD_ROOT%{_libdir}/*.a -rm -f $RPM_BUILD_ROOT%{_libdir}/*.la - -%clean -rm -rf $RPM_BUILD_ROOT - - -%post -p /sbin/ldconfig - - -%postun -p /sbin/ldconfig - - -%files -%defattr(-,root,root,-) -%doc AUTHORS COPYING README INSTALL docs/design/gst-rtp-server-design -%{_bindir}/gst-rtsp-server - -%changelog -* Thu Oct 9 2008 Christian Schaller -- First spec file From 42f270e7f2406ce7080f091abc934f59d139f761 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Wed, 21 Dec 2016 13:41:50 +0100 Subject: [PATCH 1334/1776] rtsp-stream: Fixed TCP transport case Make sure that the appsink element is actually added to the bin before trying to link it with the elements in it. https://bugzilla.gnome.org/show_bug.cgi?id=776343 --- gst/rtsp-server/rtsp-stream.c | 1 + tests/check/gst/rtspserver.c | 124 +++++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index d10b1392b8..ee92b84d16 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2462,6 +2462,7 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) } } else if (is_tcp) { /* only appsink needed, link it to the session */ + gst_bin_add (bin, priv->appsink[i]); pad = gst_element_get_static_pad (priv->appsink[i], "sink"); gst_pad_link (priv->send_src[i], pad); gst_object_unref (pad); diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 9a9f58f94f..1a92d52bce 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -191,6 +191,40 @@ start_server (gboolean set_shared_factory) GST_DEBUG ("rtsp server listening on port %d", test_port); } +static void +start_tcp_server (void) +{ + GstRTSPMountPoints *mounts; + gchar *service; + GstRTSPMediaFactory *factory; + + mounts = gst_rtsp_server_get_mount_points (server); + + factory = gst_rtsp_media_factory_new (); + + gst_rtsp_media_factory_set_protocols (factory, GST_RTSP_LOWER_TRANS_TCP); + gst_rtsp_media_factory_set_launch (factory, + "( " VIDEO_PIPELINE " " AUDIO_PIPELINE " )"); + gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); + g_object_unref (mounts); + + /* set port to any */ + gst_rtsp_server_set_service (server, "0"); + + /* attach to default main context */ + source_id = gst_rtsp_server_attach (server, NULL); + fail_if (source_id == 0); + + /* get port */ + service = gst_rtsp_server_get_service (server); + test_port = atoi (service); + fail_unless (test_port != 0); + g_free (service); + + GST_DEBUG ("rtsp server listening on port %d", test_port); + +} + /* start the testing rtsp server for RECORD mode */ static GstRTSPMediaFactory * start_record_server (const gchar * launch_line) @@ -296,6 +330,7 @@ static GstRTSPMessage * read_response (GstRTSPConnection * conn) { GstRTSPMessage *response = NULL; + GstRTSPMsgType type; if (gst_rtsp_message_new (&response) != GST_RTSP_OK) { GST_DEBUG ("failed to create response object"); @@ -306,8 +341,8 @@ read_response (GstRTSPConnection * conn) gst_rtsp_message_free (response); return NULL; } - fail_unless (gst_rtsp_message_get_type (response) == - GST_RTSP_MESSAGE_RESPONSE); + type = gst_rtsp_message_get_type (response); + fail_unless (type == GST_RTSP_MESSAGE_RESPONSE || type == GST_RTSP_MESSAGE_DATA); return response; } @@ -325,6 +360,7 @@ do_request_full (GstRTSPConnection * conn, GstRTSPMethod method, GstRTSPMessage *response; GstRTSPStatusCode code; gchar *value; + GstRTSPMsgType msg_type; /* create request */ request = create_request (conn, method, control); @@ -351,6 +387,19 @@ do_request_full (GstRTSPConnection * conn, GstRTSPMethod method, /* read response */ response = read_response (conn); + fail_unless (response != NULL); + + msg_type = gst_rtsp_message_get_type (response); + + if (msg_type == GST_RTSP_MESSAGE_DATA) { + do { + gst_rtsp_message_free (response); + response = read_response (conn); + msg_type = gst_rtsp_message_get_type (response); + } while (msg_type == GST_RTSP_MESSAGE_DATA); + } + + fail_unless (msg_type == GST_RTSP_MESSAGE_RESPONSE); /* check status line */ gst_rtsp_message_parse_response (response, &code, NULL, NULL); @@ -1105,6 +1154,76 @@ GST_START_TEST (test_play) GST_END_TEST; +GST_START_TEST (test_play_tcp) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + const gchar *audio_control; + GstRTSPRange client_ports = { 0 }; + gchar *session = NULL; + GstRTSPTransport *video_transport = NULL; + GstRTSPTransport *audio_transport = NULL; + + start_tcp_server (); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + /* send DESCRIBE request */ + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + sdp_media = gst_sdp_message_get_media (sdp_message, 1); + audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports (&client_ports); + + /* send SETUP request for the first media */ + fail_unless (do_setup_full (conn, video_control, GST_RTSP_LOWER_TRANS_TCP, + &client_ports, NULL, &session, &video_transport, + NULL) == GST_RTSP_STS_OK); + + /* check response from SETUP */ + fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP); + fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP); + fail_unless (video_transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP); + fail_unless (video_transport->mode_play); + gst_rtsp_transport_free (video_transport); + + /* send SETUP request for the second media */ + fail_unless (do_setup_full (conn, audio_control, GST_RTSP_LOWER_TRANS_TCP, + &client_ports, NULL, &session, &audio_transport, + NULL) == GST_RTSP_STS_OK); + + /* check response from SETUP */ + fail_unless (audio_transport->trans == GST_RTSP_TRANS_RTP); + fail_unless (audio_transport->profile == GST_RTSP_PROFILE_AVP); + fail_unless (audio_transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP); + fail_unless (audio_transport->mode_play); + gst_rtsp_transport_free (audio_transport); + + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_PLAY, + session)== GST_RTSP_STS_OK); + + /* send TEARDOWN request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session) == GST_RTSP_STS_OK); + + /* clean up and iterate so the clean-up can finish */ + g_free (session); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + stop_server (); + iterate (); +} + +GST_END_TEST; + GST_START_TEST (test_play_without_session) { GstRTSPConnection *conn; @@ -1992,6 +2111,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_setup_with_require_header); tcase_add_test (tc, test_setup_non_existing_stream); tcase_add_test (tc, test_play); + tcase_add_test (tc, test_play_tcp); tcase_add_test (tc, test_play_without_session); tcase_add_test (tc, test_bind_already_in_use); tcase_add_test (tc, test_play_multithreaded); From 3a911a2f58002e3e2a99031d19b37bc1161c49c8 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Wed, 4 Jan 2017 16:11:08 +0100 Subject: [PATCH 1335/1776] pkgconfig: fix -uninstalled pc file pcfiledir was never defined so the paths were wrong. https://bugzilla.gnome.org/show_bug.cgi?id=776867 --- pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in index 2aec3cc1a3..9efea8f400 100644 --- a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in +++ b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in @@ -1,8 +1,8 @@ # the standard variables don't make sense for an uninstalled copy prefix= exec_prefix= -libdir=${pcfiledir}/../gst/rtsp-server/.libs -includedir=${pcfiledir}/.. +libdir=@abs_top_builddir@/gst/rtsp-server/.libs +includedir=@abs_top_builddir@ Name: gst-rtsp-server Description: GStreamer based RTSP server From e6c6bf96ce7d3240b5343c52ff6218a323258781 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Wed, 4 Jan 2017 16:20:54 +0100 Subject: [PATCH 1336/1776] meson: generate pkg-config -uninstalled pc files Generating those files is useful for users building the GStreamer stack using meson and having to link it to another project which is still using the autotools. https://bugzilla.gnome.org/show_bug.cgi?id=776810 --- pkgconfig/Makefile.am | 6 +++++- pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in | 2 +- pkgconfig/meson.build | 12 +++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am index c45755eaf9..cf36182e0d 100644 --- a/pkgconfig/Makefile.am +++ b/pkgconfig/Makefile.am @@ -10,7 +10,11 @@ all-local: $(pcfiles) $(pcfiles_uninstalled) %-@GST_API_VERSION@.pc: %.pc cp $< $@ %-@GST_API_VERSION@-uninstalled.pc: %-uninstalled.pc - cp $< $@ +### the uninstalled libdir is depend of the build system used so set it here +### rather than hardcoding it in the file directly. + $(AM_V_GEN) sed \ + -e "s|[@]rtspserverlibdir[@]|$(abs_top_builddir)/gst/rtsp-server/.libs|" \ + $< > $@.tmp && mv $@.tmp $@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pcfiles) diff --git a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in index 9efea8f400..6c9afd6760 100644 --- a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in +++ b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in @@ -1,7 +1,7 @@ # the standard variables don't make sense for an uninstalled copy prefix= exec_prefix= -libdir=@abs_top_builddir@/gst/rtsp-server/.libs +libdir=@rtspserverlibdir@ includedir=@abs_top_builddir@ Name: gst-rtsp-server diff --git a/pkgconfig/meson.build b/pkgconfig/meson.build index c4b7179f1f..f10d572464 100644 --- a/pkgconfig/meson.build +++ b/pkgconfig/meson.build @@ -7,11 +7,21 @@ pkgconf.set('includedir', '${prefix}/@0@'.format(get_option('includedir'))) pkgconf.set('GST_API_VERSION', api_version) pkgconf.set('VERSION', gst_version) +# needed for generating -uninstalled.pc files +pkgconf.set('abs_top_builddir', join_paths(meson.current_build_dir(), '..')) +pkgconf.set('abs_top_srcdir', join_paths(meson.current_source_dir(), '..')) +pkgconf.set('rtspserverlibdir', join_paths(meson.build_root(), gst_rtsp_server.outdir())) + pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir')) -# FIXME: -uninstalled.pc files (if still needed?) configure_file(input : 'gstreamer-rtsp-server.pc.in', output : 'gstreamer-rtsp-server-1.0.pc', configuration : pkgconf, install_dir : pkg_install_dir, ) + +configure_file(input : 'gstreamer-rtsp-server-uninstalled.pc.in', + output : 'gstreamer-rtsp-server-1.0-uninstalled.pc', + configuration : pkgconf, + install_dir : pkg_install_dir +) From b27e7c6b5bc7b5ab23ef5d833bd413ce7841db8b Mon Sep 17 00:00:00 2001 From: Aleksandr Slobodeniuk Date: Mon, 9 Jan 2017 12:22:40 +0300 Subject: [PATCH 1337/1776] dosc: Fix a little typo https://bugzilla.gnome.org/show_bug.cgi?id=777037 --- gst/rtsp-server/rtsp-media-factory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 191480f8ba..fc760aab1c 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -156,7 +156,7 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) * default prepare vmethod. * * The pipeline description should return a GstBin as the toplevel element - * which can be accomplished by enclosing the dscription with brackets '(' + * which can be accomplished by enclosing the description with brackets '(' * ')'. * * The description should return a pipeline with payloaders named pay0, pay1, @@ -504,7 +504,7 @@ gst_rtsp_media_factory_add_role (GstRTSPMediaFactory * factory, * default prepare vmethod. * * The pipeline description should return a GstBin as the toplevel element - * which can be accomplished by enclosing the dscription with brackets '(' + * which can be accomplished by enclosing the description with brackets '(' * ')'. * * The description should return a pipeline with payloaders named pay0, pay1, From f47e6ab9f69ec1c77f8875ca41ee5ff268ab06ab Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Mon, 9 Jan 2017 14:12:05 +0100 Subject: [PATCH 1338/1776] rtsp-stream: fixed segmenation fault in _get_server_port() Calling function gst_rtsp_stream_get_server_port() results in segmenation fault in the RTP/RTSP/TCP case. Port that the server will use to receive RTCP makes only sense in the UDP case, however the function should handle the TCP case in a nicer way. https://bugzilla.gnome.org/show_bug.cgi?id=776345 --- gst/rtsp-server/rtsp-stream.c | 9 ++++++-- tests/check/gst/stream.c | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index ee92b84d16..6af69b480f 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1525,15 +1525,20 @@ gst_rtsp_stream_get_server_port (GstRTSPStream * stream, priv = stream->priv; g_return_if_fail (priv->joined_bin != NULL); + if (server_port) { + server_port->min = 0; + server_port->max = 0; + } + g_mutex_lock (&priv->lock); - if (family == G_SOCKET_FAMILY_IPV4) { + if (family == G_SOCKET_FAMILY_IPV4 && priv->server_addr_v4) { if (server_port) { server_port->min = priv->server_addr_v4->port; server_port->max = priv->server_addr_v4->port + priv->server_addr_v4->n_ports - 1; } } else { - if (server_port) { + if (server_port && priv->server_addr_v6) { server_port->min = priv->server_addr_v6->port; server_port->max = priv->server_addr_v6->port + priv->server_addr_v6->n_ports - 1; diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index 0447acc2b2..979c0d65aa 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -385,6 +385,47 @@ GST_START_TEST (test_allocate_udp_ports_client_settings) GST_END_TEST; +GST_START_TEST (test_tcp_transport) +{ + GstPad *srcpad; + GstElement *pay; + GstRTSPStream *stream; + GstBin *bin; + GstElement *rtpbin; + GstRTSPRange server_port; + + srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); + fail_unless (srcpad != NULL); + gst_pad_set_active (srcpad, TRUE); + pay = gst_element_factory_make ("rtpgstpay", "testpayloader"); + fail_unless (pay != NULL); + stream = gst_rtsp_stream_new (0, pay, srcpad); + fail_unless (stream != NULL); + gst_object_unref (pay); + gst_object_unref (srcpad); + rtpbin = gst_element_factory_make ("rtpbin", "testrtpbin"); + fail_unless (rtpbin != NULL); + bin = GST_BIN (gst_bin_new ("testbin")); + fail_unless (bin != NULL); + fail_unless (gst_bin_add (bin, rtpbin)); + + /* TCP transport */ + gst_rtsp_stream_set_protocols (stream, GST_RTSP_LOWER_TRANS_TCP); + fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + + /* port that the server will use to receive RTCP makes only sense in the UDP + * case so verify that the received server port is 0 in the TCP case */ + gst_rtsp_stream_get_server_port (stream, &server_port, G_SOCKET_FAMILY_IPV4); + fail_unless_equals_int (server_port.min, 0); + fail_unless_equals_int (server_port.max, 0); + + fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); + gst_object_unref (bin); + gst_object_unref (stream); +} + +GST_END_TEST; + static Suite * rtspstream_suite (void) { @@ -398,6 +439,7 @@ rtspstream_suite (void) tcase_add_test (tc, test_multicast_address_and_unicast_udp); tcase_add_test (tc, test_allocate_udp_ports_multicast); tcase_add_test (tc, test_allocate_udp_ports_client_settings); + tcase_add_test (tc, test_tcp_transport); return s; } From fb7833245de53bd6e409f5faf228be7899ce933f Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Tue, 10 Jan 2017 08:34:50 +0100 Subject: [PATCH 1339/1776] rtsp-stream: corrected if-statement in _get_server_port() This bug was accidentally introduced while fixing a segfault in _get_server_port() function. https://bugzilla.gnome.org/show_bug.cgi?id=776345 --- gst/rtsp-server/rtsp-stream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 6af69b480f..445b924d49 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1531,8 +1531,8 @@ gst_rtsp_stream_get_server_port (GstRTSPStream * stream, } g_mutex_lock (&priv->lock); - if (family == G_SOCKET_FAMILY_IPV4 && priv->server_addr_v4) { - if (server_port) { + if (family == G_SOCKET_FAMILY_IPV4) { + if (server_port && priv->server_addr_v4) { server_port->min = priv->server_addr_v4->port; server_port->max = priv->server_addr_v4->port + priv->server_addr_v4->n_ports - 1; From c860590a8cdccda4a73b29d3d2a57e2a60ee6bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 12 Jan 2017 16:14:46 +0200 Subject: [PATCH 1340/1776] Release 1.11.1 --- ChangeLog | 244 ++++++- NEWS | 1115 +---------------------------- RELEASE | 46 +- configure.ac | 12 +- gst-rtsp-server.doap | 10 + win32/common/libgstrtspserver.def | 2 + 6 files changed, 293 insertions(+), 1136 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9e5143486c..610dd606d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,247 @@ -=== release 1.10.0 === +=== release 1.11.1 === -2016-11-01 Sebastian Dröge +2017-01-12 Sebastian Dröge * configure.ac: - releasing 1.10.0 + releasing 1.11.1 + +2017-01-10 08:34:50 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: corrected if-statement in _get_server_port() + This bug was accidentally introduced while fixing a segfault + in _get_server_port() function. + https://bugzilla.gnome.org/show_bug.cgi?id=776345 + +2017-01-09 14:12:05 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/stream.c: + rtsp-stream: fixed segmenation fault in _get_server_port() + Calling function gst_rtsp_stream_get_server_port() results in + segmenation fault in the RTP/RTSP/TCP case. + Port that the server will use to receive RTCP makes only + sense in the UDP case, however the function should handle + the TCP case in a nicer way. + https://bugzilla.gnome.org/show_bug.cgi?id=776345 + +2017-01-09 12:22:40 +0300 Aleksandr Slobodeniuk + + * gst/rtsp-server/rtsp-media-factory.c: + dosc: Fix a little typo + https://bugzilla.gnome.org/show_bug.cgi?id=777037 + +2017-01-04 16:20:54 +0100 Guillaume Desmottes + + * pkgconfig/Makefile.am: + * pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in: + * pkgconfig/meson.build: + meson: generate pkg-config -uninstalled pc files + Generating those files is useful for users building the GStreamer stack + using meson and having to link it to another project which is still + using the autotools. + https://bugzilla.gnome.org/show_bug.cgi?id=776810 + +2017-01-04 16:11:08 +0100 Guillaume Desmottes + + * pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in: + pkgconfig: fix -uninstalled pc file + pcfiledir was never defined so the paths were wrong. + https://bugzilla.gnome.org/show_bug.cgi?id=776867 + +2016-12-21 13:41:50 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/rtspserver.c: + rtsp-stream: Fixed TCP transport case + Make sure that the appsink element is actually added to + the bin before trying to link it with the elements in it. + https://bugzilla.gnome.org/show_bug.cgi?id=776343 + +2016-12-16 17:26:04 +0000 Tim-Philipp Müller + + * .gitignore: + * Makefile.am: + * configure.ac: + * gst-rtsp.spec.in: + Remove generated .spec file + Likely extremely bitrotten, and we should not ship this anyway. + +2016-12-03 08:21:02 +0100 Edward Hervey + + * common: + Automatic update of common submodule + From f980fd9 to 39ac2f5 + +2016-12-02 15:40:09 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-media.c: + media: Fix pt map caps + Since decryption is handled within rtpbin, all outcoming stream + caps will be application/x-rtp (i.e. regular rtp) + Fixes RECORD with SRTP streams + +2016-12-02 15:38:04 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-media-factory.c: + media-factory: Create media objects with the proper transport mode + The function called immediately afterwards (collect_streams()) will + need it to work properly + +2016-12-02 14:36:50 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-auth.c: + rtsp-auth: Don't remove digest-auth nonces that already/still have a client connected + +2016-12-01 18:04:34 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-media-factory.c: + rtsp-media-factory: Don't create a pipeline for the media pipeline string + We're going to put a pipeline into a pipeline otherwise, which is not + exactly ideal. + +2016-10-25 15:41:28 +0300 Kseniia Vasilchuk + + * gst/rtsp-server/rtsp-media.c: + media: Fix race condition around finish_unprepare() if called multiple time + https://bugzilla.gnome.org/show_bug.cgi?id=755329 + +2016-11-30 14:06:36 +1100 Jan Schmidt + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Don't leave stale pointer after unref + Fix a warning on shutdown - don't keep a pointer to an + alread-unreffed object. + +2016-11-26 11:24:50 +0000 Tim-Philipp Müller + + * .gitmodules: + common: use https protocol for common submodule + https://bugzilla.gnome.org/show_bug.cgi?id=775110 + +2016-11-21 23:29:56 +1100 Matthew Waters + + * gst/rtsp-server/rtsp-stream.c: + stream: block the output of rtpbin instead of the source pipeline + 85c52e194bcb81928b96614be0ae47d59eccb1ce introduced a more correct + detection of the srtp rollover counter to add to the SDP. + Unfortunately, it was incomplete for live pipelines where the logic + blocks the source bin before creating the SDP and thus would never have + the necessary informaiton to create a correct SDP with srtp encryption. + Move the pad blocks to rtpbin's output pads instead so that the + necessary information can be created before we need the information for + the SDP. + https://bugzilla.gnome.org/show_bug.cgi?id=770239 + +2016-11-21 16:02:39 +0100 Dag Gullberg + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: add IDLE timeout, before session exists + The RTSP server will not timeout an idle RTSP connection + (note this is different from doing timeout on a RTSP + session). + At least for Apache this is a problem when running RTSP over + HTTPS since it uses one of the threads (there is a rather + limited number) that are available for handling requests. + https://bugzilla.gnome.org/show_bug.cgi?id=771830 + +2016-11-23 09:45:08 +0000 Tim-Philipp Müller + + * .gitignore: + .gitignore more + +2016-11-21 13:05:50 +0100 Göran Jönsson + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Set close-socket FALSE on UDP src:es + With this RTSP server can use the sockets independent on the udpsrc + state. + When the udp src is finalized it will unref socket and when g_socket + is finalized the socket will be closed. + https://bugzilla.gnome.org/show_bug.cgi?id=765673 + +2016-11-18 17:47:13 +0200 Sebastian Dröge + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Move to new helper function to parse authentication responses + https://bugzilla.gnome.org/show_bug.cgi?id=774416 + +2016-11-16 08:42:24 +0200 Sebastian Dröge + + * examples/Makefile.am: + * examples/test-auth-digest.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + * win32/common/libgstrtspserver.def: + rtsp-auth: Add support for Digest authentication + https://bugzilla.gnome.org/show_bug.cgi?id=774416 + +2016-11-17 09:41:53 -0800 Scott D Phillips + + * Makefile.am: + * gst/rtsp-server/meson.build: + * meson.build: + * tests/check/meson.build: + * win32/MANIFEST: + * win32/common/libgstrtspserver.def: + Enable building with MSVC + https://bugzilla.gnome.org/show_bug.cgi?id=774640 + +2016-11-18 20:23:14 -0300 Thibault Saunier + + * meson.build: + meson: gstreamer gst_check_dep does not exist on windows + +2016-11-17 09:43:37 -0800 Scott D Phillips + + * gst/rtsp-server/rtsp-client.c: + client: update do_send_message to match type GstRTSPClientSendFunc + This type mismatch fails building with MSVC + https://bugzilla.gnome.org/show_bug.cgi?id=774640 + +2016-11-11 14:42:08 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-sdp.c: + rtsp-sdp: Fix indentation + +2016-11-10 05:16:00 +0000 Neha Arora + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Only signal "new-state" if the state has actually changed + https://bugzilla.gnome.org/show_bug.cgi?id=774173 + +2016-08-24 11:39:13 +0200 Branko Subasic + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + client: emit signal in the beginning of each rtsp request + These signals let the application validate the requests, configure the + media/stream in a certain way and also generate error status code in + case of error or bad request. + https://bugzilla.gnome.org/show_bug.cgi?id=758062 + +2016-11-01 18:10:35 +0000 Tim-Philipp Müller + + * meson.build: + meson: update version + +=== release 1.11.0 === + +2016-11-01 18:53:15 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.10.0 === + +2016-11-01 18:06:46 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.10.0 2016-10-28 18:38:01 +0100 Tim-Philipp Müller diff --git a/NEWS b/NEWS index 547de7f3f9..a940f7bb0f 100644 --- a/NEWS +++ b/NEWS @@ -1,1114 +1 @@ -# GStreamer 1.10 Release Notes - -**GStreamer 1.10.0 was released on 1st November 2016.** - -The GStreamer team is proud to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! - -As always, this release is again packed with new features, bug fixes and other -improvements. - -See [https://gstreamer.freedesktop.org/releases/1.10/][latest] for the latest -version of this document. - -*Last updated: Tuesday 1 Nov 2016, 15:00 UTC [(log)][gitlog]* - -[latest]: https://gstreamer.freedesktop.org/releases/1.10/ -[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.10/release-notes-1.10.md - -## Introduction - -The GStreamer team is proud to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! - -As always, this release is again packed with new features, bug fixes and other -improvements. - -## Highlights - -- Several convenience APIs have been added to make developers' lives easier -- A new `GstStream` API provides applications a more meaningful view of the - structure of streams, simplifying the process of dealing with media in - complex container formats -- Experimental `decodebin3` and `playbin3` elements which bring a number of - improvements which were hard to implement within `decodebin` and `playbin` -- A new `parsebin` element to automatically unpack and parse a stream, stopping - just short of decoding -- Experimental new `meson`-based build system, bringing faster build and much - better Windows support (including for building with Visual Studio) -- A new `gst-docs` module has been created, and we are in the process of moving - our documentation to a markdown-based format for easier maintenance and - updates -- A new `gst-examples` module has been create, which contains example - GStreamer applications and is expected to grow with many more examples in - the future -- Various OpenGL and OpenGL|ES-related fixes and improvements for greater - efficiency on desktop and mobile platforms, and Vulkan support on Wayland was - also added -- Extensive improvements to the VAAPI plugins for improved robustness and - efficiency -- Lots of fixes and improvements across the board, spanning RTP/RTSP, V4L2, - Bluetooth, audio conversion, echo cancellation, and more! - -## Major new features and changes - -### Noteworthy new API, features and other changes - -#### Core API additions - -##### Receive property change notifications via bus messages - -New API was added to receive element property change notifications via -bus messages. So far, applications had to connect a callback to an element's -`notify::property-name` signal via the GObject API, which was inconvenient for -at least two reasons: one had to implement a signal callback function, and that -callback function would usually be called from one of the streaming threads, so -one had to marshal (send) any information gathered or pending requests to the -main application thread which was tedious and error-prone. - -Enter [`gst_element_add_property_notify_watch()`][notify-watch] and -[`gst_element_add_property_deep_notify_watch()`][deep-notify-watch] which will -watch for changes of a property on the specified element, either only for this -element or recursively for a whole bin or pipeline. Whenever such a -property change happens, a `GST_MESSAGE_PROPERTY_NOTIFY` message will be posted -on the pipeline bus with details of the element, the property and the new -property value, all of which can be retrieved later from the message in the -application via [`gst_message_parse_property_notify()`][parse-notify]. Unlike -the GstBus watch functions, this API does not rely on a running GLib main loop. - -The above can be used to be notified asynchronously of caps changes in the -pipeline, or volume changes on an audio sink element, for example. - -[notify-watch]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-add-property-notify-watch -[deep-notify-watch]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-add-property-deep-notify-watch -[parse-notify]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-parse-property-notify - -##### GstBin "deep" element-added and element-removed signals - -GstBin has gained `"deep-element-added"` and `"deep-element-removed"` signals -which makes it easier for applications and higher-level plugins to track when -elements are added or removed from a complex pipeline with multiple sub-bins. - -`playbin` makes use of this to implement the new `"element-setup"` signal which -can be used to configure elements as they are added to `playbin`, just like the -existing `"source-setup"` signal which can be used to configure the source -element created. - -##### Error messages can contain additional structured details - -It is often useful to provide additional, structured information in error, -warning or info messages for applications (or higher-level elements) to make -intelligent decisions based on them. To allow this, error, warning and info -messages now have API for adding arbitrary additional information to them -using a `GstStructure`: -[`GST_ELEMENT_ERROR_WITH_DETAILS`][element-error-with-details] and -corresponding API for the other message types. - -This is now used e.g. by the new [`GST_ELEMENT_FLOW_ERROR`][element-flow-error] -API to include the actual flow error in the error message, and the -[souphttpsrc element][souphttpsrc-detailed-errors] to provide the HTTP -status code, and the URL (if any) to which a redirection has happened. - -[element-error-with-details]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#GST-ELEMENT-ERROR-WITH-DETAILS:CAPS -[element-flow-error]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#GST-ELEMENT-FLOW-ERROR:CAPS -[souphttpsrc-detailed-errors]: https://cgit.freedesktop.org/gstreamer/gst-plugins-good/tree/ext/soup/gstsouphttpsrc.c?id=60d30db912a1aedd743e66b9dcd2e21d71fbb24f#n1318 - -##### Redirect messages have official API now - -Sometimes, elements need to redirect the current stream URL and tell the -application to proceed with this new URL, possibly using a different -protocol too (thus changing the pipeline configuration). Until now, this was -informally implemented using `ELEMENT` messages on the bus. - -Now this has been formalized in the form of a new `GST_MESSAGE_REDIRECT` message. -A new redirect message can be created using [`gst_message_new_redirect()`][new-redirect]. -If needed, multiple redirect locations can be specified by calling -[`gst_message_add_redirect_entry()`][add-redirect] to add further redirect -entries, all with metadata, so the application can decide which is -most suitable (e.g. depending on the bitrate tags). - -[new-redirect]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-new-redirect -[add-redirect]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-add-redirect-entry - -##### New pad linking convenience functions that automatically create ghost pads - -New pad linking convenience functions were added: -[`gst_pad_link_maybe_ghosting()`][pad-maybe-ghost] and -[`gst_pad_link_maybe_ghosting_full()`][pad-maybe-ghost-full] which were -previously internal to GStreamer have now been exposed for general use. - -The existing pad link functions will refuse to link pads or elements at -different levels in the pipeline hierarchy, requiring the developer to -create ghost pads where necessary. These new utility functions will -automatically create ghostpads as needed when linking pads at different -levels of the hierarchy (e.g. from an element inside a bin to one that's at -the same level in the hierarchy as the bin, or in another bin). - -[pad-maybe-ghost]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-link-maybe-ghosting -[pad-maybe-ghost-full]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-link-maybe-ghosting-full - -##### Miscellaneous - -Pad probes: IDLE and BLOCK probes now work slightly differently in pull mode, -so that push and pull mode have opposite scenarios for idle and blocking probes. -In push mode, it will block with some data type and IDLE won't have any data. -In pull mode, it will block _before_ getting a buffer and will be IDLE once some -data has been obtained. ([commit][commit-pad-probes], [bug][bug-pad-probes]) - -[commit-pad-probes]: https://cgit.freedesktop.org/gstreamer/gstreamer/commit/gst/gstpad.c?id=368ee8a336d0c868d81fdace54b24431a8b48cbf -[bug-pad-probes]: https://bugzilla.gnome.org/show_bug.cgi?id=761211 - -[`gst_parse_launch_full()`][parse-launch-full] can now be made to return a -`GstBin` instead of a top-level pipeline by passing the new -`GST_PARSE_FLAG_PLACE_IN_BIN` flag. - -[parse-launch-full]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstParse.html#gst-parse-launch-full - -The default GStreamer debug log handler can now be removed before -calling `gst_init()`, so that it will never get installed and won't be active -during initialization. - -A new [`STREAM_GROUP_DONE` event][stream-group-done-event] was added. In some -ways it works similar to the `EOS` event in that it can be used to unblock -downstream elements which may be waiting for further data, such as for example -`input-selector`. Unlike `EOS`, further data flow may happen after the -`STREAM_GROUP_DONE` event though (and without the need to flush the pipeline). -This is used to unblock input-selector when switching between streams in -adaptive streaming scenarios (e.g. HLS). - -[stream-group-done-event]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-new-stream-group-done - -The `gst-launch-1.0` command line tool will now print unescaped caps in verbose -mode (enabled by the -v switch). - -[`gst_element_call_async()`][call-async] has been added as convenience API for -plugin developers. It is useful for one-shot operations that need to be done -from a thread other than the current streaming thread. It is backed by a -thread-pool that is shared by all elements. - -[call-async]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-call-async - -Various race conditions have been fixed around the `GstPoll` API used by e.g. -`GstBus` and `GstBufferPool`. Some of these manifested themselves primarily -on Windows. - -`GstAdapter` can now keep track of discontinuities signalled via the `DISCONT` -buffer flag, and has gained [new API][new-adapter-api] to track PTS, DTS and -offset at the last discont. This is useful for plugins implementing advanced -trick mode scenarios. - -[new-adapter-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstAdapter.html#gst-adapter-pts-at-discont - -`GstTestClock` gained a new [`"clock-type"` property][clock-type-prop]. - -[clock-type-prop]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstTestClock.html#GstTestClock--clock-type - -#### GstStream API for stream announcement and stream selection - -New stream listing and stream selection API: new API has been added to -provide high-level abstractions for streams ([`GstStream`][stream-api]) -and collections of streams ([`GstStreamCollections`][stream-collection-api]). - -##### Stream listing - -A [`GstStream`][stream-api] contains all the information pertinent to a stream, -such as stream id, caps, tags, flags and stream type(s); it can represent a -single elementary stream (e.g. audio, video, subtitles, etc.) or a container -stream. This will depend on the context. In a decodebin3/playbin3 one -it will typically be elementary streams that can be selected and unselected. - -A [`GstStreamCollection`][stream-collection-api] represents a group of streams -and is used to announce or publish all available streams. A GstStreamCollection -is immutable - once created it won't change. If the available streams change, -e.g. because a new stream appeared or some streams disappeared, a new stream -collection will be published. This new stream collection may contain streams -from the previous collection if those streams persist, or completely new ones. -Stream collections do not yet list all theoretically available streams, -e.g. other available DVD angles or alternative resolutions/bitrate of the same -stream in case of adaptive streaming. - -New events and messages have been added to notify or update other elements and -the application about which streams are currently available and/or selected. -This way, we can easily and seamlessly let the application know whenever the -available streams change, as happens frequently with digital television streams -for example. The new system is also more flexible. For example, it is now also -possible for the application to select multiple streams of the same type -(e.g. in a transcoding/transmuxing scenario). - -A [`STREAM_COLLECTION` message][stream-collection-msg] is posted on the bus -to inform the parent bin (e.g. `playbin3`, `decodebin3`) and/or the application -about what streams are available, so you no longer have to hunt for this -information at different places. The available information includes number of -streams of each type, caps, tags etc. Bins and/or the application can intercept -the message synchronously to select and deselect streams before any data is -produced - for the case where elements such as the demuxers support the new -stream API, not necessarily in the parsebin compatibility fallback case. - -Similarly, there is also a [`STREAM_COLLECTION` event][stream-collection-event] -to inform downstream elements of the available streams. This event can be used -by elements to aggregate streams from multiple inputs into one single collection. - -The `STREAM_START` event was extended so that it can also contain a GstStream -object with all information about the current stream, see -[`gst_event_set_stream()`][event-set-stream] and -[`gst_event_parse_stream()`][event-parse-stream]. -[`gst_pad_get_stream()`][pad-get-stream] is a new utility function that can be -used to look up the GstStream from the `STREAM_START` sticky event on a pad. - -[stream-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstStream.html -[stream-collection-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstStreamCollection.html -[stream-collection-msg]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-new-stream-collection -[stream-collection-event]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-new-stream-collection -[event-set-stream]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-set-stream -[event-parse-stream]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-parse-stream -[pad-get-stream]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-get-stream - -##### Stream selection - -Once the available streams have been published, streams can be selected via -their stream ID using the new `SELECT_STREAMS` event, which can be created -with [`gst_event_new_select_streams()`][event-select-streams]. The new API -supports selecting multiple streams per stream type. In the future, we may also -implement explicit deselection of streams that will never be used, so -elements can skip these and never expose them or output data for them in the -first place. - -The application is then notified of the currently selected streams via the -new `STREAMS_SELECTED` message on the pipeline bus, containing both the current -stream collection as well as the selected streams. This might be posted in -response to the application sending a `SELECT_STREAMS` event or when -`decodebin3` or `playbin3` decide on the streams to be initially selected without -application input. - -[event-select-streams]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-new-select-streams - -##### Further reading - -See further below for some notes on the new elements supporting this new -stream API, namely: `decodebin3`, `playbin3` and `parsebin`. - -More information about the new API and the new elements can also be found here: - -- GStreamer [stream selection design docs][streams-design] -- Edward Hervey's talk ["The new streams API: Design and usage"][streams-talk] ([slides][streams-slides]) -- Edward Hervey's talk ["Decodebin3: Dealing with modern playback use cases"][db3-talk] ([slides][db3-slides]) - -[streams-design]: https://cgit.freedesktop.org/gstreamer/gstreamer/tree/docs/design/part-stream-selection.txt -[streams-talk]: https://gstconf.ubicast.tv/videos/the-new-gststream-api-design-and-usage/ -[streams-slides]: https://gstreamer.freedesktop.org/data/events/gstreamer-conference/2016/Edward%20Hervey%20-%20The%20New%20Streams%20API%20Design%20and%20Usage.pdf -[db3-talk]: https://gstconf.ubicast.tv/videos/decodebin3-or-dealing-with-modern-playback-use-cases/ -[db3-slides]: https://gstreamer.freedesktop.org/data/events/gstreamer-conference/2015/Edward%20Hervey%20-%20decodebin3.pdf - -#### Audio conversion and resampling API - -The audio conversion library received a completely new and rewritten audio -resampler, complementing the audio conversion routines moved into the audio -library in the [previous release][release-notes-1.8]. Integrating the resampler -with the other audio conversion library allows us to implement generic -conversion much more efficiently, as format conversion and resampling can now -be done in the same processing loop instead of having to do it in separate -steps (our element implementations do not make use of this yet though). - -The new audio resampler library is a combination of some of the best features -of other samplers such as ffmpeg, speex and SRC. It natively supports S16, S32, -F32 and F64 formats and uses optimized x86 and neon assembly for most of its -processing. It also has support for dynamically changing sample rates by incrementally -updating the filter tables using linear or cubic interpolation. According to -some benchmarks, it's one of the fastest and most accurate resamplers around. - -The `audioresample` plugin has been ported to the new audio library functions -to make use of the new resampler. - -[release-notes-1.8]: https://gstreamer.freedesktop.org/releases/1.8/ - -#### Support for SMPTE timecodes - -Support for SMPTE timecodes was added to the GStreamer video library. This -comes with an abstraction for timecodes, [`GstVideoTimeCode`][video-timecode] -and a [`GstMeta`][video-timecode-meta] that can be placed on video buffers for -carrying the timecode information for each frame. Additionally there is -various API for making handling of timecodes easy and to do various -calculations with them. - -A new plugin called [`timecode`][timecode-plugin] was added, that contains an -element called `timecodestamper` for putting the timecode meta on video frames -based on counting the frames and another element called `timecodewait` that -drops all video (and audio) until a specific timecode is reached. - -Additionally support was added to the Decklink plugin for including the -timecode information when sending video out or capturing it via SDI, the -`qtmux` element is able to write timecode information into the MOV container, -and the `timeoverlay` element can overlay timecodes on top of the video. - -More information can be found in the [talk about timecodes][timecode-talk] at -the GStreamer Conference 2016. - -[video-timecode]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#GstVideoTimeCode -[video-timecode-meta]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideometa.html#gst-buffer-add-video-time-code-meta -[timecode-plugin]: https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/gst/timecode -[timecode-talk]: https://gstconf.ubicast.tv/videos/smpte-timecodes-in-gstreamer/ - -#### GStreamer OpenMAX IL plugin - -The last gst-omx release, 1.2.0, was in July 2014. It was about time to get -a new one out with all the improvements that have happened in the meantime. -From now on, we will try to release gst-omx together with all other modules. - -This release features a lot of bugfixes, improved support for the Raspberry Pi -and in general improved support for zerocopy rendering via EGL and a few minor -new features. - -At this point, gst-omx is known to work best on the Raspberry Pi platform but -it is also known to work on various other platforms. Unfortunately, we are -not including configurations for any other platforms, so if you happen to use -gst-omx: please send us patches with your configuration and code changes! - -### New Elements - -#### decodebin3, playbin3, parsebin (experimental) - -This release features new decoding and playback elements as experimental -technology previews: `decodebin3` and `playbin3` will soon supersede the -existing `decodebin` and `playbin` elements. We skipped the number 2 because -it was already used back in the 0.10 days, which might cause confusion. -Experimental technology preview means that everything should work fine already, -but we can't guarantee there won't be minor behavioural changes in the -next cycle. In any case, please test and report any problems back. - -Before we go into detail about what these new elements improve, let's look at -the new [`parsebin`][parsebin] element. It works similarly to `decodebin` and -`decodebin3`, only that it stops one step short and does not plug any actual -decoder elements. It will only plug parsers, tag readers, demuxers and -depayloaders. Also note that parsebin does not contain any queueing element. - -[`decodebin3`'s][decodebin3] internal architecture is slightly different from -the existing `decodebin` element and fixes many long-standing issues with our -decoding engine. For one, data is now fed into the internal `multiqueue` element -*after* it has been parsed and timestamped, which means that the `multiqueue` -element now has more knowledge and is able to calculate the interleaving of the -various streams, thus minimizing memory requirements and doing away with magic -values for buffering limits that were conceived when videos were 240p or 360p. -Anyone who has tried to play back 4k video streams with decodebin2 -will have noticed the limitations of that approach. The improved timestamp -tracking also enables `multiqueue` to keep streams of the same type (audio, -video) aligned better, making sure switching between streams of the same type -is very fast. - -Another major improvement in `decodebin3` is that it will no longer decode -streams that are not being used. With the old `decodebin` and `playbin`, when -there were 8 audio streams we would always decode all 8 streams even -if 7 were not actually used. This caused a lot of CPU overhead, which was -particularly problematic on embedded devices. When switching between streams -`decodebin3` will try hard to re-use existing decoders. This is useful when -switching between multiple streams of the same type if they are encoded in the -same format. - -Re-using decoders is also useful when the available streams change on the fly, -as might happen with radio streams (chained Oggs), digital television -broadcasts, when adaptive streaming streams change bitrate, or when switching -gaplessly to the next title. In order to guarantee a seamless transition, the -old `decodebin2` would plug a second decoder for the new stream while finishing -up the old stream. With `decodebin3`, this is no longer needed - at least not -when the new and old format are the same. This will be particularly useful -on embedded systems where it is often not possible to run multiple decoders -at the same time, or when tearing down and setting up decoders is fairly -expensive. - -`decodebin3` also allows for multiple input streams, not just a single one. -This will be useful, in the future, for gapless playback, or for feeding -multiple external subtitle streams to decodebin/playbin. - -`playbin3` uses `decodebin3` internally, and will supercede `playbin`. -It was decided that it would be too risky to make the old `playbin` use the -new `decodebin3` in a backwards-compatible way. The new architecture -makes it awkward, if not impossible, to maintain perfect backwards compatibility -in some aspects, hence `playbin3` was born, and developers can migrate to the -new element and new API at their own pace. - -All of these new elements make use of the new `GstStream` API for listing and -selecting streams, as described above. `parsebin` provides backwards -compatibility for demuxers and parsers which do not advertise their streams -using the new API yet (which is most). - -The new elements are not entirely feature-complete yet: `playbin3` does not -support so-called decodersinks yet where the data is not decoded inside -GStreamer but passed directly for decoding to the sink. `decodebin3` is missing -the various `autoplug-*` signals to influence which decoders get autoplugged -in which order. We're looking to add back this functionality, but it will probably -be in a different way, with a single unified signal and using GstStream perhaps. - -For more information on these new elements, check out Edward Hervey's talk -[*decodebin3 - dealing with modern playback use cases*][db3-talk] - -[parsebin]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-parsebin.html -[decodebin3]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-decodebin3.html -[db3-talk]: https://gstconf.ubicast.tv/videos/decodebin3-or-dealing-with-modern-playback-use-cases/ - -#### LV2 ported from 0.10 and switched from slv2 to lilv2 - -The LV2 wrapper plugin has been ported to 1.0 and moved from using the -deprecated slv2 library to its replacement liblv2. We support sources and -filter elements. lv2 is short for *Linux Audio Developer's Simple Plugin API -(LADSPA) version 2* and is an open standard for audio plugins which includes -support for audio synthesis (generation), digital signal processing of digital -audio, and MIDI. The new lv2 plugin supersedes the existing LADSPA plugin. - -#### WebRTC DSP Plugin for echo-cancellation, gain control and noise suppression - -A set of new elements ([webrtcdsp][webrtcdsp], [webrtcechoprobe][webrtcechoprobe]) -based on the WebRTC DSP software stack can now be used to improve your audio -voice communication pipelines. They support echo cancellation, gain control, -noise suppression and more. For more details you may read -[Nicolas' blog post][webrtc-blog-post]. - -[webrtcdsp]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-webrtcdsp.html -[webrtcechoprobe]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-webrtcechoprobe.html -[webrtc-blog-post]: https://ndufresne.ca/2016/06/gstreamer-echo-canceller/ - -#### Fraunhofer FDK AAC encoder and decoder - -New encoder and decoder elements wrapping the Fraunhofer FDK AAC library have -been added (`fdkaacdec`, `fdkaacdec`). The Fraunhofer FDK AAC encoder is -generally considered to be a very high-quality AAC encoder, but unfortunately -it comes under a non-free license with the option to obtain a paid, commercial -license. - -### Noteworthy element features and additions - -#### Major RTP and RTSP improvements - -- The RTSP server and source element, as well as the RTP jitterbuffer now support - remote clock synchronization according to [RFC7273][https://tools.ietf.org/html/rfc7273]. -- Support for application and profile specific RTCP packets was added. -- The H265/HEVC payloader/depayloader is again in sync with the final RFC. -- Seeking stability of the RTSP source and server was improved a lot and - runs stably now, even when doing scrub-seeking. -- The RTSP server received various major bugfixes, including for regressions that - caused the IP/port address pool to not be considered, or NAT hole punching - to not work anymore. [Bugzilla #766612][https://bugzilla.gnome.org/show_bug.cgi?id=766612] -- Various other bugfixes that improve the stability of RTP and RTSP, including - many new unit / integration tests. - -#### Improvements to splitmuxsrc and splitmuxsink - -- The splitmux element received reliability and error handling improvements, - removing at least one deadlock case. `splitmuxsrc` now stops cleanly at the end - of the segment when handling seeks with a stop time. We fixed a bug with large - amounts of downstream buffering causing incorrect out-of-sequence playback. - -- `splitmuxsrc` now has a `"format-location"` signal to directly specify the list - of files to play from. - -- `splitmuxsink` can now optionally send force-keyunit events to upstream - elements to allow splitting files more accurately instead of having to wait - for upstream to provide a new keyframe by itself. - -#### OpenGL/GLES improvements - -##### iOS and macOS (OS/X) - -- We now create OpenGL|ES 3.x contexts on iOS by default with a fallback to - OpenGL|ES 2.x if that fails. -- Various zerocopy decoding fixes and enhancements with the - encoding/decoding/capturing elements. -- libdispatch is now used on all Apple platforms instead of GMainLoop, removing - the expensive poll()/pthread_*() overhead. - -##### New API - -- `GstGLFramebuffer` - for wrapping OpenGL frame buffer objects. It provides - facilities for attaching `GstGLMemory` objects to the necessary attachment - points, binding and unbinding and running a user-supplied function with the - framebuffer bound. -- `GstGLRenderbuffer` (a `GstGLBaseMemory` subclass) - for wrapping OpenGL - render buffer objects that are typically used for depth/stencil buffers or - for color buffers where we don't care about the output. -- `GstGLMemoryEGL` (a `GstGLMemory` subclass) - for combining `EGLImage`s with a GL - texture that replaces `GstEGLImageMemory` bringing the improvements made to the - other `GstGLMemory` implementations. This fixes a performance regression in - zerocopy decoding on the Raspberry Pi when used with an updated gst-omx. - -##### Miscellaneous improvements - -- `gltestsrc` is now usable on devices/platforms with OpenGL 3.x and OpenGL|ES - and has completed or gained support for new patterns in line with the - existing ones in `videotestsrc`. -- `gldeinterlace` is now available on devices/platforms with OpenGL|ES - implementations. -- The dispmanx backend (used on the Raspberry Pi) now supports the - `gst_video_overlay_set_window_handle()` and - `gst_video_overlay_set_render_rectangle()` functions. -- The `gltransformation` element now correctly transforms mouse coordinates (in - window space) to stream coordinates for both perspective and orthographic - projections. -- The `gltransformation` element now detects if the - `GstVideoAffineTransformationMeta` is supported downstream and will efficiently - pass its transformation downstream. This is a performance improvement as it - results in less processing being required. -- The wayland implementation now uses the multi-threaded safe event-loop API - allowing correct usage in applications that call wayland functions from - multiple threads. -- Support for native 90 degree rotations and horizontal/vertical flips - in `glimagesink`. - -#### Vulkan - -- The Vulkan elements now work under Wayland and have received numerous - bugfixes. - -#### QML elements - -- `qmlglsink` video sink now works on more platforms, notably, Windows, Wayland, - and Qt's eglfs (for embedded devices with an OpenGL implementation) including - the Raspberry Pi. -- New element `qmlglsrc` to record a QML scene into a GStreamer pipeline. - -#### KMS video sink - -- New element `kmssink` to render video using Direct Rendering Manager - (DRM) and Kernel Mode Setting (KMS) subsystems in the Linux - kernel. It is oriented to be used mostly in embedded systems. - -#### Wayland video sink - -- `waylandsink` now supports the wl_viewporter extension allowing - video scaling and cropping to be delegated to the Wayland - compositor. This extension is also been made optional, so that it can - also work on current compositors that don't support it. It also now has - support for the video meta, allowing zero-copy operations in more - cases. - -#### DVB improvements - -- `dvbsrc` now has better delivery-system autodetection and several - new parameter sanity-checks to improve its resilience to configuration - omissions and errors. Superfluous polling continues to be trimmed down, - and the debugging output has been made more consistent and precise. - Additionally, the channel-configuration parser now supports the new dvbv5 - format, enabling `dvbbasebin` to automatically playback content transmitted - on delivery systems that previously required manual description, like ISDB-T. - -#### DASH, HLS and adaptivedemux - -- HLS now has support for Alternate Rendition audio and video tracks. Full - support for Alternate Rendition subtitle tracks will be in an upcoming release. -- DASH received support for keyframe-only trick modes if the - `GST_SEEK_FLAG_TRICKMODE_KEY_UNITS` flag is given when seeking. It will - only download keyframes then, which should help with high-speed playback. - Changes to skip over multiple frames based on bandwidth and other metrics - will be added in the near future. -- Lots of reliability fixes around seek handling and bitrate switching. - -#### Bluetooth improvements - -- The `avdtpsrc` element now supports metadata such as track title, artist - name, and more, which devices can send via AVRCP. These are published as - tags on the pipeline. -- The `a2dpsink` element received some love and was cleaned up so that it - actually works after the initial GStreamer 1.0 port. - -#### GStreamer VAAPI - -- All the decoders have been split, one plugin feature per codec. So - far, the available ones, depending on the driver, are: - `vaapimpeg2dec`, `vaapih264dec`, `vaapih265dec`, `vaapivc1dec`, `vaapivp8dec`, - `vaapivp9dec` and `vaapijpegdec` (which already was split). -- Improvements when mapping VA surfaces into memory. It now differentiates - between negotiation caps and allocations caps, since the allocation - memory for surfaces may be bigger than one that is going to be - mapped. -- `vaapih265enc` now supports constant bitrate mode (CBR). -- Since several VA drivers are unmaintained, we decide to keep a whitelist - with the va drivers we actually test, which is mostly the i915 and to a lesser - degree gallium from the mesa project. Exporting the environment variable - `GST_VAAPI_ALL_DRIVERS` disables the whitelist. -- Plugin features are registered at run-time, according to their support by - the loaded VA driver. So only the decoders and encoder supported by the - system are registered. Since the driver can change, some dependencies are - tracked to invalidate the GStreamer registry and reload the plugin. -- `dmabuf` importation from upstream has been improved, gaining performance. -- `vaapipostproc` now can negotiate buffer transformations via caps. -- Decoders now can do I-frame only reverse playback. This decodes I-frames - only because the surface pool is smaller than the required by the GOP to show all the - frames. -- The upload of frames onto native GL textures has been optimized too, keeping - a cache of the internal structures for the offered textures by the sink. - -#### V4L2 changes - -- More pixels formats are now supported -- Decoder is now using `G_SELECTION` instead of the deprecated `G_CROP` -- Decoder now uses the `STOP` command to handle EOS -- Transform element can now scale the pixel aspect ratio -- Colorimetry support has been improved even more -- We now support the `OUTPUT_OVERLAY` type of video node in v4l2sink - -#### Miscellaneous - -- `multiqueue`'s input pads gained a new `"group-id"` property which - can be used to group input streams. Typically one will assign - different id numbers to audio, video and subtitle streams for - example. This way `multiqueue` can make sure streams of the same - type advance in lockstep if some of the streams are unlinked and the - `"sync-by-running-time"` property is set. This is used in - decodebin3/playbin3 to implement almost-instantaneous stream - switching. The grouping is required because different downstream - paths (audio, video, etc.) may have different buffering/latency - etc. so might be consuming data from multiqueue with a slightly - different phase, and if we track different stream groups separately - we minimize stream switching delays and buffering inside the - `multiqueue`. -- `alsasrc` now supports ALSA drivers without a position for each - channel, this is common in some professional or industrial hardware. -- `libvpx` based decoders (`vp8dec` and `vp9dec`) now create multiple threads on - computers with multiple CPUs automatically. -- `rfbsrc` - used for capturing from a VNC server - has seen a lot of - debugging. It now supports the latest version of the RFB - protocol and uses GIO everywhere. -- `tsdemux` can now read ATSC E-AC-3 streams. -- New `GstVideoDirection` video orientation interface for rotating, flipping - and mirroring video in 90° steps. It is implemented by the `videoflip` and - `glvideoflip` elements currently. -- It is now possible to give `appsrc` a duration in time, and there is now a - non-blocking try-pull API for `appsink` that returns NULL if nothing is - available right now. -- `x264enc` has support now for chroma-site and colorimetry settings -- A new JPEG2000 parser element was added, and the JPEG2000 caps were cleaned - up and gained more information needed in combination with RTP and various - container formats. -- Reverse playback support for `videorate` and `deinterlace` was implemented -- Various improvements everywhere for reverse playback and `KEY_UNITS` trick mode -- New cleaned up `rawaudioparse` and `rawvideoparse` elements that replace the - old `audioparse` and `videoparse` elements. There are compatibility element - factories registered with the old names to allow existing code to continue - to work. -- The Decklink plugin gained support for 10 bit video SMPTE timecodes, and - generally got many bugfixes for various issues. -- New API in `GstPlayer` for setting the multiview mode for stereoscopic - video, setting an HTTP/RTSP user agent and a time offset between audio and - video. In addition to that, there were various bugfixes and the new - gst-examples module contains Android, iOS, GTK+ and Qt example applications. -- `GstBin` has new API for suppressing various `GstElement` or `GstObject` - flags that would otherwise be affected by added/removed child elements. This - new API allows `GstBin` subclasses to handle for themselves if they - should be considered a sink or source element, for example. -- The `subparse` element can handle WebVTT streams now. -- A new `sdpsrc` element was added that can read an SDP from a file, or get it - as a string as property and then sets up an RTP pipeline accordingly. - -### Plugin moves - -No plugins were moved this cycle. We'll make up for it next cycle, promise! - -### Rewritten memory leak tracer - -GStreamer has had basic functionality to trace allocation and freeing of -both mini-objects (buffers, events, caps, etc.) and objects in the form of the -internal `GstAllocTrace` tracing system. This API was never exposed in the -1.x API series though. When requested, this would dump a list of objects and -mini-objects at exit time which had still not been freed at that point, -enabled with an environment variable. This subsystem has now been removed -in favour of a new implementation based on the recently-added tracing framework. - -Tracing hooks have been added to trace the creation and destruction of -GstObjects and mini-objects, and a new tracer plugin has been written using -those new hooks to track which objects are still live and which are not. If -GStreamer has been compiled against the libunwind library, the new leaks tracer -will remember where objects were allocated from as well. By default the leaks -tracer will simply output a warning if leaks have been detected on `gst_deinit()`. - -If the `GST_LEAKS_TRACER_SIG` environment variable is set, the leaks tracer -will also handle the following UNIX signals: - - - `SIGUSR1`: log alive objects - - `SIGUSR2`: create a checkpoint and print a list of objects created and - destroyed since the previous checkpoint. - -Unfortunately this will not work on Windows due to no signals, however. - -If the `GST_LEAKS_TRACER_STACK_TRACE` environment variable is set, the leaks -tracer will also log the creation stack trace of leaked objects. This may -significantly increase memory consumption however. - -New `MAY_BE_LEAKED` flags have been added to GstObject and GstMiniObject, so -that objects and mini-objects that are likely to stay around forever can be -flagged and blacklisted from the leak output. - -To give the new leak tracer a spin, simply call any GStreamer application such -as `gst-launch-1.0` or `gst-play-1.0` like this: - - GST_TRACERS=leaks gst-launch-1.0 videotestsrc num-buffers=10 ! fakesink - -If there are any leaks, a warning will be raised at the end. - -It is also possible to trace only certain types of objects or mini-objects: - - GST_TRACERS="leaks(GstEvent,GstMessage)" gst-launch-1.0 videotestsrc num-buffers=10 ! fakesink - -This dedicated leaks tracer is much much faster than valgrind since all code is -executed natively instead of being instrumented. This makes it very suitable -for use on slow machines or embedded devices. It is however limited to certain -types of leaks and won't catch memory leaks when the allocation has been made -via plain old `malloc()` or `g_malloc()` or other means. It will also not trace -non-GstObject GObjects. - -The goal is to enable leak tracing on GStreamer's Continuous-Integration and -testing system, both for the regular unit tests (make check) and media tests -(gst-validate), so that accidental leaks in common code paths can be detected -and fixed quickly. - -For more information about the new tracer, check out Guillaume Desmottes's -["Tracking Memory Leaks"][leaks-talk] talk or his [blog post][leaks-blog] about -the topic. - -[leaks-talk]: https://gstconf.ubicast.tv/videos/tracking-memory-leaks/ -[leaks-blog]: https://blog.desmottes.be/?post/2016/06/20/GStreamer-leaks-tracer - -### GES and NLE changes - -- Clip priorities are now handled by the layers, and the GESTimelineElement - priority property is now deprecated and unused -- Enhanced (de)interlacing support to always use the `deinterlace` element - and expose needed properties to users -- Allow reusing clips children after removing the clip from a layer -- We are now testing many more rendering formats in the gst-validate - test suite, and failures have been fixed. -- Also many bugs have been fixed in this cycle! - -### GStreamer validate changes - -This cycle has been focused on making GstValidate more than just a validating -tool, but also a tool to help developers debug their GStreamer issues. When -reporting issues, we try to gather as much information as possible and expose -it to end users in a useful way. For an example of such enhancements, check out -Thibault Saunier's [blog post](improving-debugging-gstreamer-validate) about -the new Not Negotiated Error reporting mechanism. - -Playbin3 support has been added so we can run validate tests with `playbin3` -instead of playbin. - -We are now able to properly communicate between `gst-validate-launcher` and -launched subprocesses with actual IPC between them. That has enabled the test -launcher to handle failing tests specifying the exact expected issue(s). - -[improving-debugging-gstreamer-validate]: https://blogs.s-osg.org/improving-debugging-gstreamer-validate/ - -### gst-libav changes - -gst-libav uses the recently released ffmpeg 3.2 now, which brings a lot of -improvements and bugfixes from the ffmpeg team in addition to various new -codec mappings on the GStreamer side and quite a few bugfixes to the GStreamer -integration to make it more robust. - -## Build and Dependencies - -### Experimental support for Meson as build system - -#### Overview - -We have have added support for building GStreamer using the -[Meson build system][meson]. This is currently experimental, but should work -fine at least on Linux using the gcc or clang toolchains and on Windows using -the MingW or MSVC toolchains. - -Autotools remains the primary build system for the time being, but we hope to -someday replace it and will steadily work towards that goal. - -More information about the background and implications of all this and where -we're hoping to go in future with this can be found in [Tim's mail][meson-mail] -to the gstreamer-devel mailing list. - -For more information on Meson check out [these videos][meson-videos] and also -the [Meson talk][meson-gstconf] at the GStreamer Conference. - -Immediate benefits for Linux users are faster builds and rebuilds. At the time -of writing the Meson build of GStreamer is used by default in GNOME's jhbuild -system. - -The Meson build currently still lacks many of the fine-grained configuration -options to enable/disable specific plugins. These will be added back in due -course. - -Note: The meson build files are not distributed in the source tarballs, you will -need to get GStreamer from git if you want try it out. - -[meson]: http://mesonbuild.com/ -[meson-mail]: https://lists.freedesktop.org/archives/gstreamer-devel/2016-September/060231.html -[meson-videos]: http://mesonbuild.com/videos.html -[meson-gstconf]: https://gstconf.ubicast.tv/videos/gstreamer-development-on-windows-ans-faster-builds-everywhere-with-meson/ - -#### Windows Visual Studio toolchain support - -Windows users might appreciate being able to build GStreamer using the MSVC -toolchain, which is not possible using autotools. This means that it will be -possible to debug GStreamer and applications in Visual Studio, for example. -We require VS2015 or newer for this at the moment. - -There are two ways to build GStreamer using the MSVC toolchain: - -1. Using the MSVC command-line tools (`cl.exe` etc.) via Meson's "ninja" backend. -2. Letting Meson's "vs2015" backend generate Visual Studio project files that - can be opened in Visual Studio and compiled from there. - -This is currently only for adventurous souls though. All the bits are in place, -but support for all of this has not been merged into GStreamer's cerbero build -tool yet at the time of writing. This will hopefully happen in the next cycle, -but for now this means that those wishing to compile GStreamer with MSVC will -have to get their hands dirty. - -There are also no binary SDK builds using the MSVC toolchain yet. - -For more information on GStreamer builds using Meson and the Windows toolchain -check out Nirbheek Chauhan's blog post ["Building and developing GStreamer using Visual Studio"][msvc-blog]. - -[msvc-blog]: http://blog.nirbheek.in/2016/07/building-and-developing-gstreamer-using.html - -### Dependencies - -#### gstreamer - -libunwind was added as an optional dependency. It is used only for debugging -and tracing purposes. - -The `opencv` plugin in gst-plugins-bad can now be built against OpenCV -version 3.1, previously only 2.3-2.5 were supported. - -#### gst-plugins-ugly - -- `mpeg2dec` now requires at least libmpeg2 0.5.1 (from 2008). - -#### gst-plugins-bad - -- `gltransformation` now requires at least graphene 1.4.0. - -- `lv2` now plugin requires at least lilv 0.16 instead of slv2. - -### Packaging notes - -Packagers please note that the `gst/gstconfig.h` public header file in the -GStreamer core library moved back from being an architecture dependent include -to being architecture independent, and thus it is no longer installed into -`$(libdir)/gstreamer-1.0/include/gst` but into the normal include directory -where it lives happily ever after with all the other public header files. The -reason for this is that we now check whether the target supports unaligned -memory access based on predefined compiler macros at compile time instead of -checking it at configure time. - -## Platform-specific improvements - -### Android - -#### New universal binaries for all supported ABIs - -We now provide a "universal" tarball to allow building apps against all the -architectures currently supported (x86, x86-64, armeabi, armeabi-v7a, -armeabi-v8a). This is needed for building with recent versions of the Android -NDK which defaults to building against all supported ABIs. Use [the Android -player example][android-player-example-build] as a reference for the required -changes. - -[android-player-example-build]: https://cgit.freedesktop.org/gstreamer/gst-examples/commit/playback/player/android?id=a5cdde9119f038a1eb365aca20faa9741a38e788 - -#### Miscellaneous - -- New `ahssrc` element that allows reading the hardware sensors, e.g. compass - or accelerometer. - -### macOS (OS/X) and iOS - -- Support for querying available devices on OS/X via the GstDeviceProvider - API was added. -- It is now possible to create OpenGL|ES 3.x contexts on iOS and use them in - combination with the VideoToolbox based decoder element. -- many OpenGL/GLES improvements, see OpenGL section above - -### Windows - -- gstconfig.h: Always use dllexport/import on Windows with MSVC -- Miscellaneous fixes to make libs and plugins compile with the MVSC toolchain -- MSVC toolchain support (see Meson section above for more details) - -## New Modules for Documentation, Examples, Meson Build - -Three new git modules have been added recently: - -### gst-docs - -This is a new module where we will maintain documentation in the markdown -format. - -It contains the former gstreamer.com SDK tutorials which have kindly been made -available by Fluendo under a Creative Commons license. The tutorials have been -reviewed and updated for GStreamer 1.x and will be available as part of the -[official GStreamer documentation][doc] going forward. The old gstreamer.com -site will then be shut down with redirects pointing to the updated tutorials. - -Some of the existing docbook XML-formatted documentation from the GStreamer -core module such as the *Application Development Manual* and the *Plugin -Writer's Guide* have been converted to markdown as well and will be maintained -in the gst-docs module in future. They will be removed from the GStreamer core -module in the next cycle. - -This is just the beginning. Our goal is to provide a more cohesive documentation -experience for our users going forward, and easier to create and maintain -documentation for developers. There is a lot more work to do, get in touch if -you want to help out. - -If you encounter any problems or spot any omissions or outdated content in the -new documentation, please [file a bug in bugzilla][doc-bug] to let us know. - -We will probably release gst-docs as a separate tarball for distributions to -package in the next cycle. - -[doc]: http://gstreamer.freedesktop.org/documentation/ -[doc-bug]: https://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer&component=documentation - -### gst-examples - -A new [module][examples-git] has been added for examples. It does not contain -much yet, currently it only contains a small [http-launch][http-launch] utility -that serves a pipeline over http as well as various [GstPlayer playback frontends][puis] -for Android, iOS, Gtk+ and Qt. - -More examples will be added over time. The examples in this repository should -be more useful and more substantial than most of the examples we ship as part -of our other modules, and also written in a way that makes them good example -code. If you have ideas for examples, let us know. - -No decision has been made yet if this module will be released and/or packaged. -It probably makes sense to do so though. - -[examples-git]: https://cgit.freedesktop.org/gstreamer/gst-examples/tree/ -[http-launch]: https://cgit.freedesktop.org/gstreamer/gst-examples/tree/network/http-launch/ -[puis]: https://cgit.freedesktop.org/gstreamer/gst-examples/tree/playback/player - -### gst-build - -[gst-build][gst-build-git] is a new meta module to build GStreamer using the -new Meson build system. This module is not required to build GStreamer with -Meson, it is merely for convenience and aims to provide a development setup -similar to the existing `gst-uninstalled` setup. - -gst-build makes use of Meson's [subproject feature][meson-subprojects] and sets -up the various GStreamer modules as subprojects, so they can all be updated and -built in parallel. - -This module is still very new and highly experimental. It should work at least -on Linux and Windows (OS/X needs some build fixes). Let us know of any issues -you encounter by popping into the `#gstreamer` IRC channel or by -[filing a bug][gst-build-bug]. - -This module will probably not be released or packaged (does not really make sense). - -[gst-build-git]: https://cgit.freedesktop.org/gstreamer/gst-build/tree/ -[gst-build-bug]: https://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer&component=gst-build -[meson-subprojects]: https://github.com/mesonbuild/meson/wiki/Subprojects - -## Contributors - -Aaron Boxer, Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, Alex -Ashley, Alex-P. Natsios, Alistair Buxton, Allen Zhang, Andreas Naumann, Andrew -Eikum, Andy Devar, Anthony G. Basile, Arjen Veenhuizen, Arnaud Vrac, Artem -Martynovich, Arun Raghavan, Aurélien Zanelli, Barun Kumar Singh, Bernhard -Miller, Brad Lackey, Branko Subasic, Carlos Garcia Campos, Carlos Rafael -Giani, Christoffer Stengren, Daiki Ueno, Damian Ziobro, Danilo Cesar Lemes de -Paula, David Buchmann, Dimitrios Katsaros, Duncan Palmer, Edward Hervey, -Emmanuel Poitier, Enrico Jorns, Enrique Ocaña González, Fabrice Bellet, -Florian Zwoch, Florin Apostol, Francisco Velazquez, Frédéric Bertolus, Fredrik -Fornwall, Gaurav Gupta, George Kiagiadakis, Georg Lippitsch, Göran Jönsson, -Graham Leggett, Gregoire Gentil, Guillaume Desmottes, Gwang Yoon Hwang, Haakon -Sporsheim, Haihua Hu, Havard Graff, Heinrich Fink, Hoonhee Lee, Hyunjun Ko, -Iain Lane, Ian, Ian Jamison, Jagyum Koo, Jake Foytik, Jakub Adam, Jan -Alexander Steffens (heftig), Jan Schmidt, Javier Martinez Canillas, Jerome -Laheurte, Jesper Larsen, Jie Jiang, Jihae Yi, Jimmy Ohn, Jinwoo Ahn, Joakim -Johansson, Joan Pau Beltran, Jonas Holmberg, Jonathan Matthew, Jonathan Roy, -Josep Torra, Julien Isorce, Jun Ji, Jürgen Slowack, Justin Kim, Kazunori -Kobayashi, Kieran Bingham, Kipp Cannon, Koop Mast, Kouhei Sutou, Kseniia, Kyle -Schwarz, Kyungyong Kim, Linus Svensson, Luis de Bethencourt, Marcin Kolny, -Marcin Lewandowski, Marianna Smidth Buschle, Mario Sanchez Prada, Mark -Combellack, Mark Nauwelaerts, Martin Kelly, Matej Knopp, Mathieu Duponchelle, -Mats Lindestam, Matthew Gruenke, Matthew Waters, Michael Olbrich, Michal Lazo, -Miguel París Díaz, Mikhail Fludkov, Minjae Kim, Mohan R, Munez, Nicola Murino, -Nicolas Dufresne, Nicolas Huet, Nikita Bobkov, Nirbheek Chauhan, Olivier -Crête, Paolo Pettinato, Patricia Muscalu, Paulo Neves, Peng Liu, Peter -Seiderer, Philippe Normand, Philippe Renon, Philipp Zabel, Pierre Lamot, Piotr -Drąg, Prashant Gotarne, Raffaele Rossi, Ray Strode, Reynaldo H. Verdejo -Pinochet, Santiago Carot-Nemesio, Scott D Phillips, Sebastian Dröge, Sebastian -Rasmussen, Sergei Saveliev, Sergey Borovkov, Sergey Mamonov, Sergio Torres -Soldado, Seungha Yang, sezero, Song Bing, Sreerenj Balachandran, Stefan Sauer, -Stephen, Steven Hoving, Stian Selnes, Thiago Santos, Thibault Saunier, Thijs -Vermeir, Thomas Bluemel, Thomas Jones, Thomas Klausner, Thomas Scheuermann, -Tim-Philipp Müller, Ting-Wei Lan, Tom Schoonjans, Ursula Maplehurst, Vanessa -Chipirras Navalon, Víctor Manuel Jáquez Leal, Vincent Penquerc'h, Vineeth TM, -Vivia Nikolaidou, Vootele Vesterblom, Wang Xin-yu (王昕宇), William Manley, -Wim Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier Claessens, xlazom00, -Yann Jouanin, Zaheer Abbas Merali - -... and many others who have contributed bug reports, translations, sent -suggestions or helped testing. - -## Bugs fixed in 1.10 - -More than [750 bugs][bugs-fixed-in-1.10] have been fixed during -the development of 1.10. - -This list does not include issues that have been cherry-picked into the -stable 1.8 branch and fixed there as well, all fixes that ended up in the -1.8 branch are also included in 1.10. - -This list also does not include issues that have been fixed without a bug -report in bugzilla, so the actual number of fixes is much higher. - -[bugs-fixed-in-1.10]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=164074&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.8.1&target_milestone=1.8.2&target_milestone=1.8.3&target_milestone=1.8.4&target_milestone=1.9.1&target_milestone=1.9.2&target_milestone=1.9.90&target_milestone=1.10.0 - -## Stable 1.10 branch - -After the 1.10.0 release there will be several 1.10.x bug-fix releases which -will contain bug fixes which have been deemed suitable for a stable branch, -but no new features or intrusive changes will be added to a bug-fix release -usually. The 1.10.x bug-fix releases will be made from the git 1.10 branch, -which is a stable branch. - -### 1.10.0 - -1.10.0 was released on 1st November 2016. - -## Known Issues - -- iOS builds with iOS 6 SDK and old C++ STL. You need to select iOS 6 instead - of 7 or 8 in your projects settings to be able to link applications. - [Bug #766366](https://bugzilla.gnome.org/show_bug.cgi?id=766366) -- Code signing for Apple platforms has some problems currently, requiring - manual work to get your application signed. [Bug #771860](https://bugzilla.gnome.org/show_bug.cgi?id=771860) -- Building applications with Android NDK r13 on Windows does not work. Other - platforms and earlier/later versions of the NDK are not affected. - [Bug #772842](https://bugzilla.gnome.org/show_bug.cgi?id=772842) -- The new leaks tracer may deadlock the application (or exhibit other undefined - behaviour) when `SIGUSR` handling is enabled via the `GST_LEAKS_TRACER_SIG` - environment variable. [Bug #770373](https://bugzilla.gnome.org/show_bug.cgi?id=770373) -- vp8enc crashes on 32 bit Windows, but was working fine in 1.6. 64 bit Windows is unaffected. - [Bug #763663](https://bugzilla.gnome.org/show_bug.cgi?id=763663) - -## Schedule for 1.12 - -Our next major feature release will be 1.12, and 1.11 will be the unstable -development version leading up to the stable 1.12 release. The development -of 1.11/1.12 will happen in the git master branch. - -The plan for the 1.12 development cycle is yet to be confirmed, but it is -expected that feature freeze will be around early/mid-January, -followed by several 1.11 pre-releases and the new 1.12 stable release -in March. - -1.12 will be backwards-compatible to the stable 1.10, 1.8, 1.6, 1.4, 1.2 and -1.0 release series. - -- - - - -*These release notes have been prepared by Olivier Crête, Sebastian Dröge, -Nicolas Dufresne, Edward Hervey, Víctor Manuel Jáquez Leal, Tim-Philipp -Müller, Reynaldo H. Verdejo Pinochet, Arun Raghavan, Thibault Saunier, -Jan Schmidt, Wim Taymans, Matthew Waters* - -*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* - +This is GStreamer 1.11.1. diff --git a/RELEASE b/RELEASE index 8b76e38d94..d5369183ba 100644 --- a/RELEASE +++ b/RELEASE @@ -1,23 +1,32 @@ -Release notes for GStreamer RTSP Server Library 1.10.0 +Release notes for GStreamer RTSP Server Library 1.11.1 -The GStreamer team is pleased to announce the first release of the new stable -1.10 release series. The 1.10 release series is adding new features on top of -the 1.0, 1.2, 1.4, 1.6 and 1.8 series and is part of the API and ABI-stable 1.x -release series of the GStreamer multimedia framework. +The GStreamer team is pleased to announce the first release of the unstable +1.11 release series. The 1.11 release series is adding new features on top of +the 1.0, 1.2, 1.4, 1.6, 1.8 and 1.10 series and is part of the API and ABI-stable 1.x release +series of the GStreamer multimedia framework. The unstable 1.11 release series +will lead to the stable 1.12 release series in the next weeks. Any newly added +API can still change until that point. -Binaries for Android, iOS, Mac OS X and Windows will be provided shortly after -the source release by the GStreamer project during the stable 1.10 release -series. +Full release notes will be provided at some point during the 1.11 release +cycle, highlighting all the new features, bugfixes, performance optimizations +and other important changes. + + +Binaries for Android, iOS, Mac OS X and Windows will be provided in the next days. Bugs fixed in this release - * 771983 : Deadlock when closing session and backlog is full. - * 772478 : Missing video stream from SDP - * 773640 : rtspclient unit test failures + * 758062 : rtsp-client: emit new rtsp request signals in the beginning of each request + * 771830 : There is no time out in idle connection RTSP server + * 774173 : media: emit signal SIGNAL_NEW_STATE only when state change happens + * 774640 : gst-rtsp-server: Enable building with MSVC + * 776867 : pkgconfig: fix -uninstalled pc file + * 777037 : rtsp-factory: just fixing a little typo in comments + * 774416 : RTSP digest Authentification for gst-rtsp-server ==== Download ==== @@ -54,8 +63,19 @@ subscribe to the gstreamer-devel list. Contributors to this release + * Aleksandr Slobodeniuk + * Branko Subasic + * Dag Gullberg + * Edward Hervey + * Guillaume Desmottes * Göran Jönsson - * Nikita Bobkov + * Jan Schmidt + * Kseniia Vasilchuk + * Matthew Waters + * Neha Arora + * Patricia Muscalu + * Scott D Phillips + * Sebastian Dröge + * Thibault Saunier * Tim-Philipp Müller - * Xavier Claessens   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 8167ff9fdd..012531b32c 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.11.0.1], +AC_INIT([GStreamer RTSP Server Library], [1.11.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1100, 0, 1100) +AS_LIBTOOL(GST, 1101, 0, 1101) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.0.1 -GSTPB_REQ=1.11.0.1 -GSTPG_REQ=1.11.0.1 -GSTPD_REQ=1.11.0.1 +GST_REQ=1.11.1 +GSTPB_REQ=1.11.1 +GSTPG_REQ=1.11.1 +GSTPD_REQ=1.11.1 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 27bb2baaba..33fe0f8d06 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.11.1 + master + + 2017-01-12 + + + + 1.10.0 diff --git a/win32/common/libgstrtspserver.def b/win32/common/libgstrtspserver.def index 18318e3f05..93f12fa10d 100644 --- a/win32/common/libgstrtspserver.def +++ b/win32/common/libgstrtspserver.def @@ -197,6 +197,7 @@ EXPORTS gst_rtsp_session_get_sessionid gst_rtsp_session_get_timeout gst_rtsp_session_get_type + gst_rtsp_session_is_expired gst_rtsp_session_is_expired_usec gst_rtsp_session_manage_media gst_rtsp_session_media_alloc_channels @@ -212,6 +213,7 @@ EXPORTS gst_rtsp_session_media_set_state gst_rtsp_session_media_set_transport gst_rtsp_session_new + gst_rtsp_session_next_timeout gst_rtsp_session_next_timeout_usec gst_rtsp_session_pool_cleanup gst_rtsp_session_pool_create From 2d9a5722fa2bf45dfe08fbb7fa4bc0291e7743a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 12 Jan 2017 16:32:59 +0200 Subject: [PATCH 1341/1776] Back to development --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 012531b32c..82a57dce7a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.11.1], +AC_INIT([GStreamer RTSP Server Library], [1.11.1.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 1101, 0, 1101) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.1 -GSTPB_REQ=1.11.1 -GSTPG_REQ=1.11.1 -GSTPD_REQ=1.11.1 +GST_REQ=1.11.1.1 +GSTPB_REQ=1.11.1.1 +GSTPG_REQ=1.11.1.1 +GSTPD_REQ=1.11.1.1 dnl *** autotools stuff **** From 6e145fadf9c5cc2c7d4bddf806b548327914bf68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 12 Jan 2017 19:04:23 +0200 Subject: [PATCH 1342/1776] rtsp-session: Only remove deprecated API if requested to do so, not just when disabling gst_rtsp_session_is_expired() and gst_rtsp_session_next_timeout() were affected. --- gst/rtsp-server/rtsp-session.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 8c664e2858..e4ef122723 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -672,7 +672,10 @@ gst_rtsp_session_next_timeout_usec (GstRTSPSession * session, gint64 now) * Deprecated: Use gst_rtsp_session_next_timeout_usec() instead. */ #ifndef GST_REMOVE_DEPRECATED -#ifndef GST_DISABLE_DEPRECATED +#ifdef GST_DISABLE_DEPRECATED +gint gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now); +#endif + gint gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) { @@ -709,7 +712,6 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) return res; } #endif -#endif /** * gst_rtsp_session_is_expired_usec: @@ -745,7 +747,9 @@ gst_rtsp_session_is_expired_usec (GstRTSPSession * session, gint64 now) * Deprecated: Use gst_rtsp_session_is_expired_usec() instead. */ #ifndef GST_REMOVE_DEPRECATED -#ifndef GST_DISABLE_DEPRECATED +#ifdef GST_DISABLE_DEPRECATED +gboolean gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now); +#endif gboolean gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) { @@ -756,4 +760,3 @@ gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) return res; } #endif -#endif From 9f889c59c2f7bd71c394d9d4f714b60f513c24df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 13 Jan 2017 12:39:36 +0000 Subject: [PATCH 1343/1776] meson: bump version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index fdd340c345..36eeaa9943 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.11.0.1', + version : '1.11.1.1', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From ac1124efb4e5e1cef2853628ba5cb46cdb30308d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 19 Jan 2017 14:24:07 +0200 Subject: [PATCH 1344/1776] rtsp-client: Fix handling of keep-alive GET_PARAMETER/SET_PARAMETER While they logically have 0 bytes length, GstRTSPConnection is appending a '\0' to everything making the size be 1 instead. --- gst/rtsp-server/rtsp-client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6f59c5e43d..63ac61727e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1250,8 +1250,8 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx) if (res != GST_RTSP_OK) goto bad_request; - if (size == 0) { - /* no body, keep-alive request */ + if (size == 1) { + /* no body (only '\0'), keep-alive request */ send_generic_response (client, GST_RTSP_STS_OK, ctx); } else { /* there is a body, handle the params */ @@ -1302,8 +1302,8 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx) if (res != GST_RTSP_OK) goto bad_request; - if (size == 0) { - /* no body, keep-alive request */ + if (size == 1) { + /* no body (only '\0'), keep-alive request */ send_generic_response (client, GST_RTSP_STS_OK, ctx); } else { /* there is a body, handle the params */ From cd4e675f0cd91619d3acfe85ceeb4ae103762d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 19 Jan 2017 14:57:19 +0200 Subject: [PATCH 1345/1776] rtsp-client: Also handle the (S|G)ET_PARAMETER case of size==0 || !data as keep-alive If there is no Content-Length header, no body would be allocated and the '\0' would also not be appended to the body. --- gst/rtsp-server/rtsp-client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 63ac61727e..cf78b17578 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1250,8 +1250,8 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx) if (res != GST_RTSP_OK) goto bad_request; - if (size == 1) { - /* no body (only '\0'), keep-alive request */ + if (size == 0 || !data || strlen ((char *) data) == 0) { + /* no body (or only '\0'), keep-alive request */ send_generic_response (client, GST_RTSP_STS_OK, ctx); } else { /* there is a body, handle the params */ @@ -1302,8 +1302,8 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx) if (res != GST_RTSP_OK) goto bad_request; - if (size == 1) { - /* no body (only '\0'), keep-alive request */ + if (size == 0 || !data || strlen ((char *) data) == 0) { + /* no body (or only '\0'), keep-alive request */ send_generic_response (client, GST_RTSP_STS_OK, ctx); } else { /* there is a body, handle the params */ From 007f48f71154f6d4ec44b41b6050107a9fe35859 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 7 Feb 2017 23:39:37 +1100 Subject: [PATCH 1346/1776] examples/test-record: Add extra line to initial printout Add an example line of how to deliver a stream to the RTSP RECORD example --- examples/test-record.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/test-record.c b/examples/test-record.c index 437eaf5e62..47b8fd92c3 100644 --- a/examples/test-record.c +++ b/examples/test-record.c @@ -92,6 +92,9 @@ main (int argc, char *argv[]) /* start serving */ g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port); + g_print ("On the sender, send a stream with rtspclientsink:\n" + " gst-launch-1.0 videotestsrc ! x264enc ! rtspclientsink location=rtsp://127.0.0.1:%s/test\n", + port); g_main_loop_run (loop); return 0; From a9cb8868fda710f4d454deab6564e173eccd3754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 14 Feb 2017 20:40:26 +0000 Subject: [PATCH 1347/1776] meson: dist meson build files Ship meson build files in tarballs, so people who use tarballs in their builds can start playing with meson already. --- Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index eb01c6a53d..7a89d2782c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,7 +24,9 @@ EXTRA_DIST = \ AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \ docs/design/gst-rtp-server-design \ gst-rtsp-server.doap \ - $(win32) + $(win32) \ + $(shell find "$(top_srcdir)" -type f -name meson.build ! -path "$(top_srcdir)/$(PACKAGE_TARNAME)-*" ) \ + config.h.meson ACLOCAL_AMFLAGS = -I m4 -I common/m4 From ed79e99cfa194e7e974d4023f9b29fb61f952156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 24 Feb 2017 15:10:07 +0200 Subject: [PATCH 1348/1776] Release 1.11.2 --- ChangeLog | 63 +++++++++++++++++++++++++++++++++++++++++--- NEWS | 2 +- RELEASE | 26 ++---------------- configure.ac | 12 ++++----- gst-rtsp-server.doap | 10 +++++++ 5 files changed, 79 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index 610dd606d9..febc1d9541 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,66 @@ -=== release 1.11.1 === +=== release 1.11.2 === -2017-01-12 Sebastian Dröge +2017-02-24 Sebastian Dröge * configure.ac: - releasing 1.11.1 + releasing 1.11.2 + +2017-02-14 20:40:26 +0000 Tim-Philipp Müller + + * Makefile.am: + meson: dist meson build files + Ship meson build files in tarballs, so people who use tarballs + in their builds can start playing with meson already. + +2017-02-07 23:39:37 +1100 Jan Schmidt + + * examples/test-record.c: + examples/test-record: Add extra line to initial printout + Add an example line of how to deliver a stream to the + RTSP RECORD example + +2017-01-19 14:57:19 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Also handle the (S|G)ET_PARAMETER case of size==0 || !data as keep-alive + If there is no Content-Length header, no body would be allocated and the + '\0' would also not be appended to the body. + +2017-01-19 14:24:07 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Fix handling of keep-alive GET_PARAMETER/SET_PARAMETER + While they logically have 0 bytes length, GstRTSPConnection is appending + a '\0' to everything making the size be 1 instead. + +2017-01-13 12:39:36 +0000 Tim-Philipp Müller + + * meson.build: + meson: bump version + +2017-01-12 19:04:23 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-session.c: + rtsp-session: Only remove deprecated API if requested to do so, not just when disabling + gst_rtsp_session_is_expired() and gst_rtsp_session_next_timeout() were + affected. + +2017-01-12 16:32:59 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.11.1 === + +2017-01-12 16:14:46 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + * win32/common/libgstrtspserver.def: + Release 1.11.1 2017-01-10 08:34:50 +0100 Patricia Muscalu diff --git a/NEWS b/NEWS index a940f7bb0f..ba794a2734 100644 --- a/NEWS +++ b/NEWS @@ -1 +1 @@ -This is GStreamer 1.11.1. +This is GStreamer 1.11.2. diff --git a/RELEASE b/RELEASE index d5369183ba..a601960422 100644 --- a/RELEASE +++ b/RELEASE @@ -1,7 +1,7 @@ -Release notes for GStreamer RTSP Server Library 1.11.1 +Release notes for GStreamer RTSP Server Library 1.11.2 -The GStreamer team is pleased to announce the first release of the unstable +The GStreamer team is pleased to announce the second release of the unstable 1.11 release series. The 1.11 release series is adding new features on top of the 1.0, 1.2, 1.4, 1.6, 1.8 and 1.10 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. The unstable 1.11 release series @@ -18,16 +18,6 @@ Binaries for Android, iOS, Mac OS X and Windows will be provided in the next day -Bugs fixed in this release - - * 758062 : rtsp-client: emit new rtsp request signals in the beginning of each request - * 771830 : There is no time out in idle connection RTSP server - * 774173 : media: emit signal SIGNAL_NEW_STATE only when state change happens - * 774640 : gst-rtsp-server: Enable building with MSVC - * 776867 : pkgconfig: fix -uninstalled pc file - * 777037 : rtsp-factory: just fixing a little typo in comments - * 774416 : RTSP digest Authentification for gst-rtsp-server - ==== Download ==== You can find source releases of gst-rtsp-server in the download @@ -63,19 +53,7 @@ subscribe to the gstreamer-devel list. Contributors to this release - * Aleksandr Slobodeniuk - * Branko Subasic - * Dag Gullberg - * Edward Hervey - * Guillaume Desmottes - * Göran Jönsson * Jan Schmidt - * Kseniia Vasilchuk - * Matthew Waters - * Neha Arora - * Patricia Muscalu - * Scott D Phillips * Sebastian Dröge - * Thibault Saunier * Tim-Philipp Müller   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 82a57dce7a..1cffcba8ff 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.11.1.1], +AC_INIT([GStreamer RTSP Server Library], [1.11.2], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1101, 0, 1101) +AS_LIBTOOL(GST, 1102, 0, 1102) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.1.1 -GSTPB_REQ=1.11.1.1 -GSTPG_REQ=1.11.1.1 -GSTPD_REQ=1.11.1.1 +GST_REQ=1.11.2 +GSTPB_REQ=1.11.2 +GSTPG_REQ=1.11.2 +GSTPD_REQ=1.11.2 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 33fe0f8d06..09c746d038 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.11.2 + master + + 2017-02-24 + + + + 1.11.1 From f5252fab9adea8f509dd07757af700920befebc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 24 Feb 2017 15:37:49 +0200 Subject: [PATCH 1349/1776] Back to development --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 1cffcba8ff..b3dc875950 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.11.2], +AC_INIT([GStreamer RTSP Server Library], [1.11.2.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 1102, 0, 1102) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.2 -GSTPB_REQ=1.11.2 -GSTPG_REQ=1.11.2 -GSTPD_REQ=1.11.2 +GST_REQ=1.11.2.1 +GSTPB_REQ=1.11.2.1 +GSTPG_REQ=1.11.2.1 +GSTPD_REQ=1.11.2.1 dnl *** autotools stuff **** From 2cd9214c8b72253bb8ee7e0bab5c5a3925f2feea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 24 Feb 2017 15:59:54 +0200 Subject: [PATCH 1350/1776] meson: Update version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 36eeaa9943..3758e4c40d 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.11.1.1', + version : '1.11.2.1', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From eb1ee7e28d4838aa653426ffabd76fad9aeb3c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 27 Feb 2017 19:10:44 +0200 Subject: [PATCH 1351/1776] gstreamer-rtsp-server: Add both srcdir and builddir to the include path Just the build dir is not going to work for srcdir!=builddir. --- pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in index 6c9afd6760..5c2df0ab03 100644 --- a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in +++ b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in @@ -9,4 +9,4 @@ Description: GStreamer based RTSP server Version: @VERSION@ Requires: gstreamer-@GST_API_VERSION@ gstreamer-plugins-base-@GST_API_VERSION@ Libs: -L${libdir} -lgstrtspserver-@GST_API_VERSION@ -Cflags: -I${includedir} -I@srcdir@/.. +Cflags: -I@abs_top_srcdir@ -I@abs_top_builddir@ -I@srcdir@/.. From 3dcd77a21c7e20a71347242caae2129644685987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 27 Mar 2017 18:19:33 +0100 Subject: [PATCH 1352/1776] examples: make test-launch pipeline shared by default as well --- examples/test-launch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/test-launch.c b/examples/test-launch.c index 03bcd410aa..1675591bae 100644 --- a/examples/test-launch.c +++ b/examples/test-launch.c @@ -69,6 +69,7 @@ main (int argc, char *argv[]) * element with pay%d names will be a stream */ factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, argv[1]); + gst_rtsp_media_factory_set_shared (factory, TRUE); /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test", factory); From 085304696ec582395f8e718cfe16050f3ecda539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 7 Apr 2017 16:35:03 +0300 Subject: [PATCH 1353/1776] Release 1.11.90 --- ChangeLog | 38 +++++++++++++++++++++++++++++++++++--- NEWS | 2 +- RELEASE | 19 ++++++++----------- configure.ac | 12 ++++++------ gst-rtsp-server.doap | 10 ++++++++++ meson.build | 2 +- 6 files changed, 61 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index febc1d9541..07665a2dfa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,41 @@ -=== release 1.11.2 === +=== release 1.11.90 === -2017-02-24 Sebastian Dröge +2017-04-07 Sebastian Dröge * configure.ac: - releasing 1.11.2 + releasing 1.11.90 + +2017-03-27 18:19:33 +0100 Tim-Philipp Müller + + * examples/test-launch.c: + examples: make test-launch pipeline shared by default as well + +2017-02-27 19:10:44 +0200 Sebastian Dröge + + * pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in: + gstreamer-rtsp-server: Add both srcdir and builddir to the include path + Just the build dir is not going to work for srcdir!=builddir. + +2017-02-24 15:59:54 +0200 Sebastian Dröge + + * meson.build: + meson: Update version + +2017-02-24 15:37:49 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.11.2 === + +2017-02-24 15:10:07 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + Release 1.11.2 2017-02-14 20:40:26 +0000 Tim-Philipp Müller diff --git a/NEWS b/NEWS index ba794a2734..8e8dc3f622 100644 --- a/NEWS +++ b/NEWS @@ -1 +1 @@ -This is GStreamer 1.11.2. +This is GStreamer 1.11.90. diff --git a/RELEASE b/RELEASE index a601960422..6097ba2b78 100644 --- a/RELEASE +++ b/RELEASE @@ -1,17 +1,15 @@ -Release notes for GStreamer RTSP Server Library 1.11.2 +Release notes for GStreamer RTSP Server Library 1.11.90 -The GStreamer team is pleased to announce the second release of the unstable -1.11 release series. The 1.11 release series is adding new features on top of -the 1.0, 1.2, 1.4, 1.6, 1.8 and 1.10 series and is part of the API and ABI-stable 1.x release -series of the GStreamer multimedia framework. The unstable 1.11 release series -will lead to the stable 1.12 release series in the next weeks. Any newly added -API can still change until that point. +The GStreamer team is pleased to announce the first release candidate of the +stable 1.12 release series. The 1.12 release series is adding new features on +top of the 1.0, 1.2, 1.4, 1.6, 1.8 and 1.10 series and is part of the API and +ABI-stable 1.x release series of the GStreamer multimedia framework. -Full release notes will be provided at some point during the 1.11 release -cycle, highlighting all the new features, bugfixes, performance optimizations -and other important changes. +Full release notes will be provided with the 1.12.0 release, highlighting all +the new features, bugfixes, performance optimizations and other important +changes. Binaries for Android, iOS, Mac OS X and Windows will be provided in the next days. @@ -53,7 +51,6 @@ subscribe to the gstreamer-devel list. Contributors to this release - * Jan Schmidt * Sebastian Dröge * Tim-Philipp Müller   \ No newline at end of file diff --git a/configure.ac b/configure.ac index b3dc875950..6933a848e7 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.11.2.1], +AC_INIT([GStreamer RTSP Server Library], [1.11.90], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1102, 0, 1102) +AS_LIBTOOL(GST, 1190, 0, 1190) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.2.1 -GSTPB_REQ=1.11.2.1 -GSTPG_REQ=1.11.2.1 -GSTPD_REQ=1.11.2.1 +GST_REQ=1.11.90 +GSTPB_REQ=1.11.90 +GSTPG_REQ=1.11.90 +GSTPD_REQ=1.11.90 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 09c746d038..6046fe0bf0 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.11.90 + master + + 2017-04-07 + + + + 1.11.2 diff --git a/meson.build b/meson.build index 3758e4c40d..3736be20a6 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.11.2.1', + version : '1.11.90', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From b5281c18c45a4be34d3447bd58e8bd9606e01402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 10 Apr 2017 23:51:12 +0100 Subject: [PATCH 1354/1776] Automatic update of common submodule From 39ac2f5 to 60aeef6 --- autogen.sh | 2 +- common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/autogen.sh b/autogen.sh index aecf0e2e4a..2d4b05b1cd 100755 --- a/autogen.sh +++ b/autogen.sh @@ -53,7 +53,7 @@ fi CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc' if test "x$package" = "xgstreamer"; then - CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --enable-docbook --enable-failing-tests --enable-poisoning" + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --enable-failing-tests --enable-poisoning" elif test "x$package" = "xgst-plugins-bad"; then CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-player-tests" fi diff --git a/common b/common index 39ac2f563e..60aeef6837 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 39ac2f563e12d22100e320c95aaab8d8e5812ca9 +Subproject commit 60aeef6837610c672cebf247ec748538faab7bf1 From 133e91462a337c61ba31715b0580adaa6652fca0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 13 Apr 2017 13:52:26 -0300 Subject: [PATCH 1355/1776] meson: Build gir --- gst/rtsp-server/meson.build | 22 +++++++++++++++++++++- meson.build | 9 +++++++++ meson_options.txt | 3 +++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 meson_options.txt diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index d65a078abe..d4b28fcb7d 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -43,6 +43,7 @@ rtsp_server_headers = [ ] install_headers(rtsp_server_headers, subdir : 'gstreamer-1.0/gst/rtsp-server') +gst_rtsp_server_deps = [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_dep] gst_rtsp_server = library('gstrtspserver-@0@'.format(api_version), rtsp_server_sources, include_directories : rtspserver_incs, @@ -50,10 +51,29 @@ gst_rtsp_server = library('gstrtspserver-@0@'.format(api_version), version : libversion, soversion : soversion, install : true, - dependencies : [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_dep], + dependencies : gst_rtsp_server_deps, vs_module_defs: vs_module_defs_dir + 'libgstrtspserver.def' ) +rtsp_server_gen_sources = [] +if build_gir + gst_gir_extra_args = gir_init_section + ['--c-include=gst/rtsp-server/rtsp-server.h'] + rtsp_server_gir = gnome.generate_gir(gst_rtsp_server, + sources : rtsp_server_headers + rtsp_server_sources, + namespace : 'GstRtspServer', + nsversion : api_version, + identifier_prefix : 'Gst', + symbol_prefix : 'gst', + export_packages : 'gstreamer-rtsp-server-' + api_version, + install : true, + extra_args : gst_gir_extra_args, + includes : ['Gst-1.0', 'GstRtsp-1.0', 'GstNet-1.0'], + dependencies : gst_rtsp_server_deps, + ) + rtsp_server_gen_sources += [rtsp_server_gir] +endif + gst_rtsp_server_dep = declare_dependency(link_with : gst_rtsp_server, include_directories : rtspserver_incs, + sources : rtsp_server_gen_sources, dependencies : [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_dep]) diff --git a/meson.build b/meson.build index 3736be20a6..31f376e8a7 100644 --- a/meson.build +++ b/meson.build @@ -59,6 +59,15 @@ gstnet_dep = dependency('gstreamer-net-1.0', version : gst_req, vs_module_defs_dir = meson.current_source_dir() + '/win32/common/' +gir = find_program('g-ir-scanner', required : false) +gnome = import('gnome') +build_gir = gir.found() and not meson.is_cross_build() and not get_option('disable_introspection') +gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**);' + \ + 'g_setenv("GST_REGISTRY_1.0", "@0@", TRUE);'.format(meson.current_build_dir() + '/gir_empty_registry.reg') + \ + 'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \ + 'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \ + 'gst_init(NULL,NULL);' ] + subdir('gst') subdir('tests') subdir('examples') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000000..e265545279 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,3 @@ +option('disable_introspection', + type : 'boolean', value : false, + description : 'Whether to disable the introspection generation') From b56930704f0c8ab17e24716f16a841154ca94021 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 13 Apr 2017 14:20:10 -0300 Subject: [PATCH 1356/1776] gi: Fix some annotations and docstrings --- gst/rtsp-server/rtsp-media-factory.c | 12 ++++++------ gst/rtsp-server/rtsp-media.c | 2 +- gst/rtsp-server/rtsp-session.c | 4 ++-- gst/rtsp-server/rtsp-stream.c | 9 +++++---- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index fc760aab1c..cecb8a02d8 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -803,10 +803,10 @@ gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory) /** * gst_rtsp_media_factory_set_multicast_iface: - * @media_factory: a #GstRTSPMediaFactory + * @factory: a #GstRTSPMediaFactory * @multicast_iface: (transfer none): a multicast interface name * - * configure @multicast_iface to be used for @media_factory. + * configure @multicast_iface to be used for @factory. */ void gst_rtsp_media_factory_set_multicast_iface (GstRTSPMediaFactory * media_factory, @@ -834,11 +834,11 @@ gst_rtsp_media_factory_set_multicast_iface (GstRTSPMediaFactory * media_factory, /** * gst_rtsp_media_factory_get_multicast_iface: - * @media_factory: a #GstRTSPMediaFactory + * @factory: a #GstRTSPMediaFactory * - * Get the multicast interface used for @media_factory. + * Get the multicast interface used for @factory. * - * Returns: (transfer full): the multicast interface for @media_factory. g_free() after + * Returns: (transfer full): the multicast interface for @factory. g_free() after * usage. */ gchar * @@ -1292,7 +1292,7 @@ gst_rtsp_media_factory_get_media_gtype (GstRTSPMediaFactory * factory) /** * gst_rtsp_media_factory_set_clock: * @factory: a #GstRTSPMediaFactory - * @clockd: the clock to be used by the media factory + * @clock: the clock to be used by the media factory * * Configures a specific clock to be used by the pipelines * of all medias created from this factory. diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index a7f3460032..996f453133 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1494,7 +1494,7 @@ gst_rtsp_media_set_publish_clock_mode (GstRTSPMedia * media, /** * gst_rtsp_media_get_publish_clock_mode: - * @factory: a #GstRTSPMedia + * @media: a #GstRTSPMedia * * Gets if and how the media clock should be published according to RFC7273. * diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index e4ef122723..e6faaf5239 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -617,7 +617,7 @@ gst_rtsp_session_allow_expire (GstRTSPSession * session) /** * gst_rtsp_session_next_timeout_usec: * @session: a #GstRTSPSession - * @now: (transfer none): the current monotonic time + * @now: the current monotonic time * * Get the amount of milliseconds till the session will expire. * @@ -716,7 +716,7 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) /** * gst_rtsp_session_is_expired_usec: * @session: a #GstRTSPSession - * @now: (transfer none): the current monotonic time + * @now: the current monotonic time * * Check if @session timeout out. * diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 445b924d49..6bb24dfc97 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1416,7 +1416,8 @@ cleanup: * gst_rtsp_stream_allocate_udp_sockets: * @stream: a #GstRTSPStream * @family: protocol family - * @transport_method: transport method + * @transport: transport method + * @use_client_setttings: Whether to use client settings or not * * Allocates RTP and RTCP ports. * @@ -1574,7 +1575,7 @@ gst_rtsp_stream_get_rtpsession (GstRTSPStream * stream) } /** - * gst_rtsp_stream_get_encoder: + * gst_rtsp_stream_get_srtp_encoder: * @stream: a #GstRTSPStream * * Get the SRTP encoder for this stream. @@ -2262,7 +2263,7 @@ gst_rtsp_stream_set_publish_clock_mode (GstRTSPStream * stream, /** * gst_rtsp_stream_get_publish_clock_mode: - * @factory: a #GstRTSPStream + * @stream: a #GstRTSPStream * * Gets if and how the stream clock should be published according to RFC7273. * @@ -2977,7 +2978,7 @@ gst_rtsp_stream_get_joined_bin (GstRTSPStream * stream) * @rtptime: (allow-none): result RTP timestamp * @seq: (allow-none): result RTP seqnum * @clock_rate: (allow-none): the clock rate - * @running_time: (allow-none): result running-time + * @running_time: result running-time * * Retrieve the current rtptime, seq and running-time. This is used to * construct a RTPInfo reply header. From 3acd5dd665378339963c29143a2e42703ad64974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 24 Apr 2017 20:30:37 +0100 Subject: [PATCH 1357/1776] Automatic update of common submodule From 60aeef6 to 48a5d85 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 60aeef6837..48a5d85ebf 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 60aeef6837610c672cebf247ec748538faab7bf1 +Subproject commit 48a5d85ebf4a0bad1c997c83100f710fe2154fbf From 3a19f439be4d4c7df16bceaff18f006b4da17e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 27 Apr 2017 17:42:02 +0300 Subject: [PATCH 1358/1776] Release 1.11.91 --- ChangeLog | 46 +++++++++++++++++++++++++++++++++++++++++--- NEWS | 2 +- RELEASE | 6 +++--- configure.ac | 12 ++++++------ gst-rtsp-server.doap | 10 ++++++++++ meson.build | 2 +- 6 files changed, 64 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 07665a2dfa..75c30c57ba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,49 @@ -=== release 1.11.90 === +=== release 1.11.91 === -2017-04-07 Sebastian Dröge +2017-04-27 Sebastian Dröge * configure.ac: - releasing 1.11.90 + releasing 1.11.91 + +2017-04-24 20:30:37 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 60aeef6 to 48a5d85 + +2017-04-13 14:20:10 -0300 Thibault Saunier + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-stream.c: + gi: Fix some annotations and docstrings + +2017-04-13 13:52:26 -0300 Thibault Saunier + + * gst/rtsp-server/meson.build: + * meson.build: + * meson_options.txt: + meson: Build gir + +2017-04-10 23:51:12 +0100 Tim-Philipp Müller + + * autogen.sh: + * common: + Automatic update of common submodule + From 39ac2f5 to 60aeef6 + +=== release 1.11.90 === + +2017-04-07 16:35:03 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + * meson.build: + Release 1.11.90 2017-03-27 18:19:33 +0100 Tim-Philipp Müller diff --git a/NEWS b/NEWS index 8e8dc3f622..bf58e3069e 100644 --- a/NEWS +++ b/NEWS @@ -1 +1 @@ -This is GStreamer 1.11.90. +This is GStreamer 1.11.91. diff --git a/RELEASE b/RELEASE index 6097ba2b78..a4db4243a5 100644 --- a/RELEASE +++ b/RELEASE @@ -1,7 +1,7 @@ -Release notes for GStreamer RTSP Server Library 1.11.90 +Release notes for GStreamer RTSP Server Library 1.11.91 -The GStreamer team is pleased to announce the first release candidate of the +The GStreamer team is pleased to announce the second release candidate of the stable 1.12 release series. The 1.12 release series is adding new features on top of the 1.0, 1.2, 1.4, 1.6, 1.8 and 1.10 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. @@ -51,6 +51,6 @@ subscribe to the gstreamer-devel list. Contributors to this release - * Sebastian Dröge + * Thibault Saunier * Tim-Philipp Müller   \ No newline at end of file diff --git a/configure.ac b/configure.ac index 6933a848e7..d2438e9855 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.11.90], +AC_INIT([GStreamer RTSP Server Library], [1.11.91], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1190, 0, 1190) +AS_LIBTOOL(GST, 1191, 0, 1191) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.90 -GSTPB_REQ=1.11.90 -GSTPG_REQ=1.11.90 -GSTPD_REQ=1.11.90 +GST_REQ=1.11.91 +GSTPB_REQ=1.11.91 +GSTPG_REQ=1.11.91 +GSTPD_REQ=1.11.91 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 6046fe0bf0..c19482fef0 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.11.91 + master + + 2017-04-27 + + + + 1.11.90 diff --git a/meson.build b/meson.build index 31f376e8a7..a65f8a3938 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.11.90', + version : '1.11.91', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From d4a0640855bd8d72927ec23c9794cf6978839722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 4 May 2017 15:40:46 +0300 Subject: [PATCH 1359/1776] Release 1.12.0 --- ChangeLog | 18 +- NEWS | 735 ++++++++++++++++++++++++++++++++++++++++++- RELEASE | 15 +- configure.ac | 12 +- gst-rtsp-server.doap | 10 + meson.build | 2 +- 6 files changed, 773 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 75c30c57ba..3e3a6308e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,21 @@ -=== release 1.11.91 === +=== release 1.12.0 === -2017-04-27 Sebastian Dröge +2017-05-04 Sebastian Dröge * configure.ac: - releasing 1.11.91 + releasing 1.12.0 + +=== release 1.11.91 === + +2017-04-27 17:42:02 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + * meson.build: + Release 1.11.91 2017-04-24 20:30:37 +0100 Tim-Philipp Müller diff --git a/NEWS b/NEWS index bf58e3069e..74fb1eaeb8 100644 --- a/NEWS +++ b/NEWS @@ -1 +1,734 @@ -This is GStreamer 1.11.91. +# GStreamer 1.12 Release Notes + +GStreamer 1.12.0 was originally released on 4th May 2017. + +The GStreamer team is proud to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! + +As always, this release is again packed with new features, bug fixes and other +improvements. + +See [https://gstreamer.freedesktop.org/releases/1.12/][latest] for the latest +version of this document. + +*Last updated: Thursday 4 May 2017, 11:00 UTC [(log)][gitlog]* + +[latest]: https://gstreamer.freedesktop.org/releases/1.12/ +[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.12/release-notes-1.12.md + +## Introduction + +The GStreamer team is proud to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! + +As always, this release is again packed with new features, bug fixes and other +improvements. + +## Highlights + +- new `msdk` plugin for Intel's Media SDK for hardware-accelerated video + encoding and decoding on Intel graphics hardware on Windows or Linux. + +- `x264enc` can now use multiple x264 library versions compiled for different + bit depths at runtime, to transparently provide support for multiple bit + depths. + +- `videoscale` and `videoconvert` now support multi-threaded scaling and + conversion, which is particularly useful with higher resolution video. + +- `h264parse` will now automatically insert AU delimiters if needed when + outputting byte-stream format, which improves standard compliance and + is needed in particular for HLS playback on iOS/macOS. + +- `rtpbin` has acquired bundle support for incoming streams + +## Major new features and changes + +### Noteworthy new API + +- The video library gained support for a number of new video formats: + + - `GBR_12LE`, `GBR_12BE`, `GBRA_12LE`, `GBRA_12BE` (planar 4:4:4 RGB/RGBA, 12 bits per channel) + - `GBRA_10LE`, `GBRA_10BE` (planar 4:4:4:4 RGBA, 10 bits per channel) + - `GBRA` (planar 4:4:4:4 ARGB, 8 bits per channel) + - `I420_12BE`, `I420_12LE` (planar 4:2:0 YUV, 12 bits per channel) + - `I422_12BE`,`I422_12LE` (planar 4:2:2 YUV, 12 bits per channel) + - `Y444_12BE`, `Y444_12LE` (planar 4:4:4 YUV, 12 bits per channel) + - `VYUY` (another packed 4:2:2 YUV format) + +- The high-level `GstPlayer` API was extended with functions for taking video + snapshots and enabling accurate seeking. It can optionally also use the + still-experimental `playbin3` element now. + +### New Elements + +- msdk: new plugin for Intel's Media SDK for hardware-accelerated video encoding + and decoding on Intel graphics hardware on Windows or Linux. This includes + an H.264 encoder/decoder (`msdkh264dec`, `msdkh264enc`), + an H.265 encoder/decoder (`msdkh265dec`, `msdkh265enc`), + an MJPEG encoder/encoder (`msdkmjpegdec`, `msdkmjpegenc`), + an MPEG-2 video encoder (`msdkmpeg2enc`) and a VP8 encoder (`msdkvp8enc`). + +- `iqa` is a new Image Quality Assessment plugin based on [DSSIM][dssim], + similar to the old (unported) videomeasure element. + +- The `faceoverlay` element, which allows you to overlay SVG graphics over + a detected face in a video stream, has been ported from 0.10. + +- our `ffmpeg` wrapper plugin now exposes/maps the ffmpeg Opus audio decoder + (`avdec_opus`) as well as the GoPro CineForm HD / CFHD decoder (`avdec_cfhd`), + and also a parser/writer for the IVF format (`avdemux_ivf` and `avmux_ivf`). + +- `audiobuffersplit` is a new element that splits raw audio buffers into + equal-sized buffers + +- `audiomixmatrix` is a new element that mixes N:M audio channels according to + a configured mix matrix. + +- The `timecodewait` element got renamed to `avwait` and can operate in + different modes now. + +- The `opencv` video processing plugin has gained a new `dewarp` element that + dewarps fisheye images. + +- `ttml` is a new plugin for parsing and rendering subtitles in Timed Text + Markup Language (TTML) format. For the time being these elements will not + be autoplugged during media playback however, unless the `GST_TTML_AUTOPLUG=1` + environment variable is set. Only the EBU-TT-D profile is supported at this + point. + +[dssim]: https://github.com/pornel/dssim + +### New element features and additions + +- `x264enc` can now use multiple x264 library versions compiled for different + bit depths at runtime, to transparently provide support for multiple bit + depths. A new configure parameter `--with-x264-libraries` has been added to + specify additional paths to look for additional x264 libraries to load. + Background is that the libx264 library is always compile for one specific + bit depth and the `x264enc` element would simply support the depth supported + by the underlying library. Now we can support multiple depths. + +- `x264enc` also picks up the interlacing mode automatically from the input + caps now and passed interlacing/TFF information correctly to the library. + +- `videoscale` and `videoconvert` now support multi-threaded scaling and + conversion, which is particularly useful with higher resolution video. + This has to be enabled explicitly via the `"n-threads"` property. + +- `videorate`'s new `"rate"` property lets you set a speed factor + on the output stream + +- `splitmuxsink`'s buffer collection and scheduling was rewritten to make + processing and splitting deterministic; before it was possible for a buffer + to end up in a different file chunk in different runs. `splitmuxsink` also + gained a new `"format-location-full"` signal that works just like the existing + `"format-location"` signal only that it is also passed the primary stream's + first buffer as argument, so that it is possible to construct the file name + based on metadata such as the buffer timestamp or any GstMeta attached to + the buffer. The new `"max-size-timecode"` property allows for timecode-based + splitting. `splitmuxsink` will now also automatically start a new file if the + input caps change in an incompatible way. + +- `fakesink` has a new `"drop-out-of-segment"` property to not drop + out-of-segment buffers, which is useful for debugging purposes. + +- `identity` gained a `"ts-offset"` property. + +- both `fakesink` and `identity` now also print what kind of metas are attached + to buffers when printing buffer details via the `"last-message"` property + used by `gst-launch-1.0 -v`. + +- multiqueue: made `"min-interleave-time"` a configurable property. + +- video nerds will be thrilled to know that `videotestsrc`'s snow is now + deterministic. `videotestsrc` also gained some new properties to make the + ball pattern based on system time, and invert colours each second + (`"animation-mode"`, `"motion"`, and `"flip"` properties). + +- `oggdemux` reverse playback should work again now. You're welcome. + +- `playbin3` and `urisourcebin` now have buffering enabled by default, and + buffering message aggregation was fixed. + +- `tcpclientsrc` now has a `"timeout"` property + +- `appsink` has gained support for buffer lists. For backwards compatibility + reasons users need to enable this explicitly with `gst_app_sink_set_buffer_list_support()`, + however. Once activated, a pulled `GstSample` can contain either a buffer + list or a single buffer. + +- `splitmuxsrc` reverse playback was fixed and handling of sparse streams, such + as subtitle tracks or metadata tracks, was improved. + +- `matroskamux` has acquired support for muxing G722 audio; it also marks all + buffers as keyframes now when streaming only audio, so that `tcpserversink` + will behave properly with audio-only streams. + +- `qtmux` gained support for ProRes 4444 XQ, HEVC/H.265 and CineForm (GoPro) formats, + and generally writes more video stream-related metadata into the track headers. + It is also allows configuration of the maximum interleave size in bytes and + time now. For fragmented mp4 we always write the `tfdt` atom now as required + by the DASH spec. + +- `qtdemux` supports FLAC, xvid, mp2, S16L and CineForm (GoPro) tracks now, and + generally tries harder to extract more video-related information from track + headers, such as colorimetry or interlacing details. It also received a + couple of fixes for the scenario where upstream operates in TIME format and + feeds chunks to qtdemux (e.g. DASH or MSE). + +- `audioecho` has two new properties to apply a delay only to certain channels + to create a surround effect, rather than an echo on all channels. This is + useful when upmixing from stereo, for example. The `"surround-delay"` property + enables this, and the `"surround-mask"` property controls which channels + are considered surround sound channels in this case. + +- `webrtcdsp` gained various new properties for gain control and also exposes + voice activity detection now, in which case it will post `"voice-activity"` + messages on the bus whenever the voice detection status changes. + +- The `decklink` capture elements for Blackmagic Decklink cards have seen a + number of improvements: + + - `decklinkvideosrc` will post a warning message on "no signal" and an info + message when the signal lock has been (re)acquired. There is also a new + read-only `"signal"` property that can be used to query the signal lock + status. The `GAP` flag will be set on buffers that are captured without + a signal lock. The new `drop-no-signal-frames` will make `decklinkvideosrc` + drop all buffers that have been captured without an input signal. The + `"skip-first-time"` property will make the source drop the first few + buffers, which is handy since some devices will at first output buffers + with the wrong resolution before they manage to figure out the right input + format and decide on the actual output caps. + + - `decklinkaudiosrc` supports more than just 2 audio channels now. + + - The capture sources no longer use the "hardware" timestamps which turn + out to be useless and instead just use the pipeline clock directly. + +- `srtpdec` now also has a readonly `"stats"` property, just like `srtpenc`. + +- `rtpbin` gained RTP bundle support, as used by e.g. WebRTC. The first + rtpsession will have a `rtpssrcdemux` element inside splitting the streams + based on their SSRC and potentially dispatch to a different rtpsession. + Because retransmission SSRCs need to be merged with the corresponding media + stream the `::on-bundled-ssrc` signal is emitted on `rtpbin` so that the + application can find out to which session the SSRC belongs. + +- `rtprtxqueue` gained two new properties exposing retransmission + statistics (`"requests"` and `"fulfilled-requests"`) + +- `kmssink` will now use the preferred mode for the monitor and render to the + base plane if nothing else has set a mode yet. This can also be done forcibly + in any case via the new `"force-modesetting"` property. Furthermore, `kmssink` + now allows only the supported connector resolutions as input caps in order to + avoid scaling or positioning of the input stream, as `kmssink` can't know + whether scaling or positioning would be more appropriate for the use case at + hand. + +- `waylandsink` can now take DMAbuf buffers as input in the presence + of a compatible Wayland compositor. This enables zero-copy transfer + from a decoder or source that outputs DMAbuf. + +- `udpsrc` can be bound to more than one interface when joining a + multicast group, this is done by giving a comma separate list of + interfaces such as multicast-iface="eth0,eth1". + +### Plugin moves + +- `dataurisrc` moved from gst-plugins-bad to core + +- The `rawparse` plugin containing the `rawaudioparse` and `rawvideoparse` + elements moved from gst-plugins-bad to gst-plugins-base. These elements + supersede the old `videoparse` and `audioparse` elements. They work the + same, with just some minor API changes. The old legacy elements still + exist in gst-plugins-bad, but may be removed at some point in the future. + +- `timecodestamper` is an element that attaches time codes to video buffers + in form of `GstVideoTimeCodeMeta`s. It had a `"clock-source"` property + which has now been removed because it was fairly useless in practice. It + gained some new properties however: the `"first-timecode"` property can + be used to set the inital timecode; alternatively `"first-timecode-to-now"` + can be set, and then the current system time at the time the first buffer + arrives is used as base time for the time codes. + + +### Plugin removals + +- The `mad` mp1/mp2/mp3 decoder plugin was removed from gst-plugins-ugly, + as libmad is GPL licensed, has been unmaintained for a very long time, and + there are better alternatives available. Use the `mpg123audiodec` element + from the `mpg123` plugin in gst-plugins-ugly instead, or `avdec_mp3` from + the `gst-libav` module which wraps the ffmpeg library. We expect that we + will be able to move mp3 decoding to gst-plugins-good in the next cycle + seeing that most patents around mp3 have expired recently or are about to + expire. + +- The `mimic` plugin was removed from gst-plugins-bad. It contained a decoder + and encoder for a video codec used by MSN messenger many many years ago (in + a galaxy far far away). The underlying library is unmaintained and no one + really needs to use this codec any more. Recorded videos can still be played + back with the MIMIC decoder in gst-libav. + +## Miscellaneous API additions + +- Request pad name templates passed to `gst_element_request_pad()` may now + contain multiple specifiers, such as e.g. `src_%u_%u`. + +- [`gst_buffer_iterate_meta_filtered()`][buffer-iterate-meta-filtered] is a + variant of `gst_buffer_iterate_meta()` that only returns metas of the + requested type and skips all other metas. + +- [`gst_pad_task_get_state()`][pad-task-get-state] gets the current state of + a task in a thread-safe way. + +- [`gst_uri_get_media_fragment_table()`][uri-get-fragment-table] provides the + media fragments of an URI as a table of key=value pairs. + +- [`gst_print()`][print], [`gst_println()`][println], [`gst_printerr()`][printerr], + and [`gst_printerrln()`][printerrln] can be used to print to stdout or stderr. + These functions are similar to `g_print()` and `g_printerr()` but they also + support all the additional format specifiers provided by the GStreamer + logging system, such as e.g. `GST_PTR_FORMAT`. + +- a `GstParamSpecArray` has been added, for elements who want to have array + type properties, such as the `audiomixmatrix` element for example. There are + also two new functions to set and get properties of this type from bindings: + - gst_util_set_object_array() + - gst_util_get_object_array() + +- various helper functions have been added to make it easier to set or get + GstStructure fields containing caps-style array or list fields from language + bindings (which usually support GValueArray but don't know about the GStreamer + specific fundamental types): + - [`gst_structure_get_array()`][get-array] + - [`gst_structure_set_array()`][set-array] + - [`gst_structure_get_list()`][get-list] + - [`gst_structure_set_list()`][set-list] + +- a new ['dynamic type' registry factory type][dynamic-type] was added to + register dynamically loadable GType types. This is useful for automatically + loading enum/flags types that are used in caps, such as for example the + `GstVideoMultiviewFlagsSet` type used in multiview video caps. + +- there is a new [`GstProxyControlBinding`][proxy-control-binding] for use + with GstController. This allows proxying the control interface from one + property on one GstObject to another property (of the same type) in another + GstObject. So e.g. in parent-child relationship, one may need to call + `gst_object_sync_values()` on the child and have a binding (set elsewhere) + on the parent update the value. This is used in `glvideomixer` and `glsinkbin` + for example, where `sync_values()` on the child pad or element will call + `sync_values()` on the exposed bin pad or element. + + Note that this doesn't solve GObject property forwarding, that must + be taken care of by the implementation manually or using GBinding. + +- `gst_base_parse_drain()` has been made public for subclasses to use. + +- `gst_base_sink_set_drop_out_of_segment()' can be used by subclasses to + prevent GstBaseSink from dropping buffers that fall outside of the segment. + +- [`gst_calculate_linear_regression()`][calc-lin-regression] is a new utility + function to calculate a linear regression. + +- [`gst_debug_get_stack_trace`][get-stack-trace] is an easy way to retrieve a + stack trace, which can be useful in tracer plugins. + +- allocators: the dmabuf allocator is now sub-classable, and there is a new + `GST_CAPS_FEATURE_MEMORY_DMABUF` define. + +- video decoder subclasses can use the newly-added function + `gst_video_decoder_allocate_output_frame_with_params()` to + pass a `GstBufferPoolAcquireParams` to the buffer pool for + each buffer allocation. + +- the video time code API has gained a dedicated [`GstVideoTimeCodeInterval`][timecode-interval] + type plus related API, including functions to add intervals to timecodes. + +- There is a new `libgstbadallocators-1.0` library in gst-plugins-bad, which + may go away again in future releases once the `GstPhysMemoryAllocator` + interface API has been validated by more users and was moved to + `libgstallocators-1.0` from gst-plugins-base. + +[timecode-interval]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#gst-video-time-code-interval-new +[buffer-iterate-meta-filtered]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#gst-buffer-iterate-meta-filtered +[pad-task-get-state]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-task-get-state +[uri-get-fragment-table]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUri.html#gst-uri-get-media-fragment-table +[print]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-print +[println]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-println +[printerr]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-printerr +[printerrln]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-printerrln +[get-array]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-get-array +[set-array]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-set-array +[get-list]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-get-list +[set-list]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-set-list +[dynamic-type]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstDynamicTypeFactory.html +[proxy-control-binding]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/gstreamer-libs-GstProxyControlBinding.html +[calc-lin-regression]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUtils.html#gst-calculate-linear-regression +[get-stack-trace]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUtils.html#gst-debug-get-stack-trace + +### GstPlayer + +New API has been added to: + + - get the number of audio/video/subtitle streams: + - `gst_player_media_info_get_number_of_streams()` + - `gst_player_media_info_get_number_of_video_streams()` + - `gst_player_media_info_get_number_of_audio_streams()` + - `gst_player_media_info_get_number_of_subtitle_streams()` + + - enable accurate seeking: `gst_player_config_set_seek_accurate()` + and `gst_player_config_get_seek_accurate()` + + - get a snapshot image of the video in RGBx, BGRx, JPEG, PNG or + native format: [`gst_player_get_video_snapshot()`][snapshot] + + - selecting use of a specific video sink element + ([`gst_player_video_overlay_video_renderer_new_with_sink()`][renderer-with-vsink]) + + - If the environment variable `GST_PLAYER_USE_PLAYBIN3` is set, GstPlayer will + use the still-experimental `playbin3` element and the `GstStreams` API for + playback. + +[snapshot]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstplayer.html#gst-player-get-video-snapshot +[renderer-with-vsink]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstplayer-videooverlayvideorenderer.html#gst-player-video-overlay-video-renderer-new-with-sink + +## Miscellaneous changes + +- video caps for interlaced video may contain an optional `"field-order"` field + now in the case of `interlaced-mode=interleaved` to signal that the field + order is always the same throughout the stream. This is useful to signal to + muxers such as mp4mux. The new field is parsed from/to `GstVideoInfo` of course. + +- video decoder and video encoder base classes try harder to proxy + interlacing, colorimetry and chroma-site related fields in caps properly. + +- The buffer stored in the `PROTECTION` events is now left unchanged. This is a + change of behaviour since 1.8, especially for the mssdemux element which used to + decode the base64 parsed data wrapped in the protection events emitted by the + demuxer. + +- `PROTECTION` events can now be injected into the pipeline from the application; + source elements deriving from GstBaseSrc will forward those downstream now. + +- The DASH demuxer is now correctly parsing the MSPR-2.0 ContentProtection nodes + and emits Protection events accordingly. Applications relying on those events + might need to decode the base64 data stored in the event buffer before using it. + +- The registry can now also be disabled by setting the environment variable + `GST_REGISTRY_DISABLE=yes`, with similar effect as the `GST_DISABLE_REGISTRY` + compile time switch. + +- Seeking performance with gstreamer-vaapi based decoders was improved. It would + recreate the decoder and surfaces on every seek which can be quite slow. + +- more robust handling of input caps changes in videoaggregator-based elements + such as `compositor`. + +- Lots of adaptive streaming-related fixes across the board (DASH, MSS, HLS). Also: + + - `mssdemux`, the Microsoft Smooth Streaming demuxer, has seen various + fixes for live streams, duration reporting and seeking. + + - The DASH manifest parser now extracts MS PlayReady ContentProtection objects + from manifests and sends them downstream as `PROTECTION` events. It also + supports multiple Period elements in external xml now. + +- gst-libav was updated to ffmpeg 3.3 but should still work with any 3.x + version. + +- GstEncodingProfile has been generally enhanced so it can, for + example, be used to get possible profiles for a given file + extension. It is now possible to define profiles based on element + factory names or using a path to a `.gep` file containing a + serialized profile. + +- `audioconvert` can now do endianness conversion in-place. All other + conversions still require a copy, but e.g. sign conversion and a few others + could also be implemented in-place now. + +- The new, experimental `playbin3` and `urisourcebin` elements got many + bugfixes and improvements and should generally be closer to a full + replacement of the old elements. + +- `interleave` now supports > 64 channels. + +### OpenGL integration + +- As usual the GStreamer OpenGL integration library has seen numerous + fixes and performance improvements all over the place, and is hopefully + ready now to become API stable and be moved to gst-plugins-base during the + 1.14 release cycle. + +- The GStreamer OpenGL integration layer has also gained support for the + Vivante EGL FB windowing system, which improves performance on platforms + such as Freescale iMX.6 for those who are stuck with the proprietary driver. + The `qmlglsink` element also supports this now if Qt is used with eglfs or + wayland backend, and it works in conjunction with [gstreamer-imx][gstreamer-imx] + of course. + +- various `qmlglsrc` improvements + +[gstreamer-imx]: https://github.com/Freescale/gstreamer-imx + +## Tracing framework and debugging improvements + +- New tracing hooks have been added to track GstMiniObject and GstObject + ref/unref operations. + +- The memory leaks tracer can optionally use this to retrieve stack traces if + enabled with e.g. `GST_TRACERS=leaks(filters="GstEvent,GstMessage",stack-traces-flags=full)` + +- The `GST_DEBUG_FILE` environment variable, which can be used to write the + debug log output to a file instead of printing it to stderr, can now contain + a name pattern, which is useful for automated testing and continuous + integration systems. The following format specifiers are supported: + + - `%p`: will be replaced with the PID + - `%r`: will be replaced with a random number, which is useful for instance + when running two processes with the same PID but in different containers. + +## Tools + +- `gst-inspect-1.0` can now list elements by type with the new `--types` + command-line option, e.g. `gst-inspect-1.0 --types=Audio/Encoder` will + show a list of audio encoders. + +- `gst-launch-1.0` and `gst_parse_launch()` have gained a new operator (`:`) + that allows linking all pads between two elements. This is useful in cases + where the exact number of pads or type of pads is not known beforehand, such + as in the `uridecodebin : encodebin` scenario, for example. In this case, + multiple links will be created if the encodebin has multiple profiles + compatible with the output of uridecodebin. + +- `gst-device-monitor-1.0` now shows a `gst-launch-1.0` snippet for each + device that shows how to make use of it in a `gst-launch-1.0` pipeline string. + +## GStreamer RTSP server + +- The RTSP server now also supports Digest authentication in addition to Basic + authentication. + +- The `GstRTSPClient` class has gained a `pre-*-request` signal and virtual + method for each client request type, emitted in the beginning of each rtsp + request. These signals or virtual methods let the application validate the + requests, configure the media/stream in a certain way and also generate error + status codes in case of an error or a bad request. + +## GStreamer VAAPI + +- GstVaapiDisplay now inherits from GstObject, thus the VA display logging + messages are better and tracing the context sharing is more readable. + +- When uploading raw images into a VA surfaces now VADeriveImages are tried + fist, improving the upload performance, if it is possible. + +- The decoders and the post-processor now can push dmabuf-based buffers to + downstream under certain conditions. For example: + + `GST_GL_PLATFORM=egl gst-play-1.0 video-sample.mkv --videosink=glimagesink` + +- Refactored the wrapping of VA surface into gstreamer memory, adding lock + when mapping and unmapping, and many other fixes. + +- Now `vaapidecodebin` loads `vaapipostproc` dynamically. It is possible to + avoid it usage with the environment variable `GST_VAAPI_DISABLE_VPP=1`. + +- Regarding encoders: they have primary rank again, since they can discover, + in run-time, the color formats they can use for upstream raw buffers and + caps renegotiation is now possible. Also the encoders push encoding info + downstream via tags. + +- About specific encoders: added constant bit-rate encoding mode for VP8 and + H265 encoder handles P010_10LE color format. + +- Regarding decoders, flush operation has been improved, now the internal VA + encoder is not recreated at each flush. Also there are several improvements + in the handling of H264 and H265 streams. + +- VAAPI plugins try to create their on GstGL context (when available) if they + cannot find it in the pipeline, to figure out what type of VA Display they + should create. + +- Regarding `vaapisink` for X11, if the backend reports that it is unable to + render correctly the current color format, an internal VA post-processor, is + instantiated (if available) and converts the color format. + +## GStreamer Editing Services and NLE + +- Enhanced auto transition behaviour + +- Fix some races in `nlecomposition` + +- Allow building with msvc + +- Added a UNIX manpage for `ges-launch` + +- API changes: + - Added ges_deinit (allowing the leak tracer to work properly) + - Added ges_layer_get_clips_in_interval + - Finally hide internal symbols that should never have been exposed + +## GStreamer validate + +- Port `gst-validate-launcher` to python 3 + +- `gst-validate-launcher` now checks if blacklisted bugs have been fixed on + bugzilla and errors out if it is the case + +- Allow building with msvc + +- Add ability for the launcher to run GStreamer unit tests + +- Added a way to activate the leaks tracer on our tests and fix leaks + +- Make the http server multithreaded + +- New testsuite for running various test scenarios on the DASH-IF test vectors + +## Build and Dependencies + +- Meson build files are now disted in tarballs, for jhbuild and so distro + packagers can start using it. Note that the Meson-based build system is not + 100% feature-equivalent with the autotools-based one yet. + +- Some plugin filenames have been changed to match the plugin names: for example + the file name of the `encoding` plugin in gst-plugins-base containing the + `encodebin` element was `libgstencodebin.so` and has been changed to + `libgstencodebin.so`. This affects only a handful of plugins across modules. + + **Developers who install GStreamer from source and just do `make install`** + **after updating the source code, without doing `make uninstall` first, will** + **have to manually remove the old installed plugin files from the installation** + **prefix, or they will get 'Cannot register existing type' critical warnings.** + +- Most of the docbook-based documentation (FAQ, Application Development Manual, + Plugin Writer's Guide, design documents) has been converted to markdown and + moved into a new gst-docs module. The gtk-doc library API references and + the plugins documentation are still built as part of the source modules though. + +- GStreamer core now optionally uses libunwind and libdw to generate backtraces. + This is useful for tracer plugins used during debugging and development. + +- There is a new `libgstbadallocators-1.0` library in gst-plugins-bad (which + may go away again in future releases once the `GstPhysMemoryAllocator` + interface API has been validated by more users). + +- `gst-omx` and `gstreamer-vaapi` modules can now also be built using the + Meson build system. + +- The `qtkitvideosrc` element for macOS was removed. The API is deprecated + since 10.9 and it wasn't shipped in the binaries since a few releases. + +## Platform-specific improvements + +### Android + +- androidmedia: add support for VP9 video decoding/encoding and Opus audio + decoding (where supported) + +### OS/X and iOS + +- `avfvideosrc`, which represents an iPhone camera or, on a Mac, a screencapture + session, so far allowed you to select an input device by device index only. + New API adds the ability to select the position (front or back facing) and + device-type (wide angle, telephoto, etc.). Furthermore, you can now also + specify the orientation (portrait, landscape, etc.) of the videostream. + +### Windows + +- `dx9screencapsrc` can now optionally also capture the cursor. + +## Contributors + +Aleix Conchillo Flaque, Alejandro G. Castro, Aleksandr Slobodeniuk, Alexandru +Băluț, Alex Ashley, Andre McCurdy, Andrew, Anton Eliasson, Antonio Ospite, +Arnaud Vrac, Arun Raghavan, Aurélien Zanelli, Axel Menzel, Benjamin Otte, +Branko Subasic, Brendan Shanks, Carl Karsten, Carlos Rafael Giani, ChangBok +Chae, Chris Bass, Christian Schaller, christophecvr, Claudio Saavedra, +Corentin Noël, Dag Gullberg, Daniel Garbanzo, Daniel Shahaf, David Evans, +David Schleef, David Warman, Dominique Leuenberger, Dongil Park, Douglas +Bagnall, Edgard Lima, Edward Hervey, Emeric Grange, Enrico Jorns, Enrique +Ocaña González, Evan Nemerson, Fabian Orccon, Fabien Dessenne, Fabrice Bellet, +Florent Thiéry, Florian Zwoch, Francisco Velazquez, Frédéric Dalleau, Garima +Gaur, Gaurav Gupta, George Kiagiadakis, Georg Lippitsch, Göran Jönsson, Graham +Leggett, Guillaume Desmottes, Gurkirpal Singh, Haihua Hu, Hanno Boeck, Havard +Graff, Heekyoung Seo, hoonhee.lee, Hyunjun Ko, Imre Eörs, Iñaki García +Etxebarria, Jagadish, Jagyum Koo, Jan Alexander Steffens (heftig), Jan +Schmidt, Jean-Christophe Trotin, Jochen Henneberg, Jonas Holmberg, Joris +Valette, Josep Torra, Juan Pablo Ugarte, Julien Isorce, Jürgen Sachs, Koop +Mast, Kseniia Vasilchuk, Lars Wendler, leigh123linux@googlemail.com, Luis de +Bethencourt, Lyon Wang, Marcin Kolny, Marinus Schraal, Mark Nauwelaerts, +Mathieu Duponchelle, Matthew Waters, Matt Staples, Michael Dutka, Michael +Olbrich, Michael Smith, Michael Tretter, Miguel París Díaz, namanyadav12, Neha +Arora, Nick Kallen, Nicola Murino, Nicolas Dechesne, Nicolas Dufresne, Nicolas +Huet, Nirbheek Chauhan, Ole André Vadla Ravnås, Olivier Crête, Patricia +Muscalu, Peter Korsgaard, Peter Seiderer, Petr Kulhavy, Philippe Normand, +Philippe Renon, Philipp Zabel, Rahul Bedarkar, Reynaldo H. Verdejo Pinochet, +Ricardo Ribalda Delgado, Rico Tzschichholz, Руслан Ижбулатов, Samuel Maroy, +Santiago Carot-Nemesio, Scott D Phillips, Sean DuBois, Sebastian Dröge, Sergey +Borovkov, Seungha Yang, shakin chou, Song Bing, Søren Juul, Sreerenj +Balachandran, Stefan Kost, Stefan Sauer, Stepan Salenikovich, Stian Selnes, +Stuart Weaver, suhas2go, Thiago Santos, Thibault Saunier, Thomas Bluemel, +Thomas Petazzoni, Tim-Philipp Müller, Ting-Wei Lan, Tobias Mueller, Todor +Tomov, Tomasz Zajac, Ulf Olsson, Ursula Maplehurst, Víctor Manuel Jáquez Leal, +Victor Toso, Vincent Penquerc'h, Vineeth TM, Vinod Kesti, Vitor Massaru Iha, +Vivia Nikolaidou, WeiChungChang, William Manley, Wim Taymans, Wojciech +Przybyl, Wonchul Lee, Xavier Claessens, Yasushi SHOJI + +... and many others who have contributed bug reports, translations, sent +suggestions or helped testing. + +## Bugs fixed in 1.12 + +More than [635 bugs][bugs-fixed-in-1.12] have been fixed during +the development of 1.12. + +This list does not include issues that have been cherry-picked into the +stable 1.10 branch and fixed there as well, all fixes that ended up in the +1.10 branch are also included in 1.12. + +This list also does not include issues that have been fixed without a bug +report in bugzilla, so the actual number of fixes is much higher. + +[bugs-fixed-in-1.12]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=213265&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.10.1&target_milestone=1.10.2&target_milestone=1.10.3&target_milestone=1.10.4&target_milestone=1.11.1&target_milestone=1.11.2&target_milestone=1.11.3&target_milestone=1.11.4&target_milestone=1.11.90&target_milestone=1.11.91&target_milestone=1.12.0 + +## Stable 1.12 branch + +After the 1.12.0 release there will be several 1.12.x bug-fix releases which +will contain bug fixes which have been deemed suitable for a stable branch, +but no new features or intrusive changes will be added to a bug-fix release +usually. The 1.12.x bug-fix releases will be made from the git 1.12 branch, which +is a stable branch. + +### 1.12.0 + +1.12.0 was released on 4th May 2017. + +## Known Issues + +- The `webrtcdsp` element is currently not shipped as part of the Windows + binary packages due to a [build system issue][bug-770264]. + +[bug-770264]: https://bugzilla.gnome.org/show_bug.cgi?id=770264 + +## Schedule for 1.14 + +Our next major feature release will be 1.14, and 1.11 will be the unstable +development version leading up to the stable 1.12 release. The development +of 1.13/1.14 will happen in the git master branch. + +The plan for the 1.14 development cycle is yet to be confirmed, but it is +expected that feature freeze will be around September 2017 +followed by several 1.13 pre-releases and the new 1.14 stable release +in October. + +1.14 will be backwards-compatible to the stable 1.12, 1.10, 1.8, 1.6, 1.4, +1.2 and 1.0 release series. + +- - - + +*These release notes have been prepared by Sebastian Dröge, Tim-Philipp Müller +and Víctor Manuel Jáquez Leal.* + +*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* diff --git a/RELEASE b/RELEASE index a4db4243a5..df6a5ccac1 100644 --- a/RELEASE +++ b/RELEASE @@ -1,15 +1,13 @@ -Release notes for GStreamer RTSP Server Library 1.11.91 +Release notes for GStreamer RTSP Server Library 1.12.0 -The GStreamer team is pleased to announce the second release candidate of the -stable 1.12 release series. The 1.12 release series is adding new features on -top of the 1.0, 1.2, 1.4, 1.6, 1.8 and 1.10 series and is part of the API and -ABI-stable 1.x release series of the GStreamer multimedia framework. +The GStreamer team is pleased to announce the first release in the stable 1.12 +release series. The 1.12 release series is adding new features on top of the +1.0, 1.2, 1.4, 1.6, 1.8 and 1.10 series and is part of the API and ABI-stable +1.x release series of the GStreamer multimedia framework. -Full release notes will be provided with the 1.12.0 release, highlighting all -the new features, bugfixes, performance optimizations and other important -changes. +Full release notes can be found here Binaries for Android, iOS, Mac OS X and Windows will be provided in the next days. @@ -51,6 +49,7 @@ subscribe to the gstreamer-devel list. Contributors to this release + * Sebastian Dröge * Thibault Saunier * Tim-Philipp Müller   \ No newline at end of file diff --git a/configure.ac b/configure.ac index d2438e9855..35b1693878 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.11.91], +AC_INIT([GStreamer RTSP Server Library], [1.12.0], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1191, 0, 1191) +AS_LIBTOOL(GST, 1200, 0, 1200) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.91 -GSTPB_REQ=1.11.91 -GSTPG_REQ=1.11.91 -GSTPD_REQ=1.11.91 +GST_REQ=1.12.0 +GSTPB_REQ=1.12.0 +GSTPG_REQ=1.12.0 +GSTPD_REQ=1.12.0 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index c19482fef0..9012720e2b 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.12.0 + master + + 2017-05-04 + + + + 1.11.91 diff --git a/meson.build b/meson.build index a65f8a3938..7d790ba2ef 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.11.91', + version : '1.12.0', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 51cd53050ed881621aea26d52c5059f00a7c7d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 4 May 2017 18:59:14 +0300 Subject: [PATCH 1360/1776] Back to development --- configure.ac | 12 ++++++------ meson.build | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 35b1693878..4c65ceb7a3 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.12.0], +AC_INIT([GStreamer RTSP Server Library], [1.13.0.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1200, 0, 1200) +AS_LIBTOOL(GST, 1300, 0, 1300) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.12.0 -GSTPB_REQ=1.12.0 -GSTPG_REQ=1.12.0 -GSTPD_REQ=1.12.0 +GST_REQ=1.13.0.1 +GSTPB_REQ=1.13.0.1 +GSTPG_REQ=1.13.0.1 +GSTPD_REQ=1.13.0.1 dnl *** autotools stuff **** diff --git a/meson.build b/meson.build index 7d790ba2ef..4789e5f4e1 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.12.0', + version : '1.13.0.1', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From e1d43cab6528c22e0c3108cf8215738a48d5a317 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 16 May 2017 14:44:43 -0400 Subject: [PATCH 1361/1776] Remove plugin specific static build option Static and dynamic plugins now have the same interface. The standard --enable-static/--enable-shared toggle are sufficient. --- configure.ac | 22 ---------------------- gst/rtsp-sink/Makefile.am | 1 - 2 files changed, 23 deletions(-) diff --git a/configure.ac b/configure.ac index 4c65ceb7a3..4c011ab6d8 100644 --- a/configure.ac +++ b/configure.ac @@ -311,28 +311,6 @@ AC_SUBST([GST_OBJ_CFLAGS]) GST_OBJ_LIBS="\$(top_builddir)/gst/rtsp-server/libgstrtspserver-$GST_API_VERSION.la \$(GST_ALL_LIBS)" AC_SUBST([GST_OBJ_LIBS]) -dnl build static plugins or not -AC_MSG_CHECKING([whether to build static plugins or not]) -AC_ARG_ENABLE( - static-plugins, - AC_HELP_STRING( - [--enable-static-plugins], - [build static plugins @<:@default=no@:>@]), - [AS_CASE( - [$enableval], [no], [], [yes], [], - [AC_MSG_ERROR([bad value "$enableval" for --enable-static-plugins])])], - [enable_static_plugins=no]) -AC_MSG_RESULT([$enable_static_plugins]) -if test "x$enable_static_plugins" = xyes; then - AC_DEFINE(GST_PLUGIN_BUILD_STATIC, 1, - [Define if static plugins should be built]) - GST_PLUGIN_LIBTOOLFLAGS="" -else - GST_PLUGIN_LIBTOOLFLAGS="--tag=disable-static" -fi -AC_SUBST(GST_PLUGIN_LIBTOOLFLAGS) -AM_CONDITIONAL(GST_PLUGIN_BUILD_STATIC, test "x$enable_static_plugins" = "xyes") - dnl If only building static libraries, define GST_STATIC_COMPILATION. This is dnl needed only on Windows, but it doesn't hurt to have it everywhere. if test x$enable_static = xyes -a x$enable_shared = xno; then diff --git a/gst/rtsp-sink/Makefile.am b/gst/rtsp-sink/Makefile.am index 23807ce6c7..f8092e5ba9 100644 --- a/gst/rtsp-sink/Makefile.am +++ b/gst/rtsp-sink/Makefile.am @@ -13,6 +13,5 @@ libgstrtspclientsink_la_LIBADD = $(top_builddir)/gst/rtsp-server/libgstrtspserve -lgstsdp-@GST_API_VERSION@ $(GST_NET_LIBS) $(GST_LIBS) \ $(GIO_LIBS) libgstrtspclientsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstrtspclientsink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) noinst_HEADERS = gstrtspclientsink.h From b344248630bebbcf5551bd2599cf39e665aa2d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 18 May 2017 10:35:18 +0100 Subject: [PATCH 1362/1776] Mark symbols explicitly for export with GST_EXPORT --- gst/rtsp-server/rtsp-address-pool.h | 14 ++++ gst/rtsp-server/rtsp-auth.h | 26 +++++++ gst/rtsp-server/rtsp-client.h | 25 +++++++ gst/rtsp-server/rtsp-context.h | 6 ++ gst/rtsp-server/rtsp-media-factory-uri.h | 7 ++ gst/rtsp-server/rtsp-media-factory.h | 61 ++++++++++++++++ gst/rtsp-server/rtsp-media.h | 89 +++++++++++++++++++++++ gst/rtsp-server/rtsp-mount-points.h | 10 +++ gst/rtsp-server/rtsp-params.h | 3 + gst/rtsp-server/rtsp-permissions.h | 10 +++ gst/rtsp-server/rtsp-sdp.h | 4 ++ gst/rtsp-server/rtsp-server.h | 32 +++++++++ gst/rtsp-server/rtsp-session-media.h | 17 +++++ gst/rtsp-server/rtsp-session-pool.h | 20 ++++++ gst/rtsp-server/rtsp-session.h | 28 ++++++++ gst/rtsp-server/rtsp-stream-transport.h | 23 ++++++ gst/rtsp-server/rtsp-stream.h | 91 ++++++++++++++++++++++++ gst/rtsp-server/rtsp-thread-pool.h | 13 ++++ gst/rtsp-server/rtsp-token.h | 12 ++++ 19 files changed, 491 insertions(+) diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index 654d10653b..45467be78c 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -82,9 +82,13 @@ struct _GstRTSPAddress { gpointer priv; }; +GST_EXPORT GType gst_rtsp_address_get_type (void); +GST_EXPORT GstRTSPAddress * gst_rtsp_address_copy (GstRTSPAddress *addr); + +GST_EXPORT void gst_rtsp_address_free (GstRTSPAddress *addr); /** @@ -149,14 +153,21 @@ struct _GstRTSPAddressPoolClass { gpointer _gst_reserved[GST_PADDING]; }; +GST_EXPORT GType gst_rtsp_address_pool_get_type (void); /* create a new address pool */ + +GST_EXPORT GstRTSPAddressPool * gst_rtsp_address_pool_new (void); +GST_EXPORT void gst_rtsp_address_pool_clear (GstRTSPAddressPool * pool); + +GST_EXPORT void gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool); +GST_EXPORT gboolean gst_rtsp_address_pool_add_range (GstRTSPAddressPool * pool, const gchar *min_address, const gchar *max_address, @@ -164,10 +175,12 @@ gboolean gst_rtsp_address_pool_add_range (GstRTSPAddressPool guint16 max_port, guint8 ttl); +GST_EXPORT GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, GstRTSPAddressFlags flags, gint n_ports); +GST_EXPORT GstRTSPAddressPoolResult gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, const gchar *ip_address, guint port, @@ -175,6 +188,7 @@ GstRTSPAddressPoolResult gst_rtsp_address_pool_reserve_address (GstRTSPAddressP guint ttl, GstRTSPAddress ** address); +GST_EXPORT gboolean gst_rtsp_address_pool_has_unicast_addresses (GstRTSPAddressPool * pool); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index dc65bc7770..fb243ac81e 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -81,37 +81,63 @@ struct _GstRTSPAuthClass { gpointer _gst_reserved[GST_PADDING - 1]; }; +GST_EXPORT GType gst_rtsp_auth_get_type (void); +GST_EXPORT GstRTSPAuth * gst_rtsp_auth_new (void); +GST_EXPORT void gst_rtsp_auth_set_tls_certificate (GstRTSPAuth *auth, GTlsCertificate *cert); + +GST_EXPORT GTlsCertificate * gst_rtsp_auth_get_tls_certificate (GstRTSPAuth *auth); +GST_EXPORT void gst_rtsp_auth_set_tls_database (GstRTSPAuth *auth, GTlsDatabase *database); + +GST_EXPORT GTlsDatabase * gst_rtsp_auth_get_tls_database (GstRTSPAuth *auth); +GST_EXPORT void gst_rtsp_auth_set_tls_authentication_mode (GstRTSPAuth *auth, GTlsAuthenticationMode mode); + +GST_EXPORT GTlsAuthenticationMode gst_rtsp_auth_get_tls_authentication_mode (GstRTSPAuth *auth); +GST_EXPORT void gst_rtsp_auth_set_default_token (GstRTSPAuth *auth, GstRTSPToken *token); + +GST_EXPORT GstRTSPToken * gst_rtsp_auth_get_default_token (GstRTSPAuth *auth); +GST_EXPORT void gst_rtsp_auth_add_basic (GstRTSPAuth *auth, const gchar * basic, GstRTSPToken *token); + +GST_EXPORT void gst_rtsp_auth_remove_basic (GstRTSPAuth *auth, const gchar * basic); +GST_EXPORT void gst_rtsp_auth_add_digest (GstRTSPAuth *auth, const gchar *user, const gchar *pass, GstRTSPToken *token); + +GST_EXPORT void gst_rtsp_auth_remove_digest (GstRTSPAuth *auth, const gchar *user); +GST_EXPORT void gst_rtsp_auth_set_supported_methods (GstRTSPAuth *auth, GstRTSPAuthMethod methods); + +GST_EXPORT GstRTSPAuthMethod gst_rtsp_auth_get_supported_methods (GstRTSPAuth *auth); +GST_EXPORT gboolean gst_rtsp_auth_check (const gchar *check); /* helpers */ + +GST_EXPORT gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass); /* checks */ diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 3daef070d2..edfce11509 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -143,38 +143,62 @@ struct _GstRTSPClientClass { gpointer _gst_reserved[GST_PADDING_LARGE-16]; }; +GST_EXPORT GType gst_rtsp_client_get_type (void); +GST_EXPORT GstRTSPClient * gst_rtsp_client_new (void); +GST_EXPORT void gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool); + +GST_EXPORT GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client); +GST_EXPORT void gst_rtsp_client_set_mount_points (GstRTSPClient *client, GstRTSPMountPoints *mounts); + +GST_EXPORT GstRTSPMountPoints * gst_rtsp_client_get_mount_points (GstRTSPClient *client); +GST_EXPORT void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth); + +GST_EXPORT GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); +GST_EXPORT void gst_rtsp_client_set_thread_pool (GstRTSPClient *client, GstRTSPThreadPool *pool); + +GST_EXPORT GstRTSPThreadPool * gst_rtsp_client_get_thread_pool (GstRTSPClient *client); +GST_EXPORT gboolean gst_rtsp_client_set_connection (GstRTSPClient *client, GstRTSPConnection *conn); + +GST_EXPORT GstRTSPConnection * gst_rtsp_client_get_connection (GstRTSPClient *client); +GST_EXPORT guint gst_rtsp_client_attach (GstRTSPClient *client, GMainContext *context); + +GST_EXPORT void gst_rtsp_client_close (GstRTSPClient * client); +GST_EXPORT void gst_rtsp_client_set_send_func (GstRTSPClient *client, GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify); +GST_EXPORT GstRTSPResult gst_rtsp_client_handle_message (GstRTSPClient *client, GstRTSPMessage *message); + +GST_EXPORT GstRTSPResult gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession *session, GstRTSPMessage *message); @@ -202,6 +226,7 @@ typedef GstRTSPFilterResult (*GstRTSPClientSessionFilterFunc) (GstRTSPClient *c GstRTSPSession *sess, gpointer user_data); +GST_EXPORT GList * gst_rtsp_client_session_filter (GstRTSPClient *client, GstRTSPClientSessionFilterFunc func, gpointer user_data); diff --git a/gst/rtsp-server/rtsp-context.h b/gst/rtsp-server/rtsp-context.h index d21c31ae55..32d1ac0b6b 100644 --- a/gst/rtsp-server/rtsp-context.h +++ b/gst/rtsp-server/rtsp-context.h @@ -78,10 +78,16 @@ struct _GstRTSPContext { gpointer _gst_reserved[GST_PADDING - 1]; }; +GST_EXPORT GType gst_rtsp_context_get_type (void); +GST_EXPORT GstRTSPContext * gst_rtsp_context_get_current (void); + +GST_EXPORT void gst_rtsp_context_push_current (GstRTSPContext * ctx); + +GST_EXPORT void gst_rtsp_context_pop_current (GstRTSPContext * ctx); diff --git a/gst/rtsp-server/rtsp-media-factory-uri.h b/gst/rtsp-server/rtsp-media-factory-uri.h index d6f68071a2..f3d4a9e1d8 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.h +++ b/gst/rtsp-server/rtsp-media-factory-uri.h @@ -65,14 +65,21 @@ struct _GstRTSPMediaFactoryURIClass { gpointer _gst_reserved[GST_PADDING]; }; +GST_EXPORT GType gst_rtsp_media_factory_uri_get_type (void); /* creating the factory */ + +GST_EXPORT GstRTSPMediaFactoryURI * gst_rtsp_media_factory_uri_new (void); /* configuring the factory */ + +GST_EXPORT void gst_rtsp_media_factory_uri_set_uri (GstRTSPMediaFactoryURI *factory, const gchar *uri); + +GST_EXPORT gchar * gst_rtsp_media_factory_uri_get_uri (GstRTSPMediaFactoryURI *factory); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 2a6099799f..57c8031233 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -97,84 +97,145 @@ struct _GstRTSPMediaFactoryClass { gpointer _gst_reserved[GST_PADDING_LARGE]; }; +GST_EXPORT GType gst_rtsp_media_factory_get_type (void); /* creating the factory */ + +GST_EXPORT GstRTSPMediaFactory * gst_rtsp_media_factory_new (void); /* configuring the factory */ + +GST_EXPORT void gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, const gchar *launch); + +GST_EXPORT gchar * gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory); +GST_EXPORT void gst_rtsp_media_factory_set_permissions (GstRTSPMediaFactory *factory, GstRTSPPermissions *permissions); + +GST_EXPORT GstRTSPPermissions * gst_rtsp_media_factory_get_permissions (GstRTSPMediaFactory *factory); + +GST_EXPORT void gst_rtsp_media_factory_add_role (GstRTSPMediaFactory *factory, const gchar *role, const gchar *fieldname, ...); +GST_EXPORT void gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory, gboolean shared); + +GST_EXPORT gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory); +GST_EXPORT void gst_rtsp_media_factory_set_stop_on_disconnect (GstRTSPMediaFactory *factory, gboolean stop_on_disconnect); + +GST_EXPORT gboolean gst_rtsp_media_factory_is_stop_on_disonnect (GstRTSPMediaFactory *factory); +GST_EXPORT void gst_rtsp_media_factory_set_suspend_mode (GstRTSPMediaFactory *factory, GstRTSPSuspendMode mode); + +GST_EXPORT GstRTSPSuspendMode gst_rtsp_media_factory_get_suspend_mode (GstRTSPMediaFactory *factory); +GST_EXPORT void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory *factory, gboolean eos_shutdown); + +GST_EXPORT gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory); +GST_EXPORT void gst_rtsp_media_factory_set_profiles (GstRTSPMediaFactory *factory, GstRTSPProfile profiles); + +GST_EXPORT GstRTSPProfile gst_rtsp_media_factory_get_profiles (GstRTSPMediaFactory *factory); +GST_EXPORT void gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory *factory, GstRTSPLowerTrans protocols); + +GST_EXPORT GstRTSPLowerTrans gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory *factory); +GST_EXPORT void gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory, GstRTSPAddressPool * pool); + +GST_EXPORT GstRTSPAddressPool * gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory); +GST_EXPORT void gst_rtsp_media_factory_set_multicast_iface (GstRTSPMediaFactory *factory, const gchar *multicast_iface); + +GST_EXPORT gchar * gst_rtsp_media_factory_get_multicast_iface (GstRTSPMediaFactory *factory); +GST_EXPORT void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint size); + +GST_EXPORT guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory); + +GST_EXPORT void gst_rtsp_media_factory_set_retransmission_time (GstRTSPMediaFactory * factory, GstClockTime time); + +GST_EXPORT GstClockTime gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory); +GST_EXPORT void gst_rtsp_media_factory_set_latency (GstRTSPMediaFactory * factory, guint latency); + +GST_EXPORT guint gst_rtsp_media_factory_get_latency (GstRTSPMediaFactory * factory); +GST_EXPORT void gst_rtsp_media_factory_set_transport_mode (GstRTSPMediaFactory *factory, GstRTSPTransportMode mode); + +GST_EXPORT GstRTSPTransportMode gst_rtsp_media_factory_get_transport_mode (GstRTSPMediaFactory *factory); +GST_EXPORT void gst_rtsp_media_factory_set_media_gtype (GstRTSPMediaFactory * factory, GType media_gtype); + +GST_EXPORT GType gst_rtsp_media_factory_get_media_gtype (GstRTSPMediaFactory * factory); +GST_EXPORT void gst_rtsp_media_factory_set_clock (GstRTSPMediaFactory *factory, GstClock * clock); + +GST_EXPORT GstClock * gst_rtsp_media_factory_get_clock (GstRTSPMediaFactory *factory); +GST_EXPORT void gst_rtsp_media_factory_set_publish_clock_mode (GstRTSPMediaFactory * factory, GstRTSPPublishClockMode mode); + +GST_EXPORT GstRTSPPublishClockMode gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory); /* creating the media from the factory and a url */ + +GST_EXPORT GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); +GST_EXPORT GstElement * gst_rtsp_media_factory_create_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index d004b5e52e..9f95e5b624 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -103,12 +103,15 @@ typedef enum { } GstRTSPPublishClockMode; #define GST_TYPE_RTSP_TRANSPORT_MODE (gst_rtsp_transport_mode_get_type()) +GST_EXPORT GType gst_rtsp_transport_mode_get_type (void); #define GST_TYPE_RTSP_SUSPEND_MODE (gst_rtsp_suspend_mode_get_type()) +GST_EXPORT GType gst_rtsp_suspend_mode_get_type (void); #define GST_TYPE_RTSP_PUBLISH_CLOCK_MODE (gst_rtsp_publish_clock_mode_get_type()) +GST_EXPORT GType gst_rtsp_publish_clock_mode_get_type (void); #include "rtsp-stream.h" @@ -186,104 +189,190 @@ struct _GstRTSPMediaClass { gpointer _gst_reserved[GST_PADDING_LARGE-1]; }; +GST_EXPORT GType gst_rtsp_media_get_type (void); /* creating the media */ + +GST_EXPORT GstRTSPMedia * gst_rtsp_media_new (GstElement *element); + +GST_EXPORT GstElement * gst_rtsp_media_get_element (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_take_pipeline (GstRTSPMedia *media, GstPipeline *pipeline); +GST_EXPORT GstRTSPMediaStatus gst_rtsp_media_get_status (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_permissions (GstRTSPMedia *media, GstRTSPPermissions *permissions); + +GST_EXPORT GstRTSPPermissions * gst_rtsp_media_get_permissions (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared); + +GST_EXPORT gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_stop_on_disconnect (GstRTSPMedia *media, gboolean stop_on_disconnect); + +GST_EXPORT gboolean gst_rtsp_media_is_stop_on_disconnect (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_transport_mode (GstRTSPMedia *media, GstRTSPTransportMode mode); + +GST_EXPORT GstRTSPTransportMode gst_rtsp_media_get_transport_mode (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_reusable (GstRTSPMedia *media, gboolean reusable); + +GST_EXPORT gboolean gst_rtsp_media_is_reusable (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_profiles (GstRTSPMedia *media, GstRTSPProfile profiles); + +GST_EXPORT GstRTSPProfile gst_rtsp_media_get_profiles (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_protocols (GstRTSPMedia *media, GstRTSPLowerTrans protocols); + +GST_EXPORT GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown); + +GST_EXPORT gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_address_pool (GstRTSPMedia *media, GstRTSPAddressPool *pool); + +GST_EXPORT GstRTSPAddressPool * gst_rtsp_media_get_address_pool (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_multicast_iface (GstRTSPMedia *media, const gchar *multicast_iface); + +GST_EXPORT gchar * gst_rtsp_media_get_multicast_iface (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size); + +GST_EXPORT guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_retransmission_time (GstRTSPMedia *media, GstClockTime time); + +GST_EXPORT GstClockTime gst_rtsp_media_get_retransmission_time (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_latency (GstRTSPMedia *media, guint latency); + +GST_EXPORT guint gst_rtsp_media_get_latency (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_use_time_provider (GstRTSPMedia *media, gboolean time_provider); + +GST_EXPORT gboolean gst_rtsp_media_is_time_provider (GstRTSPMedia *media); + +GST_EXPORT GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media, const gchar *address, guint16 port); +GST_EXPORT void gst_rtsp_media_set_clock (GstRTSPMedia *media, GstClock * clock); +GST_EXPORT void gst_rtsp_media_set_publish_clock_mode (GstRTSPMedia * media, GstRTSPPublishClockMode mode); + +GST_EXPORT GstRTSPPublishClockMode gst_rtsp_media_get_publish_clock_mode (GstRTSPMedia * media); /* prepare the media for playback */ + +GST_EXPORT gboolean gst_rtsp_media_prepare (GstRTSPMedia *media, GstRTSPThread *thread); + +GST_EXPORT gboolean gst_rtsp_media_unprepare (GstRTSPMedia *media); +GST_EXPORT void gst_rtsp_media_set_suspend_mode (GstRTSPMedia *media, GstRTSPSuspendMode mode); + +GST_EXPORT GstRTSPSuspendMode gst_rtsp_media_get_suspend_mode (GstRTSPMedia *media); +GST_EXPORT gboolean gst_rtsp_media_suspend (GstRTSPMedia *media); + +GST_EXPORT gboolean gst_rtsp_media_unsuspend (GstRTSPMedia *media); +GST_EXPORT gboolean gst_rtsp_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, GstSDPInfo * info); +GST_EXPORT gboolean gst_rtsp_media_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp); /* creating streams */ + +GST_EXPORT void gst_rtsp_media_collect_streams (GstRTSPMedia *media); + +GST_EXPORT GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia *media, GstElement *payloader, GstPad *pad); /* dealing with the media */ + +GST_EXPORT GstClock * gst_rtsp_media_get_clock (GstRTSPMedia *media); + +GST_EXPORT GstClockTime gst_rtsp_media_get_base_time (GstRTSPMedia *media); +GST_EXPORT guint gst_rtsp_media_n_streams (GstRTSPMedia *media); + +GST_EXPORT GstRTSPStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); + +GST_EXPORT GstRTSPStream * gst_rtsp_media_find_stream (GstRTSPMedia *media, const gchar * control); +GST_EXPORT gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range); + +GST_EXPORT gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, gboolean play, GstRTSPRangeUnit unit); +GST_EXPORT gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GPtrArray *transports); + +GST_EXPORT void gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state); diff --git a/gst/rtsp-server/rtsp-mount-points.h b/gst/rtsp-server/rtsp-mount-points.h index bf89b0b63f..9630beed71 100644 --- a/gst/rtsp-server/rtsp-mount-points.h +++ b/gst/rtsp-server/rtsp-mount-points.h @@ -68,21 +68,31 @@ struct _GstRTSPMountPointsClass { gpointer _gst_reserved[GST_PADDING]; }; +GST_EXPORT GType gst_rtsp_mount_points_get_type (void); /* creating a mount points */ + +GST_EXPORT GstRTSPMountPoints * gst_rtsp_mount_points_new (void); +GST_EXPORT gchar * gst_rtsp_mount_points_make_path (GstRTSPMountPoints *mounts, const GstRTSPUrl * url); /* finding a media factory */ + +GST_EXPORT GstRTSPMediaFactory * gst_rtsp_mount_points_match (GstRTSPMountPoints *mounts, const gchar *path, gint * matched); /* managing media to a mount point */ + +GST_EXPORT void gst_rtsp_mount_points_add_factory (GstRTSPMountPoints *mounts, const gchar *path, GstRTSPMediaFactory *factory); + +GST_EXPORT void gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints *mounts, const gchar *path); diff --git a/gst/rtsp-server/rtsp-params.h b/gst/rtsp-server/rtsp-params.h index 563757dde9..4b5c734a48 100644 --- a/gst/rtsp-server/rtsp-params.h +++ b/gst/rtsp-server/rtsp-params.h @@ -30,7 +30,10 @@ G_BEGIN_DECLS +GST_EXPORT GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPContext * ctx); + +GST_EXPORT GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPContext * ctx); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-permissions.h b/gst/rtsp-server/rtsp-permissions.h index 1cebb90ff4..822285cae5 100644 --- a/gst/rtsp-server/rtsp-permissions.h +++ b/gst/rtsp-server/rtsp-permissions.h @@ -26,6 +26,7 @@ typedef struct _GstRTSPPermissions GstRTSPPermissions; G_BEGIN_DECLS +GST_EXPORT GType gst_rtsp_permissions_get_type (void); #define GST_TYPE_RTSP_PERMISSIONS (gst_rtsp_permissions_get_type ()) @@ -71,20 +72,29 @@ gst_rtsp_permissions_unref (GstRTSPPermissions * permissions) } +GST_EXPORT GstRTSPPermissions * gst_rtsp_permissions_new (void); +GST_EXPORT void gst_rtsp_permissions_add_role (GstRTSPPermissions *permissions, const gchar *role, const gchar *fieldname, ...); + +GST_EXPORT void gst_rtsp_permissions_add_role_valist (GstRTSPPermissions *permissions, const gchar *role, const gchar *fieldname, va_list var_args); + +GST_EXPORT void gst_rtsp_permissions_remove_role (GstRTSPPermissions *permissions, const gchar *role); + +GST_EXPORT const GstStructure * gst_rtsp_permissions_get_role (GstRTSPPermissions *permissions, const gchar *role); +GST_EXPORT gboolean gst_rtsp_permissions_is_allowed (GstRTSPPermissions *permissions, const gchar *role, const gchar *permission); diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h index b56eb82dc6..50cafe8152 100644 --- a/gst/rtsp-server/rtsp-sdp.h +++ b/gst/rtsp-server/rtsp-sdp.h @@ -33,7 +33,11 @@ typedef struct { } GstSDPInfo; /* creating SDP */ + +GST_EXPORT gboolean gst_rtsp_sdp_from_media (GstSDPMessage *sdp, GstSDPInfo *info, GstRTSPMedia * media); + +GST_EXPORT gboolean gst_rtsp_sdp_from_stream (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream *stream); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index efb18e4efd..a928cf59ed 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -93,46 +93,77 @@ struct _GstRTSPServerClass { gpointer _gst_reserved[GST_PADDING_LARGE]; }; +GST_EXPORT GType gst_rtsp_server_get_type (void); +GST_EXPORT GstRTSPServer * gst_rtsp_server_new (void); +GST_EXPORT void gst_rtsp_server_set_address (GstRTSPServer *server, const gchar *address); + +GST_EXPORT gchar * gst_rtsp_server_get_address (GstRTSPServer *server); +GST_EXPORT void gst_rtsp_server_set_service (GstRTSPServer *server, const gchar *service); + +GST_EXPORT gchar * gst_rtsp_server_get_service (GstRTSPServer *server); +GST_EXPORT void gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog); + +GST_EXPORT gint gst_rtsp_server_get_backlog (GstRTSPServer *server); +GST_EXPORT int gst_rtsp_server_get_bound_port (GstRTSPServer *server); +GST_EXPORT void gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool); + +GST_EXPORT GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *server); +GST_EXPORT void gst_rtsp_server_set_mount_points (GstRTSPServer *server, GstRTSPMountPoints *mounts); + +GST_EXPORT GstRTSPMountPoints * gst_rtsp_server_get_mount_points (GstRTSPServer *server); +GST_EXPORT void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); + +GST_EXPORT GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server); +GST_EXPORT void gst_rtsp_server_set_thread_pool (GstRTSPServer *server, GstRTSPThreadPool *pool); + +GST_EXPORT GstRTSPThreadPool * gst_rtsp_server_get_thread_pool (GstRTSPServer *server); +GST_EXPORT gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket *socket, const gchar * ip, gint port, const gchar *initial_buffer); +GST_EXPORT gboolean gst_rtsp_server_io_func (GSocket *socket, GIOCondition condition, GstRTSPServer *server); +GST_EXPORT GSocket * gst_rtsp_server_create_socket (GstRTSPServer *server, GCancellable *cancellable, GError **error); + +GST_EXPORT GSource * gst_rtsp_server_create_source (GstRTSPServer *server, GCancellable * cancellable, GError **error); + +GST_EXPORT guint gst_rtsp_server_attach (GstRTSPServer *server, GMainContext *context); @@ -160,6 +191,7 @@ typedef GstRTSPFilterResult (*GstRTSPServerClientFilterFunc) (GstRTSPServer *se GstRTSPClient *client, gpointer user_data); +GST_EXPORT GList * gst_rtsp_server_client_filter (GstRTSPServer *server, GstRTSPServerClientFilterFunc func, gpointer user_data); diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 3f7208ccc3..612173bdf2 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -61,35 +61,52 @@ struct _GstRTSPSessionMediaClass gpointer _gst_reserved[GST_PADDING]; }; +GST_EXPORT GType gst_rtsp_session_media_get_type (void); +GST_EXPORT GstRTSPSessionMedia * gst_rtsp_session_media_new (const gchar *path, GstRTSPMedia *media); +GST_EXPORT gboolean gst_rtsp_session_media_matches (GstRTSPSessionMedia *media, const gchar *path, gint * matched); + +GST_EXPORT GstRTSPMedia * gst_rtsp_session_media_get_media (GstRTSPSessionMedia *media); +GST_EXPORT GstClockTime gst_rtsp_session_media_get_base_time (GstRTSPSessionMedia *media); /* control media */ + +GST_EXPORT gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media, GstState state); +GST_EXPORT void gst_rtsp_session_media_set_rtsp_state (GstRTSPSessionMedia *media, GstRTSPState state); + +GST_EXPORT GstRTSPState gst_rtsp_session_media_get_rtsp_state (GstRTSPSessionMedia *media); /* get stream transport config */ + +GST_EXPORT GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia *media, GstRTSPStream *stream, GstRTSPTransport *tr); + +GST_EXPORT GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia *media, guint idx); +GST_EXPORT gboolean gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia *media, GstRTSPRange *range); +GST_EXPORT gchar * gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index dd833ae902..268000407e 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -113,29 +113,49 @@ typedef GstRTSPFilterResult (*GstRTSPSessionPoolFilterFunc) (GstRTSPSessionPool gpointer user_data); +GST_EXPORT GType gst_rtsp_session_pool_get_type (void); /* creating a session pool */ + +GST_EXPORT GstRTSPSessionPool * gst_rtsp_session_pool_new (void); /* counting sessions */ + +GST_EXPORT void gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool *pool, guint max); + +GST_EXPORT guint gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool *pool); +GST_EXPORT guint gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool *pool); /* managing sessions */ + +GST_EXPORT GstRTSPSession * gst_rtsp_session_pool_create (GstRTSPSessionPool *pool); + +GST_EXPORT GstRTSPSession * gst_rtsp_session_pool_find (GstRTSPSessionPool *pool, const gchar *sessionid); + +GST_EXPORT gboolean gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, GstRTSPSession *sess); /* perform session maintenance */ + +GST_EXPORT GList * gst_rtsp_session_pool_filter (GstRTSPSessionPool *pool, GstRTSPSessionPoolFilterFunc func, gpointer user_data); + +GST_EXPORT guint gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool); + +GST_EXPORT GSource * gst_rtsp_session_pool_create_watch (GstRTSPSessionPool *pool); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 9a438fb3c1..ed97b76f21 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -79,36 +79,63 @@ struct _GstRTSPSessionClass { gpointer _gst_reserved[GST_PADDING]; }; +GST_EXPORT GType gst_rtsp_session_get_type (void); /* create a new session */ + +GST_EXPORT GstRTSPSession * gst_rtsp_session_new (const gchar *sessionid); +GST_EXPORT const gchar * gst_rtsp_session_get_sessionid (GstRTSPSession *session); +GST_EXPORT gchar * gst_rtsp_session_get_header (GstRTSPSession *session); +GST_EXPORT void gst_rtsp_session_set_timeout (GstRTSPSession *session, guint timeout); + +GST_EXPORT guint gst_rtsp_session_get_timeout (GstRTSPSession *session); /* session timeout stuff */ + +GST_EXPORT void gst_rtsp_session_touch (GstRTSPSession *session); + +GST_EXPORT void gst_rtsp_session_prevent_expire (GstRTSPSession *session); + +GST_EXPORT void gst_rtsp_session_allow_expire (GstRTSPSession *session); + +GST_EXPORT gint gst_rtsp_session_next_timeout_usec (GstRTSPSession *session, gint64 now); + +GST_EXPORT gboolean gst_rtsp_session_is_expired_usec (GstRTSPSession *session, gint64 now); #ifndef GST_DISABLE_DEPRECATED +GST_EXPORT gint gst_rtsp_session_next_timeout (GstRTSPSession *session, GTimeVal *now); + +GST_EXPORT gboolean gst_rtsp_session_is_expired (GstRTSPSession *session, GTimeVal *now); #endif /* handle media in a session */ + +GST_EXPORT GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess, const gchar *path, GstRTSPMedia *media); + +GST_EXPORT gboolean gst_rtsp_session_release_media (GstRTSPSession *sess, GstRTSPSessionMedia *media); /* get media in a session */ + +GST_EXPORT GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, const gchar *path, gint * matched); @@ -137,6 +164,7 @@ typedef GstRTSPFilterResult (*GstRTSPSessionFilterFunc) (GstRTSPSession *sess, GstRTSPSessionMedia *media, gpointer user_data); +GST_EXPORT GList * gst_rtsp_session_filter (GstRTSPSession *sess, GstRTSPSessionFilterFunc func, gpointer user_data); diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 8e2d366972..11a3395ef7 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -84,50 +84,73 @@ struct _GstRTSPStreamTransportClass { gpointer _gst_reserved[GST_PADDING]; }; +GST_EXPORT GType gst_rtsp_stream_transport_get_type (void); +GST_EXPORT GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream, GstRTSPTransport *tr); +GST_EXPORT GstRTSPStream * gst_rtsp_stream_transport_get_stream (GstRTSPStreamTransport *trans); +GST_EXPORT void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans, GstRTSPTransport * tr); + +GST_EXPORT const GstRTSPTransport * gst_rtsp_stream_transport_get_transport (GstRTSPStreamTransport *trans); +GST_EXPORT void gst_rtsp_stream_transport_set_url (GstRTSPStreamTransport *trans, const GstRTSPUrl * url); + +GST_EXPORT const GstRTSPUrl * gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport *trans); +GST_EXPORT gchar * gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport *trans, GstClockTime start_time); +GST_EXPORT void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans, GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, gpointer user_data, GDestroyNotify notify); + +GST_EXPORT void gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport *trans, GstRTSPKeepAliveFunc keep_alive, gpointer user_data, GDestroyNotify notify); + +GST_EXPORT void gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport *trans); +GST_EXPORT gboolean gst_rtsp_stream_transport_set_active (GstRTSPStreamTransport *trans, gboolean active); +GST_EXPORT void gst_rtsp_stream_transport_set_timed_out (GstRTSPStreamTransport *trans, gboolean timedout); + +GST_EXPORT gboolean gst_rtsp_stream_transport_is_timed_out (GstRTSPStreamTransport *trans); +GST_EXPORT gboolean gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport *trans, GstBuffer *buffer); + +GST_EXPORT gboolean gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport *trans, GstBuffer *buffer); +GST_EXPORT GstFlowReturn gst_rtsp_stream_transport_recv_data (GstRTSPStreamTransport *trans, guint channel, GstBuffer *buffer); diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 9ef887aa9f..a934ab58cd 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -65,121 +65,211 @@ struct _GstRTSPStreamClass { gpointer _gst_reserved[GST_PADDING]; }; +GST_EXPORT GType gst_rtsp_stream_get_type (void); +GST_EXPORT GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement *payloader, GstPad *pad); + +GST_EXPORT guint gst_rtsp_stream_get_index (GstRTSPStream *stream); + +GST_EXPORT guint gst_rtsp_stream_get_pt (GstRTSPStream *stream); + +GST_EXPORT GstPad * gst_rtsp_stream_get_srcpad (GstRTSPStream *stream); + +GST_EXPORT GstPad * gst_rtsp_stream_get_sinkpad (GstRTSPStream *stream); +GST_EXPORT void gst_rtsp_stream_set_control (GstRTSPStream *stream, const gchar *control); + +GST_EXPORT gchar * gst_rtsp_stream_get_control (GstRTSPStream *stream); + +GST_EXPORT gboolean gst_rtsp_stream_has_control (GstRTSPStream *stream, const gchar *control); +GST_EXPORT void gst_rtsp_stream_set_mtu (GstRTSPStream *stream, guint mtu); + +GST_EXPORT guint gst_rtsp_stream_get_mtu (GstRTSPStream *stream); +GST_EXPORT void gst_rtsp_stream_set_dscp_qos (GstRTSPStream *stream, gint dscp_qos); + +GST_EXPORT gint gst_rtsp_stream_get_dscp_qos (GstRTSPStream *stream); +GST_EXPORT gboolean gst_rtsp_stream_is_transport_supported (GstRTSPStream *stream, GstRTSPTransport *transport); +GST_EXPORT void gst_rtsp_stream_set_profiles (GstRTSPStream *stream, GstRTSPProfile profiles); + +GST_EXPORT GstRTSPProfile gst_rtsp_stream_get_profiles (GstRTSPStream *stream); +GST_EXPORT void gst_rtsp_stream_set_protocols (GstRTSPStream *stream, GstRTSPLowerTrans protocols); + +GST_EXPORT GstRTSPLowerTrans gst_rtsp_stream_get_protocols (GstRTSPStream *stream); +GST_EXPORT void gst_rtsp_stream_set_address_pool (GstRTSPStream *stream, GstRTSPAddressPool *pool); + +GST_EXPORT GstRTSPAddressPool * gst_rtsp_stream_get_address_pool (GstRTSPStream *stream); +GST_EXPORT void gst_rtsp_stream_set_multicast_iface (GstRTSPStream *stream, const gchar * multicast_iface); + +GST_EXPORT gchar * gst_rtsp_stream_get_multicast_iface (GstRTSPStream *stream); +GST_EXPORT GstRTSPAddress * gst_rtsp_stream_reserve_address (GstRTSPStream *stream, const gchar * address, guint port, guint n_ports, guint ttl); +GST_EXPORT gboolean gst_rtsp_stream_join_bin (GstRTSPStream *stream, GstBin *bin, GstElement *rtpbin, GstState state); + +GST_EXPORT gboolean gst_rtsp_stream_leave_bin (GstRTSPStream *stream, GstBin *bin, GstElement *rtpbin); + +GST_EXPORT GstBin * gst_rtsp_stream_get_joined_bin (GstRTSPStream *stream); +GST_EXPORT gboolean gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked); + +GST_EXPORT gboolean gst_rtsp_stream_is_blocking (GstRTSPStream * stream); +GST_EXPORT void gst_rtsp_stream_set_client_side (GstRTSPStream *stream, gboolean client_side); + +GST_EXPORT gboolean gst_rtsp_stream_is_client_side (GstRTSPStream *stream); +GST_EXPORT void gst_rtsp_stream_get_server_port (GstRTSPStream *stream, GstRTSPRange *server_port, GSocketFamily family); + +GST_EXPORT GstRTSPAddress * gst_rtsp_stream_get_multicast_address (GstRTSPStream *stream, GSocketFamily family); +GST_EXPORT GObject * gst_rtsp_stream_get_rtpsession (GstRTSPStream *stream); +GST_EXPORT GstElement * gst_rtsp_stream_get_srtp_encoder (GstRTSPStream *stream); +GST_EXPORT void gst_rtsp_stream_get_ssrc (GstRTSPStream *stream, guint *ssrc); +GST_EXPORT gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream *stream, guint *rtptime, guint *seq, guint *clock_rate, GstClockTime *running_time); + +GST_EXPORT GstCaps * gst_rtsp_stream_get_caps (GstRTSPStream *stream); +GST_EXPORT GstFlowReturn gst_rtsp_stream_recv_rtp (GstRTSPStream *stream, GstBuffer *buffer); + +GST_EXPORT GstFlowReturn gst_rtsp_stream_recv_rtcp (GstRTSPStream *stream, GstBuffer *buffer); +GST_EXPORT gboolean gst_rtsp_stream_add_transport (GstRTSPStream *stream, GstRTSPStreamTransport *trans); + +GST_EXPORT gboolean gst_rtsp_stream_remove_transport (GstRTSPStream *stream, GstRTSPStreamTransport *trans); +GST_EXPORT GSocket * gst_rtsp_stream_get_rtp_socket (GstRTSPStream *stream, GSocketFamily family); + +GST_EXPORT GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream *stream, GSocketFamily family); +GST_EXPORT gboolean gst_rtsp_stream_update_crypto (GstRTSPStream * stream, guint ssrc, GstCaps * crypto); +GST_EXPORT gboolean gst_rtsp_stream_query_position (GstRTSPStream * stream, gint64 * position); + +GST_EXPORT gboolean gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop); +GST_EXPORT void gst_rtsp_stream_set_seqnum_offset (GstRTSPStream *stream, guint16 seqnum); + +GST_EXPORT guint16 gst_rtsp_stream_get_current_seqnum (GstRTSPStream *stream); + +GST_EXPORT void gst_rtsp_stream_set_retransmission_time (GstRTSPStream *stream, GstClockTime time); + +GST_EXPORT GstClockTime gst_rtsp_stream_get_retransmission_time (GstRTSPStream *stream); + +GST_EXPORT guint gst_rtsp_stream_get_retransmission_pt (GstRTSPStream * stream); + +GST_EXPORT void gst_rtsp_stream_set_retransmission_pt (GstRTSPStream * stream, guint rtx_pt); + +GST_EXPORT void gst_rtsp_stream_set_buffer_size (GstRTSPStream *stream, guint size); + +GST_EXPORT guint gst_rtsp_stream_get_buffer_size (GstRTSPStream *stream); +GST_EXPORT void gst_rtsp_stream_set_pt_map (GstRTSPStream * stream, guint pt, GstCaps * caps); + +GST_EXPORT GstElement * gst_rtsp_stream_request_aux_sender (GstRTSPStream * stream, guint sessid); +GST_EXPORT gboolean gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, GSocketFamily family, GstRTSPTransport *transport, gboolean use_client_setttings); +GST_EXPORT void gst_rtsp_stream_set_publish_clock_mode (GstRTSPStream * stream, GstRTSPPublishClockMode mode); + +GST_EXPORT GstRTSPPublishClockMode gst_rtsp_stream_get_publish_clock_mode (GstRTSPStream * stream); /** @@ -206,6 +296,7 @@ typedef GstRTSPFilterResult (*GstRTSPStreamTransportFilterFunc) (GstRTSPStream * GstRTSPStreamTransport *trans, gpointer user_data); +GST_EXPORT GList * gst_rtsp_stream_transport_filter (GstRTSPStream *stream, GstRTSPStreamTransportFilterFunc func, gpointer user_data); diff --git a/gst/rtsp-server/rtsp-thread-pool.h b/gst/rtsp-server/rtsp-thread-pool.h index 2db59c9383..87ed73bee3 100644 --- a/gst/rtsp-server/rtsp-thread-pool.h +++ b/gst/rtsp-server/rtsp-thread-pool.h @@ -40,6 +40,7 @@ G_BEGIN_DECLS #define GST_RTSP_THREAD_POOL_CAST(obj) ((GstRTSPThreadPool*)(obj)) #define GST_RTSP_THREAD_POOL_CLASS_CAST(klass) ((GstRTSPThreadPoolClass*)(klass)) +GST_EXPORT GType gst_rtsp_thread_get_type (void); #define GST_TYPE_RTSP_THREAD (gst_rtsp_thread_get_type ()) @@ -77,9 +78,13 @@ struct _GstRTSPThread { GMainLoop *loop; }; +GST_EXPORT GstRTSPThread * gst_rtsp_thread_new (GstRTSPThreadType type); +GST_EXPORT gboolean gst_rtsp_thread_reuse (GstRTSPThread * thread); + +GST_EXPORT void gst_rtsp_thread_stop (GstRTSPThread * thread); /** @@ -154,16 +159,24 @@ struct _GstRTSPThreadPoolClass { gpointer _gst_reserved[GST_PADDING]; }; +GST_EXPORT GType gst_rtsp_thread_pool_get_type (void); +GST_EXPORT GstRTSPThreadPool * gst_rtsp_thread_pool_new (void); +GST_EXPORT void gst_rtsp_thread_pool_set_max_threads (GstRTSPThreadPool * pool, gint max_threads); + +GST_EXPORT gint gst_rtsp_thread_pool_get_max_threads (GstRTSPThreadPool * pool); +GST_EXPORT GstRTSPThread * gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool *pool, GstRTSPThreadType type, GstRTSPContext *ctx); + +GST_EXPORT void gst_rtsp_thread_pool_cleanup (void); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPThread, gst_rtsp_thread_unref) diff --git a/gst/rtsp-server/rtsp-token.h b/gst/rtsp-server/rtsp-token.h index 1d2a5551c5..34b4d50cdd 100644 --- a/gst/rtsp-server/rtsp-token.h +++ b/gst/rtsp-server/rtsp-token.h @@ -28,6 +28,7 @@ typedef struct _GstRTSPToken GstRTSPToken; G_BEGIN_DECLS +GST_EXPORT GType gst_rtsp_token_get_type(void); #define GST_TYPE_RTSP_TOKEN (gst_rtsp_token_get_type()) @@ -73,15 +74,26 @@ gst_rtsp_token_unref (GstRTSPToken * token) } +GST_EXPORT GstRTSPToken * gst_rtsp_token_new_empty (void); + +GST_EXPORT GstRTSPToken * gst_rtsp_token_new (const gchar * firstfield, ...); + +GST_EXPORT GstRTSPToken * gst_rtsp_token_new_valist (const gchar * firstfield, va_list var_args); +GST_EXPORT const GstStructure * gst_rtsp_token_get_structure (GstRTSPToken *token); + +GST_EXPORT GstStructure * gst_rtsp_token_writable_structure (GstRTSPToken *token); +GST_EXPORT const gchar * gst_rtsp_token_get_string (GstRTSPToken *token, const gchar *field); + +GST_EXPORT gboolean gst_rtsp_token_is_allowed (GstRTSPToken *token, const gchar *field); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC From 0ce18a878d43e7b15141e7ebcf365f43c9095329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 20 May 2017 15:07:31 +0100 Subject: [PATCH 1363/1776] meson: add options to set package name and origin https://bugzilla.gnome.org/show_bug.cgi?id=782172 --- meson.build | 15 +++++++++++++-- meson_options.txt | 4 ++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 4789e5f4e1..be6c837ca1 100644 --- a/meson.build +++ b/meson.build @@ -30,11 +30,22 @@ cdata.set('GETTEXT_PACKAGE', '"gst-rtsp-server-1.0"') cdata.set('PACKAGE', '"gst-rtsp-server"') cdata.set('VERSION', '"@0@"'.format(gst_version)) cdata.set('PACKAGE_VERSION', '"@0@"'.format(gst_version)) -cdata.set('GST_PACKAGE_NAME', '"GStreamer RTSP Server Library"') -cdata.set('GST_PACKAGE_ORIGIN', '"Unknown package origin"') #cdata.set('GST_API_VERSION', '"@0@"'.format(api_version)) cdata.set('GST_LICENSE', '"LGPL"') +# GStreamer package name and origin url +gst_package_name = get_option('with-package-name') +if gst_package_name == '' + if gst_version_nano == 0 + cdata.set_quoted('GST_PACKAGE_NAME', 'GStreamer RTSP Server Library source release') + elif gst_version_nano == 1 + cdata.set_quoted('GST_PACKAGE_NAME', 'GStreamer RTSP Server Library git') + else + cdata.set_quoted('GST_PACKAGE_NAME', 'GStreamer RTSP Server Library prerelease') + endif +endif +cdata.set_quoted('GST_PACKAGE_ORIGIN', get_option('with-package-origin')) + configure_file(input : 'config.h.meson', output : 'config.h', configuration : cdata) diff --git a/meson_options.txt b/meson_options.txt index e265545279..16265d35d8 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,7 @@ option('disable_introspection', type : 'boolean', value : false, description : 'Whether to disable the introspection generation') +option('with-package-name', type : 'string', + description : 'package name to use in plugins') +option('with-package-origin', type : 'string', value : 'Unknown package origin', + description : 'package origin URL to use in plugins') From c9e13468429c52c627c685bf75bf4a5eb4e436da Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 Jun 2017 12:55:41 -0400 Subject: [PATCH 1364/1776] meson: Do not use path separator in test names Avoiding warnings like: WARNING: Target "elements/audioamplify" has a path separator in its name. --- tests/check/meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/check/meson.build b/tests/check/meson.build index f93bf631b1..64c4c4572b 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -62,7 +62,9 @@ endforeach message('test env:' + all_env) foreach test_name : rtsp_server_tests - exe = executable(test_name, '@0@.c'.format(test_name), + fname = '@0@.c'.format(test_name) + test_name = test_name.underscorify() + exe = executable(test_name, fname, include_directories : rtspserver_incs, c_args : rtspserver_args + test_c_args, dependencies : [gstcheck_dep, gstrtsp_dep, gstrtp_dep, gst_rtsp_server_dep] From fe8a9bc6d51a8ac09fef5a50dcd902a382014479 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 Jun 2017 13:04:41 -0400 Subject: [PATCH 1365/1776] meson: Fix building tests and activate them again --- tests/check/meson.build | 59 +++++++++++++++-------------------------- tests/meson.build | 2 +- 2 files changed, 23 insertions(+), 38 deletions(-) diff --git a/tests/check/meson.build b/tests/check/meson.build index 64c4c4572b..de2f1289f0 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -2,29 +2,18 @@ gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, fallback : ['gstreamer', 'gst_check_dep']) -test_plugins_modules = [ - ['gstreamer-1.0', true], - ['gstreamer-plugins-base-1.0', true], - ['gstreamer-plugins-good-1.0', false], - ['gstreamer-plugins-bad-1.0', false], -] -test_plugin_path = '' -foreach m : test_plugins_modules - m_name = m[0] - m_required = m[1] - runcmd = run_command('pkg-config', '--variable=pluginsdir', m_name + ' ' + gst_req) - if runcmd.returncode() == 0 - module_plugin_path = runcmd.stdout().strip() - message('Using '+ m_name + ' plugins in ' + module_plugin_path) - if test_plugin_path == '' - test_plugin_path = module_plugin_path - elif module_plugin_path != test_plugin_path - test_plugin_path = test_plugin_path + ':' + module_plugin_path - endif - elif m_required - error('Could not determine ' + m_name + ' plugins directory for unit tests.') - endif -endforeach + +pluginsdirs = [] +if gst_dep.type_name() == 'pkgconfig' + pbase = dependency('gstreamer-plugins-base-' + api_version, required : false) + pbad = dependency('gstreamer-plugins-bad-' + api_version, required : false) + pgood = dependency('gstreamer-plugins-good-' + api_version, required : false) + + pluginsdirs = [gst_dep.get_pkgconfig_variable('pluginsdir'), + pbase.get_pkgconfig_variable('pluginsdir'), + pbad.get_pkgconfig_variable('pluginsdir'), + pgood.get_pkgconfig_variable('pluginsdir')] +endif test_c_args = [ '-UG_DISABLE_ASSERT', @@ -32,13 +21,6 @@ test_c_args = [ '-DGST_CHECK_TEST_ENVIRONMENT_BEACON="GST_PLUGIN_LOADING_WHITELIST"', ] -test_env = [ - 'GST_PLUGIN_SYSTEM_PATH_1_0=', - 'GST_PLUGIN_PATH_1_0=' + meson.build_root() + '/gst/rtsp-sink:' + test_plugin_path, - 'GST_PLUGIN_LOADING_WHITELIST=gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad:gst-rtsp-server', - 'CK_DEFAULT_TIMEOUT=120', -] - rtsp_server_tests = [ 'gst/addresspool', 'gst/client', @@ -55,13 +37,15 @@ rtsp_server_tests = [ 'gst/token', ] -all_env = '' -foreach e : test_env - all_env = all_env + ' ' + e -endforeach -message('test env:' + all_env) - foreach test_name : rtsp_server_tests + env = environment() + env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') + env.set('GST_STATE_IGNORE_ELEMENTS', '') + env.set('GST_PLUGIN_LOADING_WHITELIST', 'gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad:gst-rtsp-server') + env.set('CK_DEFAULT_TIMEOUT', '120') + env.set('GST_REGISTRY', '@0@/@1@.registry'.format(meson.current_build_dir(), test_name)) + env.set('GST_PLUGIN_PATH_1_0', [meson.build_root()] + pluginsdirs) + fname = '@0@.c'.format(test_name) test_name = test_name.underscorify() exe = executable(test_name, fname, @@ -70,7 +54,8 @@ foreach test_name : rtsp_server_tests dependencies : [gstcheck_dep, gstrtsp_dep, gstrtp_dep, gst_rtsp_server_dep] ) test(test_name, exe, - env : test_env + [ 'GST_REGISTRY=@0@/@1@.registry'.format(meson.current_build_dir(), test_name) ], + env : env, timeout : 120, + is_parallel: false ) endforeach diff --git a/tests/meson.build b/tests/meson.build index 5f1c1c96c8..0e2c8874df 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1 +1 @@ -#subdir('check') # FIXME +subdir('check') From e66d3beb0c6a4204e65d608d7e6aae8d9b95cd13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 9 Jun 2017 21:27:09 +0100 Subject: [PATCH 1366/1776] meson: config.h.meson is no longer needed --- config.h.meson | 16 ---------------- meson.build | 20 +++++++++++--------- 2 files changed, 11 insertions(+), 25 deletions(-) delete mode 100644 config.h.meson diff --git a/config.h.meson b/config.h.meson deleted file mode 100644 index c7709c8bd7..0000000000 --- a/config.h.meson +++ /dev/null @@ -1,16 +0,0 @@ -#mesondefine ENABLE_NLS -#mesondefine GETTEXT_PACKAGE -#mesondefine GST_API_VERSION -#mesondefine GST_LICENSE -#mesondefine GST_PACKAGE_NAME -#mesondefine GST_PACKAGE_ORIGIN -#mesondefine GST_PACKAGE_RELEASE_DATETIME -#mesondefine LOCALEDIR -#mesondefine PACKAGE -#mesondefine PACKAGE_BUGREPORT -#mesondefine PACKAGE_NAME -#mesondefine PACKAGE_STRING -#mesondefine PACKAGE_TARNAME -#mesondefine PACKAGE_URL -#mesondefine PACKAGE_VERSION -#mesondefine VERSION diff --git a/meson.build b/meson.build index be6c837ca1..5a7bd56b26 100644 --- a/meson.build +++ b/meson.build @@ -26,12 +26,16 @@ libversion = '@0@.@1@.0'.format(soversion, gst_version_minor.to_int() * 100 + gs plugins_install_dir = '@0@/gstreamer-1.0'.format(get_option('libdir')) cdata = configuration_data() -cdata.set('GETTEXT_PACKAGE', '"gst-rtsp-server-1.0"') -cdata.set('PACKAGE', '"gst-rtsp-server"') -cdata.set('VERSION', '"@0@"'.format(gst_version)) -cdata.set('PACKAGE_VERSION', '"@0@"'.format(gst_version)) -#cdata.set('GST_API_VERSION', '"@0@"'.format(api_version)) -cdata.set('GST_LICENSE', '"LGPL"') +cdata.set_quoted('GETTEXT_PACKAGE', 'gst-rtsp-server-1.0') +cdata.set_quoted('PACKAGE', 'gst-rtsp-server') +cdata.set_quoted('VERSION', gst_version) +cdata.set_quoted('PACKAGE_VERSION', gst_version) +cdata.set_quoted('GST_API_VERSION', api_version) +cdata.set_quoted('GST_LICENSE', 'LGPL') + +# FIXME: ENABLE_NLS (currently also missing from autotools build) +# cdata.set('ENABLE_NLS', true) +# cdata.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir'))) # GStreamer package name and origin url gst_package_name = get_option('with-package-name') @@ -46,9 +50,7 @@ if gst_package_name == '' endif cdata.set_quoted('GST_PACKAGE_ORIGIN', get_option('with-package-origin')) -configure_file(input : 'config.h.meson', - output : 'config.h', - configuration : cdata) +configure_file(output : 'config.h', configuration : cdata) rtspserver_args = ['-DHAVE_CONFIG_H'] From e96dc57e1bb16f660b15ab953062010db2afce55 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 9 Jun 2017 20:11:47 -0400 Subject: [PATCH 1367/1776] And config.h.meson is no longer dist either --- Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 7a89d2782c..a4d0281ae3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,8 +25,7 @@ EXTRA_DIST = \ docs/design/gst-rtp-server-design \ gst-rtsp-server.doap \ $(win32) \ - $(shell find "$(top_srcdir)" -type f -name meson.build ! -path "$(top_srcdir)/$(PACKAGE_TARNAME)-*" ) \ - config.h.meson + $(shell find "$(top_srcdir)" -type f -name meson.build ! -path "$(top_srcdir)/$(PACKAGE_TARNAME)-*" ) ACLOCAL_AMFLAGS = -I m4 -I common/m4 From ff7b8fe0326c94a5af54d4d77ca968b12919361e Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 9 Jun 2017 20:16:28 -0400 Subject: [PATCH 1368/1776] Distribute meson_options.txt --- Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index a4d0281ae3..4b96f787c5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,7 +25,8 @@ EXTRA_DIST = \ docs/design/gst-rtp-server-design \ gst-rtsp-server.doap \ $(win32) \ - $(shell find "$(top_srcdir)" -type f -name meson.build ! -path "$(top_srcdir)/$(PACKAGE_TARNAME)-*" ) + $(shell find "$(top_srcdir)" -type f -name meson.build ! -path "$(top_srcdir)/$(PACKAGE_TARNAME)-*" ) \ + meson_options.txt ACLOCAL_AMFLAGS = -I m4 -I common/m4 From 9df5f8ea8fd136faa2856091fb83ea108a622a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 26 Jun 2017 09:55:49 +0100 Subject: [PATCH 1369/1776] meson: fix with-package-name option https://bugzilla.gnome.org/show_bug.cgi?id=784082 --- meson.build | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 5a7bd56b26..170fc03b9a 100644 --- a/meson.build +++ b/meson.build @@ -41,13 +41,14 @@ cdata.set_quoted('GST_LICENSE', 'LGPL') gst_package_name = get_option('with-package-name') if gst_package_name == '' if gst_version_nano == 0 - cdata.set_quoted('GST_PACKAGE_NAME', 'GStreamer RTSP Server Library source release') + gst_package_name = 'GStreamer RTSP Server Library source release' elif gst_version_nano == 1 - cdata.set_quoted('GST_PACKAGE_NAME', 'GStreamer RTSP Server Library git') + gst_package_name = 'GStreamer RTSP Server Library git' else - cdata.set_quoted('GST_PACKAGE_NAME', 'GStreamer RTSP Server Library prerelease') + gst_package_name = 'GStreamer RTSP Server Library prerelease' endif endif +cdata.set_quoted('GST_PACKAGE_NAME', gst_package_name) cdata.set_quoted('GST_PACKAGE_ORIGIN', get_option('with-package-origin')) configure_file(output : 'config.h', configuration : cdata) From fe3131ae88131b63a1d115f7efcd095ee5b7fe69 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Jun 2017 16:19:04 -0400 Subject: [PATCH 1370/1776] meson: Allow using glib as a subproject --- meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 170fc03b9a..bedbc0fe96 100644 --- a/meson.build +++ b/meson.build @@ -57,7 +57,8 @@ rtspserver_args = ['-DHAVE_CONFIG_H'] rtspserver_incs = include_directories('gst/rtsp-server', '.') -glib_dep = dependency('glib-2.0', version : glib_req) +glib_dep = dependency('glib-2.0', version : glib_req, + fallback: ['glib', 'libglib_dep']) gst_dep = dependency('gstreamer-1.0', version : gst_req, fallback : ['gstreamer', 'gst_dep']) gstrtsp_dep = dependency('gstreamer-rtsp-1.0', version : gst_req, From d72284bdf8700c40e6eaca5e060cbb850a59288e Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Thu, 22 Jun 2017 07:25:07 -0700 Subject: [PATCH 1371/1776] rtsp-stream: fix connection delay due to wrong assumption on last-sample Commit 852cc09f542af5cadd79ffd7fe79d6475cf57e14 assumed that multiudpsink's last-sample always comes from the payloader. Which is wrong if auxiliary streams are multiplexed in the same stream. So check the buffer's ssrc against the caps'ssrc before to use its seqnum. If not the same ssrc just use the payloader as done prior the commit above or when there is no last-sample yet. https://bugzilla.gnome.org/show_bug.cgi?id=784094 --- gst/rtsp-server/rtsp-stream.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 6bb24dfc97..6e8c97ad2b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -3018,13 +3018,29 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, GstCaps *caps; GstBuffer *buffer; GstSegment *segment; + GstStructure *s; GstRTPBuffer rtp_buffer = GST_RTP_BUFFER_INIT; caps = gst_sample_get_caps (last_sample); buffer = gst_sample_get_buffer (last_sample); segment = gst_sample_get_segment (last_sample); + s = gst_caps_get_structure (caps, 0); if (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp_buffer)) { + guint ssrc_buf = gst_rtp_buffer_get_ssrc (&rtp_buffer); + guint ssrc_stream = 0; + if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT) && + gst_structure_get_uint (s, "ssrc", &ssrc_stream) && + ssrc_buf != ssrc_stream) { + /* Skip buffers from auxiliary streams. */ + GST_DEBUG_OBJECT (stream, + "not a buffer from the payloader, SSRC: %08x", ssrc_buf); + + gst_rtp_buffer_unmap (&rtp_buffer); + gst_sample_unref (last_sample); + goto stats; + } + if (seq) { *seq = gst_rtp_buffer_get_seq (&rtp_buffer); } @@ -3042,8 +3058,6 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, } if (clock_rate) { - GstStructure *s = gst_caps_get_structure (caps, 0); - gst_structure_get_int (s, "clock-rate", (gint *) clock_rate); if (*clock_rate == 0 && running_time) @@ -3058,6 +3072,7 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, } } +stats: if (g_object_class_find_property (payobjclass, "stats")) { g_object_get (priv->payloader, "stats", &stats, NULL); if (stats == NULL) From 8edfec2cc3778a6fdebfa24c4f6eebe39af6c26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 21 Jul 2017 13:36:00 +0100 Subject: [PATCH 1372/1776] meson: skip tests on windows for now As we do in the other modules. As libgstcheck is currently not built on windows. Fixes "Fallback variable 'gst_check_dep' in the subproject 'gstreamer' does not exist"" Meson error. --- tests/meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/meson.build b/tests/meson.build index 0e2c8874df..cd3aa67d06 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1 +1,3 @@ -subdir('check') +if host_machine.system() != 'windows' + subdir('check') +endif From b648caac43af76b03b85a1bd676b09a145d8f54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 10 Aug 2017 14:20:12 +0100 Subject: [PATCH 1373/1776] pkgconfig: remove -I@srcdir@/.. which duplicates abs_top_srcdir Fixes meson warning about undefined @srcdir@. --- pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in index 5c2df0ab03..38e1df819a 100644 --- a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in +++ b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in @@ -9,4 +9,4 @@ Description: GStreamer based RTSP server Version: @VERSION@ Requires: gstreamer-@GST_API_VERSION@ gstreamer-plugins-base-@GST_API_VERSION@ Libs: -L${libdir} -lgstrtspserver-@GST_API_VERSION@ -Cflags: -I@abs_top_srcdir@ -I@abs_top_builddir@ -I@srcdir@/.. +Cflags: -I@abs_top_srcdir@ -I@abs_top_builddir@ From 3452c5d4c62f6b50e368394ae2f66901ed0a030a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 11 Aug 2017 14:14:32 +0100 Subject: [PATCH 1374/1776] meson: hide symbols by default unless explicitly exported --- meson.build | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/meson.build b/meson.build index bedbc0fe96..05e5776749 100644 --- a/meson.build +++ b/meson.build @@ -25,6 +25,13 @@ libversion = '@0@.@1@.0'.format(soversion, gst_version_minor.to_int() * 100 + gs plugins_install_dir = '@0@/gstreamer-1.0'.format(get_option('libdir')) +cc = meson.get_compiler('c') + +# Symbol visibility +if cc.has_argument('-fvisibility=hidden') + add_project_arguments('-fvisibility=hidden', language: 'c') +endif + cdata = configuration_data() cdata.set_quoted('GETTEXT_PACKAGE', 'gst-rtsp-server-1.0') cdata.set_quoted('PACKAGE', 'gst-rtsp-server') From ffbabb1529b8b4e39001b004d185bf326a5721cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 14 Aug 2017 21:04:23 +0300 Subject: [PATCH 1375/1776] rtsp-client: Fix typo in debug message --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index cf78b17578..f007bd5db9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1412,7 +1412,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) /* ERRORS */ no_session: { - GST_ERROR ("client %p: no seesion", client); + GST_ERROR ("client %p: no session", client); send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); return FALSE; } From 7f68de02cc20a95567cc41c250c6c71efd1fd2a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 17 Aug 2017 12:26:17 +0100 Subject: [PATCH 1376/1776] Automatic update of common submodule From 48a5d85 to 3f4aa96 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 48a5d85ebf..3f4aa969cb 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 48a5d85ebf4a0bad1c997c83100f710fe2154fbf +Subproject commit 3f4aa969cbe39584a649d98d4cf321d78bd73092 From fdd6479f4bf5aeb8fa13303cda5959525f8183e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 18 Aug 2017 17:37:01 +0100 Subject: [PATCH 1377/1776] meson: don't install -uninstalled.pc file https://bugzilla.gnome.org/show_bug.cgi?id=786457 --- pkgconfig/meson.build | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pkgconfig/meson.build b/pkgconfig/meson.build index f10d572464..8ed8299514 100644 --- a/pkgconfig/meson.build +++ b/pkgconfig/meson.build @@ -17,11 +17,8 @@ pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir')) configure_file(input : 'gstreamer-rtsp-server.pc.in', output : 'gstreamer-rtsp-server-1.0.pc', configuration : pkgconf, - install_dir : pkg_install_dir, -) + install_dir : pkg_install_dir) configure_file(input : 'gstreamer-rtsp-server-uninstalled.pc.in', output : 'gstreamer-rtsp-server-1.0-uninstalled.pc', - configuration : pkgconf, - install_dir : pkg_install_dir -) + configuration : pkgconf) From d690fbd37dccbc7970529ad41bcf633282c09c78 Mon Sep 17 00:00:00 2001 From: Satya Prakash Gupta Date: Thu, 31 Aug 2017 13:24:15 +0530 Subject: [PATCH 1378/1776] sdp: fix Memory leak in error case https://bugzilla.gnome.org/show_bug.cgi?id=787059 --- gst/rtsp-server/rtsp-sdp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 0380f3e2ad..b037b2873d 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -128,6 +128,7 @@ mikey_add_crypto_sessions (GstRTSPStream * stream, GstMIKEYMessage * msg) session = gst_rtsp_stream_get_rtpsession (stream); if (session == NULL) { GST_ERROR ("unable to get RTP session from stream %p", stream); + gst_object_unref (encoder); return FALSE; } From f1088f368fd5a3d5b5f16896cea8d2f32a30fe30 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 18 Sep 2017 19:31:31 +0200 Subject: [PATCH 1379/1776] rtspclientsink: Use a mutex for protecting against concurrent send/receives This is a simple port of: * a722f6e8329032c6eda4865d6a07f4ba5981d7ea * c438545dc9e2f14f657bc0ef261fff726449867b * cd17c71dcea5c9310d21f1347c7520983e5869ac in gst-plugins-good. --- gst/rtsp-sink/gstrtspclientsink.c | 86 +++++++++++++++++++------------ gst/rtsp-sink/gstrtspclientsink.h | 3 ++ 2 files changed, 55 insertions(+), 34 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index b2aaec882e..3df5e0dc1e 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -666,6 +666,9 @@ gst_rtsp_client_sink_init (GstRTSPClientSink * sink) sink->state = GST_RTSP_STATE_INVALID; + g_mutex_init (&sink->conninfo.send_lock); + g_mutex_init (&sink->conninfo.recv_lock); + sink->internal_bin = (GstBin *) gst_bin_new ("rtspbin"); gst_element_set_locked_state (GST_ELEMENT_CAST (sink->internal_bin), TRUE); gst_bin_add (GST_BIN (sink), GST_ELEMENT_CAST (sink->internal_bin)); @@ -714,6 +717,9 @@ gst_rtsp_client_sink_finalize (GObject * object) g_rec_mutex_clear (&rtsp_client_sink->stream_rec_lock); g_rec_mutex_clear (&rtsp_client_sink->state_rec_lock); + g_mutex_clear (&rtsp_client_sink->conninfo.send_lock); + g_mutex_clear (&rtsp_client_sink->conninfo.recv_lock); + g_mutex_clear (&rtsp_client_sink->send_lock); g_mutex_clear (&rtsp_client_sink->preroll_lock); @@ -1137,6 +1143,9 @@ gst_rtsp_client_sink_request_new_pad (GstElement * element, (void) gst_rtsp_client_sink_get_factories (); + g_mutex_init (&context->conninfo.send_lock); + g_mutex_init (&context->conninfo.recv_lock); + GST_RTSP_STATE_LOCK (sink); sink->contexts = g_list_prepend (sink->contexts, context); GST_RTSP_STATE_UNLOCK (sink); @@ -1182,6 +1191,9 @@ gst_rtsp_client_sink_release_pad (GstElement * element, GstPad * pad) g_free (context->conninfo.location); context->conninfo.location = NULL; + g_mutex_clear (&context->conninfo.send_lock); + g_mutex_clear (&context->conninfo.recv_lock); + g_free (context); gst_element_remove_pad (element, pad); @@ -1603,28 +1615,34 @@ gst_rtsp_client_sink_cleanup (GstRTSPClientSink * sink) static GstRTSPResult gst_rtsp_client_sink_connection_send (GstRTSPClientSink * sink, - GstRTSPConnection * conn, GstRTSPMessage * message, GTimeVal * timeout) + GstRTSPConnInfo * conninfo, GstRTSPMessage * message, GTimeVal * timeout) { GstRTSPResult ret; - if (conn) - ret = gst_rtsp_connection_send (conn, message, timeout); - else + if (conninfo->connection) { + g_mutex_lock (&conninfo->send_lock); + ret = gst_rtsp_connection_send (conninfo->connection, message, timeout); + g_mutex_unlock (&conninfo->send_lock); + } else { ret = GST_RTSP_ERROR; + } return ret; } static GstRTSPResult gst_rtsp_client_sink_connection_receive (GstRTSPClientSink * sink, - GstRTSPConnection * conn, GstRTSPMessage * message, GTimeVal * timeout) + GstRTSPConnInfo * conninfo, GstRTSPMessage * message, GTimeVal * timeout) { GstRTSPResult ret; - if (conn) - ret = gst_rtsp_connection_receive (conn, message, timeout); - else + if (conninfo->connection) { + g_mutex_lock (&conninfo->recv_lock); + ret = gst_rtsp_connection_receive (conninfo->connection, message, timeout); + g_mutex_unlock (&conninfo->recv_lock); + } else { ret = GST_RTSP_ERROR; + } return ret; } @@ -1793,7 +1811,7 @@ gst_rtsp_client_sink_init_request (GstRTSPClientSink * sink, /* FIXME, handle server request, reply with OK, for now */ static GstRTSPResult gst_rtsp_client_sink_handle_request (GstRTSPClientSink * sink, - GstRTSPConnection * conn, GstRTSPMessage * request) + GstRTSPConnInfo * conninfo, GstRTSPMessage * request) { GstRTSPMessage response = { 0 }; GstRTSPResult res; @@ -1818,7 +1836,7 @@ gst_rtsp_client_sink_handle_request (GstRTSPClientSink * sink, if (sink->debug) gst_rtsp_message_dump (&response); - res = gst_rtsp_client_sink_connection_send (sink, conn, &response, NULL); + res = gst_rtsp_client_sink_connection_send (sink, conninfo, &response, NULL); if (res < 0) goto send_error; @@ -1869,7 +1887,7 @@ gst_rtsp_client_sink_send_keep_alive (GstRTSPClientSink * sink) gst_rtsp_message_dump (&request); res = - gst_rtsp_client_sink_connection_send (sink, sink->conninfo.connection, + gst_rtsp_client_sink_connection_send (sink, &sink->conninfo, &request, NULL); if (res < 0) goto send_error; @@ -1920,7 +1938,7 @@ gst_rtsp_client_sink_loop_rx (GstRTSPClientSink * sink) * keep-alive request to keep the session open. */ res = gst_rtsp_client_sink_connection_receive (sink, - sink->conninfo.connection, &message, &tv_timeout); + &sink->conninfo, &message, &tv_timeout); switch (res) { case GST_RTSP_OK: @@ -1964,7 +1982,7 @@ gst_rtsp_client_sink_loop_rx (GstRTSPClientSink * sink) /* server sends us a request message, handle it */ res = gst_rtsp_client_sink_handle_request (sink, - sink->conninfo.connection, &message); + &sink->conninfo, &message); if (res == GST_RTSP_EEOF) goto server_eof; else if (res < 0) @@ -2479,7 +2497,7 @@ no_user_pass: static GstRTSPResult gst_rtsp_client_sink_try_send (GstRTSPClientSink * sink, - GstRTSPConnection * conn, GstRTSPMessage * request, + GstRTSPConnInfo * conninfo, GstRTSPMessage * request, GstRTSPMessage * response, GstRTSPStatusCode * code) { GstRTSPResult res; @@ -2496,14 +2514,14 @@ again: g_mutex_lock (&sink->send_lock); res = - gst_rtsp_client_sink_connection_send (sink, conn, request, + gst_rtsp_client_sink_connection_send (sink, conninfo, request, sink->ptcp_timeout); if (res < 0) { g_mutex_unlock (&sink->send_lock); goto send_error; } - gst_rtsp_connection_reset_timeout (conn); + gst_rtsp_connection_reset_timeout (conninfo->connection); /* See if we should handle the response */ if (response == NULL) { @@ -2512,7 +2530,7 @@ again: } next: res = - gst_rtsp_client_sink_connection_receive (sink, conn, response, + gst_rtsp_client_sink_connection_receive (sink, conninfo, response, sink->ptcp_timeout); g_mutex_unlock (&sink->send_lock); @@ -2526,7 +2544,7 @@ next: switch (response->type) { case GST_RTSP_MESSAGE_REQUEST: - res = gst_rtsp_client_sink_handle_request (sink, conn, response); + res = gst_rtsp_client_sink_handle_request (sink, conninfo, response); if (res == GST_RTSP_EEOF) goto server_eof; else if (res < 0) @@ -2663,7 +2681,7 @@ gst_rtsp_client_sink_set_state (GstRTSPClientSink * sink, GstState state) * Returns: #GST_RTSP_OK if the processing was successful. */ static GstRTSPResult -gst_rtsp_client_sink_send (GstRTSPClientSink * sink, GstRTSPConnection * conn, +gst_rtsp_client_sink_send (GstRTSPClientSink * sink, GstRTSPConnInfo * conninfo, GstRTSPMessage * request, GstRTSPMessage * response, GstRTSPStatusCode * code) { @@ -2685,7 +2703,7 @@ gst_rtsp_client_sink_send (GstRTSPClientSink * sink, GstRTSPConnection * conn, method = request->type_data.request.method; if ((res = - gst_rtsp_client_sink_try_send (sink, conn, request, response, + gst_rtsp_client_sink_try_send (sink, conninfo, request, response, &int_code)) < 0) goto error; @@ -2892,7 +2910,7 @@ gst_rtsp_client_sink_connect_to_server (GstRTSPClientSink * sink, ("Retrieving server options")); if ((res = - gst_rtsp_client_sink_send (sink, sink->conninfo.connection, &request, + gst_rtsp_client_sink_send (sink, &sink->conninfo, &request, &response, NULL)) < 0) goto send_error; @@ -3074,7 +3092,7 @@ gst_rtsp_client_sink_close (GstRTSPClientSink * sink, gboolean async, GST_ELEMENT_PROGRESS (sink, CONTINUE, "close", ("Closing stream")); if ((res = - gst_rtsp_client_sink_send (sink, info->connection, &request, + gst_rtsp_client_sink_send (sink, info, &request, &response, NULL)) < 0) goto send_error; @@ -3486,7 +3504,7 @@ do_send_data (GstBuffer * buffer, guint8 channel, gst_rtsp_message_take_body (&message, map_info.data, map_info.size); res = - gst_rtsp_client_sink_try_send (sink, sink->conninfo.connection, &message, + gst_rtsp_client_sink_try_send (sink, &sink->conninfo, &message, NULL, NULL); gst_rtsp_message_steal_body (&message, &data, &usize); @@ -3534,7 +3552,7 @@ gst_rtsp_client_sink_setup_streams (GstRTSPClientSink * sink, gboolean async) GstRTSPStreamContext *context = (GstRTSPStreamContext *) walk->data; GstRTSPStream *stream; - GstRTSPConnection *conn; + GstRTSPConnInfo *info; GstRTSPProfile profiles; GstRTSPProfile cur_profile; gchar *transports; @@ -3571,14 +3589,14 @@ gst_rtsp_client_sink_setup_streams (GstRTSPClientSink * sink, gboolean async) stream); continue; } - conn = context->conninfo.connection; + info = &context->conninfo; } else { - conn = sink->conninfo.connection; + info = &sink->conninfo; } GST_DEBUG_OBJECT (sink, "doing setup of stream %p with %s", stream, context->conninfo.location); - conn_socket = gst_rtsp_connection_get_read_socket (conn); + conn_socket = gst_rtsp_connection_get_read_socket (info->connection); sa = g_socket_get_local_address (conn_socket, NULL); family = g_socket_address_get_family (sa); g_object_unref (sa); @@ -3649,7 +3667,7 @@ gst_rtsp_client_sink_setup_streams (GstRTSPClientSink * sink, gboolean async) context->index)); /* handle the code ourselves */ - res = gst_rtsp_client_sink_send (sink, conn, &request, &response, &code); + res = gst_rtsp_client_sink_send (sink, info, &request, &response, &code); if (res < 0) goto send_error; @@ -3981,7 +3999,7 @@ gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async) ("Sending server stream info")); if ((res = - gst_rtsp_client_sink_send (sink, sink->conninfo.connection, &request, + gst_rtsp_client_sink_send (sink, &sink->conninfo, &request, &response, NULL)) < 0) goto send_error; @@ -4016,7 +4034,7 @@ gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async) if (async) GST_ELEMENT_PROGRESS (sink, CONTINUE, "record", ("Starting recording")); if ((res = - gst_rtsp_client_sink_send (sink, sink->conninfo.connection, &request, + gst_rtsp_client_sink_send (sink, &sink->conninfo, &request, &response, NULL)) < 0) goto send_error; @@ -4108,7 +4126,7 @@ gst_rtsp_client_sink_pause (GstRTSPClientSink * sink, gboolean async) * aggregate control */ for (walk = sink->contexts; walk; walk = g_list_next (walk)) { GstRTSPStreamContext *stream = (GstRTSPStreamContext *) walk->data; - GstRTSPConnection *conn; + GstRTSPConnInfo *info; const gchar *setup_url; /* try aggregate control first but do non-aggregate control otherwise */ @@ -4118,9 +4136,9 @@ gst_rtsp_client_sink_pause (GstRTSPClientSink * sink, gboolean async) continue; if (sink->conninfo.connection) { - conn = sink->conninfo.connection; + info = &sink->conninfo; } else if (stream->conninfo.connection) { - conn = stream->conninfo.connection; + info = &stream->conninfo; } else { continue; } @@ -4135,7 +4153,7 @@ gst_rtsp_client_sink_pause (GstRTSPClientSink * sink, gboolean async) goto create_request_failed; if ((res = - gst_rtsp_client_sink_send (sink, conn, &request, &response, + gst_rtsp_client_sink_send (sink, info, &request, &response, NULL)) < 0) goto send_error; diff --git a/gst/rtsp-sink/gstrtspclientsink.h b/gst/rtsp-sink/gstrtspclientsink.h index a8aef5ba78..b27daf86b8 100644 --- a/gst/rtsp-sink/gstrtspclientsink.h +++ b/gst/rtsp-sink/gstrtspclientsink.h @@ -86,6 +86,9 @@ struct _GstRTSPConnInfo { GstRTSPConnection *connection; gboolean connected; gboolean flushing; + + GMutex send_lock; + GMutex recv_lock; }; typedef struct _GstRTSPStreamInfo GstRTSPStreamInfo; From c04e3b07ddef74619367f5c7a2a664c664742096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 25 Sep 2017 19:40:17 +0300 Subject: [PATCH 1380/1776] rtsp-media-factory: Don't cache any media if NULL was returned as key The docs already mentioned this, but we actually stored it in the hash table with key==NULL and leaked its reference forever. --- gst/rtsp-server/rtsp-media-factory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index cecb8a02d8..fd99298df7 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -1216,7 +1216,7 @@ gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory, NULL); /* check if we can cache this media */ - if (gst_rtsp_media_is_shared (media)) { + if (gst_rtsp_media_is_shared (media) && key) { /* insert in the hashtable, takes ownership of the key */ g_object_ref (media); g_hash_table_insert (priv->medias, key, media); From 8b38aa9c468bc1cf7a232f4f372bf83efa67d328 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 2 Jun 2017 15:37:54 -0400 Subject: [PATCH 1381/1776] stream: Use stream duration as stream-stop if segment was not configured with a stop Allowing client to know stream duration when no seeking happened. https://bugzilla.gnome.org/show_bug.cgi?id=783435 --- gst/rtsp-server/rtsp-stream.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 6e8c97ad2b..25ff9c9f72 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -3852,7 +3852,20 @@ gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop) if (format != GST_FORMAT_TIME) *stop = -1; } + gst_query_unref (query); + if (!GST_CLOCK_TIME_IS_VALID (*stop)) { + query = gst_query_new_duration (GST_FORMAT_TIME); + if ((ret = gst_element_query (sink, query))) { + GstFormat format; + + gst_query_parse_duration (query, &format, stop); + if (format != GST_FORMAT_TIME) + *stop = -1; + } + gst_query_unref (query); + } + gst_object_unref (sink); return ret; From 9706199efb7d34b0dd7524567120def38e9e8f1d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 22 Apr 2017 09:26:07 -0300 Subject: [PATCH 1382/1776] Start support for RTSP 2.0 This adds basic support for new 2.0 features, though the protocol is subposdely backward incompatible, most semantics are the sames. This commit adds: - features: * version negotiation * pipelined requests support * Media-Properties support * Accept-Ranges support - APIs: * gst_rtsp_media_seekable The RTSP methods that have been removed when using 2.0 now return BAD_REQUEST. https://bugzilla.gnome.org/show_bug.cgi?id=781446 --- gst/rtsp-server/rtsp-client.c | 158 ++++++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-media.c | 144 ++++++++++++++++++++++--------- gst/rtsp-server/rtsp-media.h | 6 ++ 3 files changed, 261 insertions(+), 47 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f007bd5db9..2890407748 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -93,6 +93,11 @@ struct _GstRTSPClientPrivate guint rtsp_ctrl_timeout_id; guint rtsp_ctrl_timeout_cnt; + + /* The version currently being used */ + GstRTSPVersion version; + + GHashTable *pipelined_requests; /* pipelined_request_id -> session_id */ }; static GMutex tunnels_lock; @@ -528,6 +533,8 @@ gst_rtsp_client_init (GstRTSPClient * client) priv->transports = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); + priv->pipelined_requests = g_hash_table_new_full (g_str_hash, + g_str_equal, g_free, g_free); } static GstRTSPFilterResult @@ -800,6 +807,10 @@ send_message (GstRTSPClient * client, GstRTSPContext * ctx, if (close) gst_rtsp_message_add_header (message, GST_RTSP_HDR_CONNECTION, "close"); + if (ctx->request) + message->type_data.response.version = + ctx->request->type_data.request.version; + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE], 0, ctx, message); @@ -1251,6 +1262,12 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx) goto bad_request; if (size == 0 || !data || strlen ((char *) data) == 0) { + if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0) { + GST_ERROR_OBJECT (client, "Using PLAY request for keep-alive is forbidden" + " in RTSP 2.0"); + goto bad_request; + } + /* no body (or only '\0'), keep-alive request */ send_generic_response (client, GST_RTSP_STS_OK, ctx); } else { @@ -1498,6 +1515,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT; gchar *path, *rtpinfo; gint matched; + gchar *seek_style = NULL; GstRTSPStatusCode sig_result; if (!(session = ctx->session)) @@ -1546,10 +1564,26 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (res == GST_RTSP_OK) { if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) { GstRTSPMediaStatus media_status; + GstSeekFlags flags = 0; + + if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_SEEK_STYLE, + &seek_style, 0)) { + if (g_strcmp0 (seek_style, "RAP") == 0) + flags = GST_SEEK_FLAG_ACCURATE; + else if (g_strcmp0 (seek_style, "CoRAP") == 0) + flags = GST_SEEK_FLAG_KEY_UNIT; + else if (g_strcmp0 (seek_style, "First-Prior") == 0) + flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_BEFORE; + else if (g_strcmp0 (seek_style, "Next") == 0) + flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_AFTER; + else + GST_FIXME_OBJECT (client, "Add support for seek style %s", + seek_style); + } /* we have a range, seek to the position */ unit = range->unit; - gst_rtsp_media_seek (media, range); + gst_rtsp_media_seek_full (media, range, flags); gst_rtsp_range_free (range); media_status = gst_rtsp_media_get_status (media); @@ -1570,6 +1604,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (rtpinfo) gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO, rtpinfo); + if (seek_style) + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_SEEK_STYLE, + seek_style); /* add the range */ str = gst_rtsp_media_get_range_string (media, TRUE, unit); @@ -2208,6 +2245,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) gint matched; gboolean new_session = FALSE; GstRTSPStatusCode sig_result; + gchar *pipelined_request_id = NULL, *accept_range = NULL; if (!ctx->uri) goto no_uri; @@ -2223,6 +2261,11 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (res != GST_RTSP_OK) goto no_transport; + /* Handle Pipelined-requests if using >= 2.0 */ + if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0) + gst_rtsp_message_get_header (ctx->request, + GST_RTSP_HDR_PIPELINED_REQUESTS, &pipelined_request_id, 0); + /* we create the session after parsing stuff so that we don't make * a session for malformed requests */ if (priv->session_pool == NULL) @@ -2292,6 +2335,9 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!(session = gst_rtsp_session_pool_create (priv->session_pool))) goto service_unavailable; + /* Pipelined requests should be cleared between sessions */ + g_hash_table_remove_all (priv->pipelined_requests); + /* make sure this client is closed when the session is closed */ client_watch_session (client, session); @@ -2303,6 +2349,11 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->session = session; } + if (pipelined_request_id) { + g_hash_table_insert (client->priv->pipelined_requests, + g_strdup (pipelined_request_id), + g_strdup (gst_rtsp_session_get_sessionid (session))); + } rtsp_ctrl_timeout_remove (priv); if (!klass->configure_client_media (client, media, stream, ctx)) @@ -2328,6 +2379,33 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) goto keymgmt_error; } + if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_ACCEPT_RANGES, + &accept_range, 0) == GST_RTSP_OK) { + GEnumValue *runit = NULL; + gint i; + gchar **valid_ranges; + GEnumClass *runit_class = g_type_class_ref (GST_TYPE_RTSP_RANGE_UNIT); + + gst_rtsp_message_dump (ctx->request); + valid_ranges = g_strsplit (accept_range, ",", -1); + + for (i = 0; valid_ranges[i]; i++) { + gchar *range = valid_ranges[i]; + + while (*range == ' ') + range++; + + runit = g_enum_get_value_by_nick (runit_class, range); + if (runit) + break; + } + g_strfreev (valid_ranges); + g_type_class_unref (runit_class); + + if (!runit) + goto unsupported_range_unit; + } + if (sessmedia == NULL) { /* manage the media in our session now, if not done already */ sessmedia = @@ -2386,6 +2464,33 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) trans_str); g_free (trans_str); + if (pipelined_request_id) + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PIPELINED_REQUESTS, + pipelined_request_id); + + if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0) { + GstClockTimeDiff seekable = gst_rtsp_media_seekable (media); + GString *media_properties = g_string_new (NULL); + + if (seekable == -1) + g_string_append (media_properties, + "No-Seeking,Time-Progressing,Time-Duration=0.0"); + else if (seekable == 0) + g_string_append (media_properties, "Beginning-Only"); + else if (seekable == G_MAXINT64) + g_string_append (media_properties, "Random-Access"); + else + g_string_append_printf (media_properties, + "Random-Access=%f, Unlimited, Immutable", + (gdouble) seekable / GST_SECOND); + + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_MEDIA_PROPERTIES, + g_string_free (media_properties, FALSE)); + /* TODO Check how Accept-Ranges should be filled */ + gst_rtsp_message_add_header (ctx->request, GST_RTSP_HDR_ACCEPT_RANGES, + "npt, clock, smpte, clock"); + } + send_message (client, ctx, ctx->response, FALSE); /* update the state */ @@ -2505,6 +2610,13 @@ unsupported_mode: send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); goto cleanup_transport; } +unsupported_range_unit: + { + GST_ERROR ("Client %p: does not support any range format we support", + client); + send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx); + goto cleanup_transport; + } keymgmt_error: { GST_ERROR ("client %p: keymgmt error", client); @@ -3036,7 +3148,8 @@ unsuspend_failed: } static gboolean -handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx) +handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx, + GstRTSPVersion version) { GstRTSPMethod options; gchar *str; @@ -3046,10 +3159,14 @@ handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx) GST_RTSP_OPTIONS | GST_RTSP_PAUSE | GST_RTSP_PLAY | - GST_RTSP_RECORD | GST_RTSP_ANNOUNCE | GST_RTSP_SETUP | GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN; + if (version < GST_RTSP_VERSION_2_0) { + options |= GST_RTSP_RECORD; + options |= GST_RTSP_ANNOUNCE; + } + str = gst_rtsp_options_as_text (options); gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK, @@ -3209,7 +3326,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) GstRTSPContext sctx = { NULL }, *ctx; GstRTSPMessage response = { 0 }; gchar *unsupported_reqs = NULL; - gchar *sessid; + gchar *sessid = NULL, *pipelined_request_id = NULL; if (!(ctx = gst_rtsp_context_get_current ())) { ctx = &sctx; @@ -3233,7 +3350,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) gst_rtsp_version_as_text (version)); /* we can only handle 1.0 requests */ - if (version != GST_RTSP_VERSION_1_0) + if (version != GST_RTSP_VERSION_1_0 && version != GST_RTSP_VERSION_2_0) goto not_supported; ctx->method = method; @@ -3272,7 +3389,20 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) } /* get the session if there is any */ - res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); + res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_PIPELINED_REQUESTS, + &pipelined_request_id, 0); + if (res == GST_RTSP_OK) { + sessid = g_hash_table_lookup (client->priv->pipelined_requests, + pipelined_request_id); + + if (!sessid) + res = GST_RTSP_ERROR; + } + + if (res != GST_RTSP_OK) + res = + gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0); + if (res == GST_RTSP_OK) { if (priv->session_pool == NULL) goto no_pool; @@ -3334,7 +3464,8 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: - handle_options_request (client, ctx); + priv->version = version; + handle_options_request (client, ctx, version); break; case GST_RTSP_DESCRIBE: handle_describe_request (client, ctx); @@ -3358,9 +3489,13 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) handle_get_param_request (client, ctx); break; case GST_RTSP_ANNOUNCE: + if (version >= GST_RTSP_VERSION_2_0) + goto invalid_command_for_version; handle_announce_request (client, ctx); break; case GST_RTSP_RECORD: + if (version >= GST_RTSP_VERSION_2_0) + goto invalid_command_for_version; handle_record_request (client, ctx); break; case GST_RTSP_REDIRECT: @@ -3394,6 +3529,15 @@ not_supported: ctx); goto done; } +invalid_command_for_version: + { + if (priv->watch != NULL) + gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); + + GST_ERROR ("client %p: invalid command for version", client); + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + goto done; + } bad_request: { GST_ERROR ("client %p: bad request", client); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 996f453133..e4df4ea4d9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -125,7 +125,7 @@ struct _GstRTSPMediaPrivate GstNetTimeProvider *nettime; gboolean is_live; - gboolean seekable; + GstClockTimeDiff seekable; gboolean buffering; GstState target_state; @@ -661,6 +661,45 @@ default_create_rtpbin (GstRTSPMedia * media) return rtpbin; } +/* must be called with state lock */ +static void +check_seekable (GstRTSPMedia * media) +{ + GstQuery *query; + GstRTSPMediaPrivate *priv = media->priv; + + /* Update the seekable state of the pipeline in case it changed */ + if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) { + /* TODO: Seeking for RECORD? */ + priv->seekable = -1; + } else { + guint i, n = priv->streams->len; + + for (i = 0; i < n; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + + if (gst_rtsp_stream_get_publish_clock_mode (stream) == + GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET) { + priv->seekable = -1; + return; + } + } + } + + query = gst_query_new_seeking (GST_FORMAT_TIME); + if (gst_element_query (priv->pipeline, query)) { + GstFormat format; + gboolean seekable; + gint64 start, end; + + gst_query_parse_seeking (query, &format, &seekable, &start, &end); + priv->seekable = seekable ? G_MAXINT64 : 0.0; + } + + gst_query_unref (query); +} + + /* must be called with state lock */ static void collect_media_stats (GstRTSPMedia * media) @@ -730,6 +769,8 @@ collect_media_stats (GstRTSPMedia * media) priv->range.max.seconds = ((gdouble) stop) / GST_SECOND; priv->range_stop = stop; } + + check_seekable (media); } } @@ -2114,9 +2155,10 @@ gst_rtsp_media_get_status (GstRTSPMedia * media) } /** - * gst_rtsp_media_seek: + * gst_rtsp_media_seek_full: * @media: a #GstRTSPMedia * @range: (transfer none): a #GstRTSPTimeRange + * @flags: The minimal set of #GstSeekFlags to use * * Seek the pipeline of @media to @range. @media must be prepared with * gst_rtsp_media_prepare(). @@ -2124,14 +2166,14 @@ gst_rtsp_media_get_status (GstRTSPMedia * media) * Returns: %TRUE on success. */ gboolean -gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) +gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, + GstSeekFlags flags) { GstRTSPMediaClass *klass; GstRTSPMediaPrivate *priv; gboolean res; GstClockTime start, stop; GstSeekType start_type, stop_type; - GstQuery *query; gint64 current_position; klass = GST_RTSP_MEDIA_GET_CLASS (media); @@ -2147,37 +2189,16 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) goto not_prepared; /* Update the seekable state of the pipeline in case it changed */ - if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) { - /* TODO: Seeking for RECORD? */ - priv->seekable = FALSE; - } else { - guint i, n = priv->streams->len; + check_seekable (media); - for (i = 0; i < n; i++) { - GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + if (priv->seekable == 0) { + GST_FIXME_OBJECT (media, "Handle going back to 0 for none live" + " not seekable streams."); - if (gst_rtsp_stream_get_publish_clock_mode (stream) == - GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET) { - priv->seekable = FALSE; - goto not_seekable; - } - } - - query = gst_query_new_seeking (GST_FORMAT_TIME); - if (gst_element_query (priv->pipeline, query)) { - GstFormat format; - gboolean seekable; - gint64 start, end; - - gst_query_parse_seeking (query, &format, &seekable, &start, &end); - priv->seekable = seekable; - } - - gst_query_unref (query); - } - - if (!priv->seekable) goto not_seekable; + } else if (priv->seekable < 0) { + goto not_seekable; + } start_type = stop_type = GST_SEEK_TYPE_NONE; @@ -2205,14 +2226,18 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) stop_type = GST_SEEK_TYPE_SET; if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) { - GstSeekFlags flags; + gboolean had_flags = flags != 0; GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); /* depends on the current playing state of the pipeline. We might need to * queue this until we get EOS. */ - flags = GST_SEEK_FLAG_FLUSH; + if (had_flags) + flags |= GST_SEEK_FLAG_FLUSH; + else + flags = GST_SEEK_FLAG_FLUSH; + /* if range start was not supplied we must continue from current position. * but since we're doing a flushing seek, let us query the current position @@ -2225,12 +2250,14 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) GST_TIME_ARGS (current_position)); start = current_position; start_type = GST_SEEK_TYPE_SET; - flags |= GST_SEEK_FLAG_ACCURATE; + if (!had_flags) + flags |= GST_SEEK_FLAG_ACCURATE; } } else { /* only set keyframe flag when modifying start */ if (start_type != GST_SEEK_TYPE_NONE) - flags |= GST_SEEK_FLAG_KEY_UNIT; + if (!had_flags) + flags |= GST_SEEK_FLAG_KEY_UNIT; } if (start == current_position && stop_type == GST_SEEK_TYPE_NONE) { @@ -2300,6 +2327,24 @@ preroll_failed: } } + +/** + * gst_rtsp_media_seek: + * @media: a #GstRTSPMedia + * @range: (transfer none): a #GstRTSPTimeRange + * + * Seek the pipeline of @media to @range. @media must be prepared with + * gst_rtsp_media_prepare(). + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) +{ + return gst_rtsp_media_seek_full (media, range, 0); +} + + static void stream_collect_blocking (GstRTSPStream * stream, gboolean * blocked) { @@ -2675,18 +2720,16 @@ start_preroll (GstRTSPMedia * media) switch (ret) { case GST_STATE_CHANGE_SUCCESS: GST_INFO ("SUCCESS state change for media %p", media); - priv->seekable = TRUE; break; case GST_STATE_CHANGE_ASYNC: GST_INFO ("ASYNC state change for media %p", media); - priv->seekable = TRUE; break; case GST_STATE_CHANGE_NO_PREROLL: /* we need to go to PLAYING */ GST_INFO ("NO_PREROLL state change: live media %p", media); /* FIXME we disable seeking for live streams for now. We should perform a * seeking query in preroll instead */ - priv->seekable = FALSE; + priv->seekable = -1; priv->is_live = TRUE; if (!(priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) { /* start blocked to make sure nothing goes to the sink */ @@ -2953,7 +2996,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) /* reset some variables */ priv->is_live = FALSE; - priv->seekable = FALSE; + priv->seekable = -1; priv->buffering = FALSE; /* we're preparing now */ @@ -3937,3 +3980,24 @@ gst_rtsp_media_get_transport_mode (GstRTSPMedia * media) return res; } + +/** + * gst_rtsp_media_get_seekbale: + * @media: a #GstRTSPMedia + * + * Check if the pipeline for @media seek and up to what point in time, + * it can seek. + * + * Returns: -1 if the stream is not seekable, 0 if seekable only to the beginning + * and > 0 to indicate the longest duration between any two random access points. + * G_MAXINT64 means any value is possible. + */ +GstClockTimeDiff +gst_rtsp_media_seekable (GstRTSPMedia * media) +{ + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + /* Currently we are not able to seek on live streams, + * and no stream is seekable only to the beginning */ + return media->priv->seekable; +} diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 9f95e5b624..9c63d8f710 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -362,6 +362,12 @@ GstRTSPStream * gst_rtsp_media_find_stream (GstRTSPMedia *media, cons GST_EXPORT gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range); +gboolean gst_rtsp_media_seek_full (GstRTSPMedia *media, + GstRTSPTimeRange *range, + GstSeekFlags flags); + +GST_EXPORT +GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia *media); GST_EXPORT gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, From f053781dd5958ae4951410af8bf2491b49fdf50b Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 6 Oct 2017 10:27:34 +0200 Subject: [PATCH 1383/1776] win32: Update export file --- win32/common/libgstrtspserver.def | 2 ++ 1 file changed, 2 insertions(+) diff --git a/win32/common/libgstrtspserver.def b/win32/common/libgstrtspserver.def index 93f12fa10d..68601bfead 100644 --- a/win32/common/libgstrtspserver.def +++ b/win32/common/libgstrtspserver.def @@ -125,6 +125,8 @@ EXPORTS gst_rtsp_media_new gst_rtsp_media_prepare gst_rtsp_media_seek + gst_rtsp_media_seek_full + gst_rtsp_media_seekable gst_rtsp_media_set_address_pool gst_rtsp_media_set_buffer_size gst_rtsp_media_set_clock From 8608c1cae4d5621a5a7cf4618d835abaa6962cb2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 9 Oct 2017 14:44:40 +0200 Subject: [PATCH 1384/1776] rtsp-media: Initialize scalar variable CID 1418985 --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e4df4ea4d9..058fa9073a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -625,7 +625,7 @@ typedef struct static void do_query_stop (GstRTSPStream * stream, DoQueryStopData * data) { - gint64 tmp; + gint64 tmp = 0; if (gst_rtsp_stream_query_stop (stream, &tmp)) { data->stop = MAX (data->stop, tmp); From 619ac7b710e6fc7b83cb995d70433a65d7714101 Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Mon, 9 Oct 2017 12:43:01 +0200 Subject: [PATCH 1385/1776] rtsp-client: unref 'pipelined_requests' in finalize The hash table priv->pipelined_requests is not unref:ed in the finalize funktion. Make sure it is. https://bugzilla.gnome.org/show_bug.cgi?id=788704 --- gst/rtsp-server/rtsp-client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 2890407748..45d178a808 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -696,6 +696,7 @@ gst_rtsp_client_finalize (GObject * obj) g_assert (priv->session_removed_id == 0); g_hash_table_unref (priv->transports); + g_hash_table_unref (priv->pipelined_requests); if (priv->connection) gst_rtsp_connection_free (priv->connection); From 89ccaa6932076e634481affef587f2756c577fa8 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 26 Oct 2017 14:43:19 +0200 Subject: [PATCH 1386/1776] docs: add media factory transport mode accessors and fix the documentation for the return value of the getter --- docs/libs/gst-rtsp-server-sections.txt | 3 +++ gst/rtsp-server/rtsp-media-factory.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 38e2d031a2..f57bc58d3b 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -256,6 +256,9 @@ gst_rtsp_media_factory_set_eos_shutdown gst_rtsp_media_factory_get_protocols gst_rtsp_media_factory_set_protocols +gst_rtsp_media_factory_get_transport_mode +gst_rtsp_media_factory_set_transport_mode + gst_rtsp_media_factory_set_profiles gst_rtsp_media_factory_get_profiles diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index fd99298df7..f610a244c9 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -1644,7 +1644,7 @@ gst_rtsp_media_factory_set_transport_mode (GstRTSPMediaFactory * factory, * Get if media created from this factory can be used for PLAY or RECORD * methods. * - * Returns: The supported transport modes. + * Returns: The transport mode. */ GstRTSPTransportMode gst_rtsp_media_factory_get_transport_mode (GstRTSPMediaFactory * factory) From c3e53322d934af47e697c94945112f06572555e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 17 Jul 2017 17:15:22 +0300 Subject: [PATCH 1387/1776] rtspclientsink: Add "accept-certificate" signal for manually checking a TLS certificate for validity https://bugzilla.gnome.org/show_bug.cgi?id=785024 --- gst/rtsp-sink/gstrtspclientsink.c | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 3df5e0dc1e..73ca9db524 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -116,6 +116,7 @@ enum SIGNAL_NEW_MANAGER, SIGNAL_NEW_PAYLOADER, SIGNAL_REQUEST_RTCP_KEY, + SIGNAL_ACCEPT_CERTIFICATE, LAST_SIGNAL }; @@ -605,6 +606,27 @@ gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) g_signal_new ("request-rtcp-key", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, GST_TYPE_CAPS, 1, G_TYPE_UINT); + /** + * GstRTSPClientSink::accept-certificate: + * @rtsp_client_sink: a #GstRTSPClientSink + * @peer_cert: the peer's #GTlsCertificate + * @errors: the problems with @peer_cert + * @user_data: user data set when the signal handler was connected. + * + * This will directly map to #GTlsConnection 's "accept-certificate" + * signal and be performed after the default checks of #GstRTSPConnection + * (checking against the #GTlsDatabase with the given #GTlsCertificateFlags) + * have failed. If no #GTlsDatabase is set on this connection, only this + * signal will be emitted. + * + * Since: 1.14 + */ + gst_rtsp_client_sink_signals[SIGNAL_ACCEPT_CERTIFICATE] = + g_signal_new ("accept-certificate", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, g_signal_accumulator_true_handled, NULL, NULL, + G_TYPE_BOOLEAN, 3, G_TYPE_TLS_CONNECTION, G_TYPE_TLS_CERTIFICATE, + G_TYPE_TLS_CERTIFICATE_FLAGS); + gstelement_class->provide_clock = gst_rtsp_client_sink_provide_clock; gstelement_class->change_state = gst_rtsp_client_sink_change_state; gstelement_class->request_new_pad = @@ -1647,6 +1669,19 @@ gst_rtsp_client_sink_connection_receive (GstRTSPClientSink * sink, return ret; } +static gboolean +accept_certificate_cb (GTlsConnection * conn, GTlsCertificate * peer_cert, + GTlsCertificateFlags errors, gpointer user_data) +{ + GstRTSPClientSink *sink = user_data; + gboolean accept = FALSE; + + g_signal_emit (sink, gst_rtsp_client_sink_signals[SIGNAL_ACCEPT_CERTIFICATE], + 0, conn, peer_cert, errors, &accept); + + return accept; +} + static GstRTSPResult gst_rtsp_conninfo_connect (GstRTSPClientSink * sink, GstRTSPConnInfo * info, gboolean async) @@ -1683,6 +1718,9 @@ gst_rtsp_conninfo_connect (GstRTSPClientSink * sink, GstRTSPConnInfo * info, if (sink->tls_interaction) gst_rtsp_connection_set_tls_interaction (info->connection, sink->tls_interaction); + + gst_rtsp_connection_set_accept_certificate_func (info->connection, + accept_certificate_cb, sink, NULL); } if (info->url->transports & GST_RTSP_LOWER_TRANS_HTTP) From 0f87202a71e5560491be66182773e923f7b094ab Mon Sep 17 00:00:00 2001 From: Jonathan Karlsson Date: Wed, 9 Aug 2017 11:52:38 +0200 Subject: [PATCH 1388/1776] rtsp-session: Handle the case when timeout=0 According to the documentation, a timeout of value 0 means that the session never timeouts. This adds handling of that. If timeout=0 we just return with a -1 from gst_rtsp_session_next_timeout_usec (). https://bugzilla.gnome.org/show_bug.cgi?id=785058 --- gst/rtsp-server/rtsp-session.c | 9 +++++++++ tests/check/gst/rtspserver.c | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index e6faaf5239..e8fd68b19c 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -69,6 +69,7 @@ struct _GstRTSPSessionPrivate #undef DEBUG #define DEFAULT_TIMEOUT 60 +#define NO_TIMEOUT -1 #define DEFAULT_ALWAYS_VISIBLE FALSE enum @@ -634,6 +635,14 @@ gst_rtsp_session_next_timeout_usec (GstRTSPSession * session, gint64 now) priv = session->priv; + g_mutex_lock (&priv->lock); + /* If timeout is set to 0, we never timeout */ + if (priv->timeout == 0) { + g_mutex_unlock (&priv->lock); + return NO_TIMEOUT; + } + g_mutex_unlock (&priv->lock); + g_mutex_lock (&priv->last_access_lock); if (g_atomic_int_get (&priv->expire_count) != 0) { /* touch session when the expire count is not 0 */ diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 1a92d52bce..7f636f5fad 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1559,6 +1559,27 @@ GST_START_TEST (test_play_multithreaded_timeout_session) GST_END_TEST; +GST_START_TEST (test_no_session_timeout) +{ + GstRTSPSession *session; + gint64 now; + gboolean is_expired; + + session = gst_rtsp_session_new ("test-session"); + gst_rtsp_session_set_timeout (session, 0); + + now = g_get_monotonic_time (); + /* add more than the extra 5 seconds that are usually added in + * gst_rtsp_session_next_timeout_usec */ + now += 7000000; + + is_expired = gst_rtsp_session_is_expired_usec (session, now); + fail_unless (is_expired == FALSE); +} + +GST_END_TEST; + + GST_START_TEST (test_play_disconnect) { GstRTSPConnection *conn; @@ -2118,6 +2139,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_play_multithreaded_block_in_describe); tcase_add_test (tc, test_play_multithreaded_timeout_client); tcase_add_test (tc, test_play_multithreaded_timeout_session); + tcase_add_test (tc, test_no_session_timeout); tcase_add_test (tc, test_play_disconnect); tcase_add_test (tc, test_play_specific_server_port); tcase_add_test (tc, test_play_smpte_range); From b5c3ef8d53e0768ee4677887bb4808ef1f169ca0 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Mon, 16 Oct 2017 10:10:17 +0200 Subject: [PATCH 1389/1776] rtsp-media: return minimum value in query position case The minimum position should be returned as we are interested in the whole interval. Change-Id: I30e297fc040c995ae40c25dee8ff56321612fe2b https://bugzilla.gnome.org/show_bug.cgi?id=788340 --- gst/rtsp-server/rtsp-media.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 058fa9073a..d3a1f5a2f8 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -593,9 +593,12 @@ do_query_position (GstRTSPStream * stream, DoQueryPositionData * data) gint64 tmp; if (gst_rtsp_stream_query_position (stream, &tmp)) { - data->position = MAX (data->position, tmp); + data->position = MIN (data->position, tmp); data->ret = TRUE; } + + GST_INFO_OBJECT (stream, "media position: %" GST_TIME_FORMAT, + GST_TIME_ARGS (data->position)); } static gboolean @@ -606,12 +609,15 @@ default_query_position (GstRTSPMedia * media, gint64 * position) priv = media->priv; - data.position = -1; + data.position = G_MAXINT64; data.ret = FALSE; g_ptr_array_foreach (priv->streams, (GFunc) do_query_position, &data); - *position = data.position; + if (!data.ret) + *position = GST_CLOCK_TIME_NONE; + else + *position = data.position; return data.ret; } From c9605cc5e1c36a2839df389d5fa002aaef43f786 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Fri, 20 Oct 2017 12:21:48 +0200 Subject: [PATCH 1390/1776] stream: set async=sync=false only for RTCP appsink Change-Id: I929a218a9adf4759f61322b6f2063aacc5595f90 https://bugzilla.gnome.org/show_bug.cgi?id=788340 --- gst/rtsp-server/rtsp-stream.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 25ff9c9f72..2551895a2c 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2463,7 +2463,8 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) &priv->mcast_udpqueue[i]); if (is_tcp) { - g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); + if (i == 1) + g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); plug_sink (bin, priv->tee[i], priv->appsink[i], &priv->appqueue[i]); } } else if (is_tcp) { From 51d670f73bb4d4fd8fbfde2daf191bc8f7a74218 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Mon, 16 Oct 2017 11:15:55 +0200 Subject: [PATCH 1391/1776] rtsp-stream: add functions to get rtp and rtcp multicast sockets Change-Id: Iddfe6e0bd250cb0159096d5eba9e4202d22b56db https://bugzilla.gnome.org/show_bug.cgi?id=788340 --- gst/rtsp-server/rtsp-stream.c | 64 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 8 +++++ 2 files changed, 72 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 2551895a2c..90eb825984 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -3545,6 +3545,70 @@ gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) return socket; } +/** + * gst_rtsp_stream_get_rtp_multicast_socket: + * @stream: a #GstRTSPStream + * @family: the socket family + * + * Get the multicast RTP socket from @stream for a @family. + * + * Returns: (transfer full) (nullable): the multicast RTP socket or %NULL if no + * socket could be allocated for @family. Unref after usage + */ +GSocket * +gst_rtsp_stream_get_rtp_multicast_socket (GstRTSPStream * stream, GSocketFamily family) +{ + GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); + GSocket *socket; + const gchar *name; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 || + family == G_SOCKET_FAMILY_IPV6, NULL); + g_return_val_if_fail (priv->mcast_udpsink[0], NULL); + + if (family == G_SOCKET_FAMILY_IPV6) + name = "socket-v6"; + else + name = "socket"; + + g_object_get (priv->mcast_udpsink[0], name, &socket, NULL); + + return socket; +} + +/** + * gst_rtsp_stream_get_rtcp_multicast_socket: + * @stream: a #GstRTSPStream + * @family: the socket family + * + * Get the multicast RTCP socket from @stream for a @family. + * + * Returns: (transfer full) (nullable): the multicast RTCP socket or %NULL if no + * socket could be allocated for @family. Unref after usage + */ +GSocket * +gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream * stream, GSocketFamily family) +{ + GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); + GSocket *socket; + const gchar *name; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 || + family == G_SOCKET_FAMILY_IPV6, NULL); + g_return_val_if_fail (priv->mcast_udpsink[1], NULL); + + if (family == G_SOCKET_FAMILY_IPV6) + name = "socket-v6"; + else + name = "socket"; + + g_object_get (priv->mcast_udpsink[1], name, &socket, NULL); + + return socket; +} + /** * gst_rtsp_stream_set_seqnum: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index a934ab58cd..7aa1aa2d3f 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -219,6 +219,14 @@ GST_EXPORT GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream *stream, GSocketFamily family); +GST_EXPORT +GSocket * gst_rtsp_stream_get_rtp_multicast_socket (GstRTSPStream *stream, + GSocketFamily family); + +GST_EXPORT +GSocket * gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream *stream, + GSocketFamily family); + GST_EXPORT gboolean gst_rtsp_stream_update_crypto (GstRTSPStream * stream, guint ssrc, GstCaps * crypto); From 5ec1b809895b35d103fbef5f20ebef0ddefd2c59 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Mon, 16 Oct 2017 11:35:10 +0200 Subject: [PATCH 1392/1776] rtsp-session-media: add function to get a list of transports Change-Id: I817e10624da0f3200f24d1b232cff481099278e3 https://bugzilla.gnome.org/show_bug.cgi?id=788340 --- gst/rtsp-server/rtsp-session-media.c | 24 ++++++++++++++++++++++++ gst/rtsp-server/rtsp-session-media.h | 3 +++ 2 files changed, 27 insertions(+) diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 0fffbcab2e..96ad1b63be 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -407,6 +407,30 @@ gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx) return result; } +/** + * gst_rtsp_session_media_get_transports: + * @media: a #GstRTSPSessionMedia + * + * Get a list of all available #GstRTSPStreamTransport in this session. + * + * Returns: (transfer full): a list of #GstRTSPStreamTransport, + * g_ptr_array_unref () after usage. + */ +GPtrArray * +gst_rtsp_session_media_get_transports (GstRTSPSessionMedia * media) +{ + GstRTSPSessionMediaPrivate *priv; + GPtrArray *result; + + g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL); + priv = media->priv; + + g_mutex_lock (&priv->lock); + result = g_ptr_array_ref (priv->transports); + g_mutex_unlock (&priv->lock); + + return result; +} /** * gst_rtsp_session_media_alloc_channels: * @media: a #GstRTSPSessionMedia diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 612173bdf2..2a6fe2aa22 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -102,6 +102,9 @@ GST_EXPORT GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia *media, guint idx); +GST_EXPORT +GPtrArray * gst_rtsp_session_media_get_transports (GstRTSPSessionMedia *media); + GST_EXPORT gboolean gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia *media, GstRTSPRange *range); From 930a602e17e4bfdf55522011d3d132bc6777452b Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Mon, 16 Oct 2017 12:40:57 +0200 Subject: [PATCH 1393/1776] rtsp-stream: obtain stream position from pad If no sinks have been added yet, obtain the current and the stop position of the stream from the send_src pad. Change-Id: Iacd4ab4bdc69f6b49370d06012880ce48a7d595a https://bugzilla.gnome.org/show_bug.cgi?id=788340 --- gst/rtsp-server/rtsp-stream.c | 149 ++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 35 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 90eb825984..ea4f034a0c 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -152,6 +152,9 @@ struct _GstRTSPStreamPrivate gulong blocked_id[2]; gboolean blocking; + /* current stream postion */ + GstClockTime position; + /* pt->caps map for RECORD streams */ GHashTable *ptmap; @@ -3746,6 +3749,7 @@ pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) { GstRTSPStreamPrivate *priv; GstRTSPStream *stream; + GstBuffer *buffer = NULL; stream = user_data; priv = stream->priv; @@ -3754,6 +3758,20 @@ pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) g_mutex_lock (&priv->lock); priv->blocking = TRUE; + + if ((info->type & GST_PAD_PROBE_TYPE_BUFFER)) { + buffer = gst_pad_probe_info_get_buffer (info); + } else if ((info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST)) { + GstBufferList *list = gst_pad_probe_info_get_buffer_list (info); + buffer = gst_buffer_list_get (list, 0); + } else { + g_assert_not_reached (); + } + + g_assert (buffer); + priv->position = GST_BUFFER_TIMESTAMP (buffer); + GST_DEBUG_OBJECT (stream, "buffer position: %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); g_mutex_unlock (&priv->lock); gst_element_post_message (priv->payloader, @@ -3835,6 +3853,7 @@ gst_rtsp_stream_is_blocking (GstRTSPStream * stream) /** * gst_rtsp_stream_query_position: * @stream: a #GstRTSPStream + * @position: current position of a #GstRTSPStream * * Query the position of the stream in %GST_FORMAT_TIME. This only considers * the RTP parts of the pipeline and not the RTCP parts. @@ -3846,36 +3865,74 @@ gst_rtsp_stream_query_position (GstRTSPStream * stream, gint64 * position) { GstRTSPStreamPrivate *priv; GstElement *sink; - gboolean ret; + GstPad *pad = NULL; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + /* query position: if no sinks have been added yet, + * we obtain the position from the pad otherwise we query the sinks */ + priv = stream->priv; g_mutex_lock (&priv->lock); /* depending on the transport type, it should query corresponding sink */ - if ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || - (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)) + if (priv->protocols & GST_RTSP_LOWER_TRANS_UDP) sink = priv->udpsink[0]; + else if (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) + sink = priv->mcast_udpsink[0]; else sink = priv->appsink[0]; - if (sink) + if (sink) { gst_object_ref (sink); + } else if (priv->send_src[0]) { + pad = gst_object_ref (priv->send_src[0]); + } else { + g_mutex_unlock (&priv->lock); + GST_WARNING_OBJECT (stream, "Couldn't obtain postion: erroneous pipeline"); + return FALSE; + } g_mutex_unlock (&priv->lock); - if (!sink) - return FALSE; + if (sink) { + if (!gst_element_query_position (sink , GST_FORMAT_TIME, position)) { + GST_WARNING_OBJECT (stream, "Couldn't obtain postion: position query failed"); + gst_object_unref (sink); + return FALSE; + } + gst_object_unref (sink); + } else if (pad) { + GstEvent *event; + const GstSegment *segment; - ret = gst_element_query_position (sink, GST_FORMAT_TIME, position); - gst_object_unref (sink); + event = gst_pad_get_sticky_event (pad, GST_EVENT_SEGMENT, 0); + if (!event) { + GST_WARNING_OBJECT (stream, "Couldn't obtain postion: no segment event"); + gst_object_unref (pad); + return FALSE; + } - return ret; + gst_event_parse_segment (event, &segment); + if (segment->format != GST_FORMAT_TIME) { + *position = -1; + } else { + g_mutex_lock (&priv->lock); + *position = priv->position; + g_mutex_unlock (&priv->lock); + *position = + gst_segment_to_stream_time (segment, GST_FORMAT_TIME, *position); + } + gst_event_unref (event); + gst_object_unref (pad); + } + + return TRUE; } /** * gst_rtsp_stream_query_stop: * @stream: a #GstRTSPStream + * @stop: current stop of a #GstRTSPStream * * Query the stop of the stream in %GST_FORMAT_TIME. This only considers * the RTP parts of the pipeline and not the RTCP parts. @@ -3887,52 +3944,74 @@ gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop) { GstRTSPStreamPrivate *priv; GstElement *sink; - GstQuery *query; - gboolean ret; + GstPad *pad = NULL; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + /* query stop position: if no sinks have been added yet, + * we obtain the stop position from the pad otherwise we query the sinks */ + priv = stream->priv; g_mutex_lock (&priv->lock); /* depending on the transport type, it should query corresponding sink */ - if ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || - (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)) + if (priv->protocols & GST_RTSP_LOWER_TRANS_UDP) sink = priv->udpsink[0]; + else if (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) + sink = priv->mcast_udpsink[0]; else sink = priv->appsink[0]; - if (sink) + if (sink) { gst_object_ref (sink); + } else if (priv->send_src[0]) { + pad = gst_object_ref (priv->send_src[0]); + } else { + g_mutex_unlock (&priv->lock); + GST_WARNING_OBJECT (stream, "Couldn't obtain stop: erroneous pipeline"); + return FALSE; + } g_mutex_unlock (&priv->lock); - if (!sink) - return FALSE; - - query = gst_query_new_segment (GST_FORMAT_TIME); - if ((ret = gst_element_query (sink, query))) { + if (sink) { + GstQuery *query; GstFormat format; + query = gst_query_new_segment (GST_FORMAT_TIME); + if (!gst_element_query (sink, query)) { + GST_WARNING_OBJECT (stream, "Couldn't obtain stop: element query failed"); + gst_query_unref (query); + gst_object_unref (sink); + return FALSE; + } gst_query_parse_segment (query, NULL, &format, NULL, stop); if (format != GST_FORMAT_TIME) *stop = -1; - } - - gst_query_unref (query); - if (!GST_CLOCK_TIME_IS_VALID (*stop)) { - query = gst_query_new_duration (GST_FORMAT_TIME); - if ((ret = gst_element_query (sink, query))) { - GstFormat format; - - gst_query_parse_duration (query, &format, stop); - if (format != GST_FORMAT_TIME) - *stop = -1; - } gst_query_unref (query); + gst_object_unref (sink); + } else if (pad) { + GstEvent *event; + const GstSegment *segment; + + event = gst_pad_get_sticky_event (pad, GST_EVENT_SEGMENT, 0); + if (!event) { + GST_WARNING_OBJECT (stream, "Couldn't obtain stop: no segment event"); + gst_object_unref (pad); + return FALSE; + } + gst_event_parse_segment (event, &segment); + if (segment->format != GST_FORMAT_TIME) { + *stop = -1; + } else { + *stop = segment->stop; + if (*stop == -1) + *stop = segment->duration; + else + *stop = gst_segment_to_stream_time (segment, GST_FORMAT_TIME, *stop); + } + gst_event_unref (event); + gst_object_unref (pad); } - gst_object_unref (sink); - - return ret; - + return TRUE; } From a7732a68e8bc6b4ba15629c652056c240c624ff0 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Tue, 17 Oct 2017 10:44:33 +0200 Subject: [PATCH 1394/1776] Dynamically reconfigure pipeline in PLAY based on transports The initial pipeline does not contain specific transport elements. The receiver and the sender parts are added after PLAY. If the media is shared, the streams are dynamically reconfigured after each PLAY. https://bugzilla.gnome.org/show_bug.cgi?id=788340 --- gst/rtsp-server/rtsp-client.c | 104 +++- gst/rtsp-server/rtsp-media.c | 109 +++- gst/rtsp-server/rtsp-media.h | 3 + gst/rtsp-server/rtsp-stream.c | 1020 ++++++++++++++++++++++++--------- gst/rtsp-server/rtsp-stream.h | 9 +- tests/check/gst/client.c | 3 - tests/check/gst/media.c | 103 +++- tests/check/gst/rtspserver.c | 259 +++++++++ tests/check/gst/stream.c | 75 ++- 9 files changed, 1341 insertions(+), 344 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 45d178a808..83131f34ef 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1518,6 +1518,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) gint matched; gchar *seek_style = NULL; GstRTSPStatusCode sig_result; + GPtrArray *transports; if (!(session = ctx->session)) goto no_session; @@ -1556,6 +1557,14 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY) goto invalid_state; + /* update the pipeline */ + transports = gst_rtsp_session_media_get_transports (sessmedia); + if (!gst_rtsp_media_complete_pipeline (media, transports)) { + g_ptr_array_unref (transports); + goto pipeline_error; + } + g_ptr_array_unref (transports); + /* in play we first unsuspend, media could be suspended from SDP or PAUSED */ if (!gst_rtsp_media_unsuspend (media)) goto unsuspend_failed; @@ -1666,6 +1675,13 @@ invalid_state: ctx); return FALSE; } +pipeline_error: + { + GST_ERROR ("client %p: failed to configure the pipeline", client); + send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, + ctx); + return FALSE; + } unsuspend_failed: { GST_ERROR ("client %p: unsuspend failed", client); @@ -1784,39 +1800,52 @@ default_configure_client_transport (GstRTSPClient * client, GstRTSPClientPrivate *priv = client->priv; /* we have a valid transport now, set the destination of the client. */ - if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - gboolean use_client_settings; + if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST || + ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP) { - use_client_settings = - gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS); + /* allocate UDP ports */ + GSocketFamily family; + gboolean use_client_settings = FALSE; - if (ct->destination && use_client_settings) { - GstRTSPAddress *addr; + family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; + if ((ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) && + gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS) && + (ct->destination != NULL)) + use_client_settings = TRUE; - addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination, - ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl); + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, + use_client_settings)) + goto error_allocating_ports; - if (addr == NULL) - goto no_address; + if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + GstRTSPAddress *addr = NULL; - gst_rtsp_address_free (addr); + if (use_client_settings) { + /* the address has been successfully allocated, let's check if it's + * the one requested by the client */ + addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination, + ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl); + + if (addr == NULL) + goto no_address; + } else { + g_free (ct->destination); + addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family); + if (addr == NULL) + goto no_address; + ct->destination = g_strdup (addr->address); + ct->port.min = addr->port; + ct->port.max = addr->port + addr->n_ports - 1; + ct->ttl = addr->ttl; + + gst_rtsp_address_free (addr); + } } else { - GstRTSPAddress *addr; - GSocketFamily family; - - family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; - - addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family); - if (addr == NULL) - goto no_address; + GstRTSPUrl *url; + url = gst_rtsp_connection_get_url (priv->connection); g_free (ct->destination); - ct->destination = g_strdup (addr->address); - ct->port.min = addr->port; - ct->port.max = addr->port + addr->n_ports - 1; - ct->ttl = addr->ttl; - - gst_rtsp_address_free (addr); + ct->destination = g_strdup (url->host); } } else { GstRTSPUrl *url; @@ -1863,9 +1892,14 @@ default_configure_client_transport (GstRTSPClient * client, return TRUE; /* ERRORS */ +error_allocating_ports: + { + GST_ERROR_OBJECT (client, "Failed to allocate UDP ports"); + return FALSE; + } no_address: { - GST_ERROR_OBJECT (client, "failed to acquire address for stream"); + GST_ERROR_OBJECT (client, "Failed to acquire address for stream"); return FALSE; } } @@ -3036,6 +3070,7 @@ handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *path; gint matched; GstRTSPStatusCode sig_result; + GPtrArray *transports; if (!(session = ctx->session)) goto no_session; @@ -3074,7 +3109,15 @@ handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx) if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY) goto invalid_state; - /* in play we first unsuspend, media could be suspended from SDP or PAUSED */ + /* update the pipeline */ + transports = gst_rtsp_session_media_get_transports (sessmedia); + if (!gst_rtsp_media_complete_pipeline (media, transports)) { + g_ptr_array_unref (transports); + goto pipeline_error; + } + g_ptr_array_unref (transports); + + /* in record we first unsuspend, media could be suspended from SDP or PAUSED */ if (!gst_rtsp_media_unsuspend (media)) goto unsuspend_failed; @@ -3140,6 +3183,13 @@ invalid_state: ctx); return FALSE; } +pipeline_error: + { + GST_ERROR ("client %p: failed to configure the pipeline", client); + send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, + ctx); + return FALSE; + } unsuspend_failed: { GST_ERROR ("client %p: unsuspend failed", client); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d3a1f5a2f8..159dd3d447 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2114,6 +2114,21 @@ media_streams_set_blocked (GstRTSPMedia * media, gboolean blocked) g_ptr_array_foreach (priv->streams, (GFunc) stream_update_blocked, media); } +static void +stream_unblock (GstRTSPStream * stream, GstRTSPMedia * media) +{ + gst_rtsp_stream_unblock_linked (stream); +} + +static void +media_unblock_linked (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + + GST_DEBUG ("media %p unblocking linked streams", media); + g_ptr_array_foreach (priv->streams, (GFunc) stream_unblock, media); +} + static void gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status) { @@ -2526,8 +2541,6 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) GST_INFO ("%p: ignoring ASYNC_DONE", media); } else { GST_INFO ("%p: got ASYNC_DONE", media); - collect_media_stats (media); - if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); } @@ -2642,6 +2655,9 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) GST_WARNING ("failed to join bin element"); } + if (priv->blocked) + gst_rtsp_stream_set_blocked (stream, TRUE); + priv->adding = FALSE; g_rec_mutex_unlock (&priv->state_lock); @@ -2720,7 +2736,9 @@ start_preroll (GstRTSPMedia * media) GstStateChangeReturn ret; GST_INFO ("setting pipeline to PAUSED for media %p", media); - /* first go to PAUSED */ + + /* start blocked since it is possible that there are no sink elements yet */ + media_streams_set_blocked (media, TRUE); ret = set_target_state (media, GST_STATE_PAUSED, TRUE); switch (ret) { @@ -2737,10 +2755,7 @@ start_preroll (GstRTSPMedia * media) * seeking query in preroll instead */ priv->seekable = -1; priv->is_live = TRUE; - if (!(priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) { - /* start blocked to make sure nothing goes to the sink */ - media_streams_set_blocked (media, TRUE); - } + ret = set_state (media, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; @@ -3100,6 +3115,8 @@ finish_unprepare (GstRTSPMedia * media) set_state (media, GST_STATE_NULL); g_rec_mutex_lock (&priv->state_lock); + media_streams_set_blocked (media, FALSE); + if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARING) return; @@ -3209,8 +3226,6 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media) goto is_busy; GST_INFO ("unprepare media %p", media); - if (priv->blocked) - media_streams_set_blocked (media, FALSE); set_target_state (media, GST_STATE_NULL, FALSE); success = TRUE; @@ -3563,7 +3578,6 @@ default_suspend (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; GstStateChangeReturn ret; - gboolean unblock = FALSE; switch (priv->suspend_mode) { case GST_RTSP_SUSPEND_MODE_NONE: @@ -3574,7 +3588,6 @@ default_suspend (GstRTSPMedia * media) ret = set_target_state (media, GST_STATE_PAUSED, TRUE); if (ret == GST_STATE_CHANGE_FAILURE) goto state_failed; - unblock = TRUE; break; case GST_RTSP_SUSPEND_MODE_RESET: GST_DEBUG ("media %p suspend to NULL", media); @@ -3587,16 +3600,11 @@ default_suspend (GstRTSPMedia * media) * is actually from NULL to PLAY will create a new sequence * number. */ g_ptr_array_foreach (priv->streams, (GFunc) do_set_seqnum, NULL); - unblock = TRUE; break; default: break; } - /* let the streams do the state changes freely, if any */ - if (unblock) - media_streams_set_blocked (media, FALSE); - return TRUE; /* ERRORS */ @@ -3674,7 +3682,19 @@ default_unsuspend (GstRTSPMedia * media) switch (priv->suspend_mode) { case GST_RTSP_SUSPEND_MODE_NONE: - gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); + if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) + break; + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); + /* at this point the media pipeline has been updated and contain all + * specific transport parts: all active streams contain at least one sink + * element and it's safe to unblock any blocked streams that are active */ + media_unblock_linked (media); + g_rec_mutex_unlock (&priv->state_lock); + if (gst_rtsp_media_get_status (media) == GST_RTSP_MEDIA_STATUS_ERROR) { + g_rec_mutex_lock (&priv->state_lock); + goto preroll_failed; + } + g_rec_mutex_lock (&priv->state_lock); break; case GST_RTSP_SUSPEND_MODE_PAUSE: gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); @@ -3682,6 +3702,10 @@ default_unsuspend (GstRTSPMedia * media) case GST_RTSP_SUSPEND_MODE_RESET: { gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); + /* at this point the media pipeline has been updated and contain all + * specific transport parts: all active streams contain at least one sink + * element and it's safe to unblock any blocked streams that are active */ + media_unblock_linked (media); if (!start_preroll (media)) goto start_failed; @@ -3771,7 +3795,7 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) } else { if (state == GST_STATE_PLAYING) /* make sure pads are not blocking anymore when going to PLAYING */ - media_streams_set_blocked (media, FALSE); + media_unblock_linked (media); set_state (media, state); @@ -4007,3 +4031,52 @@ gst_rtsp_media_seekable (GstRTSPMedia * media) * and no stream is seekable only to the beginning */ return media->priv->seekable; } + +/** + * gst_rtsp_media_complete_pipeline: + * @media: a #GstRTSPMedia + * @transports: a list of #GstRTSPTransport + * + * Add a receiver and sender parts to the pipeline based on the transport from + * SETUP. + * + * Returns: %TRUE if the media pipeline has been sucessfully updated. + */ +gboolean +gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GPtrArray * transports) +{ + GstRTSPMediaPrivate *priv; + guint i; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + g_return_val_if_fail (transports, FALSE); + + GST_DEBUG_OBJECT (media, "complete pipeline"); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStreamTransport *transport; + GstRTSPStream *stream; + const GstRTSPTransport *rtsp_transport; + + transport = g_ptr_array_index (transports, i); + if (!transport) + continue; + + stream = gst_rtsp_stream_transport_get_stream (transport); + if (!stream) + continue; + + rtsp_transport = gst_rtsp_stream_transport_get_transport (transport); + + if (!gst_rtsp_stream_complete_stream (stream, rtsp_transport)) { + g_mutex_unlock (&priv->lock); + return FALSE; + } + } + g_mutex_unlock (&priv->lock); + + return TRUE; +} diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 9c63d8f710..d78265d7c8 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -382,6 +382,9 @@ GST_EXPORT void gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state); +GST_EXPORT +gboolean gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GPtrArray * transports); + #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPMedia, gst_object_unref) #endif diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index ea4f034a0c..9a8f1c21c4 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -99,12 +99,16 @@ struct _GstRTSPStreamPrivate GstElement *udpsrc_v6[2]; GstElement *udpqueue[2]; GstElement *udpsink[2]; + GSocket *socket_v4[2]; + GSocket *socket_v6[2]; /* for UDP multicast */ GstElement *mcast_udpsrc_v4[2]; GstElement *mcast_udpsrc_v6[2]; GstElement *mcast_udpqueue[2]; GstElement *mcast_udpsink[2]; + GSocket *mcast_socket_v4[2]; + GSocket *mcast_socket_v6[2]; /* for TCP transport */ GstElement *appsrc[2]; @@ -291,6 +295,23 @@ gst_rtsp_stream_finalize (GObject * obj) if (priv->rtxsend) g_object_unref (priv->rtxsend); + if (priv->socket_v4[0]) + g_object_unref (priv->socket_v4[0]); + if (priv->socket_v4[1]) + g_object_unref (priv->socket_v4[1]); + if (priv->socket_v6[0]) + g_object_unref (priv->socket_v6[0]); + if (priv->socket_v6[1]) + g_object_unref (priv->socket_v6[1]); + if (priv->mcast_socket_v4[0]) + g_object_unref (priv->mcast_socket_v4[0]); + if (priv->mcast_socket_v4[1]) + g_object_unref (priv->mcast_socket_v4[1]); + if (priv->mcast_socket_v6[0]) + g_object_unref (priv->mcast_socket_v6[0]); + if (priv->mcast_socket_v6[1]) + g_object_unref (priv->mcast_socket_v6[1]); + g_free (priv->multicast_iface); gst_object_unref (priv->payloader); @@ -588,18 +609,14 @@ gst_rtsp_stream_get_mtu (GstRTSPStream * stream) /* Update the dscp qos property on the udp sinks */ static void -update_dscp_qos (GstRTSPStream * stream, GstElement * udpsink[2]) +update_dscp_qos (GstRTSPStream * stream, GstElement ** udpsink) { GstRTSPStreamPrivate *priv; priv = stream->priv; - if (udpsink[0]) { - g_object_set (G_OBJECT (udpsink[0]), "qos-dscp", priv->dscp_qos, NULL); - } - - if (udpsink[1]) { - g_object_set (G_OBJECT (udpsink[1]), "qos-dscp", priv->dscp_qos, NULL); + if (*udpsink) { + g_object_set (G_OBJECT (*udpsink), "qos-dscp", priv->dscp_qos, NULL); } } @@ -1087,8 +1104,8 @@ different_address: /* must be called with lock */ static void -set_sockets_for_udpsinks (GstElement * udpsink[2], GSocket * rtp_socket, - GSocket * rtcp_socket, GSocketFamily family) +set_socket_for_udpsink (GstElement * udpsink, GSocket * socket, + GSocketFamily family) { const gchar *multisink_socket; @@ -1097,95 +1114,172 @@ set_sockets_for_udpsinks (GstElement * udpsink[2], GSocket * rtp_socket, else multisink_socket = "socket"; - g_object_set (G_OBJECT (udpsink[0]), multisink_socket, rtp_socket, NULL); - g_object_set (G_OBJECT (udpsink[1]), multisink_socket, rtcp_socket, NULL); + g_object_set (G_OBJECT (udpsink), multisink_socket, socket, NULL); } +/* must be called with lock */ +static void +set_multicast_socket_for_udpsink (GstElement * udpsink, GSocket * socket, + GSocketFamily family, const gchar * multicast_iface, + const gchar * addr_str, gint port) +{ + set_socket_for_udpsink (udpsink, socket, family); + + if (multicast_iface) { + g_object_set (G_OBJECT (udpsink), "multicast-iface", + multicast_iface, NULL); + } + + g_signal_emit_by_name (udpsink, "add", addr_str, port, NULL); +} + + +/* must be called with lock */ +static void +set_unicast_socket_for_udpsink (GstElement * udpsink, GSocket * socket, + GSocketFamily family) +{ + set_socket_for_udpsink (udpsink, socket, family); +} + +static guint16 +get_port_from_socket (GSocket * socket) +{ + guint16 port; + GSocketAddress *sockaddr; + GError *err; + + GST_DEBUG ("socket: %p", socket); + sockaddr = g_socket_get_local_address (socket, &err); + if (sockaddr == NULL || !G_IS_INET_SOCKET_ADDRESS (sockaddr)) { + g_clear_object (&sockaddr); + GST_ERROR ("failed to get sockaddr: %s", err->message); + g_error_free (err); + return 0; + } + + port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (sockaddr)); + g_object_unref (sockaddr); + + return port; +} + + static gboolean -create_and_configure_udpsinks (GstRTSPStream * stream, GstElement * udpsink[2]) +create_and_configure_udpsink (GstRTSPStream * stream, GstElement ** udpsink, + GSocket *socket_v4, GSocket *socket_v6, gboolean multicast, gboolean is_rtp) { GstRTSPStreamPrivate *priv = stream->priv; - GstElement *udpsink0, *udpsink1; - udpsink0 = gst_element_factory_make ("multiudpsink", NULL); - udpsink1 = gst_element_factory_make ("multiudpsink", NULL); + *udpsink = gst_element_factory_make ("multiudpsink", NULL); - if (!udpsink0 || !udpsink1) + if (!*udpsink) goto no_udp_protocol; /* configure sinks */ - g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL); + g_object_set (G_OBJECT (*udpsink), "close-socket", FALSE, NULL); - g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); + g_object_set (G_OBJECT (*udpsink), "send-duplicates", FALSE, NULL); - g_object_set (G_OBJECT (udpsink0), "buffer-size", priv->buffer_size, NULL); + if (is_rtp) + g_object_set (G_OBJECT (*udpsink), "buffer-size", priv->buffer_size, NULL); + else + g_object_set (G_OBJECT (*udpsink), "sync", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); /* Needs to be async for RECORD streams, otherwise we will never go to * PLAYING because the sinks will wait for data while the udpsrc can't * provide data with timestamps in PAUSED. */ - if (priv->sinkpad) - g_object_set (G_OBJECT (udpsink0), "async", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); + if (!is_rtp || priv->sinkpad) + g_object_set (G_OBJECT (*udpsink), "async", FALSE, NULL); - /* join multicast group when adding clients, so we'll start receiving from it. - * We cannot rely on the udpsrc to join the group since its socket is always a - * local unicast one. */ - g_object_set (G_OBJECT (udpsink0), "auto-multicast", TRUE, NULL); - g_object_set (G_OBJECT (udpsink1), "auto-multicast", TRUE, NULL); + if (multicast) { + /* join multicast group when adding clients, so we'll start receiving from it. + * We cannot rely on the udpsrc to join the group since its socket is always a + * local unicast one. */ + g_object_set (G_OBJECT (*udpsink), "auto-multicast", TRUE, NULL); - g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL); - g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL); - - udpsink[0] = udpsink0; - udpsink[1] = udpsink1; + g_object_set (G_OBJECT (*udpsink), "loop", FALSE, NULL); + } /* update the dscp qos field in the sinks */ update_dscp_qos (stream, udpsink); + if (priv->server_addr_v4) { + GST_DEBUG_OBJECT (stream, + "udp IPv4, configure udpsinks"); + set_unicast_socket_for_udpsink (*udpsink, socket_v4, + G_SOCKET_FAMILY_IPV4); + } + + if (priv->server_addr_v6) { + GST_DEBUG_OBJECT (stream, + "udp IPv6, configure udpsinks"); + set_unicast_socket_for_udpsink (*udpsink, socket_v6, + G_SOCKET_FAMILY_IPV6); + } + + if (multicast) { + gint port; + if (priv->mcast_addr_v4) { + GST_DEBUG_OBJECT (stream, "mcast IPv4, configure udpsinks"); + port = get_port_from_socket (socket_v4); + if (!port) + goto get_port_failed; + set_multicast_socket_for_udpsink (*udpsink, socket_v4, + G_SOCKET_FAMILY_IPV4, priv->multicast_iface, priv->mcast_addr_v4->address, port); + } + + if (priv->mcast_addr_v6) { + GST_DEBUG_OBJECT (stream, "mcast IPv6, configure udpsinks"); + port = get_port_from_socket (socket_v6); + if (!port) + goto get_port_failed; + set_multicast_socket_for_udpsink (*udpsink, socket_v6, + G_SOCKET_FAMILY_IPV6, priv->multicast_iface, priv->mcast_addr_v6->address, port); + } + + } + return TRUE; /* ERRORS */ no_udp_protocol: { + GST_ERROR_OBJECT (stream, "failed to create udpsink element"); + return FALSE; + } +get_port_failed: + { + GST_ERROR_OBJECT (stream, "failed to get udp port"); return FALSE; } } /* must be called with lock */ static gboolean -create_and_configure_udpsources (GstElement * udpsrc_out[2], - GSocket * rtp_socket, GSocket * rtcp_socket) +create_and_configure_udpsource (GstElement ** udpsrc, + GSocket * socket) { GstStateChangeReturn ret; - udpsrc_out[0] = gst_element_factory_make ("udpsrc", NULL); - udpsrc_out[1] = gst_element_factory_make ("udpsrc", NULL); + g_assert (socket != NULL); - if (udpsrc_out[0] == NULL || udpsrc_out[1] == NULL) + *udpsrc = gst_element_factory_make ("udpsrc", NULL); + if (*udpsrc == NULL) goto error; - g_object_set (G_OBJECT (udpsrc_out[0]), "socket", rtp_socket, NULL); - g_object_set (G_OBJECT (udpsrc_out[1]), "socket", rtcp_socket, NULL); + g_object_set (G_OBJECT (*udpsrc), "socket", socket, NULL); /* The udpsrc cannot do the join because its socket is always a local unicast * one. The udpsink sharing the same socket will do it for us. */ - g_object_set (G_OBJECT (udpsrc_out[0]), "auto-multicast", FALSE, NULL); - g_object_set (G_OBJECT (udpsrc_out[1]), "auto-multicast", FALSE, NULL); + g_object_set (G_OBJECT (*udpsrc), "auto-multicast", FALSE, NULL); - g_object_set (G_OBJECT (udpsrc_out[0]), "loop", FALSE, NULL); - g_object_set (G_OBJECT (udpsrc_out[1]), "loop", FALSE, NULL); + g_object_set (G_OBJECT (*udpsrc), "loop", FALSE, NULL); - g_object_set (G_OBJECT (udpsrc_out[0]), "close-socket", FALSE, NULL); - g_object_set (G_OBJECT (udpsrc_out[1]), "close-socket", FALSE, NULL); + g_object_set (G_OBJECT (*udpsrc), "close-socket", FALSE, NULL); - ret = gst_element_set_state (udpsrc_out[0], GST_STATE_READY); - if (ret == GST_STATE_CHANGE_FAILURE) - goto error; - ret = gst_element_set_state (udpsrc_out[1], GST_STATE_READY); + ret = gst_element_set_state (*udpsrc, GST_STATE_READY); if (ret == GST_STATE_CHANGE_FAILURE) goto error; @@ -1194,13 +1288,9 @@ create_and_configure_udpsources (GstElement * udpsrc_out[2], /* ERRORS */ error: { - if (udpsrc_out[0]) { - gst_element_set_state (udpsrc_out[0], GST_STATE_NULL); - g_clear_object (&udpsrc_out[0]); - } - if (udpsrc_out[1]) { - gst_element_set_state (udpsrc_out[1], GST_STATE_NULL); - g_clear_object (&udpsrc_out[1]); + if (*udpsrc) { + gst_element_set_state (*udpsrc, GST_STATE_NULL); + g_clear_object (udpsrc); } return FALSE; } @@ -1208,29 +1298,21 @@ error: static gboolean alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, - GstElement * udpsrc_out[2], GstElement * udpsink_out[2], - GstRTSPAddress ** server_addr_out, gboolean multicast) + GSocket *socket_out[2], GstRTSPAddress ** server_addr_out, + gboolean multicast, GstRTSPTransport * ct) { GstRTSPStreamPrivate *priv = stream->priv; GSocket *rtp_socket = NULL; GSocket *rtcp_socket; gint tmp_rtp, tmp_rtcp; guint count; - gint rtpport, rtcpport; GList *rejected_addresses = NULL; GstRTSPAddress *addr = NULL; GInetAddress *inetaddr = NULL; - gchar *addr_str; GSocketAddress *rtp_sockaddr = NULL; GSocketAddress *rtcp_sockaddr = NULL; GstRTSPAddressPool *pool; - g_assert (!udpsrc_out[0]); - g_assert (!udpsrc_out[1]); - g_assert ((!udpsink_out[0] && !udpsink_out[1]) || - (udpsink_out[0] && udpsink_out[1])); - g_assert (*server_addr_out == NULL); - pool = priv->pool; count = 0; @@ -1262,7 +1344,7 @@ again: rejected_addresses = g_list_prepend (rejected_addresses, addr); if (!pool) - goto no_ports; + goto no_pool; flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT; if (multicast) @@ -1278,11 +1360,13 @@ again: addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); if (addr == NULL) - goto no_ports; + goto no_address; tmp_rtp = addr->port; g_clear_object (&inetaddr); + /* FIXME: Does it really work with the IP_MULTICAST_ALL socket option and + * socket control message set in udpsrc? */ if (multicast) inetaddr = g_inet_address_new_any (family); else @@ -1300,6 +1384,7 @@ again: rtp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtp); if (!g_socket_bind (rtp_socket, rtp_sockaddr, FALSE, NULL)) { + GST_DEBUG_OBJECT (stream, "rtp bind() failed, will try again"); g_object_unref (rtp_sockaddr); goto again; } @@ -1328,6 +1413,7 @@ again: rtcp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtcp); if (!g_socket_bind (rtcp_socket, rtcp_sockaddr, FALSE, NULL)) { + GST_DEBUG_OBJECT (stream, "rctp bind() failed, will try again"); g_object_unref (rtcp_sockaddr); g_clear_object (&rtp_socket); goto again; @@ -1341,62 +1427,42 @@ again: addr->n_ports = 2; } - addr_str = addr->address; g_clear_object (&inetaddr); - if (!create_and_configure_udpsources (udpsrc_out, rtp_socket, rtcp_socket)) { - goto no_udp_protocol; - } - - g_object_get (G_OBJECT (udpsrc_out[0]), "port", &rtpport, NULL); - g_object_get (G_OBJECT (udpsrc_out[1]), "port", &rtcpport, NULL); - - /* this should not happen... */ - if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) - goto port_error; - - /* This function is called twice (for v4 and v6) but we create only one pair - * of udpsinks. */ - if (!udpsink_out[0] - && !create_and_configure_udpsinks (stream, udpsink_out)) - goto no_udp_protocol; - - if (multicast) { - g_object_set (G_OBJECT (udpsink_out[0]), "multicast-iface", - priv->multicast_iface, NULL); - g_object_set (G_OBJECT (udpsink_out[1]), "multicast-iface", - priv->multicast_iface, NULL); - - g_signal_emit_by_name (udpsink_out[0], "add", addr_str, rtpport, NULL); - g_signal_emit_by_name (udpsink_out[1], "add", addr_str, rtcpport, NULL); - } - - set_sockets_for_udpsinks (udpsink_out, rtp_socket, rtcp_socket, family); - + socket_out[0] = rtp_socket; + socket_out[1] = rtcp_socket; *server_addr_out = addr; - g_list_free_full (rejected_addresses, (GDestroyNotify) gst_rtsp_address_free); + GST_DEBUG_OBJECT (stream, "allocated address: %s and ports: %d, %d", addr->address, tmp_rtp, tmp_rtcp); - g_object_unref (rtp_socket); - g_object_unref (rtcp_socket); + g_list_free_full (rejected_addresses, (GDestroyNotify) gst_rtsp_address_free); return TRUE; /* ERRORS */ no_udp_protocol: { + GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: protocol error"); + goto cleanup; + } +no_pool: + { + GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: no address pool specified"); + goto cleanup; + } +no_address: + { + GST_ERROR_OBJECT (stream, "failed to acquire address from pool"); goto cleanup; } no_ports: { - goto cleanup; - } -port_error: - { + GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: no ports"); goto cleanup; } socket_error: { + GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: socket error"); goto cleanup; } cleanup: @@ -1425,14 +1491,73 @@ cleanup: * Allocates RTP and RTCP ports. * * Returns: %TRUE if the RTP and RTCP sockets have been succeccully allocated. - * Deprecated: This function shouldn't have been made public */ gboolean gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, - GSocketFamily family, GstRTSPTransport * ct, gboolean use_client_settings) + GSocketFamily family, GstRTSPTransport * ct, + gboolean use_transport_settings) { - g_warn_if_reached (); - return FALSE; + GstRTSPStreamPrivate *priv; + gboolean ret = FALSE; + GstRTSPLowerTrans transport; + gboolean allocated = FALSE; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + g_return_val_if_fail (ct != NULL, FALSE); + priv = stream->priv; + + transport = ct->lower_transport; + + g_mutex_lock (&priv->lock); + + if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { + if (family == G_SOCKET_FAMILY_IPV4 && priv->mcast_addr_v4) + allocated = TRUE; + else if (family == G_SOCKET_FAMILY_IPV6 && priv->mcast_addr_v6) + allocated = TRUE; + } else if (transport == GST_RTSP_LOWER_TRANS_UDP) { + if (family == G_SOCKET_FAMILY_IPV4 && priv->server_addr_v4) + allocated = TRUE; + else if (family == G_SOCKET_FAMILY_IPV6 && priv->server_addr_v6) + allocated = TRUE; + } + + if (allocated) { + g_mutex_unlock (&priv->lock); + return TRUE; + } + + if (family == G_SOCKET_FAMILY_IPV4) { + /* IPv4 */ + if (transport == GST_RTSP_LOWER_TRANS_UDP) { + /* UDP unicast */ + GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_UDP, ipv4"); + ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, + priv->socket_v4, &priv->server_addr_v4, FALSE, ct); + } else { + /* multicast */ + GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_MCAST_UDP, ipv4"); + ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, + priv->mcast_socket_v4, &priv->mcast_addr_v4, TRUE, ct); + } + } else { + /* IPv6 */ + if (transport == GST_RTSP_LOWER_TRANS_UDP) { + /* unicast */ + GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_UDP, ipv6"); + ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, + priv->socket_v6, &priv->server_addr_v6, FALSE, ct); + + } else { + /* multicast */ + GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_MCAST_UDP, ipv6"); + ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, + priv->mcast_socket_v6, &priv->mcast_addr_v6, TRUE, ct); + } + } + g_mutex_unlock (&priv->lock); + + return ret; } /** @@ -1483,33 +1608,6 @@ gst_rtsp_stream_is_client_side (GstRTSPStream * stream) return ret; } -/* must be called with lock */ -static gboolean -alloc_ports (GstRTSPStream * stream) -{ - GstRTSPStreamPrivate *priv = stream->priv; - gboolean ret = TRUE; - - if (priv->protocols & GST_RTSP_LOWER_TRANS_UDP) { - ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, - priv->udpsrc_v4, priv->udpsink, &priv->server_addr_v4, FALSE); - - ret |= alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, - priv->udpsrc_v6, priv->udpsink, &priv->server_addr_v6, FALSE); - } - - /* FIXME: Maybe actually consider the return values? */ - if (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) { - ret |= alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, - priv->mcast_udpsrc_v4, priv->mcast_udpsink, &priv->mcast_addr_v4, TRUE); - - ret |= alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, - priv->mcast_udpsrc_v6, priv->mcast_udpsink, &priv->mcast_addr_v6, TRUE); - } - - return ret; -} - /** * gst_rtsp_stream_get_server_port: * @stream: a #GstRTSPStream @@ -2365,71 +2463,357 @@ on_npt_stop (GstElement * rtpbin, guint session, guint ssrc, gst_pad_send_event (stream->priv->sinkpad, gst_event_new_eos ()); } -static void -plug_sink (GstBin * bin, GstElement * tee, GstElement * sink, - GstElement ** queue_out) +typedef struct _ProbeData ProbeData; + +struct _ProbeData { - GstPad *pad; - GstPad *teepad; - GstPad *queuepad; + GstRTSPStream *stream; + /* existing sink, already linked to tee */ + GstElement *sink1; + /* new sink, about to be linked */ + GstElement *sink2; + /* new queue element, that will be linked to tee and sink1 */ + GstElement **queue1; + /* new queue element, that will be linked to tee and sink2 */ + GstElement **queue2; + GstPad *sink_pad; + GstPad *tee_pad; + guint index; +}; - gst_bin_add (bin, sink); +static void +free_cb_data (gpointer user_data) +{ + ProbeData *data = user_data; - *queue_out = gst_element_factory_make ("queue", NULL); - g_object_set (*queue_out, "max-size-buffers", 1, "max-size-bytes", 0, + gst_object_unref (data->stream); + gst_object_unref (data->sink1); + gst_object_unref (data->sink2); + gst_object_unref (data->sink_pad); + gst_object_unref (data->tee_pad); + g_free (data); +} + + +static void +create_and_plug_queue_to_unlinked_stream (GstRTSPStream * stream, GstElement *tee, + GstElement *sink, GstElement ** queue) +{ + GstRTSPStreamPrivate *priv = stream->priv; + GstPad *tee_pad; + GstPad *queue_pad; + GstPad *sink_pad; + + /* create queue for the new stream */ + *queue = gst_element_factory_make ("queue", NULL); + g_object_set (*queue, "max-size-buffers", 1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), NULL); - gst_bin_add (bin, *queue_out); + gst_bin_add (priv->joined_bin, *queue); /* link tee to queue */ - teepad = gst_element_get_request_pad (tee, "src_%u"); - pad = gst_element_get_static_pad (*queue_out, "sink"); - gst_pad_link (teepad, pad); - gst_object_unref (pad); - gst_object_unref (teepad); + tee_pad = gst_element_get_request_pad (tee, "src_%u"); + queue_pad = gst_element_get_static_pad (*queue, "sink"); + gst_pad_link (tee_pad, queue_pad); + gst_object_unref (queue_pad); + gst_object_unref (tee_pad); /* link queue to sink */ - queuepad = gst_element_get_static_pad (*queue_out, "src"); - pad = gst_element_get_static_pad (sink, "sink"); - gst_pad_link (queuepad, pad); - gst_object_unref (queuepad); - gst_object_unref (pad); + queue_pad = gst_element_get_static_pad (*queue, "src"); + sink_pad = gst_element_get_static_pad (sink, "sink"); + gst_pad_link (queue_pad, sink_pad); + gst_object_unref (queue_pad); + gst_object_unref (sink_pad); + + gst_element_sync_state_with_parent (sink); + gst_element_sync_state_with_parent (*queue); +} + +static GstPadProbeReturn +create_and_plug_queue_to_linked_stream_probe_cb (GstPad * inpad, + GstPadProbeInfo * info, gpointer user_data) +{ + GstRTSPStreamPrivate *priv; + ProbeData *data = user_data; + GstRTSPStream *stream; + GstElement **queue1; + GstElement **queue2; + GstPad *sink_pad; + GstPad *tee_pad; + GstPad *queue_pad; + guint index; + + stream = data->stream; + priv = stream->priv; + queue1 = data->queue1; + queue2 = data->queue2; + sink_pad = data->sink_pad; + tee_pad = data->tee_pad; + index = data->index; + + /* unlink tee and the existing sink: + * .-----. .---------. + * | tee | | sink1 | + * sink src->sink | + * '-----' '---------' + */ + g_assert (gst_pad_unlink (tee_pad, sink_pad)); + + /* add queue to the already existing stream */ + *queue1 = gst_element_factory_make ("queue", NULL); + g_object_set (*queue1, "max-size-buffers", 1, "max-size-bytes", 0, + "max-size-time", G_GINT64_CONSTANT (0), NULL); + gst_bin_add (priv->joined_bin, *queue1); + + /* link tee, queue and sink: + * .-----. .---------. .---------. + * | tee | | queue1 | | sink1 | + * sink src->sink src->sink | + * '-----' '---------' '---------' + */ + queue_pad = gst_element_get_static_pad (*queue1, "sink"); + gst_pad_link (tee_pad, queue_pad); + gst_object_unref (queue_pad); + queue_pad = gst_element_get_static_pad (*queue1, "src"); + gst_pad_link (queue_pad, sink_pad); + gst_object_unref (queue_pad); + + gst_element_sync_state_with_parent (*queue1); + + /* create queue and link it to tee and the new sink */ + create_and_plug_queue_to_unlinked_stream (stream, + priv->tee[index], data->sink2, queue2); + + /* the final stream: + * + * .-----. .---------. .---------. + * | tee | | queue1 | | sink1 | + * sink src->sink src->sink | + * | | '---------' '---------' + * | | .---------. .---------. + * | | | queue2 | | sink2 | + * | src->sink src->sink | + * '-----' '---------' '---------' + */ + + return GST_PAD_PROBE_REMOVE; +} + +static void +create_and_plug_queue_to_linked_stream (GstRTSPStream * stream, GstElement * sink1, + GstElement * sink2, guint index, GstElement ** queue1, + GstElement ** queue2) +{ + ProbeData *data; + + data = g_new0 (ProbeData, 1); + data->stream = gst_object_ref (stream); + data->sink1 = gst_object_ref (sink1); + data->sink2 = gst_object_ref (sink2); + data->queue1 = queue1; + data->queue2 = queue2; + data->index = index; + + data->sink_pad = gst_element_get_static_pad (sink1, "sink"); + g_assert (data->sink_pad); + data->tee_pad = gst_pad_get_peer (data->sink_pad); + g_assert (data->tee_pad); + + gst_pad_add_probe (data->tee_pad, GST_PAD_PROBE_TYPE_IDLE, + create_and_plug_queue_to_linked_stream_probe_cb, data, free_cb_data); +} + +static void +plug_udp_sink (GstRTSPStream * stream, GstElement * sink_to_plug, + GstElement ** queue_to_plug, guint index, gboolean is_mcast) +{ + GstRTSPStreamPrivate *priv = stream->priv; + GstElement *existing_sink; + + if (is_mcast) + existing_sink = priv->udpsink[index]; + else + existing_sink = priv->mcast_udpsink[index]; + + GST_DEBUG_OBJECT (stream, "plug %s sink", is_mcast ? "mcast" : "udp"); + + /* add sink to the bin */ + gst_bin_add (priv->joined_bin, sink_to_plug); + + if (priv->appsink[index] && existing_sink) { + + /* queues are already added for the existing stream, add one for + the newly added udp stream */ + create_and_plug_queue_to_unlinked_stream (stream, priv->tee[index], + sink_to_plug, queue_to_plug); + + } else if (priv->appsink[index] || existing_sink) { + GstElement **queue; + GstElement *element; + + /* add queue to the already existing stream plus the newly created udp + stream */ + if (priv->appsink[index]) { + element = priv->appsink[index]; + queue = &priv->appqueue[index]; + } else { + element = existing_sink; + if (is_mcast) + queue = &priv->udpqueue[index]; + else + queue = &priv->mcast_udpqueue[index]; + } + + create_and_plug_queue_to_linked_stream (stream, element, sink_to_plug, index, + queue, queue_to_plug); + + } else { + GstPad *tee_pad; + GstPad *sink_pad; + + GST_DEBUG_OBJECT (stream, "creating first stream"); + + /* no need to add queues */ + tee_pad = gst_element_get_request_pad (priv->tee[index], "src_%u"); + sink_pad = gst_element_get_static_pad (sink_to_plug, "sink"); + gst_pad_link (tee_pad, sink_pad); + gst_object_unref (tee_pad); + gst_object_unref (sink_pad); + } + + gst_element_sync_state_with_parent (sink_to_plug); +} + +static void +plug_tcp_sink (GstRTSPStream * stream, guint index) +{ + GstRTSPStreamPrivate *priv = stream->priv; + + GST_DEBUG_OBJECT (stream, "plug tcp sink"); + + /* add sink to the bin */ + gst_bin_add (priv->joined_bin, priv->appsink[index]); + + if (priv->mcast_udpsink[index] && priv->udpsink[index]) { + + /* queues are already added for the existing stream, add one for + the newly added tcp stream */ + create_and_plug_queue_to_unlinked_stream (stream, + priv->tee[index], priv->appsink[index], &priv->appqueue[index]); + + } else if (priv->mcast_udpsink[index] || priv->udpsink[index]) { + GstElement **queue; + GstElement *element; + + /* add queue to the already existing stream plus the newly created tcp + stream */ + if (priv->mcast_udpsink[index]) { + element = priv->mcast_udpsink[index]; + queue = &priv->mcast_udpqueue[index]; + } else { + element = priv->udpsink[index]; + queue = &priv->udpqueue[index]; + } + + create_and_plug_queue_to_linked_stream (stream, element, priv->appsink[index], index, + queue, &priv->appqueue[index]); + + } else { + GstPad *tee_pad; + GstPad *sink_pad; + + /* no need to add queues */ + tee_pad = gst_element_get_request_pad (priv->tee[index], "src_%u"); + sink_pad = gst_element_get_static_pad (priv->appsink[index], "sink"); + gst_pad_link (tee_pad, sink_pad); + gst_object_unref (tee_pad); + gst_object_unref (sink_pad); + } + + gst_element_sync_state_with_parent (priv->appsink[index]); +} + +static void +plug_sink (GstRTSPStream * stream, const GstRTSPTransport * transport, + guint index) +{ + GstRTSPStreamPrivate *priv; + gboolean is_tcp, is_udp, is_mcast; + priv = stream->priv; + + is_tcp = transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP; + is_udp = transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP; + is_mcast = transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST; + + if (is_udp) + plug_udp_sink (stream, priv->udpsink[index], + &priv->udpqueue[index], index, FALSE); + + else if (is_mcast) + plug_udp_sink (stream, priv->mcast_udpsink[index], + &priv->mcast_udpqueue[index], index, TRUE); + + else if (is_tcp) + plug_tcp_sink (stream, index); } /* must be called with lock */ -static void -create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) +static gboolean +create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport) { GstRTSPStreamPrivate *priv; GstPad *pad; - gboolean is_tcp, is_udp; + GstBin *bin; + gboolean is_tcp, is_udp, is_mcast; gint i; + GST_DEBUG_OBJECT (stream, "create sender part"); priv = stream->priv; + bin = priv->joined_bin; - is_tcp = priv->protocols & GST_RTSP_LOWER_TRANS_TCP; - is_udp = ((priv->protocols & GST_RTSP_LOWER_TRANS_UDP) || - (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)); + is_tcp = transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP; + is_udp = transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP; + is_mcast = transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST; + + GST_DEBUG_OBJECT (stream, "tcp: %d, udp: %d, mcast: %d", is_tcp, is_udp, + is_mcast); + + if (is_udp && !priv->server_addr_v4 && !priv->server_addr_v6) { + GST_WARNING_OBJECT (stream, "no sockets assigned for UDP"); + return FALSE; + } + + if (is_mcast && !priv->mcast_addr_v4 && !priv->mcast_addr_v6) { + GST_WARNING_OBJECT (stream, "no sockets assigned for UDP multicast"); + return FALSE; + } for (i = 0; i < 2; i++) { + gboolean link_tee = FALSE; /* For the sender we create this bit of pipeline for both - * RTP and RTCP. Sync and preroll are enabled on udpsink so - * we need to add a queue before appsink and udpsink to make - * the pipeline not block. For the TCP case, we want to pump - * client as fast as possible anyway. This pipeline is used - * when both TCP and UDP are present. + * RTP and RTCP. + * Initially there will be only one active transport for + * the stream, so the pipeline will look like this: + * + * .--------. .-----. .---------. + * | rtpbin | | tee | | sink | + * | send->sink src->sink | + * '--------' '-----' '---------' + * + * For each new transport, the already existing branch will + * be reconfigured by adding a queue element: * * .--------. .-----. .---------. .---------. * | rtpbin | | tee | | queue | | udpsink | * | send->sink src->sink src->sink | * '--------' | | '---------' '---------' * | | .---------. .---------. + * | | | queue | | udpsink | + * | src->sink src->sink | + * | | '---------' '---------' + * | | .---------. .---------. * | | | queue | | appsink | * | src->sink src->sink | * '-----' '---------' '---------' - * - * When only UDP or only TCP is allowed, we skip the tee and queue - * and link the udpsink (for UDP) or appsink (for TCP) directly to - * the session. */ /* Only link the RTP send src if we're going to send RTP, link @@ -2437,71 +2821,49 @@ create_sender_part (GstRTSPStream * stream, GstBin * bin, GstState state) if (!priv->srcpad && i == 0) continue; - if (is_tcp) { - /* make appsink */ - priv->appsink[i] = gst_element_factory_make ("appsink", NULL); - g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); - gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), - &sink_cb, stream, NULL); - } - - /* If we have udp always use a tee because we could have mcast clients - * requesting different ports, in which case we'll have to plug more - * udpsinks. */ - if (is_udp) { + if (!priv->tee[i]) { /* make tee for RTP/RTCP */ priv->tee[i] = gst_element_factory_make ("tee", NULL); gst_bin_add (bin, priv->tee[i]); + link_tee = TRUE; + } + if (is_udp && !priv->udpsink[i]) { + /* we create only one pair of udpsinks for IPv4 and IPv6 */ + create_and_configure_udpsink (stream, &priv->udpsink[i], priv->socket_v4[i], + priv->socket_v6[i], FALSE, (i == 0)); + plug_sink (stream, transport, i); + } else if (is_mcast && !priv->mcast_udpsink[i]) { + /* we create only one pair of mcast-udpsinks for IPv4 and IPv6 */ + create_and_configure_udpsink (stream, &priv->mcast_udpsink[i], + priv->mcast_socket_v4[i], priv->mcast_socket_v6[i], TRUE, (i == 0)); + plug_sink (stream, transport, i); + } else if (is_tcp && !priv->appsink[i]) { + /* make appsink */ + priv->appsink[i] = gst_element_factory_make ("appsink", NULL); + g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); + + /* we need to set sync and preroll to FALSE for the sink to avoid + * deadlock. This is only needed for sink sending RTCP data. */ + if (i == 1) + g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, + NULL); + + gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), + &sink_cb, stream, NULL); + plug_sink (stream, transport, i); + } + + if (link_tee) { /* and link to rtpbin send pad */ + gst_element_sync_state_with_parent (priv->tee[i]); pad = gst_element_get_static_pad (priv->tee[i], "sink"); gst_pad_link (priv->send_src[i], pad); gst_object_unref (pad); - - if (priv->udpsink[i]) - plug_sink (bin, priv->tee[i], priv->udpsink[i], &priv->udpqueue[i]); - - if (priv->mcast_udpsink[i]) - plug_sink (bin, priv->tee[i], priv->mcast_udpsink[i], - &priv->mcast_udpqueue[i]); - - if (is_tcp) { - if (i == 1) - g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); - plug_sink (bin, priv->tee[i], priv->appsink[i], &priv->appqueue[i]); - } - } else if (is_tcp) { - /* only appsink needed, link it to the session */ - gst_bin_add (bin, priv->appsink[i]); - pad = gst_element_get_static_pad (priv->appsink[i], "sink"); - gst_pad_link (priv->send_src[i], pad); - gst_object_unref (pad); - - /* when its only TCP, we need to set sync and preroll to FALSE - * for the sink to avoid deadlock. And this is only needed for - * sink used for RTCP data, not the RTP data. */ - if (i == 1) - g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); - } - - /* check if we need to set to a special state */ - if (state != GST_STATE_NULL) { - if (priv->udpsink[i]) - gst_element_set_state (priv->udpsink[i], state); - if (priv->mcast_udpsink[i]) - gst_element_set_state (priv->mcast_udpsink[i], state); - if (priv->appsink[i]) - gst_element_set_state (priv->appsink[i], state); - if (priv->appqueue[i]) - gst_element_set_state (priv->appqueue[i], state); - if (priv->udpqueue[i]) - gst_element_set_state (priv->udpqueue[i], state); - if (priv->mcast_udpqueue[i]) - gst_element_set_state (priv->mcast_udpqueue[i], state); - if (priv->tee[i]) - gst_element_set_state (priv->tee[i], state); } } + + return TRUE; } /* must be called with lock */ @@ -2533,30 +2895,48 @@ plug_src (GstRTSPStream * stream, GstBin * bin, GstElement * src, } /* must be called with lock */ -static void -create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) +static gboolean +create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * + transport) { GstRTSPStreamPrivate *priv; GstPad *pad; - gboolean is_tcp; + GstBin *bin; + gboolean tcp; + gboolean udp; + gboolean mcast; gint i; + GST_DEBUG_OBJECT (stream, "create receiver part"); priv = stream->priv; + bin = priv->joined_bin; - is_tcp = priv->protocols & GST_RTSP_LOWER_TRANS_TCP; + tcp = transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP; + udp = transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP; + mcast = transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST; for (i = 0; i < 2; i++) { /* For the receiver we create this bit of pipeline for both * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc * and it is all funneled into the rtpbin receive pad. * + * * .--------. .--------. .--------. * | udpsrc | | funnel | | rtpbin | - * | src->sink src->sink | + * | RTP src->sink src->sink | + * '--------' | | | | + * .--------. | | | | + * | appsrc | | | | | + * | RTP src->sink | | | + * '--------' '--------' | | + * | | + * .--------. .--------. | | + * | udpsrc | | funnel | | | + * | RTCP src->sink src->sink | * '--------' | | '--------' * .--------. | | * | appsrc | | | - * | src->sink | + * | RTCP src->sink | * '--------' '--------' */ @@ -2574,19 +2954,41 @@ create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) gst_pad_link (pad, priv->recv_sink[i]); gst_object_unref (pad); - if (priv->udpsrc_v4[i]) + if (udp && !priv->udpsrc_v4[i] && priv->server_addr_v4) { + GST_DEBUG_OBJECT (stream, "udp IPv4, create and configure udpsources"); + if (!create_and_configure_udpsource (&priv->udpsrc_v4[i], + priv->socket_v4[i])) + goto udpsrc_error; + plug_src (stream, bin, priv->udpsrc_v4[i], priv->funnel[i]); + } + + if (udp && !priv->udpsrc_v6[i] && priv->server_addr_v6) { + GST_DEBUG_OBJECT (stream, "udp IPv6, create and configure udpsources"); + if (!create_and_configure_udpsource (&priv->udpsrc_v6[i], + priv->socket_v6[i])) + goto udpsrc_error; - if (priv->udpsrc_v6[i]) plug_src (stream, bin, priv->udpsrc_v6[i], priv->funnel[i]); + } - if (priv->mcast_udpsrc_v4[i]) + if (mcast && !priv->mcast_udpsrc_v4[i] && priv->mcast_addr_v4) { + GST_DEBUG_OBJECT (stream, "mcast IPv4, create and configure udpsources"); + if (!create_and_configure_udpsource (&priv->mcast_udpsrc_v4[i], + priv->mcast_socket_v4[i])) + goto mcast_udpsrc_error; plug_src (stream, bin, priv->mcast_udpsrc_v4[i], priv->funnel[i]); + } - if (priv->mcast_udpsrc_v6[i]) + if (mcast && !priv->mcast_udpsrc_v6[i] && priv->mcast_addr_v6) { + GST_DEBUG_OBJECT (stream, "mcast IPv6, create and configure udpsources"); + if (!create_and_configure_udpsource (&priv->mcast_udpsrc_v6[i], + priv->mcast_socket_v6[i])) + goto mcast_udpsrc_error; plug_src (stream, bin, priv->mcast_udpsrc_v6[i], priv->funnel[i]); + } - if (is_tcp) { + if (tcp && !priv->appsrc[i]) { /* make and add appsrc */ priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL); priv->appsrc_base_time[i] = -1; @@ -2595,11 +2997,14 @@ create_receiver_part (GstRTSPStream * stream, GstBin * bin, GstState state) plug_src (stream, bin, priv->appsrc[i], priv->funnel[i]); } - /* check if we need to set to a special state */ - if (state != GST_STATE_NULL) { - gst_element_set_state (priv->funnel[i], state); - } + gst_element_sync_state_with_parent (priv->funnel[i]); } + + return TRUE; + +mcast_udpsrc_error: +udpsrc_error: + return FALSE; } static gboolean @@ -2688,9 +3093,6 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, GST_INFO ("stream %p joining bin as session %u", stream, idx); - if (!alloc_ports (stream)) - goto no_ports; - if (priv->profiles & GST_RTSP_PROFILE_SAVP || priv->profiles & GST_RTSP_PROFILE_SAVPF) { /* For SRTP */ @@ -2727,7 +3129,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, priv->send_src[0] = gst_element_get_static_pad (rtpbin, name); g_free (name); } else { - /* Need to connect our sinkpad from here */ + /* RECORD case: need to connect our sinkpad from here */ g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added, stream); /* EOS */ g_signal_connect (rtpbin, "on-npt-stop", (GCallback) on_npt_stop, stream); @@ -2766,9 +3168,6 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, g_signal_connect (priv->session, "on-sender-ssrc-active", (GCallback) on_sender_ssrc_active, stream); - create_sender_part (stream, bin, state); - create_receiver_part (stream, bin, state); - if (priv->srcpad) { /* be notified of caps changes */ priv->caps_sig = g_signal_connect (priv->send_src[0], "notify::caps", @@ -2777,6 +3176,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, } priv->joined_bin = bin; + GST_DEBUG_OBJECT (stream, "successfully joined bin"); g_mutex_unlock (&priv->lock); return TRUE; @@ -2787,12 +3187,6 @@ was_joined: g_mutex_unlock (&priv->lock); return TRUE; } -no_ports: - { - g_mutex_unlock (&priv->lock); - GST_WARNING ("failed to allocate ports %u", idx); - return FALSE; - } link_failed: { GST_WARNING ("failed to link stream %u", idx); @@ -3781,30 +4175,22 @@ pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) return GST_PAD_PROBE_OK; } -/** - * gst_rtsp_stream_set_blocked: - * @stream: a #GstRTSPStream - * @blocked: boolean indicating we should block or unblock - * - * Blocks or unblocks the dataflow on @stream. - * - * Returns: %TRUE on success - */ -gboolean -gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked) +static void +set_blocked (GstRTSPStream * stream, gboolean blocked) { GstRTSPStreamPrivate *priv; int i; - g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + GST_DEBUG_OBJECT (stream, "blocked: %d", blocked); priv = stream->priv; - g_mutex_lock (&priv->lock); if (blocked) { priv->blocking = FALSE; for (i = 0; i < 2; i++) { - if (priv->blocked_id[i] == 0) { + if (priv->blocked_id[i] != 0) + continue; + if (priv->send_src[i]) { priv->blocked_id[i] = gst_pad_add_probe (priv->send_src[i], GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, pad_blocking, @@ -3820,6 +4206,51 @@ gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked) } priv->blocking = FALSE; } +} + +/** + * gst_rtsp_stream_set_blocked: + * @stream: a #GstRTSPStream + * @blocked: boolean indicating we should block or unblock + * + * Blocks or unblocks the dataflow on @stream. + * + * Returns: %TRUE on success + */ +gboolean +gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked) +{ + GstRTSPStreamPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + g_mutex_lock (&priv->lock); + set_blocked (stream, blocked); + g_mutex_unlock (&priv->lock); + + return TRUE; +} + +/** + * gst_rtsp_stream_ublock_linked: + * @stream: a #GstRTSPStream + * + * Unblocks the dataflow on @stream if it is linked. + * + * Returns: %TRUE on success + */ +gboolean +gst_rtsp_stream_unblock_linked (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + g_mutex_lock (&priv->lock); + if (priv->send_src[0] && gst_pad_is_linked (priv->send_src[0])) + set_blocked (stream, FALSE); g_mutex_unlock (&priv->lock); return TRUE; @@ -4015,3 +4446,50 @@ gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop) return TRUE; } + +/** + * gst_rtsp_stream_complete_stream: + * @stream: a #GstRTSPStream + * @transport: a #GstRTSPTransport + * + * Add a receiver and sender part to the pipeline based on the transport from + * SETUP. + * + * Returns: %TRUE if the pipeline has been sucessfully updated. + */ +gboolean +gst_rtsp_stream_complete_stream (GstRTSPStream * stream, + const GstRTSPTransport * transport) +{ + GstRTSPStreamPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + GST_DEBUG_OBJECT (stream, "complete stream"); + + g_mutex_lock (&priv->lock); + + if (!(priv->protocols & transport->lower_transport)) + goto unallowed_transport; + + if (!create_receiver_part (stream, transport)) + goto create_receiver_error; + + /* in the RECORD case, we only add RTCP sender part */ + if (!create_sender_part (stream, transport)) + goto create_sender_error; + + g_mutex_unlock (&priv->lock); + + GST_DEBUG_OBJECT (stream, "pipeline sucsessfully updated"); + return TRUE; + +create_receiver_error: +create_sender_error: +unallowed_transport: + { + g_mutex_unlock (&priv->lock); + return FALSE; + } +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 7aa1aa2d3f..add1a88960 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -160,6 +160,10 @@ gboolean gst_rtsp_stream_set_blocked (GstRTSPStream * stream, GST_EXPORT gboolean gst_rtsp_stream_is_blocking (GstRTSPStream * stream); + +GST_EXPORT +gboolean gst_rtsp_stream_unblock_linked (GstRTSPStream * stream); + GST_EXPORT void gst_rtsp_stream_set_client_side (GstRTSPStream *stream, gboolean client_side); @@ -272,7 +276,7 @@ GstElement * gst_rtsp_stream_request_aux_sender (GstRTSPStream * st GST_EXPORT gboolean gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, GSocketFamily family, - GstRTSPTransport *transport, gboolean use_client_setttings); + GstRTSPTransport *transport, gboolean use_client_settings); GST_EXPORT void gst_rtsp_stream_set_publish_clock_mode (GstRTSPStream * stream, GstRTSPPublishClockMode mode); @@ -280,6 +284,9 @@ void gst_rtsp_stream_set_publish_clock_mode (GstRTSPStream * GST_EXPORT GstRTSPPublishClockMode gst_rtsp_stream_get_publish_clock_mode (GstRTSPStream * stream); +GST_EXPORT +gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GstRTSPTransport * transport); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 7779664c42..4adf3d18c9 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -793,7 +793,6 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) g_object_unref (session_pool); - /* simple SETUP with a valid URI and multicast, but an invalid prt */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); @@ -813,7 +812,6 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) g_object_unref (session_pool); - /* simple SETUP with a valid URI and multicast, but an invalid ttl */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); @@ -832,7 +830,6 @@ GST_START_TEST (test_client_multicast_invalid_transport_specific) fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); g_object_unref (session_pool); - teardown_client (client); g_object_unref (ctx.auth); gst_rtsp_token_unref (ctx.token); diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index b0ddb19967..cf098147ae 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -21,7 +21,73 @@ #include -GST_START_TEST (test_launch) +GST_START_TEST (test_media_seek) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPStream *stream; + GstRTSPTimeRange *range; + gchar *str; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + GstRTSPTransport *transport; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + fail_unless (gst_rtsp_media_n_streams (media) == 1); + + stream = gst_rtsp_media_get_stream (media, 0); + fail_unless (stream != NULL); + + pool = gst_rtsp_thread_pool_new (); + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + + fail_unless (gst_rtsp_media_prepare (media, thread)); + + /* define transport */ + fail_unless (gst_rtsp_transport_new (&transport) == GST_RTSP_OK); + transport->lower_transport = GST_RTSP_LOWER_TRANS_TCP; + + fail_unless (gst_rtsp_stream_complete_stream (stream, transport)); + + fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK); + fail_unless (gst_rtsp_range_parse ("npt=5.0-", &range) == GST_RTSP_OK); + + /* the media is seekable now */ + fail_unless (gst_rtsp_media_seek (media, range)); + + str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT); + fail_unless (g_str_equal (str, "npt=5-")); + + gst_rtsp_range_free (range); + g_free (str); + + fail_unless (gst_rtsp_media_unprepare (media)); + g_object_unref (media); + + gst_rtsp_url_free (url); + g_object_unref (factory); + + g_object_unref (pool); + + gst_rtsp_thread_pool_cleanup (); +} + +GST_END_TEST; + + +GST_START_TEST (test_media_seek_no_sinks) { GstRTSPMediaFactory *factory; GstRTSPMedia *media; @@ -70,15 +136,8 @@ GST_START_TEST (test_launch) fail_unless (g_str_equal (str, "npt=0-")); g_free (str); - fail_unless (gst_rtsp_media_seek (media, range)); - - str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT); - fail_unless (g_str_equal (str, "npt=5-")); - g_free (str); - - str = gst_rtsp_media_get_range_string (media, TRUE, GST_RTSP_RANGE_NPT); - fail_unless (g_str_equal (str, "npt=5-")); - g_free (str); + /* fails, need to be prepared and contain sink elements */ + fail_if (gst_rtsp_media_seek (media, range)); fail_unless (gst_rtsp_media_unprepare (media)); @@ -126,12 +185,13 @@ GST_START_TEST (test_media) GST_END_TEST; static void -test_prepare_reusable (GstRTSPThreadPool * pool, const gchar * launch_line) +test_prepare_reusable (const gchar * launch_line) { GstRTSPMediaFactory *factory; GstRTSPMedia *media; GstRTSPUrl *url; GstRTSPThread *thread; + GstRTSPThreadPool *pool; factory = gst_rtsp_media_factory_new (); fail_if (gst_rtsp_media_factory_is_shared (factory)); @@ -146,6 +206,7 @@ test_prepare_reusable (GstRTSPThreadPool * pool, const gchar * launch_line) g_object_set (G_OBJECT (media), "reusable", TRUE, NULL); + pool = gst_rtsp_thread_pool_new (); thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); @@ -162,6 +223,17 @@ test_prepare_reusable (GstRTSPThreadPool * pool, const gchar * launch_line) g_object_unref (factory); } +GST_START_TEST (test_media_reusable) +{ + + /* test reusable media */ + test_prepare_reusable ("( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + test_prepare_reusable ( + "( videotestsrc is-live=true ! rtpvrawpay pt=96 name=pay0 )"); +} + +GST_END_TEST; + GST_START_TEST (test_media_prepare) { GstRTSPMediaFactory *factory; @@ -199,11 +271,6 @@ GST_START_TEST (test_media_prepare) gst_rtsp_url_free (url); g_object_unref (factory); - /* test reusable media */ - test_prepare_reusable (pool, "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); - test_prepare_reusable (pool, - "( videotestsrc is-live=true ! rtpvrawpay pt=96 name=pay0 )"); - g_object_unref (pool); gst_rtsp_thread_pool_cleanup (); } @@ -454,9 +521,11 @@ rtspmedia_suite (void) suite_add_tcase (s, tc); tcase_set_timeout (tc, 20); - tcase_add_test (tc, test_launch); + tcase_add_test (tc, test_media_seek); + tcase_add_test (tc, test_media_seek_no_sinks); tcase_add_test (tc, test_media); tcase_add_test (tc, test_media_prepare); + tcase_add_test (tc, test_media_reusable); tcase_add_test (tc, test_media_dyn_prepare); tcase_add_test (tc, test_media_take_pipeline); tcase_add_test (tc, test_media_reset); diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 7f636f5fad..7ed151672d 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1058,6 +1058,74 @@ done: gst_buffer_unref (buffer); } +static void +do_test_play_tcp_full (const gchar * range) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + const gchar *audio_control; + GstRTSPRange client_port; + gchar *session = NULL; + GstRTSPTransport *video_transport = NULL; + GstRTSPTransport *audio_transport = NULL; + gchar *range_out = NULL; + GstRTSPLowerTrans lower_transport = GST_RTSP_LOWER_TRANS_TCP; + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + get_client_ports (&client_port); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + sdp_media = gst_sdp_message_get_media (sdp_message, 1); + audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + /* do SETUP for video and audio */ + fail_unless (do_setup_full (conn, video_control, lower_transport, + &client_port, NULL, &session, &video_transport, + NULL) == GST_RTSP_STS_OK); + fail_unless (do_setup_full (conn, audio_control, lower_transport, + &client_port, NULL, &session, &audio_transport, + NULL) == GST_RTSP_STS_OK); + + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_request (conn, GST_RTSP_PLAY, NULL, session, NULL, range, + NULL, NULL, NULL, NULL, NULL, &range_out) == GST_RTSP_STS_OK); + + if (range) + fail_unless_equals_string (range, range_out); + g_free (range_out); + + { + GstRTSPMessage *message; + fail_unless (gst_rtsp_message_new (&message) == GST_RTSP_OK); + fail_unless (gst_rtsp_connection_receive (conn, message, NULL) == GST_RTSP_OK); + fail_unless (gst_rtsp_message_get_type (message) == GST_RTSP_MESSAGE_DATA); + gst_rtsp_message_free (message); + } + + /* send TEARDOWN request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session) == GST_RTSP_STS_OK); + + /* FIXME: The rtsp-server always disconnects the transport before + * sending the RTCP BYE + * receive_rtcp (rtcp_socket, NULL, GST_RTCP_TYPE_BYE); + */ + + /* clean up and iterate so the clean-up can finish */ + g_free (session); + gst_rtsp_transport_free (video_transport); + gst_rtsp_transport_free (audio_transport); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); +} + static void do_test_play_full (const gchar * range, GstRTSPLowerTrans lower_transport, GMutex * lock) @@ -1579,6 +1647,70 @@ GST_START_TEST (test_no_session_timeout) GST_END_TEST; +/* media contains two streams: video and audio but only one + * stream is requested */ +GST_START_TEST (test_play_one_active_stream) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + GstRTSPRange client_port; + gchar *session = NULL; + GstRTSPTransport *video_transport = NULL; + GstRTSPSessionPool *pool; + GstRTSPThreadPool *thread_pool; + + thread_pool = gst_rtsp_server_get_thread_pool (server); + gst_rtsp_thread_pool_set_max_threads (thread_pool, 2); + g_object_unref (thread_pool); + + pool = gst_rtsp_server_get_session_pool (server); + g_signal_connect (server, "client-connected", + G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one); + + start_server (FALSE); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + gst_rtsp_connection_set_remember_session_id (conn, FALSE); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports (&client_port); + + /* do SETUP for video only */ + fail_unless (do_setup (conn, video_control, &client_port, &session, + &video_transport) == GST_RTSP_STS_OK); + + fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 1); + + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_PLAY, + session) == GST_RTSP_STS_OK); + + + /* send TEARDOWN request */ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session) == GST_RTSP_STS_OK); + + /* clean up and iterate so the clean-up can finish */ + g_object_unref (pool); + g_free (session); + gst_rtsp_transport_free (video_transport); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + + stop_server (); + iterate (); +} + +GST_END_TEST; GST_START_TEST (test_play_disconnect) { @@ -1772,6 +1904,22 @@ GST_START_TEST (test_play_smpte_range) GST_END_TEST; +GST_START_TEST (test_play_smpte_range_tcp) +{ + start_tcp_server (); + + do_test_play_tcp_full ("npt=5-"); + do_test_play_tcp_full ("smpte=0:00:00-"); + do_test_play_tcp_full ("smpte=1:00:00-"); + do_test_play_tcp_full ("smpte=1:00:03-"); + do_test_play_tcp_full ("clock=20120321T152256Z-"); + + stop_server (); + iterate (); +} + +GST_END_TEST; + static gpointer thread_func (gpointer data) { @@ -2112,6 +2260,113 @@ GST_START_TEST (test_record_tcp) GST_END_TEST; +static void +do_test_multiple_transports (GstRTSPLowerTrans trans1, GstRTSPLowerTrans trans2) +{ + GstRTSPConnection *conn1; + GstRTSPConnection *conn2; + GstSDPMessage *sdp_message1 = NULL; + GstSDPMessage *sdp_message2 = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + const gchar *audio_control; + GstRTSPRange client_port1, client_port2; + gchar *session1 = NULL; + gchar *session2 = NULL; + GstRTSPTransport *video_transport = NULL; + GstRTSPTransport *audio_transport = NULL; + GSocket *rtp_socket, *rtcp_socket; + + conn1 = connect_to_server (test_port, TEST_MOUNT_POINT); + conn2 = connect_to_server (test_port, TEST_MOUNT_POINT); + + sdp_message1 = do_describe (conn1, TEST_MOUNT_POINT); + + get_client_ports_full (&client_port1, &rtp_socket, &rtcp_socket); + /* get control strings from DESCRIBE response */ + sdp_media = gst_sdp_message_get_media (sdp_message1, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + sdp_media = gst_sdp_message_get_media (sdp_message1, 1); + audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + /* do SETUP for video and audio */ + fail_unless (do_setup_full (conn1, video_control, trans1, + &client_port1, NULL, &session1, &video_transport, + NULL) == GST_RTSP_STS_OK); + fail_unless (do_setup_full (conn1, audio_control, trans1, + &client_port1, NULL, &session1, &audio_transport, + NULL) == GST_RTSP_STS_OK); + + gst_rtsp_transport_free (video_transport); + gst_rtsp_transport_free (audio_transport); + + sdp_message2 = do_describe (conn2, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + sdp_media = gst_sdp_message_get_media (sdp_message2, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + sdp_media = gst_sdp_message_get_media (sdp_message2, 1); + audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports_full (&client_port2, NULL, NULL); + /* do SETUP for video and audio */ + fail_unless (do_setup_full (conn2, video_control, trans2, + &client_port2, NULL, &session2, &video_transport, + NULL) == GST_RTSP_STS_OK); + fail_unless (do_setup_full (conn2, audio_control, trans2, + &client_port2, NULL, &session2, &audio_transport, + NULL) == GST_RTSP_STS_OK); + + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_request (conn1, GST_RTSP_PLAY, NULL, session1, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL) == GST_RTSP_STS_OK); + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_request (conn2, GST_RTSP_PLAY, NULL, session2, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL) == GST_RTSP_STS_OK); + + + /* receive UDP data */ + receive_rtp (rtp_socket, NULL); + receive_rtcp (rtcp_socket, NULL, 0); + + /* receive TCP data */ + { + GstRTSPMessage *message; + fail_unless (gst_rtsp_message_new (&message) == GST_RTSP_OK); + fail_unless (gst_rtsp_connection_receive (conn2, message, NULL) == GST_RTSP_OK); + fail_unless (gst_rtsp_message_get_type (message) == GST_RTSP_MESSAGE_DATA); + gst_rtsp_message_free (message); + } + + /* send TEARDOWN request and check that we get 200 OK */ + fail_unless (do_simple_request (conn1, GST_RTSP_TEARDOWN, + session1) == GST_RTSP_STS_OK); + /* send TEARDOWN request and check that we get 200 OK */ + fail_unless (do_simple_request (conn2, GST_RTSP_TEARDOWN, + session2) == GST_RTSP_STS_OK); + + /* clean up and iterate so the clean-up can finish */ + g_object_unref (rtp_socket); + g_object_unref (rtcp_socket); + g_free (session1); + g_free (session2); + gst_rtsp_transport_free (video_transport); + gst_rtsp_transport_free (audio_transport); + gst_sdp_message_free (sdp_message1); + gst_sdp_message_free (sdp_message2); + gst_rtsp_connection_free (conn1); + gst_rtsp_connection_free (conn2); +} + +GST_START_TEST (test_multiple_transports) +{ + start_server (TRUE); + do_test_multiple_transports (GST_RTSP_LOWER_TRANS_UDP, GST_RTSP_LOWER_TRANS_TCP); + stop_server (); +} + +GST_END_TEST; + static Suite * rtspserver_suite (void) { @@ -2140,12 +2395,16 @@ rtspserver_suite (void) tcase_add_test (tc, test_play_multithreaded_timeout_client); tcase_add_test (tc, test_play_multithreaded_timeout_session); tcase_add_test (tc, test_no_session_timeout); + tcase_add_test (tc, test_play_one_active_stream); tcase_add_test (tc, test_play_disconnect); tcase_add_test (tc, test_play_specific_server_port); tcase_add_test (tc, test_play_smpte_range); + tcase_add_test (tc, test_play_smpte_range_tcp); tcase_add_test (tc, test_shared); tcase_add_test (tc, test_announce_without_sdp); tcase_add_test (tc, test_record_tcp); + tcase_add_test (tc, test_multiple_transports); + return s; } diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index 979c0d65aa..759b7beeae 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -22,7 +22,8 @@ #include #include -GST_START_TEST (test_get_sockets) +static void +get_sockets (GstRTSPLowerTrans lower_transport, GSocketFamily socket_family) { GstPad *srcpad; GstElement *pay; @@ -33,6 +34,7 @@ GST_START_TEST (test_get_sockets) GSocket *socket; gboolean have_ipv4; gboolean have_ipv6; + GstRTSPTransport *transport; srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); fail_unless (srcpad != NULL); @@ -57,18 +59,44 @@ GST_START_TEST (test_get_sockets) fail_unless (gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV6, GST_RTSP_ADDRESS_POOL_ANY_IPV6, 50000, 60000, 0)); + fail_unless (gst_rtsp_address_pool_add_range (pool, "233.252.0.0", + "233.252.0.0", 50000, 60000, 1)); + fail_unless (gst_rtsp_address_pool_add_range (pool, "FF11:DB8::1", + "FF11:DB8::1", 50000, 60000, 1)); gst_rtsp_stream_set_address_pool (stream, pool); fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); - socket = gst_rtsp_stream_get_rtp_socket (stream, G_SOCKET_FAMILY_IPV4); + /* allocate udp ports first */ + fail_unless (gst_rtsp_transport_new (&transport) == GST_RTSP_OK); + transport->lower_transport = lower_transport; + + /* no ports allocated, complete stream should fail */ + fail_if (gst_rtsp_stream_complete_stream (stream, transport)); + + /* allocate ports */ + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, + socket_family, transport, FALSE)); + + fail_unless (gst_rtsp_stream_complete_stream (stream, transport)); + fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK); + + if (lower_transport == GST_RTSP_LOWER_TRANS_UDP) + socket = gst_rtsp_stream_get_rtp_socket (stream, G_SOCKET_FAMILY_IPV4); + else + socket = gst_rtsp_stream_get_rtp_multicast_socket (stream, + G_SOCKET_FAMILY_IPV4); have_ipv4 = (socket != NULL); if (have_ipv4) { fail_unless (g_socket_get_fd (socket) >= 0); g_object_unref (socket); } - socket = gst_rtsp_stream_get_rtcp_socket (stream, G_SOCKET_FAMILY_IPV4); + if (lower_transport == GST_RTSP_LOWER_TRANS_UDP) + socket = gst_rtsp_stream_get_rtcp_socket (stream, G_SOCKET_FAMILY_IPV4); + else + socket = gst_rtsp_stream_get_rtcp_multicast_socket (stream, + G_SOCKET_FAMILY_IPV4); if (have_ipv4) { fail_unless (socket != NULL); fail_unless (g_socket_get_fd (socket) >= 0); @@ -77,14 +105,22 @@ GST_START_TEST (test_get_sockets) fail_unless (socket == NULL); } - socket = gst_rtsp_stream_get_rtp_socket (stream, G_SOCKET_FAMILY_IPV6); + if (lower_transport == GST_RTSP_LOWER_TRANS_UDP) + socket = gst_rtsp_stream_get_rtp_socket (stream, G_SOCKET_FAMILY_IPV6); + else + socket = gst_rtsp_stream_get_rtp_multicast_socket (stream, + G_SOCKET_FAMILY_IPV6); have_ipv6 = (socket != NULL); if (have_ipv6) { fail_unless (g_socket_get_fd (socket) >= 0); g_object_unref (socket); } - socket = gst_rtsp_stream_get_rtcp_socket (stream, G_SOCKET_FAMILY_IPV6); + if (lower_transport == GST_RTSP_LOWER_TRANS_UDP) + socket = gst_rtsp_stream_get_rtcp_socket (stream, G_SOCKET_FAMILY_IPV6); + else + socket = gst_rtsp_stream_get_rtcp_multicast_socket (stream, + G_SOCKET_FAMILY_IPV6); if (have_ipv6) { fail_unless (socket != NULL); fail_unless (g_socket_get_fd (socket) >= 0); @@ -104,8 +140,25 @@ GST_START_TEST (test_get_sockets) gst_object_unref (stream); } +GST_START_TEST (test_get_sockets_udp) +{ + get_sockets (GST_RTSP_LOWER_TRANS_UDP, G_SOCKET_FAMILY_IPV4); + get_sockets (GST_RTSP_LOWER_TRANS_UDP, G_SOCKET_FAMILY_IPV6); +} + GST_END_TEST; +GST_START_TEST (test_get_sockets_mcast) +{ + get_sockets (GST_RTSP_LOWER_TRANS_UDP_MCAST, G_SOCKET_FAMILY_IPV4); + get_sockets (GST_RTSP_LOWER_TRANS_UDP_MCAST, G_SOCKET_FAMILY_IPV6); +} + +GST_END_TEST; + +/* The purpose of this test is to make sure that it's not possible to allocate + * multicast UDP ports if the address pool does not contain multicast UDP + * addresses. */ GST_START_TEST (test_allocate_udp_ports_fail) { GstPad *srcpad; @@ -114,6 +167,7 @@ GST_START_TEST (test_allocate_udp_ports_fail) GstBin *bin; GstElement *rtpbin; GstRTSPAddressPool *pool; + GstRTSPTransport *transport; srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); fail_unless (srcpad != NULL); @@ -135,7 +189,13 @@ GST_START_TEST (test_allocate_udp_ports_fail) "192.168.1.1", 6000, 6001, 0)); gst_rtsp_stream_set_address_pool (stream, pool); - fail_if (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + + fail_unless (gst_rtsp_transport_new (&transport) == GST_RTSP_OK); + transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST; + fail_if (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, + transport, FALSE)); + fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK); g_object_unref (pool); fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); @@ -433,7 +493,8 @@ rtspstream_suite (void) TCase *tc = tcase_create ("general"); suite_add_tcase (s, tc); - tcase_add_test (tc, test_get_sockets); + tcase_add_test (tc, test_get_sockets_udp); + tcase_add_test (tc, test_get_sockets_mcast); tcase_add_test (tc, test_allocate_udp_ports_fail); tcase_add_test (tc, test_get_multicast_address); tcase_add_test (tc, test_multicast_address_and_unicast_udp); From efdb795c86d5e9fbc25da52406c0791ebccb0b05 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Mon, 23 Oct 2017 09:49:09 +0200 Subject: [PATCH 1395/1776] rtsp-media: seek on media pipelines that are complete Make sure that a seek is performed on pipelines that contain at least one sink element. Change-Id: Icf398e10add3191d104b1289de612412da326819 https://bugzilla.gnome.org/show_bug.cgi?id=788340 --- gst/rtsp-server/rtsp-media.c | 28 +++++++++++++++++ gst/rtsp-server/rtsp-stream.c | 59 +++++++++++++++++++++++++---------- gst/rtsp-server/rtsp-stream.h | 3 ++ 3 files changed, 73 insertions(+), 17 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 159dd3d447..0f8a194b5d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -705,6 +705,23 @@ check_seekable (GstRTSPMedia * media) gst_query_unref (query); } +/* must be called with state lock */ +static gboolean +check_complete (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + + guint i, n = priv->streams->len; + + for (i = 0; i < n; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + + if (gst_rtsp_stream_is_complete (stream)) + return TRUE; + } + + return FALSE; +} /* must be called with state lock */ static void @@ -2209,6 +2226,11 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) goto not_prepared; + /* check if the media pipeline is complete in order to perform a + * seek operation on it */ + if (!check_complete (media)) + goto not_complete; + /* Update the seekable state of the pipeline in case it changed */ check_seekable (media); @@ -2322,6 +2344,12 @@ not_prepared: GST_INFO ("media %p is not prepared", media); return FALSE; } +not_complete: + { + g_rec_mutex_unlock (&priv->state_lock); + GST_INFO ("pipeline is not complete"); + return FALSE; + } not_seekable: { g_rec_mutex_unlock (&priv->state_lock); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 9a8f1c21c4..67c02d1244 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -77,6 +77,9 @@ struct _GstRTSPStreamPrivate gboolean client_side; gchar *control; + /* TRUE if stream is complete. This means that the receiver and the sender + * parts are present in the stream. */ + gboolean is_complete; GstRTSPProfile profiles; GstRTSPLowerTrans protocols; @@ -273,6 +276,7 @@ gst_rtsp_stream_finalize (GObject * obj) { GstRTSPStream *stream; GstRTSPStreamPrivate *priv; + guint i; stream = GST_RTSP_STREAM (obj); priv = stream->priv; @@ -295,22 +299,16 @@ gst_rtsp_stream_finalize (GObject * obj) if (priv->rtxsend) g_object_unref (priv->rtxsend); - if (priv->socket_v4[0]) - g_object_unref (priv->socket_v4[0]); - if (priv->socket_v4[1]) - g_object_unref (priv->socket_v4[1]); - if (priv->socket_v6[0]) - g_object_unref (priv->socket_v6[0]); - if (priv->socket_v6[1]) - g_object_unref (priv->socket_v6[1]); - if (priv->mcast_socket_v4[0]) - g_object_unref (priv->mcast_socket_v4[0]); - if (priv->mcast_socket_v4[1]) - g_object_unref (priv->mcast_socket_v4[1]); - if (priv->mcast_socket_v6[0]) - g_object_unref (priv->mcast_socket_v6[0]); - if (priv->mcast_socket_v6[1]) - g_object_unref (priv->mcast_socket_v6[1]); + for (i = 0; i < 2; i++) { + if (priv->socket_v4[i]) + g_object_unref (priv->socket_v4[i]); + if (priv->socket_v6[i]) + g_object_unref (priv->socket_v6[i]); + if (priv->mcast_socket_v4[i]) + g_object_unref (priv->mcast_socket_v4[i]); + if (priv->mcast_socket_v6[i]) + g_object_unref (priv->mcast_socket_v6[i]); + } g_free (priv->multicast_iface); @@ -4455,7 +4453,7 @@ gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop) * Add a receiver and sender part to the pipeline based on the transport from * SETUP. * - * Returns: %TRUE if the pipeline has been sucessfully updated. + * Returns: %TRUE if the stream has been sucessfully updated. */ gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, @@ -4480,6 +4478,7 @@ gst_rtsp_stream_complete_stream (GstRTSPStream * stream, if (!create_sender_part (stream, transport)) goto create_sender_error; + priv->is_complete = TRUE; g_mutex_unlock (&priv->lock); GST_DEBUG_OBJECT (stream, "pipeline sucsessfully updated"); @@ -4493,3 +4492,29 @@ unallowed_transport: return FALSE; } } + +/** + * gst_rtsp_stream_is_complete: + * @stream: a #GstRTSPStream + * + * Checks whether the stream is complete, contains the receiver and the sender + * parts. As the stream contains sink(s) element(s), it's possible to perform + * seek operations on it. + * + * Returns: %TRUE if the stream contains at least one sink element. + */ +gboolean +gst_rtsp_stream_is_complete (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + gboolean ret = FALSE; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + g_mutex_lock (&priv->lock); + ret = priv->is_complete; + g_mutex_unlock (&priv->lock); + + return ret; +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index add1a88960..37a8275c02 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -287,6 +287,9 @@ GstRTSPPublishClockMode gst_rtsp_stream_get_publish_clock_mode (GstRTSPStream * GST_EXPORT gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GstRTSPTransport * transport); +GST_EXPORT +gboolean gst_rtsp_stream_is_complete (GstRTSPStream * stream); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object From bed93b915d8a4be12a2ab71ed10f919d55519b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 15 Nov 2017 18:15:53 +0200 Subject: [PATCH 1396/1776] win32: Update exports --- win32/common/libgstrtspserver.def | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/win32/common/libgstrtspserver.def b/win32/common/libgstrtspserver.def index 68601bfead..9fc0609d09 100644 --- a/win32/common/libgstrtspserver.def +++ b/win32/common/libgstrtspserver.def @@ -51,10 +51,13 @@ EXPORTS gst_rtsp_context_pop_current gst_rtsp_context_push_current gst_rtsp_media_collect_streams + gst_rtsp_media_complete_pipeline gst_rtsp_media_create_stream gst_rtsp_media_factory_add_role gst_rtsp_media_factory_construct + gst_rtsp_media_factory_construct_full gst_rtsp_media_factory_create_element + gst_rtsp_media_factory_create_element_full gst_rtsp_media_factory_get_address_pool gst_rtsp_media_factory_get_buffer_size gst_rtsp_media_factory_get_clock @@ -116,6 +119,7 @@ EXPORTS gst_rtsp_media_get_transport_mode gst_rtsp_media_get_type gst_rtsp_media_handle_sdp + gst_rtsp_media_handle_sdp_full gst_rtsp_media_is_eos_shutdown gst_rtsp_media_is_reusable gst_rtsp_media_is_shared @@ -146,6 +150,7 @@ EXPORTS gst_rtsp_media_set_suspend_mode gst_rtsp_media_set_transport_mode gst_rtsp_media_setup_sdp + gst_rtsp_media_setup_sdp_full gst_rtsp_media_suspend gst_rtsp_media_take_pipeline gst_rtsp_media_unprepare @@ -157,6 +162,20 @@ EXPORTS gst_rtsp_mount_points_match gst_rtsp_mount_points_new gst_rtsp_mount_points_remove_factory + gst_rtsp_onvif_client_get_type + gst_rtsp_onvif_media_collect_backchannel + gst_rtsp_onvif_media_factory_get_backchannel_bandwidth + gst_rtsp_onvif_media_factory_get_backchannel_launch + gst_rtsp_onvif_media_factory_get_type + gst_rtsp_onvif_media_factory_has_backchannel_support + gst_rtsp_onvif_media_factory_new + gst_rtsp_onvif_media_factory_set_backchannel_bandwidth + gst_rtsp_onvif_media_factory_set_backchannel_launch + gst_rtsp_onvif_media_get_backchannel_bandwidth + gst_rtsp_onvif_media_get_type + gst_rtsp_onvif_media_set_backchannel_bandwidth + gst_rtsp_onvif_server_get_type + gst_rtsp_onvif_server_new gst_rtsp_params_get gst_rtsp_params_set gst_rtsp_permissions_add_role @@ -169,6 +188,7 @@ EXPORTS gst_rtsp_publish_clock_mode_get_type gst_rtsp_sdp_from_media gst_rtsp_sdp_from_stream + gst_rtsp_sdp_make_media gst_rtsp_server_attach gst_rtsp_server_client_filter gst_rtsp_server_create_socket @@ -208,6 +228,7 @@ EXPORTS gst_rtsp_session_media_get_rtpinfo gst_rtsp_session_media_get_rtsp_state gst_rtsp_session_media_get_transport + gst_rtsp_session_media_get_transports gst_rtsp_session_media_get_type gst_rtsp_session_media_matches gst_rtsp_session_media_new @@ -234,6 +255,7 @@ EXPORTS gst_rtsp_session_touch gst_rtsp_stream_add_transport gst_rtsp_stream_allocate_udp_sockets + gst_rtsp_stream_complete_stream gst_rtsp_stream_get_address_pool gst_rtsp_stream_get_buffer_size gst_rtsp_stream_get_caps @@ -251,7 +273,9 @@ EXPORTS gst_rtsp_stream_get_publish_clock_mode gst_rtsp_stream_get_retransmission_pt gst_rtsp_stream_get_retransmission_time + gst_rtsp_stream_get_rtcp_multicast_socket gst_rtsp_stream_get_rtcp_socket + gst_rtsp_stream_get_rtp_multicast_socket gst_rtsp_stream_get_rtp_socket gst_rtsp_stream_get_rtpinfo gst_rtsp_stream_get_rtpsession @@ -264,6 +288,7 @@ EXPORTS gst_rtsp_stream_has_control gst_rtsp_stream_is_blocking gst_rtsp_stream_is_client_side + gst_rtsp_stream_is_complete gst_rtsp_stream_is_transport_supported gst_rtsp_stream_join_bin gst_rtsp_stream_leave_bin @@ -308,6 +333,7 @@ EXPORTS gst_rtsp_stream_transport_set_timed_out gst_rtsp_stream_transport_set_transport gst_rtsp_stream_transport_set_url + gst_rtsp_stream_unblock_linked gst_rtsp_stream_update_crypto gst_rtsp_suspend_mode_get_type gst_rtsp_thread_get_type From d51f8abe567587343cad0ad096e4740e9969b17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 15 Nov 2017 19:52:29 +0200 Subject: [PATCH 1397/1776] rtsp-stream: Only update the RTP udpsink if it actually exists For send-only streams it does not exist, but the RTCP udpsink might. --- gst/rtsp-server/rtsp-stream.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 67c02d1244..2b4c1ecbe4 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -3725,16 +3725,19 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, if (add) { if (ttl > 0) { GST_INFO ("setting ttl-mc %d", ttl); - g_object_set (G_OBJECT (priv->udpsink[0]), "ttl-mc", ttl, NULL); + if (priv->udpsink[0]) + g_object_set (G_OBJECT (priv->udpsink[0]), "ttl-mc", ttl, NULL); g_object_set (G_OBJECT (priv->udpsink[1]), "ttl-mc", ttl, NULL); } GST_INFO ("adding %s:%d-%d", dest, min, max); - g_signal_emit_by_name (priv->udpsink[0], "add", dest, min, NULL); + if (priv->udpsink[0]) + g_signal_emit_by_name (priv->udpsink[0], "add", dest, min, NULL); g_signal_emit_by_name (priv->udpsink[1], "add", dest, max, NULL); priv->transports = g_list_prepend (priv->transports, trans); } else { GST_INFO ("removing %s:%d-%d", dest, min, max); - g_signal_emit_by_name (priv->udpsink[0], "remove", dest, min, NULL); + if (priv->udpsink[0]) + g_signal_emit_by_name (priv->udpsink[0], "remove", dest, min, NULL); g_signal_emit_by_name (priv->udpsink[1], "remove", dest, max, NULL); priv->transports = g_list_remove (priv->transports, trans); } From 899a6cbe3574bb67547062f0f14e916f9bc0778a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 16 Nov 2017 12:18:20 +0200 Subject: [PATCH 1398/1776] win32: Fix exported symbols list --- win32/common/libgstrtspserver.def | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/win32/common/libgstrtspserver.def b/win32/common/libgstrtspserver.def index 9fc0609d09..c624920219 100644 --- a/win32/common/libgstrtspserver.def +++ b/win32/common/libgstrtspserver.def @@ -55,9 +55,7 @@ EXPORTS gst_rtsp_media_create_stream gst_rtsp_media_factory_add_role gst_rtsp_media_factory_construct - gst_rtsp_media_factory_construct_full gst_rtsp_media_factory_create_element - gst_rtsp_media_factory_create_element_full gst_rtsp_media_factory_get_address_pool gst_rtsp_media_factory_get_buffer_size gst_rtsp_media_factory_get_clock @@ -119,7 +117,6 @@ EXPORTS gst_rtsp_media_get_transport_mode gst_rtsp_media_get_type gst_rtsp_media_handle_sdp - gst_rtsp_media_handle_sdp_full gst_rtsp_media_is_eos_shutdown gst_rtsp_media_is_reusable gst_rtsp_media_is_shared @@ -150,7 +147,6 @@ EXPORTS gst_rtsp_media_set_suspend_mode gst_rtsp_media_set_transport_mode gst_rtsp_media_setup_sdp - gst_rtsp_media_setup_sdp_full gst_rtsp_media_suspend gst_rtsp_media_take_pipeline gst_rtsp_media_unprepare @@ -162,20 +158,6 @@ EXPORTS gst_rtsp_mount_points_match gst_rtsp_mount_points_new gst_rtsp_mount_points_remove_factory - gst_rtsp_onvif_client_get_type - gst_rtsp_onvif_media_collect_backchannel - gst_rtsp_onvif_media_factory_get_backchannel_bandwidth - gst_rtsp_onvif_media_factory_get_backchannel_launch - gst_rtsp_onvif_media_factory_get_type - gst_rtsp_onvif_media_factory_has_backchannel_support - gst_rtsp_onvif_media_factory_new - gst_rtsp_onvif_media_factory_set_backchannel_bandwidth - gst_rtsp_onvif_media_factory_set_backchannel_launch - gst_rtsp_onvif_media_get_backchannel_bandwidth - gst_rtsp_onvif_media_get_type - gst_rtsp_onvif_media_set_backchannel_bandwidth - gst_rtsp_onvif_server_get_type - gst_rtsp_onvif_server_new gst_rtsp_params_get gst_rtsp_params_set gst_rtsp_permissions_add_role @@ -188,7 +170,6 @@ EXPORTS gst_rtsp_publish_clock_mode_get_type gst_rtsp_sdp_from_media gst_rtsp_sdp_from_stream - gst_rtsp_sdp_make_media gst_rtsp_server_attach gst_rtsp_server_client_filter gst_rtsp_server_create_socket From 2386e91c3642f3a83de6a74c981e0b9ac85a3dd1 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 20 Nov 2017 09:32:07 +0100 Subject: [PATCH 1399/1776] rtsp-media: Handle multiple dynamic elements If we have more than one dynamic payloader in the pipeline, we need to wait until the *last* one emits 'no-more-pads' before switching to PREPARED. Failure to do so would result in a race where some of the streams wouldn't properly be prepared https://bugzilla.gnome.org/show_bug.cgi?id=769521 --- gst/rtsp-server/rtsp-media.c | 17 +++++++++++++++-- tests/check/gst/media.c | 10 +++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 0f8a194b5d..0a9898b225 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -142,6 +142,10 @@ struct _GstRTSPMediaPrivate guint latency; /* protected by lock */ GstClock *clock; /* protected by lock */ GstRTSPPublishClockMode publish_clock_mode; + + /* Dynamic element handling */ + guint nb_dynamic_elements; + guint no_more_pads_pending; }; #define DEFAULT_SHARED FALSE @@ -1821,6 +1825,8 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) gst_object_unref (pad); gst_object_unref (elem); + priv->nb_dynamic_elements++; + have_elem = TRUE; more_elem_remaining = TRUE; mode |= GST_RTSP_TRANSPORT_MODE_RECORD; @@ -2743,9 +2749,15 @@ static void no_more_pads_cb (GstElement * element, GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; + gboolean remaining_dynamic; - GST_INFO ("no more pads"); - remove_fakesink (priv); + GST_INFO_OBJECT (element, "no more pads"); + g_mutex_lock (&priv->lock); + priv->no_more_pads_pending--; + remaining_dynamic = priv->no_more_pads_pending; + g_mutex_unlock (&priv->lock); + if (remaining_dynamic == 0) + remove_fakesink (priv); } typedef struct _DynPaySignalHandlers DynPaySignalHandlers; @@ -3047,6 +3059,7 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GstRTSPThread * thread) priv->is_live = FALSE; priv->seekable = -1; priv->buffering = FALSE; + priv->no_more_pads_pending = priv->nb_dynamic_elements; /* we're preparing now */ gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index cf098147ae..b734673e6f 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -486,21 +486,21 @@ GST_START_TEST (test_media_multidyn_prepare) pool = gst_rtsp_thread_pool_new (); - fail_unless (gst_rtsp_media_n_streams (media) == 0); + fail_unless_equals_int (gst_rtsp_media_n_streams (media), 0); thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); - fail_unless (gst_rtsp_media_n_streams (media) == 2); + fail_unless_equals_int (gst_rtsp_media_n_streams (media), 2); fail_unless (gst_rtsp_media_unprepare (media)); - fail_unless (gst_rtsp_media_n_streams (media) == 0); + fail_unless_equals_int (gst_rtsp_media_n_streams (media), 0); thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); - fail_unless (gst_rtsp_media_n_streams (media) == 2); + fail_unless_equals_int (gst_rtsp_media_n_streams (media), 2); fail_unless (gst_rtsp_media_unprepare (media)); - fail_unless (gst_rtsp_media_n_streams (media) == 0); + fail_unless_equals_int (gst_rtsp_media_n_streams (media), 0); gst_object_unref (srcpad0); gst_object_unref (srcpad1); From 27d256d4caca3aec4342ce5d5d18502315939dbd Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 20 Nov 2017 18:29:02 +0100 Subject: [PATCH 1400/1776] rtsp-media: Fix previous commit We only want to count dynamic payloaders --- gst/rtsp-server/rtsp-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 0a9898b225..f9914b0bc5 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1808,6 +1808,8 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) priv->dynamic = g_list_prepend (priv->dynamic, elem); g_mutex_unlock (&priv->lock); + priv->nb_dynamic_elements++; + have_elem = TRUE; more_elem_remaining = TRUE; mode |= GST_RTSP_TRANSPORT_MODE_PLAY; @@ -1825,8 +1827,6 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) gst_object_unref (pad); gst_object_unref (elem); - priv->nb_dynamic_elements++; - have_elem = TRUE; more_elem_remaining = TRUE; mode |= GST_RTSP_TRANSPORT_MODE_RECORD; From 0dddaba9bb764c86fb40028b2d1009cabd26e0c8 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 20 Nov 2017 16:48:55 +0100 Subject: [PATCH 1401/1776] rtsp-media: Don't set float on a gint64 variable Just use 0. Fixes 'undefined' behaviour from clang --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index f9914b0bc5..b554507cde 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -703,7 +703,7 @@ check_seekable (GstRTSPMedia * media) gint64 start, end; gst_query_parse_seeking (query, &format, &seekable, &start, &end); - priv->seekable = seekable ? G_MAXINT64 : 0.0; + priv->seekable = seekable ? G_MAXINT64 : 0; } gst_query_unref (query); From d1a6418fe29915b1ff6b91d8a252500a25f56c03 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 20 Nov 2017 16:49:29 +0100 Subject: [PATCH 1402/1776] rtsp-media: Fix doc --- gst/rtsp-server/rtsp-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b554507cde..8fe9efe7e5 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -4053,7 +4053,7 @@ gst_rtsp_media_get_transport_mode (GstRTSPMedia * media) } /** - * gst_rtsp_media_get_seekbale: + * gst_rtsp_media_get_seekable: * @media: a #GstRTSPMedia * * Check if the pipeline for @media seek and up to what point in time, @@ -4061,7 +4061,7 @@ gst_rtsp_media_get_transport_mode (GstRTSPMedia * media) * * Returns: -1 if the stream is not seekable, 0 if seekable only to the beginning * and > 0 to indicate the longest duration between any two random access points. - * G_MAXINT64 means any value is possible. + * %G_MAXINT64 means any value is possible. */ GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia * media) From 6371f2fc294ef427351a470532c27bfe2caa9acb Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 20 Nov 2017 18:30:19 +0100 Subject: [PATCH 1403/1776] rtsp-media: Don't unblock with remaining dynamic payloaders If we still have some dynamic paylaoders which haven't posted no-more-pads yet, don't go to PREPARED if one of the streams blocked. The risk was that we would end up not exposing/using all specified streams. The downside is that if you have _multiple_ _live_ _dynamic_ payloaders then it will take a bit more time to start. But only if those 3 conditions are present. https://bugzilla.gnome.org/show_bug.cgi?id=769521 --- gst/rtsp-server/rtsp-media.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 8fe9efe7e5..d158938614 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2555,8 +2555,9 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) s = gst_message_get_structure (message); if (gst_structure_has_name (s, "GstRTSPStreamBlocking")) { GST_DEBUG ("media received blocking message"); - if (priv->blocked && media_streams_blocking (media)) { - GST_DEBUG ("media is blocking"); + if (priv->blocked && media_streams_blocking (media) && + priv->no_more_pads_pending == 0) { + GST_DEBUG_OBJECT (GST_MESSAGE_SRC (message), "media is blocking"); collect_media_stats (media); if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) From 4d98bc5e5585db1c10c75e162336077ff6a08a71 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 21 Nov 2017 09:53:08 +0100 Subject: [PATCH 1404/1776] Run gst-indent --- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-session-media.c | 1 + gst/rtsp-server/rtsp-stream.c | 83 ++++++++++++++-------------- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 83131f34ef..e46f58740b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1814,7 +1814,7 @@ default_configure_client_transport (GstRTSPClient * client, use_client_settings = TRUE; if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, - use_client_settings)) + use_client_settings)) goto error_allocating_ports; if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 96ad1b63be..bb0dd8d4b5 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -431,6 +431,7 @@ gst_rtsp_session_media_get_transports (GstRTSPSessionMedia * media) return result; } + /** * gst_rtsp_session_media_alloc_channels: * @media: a #GstRTSPSessionMedia diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 2b4c1ecbe4..7b458b1bb4 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1124,8 +1124,7 @@ set_multicast_socket_for_udpsink (GstElement * udpsink, GSocket * socket, set_socket_for_udpsink (udpsink, socket, family); if (multicast_iface) { - g_object_set (G_OBJECT (udpsink), "multicast-iface", - multicast_iface, NULL); + g_object_set (G_OBJECT (udpsink), "multicast-iface", multicast_iface, NULL); } g_signal_emit_by_name (udpsink, "add", addr_str, port, NULL); @@ -1165,7 +1164,8 @@ get_port_from_socket (GSocket * socket) static gboolean create_and_configure_udpsink (GstRTSPStream * stream, GstElement ** udpsink, - GSocket *socket_v4, GSocket *socket_v6, gboolean multicast, gboolean is_rtp) + GSocket * socket_v4, GSocket * socket_v6, gboolean multicast, + gboolean is_rtp) { GstRTSPStreamPrivate *priv = stream->priv; @@ -1204,17 +1204,13 @@ create_and_configure_udpsink (GstRTSPStream * stream, GstElement ** udpsink, update_dscp_qos (stream, udpsink); if (priv->server_addr_v4) { - GST_DEBUG_OBJECT (stream, - "udp IPv4, configure udpsinks"); - set_unicast_socket_for_udpsink (*udpsink, socket_v4, - G_SOCKET_FAMILY_IPV4); + GST_DEBUG_OBJECT (stream, "udp IPv4, configure udpsinks"); + set_unicast_socket_for_udpsink (*udpsink, socket_v4, G_SOCKET_FAMILY_IPV4); } if (priv->server_addr_v6) { - GST_DEBUG_OBJECT (stream, - "udp IPv6, configure udpsinks"); - set_unicast_socket_for_udpsink (*udpsink, socket_v6, - G_SOCKET_FAMILY_IPV6); + GST_DEBUG_OBJECT (stream, "udp IPv6, configure udpsinks"); + set_unicast_socket_for_udpsink (*udpsink, socket_v6, G_SOCKET_FAMILY_IPV6); } if (multicast) { @@ -1225,7 +1221,8 @@ create_and_configure_udpsink (GstRTSPStream * stream, GstElement ** udpsink, if (!port) goto get_port_failed; set_multicast_socket_for_udpsink (*udpsink, socket_v4, - G_SOCKET_FAMILY_IPV4, priv->multicast_iface, priv->mcast_addr_v4->address, port); + G_SOCKET_FAMILY_IPV4, priv->multicast_iface, + priv->mcast_addr_v4->address, port); } if (priv->mcast_addr_v6) { @@ -1234,7 +1231,8 @@ create_and_configure_udpsink (GstRTSPStream * stream, GstElement ** udpsink, if (!port) goto get_port_failed; set_multicast_socket_for_udpsink (*udpsink, socket_v6, - G_SOCKET_FAMILY_IPV6, priv->multicast_iface, priv->mcast_addr_v6->address, port); + G_SOCKET_FAMILY_IPV6, priv->multicast_iface, + priv->mcast_addr_v6->address, port); } } @@ -1256,8 +1254,7 @@ get_port_failed: /* must be called with lock */ static gboolean -create_and_configure_udpsource (GstElement ** udpsrc, - GSocket * socket) +create_and_configure_udpsource (GstElement ** udpsrc, GSocket * socket) { GstStateChangeReturn ret; @@ -1296,7 +1293,7 @@ error: static gboolean alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, - GSocket *socket_out[2], GstRTSPAddress ** server_addr_out, + GSocket * socket_out[2], GstRTSPAddress ** server_addr_out, gboolean multicast, GstRTSPTransport * ct) { GstRTSPStreamPrivate *priv = stream->priv; @@ -1431,7 +1428,8 @@ again: socket_out[1] = rtcp_socket; *server_addr_out = addr; - GST_DEBUG_OBJECT (stream, "allocated address: %s and ports: %d, %d", addr->address, tmp_rtp, tmp_rtcp); + GST_DEBUG_OBJECT (stream, "allocated address: %s and ports: %d, %d", + addr->address, tmp_rtp, tmp_rtcp); g_list_free_full (rejected_addresses, (GDestroyNotify) gst_rtsp_address_free); @@ -1445,7 +1443,8 @@ no_udp_protocol: } no_pool: { - GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: no address pool specified"); + GST_ERROR_OBJECT (stream, + "failed to allocate UDP ports: no address pool specified"); goto cleanup; } no_address: @@ -2494,8 +2493,8 @@ free_cb_data (gpointer user_data) static void -create_and_plug_queue_to_unlinked_stream (GstRTSPStream * stream, GstElement *tee, - GstElement *sink, GstElement ** queue) +create_and_plug_queue_to_unlinked_stream (GstRTSPStream * stream, + GstElement * tee, GstElement * sink, GstElement ** queue) { GstRTSPStreamPrivate *priv = stream->priv; GstPad *tee_pad; @@ -2597,8 +2596,8 @@ create_and_plug_queue_to_linked_stream_probe_cb (GstPad * inpad, } static void -create_and_plug_queue_to_linked_stream (GstRTSPStream * stream, GstElement * sink1, - GstElement * sink2, guint index, GstElement ** queue1, +create_and_plug_queue_to_linked_stream (GstRTSPStream * stream, + GstElement * sink1, GstElement * sink2, guint index, GstElement ** queue1, GstElement ** queue2) { ProbeData *data; @@ -2611,7 +2610,7 @@ create_and_plug_queue_to_linked_stream (GstRTSPStream * stream, GstElement * sin data->queue2 = queue2; data->index = index; - data->sink_pad = gst_element_get_static_pad (sink1, "sink"); + data->sink_pad = gst_element_get_static_pad (sink1, "sink"); g_assert (data->sink_pad); data->tee_pad = gst_pad_get_peer (data->sink_pad); g_assert (data->tee_pad); @@ -2661,8 +2660,8 @@ plug_udp_sink (GstRTSPStream * stream, GstElement * sink_to_plug, queue = &priv->mcast_udpqueue[index]; } - create_and_plug_queue_to_linked_stream (stream, element, sink_to_plug, index, - queue, queue_to_plug); + create_and_plug_queue_to_linked_stream (stream, element, sink_to_plug, + index, queue, queue_to_plug); } else { GstPad *tee_pad; @@ -2696,7 +2695,7 @@ plug_tcp_sink (GstRTSPStream * stream, guint index) /* queues are already added for the existing stream, add one for the newly added tcp stream */ create_and_plug_queue_to_unlinked_stream (stream, - priv->tee[index], priv->appsink[index], &priv->appqueue[index]); + priv->tee[index], priv->appsink[index], &priv->appqueue[index]); } else if (priv->mcast_udpsink[index] || priv->udpsink[index]) { GstElement **queue; @@ -2712,8 +2711,8 @@ plug_tcp_sink (GstRTSPStream * stream, guint index) queue = &priv->udpqueue[index]; } - create_and_plug_queue_to_linked_stream (stream, element, priv->appsink[index], index, - queue, &priv->appqueue[index]); + create_and_plug_queue_to_linked_stream (stream, element, + priv->appsink[index], index, queue, &priv->appqueue[index]); } else { GstPad *tee_pad; @@ -2828,8 +2827,8 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport) if (is_udp && !priv->udpsink[i]) { /* we create only one pair of udpsinks for IPv4 and IPv6 */ - create_and_configure_udpsink (stream, &priv->udpsink[i], priv->socket_v4[i], - priv->socket_v6[i], FALSE, (i == 0)); + create_and_configure_udpsink (stream, &priv->udpsink[i], + priv->socket_v4[i], priv->socket_v6[i], FALSE, (i == 0)); plug_sink (stream, transport, i); } else if (is_mcast && !priv->mcast_udpsink[i]) { /* we create only one pair of mcast-udpsinks for IPv4 and IPv6 */ @@ -2844,8 +2843,7 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport) /* we need to set sync and preroll to FALSE for the sink to avoid * deadlock. This is only needed for sink sending RTCP data. */ if (i == 1) - g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, - NULL); + g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL); gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]), &sink_cb, stream, NULL); @@ -2955,7 +2953,7 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * if (udp && !priv->udpsrc_v4[i] && priv->server_addr_v4) { GST_DEBUG_OBJECT (stream, "udp IPv4, create and configure udpsources"); if (!create_and_configure_udpsource (&priv->udpsrc_v4[i], - priv->socket_v4[i])) + priv->socket_v4[i])) goto udpsrc_error; plug_src (stream, bin, priv->udpsrc_v4[i], priv->funnel[i]); @@ -2964,7 +2962,7 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * if (udp && !priv->udpsrc_v6[i] && priv->server_addr_v6) { GST_DEBUG_OBJECT (stream, "udp IPv6, create and configure udpsources"); if (!create_and_configure_udpsource (&priv->udpsrc_v6[i], - priv->socket_v6[i])) + priv->socket_v6[i])) goto udpsrc_error; plug_src (stream, bin, priv->udpsrc_v6[i], priv->funnel[i]); @@ -2973,7 +2971,7 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * if (mcast && !priv->mcast_udpsrc_v4[i] && priv->mcast_addr_v4) { GST_DEBUG_OBJECT (stream, "mcast IPv4, create and configure udpsources"); if (!create_and_configure_udpsource (&priv->mcast_udpsrc_v4[i], - priv->mcast_socket_v4[i])) + priv->mcast_socket_v4[i])) goto mcast_udpsrc_error; plug_src (stream, bin, priv->mcast_udpsrc_v4[i], priv->funnel[i]); } @@ -2981,7 +2979,7 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * if (mcast && !priv->mcast_udpsrc_v6[i] && priv->mcast_addr_v6) { GST_DEBUG_OBJECT (stream, "mcast IPv6, create and configure udpsources"); if (!create_and_configure_udpsource (&priv->mcast_udpsrc_v6[i], - priv->mcast_socket_v6[i])) + priv->mcast_socket_v6[i])) goto mcast_udpsrc_error; plug_src (stream, bin, priv->mcast_udpsrc_v6[i], priv->funnel[i]); } @@ -3954,7 +3952,8 @@ gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) * socket could be allocated for @family. Unref after usage */ GSocket * -gst_rtsp_stream_get_rtp_multicast_socket (GstRTSPStream * stream, GSocketFamily family) +gst_rtsp_stream_get_rtp_multicast_socket (GstRTSPStream * stream, + GSocketFamily family) { GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); GSocket *socket; @@ -3986,7 +3985,8 @@ gst_rtsp_stream_get_rtp_multicast_socket (GstRTSPStream * stream, GSocketFamily * socket could be allocated for @family. Unref after usage */ GSocket * -gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream * stream, GSocketFamily family) +gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream * stream, + GSocketFamily family) { GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); GSocket *socket; @@ -4327,8 +4327,9 @@ gst_rtsp_stream_query_position (GstRTSPStream * stream, gint64 * position) g_mutex_unlock (&priv->lock); if (sink) { - if (!gst_element_query_position (sink , GST_FORMAT_TIME, position)) { - GST_WARNING_OBJECT (stream, "Couldn't obtain postion: position query failed"); + if (!gst_element_query_position (sink, GST_FORMAT_TIME, position)) { + GST_WARNING_OBJECT (stream, + "Couldn't obtain postion: position query failed"); gst_object_unref (sink); return FALSE; } @@ -4352,7 +4353,7 @@ gst_rtsp_stream_query_position (GstRTSPStream * stream, gint64 * position) *position = priv->position; g_mutex_unlock (&priv->lock); *position = - gst_segment_to_stream_time (segment, GST_FORMAT_TIME, *position); + gst_segment_to_stream_time (segment, GST_FORMAT_TIME, *position); } gst_event_unref (event); gst_object_unref (pad); From 7bf8c4d21832c16052dc2080b5f3aed7fca6f13f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 21 Nov 2017 09:53:19 +0100 Subject: [PATCH 1405/1776] rtsp-client: Don't leak addr CID #1422260 --- gst/rtsp-server/rtsp-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e46f58740b..b2b10087c4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1837,9 +1837,9 @@ default_configure_client_transport (GstRTSPClient * client, ct->port.min = addr->port; ct->port.max = addr->port + addr->n_ports - 1; ct->ttl = addr->ttl; - - gst_rtsp_address_free (addr); } + + gst_rtsp_address_free (addr); } else { GstRTSPUrl *url; From 90ca7f8b310ac63805730e0cf55529cd97a9a87f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 22 Nov 2017 12:24:38 +0100 Subject: [PATCH 1406/1776] check/media: Check that prepared media can provide a SDP Whenever a RTSPMedia is prepared, it should be able to provide a SDP --- tests/check/gst/media.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index b734673e6f..99f19b083c 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -21,6 +21,34 @@ #include +/* Check if the media can return a SDP. We don't actually check whether + * the contents are valid or not */ +static gboolean +media_has_sdp (GstRTSPMedia * media) +{ + GstSDPInfo info; + GstSDPMessage *sdp; + gchar *sdp_str; + + info.is_ipv6 = FALSE; + info.server_ip = "0.0.0.0"; + + /* Check if media can generate a SDP */ + gst_sdp_message_new (&sdp); + GST_DEBUG ("Getting SDP"); + if (!gst_rtsp_sdp_from_media (sdp, &info, media)) { + GST_WARNING ("failed to get the SDP"); + gst_sdp_message_free (sdp); + return FALSE; + } + sdp_str = gst_sdp_message_as_text (sdp); + GST_DEBUG ("Got SDP\n%s", sdp_str); + g_free (sdp_str); + gst_sdp_message_free (sdp); + + return TRUE; +} + GST_START_TEST (test_media_seek) { GstRTSPMediaFactory *factory; @@ -54,6 +82,7 @@ GST_START_TEST (test_media_seek) GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (media_has_sdp (media)); /* define transport */ fail_unless (gst_rtsp_transport_new (&transport) == GST_RTSP_OK); @@ -127,6 +156,7 @@ GST_START_TEST (test_media_seek_no_sinks) GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (media_has_sdp (media)); str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT); fail_unless (g_str_equal (str, "npt=0-")); @@ -210,12 +240,14 @@ test_prepare_reusable (const gchar * launch_line) thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (media_has_sdp (media)); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 1); thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (media_has_sdp (media)); fail_unless (gst_rtsp_media_unprepare (media)); g_object_unref (media); @@ -260,6 +292,7 @@ GST_START_TEST (test_media_prepare) thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (media_has_sdp (media)); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 1); @@ -346,6 +379,7 @@ GST_START_TEST (test_media_dyn_prepare) GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (gst_rtsp_media_n_streams (media) == 1); + fail_unless (media_has_sdp (media)); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 0); @@ -353,6 +387,7 @@ GST_START_TEST (test_media_dyn_prepare) GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (gst_rtsp_media_n_streams (media) == 1); + fail_unless (media_has_sdp (media)); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 0); @@ -414,6 +449,7 @@ GST_START_TEST (test_media_reset) thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (media_has_sdp (media)); fail_unless (gst_rtsp_media_suspend (media)); fail_unless (gst_rtsp_media_unprepare (media)); g_object_unref (media); @@ -425,6 +461,7 @@ GST_START_TEST (test_media_reset) GST_RTSP_THREAD_TYPE_MEDIA, NULL); gst_rtsp_media_set_suspend_mode (media, GST_RTSP_SUSPEND_MODE_RESET); fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (media_has_sdp (media)); fail_unless (gst_rtsp_media_suspend (media)); fail_unless (gst_rtsp_media_unprepare (media)); g_object_unref (media); @@ -492,13 +529,16 @@ GST_START_TEST (test_media_multidyn_prepare) GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless_equals_int (gst_rtsp_media_n_streams (media), 2); + fail_unless (media_has_sdp (media)); fail_unless (gst_rtsp_media_unprepare (media)); + fail_unless_equals_int (gst_rtsp_media_n_streams (media), 0); thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless_equals_int (gst_rtsp_media_n_streams (media), 2); + fail_unless (media_has_sdp (media)); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless_equals_int (gst_rtsp_media_n_streams (media), 0); From ac6169d50a6e1bf03323b7bada4bd43f4126b012 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 23 Nov 2017 09:10:54 +0100 Subject: [PATCH 1407/1776] rtsp-media: Corrected ASYNC_DONE handling Media is complete when all the transport based parts are added to the media pipeline. At this point ASYNC_DONE is posted by the media pipeline and media is ready to enter the PREPARED state. Change-Id: I50fb8dfed88ebaf057d9a35fca2d7f0a70e9d1fa https://bugzilla.gnome.org/show_bug.cgi?id=790674 --- gst/rtsp-server/rtsp-media.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d158938614..d4e4282b16 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -112,7 +112,7 @@ struct _GstRTSPMediaPrivate GstRTSPMediaStatus status; /* protected by lock */ gint prepare_count; gint n_active; - gboolean adding; + gboolean complete; /* the pipeline for the media */ GstElement *pipeline; @@ -2569,13 +2569,11 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) case GST_MESSAGE_STREAM_STATUS: break; case GST_MESSAGE_ASYNC_DONE: - if (priv->adding) { - /* when we are dynamically adding pads, the addition of the udpsrc will - * temporarily produce ASYNC_DONE messages. We have to ignore them and - * wait for the final ASYNC_DONE after everything prerolled */ - GST_INFO ("%p: ignoring ASYNC_DONE", media); - } else { - GST_INFO ("%p: got ASYNC_DONE", media); + if (priv->complete) { + /* receive the final ASYNC_DONE, that is posted by the media pipeline + * after all the transport parts have been successfully added to + * the media streams. */ + GST_DEBUG_OBJECT (media, "got async-done"); if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); } @@ -2678,11 +2676,6 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) g_object_set_data (G_OBJECT (pad), "gst-rtsp-dynpad-stream", stream); - /* we will be adding elements below that will cause ASYNC_DONE to be - * posted in the bus. We want to ignore those messages until the - * pipeline really prerolled. */ - priv->adding = TRUE; - /* join the element in the PAUSED state because this callback is * called from the streaming thread and it is PAUSED */ if (!gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline), @@ -2693,7 +2686,6 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) if (priv->blocked) gst_rtsp_stream_set_blocked (stream, TRUE); - priv->adding = FALSE; g_rec_mutex_unlock (&priv->state_lock); return; @@ -4118,6 +4110,8 @@ gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GPtrArray * transports) return FALSE; } } + + priv->complete = TRUE; g_mutex_unlock (&priv->lock); return TRUE; From 132e00adfd0333be082594bf7e64d3b96d95d263 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 23 Nov 2017 18:39:44 +0100 Subject: [PATCH 1408/1776] rtsp-media: Removed fakesink elements There is not need of adding fakesink elements to the media pipeline in the dynamic-payloader case. The media pipeline itself is dynamically updated with the receiver and sender parts that are based on the client transport information known after SETUP has been received. Change-Id: I4e88c9b500c04030669822f0d03b1842913f6cb9 https://bugzilla.gnome.org/show_bug.cgi?id=790674 --- gst/rtsp-server/rtsp-media.c | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index d4e4282b16..6d2d11353f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -116,7 +116,6 @@ struct _GstRTSPMediaPrivate /* the pipeline for the media */ GstElement *pipeline; - GstElement *fakesink; /* protected by lock */ GSource *source; guint id; GstRTSPThread *thread; @@ -2719,38 +2718,15 @@ pad_removed_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) gst_rtsp_media_remove_stream (media, stream); } -static void -remove_fakesink (GstRTSPMediaPrivate * priv) -{ - GstElement *fakesink; - - g_mutex_lock (&priv->lock); - if ((fakesink = priv->fakesink)) - gst_object_ref (fakesink); - priv->fakesink = NULL; - g_mutex_unlock (&priv->lock); - - if (fakesink) { - gst_bin_remove (GST_BIN (priv->pipeline), fakesink); - gst_element_set_state (fakesink, GST_STATE_NULL); - gst_object_unref (fakesink); - GST_INFO ("removed fakesink"); - } -} - static void no_more_pads_cb (GstElement * element, GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; - gboolean remaining_dynamic; GST_INFO_OBJECT (element, "no more pads"); g_mutex_lock (&priv->lock); priv->no_more_pads_pending--; - remaining_dynamic = priv->no_more_pads_pending; g_mutex_unlock (&priv->lock); - if (remaining_dynamic == 0) - remove_fakesink (priv); } typedef struct _DynPaySignalHandlers DynPaySignalHandlers; @@ -2893,13 +2869,6 @@ start_prepare (GstRTSPMedia * media) (GCallback) no_more_pads_cb, media); g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers); - - if (!priv->fakesink) { - /* we add a fakesink here in order to make the state change async. We remove - * the fakesink again in the no-more-pads callback. */ - priv->fakesink = gst_element_factory_make ("fakesink", "fakesink"); - gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink); - } } if (!start_preroll (media)) @@ -3154,8 +3123,6 @@ finish_unprepare (GstRTSPMedia * media) if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARING) return; - remove_fakesink (priv); - for (i = 0; i < priv->streams->len; i++) { GstRTSPStream *stream; From de930f2e4d74f1cbf1679aa03ff6f603a5eff5ef Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 23 Nov 2017 18:51:21 +0100 Subject: [PATCH 1409/1776] check/media: Fix thread pool leak. Change-Id: I0f92b1caca0ee518ae64a7dacfbd28a214c3eea1 https://bugzilla.gnome.org/show_bug.cgi?id=790674 --- tests/check/gst/media.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 99f19b083c..e1439164d4 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -253,6 +253,8 @@ test_prepare_reusable (const gchar * launch_line) g_object_unref (media); gst_rtsp_url_free (url); g_object_unref (factory); + + g_object_unref (pool); } GST_START_TEST (test_media_reusable) From bb29d2e2ee46a1e1b3ffc52a3c0da91e42d82e0b Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 23 Nov 2017 20:34:03 +0100 Subject: [PATCH 1410/1776] rtsp-media: Fix handling in default_unsuspend() Handle the case when streams are not blocked and media is suspended from PAUSED. Change-Id: I2f3d222ea7b9b20a0732ea5dc81a32d17ab75040 https://bugzilla.gnome.org/show_bug.cgi?id=790674 --- gst/rtsp-server/rtsp-media.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 6d2d11353f..aead378f1c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3685,11 +3685,16 @@ default_unsuspend (GstRTSPMedia * media) case GST_RTSP_SUSPEND_MODE_NONE: if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) break; - gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); - /* at this point the media pipeline has been updated and contain all - * specific transport parts: all active streams contain at least one sink - * element and it's safe to unblock any blocked streams that are active */ - media_unblock_linked (media); + if (media_streams_blocking (media)) { + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); + /* at this point the media pipeline has been updated and contain all + * specific transport parts: all active streams contain at least one sink + * element and it's safe to unblock any blocked streams that are active */ + media_unblock_linked (media); + } else { + /* streams are not blocked and media is suspended from PAUSED */ + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); + } g_rec_mutex_unlock (&priv->state_lock); if (gst_rtsp_media_get_status (media) == GST_RTSP_MEDIA_STATUS_ERROR) { g_rec_mutex_lock (&priv->state_lock); From 9514f2d3549f1c8847e69d3ce6e76a693bd1dc38 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 24 Nov 2017 17:34:31 +0100 Subject: [PATCH 1411/1776] rtsp-media: Enable seeking query before pipeline is complete SDP are now provided *before* the pipeline is fully complete. In order to know whether a media is seekable or not therefore requires asking the invididual streams. API: gst_rtsp_stream_seekable https://bugzilla.gnome.org/show_bug.cgi?id=790674 --- docs/libs/gst-rtsp-server-sections.txt | 2 + gst/rtsp-server/rtsp-media.c | 12 ++++++ gst/rtsp-server/rtsp-stream.c | 52 ++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 3 ++ win32/common/libgstrtspserver.def | 1 + 5 files changed, 70 insertions(+) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index f57bc58d3b..3299fd71e9 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -610,6 +610,8 @@ gst_rtsp_stream_update_crypto gst_rtsp_stream_set_pt_map gst_rtsp_stream_request_aux_sender +gst_rtsp_stream_seekable + GstRTSPStreamTransportFilterFunc gst_rtsp_stream_transport_filter diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index aead378f1c..e10ad8bfcf 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -703,8 +703,20 @@ check_seekable (GstRTSPMedia * media) gst_query_parse_seeking (query, &format, &seekable, &start, &end); priv->seekable = seekable ? G_MAXINT64 : 0; + } else if (priv->streams->len) { + gboolean seekable = TRUE; + guint i, n = priv->streams->len; + + GST_DEBUG_OBJECT (media, "Checking %d streams", n); + for (i = 0; i < n; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + seekable &= gst_rtsp_stream_seekable (stream); + } + priv->seekable = seekable ? G_MAXINT64 : -1; } + GST_DEBUG_OBJECT (media, "seekable:%" G_GINT64_FORMAT, priv->seekable); + gst_query_unref (query); } diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 7b458b1bb4..fee99ac950 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4449,6 +4449,58 @@ gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop) return TRUE; } +/** + * gst_rtsp_stream_seekable: + * @stream: a #GstRTSPStream + * + * Checks whether the individual @stream is seekable. + * + * Returns: %TRUE if @stream is seekable, else %FALSE. + */ +gboolean +gst_rtsp_stream_seekable (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + GstPad *pad = NULL; + GstQuery *query = NULL; + gboolean seekable = FALSE; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + /* query stop position: if no sinks have been added yet, + * we obtain the stop position from the pad otherwise we query the sinks */ + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + /* depending on the transport type, it should query corresponding sink */ + if (priv->srcpad) { + pad = gst_object_ref (priv->srcpad); + } else { + g_mutex_unlock (&priv->lock); + GST_WARNING_OBJECT (stream, "Pad not available, can't query seekability"); + goto beach; + } + g_mutex_unlock (&priv->lock); + + query = gst_query_new_seeking (GST_FORMAT_TIME); + if (!gst_pad_query (pad, query)) { + GST_WARNING_OBJECT (stream, "seeking query failed"); + goto beach; + } + gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL); + +beach: + if (pad) + gst_object_unref (pad); + if (query) + gst_query_unref (query); + + GST_DEBUG_OBJECT (stream, "Returning %d", seekable); + + return seekable; +} + /** * gst_rtsp_stream_complete_stream: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 37a8275c02..3583d4a390 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -243,6 +243,9 @@ GST_EXPORT gboolean gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop); +GST_EXPORT +gboolean gst_rtsp_stream_seekable (GstRTSPStream *stream); + GST_EXPORT void gst_rtsp_stream_set_seqnum_offset (GstRTSPStream *stream, guint16 seqnum); diff --git a/win32/common/libgstrtspserver.def b/win32/common/libgstrtspserver.def index c624920219..f233ac8917 100644 --- a/win32/common/libgstrtspserver.def +++ b/win32/common/libgstrtspserver.def @@ -281,6 +281,7 @@ EXPORTS gst_rtsp_stream_remove_transport gst_rtsp_stream_request_aux_sender gst_rtsp_stream_reserve_address + gst_rtsp_stream_seekable gst_rtsp_stream_set_address_pool gst_rtsp_stream_set_blocked gst_rtsp_stream_set_buffer_size From bad6f5690a9924581e50edf5ac922ca87769d2bb Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 25 Nov 2017 07:53:30 +0100 Subject: [PATCH 1412/1776] check: Add seekability testing on medias Make sure that once GstRTSPMedia are prepared they returned the expected seekability results https://bugzilla.gnome.org/show_bug.cgi?id=790674 --- tests/check/gst/media.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index e1439164d4..11e0bfdfaa 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -215,7 +215,7 @@ GST_START_TEST (test_media) GST_END_TEST; static void -test_prepare_reusable (const gchar * launch_line) +test_prepare_reusable (const gchar * launch_line, gboolean is_live) { GstRTSPMediaFactory *factory; GstRTSPMedia *media; @@ -241,6 +241,11 @@ test_prepare_reusable (const gchar * launch_line) GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (media_has_sdp (media)); + if (is_live) { /* Live is not seekable */ + fail_unless_equals_int64 (gst_rtsp_media_seekable (media), -1); + } else { + fail_unless_equals_int64 (gst_rtsp_media_seekable (media), G_MAXINT64); + } fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 1); @@ -261,9 +266,10 @@ GST_START_TEST (test_media_reusable) { /* test reusable media */ - test_prepare_reusable ("( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); - test_prepare_reusable ( - "( videotestsrc is-live=true ! rtpvrawpay pt=96 name=pay0 )"); + test_prepare_reusable ("( videotestsrc ! rtpvrawpay pt=96 name=pay0 )", + FALSE); + test_prepare_reusable + ("( videotestsrc is-live=true ! rtpvrawpay pt=96 name=pay0 )", TRUE); } GST_END_TEST; @@ -295,6 +301,7 @@ GST_START_TEST (test_media_prepare) GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (media_has_sdp (media)); + fail_unless_equals_int64 (gst_rtsp_media_seekable (media), G_MAXINT64); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 1); @@ -382,6 +389,7 @@ GST_START_TEST (test_media_dyn_prepare) fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (gst_rtsp_media_n_streams (media) == 1); fail_unless (media_has_sdp (media)); + fail_unless_equals_int64 (gst_rtsp_media_seekable (media), G_MAXINT64); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 0); @@ -390,6 +398,7 @@ GST_START_TEST (test_media_dyn_prepare) fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (gst_rtsp_media_n_streams (media) == 1); fail_unless (media_has_sdp (media)); + fail_unless_equals_int64 (gst_rtsp_media_seekable (media), G_MAXINT64); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 0); @@ -452,6 +461,7 @@ GST_START_TEST (test_media_reset) GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (media_has_sdp (media)); + fail_unless_equals_int64 (gst_rtsp_media_seekable (media), G_MAXINT64); fail_unless (gst_rtsp_media_suspend (media)); fail_unless (gst_rtsp_media_unprepare (media)); g_object_unref (media); @@ -464,6 +474,7 @@ GST_START_TEST (test_media_reset) gst_rtsp_media_set_suspend_mode (media, GST_RTSP_SUSPEND_MODE_RESET); fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (media_has_sdp (media)); + fail_unless_equals_int64 (gst_rtsp_media_seekable (media), G_MAXINT64); fail_unless (gst_rtsp_media_suspend (media)); fail_unless (gst_rtsp_media_unprepare (media)); g_object_unref (media); @@ -532,8 +543,8 @@ GST_START_TEST (test_media_multidyn_prepare) fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless_equals_int (gst_rtsp_media_n_streams (media), 2); fail_unless (media_has_sdp (media)); + fail_unless_equals_int64 (gst_rtsp_media_seekable (media), G_MAXINT64); fail_unless (gst_rtsp_media_unprepare (media)); - fail_unless_equals_int (gst_rtsp_media_n_streams (media), 0); thread = gst_rtsp_thread_pool_get_thread (pool, @@ -541,6 +552,7 @@ GST_START_TEST (test_media_multidyn_prepare) fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless_equals_int (gst_rtsp_media_n_streams (media), 2); fail_unless (media_has_sdp (media)); + fail_unless_equals_int64 (gst_rtsp_media_seekable (media), G_MAXINT64); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless_equals_int (gst_rtsp_media_n_streams (media), 0); From 58aa58f049e448684bfe870259ad4e96007b7c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 26 Nov 2017 12:47:08 +0000 Subject: [PATCH 1413/1776] rtsp-server: add missing GST_EXPORT and export deprecated funcs --- gst/rtsp-server/rtsp-media.h | 2 ++ gst/rtsp-server/rtsp-server.h | 9 +++++++++ gst/rtsp-server/rtsp-session.c | 7 ------- gst/rtsp-server/rtsp-session.h | 8 ++++---- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index d78265d7c8..e4c95f13dd 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -362,6 +362,8 @@ GstRTSPStream * gst_rtsp_media_find_stream (GstRTSPMedia *media, cons GST_EXPORT gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range); + +GST_EXPORT gboolean gst_rtsp_media_seek_full (GstRTSPMedia *media, GstRTSPTimeRange *range, GstSeekFlags flags); diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index a928cf59ed..0208d29032 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -24,6 +24,15 @@ G_BEGIN_DECLS +/* Do *not* use these defines outside of rtsp-server. Use G_DEPRECATED instead. */ +#ifdef GST_DISABLE_DEPRECATED +#define GST_RTSP_SERVER_DEPRECATED GST_EXPORT +#define GST_RTSP_SERVER_DEPRECATED_FOR(f) GST_EXPORT +#else +#define GST_RTSP_SERVER_DEPRECATED G_DEPRECATED GST_EXPORT +#define GST_RTSP_SERVER_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) GST_EXPORT +#endif + typedef struct _GstRTSPServer GstRTSPServer; typedef struct _GstRTSPServerClass GstRTSPServerClass; typedef struct _GstRTSPServerPrivate GstRTSPServerPrivate; diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index e8fd68b19c..8e82ce2854 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -681,10 +681,6 @@ gst_rtsp_session_next_timeout_usec (GstRTSPSession * session, gint64 now) * Deprecated: Use gst_rtsp_session_next_timeout_usec() instead. */ #ifndef GST_REMOVE_DEPRECATED -#ifdef GST_DISABLE_DEPRECATED -gint gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now); -#endif - gint gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) { @@ -756,9 +752,6 @@ gst_rtsp_session_is_expired_usec (GstRTSPSession * session, gint64 now) * Deprecated: Use gst_rtsp_session_is_expired_usec() instead. */ #ifndef GST_REMOVE_DEPRECATED -#ifdef GST_DISABLE_DEPRECATED -gboolean gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now); -#endif gboolean gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) { diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index ed97b76f21..8f7cf4d729 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -20,6 +20,7 @@ #include #include +#include /* for GST_RTSP_SERVER_DEPRECATED_FOR */ #ifndef __GST_RTSP_SESSION_H__ #define __GST_RTSP_SESSION_H__ @@ -115,13 +116,12 @@ gint gst_rtsp_session_next_timeout_usec (GstRTSPSession *se GST_EXPORT gboolean gst_rtsp_session_is_expired_usec (GstRTSPSession *session, gint64 now); -#ifndef GST_DISABLE_DEPRECATED -GST_EXPORT + +GST_RTSP_SERVER_DEPRECATED_FOR(gst_rtsp_session_next_timeout_usec) gint gst_rtsp_session_next_timeout (GstRTSPSession *session, GTimeVal *now); -GST_EXPORT +GST_RTSP_SERVER_DEPRECATED_FOR(gst_rtsp_session_is_expired_usec) gboolean gst_rtsp_session_is_expired (GstRTSPSession *session, GTimeVal *now); -#endif /* handle media in a session */ From a877229d38f547d0ee0d5f0a4d888ca8fafa6723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 26 Nov 2017 12:28:40 +0000 Subject: [PATCH 1414/1776] autotools: stop controlling symbol visibility with -export-symbols-regex Instead, use -fvisibility=hidden and explicit exports via GST_EXPORT. This should result in consistent behaviour for the autotools and Meson builds. --- configure.ac | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 4c011ab6d8..fa9350406a 100644 --- a/configure.ac +++ b/configure.ac @@ -264,6 +264,10 @@ else fi AC_SUBST(DEPRECATED_CFLAGS) +VISIBILITY_CFLAGS="" +AS_COMPILER_FLAG([-fvisibility=hidden], [VISIBILITY_CFLAGS="-fvisibility=hidden"]) +AC_SUBST(VISIBILITY_CFLAGS) + dnl every flag in GST_OPTION_CFLAGS can be overridden at make time GST_OPTION_CFLAGS="\$(WARNING_CFLAGS) \$(ERROR_CFLAGS) \$(DEBUG_CFLAGS) \$(PROFILE_CFLAGS) \$(GCOV_CFLAGS) \$(OPT_CFLAGS) \$(DEPRECATED_CFLAGS)" AC_SUBST(GST_OPTION_CFLAGS) @@ -271,7 +275,7 @@ AC_SUBST(GST_OPTION_CFLAGS) dnl FIXME: do we want to rename to GST_ALL_* ? dnl prefer internal headers to already installed ones dnl add GST_OPTION_CFLAGS, but overridable -GST_CFLAGS="$GST_CFLAGS \$(GST_STATIC_CFLAGS) \$(GST_OPTION_CFLAGS)" +GST_CFLAGS="$GST_CFLAGS \$(GST_STATIC_CFLAGS) \$(GST_OPTION_CFLAGS) \$(VISIBILITY_CFLAGS)" AC_SUBST(GST_CFLAGS) AC_SUBST(GST_LIBS) @@ -300,7 +304,7 @@ 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 -GST_LIB_LDFLAGS="-export-symbols-regex \^[_]?\(gst_\|Gst\|GST_\).*" +GST_LIB_LDFLAGS="" AC_SUBST(GST_LIB_LDFLAGS) dnl GST_OBJ_* @@ -318,7 +322,7 @@ if test x$enable_static = xyes -a x$enable_shared = xno; then fi AC_SUBST(GST_STATIC_CFLAGS) -GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_.*' $GST_ALL_LDFLAGS" +GST_PLUGIN_LDFLAGS="-module -avoid-version $GST_ALL_LDFLAGS" AC_SUBST(GST_PLUGIN_LDFLAGS) PKG_CHECK_MODULES(LIBCGROUP, libcgroup >= 0.26, HAVE_LIBCGROUP="yes", HAVE_LIBCGROUP="no") From 8c1cdb7a4a96289fe37ea42d7123da0d7731498b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 26 Nov 2017 12:53:42 +0000 Subject: [PATCH 1415/1776] win32: remove .def file with exports They're no longer needed, symbol exporting is now explicit via GST_EXPORT in all cases (autotools, meson, incl. MSVC). --- Makefile.am | 4 - gst/rtsp-server/meson.build | 4 +- win32/MANIFEST | 2 - win32/common/libgstrtspserver.def | 339 ------------------------------ 4 files changed, 1 insertion(+), 348 deletions(-) delete mode 100644 win32/MANIFEST delete mode 100644 win32/common/libgstrtspserver.def diff --git a/Makefile.am b/Makefile.am index 4b96f787c5..d663e61891 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,15 +16,11 @@ SUBDIRS = \ DIST_SUBDIRS = gst common pkgconfig docs examples tests -# include before EXTRA_DIST for win32 assignment -include $(top_srcdir)/common/win32.mak - EXTRA_DIST = \ ChangeLog autogen.sh depcomp \ AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \ docs/design/gst-rtp-server-design \ gst-rtsp-server.doap \ - $(win32) \ $(shell find "$(top_srcdir)" -type f -name meson.build ! -path "$(top_srcdir)/$(PACKAGE_TARNAME)-*" ) \ meson_options.txt diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index d4b28fcb7d..8e254efae9 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -51,9 +51,7 @@ gst_rtsp_server = library('gstrtspserver-@0@'.format(api_version), version : libversion, soversion : soversion, install : true, - dependencies : gst_rtsp_server_deps, - vs_module_defs: vs_module_defs_dir + 'libgstrtspserver.def' -) + dependencies : gst_rtsp_server_deps) rtsp_server_gen_sources = [] if build_gir diff --git a/win32/MANIFEST b/win32/MANIFEST deleted file mode 100644 index 8cdea81e53..0000000000 --- a/win32/MANIFEST +++ /dev/null @@ -1,2 +0,0 @@ -win32/MANIFEST -win32/common/libgstrtspserver.def diff --git a/win32/common/libgstrtspserver.def b/win32/common/libgstrtspserver.def deleted file mode 100644 index f233ac8917..0000000000 --- a/win32/common/libgstrtspserver.def +++ /dev/null @@ -1,339 +0,0 @@ -EXPORTS - gst_rtsp_address_copy - gst_rtsp_address_free - gst_rtsp_address_get_type - gst_rtsp_address_pool_acquire_address - gst_rtsp_address_pool_add_range - gst_rtsp_address_pool_clear - gst_rtsp_address_pool_dump - gst_rtsp_address_pool_get_type - gst_rtsp_address_pool_has_unicast_addresses - gst_rtsp_address_pool_new - gst_rtsp_address_pool_reserve_address - gst_rtsp_auth_add_basic - gst_rtsp_auth_add_digest - gst_rtsp_auth_check - gst_rtsp_auth_get_default_token - gst_rtsp_auth_get_supported_methods - gst_rtsp_auth_get_tls_authentication_mode - gst_rtsp_auth_get_tls_certificate - gst_rtsp_auth_get_tls_database - gst_rtsp_auth_get_type - gst_rtsp_auth_make_basic - gst_rtsp_auth_new - gst_rtsp_auth_remove_basic - gst_rtsp_auth_remove_digest - gst_rtsp_auth_set_default_token - gst_rtsp_auth_set_supported_methods - gst_rtsp_auth_set_tls_authentication_mode - gst_rtsp_auth_set_tls_certificate - gst_rtsp_auth_set_tls_database - gst_rtsp_client_attach - gst_rtsp_client_close - gst_rtsp_client_get_auth - gst_rtsp_client_get_connection - gst_rtsp_client_get_mount_points - gst_rtsp_client_get_session_pool - gst_rtsp_client_get_thread_pool - gst_rtsp_client_get_type - gst_rtsp_client_handle_message - gst_rtsp_client_new - gst_rtsp_client_send_message - gst_rtsp_client_session_filter - gst_rtsp_client_set_auth - gst_rtsp_client_set_connection - gst_rtsp_client_set_mount_points - gst_rtsp_client_set_send_func - gst_rtsp_client_set_session_pool - gst_rtsp_client_set_thread_pool - gst_rtsp_context_get_current - gst_rtsp_context_get_type - gst_rtsp_context_pop_current - gst_rtsp_context_push_current - gst_rtsp_media_collect_streams - gst_rtsp_media_complete_pipeline - gst_rtsp_media_create_stream - gst_rtsp_media_factory_add_role - gst_rtsp_media_factory_construct - gst_rtsp_media_factory_create_element - gst_rtsp_media_factory_get_address_pool - gst_rtsp_media_factory_get_buffer_size - gst_rtsp_media_factory_get_clock - gst_rtsp_media_factory_get_latency - gst_rtsp_media_factory_get_launch - gst_rtsp_media_factory_get_media_gtype - gst_rtsp_media_factory_get_multicast_iface - gst_rtsp_media_factory_get_permissions - gst_rtsp_media_factory_get_profiles - gst_rtsp_media_factory_get_protocols - gst_rtsp_media_factory_get_publish_clock_mode - gst_rtsp_media_factory_get_retransmission_time - gst_rtsp_media_factory_get_suspend_mode - gst_rtsp_media_factory_get_transport_mode - gst_rtsp_media_factory_get_type - gst_rtsp_media_factory_is_eos_shutdown - gst_rtsp_media_factory_is_shared - gst_rtsp_media_factory_is_stop_on_disonnect - gst_rtsp_media_factory_new - gst_rtsp_media_factory_set_address_pool - gst_rtsp_media_factory_set_buffer_size - gst_rtsp_media_factory_set_clock - gst_rtsp_media_factory_set_eos_shutdown - gst_rtsp_media_factory_set_latency - gst_rtsp_media_factory_set_launch - gst_rtsp_media_factory_set_media_gtype - gst_rtsp_media_factory_set_multicast_iface - gst_rtsp_media_factory_set_permissions - gst_rtsp_media_factory_set_profiles - gst_rtsp_media_factory_set_protocols - gst_rtsp_media_factory_set_publish_clock_mode - gst_rtsp_media_factory_set_retransmission_time - gst_rtsp_media_factory_set_shared - gst_rtsp_media_factory_set_stop_on_disconnect - gst_rtsp_media_factory_set_suspend_mode - gst_rtsp_media_factory_set_transport_mode - gst_rtsp_media_factory_uri_get_type - gst_rtsp_media_factory_uri_get_uri - gst_rtsp_media_factory_uri_new - gst_rtsp_media_factory_uri_set_uri - gst_rtsp_media_find_stream - gst_rtsp_media_get_address_pool - gst_rtsp_media_get_base_time - gst_rtsp_media_get_buffer_size - gst_rtsp_media_get_clock - gst_rtsp_media_get_element - gst_rtsp_media_get_latency - gst_rtsp_media_get_multicast_iface - gst_rtsp_media_get_permissions - gst_rtsp_media_get_profiles - gst_rtsp_media_get_protocols - gst_rtsp_media_get_publish_clock_mode - gst_rtsp_media_get_range_string - gst_rtsp_media_get_retransmission_time - gst_rtsp_media_get_status - gst_rtsp_media_get_stream - gst_rtsp_media_get_suspend_mode - gst_rtsp_media_get_time_provider - gst_rtsp_media_get_transport_mode - gst_rtsp_media_get_type - gst_rtsp_media_handle_sdp - gst_rtsp_media_is_eos_shutdown - gst_rtsp_media_is_reusable - gst_rtsp_media_is_shared - gst_rtsp_media_is_stop_on_disconnect - gst_rtsp_media_is_time_provider - gst_rtsp_media_n_streams - gst_rtsp_media_new - gst_rtsp_media_prepare - gst_rtsp_media_seek - gst_rtsp_media_seek_full - gst_rtsp_media_seekable - gst_rtsp_media_set_address_pool - gst_rtsp_media_set_buffer_size - gst_rtsp_media_set_clock - gst_rtsp_media_set_eos_shutdown - gst_rtsp_media_set_latency - gst_rtsp_media_set_multicast_iface - gst_rtsp_media_set_permissions - gst_rtsp_media_set_pipeline_state - gst_rtsp_media_set_profiles - gst_rtsp_media_set_protocols - gst_rtsp_media_set_publish_clock_mode - gst_rtsp_media_set_retransmission_time - gst_rtsp_media_set_reusable - gst_rtsp_media_set_shared - gst_rtsp_media_set_state - gst_rtsp_media_set_stop_on_disconnect - gst_rtsp_media_set_suspend_mode - gst_rtsp_media_set_transport_mode - gst_rtsp_media_setup_sdp - gst_rtsp_media_suspend - gst_rtsp_media_take_pipeline - gst_rtsp_media_unprepare - gst_rtsp_media_unsuspend - gst_rtsp_media_use_time_provider - gst_rtsp_mount_points_add_factory - gst_rtsp_mount_points_get_type - gst_rtsp_mount_points_make_path - gst_rtsp_mount_points_match - gst_rtsp_mount_points_new - gst_rtsp_mount_points_remove_factory - gst_rtsp_params_get - gst_rtsp_params_set - gst_rtsp_permissions_add_role - gst_rtsp_permissions_add_role_valist - gst_rtsp_permissions_get_role - gst_rtsp_permissions_get_type - gst_rtsp_permissions_is_allowed - gst_rtsp_permissions_new - gst_rtsp_permissions_remove_role - gst_rtsp_publish_clock_mode_get_type - gst_rtsp_sdp_from_media - gst_rtsp_sdp_from_stream - gst_rtsp_server_attach - gst_rtsp_server_client_filter - gst_rtsp_server_create_socket - gst_rtsp_server_create_source - gst_rtsp_server_get_address - gst_rtsp_server_get_auth - gst_rtsp_server_get_backlog - gst_rtsp_server_get_bound_port - gst_rtsp_server_get_mount_points - gst_rtsp_server_get_service - gst_rtsp_server_get_session_pool - gst_rtsp_server_get_thread_pool - gst_rtsp_server_get_type - gst_rtsp_server_io_func - gst_rtsp_server_new - gst_rtsp_server_set_address - gst_rtsp_server_set_auth - gst_rtsp_server_set_backlog - gst_rtsp_server_set_mount_points - gst_rtsp_server_set_service - gst_rtsp_server_set_session_pool - gst_rtsp_server_set_thread_pool - gst_rtsp_server_transfer_connection - gst_rtsp_session_allow_expire - gst_rtsp_session_filter - gst_rtsp_session_get_header - gst_rtsp_session_get_media - gst_rtsp_session_get_sessionid - gst_rtsp_session_get_timeout - gst_rtsp_session_get_type - gst_rtsp_session_is_expired - gst_rtsp_session_is_expired_usec - gst_rtsp_session_manage_media - gst_rtsp_session_media_alloc_channels - gst_rtsp_session_media_get_base_time - gst_rtsp_session_media_get_media - gst_rtsp_session_media_get_rtpinfo - gst_rtsp_session_media_get_rtsp_state - gst_rtsp_session_media_get_transport - gst_rtsp_session_media_get_transports - gst_rtsp_session_media_get_type - gst_rtsp_session_media_matches - gst_rtsp_session_media_new - gst_rtsp_session_media_set_rtsp_state - gst_rtsp_session_media_set_state - gst_rtsp_session_media_set_transport - gst_rtsp_session_new - gst_rtsp_session_next_timeout - gst_rtsp_session_next_timeout_usec - gst_rtsp_session_pool_cleanup - gst_rtsp_session_pool_create - gst_rtsp_session_pool_create_watch - gst_rtsp_session_pool_filter - gst_rtsp_session_pool_find - gst_rtsp_session_pool_get_max_sessions - gst_rtsp_session_pool_get_n_sessions - gst_rtsp_session_pool_get_type - gst_rtsp_session_pool_new - gst_rtsp_session_pool_remove - gst_rtsp_session_pool_set_max_sessions - gst_rtsp_session_prevent_expire - gst_rtsp_session_release_media - gst_rtsp_session_set_timeout - gst_rtsp_session_touch - gst_rtsp_stream_add_transport - gst_rtsp_stream_allocate_udp_sockets - gst_rtsp_stream_complete_stream - gst_rtsp_stream_get_address_pool - gst_rtsp_stream_get_buffer_size - gst_rtsp_stream_get_caps - gst_rtsp_stream_get_control - gst_rtsp_stream_get_current_seqnum - gst_rtsp_stream_get_dscp_qos - gst_rtsp_stream_get_index - gst_rtsp_stream_get_joined_bin - gst_rtsp_stream_get_mtu - gst_rtsp_stream_get_multicast_address - gst_rtsp_stream_get_multicast_iface - gst_rtsp_stream_get_profiles - gst_rtsp_stream_get_protocols - gst_rtsp_stream_get_pt - gst_rtsp_stream_get_publish_clock_mode - gst_rtsp_stream_get_retransmission_pt - gst_rtsp_stream_get_retransmission_time - gst_rtsp_stream_get_rtcp_multicast_socket - gst_rtsp_stream_get_rtcp_socket - gst_rtsp_stream_get_rtp_multicast_socket - gst_rtsp_stream_get_rtp_socket - gst_rtsp_stream_get_rtpinfo - gst_rtsp_stream_get_rtpsession - gst_rtsp_stream_get_server_port - gst_rtsp_stream_get_sinkpad - gst_rtsp_stream_get_srcpad - gst_rtsp_stream_get_srtp_encoder - gst_rtsp_stream_get_ssrc - gst_rtsp_stream_get_type - gst_rtsp_stream_has_control - gst_rtsp_stream_is_blocking - gst_rtsp_stream_is_client_side - gst_rtsp_stream_is_complete - gst_rtsp_stream_is_transport_supported - gst_rtsp_stream_join_bin - gst_rtsp_stream_leave_bin - gst_rtsp_stream_new - gst_rtsp_stream_query_position - gst_rtsp_stream_query_stop - gst_rtsp_stream_recv_rtcp - gst_rtsp_stream_recv_rtp - gst_rtsp_stream_remove_transport - gst_rtsp_stream_request_aux_sender - gst_rtsp_stream_reserve_address - gst_rtsp_stream_seekable - gst_rtsp_stream_set_address_pool - gst_rtsp_stream_set_blocked - gst_rtsp_stream_set_buffer_size - gst_rtsp_stream_set_client_side - gst_rtsp_stream_set_control - gst_rtsp_stream_set_dscp_qos - gst_rtsp_stream_set_mtu - gst_rtsp_stream_set_multicast_iface - gst_rtsp_stream_set_profiles - gst_rtsp_stream_set_protocols - gst_rtsp_stream_set_pt_map - gst_rtsp_stream_set_publish_clock_mode - gst_rtsp_stream_set_retransmission_pt - gst_rtsp_stream_set_retransmission_time - gst_rtsp_stream_set_seqnum_offset - gst_rtsp_stream_transport_filter - gst_rtsp_stream_transport_get_rtpinfo - gst_rtsp_stream_transport_get_stream - gst_rtsp_stream_transport_get_transport - gst_rtsp_stream_transport_get_type - gst_rtsp_stream_transport_get_url - gst_rtsp_stream_transport_is_timed_out - gst_rtsp_stream_transport_keep_alive - gst_rtsp_stream_transport_new - gst_rtsp_stream_transport_recv_data - gst_rtsp_stream_transport_send_rtcp - gst_rtsp_stream_transport_send_rtp - gst_rtsp_stream_transport_set_active - gst_rtsp_stream_transport_set_callbacks - gst_rtsp_stream_transport_set_keepalive - gst_rtsp_stream_transport_set_timed_out - gst_rtsp_stream_transport_set_transport - gst_rtsp_stream_transport_set_url - gst_rtsp_stream_unblock_linked - gst_rtsp_stream_update_crypto - gst_rtsp_suspend_mode_get_type - gst_rtsp_thread_get_type - gst_rtsp_thread_new - gst_rtsp_thread_pool_cleanup - gst_rtsp_thread_pool_get_max_threads - gst_rtsp_thread_pool_get_thread - gst_rtsp_thread_pool_get_type - gst_rtsp_thread_pool_new - gst_rtsp_thread_pool_set_max_threads - gst_rtsp_thread_reuse - gst_rtsp_thread_stop - gst_rtsp_token_get_string - gst_rtsp_token_get_structure - gst_rtsp_token_get_type - gst_rtsp_token_is_allowed - gst_rtsp_token_new - gst_rtsp_token_new_empty - gst_rtsp_token_new_valist - gst_rtsp_token_writable_structure - gst_rtsp_transport_mode_get_type From 3d61e20a99263ec2e08c130854f9faaa8b752377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 26 Nov 2017 14:46:05 +0000 Subject: [PATCH 1416/1776] rtsp: fix distcheck --- gst/rtsp-server/rtsp-session.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 8f7cf4d729..229202da58 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -20,7 +20,7 @@ #include #include -#include /* for GST_RTSP_SERVER_DEPRECATED_FOR */ +#include "rtsp-server.h" /* for GST_RTSP_SERVER_DEPRECATED_FOR */ #ifndef __GST_RTSP_SESSION_H__ #define __GST_RTSP_SESSION_H__ From c390202faac4d3e96489d79ca2436117ecb376cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 26 Nov 2017 16:29:49 +0000 Subject: [PATCH 1417/1776] meson: remove vs_module_defs_dir variable which is no longer needed --- meson.build | 2 -- 1 file changed, 2 deletions(-) diff --git a/meson.build b/meson.build index 05e5776749..96f704be1e 100644 --- a/meson.build +++ b/meson.build @@ -79,8 +79,6 @@ gstapp_dep = dependency('gstreamer-app-1.0', version : gst_req, gstnet_dep = dependency('gstreamer-net-1.0', version : gst_req, fallback : ['gstreamer', 'gst_net_dep']) -vs_module_defs_dir = meson.current_source_dir() + '/win32/common/' - gir = find_program('g-ir-scanner', required : false) gnome = import('gnome') build_gir = gir.found() and not meson.is_cross_build() and not get_option('disable_introspection') From 0015791f8fe72e648cef264f49f6e3c9c224caf7 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Sat, 25 Nov 2017 20:45:44 +0100 Subject: [PATCH 1418/1776] rtsp-media: Fix missing lock in gst_rtsp_media_seekable() https://bugzilla.gnome.org/show_bug.cgi?id=790674 --- gst/rtsp-server/rtsp-media.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e10ad8bfcf..5cd8d658dc 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2581,9 +2581,9 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) break; case GST_MESSAGE_ASYNC_DONE: if (priv->complete) { - /* receive the final ASYNC_DONE, that is posted by the media pipeline - * after all the transport parts have been successfully added to - * the media streams. */ + /* receive the final ASYNC_DONE, that is posted by the media pipeline + * after all the transport parts have been successfully added to + * the media streams. */ GST_DEBUG_OBJECT (media, "got async-done"); if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); @@ -4043,11 +4043,20 @@ gst_rtsp_media_get_transport_mode (GstRTSPMedia * media) GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia * media) { + GstRTSPMediaPrivate *priv; + GstClockTimeDiff res; + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + priv = media->priv; + /* Currently we are not able to seek on live streams, * and no stream is seekable only to the beginning */ - return media->priv->seekable; + g_mutex_lock (&priv->lock); + res = priv->seekable; + g_mutex_unlock (&priv->lock); + + return res; } /** From caa3f1caac3d3ce43a86e27c06d3c4c7da15473c Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Sat, 25 Nov 2017 20:32:02 +0100 Subject: [PATCH 1419/1776] rtsp-stream: Do not reset 'blocking' if stream is already blocked https://bugzilla.gnome.org/show_bug.cgi?id=790674 --- gst/rtsp-server/rtsp-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index fee99ac950..94d619709e 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4187,11 +4187,11 @@ set_blocked (GstRTSPStream * stream, gboolean blocked) priv = stream->priv; if (blocked) { - priv->blocking = FALSE; for (i = 0; i < 2; i++) { if (priv->blocked_id[i] != 0) continue; if (priv->send_src[i]) { + priv->blocking = FALSE; priv->blocked_id[i] = gst_pad_add_probe (priv->send_src[i], GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, pad_blocking, From abeb896232be1aad8867093f0dbeed3a95f56200 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Sat, 25 Nov 2017 20:34:16 +0100 Subject: [PATCH 1420/1776] check/media: Add seekability test case: not all streams are active Media contains two streams but only one is complete and prepared for playing. https://bugzilla.gnome.org/show_bug.cgi?id=790674 --- tests/check/gst/media.c | 75 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 11e0bfdfaa..38c2dc307d 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -115,6 +115,80 @@ GST_START_TEST (test_media_seek) GST_END_TEST; +/* case: media is complete and contains two streams but only one is active */ +GST_START_TEST (test_media_seek_one_active_stream) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPStream *stream1; + GstRTSPStream *stream2; + GstRTSPTimeRange *range; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + GstRTSPTransport *transport; + + factory = gst_rtsp_media_factory_new (); + fail_if (gst_rtsp_media_factory_is_shared (factory)); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 " + " audiotestsrc ! audioconvert ! rtpL16pay name=pay1 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + fail_unless (gst_rtsp_media_n_streams (media) == 2); + + stream1 = gst_rtsp_media_get_stream (media, 0); + fail_unless (stream1 != NULL); + + pool = gst_rtsp_thread_pool_new (); + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + + fail_unless (gst_rtsp_media_prepare (media, thread)); + fail_unless (media_has_sdp (media)); + + /* define transport */ + fail_unless (gst_rtsp_transport_new (&transport) == GST_RTSP_OK); + transport->lower_transport = GST_RTSP_LOWER_TRANS_TCP; + + fail_unless_equals_int64 (gst_rtsp_media_seekable (media), G_MAXINT64); + + /* video stream is complete and seekable */ + fail_unless (gst_rtsp_stream_complete_stream (stream1, transport)); + fail_unless (gst_rtsp_stream_seekable (stream1)); + + /* audio stream is blocked (it does not contain any transport based part), + * but it's seekable */ + stream2 = gst_rtsp_media_get_stream (media, 1); + fail_unless (stream2 != NULL); + fail_unless (gst_rtsp_stream_seekable (stream2)); + + fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK); + fail_unless (gst_rtsp_range_parse ("npt=3.0-", &range) == GST_RTSP_OK); + + /* the media is seekable now */ + fail_unless (gst_rtsp_media_seek (media, range)); + + gst_rtsp_range_free (range); + + fail_unless (gst_rtsp_media_unprepare (media)); + g_object_unref (media); + + gst_rtsp_url_free (url); + g_object_unref (factory); + + g_object_unref (pool); + + gst_rtsp_thread_pool_cleanup (); +} + +GST_END_TEST; + GST_START_TEST (test_media_seek_no_sinks) { @@ -577,6 +651,7 @@ rtspmedia_suite (void) tcase_set_timeout (tc, 20); tcase_add_test (tc, test_media_seek); tcase_add_test (tc, test_media_seek_no_sinks); + tcase_add_test (tc, test_media_seek_one_active_stream); tcase_add_test (tc, test_media); tcase_add_test (tc, test_media_prepare); tcase_add_test (tc, test_media_reusable); From 16d0d8c7c895a15fa9b11ad99eb799771c1833fd Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 27 Nov 2017 20:18:24 +1100 Subject: [PATCH 1421/1776] Automatic update of common submodule From 3f4aa96 to e8c7a71 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 3f4aa969cb..e8c7a71bf3 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 3f4aa969cbe39584a649d98d4cf321d78bd73092 +Subproject commit e8c7a71bf3e2ee48f682011bd63d64a8c78ea3b6 From 1555143299ccedb0ff8ed9e7ee1c59285b1b13f4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 26 Nov 2017 13:26:39 -0300 Subject: [PATCH 1422/1776] Fix build when -Werror=deprecated-declarations is on MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As gst_rtsp_session_next_timeout is deprecated. ``` ../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-session.c:760:3: error: ‘gst_rtsp_session_next_timeout’ is deprecated: Use 'gst_rtsp_session_next_timeout_usec' instead [-Werror=deprecated-declarations] res = (gst_rtsp_session_next_timeout (session, now) == 0); ^~~ ../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-session.c:685:1: note: declared here gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` --- gst/rtsp-server/rtsp-session.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 8e82ce2854..706664203d 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -757,7 +757,8 @@ gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) { gboolean res; - res = (gst_rtsp_session_next_timeout (session, now) == 0); + res = gst_rtsp_session_next_timeout_usec (session, + (now->tv_sec * G_USEC_PER_SEC) + (now->tv_usec)); return res; } From 0dae3a007d25a2120a9d2cfaada6c5efc4cc2f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 6 Dec 2017 20:42:39 +0000 Subject: [PATCH 1423/1776] meson: build more tests and add options to disable tests and examples --- meson.build | 8 ++++++-- meson_options.txt | 4 ++++ tests/meson.build | 9 +++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 96f704be1e..9117a96104 100644 --- a/meson.build +++ b/meson.build @@ -89,6 +89,10 @@ gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**);' + 'gst_init(NULL,NULL);' ] subdir('gst') -subdir('tests') -subdir('examples') +if get_option('tests') + subdir('tests') +endif +if get_option('examples') + subdir('examples') +endif subdir('pkgconfig') diff --git a/meson_options.txt b/meson_options.txt index 16265d35d8..cf9d95fb76 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -5,3 +5,7 @@ option('with-package-name', type : 'string', description : 'package name to use in plugins') option('with-package-origin', type : 'string', value : 'Unknown package origin', description : 'package origin URL to use in plugins') +option('tests', type : 'boolean', value : true, + description : 'Build and enable unit tests') +option('examples', type : 'boolean', value : true, + description : 'Build the examples') diff --git a/tests/meson.build b/tests/meson.build index cd3aa67d06..f87683d9ef 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,3 +1,12 @@ if host_machine.system() != 'windows' subdir('check') endif + +test_cleanup_exe = executable('test-cleanup', 'test-cleanup.c', + dependencies: gst_rtsp_server_dep) + +test_reuse_exe = executable('test-reuse', 'test-reuse.c', + dependencies: gst_rtsp_server_dep) + +test('test-cleanup', test_cleanup_exe) +test('test-reuse', test_reuse_exe) From f5b7f57a1764820b312cb16cb24aa36f1db0ec33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 6 Dec 2017 20:47:22 +0000 Subject: [PATCH 1424/1776] tests: disable all tests when --disable-tests is used Move conditional subdir include into top level. Based on patch by: Joel Holdsworth https://bugzilla.gnome.org/show_bug.cgi?id=757703 --- Makefile.am | 10 ++++++++-- tests/Makefile.am | 12 ++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Makefile.am b/Makefile.am index d663e61891..4489fc93ce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,13 +6,19 @@ else SUBDIRS_EXAMPLES = endif -SUBDIRS = \ +if BUILD_TESTS +SUBDIRS_TESTS = tests +else +SUBDIRS_TESTS = +endif + +SUBDIRS = \ gst \ common \ pkgconfig \ docs \ $(SUBDIRS_EXAMPLES) \ - tests + $(SUBDIRS_TESTS) DIST_SUBDIRS = gst common pkgconfig docs examples tests diff --git a/tests/Makefile.am b/tests/Makefile.am index ca2ba661e8..f653107024 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -6,14 +6,6 @@ AM_LDFLAGS = \ $(GST_LIBS) \ $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la -if BUILD_TESTS -SUBDIRS_CHECK = check -else -SUBDIRS_CHECK = -endif +SUBDIRS = check -SUBDIRS = \ - $(SUBDIRS_CHECK) - -DIST_SUBDIRS = \ - check +DIST_SUBDIRS = check From 64a46d47ba73e94838ba03317d72c2f02f2ce429 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 7 Dec 2017 16:08:29 +0100 Subject: [PATCH 1425/1776] rtsp-server: Minor doc fixes Mostly for g-i --- gst/rtsp-server/rtsp-media.c | 2 +- gst/rtsp-server/rtsp-session-media.c | 4 ++-- gst/rtsp-server/rtsp-stream.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 5cd8d658dc..cebd75fc95 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -4062,7 +4062,7 @@ gst_rtsp_media_seekable (GstRTSPMedia * media) /** * gst_rtsp_media_complete_pipeline: * @media: a #GstRTSPMedia - * @transports: a list of #GstRTSPTransport + * @transports: (element-type GstRTSPTransport): a list of #GstRTSPTransport * * Add a receiver and sender parts to the pipeline based on the transport from * SETUP. diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index bb0dd8d4b5..0aaf543dd5 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -413,8 +413,8 @@ gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx) * * Get a list of all available #GstRTSPStreamTransport in this session. * - * Returns: (transfer full): a list of #GstRTSPStreamTransport, - * g_ptr_array_unref () after usage. + * Returns: (transfer full) (element-type GstRTSPStreamTransport): a + * list of #GstRTSPStreamTransport, g_ptr_array_unref () after usage. */ GPtrArray * gst_rtsp_session_media_get_transports (GstRTSPSessionMedia * media) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 94d619709e..d8d951ba69 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1483,7 +1483,7 @@ cleanup: * @stream: a #GstRTSPStream * @family: protocol family * @transport: transport method - * @use_client_setttings: Whether to use client settings or not + * @use_client_settings: Whether to use client settings or not * * Allocates RTP and RTCP ports. * From b4ab386e8726c162c5744c74894a3cae7f970d65 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Thu, 14 Dec 2017 14:53:35 +1100 Subject: [PATCH 1426/1776] Automatic update of common submodule From e8c7a71 to 3fa2c9e --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index e8c7a71bf3..3fa2c9e372 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit e8c7a71bf3e2ee48f682011bd63d64a8c78ea3b6 +Subproject commit 3fa2c9e372bceec30be91e67fb02b6cb05bed493 From 96cfed48bfd06d4c620fa0630131ac0d5aa33db7 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Sat, 16 Dec 2017 21:01:43 +0100 Subject: [PATCH 1427/1776] rtspclientsink: Wait until OPEN has been scheduled Make sure that the sink thread has started opening connection to the server before continuing. https://bugzilla.gnome.org/show_bug.cgi?id=790412 --- gst/rtsp-sink/gstrtspclientsink.c | 18 ++++++++++++++++++ gst/rtsp-sink/gstrtspclientsink.h | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 73ca9db524..d49f224c36 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -3025,6 +3025,12 @@ gst_rtsp_client_sink_open (GstRTSPClientSink * sink, gboolean async) sink->methods = GST_RTSP_SETUP | GST_RTSP_RECORD | GST_RTSP_PAUSE | GST_RTSP_TEARDOWN; + g_mutex_lock (&sink->open_conn_lock); + sink->open_conn_start = TRUE; + g_cond_broadcast (&sink->open_conn_cond); + GST_DEBUG_OBJECT (sink, "connection to server started"); + g_mutex_unlock (&sink->open_conn_lock); + if ((ret = gst_rtsp_client_sink_connect_to_server (sink, async)) < 0) goto open_failed; @@ -4569,6 +4575,18 @@ gst_rtsp_client_sink_change_state (GstElement * element, ret = GST_STATE_CHANGE_ASYNC; g_mutex_unlock (&rtsp_client_sink->preroll_lock); gst_rtsp_client_sink_loop_send_cmd (rtsp_client_sink, CMD_OPEN, 0); + + /* CMD_OPEN has been scheduled. Wait until the sink thread starts + * opening connection to the server */ + g_mutex_lock (&rtsp_client_sink->open_conn_lock); + while (!rtsp_client_sink->open_conn_start) { + GST_DEBUG_OBJECT (rtsp_client_sink, + "wait for connection to be started"); + g_cond_wait (&rtsp_client_sink->open_conn_cond, + &rtsp_client_sink->open_conn_lock); + } + rtsp_client_sink->open_conn_start = FALSE; + g_mutex_unlock (&rtsp_client_sink->open_conn_lock); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING:{ GST_DEBUG_OBJECT (rtsp_client_sink, diff --git a/gst/rtsp-sink/gstrtspclientsink.h b/gst/rtsp-sink/gstrtspclientsink.h index b27daf86b8..476165ae4c 100644 --- a/gst/rtsp-sink/gstrtspclientsink.h +++ b/gst/rtsp-sink/gstrtspclientsink.h @@ -230,6 +230,11 @@ struct _GstRTSPClientSink { GMutex preroll_lock; GCond preroll_cond; + /* TRUE if connection to server has been scheduled */ + gboolean open_conn_start; + GMutex open_conn_lock; + GCond open_conn_cond; + GstClockTime rtx_time; GstRTSPProfile profiles; From 64f1a3ab8527a33512682355ddc8adb604d26148 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Sat, 16 Dec 2017 21:46:53 +0100 Subject: [PATCH 1428/1776] rtspclientsink: Use the new rtsp-stream API https://bugzilla.gnome.org/show_bug.cgi?id=790412 --- gst/rtsp-sink/gstrtspclientsink.c | 83 ++++++++++++++++++++++++++----- gst/rtsp-sink/gstrtspclientsink.h | 5 ++ 2 files changed, 75 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index d49f224c36..246975c98c 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -3037,10 +3037,6 @@ gst_rtsp_client_sink_open (GstRTSPClientSink * sink, gboolean async) if (async) gst_rtsp_client_sink_loop_end_cmd (sink, CMD_OPEN, ret); - /* Collect all our input streams and create - * stream objects before actually returning */ - gst_rtsp_client_sink_collect_streams (sink); - return ret; /* ERRORS */ @@ -3357,6 +3353,9 @@ gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink) } context->joined = TRUE; + /* Block the stream, as it does not have any transport parts yet */ + gst_rtsp_stream_set_blocked (context->stream, TRUE); + /* Let the stream object receive data */ gst_pad_remove_probe (srcpad, context->payloader_block_id); @@ -3710,6 +3709,28 @@ gst_rtsp_client_sink_setup_streams (GstRTSPClientSink * sink, gboolean async) GST_ELEMENT_PROGRESS (sink, CONTINUE, "request", ("SETUP stream %d", context->index)); + { + GstRTSPTransport *transport; + + gst_rtsp_transport_new (&transport); + if (gst_rtsp_transport_parse (transports, transport) != GST_RTSP_OK) + goto parse_transport_failed; + if (transport->lower_transport != GST_RTSP_LOWER_TRANS_TCP) { + if (!gst_rtsp_stream_allocate_udp_sockets (stream, family, transport, + FALSE)) { + gst_rtsp_transport_free (transport); + goto allocate_udp_ports_failed; + } + } + if (!gst_rtsp_stream_complete_stream (stream, transport)) { + gst_rtsp_transport_free (transport); + goto complete_stream_failed; + } + + gst_rtsp_transport_free (transport); + gst_rtsp_stream_set_blocked (stream, FALSE); + } + /* handle the code ourselves */ res = gst_rtsp_client_sink_send (sink, info, &request, &response, &code); if (res < 0) @@ -3885,6 +3906,30 @@ create_request_failed: g_free (str); goto cleanup_error; } +parse_transport_failed: + { + GST_RTSP_STATE_UNLOCK (sink); + GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL), + ("Could not parse transport.")); + res = GST_RTSP_ERROR; + goto cleanup_error; + } +allocate_udp_ports_failed: + { + GST_RTSP_STATE_UNLOCK (sink); + GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL), + ("Could not parse transport.")); + res = GST_RTSP_ERROR; + goto cleanup_error; + } +complete_stream_failed: + { + GST_RTSP_STATE_UNLOCK (sink); + GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL), + ("Could not parse transport.")); + res = GST_RTSP_ERROR; + goto cleanup_error; + } send_error: { gchar *str = gst_rtsp_strresult (res); @@ -3958,19 +4003,28 @@ gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async) GSocket *conn_socket; GList *walk; - /* Wait for streams to preroll */ g_mutex_lock (&sink->preroll_lock); - while (sink->in_async) { - GST_LOG_OBJECT (sink, "Waiting for ASYNC_DONE preroll"); - g_cond_wait (&sink->preroll_cond, &sink->preroll_lock); - } - g_mutex_unlock (&sink->preroll_lock); - if (sink->state == GST_RTSP_STATE_PLAYING) { /* Already recording, don't send another request */ GST_LOG_OBJECT (sink, "Already in RECORD. Skipping duplicate request."); + g_mutex_unlock (&sink->preroll_lock); goto done; } + g_mutex_unlock (&sink->preroll_lock); + + /* Collect all our input streams and create + * stream objects before actually returning. + * The streams are blocked at this point as we do not have any transport + * parts yet. */ + gst_rtsp_client_sink_collect_streams (sink); + + g_mutex_lock (&sink->block_streams_lock); + /* Wait for streams to be blocked */ + while (!sink->streams_blocked) { + GST_DEBUG_OBJECT (sink, "waiting for streams to be blocked"); + g_cond_wait (&sink->block_streams_cond, &sink->block_streams_lock); + } + g_mutex_unlock (&sink->block_streams_lock); /* Send announce, then setup for all streams */ gst_sdp_message_init (&sink->cursdp); @@ -4294,7 +4348,11 @@ gst_rtsp_client_sink_handle_message (GstBin * bin, GstMessage * message) return; } else if (gst_structure_has_name (s, "GstRTSPStreamBlocking")) { /* An RTSPStream has prerolled */ - g_cond_broadcast (&rtsp_client_sink->preroll_cond); + GST_DEBUG_OBJECT (rtsp_client_sink, "received GstRTSPStreamBlocking"); + g_mutex_lock (&rtsp_client_sink->block_streams_lock); + rtsp_client_sink->streams_blocked = TRUE; + g_cond_broadcast (&rtsp_client_sink->block_streams_cond); + g_mutex_unlock (&rtsp_client_sink->block_streams_lock); } GST_BIN_CLASS (parent_class)->handle_message (bin, message); break; @@ -4443,7 +4501,6 @@ gst_rtsp_client_sink_start (GstRTSPClientSink * sink) GST_DEBUG_OBJECT (sink, "starting"); sink->streams_collected = FALSE; - sink->in_async = TRUE; gst_element_set_locked_state (GST_ELEMENT (sink->internal_bin), TRUE); gst_rtsp_client_sink_set_state (sink, GST_STATE_READY); diff --git a/gst/rtsp-sink/gstrtspclientsink.h b/gst/rtsp-sink/gstrtspclientsink.h index 476165ae4c..9082530725 100644 --- a/gst/rtsp-sink/gstrtspclientsink.h +++ b/gst/rtsp-sink/gstrtspclientsink.h @@ -217,6 +217,11 @@ struct _GstRTSPClientSink { /* TRUE when stream info has been collected */ gboolean streams_collected; + /* TRUE when streams have been blocked */ + gboolean streams_blocked; + GMutex block_streams_lock; + GCond block_streams_cond; + guint next_pad_id; gint next_dyn_pt; From 4d86f99449839f74d0ade7f86451ed70bebdbb60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 19 Dec 2017 11:14:48 +0200 Subject: [PATCH 1429/1776] rtsp-stream: Decide based on the sockets, not the addresses if we already allocated a socket In the multicast case (as in test-multicast, not test-multicast2), the address could be allocated/reserved (and thus set) already without allocating the actual socket. We need to allocate the socket here still instead of just claiming that it was already allocated. See https://bugzilla.gnome.org/show_bug.cgi?id=791743#c2 --- gst/rtsp-server/rtsp-stream.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index d8d951ba69..39628d2aea 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1508,18 +1508,19 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, g_mutex_lock (&priv->lock); if (transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - if (family == G_SOCKET_FAMILY_IPV4 && priv->mcast_addr_v4) + if (family == G_SOCKET_FAMILY_IPV4 && priv->mcast_socket_v4[0]) allocated = TRUE; - else if (family == G_SOCKET_FAMILY_IPV6 && priv->mcast_addr_v6) + else if (family == G_SOCKET_FAMILY_IPV6 && priv->mcast_socket_v6[0]) allocated = TRUE; } else if (transport == GST_RTSP_LOWER_TRANS_UDP) { - if (family == G_SOCKET_FAMILY_IPV4 && priv->server_addr_v4) + if (family == G_SOCKET_FAMILY_IPV4 && priv->socket_v4[0]) allocated = TRUE; - else if (family == G_SOCKET_FAMILY_IPV6 && priv->server_addr_v6) + else if (family == G_SOCKET_FAMILY_IPV6 && priv->socket_v6[0]) allocated = TRUE; } if (allocated) { + GST_DEBUG_OBJECT (stream, "Allocated already"); g_mutex_unlock (&priv->lock); return TRUE; } From 4ec17b1975d38c3a87d593751197b9503ae14fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 19 Dec 2017 11:34:37 +0200 Subject: [PATCH 1430/1776] rtsp-stream: Set multicast TTL on the multicast sockets And not if we do unicast UDP. https://bugzilla.gnome.org/show_bug.cgi?id=791743 --- gst/rtsp-server/rtsp-stream.c | 43 ++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 39628d2aea..4a3d44c438 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1119,14 +1119,20 @@ set_socket_for_udpsink (GstElement * udpsink, GSocket * socket, static void set_multicast_socket_for_udpsink (GstElement * udpsink, GSocket * socket, GSocketFamily family, const gchar * multicast_iface, - const gchar * addr_str, gint port) + const gchar * addr_str, gint port, gint mcast_ttl) { set_socket_for_udpsink (udpsink, socket, family); if (multicast_iface) { + GST_INFO ("setting multicast-iface %s", multicast_iface); g_object_set (G_OBJECT (udpsink), "multicast-iface", multicast_iface, NULL); } + if (mcast_ttl > 0) { + GST_INFO ("setting ttl-mc %d", mcast_ttl); + g_object_set (G_OBJECT (udpsink), "ttl-mc", mcast_ttl, NULL); + } + g_signal_emit_by_name (udpsink, "add", addr_str, port, NULL); } @@ -1165,7 +1171,7 @@ get_port_from_socket (GSocket * socket) static gboolean create_and_configure_udpsink (GstRTSPStream * stream, GstElement ** udpsink, GSocket * socket_v4, GSocket * socket_v6, gboolean multicast, - gboolean is_rtp) + gboolean is_rtp, gint mcast_ttl) { GstRTSPStreamPrivate *priv = stream->priv; @@ -1222,7 +1228,7 @@ create_and_configure_udpsink (GstRTSPStream * stream, GstElement ** udpsink, goto get_port_failed; set_multicast_socket_for_udpsink (*udpsink, socket_v4, G_SOCKET_FAMILY_IPV4, priv->multicast_iface, - priv->mcast_addr_v4->address, port); + priv->mcast_addr_v4->address, port, mcast_ttl); } if (priv->mcast_addr_v6) { @@ -1232,7 +1238,7 @@ create_and_configure_udpsink (GstRTSPStream * stream, GstElement ** udpsink, goto get_port_failed; set_multicast_socket_for_udpsink (*udpsink, socket_v6, G_SOCKET_FAMILY_IPV6, priv->multicast_iface, - priv->mcast_addr_v6->address, port); + priv->mcast_addr_v6->address, port, mcast_ttl); } } @@ -2762,6 +2768,7 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport) GstPad *pad; GstBin *bin; gboolean is_tcp, is_udp, is_mcast; + gint mcast_ttl = 0; gint i; GST_DEBUG_OBJECT (stream, "create sender part"); @@ -2772,8 +2779,11 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport) is_udp = transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP; is_mcast = transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST; - GST_DEBUG_OBJECT (stream, "tcp: %d, udp: %d, mcast: %d", is_tcp, is_udp, - is_mcast); + if (is_mcast) + mcast_ttl = transport->ttl; + + GST_DEBUG_OBJECT (stream, "tcp: %d, udp: %d, mcast: %d (ttl: %d)", is_tcp, + is_udp, is_mcast, mcast_ttl); if (is_udp && !priv->server_addr_v4 && !priv->server_addr_v6) { GST_WARNING_OBJECT (stream, "no sockets assigned for UDP"); @@ -2829,12 +2839,13 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport) if (is_udp && !priv->udpsink[i]) { /* we create only one pair of udpsinks for IPv4 and IPv6 */ create_and_configure_udpsink (stream, &priv->udpsink[i], - priv->socket_v4[i], priv->socket_v6[i], FALSE, (i == 0)); + priv->socket_v4[i], priv->socket_v6[i], FALSE, (i == 0), mcast_ttl); plug_sink (stream, transport, i); } else if (is_mcast && !priv->mcast_udpsink[i]) { /* we create only one pair of mcast-udpsinks for IPv4 and IPv6 */ create_and_configure_udpsink (stream, &priv->mcast_udpsink[i], - priv->mcast_socket_v4[i], priv->mcast_socket_v6[i], TRUE, (i == 0)); + priv->mcast_socket_v4[i], priv->mcast_socket_v6[i], TRUE, (i == 0), + mcast_ttl); plug_sink (stream, transport, i); } else if (is_tcp && !priv->appsink[i]) { /* make appsink */ @@ -3695,6 +3706,14 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, if (!check_mcast_part_for_transport (stream, tr)) goto mcast_error; priv->transports = g_list_prepend (priv->transports, trans); + + if (tr->ttl > 0) { + GST_INFO ("setting ttl-mc %d", tr->ttl); + if (priv->udpsink[0]) + g_object_set (G_OBJECT (priv->udpsink[0]), "ttl-mc", tr->ttl, NULL); + if (priv->udpsink[1]) + g_object_set (G_OBJECT (priv->udpsink[1]), "ttl-mc", tr->ttl, NULL); + } } else { priv->transports = g_list_remove (priv->transports, trans); } @@ -3704,13 +3723,11 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, { gchar *dest; gint min, max; - guint ttl = 0; dest = tr->destination; if (tr->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { min = tr->port.min; max = tr->port.max; - ttl = tr->ttl; } else if (priv->client_side) { /* In client side mode the 'destination' is the RTSP server, so send * to those ports */ @@ -3722,12 +3739,6 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, } if (add) { - if (ttl > 0) { - GST_INFO ("setting ttl-mc %d", ttl); - if (priv->udpsink[0]) - g_object_set (G_OBJECT (priv->udpsink[0]), "ttl-mc", ttl, NULL); - g_object_set (G_OBJECT (priv->udpsink[1]), "ttl-mc", ttl, NULL); - } GST_INFO ("adding %s:%d-%d", dest, min, max); if (priv->udpsink[0]) g_signal_emit_by_name (priv->udpsink[0], "add", dest, min, NULL); From 587c1c470713f0a46a0b672a5d639b31efb44a6c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 20 Dec 2017 14:17:02 +0100 Subject: [PATCH 1431/1776] rtpsclientsink: Initialize and clear newly added mutex and cond While it *did* work, glib would automatically create new mutex and cond ... which never got freed --- gst/rtsp-sink/gstrtspclientsink.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 246975c98c..69d727d238 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -691,6 +691,12 @@ gst_rtsp_client_sink_init (GstRTSPClientSink * sink) g_mutex_init (&sink->conninfo.send_lock); g_mutex_init (&sink->conninfo.recv_lock); + g_mutex_init (&sink->block_streams_lock); + g_cond_init (&sink->block_streams_cond); + + g_mutex_init (&sink->open_conn_lock); + g_cond_init (&sink->open_conn_cond); + sink->internal_bin = (GstBin *) gst_bin_new ("rtspbin"); gst_element_set_locked_state (GST_ELEMENT_CAST (sink->internal_bin), TRUE); gst_bin_add (GST_BIN (sink), GST_ELEMENT_CAST (sink->internal_bin)); @@ -747,6 +753,12 @@ gst_rtsp_client_sink_finalize (GObject * object) g_mutex_clear (&rtsp_client_sink->preroll_lock); g_cond_clear (&rtsp_client_sink->preroll_cond); + g_mutex_clear (&rtsp_client_sink->block_streams_lock); + g_cond_clear (&rtsp_client_sink->block_streams_cond); + + g_mutex_clear (&rtsp_client_sink->open_conn_lock); + g_cond_clear (&rtsp_client_sink->open_conn_cond); + G_OBJECT_CLASS (parent_class)->finalize (object); } From 3d860913c66414b8737d1bf945dfe2434ac1e14b Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Tue, 2 Jan 2018 14:19:31 +0100 Subject: [PATCH 1432/1776] test: rtspserver: plug memory leak in test_no_session_timeout In test_no_session_timeout, unref the rtsp session object when the test is done. https://bugzilla.gnome.org/show_bug.cgi?id=792127 --- tests/check/gst/rtspserver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 7ed151672d..cfd8d9583e 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1643,6 +1643,8 @@ GST_START_TEST (test_no_session_timeout) is_expired = gst_rtsp_session_is_expired_usec (session, now); fail_unless (is_expired == FALSE); + + g_object_unref (session); } GST_END_TEST; From 9238b7e19a1fb8b4e0d29684d23e049b6f543513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 13 Jan 2018 14:58:00 +0000 Subject: [PATCH 1433/1776] tests: rtspclientsink: fix leak --- tests/check/gst/rtspclientsink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/check/gst/rtspclientsink.c b/tests/check/gst/rtspclientsink.c index 83c40e9cdd..b45ff0a815 100644 --- a/tests/check/gst/rtspclientsink.c +++ b/tests/check/gst/rtspclientsink.c @@ -142,6 +142,7 @@ media_constructed_cb (GstRTSPMediaFactory * mfactory, GstRTSPMedia * media, bin = gst_rtsp_media_get_element (media); *p_sink = gst_bin_get_by_name (GST_BIN (bin), "sink"); GST_INFO ("media constructed!: %" GST_PTR_FORMAT, *p_sink); + gst_object_unref (bin); } #define AUDIO_PIPELINE "audiotestsrc num-buffers=%d ! " \ From d0a4ddc2bb390109a75b9b07655dff54f5c3eb43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 13 Jan 2018 14:58:55 +0000 Subject: [PATCH 1434/1776] tests: rtspserver: fix another ref leak Even if this didn't show up in valgrind. --- tests/check/gst/rtspserver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index cfd8d9583e..b73de7bb4b 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -2091,6 +2091,7 @@ media_constructed_cb (GstRTSPMediaFactory * mfactory, GstRTSPMedia * media, bin = gst_rtsp_media_get_element (media); *p_sink = gst_bin_get_by_name (GST_BIN (bin), "sink"); GST_INFO ("media constructed!: %" GST_PTR_FORMAT, *p_sink); + gst_object_unref (bin); } #define RECORD_N_BUFS 10 From 4e048f7b8a418d9345548548fc8f5f93fe08e170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 13 Jan 2018 15:02:28 +0000 Subject: [PATCH 1435/1776] tests: fix indentation Fix and "fix". --- tests/check/gst/rtspclientsink.c | 3 ++- tests/check/gst/rtspserver.c | 14 +++++++++----- tests/check/gst/sessionpool.c | 18 ++++++++++++------ tests/check/gst/stream.c | 4 ++-- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/tests/check/gst/rtspclientsink.c b/tests/check/gst/rtspclientsink.c index b45ff0a815..da2f2dd8d0 100644 --- a/tests/check/gst/rtspclientsink.c +++ b/tests/check/gst/rtspclientsink.c @@ -156,7 +156,8 @@ GST_START_TEST (test_record) gint i; mfactory = - start_record_server ("( rtppcmadepay name=depay0 ! appsink name=sink async=false )"); + start_record_server + ("( rtppcmadepay name=depay0 ! appsink name=sink async=false )"); g_signal_connect (mfactory, "media-constructed", G_CALLBACK (media_constructed_cb), &server_sink); diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index b73de7bb4b..b8b1608a96 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -342,7 +342,8 @@ read_response (GstRTSPConnection * conn) return NULL; } type = gst_rtsp_message_get_type (response); - fail_unless (type == GST_RTSP_MESSAGE_RESPONSE || type == GST_RTSP_MESSAGE_DATA); + fail_unless (type == GST_RTSP_MESSAGE_RESPONSE + || type == GST_RTSP_MESSAGE_DATA); return response; } @@ -1104,7 +1105,8 @@ do_test_play_tcp_full (const gchar * range) { GstRTSPMessage *message; fail_unless (gst_rtsp_message_new (&message) == GST_RTSP_OK); - fail_unless (gst_rtsp_connection_receive (conn, message, NULL) == GST_RTSP_OK); + fail_unless (gst_rtsp_connection_receive (conn, message, + NULL) == GST_RTSP_OK); fail_unless (gst_rtsp_message_get_type (message) == GST_RTSP_MESSAGE_DATA); gst_rtsp_message_free (message); } @@ -1276,7 +1278,7 @@ GST_START_TEST (test_play_tcp) /* send PLAY request and check that we get 200 OK */ fail_unless (do_simple_request (conn, GST_RTSP_PLAY, - session)== GST_RTSP_STS_OK); + session) == GST_RTSP_STS_OK); /* send TEARDOWN request and check that we get 200 OK */ fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, @@ -2336,7 +2338,8 @@ do_test_multiple_transports (GstRTSPLowerTrans trans1, GstRTSPLowerTrans trans2) { GstRTSPMessage *message; fail_unless (gst_rtsp_message_new (&message) == GST_RTSP_OK); - fail_unless (gst_rtsp_connection_receive (conn2, message, NULL) == GST_RTSP_OK); + fail_unless (gst_rtsp_connection_receive (conn2, message, + NULL) == GST_RTSP_OK); fail_unless (gst_rtsp_message_get_type (message) == GST_RTSP_MESSAGE_DATA); gst_rtsp_message_free (message); } @@ -2364,7 +2367,8 @@ do_test_multiple_transports (GstRTSPLowerTrans trans1, GstRTSPLowerTrans trans2) GST_START_TEST (test_multiple_transports) { start_server (TRUE); - do_test_multiple_transports (GST_RTSP_LOWER_TRANS_UDP, GST_RTSP_LOWER_TRANS_TCP); + do_test_multiple_transports (GST_RTSP_LOWER_TRANS_UDP, + GST_RTSP_LOWER_TRANS_TCP); stop_server (); } diff --git a/tests/check/gst/sessionpool.c b/tests/check/gst/sessionpool.c index c1cc149c96..ebccad686e 100644 --- a/tests/check/gst/sessionpool.c +++ b/tests/check/gst/sessionpool.c @@ -111,8 +111,10 @@ GST_START_TEST (test_pool) { Responses responses = { - {session1, session2, session3}, - {GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_KEEP}, + {session1, session2, session3} + , + {GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_KEEP} + , }; list = gst_rtsp_session_pool_filter (pool, filter_func, &responses); @@ -121,8 +123,10 @@ GST_START_TEST (test_pool) { Responses responses = { - {session1, session2, session3}, - {GST_RTSP_FILTER_REF, GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_KEEP}, + {session1, session2, session3} + , + {GST_RTSP_FILTER_REF, GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_KEEP} + , }; list = gst_rtsp_session_pool_filter (pool, filter_func, &responses); @@ -133,8 +137,10 @@ GST_START_TEST (test_pool) { Responses responses = { - {session1, session2, session3}, - {GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_REMOVE}, + {session1, session2, session3} + , + {GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_KEEP, GST_RTSP_FILTER_REMOVE} + , }; list = gst_rtsp_session_pool_filter (pool, filter_func, &responses); diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index 759b7beeae..7b59c0abc9 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -76,7 +76,7 @@ get_sockets (GstRTSPLowerTrans lower_transport, GSocketFamily socket_family) /* allocate ports */ fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, - socket_family, transport, FALSE)); + socket_family, transport, FALSE)); fail_unless (gst_rtsp_stream_complete_stream (stream, transport)); fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK); @@ -194,7 +194,7 @@ GST_START_TEST (test_allocate_udp_ports_fail) fail_unless (gst_rtsp_transport_new (&transport) == GST_RTSP_OK); transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST; fail_if (gst_rtsp_stream_allocate_udp_sockets (stream, G_SOCKET_FAMILY_IPV4, - transport, FALSE)); + transport, FALSE)); fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK); g_object_unref (pool); From 54a8c6bddfb877c5eb953ffeb3892ceae4b91835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 18 Jan 2018 11:07:45 +0000 Subject: [PATCH 1436/1776] rtsp-token: add some API to set fields from bindings The existing functions are all vararg-based and as such not usable from bindings. https://bugzilla.gnome.org/show_bug.cgi?id=787073 --- docs/libs/gst-rtsp-server-sections.txt | 2 ++ gst/rtsp-server/rtsp-token.c | 48 ++++++++++++++++++++++++++ gst/rtsp-server/rtsp-token.h | 10 +++++- tests/check/gst/token.c | 11 ++++++ 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 3299fd71e9..669abb9cc5 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -725,7 +725,9 @@ gst_rtsp_token_ref gst_rtsp_token_unref gst_rtsp_token_get_structure gst_rtsp_token_writable_structure +gst_rtsp_token_set_string gst_rtsp_token_get_string +gst_rtsp_token_set_bool gst_rtsp_token_is_allowed GST_RTSP_TOKEN_CAST diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index 69250f9adc..c002e8af84 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -165,6 +165,54 @@ gst_rtsp_token_new_valist (const gchar * firstfield, va_list var_args) return token; } +/** + * gst_rtsp_token_set_string: + * @token: The #GstRTSPToken. + * @field: field to set + * @string_value: string value to set + * + * Sets a string value on @token. + * + * Since: 1.14 + */ +void +gst_rtsp_token_set_string (GstRTSPToken * token, const gchar * field, + const gchar * string_value) +{ + GstStructure *s; + + g_return_if_fail (token != NULL); + g_return_if_fail (field != NULL); + g_return_if_fail (string_value != NULL); + + s = gst_rtsp_token_writable_structure (token); + if (s != NULL) + gst_structure_set (s, field, G_TYPE_STRING, string_value, NULL); +} + +/** + * gst_rtsp_token_set_bool: + * @token: The #GstRTSPToken. + * @field: field to set + * @bool_value: boolean value to set + * + * Sets a boolean value on @token. + * + * Since: 1.14 + */ +void +gst_rtsp_token_set_bool (GstRTSPToken * token, const gchar * field, + gboolean bool_value) +{ + GstStructure *s; + + g_return_if_fail (token != NULL); + g_return_if_fail (field != NULL); + + s = gst_rtsp_token_writable_structure (token); + if (s != NULL) + gst_structure_set (s, field, G_TYPE_BOOLEAN, bool_value, NULL); +} /** * gst_rtsp_token_get_structure: diff --git a/gst/rtsp-server/rtsp-token.h b/gst/rtsp-server/rtsp-token.h index 34b4d50cdd..3122ed4873 100644 --- a/gst/rtsp-server/rtsp-token.h +++ b/gst/rtsp-server/rtsp-token.h @@ -89,13 +89,21 @@ const GstStructure * gst_rtsp_token_get_structure (GstRTSPToken *token); GST_EXPORT GstStructure * gst_rtsp_token_writable_structure (GstRTSPToken *token); +GST_EXPORT +void gst_rtsp_token_set_string (GstRTSPToken * token, + const gchar * field, + const gchar * string_value); GST_EXPORT const gchar * gst_rtsp_token_get_string (GstRTSPToken *token, const gchar *field); - +GST_EXPORT +void gst_rtsp_token_set_bool (GstRTSPToken * token, + const gchar * field, + gboolean bool_value); GST_EXPORT gboolean gst_rtsp_token_is_allowed (GstRTSPToken *token, const gchar *field); + #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPToken, gst_rtsp_token_unref) #endif diff --git a/tests/check/gst/token.c b/tests/check/gst/token.c index df5bbd5162..3b21c9794e 100644 --- a/tests/check/gst/token.c +++ b/tests/check/gst/token.c @@ -78,6 +78,17 @@ GST_START_TEST (test_token) fail_unless (gst_rtsp_token_is_allowed (token, "permission1")); fail_unless (gst_rtsp_token_is_allowed (token, "permission2")); fail_unless_equals_string (gst_rtsp_token_get_string (token, "role"), "user"); + + gst_rtsp_token_set_bool (token, "permission3", FALSE); + fail_unless (!gst_rtsp_token_is_allowed (token, "permission3")); + gst_rtsp_token_set_bool (token, "permission4", TRUE); + fail_unless (gst_rtsp_token_is_allowed (token, "permission4")); + + fail_unless_equals_string (gst_rtsp_token_get_string (token, "role"), "user"); + gst_rtsp_token_set_string (token, "role", "admin"); + fail_unless_equals_string (gst_rtsp_token_get_string (token, "role"), + "admin"); + gst_rtsp_token_unref (token); } From 8708262ebe27f04f66fad4448c95042713ea5d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 18 Jan 2018 11:32:32 +0000 Subject: [PATCH 1437/1776] rtsp-token: annotate constructors for bindings This maps _new_empty() to _new(), which also makes RTSPToken() work properly now. Since this API wasn't usable from bindings before, this should hopefully be fine. https://bugzilla.gnome.org/show_bug.cgi?id=787073 --- gst/rtsp-server/rtsp-token.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index c002e8af84..733546fbdf 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -96,7 +96,7 @@ gst_rtsp_token_init (GstRTSPTokenImpl * token, GstStructure * structure) } /** - * gst_rtsp_token_new_empty: + * gst_rtsp_token_new_empty: (rename-to gst_rtsp_token_new) * * Create a new empty Authorization token. * @@ -118,7 +118,7 @@ gst_rtsp_token_new_empty (void) } /** - * gst_rtsp_token_new: + * gst_rtsp_token_new: (skip) * @firstfield: the first fieldname * @...: additional arguments * @@ -141,7 +141,7 @@ gst_rtsp_token_new (const gchar * firstfield, ...) } /** - * gst_rtsp_token_new_valist: + * gst_rtsp_token_new_valist: (skip) * @firstfield: the first fieldname * @var_args: additional arguments * From b1f515178a363df0322d7adbd5754e1f6e2083c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 18 Jan 2018 23:53:20 +0000 Subject: [PATCH 1438/1776] permissions: add some new API to make this usable from bindings https://bugzilla.gnome.org/show_bug.cgi?id=787073 --- docs/libs/gst-rtsp-server-sections.txt | 2 + gst/rtsp-server/rtsp-permissions.c | 55 +++++++++++++++++++++++++- gst/rtsp-server/rtsp-permissions.h | 10 +++++ tests/check/gst/permissions.c | 24 +++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 669abb9cc5..677ece1353 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -356,6 +356,8 @@ gst_rtsp_permissions_ref gst_rtsp_permissions_unref gst_rtsp_permissions_add_role gst_rtsp_permissions_add_role_valist +gst_rtsp_permissions_add_role_empty +gst_rtsp_permissions_add_permission_for_role gst_rtsp_permissions_remove_role gst_rtsp_permissions_get_role gst_rtsp_permissions_is_allowed diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index 66e9e44340..34cf42a570 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -123,6 +123,60 @@ gst_rtsp_permissions_new (void) return GST_RTSP_PERMISSIONS (permissions); } +/** + * gst_rtsp_permissions_add_permission_for_role: + * @permissions: a #GstRTSPPermissions + * @role: a role + * @permission: the permission + * @allowed: whether the role has this permission or not + * + * Add a new @permission for @role to @permissions with the access in @allowed. + * + * Since: 1.14 + */ +void +gst_rtsp_permissions_add_permission_for_role (GstRTSPPermissions * permissions, + const gchar * role, const gchar * permission, gboolean allowed) +{ + GstRTSPPermissionsImpl *impl = (GstRTSPPermissionsImpl *) permissions; + guint i, len; + + g_return_if_fail (GST_IS_RTSP_PERMISSIONS (permissions)); + g_return_if_fail (gst_mini_object_is_writable (&permissions->mini_object)); + g_return_if_fail (role != NULL); + g_return_if_fail (permission != NULL); + + len = impl->roles->len; + for (i = 0; i < len; i++) { + GstStructure *entry = g_ptr_array_index (impl->roles, i); + + if (gst_structure_has_name (entry, role)) { + gst_structure_set (entry, permission, G_TYPE_BOOLEAN, allowed, NULL); + return; + } + } + + gst_rtsp_permissions_add_role (permissions, role, + permission, G_TYPE_BOOLEAN, allowed, NULL); +} + +/** + * gst_rtsp_permissions_add_role_empty: (rename-to gst_rtsp_permissions_add_role) + * @permissions: a #GstRTSPPermissions + * @role: a role + * + * Add a new @role to @permissions without any permissions. You can add + * permissions for the role with gst_rtsp_permissions_add_permission_for_role(). + * + * Since: 1.14 + */ +void +gst_rtsp_permissions_add_role_empty (GstRTSPPermissions * permissions, + const gchar * role) +{ + gst_rtsp_permissions_add_role (permissions, role, NULL); +} + /** * gst_rtsp_permissions_add_role: * @permissions: a #GstRTSPPermissions @@ -165,7 +219,6 @@ gst_rtsp_permissions_add_role_valist (GstRTSPPermissions * permissions, g_return_if_fail (GST_IS_RTSP_PERMISSIONS (permissions)); g_return_if_fail (gst_mini_object_is_writable (&permissions->mini_object)); g_return_if_fail (role != NULL); - g_return_if_fail (fieldname != NULL); structure = gst_structure_new_valist (role, fieldname, var_args); g_return_if_fail (structure != NULL); diff --git a/gst/rtsp-server/rtsp-permissions.h b/gst/rtsp-server/rtsp-permissions.h index 822285cae5..4bdff46ce2 100644 --- a/gst/rtsp-server/rtsp-permissions.h +++ b/gst/rtsp-server/rtsp-permissions.h @@ -86,6 +86,16 @@ void gst_rtsp_permissions_add_role_valist (GstRTSPPermissions * const gchar *fieldname, va_list var_args); +GST_EXPORT +void gst_rtsp_permissions_add_role_empty (GstRTSPPermissions * permissions, + const gchar * role); + +GST_EXPORT +void gst_rtsp_permissions_add_permission_for_role (GstRTSPPermissions * permissions, + const gchar * role, + const gchar * permission, + gboolean allowed); + GST_EXPORT void gst_rtsp_permissions_remove_role (GstRTSPPermissions *permissions, const gchar *role); diff --git a/tests/check/gst/permissions.c b/tests/check/gst/permissions.c index 0dcf7703b3..8083b1d55e 100644 --- a/tests/check/gst/permissions.c +++ b/tests/check/gst/permissions.c @@ -86,6 +86,30 @@ GST_START_TEST (test_permissions) fail_unless (gst_rtsp_permissions_is_allowed (perms, "admin", "permission2")); fail_if (gst_rtsp_permissions_is_allowed (perms, "user", "permission1")); fail_if (gst_rtsp_permissions_is_allowed (perms, "user", "permission2")); + + /* _add_permission_for_role() should overwrite existing or create new role */ + fail_unless (gst_rtsp_permissions_is_allowed (perms, "admin", "permission1")); + gst_rtsp_permissions_add_permission_for_role (perms, "admin", "permission1", + FALSE); + fail_if (gst_rtsp_permissions_is_allowed (perms, "admin", "permission1")); + + fail_if (gst_rtsp_permissions_is_allowed (perms, "tester", "permission1")); + gst_rtsp_permissions_add_permission_for_role (perms, "tester", "permission1", + TRUE); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "tester", + "permission1")); + gst_rtsp_permissions_add_permission_for_role (perms, "tester", "permission1", + FALSE); + fail_if (gst_rtsp_permissions_is_allowed (perms, "tester", "permission1")); + gst_rtsp_permissions_add_permission_for_role (perms, "tester", "permission2", + TRUE); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "tester", + "permission2")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "tester", "permission3")); + + gst_rtsp_permissions_add_role_empty (perms, "noone"); + fail_if (gst_rtsp_permissions_is_allowed (perms, "noone", "permission1")); + gst_rtsp_permissions_unref (perms); } From c3e58dfdbe61ddc19441a8251caa0cbc5a669a2e Mon Sep 17 00:00:00 2001 From: Andrew Bott Date: Fri, 16 Sep 2016 20:41:19 +0000 Subject: [PATCH 1439/1776] mount-points: fix matching of paths where there's also an entry with a common prefix e.g. with the following mount points /raw /raw/snapshot /raw/video _match() would not match /raw/video and /raw/snapshot correctly. https://bugzilla.gnome.org/show_bug.cgi?id=771555 --- gst/rtsp-server/rtsp-mount-points.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index c6a8c06dce..77d82ed471 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -248,6 +248,8 @@ gst_rtsp_mount_points_match (GstRTSPMountPoints * mounts, item.path = (gchar *) path; item.len = strlen (path); + GST_LOG ("Looking for mount point path %s", path); + g_mutex_lock (&priv->lock); if (priv->dirty) { g_sequence_sort (priv->mounts, data_item_compare, mounts); @@ -266,18 +268,17 @@ gst_rtsp_mount_points_match (GstRTSPMountPoints * mounts, data_item_dump (ritem, "inspect: "); - if (best == NULL) { - if (has_prefix (&item, ritem)) { + /* The sequence is sorted, so any prefix match is an improvement upon + * the previous best match, as '/abc' will always be before '/abcd' */ + if (has_prefix (&item, ritem)) { + if (best == NULL) { data_item_dump (ritem, "prefix: "); - best = iter; + } else { + data_item_dump (ritem, "new best: "); } - } else { - if (!has_prefix (&item, ritem)) - break; - best = iter; - data_item_dump (ritem, "new best: "); } + iter = g_sequence_iter_next (iter); } if (best) { From f5b99d8fcebe9ec00a2c9c9f550d25caa253bac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 25 Jan 2018 12:06:57 +0000 Subject: [PATCH 1440/1776] tests: mountpoints: add more checks for mount point path matching https://bugzilla.gnome.org/show_bug.cgi?id=771555 --- tests/check/gst/mountpoints.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/check/gst/mountpoints.c b/tests/check/gst/mountpoints.c index 31a223e8e5..6a35bd2333 100644 --- a/tests/check/gst/mountpoints.c +++ b/tests/check/gst/mountpoints.c @@ -69,6 +69,9 @@ static const gchar *paths[] = { "/tark/bar/baz", "/tark/bar/baz/t", "/boozop", + "/raw", + "/raw/video", + "/raw/snapshot", }; GST_START_TEST (test_match) @@ -124,6 +127,14 @@ GST_START_TEST (test_match) fail_unless (tmp == f[4]); fail_unless (matched == 13); g_object_unref (tmp); + tmp = gst_rtsp_mount_points_match (mounts, "/raw/video", &matched); + fail_unless (tmp == f[8]); + fail_unless (matched == 10); + g_object_unref (tmp); + tmp = gst_rtsp_mount_points_match (mounts, "/raw/snapshot", &matched); + fail_unless (tmp == f[9]); + fail_unless (matched == 13); + g_object_unref (tmp); g_object_unref (mounts); } From 5964247829b8b6011b535be0dcfafc572467b809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 25 Jan 2018 12:09:03 +0000 Subject: [PATCH 1441/1776] mount-points: bail out of loop again when matching mount points Previous patch led to us iterating the entire sequence. Bail out of the loop again if we have a match but are moving away from it. https://bugzilla.gnome.org/show_bug.cgi?id=771555 --- gst/rtsp-server/rtsp-mount-points.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 77d82ed471..858c3917a1 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -277,6 +277,11 @@ gst_rtsp_mount_points_match (GstRTSPMountPoints * mounts, data_item_dump (ritem, "new best: "); } best = iter; + } else { + /* if have a match and the current item doesn't prefix match the best we + * found so far then we're moving away and can bail out of the loop */ + if (best != NULL && !has_prefix (ritem, g_sequence_get (best))) + break; } iter = g_sequence_iter_next (iter); From 3a8bed19da1e510e18d48dce747a51339152d328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 30 Jan 2018 20:35:21 +0000 Subject: [PATCH 1442/1776] meson: use -fno-strict-aliasing where supported https://bugzilla.gnome.org/show_bug.cgi?id=769183 --- meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meson.build b/meson.build index 9117a96104..1e860a4b7f 100644 --- a/meson.build +++ b/meson.build @@ -32,6 +32,11 @@ if cc.has_argument('-fvisibility=hidden') add_project_arguments('-fvisibility=hidden', language: 'c') endif +# Disable strict aliasing +if cc.has_argument('-fno-strict-aliasing') + add_project_arguments('-fno-strict-aliasing', language: 'c') +endif + cdata = configuration_data() cdata.set_quoted('GETTEXT_PACKAGE', 'gst-rtsp-server-1.0') cdata.set_quoted('PACKAGE', 'gst-rtsp-server') From 22e1bc7763d2ddde71553788d52c4b027c4e6f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 4 Feb 2018 12:24:09 +0100 Subject: [PATCH 1443/1776] autotools: use -fno-strict-aliasing where supported https://bugzilla.gnome.org/show_bug.cgi?id=769183 --- configure.ac | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fa9350406a..40ee2f7677 100644 --- a/configure.ac +++ b/configure.ac @@ -268,6 +268,10 @@ VISIBILITY_CFLAGS="" AS_COMPILER_FLAG([-fvisibility=hidden], [VISIBILITY_CFLAGS="-fvisibility=hidden"]) AC_SUBST(VISIBILITY_CFLAGS) +dnl disable strict aliasing +AS_COMPILER_FLAG([-fno-strict-aliasing], [EXTRA_CFLAGS="-fno-strict-aliasing"]) +AC_SUBST(EXTRA_CFLAGS) + dnl every flag in GST_OPTION_CFLAGS can be overridden at make time GST_OPTION_CFLAGS="\$(WARNING_CFLAGS) \$(ERROR_CFLAGS) \$(DEBUG_CFLAGS) \$(PROFILE_CFLAGS) \$(GCOV_CFLAGS) \$(OPT_CFLAGS) \$(DEPRECATED_CFLAGS)" AC_SUBST(GST_OPTION_CFLAGS) @@ -275,7 +279,7 @@ AC_SUBST(GST_OPTION_CFLAGS) dnl FIXME: do we want to rename to GST_ALL_* ? dnl prefer internal headers to already installed ones dnl add GST_OPTION_CFLAGS, but overridable -GST_CFLAGS="$GST_CFLAGS \$(GST_STATIC_CFLAGS) \$(GST_OPTION_CFLAGS) \$(VISIBILITY_CFLAGS)" +GST_CFLAGS="$GST_CFLAGS $EXTRA_CFLAGS \$(GST_STATIC_CFLAGS) \$(GST_OPTION_CFLAGS) \$(VISIBILITY_CFLAGS)" AC_SUBST(GST_CFLAGS) AC_SUBST(GST_LIBS) From 03a512e4e15423be44f1fddffa7870a6770179b2 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 6 Feb 2018 17:58:49 +0100 Subject: [PATCH 1444/1776] rtsp-client: add type annotations gi doesn't seem to be able to figure out the type of the signal parameters when defined with G_DEFINE_POINTER_TYPE --- gst/rtsp-server/rtsp-client.c | 77 ++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 11 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b2b10087c4..54498ad3c4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -248,7 +248,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) /** * GstRTSPClient::pre-options-request: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext * * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, * otherwise an appropriate return code @@ -262,6 +262,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::options-request: + * @client: a #GstRTSPClient + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext + */ gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST] = g_signal_new ("options-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, options_request), @@ -271,7 +276,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) /** * GstRTSPClient::pre-describe-request: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext * * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, * otherwise an appropriate return code @@ -285,6 +290,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::describe-request: + * @client: a #GstRTSPClient + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext + */ gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST] = g_signal_new ("describe-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, describe_request), @@ -294,7 +304,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) /** * GstRTSPClient::pre-setup-request: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext * * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, * otherwise an appropriate return code @@ -308,6 +318,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::setup-request: + * @client: a #GstRTSPClient + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext + */ gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST] = g_signal_new ("setup-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, setup_request), @@ -317,7 +332,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) /** * GstRTSPClient::pre-play-request: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext * * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, * otherwise an appropriate return code @@ -331,6 +346,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::play-request: + * @client: a #GstRTSPClient + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext + */ gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST] = g_signal_new ("play-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, play_request), @@ -340,7 +360,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) /** * GstRTSPClient::pre-pause-request: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext * * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, * otherwise an appropriate return code @@ -354,6 +374,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pause-request: + * @client: a #GstRTSPClient + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext + */ gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST] = g_signal_new ("pause-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, pause_request), @@ -363,7 +388,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) /** * GstRTSPClient::pre-teardown-request: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext * * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, * otherwise an appropriate return code @@ -377,6 +402,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::teardown-request: + * @client: a #GstRTSPClient + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext + */ gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST] = g_signal_new ("teardown-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, teardown_request), @@ -386,7 +416,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) /** * GstRTSPClient::pre-set-parameter-request: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext * * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, * otherwise an appropriate return code @@ -400,6 +430,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::set-parameter-request: + * @client: a #GstRTSPClient + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext + */ gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST] = g_signal_new ("set-parameter-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, @@ -409,7 +444,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) /** * GstRTSPClient::pre-get-parameter-request: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext * * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, * otherwise an appropriate return code @@ -423,12 +458,22 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::get-parameter-request: + * @client: a #GstRTSPClient + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext + */ gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST] = g_signal_new ("get-parameter-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, get_parameter_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::handle-response: + * @client: a #GstRTSPClient + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext + */ gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE] = g_signal_new ("handle-response", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, @@ -450,7 +495,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) /** * GstRTSPClient::pre-announce-request: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext * * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, * otherwise an appropriate return code @@ -464,6 +509,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::announce-request: + * @client: a #GstRTSPClient + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext + */ gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST] = g_signal_new ("announce-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, announce_request), @@ -473,7 +523,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) /** * GstRTSPClient::pre-record-request: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext * * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, * otherwise an appropriate return code @@ -487,6 +537,11 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::record-request: + * @client: a #GstRTSPClient + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext + */ gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST] = g_signal_new ("record-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, record_request), @@ -496,7 +551,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) /** * GstRTSPClient::check-requirements: * @client: a #GstRTSPClient - * @ctx: a #GstRTSPContext + * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext * @arr: a NULL-terminated array of strings * * Returns: a newly allocated string with comma-separated list of From 261374873085f60a6318e3c2698d0acc8c0142b2 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 6 Feb 2018 18:00:33 +0100 Subject: [PATCH 1445/1776] gst_rtsp_context_get_current: add (skip) annotation The return value type is defined with G_DEFINE_POINTER_TYPE, and gi emits the following warning: Invalid non-constant return of bare structure or union; register as boxed type or (skip) --- gst/rtsp-server/rtsp-context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-context.c b/gst/rtsp-server/rtsp-context.c index 919ca2dc53..def64f22bd 100644 --- a/gst/rtsp-server/rtsp-context.c +++ b/gst/rtsp-server/rtsp-context.c @@ -31,7 +31,7 @@ G_DEFINE_POINTER_TYPE (GstRTSPContext, gst_rtsp_context); static GPrivate current_context; /** - * gst_rtsp_context_get_current: + * gst_rtsp_context_get_current: (skip): * * Get the current #GstRTSPContext. This object is retrieved from the * current thread that is handling the request for a client. From cd962024657154a76755dd68a203d7305d45371f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 8 Feb 2018 19:15:10 +0000 Subject: [PATCH 1446/1776] meson: make version numbers ints and fix int/string comparison WARNING: Trying to compare values of different types (str, int). The result of this is undefined and will become a hard error in a future Meson release. --- meson.build | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/meson.build b/meson.build index 1e860a4b7f..7dad698781 100644 --- a/meson.build +++ b/meson.build @@ -5,11 +5,11 @@ project('gst-rtsp-server', 'c', gst_version = meson.project_version() version_arr = gst_version.split('.') -gst_version_major = version_arr[0] -gst_version_minor = version_arr[1] -gst_version_micro = version_arr[2] -if version_arr.length() == 4 - gst_version_nano = version_arr[3] +gst_version_major = version_arr[0].to_int() +gst_version_minor = version_arr[1].to_int() +gst_version_micro = version_arr[2].to_int() + if version_arr.length() == 4 + gst_version_nano = version_arr[3].to_int() else gst_version_nano = 0 endif @@ -21,7 +21,7 @@ api_version = '1.0' soversion = 0 # maintaining compatibility with the previous libtool versioning # current = minor * 100 + micro -libversion = '@0@.@1@.0'.format(soversion, gst_version_minor.to_int() * 100 + gst_version_micro.to_int()) +libversion = '@0@.@1@.0'.format(soversion, gst_version_minor * 100 + gst_version_micro) plugins_install_dir = '@0@/gstreamer-1.0'.format(get_option('libdir')) From 2bb00ebfaad3c84726437dae2689e2b45a0507d2 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 12 Feb 2018 19:12:35 +0100 Subject: [PATCH 1447/1776] test-cleanup: bind any port The meson test suite runs tests in parallel, trying to bind a single port made the test fail. --- tests/test-cleanup.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test-cleanup.c b/tests/test-cleanup.c index aa0d3a40ee..e0bf023f88 100644 --- a/tests/test-cleanup.c +++ b/tests/test-cleanup.c @@ -43,6 +43,9 @@ main (int argc, char *argv[]) /* create a server instance */ server = gst_rtsp_server_new (); + /* We just want to bind any port here, so that tests can run in parallel */ + gst_rtsp_server_set_service (server, "0"); + /* attach the server to the default maincontext */ if ((id = gst_rtsp_server_attach (server, NULL)) == 0) goto failed; From c725ef01a4dd5b6fe97e2e68883df082223ba501 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 10 Feb 2018 00:07:25 +0100 Subject: [PATCH 1448/1776] All around: add annotations and API guards --- gst/rtsp-server/rtsp-auth.c | 6 ++-- gst/rtsp-server/rtsp-client.c | 20 +++++------ gst/rtsp-server/rtsp-media-factory.c | 14 ++++---- gst/rtsp-server/rtsp-media.c | 20 +++++------ gst/rtsp-server/rtsp-mount-points.c | 2 +- gst/rtsp-server/rtsp-server.c | 22 ++++++------ gst/rtsp-server/rtsp-session-media.c | 8 ++--- gst/rtsp-server/rtsp-session-pool.c | 4 +-- gst/rtsp-server/rtsp-session.c | 9 ++--- gst/rtsp-server/rtsp-stream-transport.c | 16 ++++++--- gst/rtsp-server/rtsp-stream.c | 46 ++++++++++++++----------- gst/rtsp-server/rtsp-thread-pool.c | 3 +- 12 files changed, 91 insertions(+), 79 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 85758c4cb9..cfad96650e 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -290,7 +290,7 @@ gst_rtsp_auth_set_tls_certificate (GstRTSPAuth * auth, GTlsCertificate * cert) * * Get the #GTlsCertificate used for negotiating TLS @auth. * - * Returns: (transfer full): the #GTlsCertificate of @auth. g_object_unref() after + * Returns: (transfer full) (nullable): the #GTlsCertificate of @auth. g_object_unref() after * usage. */ GTlsCertificate * @@ -350,7 +350,7 @@ gst_rtsp_auth_set_tls_database (GstRTSPAuth * auth, GTlsDatabase * database) * * Get the #GTlsDatabase used for verifying client certificate. * - * Returns: (transfer full): the #GTlsDatabase of @auth. g_object_unref() after + * Returns: (transfer full) (nullable): the #GTlsDatabase of @auth. g_object_unref() after * usage. * Since: 1.6 */ @@ -460,7 +460,7 @@ gst_rtsp_auth_set_default_token (GstRTSPAuth * auth, GstRTSPToken * token) * Get the default token for @auth. This token will be used for unauthenticated * users. * - * Returns: (transfer full): the #GstRTSPToken of @auth. gst_rtsp_token_unref() after + * Returns: (transfer full) (nullable): the #GstRTSPToken of @auth. gst_rtsp_token_unref() after * usage. */ GstRTSPToken * diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 54498ad3c4..4b5d5a3fb8 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -3806,7 +3806,7 @@ invalid_length: /** * gst_rtsp_client_set_session_pool: * @client: a #GstRTSPClient - * @pool: (transfer none): a #GstRTSPSessionPool + * @pool: (transfer none) (nullable): a #GstRTSPSessionPool * * Set @pool as the sessionpool for @client which it will use to find * or allocate sessions. the sessionpool is usually inherited from the server @@ -3847,7 +3847,7 @@ gst_rtsp_client_set_session_pool (GstRTSPClient * client, * * Get the #GstRTSPSessionPool object that @client uses to manage its sessions. * - * Returns: (transfer full): a #GstRTSPSessionPool, unref after usage. + * Returns: (transfer full) (nullable): a #GstRTSPSessionPool, unref after usage. */ GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient * client) @@ -3870,7 +3870,7 @@ gst_rtsp_client_get_session_pool (GstRTSPClient * client) /** * gst_rtsp_client_set_mount_points: * @client: a #GstRTSPClient - * @mounts: (transfer none): a #GstRTSPMountPoints + * @mounts: (transfer none) (nullable): a #GstRTSPMountPoints * * Set @mounts as the mount points for @client which it will use to map urls * to media streams. These mount points are usually inherited from the server that @@ -3905,7 +3905,7 @@ gst_rtsp_client_set_mount_points (GstRTSPClient * client, * * Get the #GstRTSPMountPoints object that @client uses to manage its sessions. * - * Returns: (transfer full): a #GstRTSPMountPoints, unref after usage. + * Returns: (transfer full) (nullable): a #GstRTSPMountPoints, unref after usage. */ GstRTSPMountPoints * gst_rtsp_client_get_mount_points (GstRTSPClient * client) @@ -3928,7 +3928,7 @@ gst_rtsp_client_get_mount_points (GstRTSPClient * client) /** * gst_rtsp_client_set_auth: * @client: a #GstRTSPClient - * @auth: (transfer none): a #GstRTSPAuth + * @auth: (transfer none) (nullable): a #GstRTSPAuth * * configure @auth to be used as the authentication manager of @client. */ @@ -3961,8 +3961,8 @@ gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth) * * Get the #GstRTSPAuth used as the authentication manager of @client. * - * Returns: (transfer full): the #GstRTSPAuth of @client. g_object_unref() after - * usage. + * Returns: (transfer full) (nullable): the #GstRTSPAuth of @client. + * g_object_unref() after usage. */ GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient * client) @@ -3985,7 +3985,7 @@ gst_rtsp_client_get_auth (GstRTSPClient * client) /** * gst_rtsp_client_set_thread_pool: * @client: a #GstRTSPClient - * @pool: (transfer none): a #GstRTSPThreadPool + * @pool: (transfer none) (nullable): a #GstRTSPThreadPool * * configure @pool to be used as the thread pool of @client. */ @@ -4018,7 +4018,7 @@ gst_rtsp_client_set_thread_pool (GstRTSPClient * client, * * Get the #GstRTSPThreadPool used as the thread pool of @client. * - * Returns: (transfer full): the #GstRTSPThreadPool of @client. g_object_unref() after + * Returns: (transfer full) (nullable): the #GstRTSPThreadPool of @client. g_object_unref() after * usage. */ GstRTSPThreadPool * @@ -4110,7 +4110,7 @@ no_address: * * Get the #GstRTSPConnection of @client. * - * Returns: (transfer none): the #GstRTSPConnection of @client. + * Returns: (transfer none) (nullable): the #GstRTSPConnection of @client. * The connection object returned remains valid until the client is freed. */ GstRTSPConnection * diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index f610a244c9..e5ad6a87c5 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -411,7 +411,7 @@ gst_rtsp_media_factory_new (void) /** * gst_rtsp_media_factory_set_permissions: * @factory: a #GstRTSPMediaFactory - * @permissions: (transfer none): a #GstRTSPPermissions + * @permissions: (transfer none) (nullable): a #GstRTSPPermissions * * Set @permissions on @factory. */ @@ -439,7 +439,7 @@ gst_rtsp_media_factory_set_permissions (GstRTSPMediaFactory * factory, * * Get the permissions object from @factory. * - * Returns: (transfer full): a #GstRTSPPermissions object, unref after usage. + * Returns: (transfer full) (nullable): a #GstRTSPPermissions object, unref after usage. */ GstRTSPPermissions * gst_rtsp_media_factory_get_permissions (GstRTSPMediaFactory * factory) @@ -534,7 +534,7 @@ gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory, * Get the gst_parse_launch() pipeline description that will be used in the * default prepare vmethod. * - * Returns: (transfer full): the configured launch description. g_free() after + * Returns: (transfer full) (nullable): the configured launch description. g_free() after * usage. */ gchar * @@ -748,7 +748,7 @@ gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory) /** * gst_rtsp_media_factory_set_address_pool: * @factory: a #GstRTSPMediaFactory - * @pool: (transfer none): a #GstRTSPAddressPool + * @pool: (transfer none) (nullable): a #GstRTSPAddressPool * * configure @pool to be used as the address pool of @factory. */ @@ -780,7 +780,7 @@ gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory, * * Get the #GstRTSPAddressPool used as the address pool of @factory. * - * Returns: (transfer full): the #GstRTSPAddressPool of @factory. g_object_unref() after + * Returns: (transfer full) (nullable): the #GstRTSPAddressPool of @factory. g_object_unref() after * usage. */ GstRTSPAddressPool * @@ -804,7 +804,7 @@ gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory) /** * gst_rtsp_media_factory_set_multicast_iface: * @factory: a #GstRTSPMediaFactory - * @multicast_iface: (transfer none): a multicast interface name + * @multicast_iface: (transfer none) (nullable): a multicast interface name * * configure @multicast_iface to be used for @factory. */ @@ -838,7 +838,7 @@ gst_rtsp_media_factory_set_multicast_iface (GstRTSPMediaFactory * media_factory, * * Get the multicast interface used for @factory. * - * Returns: (transfer full): the multicast interface for @factory. g_free() after + * Returns: (transfer full) (nullable): the multicast interface for @factory. g_free() after * usage. */ gchar * diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index cebd75fc95..5ef4dc07fc 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -892,7 +892,7 @@ gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline) /** * gst_rtsp_media_set_permissions: * @media: a #GstRTSPMedia - * @permissions: (transfer none): a #GstRTSPPermissions + * @permissions: (transfer none) (nullable): a #GstRTSPPermissions * * Set @permissions on @media. */ @@ -920,7 +920,7 @@ gst_rtsp_media_set_permissions (GstRTSPMedia * media, * * Get the permissions object from @media. * - * Returns: (transfer full): a #GstRTSPPermissions object, unref after usage. + * Returns: (transfer full) (nullable): a #GstRTSPPermissions object, unref after usage. */ GstRTSPPermissions * gst_rtsp_media_get_permissions (GstRTSPMedia * media) @@ -1598,7 +1598,7 @@ gst_rtsp_media_get_publish_clock_mode (GstRTSPMedia * media) /** * gst_rtsp_media_set_address_pool: * @media: a #GstRTSPMedia - * @pool: (transfer none): a #GstRTSPAddressPool + * @pool: (transfer none) (nullable): a #GstRTSPAddressPool * * configure @pool to be used as the address pool of @media. */ @@ -1634,8 +1634,8 @@ gst_rtsp_media_set_address_pool (GstRTSPMedia * media, * * Get the #GstRTSPAddressPool used as the address pool of @media. * - * Returns: (transfer full): the #GstRTSPAddressPool of @media. g_object_unref() after - * usage. + * Returns: (transfer full) (nullable): the #GstRTSPAddressPool of @media. + * g_object_unref() after usage. */ GstRTSPAddressPool * gst_rtsp_media_get_address_pool (GstRTSPMedia * media) @@ -1658,7 +1658,7 @@ gst_rtsp_media_get_address_pool (GstRTSPMedia * media) /** * gst_rtsp_media_set_multicast_iface: * @media: a #GstRTSPMedia - * @multicast_iface: (transfer none): a multicast interface name + * @multicast_iface: (transfer none) (nullable): a multicast interface name * * configure @multicast_iface to be used for @media. */ @@ -1694,8 +1694,8 @@ gst_rtsp_media_set_multicast_iface (GstRTSPMedia * media, * * Get the multicast interface used for @media. * - * Returns: (transfer full): the multicast interface for @media. g_free() after - * usage. + * Returns: (transfer full) (nullable): the multicast interface for @media. + * g_free() after usage. */ gchar * gst_rtsp_media_get_multicast_iface (GstRTSPMedia * media) @@ -2074,7 +2074,7 @@ default_convert_range (GstRTSPMedia * media, GstRTSPTimeRange * range, * Get the current range as a string. @media must be prepared with * gst_rtsp_media_prepare (). * - * Returns: (transfer full): The range as a string, g_free() after usage. + * Returns: (transfer full) (nullable): The range as a string, g_free() after usage. */ gchar * gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play, @@ -3289,7 +3289,7 @@ get_clock_unlocked (GstRTSPMedia * media) * * @media must be prepared before this method returns a valid clock object. * - * Returns: (transfer full): the #GstClock used by @media. unref after usage. + * Returns: (transfer full) (nullable): the #GstClock used by @media. unref after usage. */ GstClock * gst_rtsp_media_get_clock (GstRTSPMedia * media) diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 858c3917a1..53b4ffd85e 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -181,7 +181,7 @@ default_make_path (GstRTSPMountPoints * mounts, const GstRTSPUrl * url) * * Make a path string from @url. * - * Returns: (transfer full): a path string for @url, g_free() after usage. + * Returns: (transfer full) (nullable): a path string for @url, g_free() after usage. */ gchar * gst_rtsp_mount_points_make_path (GstRTSPMountPoints * mounts, diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 37a3b0fdf3..91f4dfb05d 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -328,7 +328,7 @@ gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address) * * Get the address on which the server will accept connections. * - * Returns: (transfer full): the server address. g_free() after usage. + * Returns: (transfer full) (nullable): the server address. g_free() after usage. */ gchar * gst_rtsp_server_get_address (GstRTSPServer * server) @@ -417,7 +417,7 @@ gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service) * * Get the service on which the server will accept connections. * - * Returns: (transfer full): the service. use g_free() after usage. + * Returns: (transfer full) (nullable): the service. use g_free() after usage. */ gchar * gst_rtsp_server_get_service (GstRTSPServer * server) @@ -488,7 +488,7 @@ gst_rtsp_server_get_backlog (GstRTSPServer * server) /** * gst_rtsp_server_set_session_pool: * @server: a #GstRTSPServer - * @pool: (transfer none): a #GstRTSPSessionPool + * @pool: (transfer none) (nullable): a #GstRTSPSessionPool * * configure @pool to be used as the session pool of @server. */ @@ -521,7 +521,7 @@ gst_rtsp_server_set_session_pool (GstRTSPServer * server, * * Get the #GstRTSPSessionPool used as the session pool of @server. * - * Returns: (transfer full): the #GstRTSPSessionPool used for sessions. g_object_unref() after + * Returns: (transfer full) (nullable): the #GstRTSPSessionPool used for sessions. g_object_unref() after * usage. */ GstRTSPSessionPool * @@ -545,7 +545,7 @@ gst_rtsp_server_get_session_pool (GstRTSPServer * server) /** * gst_rtsp_server_set_mount_points: * @server: a #GstRTSPServer - * @mounts: (transfer none): a #GstRTSPMountPoints + * @mounts: (transfer none) (nullable): a #GstRTSPMountPoints * * configure @mounts to be used as the mount points of @server. */ @@ -579,7 +579,7 @@ gst_rtsp_server_set_mount_points (GstRTSPServer * server, * * Get the #GstRTSPMountPoints used as the mount points of @server. * - * Returns: (transfer full): the #GstRTSPMountPoints of @server. g_object_unref() after + * Returns: (transfer full) (nullable): the #GstRTSPMountPoints of @server. g_object_unref() after * usage. */ GstRTSPMountPoints * @@ -603,7 +603,7 @@ gst_rtsp_server_get_mount_points (GstRTSPServer * server) /** * gst_rtsp_server_set_auth: * @server: a #GstRTSPServer - * @auth: (transfer none): a #GstRTSPAuth + * @auth: (transfer none) (nullable): a #GstRTSPAuth * * configure @auth to be used as the authentication manager of @server. */ @@ -636,7 +636,7 @@ gst_rtsp_server_set_auth (GstRTSPServer * server, GstRTSPAuth * auth) * * Get the #GstRTSPAuth used as the authentication manager of @server. * - * Returns: (transfer full): the #GstRTSPAuth of @server. g_object_unref() after + * Returns: (transfer full) (nullable): the #GstRTSPAuth of @server. g_object_unref() after * usage. */ GstRTSPAuth * @@ -660,7 +660,7 @@ gst_rtsp_server_get_auth (GstRTSPServer * server) /** * gst_rtsp_server_set_thread_pool: * @server: a #GstRTSPServer - * @pool: (transfer none): a #GstRTSPThreadPool + * @pool: (transfer none) (nullable): a #GstRTSPThreadPool * * configure @pool to be used as the thread pool of @server. */ @@ -693,7 +693,7 @@ gst_rtsp_server_set_thread_pool (GstRTSPServer * server, * * Get the #GstRTSPThreadPool used as the thread pool of @server. * - * Returns: (transfer full): the #GstRTSPThreadPool of @server. g_object_unref() after + * Returns: (transfer full) (nullable): the #GstRTSPThreadPool of @server. g_object_unref() after * usage. */ GstRTSPThreadPool * @@ -1088,7 +1088,7 @@ default_create_client (GstRTSPServer * server) * @socket: (transfer full): a network socket * @ip: the IP address of the remote client * @port: the port used by the other end - * @initial_buffer: any initial data that was already read from the socket + * @initial_buffer: (nullable): any initial data that was already read from the socket * * Take an existing network socket and use it for an RTSP connection. This * is used when transferring a socket from an HTTP server which should be used diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 0aaf543dd5..3138449d4c 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -210,8 +210,8 @@ gst_rtsp_session_media_matches (GstRTSPSessionMedia * media, * * Get the #GstRTSPMedia that was used when constructing @media * - * Returns: (transfer none): the #GstRTSPMedia of @media. Remains valid as long - * as @media is valid. + * Returns: (transfer none) (nullable): the #GstRTSPMedia of @media. + * Remains valid as long as @media is valid. */ GstRTSPMedia * gst_rtsp_session_media_get_media (GstRTSPSessionMedia * media) @@ -387,8 +387,8 @@ gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media, * * Get a previously created #GstRTSPStreamTransport for the stream at @idx. * - * Returns: (transfer none): a #GstRTSPStreamTransport that is valid until the - * session of @media is unreffed. + * Returns: (transfer none) (nullable): a #GstRTSPStreamTransport that is + * valid until the session of @media is unreffed. */ GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 60aa30c49c..9ab2d27e40 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -341,7 +341,7 @@ create_session (GstRTSPSessionPool * pool, const gchar * id) * * Create a new #GstRTSPSession object in @pool. * - * Returns: (transfer full): a new #GstRTSPSession. + * Returns: (transfer full) (nullable): a new #GstRTSPSession. */ GstRTSPSession * gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) @@ -751,7 +751,7 @@ static GSourceFuncs gst_pool_source_funcs = { * Create a #GSource that will be dispatched when the session should be cleaned * up. * - * Returns: (transfer full): a #GSource + * Returns: (transfer full) (nullable): a #GSource */ GSource * gst_rtsp_session_pool_create_watch (GstRTSPSessionPool * pool) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 706664203d..83a998527e 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -320,7 +320,7 @@ gst_rtsp_session_release_media (GstRTSPSession * sess, * Get the session media for @path. @matched will contain the number of matched * characters of @path. * - * Returns: (transfer none): the configuration for @path in @sess. + * Returns: (transfer none) (nullable): the configuration for @path in @sess. */ GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession * sess, const gchar * path, @@ -480,8 +480,8 @@ gst_rtsp_session_new (const gchar * sessionid) * * Get the sessionid of @session. * - * Returns: (transfer none): the sessionid of @session. The value remains valid - * as long as @session is alive. + * Returns: (transfer none) (nullable): the sessionid of @session. + * The value remains valid as long as @session is alive. */ const gchar * gst_rtsp_session_get_sessionid (GstRTSPSession * session) @@ -497,7 +497,8 @@ gst_rtsp_session_get_sessionid (GstRTSPSession * session) * * Get the string that can be placed in the Session header field. * - * Returns: (transfer full): the Session header of @session. g_free() after usage. + * Returns: (transfer full) (nullable): the Session header of @session. + * g_free() after usage. */ gchar * gst_rtsp_session_get_header (GstRTSPSession * session) diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 0498830ea4..a9aa897cea 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -164,7 +164,7 @@ gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr) * * Get the #GstRTSPStream used when constructing @trans. * - * Returns: (transfer none): the stream used when constructing @trans. + * Returns: (transfer none) (nullable): the stream used when constructing @trans. */ GstRTSPStream * gst_rtsp_stream_transport_get_stream (GstRTSPStreamTransport * trans) @@ -263,7 +263,7 @@ gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans, * * Get the transport configured in @trans. * - * Returns: (transfer none): the transport configured in @trans. It remains + * Returns: (transfer none) (nullable): the transport configured in @trans. It remains * valid for as long as @trans is valid. */ const GstRTSPTransport * @@ -277,7 +277,7 @@ gst_rtsp_stream_transport_get_transport (GstRTSPStreamTransport * trans) /** * gst_rtsp_stream_transport_set_url: * @trans: a #GstRTSPStreamTransport - * @url: (transfer none): a client #GstRTSPUrl + * @url: (transfer none) (nullable): a client #GstRTSPUrl * * Set @url as the client url. */ @@ -303,8 +303,8 @@ gst_rtsp_stream_transport_set_url (GstRTSPStreamTransport * trans, * * Get the url configured in @trans. * - * Returns: (transfer none): the url configured in @trans. It remains - * valid for as long as @trans is valid. + * Returns: (transfer none) (nullable): the url configured in @trans. + * It remains valid for as long as @trans is valid. */ const GstRTSPUrl * gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport * trans) @@ -453,6 +453,8 @@ gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport * trans, GstRTSPStreamTransportPrivate *priv; gboolean res = FALSE; + g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE); + priv = trans->priv; if (priv->send_rtp) @@ -482,6 +484,8 @@ gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport * trans, GstRTSPStreamTransportPrivate *priv; gboolean res = FALSE; + g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE); + priv = trans->priv; if (priv->send_rtcp) @@ -531,6 +535,8 @@ gst_rtsp_stream_transport_recv_data (GstRTSPStreamTransport * trans, const GstRTSPTransport *tr; GstFlowReturn res; + g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); + priv = trans->priv; tr = priv->transport; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4a3d44c438..e47e95ffee 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -446,7 +446,7 @@ gst_rtsp_stream_get_pt (GstRTSPStream * stream) * * Get the srcpad associated with @stream. * - * Returns: (transfer full): the srcpad. Unref after usage. + * Returns: (transfer full) (nullable): the srcpad. Unref after usage. */ GstPad * gst_rtsp_stream_get_srcpad (GstRTSPStream * stream) @@ -465,7 +465,7 @@ gst_rtsp_stream_get_srcpad (GstRTSPStream * stream) * * Get the sinkpad associated with @stream. * - * Returns: (transfer full): the sinkpad. Unref after usage. + * Returns: (transfer full) (nullable): the sinkpad. Unref after usage. */ GstPad * gst_rtsp_stream_get_sinkpad (GstRTSPStream * stream) @@ -484,7 +484,7 @@ gst_rtsp_stream_get_sinkpad (GstRTSPStream * stream) * * Get the control string to identify this stream. * - * Returns: (transfer full): the control string. g_free() after usage. + * Returns: (transfer full) (nullable): the control string. g_free() after usage. */ gchar * gst_rtsp_stream_get_control (GstRTSPStream * stream) @@ -507,7 +507,7 @@ gst_rtsp_stream_get_control (GstRTSPStream * stream) /** * gst_rtsp_stream_set_control: * @stream: a #GstRTSPStream - * @control: a control string + * @control: (nullable): a control string * * Set the control string in @stream. */ @@ -529,7 +529,7 @@ gst_rtsp_stream_set_control (GstRTSPStream * stream, const gchar * control) /** * gst_rtsp_stream_has_control: * @stream: a #GstRTSPStream - * @control: a control string + * @control: (nullable): a control string * * Check if @stream has the control string @control. * @@ -682,6 +682,7 @@ gst_rtsp_stream_is_transport_supported (GstRTSPStream * stream, GstRTSPStreamPrivate *priv; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + g_return_val_if_fail (transport != NULL, FALSE); priv = stream->priv; @@ -817,7 +818,7 @@ gst_rtsp_stream_get_protocols (GstRTSPStream * stream) /** * gst_rtsp_stream_set_address_pool: * @stream: a #GstRTSPStream - * @pool: (transfer none): a #GstRTSPAddressPool + * @pool: (transfer none) (nullable): a #GstRTSPAddressPool * * configure @pool to be used as the address pool of @stream. */ @@ -851,8 +852,8 @@ gst_rtsp_stream_set_address_pool (GstRTSPStream * stream, * * Get the #GstRTSPAddressPool used as the address pool of @stream. * - * Returns: (transfer full): the #GstRTSPAddressPool of @stream. g_object_unref() after - * usage. + * Returns: (transfer full) (nullable): the #GstRTSPAddressPool of @stream. + * g_object_unref() after usage. */ GstRTSPAddressPool * gst_rtsp_stream_get_address_pool (GstRTSPStream * stream) @@ -875,7 +876,7 @@ gst_rtsp_stream_get_address_pool (GstRTSPStream * stream) /** * gst_rtsp_stream_set_multicast_iface: * @stream: a #GstRTSPStream - * @multicast_iface: (transfer none): a multicast interface name + * @multicast_iface: (transfer none) (nullable): a multicast interface name * * configure @multicast_iface to be used for @stream. */ @@ -910,8 +911,8 @@ gst_rtsp_stream_set_multicast_iface (GstRTSPStream * stream, * * Get the multicast interface used for @stream. * - * Returns: (transfer full): the multicast interface for @stream. g_free() after - * usage. + * Returns: (transfer full) (nullable): the multicast interface for @stream. + * g_free() after usage. */ gchar * gst_rtsp_stream_get_multicast_iface (GstRTSPStream * stream) @@ -2280,7 +2281,7 @@ request_rtp_rtcp_decoder (GstElement * rtpbin, guint session, * * Creating a rtxsend bin * - * Returns: (transfer full): a #GstElement. + * Returns: (transfer full) (nullable): a #GstElement. * * Since: 1.6 */ @@ -2340,6 +2341,9 @@ gst_rtsp_stream_set_pt_map (GstRTSPStream * stream, guint pt, GstCaps * caps) { GstRTSPStreamPrivate *priv = stream->priv; + if (!GST_IS_CAPS (caps)) + return; + g_mutex_lock (&priv->lock); g_hash_table_insert (priv->ptmap, GINT_TO_POINTER (pt), gst_caps_ref (caps)); g_mutex_unlock (&priv->lock); @@ -3359,7 +3363,7 @@ wrong_bin: * * Get the previous joined bin with gst_rtsp_stream_join_bin() or NULL. * - * Return: (transfer full): the joined bin or NULL. + * Return: (transfer full) (nullable): the joined bin or NULL. */ GstBin * gst_rtsp_stream_get_joined_bin (GstRTSPStream * stream) @@ -3381,10 +3385,10 @@ gst_rtsp_stream_get_joined_bin (GstRTSPStream * stream) /** * gst_rtsp_stream_get_rtpinfo: * @stream: a #GstRTSPStream - * @rtptime: (allow-none): result RTP timestamp - * @seq: (allow-none): result RTP seqnum - * @clock_rate: (allow-none): the clock rate - * @running_time: result running-time + * @rtptime: (allow-none) (out caller-allocates): result RTP timestamp + * @seq: (allow-none) (out caller-allocates): result RTP seqnum + * @clock_rate: (allow-none) (out caller-allocates): the clock rate + * @running_time: (out caller-allocates): result running-time * * Retrieve the current rtptime, seq and running-time. This is used to * construct a RTPInfo reply header. @@ -3534,8 +3538,8 @@ no_stats: * * Retrieve the current caps of @stream. * - * Returns: (transfer full): the #GstCaps of @stream. use gst_caps_unref() - * after usage. + * Returns: (transfer full) (nullable): the #GstCaps of @stream. + * use gst_caps_unref() after usage. */ GstCaps * gst_rtsp_stream_get_caps (GstRTSPStream * stream) @@ -4297,7 +4301,7 @@ gst_rtsp_stream_is_blocking (GstRTSPStream * stream) /** * gst_rtsp_stream_query_position: * @stream: a #GstRTSPStream - * @position: current position of a #GstRTSPStream + * @position: (out): current position of a #GstRTSPStream * * Query the position of the stream in %GST_FORMAT_TIME. This only considers * the RTP parts of the pipeline and not the RTCP parts. @@ -4377,7 +4381,7 @@ gst_rtsp_stream_query_position (GstRTSPStream * stream, gint64 * position) /** * gst_rtsp_stream_query_stop: * @stream: a #GstRTSPStream - * @stop: current stop of a #GstRTSPStream + * @stop: (out): current stop of a #GstRTSPStream * * Query the stop of the stream in %GST_FORMAT_TIME. This only considers * the RTP parts of the pipeline and not the RTCP parts. diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index 6c12ac8e66..a3cb850c12 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -512,7 +512,8 @@ thread_error: * * Get a new #GstRTSPThread for @type and @ctx. * - * Returns: (transfer full): a new #GstRTSPThread, gst_rtsp_thread_stop() after usage + * Returns: (transfer full) (nullable): a new #GstRTSPThread, + * gst_rtsp_thread_stop() after usage */ GstRTSPThread * gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool * pool, From ee44f38051c42cc87a4659c85f27febe096f004d Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 13 Feb 2018 18:59:16 +0100 Subject: [PATCH 1449/1776] set_clock functions: Add nullable annotations --- gst/rtsp-server/rtsp-media-factory.c | 2 +- gst/rtsp-server/rtsp-media.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index e5ad6a87c5..909384759f 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -1292,7 +1292,7 @@ gst_rtsp_media_factory_get_media_gtype (GstRTSPMediaFactory * factory) /** * gst_rtsp_media_factory_set_clock: * @factory: a #GstRTSPMediaFactory - * @clock: the clock to be used by the media factory + * @clock: (nullable): the clock to be used by the media factory * * Configures a specific clock to be used by the pipelines * of all medias created from this factory. diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 5ef4dc07fc..500e8b90c9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1512,7 +1512,7 @@ gst_rtsp_media_is_time_provider (GstRTSPMedia * media) /** * gst_rtsp_media_set_clock: * @media: a #GstRTSPMedia - * @clock: #GstClock to be used + * @clock: (nullable): #GstClock to be used * * Configure the clock used for the media. */ From 9046b5d083d055cda4168a5aa4f63ec6a7e6646a Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 14 Feb 2018 17:11:19 +0100 Subject: [PATCH 1450/1776] session-pool: remove nullable return annotation create_watch can only return NULL from the API guards, no need for nullable. --- gst/rtsp-server/rtsp-session-pool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 9ab2d27e40..3915b8cbb1 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -751,7 +751,7 @@ static GSourceFuncs gst_pool_source_funcs = { * Create a #GSource that will be dispatched when the session should be cleaned * up. * - * Returns: (transfer full) (nullable): a #GSource + * Returns: (transfer full): a #GSource */ GSource * gst_rtsp_session_pool_create_watch (GstRTSPSessionPool * pool) From f862676ec71d57a25118b86f36b94b6bb579c150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 15 Feb 2018 17:15:40 +0000 Subject: [PATCH 1451/1776] Release 1.13.1 --- NEWS | 676 ++++--------------------------------------- configure.ac | 12 +- gst-rtsp-server.doap | 50 ++++ meson.build | 2 +- 4 files changed, 115 insertions(+), 625 deletions(-) diff --git a/NEWS b/NEWS index 74fb1eaeb8..385e4b6315 100644 --- a/NEWS +++ b/NEWS @@ -1,20 +1,18 @@ -# GStreamer 1.12 Release Notes +# GStreamer 1.14 Release Notes -GStreamer 1.12.0 was originally released on 4th May 2017. +GStreamer 1.14.0 has not been released yet. It is scheduled for release +in late February / early March 2018. -The GStreamer team is proud to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! +There are unstable pre-releases available for testing and development purposes. +The latest pre-release is version 1.13.1 and was released on 15 February 2018. -As always, this release is again packed with new features, bug fixes and other -improvements. - -See [https://gstreamer.freedesktop.org/releases/1.12/][latest] for the latest +See [https://gstreamer.freedesktop.org/releases/1.14/][latest] for the latest version of this document. -*Last updated: Thursday 4 May 2017, 11:00 UTC [(log)][gitlog]* +*Last updated: Thursday 15 February 2018, 16:30 UTC [(log)][gitlog]* -[latest]: https://gstreamer.freedesktop.org/releases/1.12/ -[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.12/release-notes-1.12.md +[latest]: https://gstreamer.freedesktop.org/releases/1.14/ +[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.14/release-notes-1.14.md ## Introduction @@ -26,684 +24,127 @@ improvements. ## Highlights -- new `msdk` plugin for Intel's Media SDK for hardware-accelerated video - encoding and decoding on Intel graphics hardware on Windows or Linux. - -- `x264enc` can now use multiple x264 library versions compiled for different - bit depths at runtime, to transparently provide support for multiple bit - depths. - -- `videoscale` and `videoconvert` now support multi-threaded scaling and - conversion, which is particularly useful with higher resolution video. - -- `h264parse` will now automatically insert AU delimiters if needed when - outputting byte-stream format, which improves standard compliance and - is needed in particular for HLS playback on iOS/macOS. - -- `rtpbin` has acquired bundle support for incoming streams +- this section will be completed shortly ## Major new features and changes ### Noteworthy new API -- The video library gained support for a number of new video formats: - - - `GBR_12LE`, `GBR_12BE`, `GBRA_12LE`, `GBRA_12BE` (planar 4:4:4 RGB/RGBA, 12 bits per channel) - - `GBRA_10LE`, `GBRA_10BE` (planar 4:4:4:4 RGBA, 10 bits per channel) - - `GBRA` (planar 4:4:4:4 ARGB, 8 bits per channel) - - `I420_12BE`, `I420_12LE` (planar 4:2:0 YUV, 12 bits per channel) - - `I422_12BE`,`I422_12LE` (planar 4:2:2 YUV, 12 bits per channel) - - `Y444_12BE`, `Y444_12LE` (planar 4:4:4 YUV, 12 bits per channel) - - `VYUY` (another packed 4:2:2 YUV format) - -- The high-level `GstPlayer` API was extended with functions for taking video - snapshots and enabling accurate seeking. It can optionally also use the - still-experimental `playbin3` element now. +- this section will be filled in shortly ### New Elements -- msdk: new plugin for Intel's Media SDK for hardware-accelerated video encoding - and decoding on Intel graphics hardware on Windows or Linux. This includes - an H.264 encoder/decoder (`msdkh264dec`, `msdkh264enc`), - an H.265 encoder/decoder (`msdkh265dec`, `msdkh265enc`), - an MJPEG encoder/encoder (`msdkmjpegdec`, `msdkmjpegenc`), - an MPEG-2 video encoder (`msdkmpeg2enc`) and a VP8 encoder (`msdkvp8enc`). - -- `iqa` is a new Image Quality Assessment plugin based on [DSSIM][dssim], - similar to the old (unported) videomeasure element. - -- The `faceoverlay` element, which allows you to overlay SVG graphics over - a detected face in a video stream, has been ported from 0.10. - -- our `ffmpeg` wrapper plugin now exposes/maps the ffmpeg Opus audio decoder - (`avdec_opus`) as well as the GoPro CineForm HD / CFHD decoder (`avdec_cfhd`), - and also a parser/writer for the IVF format (`avdemux_ivf` and `avmux_ivf`). - -- `audiobuffersplit` is a new element that splits raw audio buffers into - equal-sized buffers - -- `audiomixmatrix` is a new element that mixes N:M audio channels according to - a configured mix matrix. - -- The `timecodewait` element got renamed to `avwait` and can operate in - different modes now. - -- The `opencv` video processing plugin has gained a new `dewarp` element that - dewarps fisheye images. - -- `ttml` is a new plugin for parsing and rendering subtitles in Timed Text - Markup Language (TTML) format. For the time being these elements will not - be autoplugged during media playback however, unless the `GST_TTML_AUTOPLUG=1` - environment variable is set. Only the EBU-TT-D profile is supported at this - point. - -[dssim]: https://github.com/pornel/dssim +- this section will be filled in shortly ### New element features and additions -- `x264enc` can now use multiple x264 library versions compiled for different - bit depths at runtime, to transparently provide support for multiple bit - depths. A new configure parameter `--with-x264-libraries` has been added to - specify additional paths to look for additional x264 libraries to load. - Background is that the libx264 library is always compile for one specific - bit depth and the `x264enc` element would simply support the depth supported - by the underlying library. Now we can support multiple depths. +- this section will be filled in shortly -- `x264enc` also picks up the interlacing mode automatically from the input - caps now and passed interlacing/TFF information correctly to the library. - -- `videoscale` and `videoconvert` now support multi-threaded scaling and - conversion, which is particularly useful with higher resolution video. - This has to be enabled explicitly via the `"n-threads"` property. - -- `videorate`'s new `"rate"` property lets you set a speed factor - on the output stream - -- `splitmuxsink`'s buffer collection and scheduling was rewritten to make - processing and splitting deterministic; before it was possible for a buffer - to end up in a different file chunk in different runs. `splitmuxsink` also - gained a new `"format-location-full"` signal that works just like the existing - `"format-location"` signal only that it is also passed the primary stream's - first buffer as argument, so that it is possible to construct the file name - based on metadata such as the buffer timestamp or any GstMeta attached to - the buffer. The new `"max-size-timecode"` property allows for timecode-based - splitting. `splitmuxsink` will now also automatically start a new file if the - input caps change in an incompatible way. - -- `fakesink` has a new `"drop-out-of-segment"` property to not drop - out-of-segment buffers, which is useful for debugging purposes. - -- `identity` gained a `"ts-offset"` property. - -- both `fakesink` and `identity` now also print what kind of metas are attached - to buffers when printing buffer details via the `"last-message"` property - used by `gst-launch-1.0 -v`. - -- multiqueue: made `"min-interleave-time"` a configurable property. - -- video nerds will be thrilled to know that `videotestsrc`'s snow is now - deterministic. `videotestsrc` also gained some new properties to make the - ball pattern based on system time, and invert colours each second - (`"animation-mode"`, `"motion"`, and `"flip"` properties). - -- `oggdemux` reverse playback should work again now. You're welcome. - -- `playbin3` and `urisourcebin` now have buffering enabled by default, and - buffering message aggregation was fixed. - -- `tcpclientsrc` now has a `"timeout"` property - -- `appsink` has gained support for buffer lists. For backwards compatibility - reasons users need to enable this explicitly with `gst_app_sink_set_buffer_list_support()`, - however. Once activated, a pulled `GstSample` can contain either a buffer - list or a single buffer. - -- `splitmuxsrc` reverse playback was fixed and handling of sparse streams, such - as subtitle tracks or metadata tracks, was improved. - -- `matroskamux` has acquired support for muxing G722 audio; it also marks all - buffers as keyframes now when streaming only audio, so that `tcpserversink` - will behave properly with audio-only streams. - -- `qtmux` gained support for ProRes 4444 XQ, HEVC/H.265 and CineForm (GoPro) formats, - and generally writes more video stream-related metadata into the track headers. - It is also allows configuration of the maximum interleave size in bytes and - time now. For fragmented mp4 we always write the `tfdt` atom now as required - by the DASH spec. - -- `qtdemux` supports FLAC, xvid, mp2, S16L and CineForm (GoPro) tracks now, and - generally tries harder to extract more video-related information from track - headers, such as colorimetry or interlacing details. It also received a - couple of fixes for the scenario where upstream operates in TIME format and - feeds chunks to qtdemux (e.g. DASH or MSE). - -- `audioecho` has two new properties to apply a delay only to certain channels - to create a surround effect, rather than an echo on all channels. This is - useful when upmixing from stereo, for example. The `"surround-delay"` property - enables this, and the `"surround-mask"` property controls which channels - are considered surround sound channels in this case. - -- `webrtcdsp` gained various new properties for gain control and also exposes - voice activity detection now, in which case it will post `"voice-activity"` - messages on the bus whenever the voice detection status changes. - -- The `decklink` capture elements for Blackmagic Decklink cards have seen a - number of improvements: - - - `decklinkvideosrc` will post a warning message on "no signal" and an info - message when the signal lock has been (re)acquired. There is also a new - read-only `"signal"` property that can be used to query the signal lock - status. The `GAP` flag will be set on buffers that are captured without - a signal lock. The new `drop-no-signal-frames` will make `decklinkvideosrc` - drop all buffers that have been captured without an input signal. The - `"skip-first-time"` property will make the source drop the first few - buffers, which is handy since some devices will at first output buffers - with the wrong resolution before they manage to figure out the right input - format and decide on the actual output caps. - - - `decklinkaudiosrc` supports more than just 2 audio channels now. - - - The capture sources no longer use the "hardware" timestamps which turn - out to be useless and instead just use the pipeline clock directly. - -- `srtpdec` now also has a readonly `"stats"` property, just like `srtpenc`. - -- `rtpbin` gained RTP bundle support, as used by e.g. WebRTC. The first - rtpsession will have a `rtpssrcdemux` element inside splitting the streams - based on their SSRC and potentially dispatch to a different rtpsession. - Because retransmission SSRCs need to be merged with the corresponding media - stream the `::on-bundled-ssrc` signal is emitted on `rtpbin` so that the - application can find out to which session the SSRC belongs. - -- `rtprtxqueue` gained two new properties exposing retransmission - statistics (`"requests"` and `"fulfilled-requests"`) - -- `kmssink` will now use the preferred mode for the monitor and render to the - base plane if nothing else has set a mode yet. This can also be done forcibly - in any case via the new `"force-modesetting"` property. Furthermore, `kmssink` - now allows only the supported connector resolutions as input caps in order to - avoid scaling or positioning of the input stream, as `kmssink` can't know - whether scaling or positioning would be more appropriate for the use case at - hand. - -- `waylandsink` can now take DMAbuf buffers as input in the presence - of a compatible Wayland compositor. This enables zero-copy transfer - from a decoder or source that outputs DMAbuf. - -- `udpsrc` can be bound to more than one interface when joining a - multicast group, this is done by giving a comma separate list of - interfaces such as multicast-iface="eth0,eth1". - -### Plugin moves - -- `dataurisrc` moved from gst-plugins-bad to core - -- The `rawparse` plugin containing the `rawaudioparse` and `rawvideoparse` - elements moved from gst-plugins-bad to gst-plugins-base. These elements - supersede the old `videoparse` and `audioparse` elements. They work the - same, with just some minor API changes. The old legacy elements still - exist in gst-plugins-bad, but may be removed at some point in the future. - -- `timecodestamper` is an element that attaches time codes to video buffers - in form of `GstVideoTimeCodeMeta`s. It had a `"clock-source"` property - which has now been removed because it was fairly useless in practice. It - gained some new properties however: the `"first-timecode"` property can - be used to set the inital timecode; alternatively `"first-timecode-to-now"` - can be set, and then the current system time at the time the first buffer - arrives is used as base time for the time codes. +### Plugin and library moves +- this section will be filled in shortly ### Plugin removals -- The `mad` mp1/mp2/mp3 decoder plugin was removed from gst-plugins-ugly, - as libmad is GPL licensed, has been unmaintained for a very long time, and - there are better alternatives available. Use the `mpg123audiodec` element - from the `mpg123` plugin in gst-plugins-ugly instead, or `avdec_mp3` from - the `gst-libav` module which wraps the ffmpeg library. We expect that we - will be able to move mp3 decoding to gst-plugins-good in the next cycle - seeing that most patents around mp3 have expired recently or are about to - expire. +- this section will be filled in shortly -- The `mimic` plugin was removed from gst-plugins-bad. It contained a decoder - and encoder for a video codec used by MSN messenger many many years ago (in - a galaxy far far away). The underlying library is unmaintained and no one - really needs to use this codec any more. Recorded videos can still be played - back with the MIMIC decoder in gst-libav. ## Miscellaneous API additions -- Request pad name templates passed to `gst_element_request_pad()` may now - contain multiple specifiers, such as e.g. `src_%u_%u`. - -- [`gst_buffer_iterate_meta_filtered()`][buffer-iterate-meta-filtered] is a - variant of `gst_buffer_iterate_meta()` that only returns metas of the - requested type and skips all other metas. - -- [`gst_pad_task_get_state()`][pad-task-get-state] gets the current state of - a task in a thread-safe way. - -- [`gst_uri_get_media_fragment_table()`][uri-get-fragment-table] provides the - media fragments of an URI as a table of key=value pairs. - -- [`gst_print()`][print], [`gst_println()`][println], [`gst_printerr()`][printerr], - and [`gst_printerrln()`][printerrln] can be used to print to stdout or stderr. - These functions are similar to `g_print()` and `g_printerr()` but they also - support all the additional format specifiers provided by the GStreamer - logging system, such as e.g. `GST_PTR_FORMAT`. - -- a `GstParamSpecArray` has been added, for elements who want to have array - type properties, such as the `audiomixmatrix` element for example. There are - also two new functions to set and get properties of this type from bindings: - - gst_util_set_object_array() - - gst_util_get_object_array() - -- various helper functions have been added to make it easier to set or get - GstStructure fields containing caps-style array or list fields from language - bindings (which usually support GValueArray but don't know about the GStreamer - specific fundamental types): - - [`gst_structure_get_array()`][get-array] - - [`gst_structure_set_array()`][set-array] - - [`gst_structure_get_list()`][get-list] - - [`gst_structure_set_list()`][set-list] - -- a new ['dynamic type' registry factory type][dynamic-type] was added to - register dynamically loadable GType types. This is useful for automatically - loading enum/flags types that are used in caps, such as for example the - `GstVideoMultiviewFlagsSet` type used in multiview video caps. - -- there is a new [`GstProxyControlBinding`][proxy-control-binding] for use - with GstController. This allows proxying the control interface from one - property on one GstObject to another property (of the same type) in another - GstObject. So e.g. in parent-child relationship, one may need to call - `gst_object_sync_values()` on the child and have a binding (set elsewhere) - on the parent update the value. This is used in `glvideomixer` and `glsinkbin` - for example, where `sync_values()` on the child pad or element will call - `sync_values()` on the exposed bin pad or element. - - Note that this doesn't solve GObject property forwarding, that must - be taken care of by the implementation manually or using GBinding. - -- `gst_base_parse_drain()` has been made public for subclasses to use. - -- `gst_base_sink_set_drop_out_of_segment()' can be used by subclasses to - prevent GstBaseSink from dropping buffers that fall outside of the segment. - -- [`gst_calculate_linear_regression()`][calc-lin-regression] is a new utility - function to calculate a linear regression. - -- [`gst_debug_get_stack_trace`][get-stack-trace] is an easy way to retrieve a - stack trace, which can be useful in tracer plugins. - -- allocators: the dmabuf allocator is now sub-classable, and there is a new - `GST_CAPS_FEATURE_MEMORY_DMABUF` define. - -- video decoder subclasses can use the newly-added function - `gst_video_decoder_allocate_output_frame_with_params()` to - pass a `GstBufferPoolAcquireParams` to the buffer pool for - each buffer allocation. - -- the video time code API has gained a dedicated [`GstVideoTimeCodeInterval`][timecode-interval] - type plus related API, including functions to add intervals to timecodes. - -- There is a new `libgstbadallocators-1.0` library in gst-plugins-bad, which - may go away again in future releases once the `GstPhysMemoryAllocator` - interface API has been validated by more users and was moved to - `libgstallocators-1.0` from gst-plugins-base. - -[timecode-interval]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#gst-video-time-code-interval-new -[buffer-iterate-meta-filtered]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#gst-buffer-iterate-meta-filtered -[pad-task-get-state]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-task-get-state -[uri-get-fragment-table]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUri.html#gst-uri-get-media-fragment-table -[print]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-print -[println]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-println -[printerr]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-printerr -[printerrln]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-printerrln -[get-array]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-get-array -[set-array]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-set-array -[get-list]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-get-list -[set-list]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-set-list -[dynamic-type]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstDynamicTypeFactory.html -[proxy-control-binding]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/gstreamer-libs-GstProxyControlBinding.html -[calc-lin-regression]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUtils.html#gst-calculate-linear-regression -[get-stack-trace]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUtils.html#gst-debug-get-stack-trace +- this section will be filled in shortly ### GstPlayer -New API has been added to: - - - get the number of audio/video/subtitle streams: - - `gst_player_media_info_get_number_of_streams()` - - `gst_player_media_info_get_number_of_video_streams()` - - `gst_player_media_info_get_number_of_audio_streams()` - - `gst_player_media_info_get_number_of_subtitle_streams()` - - - enable accurate seeking: `gst_player_config_set_seek_accurate()` - and `gst_player_config_get_seek_accurate()` - - - get a snapshot image of the video in RGBx, BGRx, JPEG, PNG or - native format: [`gst_player_get_video_snapshot()`][snapshot] - - - selecting use of a specific video sink element - ([`gst_player_video_overlay_video_renderer_new_with_sink()`][renderer-with-vsink]) - - - If the environment variable `GST_PLAYER_USE_PLAYBIN3` is set, GstPlayer will - use the still-experimental `playbin3` element and the `GstStreams` API for - playback. - -[snapshot]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstplayer.html#gst-player-get-video-snapshot -[renderer-with-vsink]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstplayer-videooverlayvideorenderer.html#gst-player-video-overlay-video-renderer-new-with-sink +- this section will be filled in shortly ## Miscellaneous changes -- video caps for interlaced video may contain an optional `"field-order"` field - now in the case of `interlaced-mode=interleaved` to signal that the field - order is always the same throughout the stream. This is useful to signal to - muxers such as mp4mux. The new field is parsed from/to `GstVideoInfo` of course. - -- video decoder and video encoder base classes try harder to proxy - interlacing, colorimetry and chroma-site related fields in caps properly. - -- The buffer stored in the `PROTECTION` events is now left unchanged. This is a - change of behaviour since 1.8, especially for the mssdemux element which used to - decode the base64 parsed data wrapped in the protection events emitted by the - demuxer. - -- `PROTECTION` events can now be injected into the pipeline from the application; - source elements deriving from GstBaseSrc will forward those downstream now. - -- The DASH demuxer is now correctly parsing the MSPR-2.0 ContentProtection nodes - and emits Protection events accordingly. Applications relying on those events - might need to decode the base64 data stored in the event buffer before using it. - -- The registry can now also be disabled by setting the environment variable - `GST_REGISTRY_DISABLE=yes`, with similar effect as the `GST_DISABLE_REGISTRY` - compile time switch. - -- Seeking performance with gstreamer-vaapi based decoders was improved. It would - recreate the decoder and surfaces on every seek which can be quite slow. - -- more robust handling of input caps changes in videoaggregator-based elements - such as `compositor`. - -- Lots of adaptive streaming-related fixes across the board (DASH, MSS, HLS). Also: - - - `mssdemux`, the Microsoft Smooth Streaming demuxer, has seen various - fixes for live streams, duration reporting and seeking. - - - The DASH manifest parser now extracts MS PlayReady ContentProtection objects - from manifests and sends them downstream as `PROTECTION` events. It also - supports multiple Period elements in external xml now. - -- gst-libav was updated to ffmpeg 3.3 but should still work with any 3.x - version. - -- GstEncodingProfile has been generally enhanced so it can, for - example, be used to get possible profiles for a given file - extension. It is now possible to define profiles based on element - factory names or using a path to a `.gep` file containing a - serialized profile. - -- `audioconvert` can now do endianness conversion in-place. All other - conversions still require a copy, but e.g. sign conversion and a few others - could also be implemented in-place now. - -- The new, experimental `playbin3` and `urisourcebin` elements got many - bugfixes and improvements and should generally be closer to a full - replacement of the old elements. - -- `interleave` now supports > 64 channels. +- this section will be filled in shortly ### OpenGL integration -- As usual the GStreamer OpenGL integration library has seen numerous - fixes and performance improvements all over the place, and is hopefully - ready now to become API stable and be moved to gst-plugins-base during the - 1.14 release cycle. - -- The GStreamer OpenGL integration layer has also gained support for the - Vivante EGL FB windowing system, which improves performance on platforms - such as Freescale iMX.6 for those who are stuck with the proprietary driver. - The `qmlglsink` element also supports this now if Qt is used with eglfs or - wayland backend, and it works in conjunction with [gstreamer-imx][gstreamer-imx] - of course. - -- various `qmlglsrc` improvements - -[gstreamer-imx]: https://github.com/Freescale/gstreamer-imx +- this section will be filled in shortly ## Tracing framework and debugging improvements -- New tracing hooks have been added to track GstMiniObject and GstObject - ref/unref operations. - -- The memory leaks tracer can optionally use this to retrieve stack traces if - enabled with e.g. `GST_TRACERS=leaks(filters="GstEvent,GstMessage",stack-traces-flags=full)` - -- The `GST_DEBUG_FILE` environment variable, which can be used to write the - debug log output to a file instead of printing it to stderr, can now contain - a name pattern, which is useful for automated testing and continuous - integration systems. The following format specifiers are supported: - - - `%p`: will be replaced with the PID - - `%r`: will be replaced with a random number, which is useful for instance - when running two processes with the same PID but in different containers. +- this section will be filled in shortly ## Tools -- `gst-inspect-1.0` can now list elements by type with the new `--types` - command-line option, e.g. `gst-inspect-1.0 --types=Audio/Encoder` will - show a list of audio encoders. - -- `gst-launch-1.0` and `gst_parse_launch()` have gained a new operator (`:`) - that allows linking all pads between two elements. This is useful in cases - where the exact number of pads or type of pads is not known beforehand, such - as in the `uridecodebin : encodebin` scenario, for example. In this case, - multiple links will be created if the encodebin has multiple profiles - compatible with the output of uridecodebin. - -- `gst-device-monitor-1.0` now shows a `gst-launch-1.0` snippet for each - device that shows how to make use of it in a `gst-launch-1.0` pipeline string. +- this section will be filled in shortly ## GStreamer RTSP server -- The RTSP server now also supports Digest authentication in addition to Basic - authentication. - -- The `GstRTSPClient` class has gained a `pre-*-request` signal and virtual - method for each client request type, emitted in the beginning of each rtsp - request. These signals or virtual methods let the application validate the - requests, configure the media/stream in a certain way and also generate error - status codes in case of an error or a bad request. +- this section will be filled in shortly ## GStreamer VAAPI -- GstVaapiDisplay now inherits from GstObject, thus the VA display logging - messages are better and tracing the context sharing is more readable. - -- When uploading raw images into a VA surfaces now VADeriveImages are tried - fist, improving the upload performance, if it is possible. - -- The decoders and the post-processor now can push dmabuf-based buffers to - downstream under certain conditions. For example: - - `GST_GL_PLATFORM=egl gst-play-1.0 video-sample.mkv --videosink=glimagesink` - -- Refactored the wrapping of VA surface into gstreamer memory, adding lock - when mapping and unmapping, and many other fixes. - -- Now `vaapidecodebin` loads `vaapipostproc` dynamically. It is possible to - avoid it usage with the environment variable `GST_VAAPI_DISABLE_VPP=1`. - -- Regarding encoders: they have primary rank again, since they can discover, - in run-time, the color formats they can use for upstream raw buffers and - caps renegotiation is now possible. Also the encoders push encoding info - downstream via tags. - -- About specific encoders: added constant bit-rate encoding mode for VP8 and - H265 encoder handles P010_10LE color format. - -- Regarding decoders, flush operation has been improved, now the internal VA - encoder is not recreated at each flush. Also there are several improvements - in the handling of H264 and H265 streams. - -- VAAPI plugins try to create their on GstGL context (when available) if they - cannot find it in the pipeline, to figure out what type of VA Display they - should create. - -- Regarding `vaapisink` for X11, if the backend reports that it is unable to - render correctly the current color format, an internal VA post-processor, is - instantiated (if available) and converts the color format. +- this section will be filled in shortly ## GStreamer Editing Services and NLE -- Enhanced auto transition behaviour - -- Fix some races in `nlecomposition` - -- Allow building with msvc - -- Added a UNIX manpage for `ges-launch` - -- API changes: - - Added ges_deinit (allowing the leak tracer to work properly) - - Added ges_layer_get_clips_in_interval - - Finally hide internal symbols that should never have been exposed +- this section will be filled in shortly ## GStreamer validate -- Port `gst-validate-launcher` to python 3 +- this section will be filled in shortly -- `gst-validate-launcher` now checks if blacklisted bugs have been fixed on - bugzilla and errors out if it is the case +## GStreamer Python Bindings -- Allow building with msvc - -- Add ability for the launcher to run GStreamer unit tests - -- Added a way to activate the leaks tracer on our tests and fix leaks - -- Make the http server multithreaded - -- New testsuite for running various test scenarios on the DASH-IF test vectors +- this section will be filled in shortly ## Build and Dependencies -- Meson build files are now disted in tarballs, for jhbuild and so distro - packagers can start using it. Note that the Meson-based build system is not - 100% feature-equivalent with the autotools-based one yet. - -- Some plugin filenames have been changed to match the plugin names: for example - the file name of the `encoding` plugin in gst-plugins-base containing the - `encodebin` element was `libgstencodebin.so` and has been changed to - `libgstencodebin.so`. This affects only a handful of plugins across modules. - - **Developers who install GStreamer from source and just do `make install`** - **after updating the source code, without doing `make uninstall` first, will** - **have to manually remove the old installed plugin files from the installation** - **prefix, or they will get 'Cannot register existing type' critical warnings.** - -- Most of the docbook-based documentation (FAQ, Application Development Manual, - Plugin Writer's Guide, design documents) has been converted to markdown and - moved into a new gst-docs module. The gtk-doc library API references and - the plugins documentation are still built as part of the source modules though. - -- GStreamer core now optionally uses libunwind and libdw to generate backtraces. - This is useful for tracer plugins used during debugging and development. - -- There is a new `libgstbadallocators-1.0` library in gst-plugins-bad (which - may go away again in future releases once the `GstPhysMemoryAllocator` - interface API has been validated by more users). - -- `gst-omx` and `gstreamer-vaapi` modules can now also be built using the - Meson build system. - -- The `qtkitvideosrc` element for macOS was removed. The API is deprecated - since 10.9 and it wasn't shipped in the binaries since a few releases. +- this section will be filled in shortly ## Platform-specific improvements ### Android -- androidmedia: add support for VP9 video decoding/encoding and Opus audio - decoding (where supported) +- this section will be filled in shortly -### OS/X and iOS +### macOS and iOS -- `avfvideosrc`, which represents an iPhone camera or, on a Mac, a screencapture - session, so far allowed you to select an input device by device index only. - New API adds the ability to select the position (front or back facing) and - device-type (wide angle, telephoto, etc.). Furthermore, you can now also - specify the orientation (portrait, landscape, etc.) of the videostream. +- this section will be filled in shortly ### Windows -- `dx9screencapsrc` can now optionally also capture the cursor. +- this section will be filled in shortly ## Contributors -Aleix Conchillo Flaque, Alejandro G. Castro, Aleksandr Slobodeniuk, Alexandru -Băluț, Alex Ashley, Andre McCurdy, Andrew, Anton Eliasson, Antonio Ospite, -Arnaud Vrac, Arun Raghavan, Aurélien Zanelli, Axel Menzel, Benjamin Otte, -Branko Subasic, Brendan Shanks, Carl Karsten, Carlos Rafael Giani, ChangBok -Chae, Chris Bass, Christian Schaller, christophecvr, Claudio Saavedra, -Corentin Noël, Dag Gullberg, Daniel Garbanzo, Daniel Shahaf, David Evans, -David Schleef, David Warman, Dominique Leuenberger, Dongil Park, Douglas -Bagnall, Edgard Lima, Edward Hervey, Emeric Grange, Enrico Jorns, Enrique -Ocaña González, Evan Nemerson, Fabian Orccon, Fabien Dessenne, Fabrice Bellet, -Florent Thiéry, Florian Zwoch, Francisco Velazquez, Frédéric Dalleau, Garima -Gaur, Gaurav Gupta, George Kiagiadakis, Georg Lippitsch, Göran Jönsson, Graham -Leggett, Guillaume Desmottes, Gurkirpal Singh, Haihua Hu, Hanno Boeck, Havard -Graff, Heekyoung Seo, hoonhee.lee, Hyunjun Ko, Imre Eörs, Iñaki García -Etxebarria, Jagadish, Jagyum Koo, Jan Alexander Steffens (heftig), Jan -Schmidt, Jean-Christophe Trotin, Jochen Henneberg, Jonas Holmberg, Joris -Valette, Josep Torra, Juan Pablo Ugarte, Julien Isorce, Jürgen Sachs, Koop -Mast, Kseniia Vasilchuk, Lars Wendler, leigh123linux@googlemail.com, Luis de -Bethencourt, Lyon Wang, Marcin Kolny, Marinus Schraal, Mark Nauwelaerts, -Mathieu Duponchelle, Matthew Waters, Matt Staples, Michael Dutka, Michael -Olbrich, Michael Smith, Michael Tretter, Miguel París Díaz, namanyadav12, Neha -Arora, Nick Kallen, Nicola Murino, Nicolas Dechesne, Nicolas Dufresne, Nicolas -Huet, Nirbheek Chauhan, Ole André Vadla Ravnås, Olivier Crête, Patricia -Muscalu, Peter Korsgaard, Peter Seiderer, Petr Kulhavy, Philippe Normand, -Philippe Renon, Philipp Zabel, Rahul Bedarkar, Reynaldo H. Verdejo Pinochet, -Ricardo Ribalda Delgado, Rico Tzschichholz, Руслан Ижбулатов, Samuel Maroy, -Santiago Carot-Nemesio, Scott D Phillips, Sean DuBois, Sebastian Dröge, Sergey -Borovkov, Seungha Yang, shakin chou, Song Bing, Søren Juul, Sreerenj -Balachandran, Stefan Kost, Stefan Sauer, Stepan Salenikovich, Stian Selnes, -Stuart Weaver, suhas2go, Thiago Santos, Thibault Saunier, Thomas Bluemel, -Thomas Petazzoni, Tim-Philipp Müller, Ting-Wei Lan, Tobias Mueller, Todor -Tomov, Tomasz Zajac, Ulf Olsson, Ursula Maplehurst, Víctor Manuel Jáquez Leal, -Victor Toso, Vincent Penquerc'h, Vineeth TM, Vinod Kesti, Vitor Massaru Iha, -Vivia Nikolaidou, WeiChungChang, William Manley, Wim Taymans, Wojciech -Przybyl, Wonchul Lee, Xavier Claessens, Yasushi SHOJI +- this section will be filled in shortly ... and many others who have contributed bug reports, translations, sent suggestions or helped testing. -## Bugs fixed in 1.12 +## Bugs fixed in 1.14 -More than [635 bugs][bugs-fixed-in-1.12] have been fixed during -the development of 1.12. +- this section will be filled in shortly + +More than [704 bugs][bugs-fixed-in-1.14] have been fixed during +the development of 1.14. This list does not include issues that have been cherry-picked into the -stable 1.10 branch and fixed there as well, all fixes that ended up in the -1.10 branch are also included in 1.12. +stable 1.12 branch and fixed there as well, all fixes that ended up in the +1.12 branch are also included in 1.14. This list also does not include issues that have been fixed without a bug report in bugzilla, so the actual number of fixes is much higher. -[bugs-fixed-in-1.12]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=213265&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.10.1&target_milestone=1.10.2&target_milestone=1.10.3&target_milestone=1.10.4&target_milestone=1.11.1&target_milestone=1.11.2&target_milestone=1.11.3&target_milestone=1.11.4&target_milestone=1.11.90&target_milestone=1.11.91&target_milestone=1.12.0 +[bugs-fixed-in-1.14]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=213265&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.12.1&target_milestone=1.12.2&target_milestone=1.12.3&target_milestone=1.12.4&target_milestone=1.13.1&target_milestone=1.13.2&target_milestone=1.13.3&target_milestone=1.13.4&target_milestone=1.13.90&target_milestone=1.13.91&target_milestone=1.14.0 -## Stable 1.12 branch +## Stable 1.14 branch -After the 1.12.0 release there will be several 1.12.x bug-fix releases which +After the 1.14.0 release there will be several 1.14.x bug-fix releases which will contain bug fixes which have been deemed suitable for a stable branch, but no new features or intrusive changes will be added to a bug-fix release -usually. The 1.12.x bug-fix releases will be made from the git 1.12 branch, which -is a stable branch. +usually. The 1.14.x bug-fix releases will be made from the git 1.14 branch, +which is a stable branch. -### 1.12.0 +### 1.14.0 -1.12.0 was released on 4th May 2017. +1.14.0 is scheduled to be released in late February / early March 2018. ## Known Issues @@ -712,23 +153,22 @@ is a stable branch. [bug-770264]: https://bugzilla.gnome.org/show_bug.cgi?id=770264 -## Schedule for 1.14 +## Schedule for 1.16 -Our next major feature release will be 1.14, and 1.11 will be the unstable -development version leading up to the stable 1.12 release. The development -of 1.13/1.14 will happen in the git master branch. +Our next major feature release will be 1.16, and 1.15 will be the unstable +development version leading up to the stable 1.16 release. The development +of 1.15/1.16 will happen in the git master branch. -The plan for the 1.14 development cycle is yet to be confirmed, but it is -expected that feature freeze will be around September 2017 -followed by several 1.13 pre-releases and the new 1.14 stable release -in October. +The plan for the 1.16 development cycle is yet to be confirmed, but it is +expected that feature freeze will be around August 2017 +followed by several 1.15 pre-releases and the new 1.16 stable release +in September. -1.14 will be backwards-compatible to the stable 1.12, 1.10, 1.8, 1.6, 1.4, +1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. - - - -*These release notes have been prepared by Sebastian Dröge, Tim-Philipp Müller -and Víctor Manuel Jáquez Leal.* +*These release notes have been prepared by Tim-Philipp Müller.* *License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* diff --git a/configure.ac b/configure.ac index 40ee2f7677..3bd2392e51 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.13.0.1], +AC_INIT([GStreamer RTSP Server Library], [1.13.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1300, 0, 1300) +AS_LIBTOOL(GST, 1301, 0, 1301) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.13.0.1 -GSTPB_REQ=1.13.0.1 -GSTPG_REQ=1.13.0.1 -GSTPD_REQ=1.13.0.1 +GST_REQ=1.13.1 +GSTPB_REQ=1.13.1 +GSTPG_REQ=1.13.1 +GSTPD_REQ=1.13.1 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 9012720e2b..170d9c2b77 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,56 @@ RTSP server library based on GStreamer + + + 1.13.1 + master + + 2018-02-15 + + + + + + + 1.12.4 + 1.12 + + 2017-12-07 + + + + + + + 1.12.3 + 1.12 + + 2017-09-18 + + + + + + + 1.12.2 + 1.12 + + 2017-07-14 + + + + + + + 1.12.1 + 1.12 + + 2017-06-20 + + + + 1.12.0 diff --git a/meson.build b/meson.build index 7dad698781..4ca3fb6fe0 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.13.0.1', + version : '1.13.1', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 94e70b77aa8ee4ab360ce3b1d3187fcd61157d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 15 Feb 2018 19:44:28 +0000 Subject: [PATCH 1452/1776] Back to development --- configure.ac | 10 +++++----- meson.build | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 3bd2392e51..51dd766f20 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.13.1], +AC_INIT([GStreamer RTSP Server Library], [1.13.1.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 1301, 0, 1301) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.13.1 -GSTPB_REQ=1.13.1 -GSTPG_REQ=1.13.1 -GSTPD_REQ=1.13.1 +GST_REQ=1.13.1.1 +GSTPB_REQ=1.13.1.1 +GSTPG_REQ=1.13.1.1 +GSTPD_REQ=1.13.1.1 dnl *** autotools stuff **** diff --git a/meson.build b/meson.build index 4ca3fb6fe0..559b790db9 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.13.1', + version : '1.13.1.1', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 231700b2bbcafbdb77ad83183bc54a8668961495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 12 Oct 2017 21:00:16 +0300 Subject: [PATCH 1453/1776] rtsp-media: Add support for sending+receiving medias We need to add an appsrc/appsink in that case because otherwise the media bin will be a sink and a source for rtpbin, causing a pipeline loop. https://bugzilla.gnome.org/show_bug.cgi?id=788950 --- gst/rtsp-server/rtsp-media.c | 168 +++++++++++++++++++++++++++++++++-- 1 file changed, 162 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 500e8b90c9..433cc8e378 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -119,6 +119,7 @@ struct _GstRTSPMediaPrivate GSource *source; guint id; GstRTSPThread *thread; + GList *pending_pipeline_elements; gboolean time_provider; GstNetTimeProvider *nettime; @@ -462,6 +463,7 @@ gst_rtsp_media_finalize (GObject * obj) g_ptr_array_unref (priv->streams); g_list_free_full (priv->dynamic, gst_object_unref); + g_list_free_full (priv->pending_pipeline_elements, gst_object_unref); if (priv->pipeline) gst_object_unref (priv->pipeline); @@ -867,6 +869,7 @@ gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline) GstRTSPMediaPrivate *priv; GstElement *old; GstNetTimeProvider *nettime; + GList *l; g_return_if_fail (GST_IS_RTSP_MEDIA (media)); g_return_if_fail (GST_IS_PIPELINE (pipeline)); @@ -887,6 +890,12 @@ gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline) gst_object_unref (nettime); gst_bin_add (GST_BIN_CAST (pipeline), priv->element); + + for (l = priv->pending_pipeline_elements; l; l = l->next) { + gst_bin_add (GST_BIN_CAST (pipeline), l->data); + } + g_list_free (priv->pending_pipeline_elements); + priv->pending_pipeline_elements = NULL; } /** @@ -1852,6 +1861,78 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) } } +typedef struct +{ + GstElement *appsink, *appsrc; + GstRTSPStream *stream; +} AppSinkSrcData; + +static GstFlowReturn +appsink_new_sample (GstAppSink * appsink, gpointer user_data) +{ + AppSinkSrcData *data = user_data; + GstSample *sample; + GstFlowReturn ret; + + sample = gst_app_sink_pull_sample (appsink); + if (!sample) + return GST_FLOW_FLUSHING; + + + ret = gst_app_src_push_sample (GST_APP_SRC (data->appsrc), sample); + gst_sample_unref (sample); + return ret; +} + +static GstAppSinkCallbacks appsink_callbacks = { + NULL, + NULL, + appsink_new_sample, +}; + +static GstPadProbeReturn +appsink_pad_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) +{ + AppSinkSrcData *data = user_data; + + if (GST_IS_EVENT (info->data) + && GST_EVENT_TYPE (info->data) == GST_EVENT_LATENCY) { + GstClockTime min, max; + + if (gst_base_sink_query_latency (GST_BASE_SINK (data->appsink), NULL, NULL, + &min, &max)) { + g_object_set (data->appsrc, "min-latency", min, "max-latency", max, NULL); + g_print ("setting latency to %lu %lu\n", min, max); + } + } else if (GST_IS_QUERY (info->data)) { + GstPad *srcpad = gst_element_get_static_pad (data->appsrc, "src"); + if (gst_pad_peer_query (srcpad, GST_QUERY_CAST (info->data))) { + gst_object_unref (srcpad); + return GST_PAD_PROBE_HANDLED; + } + gst_object_unref (srcpad); + } + + return GST_PAD_PROBE_OK; +} + +static GstPadProbeReturn +appsrc_pad_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) +{ + AppSinkSrcData *data = user_data; + + if (GST_IS_QUERY (info->data)) { + GstPad *sinkpad = gst_element_get_static_pad (data->appsink, "sink"); + if (gst_pad_peer_query (sinkpad, GST_QUERY_CAST (info->data))) { + gst_object_unref (sinkpad); + return GST_PAD_PROBE_HANDLED; + } + gst_object_unref (sinkpad); + } + + return GST_PAD_PROBE_OK; +} + /** * gst_rtsp_media_create_stream: * @media: a #GstRTSPMedia @@ -1870,9 +1951,10 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, { GstRTSPMediaPrivate *priv; GstRTSPStream *stream; - GstPad *ghostpad; + GstPad *streampad; gchar *name; gint idx; + AppSinkSrcData *data = NULL; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL); @@ -1890,12 +1972,71 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, else name = g_strdup_printf ("sink_%u", idx); - ghostpad = gst_ghost_pad_new (name, pad); - gst_pad_set_active (ghostpad, TRUE); - gst_element_add_pad (priv->element, ghostpad); + if ((GST_PAD_IS_SRC (pad) && priv->element->numsinkpads > 0) || + (GST_PAD_IS_SINK (pad) && priv->element->numsrcpads > 0)) { + GstElement *appsink, *appsrc; + GstPad *sinkpad, *srcpad; + + appsink = gst_element_factory_make ("appsink", NULL); + appsrc = gst_element_factory_make ("appsrc", NULL); + + if (GST_PAD_IS_SINK (pad)) { + srcpad = gst_element_get_static_pad (appsrc, "src"); + + gst_bin_add (GST_BIN (priv->element), appsrc); + + gst_pad_link (srcpad, pad); + gst_object_unref (srcpad); + + streampad = gst_element_get_static_pad (appsink, "sink"); + + priv->pending_pipeline_elements = + g_list_prepend (priv->pending_pipeline_elements, appsink); + } else { + sinkpad = gst_element_get_static_pad (appsink, "sink"); + + gst_pad_link (pad, sinkpad); + gst_object_unref (sinkpad); + + streampad = gst_element_get_static_pad (appsrc, "src"); + + priv->pending_pipeline_elements = + g_list_prepend (priv->pending_pipeline_elements, appsrc); + } + + g_object_set (appsrc, "block", TRUE, "format", GST_FORMAT_TIME, "is-live", + TRUE, NULL); + g_object_set (appsink, "sync", FALSE, "async", FALSE, NULL); + + data = g_new0 (AppSinkSrcData, 1); + data->appsink = appsink; + data->appsrc = appsrc; + + sinkpad = gst_element_get_static_pad (appsink, "sink"); + gst_pad_add_probe (sinkpad, + GST_PAD_PROBE_TYPE_EVENT_UPSTREAM | GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM, + appsink_pad_probe, data, NULL); + gst_object_unref (sinkpad); + + srcpad = gst_element_get_static_pad (appsrc, "src"); + gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_QUERY_UPSTREAM, + appsrc_pad_probe, data, NULL); + gst_object_unref (srcpad); + + gst_app_sink_set_callbacks (GST_APP_SINK (appsink), &appsink_callbacks, + data, NULL); + g_object_set_data_full (G_OBJECT (streampad), "media-appsink-appsrc", data, + g_free); + } else { + streampad = gst_ghost_pad_new (name, pad); + gst_pad_set_active (streampad, TRUE); + gst_element_add_pad (priv->element, streampad); + } g_free (name); - stream = gst_rtsp_stream_new (idx, payloader, ghostpad); + stream = gst_rtsp_stream_new (idx, payloader, streampad); + if (data) + data->stream = stream; if (priv->pool) gst_rtsp_stream_set_address_pool (stream, priv->pool); gst_rtsp_stream_set_multicast_iface (stream, priv->multicast_iface); @@ -1943,13 +2084,28 @@ gst_rtsp_media_remove_stream (GstRTSPMedia * media, GstRTSPStream * stream) { GstRTSPMediaPrivate *priv; GstPad *srcpad; + AppSinkSrcData *data; priv = media->priv; g_mutex_lock (&priv->lock); /* remove the ghostpad */ srcpad = gst_rtsp_stream_get_srcpad (stream); - gst_element_remove_pad (priv->element, srcpad); + data = g_object_get_data (G_OBJECT (srcpad), "media-appsink-appsrc"); + if (data) { + if (GST_OBJECT_PARENT (data->appsrc) == GST_OBJECT_CAST (priv->pipeline)) + gst_bin_remove (GST_BIN_CAST (priv->pipeline), data->appsrc); + else if (GST_OBJECT_PARENT (data->appsrc) == + GST_OBJECT_CAST (priv->element)) + gst_bin_remove (GST_BIN_CAST (priv->element), data->appsrc); + if (GST_OBJECT_PARENT (data->appsink) == GST_OBJECT_CAST (priv->pipeline)) + gst_bin_remove (GST_BIN_CAST (priv->pipeline), data->appsink); + else if (GST_OBJECT_PARENT (data->appsink) == + GST_OBJECT_CAST (priv->element)) + gst_bin_remove (GST_BIN_CAST (priv->element), data->appsink); + } else { + gst_element_remove_pad (priv->element, srcpad); + } gst_object_unref (srcpad); /* now remove the stream */ g_object_ref (stream); From 72dc8acd86aba6b44b6a3ffdfa70218b3f312ad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 25 Sep 2017 19:41:05 +0300 Subject: [PATCH 1454/1776] rtsp: Add support for ONVIF backchannel This adds a new RTSP server, client, media-factory and media subclass for handling the specifics of the backchannel. Ideally this later can be extended with other ONVIF specific features. --- docs/libs/gst-rtsp-server-docs.sgml | 4 + docs/libs/gst-rtsp-server-sections.txt | 107 +++++ examples/.gitignore | 1 + examples/Makefile.am | 10 +- examples/test-onvif-backchannel.c | 71 +++ gst/rtsp-server/Makefile.am | 12 +- gst/rtsp-server/rtsp-media.h | 1 - gst/rtsp-server/rtsp-onvif-client.c | 100 +++++ gst/rtsp-server/rtsp-onvif-client.h | 57 +++ gst/rtsp-server/rtsp-onvif-media-factory.c | 491 +++++++++++++++++++++ gst/rtsp-server/rtsp-onvif-media-factory.h | 77 ++++ gst/rtsp-server/rtsp-onvif-media.c | 330 ++++++++++++++ gst/rtsp-server/rtsp-onvif-media.h | 66 +++ gst/rtsp-server/rtsp-onvif-server.c | 100 +++++ gst/rtsp-server/rtsp-onvif-server.h | 65 +++ gst/rtsp-server/rtsp-sdp.c | 8 +- gst/rtsp-server/rtsp-sdp.h | 4 + 17 files changed, 1497 insertions(+), 7 deletions(-) create mode 100644 examples/test-onvif-backchannel.c create mode 100644 gst/rtsp-server/rtsp-onvif-client.c create mode 100644 gst/rtsp-server/rtsp-onvif-client.h create mode 100644 gst/rtsp-server/rtsp-onvif-media-factory.c create mode 100644 gst/rtsp-server/rtsp-onvif-media-factory.h create mode 100644 gst/rtsp-server/rtsp-onvif-media.c create mode 100644 gst/rtsp-server/rtsp-onvif-media.h create mode 100644 gst/rtsp-server/rtsp-onvif-server.c create mode 100644 gst/rtsp-server/rtsp-onvif-server.h diff --git a/docs/libs/gst-rtsp-server-docs.sgml b/docs/libs/gst-rtsp-server-docs.sgml index 06141f838c..26c2a51011 100644 --- a/docs/libs/gst-rtsp-server-docs.sgml +++ b/docs/libs/gst-rtsp-server-docs.sgml @@ -33,6 +33,10 @@ + + + + diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 677ece1353..86e3f25a43 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -182,7 +182,9 @@ gst_rtsp_media_set_latency gst_rtsp_media_get_latency gst_rtsp_media_setup_sdp +gst_rtsp_media_setup_sdp_full gst_rtsp_media_handle_sdp +gst_rtsp_media_handle_sdp_full gst_rtsp_media_prepare @@ -281,7 +283,9 @@ gst_rtsp_media_factory_set_media_gtype gst_rtsp_media_factory_get_media_gtype gst_rtsp_media_factory_construct +gst_rtsp_media_factory_construct_full gst_rtsp_media_factory_create_element +gst_rtsp_media_factory_create_element_full GST_RTSP_MEDIA_FACTORY_CAST @@ -739,3 +743,106 @@ GST_TYPE_RTSP_TOKEN gst_rtsp_token_get_type
+
+rtsp-onvif-server +GstRTSPOnvifServer +GstRTSPOnvifServer +GstRTSPOnvifServerClass + +gst_rtsp_onvif_server_new + +GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT + +gst_rtsp_onvif_server_get_type +GST_TYPE_RTSP_ONVIF_SERVER +GST_RTSP_ONVIF_SERVER +GST_RTSP_ONVIF_SERVER_CAST +GST_RTSP_ONVIF_SERVER_CLASS +GST_RTSP_ONVIF_SERVER_CLASS_CAST +GST_RTSP_ONVIF_SERVER_GET_CLASS +GST_IS_RTSP_ONVIF_SERVER +GST_IS_RTSP_ONVIF_SERVER_CLASS +
+ +
+rtsp-onvif-server +GstRTSPOnvifServer +GstRTSPOnvifServer +GstRTSPOnvifServerClass + +gst_rtsp_onvif_server_new + +gst_rtsp_onvif_server_get_type +GST_TYPE_RTSP_ONVIF_SERVER +GST_RTSP_ONVIF_SERVER +GST_RTSP_ONVIF_SERVER_CAST +GST_RTSP_ONVIF_SERVER_CLASS +GST_RTSP_ONVIF_SERVER_CLASS_CAST +GST_RTSP_ONVIF_SERVER_GET_CLASS +GST_IS_RTSP_ONVIF_SERVER +GST_IS_RTSP_ONVIF_SERVER_CLASS +
+ +
+rtsp-onvif-client +GstRTSPOnvifClient +GstRTSPOnvifClient +GstRTSPOnvifClientClass + +gst_rtsp_onvif_client_get_type +GST_TYPE_RTSP_ONVIF_CLIENT +GST_RTSP_ONVIF_CLIENT +GST_RTSP_ONVIF_CLIENT_CAST +GST_RTSP_ONVIF_CLIENT_CLASS +GST_RTSP_ONVIF_CLIENT_CLASS_CAST +GST_RTSP_ONVIF_CLIENT_GET_CLASS +GST_IS_RTSP_ONVIF_CLIENT +GST_IS_RTSP_ONVIF_CLIENT_CLASS +
+ +
+rtsp-onvif-media-factory +GstRTSPOnvifMediaFactory +GstRTSPOnvifMediaFactory +GstRTSPOnvifMediaFactoryClass + +gst_rtsp_onvif_media_factory_new +gst_rtsp_onvif_media_factory_has_backchannel_support +gst_rtsp_onvif_media_factory_set_backchannel_bandwidth +gst_rtsp_onvif_media_factory_get_backchannel_bandwidth +gst_rtsp_onvif_media_factory_set_backchannel_launch +gst_rtsp_onvif_media_factory_get_backchannel_launch + +GstRTSPOnvifMediaFactoryPrivate +gst_rtsp_onvif_media_factory_get_type +GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY +GST_RTSP_ONVIF_MEDIA_FACTORY +GST_RTSP_ONVIF_MEDIA_FACTORY_CAST +GST_RTSP_ONVIF_MEDIA_FACTORY_CLASS +GST_RTSP_ONVIF_MEDIA_FACTORY_CLASS_CAST +GST_RTSP_ONVIF_MEDIA_FACTORY_GET_CLASS +GST_IS_RTSP_ONVIF_MEDIA_FACTORY +GST_IS_RTSP_ONVIF_MEDIA_FACTORY_CLASS +
+ +
+rtsp-onvif-media +GstRTSPOnvifMedia +GstRTSPOnvifMedia +GstRTSPOnvifMediaClass + +gst_rtsp_onvif_media_collect_backchannel +gst_rtsp_onvif_media_get_backchannel_bandwidth +gst_rtsp_onvif_media_set_backchannel_bandwidth + +GstRTSPOnvifMediaPrivate +gst_rtsp_onvif_media_get_type +GST_TYPE_RTSP_ONVIF_MEDIA +GST_RTSP_ONVIF_MEDIA +GST_RTSP_ONVIF_MEDIA_CAST +GST_RTSP_ONVIF_MEDIA_CLASS +GST_RTSP_ONVIF_MEDIA_CLASS_CAST +GST_RTSP_ONVIF_MEDIA_GET_CLASS +GST_IS_RTSP_ONVIF_MEDIA +GST_IS_RTSP_ONVIF_MEDIA_CLASS +
diff --git a/examples/.gitignore b/examples/.gitignore index 0907268c82..d9df57c609 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -13,3 +13,4 @@ test-uri test-auth test-netclock test-netclock-client +test-onvif-backchannel diff --git a/examples/Makefile.am b/examples/Makefile.am index a76f909127..43f811a84c 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,7 +2,8 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ test-launch test-sdp test-uri test-auth test-auth-digest \ test-multicast test-multicast2 test-appsrc \ test-video-rtx test-record test-record-auth \ - test-netclock test-netclock-client + test-netclock test-netclock-client \ + test-onvif-backchannel #INCLUDES = -I$(top_srcdir) -I$(srcdir) @@ -28,3 +29,10 @@ test_netclock_client_LDADD = \ $(LDADD) \ $(GST_NET_LIBS) +test_onvif_backchannel_CFLAGS = \ + $(AM_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) +test_onvif_backchannel_LDADD = \ + $(LDADD) \ + $(GST_PLUGINS_BASE_LIBS) -lgstrtsp-1.0 -lgstsdp-1.0 + diff --git a/examples/test-onvif-backchannel.c b/examples/test-onvif-backchannel.c new file mode 100644 index 0000000000..906c10bbee --- /dev/null +++ b/examples/test-onvif-backchannel.c @@ -0,0 +1,71 @@ +/* GStreamer + * Copyright (C) 2017 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_onvif_server_new (); + + /* get the mount points for this server, every server has a default object + * that be used to map uri mount points to media factories */ + mounts = gst_rtsp_server_get_mount_points (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_onvif_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc is-live=true ! x264enc ! rtph264pay name=pay0 pt=96 audiotestsrc is-live=true ! mulawenc ! rtppcmupay name=pay1 )"); + gst_rtsp_onvif_media_factory_set_backchannel_launch + (GST_RTSP_ONVIF_MEDIA_FACTORY (factory), + "( capsfilter caps=\"application/x-rtp, media=audio, payload=0, clock-rate=8000, encoding-name=PCMU\" name=depay_backchannel ! rtppcmudepay ! fakesink async=false )"); + gst_rtsp_media_factory_set_shared (factory, FALSE); + gst_rtsp_media_factory_set_media_gtype (factory, GST_TYPE_RTSP_ONVIF_MEDIA); + + /* attach the test factory to the /test url */ + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mounts); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + g_main_loop_run (loop); + + return 0; +} diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 224b48bcb3..95b239f1a2 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -17,7 +17,11 @@ public_headers = \ rtsp-session-pool.h \ rtsp-token.h \ rtsp-client.h \ - rtsp-server.h + rtsp-server.h \ + rtsp-onvif-server.h \ + rtsp-onvif-client.h \ + rtsp-onvif-media-factory.h \ + rtsp-onvif-media.h c_sources = \ rtsp-auth.c \ @@ -38,7 +42,11 @@ c_sources = \ rtsp-session-pool.c \ rtsp-token.c \ rtsp-client.c \ - rtsp-server.c + rtsp-server.c \ + rtsp-onvif-server.c \ + rtsp-onvif-client.c \ + rtsp-onvif-media-factory.c \ + rtsp-onvif-media.c noinst_HEADERS = diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index e4c95f13dd..ae332ff0dc 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -332,7 +332,6 @@ gboolean gst_rtsp_media_setup_sdp (GstRTSPMedia * media, Gst GST_EXPORT gboolean gst_rtsp_media_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp); - /* creating streams */ GST_EXPORT diff --git a/gst/rtsp-server/rtsp-onvif-client.c b/gst/rtsp-server/rtsp-onvif-client.c new file mode 100644 index 0000000000..2fb50fa04f --- /dev/null +++ b/gst/rtsp-server/rtsp-onvif-client.c @@ -0,0 +1,100 @@ +/* GStreamer + * Copyright (C) 2017 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "rtsp-onvif-client.h" +#include "rtsp-onvif-server.h" +#include "rtsp-onvif-media-factory.h" + +G_DEFINE_TYPE (GstRTSPOnvifClient, gst_rtsp_onvif_client, GST_TYPE_RTSP_CLIENT); + +static gchar * +gst_rtsp_onvif_client_check_requirements (GstRTSPClient * client, + GstRTSPContext * ctx, gchar ** requirements) +{ + GstRTSPMountPoints *mount_points = NULL; + GstRTSPMediaFactory *factory = NULL; + gchar *path = NULL; + gboolean has_backchannel = FALSE; + GString *unsupported = g_string_new (""); + + while (*requirements) { + if (strcmp (*requirements, GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT) == 0) { + has_backchannel = TRUE; + } else { + if (unsupported->len) + g_string_append (unsupported, ", "); + g_string_append (unsupported, *requirements); + } + requirements++; + } + + if (unsupported->len) + goto out; + + mount_points = gst_rtsp_client_get_mount_points (client); + if (!(path = gst_rtsp_mount_points_make_path (mount_points, ctx->uri))) + goto out; + + if (!(factory = gst_rtsp_mount_points_match (mount_points, path, NULL))) + goto out; + + if (has_backchannel && !GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory)) { + if (unsupported->len) + g_string_append (unsupported, ", "); + g_string_append (unsupported, GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT); + } else if (has_backchannel) { + GstRTSPOnvifMediaFactory *onvif_factory = + GST_RTSP_ONVIF_MEDIA_FACTORY (factory); + + if (!gst_rtsp_onvif_media_factory_has_backchannel_support (onvif_factory)) { + if (unsupported->len) + g_string_append (unsupported, ", "); + g_string_append (unsupported, GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT); + } + } + +out: + if (path) + g_free (path); + if (factory) + g_object_unref (factory); + if (mount_points) + g_object_unref (mount_points); + + return g_string_free (unsupported, FALSE); +} + +static void +gst_rtsp_onvif_client_class_init (GstRTSPOnvifClientClass * klass) +{ + GstRTSPClientClass *client_klass = (GstRTSPClientClass *) klass; + + client_klass->check_requirements = gst_rtsp_onvif_client_check_requirements; +} + +static void +gst_rtsp_onvif_client_init (GstRTSPOnvifClient * client) +{ +} diff --git a/gst/rtsp-server/rtsp-onvif-client.h b/gst/rtsp-server/rtsp-onvif-client.h new file mode 100644 index 0000000000..0dc4e98da1 --- /dev/null +++ b/gst/rtsp-server/rtsp-onvif-client.h @@ -0,0 +1,57 @@ +/* GStreamer + * Copyright (C) 2017 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_RTSP_ONVIF_CLIENT_H__ +#define __GST_RTSP_ONVIF_CLIENT_H__ + +#include +#include "rtsp-client.h" + +#define GST_TYPE_RTSP_ONVIF_CLIENT (gst_rtsp_onvif_client_get_type ()) +#define GST_IS_RTSP_ONVIF_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_ONVIF_CLIENT)) +#define GST_IS_RTSP_ONVIF_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_ONVIF_CLIENT)) +#define GST_RTSP_ONVIF_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_ONVIF_CLIENT, GstRTSPOnvifClientClass)) +#define GST_RTSP_ONVIF_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_ONVIF_CLIENT, GstRTSPOnvifClient)) +#define GST_RTSP_ONVIF_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_ONVIF_CLIENT, GstRTSPOnvifClientClass)) +#define GST_RTSP_ONVIF_CLIENT_CAST(obj) ((GstRTSPOnvifClient*)(obj)) +#define GST_RTSP_ONVIF_CLIENT_CLASS_CAST(klass) ((GstRTSPOnvifClientClass*)(klass)) + +typedef struct GstRTSPOnvifClientClass GstRTSPOnvifClientClass; +typedef struct GstRTSPOnvifClient GstRTSPOnvifClient; + +struct GstRTSPOnvifClientClass +{ + GstRTSPClientClass parent; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + +struct GstRTSPOnvifClient +{ + GstRTSPClient parent; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; +}; + +GST_EXPORT +GType gst_rtsp_onvif_client_get_type (void); + +#endif /* __GST_RTSP_ONVIF_CLIENT_H__ */ diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.c b/gst/rtsp-server/rtsp-onvif-media-factory.c new file mode 100644 index 0000000000..a200f1d76b --- /dev/null +++ b/gst/rtsp-server/rtsp-onvif-media-factory.c @@ -0,0 +1,491 @@ +/* GStreamer + * Copyright (C) 2017 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:rtsp-onvif-media-factory + * @short_description: A factory for ONVIF media pipelines + * @see_also: #GstRTSPMediaFactory, #GstRTSPOnvifMedia + * + * The #GstRTSPOnvifMediaFactory is responsible for creating or recycling + * #GstRTSPMedia objects based on the passed URL. Different to + * #GstRTSPMediaFactory, this supports special ONVIF features and can create + * #GstRTSPOnvifMedia in addition to normal #GstRTSPMedia. + * + * Special ONVIF features that are currently supported is a backchannel for + * the client to send back media to the server in a normal PLAY media, see + * gst_rtsp_onvif_media_factory_set_backchannel_launch() and + * gst_rtsp_onvif_media_factory_set_backchannel_bandwidth(). + * + * Since: 1.14 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "rtsp-onvif-media-factory.h" +#include "rtsp-onvif-media.h" +#include "rtsp-onvif-server.h" + +struct GstRTSPOnvifMediaFactoryPrivate +{ + GMutex lock; + gchar *backchannel_launch; + guint backchannel_bandwidth; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPOnvifMediaFactory, + gst_rtsp_onvif_media_factory, GST_TYPE_RTSP_MEDIA_FACTORY); + +static gboolean +requires_backchannel (GstRTSPMessage * msg) +{ + GstRTSPResult res; + gint i; + gchar *reqs = NULL; + + i = 0; + do { + res = gst_rtsp_message_get_header (msg, GST_RTSP_HDR_REQUIRE, &reqs, i++); + + if (res == GST_RTSP_ENOTIMPL) + break; + + if (strcmp (reqs, GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT) == 0) + return TRUE; + } while (TRUE); + + return FALSE; +} + +static gchar * +gst_rtsp_onvif_media_factory_gen_key (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url) +{ + GstRTSPContext *ctx = gst_rtsp_context_get_current (); + GstRTSPMessage *msg = ctx->request; + + /* Only medias where no backchannel was requested can be shared */ + if (requires_backchannel (msg)) + return NULL; + + return + GST_RTSP_MEDIA_FACTORY_CLASS + (gst_rtsp_onvif_media_factory_parent_class)->gen_key (factory, url); +} + +static GstRTSPMedia * +gst_rtsp_onvif_media_factory_construct (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url) +{ + GstRTSPMedia *media; + GstElement *element, *pipeline; + GstRTSPMediaFactoryClass *klass; + GType media_gtype; + gboolean got_backchannel_stream; + GstRTSPContext *ctx = gst_rtsp_context_get_current (); + + /* Mostly a copy of the default implementation but with backchannel support below, + * unfortunately we can't re-use the default one because of how the virtual + * method is define */ + + /* Everything but play is unsupported */ + if (gst_rtsp_media_factory_get_transport_mode (factory) != + GST_RTSP_TRANSPORT_MODE_PLAY) + return NULL; + + /* we only support onvif media here: otherwise a plain GstRTSPMediaFactory + * could've been used as well */ + media_gtype = gst_rtsp_media_factory_get_media_gtype (factory); + if (!g_type_is_a (media_gtype, GST_TYPE_RTSP_ONVIF_MEDIA)) + return NULL; + + klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); + + if (!klass->create_pipeline) + goto no_create; + + element = gst_rtsp_media_factory_create_element (factory, url); + if (element == NULL) + goto no_element; + + /* create a new empty media */ + media = + g_object_new (media_gtype, "element", element, + "transport-mode", GST_RTSP_TRANSPORT_MODE_PLAY, NULL); + + /* this adds the non-backchannel streams */ + gst_rtsp_media_collect_streams (media); + + /* this adds the backchannel stream */ + got_backchannel_stream = + gst_rtsp_onvif_media_collect_backchannel (GST_RTSP_ONVIF_MEDIA (media)); + /* FIXME: This should not happen! We checked for that before */ + if (requires_backchannel (ctx->request) && !got_backchannel_stream) { + g_object_unref (media); + return NULL; + } + + pipeline = klass->create_pipeline (factory, media); + if (pipeline == NULL) + goto no_pipeline; + + gst_rtsp_onvif_media_set_backchannel_bandwidth (GST_RTSP_ONVIF_MEDIA (media), + GST_RTSP_ONVIF_MEDIA_FACTORY (factory)->priv->backchannel_bandwidth); + + return media; + + /* ERRORS */ +no_create: + { + g_critical ("no create_pipeline function"); + return NULL; + } +no_element: + { + g_critical ("could not create element"); + return NULL; + } +no_pipeline: + { + g_critical ("can't create pipeline"); + g_object_unref (media); + return NULL; + } +} + +static GstElement * +gst_rtsp_onvif_media_factory_create_element (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url) +{ + GstElement *element; + GError *error = NULL; + gchar *launch; + GstRTSPContext *ctx = gst_rtsp_context_get_current (); + + /* Mostly a copy of the default implementation but with backchannel support below, + * unfortunately we can't re-use the default one because of how the virtual + * method is define */ + + launch = gst_rtsp_media_factory_get_launch (factory); + + /* we need a parse syntax */ + if (launch == NULL) + goto no_launch; + + /* parse the user provided launch line */ + element = + gst_parse_launch_full (launch, NULL, GST_PARSE_FLAG_PLACE_IN_BIN, &error); + if (element == NULL) + goto parse_error; + + g_free (launch); + + if (error != NULL) { + /* a recoverable error was encountered */ + GST_WARNING ("recoverable parsing error: %s", error->message); + g_error_free (error); + } + + /* add backchannel pipeline part, if requested */ + if (requires_backchannel (ctx->request)) { + GstRTSPOnvifMediaFactory *onvif_factory = + GST_RTSP_ONVIF_MEDIA_FACTORY (factory); + GstElement *backchannel_bin; + GstElement *backchannel_depay; + GstPad *depay_pad, *depay_ghostpad; + + launch = + gst_rtsp_onvif_media_factory_get_backchannel_launch (onvif_factory); + if (launch == NULL) + goto no_launch_backchannel; + + backchannel_bin = + gst_parse_bin_from_description_full (launch, FALSE, NULL, + GST_PARSE_FLAG_PLACE_IN_BIN, &error); + if (backchannel_bin == NULL) + goto parse_error_backchannel; + + g_free (launch); + + if (error != NULL) { + /* a recoverable error was encountered */ + GST_WARNING ("recoverable parsing error: %s", error->message); + g_error_free (error); + } + + gst_object_set_name (GST_OBJECT (backchannel_bin), "onvif-backchannel"); + + backchannel_depay = + gst_bin_get_by_name (GST_BIN (backchannel_bin), "depay_backchannel"); + if (!backchannel_depay) { + gst_object_unref (backchannel_bin); + goto wrongly_formatted_backchannel_bin; + } + + depay_pad = gst_element_get_static_pad (backchannel_depay, "sink"); + if (!depay_pad) { + gst_object_unref (backchannel_depay); + gst_object_unref (backchannel_bin); + goto wrongly_formatted_backchannel_bin; + } + + depay_ghostpad = gst_ghost_pad_new ("sink", depay_pad); + gst_element_add_pad (backchannel_bin, depay_ghostpad); + + gst_bin_add (GST_BIN (element), backchannel_bin); + } + + return element; + + /* ERRORS */ +no_launch: + { + g_critical ("no launch line specified"); + g_free (launch); + return NULL; + } +parse_error: + { + g_critical ("could not parse launch syntax (%s): %s", launch, + (error ? error->message : "unknown reason")); + if (error) + g_error_free (error); + g_free (launch); + return NULL; + } +no_launch_backchannel: + { + g_critical ("no backchannel launch line specified"); + gst_object_unref (element); + return NULL; + } +parse_error_backchannel: + { + g_critical ("could not parse backchannel launch syntax (%s): %s", launch, + (error ? error->message : "unknown reason")); + if (error) + g_error_free (error); + g_free (launch); + gst_object_unref (element); + return NULL; + } + +wrongly_formatted_backchannel_bin: + { + g_critical ("invalidly formatted backchannel bin"); + + gst_object_unref (element); + return NULL; + } +} + +static gboolean + gst_rtsp_onvif_media_factory_has_backchannel_support_default + (GstRTSPOnvifMediaFactory * factory) +{ + /* No locking here, we just check if it's non-NULL */ + return factory->priv->backchannel_launch != NULL; +} + +static void +gst_rtsp_onvif_media_factory_finalize (GObject * object) +{ + GstRTSPOnvifMediaFactory *factory = GST_RTSP_ONVIF_MEDIA_FACTORY (object); + + g_free (factory->priv->backchannel_launch); + factory->priv->backchannel_launch = NULL; + + g_mutex_clear (&factory->priv->lock); + + return + G_OBJECT_CLASS (gst_rtsp_onvif_media_factory_parent_class)->finalize + (object); +} + +static void +gst_rtsp_onvif_media_factory_class_init (GstRTSPOnvifMediaFactoryClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstRTSPMediaFactoryClass *factory_klass = (GstRTSPMediaFactoryClass *) klass; + + gobject_class->finalize = gst_rtsp_onvif_media_factory_finalize; + + factory_klass->gen_key = gst_rtsp_onvif_media_factory_gen_key; + factory_klass->construct = gst_rtsp_onvif_media_factory_construct; + factory_klass->create_element = gst_rtsp_onvif_media_factory_create_element; + + klass->has_backchannel_support = + gst_rtsp_onvif_media_factory_has_backchannel_support_default; +} + +static void +gst_rtsp_onvif_media_factory_init (GstRTSPOnvifMediaFactory * factory) +{ + factory->priv = gst_rtsp_onvif_media_factory_get_instance_private (factory); + g_mutex_init (&factory->priv->lock); +} + +/** + * gst_rtsp_onvif_media_factory_set_backchannel_launch: + * @factory: a #GstRTSPMediaFactory + * @launch: the launch description + * + * The gst_parse_launch() line to use for constructing the ONVIF backchannel + * pipeline in the default prepare vmethod if requested by the client. + * + * The pipeline description should return a GstBin as the toplevel element + * which can be accomplished by enclosing the description with brackets '(' + * ')'. + * + * The description should return a pipeline with a single depayloader named + * depay_backchannel. A caps query on the depayloader's sinkpad should return + * all possible, complete RTP caps that are going to be supported. At least + * the payload type, clock-rate and encoding-name need to be specified. + * + * Since: 1.14 + */ +void +gst_rtsp_onvif_media_factory_set_backchannel_launch (GstRTSPOnvifMediaFactory * + factory, const gchar * launch) +{ + g_return_if_fail (GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory)); + + g_mutex_lock (&factory->priv->lock); + g_free (factory->priv->backchannel_launch); + factory->priv->backchannel_launch = g_strdup (launch); + g_mutex_unlock (&factory->priv->lock); +} + +/** + * gst_rtsp_onvif_media_factory_get_backchannel_launch: + * @factory: a #GstRTSPMediaFactory + * + * Get the gst_parse_launch() pipeline description that will be used in the + * default prepare vmethod for generating the ONVIF backchannel pipeline. + * + * Returns: (transfer full): the configured backchannel launch description. g_free() after + * usage. + * + * Since: 1.14 + */ +gchar * +gst_rtsp_onvif_media_factory_get_backchannel_launch (GstRTSPOnvifMediaFactory * + factory) +{ + gchar *launch; + + g_return_val_if_fail (GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory), NULL); + + g_mutex_lock (&factory->priv->lock); + launch = g_strdup (factory->priv->backchannel_launch); + g_mutex_unlock (&factory->priv->lock); + + return launch; +} + +/** + * gst_rtsp_onvif_media_factory_has_backchannel_support: + * @factory: a #GstRTSPMediaFactory + * + * Returns %TRUE if an ONVIF backchannel is supported by the media factory. + * + * Returns: %TRUE if an ONVIF backchannel is supported by the media factory. + * + * Since: 1.14 + */ +gboolean +gst_rtsp_onvif_media_factory_has_backchannel_support (GstRTSPOnvifMediaFactory * + factory) +{ + GstRTSPOnvifMediaFactoryClass *klass; + + g_return_val_if_fail (GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory), FALSE); + + klass = GST_RTSP_ONVIF_MEDIA_FACTORY_GET_CLASS (factory); + + if (klass->has_backchannel_support) + return klass->has_backchannel_support (factory); + + return FALSE; +} + +/** + * gst_rtsp_onvif_media_factory_set_backchannel_bandwidth: + * @factory: a #GstRTSPMediaFactory + * @bandwidth: the bandwidth in bits per second + * + * Set the configured/supported bandwidth of the ONVIF backchannel pipeline in + * bits per second. + * + * Since: 1.14 + */ +void +gst_rtsp_onvif_media_factory_set_backchannel_bandwidth (GstRTSPOnvifMediaFactory + * factory, guint bandwidth) +{ + g_return_if_fail (GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory)); + + g_mutex_lock (&factory->priv->lock); + factory->priv->backchannel_bandwidth = bandwidth; + g_mutex_unlock (&factory->priv->lock); +} + +/** + * gst_rtsp_onvif_media_factory_get_backchannel_bandwidth: + * @factory: a #GstRTSPMediaFactory + * + * Get the configured/supported bandwidth of the ONVIF backchannel pipeline in + * bits per second. + * + * Returns: the configured/supported backchannel bandwidth. + * + * Since: 1.14 + */ +guint +gst_rtsp_onvif_media_factory_get_backchannel_bandwidth (GstRTSPOnvifMediaFactory + * factory) +{ + guint bandwidth; + + g_return_val_if_fail (GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory), 0); + + g_mutex_lock (&factory->priv->lock); + bandwidth = factory->priv->backchannel_bandwidth; + g_mutex_unlock (&factory->priv->lock); + + return bandwidth; +} + +/** + * gst_rtsp_onvif_media_factory_new: + * + * Create a new #GstRTSPOnvifMediaFactory + * + * Returns: A new #GstRTSPOnvifMediaFactory + * + * Since: 1.14 + */ +GstRTSPMediaFactory * +gst_rtsp_onvif_media_factory_new (void) +{ + return g_object_new (GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY, NULL); +} diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.h b/gst/rtsp-server/rtsp-onvif-media-factory.h new file mode 100644 index 0000000000..54687489e5 --- /dev/null +++ b/gst/rtsp-server/rtsp-onvif-media-factory.h @@ -0,0 +1,77 @@ +/* GStreamer + * Copyright (C) 2017 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_RTSP_ONVIF_MEDIA_FACTORY_H__ +#define __GST_RTSP_ONVIF_MEDIA_FACTORY_H__ + +#include +#include "rtsp-media-factory.h" + +#define GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY (gst_rtsp_onvif_media_factory_get_type ()) +#define GST_IS_RTSP_ONVIF_MEDIA_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY)) +#define GST_IS_RTSP_ONVIF_MEDIA_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY)) +#define GST_RTSP_ONVIF_MEDIA_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY, GstRTSPOnvifMediaFactoryClass)) +#define GST_RTSP_ONVIF_MEDIA_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY, GstRTSPOnvifMediaFactory)) +#define GST_RTSP_ONVIF_MEDIA_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY, GstRTSPOnvifMediaFactoryClass)) +#define GST_RTSP_ONVIF_MEDIA_FACTORY_CAST(obj) ((GstRTSPOnvifMediaFactory*)(obj)) +#define GST_RTSP_ONVIF_MEDIA_FACTORY_CLASS_CAST(klass) ((GstRTSPOnvifMediaFactoryClass*)(klass)) + +typedef struct GstRTSPOnvifMediaFactoryClass GstRTSPOnvifMediaFactoryClass; +typedef struct GstRTSPOnvifMediaFactory GstRTSPOnvifMediaFactory; +typedef struct GstRTSPOnvifMediaFactoryPrivate GstRTSPOnvifMediaFactoryPrivate; + +struct GstRTSPOnvifMediaFactoryClass +{ + GstRTSPMediaFactoryClass parent; + gboolean (*has_backchannel_support) (GstRTSPOnvifMediaFactory * factory); + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + +struct GstRTSPOnvifMediaFactory +{ + GstRTSPMediaFactory parent; + GstRTSPOnvifMediaFactoryPrivate *priv; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; +}; + +GST_EXPORT +GType gst_rtsp_onvif_media_factory_get_type (void); + +GST_EXPORT +GstRTSPMediaFactory *gst_rtsp_onvif_media_factory_new (void); + +GST_EXPORT +void gst_rtsp_onvif_media_factory_set_backchannel_launch (GstRTSPOnvifMediaFactory * + factory, const gchar * launch); +GST_EXPORT +gchar * gst_rtsp_onvif_media_factory_get_backchannel_launch (GstRTSPOnvifMediaFactory * factory); + +GST_EXPORT +gboolean gst_rtsp_onvif_media_factory_has_backchannel_support (GstRTSPOnvifMediaFactory * factory); + +GST_EXPORT +void gst_rtsp_onvif_media_factory_set_backchannel_bandwidth (GstRTSPOnvifMediaFactory * factory, guint bandwidth); +GST_EXPORT +guint gst_rtsp_onvif_media_factory_get_backchannel_bandwidth (GstRTSPOnvifMediaFactory * factory); + +#endif /* __GST_RTSP_ONVIF_MEDIA_FACTORY_H__ */ diff --git a/gst/rtsp-server/rtsp-onvif-media.c b/gst/rtsp-server/rtsp-onvif-media.c new file mode 100644 index 0000000000..8cd72615e5 --- /dev/null +++ b/gst/rtsp-server/rtsp-onvif-media.c @@ -0,0 +1,330 @@ +/* GStreamer + * Copyright (C) 2017 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:rtsp-onvif-media + * @short_description: The ONVIF media pipeline + * @see_also: #GstRTSPMedia, #GstRTSPOnvifMediaFactory, #GstRTSPStream, #GstRTSPSession, + * #GstRTSPSessionMedia + * + * a #GstRTSPOnvifMedia contains the complete GStreamer pipeline to manage the + * streaming to the clients. The actual data transfer is done by the + * #GstRTSPStream objects that are created and exposed by the #GstRTSPMedia. + * + * On top of #GstRTSPMedia this subclass adds special ONVIF features. + * Special ONVIF features that are currently supported is a backchannel for + * the client to send back media to the server in a normal PLAY media. To + * handle the ONVIF backchannel, a #GstRTSPOnvifMediaFactory and + * #GstRTSPOnvifServer has to be used. + * + * Since: 1.14 + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "rtsp-onvif-media.h" + +struct GstRTSPOnvifMediaPrivate +{ + GMutex lock; + guint backchannel_bandwidth; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPOnvifMedia, gst_rtsp_onvif_media, + GST_TYPE_RTSP_MEDIA); + +static gboolean +gst_rtsp_onvif_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, + GstSDPInfo * info) +{ + guint i, n_streams; + gchar *rangestr; + gboolean res; + + /* Mostly a copy of gst_rtsp_sdp_from_media() which handles the backchannel + * stream separately and adds sendonly/recvonly attributes to each media + */ + + n_streams = gst_rtsp_media_n_streams (media); + + rangestr = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT); + if (rangestr == NULL) + goto not_prepared; + + gst_sdp_message_add_attribute (sdp, "range", rangestr); + g_free (rangestr); + + res = TRUE; + for (i = 0; res && (i < n_streams); i++) { + GstRTSPStream *stream; + GstCaps *caps = NULL; + GstRTSPProfile profiles; + guint mask; + gboolean res; + GstPad *sinkpad = NULL; + guint n_caps, j; + + /* Mostly a copy of gst_rtsp_sdp_from_stream() which handles the + * backchannel stream separately */ + + stream = gst_rtsp_media_get_stream (media, i); + + if ((sinkpad = gst_rtsp_stream_get_sinkpad (stream))) { + caps = gst_pad_query_caps (sinkpad, NULL); + } else { + caps = gst_rtsp_stream_get_caps (stream); + } + + if (caps == NULL) { + GST_ERROR ("stream %p has no caps", stream); + res = FALSE; + if (sinkpad) + gst_object_unref (sinkpad); + break; + } else if (!sinkpad && !gst_caps_is_fixed (caps)) { + GST_ERROR ("stream %p has unfixed caps", stream); + res = FALSE; + gst_caps_unref (caps); + break; + } + + n_caps = gst_caps_get_size (caps); + for (j = 0; res && j < n_caps; j++) { + GstStructure *s = gst_caps_get_structure (caps, j); + GstCaps *media_caps = gst_caps_new_full (gst_structure_copy (s), NULL); + + if (!gst_caps_is_fixed (media_caps)) { + GST_ERROR ("media caps for stream %p are not all fixed", stream); + res = FALSE; + gst_caps_unref (media_caps); + break; + } + + /* make a new media for each profile */ + profiles = gst_rtsp_stream_get_profiles (stream); + mask = 1; + res = TRUE; + while (res && (profiles >= mask)) { + GstRTSPProfile prof = profiles & mask; + + if (prof) { + res = gst_rtsp_sdp_make_media (sdp, info, stream, media_caps, prof); + if (res) { + GstSDPMedia *smedia = + &g_array_index (sdp->medias, GstSDPMedia, sdp->medias->len - 1); + + if (sinkpad) { + GstRTSPOnvifMedia *onvif_media = GST_RTSP_ONVIF_MEDIA (media); + + gst_sdp_media_add_attribute (smedia, "sendonly", ""); + if (onvif_media->priv->backchannel_bandwidth > 0) + gst_sdp_media_add_bandwidth (smedia, GST_SDP_BWTYPE_AS, + onvif_media->priv->backchannel_bandwidth); + } else { + gst_sdp_media_add_attribute (smedia, "recvonly", ""); + } + } + } + + mask <<= 1; + } + + if (sinkpad) { + GstStructure *s = gst_caps_get_structure (media_caps, 0); + gint pt = -1; + + if (!gst_structure_get_int (s, "payload", &pt) || pt < 0) { + GST_ERROR ("stream %p has no payload type", stream); + res = FALSE; + gst_caps_unref (media_caps); + gst_object_unref (sinkpad); + break; + } + + gst_rtsp_stream_set_pt_map (stream, pt, media_caps); + } + + gst_caps_unref (media_caps); + } + + gst_caps_unref (caps); + if (sinkpad) + gst_object_unref (sinkpad); + } + + { + GstNetTimeProvider *provider; + + if ((provider = + gst_rtsp_media_get_time_provider (media, info->server_ip, 0))) { + GstClock *clock; + gchar *address, *str; + gint port; + + g_object_get (provider, "clock", &clock, "address", &address, "port", + &port, NULL); + + str = g_strdup_printf ("GstNetTimeProvider %s %s:%d %" G_GUINT64_FORMAT, + g_type_name (G_TYPE_FROM_INSTANCE (clock)), address, port, + gst_clock_get_time (clock)); + + gst_sdp_message_add_attribute (sdp, "x-gst-clock", str); + g_free (str); + gst_object_unref (clock); + g_free (address); + gst_object_unref (provider); + } + } + + return res; + + /* ERRORS */ +not_prepared: + { + GST_ERROR ("media %p is not prepared", media); + return FALSE; + } +} + +static void +gst_rtsp_onvif_media_finalize (GObject * object) +{ + GstRTSPOnvifMedia *media = GST_RTSP_ONVIF_MEDIA (object); + + g_mutex_clear (&media->priv->lock); + + return G_OBJECT_CLASS (gst_rtsp_onvif_media_parent_class)->finalize (object); +} + +static void +gst_rtsp_onvif_media_class_init (GstRTSPOnvifMediaClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstRTSPMediaClass *media_class = (GstRTSPMediaClass *) klass; + + gobject_class->finalize = gst_rtsp_onvif_media_finalize; + + media_class->setup_sdp = gst_rtsp_onvif_media_setup_sdp; +} + +static void +gst_rtsp_onvif_media_init (GstRTSPOnvifMedia * media) +{ + media->priv = gst_rtsp_onvif_media_get_instance_private (media); + g_mutex_init (&media->priv->lock); +} + +/** + * gst_rtsp_onvif_media_collect_backchannel: + * @media: a #GstRTSPOnvifMedia + * + * Find the ONVIF backchannel depayloader element. It should be named + * 'depay_backchannel', be placed in a bin called 'onvif-backchannel' + * and return all supported RTP caps on a caps query. Complete RTP caps with + * at least the payload type, clock-rate and encoding-name are required. + * + * A new #GstRTSPStream is created for the backchannel if found. + * + * Returns: %TRUE if a backchannel stream could be found and created + * + * Since: 1.14 + */ +gboolean +gst_rtsp_onvif_media_collect_backchannel (GstRTSPOnvifMedia * media) +{ + GstElement *element, *backchannel_bin = NULL; + GstPad *pad = NULL; + gboolean ret = FALSE; + + g_return_val_if_fail (GST_IS_RTSP_ONVIF_MEDIA (media), FALSE); + + element = gst_rtsp_media_get_element (GST_RTSP_MEDIA (media)); + if (!element) + return ret; + + backchannel_bin = + gst_bin_get_by_name (GST_BIN (element), "onvif-backchannel"); + if (!backchannel_bin) + goto out; + + pad = gst_element_get_static_pad (backchannel_bin, "sink"); + if (!pad) + goto out; + + gst_rtsp_media_create_stream (GST_RTSP_MEDIA (media), backchannel_bin, pad); + ret = TRUE; + +out: + if (pad) + gst_object_unref (pad); + if (backchannel_bin) + gst_object_unref (backchannel_bin); + gst_object_unref (element); + + return ret; +} + +/** + * gst_rtsp_onvif_media_set_backchannel_bandwidth: + * @factory: a #GstRTSPMedia + * @bandwidth: the bandwidth in bits per second + * + * Set the configured/supported bandwidth of the ONVIF backchannel pipeline in + * bits per second. + * + * Since: 1.14 + */ +void +gst_rtsp_onvif_media_set_backchannel_bandwidth (GstRTSPOnvifMedia * media, + guint bandwidth) +{ + g_return_if_fail (GST_IS_RTSP_ONVIF_MEDIA (media)); + + g_mutex_lock (&media->priv->lock); + media->priv->backchannel_bandwidth = bandwidth; + g_mutex_unlock (&media->priv->lock); +} + +/** + * gst_rtsp_onvif_media_get_backchannel_bandwidth: + * @factory: a #GstRTSPMedia + * + * Get the configured/supported bandwidth of the ONVIF backchannel pipeline in + * bits per second. + * + * Returns: the configured/supported backchannel bandwidth. + * + * Since: 1.14 + */ +guint +gst_rtsp_onvif_media_get_backchannel_bandwidth (GstRTSPOnvifMedia * media) +{ + guint bandwidth; + + g_return_val_if_fail (GST_IS_RTSP_ONVIF_MEDIA (media), 0); + + g_mutex_lock (&media->priv->lock); + bandwidth = media->priv->backchannel_bandwidth; + g_mutex_unlock (&media->priv->lock); + + return bandwidth; +} diff --git a/gst/rtsp-server/rtsp-onvif-media.h b/gst/rtsp-server/rtsp-onvif-media.h new file mode 100644 index 0000000000..a45c11ed94 --- /dev/null +++ b/gst/rtsp-server/rtsp-onvif-media.h @@ -0,0 +1,66 @@ +/* GStreamer + * Copyright (C) 2017 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_RTSP_ONVIF_MEDIA_H__ +#define __GST_RTSP_ONVIF_MEDIA_H__ + +#include +#include "rtsp-media.h" + +#define GST_TYPE_RTSP_ONVIF_MEDIA (gst_rtsp_onvif_media_get_type ()) +#define GST_IS_RTSP_ONVIF_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_ONVIF_MEDIA)) +#define GST_IS_RTSP_ONVIF_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_ONVIF_MEDIA)) +#define GST_RTSP_ONVIF_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_ONVIF_MEDIA, GstRTSPOnvifMediaClass)) +#define GST_RTSP_ONVIF_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_ONVIF_MEDIA, GstRTSPOnvifMedia)) +#define GST_RTSP_ONVIF_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_ONVIF_MEDIA, GstRTSPOnvifMediaClass)) +#define GST_RTSP_ONVIF_MEDIA_CAST(obj) ((GstRTSPOnvifMedia*)(obj)) +#define GST_RTSP_ONVIF_MEDIA_CLASS_CAST(klass) ((GstRTSPOnvifMediaClass*)(klass)) + +typedef struct GstRTSPOnvifMediaClass GstRTSPOnvifMediaClass; +typedef struct GstRTSPOnvifMedia GstRTSPOnvifMedia; +typedef struct GstRTSPOnvifMediaPrivate GstRTSPOnvifMediaPrivate; + +struct GstRTSPOnvifMediaClass +{ + GstRTSPMediaClass parent; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + +struct GstRTSPOnvifMedia +{ + GstRTSPMedia parent; + GstRTSPOnvifMediaPrivate *priv; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; +}; + +GST_EXPORT +GType gst_rtsp_onvif_media_get_type (void); +GST_EXPORT +gboolean gst_rtsp_onvif_media_collect_backchannel (GstRTSPOnvifMedia * media); + +GST_EXPORT +void gst_rtsp_onvif_media_set_backchannel_bandwidth (GstRTSPOnvifMedia * media, guint bandwidth); +GST_EXPORT +guint gst_rtsp_onvif_media_get_backchannel_bandwidth (GstRTSPOnvifMedia * media); + +#endif /* __GST_RTSP_ONVIF_MEDIA_H__ */ diff --git a/gst/rtsp-server/rtsp-onvif-server.c b/gst/rtsp-server/rtsp-onvif-server.c new file mode 100644 index 0000000000..3c3c6f4992 --- /dev/null +++ b/gst/rtsp-server/rtsp-onvif-server.c @@ -0,0 +1,100 @@ +/* GStreamer + * Copyright (C) 2017 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/** + * SECTION:rtsp-onvif-server + * @short_description: The main server object + * @see_also: #GstRTSPOnvifMediaFactory, #GstRTSPClient + * + * The server object is the object listening for connections on a port and + * creating #GstRTSPOnvifClient objects to handle those connections. + * + * The only different to #GstRTSPServer is that #GstRTSPOnvifServer creates + * #GstRTSPOnvifClient that have special handling for ONVIF specific features, + * like a backchannel that allows clients to send back media to the server. + * + * Since: 1.14 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "rtsp-onvif-server.h" +#include "rtsp-onvif-client.h" + +G_DEFINE_TYPE (GstRTSPOnvifServer, gst_rtsp_onvif_server, GST_TYPE_RTSP_SERVER); + +static GstRTSPClient * +gst_rtsp_onvif_server_create_client (GstRTSPServer * server) +{ + GstRTSPClient *client; + GstRTSPSessionPool *session_pool; + GstRTSPMountPoints *mount_points; + GstRTSPAuth *auth; + GstRTSPThreadPool *thread_pool; + + /* a new client connected, create a session to handle the client. */ + client = g_object_new (GST_TYPE_RTSP_ONVIF_CLIENT, NULL); + + /* set the session pool that this client should use */ + session_pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_client_set_session_pool (client, session_pool); + g_object_unref (session_pool); + /* set the mount points that this client should use */ + mount_points = gst_rtsp_server_get_mount_points (server); + gst_rtsp_client_set_mount_points (client, mount_points); + g_object_unref (mount_points); + /* set authentication manager */ + auth = gst_rtsp_server_get_auth (server); + gst_rtsp_client_set_auth (client, auth); + if (auth) + g_object_unref (auth); + /* set threadpool */ + thread_pool = gst_rtsp_server_get_thread_pool (server); + gst_rtsp_client_set_thread_pool (client, thread_pool); + g_object_unref (thread_pool); + + return client; +} + +/** + * gst_rtsp_onvif_server_new: + * + * Create a new #GstRTSPOnvifServer instance. + * + * Returns: (transfer full): a new #GstRTSPOnvifServer + */ +GstRTSPServer * +gst_rtsp_onvif_server_new (void) +{ + return g_object_new (GST_TYPE_RTSP_ONVIF_SERVER, NULL); +} + +static void +gst_rtsp_onvif_server_class_init (GstRTSPOnvifServerClass * klass) +{ + GstRTSPServerClass *server_klass = (GstRTSPServerClass *) klass; + + server_klass->create_client = gst_rtsp_onvif_server_create_client; +} + +static void +gst_rtsp_onvif_server_init (GstRTSPOnvifServer * server) +{ +} diff --git a/gst/rtsp-server/rtsp-onvif-server.h b/gst/rtsp-server/rtsp-onvif-server.h new file mode 100644 index 0000000000..56bd9dce59 --- /dev/null +++ b/gst/rtsp-server/rtsp-onvif-server.h @@ -0,0 +1,65 @@ +/* GStreamer + * Copyright (C) 2017 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_RTSP_ONVIF_SERVER_H__ +#define __GST_RTSP_ONVIF_SERVER_H__ + +#include +#include "rtsp-server.h" + +#define GST_TYPE_RTSP_ONVIF_SERVER (gst_rtsp_onvif_server_get_type ()) +#define GST_IS_RTSP_ONVIF_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_ONVIF_SERVER)) +#define GST_IS_RTSP_ONVIF_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_ONVIF_SERVER)) +#define GST_RTSP_ONVIF_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_ONVIF_SERVER, GstRTSPOnvifServerClass)) +#define GST_RTSP_ONVIF_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_ONVIF_SERVER, GstRTSPOnvifServer)) +#define GST_RTSP_ONVIF_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_ONVIF_SERVER, GstRTSPOnvifServerClass)) +#define GST_RTSP_ONVIF_SERVER_CAST(obj) ((GstRTSPOnvifServer*)(obj)) +#define GST_RTSP_ONVIF_SERVER_CLASS_CAST(klass) ((GstRTSPOnvifServerClass*)(klass)) + +typedef struct GstRTSPOnvifServerClass GstRTSPOnvifServerClass; +typedef struct GstRTSPOnvifServer GstRTSPOnvifServer; + +struct GstRTSPOnvifServerClass +{ + GstRTSPServerClass parent; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + +struct GstRTSPOnvifServer +{ + GstRTSPServer parent; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; +}; + +GST_EXPORT +GType gst_rtsp_onvif_server_get_type (void); +GST_EXPORT +GstRTSPServer *gst_rtsp_onvif_server_new (void); + +#define GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT "www.onvif.org/ver20/backchannel" + +#include "rtsp-onvif-client.h" +#include "rtsp-onvif-media-factory.h" +#include "rtsp-onvif-media.h" + +#endif /* __GST_RTSP_ONVIF_SERVER_H__ */ diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index b037b2873d..ff55c0221a 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -70,6 +70,8 @@ update_sdp_from_tags (GstRTSPStream * stream, GstSDPMedia * stream_media) GstPad *src_pad; src_pad = gst_rtsp_stream_get_srcpad (stream); + if (!src_pad) + return; gst_pad_sticky_events_foreach (src_pad, get_info_from_tags, stream_media); @@ -179,8 +181,8 @@ cleanup: } } -static gboolean -make_media (GstSDPMessage * sdp, GstSDPInfo * info, +gboolean +gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream * stream, GstCaps * caps, GstRTSPProfile profile) { GstSDPMedia *smedia; @@ -557,7 +559,7 @@ gst_rtsp_sdp_from_stream (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPProfile prof = profiles & mask; if (prof) - res = make_media (sdp, info, stream, caps, prof); + res = gst_rtsp_sdp_make_media (sdp, info, stream, caps, prof); mask <<= 1; } diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h index 50cafe8152..8683e32c3d 100644 --- a/gst/rtsp-server/rtsp-sdp.h +++ b/gst/rtsp-server/rtsp-sdp.h @@ -40,6 +40,10 @@ gboolean gst_rtsp_sdp_from_media (GstSDPMessage *sdp, GstSDPInfo *in GST_EXPORT gboolean gst_rtsp_sdp_from_stream (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream *stream); +GST_EXPORT +gboolean +gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream * stream, GstCaps * caps, GstRTSPProfile profile); + G_END_DECLS #endif /* __GST_RTSP_SDP_H__ */ From 3d275b1345b76151418e3f56ed014d9089ac1a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 22 Jan 2018 12:46:34 +0200 Subject: [PATCH 1455/1776] rtsp-server: Switch around sendonly/recvonly attributes They are wrong in the ONVIF streaming spec. The backchannel should be recvonly and the normal media should be sendonly: direction is always from the point of view of the SDP offerer (the server) according to RFC 3264. --- gst/rtsp-server/rtsp-onvif-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-onvif-media.c b/gst/rtsp-server/rtsp-onvif-media.c index 8cd72615e5..261010df51 100644 --- a/gst/rtsp-server/rtsp-onvif-media.c +++ b/gst/rtsp-server/rtsp-onvif-media.c @@ -135,12 +135,12 @@ gst_rtsp_onvif_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, if (sinkpad) { GstRTSPOnvifMedia *onvif_media = GST_RTSP_ONVIF_MEDIA (media); - gst_sdp_media_add_attribute (smedia, "sendonly", ""); + gst_sdp_media_add_attribute (smedia, "recvonly", ""); if (onvif_media->priv->backchannel_bandwidth > 0) gst_sdp_media_add_bandwidth (smedia, GST_SDP_BWTYPE_AS, onvif_media->priv->backchannel_bandwidth); } else { - gst_sdp_media_add_attribute (smedia, "recvonly", ""); + gst_sdp_media_add_attribute (smedia, "sendonly", ""); } } } From 62aae8c7dc4b8fb1bdc1e89f603e44c7804c612c Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Sat, 21 Oct 2017 14:06:30 +0200 Subject: [PATCH 1456/1776] onvif: Make requires_backchannel() public ...in order to let subclasses building the onvif part of the pipeline check whether backchannel shall be included or not. --- gst/rtsp-server/rtsp-onvif-media-factory.c | 26 +++++++++++++++++----- gst/rtsp-server/rtsp-onvif-media-factory.h | 2 ++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.c b/gst/rtsp-server/rtsp-onvif-media-factory.c index a200f1d76b..f24260896b 100644 --- a/gst/rtsp-server/rtsp-onvif-media-factory.c +++ b/gst/rtsp-server/rtsp-onvif-media-factory.c @@ -55,13 +55,27 @@ struct GstRTSPOnvifMediaFactoryPrivate G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPOnvifMediaFactory, gst_rtsp_onvif_media_factory, GST_TYPE_RTSP_MEDIA_FACTORY); -static gboolean -requires_backchannel (GstRTSPMessage * msg) +/** + * gst_rtsp_onvif_media_factory_requires_backchannel: + * @factory: a #GstRTSPMediaFactory + * + * Checks whether the client request requires backchannel. + * + * Returns: %TRUE if the client request requires backchannel. + * + * Since: 1.14 + */ +gboolean +gst_rtsp_onvif_media_factory_requires_backchannel (GstRTSPMediaFactory * + factory, GstRTSPContext * ctx) { + GstRTSPMessage *msg = ctx->request; GstRTSPResult res; gint i; gchar *reqs = NULL; + g_return_val_if_fail (GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory), FALSE); + i = 0; do { res = gst_rtsp_message_get_header (msg, GST_RTSP_HDR_REQUIRE, &reqs, i++); @@ -81,10 +95,9 @@ gst_rtsp_onvif_media_factory_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { GstRTSPContext *ctx = gst_rtsp_context_get_current (); - GstRTSPMessage *msg = ctx->request; /* Only medias where no backchannel was requested can be shared */ - if (requires_backchannel (msg)) + if (gst_rtsp_onvif_media_factory_requires_backchannel (factory, ctx)) return NULL; return @@ -139,7 +152,8 @@ gst_rtsp_onvif_media_factory_construct (GstRTSPMediaFactory * factory, got_backchannel_stream = gst_rtsp_onvif_media_collect_backchannel (GST_RTSP_ONVIF_MEDIA (media)); /* FIXME: This should not happen! We checked for that before */ - if (requires_backchannel (ctx->request) && !got_backchannel_stream) { + if (gst_rtsp_onvif_media_factory_requires_backchannel (factory, ctx) && + !got_backchannel_stream) { g_object_unref (media); return NULL; } @@ -206,7 +220,7 @@ gst_rtsp_onvif_media_factory_create_element (GstRTSPMediaFactory * factory, } /* add backchannel pipeline part, if requested */ - if (requires_backchannel (ctx->request)) { + if (gst_rtsp_onvif_media_factory_requires_backchannel (factory, ctx)) { GstRTSPOnvifMediaFactory *onvif_factory = GST_RTSP_ONVIF_MEDIA_FACTORY (factory); GstElement *backchannel_bin; diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.h b/gst/rtsp-server/rtsp-onvif-media-factory.h index 54687489e5..09e9d4bde9 100644 --- a/gst/rtsp-server/rtsp-onvif-media-factory.h +++ b/gst/rtsp-server/rtsp-onvif-media-factory.h @@ -74,4 +74,6 @@ void gst_rtsp_onvif_media_factory_set_backchannel_bandwidth (GstRTSPOnvifMediaFa GST_EXPORT guint gst_rtsp_onvif_media_factory_get_backchannel_bandwidth (GstRTSPOnvifMediaFactory * factory); +gboolean gst_rtsp_onvif_media_factory_requires_backchannel (GstRTSPMediaFactory * factory, GstRTSPContext * ctx); + #endif /* __GST_RTSP_ONVIF_MEDIA_FACTORY_H__ */ From 14c511ae6274a02d5613a525e6af01466cbf67fe Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Mon, 5 Feb 2018 11:49:07 +0100 Subject: [PATCH 1457/1776] stream: Add functions for checking if stream is receiver or sender ...and replace all checks for RECORD in GstRTSPMedia which are really for "sender-only". This way the code becomes more generic and introducing support for onvif-backchannel later on will require no changes in GstRTSPMedia. --- gst/rtsp-server/rtsp-media.c | 29 +++++++++++++++++---- gst/rtsp-server/rtsp-stream.c | 48 +++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 6 +++++ 3 files changed, 78 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 433cc8e378..193f5e05b7 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -672,6 +672,25 @@ default_create_rtpbin (GstRTSPMedia * media) return rtpbin; } +static gboolean +is_receive_only (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + gboolean recive_only = TRUE; + guint i; + + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + if (gst_rtsp_stream_is_sender (stream) || + !gst_rtsp_stream_is_receiver (stream)) { + recive_only = FALSE; + break; + } + } + + return recive_only; +} + /* must be called with state lock */ static void check_seekable (GstRTSPMedia * media) @@ -680,8 +699,8 @@ check_seekable (GstRTSPMedia * media) GstRTSPMediaPrivate *priv = media->priv; /* Update the seekable state of the pipeline in case it changed */ - if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) { - /* TODO: Seeking for RECORD? */ + if (is_receive_only (media)) { + /* TODO: Seeking for "receive-only"? */ priv->seekable = -1; } else { guint i, n = priv->streams->len; @@ -2640,8 +2659,8 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) GST_DEBUG ("%p: went from %s to %s (pending %s)", media, gst_element_state_get_name (old), gst_element_state_get_name (new), gst_element_state_get_name (pending)); - if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD) - && old == GST_STATE_READY && new == GST_STATE_PAUSED) { + if (priv->no_more_pads_pending == 0 && is_receive_only (media) && + old == GST_STATE_READY && new == GST_STATE_PAUSED) { GST_INFO ("%p: went to PAUSED, prepared now", media); collect_media_stats (media); @@ -3851,7 +3870,7 @@ default_unsuspend (GstRTSPMedia * media) switch (priv->suspend_mode) { case GST_RTSP_SUSPEND_MODE_NONE: - if ((priv->transport_mode & GST_RTSP_TRANSPORT_MODE_RECORD)) + if (is_receive_only (media)) break; if (media_streams_blocking (media)) { gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index e47e95ffee..45b623844b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4590,3 +4590,51 @@ gst_rtsp_stream_is_complete (GstRTSPStream * stream) return ret; } + +/** + * gst_rtsp_stream_is_sender: + * @stream: a #GstRTSPStream + * + * Checks whether the stream is a sender. + * + * Returns: %TRUE if the stream is a sender and %FALSE otherwise. + */ +gboolean +gst_rtsp_stream_is_sender (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + gboolean ret = FALSE; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + g_mutex_lock (&priv->lock); + ret = (priv->srcpad != NULL); + g_mutex_unlock (&priv->lock); + + return ret; +} + +/** + * gst_rtsp_stream_is_receiver: + * @stream: a #GstRTSPStream + * + * Checks whether the stream is a receiver. + * + * Returns: %TRUE if the stream is a receiver and %FALSE otherwise. + */ +gboolean +gst_rtsp_stream_is_receiver (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + gboolean ret = FALSE; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + priv = stream->priv; + g_mutex_lock (&priv->lock); + ret = (priv->sinkpad != NULL); + g_mutex_unlock (&priv->lock); + + return ret; +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 3583d4a390..dc248d18d3 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -293,6 +293,12 @@ gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GST_EXPORT gboolean gst_rtsp_stream_is_complete (GstRTSPStream * stream); +GST_EXPORT +gboolean gst_rtsp_stream_is_sender (GstRTSPStream * stream); + +GST_EXPORT +gboolean gst_rtsp_stream_is_receiver (GstRTSPStream * stream); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object From b7e819821184d5a07f5f52514a2fa8b36fb48ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Mon, 19 Feb 2018 11:57:29 +0100 Subject: [PATCH 1458/1776] rtp-server: remove redefined variable res is a boolean variable which is defined in the function scope and redefined, with no reason, in the loop scope. This patch removes the redefinition. https://bugzilla.gnome.org/show_bug.cgi?id=793592 --- gst/rtsp-server/rtsp-onvif-media.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-onvif-media.c b/gst/rtsp-server/rtsp-onvif-media.c index 261010df51..ecafa7cd48 100644 --- a/gst/rtsp-server/rtsp-onvif-media.c +++ b/gst/rtsp-server/rtsp-onvif-media.c @@ -79,7 +79,6 @@ gst_rtsp_onvif_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, GstCaps *caps = NULL; GstRTSPProfile profiles; guint mask; - gboolean res; GstPad *sinkpad = NULL; guint n_caps, j; From 99edc9445adb55f76d790338f261f7af27959b21 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 23 Feb 2018 03:26:21 +0100 Subject: [PATCH 1459/1776] rtsp-auth: fix set_tls_authentication_mode annotation --- gst/rtsp-server/rtsp-auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index cfad96650e..d01927573a 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -375,7 +375,7 @@ gst_rtsp_auth_get_tls_database (GstRTSPAuth * auth) /** * gst_rtsp_auth_set_tls_authentication_mode: * @auth: a #GstRTSPAuth - * @mode: (transfer none) (allow-none): a #GTlsAuthenticationMode + * @mode: a #GTlsAuthenticationMode * * The #GTlsAuthenticationMode to set on the underlying GTlsServerConnection. * When set to another value than %G_TLS_AUTHENTICATION_NONE, From ddb0d83844d0fe6c3c53c1d64bab7add948db0f7 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 22 Feb 2018 20:17:33 +0100 Subject: [PATCH 1460/1776] rtsp-media: fix RECORD getting stuck The test_record case was working because async=false had been added in https://bugzilla.gnome.org/show_bug.cgi?id=757488 but that was incorrect, as it should not be needed. Removing async=false made the test fail as expected, this is fixed by not trying to preroll when preparing the media for RECORD, as start_prepare is called upon receiving ANNOUNCE, and our peer will not start sending media until it has received a response to that request, and sent and received a response to RECORD as well, thus obviously preventing preroll. https://bugzilla.gnome.org/show_bug.cgi?id=793738 --- gst/rtsp-server/rtsp-media.c | 8 +++++++- tests/check/gst/rtspclientsink.c | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 193f5e05b7..8f21fa9b31 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3058,8 +3058,14 @@ start_prepare (GstRTSPMedia * media) g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers); } - if (!start_preroll (media)) + if (priv->nb_dynamic_elements == 0 && is_receive_only (media)) { + /* If we are receive_only (RECORD), do not try to preroll, to avoid + * a second ASYNC state change failing */ + priv->is_live = TRUE; + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); + } else if (!start_preroll (media)) { goto preroll_failed; + } g_rec_mutex_unlock (&priv->state_lock); diff --git a/tests/check/gst/rtspclientsink.c b/tests/check/gst/rtspclientsink.c index da2f2dd8d0..ddafdbae80 100644 --- a/tests/check/gst/rtspclientsink.c +++ b/tests/check/gst/rtspclientsink.c @@ -157,7 +157,7 @@ GST_START_TEST (test_record) mfactory = start_record_server - ("( rtppcmadepay name=depay0 ! appsink name=sink async=false )"); + ("( rtppcmadepay name=depay0 ! appsink name=sink )"); g_signal_connect (mfactory, "media-constructed", G_CALLBACK (media_constructed_cb), &server_sink); From 5f29712243e567d1ffcc2356654dfac00b46a5ee Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Mon, 26 Feb 2018 14:16:54 +0100 Subject: [PATCH 1461/1776] rtsp-media: Replace g_print() log line https://bugzilla.gnome.org/show_bug.cgi?id=793838 --- gst/rtsp-server/rtsp-media.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 8f21fa9b31..a1ab7aae6d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1921,7 +1921,8 @@ appsink_pad_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) if (gst_base_sink_query_latency (GST_BASE_SINK (data->appsink), NULL, NULL, &min, &max)) { g_object_set (data->appsrc, "min-latency", min, "max-latency", max, NULL); - g_print ("setting latency to %lu %lu\n", min, max); + GST_DEBUG ("setting latency to min %" GST_TIME_FORMAT " max %" + GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); } } else if (GST_IS_QUERY (info->data)) { GstPad *srcpad = gst_element_get_static_pad (data->appsrc, "src"); From 731c4640071f2e87d07fb45a176159b1468222a1 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 24 Feb 2018 03:52:15 +0100 Subject: [PATCH 1462/1776] rtspclientsink: allow setting payloader as pad property This was a FIXME item, and can be quite useful, also allowing to specify payloader properties from the command line, which is always nice. https://bugzilla.gnome.org/show_bug.cgi?id=793776 --- gst/rtsp-sink/gstrtspclientsink.c | 252 ++++++++++++++++++++++++++---- 1 file changed, 225 insertions(+), 27 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 69d727d238..9a964452f3 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -102,10 +102,120 @@ #include "gstrtspclientsink.h" +typedef struct _GstRtspClientSinkPad GstRtspClientSinkPad; +typedef GstGhostPadClass GstRtspClientSinkPadClass; + +struct _GstRtspClientSinkPad +{ + GstGhostPad parent; + GstElement *custom_payloader; +}; + +enum +{ + PROP_PAD_0, + PROP_PAD_PAYLOADER +}; + +G_DEFINE_TYPE (GstRtspClientSinkPad, gst_rtsp_client_sink_pad, + GST_TYPE_GHOST_PAD); +#define GST_TYPE_RTSP_CLIENT_SINK_PAD (gst_rtsp_client_sink_pad_get_type ()) +#define GST_RTSP_CLIENT_SINK_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTSP_CLIENT_SINK_PAD,GstRtspClientSinkPad)) + +static void +gst_rtsp_client_sink_pad_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstRtspClientSinkPad *pad; + + pad = GST_RTSP_CLIENT_SINK_PAD (object); + + switch (prop_id) { + case PROP_PAD_PAYLOADER: + GST_OBJECT_LOCK (pad); + if (pad->custom_payloader) + gst_object_unref (pad->custom_payloader); + pad->custom_payloader = g_value_get_object (value); + gst_object_ref_sink (pad->custom_payloader); + GST_OBJECT_UNLOCK (pad); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_rtsp_client_sink_pad_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstRtspClientSinkPad *pad; + + pad = GST_RTSP_CLIENT_SINK_PAD (object); + + switch (prop_id) { + case PROP_PAD_PAYLOADER: + GST_OBJECT_LOCK (pad); + g_value_set_object (value, pad->custom_payloader); + GST_OBJECT_UNLOCK (pad); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_rtsp_client_sink_pad_dispose (GObject * object) +{ + GstRtspClientSinkPad *pad = GST_RTSP_CLIENT_SINK_PAD (object); + + if (pad->custom_payloader) + gst_object_unref (pad->custom_payloader); + + G_OBJECT_CLASS (gst_rtsp_client_sink_pad_parent_class)->dispose (object); +} + +static void +gst_rtsp_client_sink_pad_class_init (GstRtspClientSinkPadClass * klass) +{ + GObjectClass *gobject_klass; + + gobject_klass = (GObjectClass *) klass; + + gobject_klass->set_property = gst_rtsp_client_sink_pad_set_property; + gobject_klass->get_property = gst_rtsp_client_sink_pad_get_property; + gobject_klass->dispose = gst_rtsp_client_sink_pad_dispose; + + g_object_class_install_property (gobject_klass, PROP_PAD_PAYLOADER, + g_param_spec_object ("payloader", "Payloader", + "The payloader element to use (NULL = default automatically selected)", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +static void +gst_rtsp_client_sink_pad_init (GstRtspClientSinkPad * pad) +{ +} + +static GstPad * +gst_rtsp_client_sink_pad_new (const GstPadTemplate * pad_tmpl, + const gchar * name) +{ + GstRtspClientSinkPad *ret; + + ret = + g_object_new (GST_TYPE_RTSP_CLIENT_SINK_PAD, "direction", GST_PAD_SINK, + "template", pad_tmpl, "name", name, NULL); + gst_ghost_pad_construct (GST_GHOST_PAD_CAST (ret)); + + return GST_PAD (ret); +} + GST_DEBUG_CATEGORY_STATIC (rtsp_client_sink_debug); #define GST_CAT_DEFAULT (rtsp_client_sink_debug) -static GstStaticPadTemplate rtptemplate = GST_STATIC_PAD_TEMPLATE ("stream_%u", +static GstStaticPadTemplate rtptemplate = GST_STATIC_PAD_TEMPLATE ("sink_%u", GST_PAD_SINK, GST_PAD_REQUEST, GST_STATIC_CAPS_ANY); /* Actual caps come from available set of payloaders */ @@ -280,10 +390,58 @@ G_STMT_START { \ static guint gst_rtsp_client_sink_signals[LAST_SIGNAL] = { 0 }; +/********************************* + * GstChildProxy implementation * + *********************************/ +static GObject * +gst_rtsp_client_sink_child_proxy_get_child_by_index (GstChildProxy * + child_proxy, guint index) +{ + GObject *obj; + GstRTSPClientSink *cs = GST_RTSP_CLIENT_SINK (child_proxy); + + GST_OBJECT_LOCK (cs); + if ((obj = g_list_nth_data (GST_ELEMENT (cs)->sinkpads, index))) + g_object_ref (obj); + GST_OBJECT_UNLOCK (cs); + + return obj; +} + +static guint +gst_rtsp_client_sink_child_proxy_get_children_count (GstChildProxy * + child_proxy) +{ + guint count = 0; + + GST_OBJECT_LOCK (child_proxy); + count = GST_ELEMENT (child_proxy)->numsinkpads; + GST_OBJECT_UNLOCK (child_proxy); + + GST_INFO_OBJECT (child_proxy, "Children Count: %d", count); + + return count; +} + +static void +gst_rtsp_client_sink_child_proxy_init (gpointer g_iface, gpointer iface_data) +{ + GstChildProxyInterface *iface = g_iface; + + GST_INFO ("intializing child proxy interface"); + iface->get_child_by_index = + gst_rtsp_client_sink_child_proxy_get_child_by_index; + iface->get_children_count = + gst_rtsp_client_sink_child_proxy_get_children_count; +} + #define gst_rtsp_client_sink_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstRTSPClientSink, gst_rtsp_client_sink, GST_TYPE_BIN, G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, - gst_rtsp_client_sink_uri_handler_init)); + gst_rtsp_client_sink_uri_handler_init); + G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY, + gst_rtsp_client_sink_child_proxy_init); + ); #ifndef GST_DISABLE_GST_DEBUG static inline const gchar * @@ -634,7 +792,8 @@ gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtsp_client_sink_release_pad); - gst_element_class_add_static_pad_template (gstelement_class, &rtptemplate); + gst_element_class_add_static_pad_template_with_gtype (gstelement_class, + &rtptemplate, GST_TYPE_RTSP_CLIENT_SINK_PAD); gst_element_class_set_static_metadata (gstelement_class, "RTSP RECORD client", "Sink/Network", @@ -839,7 +998,36 @@ gst_rtsp_client_sink_get_factories (void) } static GstCaps * -gst_rtsp_client_sink_get_payloader_caps (void) +gst_rtsp_client_sink_get_payloader_caps (GstElementFactory *factory) +{ + const GList *tmp; + GstCaps *caps = gst_caps_new_empty(); + + for (tmp = gst_element_factory_get_static_pad_templates (factory); + tmp; tmp = g_list_next (tmp)) { + GstStaticPadTemplate *template = tmp->data; + + if (template->direction == GST_PAD_SINK) { + GstCaps *static_caps = gst_static_pad_template_get_caps (template); + + GST_LOG ("Found pad template %s on factory %s", + template->name_template, gst_plugin_feature_get_name (factory)); + + if (static_caps) + caps = gst_caps_merge (caps, static_caps); + + /* Early out, any is absorbing */ + if (gst_caps_is_any (caps)) + goto out; + } + } + +out: + return caps; +} + +static GstCaps * +gst_rtsp_client_sink_get_all_payloaders_caps (void) { /* Cached caps result */ static GstCaps *ret; @@ -851,27 +1039,15 @@ gst_rtsp_client_sink_get_payloader_caps (void) factories = gst_rtsp_client_sink_get_factories (); for (cur = factories; cur != NULL; cur = g_list_next (cur)) { GstElementFactory *factory = GST_ELEMENT_FACTORY (cur->data); - const GList *tmp; + GstCaps *payloader_caps = gst_rtsp_client_sink_get_payloader_caps (factory); - for (tmp = gst_element_factory_get_static_pad_templates (factory); - tmp; tmp = g_list_next (tmp)) { - GstStaticPadTemplate *template = tmp->data; + caps = gst_caps_merge (caps, payloader_caps); - if (template->direction == GST_PAD_SINK) { - GstCaps *static_caps = gst_static_pad_template_get_caps (template); - - GST_LOG ("Found pad template %s on factory %s", - template->name_template, gst_plugin_feature_get_name (factory)); - - if (static_caps) - caps = gst_caps_merge (caps, static_caps); - - /* Early out, any is absorbing */ - if (gst_caps_is_any (caps)) - goto out; - } - } + /* Early out, any is absorbing */ + if (gst_caps_is_any (caps)) + goto out; } + out: g_once_init_leave (&ret, caps); } @@ -1003,14 +1179,20 @@ gst_rtsp_client_sink_setup_payloader (GstRTSPClientSink * sink, GstPad * pad, GstCaps * caps) { GstRTSPStreamContext *context; + GstRtspClientSinkPad *cspad = GST_RTSP_CLIENT_SINK_PAD (pad); GstElement *payloader; GstPad *sinkpad, *srcpad, *ghostsink; context = gst_pad_get_element_private (pad); - /* Find the payloader. FIXME: Allow user to provide payloader via pad property */ - payloader = gst_rtsp_client_sink_make_payloader (caps); + if (cspad->custom_payloader) { + payloader = cspad->custom_payloader; + } else { + /* Find the payloader. */ + payloader = gst_rtsp_client_sink_make_payloader (caps); + } + if (payloader == NULL) return FALSE; @@ -1084,6 +1266,11 @@ gst_rtsp_client_sink_sinkpad_event (GstPad * pad, GstObject * parent, if (!gst_rtsp_client_sink_setup_payloader (GST_RTSP_CLIENT_SINK (parent), pad, caps)) { + GstRtspClientSinkPad *cspad = GST_RTSP_CLIENT_SINK_PAD (pad); + GST_ELEMENT_ERROR (parent, CORE, NEGOTIATION, + ("Could not create payloader"), + ("Custom payloader: %p, caps: %" GST_PTR_FORMAT, + cspad->custom_payloader, caps)); gst_event_unref (event); return FALSE; } @@ -1102,8 +1289,17 @@ gst_rtsp_client_sink_sinkpad_query (GstPad * pad, GstObject * parent, if (GST_QUERY_TYPE (query) == GST_QUERY_CAPS) { GstPad *target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); if (target == NULL) { - /* No target yet - return the union of all payloader caps */ - GstCaps *caps = gst_rtsp_client_sink_get_payloader_caps (); + GstRtspClientSinkPad *cspad = GST_RTSP_CLIENT_SINK_PAD (pad); + GstCaps *caps; + + if (cspad->custom_payloader) { + GstElementFactory *factory = gst_element_get_factory (cspad->custom_payloader); + + caps = gst_rtsp_client_sink_get_payloader_caps (factory); + } else { + /* No target yet - return the union of all payloader caps */ + caps = gst_rtsp_client_sink_get_all_payloaders_caps (); + } GST_TRACE_OBJECT (parent, "Returning payloader caps %" GST_PTR_FORMAT, caps); @@ -1155,7 +1351,7 @@ gst_rtsp_client_sink_request_new_pad (GstElement * element, GST_OBJECT_UNLOCK (sink); tmpname = g_strdup_printf ("sink_%u", idx); - pad = gst_ghost_pad_new_no_target_from_template (tmpname, templ); + pad = gst_rtsp_client_sink_pad_new (templ, tmpname); g_free (tmpname); GST_DEBUG_OBJECT (element, "Creating request pad %" GST_PTR_FORMAT, pad); @@ -1174,6 +1370,8 @@ gst_rtsp_client_sink_request_new_pad (GstElement * element, /* The rest of the context is configured on a caps set */ gst_pad_set_active (pad, TRUE); gst_element_add_pad (element, pad); + gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (pad), + GST_PAD_NAME (pad)); (void) gst_rtsp_client_sink_get_factories (); From a41d0fb5c2e805afa8bbed651e9ea7e41ef32450 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 26 Feb 2018 20:27:57 +0100 Subject: [PATCH 1463/1776] rtspclientsink: add missing get_type prototype --- gst/rtsp-sink/gstrtspclientsink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 9a964452f3..0ef2a5b09b 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -117,6 +117,7 @@ enum PROP_PAD_PAYLOADER }; +static GType gst_rtsp_client_sink_pad_get_type (void); G_DEFINE_TYPE (GstRtspClientSinkPad, gst_rtsp_client_sink_pad, GST_TYPE_GHOST_PAD); #define GST_TYPE_RTSP_CLIENT_SINK_PAD (gst_rtsp_client_sink_pad_get_type ()) From fcf71d8efb3eef72eba05f9b7946665a68395543 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 26 Feb 2018 22:57:39 +0100 Subject: [PATCH 1464/1776] rspclientsink: fix recent code indentation --- gst/rtsp-sink/gstrtspclientsink.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 0ef2a5b09b..040bfc66ad 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -999,10 +999,10 @@ gst_rtsp_client_sink_get_factories (void) } static GstCaps * -gst_rtsp_client_sink_get_payloader_caps (GstElementFactory *factory) +gst_rtsp_client_sink_get_payloader_caps (GstElementFactory * factory) { const GList *tmp; - GstCaps *caps = gst_caps_new_empty(); + GstCaps *caps = gst_caps_new_empty (); for (tmp = gst_element_factory_get_static_pad_templates (factory); tmp; tmp = g_list_next (tmp)) { @@ -1040,7 +1040,8 @@ gst_rtsp_client_sink_get_all_payloaders_caps (void) factories = gst_rtsp_client_sink_get_factories (); for (cur = factories; cur != NULL; cur = g_list_next (cur)) { GstElementFactory *factory = GST_ELEMENT_FACTORY (cur->data); - GstCaps *payloader_caps = gst_rtsp_client_sink_get_payloader_caps (factory); + GstCaps *payloader_caps = + gst_rtsp_client_sink_get_payloader_caps (factory); caps = gst_caps_merge (caps, payloader_caps); @@ -1294,7 +1295,8 @@ gst_rtsp_client_sink_sinkpad_query (GstPad * pad, GstObject * parent, GstCaps *caps; if (cspad->custom_payloader) { - GstElementFactory *factory = gst_element_get_factory (cspad->custom_payloader); + GstElementFactory *factory = + gst_element_get_factory (cspad->custom_payloader); caps = gst_rtsp_client_sink_get_payloader_caps (factory); } else { From 7f6367cc63937f80b45c6060f8b1f64e40d97fd3 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 26 Feb 2018 22:59:00 +0100 Subject: [PATCH 1465/1776] rtspclientsink: fix extra unref of custom payloader --- gst/rtsp-sink/gstrtspclientsink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 040bfc66ad..090b056317 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -1239,7 +1239,8 @@ gst_rtsp_client_sink_setup_payloader (GstRTSPClientSink * sink, GstPad * pad, no_sinkpad: GST_ERROR_OBJECT (sink, "Could not find sink pad on payloader %" GST_PTR_FORMAT, payloader); - gst_object_unref (payloader); + if (!cspad->custom_payloader) + gst_object_unref (payloader); return FALSE; no_srcpad: From ba9395c158093ee736a2faedd7e2689fc36bf44a Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 26 Feb 2018 22:59:17 +0100 Subject: [PATCH 1466/1776] rtspclientsink: fix retrieval of custom payloader caps If a bin is passed as the custom payloader, the caps of its factory will be empty, the correct way to obtain the caps is to query its sinkpad. --- gst/rtsp-sink/gstrtspclientsink.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 090b056317..454c58d43b 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -1296,10 +1296,17 @@ gst_rtsp_client_sink_sinkpad_query (GstPad * pad, GstObject * parent, GstCaps *caps; if (cspad->custom_payloader) { - GstElementFactory *factory = - gst_element_get_factory (cspad->custom_payloader); + GstPad *sinkpad = + gst_element_get_static_pad (cspad->custom_payloader, "sink"); - caps = gst_rtsp_client_sink_get_payloader_caps (factory); + if (sinkpad) { + caps = gst_pad_query_caps (sinkpad, NULL); + gst_object_unref (sinkpad); + } else { + GST_ELEMENT_ERROR (parent, CORE, NEGOTIATION, (NULL), + ("Custom payloaders are expected to expose a sink pad named 'sink'")); + return FALSE; + } } else { /* No target yet - return the union of all payloader caps */ caps = gst_rtsp_client_sink_get_all_payloaders_caps (); From 6f308daa5faa6e9dc2fc3da69b90434ea8e25b0c Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 27 Feb 2018 20:34:49 +0100 Subject: [PATCH 1467/1776] rtspclientsink: if OPEN failed, unqueue next command As READY_TO_PAUSED can no longer return async, the RECORD command will be queued before the OPEN command fails (for example in case the server could not be connected), and record then waits for ever. https://bugzilla.gnome.org/show_bug.cgi?id=793896 --- gst/rtsp-sink/gstrtspclientsink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 454c58d43b..358b4e6624 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -4684,7 +4684,9 @@ gst_rtsp_client_sink_thread (GstRTSPClientSink * sink) switch (cmd) { case CMD_OPEN: - gst_rtsp_client_sink_open (sink, TRUE); + if (gst_rtsp_client_sink_open (sink, TRUE) == GST_RTSP_ERROR) + gst_rtsp_client_sink_loop_send_cmd (sink, CMD_WAIT, + CMD_ALL & ~CMD_CLOSE); break; case CMD_RECORD: gst_rtsp_client_sink_record (sink, TRUE); From 0dc617058203acae4db137621ee7ac388dd9eb30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 28 Feb 2018 21:12:43 +0200 Subject: [PATCH 1468/1776] rtsp-client: Place netaddress meta on packets received via TCP This allows us to later map signals from rtpbin/rtpsource back to the corresponding stream transport, and allows to do keep-alive based on RTCP packets in case of TCP media transport. https://bugzilla.gnome.org/show_bug.cgi?id=789646 --- gst/rtsp-server/rtsp-client.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 4b5d5a3fb8..9df4c9bb92 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -3784,6 +3784,37 @@ handle_data (GstRTSPClient * client, GstRTSPMessage * message) trans = g_hash_table_lookup (priv->transports, GINT_TO_POINTER ((gint) channel)); if (trans) { + GSocketAddress *addr; + + /* Only create the socket address once for the transport, we don't really + * want to do that for every single packet. + * + * The netaddress meta is later used by the RTP stack to know where + * packets came from and allows us to match it again to a stream transport + * + * In theory we could use the remote socket address of the RTSP connection + * here, but this would fail with a custom configure_client_transport() + * implementation. + */ + if (!(addr = + g_object_get_data (G_OBJECT (trans), "rtsp-client.remote-addr"))) { + const GstRTSPTransport *tr; + GInetAddress *iaddr; + + tr = gst_rtsp_stream_transport_get_transport (trans); + iaddr = g_inet_address_new_from_string (tr->destination); + if (iaddr) { + addr = g_inet_socket_address_new (iaddr, tr->client_port.min); + g_object_unref (iaddr); + g_object_set_data_full (G_OBJECT (trans), "rtsp-client.remote-addr", + addr, (GDestroyNotify) g_object_unref); + } + } + + if (addr) { + gst_buffer_add_net_address_meta (buffer, addr); + } + /* dispatch to the stream based on the channel number */ GST_LOG_OBJECT (client, "%u bytes of data on channel %u", size, channel); gst_rtsp_stream_transport_recv_data (trans, channel, buffer); From 030992d03a0a3933397407c1ff7bfa4176373674 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 1 Mar 2018 19:28:16 +0100 Subject: [PATCH 1469/1776] meson: enable more warnings --- meson.build | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/meson.build b/meson.build index 559b790db9..30affba283 100644 --- a/meson.build +++ b/meson.build @@ -67,6 +67,33 @@ configure_file(output : 'config.h', configuration : cdata) rtspserver_args = ['-DHAVE_CONFIG_H'] +warning_flags = [ + '-Wmissing-declarations', + '-Wmissing-prototypes', + '-Wredundant-decls', + '-Wundef', + '-Wwrite-strings', + '-Wformat', + '-Wformat-nonliteral', + '-Wformat-security', + '-Wold-style-definition', + '-Waggregate-return', + '-Wnested-externs', + '-Winit-self', + '-Wmissing-include-dirs', + '-Waddress', + '-Wno-multichar', + '-Wdeclaration-after-statement', + '-Wvla', + '-Wpointer-arith', +] + +foreach extra_arg : warning_flags + if cc.has_argument (extra_arg) + add_project_arguments([extra_arg], language: 'c') + endif +endforeach + rtspserver_incs = include_directories('gst/rtsp-server', '.') glib_dep = dependency('glib-2.0', version : glib_req, From e356cf33f25e4c495355e54ff885b8d2ca3971d3 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 2 Mar 2018 01:36:23 +0100 Subject: [PATCH 1470/1776] permissions: more bindings-friendly API https://bugzilla.gnome.org/show_bug.cgi?id=793975 --- docs/libs/gst-rtsp-server-sections.txt | 2 + gst/rtsp-server/rtsp-media-factory.c | 25 ++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 3 ++ gst/rtsp-server/rtsp-permissions.c | 53 ++++++++++++++++++++------ gst/rtsp-server/rtsp-permissions.h | 3 ++ tests/check/gst/permissions.c | 9 +++++ 6 files changed, 83 insertions(+), 12 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 86e3f25a43..103cd4ae35 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -248,6 +248,7 @@ gst_rtsp_media_factory_set_launch gst_rtsp_media_factory_get_permissions gst_rtsp_media_factory_set_permissions gst_rtsp_media_factory_add_role +gst_rtsp_media_factory_add_role_from_structure gst_rtsp_media_factory_set_shared gst_rtsp_media_factory_is_shared @@ -361,6 +362,7 @@ gst_rtsp_permissions_unref gst_rtsp_permissions_add_role gst_rtsp_permissions_add_role_valist gst_rtsp_permissions_add_role_empty +gst_rtsp_permissions_add_role_from_structure gst_rtsp_permissions_add_permission_for_role gst_rtsp_permissions_remove_role gst_rtsp_permissions_get_role diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 909384759f..b7ba295010 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -494,6 +494,31 @@ gst_rtsp_media_factory_add_role (GstRTSPMediaFactory * factory, GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); } +/** + * gst_rtsp_media_factory_add_role_from_structure: + * + * A convenience wrapper around gst_rtsp_permissions_add_role_from_structure(). + * If @factory had no permissions, new permissions will be created and the + * role will be added to it. + */ +void +gst_rtsp_media_factory_add_role_from_structure (GstRTSPMediaFactory * factory, + GstStructure * structure) +{ + GstRTSPMediaFactoryPrivate *priv; + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + g_return_if_fail (GST_IS_STRUCTURE (structure)); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + if (priv->permissions == NULL) + priv->permissions = gst_rtsp_permissions_new (); + + gst_rtsp_permissions_add_role_from_structure (priv->permissions, structure); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + /** * gst_rtsp_media_factory_set_launch: * @factory: a #GstRTSPMediaFactory diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 57c8031233..c76a2408d6 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -127,6 +127,9 @@ void gst_rtsp_media_factory_add_role (GstRTSPMediaFacto const gchar *fieldname, ...); GST_EXPORT +void gst_rtsp_media_factory_add_role_from_structure (GstRTSPMediaFactory * factory, + GstStructure *structure); +GST_EXPORT void gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory, gboolean shared); diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index 34cf42a570..95750488b6 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -105,6 +105,28 @@ gst_rtsp_permissions_init (GstRTSPPermissionsImpl * permissions) g_ptr_array_new_with_free_func ((GDestroyNotify) free_structure); } +static void +add_role_from_structure (GstRTSPPermissionsImpl * impl, + GstStructure * structure) +{ + guint i, len; + const gchar *role = gst_structure_get_name (structure); + + len = impl->roles->len; + for (i = 0; i < len; i++) { + GstStructure *entry = g_ptr_array_index (impl->roles, i); + + if (gst_structure_has_name (entry, role)) { + g_ptr_array_remove_index_fast (impl->roles, i); + break; + } + } + + gst_structure_set_parent_refcount (structure, + &impl->permissions.mini_object.refcount); + g_ptr_array_add (impl->roles, structure); +} + /** * gst_rtsp_permissions_new: * @@ -214,7 +236,6 @@ gst_rtsp_permissions_add_role_valist (GstRTSPPermissions * permissions, { GstRTSPPermissionsImpl *impl = (GstRTSPPermissionsImpl *) permissions; GstStructure *structure; - guint i, len; g_return_if_fail (GST_IS_RTSP_PERMISSIONS (permissions)); g_return_if_fail (gst_mini_object_is_writable (&permissions->mini_object)); @@ -223,19 +244,27 @@ gst_rtsp_permissions_add_role_valist (GstRTSPPermissions * permissions, structure = gst_structure_new_valist (role, fieldname, var_args); g_return_if_fail (structure != NULL); - len = impl->roles->len; - for (i = 0; i < len; i++) { - GstStructure *entry = g_ptr_array_index (impl->roles, i); + add_role_from_structure (impl, structure); +} - if (gst_structure_has_name (entry, role)) { - g_ptr_array_remove_index_fast (impl->roles, i); - break; - } - } +/** + * gst_rtsp_permissions_add_role_from_structure: + * + * Add a new role to @permissions based on @structure + */ +void +gst_rtsp_permissions_add_role_from_structure (GstRTSPPermissions * permissions, + GstStructure * structure) +{ + GstRTSPPermissionsImpl *impl = (GstRTSPPermissionsImpl *) permissions; + GstStructure *copy; - gst_structure_set_parent_refcount (structure, - &impl->permissions.mini_object.refcount); - g_ptr_array_add (impl->roles, structure); + g_return_if_fail (GST_IS_RTSP_PERMISSIONS (permissions)); + g_return_if_fail (GST_IS_STRUCTURE (structure)); + + copy = gst_structure_copy (structure); + + add_role_from_structure (impl, copy); } /** diff --git a/gst/rtsp-server/rtsp-permissions.h b/gst/rtsp-server/rtsp-permissions.h index 4bdff46ce2..792e3974ee 100644 --- a/gst/rtsp-server/rtsp-permissions.h +++ b/gst/rtsp-server/rtsp-permissions.h @@ -91,6 +91,9 @@ void gst_rtsp_permissions_add_role_empty (GstRTSPPermissions * const gchar * role); GST_EXPORT +void gst_rtsp_permissions_add_role_from_structure (GstRTSPPermissions * permissions, + GstStructure *structure); +GST_EXPORT void gst_rtsp_permissions_add_permission_for_role (GstRTSPPermissions * permissions, const gchar * role, const gchar * permission, diff --git a/tests/check/gst/permissions.c b/tests/check/gst/permissions.c index 8083b1d55e..6f5ccf0d2f 100644 --- a/tests/check/gst/permissions.c +++ b/tests/check/gst/permissions.c @@ -25,6 +25,7 @@ GST_START_TEST (test_permissions) { GstRTSPPermissions *perms; GstRTSPPermissions *copy; + GstStructure *role_structure; perms = gst_rtsp_permissions_new (); fail_if (gst_rtsp_permissions_is_allowed (perms, "missing", "permission1")); @@ -110,6 +111,14 @@ GST_START_TEST (test_permissions) gst_rtsp_permissions_add_role_empty (perms, "noone"); fail_if (gst_rtsp_permissions_is_allowed (perms, "noone", "permission1")); + role_structure = gst_structure_new ("tester", "permission1", G_TYPE_BOOLEAN, + TRUE, NULL); + gst_rtsp_permissions_add_role_from_structure (perms, role_structure); + gst_structure_free (role_structure); + fail_unless (gst_rtsp_permissions_is_allowed (perms, "tester", + "permission1")); + fail_if (gst_rtsp_permissions_is_allowed (perms, "tester", "permission2")); + gst_rtsp_permissions_unref (perms); } From 1288faeae70478a776591070ea7c8c7b40eabbe3 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 2 Mar 2018 16:24:23 +0100 Subject: [PATCH 1471/1776] permissions: add Since tags and example for new API --- gst/rtsp-server/rtsp-media-factory.c | 2 ++ gst/rtsp-server/rtsp-permissions.c | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index b7ba295010..5987d1b923 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -500,6 +500,8 @@ gst_rtsp_media_factory_add_role (GstRTSPMediaFactory * factory, * A convenience wrapper around gst_rtsp_permissions_add_role_from_structure(). * If @factory had no permissions, new permissions will be created and the * role will be added to it. + * + * Since: 1.14 */ void gst_rtsp_media_factory_add_role_from_structure (GstRTSPMediaFactory * factory, diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index 95750488b6..1667db746f 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -250,7 +250,15 @@ gst_rtsp_permissions_add_role_valist (GstRTSPPermissions * permissions, /** * gst_rtsp_permissions_add_role_from_structure: * - * Add a new role to @permissions based on @structure + * Add a new role to @permissions based on @structure, for example + * given a role named `tester`, which should be granted a permission named + * `permission1`, the structure could be created with: + * + * ``` + * gst_structure_new ("tester", "permission1", G_TYPE_BOOLEAN, TRUE, NULL); + * ``` + * + * Since: 1.14 */ void gst_rtsp_permissions_add_role_from_structure (GstRTSPPermissions * permissions, From e6e64c95c6381d5fd893ffa18181cf79d49d99ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 3 Mar 2018 22:49:34 +0000 Subject: [PATCH 1472/1776] Release 1.13.90 --- ChangeLog | 944 ++++++++++++++++++++++++++++++++++++++++++- NEWS | 281 ++++++++----- RELEASE | 67 ++- configure.ac | 12 +- gst-rtsp-server.doap | 12 +- meson.build | 2 +- 6 files changed, 1178 insertions(+), 140 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3e3a6308e0..4826941f57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,947 @@ -=== release 1.12.0 === +=== release 1.13.90 === -2017-05-04 Sebastian Dröge +2018-03-03 22:49:34 +0000 Tim-Philipp Müller + + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + * meson.build: + Release 1.13.90 + +2018-03-02 16:24:23 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-permissions.c: + permissions: add Since tags and example for new API + +2018-03-02 01:36:23 +0100 Mathieu Duponchelle + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-permissions.c: + * gst/rtsp-server/rtsp-permissions.h: + * tests/check/gst/permissions.c: + permissions: more bindings-friendly API + https://bugzilla.gnome.org/show_bug.cgi?id=793975 + +2018-03-01 19:28:16 +0100 Mathieu Duponchelle + + * meson.build: + meson: enable more warnings + +2018-02-28 21:12:43 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Place netaddress meta on packets received via TCP + This allows us to later map signals from rtpbin/rtpsource back to the + corresponding stream transport, and allows to do keep-alive based on + RTCP packets in case of TCP media transport. + https://bugzilla.gnome.org/show_bug.cgi?id=789646 + +2018-02-27 20:34:49 +0100 Mathieu Duponchelle + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: if OPEN failed, unqueue next command + As READY_TO_PAUSED can no longer return async, the RECORD + command will be queued before the OPEN command fails + (for example in case the server could not be connected), + and record then waits for ever. + https://bugzilla.gnome.org/show_bug.cgi?id=793896 + +2018-02-26 22:59:17 +0100 Mathieu Duponchelle + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: fix retrieval of custom payloader caps + If a bin is passed as the custom payloader, the caps of + its factory will be empty, the correct way to obtain the caps + is to query its sinkpad. + +2018-02-26 22:59:00 +0100 Mathieu Duponchelle + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: fix extra unref of custom payloader + +2018-02-26 22:57:39 +0100 Mathieu Duponchelle + + * gst/rtsp-sink/gstrtspclientsink.c: + rspclientsink: fix recent code indentation + +2018-02-26 20:27:57 +0100 Mathieu Duponchelle + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: add missing get_type prototype + +2018-02-24 03:52:15 +0100 Mathieu Duponchelle + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: allow setting payloader as pad property + This was a FIXME item, and can be quite useful, also + allowing to specify payloader properties from the command + line, which is always nice. + https://bugzilla.gnome.org/show_bug.cgi?id=793776 + +2018-02-26 14:16:54 +0100 Carlos Rafael Giani + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Replace g_print() log line + https://bugzilla.gnome.org/show_bug.cgi?id=793838 + +2018-02-22 20:17:33 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/rtspclientsink.c: + rtsp-media: fix RECORD getting stuck + The test_record case was working because async=false had + been added in https://bugzilla.gnome.org/show_bug.cgi?id=757488 + but that was incorrect, as it should not be needed. + Removing async=false made the test fail as expected, this is + fixed by not trying to preroll when preparing the media for + RECORD, as start_prepare is called upon receiving ANNOUNCE, + and our peer will not start sending media until it has received + a response to that request, and sent and received a response + to RECORD as well, thus obviously preventing preroll. + https://bugzilla.gnome.org/show_bug.cgi?id=793738 + +2018-02-23 03:26:21 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-auth.c: + rtsp-auth: fix set_tls_authentication_mode annotation + +2018-02-19 11:57:29 +0100 Víctor Manuel Jáquez Leal + + * gst/rtsp-server/rtsp-onvif-media.c: + rtp-server: remove redefined variable + res is a boolean variable which is defined in the function scope and + redefined, with no reason, in the loop scope. This patch removes the + redefinition. + https://bugzilla.gnome.org/show_bug.cgi?id=793592 + +2018-02-05 11:49:07 +0100 Ognyan Tonchev + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + stream: Add functions for checking if stream is receiver or sender + ...and replace all checks for RECORD in GstRTSPMedia which are really + for "sender-only". This way the code becomes more generic and introducing + support for onvif-backchannel later on will require no changes in + GstRTSPMedia. + +2017-10-21 14:06:30 +0200 Ognyan Tonchev + + * gst/rtsp-server/rtsp-onvif-media-factory.c: + * gst/rtsp-server/rtsp-onvif-media-factory.h: + onvif: Make requires_backchannel() public + ...in order to let subclasses building the onvif part of the pipeline + check whether backchannel shall be included or not. + +2018-01-22 12:46:34 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-onvif-media.c: + rtsp-server: Switch around sendonly/recvonly attributes + They are wrong in the ONVIF streaming spec. The backchannel should be + recvonly and the normal media should be sendonly: direction is always + from the point of view of the SDP offerer (the server) according to + RFC 3264. + +2017-09-25 19:41:05 +0300 Sebastian Dröge + + * docs/libs/gst-rtsp-server-docs.sgml: + * docs/libs/gst-rtsp-server-sections.txt: + * examples/.gitignore: + * examples/Makefile.am: + * examples/test-onvif-backchannel.c: + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-onvif-client.c: + * gst/rtsp-server/rtsp-onvif-client.h: + * gst/rtsp-server/rtsp-onvif-media-factory.c: + * gst/rtsp-server/rtsp-onvif-media-factory.h: + * gst/rtsp-server/rtsp-onvif-media.c: + * gst/rtsp-server/rtsp-onvif-media.h: + * gst/rtsp-server/rtsp-onvif-server.c: + * gst/rtsp-server/rtsp-onvif-server.h: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-sdp.h: + rtsp: Add support for ONVIF backchannel + This adds a new RTSP server, client, media-factory and media subclass + for handling the specifics of the backchannel. Ideally this later can be + extended with other ONVIF specific features. + +2017-10-12 21:00:16 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Add support for sending+receiving medias + We need to add an appsrc/appsink in that case because otherwise the + media bin will be a sink and a source for rtpbin, causing a pipeline + loop. + https://bugzilla.gnome.org/show_bug.cgi?id=788950 + +2018-02-15 19:44:28 +0000 Tim-Philipp Müller * configure.ac: - releasing 1.12.0 + * meson.build: + Back to development + +=== release 1.13.1 === + +2018-02-15 17:15:40 +0000 Tim-Philipp Müller + + * NEWS: + * configure.ac: + * gst-rtsp-server.doap: + * meson.build: + Release 1.13.1 + +2018-02-14 17:11:19 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-session-pool.c: + session-pool: remove nullable return annotation + create_watch can only return NULL from the API guards, no + need for nullable. + +2018-02-13 18:59:16 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + set_clock functions: Add nullable annotations + +2018-02-10 00:07:25 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-thread-pool.c: + All around: add annotations and API guards + +2018-02-12 19:12:35 +0100 Mathieu Duponchelle + + * tests/test-cleanup.c: + test-cleanup: bind any port + The meson test suite runs tests in parallel, trying to bind + a single port made the test fail. + +2018-02-08 19:15:10 +0000 Tim-Philipp Müller + + * meson.build: + meson: make version numbers ints and fix int/string comparison + WARNING: Trying to compare values of different types (str, int). + The result of this is undefined and will become a hard error + in a future Meson release. + +2018-02-06 18:00:33 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-context.c: + gst_rtsp_context_get_current: add (skip) annotation + The return value type is defined with G_DEFINE_POINTER_TYPE, + and gi emits the following warning: + Invalid non-constant return of bare structure or union; register as + boxed type or (skip) + +2018-02-06 17:58:49 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: add type annotations + gi doesn't seem to be able to figure out the type of the + signal parameters when defined with G_DEFINE_POINTER_TYPE + +2018-02-04 12:24:09 +0100 Tim-Philipp Müller + + * configure.ac: + autotools: use -fno-strict-aliasing where supported + https://bugzilla.gnome.org/show_bug.cgi?id=769183 + +2018-01-30 20:35:21 +0000 Tim-Philipp Müller + + * meson.build: + meson: use -fno-strict-aliasing where supported + https://bugzilla.gnome.org/show_bug.cgi?id=769183 + +2018-01-25 12:09:03 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-mount-points.c: + mount-points: bail out of loop again when matching mount points + Previous patch led to us iterating the entire sequence. Bail out + of the loop again if we have a match but are moving away from it. + https://bugzilla.gnome.org/show_bug.cgi?id=771555 + +2018-01-25 12:06:57 +0000 Tim-Philipp Müller + + * tests/check/gst/mountpoints.c: + tests: mountpoints: add more checks for mount point path matching + https://bugzilla.gnome.org/show_bug.cgi?id=771555 + +2016-09-16 20:41:19 +0000 Andrew Bott + + * gst/rtsp-server/rtsp-mount-points.c: + mount-points: fix matching of paths where there's also an entry with a common prefix + e.g. with the following mount points + /raw + /raw/snapshot + /raw/video + _match() would not match /raw/video and /raw/snapshot correctly. + https://bugzilla.gnome.org/show_bug.cgi?id=771555 + +2018-01-18 23:53:20 +0000 Tim-Philipp Müller + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-permissions.c: + * gst/rtsp-server/rtsp-permissions.h: + * tests/check/gst/permissions.c: + permissions: add some new API to make this usable from bindings + https://bugzilla.gnome.org/show_bug.cgi?id=787073 + +2018-01-18 11:32:32 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-token.c: + rtsp-token: annotate constructors for bindings + This maps _new_empty() to _new(), which also makes RTSPToken() + work properly now. Since this API wasn't usable from bindings + before, this should hopefully be fine. + https://bugzilla.gnome.org/show_bug.cgi?id=787073 + +2018-01-18 11:07:45 +0000 Tim-Philipp Müller + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-token.c: + * gst/rtsp-server/rtsp-token.h: + * tests/check/gst/token.c: + rtsp-token: add some API to set fields from bindings + The existing functions are all vararg-based and as such + not usable from bindings. + https://bugzilla.gnome.org/show_bug.cgi?id=787073 + +2018-01-13 15:02:28 +0000 Tim-Philipp Müller + + * tests/check/gst/rtspclientsink.c: + * tests/check/gst/rtspserver.c: + * tests/check/gst/sessionpool.c: + * tests/check/gst/stream.c: + tests: fix indentation + Fix and "fix". + +2018-01-13 14:58:55 +0000 Tim-Philipp Müller + + * tests/check/gst/rtspserver.c: + tests: rtspserver: fix another ref leak + Even if this didn't show up in valgrind. + +2018-01-13 14:58:00 +0000 Tim-Philipp Müller + + * tests/check/gst/rtspclientsink.c: + tests: rtspclientsink: fix leak + +2018-01-02 14:19:31 +0100 Branko Subasic + + * tests/check/gst/rtspserver.c: + test: rtspserver: plug memory leak in test_no_session_timeout + In test_no_session_timeout, unref the rtsp session object when the + test is done. + https://bugzilla.gnome.org/show_bug.cgi?id=792127 + +2017-12-20 14:17:02 +0100 Edward Hervey + + * gst/rtsp-sink/gstrtspclientsink.c: + rtpsclientsink: Initialize and clear newly added mutex and cond + While it *did* work, glib would automatically create new mutex and cond + ... which never got freed + +2017-12-19 11:34:37 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Set multicast TTL on the multicast sockets + And not if we do unicast UDP. + https://bugzilla.gnome.org/show_bug.cgi?id=791743 + +2017-12-19 11:14:48 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Decide based on the sockets, not the addresses if we already allocated a socket + In the multicast case (as in test-multicast, not test-multicast2), the + address could be allocated/reserved (and thus set) already without + allocating the actual socket. We need to allocate the socket here still + instead of just claiming that it was already allocated. + See https://bugzilla.gnome.org/show_bug.cgi?id=791743#c2 + +2017-12-16 21:46:53 +0100 Patricia Muscalu + + * gst/rtsp-sink/gstrtspclientsink.c: + * gst/rtsp-sink/gstrtspclientsink.h: + rtspclientsink: Use the new rtsp-stream API + https://bugzilla.gnome.org/show_bug.cgi?id=790412 + +2017-12-16 21:01:43 +0100 Patricia Muscalu + + * gst/rtsp-sink/gstrtspclientsink.c: + * gst/rtsp-sink/gstrtspclientsink.h: + rtspclientsink: Wait until OPEN has been scheduled + Make sure that the sink thread has started opening connection + to the server before continuing. + https://bugzilla.gnome.org/show_bug.cgi?id=790412 + +2017-12-14 14:53:35 +1100 Matthew Waters + + * common: + Automatic update of common submodule + From e8c7a71 to 3fa2c9e + +2017-12-07 16:08:29 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-server: Minor doc fixes + Mostly for g-i + +2017-12-06 20:47:22 +0000 Tim-Philipp Müller + + * Makefile.am: + * tests/Makefile.am: + tests: disable all tests when --disable-tests is used + Move conditional subdir include into top level. + Based on patch by: Joel Holdsworth + https://bugzilla.gnome.org/show_bug.cgi?id=757703 + +2017-12-06 20:42:39 +0000 Tim-Philipp Müller + + * meson.build: + * meson_options.txt: + * tests/meson.build: + meson: build more tests and add options to disable tests and examples + +2017-11-26 13:26:39 -0300 Thibault Saunier + + * gst/rtsp-server/rtsp-session.c: + Fix build when -Werror=deprecated-declarations is on + As gst_rtsp_session_next_timeout is deprecated. + ``` + ../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-session.c:760:3: error: ‘gst_rtsp_session_next_timeout’ is deprecated: Use 'gst_rtsp_session_next_timeout_usec' instead [-Werror=deprecated-declarations] + res = (gst_rtsp_session_next_timeout (session, now) == 0); + ^~~ + ../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-session.c:685:1: note: declared here + gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ``` + +2017-11-27 20:18:24 +1100 Matthew Waters + + * common: + Automatic update of common submodule + From 3f4aa96 to e8c7a71 + +2017-11-25 20:34:16 +0100 Patricia Muscalu + + * tests/check/gst/media.c: + check/media: Add seekability test case: not all streams are active + Media contains two streams but only one is complete and prepared + for playing. + https://bugzilla.gnome.org/show_bug.cgi?id=790674 + +2017-11-25 20:32:02 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Do not reset 'blocking' if stream is already blocked + https://bugzilla.gnome.org/show_bug.cgi?id=790674 + +2017-11-25 20:45:44 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Fix missing lock in gst_rtsp_media_seekable() + https://bugzilla.gnome.org/show_bug.cgi?id=790674 + +2017-11-26 16:29:49 +0000 Tim-Philipp Müller + + * meson.build: + meson: remove vs_module_defs_dir variable which is no longer needed + +2017-11-26 14:46:05 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-session.h: + rtsp: fix distcheck + +2017-11-26 12:53:42 +0000 Tim-Philipp Müller + + * Makefile.am: + * gst/rtsp-server/meson.build: + * win32/MANIFEST: + * win32/common/libgstrtspserver.def: + win32: remove .def file with exports + They're no longer needed, symbol exporting is now explicit + via GST_EXPORT in all cases (autotools, meson, incl. MSVC). + +2017-11-26 12:28:40 +0000 Tim-Philipp Müller + + * configure.ac: + autotools: stop controlling symbol visibility with -export-symbols-regex + Instead, use -fvisibility=hidden and explicit exports via GST_EXPORT. + This should result in consistent behaviour for the autotools and + Meson builds. + +2017-11-26 12:47:08 +0000 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + rtsp-server: add missing GST_EXPORT and export deprecated funcs + +2017-11-25 07:53:30 +0100 Edward Hervey + + * tests/check/gst/media.c: + check: Add seekability testing on medias + Make sure that once GstRTSPMedia are prepared they returned + the expected seekability results + https://bugzilla.gnome.org/show_bug.cgi?id=790674 + +2017-11-24 17:34:31 +0100 Edward Hervey + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * win32/common/libgstrtspserver.def: + rtsp-media: Enable seeking query before pipeline is complete + SDP are now provided *before* the pipeline is fully complete. In order + to know whether a media is seekable or not therefore requires asking + the invididual streams. + API: gst_rtsp_stream_seekable + https://bugzilla.gnome.org/show_bug.cgi?id=790674 + +2017-11-23 20:34:03 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Fix handling in default_unsuspend() + Handle the case when streams are not blocked and media + is suspended from PAUSED. + Change-Id: I2f3d222ea7b9b20a0732ea5dc81a32d17ab75040 + https://bugzilla.gnome.org/show_bug.cgi?id=790674 + +2017-11-23 18:51:21 +0100 Patricia Muscalu + + * tests/check/gst/media.c: + check/media: Fix thread pool leak. + Change-Id: I0f92b1caca0ee518ae64a7dacfbd28a214c3eea1 + https://bugzilla.gnome.org/show_bug.cgi?id=790674 + +2017-11-23 18:39:44 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Removed fakesink elements + There is not need of adding fakesink elements to the media + pipeline in the dynamic-payloader case. + The media pipeline itself is dynamically updated with + the receiver and sender parts that are based on the client + transport information known after SETUP has been received. + Change-Id: I4e88c9b500c04030669822f0d03b1842913f6cb9 + https://bugzilla.gnome.org/show_bug.cgi?id=790674 + +2017-11-23 09:10:54 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Corrected ASYNC_DONE handling + Media is complete when all the transport based parts are + added to the media pipeline. At this point ASYNC_DONE is + posted by the media pipeline and media is ready to enter + the PREPARED state. + Change-Id: I50fb8dfed88ebaf057d9a35fca2d7f0a70e9d1fa + https://bugzilla.gnome.org/show_bug.cgi?id=790674 + +2017-11-22 12:24:38 +0100 Edward Hervey + + * tests/check/gst/media.c: + check/media: Check that prepared media can provide a SDP + Whenever a RTSPMedia is prepared, it should be able to provide a SDP + +2017-11-21 09:53:19 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Don't leak addr + CID #1422260 + +2017-11-21 09:53:08 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-stream.c: + Run gst-indent + +2017-11-20 18:30:19 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Don't unblock with remaining dynamic payloaders + If we still have some dynamic paylaoders which haven't posted + no-more-pads yet, don't go to PREPARED if one of the streams + blocked. + The risk was that we would end up not exposing/using all specified + streams. + The downside is that if you have _multiple_ _live_ _dynamic_ payloaders + then it will take a bit more time to start. But only if those 3 + conditions are present. + https://bugzilla.gnome.org/show_bug.cgi?id=769521 + +2017-11-20 16:49:29 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Fix doc + +2017-11-20 16:48:55 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Don't set float on a gint64 variable + Just use 0. Fixes 'undefined' behaviour from clang + +2017-11-20 18:29:02 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Fix previous commit + We only want to count dynamic payloaders + +2017-11-20 09:32:07 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/media.c: + rtsp-media: Handle multiple dynamic elements + If we have more than one dynamic payloader in the pipeline, we need + to wait until the *last* one emits 'no-more-pads' before switching + to PREPARED. + Failure to do so would result in a race where some of the streams + wouldn't properly be prepared + https://bugzilla.gnome.org/show_bug.cgi?id=769521 + +2017-11-16 12:18:20 +0200 Sebastian Dröge + + * win32/common/libgstrtspserver.def: + win32: Fix exported symbols list + +2017-11-15 19:52:29 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Only update the RTP udpsink if it actually exists + For send-only streams it does not exist, but the RTCP udpsink might. + +2017-11-15 18:15:53 +0200 Sebastian Dröge + + * win32/common/libgstrtspserver.def: + win32: Update exports + +2017-10-23 09:49:09 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-media: seek on media pipelines that are complete + Make sure that a seek is performed on pipelines that + contain at least one sink element. + Change-Id: Icf398e10add3191d104b1289de612412da326819 + https://bugzilla.gnome.org/show_bug.cgi?id=788340 + +2017-10-17 10:44:33 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/client.c: + * tests/check/gst/media.c: + * tests/check/gst/rtspserver.c: + * tests/check/gst/stream.c: + Dynamically reconfigure pipeline in PLAY based on transports + The initial pipeline does not contain specific transport + elements. The receiver and the sender parts are added + after PLAY. + If the media is shared, the streams are dynamically + reconfigured after each PLAY. + https://bugzilla.gnome.org/show_bug.cgi?id=788340 + +2017-10-16 12:40:57 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: obtain stream position from pad + If no sinks have been added yet, obtain the current and + the stop position of the stream from the send_src pad. + Change-Id: Iacd4ab4bdc69f6b49370d06012880ce48a7d595a + https://bugzilla.gnome.org/show_bug.cgi?id=788340 + +2017-10-16 11:35:10 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-media.h: + rtsp-session-media: add function to get a list of transports + Change-Id: I817e10624da0f3200f24d1b232cff481099278e3 + https://bugzilla.gnome.org/show_bug.cgi?id=788340 + +2017-10-16 11:15:55 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-stream: add functions to get rtp and rtcp multicast sockets + Change-Id: Iddfe6e0bd250cb0159096d5eba9e4202d22b56db + https://bugzilla.gnome.org/show_bug.cgi?id=788340 + +2017-10-20 12:21:48 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + stream: set async=sync=false only for RTCP appsink + Change-Id: I929a218a9adf4759f61322b6f2063aacc5595f90 + https://bugzilla.gnome.org/show_bug.cgi?id=788340 + +2017-10-16 10:10:17 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: return minimum value in query position case + The minimum position should be returned as we are interested + in the whole interval. + Change-Id: I30e297fc040c995ae40c25dee8ff56321612fe2b + https://bugzilla.gnome.org/show_bug.cgi?id=788340 + +2017-08-09 11:52:38 +0200 Jonathan Karlsson + + * gst/rtsp-server/rtsp-session.c: + * tests/check/gst/rtspserver.c: + rtsp-session: Handle the case when timeout=0 + According to the documentation, a timeout of value 0 means + that the session never timeouts. This adds handling of that. + If timeout=0 we just return with a -1 from + gst_rtsp_session_next_timeout_usec (). + https://bugzilla.gnome.org/show_bug.cgi?id=785058 + +2017-07-17 17:15:22 +0300 Sebastian Dröge + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Add "accept-certificate" signal for manually checking a TLS certificate for validity + https://bugzilla.gnome.org/show_bug.cgi?id=785024 + +2017-10-26 14:43:19 +0200 Mathieu Duponchelle + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-media-factory.c: + docs: add media factory transport mode accessors + and fix the documentation for the return value of the getter + +2017-10-09 12:43:01 +0200 Branko Subasic + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: unref 'pipelined_requests' in finalize + The hash table priv->pipelined_requests is not unref:ed in the + finalize funktion. Make sure it is. + https://bugzilla.gnome.org/show_bug.cgi?id=788704 + +2017-10-09 14:44:40 +0200 Thibault Saunier + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Initialize scalar variable + CID 1418985 + +2017-10-06 10:27:34 +0200 Edward Hervey + + * win32/common/libgstrtspserver.def: + win32: Update export file + +2017-04-22 09:26:07 -0300 Thibault Saunier + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + Start support for RTSP 2.0 + This adds basic support for new 2.0 features, though the protocol is + subposdely backward incompatible, most semantics are the sames. + This commit adds: + - features: + * version negotiation + * pipelined requests support + * Media-Properties support + * Accept-Ranges support + - APIs: + * gst_rtsp_media_seekable + The RTSP methods that have been removed when using 2.0 now return + BAD_REQUEST. + https://bugzilla.gnome.org/show_bug.cgi?id=781446 + +2017-06-02 15:37:54 -0400 Thibault Saunier + + * gst/rtsp-server/rtsp-stream.c: + stream: Use stream duration as stream-stop if segment was not configured with a stop + Allowing client to know stream duration when no seeking happened. + https://bugzilla.gnome.org/show_bug.cgi?id=783435 + +2017-09-25 19:40:17 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-media-factory.c: + rtsp-media-factory: Don't cache any media if NULL was returned as key + The docs already mentioned this, but we actually stored it in the hash + table with key==NULL and leaked its reference forever. + +2017-09-18 19:31:31 +0200 Mathieu Duponchelle + + * gst/rtsp-sink/gstrtspclientsink.c: + * gst/rtsp-sink/gstrtspclientsink.h: + rtspclientsink: Use a mutex for protecting against concurrent send/receives + This is a simple port of: + * a722f6e8329032c6eda4865d6a07f4ba5981d7ea + * c438545dc9e2f14f657bc0ef261fff726449867b + * cd17c71dcea5c9310d21f1347c7520983e5869ac + in gst-plugins-good. + +2017-08-31 13:24:15 +0530 Satya Prakash Gupta + + * gst/rtsp-server/rtsp-sdp.c: + sdp: fix Memory leak in error case + https://bugzilla.gnome.org/show_bug.cgi?id=787059 + +2017-08-18 17:37:01 +0100 Tim-Philipp Müller + + * pkgconfig/meson.build: + meson: don't install -uninstalled.pc file + https://bugzilla.gnome.org/show_bug.cgi?id=786457 + +2017-08-17 12:26:17 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 48a5d85 to 3f4aa96 + +2017-08-14 21:04:23 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Fix typo in debug message + +2017-08-11 14:14:32 +0100 Tim-Philipp Müller + + * meson.build: + meson: hide symbols by default unless explicitly exported + +2017-08-10 14:20:12 +0100 Tim-Philipp Müller + + * pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in: + pkgconfig: remove -I@srcdir@/.. which duplicates abs_top_srcdir + Fixes meson warning about undefined @srcdir@. + +2017-07-21 13:36:00 +0100 Tim-Philipp Müller + + * tests/meson.build: + meson: skip tests on windows for now + As we do in the other modules. As libgstcheck is currently not + built on windows. Fixes "Fallback variable 'gst_check_dep' in + the subproject 'gstreamer' does not exist"" Meson error. + +2017-06-22 07:25:07 -0700 Julien Isorce + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: fix connection delay due to wrong assumption on last-sample + Commit 852cc09f542af5cadd79ffd7fe79d6475cf57e14 assumed that + multiudpsink's last-sample always comes from the payloader. Which + is wrong if auxiliary streams are multiplexed in the same stream. + So check the buffer's ssrc against the caps'ssrc before to use its + seqnum. If not the same ssrc just use the payloader as done prior + the commit above or when there is no last-sample yet. + https://bugzilla.gnome.org/show_bug.cgi?id=784094 + +2017-06-23 16:19:04 -0400 Thibault Saunier + + * meson.build: + meson: Allow using glib as a subproject + +2017-06-26 09:55:49 +0100 Tim-Philipp Müller + + * meson.build: + meson: fix with-package-name option + https://bugzilla.gnome.org/show_bug.cgi?id=784082 + +2017-06-09 20:16:28 -0400 Nicolas Dufresne + + * Makefile.am: + Distribute meson_options.txt + +2017-06-09 20:11:47 -0400 Nicolas Dufresne + + * Makefile.am: + And config.h.meson is no longer dist either + +2017-06-09 21:27:09 +0100 Tim-Philipp Müller + + * config.h.meson: + * meson.build: + meson: config.h.meson is no longer needed + +2017-06-07 13:04:41 -0400 Thibault Saunier + + * tests/check/meson.build: + * tests/meson.build: + meson: Fix building tests and activate them again + +2017-06-07 12:55:41 -0400 Thibault Saunier + + * tests/check/meson.build: + meson: Do not use path separator in test names + Avoiding warnings like: + WARNING: Target "elements/audioamplify" has a path separator in its name. + +2017-05-20 15:07:31 +0100 Tim-Philipp Müller + + * meson.build: + * meson_options.txt: + meson: add options to set package name and origin + https://bugzilla.gnome.org/show_bug.cgi?id=782172 + +2017-05-18 10:35:18 +0100 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-address-pool.h: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-context.h: + * gst/rtsp-server/rtsp-media-factory-uri.h: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-mount-points.h: + * gst/rtsp-server/rtsp-params.h: + * gst/rtsp-server/rtsp-permissions.h: + * gst/rtsp-server/rtsp-sdp.h: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.h: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.h: + * gst/rtsp-server/rtsp-thread-pool.h: + * gst/rtsp-server/rtsp-token.h: + Mark symbols explicitly for export with GST_EXPORT + +2017-05-16 14:44:43 -0400 Nicolas Dufresne + + * configure.ac: + * gst/rtsp-sink/Makefile.am: + Remove plugin specific static build option + Static and dynamic plugins now have the same interface. The standard + --enable-static/--enable-shared toggle are sufficient. + +2017-05-04 18:59:14 +0300 Sebastian Dröge + + * configure.ac: + * meson.build: + Back to development + +=== release 1.12.0 === + +2017-05-04 15:40:46 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + * meson.build: + Release 1.12.0 === release 1.11.91 === diff --git a/NEWS b/NEWS index 385e4b6315..c85b362017 100644 --- a/NEWS +++ b/NEWS @@ -1,174 +1,235 @@ -# GStreamer 1.14 Release Notes + + +GSTREAMER 1.14 RELEASE NOTES + GStreamer 1.14.0 has not been released yet. It is scheduled for release -in late February / early March 2018. +in early March 2018. -There are unstable pre-releases available for testing and development purposes. -The latest pre-release is version 1.13.1 and was released on 15 February 2018. +There are unstable pre-releases available for testing and development +purposes. The latest pre-release is version 1.13.90 (rc1) and was +released on 03 March 2018. -See [https://gstreamer.freedesktop.org/releases/1.14/][latest] for the latest +See https://gstreamer.freedesktop.org/releases/1.14/ for the latest version of this document. -*Last updated: Thursday 15 February 2018, 16:30 UTC [(log)][gitlog]* - -[latest]: https://gstreamer.freedesktop.org/releases/1.14/ -[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.14/release-notes-1.14.md - -## Introduction - -The GStreamer team is proud to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! - -As always, this release is again packed with new features, bug fixes and other -improvements. - -## Highlights - -- this section will be completed shortly - -## Major new features and changes - -### Noteworthy new API - -- this section will be filled in shortly - -### New Elements - -- this section will be filled in shortly - -### New element features and additions - -- this section will be filled in shortly - -### Plugin and library moves - -- this section will be filled in shortly - -### Plugin removals - -- this section will be filled in shortly +_Last updated: Saturday 03 March 2018, 16:30 UTC (log)_ -## Miscellaneous API additions +Introduction -- this section will be filled in shortly +The GStreamer team is proud to announce a new major feature release in +the stable 1.x API series of your favourite cross-platform multimedia +framework! -### GstPlayer +As always, this release is again packed with new features, bug fixes and +other improvements. -- this section will be filled in shortly -## Miscellaneous changes +Highlights -- this section will be filled in shortly +- this section will be completed shortly -### OpenGL integration -- this section will be filled in shortly +Major new features and changes -## Tracing framework and debugging improvements +Noteworthy new API -- this section will be filled in shortly +- this section will be filled in shortly -## Tools +New Elements -- this section will be filled in shortly +- this section will be filled in shortly -## GStreamer RTSP server +New element features and additions -- this section will be filled in shortly +- this section will be filled in shortly -## GStreamer VAAPI +Plugin and library moves -- this section will be filled in shortly +- this section will be filled in shortly -## GStreamer Editing Services and NLE +Plugin removals -- this section will be filled in shortly +- this section will be filled in shortly -## GStreamer validate -- this section will be filled in shortly +Miscellaneous API additions -## GStreamer Python Bindings +- this section will be filled in shortly -- this section will be filled in shortly +GstPlayer -## Build and Dependencies +- this section will be filled in shortly -- this section will be filled in shortly -## Platform-specific improvements +Miscellaneous changes -### Android +- this section will be filled in shortly -- this section will be filled in shortly +OpenGL integration -### macOS and iOS +- this section will be filled in shortly -- this section will be filled in shortly -### Windows +Tracing framework and debugging improvements -- this section will be filled in shortly +- this section will be filled in shortly -## Contributors -- this section will be filled in shortly +Tools + +- this section will be filled in shortly + + +GStreamer RTSP server + +- this section will be filled in shortly + + +GStreamer VAAPI + +- this section will be filled in shortly + + +GStreamer Editing Services and NLE + +- this section will be filled in shortly + + +GStreamer validate + +- this section will be filled in shortly + + +GStreamer Python Bindings + +- this section will be filled in shortly + + +Build and Dependencies + +- this section will be filled in shortly + + +Platform-specific improvements + +Android + +- this section will be filled in shortly + +macOS and iOS + +- this section will be filled in shortly + +Windows + +- this section will be filled in shortly + + +Contributors + +Aaron Boxer, Adrián Pardini, Adrien SCH, Akinobu Mita, Alban Bedel, +Alessandro Decina, Alex Ashley, Alicia Boya García, Alistair Buxton, +Alvaro Margulis, Anders Jonsson, Andreas Frisch, Andrejs Vasiljevs, +Andrew Bott, Antoine Jacoutot, Antonio Ospite, Antoni Silvestre, Anton +Obzhirov, Anuj Jaiswal, Arjen Veenhuizen, Arnaud Bonatti, Arun Raghavan, +Ashish Kumar, Aurélien Zanelli, Ayaka, Branislav Katreniak, Branko +Subasic, Brion Vibber, Carlos Rafael Giani, Cassandra Rommel, Chris +Bass, Chris Paulson-Ellis, Christoph Reiter, Claudio Saavedra, Clemens +Lang, Cyril Lashkevich, Daniel van Vugt, Dave Craig, Dave Johnstone, +David Evans, David Schleef, Deepak Srivastava, Dimitrios Katsaros, +Dmitry Zhadinets, Dongil Park, Dustin Spicuzza, Eduard Sinelnikov, +Edward Hervey, Enrico Jorns, Eunhae Choi, Ezequiel Garcia, fengalin, +Filippo Argiolas, Florent Thiéry, Florian Zwoch, Francisco Velazquez, +François Laignel, fvanzile, George Kiagiadakis, Georg Lippitsch, Graham +Leggett, Guillaume Desmottes, Gurkirpal Singh, Gwang Yoon Hwang, Gwenole +Beauchesne, Haakon Sporsheim, Haihua Hu, Håvard Graff, Heekyoung Seo, +Heinrich Fink, Holger Kaelberer, Hoonhee Lee, Hosang Lee, Hyunjun Ko, +Ian Jamison, James Stevenson, Jan Alexander Steffens (heftig), Jan +Schmidt, Jason Lin, Jens Georg, Jeremy Hiatt, Jérôme Laheurte, Jimmy +Ohn, Jochen Henneberg, John Ludwig, John Nikolaides, Jonathan Karlsson, +Josep Torra, Juan Navarro, Juan Pablo Ugarte, Julien Isorce, Jun Xie, +Jussi Kukkonen, Justin Kim, Lasse Laursen, Lubosz Sarnecki, Luc +Deschenaux, Luis de Bethencourt, Marcin Lewandowski, Mario Alfredo +Carrillo Arevalo, Mark Nauwelaerts, Martin Kelly, Matej Knopp, Mathieu +Duponchelle, Matteo Valdina, Matt Fischer, Matthew Waters, Matthieu +Bouron, Matthieu Crapet, Matt Staples, Michael Catanzaro, Michael +Olbrich, Michael Shigorin, Michael Tretter, Michał Dębski, Michał Górny, +Michele Dionisio, Miguel París, Mikhail Fludkov, Munez, Nael Ouedraogo, +Neos3452, Nicholas Panayis, Nick Kallen, Nicola Murino, Nicolas +Dechesne, Nicolas Dufresne, Nirbheek Chauhan, Ognyan Tonchev, Ole André +Vadla Ravnås, Oleksij Rempel, Olivier Crête, Omar Akkila, Orestis +Floros, Patricia Muscalu, Patrick Radizi, Paul Kim, Per-Erik Brodin, +Peter Seiderer, Philip Craig, Philippe Normand, Philippe Renon, Philipp +Zabel, Pierre Pouzol, Piotr Drąg, Ponnam Srinivas, Pratheesh Gangadhar, +Raimo Järvi, Ramprakash Jelari, Ravi Kiran K N, Reynaldo H. Verdejo +Pinochet, Rico Tzschichholz, Robert Rosengren, Roland Peffer, Руслан +Ижбулатов, Sam Hurst, Sam Thursfield, Sangkyu Park, Sanjay NM, Satya +Prakash Gupta, Scott D Phillips, Sean DuBois, Sebastian Cote, Sebastian +Dröge, Sebastian Rasmussen, Sejun Park, Sergey Borovkov, Seungha Yang, +Shakin Chou, Shinya Saito, Simon Himmelbauer, Sky Juan, Song Bing, +Sreerenj Balachandran, Stefan Kost, Stefan Popa, Stefan Sauer, Stian +Selnes, Thiago Santos, Thibault Saunier, Thijs Vermeir, Tim Allen, +Tim-Philipp Müller, Ting-Wei Lan, Tomas Rataj, Tom Bailey, Tonu Jaansoo, +U. Artie Eoff, Umang Jain, Ursula Maplehurst, VaL Doroshchuk, Vasilis +Liaskovitis, Víctor Manuel Jáquez Leal, vijay, Vincent Penquerc'h, +Vineeth T M, Vivia Nikolaidou, Wang Xin-yu (王昕宇), Wei Feng, Wim +Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier Claessens, +XuGuangxin, Yasushi SHOJI, Yi A Wang, Youness Alaoui, ... and many others who have contributed bug reports, translations, sent suggestions or helped testing. -## Bugs fixed in 1.14 -- this section will be filled in shortly +Bugs fixed in 1.14 -More than [704 bugs][bugs-fixed-in-1.14] have been fixed during -the development of 1.14. +- this section will be filled in shortly + +More than 704 bugs have been fixed during the development of 1.14. This list does not include issues that have been cherry-picked into the -stable 1.12 branch and fixed there as well, all fixes that ended up in the -1.12 branch are also included in 1.14. +stable 1.12 branch and fixed there as well, all fixes that ended up in +the 1.12 branch are also included in 1.14. -This list also does not include issues that have been fixed without a bug -report in bugzilla, so the actual number of fixes is much higher. +This list also does not include issues that have been fixed without a +bug report in bugzilla, so the actual number of fixes is much higher. -[bugs-fixed-in-1.14]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=213265&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.12.1&target_milestone=1.12.2&target_milestone=1.12.3&target_milestone=1.12.4&target_milestone=1.13.1&target_milestone=1.13.2&target_milestone=1.13.3&target_milestone=1.13.4&target_milestone=1.13.90&target_milestone=1.13.91&target_milestone=1.14.0 -## Stable 1.14 branch +Stable 1.14 branch -After the 1.14.0 release there will be several 1.14.x bug-fix releases which -will contain bug fixes which have been deemed suitable for a stable branch, -but no new features or intrusive changes will be added to a bug-fix release -usually. The 1.14.x bug-fix releases will be made from the git 1.14 branch, -which is a stable branch. +After the 1.14.0 release there will be several 1.14.x bug-fix releases +which will contain bug fixes which have been deemed suitable for a +stable branch, but no new features or intrusive changes will be added to +a bug-fix release usually. The 1.14.x bug-fix releases will be made from +the git 1.14 branch, which is a stable branch. -### 1.14.0 +1.14.0 -1.14.0 is scheduled to be released in late February / early March 2018. +1.14.0 is scheduled to be released in early March 2018. -## Known Issues -- The `webrtcdsp` element is currently not shipped as part of the Windows - binary packages due to a [build system issue][bug-770264]. +Known Issues -[bug-770264]: https://bugzilla.gnome.org/show_bug.cgi?id=770264 +- The webrtcdsp element is currently not shipped as part of the + Windows binary packages due to a build system issue. -## Schedule for 1.16 -Our next major feature release will be 1.16, and 1.15 will be the unstable -development version leading up to the stable 1.16 release. The development -of 1.15/1.16 will happen in the git master branch. +Schedule for 1.16 -The plan for the 1.16 development cycle is yet to be confirmed, but it is -expected that feature freeze will be around August 2017 -followed by several 1.15 pre-releases and the new 1.16 stable release -in September. +Our next major feature release will be 1.16, and 1.15 will be the +unstable development version leading up to the stable 1.16 release. The +development of 1.15/1.16 will happen in the git master branch. -1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, -1.2 and 1.0 release series. +The plan for the 1.16 development cycle is yet to be confirmed, but it +is expected that feature freeze will be around August 2017 followed by +several 1.15 pre-releases and the new 1.16 stable release in September. -- - - +1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, +1.6, 1.4, 1.2 and 1.0 release series. -*These release notes have been prepared by Tim-Philipp Müller.* +------------------------------------------------------------------------ -*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* +_These release notes have been prepared by Tim-Philipp Müller._ + +_License: CC BY-SA 4.0_ diff --git a/RELEASE b/RELEASE index df6a5ccac1..f253d44f14 100644 --- a/RELEASE +++ b/RELEASE @@ -1,26 +1,63 @@ +This is GStreamer gst-rtsp-server 1.13.90. -Release notes for GStreamer RTSP Server Library 1.12.0 +The GStreamer team is pleased to announce the first release candidate for the +upcoming stable 1.14 release series. -The GStreamer team is pleased to announce the first release in the stable 1.12 -release series. The 1.12 release series is adding new features on top of the -1.0, 1.2, 1.4, 1.6, 1.8 and 1.10 series and is part of the API and ABI-stable -1.x release series of the GStreamer multimedia framework. +The 1.14 release series adds new features on top of the 1.0, 1.2, 1.4, 1.6, +1.8, 1.10 and 1.12 series and is part of the API and ABI-stable 1.x release +series of the GStreamer multimedia framework. +Full release notes can be found at: -Full release notes can be found here + https://gstreamer.freedesktop.org/releases/1.14/ +Binaries for Android, iOS, Mac OS X and Windows will be provided shortly +after the release. -Binaries for Android, iOS, Mac OS X and Windows will be provided in the next days. +This module will not be very useful by itself and should be used in conjunction +with other GStreamer modules for a complete multimedia experience. - + - gstreamer: provides the core GStreamer libraries and some generic plugins + + - gst-plugins-base: a basic set of well-supported plugins and additional + media-specific GStreamer helper libraries for audio, + video, rtsp, rtp, tags, OpenGL, etc. + + - gst-plugins-good: a set of well-supported plugins under our preferred + license + + - gst-plugins-ugly: a set of well-supported plugins which might pose + problems for distributors + + - gst-plugins-bad: a set of plugins of varying quality that have not made + their way into one of core/base/good/ugly yet, for one + reason or another. Many of these are are production quality + elements, but may still be missing documentation or unit + tests; others haven't passed the rigorous quality testing + we expect yet. + + - gst-libav: a set of codecs plugins based on the ffmpeg library. This is + where you can find audio and video decoders and encoders + for a wide variety of formats including H.264, AAC, etc. + + - gstreamer-vaapi: hardware-accelerated video decoding and encoding using + VA-API on Linux. Primarily for Intel graphics hardware. + + - gst-omx: hardware-accelerated video decoding and encoding, primarily for + embedded Linux systems that provide an OpenMax + implementation layer such as the Raspberry Pi. + + - gst-rtsp-server: library to serve files or streaming pipelines via RTSP + + - gst-editing-services: library an plugins for non-linear editing ==== Download ==== -You can find source releases of gst-rtsp-server in the download -directory: https://gstreamer.freedesktop.org/src/gst-rtsp-server/ +You can find source releases of gstreamer in the download +directory: https://gstreamer.freedesktop.org/src/gstreamer/ The git repository and details how to clone it can be found at -http://cgit.freedesktop.org/gstreamer/gst-rtsp-server/ +http://cgit.freedesktop.org/gstreamer/gstreamer/ ==== Homepage ==== @@ -45,11 +82,3 @@ from there (see link above). Interested developers of the core library, plugins, and applications should subscribe to the gstreamer-devel list. - - -Contributors to this release - - * Sebastian Dröge - * Thibault Saunier - * Tim-Philipp Müller -  \ No newline at end of file diff --git a/configure.ac b/configure.ac index 51dd766f20..0fc1f01e91 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.13.1.1], +AC_INIT([GStreamer RTSP Server Library], [1.13.90], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1301, 0, 1301) +AS_LIBTOOL(GST, 1390, 0, 1390) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.13.1.1 -GSTPB_REQ=1.13.1.1 -GSTPG_REQ=1.13.1.1 -GSTPD_REQ=1.13.1.1 +GST_REQ=1.13.90 +GSTPB_REQ=1.13.90 +GSTPG_REQ=1.13.90 +GSTPD_REQ=1.13.90 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 170d9c2b77..efb94e6ccb 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -28,7 +28,17 @@ RTSP server library based on GStreamer - + + + + + 1.13.90 + master + + 2018-03-03 + + + diff --git a/meson.build b/meson.build index 30affba283..200c7a8871 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.13.1.1', + version : '1.13.90', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From e5527e4403ca096f9c671b626d520b14808ea165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 7 Mar 2018 12:20:05 +0200 Subject: [PATCH 1473/1776] rtsp-onvif-media-factory: Document that backchannel pipelines must end with async=false sinks https://bugzilla.gnome.org/show_bug.cgi?id=794143 --- gst/rtsp-server/rtsp-onvif-media-factory.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.c b/gst/rtsp-server/rtsp-onvif-media-factory.c index f24260896b..7da567091c 100644 --- a/gst/rtsp-server/rtsp-onvif-media-factory.c +++ b/gst/rtsp-server/rtsp-onvif-media-factory.c @@ -375,6 +375,11 @@ gst_rtsp_onvif_media_factory_init (GstRTSPOnvifMediaFactory * factory) * all possible, complete RTP caps that are going to be supported. At least * the payload type, clock-rate and encoding-name need to be specified. * + * Note: The pipeline part passed here must end in sinks that are not waiting + * until pre-rolling before reaching the PAUSED state, i.e. setting + * async=false on #GstBaseSink. Otherwise the whole media will not be able to + * prepare. + * * Since: 1.14 */ void From 2df75442d0c3296e2b67b1d7aef5a89c95c30c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 13 Mar 2018 13:30:41 +0000 Subject: [PATCH 1474/1776] rtsp-server: GST_EXPORT -> GST_RTSP_SERVER_API We need different export decorators for the different libs. For now no actual change though, just rename before the release, and add prelude headers to define the new decorator to GST_EXPORT. --- gst/rtsp-server/Makefile.am | 1 + gst/rtsp-server/meson.build | 1 + gst/rtsp-server/rtsp-address-pool.h | 27 ++-- gst/rtsp-server/rtsp-auth.h | 37 +++--- gst/rtsp-server/rtsp-client.h | 37 +++--- gst/rtsp-server/rtsp-context.h | 9 +- gst/rtsp-server/rtsp-media-factory-uri.h | 8 +- gst/rtsp-server/rtsp-media-factory.h | 80 ++++++------ gst/rtsp-server/rtsp-media.h | 126 ++++++++++--------- gst/rtsp-server/rtsp-mount-points.h | 12 +- gst/rtsp-server/rtsp-onvif-client.h | 2 +- gst/rtsp-server/rtsp-onvif-media-factory.h | 14 +-- gst/rtsp-server/rtsp-onvif-media.h | 8 +- gst/rtsp-server/rtsp-onvif-server.h | 4 +- gst/rtsp-server/rtsp-params.h | 4 +- gst/rtsp-server/rtsp-permissions.h | 22 ++-- gst/rtsp-server/rtsp-sdp.h | 6 +- gst/rtsp-server/rtsp-server-prelude.h | 31 +++++ gst/rtsp-server/rtsp-server.h | 55 ++++---- gst/rtsp-server/rtsp-session-media.h | 28 +++-- gst/rtsp-server/rtsp-session-pool.h | 24 ++-- gst/rtsp-server/rtsp-session.h | 30 ++--- gst/rtsp-server/rtsp-stream-transport.h | 36 +++--- gst/rtsp-server/rtsp-stream.h | 138 +++++++++++---------- gst/rtsp-server/rtsp-thread-pool.h | 20 +-- gst/rtsp-server/rtsp-token.h | 20 +-- 26 files changed, 415 insertions(+), 365 deletions(-) create mode 100644 gst/rtsp-server/rtsp-server-prelude.h diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 95b239f1a2..560b63d05a 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -18,6 +18,7 @@ public_headers = \ rtsp-token.h \ rtsp-client.h \ rtsp-server.h \ + rtsp-server-prelude.h \ rtsp-onvif-server.h \ rtsp-onvif-client.h \ rtsp-onvif-media-factory.h \ diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index 8e254efae9..c2d7b37036 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -40,6 +40,7 @@ rtsp_server_headers = [ 'rtsp-token.h', 'rtsp-client.h', 'rtsp-server.h', + 'rtsp-server-prelude.h', ] install_headers(rtsp_server_headers, subdir : 'gstreamer-1.0/gst/rtsp-server') diff --git a/gst/rtsp-server/rtsp-address-pool.h b/gst/rtsp-server/rtsp-address-pool.h index 45467be78c..997cfd1d77 100644 --- a/gst/rtsp-server/rtsp-address-pool.h +++ b/gst/rtsp-server/rtsp-address-pool.h @@ -17,11 +17,12 @@ * Boston, MA 02110-1301, USA. */ -#include - #ifndef __GST_RTSP_ADDRESS_POOL_H__ #define __GST_RTSP_ADDRESS_POOL_H__ +#include +#include "rtsp-server-prelude.h" + G_BEGIN_DECLS #define GST_TYPE_RTSP_ADDRESS_POOL (gst_rtsp_address_pool_get_type ()) @@ -82,13 +83,13 @@ struct _GstRTSPAddress { gpointer priv; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_address_get_type (void); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAddress * gst_rtsp_address_copy (GstRTSPAddress *addr); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_address_free (GstRTSPAddress *addr); /** @@ -153,21 +154,21 @@ struct _GstRTSPAddressPoolClass { gpointer _gst_reserved[GST_PADDING]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_address_pool_get_type (void); /* create a new address pool */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAddressPool * gst_rtsp_address_pool_new (void); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_address_pool_clear (GstRTSPAddressPool * pool); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_address_pool_dump (GstRTSPAddressPool * pool); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_address_pool_add_range (GstRTSPAddressPool * pool, const gchar *min_address, const gchar *max_address, @@ -175,12 +176,12 @@ gboolean gst_rtsp_address_pool_add_range (GstRTSPAddressPool guint16 max_port, guint8 ttl); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool, GstRTSPAddressFlags flags, gint n_ports); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAddressPoolResult gst_rtsp_address_pool_reserve_address (GstRTSPAddressPool * pool, const gchar *ip_address, guint port, @@ -188,7 +189,7 @@ GstRTSPAddressPoolResult gst_rtsp_address_pool_reserve_address (GstRTSPAddressP guint ttl, GstRTSPAddress ** address); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_address_pool_has_unicast_addresses (GstRTSPAddressPool * pool); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index fb243ac81e..3bfe63df93 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -26,6 +26,7 @@ typedef struct _GstRTSPAuth GstRTSPAuth; typedef struct _GstRTSPAuthClass GstRTSPAuthClass; typedef struct _GstRTSPAuthPrivate GstRTSPAuthPrivate; +#include "rtsp-server-prelude.h" #include "rtsp-client.h" #include "rtsp-token.h" @@ -81,63 +82,63 @@ struct _GstRTSPAuthClass { gpointer _gst_reserved[GST_PADDING - 1]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_auth_get_type (void); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAuth * gst_rtsp_auth_new (void); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_auth_set_tls_certificate (GstRTSPAuth *auth, GTlsCertificate *cert); -GST_EXPORT +GST_RTSP_SERVER_API GTlsCertificate * gst_rtsp_auth_get_tls_certificate (GstRTSPAuth *auth); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_auth_set_tls_database (GstRTSPAuth *auth, GTlsDatabase *database); -GST_EXPORT +GST_RTSP_SERVER_API GTlsDatabase * gst_rtsp_auth_get_tls_database (GstRTSPAuth *auth); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_auth_set_tls_authentication_mode (GstRTSPAuth *auth, GTlsAuthenticationMode mode); -GST_EXPORT +GST_RTSP_SERVER_API GTlsAuthenticationMode gst_rtsp_auth_get_tls_authentication_mode (GstRTSPAuth *auth); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_auth_set_default_token (GstRTSPAuth *auth, GstRTSPToken *token); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPToken * gst_rtsp_auth_get_default_token (GstRTSPAuth *auth); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_auth_add_basic (GstRTSPAuth *auth, const gchar * basic, GstRTSPToken *token); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_auth_remove_basic (GstRTSPAuth *auth, const gchar * basic); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_auth_add_digest (GstRTSPAuth *auth, const gchar *user, const gchar *pass, GstRTSPToken *token); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_auth_remove_digest (GstRTSPAuth *auth, const gchar *user); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_auth_set_supported_methods (GstRTSPAuth *auth, GstRTSPAuthMethod methods); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAuthMethod gst_rtsp_auth_get_supported_methods (GstRTSPAuth *auth); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_auth_check (const gchar *check); /* helpers */ -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass); /* checks */ diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index edfce11509..01846bc249 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -29,6 +29,7 @@ typedef struct _GstRTSPClient GstRTSPClient; typedef struct _GstRTSPClientClass GstRTSPClientClass; typedef struct _GstRTSPClientPrivate GstRTSPClientPrivate; +#include "rtsp-server-prelude.h" #include "rtsp-context.h" #include "rtsp-mount-points.h" #include "rtsp-sdp.h" @@ -143,62 +144,62 @@ struct _GstRTSPClientClass { gpointer _gst_reserved[GST_PADDING_LARGE-16]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_client_get_type (void); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPClient * gst_rtsp_client_new (void); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_client_set_mount_points (GstRTSPClient *client, GstRTSPMountPoints *mounts); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPMountPoints * gst_rtsp_client_get_mount_points (GstRTSPClient *client); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_client_set_thread_pool (GstRTSPClient *client, GstRTSPThreadPool *pool); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPThreadPool * gst_rtsp_client_get_thread_pool (GstRTSPClient *client); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_client_set_connection (GstRTSPClient *client, GstRTSPConnection *conn); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPConnection * gst_rtsp_client_get_connection (GstRTSPClient *client); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_client_attach (GstRTSPClient *client, GMainContext *context); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_client_close (GstRTSPClient * client); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_client_set_send_func (GstRTSPClient *client, GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPResult gst_rtsp_client_handle_message (GstRTSPClient *client, GstRTSPMessage *message); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPResult gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession *session, GstRTSPMessage *message); @@ -226,7 +227,7 @@ typedef GstRTSPFilterResult (*GstRTSPClientSessionFilterFunc) (GstRTSPClient *c GstRTSPSession *sess, gpointer user_data); -GST_EXPORT +GST_RTSP_SERVER_API GList * gst_rtsp_client_session_filter (GstRTSPClient *client, GstRTSPClientSessionFilterFunc func, gpointer user_data); diff --git a/gst/rtsp-server/rtsp-context.h b/gst/rtsp-server/rtsp-context.h index 32d1ac0b6b..dcd2f9b85e 100644 --- a/gst/rtsp-server/rtsp-context.h +++ b/gst/rtsp-server/rtsp-context.h @@ -29,6 +29,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPContext GstRTSPContext; +#include "rtsp-server-prelude.h" #include "rtsp-server.h" #include "rtsp-media.h" #include "rtsp-media-factory.h" @@ -78,16 +79,16 @@ struct _GstRTSPContext { gpointer _gst_reserved[GST_PADDING - 1]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_context_get_type (void); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPContext * gst_rtsp_context_get_current (void); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_context_push_current (GstRTSPContext * ctx); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_context_pop_current (GstRTSPContext * ctx); diff --git a/gst/rtsp-server/rtsp-media-factory-uri.h b/gst/rtsp-server/rtsp-media-factory-uri.h index f3d4a9e1d8..cd0e9d53db 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.h +++ b/gst/rtsp-server/rtsp-media-factory-uri.h @@ -65,21 +65,21 @@ struct _GstRTSPMediaFactoryURIClass { gpointer _gst_reserved[GST_PADDING]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_media_factory_uri_get_type (void); /* creating the factory */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPMediaFactoryURI * gst_rtsp_media_factory_uri_new (void); /* configuring the factory */ -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_uri_set_uri (GstRTSPMediaFactoryURI *factory, const gchar *uri); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_media_factory_uri_get_uri (GstRTSPMediaFactoryURI *factory); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index c76a2408d6..350dae8919 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -97,148 +97,148 @@ struct _GstRTSPMediaFactoryClass { gpointer _gst_reserved[GST_PADDING_LARGE]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_media_factory_get_type (void); /* creating the factory */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPMediaFactory * gst_rtsp_media_factory_new (void); /* configuring the factory */ -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, const gchar *launch); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_permissions (GstRTSPMediaFactory *factory, GstRTSPPermissions *permissions); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPPermissions * gst_rtsp_media_factory_get_permissions (GstRTSPMediaFactory *factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_add_role (GstRTSPMediaFactory *factory, const gchar *role, const gchar *fieldname, ...); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_add_role_from_structure (GstRTSPMediaFactory * factory, GstStructure *structure); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory, gboolean shared); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_stop_on_disconnect (GstRTSPMediaFactory *factory, gboolean stop_on_disconnect); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_factory_is_stop_on_disonnect (GstRTSPMediaFactory *factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_suspend_mode (GstRTSPMediaFactory *factory, GstRTSPSuspendMode mode); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPSuspendMode gst_rtsp_media_factory_get_suspend_mode (GstRTSPMediaFactory *factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory *factory, gboolean eos_shutdown); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_profiles (GstRTSPMediaFactory *factory, GstRTSPProfile profiles); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPProfile gst_rtsp_media_factory_get_profiles (GstRTSPMediaFactory *factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory *factory, GstRTSPLowerTrans protocols); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPLowerTrans gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory *factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFactory * factory, GstRTSPAddressPool * pool); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAddressPool * gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_multicast_iface (GstRTSPMediaFactory *factory, const gchar *multicast_iface); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_media_factory_get_multicast_iface (GstRTSPMediaFactory *factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint size); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_retransmission_time (GstRTSPMediaFactory * factory, GstClockTime time); -GST_EXPORT +GST_RTSP_SERVER_API GstClockTime gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_latency (GstRTSPMediaFactory * factory, guint latency); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_media_factory_get_latency (GstRTSPMediaFactory * factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_transport_mode (GstRTSPMediaFactory *factory, GstRTSPTransportMode mode); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPTransportMode gst_rtsp_media_factory_get_transport_mode (GstRTSPMediaFactory *factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_media_gtype (GstRTSPMediaFactory * factory, GType media_gtype); -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_media_factory_get_media_gtype (GstRTSPMediaFactory * factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_clock (GstRTSPMediaFactory *factory, GstClock * clock); -GST_EXPORT +GST_RTSP_SERVER_API GstClock * gst_rtsp_media_factory_get_clock (GstRTSPMediaFactory *factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_publish_clock_mode (GstRTSPMediaFactory * factory, GstRTSPPublishClockMode mode); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPPublishClockMode gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory); /* creating the media from the factory and a url */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); -GST_EXPORT +GST_RTSP_SERVER_API GstElement * gst_rtsp_media_factory_create_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index ae332ff0dc..4d47517549 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -24,6 +24,8 @@ #ifndef __GST_RTSP_MEDIA_H__ #define __GST_RTSP_MEDIA_H__ +#include "rtsp-server-prelude.h" + G_BEGIN_DECLS /* types for the media */ @@ -103,15 +105,15 @@ typedef enum { } GstRTSPPublishClockMode; #define GST_TYPE_RTSP_TRANSPORT_MODE (gst_rtsp_transport_mode_get_type()) -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_transport_mode_get_type (void); #define GST_TYPE_RTSP_SUSPEND_MODE (gst_rtsp_suspend_mode_get_type()) -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_suspend_mode_get_type (void); #define GST_TYPE_RTSP_PUBLISH_CLOCK_MODE (gst_rtsp_publish_clock_mode_get_type()) -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_publish_clock_mode_get_type (void); #include "rtsp-stream.h" @@ -189,201 +191,201 @@ struct _GstRTSPMediaClass { gpointer _gst_reserved[GST_PADDING_LARGE-1]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_media_get_type (void); /* creating the media */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPMedia * gst_rtsp_media_new (GstElement *element); -GST_EXPORT +GST_RTSP_SERVER_API GstElement * gst_rtsp_media_get_element (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_take_pipeline (GstRTSPMedia *media, GstPipeline *pipeline); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPMediaStatus gst_rtsp_media_get_status (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_permissions (GstRTSPMedia *media, GstRTSPPermissions *permissions); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPPermissions * gst_rtsp_media_get_permissions (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_stop_on_disconnect (GstRTSPMedia *media, gboolean stop_on_disconnect); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_is_stop_on_disconnect (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_transport_mode (GstRTSPMedia *media, GstRTSPTransportMode mode); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPTransportMode gst_rtsp_media_get_transport_mode (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_reusable (GstRTSPMedia *media, gboolean reusable); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_is_reusable (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_profiles (GstRTSPMedia *media, GstRTSPProfile profiles); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPProfile gst_rtsp_media_get_profiles (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_protocols (GstRTSPMedia *media, GstRTSPLowerTrans protocols); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_address_pool (GstRTSPMedia *media, GstRTSPAddressPool *pool); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAddressPool * gst_rtsp_media_get_address_pool (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_multicast_iface (GstRTSPMedia *media, const gchar *multicast_iface); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_media_get_multicast_iface (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_retransmission_time (GstRTSPMedia *media, GstClockTime time); -GST_EXPORT +GST_RTSP_SERVER_API GstClockTime gst_rtsp_media_get_retransmission_time (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_latency (GstRTSPMedia *media, guint latency); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_media_get_latency (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_use_time_provider (GstRTSPMedia *media, gboolean time_provider); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_is_time_provider (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media, const gchar *address, guint16 port); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_clock (GstRTSPMedia *media, GstClock * clock); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_publish_clock_mode (GstRTSPMedia * media, GstRTSPPublishClockMode mode); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPPublishClockMode gst_rtsp_media_get_publish_clock_mode (GstRTSPMedia * media); /* prepare the media for playback */ -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_prepare (GstRTSPMedia *media, GstRTSPThread *thread); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_unprepare (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_suspend_mode (GstRTSPMedia *media, GstRTSPSuspendMode mode); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPSuspendMode gst_rtsp_media_get_suspend_mode (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_suspend (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_unsuspend (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, GstSDPInfo * info); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp); /* creating streams */ -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_collect_streams (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia *media, GstElement *payloader, GstPad *pad); /* dealing with the media */ -GST_EXPORT +GST_RTSP_SERVER_API GstClock * gst_rtsp_media_get_clock (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API GstClockTime gst_rtsp_media_get_base_time (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_media_n_streams (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPStream * gst_rtsp_media_find_stream (GstRTSPMedia *media, const gchar * control); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_seek_full (GstRTSPMedia *media, GstRTSPTimeRange *range, GstSeekFlags flags); -GST_EXPORT +GST_RTSP_SERVER_API GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, gboolean play, GstRTSPRangeUnit unit); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GPtrArray *transports); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GstState state); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GPtrArray * transports); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC diff --git a/gst/rtsp-server/rtsp-mount-points.h b/gst/rtsp-server/rtsp-mount-points.h index 9630beed71..200620dcdd 100644 --- a/gst/rtsp-server/rtsp-mount-points.h +++ b/gst/rtsp-server/rtsp-mount-points.h @@ -68,31 +68,31 @@ struct _GstRTSPMountPointsClass { gpointer _gst_reserved[GST_PADDING]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_mount_points_get_type (void); /* creating a mount points */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPMountPoints * gst_rtsp_mount_points_new (void); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_mount_points_make_path (GstRTSPMountPoints *mounts, const GstRTSPUrl * url); /* finding a media factory */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPMediaFactory * gst_rtsp_mount_points_match (GstRTSPMountPoints *mounts, const gchar *path, gint * matched); /* managing media to a mount point */ -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_mount_points_add_factory (GstRTSPMountPoints *mounts, const gchar *path, GstRTSPMediaFactory *factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints *mounts, const gchar *path); diff --git a/gst/rtsp-server/rtsp-onvif-client.h b/gst/rtsp-server/rtsp-onvif-client.h index 0dc4e98da1..5514209922 100644 --- a/gst/rtsp-server/rtsp-onvif-client.h +++ b/gst/rtsp-server/rtsp-onvif-client.h @@ -51,7 +51,7 @@ struct GstRTSPOnvifClient gpointer _gst_reserved[GST_PADDING]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_onvif_client_get_type (void); #endif /* __GST_RTSP_ONVIF_CLIENT_H__ */ diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.h b/gst/rtsp-server/rtsp-onvif-media-factory.h index 09e9d4bde9..0827039c4e 100644 --- a/gst/rtsp-server/rtsp-onvif-media-factory.h +++ b/gst/rtsp-server/rtsp-onvif-media-factory.h @@ -54,24 +54,24 @@ struct GstRTSPOnvifMediaFactory gpointer _gst_reserved[GST_PADDING]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_onvif_media_factory_get_type (void); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPMediaFactory *gst_rtsp_onvif_media_factory_new (void); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_onvif_media_factory_set_backchannel_launch (GstRTSPOnvifMediaFactory * factory, const gchar * launch); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_onvif_media_factory_get_backchannel_launch (GstRTSPOnvifMediaFactory * factory); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_onvif_media_factory_has_backchannel_support (GstRTSPOnvifMediaFactory * factory); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_onvif_media_factory_set_backchannel_bandwidth (GstRTSPOnvifMediaFactory * factory, guint bandwidth); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_onvif_media_factory_get_backchannel_bandwidth (GstRTSPOnvifMediaFactory * factory); gboolean gst_rtsp_onvif_media_factory_requires_backchannel (GstRTSPMediaFactory * factory, GstRTSPContext * ctx); diff --git a/gst/rtsp-server/rtsp-onvif-media.h b/gst/rtsp-server/rtsp-onvif-media.h index a45c11ed94..3997c3ea06 100644 --- a/gst/rtsp-server/rtsp-onvif-media.h +++ b/gst/rtsp-server/rtsp-onvif-media.h @@ -53,14 +53,14 @@ struct GstRTSPOnvifMedia gpointer _gst_reserved[GST_PADDING]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_onvif_media_get_type (void); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_onvif_media_collect_backchannel (GstRTSPOnvifMedia * media); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_onvif_media_set_backchannel_bandwidth (GstRTSPOnvifMedia * media, guint bandwidth); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_onvif_media_get_backchannel_bandwidth (GstRTSPOnvifMedia * media); #endif /* __GST_RTSP_ONVIF_MEDIA_H__ */ diff --git a/gst/rtsp-server/rtsp-onvif-server.h b/gst/rtsp-server/rtsp-onvif-server.h index 56bd9dce59..f9d8e4899f 100644 --- a/gst/rtsp-server/rtsp-onvif-server.h +++ b/gst/rtsp-server/rtsp-onvif-server.h @@ -51,9 +51,9 @@ struct GstRTSPOnvifServer gpointer _gst_reserved[GST_PADDING]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_onvif_server_get_type (void); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPServer *gst_rtsp_onvif_server_new (void); #define GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT "www.onvif.org/ver20/backchannel" diff --git a/gst/rtsp-server/rtsp-params.h b/gst/rtsp-server/rtsp-params.h index 4b5c734a48..f2863169d4 100644 --- a/gst/rtsp-server/rtsp-params.h +++ b/gst/rtsp-server/rtsp-params.h @@ -30,10 +30,10 @@ G_BEGIN_DECLS -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPContext * ctx); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPContext * ctx); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-permissions.h b/gst/rtsp-server/rtsp-permissions.h index 792e3974ee..fac55e400d 100644 --- a/gst/rtsp-server/rtsp-permissions.h +++ b/gst/rtsp-server/rtsp-permissions.h @@ -22,11 +22,13 @@ #ifndef __GST_RTSP_PERMISSIONS_H__ #define __GST_RTSP_PERMISSIONS_H__ +#include "rtsp-server-prelude.h" + typedef struct _GstRTSPPermissions GstRTSPPermissions; G_BEGIN_DECLS -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_permissions_get_type (void); #define GST_TYPE_RTSP_PERMISSIONS (gst_rtsp_permissions_get_type ()) @@ -72,42 +74,42 @@ gst_rtsp_permissions_unref (GstRTSPPermissions * permissions) } -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPPermissions * gst_rtsp_permissions_new (void); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_permissions_add_role (GstRTSPPermissions *permissions, const gchar *role, const gchar *fieldname, ...); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_permissions_add_role_valist (GstRTSPPermissions *permissions, const gchar *role, const gchar *fieldname, va_list var_args); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_permissions_add_role_empty (GstRTSPPermissions * permissions, const gchar * role); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_permissions_add_role_from_structure (GstRTSPPermissions * permissions, GstStructure *structure); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_permissions_add_permission_for_role (GstRTSPPermissions * permissions, const gchar * role, const gchar * permission, gboolean allowed); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_permissions_remove_role (GstRTSPPermissions *permissions, const gchar *role); -GST_EXPORT +GST_RTSP_SERVER_API const GstStructure * gst_rtsp_permissions_get_role (GstRTSPPermissions *permissions, const gchar *role); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_permissions_is_allowed (GstRTSPPermissions *permissions, const gchar *role, const gchar *permission); diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h index 8683e32c3d..20d2ac8c6b 100644 --- a/gst/rtsp-server/rtsp-sdp.h +++ b/gst/rtsp-server/rtsp-sdp.h @@ -34,13 +34,13 @@ typedef struct { /* creating SDP */ -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_sdp_from_media (GstSDPMessage *sdp, GstSDPInfo *info, GstRTSPMedia * media); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_sdp_from_stream (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream * stream, GstCaps * caps, GstRTSPProfile profile); diff --git a/gst/rtsp-server/rtsp-server-prelude.h b/gst/rtsp-server/rtsp-server-prelude.h new file mode 100644 index 0000000000..4f0dca8d36 --- /dev/null +++ b/gst/rtsp-server/rtsp-server-prelude.h @@ -0,0 +1,31 @@ +/* GStreamer RtspServer Library + * Copyright (C) 2018 GStreamer developers + * + * rtspserver-prelude.h: prelude include header for gst-rtspserver library + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_RTSP_SERVER_PRELUDE_H__ +#define __GST_RTSP_SERVER_PRELUDE_H__ + +#include + +#ifndef GST_RTSP_SERVER_API +#define GST_RTSP_SERVER_API GST_EXPORT +#endif + +#endif /* __GST_RTSP_SERVER_PRELUDE_H__ */ diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 0208d29032..7364864875 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -26,17 +26,18 @@ G_BEGIN_DECLS /* Do *not* use these defines outside of rtsp-server. Use G_DEPRECATED instead. */ #ifdef GST_DISABLE_DEPRECATED -#define GST_RTSP_SERVER_DEPRECATED GST_EXPORT -#define GST_RTSP_SERVER_DEPRECATED_FOR(f) GST_EXPORT +#define GST_RTSP_SERVER_DEPRECATED GST_RTSP_SERVER_API +#define GST_RTSP_SERVER_DEPRECATED_FOR(f) GST_RTSP_SERVER_API #else -#define GST_RTSP_SERVER_DEPRECATED G_DEPRECATED GST_EXPORT -#define GST_RTSP_SERVER_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) GST_EXPORT +#define GST_RTSP_SERVER_DEPRECATED G_DEPRECATED GST_RTSP_SERVER_API +#define GST_RTSP_SERVER_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) GST_RTSP_SERVER_API #endif typedef struct _GstRTSPServer GstRTSPServer; typedef struct _GstRTSPServerClass GstRTSPServerClass; typedef struct _GstRTSPServerPrivate GstRTSPServerPrivate; +#include "rtsp-server-prelude.h" #include "rtsp-session-pool.h" #include "rtsp-session.h" #include "rtsp-media.h" @@ -102,77 +103,77 @@ struct _GstRTSPServerClass { gpointer _gst_reserved[GST_PADDING_LARGE]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_server_get_type (void); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPServer * gst_rtsp_server_new (void); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_server_set_address (GstRTSPServer *server, const gchar *address); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_server_get_address (GstRTSPServer *server); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_server_set_service (GstRTSPServer *server, const gchar *service); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_server_get_service (GstRTSPServer *server); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog); -GST_EXPORT +GST_RTSP_SERVER_API gint gst_rtsp_server_get_backlog (GstRTSPServer *server); -GST_EXPORT +GST_RTSP_SERVER_API int gst_rtsp_server_get_bound_port (GstRTSPServer *server); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *server); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_server_set_mount_points (GstRTSPServer *server, GstRTSPMountPoints *mounts); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPMountPoints * gst_rtsp_server_get_mount_points (GstRTSPServer *server); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_server_set_thread_pool (GstRTSPServer *server, GstRTSPThreadPool *pool); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPThreadPool * gst_rtsp_server_get_thread_pool (GstRTSPServer *server); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket *socket, const gchar * ip, gint port, const gchar *initial_buffer); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_server_io_func (GSocket *socket, GIOCondition condition, GstRTSPServer *server); -GST_EXPORT +GST_RTSP_SERVER_API GSocket * gst_rtsp_server_create_socket (GstRTSPServer *server, GCancellable *cancellable, GError **error); -GST_EXPORT +GST_RTSP_SERVER_API GSource * gst_rtsp_server_create_source (GstRTSPServer *server, GCancellable * cancellable, GError **error); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_server_attach (GstRTSPServer *server, GMainContext *context); @@ -200,7 +201,7 @@ typedef GstRTSPFilterResult (*GstRTSPServerClientFilterFunc) (GstRTSPServer *se GstRTSPClient *client, gpointer user_data); -GST_EXPORT +GST_RTSP_SERVER_API GList * gst_rtsp_server_client_filter (GstRTSPServer *server, GstRTSPServerClientFilterFunc func, gpointer user_data); diff --git a/gst/rtsp-server/rtsp-session-media.h b/gst/rtsp-server/rtsp-session-media.h index 2a6fe2aa22..a20946606d 100644 --- a/gst/rtsp-server/rtsp-session-media.h +++ b/gst/rtsp-server/rtsp-session-media.h @@ -24,6 +24,8 @@ #ifndef __GST_RTSP_SESSION_MEDIA_H__ #define __GST_RTSP_SESSION_MEDIA_H__ +#include "rtsp-server-prelude.h" + G_BEGIN_DECLS #define GST_TYPE_RTSP_SESSION_MEDIA (gst_rtsp_session_media_get_type ()) @@ -61,55 +63,55 @@ struct _GstRTSPSessionMediaClass gpointer _gst_reserved[GST_PADDING]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_session_media_get_type (void); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPSessionMedia * gst_rtsp_session_media_new (const gchar *path, GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_session_media_matches (GstRTSPSessionMedia *media, const gchar *path, gint * matched); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPMedia * gst_rtsp_session_media_get_media (GstRTSPSessionMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API GstClockTime gst_rtsp_session_media_get_base_time (GstRTSPSessionMedia *media); /* control media */ -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMedia *media, GstState state); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_session_media_set_rtsp_state (GstRTSPSessionMedia *media, GstRTSPState state); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPState gst_rtsp_session_media_get_rtsp_state (GstRTSPSessionMedia *media); /* get stream transport config */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia *media, GstRTSPStream *stream, GstRTSPTransport *tr); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia *media, guint idx); -GST_EXPORT +GST_RTSP_SERVER_API GPtrArray * gst_rtsp_session_media_get_transports (GstRTSPSessionMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia *media, GstRTSPRange *range); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC diff --git a/gst/rtsp-server/rtsp-session-pool.h b/gst/rtsp-server/rtsp-session-pool.h index 268000407e..aeb375c3cb 100644 --- a/gst/rtsp-server/rtsp-session-pool.h +++ b/gst/rtsp-server/rtsp-session-pool.h @@ -22,6 +22,8 @@ #ifndef __GST_RTSP_SESSION_POOL_H__ #define __GST_RTSP_SESSION_POOL_H__ +#include "rtsp-server-prelude.h" + G_BEGIN_DECLS typedef struct _GstRTSPSessionPool GstRTSPSessionPool; @@ -113,49 +115,49 @@ typedef GstRTSPFilterResult (*GstRTSPSessionPoolFilterFunc) (GstRTSPSessionPool gpointer user_data); -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_session_pool_get_type (void); /* creating a session pool */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPSessionPool * gst_rtsp_session_pool_new (void); /* counting sessions */ -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_session_pool_set_max_sessions (GstRTSPSessionPool *pool, guint max); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_session_pool_get_max_sessions (GstRTSPSessionPool *pool); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_session_pool_get_n_sessions (GstRTSPSessionPool *pool); /* managing sessions */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPSession * gst_rtsp_session_pool_create (GstRTSPSessionPool *pool); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPSession * gst_rtsp_session_pool_find (GstRTSPSessionPool *pool, const gchar *sessionid); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_session_pool_remove (GstRTSPSessionPool *pool, GstRTSPSession *sess); /* perform session maintenance */ -GST_EXPORT +GST_RTSP_SERVER_API GList * gst_rtsp_session_pool_filter (GstRTSPSessionPool *pool, GstRTSPSessionPoolFilterFunc func, gpointer user_data); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_session_pool_cleanup (GstRTSPSessionPool *pool); -GST_EXPORT +GST_RTSP_SERVER_API GSource * gst_rtsp_session_pool_create_watch (GstRTSPSessionPool *pool); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 229202da58..62d653a247 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -80,41 +80,41 @@ struct _GstRTSPSessionClass { gpointer _gst_reserved[GST_PADDING]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_session_get_type (void); /* create a new session */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPSession * gst_rtsp_session_new (const gchar *sessionid); -GST_EXPORT +GST_RTSP_SERVER_API const gchar * gst_rtsp_session_get_sessionid (GstRTSPSession *session); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_session_get_header (GstRTSPSession *session); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_session_set_timeout (GstRTSPSession *session, guint timeout); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_session_get_timeout (GstRTSPSession *session); /* session timeout stuff */ -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_session_touch (GstRTSPSession *session); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_session_prevent_expire (GstRTSPSession *session); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_session_allow_expire (GstRTSPSession *session); -GST_EXPORT +GST_RTSP_SERVER_API gint gst_rtsp_session_next_timeout_usec (GstRTSPSession *session, gint64 now); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_session_is_expired_usec (GstRTSPSession *session, gint64 now); GST_RTSP_SERVER_DEPRECATED_FOR(gst_rtsp_session_next_timeout_usec) @@ -125,17 +125,17 @@ gboolean gst_rtsp_session_is_expired (GstRTSPSession *se /* handle media in a session */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess, const gchar *path, GstRTSPMedia *media); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_session_release_media (GstRTSPSession *sess, GstRTSPSessionMedia *media); /* get media in a session */ -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess, const gchar *path, gint * matched); @@ -164,7 +164,7 @@ typedef GstRTSPFilterResult (*GstRTSPSessionFilterFunc) (GstRTSPSession *sess, GstRTSPSessionMedia *media, gpointer user_data); -GST_EXPORT +GST_RTSP_SERVER_API GList * gst_rtsp_session_filter (GstRTSPSession *sess, GstRTSPSessionFilterFunc func, gpointer user_data); diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 11a3395ef7..f608b8ae42 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -24,6 +24,8 @@ #ifndef __GST_RTSP_STREAM_TRANSPORT_H__ #define __GST_RTSP_STREAM_TRANSPORT_H__ +#include "rtsp-server-prelude.h" + G_BEGIN_DECLS /* types for the media */ @@ -84,73 +86,73 @@ struct _GstRTSPStreamTransportClass { gpointer _gst_reserved[GST_PADDING]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_stream_transport_get_type (void); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream, GstRTSPTransport *tr); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPStream * gst_rtsp_stream_transport_get_stream (GstRTSPStreamTransport *trans); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans, GstRTSPTransport * tr); -GST_EXPORT +GST_RTSP_SERVER_API const GstRTSPTransport * gst_rtsp_stream_transport_get_transport (GstRTSPStreamTransport *trans); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_transport_set_url (GstRTSPStreamTransport *trans, const GstRTSPUrl * url); -GST_EXPORT +GST_RTSP_SERVER_API const GstRTSPUrl * gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport *trans); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport *trans, GstClockTime start_time); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans, GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, gpointer user_data, GDestroyNotify notify); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport *trans, GstRTSPKeepAliveFunc keep_alive, gpointer user_data, GDestroyNotify notify); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport *trans); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_transport_set_active (GstRTSPStreamTransport *trans, gboolean active); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_transport_set_timed_out (GstRTSPStreamTransport *trans, gboolean timedout); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_transport_is_timed_out (GstRTSPStreamTransport *trans); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport *trans, GstBuffer *buffer); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport *trans, GstBuffer *buffer); -GST_EXPORT +GST_RTSP_SERVER_API GstFlowReturn gst_rtsp_stream_transport_recv_data (GstRTSPStreamTransport *trans, guint channel, GstBuffer *buffer); diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index dc248d18d3..f16c944621 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -24,6 +24,8 @@ #ifndef __GST_RTSP_STREAM_H__ #define __GST_RTSP_STREAM_H__ +#include "rtsp-server-prelude.h" + G_BEGIN_DECLS /* types for the media stream */ @@ -65,238 +67,238 @@ struct _GstRTSPStreamClass { gpointer _gst_reserved[GST_PADDING]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_stream_get_type (void); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPStream * gst_rtsp_stream_new (guint idx, GstElement *payloader, GstPad *pad); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_stream_get_index (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_stream_get_pt (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API GstPad * gst_rtsp_stream_get_srcpad (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API GstPad * gst_rtsp_stream_get_sinkpad (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_control (GstRTSPStream *stream, const gchar *control); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_stream_get_control (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_has_control (GstRTSPStream *stream, const gchar *control); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_mtu (GstRTSPStream *stream, guint mtu); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_stream_get_mtu (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_dscp_qos (GstRTSPStream *stream, gint dscp_qos); -GST_EXPORT +GST_RTSP_SERVER_API gint gst_rtsp_stream_get_dscp_qos (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_is_transport_supported (GstRTSPStream *stream, GstRTSPTransport *transport); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_profiles (GstRTSPStream *stream, GstRTSPProfile profiles); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPProfile gst_rtsp_stream_get_profiles (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_protocols (GstRTSPStream *stream, GstRTSPLowerTrans protocols); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPLowerTrans gst_rtsp_stream_get_protocols (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_address_pool (GstRTSPStream *stream, GstRTSPAddressPool *pool); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAddressPool * gst_rtsp_stream_get_address_pool (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_multicast_iface (GstRTSPStream *stream, const gchar * multicast_iface); -GST_EXPORT +GST_RTSP_SERVER_API gchar * gst_rtsp_stream_get_multicast_iface (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAddress * gst_rtsp_stream_reserve_address (GstRTSPStream *stream, const gchar * address, guint port, guint n_ports, guint ttl); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_join_bin (GstRTSPStream *stream, GstBin *bin, GstElement *rtpbin, GstState state); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_leave_bin (GstRTSPStream *stream, GstBin *bin, GstElement *rtpbin); -GST_EXPORT +GST_RTSP_SERVER_API GstBin * gst_rtsp_stream_get_joined_bin (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_is_blocking (GstRTSPStream * stream); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_unblock_linked (GstRTSPStream * stream); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_client_side (GstRTSPStream *stream, gboolean client_side); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_is_client_side (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_get_server_port (GstRTSPStream *stream, GstRTSPRange *server_port, GSocketFamily family); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPAddress * gst_rtsp_stream_get_multicast_address (GstRTSPStream *stream, GSocketFamily family); -GST_EXPORT +GST_RTSP_SERVER_API GObject * gst_rtsp_stream_get_rtpsession (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API GstElement * gst_rtsp_stream_get_srtp_encoder (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_get_ssrc (GstRTSPStream *stream, guint *ssrc); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream *stream, guint *rtptime, guint *seq, guint *clock_rate, GstClockTime *running_time); -GST_EXPORT +GST_RTSP_SERVER_API GstCaps * gst_rtsp_stream_get_caps (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API GstFlowReturn gst_rtsp_stream_recv_rtp (GstRTSPStream *stream, GstBuffer *buffer); -GST_EXPORT +GST_RTSP_SERVER_API GstFlowReturn gst_rtsp_stream_recv_rtcp (GstRTSPStream *stream, GstBuffer *buffer); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_add_transport (GstRTSPStream *stream, GstRTSPStreamTransport *trans); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_remove_transport (GstRTSPStream *stream, GstRTSPStreamTransport *trans); -GST_EXPORT +GST_RTSP_SERVER_API GSocket * gst_rtsp_stream_get_rtp_socket (GstRTSPStream *stream, GSocketFamily family); -GST_EXPORT +GST_RTSP_SERVER_API GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream *stream, GSocketFamily family); -GST_EXPORT +GST_RTSP_SERVER_API GSocket * gst_rtsp_stream_get_rtp_multicast_socket (GstRTSPStream *stream, GSocketFamily family); -GST_EXPORT +GST_RTSP_SERVER_API GSocket * gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream *stream, GSocketFamily family); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_update_crypto (GstRTSPStream * stream, guint ssrc, GstCaps * crypto); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_query_position (GstRTSPStream * stream, gint64 * position); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_seekable (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_seqnum_offset (GstRTSPStream *stream, guint16 seqnum); -GST_EXPORT +GST_RTSP_SERVER_API guint16 gst_rtsp_stream_get_current_seqnum (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_retransmission_time (GstRTSPStream *stream, GstClockTime time); -GST_EXPORT +GST_RTSP_SERVER_API GstClockTime gst_rtsp_stream_get_retransmission_time (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_stream_get_retransmission_pt (GstRTSPStream * stream); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_retransmission_pt (GstRTSPStream * stream, guint rtx_pt); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_buffer_size (GstRTSPStream *stream, guint size); -GST_EXPORT +GST_RTSP_SERVER_API guint gst_rtsp_stream_get_buffer_size (GstRTSPStream *stream); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_pt_map (GstRTSPStream * stream, guint pt, GstCaps * caps); -GST_EXPORT +GST_RTSP_SERVER_API GstElement * gst_rtsp_stream_request_aux_sender (GstRTSPStream * stream, guint sessid); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, GSocketFamily family, GstRTSPTransport *transport, gboolean use_client_settings); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_stream_set_publish_clock_mode (GstRTSPStream * stream, GstRTSPPublishClockMode mode); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPPublishClockMode gst_rtsp_stream_get_publish_clock_mode (GstRTSPStream * stream); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GstRTSPTransport * transport); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_is_complete (GstRTSPStream * stream); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_is_sender (GstRTSPStream * stream); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_is_receiver (GstRTSPStream * stream); /** @@ -323,7 +325,7 @@ typedef GstRTSPFilterResult (*GstRTSPStreamTransportFilterFunc) (GstRTSPStream * GstRTSPStreamTransport *trans, gpointer user_data); -GST_EXPORT +GST_RTSP_SERVER_API GList * gst_rtsp_stream_transport_filter (GstRTSPStream *stream, GstRTSPStreamTransportFilterFunc func, gpointer user_data); diff --git a/gst/rtsp-server/rtsp-thread-pool.h b/gst/rtsp-server/rtsp-thread-pool.h index 87ed73bee3..01ca3ac711 100644 --- a/gst/rtsp-server/rtsp-thread-pool.h +++ b/gst/rtsp-server/rtsp-thread-pool.h @@ -40,7 +40,7 @@ G_BEGIN_DECLS #define GST_RTSP_THREAD_POOL_CAST(obj) ((GstRTSPThreadPool*)(obj)) #define GST_RTSP_THREAD_POOL_CLASS_CAST(klass) ((GstRTSPThreadPoolClass*)(klass)) -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_thread_get_type (void); #define GST_TYPE_RTSP_THREAD (gst_rtsp_thread_get_type ()) @@ -78,13 +78,13 @@ struct _GstRTSPThread { GMainLoop *loop; }; -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPThread * gst_rtsp_thread_new (GstRTSPThreadType type); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_thread_reuse (GstRTSPThread * thread); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_thread_stop (GstRTSPThread * thread); /** @@ -159,24 +159,24 @@ struct _GstRTSPThreadPoolClass { gpointer _gst_reserved[GST_PADDING]; }; -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_thread_pool_get_type (void); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPThreadPool * gst_rtsp_thread_pool_new (void); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_thread_pool_set_max_threads (GstRTSPThreadPool * pool, gint max_threads); -GST_EXPORT +GST_RTSP_SERVER_API gint gst_rtsp_thread_pool_get_max_threads (GstRTSPThreadPool * pool); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPThread * gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool *pool, GstRTSPThreadType type, GstRTSPContext *ctx); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_thread_pool_cleanup (void); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPThread, gst_rtsp_thread_unref) diff --git a/gst/rtsp-server/rtsp-token.h b/gst/rtsp-server/rtsp-token.h index 3122ed4873..27e18fbc48 100644 --- a/gst/rtsp-server/rtsp-token.h +++ b/gst/rtsp-server/rtsp-token.h @@ -28,7 +28,7 @@ typedef struct _GstRTSPToken GstRTSPToken; G_BEGIN_DECLS -GST_EXPORT +GST_RTSP_SERVER_API GType gst_rtsp_token_get_type(void); #define GST_TYPE_RTSP_TOKEN (gst_rtsp_token_get_type()) @@ -74,33 +74,33 @@ gst_rtsp_token_unref (GstRTSPToken * token) } -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPToken * gst_rtsp_token_new_empty (void); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPToken * gst_rtsp_token_new (const gchar * firstfield, ...); -GST_EXPORT +GST_RTSP_SERVER_API GstRTSPToken * gst_rtsp_token_new_valist (const gchar * firstfield, va_list var_args); -GST_EXPORT +GST_RTSP_SERVER_API const GstStructure * gst_rtsp_token_get_structure (GstRTSPToken *token); -GST_EXPORT +GST_RTSP_SERVER_API GstStructure * gst_rtsp_token_writable_structure (GstRTSPToken *token); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_token_set_string (GstRTSPToken * token, const gchar * field, const gchar * string_value); -GST_EXPORT +GST_RTSP_SERVER_API const gchar * gst_rtsp_token_get_string (GstRTSPToken *token, const gchar *field); -GST_EXPORT +GST_RTSP_SERVER_API void gst_rtsp_token_set_bool (GstRTSPToken * token, const gchar * field, gboolean bool_value); -GST_EXPORT +GST_RTSP_SERVER_API gboolean gst_rtsp_token_is_allowed (GstRTSPToken *token, const gchar *field); From dc4a6d07ad86170f6939705d647e58035a02452e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 13 Mar 2018 19:28:33 +0000 Subject: [PATCH 1475/1776] Release 1.13.91 --- ChangeLog | 51 +++ NEWS | 924 +++++++++++++++++++++++++++++++++++++++++-- RELEASE | 2 +- configure.ac | 12 +- gst-rtsp-server.doap | 10 + meson.build | 2 +- 6 files changed, 958 insertions(+), 43 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4826941f57..c7e0d6257a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,58 @@ +=== release 1.13.91 === + +2018-03-13 19:28:33 +0000 Tim-Philipp Müller + + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + * meson.build: + Release 1.13.91 + +2018-03-13 13:30:41 +0000 Tim-Philipp Müller + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/meson.build: + * gst/rtsp-server/rtsp-address-pool.h: + * gst/rtsp-server/rtsp-auth.h: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-context.h: + * gst/rtsp-server/rtsp-media-factory-uri.h: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-mount-points.h: + * gst/rtsp-server/rtsp-onvif-client.h: + * gst/rtsp-server/rtsp-onvif-media-factory.h: + * gst/rtsp-server/rtsp-onvif-media.h: + * gst/rtsp-server/rtsp-onvif-server.h: + * gst/rtsp-server/rtsp-params.h: + * gst/rtsp-server/rtsp-permissions.h: + * gst/rtsp-server/rtsp-sdp.h: + * gst/rtsp-server/rtsp-server-prelude.h: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session-media.h: + * gst/rtsp-server/rtsp-session-pool.h: + * gst/rtsp-server/rtsp-session.h: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.h: + * gst/rtsp-server/rtsp-thread-pool.h: + * gst/rtsp-server/rtsp-token.h: + rtsp-server: GST_EXPORT -> GST_RTSP_SERVER_API + We need different export decorators for the different libs. + For now no actual change though, just rename before the release, + and add prelude headers to define the new decorator to GST_EXPORT. + +2018-03-07 12:20:05 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-onvif-media-factory.c: + rtsp-onvif-media-factory: Document that backchannel pipelines must end with async=false sinks + https://bugzilla.gnome.org/show_bug.cgi?id=794143 + === release 1.13.90 === 2018-03-03 22:49:34 +0000 Tim-Philipp Müller + * ChangeLog: * NEWS: * RELEASE: * configure.ac: diff --git a/NEWS b/NEWS index c85b362017..407ab98387 100644 --- a/NEWS +++ b/NEWS @@ -7,13 +7,13 @@ GStreamer 1.14.0 has not been released yet. It is scheduled for release in early March 2018. There are unstable pre-releases available for testing and development -purposes. The latest pre-release is version 1.13.90 (rc1) and was -released on 03 March 2018. +purposes. The latest pre-release is version 1.13.91 (rc2) and was +released on 12 March 2018. See https://gstreamer.freedesktop.org/releases/1.14/ for the latest version of this document. -_Last updated: Saturday 03 March 2018, 16:30 UTC (log)_ +_Last updated: Monday 12 March 2018, 18:00 UTC (log)_ Introduction @@ -28,103 +28,957 @@ other improvements. Highlights -- this section will be completed shortly +- WebRTC support: real-time audio/video streaming to and from web + browsers + +- Experimental support for the next-gen royalty-free AV1 video codec + +- Video4Linux: encoding support, stable element names and faster + device probing + +- Support for the Secure Reliable Transport (SRT) video streaming + protocol + +- RTP Forward Error Correction (FEC) support (ULPFEC) + +- RTSP 2.0 support in rtspsrc and gst-rtsp-server + +- ONVIF audio backchannel support in gst-rtsp-server and rtspsrc + +- playbin3 gapless playback and pre-buffering support + +- tee, our stream splitter/duplication element, now does allocation + query aggregation which is important for efficient data handling and + zero-copy + +- QuickTime muxer has a new prefill recording mode that allows file + import in Adobe Premiere and FinalCut Pro while the file is still + being written. + +- rtpjitterbuffer fast-start mode and timestamp offset adjustment + smoothing + +- souphttpsrc connection sharing, which allows for connection reuse, + cookie sharing, etc. + +- nvdec: new plugin for hardware-accelerated video decoding using the + NVIDIA NVDEC API + +- Adaptive DASH trick play support + +- ipcpipeline: new plugin that allows splitting a pipeline across + multiple processes + +- Major gobject-introspection annotation improvements for large parts + of the library API Major new features and changes -Noteworthy new API +WebRTC support -- this section will be filled in shortly +There is now basic support for WebRTC in GStreamer in form of a new +webrtcbin element and a webrtc support library. This allows you to build +applications that set up connections with and stream to and from other +WebRTC peers, whilst leveraging all of the usual GStreamer features such +as hardware-accelerated encoding and decoding, OpenGL integration, +zero-copy and embedded platform support. And it's easy to build and +integrate into your application too! + +WebRTC enables real-time communication of audio, video and data with web +browsers and native apps, and it is supported or about to be support by +recent versions of all major browsers and operating systems. + +GStreamer's new WebRTC implementation uses libnice for Interactive +Connectivity Establishment (ICE) to figure out the best way to +communicate with other peers, punch holes into firewalls, and traverse +NATs. + +The implementation is not complete, but all the basics are there, and +the code sticks fairly close to the PeerConnection API. Where +functionality is missing it should be fairly obvious where it needs to +go. + +For more details, background and example code, check out Nirbheek's blog +post _GStreamer has grown a WebRTC implementation_, as well as Matthew's +_GStreamer WebRTC_ talk from last year's GStreamer Conference in Prague. New Elements -- this section will be filled in shortly +- webrtcbin handles the transport aspects of webrtc connections (see + WebRTC section above for more details) -New element features and additions +- New srtsink and srtsrc elements for the Secure Reliable Transport + (SRT) video streaming protocol, which aims to be easy to use whilst + striking a new balance between reliability and latency for low + latency video streaming use cases. More details about SRT and the + implementation in GStreamer in Olivier's blog post _SRT in + GStreamer_. -- this section will be filled in shortly +- av1enc and av1dec elements providing experimental support for the + next-generation royalty free video AV1 codec, alongside Matroska + support for it. + +- hlssink2 is a rewrite of the existing hlssink element, but unlike + its predecessor hlssink2 takes elementary streams as input and + handles the muxing to MPEG-TS internally. It also leverages + splitmuxsink internally to do the splitting. This allows more + control over the chunk splitting and sizing process and relies less + on the co-operation of an upstream muxer. Different to the old + hlssink it also works with pre-encoded streams and does not require + close interaction with an upstream encoder element. + +- audiolatency is a new element for measuring audio latency end-to-end + and is useful to measure roundtrip latency including both the + GStreamer-internal latency as well as latency added by external + components or circuits. + +- 'fakevideosink is basically a null sink for video data and very + similar to fakesink, only that it will answer allocation queries and + will advertise support for various video-specific things such + GstVideoMeta, GstVideoCropMeta and GstVideoOverlayCompositionMeta + like a normal video sink would. This is useful for throughput + testing and testing the zero-copy path when creating a new pipeline. + +- ipcpipeline: new plugin that allows the splitting of a pipeline into + multiple processes. Usually a GStreamer pipeline runs in a single + process and parallelism is achieved by distributing workloads using + multiple threads. This means that all elements in the pipeline have + access to all the other elements' memory space however, including + that of any libraries used. For security reasons one might therefore + want to put sensitive parts of a pipeline such as DRM and decryption + handling into a separate process to isolate it from the rest of the + pipeline. This can now be achieved with the new ipcpipeline plugin. + Check out George's blog post _ipcpipeline: Splitting a GStreamer + pipeline into multiple processes_ or his lightning talk from last + year's GStreamer Conference in Prague for all the gory details. + +  +- proxysink and proxysrc are new elements to pass data from one + pipeline to another within the same process, very similar to the + existing inter elements, but not limited to raw audio and video + data. These new proxy elements are very special in how they work + under the hood, which makes them extremely powerful, but also + dangerous if not used with care. The reason for this is that it's + not just data that's passed from sink to src, but these elements + basically establish a two-way wormhole that passes through queries + and events in both directions, which means caps negotiation and + allocation query driven zero-copy can work through this wormhole. + There are scheduling considerations as well: proxysink forwards + everything into the proxysrc pipeline directly from the proxysink + streaming thread. There is a queue element inside proxysrc to + decouple the source thread from the sink thread, but that queue is + not unlimited, so it is entirely possible that the proxysink + pipeline thread gets stuck in the proxysrc pipeline, e.g. when that + pipeline is paused or stops consuming data for some other reason. + This means that one should always shut down down the proxysrc + pipeline before shutting down the proxysink pipeline, for example. + Or at least take care when shutting down pipelines. Usually this is + not a problem though, especially not in live pipelines. For more + information see Nirbheek's blog post _Decoupling GStreamer + Pipelines_, and also check out out the new ipcpipeline plugin for + sending data from one process to another process (see above). + +- lcms is a new LCMS-based ICC color profile correction element + +- openmptdec is a new OpenMPT-based decoder for module music formats, + such as S3M, MOD, XM, IT. It is built on top of a new + GstNonstreamAudioDecoder base class which aims to unify handling of + files which do not operate a streaming model. The wildmidi plugin + has also been revived and is also implemented on top of this new + base class. + +- The curl plugin has gained a new curlhttpsrc element, which is + useful for testing HTTP protocol version 2.0 amongst other things. + +Noteworthy new API + +- GstPromise provides future/promise-like functionality. This is used + in the GStreamer WebRTC implementation. + +  +- GstReferenceTimestampMeta is a new meta that allows you to attach + additional reference timestamps to a buffer. These timestamps don't + have to relate to the pipeline clock in any way. Examples of this + could be an NTP timestamp when the media was captured, a frame + counter on the capture side or the (local) UNIX timestamp when the + media was captured. The decklink elements make use of this. + +  +- GstVideoRegionOfInterestMeta: it's now possible to attach generic + free-form element-specific parameters to a region of interest meta, + for example to tell a downstream encoder to use certain codec + parameters for a certain region. + +  +- gst_bus_get_pollfd can be used to obtain a file descriptor for the + bus that can be poll()-ed on for new messages. This is useful for + integration with non-GLib event loops. + +  +- gst_get_main_executable_path() can be used by wrapper plugins that + need to find things in the directory where the application + executable is located. In the same vein, + GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE can be used to + signal that plugin dependency paths are relative to the main + executable. + +- pad templates can be told about the GType of the pad subclass of the + pad via newly-added GstPadTemplate API API or the + gst_element_class_add_static_pad_template_with_gtype() convenience + function. gst-inspect-1.0 will use this information to print pad + properties. + +  +- new convenience functions to iterate over element pads without using + the GstIterator API: gst_element_foreach_pad(), + gst_element_foreach_src_pad(), and gst_element_foreach_sink_pad(). + +  +- GstBaseSrc and appsrc have gained support for buffer lists: + GstBaseSrc subclasses can use gst_base_src_submit_buffer_list(), and + applications can use gst_app_src_push_buffer_list() to push a buffer + list into appsrc. + +  +- The GstHarness unit test harness has a couple of new convenience + functions to retrieve all pending data in the harness in form of a + single chunk of memory. + +  +- GstAudioStreamAlign is a new helper object for audio elements that + handles discontinuity detection and sample alignment. It will align + samples after the previous buffer's samples, but keep track of the + divergence between buffer timestamps and sample position (jitter). + If it exceeds a configurable threshold the alignment will be reset. + This simply factors out code that was duplicated in a number of + elements into a common helper API. + +  +- The GstVideoEncoder base class implements Quality of Service (QoS) + now. This is disabled by default and must be opted in by setting the + "qos" property, which will make the base class gather statistics + about the real-time performance of the pipeline from downstream + elements (usually sinks that sync the pipeline clock). Subclasses + can then make use of this by checking whether input frames are late + already using gst_video_encoder_get_max_encode_time() If late, they + can just drop them and skip encoding in the hope that the pipeline + will catch up. + +  +- The GstVideoOverlay interface gained a few helper functions for + installing and handling a "render-rectangle" property on elements + that implement this interface, so that this functionality can also + be used from the command line for testing and debugging purposes. + The property wasn't added to the interface itself as that would + require all implementors to provide it which would not be + backwards-compatible. + +  +- A new base class, GstNonstreamAudioDecoder for non-stream audio + decoders was added to gst-plugins-bad. This base-class is meant to + be used for audio decoders that require the whole stream to be + loaded first before decoding can start. Examples of this are module + formats (MOD/S3M/XM/IT/etc), C64 SID tunes, video console music + files (GYM/VGM/etc), MIDI files and others. The new openmptdec + element is based on this. + +  +- Full list of API new in 1.14: +- GStreamer core API new in 1.14 +- GStreamer base library API new in 1.14 +- gst-plugins-base libraries API new in 1.14 +- gst-plugins-bad: no list, mostly GstWebRTC library and new + non-stream audio decoder base class. + +New RTP features and improvements + +- rtpulpfecenc and rtpulpfecdec are new elements that implement + Generic Forward Error Correction (FEC) using Uneven Level Protection + (ULP) as described in RFC 5109. This can be used to protect against + certain types of (non-bursty) packet loss, and important packets + such as those containing codec configuration data or key frames can + be protected with higher redundancy. Equally, packets that are not + particularly important can be given low priority or not be protected + at all. If packets are lost, the receiver can then hopefully restore + the lost packet(s) from the surrounding packets which were received. + This is an alternative to, or rather complementary to, dealing with + packet loss using _retransmission (rtx)_. GStreamer has had + retransmission support for a long time, but Forward Error Correction + allows for different trade-offs: The advantage of Forward Error + Correction is that it doesn't add latency, whereas retransmission + requires at least one more roundtrip to request and hopefully + receive lost packets; Forward Error Correction increases the + required bandwidth however, even in situations where there is no + packet loss at all, so one will typically want to fine-tune the + overhead and mechanisms used based on the characteristics of the + link at the time. + +- New _Redundant Audio Data (RED)_ encoders and decoders for RTP as + per RFC 2198 are also provided (rtpredenc and rtpreddec), mostly for + chrome webrtc compatibility, as chrome will wrap ULPFEC-protected + streams in RED packets, and such streams need to be wrapped and + unwrapped in order to use ULPFEC with chrome. + +  +- a few new buffer flags for FEC support: + GST_BUFFER_FLAG_NON_DROPPABLE can be used to mark important buffers, + e.g. to flag RTP packets carrying keyframes or codec setup data for + RTP Forward Error Correction purposes, or to prevent still video + frames from being dropped by elements due to QoS. There already is a + GST_BUFFER_FLAG_DROPPABLE. GST_RTP_BUFFER_FLAG_REDUNDANT is used to + signal internally that a packet represents a redundant RTP packet + and used in rtpstorage to hold back the packet and use it only for + recovery from packet loss. Further work is still needed in + payloaders to make use of these. + +- rtpbin now has an option for increasing timestamp offsets gradually: + Instant large changes to the internal ts_offset may cause timestamps + to move backwards and also cause visible glitches in media playback. + The new "max-ts-offset-adjustment" and "max-ts-offset" properties + let the application control the rate to apply changes to ts_offset. + There have also been some EOS/BYE handling improvements in rtpbin. + +- rtpjitterbuffer has a new fast start mode: in many scenarios the + jitter buffer will have to wait for the full configured latency + before it can start outputting packets. The reason for that is that + it often can't know what the sequence number of the first expected + RTP packet is, so it can't know whether a packet earlier than the + earliest packet received will still arrive in future. This behaviour + can now be bypassed by setting the "faststart-min-packets" property + to the number of consecutive packets needed to start, and the jitter + buffer will start output packets as soon as it has N consecutive + packets queued internally. This is particularly useful to get a + first video frame decoded and rendered as quickly as possible. + +- rtpL8pay and rtpL8depay provide RTP payloading and depayloading for + 8-bit raw audio + +New element features + +- playbin3 has gained support or gapless playback via the + "about-to-finish" signal where users can set the uri for the next + item to play. For non-live streams this will be emitted as soon as + the first uri has finished downloading, so with sufficiently large + buffers it is now possible to pre-buffer the next item well ahead of + time (unlike playbin where there would not be a lot of time between + "about-to-finish" emission and the end of the stream). If the stream + format of the next stream is the same as that of the previous + stream, the data will be concatenated via the concat element. + Whether this will result in true gaplessness depends on the + container format and codecs used, there might still be codec-related + gaps between streams with some codecs. + +- tee now does allocation query aggregation, which is important for + zero-copy and efficient data handling, especially for video. Those + who want to drop allocation queries on purpose can use the identity + element's new "drop-allocation" property for that instead. + +- audioconvert now has a "mix-matrix" property, which obsoletes the + audiomixmatrix element. There's also mix matrix support in the audio + conversion and channel mixing API. + +- x264enc: new "insert-vui" property to disable VUI (Video Usability + Information) parameter insertion into the stream, which allows + creation of streams that are compatible with certain legacy hardware + decoders that will refuse to decode in certain combinations of + resolution and VUI parameters; the max. allowed number of B-frames + was also increased from 4 to 16. + +- dvdlpcmdec: has gained support for Blu-Ray audio LPCM. + +- appsrc has gained support for buffer lists (see above) and also seen + some other performance improvements. + +- flvmux has been ported to the GstAggregator base class which means + it can work in defined-latency mode with live input sources and + continue streaming if one of the inputs stops producing data. + +- jpegenc has gained a "snapshot" property just like pngenc to make it + easier to just output a single encoded frame. + +- jpegdec will now handle interlaced MJPEG streams properly and also + handle frames without an End of Image marker better. + +- v4l2: There are now video encoders for VP8, VP9, MPEG4, and H263. + The v4l2 video decoder handles dynamic resolution changes, and the + video4linux device provider now does much faster device probing. The + plugin also no longer uses the libv4l2 library by default, as it has + prevented a lot of interesting use cases like CREATE_BUFS, DMABuf, + usage of TRY_FMT. As the libv4l2 library is totally inactive and not + really maintained, we decided to disable it. This might affect a + small number of cheap/old webcams with custom vendor formats for + which we do not provide conversion in GStreamer. It is possible to + re-enable support for libv4l2 at run-time however, by setting the + environment variable GST_V4L2_USE_LIBV4L2=1. + +- rtspsrc now has support for RTSP protocol version 2.0 as well as + ONVIF audio backchannels (see below for more details). It also + sports a new ["accept-certificate"] signal for "manually" checking a + TLS certificate for validity. It now also prints RTSP/SDP messages + to the gstreamer debug log instead of stdout. + +- shout2send now uses non-blocking I/O and has a configurable network + operations timeout. + +- splitmuxsink has gained a "split-now" action signal and new + "alignment-threshold" and "use-robust-muxing" properties. If robust + muxing is enabled, it will check and set the muxer's reserved space + properties if present. This is primarily for use with mp4mux's + robust muxing mode. + +- qtmux has a new _prefill recording mode_ which sets up a moov header + with the correct sample positions beforehand, which then allows + software like Adobe Premiere and FinalCut Pro to import the files + while they are still being written to. This only works with constant + framerate I-frame only streams, and for now only support for ProRes + video and raw audio is implemented but adding new codecs is just a + matter of defining appropriate maximum frame sizes. + +- qtmux also supports writing of svmi atoms with stereoscopic video + information now. Trak timescales can be configured on a per-stream + basis using the "trak-timescale" property on the sink pads. Various + new formats can be muxed: MPEG layer 1 and 2, AC3 and Opus, as well + as PNG and VP9. + +- souphttpsrc now does connection sharing by default, shares its + SoupSession with other elements in the same pipeline via a + GstContext if possible (session-wide settings are all the defaults). + This allows for connection reuse, cookie sharing, etc. Applications + can also force a context to use. In other news, HTTP headers + received from the server are posted as element messages on the bus + now for easier diagnostics, and it's also possible now to use other + types of proxy servers such as SOCKS4 or SOCKS5 proxies, support for + which is implemented directly in gio. Before only HTTP proxies were + allowed. + +- qtmux, mp4mux and matroskamux will now refuse caps changes of input + streams at runtime. This isn't really supported with these + containers (or would have to be implemented differently with a + considerable effort) and doesn't produce valid and spec-compliant + files that will play everywhere. So if you can't guarantee that the + input caps won't change, use a container format that does support on + the fly caps changes for a stream such as MPEG-TS or use + splitmuxsink which can start a new file when the caps change. What + would happen before is that e.g. rtph264depay or rtph265depay would + simply send new SPS/PPS inband even for AVC format, which would then + get muxed into the container as if nothing changed. Some decoders + will handle this just fine, but that's often more luck than by + design. In any case, it's not right, so we disallow it now. + +- matroskamux had Table of Content (TOC) support now (chapters etc.) + and matroskademux TOC support has been improved. matroskademux has + also seen seeking improvements searching for the right cluster and + position. + +- videocrop now uses GstVideoCropMeta if downstream supports it, which + means cropping can be handled more efficiently without any copying. + +- compositor now has support for _crossfade blending_, which can be + used via the new "crossfade-ratio" property on the sink pads. + +- The avwait element has a new "end-timecode" property and posts + "avwait-status" element messages now whenever avwait starts or stops + passing through data (e.g. because target-timecode and end-timecode + respectively have been reached). + +  +- h265parse and h265parse will try harder to make upstream output the + same caps as downstream requires or prefers, thus avoiding + unnecessary conversion. The parsers also expose chroma format and + bit depth in the caps now. + +- The dtls elements now longer rely on or require the application to + run a GLib main loop that iterates the default main context + (GStreamer plugins should never rely on the application running a + GLib main loop). + +- openh264enc allows to change the encoding bitrate dynamically at + runtime now + +- nvdec is a new plugin for hardware-accelerated video decoding using + the NVIDIA NVDEC API (which replaces the old VDPAU API which is no + longer supported by NVIDIA) + +- The NVIDIA NVENC hardware-accelerated video encoders now support + dynamic bitrate and preset reconfiguration and support the I420 + 4:2:0 video format. It's also possible to configure the gop size via + the new "gop-size" property. + +- The MPEG-TS muxer and demuxer (tsmux, tsdemux) now have support for + JPEG2000 + +- openjpegdec and jpeg2000parse support 2-component images now (gray + with alpha), and jpeg2000parse has gained limited support for + conversion between JPEG2000 stream-formats. (JP2, J2C, JPC) and also + extracts more details such as colorimetry, interlace-mode, + field-order, multiview-mode and chroma siting. + +- The decklink plugin for Blackmagic capture and playback cards have + seen numerous improvements: + +- decklinkaudiosrc and decklinkvideosrc now put hardware reference + timestamp on buffers in form of GstReferenceTimestampMetas. + This can be useful to know on multi-channel cards which frames from + different channels were captured at the same time. + +- decklinkvideosink has gained support for Decklink hardware keying + with two new properties ("keyer-mode" and "keyer-level") to control + the built-in hardware keyer of Decklink cards. + +- decklinkaudiosink has been re-implemented around GstBaseSink instead + of the GstAudioBaseSink base class, since the Decklink APIs don't + fit very well with the GstAudioBaseSink APIs, which used to cause + various problems due to inaccuracies in the clock calculations. + Problems were audio drop-outs and A/V sync going wrong after + pausing/seeking. + +- support for more than 16 devices, without any artificial limit + +- work continued on the msdk plugin for Intel's Media SDK which + enables hardware-accelerated video encoding and decoding on Intel + graphics hardware on Windows or Linux. More tuning options were + added, and more pixel formats and video codecs are supported now. + The encoder now also handles force-key-unit events and can insert + frame-packing SEIs for side-by-side and top-bottom stereoscopic 3D + video. + +- dashdemux can now do adaptive trick play of certain types of DASH + streams, meaning it can do fast-forward/fast-rewind of normal (non-I + frame only) streams even at high speeds without saturating network + bandwidth or exceeding decoder capabilities. It will keep statistics + and skip keyframes or fragments as needed. See Sebastian's blog post + _DASH trick-mode playback in GStreamer_ for more details. It also + supports webvtt subtitle streams now and has seen improvements when + seeking in live streams. + +  +- kmssink has seen lots of fixes and improvements in this cycle, + including: + +- Raspberry Pi (vc4) and Xilinx DRM driver support + +- new "render-rectangle" property that can be used from the command + line as well as "display-width" and "display-height", and + "can-scale" properties + +- GstVideoCropMeta support Plugin and library moves -- this section will be filled in shortly +MPEG-1 audio (mp1, mp2, mp3) decoders and encoders moved to -good + +Following the expiration of the last remaining mp3 patents in most +jurisdictions, and the termination of the mp3 licensing program, as well +as the decision by certain distros to officially start shipping full mp3 +decoding and encoding support, these plugins should now no longer be +problematic for most distributors and have therefore been moved from +-ugly and -bad to gst-plugins-good. Distributors can still disable these +plugins if desired. + +In particular these are: + +- mpg123audiodec: an mp1/mp2/mp3 audio decoder using libmpg123 +- lamemp3enc: an mp3 encoder using LAME +- twolamemp2enc: an mp2 encoder using TwoLAME + +GstAggregator moved from -bad to core + +GstAggregator has been moved from gst-plugins-bad to the base library in +GStreamer and is now stable API. + +GstAggregator is a new base class for mixers and muxers that have to +handle multiple input pads and aggregate streams into one output stream. +It improves upon the existing GstCollectPads API in that it is a proper +base class which was also designed with live streaming in mind. +GstAggregator subclasses will operate in a mode with defined latency if +any of the inputs are live streams. This ensures that the pipeline won't +stall if any of the inputs stop producing data, and that the configured +maximum latency is never exceeded. + +GstAudioAggregator, audiomixer and audiointerleave moved from -bad to -base + +GstAudioAggregator is a new base class for raw audio mixers and muxers +and is based on GstAggregator (see above). It provides defined-latency +mixing of raw audio inputs and ensures that the pipeline won't stall +even if one of the input streams stops producing data. + +As part of the move to stabilise the API there were some last-minute API +changes and clean-ups, but those should mostly affect internal elements. + +It is used by the audiomixer element, which is a replacement for +'adder', which did not handle live inputs very well and did not align +input streams according to running time. audiomixer should behave much +better in that respect and generally behave as one would expected in +most scenarios. + +Similarly, audiointerleave replaces the 'interleave' element which did +not handle live inputs or non-aligned inputs very robustly. + +GstAudioAggregator and its subclases have gained support for input +format conversion, which does not include sample rate conversion though +as that would add additional latency. Furthermore, GAP events are now +handled correctly. + +We hope to move the video equivalents (GstVideoAggregator and +compositor) to -base in the next cycle, i.e. for 1.16. + +GStreamer OpenGL integration library and plugin moved from -bad to -base + +The GStreamer OpenGL integration library and opengl plugin have moved +from gst-plugins-bad to -base and are now part of the stable API canon. +Not all OpenGL elements have been moved; a few had to be left behind in +gst-plugins-bad in the new openglmixers plugin, because they depend on +the GstVideoAggregator base class which we were not able to move in this +cycle. We hope to reunite these elements with the rest of their family +for 1.16 though. + +This is quite a milestone, thanks to everyone who worked to make this +happen! + +Qt QML and GTK plugins moved from -bad to -good + +The Qt QML-based qmlgl plugin has moved to -good and provides a +qmlglsink video sink element as well as a qmlglsrc element. qmlglsink +renders video into a QQuickItem, and qmlglsrc captures a window from a +QML view and feeds it as video into a pipeline for further processing. +Both elements leverage GStreamer's OpenGL integration. In addition to +the move to -good the following features were added: + +- A proxy object is now used for thread-safe access to the QML widget + which prevents crashes in corner case scenarios: QML can destroy the + video widget at any time, so without this we might be left with a + dangling pointer. + +- EGL is now supported with the X11 backend, which works e.g. on + Freescale imx6 + +The GTK+ plugin has also moved from -bad to -good. It includes gtksink +and gtkglsink which both render video into a GtkWidget. gtksink uses +Cairo for rendering the video, which will work everywhere in all +scenarios but involves an extra memory copy, whereas gtkglsink fully +leverages GStreamer's OpenGL integration, but might not work properly in +all scenarios, e.g. where the OpenGL driver does not properly support +multiple sharing contexts in different threads; on Linux Nouveau is +known to be broken in this respect, whilst NVIDIA's proprietary drivers +and most other drivers generally work fine, and the experience with +Intel's driver seems to be fixed; some proprietary embedded Linux +drivers don't work; macOS works). + +GstPhysMemoryAllocator interface moved from -bad to -base + +GstPhysMemoryAllocator is a marker interface for allocators with +physical address backed memory. Plugin removals -- this section will be filled in shortly +- the sunaudio plugin was removed, since it couldn't ever have been + built or used with GStreamer 1.0, but no one even noticed in all + these years. +- the schroedinger-based Dirac encoder/decoder plugin has been + removed, as there is no longer any upstream or anyone else + maintaining it. Seeing that it's quite a fringe codec it seemed best + to simply remove it. -Miscellaneous API additions +API removals -- this section will be filled in shortly - -GstPlayer - -- this section will be filled in shortly +- some MPEG video parser API in the API unstable codecutils library in + gst-plugins-bad was removed after having been deprecated for 5 + years. Miscellaneous changes -- this section will be filled in shortly +- The video support library has gained support for a few new pixel + formats: +- NV16_10LE32: 10-bit variant of NV16, packed into 32bit words (plus 2 + bits padding) +- NV12_10LE32: 10-bit variant of NV12, packed into 32bit words (plus 2 + bits padding) +- GRAY10_LE32: 10-bit grayscale, packed in 32bit words (plus 2 bits + padding) + +- decodebin, playbin and GstDiscoverer have seen stability + improvements in corner cases such as shutdown while still starting + up or shutdown in error cases (hat tip to the oss-fuzz project). + +- floating reference handling was inconsistent and has been cleaned up + across the board, including annotations. This solves various + long-standing memory leaks in language bindings, which e.g. often + caused elements and pads to be leaked. + +- major gobject-introspection annotation improvements for large parts + of the library API, including nullability of return types and + function parameters, correct types (e.g. strings vs. filenames), + ownership transfer, array length parameters, etc. This allows to use + bigger parts of the GStreamer API to be safely used from dynamic + language bindings (e.g. Python, Javascript) and allows static + bindings (e.g. C#, Rust, Vala) to autogenerate more API bindings + without manual intervention. OpenGL integration -- this section will be filled in shortly +- The GStreamer OpenGL integration library has moved to + gst-plugins-base and is now part of our stable API. + +- new MESA3D GBM BACKEND. On devices with working libdrm support, it + is possible to use Mesa3D's GBM library to set up an EGL context + directly on top of KMS. This makes it possible to use the GStreamer + OpenGL elements without a windowing system if a libdrm- and + Mesa3D-supported GPU is present. + +- Prefer wayland display over X11: As most Wayland compositors support + XWayland, the X11 backend would get selected. + +- gldownload can export dmabufs now, and glupload will advertise + dmabuf as caps feature. Tracing framework and debugging improvements -- this section will be filled in shortly +- NEW MEMORY RINGBUFFER BASED DEBUG LOGGER, useful for long-running + applications or to retrieve diagnostics when encountering an error. + The GStreamer debug logging system provides in-depth debug logging + about what is going on inside a pipeline. When enabled, debug logs + are usually written into a file, printed to the terminal, or handed + off to a log handler installed by the application. However, at + higher debug levels the volume of debug output quickly becomes + unmanageable, which poses a problem in disk-space or bandwidth + restricted environments or with long-running pipelines where a + problem might only manifest itself after multiple days. In those + situations, developers are usually only interested in the most + recent debug log output. The new in-memory ringbuffer logger makes + this easy: just installed it with gst_debug_add_ring_buffer_logger() + and retrieve logs with gst_debug_ring_buffer_logger_get_logs() when + needed. It is possible to limit the memory usage per thread and set + a timeout to determine how long messages are kept around. It was + always possible to implement this in the application with a custom + log handler of course, this just provides this functionality as part + of GStreamer. + +  +- 'fakevideosink is a null sink for video data that advertises + video-specific metas ane behaves like a video sink. See above for + more details. + +- gst_util_dump_buffer() prints the content of a buffer to stdout. + +- gst_pad_link_get_name() and gst_state_change_get_name() print pad + link return values and state change transition values as strings. + +- The LATENCY TRACER has seen a few improvements: trace records now + contain timestamps which is useful to plot things over time, and + downstream synchronisation time is now excluded from the measured + values. + +- Miniobject refcount tracing and logging was not entirley + thread-safe, there were duplicates or missing entries at times. This + has now been made reliable. + +- The netsim element, which can be used to simulate network jitter, + packet reordering and packet loss, received new features and + improvements: it can now also simulate network congestion using a + token bucket algorithm. This can be enabled via the "max-kbps" + property. Packet reordering can be disabled now via the + "allow-reordering" property: Reordering of packets is not very + common in networks, and the delay functions will always introduce + reordering if delay > packet-spacing, so by setting + "allow-reordering" to FALSE you guarantee that the packets are in + order, while at the same time introducing delay/jitter to them. By + using the new "delay-distribution" property the use can control how + the delay applied to delayed packets is distributed: This is either + the uniform distribution (as before) or the normal distribution; in + addition there is also the gamma distribution which simulates the + delay on wifi networks better. Tools -- this section will be filled in shortly +- gst-inspect-1.0 now prints pad properties for elements that have pad + subclasses with special properties, such as compositor or + audiomixer. This only works for elements that use the newly-added + GstPadTemplate API API or the + gst_element_class_add_static_pad_template_with_gtype() convenience + function to tell GStreamer about the special pad subclass. + +- gst-launch-1.0 now generates a gstreamer pipeline diagram (.dot + file) whenever SIGHUP is sent to it on Linux/*nix systems. + +- gst-discoverer-1.0 can now analyse live streams such as rtsp:// URIs GStreamer RTSP server -- this section will be filled in shortly +- Initial support for [RTSP protocol version + 2.0][rtsp2-lightning-talk] was added, which is to the best of our + knowledge the first RTSP 2.0 implementation ever! + +- ONVIF audio backchannel support. This is an extension specified by + ONVIF that allows RTSP clients (e.g. a control room operator) to + send audio back to the RTSP server (e.g. an IP camera). + Theoretically this could have been done also by using the RECORD + method of the RTSP protocol, but ONVIF chose not to do that, so the + backchannel is set up alongside the other streams. Format + negotiation needs to be done out of band, if needed. Use the new + ONVIF-specific subclasses GstRTSPOnvifServer and + GstRTSPOnvifMediaFactory to enable this functionality. + +  +- The internal server streaming pipeline is now dynamically + reconfigured on PLAY based on the transports needed. This means that + the server no longer adds the pipeline plumbing for all possible + transports from the start, but only if needed as needed. This + improves performance and memory footprint. + +- rtspclientsink has gained an "accept-certificate" signal for + manually checking a TLS certificate for validity. + +- Fix keep-alive/timeout issue for certain clients using TCP + interleave as transport who don't do keep-alive via some other + method such as periodic RTSP OPTION requests. We now put netaddress + metas on the packets from the TCP interleaved stream, so can map + RTCP packets to the right stream in the server and can handle them + properly. + +- Language bindings improvements: in general there were quite a few + improvements in the gobject-introspection annotations, but we also + extended the permissions API which was not usable from bindings + before. + +- Fix corner case issue where the wrong mount point was found when + there were multiple mount points with a common prefix. GStreamer VAAPI -- this section will be filled in shortly +- this section will be filled in shortly {FIXME!} GStreamer Editing Services and NLE -- this section will be filled in shortly +- this section will be filled in shortly {FIXME!} GStreamer validate -- this section will be filled in shortly +- this section will be filled in shortly {FIXME!} GStreamer Python Bindings -- this section will be filled in shortly +- this section will be filled in shortly {FIXME!} Build and Dependencies -- this section will be filled in shortly +- the new WebRTC support in gst-plugins-bad depends on the GStreamer + elements that ship as part of libnice, and libnice version 1.1.14 is + required. Also the dtls and srtp plugins. + +- gst-plugins-bad no longer depends on the libschroedinger Dirac codec + library. + +- The srtp plugin can now also be built against libsrtp2. + +- some plugins and libraries have moved between modules, see the + _Plugin and_ _library moves_ section above, and their respective + dependencies have moved with them of course, e.g. the GStreamer + OpenGL integration support library and plugin is now in + gst-plugins-base, and mpg123, LAME and twoLAME based audio decoder + and encoder plugins are now in gst-plugins-good. + +- Unify static and dynamic plugin interface and remove plugin specific + static build option: Static and dynamic plugins now have the same + interface. The standard --enable-static/--enable-shared toggle is + sufficient. This allows building static and shared plugins from the + same object files, instead of having to build everything twice. + +- The default plugin entry point has changed. This will only affect + plugins that are recompiled against new GStreamer headers. Binary + plugins using the old entry point will continue to work. However, + plugins that are recompiled must have matching plugin names in + GST_PLUGIN_DEFINE and filenames, as the plugin entry point for + shared plugins is now deduced from the plugin filename. This means + you can no longer have a plugin called foo living in a file called + libfoobar.so or such, the plugin filename needs to match. This might + cause problems with some external third party plugin modules when + they get rebuilt against GStreamer 1.14. + + +Note to packagers and distributors + +A number of libraries, APIs and plugins moved between modules and/or +libraries in different modules between version 1.12.x and 1.14.x, see +the _Plugin and_ _library moves_ section above. Some APIs have seen +minor ABI changes in the course of moving them into the stable APIs +section. + +This means that you should try to ensure that all major GStreamer +modules are synced to the same major version (1.12 or 1.13/1.14) and can +only be upgraded in lockstep, so that your users never end up with a mix +of major versions on their system at the same time, as this may cause +breakages. + +Also, plugins compiled against >= 1.14 headers will not load with +GStreamer <= 1.12 owing to a new plugin entry point (but plugin binaries +built against older GStreamer versions will continue to load with newer +versions of GStreamer of course). + +There is also a small structure size related ABI breakage introduced in +the gst-plugins-bad codecparsers library between version 1.13.90 and +1.13.91. This should "only" affect gstreamer-vaapi, so anyone who ships +the release candidates is advised to upgrade those two modules at the +same time. Platform-specific improvements Android -- this section will be filled in shortly +- ahcsrc (Android camera source) does autofocus now macOS and iOS -- this section will be filled in shortly +- this section will be filled in shortly {FIXME!} Windows -- this section will be filled in shortly +- The GStreamer wasapi plugin was rewritten and should not only be + usable now, but in top shape and suitable for low-latency use cases. + The Windows Audio Session API (WASAPI) is Microsoft's most modern + method for talking with audio devices, and now that the wasapi + plugin is up to scratch it is preferred over the directsound plugin. + The ranks of the wasapisink and wasapisrc elements have been updated + to reflect this. Further improvements include: + +- support for more than 2 channels + +- a new "low-latency" property to enable low-latency operation (which + should always be safe to enable) + +- support for the AudioClient3 API which is only available on Windows + 10: in wasapisink this will be used automatically if available; in + wasapisrc it will have to be enabled explicitly via the + "use-audioclient3" property, as capturing audio with low latency and + without glitches seems to require setting the realtime priority of + the entire pipeline to "critical", which cannot be done from inside + the element, but has to be done in the application. + +- set realtime thread priority to avoid glitches + +- allow opening devices in exclusive mode, which provides much lower + latency compared to shared mode where WASAPI's engine period is + 10ms. This can be activated via the "exclusive" property. + +- There are now GstDeviceProvider implementations for the wasapi and + directsound plugins, so it's now possible to discover both audio + sources and audio sinks on Windows via the GstDeviceMonitor API + +- debug log timestamps are now higher granularity owing to + g_get_monotonic_time() now being used as fallback in + gst_utils_get_timestamp(). Before that, there would sometimes be + 10-20 lines of debug log output sporting the same timestamp. Contributors @@ -184,9 +1038,7 @@ suggestions or helped testing. Bugs fixed in 1.14 -- this section will be filled in shortly - -More than 704 bugs have been fixed during the development of 1.14. +More than 800 bugs have been fixed during the development of 1.14. This list does not include issues that have been cherry-picked into the stable 1.12 branch and fixed there as well, all fixes that ended up in @@ -211,7 +1063,8 @@ the git 1.14 branch, which is a stable branch. Known Issues -- The webrtcdsp element is currently not shipped as part of the +- The webrtcdsp element (which is unrelated to the newly-landed + GStreamer webrtc support) is currently not shipped as part of the Windows binary packages due to a build system issue. @@ -230,6 +1083,7 @@ several 1.15 pre-releases and the new 1.16 stable release in September. ------------------------------------------------------------------------ -_These release notes have been prepared by Tim-Philipp Müller._ +_These release notes have been prepared by Tim-Philipp Müller with_ +_contributions from Sebastian Dröge._ _License: CC BY-SA 4.0_ diff --git a/RELEASE b/RELEASE index f253d44f14..f201622438 100644 --- a/RELEASE +++ b/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-rtsp-server 1.13.90. +This is GStreamer gst-rtsp-server 1.13.91. The GStreamer team is pleased to announce the first release candidate for the upcoming stable 1.14 release series. diff --git a/configure.ac b/configure.ac index 0fc1f01e91..4ef18c1542 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.13.90], +AC_INIT([GStreamer RTSP Server Library], [1.13.91], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1390, 0, 1390) +AS_LIBTOOL(GST, 1391, 0, 1391) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.13.90 -GSTPB_REQ=1.13.90 -GSTPG_REQ=1.13.90 -GSTPD_REQ=1.13.90 +GST_REQ=1.13.91 +GSTPB_REQ=1.13.91 +GSTPG_REQ=1.13.91 +GSTPD_REQ=1.13.91 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index efb94e6ccb..3cdb864df1 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.13.91 + master + + 2018-03-13 + + + + 1.13.90 diff --git a/meson.build b/meson.build index 200c7a8871..9643163fec 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.13.90', + version : '1.13.91', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 2fdb040b2669e4190de5ccf96ccebd7c85051593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 19 Mar 2018 20:27:04 +0000 Subject: [PATCH 1476/1776] Release 1.14.0 --- ChangeLog | 13 +++ NEWS | 222 ++++++++++++++++++++++++++++++++----------- RELEASE | 15 +-- configure.ac | 12 +-- gst-rtsp-server.doap | 10 ++ meson.build | 2 +- 6 files changed, 207 insertions(+), 67 deletions(-) diff --git a/ChangeLog b/ChangeLog index c7e0d6257a..789baa10f2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,20 @@ +=== release 1.14.0 === + +2018-03-19 20:27:04 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + * meson.build: + Release 1.14.0 + === release 1.13.91 === 2018-03-13 19:28:33 +0000 Tim-Philipp Müller + * ChangeLog: * NEWS: * RELEASE: * configure.ac: diff --git a/NEWS b/NEWS index 407ab98387..64dcb91eaf 100644 --- a/NEWS +++ b/NEWS @@ -3,17 +3,19 @@ GSTREAMER 1.14 RELEASE NOTES -GStreamer 1.14.0 has not been released yet. It is scheduled for release -in early March 2018. +The GStreamer team is proud to announce a new major feature release in +the stable 1.x API series of your favourite cross-platform multimedia +framework! -There are unstable pre-releases available for testing and development -purposes. The latest pre-release is version 1.13.91 (rc2) and was -released on 12 March 2018. +As always, this release is again packed with new features, bug fixes and +other improvements. + +GStreamer 1.14.0 was released on 19 March 2018. See https://gstreamer.freedesktop.org/releases/1.14/ for the latest version of this document. -_Last updated: Monday 12 March 2018, 18:00 UTC (log)_ +_Last updated: Monday 19 March 2018, 12:00 UTC (log)_ Introduction @@ -72,6 +74,13 @@ Highlights - Major gobject-introspection annotation improvements for large parts of the library API +- GStreamer C# bindings have been revived and seen many updates and + fixes + +- The externally maintained GStreamer Rust bindings had many usability + improvements and cover most of the API now. Coinciding with the 1.14 + release, a new release with the 1.14 API additions is happening. + Major new features and changes @@ -153,7 +162,6 @@ New Elements pipeline into multiple processes_ or his lightning talk from last year's GStreamer Conference in Prague for all the gory details. -  - proxysink and proxysrc are new elements to pass data from one pipeline to another within the same process, very similar to the existing inter elements, but not limited to raw audio and video @@ -191,12 +199,14 @@ New Elements - The curl plugin has gained a new curlhttpsrc element, which is useful for testing HTTP protocol version 2.0 amongst other things. +- The msdk plugin has gained a MPEG-2 video decoder(msdkmpeg2dec), VP8 + decoder(msdkvp8dec) and a VC1/WMV decoder(msdkvc1dec) + Noteworthy new API - GstPromise provides future/promise-like functionality. This is used in the GStreamer WebRTC implementation. -  - GstReferenceTimestampMeta is a new meta that allows you to attach additional reference timestamps to a buffer. These timestamps don't have to relate to the pipeline clock in any way. Examples of this @@ -204,18 +214,15 @@ Noteworthy new API counter on the capture side or the (local) UNIX timestamp when the media was captured. The decklink elements make use of this. -  - GstVideoRegionOfInterestMeta: it's now possible to attach generic free-form element-specific parameters to a region of interest meta, for example to tell a downstream encoder to use certain codec parameters for a certain region. -  - gst_bus_get_pollfd can be used to obtain a file descriptor for the bus that can be poll()-ed on for new messages. This is useful for integration with non-GLib event loops. -  - gst_get_main_executable_path() can be used by wrapper plugins that need to find things in the directory where the application executable is located. In the same vein, @@ -229,23 +236,19 @@ Noteworthy new API function. gst-inspect-1.0 will use this information to print pad properties. -  - new convenience functions to iterate over element pads without using the GstIterator API: gst_element_foreach_pad(), gst_element_foreach_src_pad(), and gst_element_foreach_sink_pad(). -  - GstBaseSrc and appsrc have gained support for buffer lists: GstBaseSrc subclasses can use gst_base_src_submit_buffer_list(), and applications can use gst_app_src_push_buffer_list() to push a buffer list into appsrc. -  - The GstHarness unit test harness has a couple of new convenience functions to retrieve all pending data in the harness in form of a single chunk of memory. -  - GstAudioStreamAlign is a new helper object for audio elements that handles discontinuity detection and sample alignment. It will align samples after the previous buffer's samples, but keep track of the @@ -254,7 +257,6 @@ Noteworthy new API This simply factors out code that was duplicated in a number of elements into a common helper API. -  - The GstVideoEncoder base class implements Quality of Service (QoS) now. This is disabled by default and must be opted in by setting the "qos" property, which will make the base class gather statistics @@ -265,7 +267,6 @@ Noteworthy new API can just drop them and skip encoding in the hope that the pipeline will catch up. -  - The GstVideoOverlay interface gained a few helper functions for installing and handling a "render-rectangle" property on elements that implement this interface, so that this functionality can also @@ -274,7 +275,6 @@ Noteworthy new API require all implementors to provide it which would not be backwards-compatible. -  - A new base class, GstNonstreamAudioDecoder for non-stream audio decoders was added to gst-plugins-bad. This base-class is meant to be used for audio decoders that require the whole stream to be @@ -283,7 +283,6 @@ Noteworthy new API files (GYM/VGM/etc), MIDI files and others. The new openmptdec element is based on this. -  - Full list of API new in 1.14: - GStreamer core API new in 1.14 - GStreamer base library API new in 1.14 @@ -320,7 +319,6 @@ New RTP features and improvements streams in RED packets, and such streams need to be wrapped and unwrapped in order to use ULPFEC with chrome. -  - a few new buffer flags for FEC support: GST_BUFFER_FLAG_NON_DROPPABLE can be used to mark important buffers, e.g. to flag RTP packets carrying keyframes or codec setup data for @@ -333,11 +331,12 @@ New RTP features and improvements payloaders to make use of these. - rtpbin now has an option for increasing timestamp offsets gradually: - Instant large changes to the internal ts_offset may cause timestamps - to move backwards and also cause visible glitches in media playback. - The new "max-ts-offset-adjustment" and "max-ts-offset" properties - let the application control the rate to apply changes to ts_offset. - There have also been some EOS/BYE handling improvements in rtpbin. + Sudden large changes to the internal ts_offset may cause timestamps + to move backwards and may also cause visible glitches in media + playback. The new "max-ts-offset-adjustment" and "max-ts-offset" + properties let the application control the rate to apply changes to + ts_offset. There have also been some EOS/BYE handling improvements + in rtpbin. - rtpjitterbuffer has a new fast start mode: in many scenarios the jitter buffer will have to wait for the full configured latency @@ -395,10 +394,10 @@ New element features continue streaming if one of the inputs stops producing data. - jpegenc has gained a "snapshot" property just like pngenc to make it - easier to just output a single encoded frame. + easier to output just a single encoded frame. - jpegdec will now handle interlaced MJPEG streams properly and also - handle frames without an End of Image marker better. + handles frames without an End of Image marker better. - v4l2: There are now video encoders for VP8, VP9, MPEG4, and H263. The v4l2 video decoder handles dynamic resolution changes, and the @@ -414,7 +413,7 @@ New element features - rtspsrc now has support for RTSP protocol version 2.0 as well as ONVIF audio backchannels (see below for more details). It also - sports a new ["accept-certificate"] signal for "manually" checking a + sports a new "accept-certificate" signal for "manually" checking a TLS certificate for validity. It now also prints RTSP/SDP messages to the gstreamer debug log instead of stdout. @@ -432,8 +431,9 @@ New element features software like Adobe Premiere and FinalCut Pro to import the files while they are still being written to. This only works with constant framerate I-frame only streams, and for now only support for ProRes - video and raw audio is implemented but adding new codecs is just a - matter of defining appropriate maximum frame sizes. + video and raw audio is implemented. Adding support for additional + codecs is just a matter of defining appropriate maximum frame sizes + though. - qtmux also supports writing of svmi atoms with stereoscopic video information now. Trak timescales can be configured on a per-stream @@ -441,7 +441,7 @@ New element features new formats can be muxed: MPEG layer 1 and 2, AC3 and Opus, as well as PNG and VP9. -- souphttpsrc now does connection sharing by default, shares its +- souphttpsrc now does connection sharing by default: it shares its SoupSession with other elements in the same pipeline via a GstContext if possible (session-wide settings are all the defaults). This allows for connection reuse, cookie sharing, etc. Applications @@ -466,7 +466,7 @@ New element features will handle this just fine, but that's often more luck than by design. In any case, it's not right, so we disallow it now. -- matroskamux had Table of Content (TOC) support now (chapters etc.) +- matroskamux has Table of Content (TOC) support now (chapters etc.) and matroskademux TOC support has been improved. matroskademux has also seen seeking improvements searching for the right cluster and position. @@ -482,7 +482,6 @@ New element features passing through data (e.g. because target-timecode and end-timecode respectively have been reached). -  - h265parse and h265parse will try harder to make upstream output the same caps as downstream requires or prefers, thus avoiding unnecessary conversion. The parsers also expose chroma format and @@ -537,11 +536,18 @@ New element features - work continued on the msdk plugin for Intel's Media SDK which enables hardware-accelerated video encoding and decoding on Intel - graphics hardware on Windows or Linux. More tuning options were - added, and more pixel formats and video codecs are supported now. - The encoder now also handles force-key-unit events and can insert - frame-packing SEIs for side-by-side and top-bottom stereoscopic 3D - video. + graphics hardware on Windows or Linux. Added the video memory, + buffer pool, and context/session sharing support which helps to + improve the performance and resource utilization. Rendernode support + is in place which helps to avoid the constraint of having a running + graphics server as DRM-Master. Encoders are exposing a number rate + control algorithms now. More encoder tuning options like + trellis-quantiztion (h264), slice size control (h264), B-pyramid + prediction(h264), MB-level bitrate control, frame partitioning and + adaptive I/B frame insertion were added, and more pixel formats and + video codecs are supported now. The encoder now also handles + force-key-unit events and can insert frame-packing SEIs for + side-by-side and top-bottom stereoscopic 3D video. - dashdemux can now do adaptive trick play of certain types of DASH streams, meaning it can do fast-forward/fast-rewind of normal (non-I @@ -552,7 +558,6 @@ New element features supports webvtt subtitle streams now and has seen improvements when seeking in live streams. -  - kmssink has seen lots of fixes and improvements in this cycle, including: @@ -662,7 +667,7 @@ all scenarios, e.g. where the OpenGL driver does not properly support multiple sharing contexts in different threads; on Linux Nouveau is known to be broken in this respect, whilst NVIDIA's proprietary drivers and most other drivers generally work fine, and the experience with -Intel's driver seems to be fixed; some proprietary embedded Linux +Intel's driver seems to be mixed; some proprietary embedded Linux drivers don't work; macOS works). GstPhysMemoryAllocator interface moved from -bad to -base @@ -757,7 +762,6 @@ Tracing framework and debugging improvements log handler of course, this just provides this functionality as part of GStreamer. -  - 'fakevideosink is a null sink for video data that advertises video-specific metas ane behaves like a video sink. See above for more details. @@ -786,7 +790,7 @@ Tracing framework and debugging improvements reordering if delay > packet-spacing, so by setting "allow-reordering" to FALSE you guarantee that the packets are in order, while at the same time introducing delay/jitter to them. By - using the new "delay-distribution" property the use can control how + using the new "delay-distribution" property the user can control how the delay applied to delayed packets is distributed: This is either the uniform distribution (as before) or the normal distribution; in addition there is also the gamma distribution which simulates the @@ -810,9 +814,8 @@ Tools GStreamer RTSP server -- Initial support for [RTSP protocol version - 2.0][rtsp2-lightning-talk] was added, which is to the best of our - knowledge the first RTSP 2.0 implementation ever! +- Initial support for RTSP protocol version 2.0 was added, which is to + the best of our knowledge the first RTSP 2.0 implementation ever! - ONVIF audio backchannel support. This is an extension specified by ONVIF that allows RTSP clients (e.g. a control room operator) to @@ -824,7 +827,6 @@ GStreamer RTSP server ONVIF-specific subclasses GstRTSPOnvifServer and GstRTSPOnvifMediaFactory to enable this functionality. -  - The internal server streaming pipeline is now dynamically reconfigured on PLAY based on the transports needed. This means that the server no longer adds the pipeline plumbing for all possible @@ -852,22 +854,125 @@ GStreamer RTSP server GStreamer VAAPI -- this section will be filled in shortly {FIXME!} +- Improve DMABuf's usage, both upstream and dowstream, and + memory:DMABuf caps feature is also negotiated when the dmabuf-based + buffer cannot be mapped onto user-space. + +- VA initialization was fixed when it is used in headless systems. + +- VA display sharing, through GstContext, among the pipeline, has been + improved, adding the possibility to the application share its VA + display (external display) via gst.vaapi.app.Display context. + +- VA display cache was removed. + +- libva's log messages are now redirected into the GStreamer log + handler. + +- Decoders improved their upstream re-negotiation by avoiding to + re-instantiate the internal decoder if stream caps are compatible + with the previous one. + +- When downstream doesn't support GstVideoMeta and the decoded frames + don't have standard strides, they are copied onto system + memory-based buffers. + +- H.264 decoder has a low-latency property, for live streams which + doesn't conform the H.264 specification but still it is required to + push the frames to downstream as soon as possible. + +- As part of the Google Summer of Code 2017 the H.264 decoder drops + MVC and SVC frames when base-only property is enabled. + +- Added support for libva-2.0 (VA-API 1.0). + +- H.264 and H.265 encoders handle Region-Of-Interest metas by adding a + delta-qp for every rectangle within the frame specified by those + metas. + +- Encoders for H.264 and H.265 set the media profile by the downstream + caps. + +- H.264 encoder inserts an AU delimiter for each encoded frame when + aud property is enabled (it is only available for certain drivers + and platforms). + +- H.264 encoder supports for P and B hierarchical prediction modes. + +- All encoders handles a quality-level property, which is a number + from 1 to 8, where a lower number means higher quality, but slower + processing, and vice-versa. + +- VP8 and VP9 encoders support constant bit-rate mode (CBR). + +- VP8, VP9 and H.265 encoders support variable bit-rate mode (VBR). + +- Resurrected GstGLUploadTextureMeta handling for EGL backends. + +- H.265 encoder can configure its number of reference frames via the + refs property. + +- Add H.264 encoder mbbrc property, which controls the macro-block + bitrate as auto, on or off. + +- Add H.264 encoder temporal-levels property, to select the number of + temporal levels to be included. + +- Add to H.264 and H.265 encoders the properties qp-ip and qp-ib, to + handle the QP (quality parameter) difference between the I and P + frames, and the I and B frames, respectively. + +- vaapisink was demoted to marginal rank on Wayland because COGL + cannot display YUV surfaces. GStreamer Editing Services and NLE -- this section will be filled in shortly {FIXME!} +- Handle crossfade in complex scenarios by using the new + compositorpad::crossfade-ratio property + +- Add API allowing to stop using proxies for clips in the timeline + +- Allow management of none square pixel aspect ratios by allowing + application to deal with them in the way they want + +- Misc fixes around the timeline editing API GStreamer validate -- this section will be filled in shortly {FIXME!} +- Handle running scenarios on live pipelines (in the "content sense", + not the GStreamer one) + +- Implement RTSP support with a basic server based on gst-rtsp-server, + and add RTSP 1.0 and 2.0 integration tests + +- Implement a plugin that allows users to implement configurable + tests. It currently can check if a particular element is added a + configurable number of time in the pipeline. In the future that + plugin should allow us to implement specific tests of any kind in a + descriptive way + +- Add a verbosity configuration which behaves in a similare way as the + gst-launch-1.0 verbose flags allowing the informations to be + outputed on any running pipeline when enabling GstValidate. + +- Misc optimization in the launcher, making the tests run much faster. -GStreamer Python Bindings +GStreamer C# bindings -- this section will be filled in shortly {FIXME!} +- Port to the meson build system, autotools support has been removed + +- Use a new GlibSharp version, set as a meson subproject + +- Update wrapped API to GStreamer 1.14 + +- Removed the need for "glue" code + +- Provide a nuget + +- Misc API fixes Build and Dependencies @@ -1058,7 +1163,15 @@ the git 1.14 branch, which is a stable branch. 1.14.0 -1.14.0 is scheduled to be released in early March 2018. +1.14.0 was released on 19 March 2018. + +1.14.1 + +The first 1.14 bug-fix release (1.14.1) is scheduled to be released +around the end of March or beginning of April. + +This release only contains bugfixes and it should be safe to update from +1.14.0. Known Issues @@ -1075,7 +1188,7 @@ unstable development version leading up to the stable 1.16 release. The development of 1.15/1.16 will happen in the git master branch. The plan for the 1.16 development cycle is yet to be confirmed, but it -is expected that feature freeze will be around August 2017 followed by +is expected that feature freeze will be around August 2018 followed by several 1.15 pre-releases and the new 1.16 stable release in September. 1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, @@ -1084,6 +1197,7 @@ several 1.15 pre-releases and the new 1.16 stable release in September. ------------------------------------------------------------------------ _These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge._ +_contributions from Sebastian Dröge, Sreerenj Balachandran, Thibault +Saunier_ _and Víctor Manuel Jáquez Leal._ _License: CC BY-SA 4.0_ diff --git a/RELEASE b/RELEASE index f201622438..729b9301a0 100644 --- a/RELEASE +++ b/RELEASE @@ -1,11 +1,14 @@ -This is GStreamer gst-rtsp-server 1.13.91. +This is GStreamer gst-rtsp-server 1.14.0. -The GStreamer team is pleased to announce the first release candidate for the -upcoming stable 1.14 release series. +The GStreamer team is thrilled to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! -The 1.14 release series adds new features on top of the 1.0, 1.2, 1.4, 1.6, -1.8, 1.10 and 1.12 series and is part of the API and ABI-stable 1.x release -series of the GStreamer multimedia framework. +As always, this release is again packed with new features, bug fixes and +other improvements. + +The 1.14 release series adds new features on top of the 1.12 series and is +part of the API and ABI-stable 1.x release series of the GStreamer multimedia +framework. Full release notes can be found at: diff --git a/configure.ac b/configure.ac index 4ef18c1542..2d533eacd5 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.13.91], +AC_INIT([GStreamer RTSP Server Library], [1.14.0], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1391, 0, 1391) +AS_LIBTOOL(GST, 1400, 0, 1400) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.13.91 -GSTPB_REQ=1.13.91 -GSTPG_REQ=1.13.91 -GSTPD_REQ=1.13.91 +GST_REQ=1.14.0 +GSTPB_REQ=1.14.0 +GSTPG_REQ=1.14.0 +GSTPD_REQ=1.14.0 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 3cdb864df1..7e7c171d8c 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.14.0 + master + + 2018-03-19 + + + + 1.13.91 diff --git a/meson.build b/meson.build index 9643163fec..9682e2639a 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.13.91', + version : '1.14.0', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 034d818ec54ee664d97cfc4aabaa45a7112be43c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 20 Mar 2018 10:21:36 +0000 Subject: [PATCH 1477/1776] Back to development --- NEWS | 1125 +++----------------------------------------------- RELEASE | 15 +- configure.ac | 12 +- meson.build | 2 +- 4 files changed, 71 insertions(+), 1083 deletions(-) diff --git a/NEWS b/NEWS index 64dcb91eaf..5366a0dfcd 100644 --- a/NEWS +++ b/NEWS @@ -1,21 +1,25 @@ -GSTREAMER 1.14 RELEASE NOTES +GSTREAMER 1.16 RELEASE NOTES -The GStreamer team is proud to announce a new major feature release in -the stable 1.x API series of your favourite cross-platform multimedia -framework! +GStreamer 1.16 has not been released yet. It is scheduled for release +around September 2018. -As always, this release is again packed with new features, bug fixes and -other improvements. +1.15.0.1 is the unstable development version that is being developed in +the git master branch and which will eventually result in 1.16. -GStreamer 1.14.0 was released on 19 March 2018. +The plan for the 1.16 development cycle is yet to be confirmed, but it +is expected that feature freeze will be around August 2017 followed by +several 1.15 pre-releases and the new 1.16 stable release in September. -See https://gstreamer.freedesktop.org/releases/1.14/ for the latest +1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, +1.6, 1.4, 1.2 and 1.0 release series. + +See https://gstreamer.freedesktop.org/releases/1.16/ for the latest version of this document. -_Last updated: Monday 19 March 2018, 12:00 UTC (log)_ +_Last updated: Tuesday 20 March 2018, 01:30 UTC (log)_ Introduction @@ -30,1165 +34,154 @@ other improvements. Highlights -- WebRTC support: real-time audio/video streaming to and from web - browsers - -- Experimental support for the next-gen royalty-free AV1 video codec - -- Video4Linux: encoding support, stable element names and faster - device probing - -- Support for the Secure Reliable Transport (SRT) video streaming - protocol - -- RTP Forward Error Correction (FEC) support (ULPFEC) - -- RTSP 2.0 support in rtspsrc and gst-rtsp-server - -- ONVIF audio backchannel support in gst-rtsp-server and rtspsrc - -- playbin3 gapless playback and pre-buffering support - -- tee, our stream splitter/duplication element, now does allocation - query aggregation which is important for efficient data handling and - zero-copy - -- QuickTime muxer has a new prefill recording mode that allows file - import in Adobe Premiere and FinalCut Pro while the file is still - being written. - -- rtpjitterbuffer fast-start mode and timestamp offset adjustment - smoothing - -- souphttpsrc connection sharing, which allows for connection reuse, - cookie sharing, etc. - -- nvdec: new plugin for hardware-accelerated video decoding using the - NVIDIA NVDEC API - -- Adaptive DASH trick play support - -- ipcpipeline: new plugin that allows splitting a pipeline across - multiple processes - -- Major gobject-introspection annotation improvements for large parts - of the library API - -- GStreamer C# bindings have been revived and seen many updates and - fixes - -- The externally maintained GStreamer Rust bindings had many usability - improvements and cover most of the API now. Coinciding with the 1.14 - release, a new release with the 1.14 API additions is happening. +- this section will be completed in due course Major new features and changes -WebRTC support +Noteworthy new API -There is now basic support for WebRTC in GStreamer in form of a new -webrtcbin element and a webrtc support library. This allows you to build -applications that set up connections with and stream to and from other -WebRTC peers, whilst leveraging all of the usual GStreamer features such -as hardware-accelerated encoding and decoding, OpenGL integration, -zero-copy and embedded platform support. And it's easy to build and -integrate into your application too! - -WebRTC enables real-time communication of audio, video and data with web -browsers and native apps, and it is supported or about to be support by -recent versions of all major browsers and operating systems. - -GStreamer's new WebRTC implementation uses libnice for Interactive -Connectivity Establishment (ICE) to figure out the best way to -communicate with other peers, punch holes into firewalls, and traverse -NATs. - -The implementation is not complete, but all the basics are there, and -the code sticks fairly close to the PeerConnection API. Where -functionality is missing it should be fairly obvious where it needs to -go. - -For more details, background and example code, check out Nirbheek's blog -post _GStreamer has grown a WebRTC implementation_, as well as Matthew's -_GStreamer WebRTC_ talk from last year's GStreamer Conference in Prague. +- this section will be filled in in due course New Elements -- webrtcbin handles the transport aspects of webrtc connections (see - WebRTC section above for more details) +- this section will be filled in in due course -- New srtsink and srtsrc elements for the Secure Reliable Transport - (SRT) video streaming protocol, which aims to be easy to use whilst - striking a new balance between reliability and latency for low - latency video streaming use cases. More details about SRT and the - implementation in GStreamer in Olivier's blog post _SRT in - GStreamer_. +New element features and additions -- av1enc and av1dec elements providing experimental support for the - next-generation royalty free video AV1 codec, alongside Matroska - support for it. - -- hlssink2 is a rewrite of the existing hlssink element, but unlike - its predecessor hlssink2 takes elementary streams as input and - handles the muxing to MPEG-TS internally. It also leverages - splitmuxsink internally to do the splitting. This allows more - control over the chunk splitting and sizing process and relies less - on the co-operation of an upstream muxer. Different to the old - hlssink it also works with pre-encoded streams and does not require - close interaction with an upstream encoder element. - -- audiolatency is a new element for measuring audio latency end-to-end - and is useful to measure roundtrip latency including both the - GStreamer-internal latency as well as latency added by external - components or circuits. - -- 'fakevideosink is basically a null sink for video data and very - similar to fakesink, only that it will answer allocation queries and - will advertise support for various video-specific things such - GstVideoMeta, GstVideoCropMeta and GstVideoOverlayCompositionMeta - like a normal video sink would. This is useful for throughput - testing and testing the zero-copy path when creating a new pipeline. - -- ipcpipeline: new plugin that allows the splitting of a pipeline into - multiple processes. Usually a GStreamer pipeline runs in a single - process and parallelism is achieved by distributing workloads using - multiple threads. This means that all elements in the pipeline have - access to all the other elements' memory space however, including - that of any libraries used. For security reasons one might therefore - want to put sensitive parts of a pipeline such as DRM and decryption - handling into a separate process to isolate it from the rest of the - pipeline. This can now be achieved with the new ipcpipeline plugin. - Check out George's blog post _ipcpipeline: Splitting a GStreamer - pipeline into multiple processes_ or his lightning talk from last - year's GStreamer Conference in Prague for all the gory details. - -- proxysink and proxysrc are new elements to pass data from one - pipeline to another within the same process, very similar to the - existing inter elements, but not limited to raw audio and video - data. These new proxy elements are very special in how they work - under the hood, which makes them extremely powerful, but also - dangerous if not used with care. The reason for this is that it's - not just data that's passed from sink to src, but these elements - basically establish a two-way wormhole that passes through queries - and events in both directions, which means caps negotiation and - allocation query driven zero-copy can work through this wormhole. - There are scheduling considerations as well: proxysink forwards - everything into the proxysrc pipeline directly from the proxysink - streaming thread. There is a queue element inside proxysrc to - decouple the source thread from the sink thread, but that queue is - not unlimited, so it is entirely possible that the proxysink - pipeline thread gets stuck in the proxysrc pipeline, e.g. when that - pipeline is paused or stops consuming data for some other reason. - This means that one should always shut down down the proxysrc - pipeline before shutting down the proxysink pipeline, for example. - Or at least take care when shutting down pipelines. Usually this is - not a problem though, especially not in live pipelines. For more - information see Nirbheek's blog post _Decoupling GStreamer - Pipelines_, and also check out out the new ipcpipeline plugin for - sending data from one process to another process (see above). - -- lcms is a new LCMS-based ICC color profile correction element - -- openmptdec is a new OpenMPT-based decoder for module music formats, - such as S3M, MOD, XM, IT. It is built on top of a new - GstNonstreamAudioDecoder base class which aims to unify handling of - files which do not operate a streaming model. The wildmidi plugin - has also been revived and is also implemented on top of this new - base class. - -- The curl plugin has gained a new curlhttpsrc element, which is - useful for testing HTTP protocol version 2.0 amongst other things. - -- The msdk plugin has gained a MPEG-2 video decoder(msdkmpeg2dec), VP8 - decoder(msdkvp8dec) and a VC1/WMV decoder(msdkvc1dec) - -Noteworthy new API - -- GstPromise provides future/promise-like functionality. This is used - in the GStreamer WebRTC implementation. - -- GstReferenceTimestampMeta is a new meta that allows you to attach - additional reference timestamps to a buffer. These timestamps don't - have to relate to the pipeline clock in any way. Examples of this - could be an NTP timestamp when the media was captured, a frame - counter on the capture side or the (local) UNIX timestamp when the - media was captured. The decklink elements make use of this. - -- GstVideoRegionOfInterestMeta: it's now possible to attach generic - free-form element-specific parameters to a region of interest meta, - for example to tell a downstream encoder to use certain codec - parameters for a certain region. - -- gst_bus_get_pollfd can be used to obtain a file descriptor for the - bus that can be poll()-ed on for new messages. This is useful for - integration with non-GLib event loops. - -- gst_get_main_executable_path() can be used by wrapper plugins that - need to find things in the directory where the application - executable is located. In the same vein, - GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE can be used to - signal that plugin dependency paths are relative to the main - executable. - -- pad templates can be told about the GType of the pad subclass of the - pad via newly-added GstPadTemplate API API or the - gst_element_class_add_static_pad_template_with_gtype() convenience - function. gst-inspect-1.0 will use this information to print pad - properties. - -- new convenience functions to iterate over element pads without using - the GstIterator API: gst_element_foreach_pad(), - gst_element_foreach_src_pad(), and gst_element_foreach_sink_pad(). - -- GstBaseSrc and appsrc have gained support for buffer lists: - GstBaseSrc subclasses can use gst_base_src_submit_buffer_list(), and - applications can use gst_app_src_push_buffer_list() to push a buffer - list into appsrc. - -- The GstHarness unit test harness has a couple of new convenience - functions to retrieve all pending data in the harness in form of a - single chunk of memory. - -- GstAudioStreamAlign is a new helper object for audio elements that - handles discontinuity detection and sample alignment. It will align - samples after the previous buffer's samples, but keep track of the - divergence between buffer timestamps and sample position (jitter). - If it exceeds a configurable threshold the alignment will be reset. - This simply factors out code that was duplicated in a number of - elements into a common helper API. - -- The GstVideoEncoder base class implements Quality of Service (QoS) - now. This is disabled by default and must be opted in by setting the - "qos" property, which will make the base class gather statistics - about the real-time performance of the pipeline from downstream - elements (usually sinks that sync the pipeline clock). Subclasses - can then make use of this by checking whether input frames are late - already using gst_video_encoder_get_max_encode_time() If late, they - can just drop them and skip encoding in the hope that the pipeline - will catch up. - -- The GstVideoOverlay interface gained a few helper functions for - installing and handling a "render-rectangle" property on elements - that implement this interface, so that this functionality can also - be used from the command line for testing and debugging purposes. - The property wasn't added to the interface itself as that would - require all implementors to provide it which would not be - backwards-compatible. - -- A new base class, GstNonstreamAudioDecoder for non-stream audio - decoders was added to gst-plugins-bad. This base-class is meant to - be used for audio decoders that require the whole stream to be - loaded first before decoding can start. Examples of this are module - formats (MOD/S3M/XM/IT/etc), C64 SID tunes, video console music - files (GYM/VGM/etc), MIDI files and others. The new openmptdec - element is based on this. - -- Full list of API new in 1.14: -- GStreamer core API new in 1.14 -- GStreamer base library API new in 1.14 -- gst-plugins-base libraries API new in 1.14 -- gst-plugins-bad: no list, mostly GstWebRTC library and new - non-stream audio decoder base class. - -New RTP features and improvements - -- rtpulpfecenc and rtpulpfecdec are new elements that implement - Generic Forward Error Correction (FEC) using Uneven Level Protection - (ULP) as described in RFC 5109. This can be used to protect against - certain types of (non-bursty) packet loss, and important packets - such as those containing codec configuration data or key frames can - be protected with higher redundancy. Equally, packets that are not - particularly important can be given low priority or not be protected - at all. If packets are lost, the receiver can then hopefully restore - the lost packet(s) from the surrounding packets which were received. - This is an alternative to, or rather complementary to, dealing with - packet loss using _retransmission (rtx)_. GStreamer has had - retransmission support for a long time, but Forward Error Correction - allows for different trade-offs: The advantage of Forward Error - Correction is that it doesn't add latency, whereas retransmission - requires at least one more roundtrip to request and hopefully - receive lost packets; Forward Error Correction increases the - required bandwidth however, even in situations where there is no - packet loss at all, so one will typically want to fine-tune the - overhead and mechanisms used based on the characteristics of the - link at the time. - -- New _Redundant Audio Data (RED)_ encoders and decoders for RTP as - per RFC 2198 are also provided (rtpredenc and rtpreddec), mostly for - chrome webrtc compatibility, as chrome will wrap ULPFEC-protected - streams in RED packets, and such streams need to be wrapped and - unwrapped in order to use ULPFEC with chrome. - -- a few new buffer flags for FEC support: - GST_BUFFER_FLAG_NON_DROPPABLE can be used to mark important buffers, - e.g. to flag RTP packets carrying keyframes or codec setup data for - RTP Forward Error Correction purposes, or to prevent still video - frames from being dropped by elements due to QoS. There already is a - GST_BUFFER_FLAG_DROPPABLE. GST_RTP_BUFFER_FLAG_REDUNDANT is used to - signal internally that a packet represents a redundant RTP packet - and used in rtpstorage to hold back the packet and use it only for - recovery from packet loss. Further work is still needed in - payloaders to make use of these. - -- rtpbin now has an option for increasing timestamp offsets gradually: - Sudden large changes to the internal ts_offset may cause timestamps - to move backwards and may also cause visible glitches in media - playback. The new "max-ts-offset-adjustment" and "max-ts-offset" - properties let the application control the rate to apply changes to - ts_offset. There have also been some EOS/BYE handling improvements - in rtpbin. - -- rtpjitterbuffer has a new fast start mode: in many scenarios the - jitter buffer will have to wait for the full configured latency - before it can start outputting packets. The reason for that is that - it often can't know what the sequence number of the first expected - RTP packet is, so it can't know whether a packet earlier than the - earliest packet received will still arrive in future. This behaviour - can now be bypassed by setting the "faststart-min-packets" property - to the number of consecutive packets needed to start, and the jitter - buffer will start output packets as soon as it has N consecutive - packets queued internally. This is particularly useful to get a - first video frame decoded and rendered as quickly as possible. - -- rtpL8pay and rtpL8depay provide RTP payloading and depayloading for - 8-bit raw audio - -New element features - -- playbin3 has gained support or gapless playback via the - "about-to-finish" signal where users can set the uri for the next - item to play. For non-live streams this will be emitted as soon as - the first uri has finished downloading, so with sufficiently large - buffers it is now possible to pre-buffer the next item well ahead of - time (unlike playbin where there would not be a lot of time between - "about-to-finish" emission and the end of the stream). If the stream - format of the next stream is the same as that of the previous - stream, the data will be concatenated via the concat element. - Whether this will result in true gaplessness depends on the - container format and codecs used, there might still be codec-related - gaps between streams with some codecs. - -- tee now does allocation query aggregation, which is important for - zero-copy and efficient data handling, especially for video. Those - who want to drop allocation queries on purpose can use the identity - element's new "drop-allocation" property for that instead. - -- audioconvert now has a "mix-matrix" property, which obsoletes the - audiomixmatrix element. There's also mix matrix support in the audio - conversion and channel mixing API. - -- x264enc: new "insert-vui" property to disable VUI (Video Usability - Information) parameter insertion into the stream, which allows - creation of streams that are compatible with certain legacy hardware - decoders that will refuse to decode in certain combinations of - resolution and VUI parameters; the max. allowed number of B-frames - was also increased from 4 to 16. - -- dvdlpcmdec: has gained support for Blu-Ray audio LPCM. - -- appsrc has gained support for buffer lists (see above) and also seen - some other performance improvements. - -- flvmux has been ported to the GstAggregator base class which means - it can work in defined-latency mode with live input sources and - continue streaming if one of the inputs stops producing data. - -- jpegenc has gained a "snapshot" property just like pngenc to make it - easier to output just a single encoded frame. - -- jpegdec will now handle interlaced MJPEG streams properly and also - handles frames without an End of Image marker better. - -- v4l2: There are now video encoders for VP8, VP9, MPEG4, and H263. - The v4l2 video decoder handles dynamic resolution changes, and the - video4linux device provider now does much faster device probing. The - plugin also no longer uses the libv4l2 library by default, as it has - prevented a lot of interesting use cases like CREATE_BUFS, DMABuf, - usage of TRY_FMT. As the libv4l2 library is totally inactive and not - really maintained, we decided to disable it. This might affect a - small number of cheap/old webcams with custom vendor formats for - which we do not provide conversion in GStreamer. It is possible to - re-enable support for libv4l2 at run-time however, by setting the - environment variable GST_V4L2_USE_LIBV4L2=1. - -- rtspsrc now has support for RTSP protocol version 2.0 as well as - ONVIF audio backchannels (see below for more details). It also - sports a new "accept-certificate" signal for "manually" checking a - TLS certificate for validity. It now also prints RTSP/SDP messages - to the gstreamer debug log instead of stdout. - -- shout2send now uses non-blocking I/O and has a configurable network - operations timeout. - -- splitmuxsink has gained a "split-now" action signal and new - "alignment-threshold" and "use-robust-muxing" properties. If robust - muxing is enabled, it will check and set the muxer's reserved space - properties if present. This is primarily for use with mp4mux's - robust muxing mode. - -- qtmux has a new _prefill recording mode_ which sets up a moov header - with the correct sample positions beforehand, which then allows - software like Adobe Premiere and FinalCut Pro to import the files - while they are still being written to. This only works with constant - framerate I-frame only streams, and for now only support for ProRes - video and raw audio is implemented. Adding support for additional - codecs is just a matter of defining appropriate maximum frame sizes - though. - -- qtmux also supports writing of svmi atoms with stereoscopic video - information now. Trak timescales can be configured on a per-stream - basis using the "trak-timescale" property on the sink pads. Various - new formats can be muxed: MPEG layer 1 and 2, AC3 and Opus, as well - as PNG and VP9. - -- souphttpsrc now does connection sharing by default: it shares its - SoupSession with other elements in the same pipeline via a - GstContext if possible (session-wide settings are all the defaults). - This allows for connection reuse, cookie sharing, etc. Applications - can also force a context to use. In other news, HTTP headers - received from the server are posted as element messages on the bus - now for easier diagnostics, and it's also possible now to use other - types of proxy servers such as SOCKS4 or SOCKS5 proxies, support for - which is implemented directly in gio. Before only HTTP proxies were - allowed. - -- qtmux, mp4mux and matroskamux will now refuse caps changes of input - streams at runtime. This isn't really supported with these - containers (or would have to be implemented differently with a - considerable effort) and doesn't produce valid and spec-compliant - files that will play everywhere. So if you can't guarantee that the - input caps won't change, use a container format that does support on - the fly caps changes for a stream such as MPEG-TS or use - splitmuxsink which can start a new file when the caps change. What - would happen before is that e.g. rtph264depay or rtph265depay would - simply send new SPS/PPS inband even for AVC format, which would then - get muxed into the container as if nothing changed. Some decoders - will handle this just fine, but that's often more luck than by - design. In any case, it's not right, so we disallow it now. - -- matroskamux has Table of Content (TOC) support now (chapters etc.) - and matroskademux TOC support has been improved. matroskademux has - also seen seeking improvements searching for the right cluster and - position. - -- videocrop now uses GstVideoCropMeta if downstream supports it, which - means cropping can be handled more efficiently without any copying. - -- compositor now has support for _crossfade blending_, which can be - used via the new "crossfade-ratio" property on the sink pads. - -- The avwait element has a new "end-timecode" property and posts - "avwait-status" element messages now whenever avwait starts or stops - passing through data (e.g. because target-timecode and end-timecode - respectively have been reached). - -- h265parse and h265parse will try harder to make upstream output the - same caps as downstream requires or prefers, thus avoiding - unnecessary conversion. The parsers also expose chroma format and - bit depth in the caps now. - -- The dtls elements now longer rely on or require the application to - run a GLib main loop that iterates the default main context - (GStreamer plugins should never rely on the application running a - GLib main loop). - -- openh264enc allows to change the encoding bitrate dynamically at - runtime now - -- nvdec is a new plugin for hardware-accelerated video decoding using - the NVIDIA NVDEC API (which replaces the old VDPAU API which is no - longer supported by NVIDIA) - -- The NVIDIA NVENC hardware-accelerated video encoders now support - dynamic bitrate and preset reconfiguration and support the I420 - 4:2:0 video format. It's also possible to configure the gop size via - the new "gop-size" property. - -- The MPEG-TS muxer and demuxer (tsmux, tsdemux) now have support for - JPEG2000 - -- openjpegdec and jpeg2000parse support 2-component images now (gray - with alpha), and jpeg2000parse has gained limited support for - conversion between JPEG2000 stream-formats. (JP2, J2C, JPC) and also - extracts more details such as colorimetry, interlace-mode, - field-order, multiview-mode and chroma siting. - -- The decklink plugin for Blackmagic capture and playback cards have - seen numerous improvements: - -- decklinkaudiosrc and decklinkvideosrc now put hardware reference - timestamp on buffers in form of GstReferenceTimestampMetas. - This can be useful to know on multi-channel cards which frames from - different channels were captured at the same time. - -- decklinkvideosink has gained support for Decklink hardware keying - with two new properties ("keyer-mode" and "keyer-level") to control - the built-in hardware keyer of Decklink cards. - -- decklinkaudiosink has been re-implemented around GstBaseSink instead - of the GstAudioBaseSink base class, since the Decklink APIs don't - fit very well with the GstAudioBaseSink APIs, which used to cause - various problems due to inaccuracies in the clock calculations. - Problems were audio drop-outs and A/V sync going wrong after - pausing/seeking. - -- support for more than 16 devices, without any artificial limit - -- work continued on the msdk plugin for Intel's Media SDK which - enables hardware-accelerated video encoding and decoding on Intel - graphics hardware on Windows or Linux. Added the video memory, - buffer pool, and context/session sharing support which helps to - improve the performance and resource utilization. Rendernode support - is in place which helps to avoid the constraint of having a running - graphics server as DRM-Master. Encoders are exposing a number rate - control algorithms now. More encoder tuning options like - trellis-quantiztion (h264), slice size control (h264), B-pyramid - prediction(h264), MB-level bitrate control, frame partitioning and - adaptive I/B frame insertion were added, and more pixel formats and - video codecs are supported now. The encoder now also handles - force-key-unit events and can insert frame-packing SEIs for - side-by-side and top-bottom stereoscopic 3D video. - -- dashdemux can now do adaptive trick play of certain types of DASH - streams, meaning it can do fast-forward/fast-rewind of normal (non-I - frame only) streams even at high speeds without saturating network - bandwidth or exceeding decoder capabilities. It will keep statistics - and skip keyframes or fragments as needed. See Sebastian's blog post - _DASH trick-mode playback in GStreamer_ for more details. It also - supports webvtt subtitle streams now and has seen improvements when - seeking in live streams. - -- kmssink has seen lots of fixes and improvements in this cycle, - including: - -- Raspberry Pi (vc4) and Xilinx DRM driver support - -- new "render-rectangle" property that can be used from the command - line as well as "display-width" and "display-height", and - "can-scale" properties - -- GstVideoCropMeta support +- this section will be filled in in due course Plugin and library moves -MPEG-1 audio (mp1, mp2, mp3) decoders and encoders moved to -good - -Following the expiration of the last remaining mp3 patents in most -jurisdictions, and the termination of the mp3 licensing program, as well -as the decision by certain distros to officially start shipping full mp3 -decoding and encoding support, these plugins should now no longer be -problematic for most distributors and have therefore been moved from --ugly and -bad to gst-plugins-good. Distributors can still disable these -plugins if desired. - -In particular these are: - -- mpg123audiodec: an mp1/mp2/mp3 audio decoder using libmpg123 -- lamemp3enc: an mp3 encoder using LAME -- twolamemp2enc: an mp2 encoder using TwoLAME - -GstAggregator moved from -bad to core - -GstAggregator has been moved from gst-plugins-bad to the base library in -GStreamer and is now stable API. - -GstAggregator is a new base class for mixers and muxers that have to -handle multiple input pads and aggregate streams into one output stream. -It improves upon the existing GstCollectPads API in that it is a proper -base class which was also designed with live streaming in mind. -GstAggregator subclasses will operate in a mode with defined latency if -any of the inputs are live streams. This ensures that the pipeline won't -stall if any of the inputs stop producing data, and that the configured -maximum latency is never exceeded. - -GstAudioAggregator, audiomixer and audiointerleave moved from -bad to -base - -GstAudioAggregator is a new base class for raw audio mixers and muxers -and is based on GstAggregator (see above). It provides defined-latency -mixing of raw audio inputs and ensures that the pipeline won't stall -even if one of the input streams stops producing data. - -As part of the move to stabilise the API there were some last-minute API -changes and clean-ups, but those should mostly affect internal elements. - -It is used by the audiomixer element, which is a replacement for -'adder', which did not handle live inputs very well and did not align -input streams according to running time. audiomixer should behave much -better in that respect and generally behave as one would expected in -most scenarios. - -Similarly, audiointerleave replaces the 'interleave' element which did -not handle live inputs or non-aligned inputs very robustly. - -GstAudioAggregator and its subclases have gained support for input -format conversion, which does not include sample rate conversion though -as that would add additional latency. Furthermore, GAP events are now -handled correctly. - -We hope to move the video equivalents (GstVideoAggregator and -compositor) to -base in the next cycle, i.e. for 1.16. - -GStreamer OpenGL integration library and plugin moved from -bad to -base - -The GStreamer OpenGL integration library and opengl plugin have moved -from gst-plugins-bad to -base and are now part of the stable API canon. -Not all OpenGL elements have been moved; a few had to be left behind in -gst-plugins-bad in the new openglmixers plugin, because they depend on -the GstVideoAggregator base class which we were not able to move in this -cycle. We hope to reunite these elements with the rest of their family -for 1.16 though. - -This is quite a milestone, thanks to everyone who worked to make this -happen! - -Qt QML and GTK plugins moved from -bad to -good - -The Qt QML-based qmlgl plugin has moved to -good and provides a -qmlglsink video sink element as well as a qmlglsrc element. qmlglsink -renders video into a QQuickItem, and qmlglsrc captures a window from a -QML view and feeds it as video into a pipeline for further processing. -Both elements leverage GStreamer's OpenGL integration. In addition to -the move to -good the following features were added: - -- A proxy object is now used for thread-safe access to the QML widget - which prevents crashes in corner case scenarios: QML can destroy the - video widget at any time, so without this we might be left with a - dangling pointer. - -- EGL is now supported with the X11 backend, which works e.g. on - Freescale imx6 - -The GTK+ plugin has also moved from -bad to -good. It includes gtksink -and gtkglsink which both render video into a GtkWidget. gtksink uses -Cairo for rendering the video, which will work everywhere in all -scenarios but involves an extra memory copy, whereas gtkglsink fully -leverages GStreamer's OpenGL integration, but might not work properly in -all scenarios, e.g. where the OpenGL driver does not properly support -multiple sharing contexts in different threads; on Linux Nouveau is -known to be broken in this respect, whilst NVIDIA's proprietary drivers -and most other drivers generally work fine, and the experience with -Intel's driver seems to be mixed; some proprietary embedded Linux -drivers don't work; macOS works). - -GstPhysMemoryAllocator interface moved from -bad to -base - -GstPhysMemoryAllocator is a marker interface for allocators with -physical address backed memory. +- this section will be filled in in due course Plugin removals -- the sunaudio plugin was removed, since it couldn't ever have been - built or used with GStreamer 1.0, but no one even noticed in all - these years. +- this section will be filled in in due course -- the schroedinger-based Dirac encoder/decoder plugin has been - removed, as there is no longer any upstream or anyone else - maintaining it. Seeing that it's quite a fringe codec it seemed best - to simply remove it. -API removals +Miscellaneous API additions -- some MPEG video parser API in the API unstable codecutils library in - gst-plugins-bad was removed after having been deprecated for 5 - years. +- this section will be filled in in due course + +GstPlayer + +- this section will be filled in in due course Miscellaneous changes -- The video support library has gained support for a few new pixel - formats: -- NV16_10LE32: 10-bit variant of NV16, packed into 32bit words (plus 2 - bits padding) -- NV12_10LE32: 10-bit variant of NV12, packed into 32bit words (plus 2 - bits padding) -- GRAY10_LE32: 10-bit grayscale, packed in 32bit words (plus 2 bits - padding) - -- decodebin, playbin and GstDiscoverer have seen stability - improvements in corner cases such as shutdown while still starting - up or shutdown in error cases (hat tip to the oss-fuzz project). - -- floating reference handling was inconsistent and has been cleaned up - across the board, including annotations. This solves various - long-standing memory leaks in language bindings, which e.g. often - caused elements and pads to be leaked. - -- major gobject-introspection annotation improvements for large parts - of the library API, including nullability of return types and - function parameters, correct types (e.g. strings vs. filenames), - ownership transfer, array length parameters, etc. This allows to use - bigger parts of the GStreamer API to be safely used from dynamic - language bindings (e.g. Python, Javascript) and allows static - bindings (e.g. C#, Rust, Vala) to autogenerate more API bindings - without manual intervention. +- this section will be filled in in due course OpenGL integration -- The GStreamer OpenGL integration library has moved to - gst-plugins-base and is now part of our stable API. - -- new MESA3D GBM BACKEND. On devices with working libdrm support, it - is possible to use Mesa3D's GBM library to set up an EGL context - directly on top of KMS. This makes it possible to use the GStreamer - OpenGL elements without a windowing system if a libdrm- and - Mesa3D-supported GPU is present. - -- Prefer wayland display over X11: As most Wayland compositors support - XWayland, the X11 backend would get selected. - -- gldownload can export dmabufs now, and glupload will advertise - dmabuf as caps feature. +- this section will be filled in in due course Tracing framework and debugging improvements -- NEW MEMORY RINGBUFFER BASED DEBUG LOGGER, useful for long-running - applications or to retrieve diagnostics when encountering an error. - The GStreamer debug logging system provides in-depth debug logging - about what is going on inside a pipeline. When enabled, debug logs - are usually written into a file, printed to the terminal, or handed - off to a log handler installed by the application. However, at - higher debug levels the volume of debug output quickly becomes - unmanageable, which poses a problem in disk-space or bandwidth - restricted environments or with long-running pipelines where a - problem might only manifest itself after multiple days. In those - situations, developers are usually only interested in the most - recent debug log output. The new in-memory ringbuffer logger makes - this easy: just installed it with gst_debug_add_ring_buffer_logger() - and retrieve logs with gst_debug_ring_buffer_logger_get_logs() when - needed. It is possible to limit the memory usage per thread and set - a timeout to determine how long messages are kept around. It was - always possible to implement this in the application with a custom - log handler of course, this just provides this functionality as part - of GStreamer. - -- 'fakevideosink is a null sink for video data that advertises - video-specific metas ane behaves like a video sink. See above for - more details. - -- gst_util_dump_buffer() prints the content of a buffer to stdout. - -- gst_pad_link_get_name() and gst_state_change_get_name() print pad - link return values and state change transition values as strings. - -- The LATENCY TRACER has seen a few improvements: trace records now - contain timestamps which is useful to plot things over time, and - downstream synchronisation time is now excluded from the measured - values. - -- Miniobject refcount tracing and logging was not entirley - thread-safe, there were duplicates or missing entries at times. This - has now been made reliable. - -- The netsim element, which can be used to simulate network jitter, - packet reordering and packet loss, received new features and - improvements: it can now also simulate network congestion using a - token bucket algorithm. This can be enabled via the "max-kbps" - property. Packet reordering can be disabled now via the - "allow-reordering" property: Reordering of packets is not very - common in networks, and the delay functions will always introduce - reordering if delay > packet-spacing, so by setting - "allow-reordering" to FALSE you guarantee that the packets are in - order, while at the same time introducing delay/jitter to them. By - using the new "delay-distribution" property the user can control how - the delay applied to delayed packets is distributed: This is either - the uniform distribution (as before) or the normal distribution; in - addition there is also the gamma distribution which simulates the - delay on wifi networks better. +- this section will be filled in in due course Tools -- gst-inspect-1.0 now prints pad properties for elements that have pad - subclasses with special properties, such as compositor or - audiomixer. This only works for elements that use the newly-added - GstPadTemplate API API or the - gst_element_class_add_static_pad_template_with_gtype() convenience - function to tell GStreamer about the special pad subclass. - -- gst-launch-1.0 now generates a gstreamer pipeline diagram (.dot - file) whenever SIGHUP is sent to it on Linux/*nix systems. - -- gst-discoverer-1.0 can now analyse live streams such as rtsp:// URIs +- this section will be filled in in due course GStreamer RTSP server -- Initial support for RTSP protocol version 2.0 was added, which is to - the best of our knowledge the first RTSP 2.0 implementation ever! - -- ONVIF audio backchannel support. This is an extension specified by - ONVIF that allows RTSP clients (e.g. a control room operator) to - send audio back to the RTSP server (e.g. an IP camera). - Theoretically this could have been done also by using the RECORD - method of the RTSP protocol, but ONVIF chose not to do that, so the - backchannel is set up alongside the other streams. Format - negotiation needs to be done out of band, if needed. Use the new - ONVIF-specific subclasses GstRTSPOnvifServer and - GstRTSPOnvifMediaFactory to enable this functionality. - -- The internal server streaming pipeline is now dynamically - reconfigured on PLAY based on the transports needed. This means that - the server no longer adds the pipeline plumbing for all possible - transports from the start, but only if needed as needed. This - improves performance and memory footprint. - -- rtspclientsink has gained an "accept-certificate" signal for - manually checking a TLS certificate for validity. - -- Fix keep-alive/timeout issue for certain clients using TCP - interleave as transport who don't do keep-alive via some other - method such as periodic RTSP OPTION requests. We now put netaddress - metas on the packets from the TCP interleaved stream, so can map - RTCP packets to the right stream in the server and can handle them - properly. - -- Language bindings improvements: in general there were quite a few - improvements in the gobject-introspection annotations, but we also - extended the permissions API which was not usable from bindings - before. - -- Fix corner case issue where the wrong mount point was found when - there were multiple mount points with a common prefix. +- this section will be filled in in due course GStreamer VAAPI -- Improve DMABuf's usage, both upstream and dowstream, and - memory:DMABuf caps feature is also negotiated when the dmabuf-based - buffer cannot be mapped onto user-space. - -- VA initialization was fixed when it is used in headless systems. - -- VA display sharing, through GstContext, among the pipeline, has been - improved, adding the possibility to the application share its VA - display (external display) via gst.vaapi.app.Display context. - -- VA display cache was removed. - -- libva's log messages are now redirected into the GStreamer log - handler. - -- Decoders improved their upstream re-negotiation by avoiding to - re-instantiate the internal decoder if stream caps are compatible - with the previous one. - -- When downstream doesn't support GstVideoMeta and the decoded frames - don't have standard strides, they are copied onto system - memory-based buffers. - -- H.264 decoder has a low-latency property, for live streams which - doesn't conform the H.264 specification but still it is required to - push the frames to downstream as soon as possible. - -- As part of the Google Summer of Code 2017 the H.264 decoder drops - MVC and SVC frames when base-only property is enabled. - -- Added support for libva-2.0 (VA-API 1.0). - -- H.264 and H.265 encoders handle Region-Of-Interest metas by adding a - delta-qp for every rectangle within the frame specified by those - metas. - -- Encoders for H.264 and H.265 set the media profile by the downstream - caps. - -- H.264 encoder inserts an AU delimiter for each encoded frame when - aud property is enabled (it is only available for certain drivers - and platforms). - -- H.264 encoder supports for P and B hierarchical prediction modes. - -- All encoders handles a quality-level property, which is a number - from 1 to 8, where a lower number means higher quality, but slower - processing, and vice-versa. - -- VP8 and VP9 encoders support constant bit-rate mode (CBR). - -- VP8, VP9 and H.265 encoders support variable bit-rate mode (VBR). - -- Resurrected GstGLUploadTextureMeta handling for EGL backends. - -- H.265 encoder can configure its number of reference frames via the - refs property. - -- Add H.264 encoder mbbrc property, which controls the macro-block - bitrate as auto, on or off. - -- Add H.264 encoder temporal-levels property, to select the number of - temporal levels to be included. - -- Add to H.264 and H.265 encoders the properties qp-ip and qp-ib, to - handle the QP (quality parameter) difference between the I and P - frames, and the I and B frames, respectively. - -- vaapisink was demoted to marginal rank on Wayland because COGL - cannot display YUV surfaces. +- this section will be filled in in due course GStreamer Editing Services and NLE -- Handle crossfade in complex scenarios by using the new - compositorpad::crossfade-ratio property - -- Add API allowing to stop using proxies for clips in the timeline - -- Allow management of none square pixel aspect ratios by allowing - application to deal with them in the way they want - -- Misc fixes around the timeline editing API +- this section will be filled in in due course GStreamer validate -- Handle running scenarios on live pipelines (in the "content sense", - not the GStreamer one) - -- Implement RTSP support with a basic server based on gst-rtsp-server, - and add RTSP 1.0 and 2.0 integration tests - -- Implement a plugin that allows users to implement configurable - tests. It currently can check if a particular element is added a - configurable number of time in the pipeline. In the future that - plugin should allow us to implement specific tests of any kind in a - descriptive way - -- Add a verbosity configuration which behaves in a similare way as the - gst-launch-1.0 verbose flags allowing the informations to be - outputed on any running pipeline when enabling GstValidate. - -- Misc optimization in the launcher, making the tests run much faster. +- this section will be filled in in due course -GStreamer C# bindings +GStreamer Python Bindings -- Port to the meson build system, autotools support has been removed - -- Use a new GlibSharp version, set as a meson subproject - -- Update wrapped API to GStreamer 1.14 - -- Removed the need for "glue" code - -- Provide a nuget - -- Misc API fixes +- this section will be filled in in due course Build and Dependencies -- the new WebRTC support in gst-plugins-bad depends on the GStreamer - elements that ship as part of libnice, and libnice version 1.1.14 is - required. Also the dtls and srtp plugins. - -- gst-plugins-bad no longer depends on the libschroedinger Dirac codec - library. - -- The srtp plugin can now also be built against libsrtp2. - -- some plugins and libraries have moved between modules, see the - _Plugin and_ _library moves_ section above, and their respective - dependencies have moved with them of course, e.g. the GStreamer - OpenGL integration support library and plugin is now in - gst-plugins-base, and mpg123, LAME and twoLAME based audio decoder - and encoder plugins are now in gst-plugins-good. - -- Unify static and dynamic plugin interface and remove plugin specific - static build option: Static and dynamic plugins now have the same - interface. The standard --enable-static/--enable-shared toggle is - sufficient. This allows building static and shared plugins from the - same object files, instead of having to build everything twice. - -- The default plugin entry point has changed. This will only affect - plugins that are recompiled against new GStreamer headers. Binary - plugins using the old entry point will continue to work. However, - plugins that are recompiled must have matching plugin names in - GST_PLUGIN_DEFINE and filenames, as the plugin entry point for - shared plugins is now deduced from the plugin filename. This means - you can no longer have a plugin called foo living in a file called - libfoobar.so or such, the plugin filename needs to match. This might - cause problems with some external third party plugin modules when - they get rebuilt against GStreamer 1.14. - - -Note to packagers and distributors - -A number of libraries, APIs and plugins moved between modules and/or -libraries in different modules between version 1.12.x and 1.14.x, see -the _Plugin and_ _library moves_ section above. Some APIs have seen -minor ABI changes in the course of moving them into the stable APIs -section. - -This means that you should try to ensure that all major GStreamer -modules are synced to the same major version (1.12 or 1.13/1.14) and can -only be upgraded in lockstep, so that your users never end up with a mix -of major versions on their system at the same time, as this may cause -breakages. - -Also, plugins compiled against >= 1.14 headers will not load with -GStreamer <= 1.12 owing to a new plugin entry point (but plugin binaries -built against older GStreamer versions will continue to load with newer -versions of GStreamer of course). - -There is also a small structure size related ABI breakage introduced in -the gst-plugins-bad codecparsers library between version 1.13.90 and -1.13.91. This should "only" affect gstreamer-vaapi, so anyone who ships -the release candidates is advised to upgrade those two modules at the -same time. +- this section will be filled in in due course Platform-specific improvements Android -- ahcsrc (Android camera source) does autofocus now +- this section will be filled in in due course macOS and iOS -- this section will be filled in shortly {FIXME!} +- this section will be filled in in due course Windows -- The GStreamer wasapi plugin was rewritten and should not only be - usable now, but in top shape and suitable for low-latency use cases. - The Windows Audio Session API (WASAPI) is Microsoft's most modern - method for talking with audio devices, and now that the wasapi - plugin is up to scratch it is preferred over the directsound plugin. - The ranks of the wasapisink and wasapisrc elements have been updated - to reflect this. Further improvements include: - -- support for more than 2 channels - -- a new "low-latency" property to enable low-latency operation (which - should always be safe to enable) - -- support for the AudioClient3 API which is only available on Windows - 10: in wasapisink this will be used automatically if available; in - wasapisrc it will have to be enabled explicitly via the - "use-audioclient3" property, as capturing audio with low latency and - without glitches seems to require setting the realtime priority of - the entire pipeline to "critical", which cannot be done from inside - the element, but has to be done in the application. - -- set realtime thread priority to avoid glitches - -- allow opening devices in exclusive mode, which provides much lower - latency compared to shared mode where WASAPI's engine period is - 10ms. This can be activated via the "exclusive" property. - -- There are now GstDeviceProvider implementations for the wasapi and - directsound plugins, so it's now possible to discover both audio - sources and audio sinks on Windows via the GstDeviceMonitor API - -- debug log timestamps are now higher granularity owing to - g_get_monotonic_time() now being used as fallback in - gst_utils_get_timestamp(). Before that, there would sometimes be - 10-20 lines of debug log output sporting the same timestamp. +- this section will be filled in in due course Contributors -Aaron Boxer, Adrián Pardini, Adrien SCH, Akinobu Mita, Alban Bedel, -Alessandro Decina, Alex Ashley, Alicia Boya García, Alistair Buxton, -Alvaro Margulis, Anders Jonsson, Andreas Frisch, Andrejs Vasiljevs, -Andrew Bott, Antoine Jacoutot, Antonio Ospite, Antoni Silvestre, Anton -Obzhirov, Anuj Jaiswal, Arjen Veenhuizen, Arnaud Bonatti, Arun Raghavan, -Ashish Kumar, Aurélien Zanelli, Ayaka, Branislav Katreniak, Branko -Subasic, Brion Vibber, Carlos Rafael Giani, Cassandra Rommel, Chris -Bass, Chris Paulson-Ellis, Christoph Reiter, Claudio Saavedra, Clemens -Lang, Cyril Lashkevich, Daniel van Vugt, Dave Craig, Dave Johnstone, -David Evans, David Schleef, Deepak Srivastava, Dimitrios Katsaros, -Dmitry Zhadinets, Dongil Park, Dustin Spicuzza, Eduard Sinelnikov, -Edward Hervey, Enrico Jorns, Eunhae Choi, Ezequiel Garcia, fengalin, -Filippo Argiolas, Florent Thiéry, Florian Zwoch, Francisco Velazquez, -François Laignel, fvanzile, George Kiagiadakis, Georg Lippitsch, Graham -Leggett, Guillaume Desmottes, Gurkirpal Singh, Gwang Yoon Hwang, Gwenole -Beauchesne, Haakon Sporsheim, Haihua Hu, Håvard Graff, Heekyoung Seo, -Heinrich Fink, Holger Kaelberer, Hoonhee Lee, Hosang Lee, Hyunjun Ko, -Ian Jamison, James Stevenson, Jan Alexander Steffens (heftig), Jan -Schmidt, Jason Lin, Jens Georg, Jeremy Hiatt, Jérôme Laheurte, Jimmy -Ohn, Jochen Henneberg, John Ludwig, John Nikolaides, Jonathan Karlsson, -Josep Torra, Juan Navarro, Juan Pablo Ugarte, Julien Isorce, Jun Xie, -Jussi Kukkonen, Justin Kim, Lasse Laursen, Lubosz Sarnecki, Luc -Deschenaux, Luis de Bethencourt, Marcin Lewandowski, Mario Alfredo -Carrillo Arevalo, Mark Nauwelaerts, Martin Kelly, Matej Knopp, Mathieu -Duponchelle, Matteo Valdina, Matt Fischer, Matthew Waters, Matthieu -Bouron, Matthieu Crapet, Matt Staples, Michael Catanzaro, Michael -Olbrich, Michael Shigorin, Michael Tretter, Michał Dębski, Michał Górny, -Michele Dionisio, Miguel París, Mikhail Fludkov, Munez, Nael Ouedraogo, -Neos3452, Nicholas Panayis, Nick Kallen, Nicola Murino, Nicolas -Dechesne, Nicolas Dufresne, Nirbheek Chauhan, Ognyan Tonchev, Ole André -Vadla Ravnås, Oleksij Rempel, Olivier Crête, Omar Akkila, Orestis -Floros, Patricia Muscalu, Patrick Radizi, Paul Kim, Per-Erik Brodin, -Peter Seiderer, Philip Craig, Philippe Normand, Philippe Renon, Philipp -Zabel, Pierre Pouzol, Piotr Drąg, Ponnam Srinivas, Pratheesh Gangadhar, -Raimo Järvi, Ramprakash Jelari, Ravi Kiran K N, Reynaldo H. Verdejo -Pinochet, Rico Tzschichholz, Robert Rosengren, Roland Peffer, Руслан -Ижбулатов, Sam Hurst, Sam Thursfield, Sangkyu Park, Sanjay NM, Satya -Prakash Gupta, Scott D Phillips, Sean DuBois, Sebastian Cote, Sebastian -Dröge, Sebastian Rasmussen, Sejun Park, Sergey Borovkov, Seungha Yang, -Shakin Chou, Shinya Saito, Simon Himmelbauer, Sky Juan, Song Bing, -Sreerenj Balachandran, Stefan Kost, Stefan Popa, Stefan Sauer, Stian -Selnes, Thiago Santos, Thibault Saunier, Thijs Vermeir, Tim Allen, -Tim-Philipp Müller, Ting-Wei Lan, Tomas Rataj, Tom Bailey, Tonu Jaansoo, -U. Artie Eoff, Umang Jain, Ursula Maplehurst, VaL Doroshchuk, Vasilis -Liaskovitis, Víctor Manuel Jáquez Leal, vijay, Vincent Penquerc'h, -Vineeth T M, Vivia Nikolaidou, Wang Xin-yu (王昕宇), Wei Feng, Wim -Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier Claessens, -XuGuangxin, Yasushi SHOJI, Yi A Wang, Youness Alaoui, +- this section will be filled in in due course ... and many others who have contributed bug reports, translations, sent suggestions or helped testing. -Bugs fixed in 1.14 +Bugs fixed in 1.16 -More than 800 bugs have been fixed during the development of 1.14. +- this section will be filled in in due course + +More than XXX bugs have been fixed during the development of 1.16. This list does not include issues that have been cherry-picked into the -stable 1.12 branch and fixed there as well, all fixes that ended up in -the 1.12 branch are also included in 1.14. +stable 1.16 branch and fixed there as well, all fixes that ended up in +the 1.16 branch are also included in 1.16. This list also does not include issues that have been fixed without a bug report in bugzilla, so the actual number of fixes is much higher. -Stable 1.14 branch +Stable 1.16 branch -After the 1.14.0 release there will be several 1.14.x bug-fix releases +After the 1.16.0 release there will be several 1.16.x bug-fix releases which will contain bug fixes which have been deemed suitable for a stable branch, but no new features or intrusive changes will be added to -a bug-fix release usually. The 1.14.x bug-fix releases will be made from -the git 1.14 branch, which is a stable branch. +a bug-fix release usually. The 1.16.x bug-fix releases will be made from +the git 1.16 branch, which is a stable branch. -1.14.0 +1.16.0 -1.14.0 was released on 19 March 2018. - -1.14.1 - -The first 1.14 bug-fix release (1.14.1) is scheduled to be released -around the end of March or beginning of April. - -This release only contains bugfixes and it should be safe to update from -1.14.0. +1.16.0 is scheduled to be released around September 2018. Known Issues -- The webrtcdsp element (which is unrelated to the newly-landed - GStreamer webrtc support) is currently not shipped as part of the +- The webrtcdsp element is currently not shipped as part of the Windows binary packages due to a build system issue. -Schedule for 1.16 +Schedule for 1.18 Our next major feature release will be 1.16, and 1.15 will be the unstable development version leading up to the stable 1.16 release. The development of 1.15/1.16 will happen in the git master branch. The plan for the 1.16 development cycle is yet to be confirmed, but it -is expected that feature freeze will be around August 2018 followed by +is expected that feature freeze will be around August 2017 followed by several 1.15 pre-releases and the new 1.16 stable release in September. 1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, @@ -1196,8 +189,6 @@ several 1.15 pre-releases and the new 1.16 stable release in September. ------------------------------------------------------------------------ -_These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge, Sreerenj Balachandran, Thibault -Saunier_ _and Víctor Manuel Jáquez Leal._ +_These release notes have been prepared by Tim-Philipp Müller._ _License: CC BY-SA 4.0_ diff --git a/RELEASE b/RELEASE index 729b9301a0..e8b15b2d7d 100644 --- a/RELEASE +++ b/RELEASE @@ -1,18 +1,15 @@ -This is GStreamer gst-rtsp-server 1.14.0. +This is GStreamer gst-rtsp-server 1.15.0.1. -The GStreamer team is thrilled to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! +GStreamer 1.15 is the development version leading up to the next major +stable version which will be 1.16. -As always, this release is again packed with new features, bug fixes and -other improvements. - -The 1.14 release series adds new features on top of the 1.12 series and is +The 1.15 development series adds new features on top of the 1.14 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. -Full release notes can be found at: +Full release notes will one day be found at: - https://gstreamer.freedesktop.org/releases/1.14/ + https://gstreamer.freedesktop.org/releases/1.16/ Binaries for Android, iOS, Mac OS X and Windows will be provided shortly after the release. diff --git a/configure.ac b/configure.ac index 2d533eacd5..ac520a9e07 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.14.0], +AC_INIT([GStreamer RTSP Server Library], [1.15.0.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1400, 0, 1400) +AS_LIBTOOL(GST, 1500, 0, 1500) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.14.0 -GSTPB_REQ=1.14.0 -GSTPG_REQ=1.14.0 -GSTPD_REQ=1.14.0 +GST_REQ=1.15.0.1 +GSTPB_REQ=1.15.0.1 +GSTPG_REQ=1.15.0.1 +GSTPD_REQ=1.15.0.1 dnl *** autotools stuff **** diff --git a/meson.build b/meson.build index 9682e2639a..775940fded 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.14.0', + version : '1.15.0.1', meson_version : '>= 0.33.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 3d21e8d4c89a5428c6caed13fec86e2568c895ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 20 Mar 2018 16:21:37 +0200 Subject: [PATCH 1478/1776] rtsp-media-factory-uri: Fix compilation with latest GLib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rtsp-media-factory-uri.c: In function ‘rtsp_media_factory_uri_create_element’: rtsp-media-factory-uri.c:621:17: error: assignment from incompatible pointer type [-Werror=incompatible-pointer-types] data->factory = g_object_ref (factory); ^ --- gst/rtsp-server/rtsp-media-factory-uri.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 01f3f990b2..3598dde25a 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -618,7 +618,7 @@ rtsp_media_factory_uri_create_element (GstRTSPMediaFactory * factory, /* keep factory data around */ data = g_new0 (FactoryData, 1); - data->factory = g_object_ref (factory); + data->factory = g_object_ref (urifact); data->pt = 96; g_object_set_data_full (G_OBJECT (element), factory_key, From 3a129300f0e6e7d0336c2d2c315a2b36e052eaf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Thu, 15 Feb 2018 13:26:16 +0100 Subject: [PATCH 1479/1776] rtsp-client:Error handling when equal http session cookie There are some clients that are sending same session cookie on random basis. https://bugzilla.gnome.org/show_bug.cgi?id=753616 --- gst/rtsp-server/rtsp-client.c | 41 ++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 9df4c9bb92..453d5887f1 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -54,6 +54,13 @@ #define GST_RTSP_CLIENT_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_CLIENT, GstRTSPClientPrivate)) +typedef enum +{ + TUNNEL_STATE_UNKNOWN, + TUNNEL_STATE_GET, + TUNNEL_STATE_POST +} GstRTSPTunnelState; + /* locking order: * send_lock, lock, tunnels_lock */ @@ -98,6 +105,7 @@ struct _GstRTSPClientPrivate GstRTSPVersion version; GHashTable *pipelined_requests; /* pipelined_request_id -> session_id */ + GstRTSPTunnelState tstate; }; static GMutex tunnels_lock; @@ -590,6 +598,7 @@ gst_rtsp_client_init (GstRTSPClient * client) g_object_unref); priv->pipelined_requests = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + priv->tstate = TUNNEL_STATE_UNKNOWN; } static GstRTSPFilterResult @@ -4436,7 +4445,7 @@ tunnel_lost (GstRTSPWatch * watch, gpointer user_data) return GST_RTSP_OK; } -static gboolean +static GstRTSPStatusCode handle_tunnel (GstRTSPClient * client) { GstRTSPClientPrivate *priv = client->priv; @@ -4472,6 +4481,8 @@ handle_tunnel (GstRTSPClient * client) g_mutex_lock (&opriv->watch_lock); if (opriv->watch == NULL) goto tunnel_closed; + if (opriv->tstate == priv->tstate) + goto tunnel_duplicate_id; GST_INFO ("client %p: found previous tunnel %p (old %p, new %p)", client, oclient, opriv->connection, priv->connection); @@ -4488,20 +4499,27 @@ handle_tunnel (GstRTSPClient * client) gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); } - return TRUE; + return GST_RTSP_STS_OK; /* ERRORS */ no_tunnelid: { GST_ERROR ("client %p: no tunnelid provided", client); - return FALSE; + return GST_RTSP_STS_SERVICE_UNAVAILABLE; } tunnel_closed: { GST_ERROR ("client %p: tunnel session %s was closed", client, tunnelid); g_mutex_unlock (&opriv->watch_lock); g_object_unref (oclient); - return FALSE; + return GST_RTSP_STS_SERVICE_UNAVAILABLE; + } +tunnel_duplicate_id: + { + GST_ERROR ("client %p: tunnel session %s was duplicate", client, tunnelid); + g_mutex_unlock (&opriv->watch_lock); + g_object_unref (oclient); + return GST_RTSP_STS_BAD_REQUEST; } } @@ -4513,11 +4531,11 @@ tunnel_get (GstRTSPWatch * watch, gpointer user_data) GST_INFO ("client %p: tunnel get (connection %p)", client, client->priv->connection); - if (!handle_tunnel (client)) { - return GST_RTSP_STS_SERVICE_UNAVAILABLE; - } + g_mutex_lock (&client->priv->lock); + client->priv->tstate = TUNNEL_STATE_GET; + g_mutex_unlock (&client->priv->lock); - return GST_RTSP_STS_OK; + return handle_tunnel (client); } static GstRTSPResult @@ -4528,9 +4546,12 @@ tunnel_post (GstRTSPWatch * watch, gpointer user_data) GST_INFO ("client %p: tunnel post (connection %p)", client, client->priv->connection); - if (!handle_tunnel (client)) { + g_mutex_lock (&client->priv->lock); + client->priv->tstate = TUNNEL_STATE_POST; + g_mutex_unlock (&client->priv->lock); + + if (handle_tunnel (client) != GST_RTSP_STS_OK) return GST_RTSP_ERROR; - } return GST_RTSP_OK; } From 7f9b8c2107f3b64eda753ae27e44958ee2020930 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 29 Mar 2018 02:51:02 +0200 Subject: [PATCH 1480/1776] rtspclientsink: Fix client ports for the RTCP backchannel This was broken since the work for delayed transport creation was merged: the creation of the transports string depends on calling stream_get_server_port, which only starts returning something meaningful after a call to stream_allocate_udp_sockets has been made, this function expects a transport that we parse from the transport string ... Significant refactoring is in order, but does not look entirely trivial, for now we put a band aid on and create a second transport string after the stream has been completed, to pass it in the request headers instead of the previous, incomplete one. https://bugzilla.gnome.org/show_bug.cgi?id=794789 --- gst/rtsp-sink/gstrtspclientsink.c | 22 +++++++++++++++++++--- tests/check/gst/rtspclientsink.c | 26 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 358b4e6624..29ac59f1c3 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -3909,9 +3909,6 @@ gst_rtsp_client_sink_setup_streams (GstRTSPClientSink * sink, gboolean async) goto create_request_failed; } - /* select transport */ - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_TRANSPORT, transports); - /* set up keys */ if (cur_profile == GST_RTSP_PROFILE_SAVP || cur_profile == GST_RTSP_PROFILE_SAVPF) { @@ -3952,6 +3949,25 @@ gst_rtsp_client_sink_setup_streams (GstRTSPClientSink * sink, gboolean async) gst_rtsp_stream_set_blocked (stream, FALSE); } + /* FIXME: + * the creation of the transports string depends on + * calling stream_get_server_port, which only starts returning + * something meaningful after a call to stream_allocate_udp_sockets + * has been made, this function expects a transport that we parse + * from the transport string ... + * + * Significant refactoring is in order, but does not look entirely + * trivial, for now we put a band aid on and create a second transport + * string after the stream has been completed, to pass it in + * the request headers instead of the previous, incomplete one. + */ + g_free (transports); + res = gst_rtsp_client_sink_create_transports_string (sink, context, family, + protocols & protocol_masks[mask], cur_profile, &transports); + + /* select transport */ + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_TRANSPORT, transports); + /* handle the code ourselves */ res = gst_rtsp_client_sink_send (sink, info, &request, &response, &code); if (res < 0) diff --git a/tests/check/gst/rtspclientsink.c b/tests/check/gst/rtspclientsink.c index ddafdbae80..f0533070e2 100644 --- a/tests/check/gst/rtspclientsink.c +++ b/tests/check/gst/rtspclientsink.c @@ -38,6 +38,7 @@ static GstRTSPServer *server = NULL; /* tcp port that the test server listens for rtsp requests on */ static gint test_port = 0; +static gint server_send_rtcp_port; /* id of the server's source within the GMainContext */ static guint source_id; @@ -132,6 +133,26 @@ get_server_uri (gint port, const gchar * mount_point) return uri_string; } +static GstRTSPFilterResult +check_transport (GstRTSPStream *stream, GstRTSPStreamTransport *strans, gpointer user_data) +{ + const GstRTSPTransport *trans = gst_rtsp_stream_transport_get_transport (strans); + + server_send_rtcp_port = trans->client_port.max; + + return GST_RTSP_FILTER_KEEP; +} + +static void +new_state_cb (GstRTSPMedia * media, gint state, gpointer user_data) +{ + if (state == GST_STATE_PLAYING) { + GstRTSPStream *stream = gst_rtsp_media_get_stream (media, 0); + + gst_rtsp_stream_transport_filter (stream, (GstRTSPStreamTransportFilterFunc) check_transport, user_data); + } +} + static void media_constructed_cb (GstRTSPMediaFactory * mfactory, GstRTSPMedia * media, gpointer user_data) @@ -139,6 +160,9 @@ media_constructed_cb (GstRTSPMediaFactory * mfactory, GstRTSPMedia * media, GstElement **p_sink = user_data; GstElement *bin; + g_signal_connect (media, "new-state", + G_CALLBACK (new_state_cb), user_data); + bin = gst_rtsp_media_get_element (media); *p_sink = gst_bin_get_by_name (GST_BIN (bin), "sink"); GST_INFO ("media constructed!: %" GST_PTR_FORMAT, *p_sink); @@ -193,6 +217,8 @@ GST_START_TEST (test_record) iterate (); + fail_unless (server_send_rtcp_port != 0); + /* check received data (we assume every buffer created by audiotestsrc and * subsequently encoded by mulawenc results in exactly one RTP packet) */ for (i = 0; i < RECORD_N_BUFS; ++i) { From a093f4442b01f3ec670567c0cbaba33a7b35f233 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 29 Mar 2018 16:06:31 +0200 Subject: [PATCH 1481/1776] rtsp-stream: extract handle_keymgmt from rtsp-client rtspclientsink will also need to parse KeyMgmt headers sent by the server to decrypt the RTCP backchannel stream https://bugzilla.gnome.org/show_bug.cgi?id=794813 --- gst/rtsp-server/rtsp-client.c | 263 +-------------------------------- gst/rtsp-server/rtsp-stream.c | 269 ++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 3 + 3 files changed, 273 insertions(+), 262 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 453d5887f1..a34d1e7eee 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2021,267 +2021,6 @@ make_server_transport (GstRTSPClient * client, GstRTSPMedia * media, return st; } -#define AES_128_KEY_LEN 16 -#define AES_256_KEY_LEN 32 - -#define HMAC_32_KEY_LEN 4 -#define HMAC_80_KEY_LEN 10 - -static gboolean -mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy) -{ - const gchar *srtp_cipher; - const gchar *srtp_auth; - const GstMIKEYPayload *sp; - guint i; - - /* loop over Security policy until we find one containing policy */ - for (i = 0;; i++) { - if ((sp = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, i)) == NULL) - break; - - if (((GstMIKEYPayloadSP *) sp)->policy == policy) - break; - } - - /* the default ciphers */ - srtp_cipher = "aes-128-icm"; - srtp_auth = "hmac-sha1-80"; - - /* now override the defaults with what is in the Security Policy */ - if (sp != NULL) { - guint len; - - /* collect all the params and go over them */ - len = gst_mikey_payload_sp_get_n_params (sp); - for (i = 0; i < len; i++) { - const GstMIKEYPayloadSPParam *param = - gst_mikey_payload_sp_get_param (sp, i); - - switch (param->type) { - case GST_MIKEY_SP_SRTP_ENC_ALG: - switch (param->val[0]) { - case 0: - srtp_cipher = "null"; - break; - case 2: - case 1: - srtp_cipher = "aes-128-icm"; - break; - default: - break; - } - break; - case GST_MIKEY_SP_SRTP_ENC_KEY_LEN: - switch (param->val[0]) { - case AES_128_KEY_LEN: - srtp_cipher = "aes-128-icm"; - break; - case AES_256_KEY_LEN: - srtp_cipher = "aes-256-icm"; - break; - default: - break; - } - break; - case GST_MIKEY_SP_SRTP_AUTH_ALG: - switch (param->val[0]) { - case 0: - srtp_auth = "null"; - break; - case 2: - case 1: - srtp_auth = "hmac-sha1-80"; - break; - default: - break; - } - break; - case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN: - switch (param->val[0]) { - case HMAC_32_KEY_LEN: - srtp_auth = "hmac-sha1-32"; - break; - case HMAC_80_KEY_LEN: - srtp_auth = "hmac-sha1-80"; - break; - default: - break; - } - break; - case GST_MIKEY_SP_SRTP_SRTP_ENC: - break; - case GST_MIKEY_SP_SRTP_SRTCP_ENC: - break; - default: - break; - } - } - } - /* now configure the SRTP parameters */ - gst_caps_set_simple (caps, - "srtp-cipher", G_TYPE_STRING, srtp_cipher, - "srtp-auth", G_TYPE_STRING, srtp_auth, - "srtcp-cipher", G_TYPE_STRING, srtp_cipher, - "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL); - - return TRUE; -} - -static gboolean -handle_mikey_data (GstRTSPClient * client, GstRTSPContext * ctx, - guint8 * data, gsize size) -{ - GstMIKEYMessage *msg; - guint i, n_cs; - GstCaps *caps = NULL; - GstMIKEYPayloadKEMAC *kemac; - const GstMIKEYPayloadKeyData *pkd; - GstBuffer *key; - - /* the MIKEY message contains a CSB or crypto session bundle. It is a - * set of Crypto Sessions protected with the same master key. - * In the context of SRTP, an RTP and its RTCP stream is part of a - * crypto session */ - if ((msg = gst_mikey_message_new_from_data (data, size, NULL, NULL)) == NULL) - goto parse_failed; - - /* we can only handle SRTP crypto sessions for now */ - if (msg->map_type != GST_MIKEY_MAP_TYPE_SRTP) - goto invalid_map_type; - - /* get the number of crypto sessions. This maps SSRC to its - * security parameters */ - n_cs = gst_mikey_message_get_n_cs (msg); - if (n_cs == 0) - goto no_crypto_sessions; - - /* we also need keys */ - if (!(kemac = (GstMIKEYPayloadKEMAC *) gst_mikey_message_find_payload - (msg, GST_MIKEY_PT_KEMAC, 0))) - goto no_keys; - - /* we don't support encrypted keys */ - if (kemac->enc_alg != GST_MIKEY_ENC_NULL - || kemac->mac_alg != GST_MIKEY_MAC_NULL) - goto unsupported_encryption; - - /* get Key data sub-payload */ - pkd = (const GstMIKEYPayloadKeyData *) - gst_mikey_payload_kemac_get_sub (&kemac->pt, 0); - - key = - gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len), - pkd->key_len); - - /* go over all crypto sessions and create the security policy for each - * SSRC */ - for (i = 0; i < n_cs; i++) { - const GstMIKEYMapSRTP *map = gst_mikey_message_get_cs_srtp (msg, i); - - caps = gst_caps_new_simple ("application/x-srtp", - "ssrc", G_TYPE_UINT, map->ssrc, - "roc", G_TYPE_UINT, map->roc, "srtp-key", GST_TYPE_BUFFER, key, NULL); - mikey_apply_policy (caps, msg, map->policy); - - gst_rtsp_stream_update_crypto (ctx->stream, map->ssrc, caps); - gst_caps_unref (caps); - } - gst_mikey_message_unref (msg); - gst_buffer_unref (key); - - return TRUE; - - /* ERRORS */ -parse_failed: - { - GST_DEBUG_OBJECT (client, "failed to parse MIKEY message"); - return FALSE; - } -invalid_map_type: - { - GST_DEBUG_OBJECT (client, "invalid map type %d", msg->map_type); - goto cleanup_message; - } -no_crypto_sessions: - { - GST_DEBUG_OBJECT (client, "no crypto sessions"); - goto cleanup_message; - } -no_keys: - { - GST_DEBUG_OBJECT (client, "no keys found"); - goto cleanup_message; - } -unsupported_encryption: - { - GST_DEBUG_OBJECT (client, "unsupported key encryption"); - goto cleanup_message; - } -cleanup_message: - { - gst_mikey_message_unref (msg); - return FALSE; - } -} - -#define IS_STRIP_CHAR(c) (g_ascii_isspace ((guchar)(c)) || ((c) == '\"')) - -static void -strip_chars (gchar * str) -{ - gchar *s; - gsize len; - - len = strlen (str); - while (len--) { - if (!IS_STRIP_CHAR (str[len])) - break; - str[len] = '\0'; - } - for (s = str; *s && IS_STRIP_CHAR (*s); s++); - memmove (str, s, len + 1); -} - -/* KeyMgmt = "KeyMgmt" ":" key-mgmt-spec 0*("," key-mgmt-spec) - * key-mgmt-spec = "prot" "=" KMPID ";" ["uri" "=" %x22 URI %x22 ";"] - */ -static gboolean -handle_keymgmt (GstRTSPClient * client, GstRTSPContext * ctx, gchar * keymgmt) -{ - gchar **specs; - gint i, j; - - specs = g_strsplit (keymgmt, ",", 0); - for (i = 0; specs[i]; i++) { - gchar **split; - - split = g_strsplit (specs[i], ";", 0); - for (j = 0; split[j]; j++) { - g_strstrip (split[j]); - if (g_str_has_prefix (split[j], "prot=")) { - g_strstrip (split[j] + 5); - if (!g_str_equal (split[j] + 5, "mikey")) - break; - GST_DEBUG ("found mikey"); - } else if (g_str_has_prefix (split[j], "uri=")) { - strip_chars (split[j] + 4); - GST_DEBUG ("found uri '%s'", split[j] + 4); - } else if (g_str_has_prefix (split[j], "data=")) { - guchar *data; - gsize size; - strip_chars (split[j] + 5); - GST_DEBUG ("found data '%s'", split[j] + 5); - data = g_base64_decode_inplace (split[j] + 5, &size); - handle_mikey_data (client, ctx, data, size); - } - } - g_strfreev (split); - } - g_strfreev (specs); - return TRUE; -} - static gboolean rtsp_ctrl_timeout_cb (gpointer user_data) { @@ -2474,7 +2213,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) /* parse the keymgmt */ if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_KEYMGMT, &keymgmt, 0) == GST_RTSP_OK) { - if (!handle_keymgmt (client, ctx, keymgmt)) + if (!gst_rtsp_stream_handle_keymgmt (ctx->stream, keymgmt)) goto keymgmt_error; } diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 45b623844b..f640d5a033 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4638,3 +4638,272 @@ gst_rtsp_stream_is_receiver (GstRTSPStream * stream) return ret; } + +#define AES_128_KEY_LEN 16 +#define AES_256_KEY_LEN 32 + +#define HMAC_32_KEY_LEN 4 +#define HMAC_80_KEY_LEN 10 + +static gboolean +mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy) +{ + const gchar *srtp_cipher; + const gchar *srtp_auth; + const GstMIKEYPayload *sp; + guint i; + + /* loop over Security policy until we find one containing policy */ + for (i = 0;; i++) { + if ((sp = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, i)) == NULL) + break; + + if (((GstMIKEYPayloadSP *) sp)->policy == policy) + break; + } + + /* the default ciphers */ + srtp_cipher = "aes-128-icm"; + srtp_auth = "hmac-sha1-80"; + + /* now override the defaults with what is in the Security Policy */ + if (sp != NULL) { + guint len; + + /* collect all the params and go over them */ + len = gst_mikey_payload_sp_get_n_params (sp); + for (i = 0; i < len; i++) { + const GstMIKEYPayloadSPParam *param = + gst_mikey_payload_sp_get_param (sp, i); + + switch (param->type) { + case GST_MIKEY_SP_SRTP_ENC_ALG: + switch (param->val[0]) { + case 0: + srtp_cipher = "null"; + break; + case 2: + case 1: + srtp_cipher = "aes-128-icm"; + break; + default: + break; + } + break; + case GST_MIKEY_SP_SRTP_ENC_KEY_LEN: + switch (param->val[0]) { + case AES_128_KEY_LEN: + srtp_cipher = "aes-128-icm"; + break; + case AES_256_KEY_LEN: + srtp_cipher = "aes-256-icm"; + break; + default: + break; + } + break; + case GST_MIKEY_SP_SRTP_AUTH_ALG: + switch (param->val[0]) { + case 0: + srtp_auth = "null"; + break; + case 2: + case 1: + srtp_auth = "hmac-sha1-80"; + break; + default: + break; + } + break; + case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN: + switch (param->val[0]) { + case HMAC_32_KEY_LEN: + srtp_auth = "hmac-sha1-32"; + break; + case HMAC_80_KEY_LEN: + srtp_auth = "hmac-sha1-80"; + break; + default: + break; + } + break; + case GST_MIKEY_SP_SRTP_SRTP_ENC: + break; + case GST_MIKEY_SP_SRTP_SRTCP_ENC: + break; + default: + break; + } + } + } + /* now configure the SRTP parameters */ + gst_caps_set_simple (caps, + "srtp-cipher", G_TYPE_STRING, srtp_cipher, + "srtp-auth", G_TYPE_STRING, srtp_auth, + "srtcp-cipher", G_TYPE_STRING, srtp_cipher, + "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL); + + return TRUE; +} + +static gboolean +handle_mikey_data (GstRTSPStream * stream, guint8 * data, gsize size) +{ + GstMIKEYMessage *msg; + guint i, n_cs; + GstCaps *caps = NULL; + GstMIKEYPayloadKEMAC *kemac; + const GstMIKEYPayloadKeyData *pkd; + GstBuffer *key; + + /* the MIKEY message contains a CSB or crypto session bundle. It is a + * set of Crypto Sessions protected with the same master key. + * In the context of SRTP, an RTP and its RTCP stream is part of a + * crypto session */ + if ((msg = gst_mikey_message_new_from_data (data, size, NULL, NULL)) == NULL) + goto parse_failed; + + /* we can only handle SRTP crypto sessions for now */ + if (msg->map_type != GST_MIKEY_MAP_TYPE_SRTP) + goto invalid_map_type; + + /* get the number of crypto sessions. This maps SSRC to its + * security parameters */ + n_cs = gst_mikey_message_get_n_cs (msg); + if (n_cs == 0) + goto no_crypto_sessions; + + /* we also need keys */ + if (!(kemac = (GstMIKEYPayloadKEMAC *) gst_mikey_message_find_payload + (msg, GST_MIKEY_PT_KEMAC, 0))) + goto no_keys; + + /* we don't support encrypted keys */ + if (kemac->enc_alg != GST_MIKEY_ENC_NULL + || kemac->mac_alg != GST_MIKEY_MAC_NULL) + goto unsupported_encryption; + + /* get Key data sub-payload */ + pkd = (const GstMIKEYPayloadKeyData *) + gst_mikey_payload_kemac_get_sub (&kemac->pt, 0); + + key = + gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len), + pkd->key_len); + + /* go over all crypto sessions and create the security policy for each + * SSRC */ + for (i = 0; i < n_cs; i++) { + const GstMIKEYMapSRTP *map = gst_mikey_message_get_cs_srtp (msg, i); + + caps = gst_caps_new_simple ("application/x-srtp", + "ssrc", G_TYPE_UINT, map->ssrc, + "roc", G_TYPE_UINT, map->roc, "srtp-key", GST_TYPE_BUFFER, key, NULL); + mikey_apply_policy (caps, msg, map->policy); + + gst_rtsp_stream_update_crypto (stream, map->ssrc, caps); + gst_caps_unref (caps); + } + gst_mikey_message_unref (msg); + gst_buffer_unref (key); + + return TRUE; + + /* ERRORS */ +parse_failed: + { + GST_DEBUG_OBJECT (stream, "failed to parse MIKEY message"); + return FALSE; + } +invalid_map_type: + { + GST_DEBUG_OBJECT (stream, "invalid map type %d", msg->map_type); + goto cleanup_message; + } +no_crypto_sessions: + { + GST_DEBUG_OBJECT (stream, "no crypto sessions"); + goto cleanup_message; + } +no_keys: + { + GST_DEBUG_OBJECT (stream, "no keys found"); + goto cleanup_message; + } +unsupported_encryption: + { + GST_DEBUG_OBJECT (stream, "unsupported key encryption"); + goto cleanup_message; + } +cleanup_message: + { + gst_mikey_message_unref (msg); + return FALSE; + } +} + +#define IS_STRIP_CHAR(c) (g_ascii_isspace ((guchar)(c)) || ((c) == '\"')) + +static void +strip_chars (gchar * str) +{ + gchar *s; + gsize len; + + len = strlen (str); + while (len--) { + if (!IS_STRIP_CHAR (str[len])) + break; + str[len] = '\0'; + } + for (s = str; *s && IS_STRIP_CHAR (*s); s++); + memmove (str, s, len + 1); +} + +/** + * gst_rtsp_stream_handle_keymgmt: + * @stream: a #GstRTSPStream + * @keymgmt: a keymgmt header + * + * Parse and handle a KeyMgmt header. + * + * Since: 1.16 + */ +/* KeyMgmt = "KeyMgmt" ":" key-mgmt-spec 0*("," key-mgmt-spec) + * key-mgmt-spec = "prot" "=" KMPID ";" ["uri" "=" %x22 URI %x22 ";"] + */ +gboolean +gst_rtsp_stream_handle_keymgmt (GstRTSPStream * stream, const gchar * keymgmt) +{ + gchar **specs; + gint i, j; + + specs = g_strsplit (keymgmt, ",", 0); + for (i = 0; specs[i]; i++) { + gchar **split; + + split = g_strsplit (specs[i], ";", 0); + for (j = 0; split[j]; j++) { + g_strstrip (split[j]); + if (g_str_has_prefix (split[j], "prot=")) { + g_strstrip (split[j] + 5); + if (!g_str_equal (split[j] + 5, "mikey")) + break; + GST_DEBUG ("found mikey"); + } else if (g_str_has_prefix (split[j], "uri=")) { + strip_chars (split[j] + 4); + GST_DEBUG ("found uri '%s'", split[j] + 4); + } else if (g_str_has_prefix (split[j], "data=")) { + guchar *data; + gsize size; + strip_chars (split[j] + 5); + GST_DEBUG ("found data '%s'", split[j] + 5); + data = g_base64_decode_inplace (split[j] + 5, &size); + handle_mikey_data (stream, data, size); + } + } + g_strfreev (split); + } + g_strfreev (specs); + return TRUE; +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index f16c944621..9e3ec54f13 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -301,6 +301,9 @@ gboolean gst_rtsp_stream_is_sender (GstRTSPStream * stream); GST_RTSP_SERVER_API gboolean gst_rtsp_stream_is_receiver (GstRTSPStream * stream); +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_handle_keymgmt (GstRTSPStream *stream, const gchar *keymgmt); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object From ae0e08dac247a517072450213d8f63f801101161 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 29 Mar 2018 16:12:26 +0200 Subject: [PATCH 1482/1776] rtsp-client: Send KeyMgmt header in ANNOUNCE response When sending back an encrypted RTCP back channel, it is useful for the client to know the encryption key. https://bugzilla.gnome.org/show_bug.cgi?id=794813 --- gst/rtsp-server/rtsp-client.c | 87 +++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a34d1e7eee..7a96ad2b0a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2062,6 +2062,73 @@ rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv) g_mutex_unlock (&priv->lock); } +static gchar * +stream_make_keymgmt (GstRTSPClient * client, const gchar *location, GstRTSPStream * stream) +{ + gchar *base64, *result = NULL; + GstMIKEYMessage *mikey_msg; + GstCaps *srtcpparams; + GstElement *rtcp_encoder; + gint srtcp_cipher, srtp_cipher; + gint srtcp_auth, srtp_auth; + GstBuffer *key; + GType ciphertype, authtype; + GEnumClass *cipher_enum, *auth_enum; + GEnumValue *srtcp_cipher_value, *srtp_cipher_value, *srtcp_auth_value, *srtp_auth_value; + + rtcp_encoder = gst_rtsp_stream_get_srtp_encoder (stream); + + if (!rtcp_encoder) + goto done; + + ciphertype = g_type_from_name ("GstSrtpCipherType"); + authtype = g_type_from_name ("GstSrtpAuthType"); + + cipher_enum = g_type_class_ref (ciphertype); + auth_enum = g_type_class_ref (authtype); + + /* We need to bring the encoder to READY so that it generates its key */ + gst_element_set_state (rtcp_encoder, GST_STATE_READY); + + g_object_get (rtcp_encoder, "rtcp-cipher", &srtcp_cipher, "rtcp-auth", &srtcp_auth, + "rtp-cipher", &srtp_cipher, "rtp-auth", &srtp_auth, "key", &key, NULL); + g_object_unref (rtcp_encoder); + + srtcp_cipher_value = g_enum_get_value (cipher_enum, srtcp_cipher); + srtp_cipher_value = g_enum_get_value (cipher_enum, srtp_cipher); + srtcp_auth_value = g_enum_get_value (auth_enum, srtcp_auth); + srtp_auth_value = g_enum_get_value (auth_enum, srtp_auth); + + g_type_class_unref (cipher_enum); + g_type_class_unref (auth_enum); + + srtcpparams = gst_caps_new_simple ("application/x-srtcp", + "srtcp-cipher", G_TYPE_STRING, srtcp_cipher_value->value_nick, + "srtcp-auth", G_TYPE_STRING, srtcp_auth_value->value_nick, + "srtp-cipher", G_TYPE_STRING, srtp_cipher_value->value_nick, + "srtp-auth", G_TYPE_STRING, srtp_auth_value->value_nick, + "srtp-key", GST_TYPE_BUFFER, key, NULL); + + mikey_msg = gst_mikey_message_new_from_caps (srtcpparams); + if (mikey_msg) { + guint send_ssrc; + + gst_rtsp_stream_get_ssrc (stream, &send_ssrc); + gst_mikey_message_add_cs_srtp (mikey_msg, 0, send_ssrc, 0); + + base64 = gst_mikey_message_base64_encode (mikey_msg); + gst_mikey_message_unref (mikey_msg); + + if (base64) { + result = gst_sdp_make_keymgmt (location, base64); + g_free (base64); + } + } + +done: + return result; +} + static gboolean handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) { @@ -2718,6 +2785,7 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) guint8 *data; guint size; GstRTSPStatusCode sig_result; + guint i, n_streams; klass = GST_RTSP_CLIENT_GET_CLASS (client); @@ -2771,13 +2839,26 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!klass->handle_sdp (client, ctx, media, sdp)) goto unhandled_sdp; + gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK, + gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request); + + n_streams = gst_rtsp_media_n_streams (media); + for (i = 0; i < n_streams; i++) { + GstRTSPStream *stream = gst_rtsp_media_get_stream (media, i); + gchar *location = g_strdup_printf ("rtsp://%s%s:8554/stream=%d", priv->server_ip, path, i); + gchar *keymgmt = stream_make_keymgmt (client, location, stream); + + if (keymgmt) + gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_KEYMGMT, keymgmt); + + g_free (location); + g_free (keymgmt); + } + /* we suspend after the announce */ gst_rtsp_media_suspend (media); g_object_unref (media); - gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK, - gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request); - send_message (client, ctx, ctx->response, FALSE); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST], From c683cadcdf8c3d9a2d5952542fb7781d8eacc4ff Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 29 Mar 2018 16:15:45 +0200 Subject: [PATCH 1483/1776] rtspclientsink: Handle the KeyMgmt header in ANNOUNCE response This in order to be able to decrypt the RTCP backchannel https://bugzilla.gnome.org/show_bug.cgi?id=794813 --- gst/rtsp-sink/gstrtspclientsink.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 29ac59f1c3..e622112e27 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -4232,6 +4232,8 @@ gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async) GstSDPMessage *sdp; guint sdp_index = 0; GstSDPInfo info = { 0, }; + gchar *keymgmt; + guint i; const gchar *proto; gchar *sess_id, *client_ip, *str; @@ -4338,6 +4340,17 @@ gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async) &response, NULL)) < 0) goto send_error; + /* parse the keymgmt */ + i = 0; + walk = sink->contexts; + while (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_KEYMGMT, + &keymgmt, i++) == GST_RTSP_OK) { + GstRTSPStreamContext *context = (GstRTSPStreamContext *) walk->data; + walk = g_list_next (walk); + if (!gst_rtsp_stream_handle_keymgmt (context->stream, keymgmt)) + goto keymgmt_error; + } + /* send setup for all streams */ if ((res = gst_rtsp_client_sink_setup_streams (sink, async)) < 0) goto setup_failed; @@ -4414,6 +4427,11 @@ send_error: * taken care of it because we passed NULL for the response code */ goto cleanup_error; } +keymgmt_error: + { + GST_ELEMENT_ERROR (sink, STREAM, DECRYPT_NOKEY, (NULL), + ("Could not handle KeyMgmt")); + } setup_failed: { GST_ERROR_OBJECT (sink, "setup failed"); From 7894328029175ad792df277b1b08c09b201dffb5 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 29 Mar 2018 16:18:42 +0200 Subject: [PATCH 1484/1776] rtspclientsink: add rtx ssrc to mikey's crypto sessions https://bugzilla.gnome.org/show_bug.cgi?id=794813 --- gst/rtsp-sink/gstrtspclientsink.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index e622112e27..a96a627d91 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -3711,13 +3711,17 @@ gst_rtsp_client_sink_stream_make_keymgmt (GstRTSPClientSink * sink, mikey_msg = gst_mikey_message_new_from_caps (context->srtcpparams); if (mikey_msg) { - guint send_ssrc; + guint send_ssrc, send_rtx_ssrc; + const GstStructure *s = gst_caps_get_structure (context->srtcpparams, 0); /* add policy '0' for our SSRC */ gst_rtsp_stream_get_ssrc (context->stream, &send_ssrc); GST_LOG_OBJECT (sink, "Stream %p ssrc %x", context->stream, send_ssrc); gst_mikey_message_add_cs_srtp (mikey_msg, 0, send_ssrc, 0); + if (gst_structure_get_uint (s, "rtx-ssrc", &send_rtx_ssrc)) + gst_mikey_message_add_cs_srtp (mikey_msg, 0, send_rtx_ssrc, 0); + base64 = gst_mikey_message_base64_encode (mikey_msg); gst_mikey_message_unref (mikey_msg); From 988db52016f3c5c75289a4db06331e37232323d3 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 29 Mar 2018 22:49:26 +0200 Subject: [PATCH 1485/1776] rtsp-server: add API to enable retransmission requests "do-retransmission" was previously set when rtx-time != 0, which made no sense as do-retransmission is used to enable the sending of retransmission requests, where as rtx-time is used by the peer to enable storing of buffers in order to respond to retransmission requests. rtsp-media now also provides a callback for the request-aux-receiver signal. https://bugzilla.gnome.org/show_bug.cgi?id=794822 --- docs/libs/gst-rtsp-server-sections.txt | 7 ++ gst/rtsp-server/rtsp-media-factory.c | 53 ++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 7 ++ gst/rtsp-server/rtsp-media.c | 95 ++++++++++++++++++++++++-- gst/rtsp-server/rtsp-media.h | 7 ++ gst/rtsp-server/rtsp-stream.c | 79 +++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 3 + 7 files changed, 246 insertions(+), 5 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 103cd4ae35..956ac0a843 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -178,6 +178,9 @@ gst_rtsp_media_get_buffer_size gst_rtsp_media_set_retransmission_time gst_rtsp_media_get_retransmission_time +gst_rtsp_media_set_do_retransmission +gst_rtsp_media_get_do_retransmission + gst_rtsp_media_set_latency gst_rtsp_media_get_latency @@ -277,6 +280,9 @@ gst_rtsp_media_factory_set_suspend_mode gst_rtsp_media_factory_set_retransmission_time gst_rtsp_media_factory_get_retransmission_time +gst_rtsp_media_factory_set_do_retransmission +gst_rtsp_media_factory_get_do_retransmission + gst_rtsp_media_factory_set_latency gst_rtsp_media_factory_get_latency @@ -617,6 +623,7 @@ gst_rtsp_stream_update_crypto gst_rtsp_stream_set_pt_map gst_rtsp_stream_request_aux_sender +gst_rtsp_stream_request_aux_receiver gst_rtsp_stream_seekable diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 5987d1b923..80208d371e 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -65,6 +65,7 @@ struct _GstRTSPMediaFactoryPrivate GstClockTime rtx_time; guint latency; + gboolean do_retransmission; GMutex medias_lock; GHashTable *medias; /* protected by medias_lock */ @@ -87,6 +88,7 @@ struct _GstRTSPMediaFactoryPrivate #define DEFAULT_LATENCY 200 #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE +#define DEFAULT_DO_RETRANSMISSION FALSE enum { @@ -264,6 +266,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->transport_mode = DEFAULT_TRANSPORT_MODE; priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; + priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; g_mutex_init (&priv->lock); g_mutex_init (&priv->medias_lock); @@ -1085,6 +1088,55 @@ gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory) return res; } +/** + * gst_rtsp_media_factory_set_do_retransmission: + * + * Set whether retransmission requests will be sent for + * receiving media + * + * Since: 1.16 + */ +void +gst_rtsp_media_factory_set_do_retransmission (GstRTSPMediaFactory * factory, + gboolean do_retransmission) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + priv = factory->priv; + + GST_DEBUG_OBJECT (factory, "Do retransmission %d", do_retransmission); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv->do_retransmission = do_retransmission; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_do_retransmission: + * + * Returns: Whether retransmission requests will be sent for receiving media + * + * Since: 1.16 + */ +gboolean +gst_rtsp_media_factory_get_do_retransmission (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + res = priv->do_retransmission; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return res; +} + /** * gst_rtsp_media_factory_set_latency: * @factory: a #GstRTSPMediaFactory @@ -1584,6 +1636,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_profiles (media, profiles); gst_rtsp_media_set_protocols (media, protocols); gst_rtsp_media_set_retransmission_time (media, rtx_time); + gst_rtsp_media_set_do_retransmission (media, priv->do_retransmission); gst_rtsp_media_set_latency (media, latency); gst_rtsp_media_set_transport_mode (media, transport_mode); gst_rtsp_media_set_stop_on_disconnect (media, stop_on_disconnect); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 350dae8919..7fb7fccde8 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -198,6 +198,13 @@ void gst_rtsp_media_factory_set_retransmission_time (GstRTSPMed GST_RTSP_SERVER_API GstClockTime gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory); +GST_RTSP_SERVER_API +void gst_rtsp_media_factory_set_do_retransmission (GstRTSPMediaFactory * factory, + gboolean do_retransmission); + +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_factory_get_do_retransmission (GstRTSPMediaFactory * factory); + GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_latency (GstRTSPMediaFactory * factory, guint latency); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index a1ab7aae6d..217dc35bad 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -139,6 +139,7 @@ struct _GstRTSPMediaPrivate GList *payloads; /* protected by lock */ GstClockTime rtx_time; /* protected by lock */ + gboolean do_retransmission; /* protected by lock */ guint latency; /* protected by lock */ GstClock *clock; /* protected by lock */ GstRTSPPublishClockMode publish_clock_mode; @@ -161,6 +162,8 @@ struct _GstRTSPMediaPrivate #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE +#define DEFAULT_DO_RETRANSMISSION FALSE + /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -444,6 +447,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->transport_mode = DEFAULT_TRANSPORT_MODE; priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; + priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; } static void @@ -1408,9 +1412,6 @@ gst_rtsp_media_set_retransmission_time (GstRTSPMedia * media, GstClockTime time) gst_rtsp_stream_set_retransmission_time (stream, time); } - - if (priv->rtpbin) - g_object_set (priv->rtpbin, "do-retransmission", time > 0, NULL); g_mutex_unlock (&priv->lock); } @@ -1439,6 +1440,54 @@ gst_rtsp_media_get_retransmission_time (GstRTSPMedia * media) return res; } +/** + * gst_rtsp_media_set_do_retransmission: + * + * Set whether retransmission requests will be sent + * + * Since: 1.16 + */ +void +gst_rtsp_media_set_do_retransmission (GstRTSPMedia * media, gboolean do_retransmission) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->do_retransmission = do_retransmission; + + if (priv->rtpbin) + g_object_set (priv->rtpbin, "do-retransmission", do_retransmission, NULL); + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_get_do_retransmission: + * + * Returns: Whether retransmission requests will be sent + * + * Since: 1.16 + */ +gboolean +gst_rtsp_media_get_do_retransmission (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->do_retransmission; + g_mutex_unlock (&priv->lock); + + return res; +} + /** * gst_rtsp_media_set_latency: * @media: a #GstRTSPMedia @@ -2997,6 +3046,7 @@ request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPMedia * media) GstRTSPMediaPrivate *priv = media->priv; GstRTSPStream *stream = NULL; guint i; + GstElement *res = NULL; g_mutex_lock (&priv->lock); for (i = 0; i < priv->streams->len; i++) { @@ -3004,10 +3054,40 @@ request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPMedia * media) if (sessid == gst_rtsp_stream_get_index (stream)) break; + + stream = NULL; } g_mutex_unlock (&priv->lock); - return gst_rtsp_stream_request_aux_sender (stream, sessid); + if (stream) + res = gst_rtsp_stream_request_aux_sender (stream, sessid); + + return res; +} + +static GstElement * +request_aux_receiver (GstElement * rtpbin, guint sessid, GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + GstRTSPStream *stream = NULL; + guint i; + GstElement *res = NULL; + + g_mutex_lock (&priv->lock); + for (i = 0; i < priv->streams->len; i++) { + stream = g_ptr_array_index (priv->streams, i); + + if (sessid == gst_rtsp_stream_get_index (stream)) + break; + + stream = NULL; + } + g_mutex_unlock (&priv->lock); + + if (stream) + res = gst_rtsp_stream_request_aux_receiver (stream, sessid); + + return res; } static gboolean @@ -3034,6 +3114,11 @@ start_prepare (GstRTSPMedia * media) (GCallback) request_aux_sender, media); } + if (priv->do_retransmission) { + g_signal_connect (priv->rtpbin, "request-aux-receiver", + (GCallback) request_aux_receiver, media); + } + if (!gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin, GST_STATE_NULL)) { goto join_bin_failed; @@ -3041,7 +3126,7 @@ start_prepare (GstRTSPMedia * media) } if (priv->rtpbin) - g_object_set (priv->rtpbin, "do-retransmission", priv->rtx_time > 0, NULL); + g_object_set (priv->rtpbin, "do-retransmission", priv->do_retransmission, NULL); for (walk = priv->dynamic; walk; walk = g_list_next (walk)) { GstElement *elem = walk->data; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 4d47517549..84dfb14591 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -281,6 +281,13 @@ void gst_rtsp_media_set_retransmission_time (GstRTSPMedia *med GST_RTSP_SERVER_API GstClockTime gst_rtsp_media_get_retransmission_time (GstRTSPMedia *media); +GST_RTSP_SERVER_API +void gst_rtsp_media_set_do_retransmission (GstRTSPMedia * media, + gboolean do_retransmission); + +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_get_do_retransmission (GstRTSPMedia * media); + GST_RTSP_SERVER_API void gst_rtsp_media_set_latency (GstRTSPMedia *media, guint latency); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index f640d5a033..abc0a5632d 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -124,6 +124,7 @@ struct _GstRTSPStreamPrivate /* retransmission */ GstElement *rtxsend; + GstElement *rtxreceive; guint rtx_pt; GstClockTime rtx_time; @@ -298,6 +299,8 @@ gst_rtsp_stream_finalize (GObject * obj) g_object_unref (priv->pool); if (priv->rtxsend) g_object_unref (priv->rtxsend); + if (priv->rtxreceive) + g_object_unref (priv->rtxreceive); for (i = 0; i < 2; i++) { if (priv->socket_v4[i]) @@ -2328,6 +2331,81 @@ gst_rtsp_stream_request_aux_sender (GstRTSPStream * stream, guint sessid) return bin; } +static void +add_rtx_pt (gpointer key, GstCaps *caps, GstStructure *pt_map) +{ + guint pt = GPOINTER_TO_INT (key); + const GstStructure *s = gst_caps_get_structure (caps, 0); + const gchar *apt; + + if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"), "RTX") && + (apt = gst_structure_get_string (s, "apt"))) { + gst_structure_set (pt_map, apt, G_TYPE_UINT, pt, NULL); + } +} + +/* Call with priv->lock taken */ +static void +update_rtx_receive_pt_map (GstRTSPStream * stream) +{ + GstStructure *pt_map; + + if (!stream->priv->rtxreceive) + goto done; + + pt_map = gst_structure_new_empty ("application/x-rtp-pt-map"); + g_hash_table_foreach (stream->priv->ptmap, (GHFunc) add_rtx_pt, pt_map); + g_object_set (stream->priv->rtxreceive, "payload-type-map", pt_map, NULL); + gst_structure_free (pt_map); + +done: + return; +} + +/** + * gst_rtsp_stream_request_aux_receiver: + * @stream: a #GstRTSPStream + * @sessid: the session id + * + * Creating a rtxreceive bin + * + * Returns: (transfer full) (nullable): a #GstElement. + * + * Since: 1.16 + */ +GstElement * +gst_rtsp_stream_request_aux_receiver (GstRTSPStream * stream, guint sessid) +{ + GstElement *bin; + GstPad *pad; + gchar *name; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + g_mutex_lock (&stream->priv->lock); + + bin = gst_bin_new (NULL); + stream->priv->rtxreceive = gst_element_factory_make ("rtprtxreceive", NULL); + update_rtx_receive_pt_map (stream); + gst_bin_add (GST_BIN (bin), gst_object_ref (stream->priv->rtxreceive)); + + pad = gst_element_get_static_pad (stream->priv->rtxreceive, "src"); + name = g_strdup_printf ("src_%u", sessid); + gst_element_add_pad (bin, gst_ghost_pad_new (name, pad)); + g_free (name); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (stream->priv->rtxreceive, "sink"); + name = g_strdup_printf ("sink_%u", sessid); + gst_element_add_pad (bin, gst_ghost_pad_new (name, pad)); + g_free (name); + gst_object_unref (pad); + + g_mutex_unlock (&stream->priv->lock); + + return bin; +} + /** * gst_rtsp_stream_set_pt_map: * @stream: a #GstRTSPStream @@ -2346,6 +2424,7 @@ gst_rtsp_stream_set_pt_map (GstRTSPStream * stream, guint pt, GstCaps * caps) g_mutex_lock (&priv->lock); g_hash_table_insert (priv->ptmap, GINT_TO_POINTER (pt), gst_caps_ref (caps)); + update_rtx_receive_pt_map (stream); g_mutex_unlock (&priv->lock); } diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 9e3ec54f13..89839f83bf 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -279,6 +279,9 @@ void gst_rtsp_stream_set_pt_map (GstRTSPStream * st GST_RTSP_SERVER_API GstElement * gst_rtsp_stream_request_aux_sender (GstRTSPStream * stream, guint sessid); +GST_RTSP_SERVER_API +GstElement * gst_rtsp_stream_request_aux_receiver (GstRTSPStream * stream, guint sessid); + GST_RTSP_SERVER_API gboolean gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, GSocketFamily family, GstRTSPTransport *transport, gboolean use_client_settings); From 8bf341ad02dfe5d056147320c8cdf85989c5a195 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 30 Mar 2018 23:10:10 +0200 Subject: [PATCH 1486/1776] rtsp-stream: do not take lock in request_aux_receiver Added it right before pushing the previous commit, it is incorrect and deadlocks because this function gets called from the join_bin thread, which already holds the lock, that's the reason why request_aux_sender didn't take the lock either. --- gst/rtsp-server/rtsp-stream.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index abc0a5632d..e4563e1647 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2382,8 +2382,6 @@ gst_rtsp_stream_request_aux_receiver (GstRTSPStream * stream, guint sessid) g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); - g_mutex_lock (&stream->priv->lock); - bin = gst_bin_new (NULL); stream->priv->rtxreceive = gst_element_factory_make ("rtprtxreceive", NULL); update_rtx_receive_pt_map (stream); @@ -2401,8 +2399,6 @@ gst_rtsp_stream_request_aux_receiver (GstRTSPStream * stream, guint sessid) g_free (name); gst_object_unref (pad); - g_mutex_unlock (&stream->priv->lock); - return bin; } From c36d6b477cbee88381ecce45abccbd47309bb7d3 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 30 Mar 2018 23:34:01 +0200 Subject: [PATCH 1487/1776] rtsp-client: do not free string passed to take_header --- gst/rtsp-server/rtsp-client.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 7a96ad2b0a..e2112c1363 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2852,7 +2852,6 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_KEYMGMT, keymgmt); g_free (location); - g_free (keymgmt); } /* we suspend after the announce */ From e3bbd40f0e288968f3b5e8cffa8a90e1018774bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 2 Apr 2018 12:35:04 +0100 Subject: [PATCH 1488/1776] rtspclientsink: make sure not to use freed string Set transport string to NULL after freeing it, so that at worst we get a NULL pointer if constructing a new transport string fails (which shouldn't really fail here). Also check return value of that, just in case. CID 1433768. --- gst/rtsp-sink/gstrtspclientsink.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index a96a627d91..f400a85469 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -3966,9 +3966,13 @@ gst_rtsp_client_sink_setup_streams (GstRTSPClientSink * sink, gboolean async) * the request headers instead of the previous, incomplete one. */ g_free (transports); + transports = NULL; res = gst_rtsp_client_sink_create_transports_string (sink, context, family, protocols & protocol_masks[mask], cur_profile, &transports); + if (res < 0 || transports == NULL) + goto setup_transport_failed; + /* select transport */ gst_rtsp_message_take_header (&request, GST_RTSP_HDR_TRANSPORT, transports); From 48ad01beba0ebb7a91bcd461a610a49453343393 Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Tue, 3 Apr 2018 08:57:47 +0200 Subject: [PATCH 1489/1776] rtsp-media: query the position on active streams if media is complete If the media is complete, i.e. one or more streams have been configured with sinks, then we want to query the position on those streams only. A query on an incomplete stream may return a position that originates from an earlier preroll. https://bugzilla.gnome.org/show_bug.cgi?id=794964 --- gst/rtsp-server/rtsp-media.c | 17 +++++++++++++++++ tests/check/gst/media.c | 11 ++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 217dc35bad..b6d69c6df6 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -228,6 +228,7 @@ static gboolean wait_preroll (GstRTSPMedia * media); static GstElement *find_payload_element (GstElement * payloader); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; +static gboolean check_complete (GstRTSPMedia * media); #define C_ENUM(v) ((gint) v) @@ -593,6 +594,7 @@ gst_rtsp_media_set_property (GObject * object, guint propid, typedef struct { gint64 position; + gboolean complete_streams_only; gboolean ret; } DoQueryPositionData; @@ -601,6 +603,12 @@ do_query_position (GstRTSPStream * stream, DoQueryPositionData * data) { gint64 tmp; + if (data->complete_streams_only && !gst_rtsp_stream_is_complete (stream)) + { + GST_DEBUG_OBJECT (stream, "stream not complete, do not query position"); + return; + } + if (gst_rtsp_stream_query_position (stream, &tmp)) { data->position = MIN (data->position, tmp); data->ret = TRUE; @@ -621,6 +629,15 @@ default_query_position (GstRTSPMedia * media, gint64 * position) data.position = G_MAXINT64; data.ret = FALSE; + /* if the media is complete, i.e. one or more streams have been configured + * with sinks, then we want to query the position on those streams only. + * a query on an incmplete stream may return a position that originates from + * an earlier preroll */ + if (check_complete (media)) + data.complete_streams_only = TRUE; + else + data.complete_streams_only = FALSE; + g_ptr_array_foreach (priv->streams, (GFunc) do_query_position, &data); if (!data.ret) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 38c2dc307d..20527fcd98 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -127,6 +127,8 @@ GST_START_TEST (test_media_seek_one_active_stream) GstRTSPThreadPool *pool; GstRTSPThread *thread; GstRTSPTransport *transport; + char *range_str; + GstRTSPTimeRange *play_range; factory = gst_rtsp_media_factory_new (); fail_if (gst_rtsp_media_factory_is_shared (factory)); @@ -174,7 +176,15 @@ GST_START_TEST (test_media_seek_one_active_stream) /* the media is seekable now */ fail_unless (gst_rtsp_media_seek (media, range)); + /* verify that we got the expected range, 'npt=3.0-' */ + range_str = gst_rtsp_media_get_range_string (media, TRUE, GST_RTSP_RANGE_NPT); + fail_unless (gst_rtsp_range_parse (range_str, &play_range) == GST_RTSP_OK); + fail_unless (play_range->min.seconds == range->min.seconds); + fail_unless (play_range->max.seconds == range->max.seconds); + gst_rtsp_range_free (range); + gst_rtsp_range_free (play_range); + g_free (range_str); fail_unless (gst_rtsp_media_unprepare (media)); g_object_unref (media); @@ -189,7 +199,6 @@ GST_START_TEST (test_media_seek_one_active_stream) GST_END_TEST; - GST_START_TEST (test_media_seek_no_sinks) { GstRTSPMediaFactory *factory; From ef878da70330816701ca7c7017c32bc889b603b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 4 Apr 2018 10:06:06 +0300 Subject: [PATCH 1490/1776] gst: Run everything through gst-indent again --- gst/rtsp-server/rtsp-client.c | 18 ++++++++++++------ gst/rtsp-server/rtsp-media-factory.c | 2 +- gst/rtsp-server/rtsp-media.c | 10 ++++++---- gst/rtsp-server/rtsp-stream.c | 2 +- tests/check/gst/rtspclientsink.c | 15 ++++++++------- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e2112c1363..724065f378 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2063,7 +2063,8 @@ rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv) } static gchar * -stream_make_keymgmt (GstRTSPClient * client, const gchar *location, GstRTSPStream * stream) +stream_make_keymgmt (GstRTSPClient * client, const gchar * location, + GstRTSPStream * stream) { gchar *base64, *result = NULL; GstMIKEYMessage *mikey_msg; @@ -2074,7 +2075,8 @@ stream_make_keymgmt (GstRTSPClient * client, const gchar *location, GstRTSPStrea GstBuffer *key; GType ciphertype, authtype; GEnumClass *cipher_enum, *auth_enum; - GEnumValue *srtcp_cipher_value, *srtp_cipher_value, *srtcp_auth_value, *srtp_auth_value; + GEnumValue *srtcp_cipher_value, *srtp_cipher_value, *srtcp_auth_value, + *srtp_auth_value; rtcp_encoder = gst_rtsp_stream_get_srtp_encoder (stream); @@ -2090,8 +2092,9 @@ stream_make_keymgmt (GstRTSPClient * client, const gchar *location, GstRTSPStrea /* We need to bring the encoder to READY so that it generates its key */ gst_element_set_state (rtcp_encoder, GST_STATE_READY); - g_object_get (rtcp_encoder, "rtcp-cipher", &srtcp_cipher, "rtcp-auth", &srtcp_auth, - "rtp-cipher", &srtp_cipher, "rtp-auth", &srtp_auth, "key", &key, NULL); + g_object_get (rtcp_encoder, "rtcp-cipher", &srtcp_cipher, "rtcp-auth", + &srtcp_auth, "rtp-cipher", &srtp_cipher, "rtp-auth", &srtp_auth, "key", + &key, NULL); g_object_unref (rtcp_encoder); srtcp_cipher_value = g_enum_get_value (cipher_enum, srtcp_cipher); @@ -2845,11 +2848,14 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) n_streams = gst_rtsp_media_n_streams (media); for (i = 0; i < n_streams; i++) { GstRTSPStream *stream = gst_rtsp_media_get_stream (media, i); - gchar *location = g_strdup_printf ("rtsp://%s%s:8554/stream=%d", priv->server_ip, path, i); + gchar *location = + g_strdup_printf ("rtsp://%s%s:8554/stream=%d", priv->server_ip, path, + i); gchar *keymgmt = stream_make_keymgmt (client, location, stream); if (keymgmt) - gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_KEYMGMT, keymgmt); + gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_KEYMGMT, + keymgmt); g_free (location); } diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 80208d371e..46c0becfa0 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -1098,7 +1098,7 @@ gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory) */ void gst_rtsp_media_factory_set_do_retransmission (GstRTSPMediaFactory * factory, - gboolean do_retransmission) + gboolean do_retransmission) { GstRTSPMediaFactoryPrivate *priv; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b6d69c6df6..3614796bf8 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -228,6 +228,7 @@ static gboolean wait_preroll (GstRTSPMedia * media); static GstElement *find_payload_element (GstElement * payloader); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; + static gboolean check_complete (GstRTSPMedia * media); #define C_ENUM(v) ((gint) v) @@ -603,8 +604,7 @@ do_query_position (GstRTSPStream * stream, DoQueryPositionData * data) { gint64 tmp; - if (data->complete_streams_only && !gst_rtsp_stream_is_complete (stream)) - { + if (data->complete_streams_only && !gst_rtsp_stream_is_complete (stream)) { GST_DEBUG_OBJECT (stream, "stream not complete, do not query position"); return; } @@ -1465,7 +1465,8 @@ gst_rtsp_media_get_retransmission_time (GstRTSPMedia * media) * Since: 1.16 */ void -gst_rtsp_media_set_do_retransmission (GstRTSPMedia * media, gboolean do_retransmission) +gst_rtsp_media_set_do_retransmission (GstRTSPMedia * media, + gboolean do_retransmission) { GstRTSPMediaPrivate *priv; @@ -3143,7 +3144,8 @@ start_prepare (GstRTSPMedia * media) } if (priv->rtpbin) - g_object_set (priv->rtpbin, "do-retransmission", priv->do_retransmission, NULL); + g_object_set (priv->rtpbin, "do-retransmission", priv->do_retransmission, + NULL); for (walk = priv->dynamic; walk; walk = g_list_next (walk)) { GstElement *elem = walk->data; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index e4563e1647..8b7bff7129 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2332,7 +2332,7 @@ gst_rtsp_stream_request_aux_sender (GstRTSPStream * stream, guint sessid) } static void -add_rtx_pt (gpointer key, GstCaps *caps, GstStructure *pt_map) +add_rtx_pt (gpointer key, GstCaps * caps, GstStructure * pt_map) { guint pt = GPOINTER_TO_INT (key); const GstStructure *s = gst_caps_get_structure (caps, 0); diff --git a/tests/check/gst/rtspclientsink.c b/tests/check/gst/rtspclientsink.c index f0533070e2..2647ce8ba3 100644 --- a/tests/check/gst/rtspclientsink.c +++ b/tests/check/gst/rtspclientsink.c @@ -134,9 +134,11 @@ get_server_uri (gint port, const gchar * mount_point) } static GstRTSPFilterResult -check_transport (GstRTSPStream *stream, GstRTSPStreamTransport *strans, gpointer user_data) +check_transport (GstRTSPStream * stream, GstRTSPStreamTransport * strans, + gpointer user_data) { - const GstRTSPTransport *trans = gst_rtsp_stream_transport_get_transport (strans); + const GstRTSPTransport *trans = + gst_rtsp_stream_transport_get_transport (strans); server_send_rtcp_port = trans->client_port.max; @@ -149,7 +151,8 @@ new_state_cb (GstRTSPMedia * media, gint state, gpointer user_data) if (state == GST_STATE_PLAYING) { GstRTSPStream *stream = gst_rtsp_media_get_stream (media, 0); - gst_rtsp_stream_transport_filter (stream, (GstRTSPStreamTransportFilterFunc) check_transport, user_data); + gst_rtsp_stream_transport_filter (stream, + (GstRTSPStreamTransportFilterFunc) check_transport, user_data); } } @@ -160,8 +163,7 @@ media_constructed_cb (GstRTSPMediaFactory * mfactory, GstRTSPMedia * media, GstElement **p_sink = user_data; GstElement *bin; - g_signal_connect (media, "new-state", - G_CALLBACK (new_state_cb), user_data); + g_signal_connect (media, "new-state", G_CALLBACK (new_state_cb), user_data); bin = gst_rtsp_media_get_element (media); *p_sink = gst_bin_get_by_name (GST_BIN (bin), "sink"); @@ -180,8 +182,7 @@ GST_START_TEST (test_record) gint i; mfactory = - start_record_server - ("( rtppcmadepay name=depay0 ! appsink name=sink )"); + start_record_server ("( rtppcmadepay name=depay0 ! appsink name=sink )"); g_signal_connect (mfactory, "media-constructed", G_CALLBACK (media_constructed_cb), &server_sink); From d49edc5582fa701d981ad0b98d76fe445e09bb38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 16 Apr 2018 10:53:52 +0100 Subject: [PATCH 1491/1776] Automatic update of common submodule From 3fa2c9e to ed78bee --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 3fa2c9e372..ed78bee437 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 3fa2c9e372bceec30be91e67fb02b6cb05bed493 +Subproject commit ed78bee437dcbe22e6eef0031d9a29d157c0461f From 9f5d3ee7a8ccf92b883e9e6a31151cb3d45bf7a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 17 Apr 2018 17:47:30 +0300 Subject: [PATCH 1492/1776] Revert "rtsp-server: Switch around sendonly/recvonly attributes" This reverts commit 3d275b1345b76151418e3f56ed014d9089ac1a57. While RFC 3264 (SDP) says that sendonly/recvonly are from the point of view of the requester, the actual RTSP RFCs (RFC 2326 / 7826) disagree and say the opposite, just like the ONVIF standard. Let's follow those RFCs as we're doing RTSP here, and add a property at a later time if needed to switch to the SDP RFC behaviour. https://bugzilla.gnome.org/show_bug.cgi?id=793964 --- gst/rtsp-server/rtsp-onvif-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-onvif-media.c b/gst/rtsp-server/rtsp-onvif-media.c index ecafa7cd48..6e8fd1dbc3 100644 --- a/gst/rtsp-server/rtsp-onvif-media.c +++ b/gst/rtsp-server/rtsp-onvif-media.c @@ -134,12 +134,12 @@ gst_rtsp_onvif_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, if (sinkpad) { GstRTSPOnvifMedia *onvif_media = GST_RTSP_ONVIF_MEDIA (media); - gst_sdp_media_add_attribute (smedia, "recvonly", ""); + gst_sdp_media_add_attribute (smedia, "sendonly", ""); if (onvif_media->priv->backchannel_bandwidth > 0) gst_sdp_media_add_bandwidth (smedia, GST_SDP_BWTYPE_AS, onvif_media->priv->backchannel_bandwidth); } else { - gst_sdp_media_add_attribute (smedia, "sendonly", ""); + gst_sdp_media_add_attribute (smedia, "recvonly", ""); } } } From bfc35ae1aec5582f8086e27205f04e28d54c8954 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 2 Apr 2018 22:49:35 +0200 Subject: [PATCH 1493/1776] Implement support for ULP Forward Error Correction In this initial commit, interface is only exposed for RECORD, further work will be needed in rtspsrc to support this for PLAY. https://bugzilla.gnome.org/show_bug.cgi?id=794911 --- docs/libs/gst-rtsp-server-sections.txt | 7 ++ gst/rtsp-server/rtsp-media.c | 54 +++++++- gst/rtsp-server/rtsp-sdp.c | 91 +++++++++----- gst/rtsp-server/rtsp-stream.c | 164 +++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 22 ++++ gst/rtsp-sink/gstrtspclientsink.c | 62 +++++++++- gst/rtsp-sink/gstrtspclientsink.h | 2 + 7 files changed, 370 insertions(+), 32 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 956ac0a843..3e43110a2a 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -630,6 +630,13 @@ gst_rtsp_stream_seekable GstRTSPStreamTransportFilterFunc gst_rtsp_stream_transport_filter +gst_rtsp_stream_set_ulpfec_pt +gst_rtsp_stream_get_ulpfec_pt +gst_rtsp_stream_set_ulpfec_percentage +gst_rtsp_stream_get_ulpfec_percentage +gst_rtsp_stream_request_ulpfec_decoder +gst_rtsp_stream_request_ulpfec_encoder + GST_RTSP_STREAM_CAST GST_RTSP_STREAM_CLASS_CAST diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 3614796bf8..0427b6bec5 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1517,6 +1517,7 @@ void gst_rtsp_media_set_latency (GstRTSPMedia * media, guint latency) { GstRTSPMediaPrivate *priv; + guint i; g_return_if_fail (GST_IS_RTSP_MEDIA (media)); @@ -1526,8 +1527,19 @@ gst_rtsp_media_set_latency (GstRTSPMedia * media, guint latency) g_mutex_lock (&priv->lock); priv->latency = latency; - if (priv->rtpbin) + if (priv->rtpbin) { g_object_set (priv->rtpbin, "latency", latency, NULL); + + for (i = 0; i < media->priv->streams->len; i++) { + GObject *storage = NULL; + + g_signal_emit_by_name (G_OBJECT (media->priv->rtpbin), "get-storage", + i, &storage); + if (storage) + g_object_set (storage, "size-time", (media->priv->latency + 50) * GST_MSECOND, NULL); + } + } + g_mutex_unlock (&priv->lock); } @@ -3108,6 +3120,38 @@ request_aux_receiver (GstElement * rtpbin, guint sessid, GstRTSPMedia * media) return res; } +static GstElement * +request_fec_decoder (GstElement * rtpbin, guint sessid, GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + GstRTSPStream *stream = NULL; + guint i; + GstElement *res = NULL; + + g_mutex_lock (&priv->lock); + for (i = 0; i < priv->streams->len; i++) { + stream = g_ptr_array_index (priv->streams, i); + + if (sessid == gst_rtsp_stream_get_index (stream)) + break; + + stream = NULL; + } + g_mutex_unlock (&priv->lock); + + if (stream) { + res = gst_rtsp_stream_request_ulpfec_decoder (stream, rtpbin, sessid); + } + + return res; +} + +static void +new_storage_cb (GstElement * rtpbin, GObject * storage, guint sessid, GstRTSPMedia * media) +{ + g_object_set (storage, "size-time", (media->priv->latency + 50) * GST_MSECOND, NULL); +} + static gboolean start_prepare (GstRTSPMedia * media) { @@ -3119,6 +3163,9 @@ start_prepare (GstRTSPMedia * media) if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARING) goto no_longer_preparing; + g_signal_connect (priv->rtpbin, "new-storage", G_CALLBACK (new_storage_cb), media); + g_signal_connect (priv->rtpbin, "request-fec-decoder", G_CALLBACK (request_fec_decoder), media); + /* link streams we already have, other streams might appear when we have * dynamic elements */ for (i = 0; i < priv->streams->len; i++) { @@ -3145,7 +3192,7 @@ start_prepare (GstRTSPMedia * media) if (priv->rtpbin) g_object_set (priv->rtpbin, "do-retransmission", priv->do_retransmission, - NULL); + "do-lost", TRUE, NULL); for (walk = priv->dynamic; walk; walk = g_list_next (walk)) { GstElement *elem = walk->data; @@ -3806,6 +3853,9 @@ default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp) s = gst_caps_get_structure (caps, 0); gst_structure_set_name (s, "application/x-rtp"); + if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"), "ULPFEC")) + gst_structure_set (s, "is-fec", G_TYPE_BOOLEAN, TRUE, NULL); + gst_rtsp_stream_set_pt_map (stream, pt, caps); gst_caps_unref (caps); } diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index ff55c0221a..3795b42fd3 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -373,40 +373,75 @@ gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info, update_sdp_from_tags (stream, smedia); - if ((profile == GST_RTSP_PROFILE_AVPF || profile == GST_RTSP_PROFILE_SAVPF) - && (rtx_time = gst_rtsp_stream_get_retransmission_time (stream))) { - /* ssrc multiplexed retransmit functionality */ - guint rtx_pt = gst_rtsp_stream_get_retransmission_pt (stream); + if (profile == GST_RTSP_PROFILE_AVPF || profile == GST_RTSP_PROFILE_SAVPF) { + if ((rtx_time = gst_rtsp_stream_get_retransmission_time (stream))) { + /* ssrc multiplexed retransmit functionality */ + guint rtx_pt = gst_rtsp_stream_get_retransmission_pt (stream); - if (rtx_pt == 0) { - g_warning ("failed to find an available dynamic payload type. " - "Not adding retransmission"); - } else { - gchar *tmp; - GstStructure *s; - gint caps_pt, caps_rate; + if (rtx_pt == 0) { + g_warning ("failed to find an available dynamic payload type. " + "Not adding retransmission"); + } else { + gchar *tmp; + GstStructure *s; + gint caps_pt, caps_rate; - s = gst_caps_get_structure (caps, 0); - if (s == NULL) - goto no_caps_info; + s = gst_caps_get_structure (caps, 0); + if (s == NULL) + goto no_caps_info; - /* get payload type and clock rate */ - gst_structure_get_int (s, "payload", &caps_pt); - gst_structure_get_int (s, "clock-rate", &caps_rate); + /* get payload type and clock rate */ + gst_structure_get_int (s, "payload", &caps_pt); + gst_structure_get_int (s, "clock-rate", &caps_rate); - tmp = g_strdup_printf ("%d", rtx_pt); - gst_sdp_media_add_format (smedia, tmp); - g_free (tmp); + tmp = g_strdup_printf ("%d", rtx_pt); + gst_sdp_media_add_format (smedia, tmp); + g_free (tmp); - tmp = g_strdup_printf ("%d rtx/%d", rtx_pt, caps_rate); - gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); - g_free (tmp); + tmp = g_strdup_printf ("%d rtx/%d", rtx_pt, caps_rate); + gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); + g_free (tmp); - tmp = - g_strdup_printf ("%d apt=%d;rtx-time=%" G_GINT64_FORMAT, rtx_pt, - caps_pt, GST_TIME_AS_MSECONDS (rtx_time)); - gst_sdp_media_add_attribute (smedia, "fmtp", tmp); - g_free (tmp); + tmp = + g_strdup_printf ("%d apt=%d;rtx-time=%" G_GINT64_FORMAT, rtx_pt, + caps_pt, GST_TIME_AS_MSECONDS (rtx_time)); + gst_sdp_media_add_attribute (smedia, "fmtp", tmp); + g_free (tmp); + } + } + + if (gst_rtsp_stream_get_ulpfec_percentage (stream)) { + guint ulpfec_pt = gst_rtsp_stream_get_ulpfec_pt (stream); + + if (ulpfec_pt == 0) { + g_warning ("failed to find an available dynamic payload type. " + "Not adding ulpfec"); + } else { + gchar *tmp; + GstStructure *s; + gint caps_pt, caps_rate; + + s = gst_caps_get_structure (caps, 0); + if (s == NULL) + goto no_caps_info; + + /* get payload type and clock rate */ + gst_structure_get_int (s, "payload", &caps_pt); + gst_structure_get_int (s, "clock-rate", &caps_rate); + + tmp = g_strdup_printf ("%d", ulpfec_pt); + gst_sdp_media_add_format (smedia, tmp); + g_free (tmp); + + tmp = g_strdup_printf ("%d ulpfec/%d", ulpfec_pt, caps_rate); + gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); + g_free (tmp); + + tmp = + g_strdup_printf ("%d apt=%d", ulpfec_pt, caps_pt); + gst_sdp_media_add_attribute (smedia, "fmtp", tmp); + g_free (tmp); + } } } diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 8b7bff7129..40c12241fc 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -128,6 +128,13 @@ struct _GstRTSPStreamPrivate guint rtx_pt; GstClockTime rtx_time; + /* Forward Error Correction with RFC 5109 */ + GstElement *ulpfec_decoder; + GstElement *ulpfec_encoder; + guint ulpfec_pt; + gboolean ulpfec_enabled; + guint ulpfec_percentage; + /* pool used to manage unicast and multicast addresses */ GstRTSPAddressPool *pool; @@ -301,6 +308,10 @@ gst_rtsp_stream_finalize (GObject * obj) g_object_unref (priv->rtxsend); if (priv->rtxreceive) g_object_unref (priv->rtxreceive); + if (priv->ulpfec_encoder) + gst_object_unref (priv->ulpfec_encoder); + if (priv->ulpfec_decoder) + gst_object_unref (priv->ulpfec_decoder); for (i = 0; i < 2; i++) { if (priv->socket_v4[i]) @@ -2362,6 +2373,28 @@ done: return; } +static void +retrieve_ulpfec_pt (gpointer key, GstCaps *caps, GstElement *ulpfec_decoder) +{ + guint pt = GPOINTER_TO_INT (key); + const GstStructure *s = gst_caps_get_structure (caps, 0); + + if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"), "ULPFEC")) + g_object_set (ulpfec_decoder, "pt", pt, NULL); +} + +static void +update_ulpfec_decoder_pt (GstRTSPStream * stream) +{ + if (!stream->priv->ulpfec_decoder) + goto done; + + g_hash_table_foreach (stream->priv->ptmap, (GHFunc) retrieve_ulpfec_pt, stream->priv->ulpfec_decoder); + +done: + return; +} + /** * gst_rtsp_stream_request_aux_receiver: * @stream: a #GstRTSPStream @@ -2385,6 +2418,7 @@ gst_rtsp_stream_request_aux_receiver (GstRTSPStream * stream, guint sessid) bin = gst_bin_new (NULL); stream->priv->rtxreceive = gst_element_factory_make ("rtprtxreceive", NULL); update_rtx_receive_pt_map (stream); + update_ulpfec_decoder_pt (stream); gst_bin_add (GST_BIN (bin), gst_object_ref (stream->priv->rtxreceive)); pad = gst_element_get_static_pad (stream->priv->rtxreceive, "src"); @@ -4982,3 +5016,133 @@ gst_rtsp_stream_handle_keymgmt (GstRTSPStream * stream, const gchar * keymgmt) g_strfreev (specs); return TRUE; } + + +/** + * gst_rtsp_stream_get_ulpfec_pt: + * + * Returns: the payload type used for ULPFEC protection packets + * + * Since: 1.16 + */ +guint +gst_rtsp_stream_get_ulpfec_pt (GstRTSPStream *stream) +{ + guint res; + + g_mutex_lock (&stream->priv->lock); + res = stream->priv->ulpfec_pt; + g_mutex_unlock (&stream->priv->lock); + + return res; +} + +/** + * gst_rtsp_stream_set_ulpfec_pt: + * + * Set the payload type to be used for ULPFEC protection packets + * + * Since: 1.16 + */ +void +gst_rtsp_stream_set_ulpfec_pt (GstRTSPStream * stream, guint pt) +{ + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + g_mutex_lock (&stream->priv->lock); + stream->priv->ulpfec_pt = pt; + if (stream->priv->ulpfec_encoder) { + g_object_set (stream->priv->ulpfec_encoder, "pt", pt, NULL); + } + g_mutex_unlock (&stream->priv->lock); +} + +/** + * gst_rtsp_stream_request_ulpfec_decoder: + * + * Creating a rtpulpfecdec element + * + * Returns: (transfer full) (nullable): a #GstElement. + * + * Since: 1.16 + */ +GstElement * +gst_rtsp_stream_request_ulpfec_decoder (GstRTSPStream * stream, GstElement *rtpbin, guint sessid) +{ + GObject *internal_storage = NULL; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + stream->priv->ulpfec_decoder = gst_object_ref (gst_element_factory_make ("rtpulpfecdec", NULL)); + + g_signal_emit_by_name (G_OBJECT (rtpbin), "get-internal-storage", sessid, &internal_storage); + g_object_set (stream->priv->ulpfec_decoder, "storage", internal_storage, NULL); + g_object_unref (internal_storage); + update_ulpfec_decoder_pt (stream); + + return stream->priv->ulpfec_decoder; +} + +/** + * gst_rtsp_stream_request_ulpfec_encoder: + * + * Creating a rtpulpfecenc element + * + * Returns: (transfer full) (nullable): a #GstElement. + * + * Since: 1.16 + */ +GstElement * +gst_rtsp_stream_request_ulpfec_encoder (GstRTSPStream * stream, guint sessid) +{ + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + if (!stream->priv->ulpfec_percentage) + return NULL; + + stream->priv->ulpfec_encoder = gst_object_ref (gst_element_factory_make ("rtpulpfecenc", NULL)); + + g_object_set (stream->priv->ulpfec_encoder, "pt", stream->priv->ulpfec_pt, "percentage", stream->priv->ulpfec_percentage, NULL); + + return stream->priv->ulpfec_encoder; +} + +/** + * gst_rtsp_stream_set_ulpfec_percentage: + * + * Sets the amount of redundancy to apply when creating ULPFEC + * protection packets. + * + * Since: 1.16 + */ +void +gst_rtsp_stream_set_ulpfec_percentage (GstRTSPStream *stream, guint percentage) +{ + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + g_mutex_lock (&stream->priv->lock); + stream->priv->ulpfec_percentage = percentage; + if (stream->priv->ulpfec_encoder) { + g_object_set (stream->priv->ulpfec_encoder, "percentage", percentage, NULL); + } + g_mutex_unlock (&stream->priv->lock); +} + +/** + * gst_rtsp_stream_get_ulpfec_percentage: + * + * Returns: the amount of redundancy applied when creating ULPFEC + * protection packets. + * + * Since: 1.16 + */ +guint +gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream *stream) +{ + guint res; + + g_mutex_lock (&stream->priv->lock); + res = stream->priv->ulpfec_percentage; + g_mutex_unlock (&stream->priv->lock); + + return res; +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 89839f83bf..1f527a462d 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -307,6 +307,28 @@ gboolean gst_rtsp_stream_is_receiver (GstRTSPStream * stream); GST_RTSP_SERVER_API gboolean gst_rtsp_stream_handle_keymgmt (GstRTSPStream *stream, const gchar *keymgmt); +/* ULP Forward Error Correction (RFC 5109) */ +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_get_ulpfec_enabled (GstRTSPStream *stream); + +GST_RTSP_SERVER_API +void gst_rtsp_stream_set_ulpfec_pt (GstRTSPStream *stream, guint pt); + +GST_RTSP_SERVER_API +guint gst_rtsp_stream_get_ulpfec_pt (GstRTSPStream *stream); + +GST_RTSP_SERVER_API +GstElement * gst_rtsp_stream_request_ulpfec_decoder (GstRTSPStream *stream, GstElement *rtpbin, guint sessid); + +GST_RTSP_SERVER_API +GstElement * gst_rtsp_stream_request_ulpfec_encoder (GstRTSPStream *stream, guint sessid); + +GST_RTSP_SERVER_API +void gst_rtsp_stream_set_ulpfec_percentage (GstRTSPStream *stream, guint percentage); + +GST_RTSP_SERVER_API +guint gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream *stream); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index f400a85469..5d37c56b80 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -109,14 +109,18 @@ struct _GstRtspClientSinkPad { GstGhostPad parent; GstElement *custom_payloader; + guint ulpfec_percentage; }; enum { PROP_PAD_0, - PROP_PAD_PAYLOADER + PROP_PAD_PAYLOADER, + PROP_PAD_ULPFEC_PERCENTAGE }; +#define DEFAULT_PAD_ULPFEC_PERCENTAGE 0 + static GType gst_rtsp_client_sink_pad_get_type (void); G_DEFINE_TYPE (GstRtspClientSinkPad, gst_rtsp_client_sink_pad, GST_TYPE_GHOST_PAD); @@ -140,6 +144,11 @@ gst_rtsp_client_sink_pad_set_property (GObject * object, guint prop_id, gst_object_ref_sink (pad->custom_payloader); GST_OBJECT_UNLOCK (pad); break; + case PROP_PAD_ULPFEC_PERCENTAGE: + GST_OBJECT_LOCK (pad); + pad->ulpfec_percentage = g_value_get_uint (value); + GST_OBJECT_UNLOCK (pad); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -160,6 +169,11 @@ gst_rtsp_client_sink_pad_get_property (GObject * object, guint prop_id, g_value_set_object (value, pad->custom_payloader); GST_OBJECT_UNLOCK (pad); break; + case PROP_PAD_ULPFEC_PERCENTAGE: + GST_OBJECT_LOCK (pad); + g_value_set_uint (value, pad->ulpfec_percentage); + GST_OBJECT_UNLOCK (pad); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -192,6 +206,11 @@ gst_rtsp_client_sink_pad_class_init (GstRtspClientSinkPadClass * klass) g_param_spec_object ("payloader", "Payloader", "The payloader element to use (NULL = default automatically selected)", GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_klass, PROP_PAD_ULPFEC_PERCENTAGE, + g_param_spec_uint ("ulpfec-percentage", "ULPFEC percentage", + "The percentage of ULP redundancy to apply", 0, 100, DEFAULT_PAD_ULPFEC_PERCENTAGE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void @@ -1099,7 +1118,7 @@ gst_rtsp_client_sink_create_stream (GstRTSPClientSink * sink, GstRTSPStreamContext * context, GstElement * payloader, GstPad * pad) { GstRTSPStream *stream = NULL; - guint pt, aux_pt; + guint pt, aux_pt, ulpfec_pt; GST_OBJECT_LOCK (sink); @@ -1125,6 +1144,11 @@ gst_rtsp_client_sink_create_stream (GstRTSPClientSink * sink, goto no_free_pt; sink->next_dyn_pt++; + ulpfec_pt = sink->next_dyn_pt; + if (ulpfec_pt > 127) + goto no_free_pt; + sink->next_dyn_pt++; + GST_OBJECT_UNLOCK (sink); @@ -1143,6 +1167,9 @@ gst_rtsp_client_sink_create_stream (GstRTSPClientSink * sink, gst_rtsp_stream_set_mtu (stream, sink->rtp_blocksize); gst_rtsp_stream_set_multicast_iface (stream, sink->multi_iface); + gst_rtsp_stream_set_ulpfec_pt (stream, ulpfec_pt); + gst_rtsp_stream_set_ulpfec_percentage (stream, context->ulpfec_percentage); + #if 0 if (priv->pool) gst_rtsp_stream_set_address_pool (stream, priv->pool); @@ -1229,6 +1256,8 @@ gst_rtsp_client_sink_setup_payloader (GstRTSPClientSink * sink, GstPad * pad, gst_object_unref (GST_OBJECT (sinkpad)); GST_RTSP_STATE_UNLOCK (sink); + context->ulpfec_percentage = cspad->ulpfec_percentage; + gst_element_sync_state_with_parent (payloader); gst_object_unref (payloader); @@ -3502,6 +3531,32 @@ request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPClientSink * sink) return ret; } +static GstElement * +request_fec_encoder (GstElement * rtpbin, guint sessid, GstRTSPClientSink * sink) +{ + GstRTSPStream *stream = NULL; + GstElement *ret = NULL; + GList *walk; + + GST_RTSP_STATE_LOCK (sink); + for (walk = sink->contexts; walk; walk = g_list_next (walk)) { + GstRTSPStreamContext *context = (GstRTSPStreamContext *) walk->data; + + if (sessid == gst_rtsp_stream_get_index (context->stream)) { + stream = context->stream; + break; + } + } + + if (stream != NULL) { + ret = gst_rtsp_stream_request_ulpfec_encoder (stream, sessid); + } + + GST_RTSP_STATE_UNLOCK (sink); + + return ret; +} + static gboolean gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink) { @@ -3568,6 +3623,9 @@ gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink) (GCallback) request_aux_sender, sink); } + g_signal_connect (sink->rtpbin, "request-fec-encoder", + (GCallback) request_fec_encoder, sink); + if (!gst_rtsp_stream_join_bin (context->stream, GST_BIN (sink->internal_bin), sink->rtpbin, GST_STATE_PAUSED)) { goto join_bin_failed; diff --git a/gst/rtsp-sink/gstrtspclientsink.h b/gst/rtsp-sink/gstrtspclientsink.h index 9082530725..38230fa305 100644 --- a/gst/rtsp-sink/gstrtspclientsink.h +++ b/gst/rtsp-sink/gstrtspclientsink.h @@ -118,6 +118,8 @@ struct _GstRTSPStreamContext { guint8 channel[2]; GstRTSPStreamTransport *stream_transport; + + guint ulpfec_percentage; }; /** From 808b49cbfc9cd7f5df5b36a6a66f918cfb8c65b6 Mon Sep 17 00:00:00 2001 From: Joakim Johansson Date: Tue, 17 Apr 2018 11:03:11 +0200 Subject: [PATCH 1494/1776] rtsp-client: Fix session timeout When streaming data over TCP then is not the keep-alive functionality working. The reason is that the function do_send_data have changed to boolean but the code is still checking the received result from send_func with GST_RTSP_OK. The result is that a successful send_func will always lead to that do_send_data is returning false and the keep-alive will not be updated. https://bugzilla.gnome.org/show_bug.cgi?id=795321 --- gst/rtsp-server/rtsp-client.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 724065f378..d987c1f978 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1065,7 +1065,7 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) { GstRTSPClientPrivate *priv = client->priv; GstRTSPMessage message = { 0 }; - GstRTSPResult res = GST_RTSP_OK; + gboolean ret = TRUE; GstMapInfo map_info; guint8 *data; guint usize; @@ -1080,7 +1080,7 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) g_mutex_lock (&priv->send_lock); if (priv->send_func) - res = priv->send_func (client, &message, FALSE, priv->send_data); + ret = priv->send_func (client, &message, FALSE, priv->send_data); g_mutex_unlock (&priv->send_lock); gst_rtsp_message_steal_body (&message, &data, &usize); @@ -1088,7 +1088,7 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) gst_rtsp_message_unset (&message); - return res == GST_RTSP_OK; + return ret; } /** From 90d006141a38ca0d9c719f22c49880cfc073016e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 22 Apr 2018 20:09:01 +0100 Subject: [PATCH 1495/1776] configure: check for -good and -bad plugins only in uninstalled setup Avoids confusing configure messages looking or a -good .pc file that doesn't exist. Also use plugindir variables that common macros set while at it. https://bugzilla.gnome.org/show_bug.cgi?id=795466 --- configure.ac | 17 +++++------------ tests/check/Makefile.am | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index ac520a9e07..9d6790b517 100644 --- a/configure.ac +++ b/configure.ac @@ -176,19 +176,12 @@ AG_GST_CHECK_GST_BASE($GST_API_VERSION, [$GST_REQ], [yes]) AG_GST_CHECK_GST_NET($GST_API_VERSION, [$GST_REQ], yes) AG_GST_CHECK_GST_PLUGINS_BASE($GST_API_VERSION, [$GSTPB_REQ], [yes]) -GSTPB_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-base-$GST_API_VERSION --variable pluginsdir` -AC_SUBST(GSTPB_PLUGINS_DIR) -AC_MSG_NOTICE(Using GStreamer Base Plugins in $GSTPB_PLUGINS_DIR) -AG_GST_CHECK_GST_PLUGINS_GOOD($GST_API_VERSION, [$GSTPG_REQ], [yes]) -GSTPG_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-good-$GST_API_VERSION --variable pluginsdir` -AC_SUBST(GSTPG_PLUGINS_DIR) -AC_MSG_NOTICE(Using GStreamer Good Plugins in $GSTPG_PLUGINS_DIR) - -AG_GST_CHECK_GST_PLUGINS_BAD($GST_API_VERSION, [$GSTPD_REQ], [yes]) -GSTPD_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-bad-$GST_API_VERSION --variable pluginsdir` -AC_SUBST(GSTPD_PLUGINS_DIR) -AC_MSG_NOTICE(Using GStreamer Bad Plugins in $GSTPD_PLUGINS_DIR) +dnl check for uninstalled plugin directories for unit tests +AG_GST_CHECK_UNINSTALLED_SETUP([ + AG_GST_CHECK_GST_PLUGINS_GOOD($GST_API_VERSION, [$GSTPB_REQ]) + AG_GST_CHECK_GST_PLUGINS_BAD($GST_API_VERSION, [$GSTPB_REQ]) +]) AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) AM_CONDITIONAL(HAVE_CHECK, test "x$HAVE_GST_CHECK" = "xyes") diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index d4bdf7227e..574297cfb4 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -10,7 +10,7 @@ AM_TESTS_ENVIRONMENT += \ GST_STATE_IGNORE_ELEMENTS="$(STATE_IGNORE_ELEMENTS)" \ $(REGISTRY_ENVIRONMENT) \ GST_PLUGIN_SYSTEM_PATH_1_0= \ - GST_PLUGIN_PATH_1_0=$(GST_PLUGINS_DIR):$(GSTPB_PLUGINS_DIR):$(GSTPG_PLUGINS_DIR):$(GSTPD_PLUGINS_DIR):$(top_builddir)/gst \ + GST_PLUGIN_PATH_1_0=$(GST_PLUGINS_DIR):$(GST_PLUGINS_BASE_DIR):$(GST_PLUGINS_GOOD_DIR):$(GST_PLUGINS_BAD_DIR):$(top_builddir)/gst \ GST_PLUGIN_LOADING_WHITELIST="gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad:gst-rtsp-server" From 858a9d2054a2209e09597645b8dee8ad746e95c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 25 Apr 2018 11:00:32 +0100 Subject: [PATCH 1496/1776] meson: use -Wl,-Bsymbolic-functions where supported Just like the autotools build. --- meson.build | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 775940fded..ebea2e9816 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('gst-rtsp-server', 'c', version : '1.15.0.1', - meson_version : '>= 0.33.0', + meson_version : '>= 0.46.0', default_options : ['warning_level=1', 'buildtype=debugoptimized']) gst_version = meson.project_version() @@ -27,6 +27,10 @@ plugins_install_dir = '@0@/gstreamer-1.0'.format(get_option('libdir')) cc = meson.get_compiler('c') +if cc.has_link_argument('-Wl,-Bsymbolic-functions') + add_project_link_arguments('-Wl,-Bsymbolic-functions', language : 'c') +endif + # Symbol visibility if cc.has_argument('-fvisibility=hidden') add_project_arguments('-fvisibility=hidden', language: 'c') From 208258472cfe673641435285efc24ad26ab07431 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Sat, 5 May 2018 19:51:52 +0530 Subject: [PATCH 1497/1776] meson: Update option names to omit disable_ and with- prefixes Also yield common options to the outer project (gst-build in our case) so that they don't have to be set manually. --- meson.build | 6 +++--- meson_options.txt | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/meson.build b/meson.build index ebea2e9816..228b256593 100644 --- a/meson.build +++ b/meson.build @@ -54,7 +54,7 @@ cdata.set_quoted('GST_LICENSE', 'LGPL') # cdata.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir'))) # GStreamer package name and origin url -gst_package_name = get_option('with-package-name') +gst_package_name = get_option('package-name') if gst_package_name == '' if gst_version_nano == 0 gst_package_name = 'GStreamer RTSP Server Library source release' @@ -65,7 +65,7 @@ if gst_package_name == '' endif endif cdata.set_quoted('GST_PACKAGE_NAME', gst_package_name) -cdata.set_quoted('GST_PACKAGE_ORIGIN', get_option('with-package-origin')) +cdata.set_quoted('GST_PACKAGE_ORIGIN', get_option('package-origin')) configure_file(output : 'config.h', configuration : cdata) @@ -117,7 +117,7 @@ gstnet_dep = dependency('gstreamer-net-1.0', version : gst_req, gir = find_program('g-ir-scanner', required : false) gnome = import('gnome') -build_gir = gir.found() and not meson.is_cross_build() and not get_option('disable_introspection') +build_gir = gir.found() and not meson.is_cross_build() and get_option('introspection') gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**);' + \ 'g_setenv("GST_REGISTRY_1.0", "@0@", TRUE);'.format(meson.current_build_dir() + '/gir_empty_registry.reg') + \ 'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \ diff --git a/meson_options.txt b/meson_options.txt index cf9d95fb76..c8c5282115 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,11 +1,11 @@ -option('disable_introspection', - type : 'boolean', value : false, - description : 'Whether to disable the introspection generation') -option('with-package-name', type : 'string', +option('introspection', type : 'boolean', value : true, yield : true, + description : 'Generate gobject-introspection bindings') +option('package-name', type : 'string', yield : true, description : 'package name to use in plugins') -option('with-package-origin', type : 'string', value : 'Unknown package origin', +option('package-origin', type : 'string', + value : 'Unknown package origin', yield : true, description : 'package origin URL to use in plugins') option('tests', type : 'boolean', value : true, description : 'Build and enable unit tests') -option('examples', type : 'boolean', value : true, +option('examples', type : 'boolean', value : true, yield : true, description : 'Build the examples') From b3a4df7ab8e5ef07e83438cb3ad041bc04253525 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Wed, 9 May 2018 04:09:02 +1000 Subject: [PATCH 1498/1776] rtspclientsink: Don't deadlock in preroll on early close If the connection is closed very early, the flushing marker might not get set and rtspclientsink can get deadlocked waiting for preroll forever. https://bugzilla.gnome.org/show_bug.cgi?id=786961 --- gst/rtsp-sink/gstrtspclientsink.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 5d37c56b80..297016cb9c 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -209,7 +209,8 @@ gst_rtsp_client_sink_pad_class_init (GstRtspClientSinkPadClass * klass) g_object_class_install_property (gobject_klass, PROP_PAD_ULPFEC_PERCENTAGE, g_param_spec_uint ("ulpfec-percentage", "ULPFEC percentage", - "The percentage of ULP redundancy to apply", 0, 100, DEFAULT_PAD_ULPFEC_PERCENTAGE, + "The percentage of ULP redundancy to apply", 0, 100, + DEFAULT_PAD_ULPFEC_PERCENTAGE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } @@ -2035,7 +2036,10 @@ gst_rtsp_conninfo_close (GstRTSPClientSink * sink, GstRTSPConnInfo * info, /* free connection */ GST_DEBUG_OBJECT (sink, "freeing connection..."); gst_rtsp_connection_free (info->connection); + g_mutex_lock (&sink->preroll_lock); info->connection = NULL; + g_cond_broadcast (&sink->preroll_cond); + g_mutex_unlock (&sink->preroll_lock); } GST_RTSP_STATE_UNLOCK (sink); return GST_RTSP_OK; @@ -3532,7 +3536,8 @@ request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPClientSink * sink) } static GstElement * -request_fec_encoder (GstElement * rtpbin, guint sessid, GstRTSPClientSink * sink) +request_fec_encoder (GstElement * rtpbin, guint sessid, + GstRTSPClientSink * sink) { GstRTSPStream *stream = NULL; GstElement *ret = NULL; @@ -3643,7 +3648,8 @@ gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink) /* Now wait for the preroll of the rtp bin */ g_mutex_lock (&sink->preroll_lock); - while (!sink->prerolled && !sink->conninfo.flushing) { + while (!sink->prerolled && sink->conninfo.connection + && !sink->conninfo.flushing) { GST_LOG_OBJECT (sink, "Waiting for preroll before continuing"); g_cond_wait (&sink->preroll_cond, &sink->preroll_lock); } From 913eae2e7ed1e491f81e8ff7d80872cb3d49aa1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Bj=C3=A4reholt?= Date: Tue, 8 May 2018 14:13:31 +0200 Subject: [PATCH 1499/1776] rtsp-onvif-media-factory: export gst_rtsp_onvif_media_factory_requires_backchannel https://bugzilla.gnome.org/show_bug.cgi?id=796229 --- gst/rtsp-server/rtsp-onvif-media-factory.h | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.h b/gst/rtsp-server/rtsp-onvif-media-factory.h index 0827039c4e..778b8f9cc2 100644 --- a/gst/rtsp-server/rtsp-onvif-media-factory.h +++ b/gst/rtsp-server/rtsp-onvif-media-factory.h @@ -74,6 +74,7 @@ void gst_rtsp_onvif_media_factory_set_backchannel_bandwidth (GstRTSPOnvifMediaFa GST_RTSP_SERVER_API guint gst_rtsp_onvif_media_factory_get_backchannel_bandwidth (GstRTSPOnvifMediaFactory * factory); +GST_RTSP_SERVER_API gboolean gst_rtsp_onvif_media_factory_requires_backchannel (GstRTSPMediaFactory * factory, GstRTSPContext * ctx); #endif /* __GST_RTSP_ONVIF_MEDIA_FACTORY_H__ */ From 89e6ee73b10153a405c120656afcde001171fc46 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 18 May 2018 14:53:49 +0200 Subject: [PATCH 1500/1776] Makefile: Don't hardcode libtool for g-i build Similar to the other commits in core/base/bad --- gst/rtsp-server/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 560b63d05a..9bc1169a85 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -98,7 +98,7 @@ GstRtspServer-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@ --include=Gst-@GST_API_VERSION@ \ --include=GstRtsp-@GST_API_VERSION@ \ --include=GstNet-@GST_API_VERSION@ \ - --libtool="$(top_builddir)/libtool" \ + --libtool="${LIBTOOL}" \ --pkg gstreamer-@GST_API_VERSION@ \ --pkg gstreamer-rtsp-@GST_API_VERSION@ \ --pkg gstreamer-net-@GST_API_VERSION@ \ From 768fb5695c91ef1fb95ea056da0a5eace21168e6 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Tue, 5 Jun 2018 08:44:44 +0200 Subject: [PATCH 1501/1776] Get payloader stats only for the sending streams Get/set payloader properties only for streams that actually contain a payloader element. https://bugzilla.gnome.org/show_bug.cgi?id=796523 --- gst/rtsp-server/rtsp-client.c | 3 +++ gst/rtsp-server/rtsp-media.c | 10 ++++++++-- gst/rtsp-server/rtsp-sdp.c | 5 +++-- gst/rtsp-server/rtsp-session-media.c | 2 ++ gst/rtsp-server/rtsp-stream-transport.c | 2 ++ 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d987c1f978..fb6998c2ce 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1826,6 +1826,9 @@ default_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media, GstRTSPMessage *request = ctx->request; gchar *blocksize_str; + if (!gst_rtsp_stream_is_sender (stream)) + return TRUE; + if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_BLOCKSIZE, &blocksize_str, 0) == GST_RTSP_OK) { guint64 blocksize; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 0427b6bec5..578c385405 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -604,6 +604,9 @@ do_query_position (GstRTSPStream * stream, DoQueryPositionData * data) { gint64 tmp; + if (!gst_rtsp_stream_is_sender (stream)) + return; + if (data->complete_streams_only && !gst_rtsp_stream_is_complete (stream)) { GST_DEBUG_OBJECT (stream, "stream not complete, do not query position"); return; @@ -3917,8 +3920,11 @@ static void do_set_seqnum (GstRTSPStream * stream) { guint16 seq_num; - seq_num = gst_rtsp_stream_get_current_seqnum (stream); - gst_rtsp_stream_set_seqnum_offset (stream, seq_num + 1); + + if (gst_rtsp_stream_is_sender (stream)) { + seq_num = gst_rtsp_stream_get_current_seqnum (stream); + gst_rtsp_stream_set_seqnum_offset (stream, seq_num + 1); + } } /* call with state_lock */ diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 3795b42fd3..da9f36f0f5 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -288,8 +288,9 @@ gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPPublishClockMode publish_clock_mode = gst_rtsp_stream_get_publish_clock_mode (stream); - gst_rtsp_stream_get_rtpinfo (stream, &rtptime, NULL, &clock_rate, - &running_time); + if (gst_rtsp_stream_is_sender (stream)) + gst_rtsp_stream_get_rtpinfo (stream, &rtptime, NULL, &clock_rate, + &running_time); base_time = gst_element_get_base_time (GST_ELEMENT_CAST (joined_bin)); g_assert (base_time != GST_CLOCK_TIME_NONE); clock_time = running_time + base_time; diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 3138449d4c..a1eb98ea06 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -281,6 +281,8 @@ gst_rtsp_session_media_get_rtpinfo (GstRTSPSessionMedia * media) } stream = gst_rtsp_stream_transport_get_stream (transport); + if (!gst_rtsp_stream_is_sender (stream)) + continue; if (!gst_rtsp_stream_get_rtpinfo (stream, NULL, NULL, NULL, &running_time)) continue; diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index a9aa897cea..9da62d87e8 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -339,6 +339,8 @@ gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport * trans, priv = trans->priv; + if (!gst_rtsp_stream_is_sender (priv->stream)) + return NULL; if (!gst_rtsp_stream_get_rtpinfo (priv->stream, &rtptime, &seq, &clock_rate, &running_time)) return NULL; From 36cc79c5e206dd3accaf8e8de12308b1ab8692aa Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 20 Jun 2018 01:35:47 +0200 Subject: [PATCH 1502/1776] meson: build auth-digest example --- examples/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/meson.build b/examples/meson.build index 0a504470f3..80da73acc0 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -1,6 +1,7 @@ examples = [ 'test-appsrc', 'test-auth', + 'test-auth-digest', 'test-launch', 'test-mp4', 'test-multicast2', From 3b70c68e6e48d22908035d6c2a94d498e31add8d Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 20 Jun 2018 00:10:18 +0200 Subject: [PATCH 1503/1776] rtsp-stream: only create funnel if it didn't exist already. This precented using multiple protocols for the same stream. https://bugzilla.gnome.org/show_bug.cgi?id=796634 --- gst/rtsp-server/rtsp-stream.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 40c12241fc..e9be929bb1 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -3068,12 +3068,14 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * } /* make funnel for the RTP/RTCP receivers */ - priv->funnel[i] = gst_element_factory_make ("funnel", NULL); - gst_bin_add (bin, priv->funnel[i]); + if (!priv->funnel[i]) { + priv->funnel[i] = gst_element_factory_make ("funnel", NULL); + gst_bin_add (bin, priv->funnel[i]); - pad = gst_element_get_static_pad (priv->funnel[i], "src"); - gst_pad_link (pad, priv->recv_sink[i]); - gst_object_unref (pad); + pad = gst_element_get_static_pad (priv->funnel[i], "src"); + gst_pad_link (pad, priv->recv_sink[i]); + gst_object_unref (pad); + } if (udp && !priv->udpsrc_v4[i] && priv->server_addr_v4) { GST_DEBUG_OBJECT (stream, "udp IPv4, create and configure udpsources"); From ea67b932b3668d0cb006544a1ae4b852a0cf8f92 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 20 Jun 2018 04:30:04 +0200 Subject: [PATCH 1504/1776] docs: add missing auth methods --- docs/libs/gst-rtsp-server-sections.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 3e43110a2a..953bf71a7d 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -51,9 +51,13 @@ gst_rtsp_auth_set_tls_authentication_mode gst_rtsp_auth_make_basic gst_rtsp_auth_add_basic gst_rtsp_auth_remove_basic +gst_rtsp_auth_add_digest +gst_rtsp_auth_remove_digest gst_rtsp_auth_check gst_rtsp_auth_get_default_token gst_rtsp_auth_set_default_token +gst_rtsp_auth_get_supported_methods +gst_rtsp_auth_set_supported_methods GST_RTSP_AUTH_CHECK_CONNECT From b5a61f488dba3d558bc53c592fd845c7d0236b41 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 19 Jun 2018 14:53:02 +1000 Subject: [PATCH 1505/1776] rtspclientsink: fix waiting for multiple streams We were previously only ever waiting for a single stream to notify it's blocked status through GstRTSPStreamBlocking. Actually count streams to wait for. Fixes rtspclientsink sending SDP's without out some of the input streams. https://bugzilla.gnome.org/show_bug.cgi?id=796624 --- gst/rtsp-sink/gstrtspclientsink.c | 7 +++++-- gst/rtsp-sink/gstrtspclientsink.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 297016cb9c..175b4ea705 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -1434,6 +1434,9 @@ gst_rtsp_client_sink_release_pad (GstElement * element, GstPad * pad) context = gst_pad_get_element_private (pad); + /* FIXME: we may need to change our blocking state waiting for + * GstRTSPStreamBlocking messages */ + GST_RTSP_STATE_LOCK (sink); sink->contexts = g_list_remove (sink->contexts, context); GST_RTSP_STATE_UNLOCK (sink); @@ -4331,7 +4334,7 @@ gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async) g_mutex_lock (&sink->block_streams_lock); /* Wait for streams to be blocked */ - while (!sink->streams_blocked) { + while (sink->n_streams_blocked < g_list_length (sink->contexts)) { GST_DEBUG_OBJECT (sink, "waiting for streams to be blocked"); g_cond_wait (&sink->block_streams_cond, &sink->block_streams_lock); } @@ -4677,7 +4680,7 @@ gst_rtsp_client_sink_handle_message (GstBin * bin, GstMessage * message) /* An RTSPStream has prerolled */ GST_DEBUG_OBJECT (rtsp_client_sink, "received GstRTSPStreamBlocking"); g_mutex_lock (&rtsp_client_sink->block_streams_lock); - rtsp_client_sink->streams_blocked = TRUE; + rtsp_client_sink->n_streams_blocked++; g_cond_broadcast (&rtsp_client_sink->block_streams_cond); g_mutex_unlock (&rtsp_client_sink->block_streams_lock); } diff --git a/gst/rtsp-sink/gstrtspclientsink.h b/gst/rtsp-sink/gstrtspclientsink.h index 38230fa305..f7845c03fa 100644 --- a/gst/rtsp-sink/gstrtspclientsink.h +++ b/gst/rtsp-sink/gstrtspclientsink.h @@ -220,7 +220,7 @@ struct _GstRTSPClientSink { gboolean streams_collected; /* TRUE when streams have been blocked */ - gboolean streams_blocked; + guint n_streams_blocked; GMutex block_streams_lock; GCond block_streams_cond; From 5ede2a5c5c89734d195b7d3f9e6ab5fd80bb1d53 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 20 Jun 2018 04:37:11 +0200 Subject: [PATCH 1506/1776] rtsp-auth: Add support for parsing .htdigest files Passwords are usually not stored in clear text, but instead stored already hashed in a .htdigest file. Add support for parsing such files, add API to allow setting a custom realm in RTSPAuth, and update the digest example. https://bugzilla.gnome.org/show_bug.cgi?id=796637 --- docs/libs/gst-rtsp-server-sections.txt | 3 + examples/test-auth-digest.c | 46 +++++++- gst/rtsp-server/rtsp-auth.c | 153 ++++++++++++++++++++++++- gst/rtsp-server/rtsp-auth.h | 8 ++ 4 files changed, 203 insertions(+), 7 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 953bf71a7d..969abf60a9 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -48,11 +48,14 @@ gst_rtsp_auth_get_tls_database gst_rtsp_auth_set_tls_database gst_rtsp_auth_get_tls_authentication_mode gst_rtsp_auth_set_tls_authentication_mode +gst_rtsp_auth_set_realm +gst_rtsp_auth_get_realm gst_rtsp_auth_make_basic gst_rtsp_auth_add_basic gst_rtsp_auth_remove_basic gst_rtsp_auth_add_digest gst_rtsp_auth_remove_digest +gst_rtsp_auth_parse_htdigest gst_rtsp_auth_check gst_rtsp_auth_get_default_token gst_rtsp_auth_set_default_token diff --git a/examples/test-auth-digest.c b/examples/test-auth-digest.c index 6384da3d0c..f779c05774 100644 --- a/examples/test-auth-digest.c +++ b/examples/test-auth-digest.c @@ -21,6 +21,18 @@ #include +static gchar *htdigest_path = NULL; +static gchar *realm = NULL; + +static GOptionEntry entries[] = { + {"htdigest-path", 'h', 0, G_OPTION_ARG_STRING, &htdigest_path, + "Path to an htdigest file to parse (default: None)", "PATH"}, + {"realm", 'r', 0, G_OPTION_ARG_STRING, &realm, + "Authentication realm (default: None)", "REALM"}, + {NULL} +}; + + static gboolean remove_func (GstRTSPSessionPool * pool, GstRTSPSession * session, GstRTSPServer * server) @@ -63,8 +75,19 @@ main (int argc, char *argv[]) GstRTSPMediaFactory *factory; GstRTSPAuth *auth; GstRTSPToken *token; + GOptionContext *optctx; + GError *error = NULL; - gst_init (&argc, &argv); + optctx = g_option_context_new (NULL); + g_option_context_add_main_entries (optctx, entries, NULL); + g_option_context_add_group (optctx, gst_init_get_option_group ()); + if (!g_option_context_parse (optctx, &argc, &argv, &error)) { + g_printerr ("Error parsing options: %s\n", error->message); + g_option_context_free (optctx); + g_clear_error (&error); + return -1; + } + g_option_context_free (optctx); loop = g_main_loop_new (NULL, FALSE); @@ -142,6 +165,23 @@ main (int argc, char *argv[]) gst_rtsp_auth_add_digest (auth, "user", "password", token); gst_rtsp_token_unref (token); + if (htdigest_path) { + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + + if (!gst_rtsp_auth_parse_htdigest (auth, htdigest_path, token)) { + g_printerr ("Could not parse htdigest at %s\n", htdigest_path); + gst_rtsp_token_unref (token); + goto failed; + } + + gst_rtsp_token_unref (token); + } + + if (realm) + gst_rtsp_auth_set_realm (auth, realm); + /* make admin token */ token = gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, @@ -171,6 +211,10 @@ main (int argc, char *argv[]) g_print ("stream with user:password ready at rtsp://127.0.0.1:8554/test\n"); g_print ("stream with admin:power ready at rtsp://127.0.0.1:8554/test\n"); g_print ("stream with admin2:power2 ready at rtsp://127.0.0.1:8554/test2\n"); + + if (htdigest_path) + g_print ("stream with htdigest users ready at rtsp://127.0.0.1:8554/test\n"); + g_main_loop_run (loop); return 0; diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index d01927573a..02c20e9b9f 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -67,12 +67,14 @@ struct _GstRTSPAuthPrivate GstRTSPToken *default_token; GstRTSPMethod methods; GstRTSPAuthMethod auth_methods; + gchar *realm; }; typedef struct { GstRTSPToken *token; gchar *pass; + gchar *md5_pass; } GstRTSPDigestEntry; typedef struct @@ -88,6 +90,7 @@ gst_rtsp_digest_entry_free (GstRTSPDigestEntry * entry) { gst_rtsp_token_unref (entry->token); g_free (entry->pass); + g_free (entry->md5_pass); g_free (entry); } @@ -195,6 +198,7 @@ gst_rtsp_auth_init (GstRTSPAuth * auth) /* bitwise or of all methods that need authentication */ priv->methods = 0; priv->auth_methods = GST_RTSP_AUTH_BASIC; + priv->realm = g_strdup ("GStreamer RTSP Server"); } static void @@ -213,6 +217,7 @@ gst_rtsp_auth_finalize (GObject * obj) g_hash_table_unref (priv->digest); g_hash_table_unref (priv->nonces); g_mutex_clear (&priv->lock); + g_free (priv->realm); G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj); } @@ -565,6 +570,99 @@ gst_rtsp_auth_add_digest (GstRTSPAuth * auth, const gchar * user, g_mutex_unlock (&priv->lock); } +/* With auth lock taken */ +static gboolean +update_digest_cb (gchar *key, GstRTSPDigestEntry *entry, GHashTable *digest) +{ + g_hash_table_replace (digest, key, entry); + + return TRUE; +} + +/** + * gst_rtsp_auth_parse_htdigest: + * @path: (type filename): Path to the htdigest file + * @token: (transfer none): authorisation token + * + * Parse the contents of the file at @path and enable the privileges + * listed in @token for the users it describes. + * + * The format of the file is expected to match the format described by + * , + * as output by the `htdigest` command. + * + * Returns: %TRUE if the file was successfully parsed, %FALSE otherwise. + * + * Since: 1.16 + */ +gboolean +gst_rtsp_auth_parse_htdigest (GstRTSPAuth *auth, const gchar *path, + GstRTSPToken *token) +{ + GstRTSPAuthPrivate *priv; + gboolean ret = FALSE; + gchar *line = NULL; + gchar *eol = NULL; + gchar *contents = NULL; + GError *error = NULL; + GHashTable *new_entries = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify) gst_rtsp_digest_entry_free); + + + g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE); + g_return_val_if_fail (path != NULL, FALSE); + g_return_val_if_fail (GST_IS_RTSP_TOKEN (token), FALSE); + + priv = auth->priv; + if (!g_file_get_contents (path, &contents, NULL, &error)) { + GST_ERROR_OBJECT(auth, "Could not parse htdigest: %s", error->message); + goto done; + } + + for (line = contents; line && *line; line = eol ? eol + 1 : NULL) { + GstRTSPDigestEntry *entry; + gchar **strv; + eol = strchr (line, '\n'); + + if (eol) + *eol = '\0'; + + strv = g_strsplit (line, ":", -1); + + if (!(strv[0] && strv[1] && strv[2] && !strv[3])) { + GST_ERROR_OBJECT (auth, "Invalid htdigest format"); + g_strfreev (strv); + goto done; + } + + if (strlen (strv[2]) != 32) { + GST_ERROR_OBJECT (auth, "Invalid htdigest format, hash is expected to be 32 characters long"); + g_strfreev (strv); + goto done; + } + + entry = g_new0 (GstRTSPDigestEntry, 1); + entry->token = gst_rtsp_token_ref (token); + entry->md5_pass = g_strdup (strv[2]); + g_hash_table_replace (new_entries, g_strdup (strv[0]), entry); + g_strfreev (strv); + } + + ret = TRUE; + + /* We only update digest if the file was entirely valid */ + g_mutex_lock (&priv->lock); + g_hash_table_foreach_steal (new_entries, (GHRFunc) update_digest_cb, priv->digest); + g_mutex_unlock (&priv->lock); + +done: + if (error) + g_clear_error (&error); + g_free(contents); + g_hash_table_unref (new_entries); + return ret; +} + /** * gst_rtsp_auth_remove_digest: * @auth: a #GstRTSPAuth @@ -709,10 +807,17 @@ default_digest_auth (GstRTSPAuth * auth, GstRTSPContext * ctx, if (nonce_entry->client && nonce_entry->client != ctx->client) goto out; - expected_response = - gst_rtsp_generate_digest_auth_response (NULL, - gst_rtsp_method_as_text (ctx->method), "GStreamer RTSP Server", user, - digest_entry->pass, uri, nonce); + if (digest_entry->md5_pass) { + expected_response = gst_rtsp_generate_digest_auth_response_from_md5 (NULL, + gst_rtsp_method_as_text (ctx->method), digest_entry->md5_pass, + uri, nonce); + } else { + expected_response = + gst_rtsp_generate_digest_auth_response (NULL, + gst_rtsp_method_as_text (ctx->method), realm, user, + digest_entry->pass, uri, nonce); + } + if (!expected_response || strcmp (response, expected_response) != 0) goto out; @@ -794,8 +899,10 @@ static void default_generate_authenticate_header (GstRTSPAuth * auth, GstRTSPContext * ctx) { if (auth->priv->auth_methods & GST_RTSP_AUTH_BASIC) { + gchar *auth_header = g_strdup_printf("Basic realm=\"%s\"", auth->priv->realm); gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_WWW_AUTHENTICATE, - "Basic realm=\"GStreamer RTSP Server\""); + auth_header); + g_free (auth_header); } if (auth->priv->auth_methods & GST_RTSP_AUTH_DIGEST) { @@ -807,7 +914,7 @@ default_generate_authenticate_header (GstRTSPAuth * auth, GstRTSPContext * ctx) auth_header = g_strdup_printf - ("Digest realm=\"GStreamer RTSP Server\", nonce=\"%s\"", nonce_value); + ("Digest realm=\"%s\", nonce=\"%s\"", auth->priv->realm, nonce_value); gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_WWW_AUTHENTICATE, auth_header); g_free (auth_header); @@ -1117,3 +1224,37 @@ gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass) return result; } + +/** + * gst_rtsp_auth_set_realm: + * + * Set the @realm of @auth + * + * Since: 1.16 + */ +void +gst_rtsp_auth_set_realm (GstRTSPAuth *auth, const gchar *realm) +{ + g_return_if_fail (GST_IS_RTSP_AUTH (auth)); + g_return_if_fail (realm != NULL); + + if (auth->priv->realm) + g_free (auth->priv->realm); + + auth->priv->realm = g_strdup (realm); +} + +/** + * gst_rtsp_auth_get_realm: + * + * Returns: (transfer full): the @realm of @auth + * + * Since: 1.16 + */ +gchar * +gst_rtsp_auth_get_realm (GstRTSPAuth *auth) +{ + g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), NULL); + + return g_strdup(auth->priv->realm); +} diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h index 3bfe63df93..05a3e5a455 100644 --- a/gst/rtsp-server/rtsp-auth.h +++ b/gst/rtsp-server/rtsp-auth.h @@ -135,6 +135,14 @@ GstRTSPAuthMethod gst_rtsp_auth_get_supported_methods (GstRTSPAuth *auth); GST_RTSP_SERVER_API gboolean gst_rtsp_auth_check (const gchar *check); +GST_RTSP_SERVER_API +gboolean gst_rtsp_auth_parse_htdigest (GstRTSPAuth *auth, const gchar *path, GstRTSPToken *token); + +GST_RTSP_SERVER_API +void gst_rtsp_auth_set_realm (GstRTSPAuth *auth, const gchar *realm); + +GST_RTSP_SERVER_API +gchar * gst_rtsp_auth_get_realm (GstRTSPAuth *auth); /* helpers */ From e0f31b4ca4013b789c2fb9b589286d869448f228 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 22 Jun 2018 23:17:08 +1000 Subject: [PATCH 1507/1776] examples: Add test-video-disconnect example Simple example which cuts off all clients 10 seconds after the first one connects. --- examples/Makefile.am | 2 +- examples/test-video-disconnect.c | 222 +++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 examples/test-video-disconnect.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 43f811a84c..6a70d728fe 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -3,7 +3,7 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ test-multicast test-multicast2 test-appsrc \ test-video-rtx test-record test-record-auth \ test-netclock test-netclock-client \ - test-onvif-backchannel + test-onvif-backchannel test-video-disconnect #INCLUDES = -I$(top_srcdir) -I$(srcdir) diff --git a/examples/test-video-disconnect.c b/examples/test-video-disconnect.c new file mode 100644 index 0000000000..809a363882 --- /dev/null +++ b/examples/test-video-disconnect.c @@ -0,0 +1,222 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * Copyright (C) 2018 Jan Schmidt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* This example disconnects any clients and exits 10 seconds + * after the first client connects */ + +#include + +#include + +guint exit_timeout_id = 0; + +/* define this if you want the resource to only be available when using + * user/password as the password */ +#undef WITH_AUTH + +/* define this if you want the server to use TLS (it will also need WITH_AUTH + * to be defined) */ +#undef WITH_TLS + +/* this timeout is periodically run to clean up the expired sessions from the + * pool. This needs to be run explicitly currently but might be done + * automatically as part of the mainloop. */ +static gboolean +timeout (GstRTSPServer * server) +{ + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_cleanup (pool); + g_object_unref (pool); + + return TRUE; +} + +static GstRTSPFilterResult +client_filter (GstRTSPServer * server, GstRTSPClient * client, + gpointer user_data) +{ + /* Simple filter that shuts down all clients. */ + return GST_RTSP_FILTER_REMOVE; +} + +/* Timeout that runs 10 seconds after the first client connects and triggers + * the shutdown of the server */ +static gboolean +shutdown_timeout (GstRTSPServer * server) +{ + GstRTSPMountPoints *mounts; + g_print ("Time for everyone to go. Removing mount point\n"); + /* Remove the mount point to prevent new clients connecting */ + mounts = gst_rtsp_server_get_mount_points (server); + gst_rtsp_mount_points_remove_factory (mounts, "/test"); + g_object_unref (mounts); + + /* Filter existing clients and remove them */ + g_print ("Disconnecting existing clients\n"); + gst_rtsp_server_client_filter (server, client_filter, NULL); + return FALSE; +} + +static void +client_connected (GstRTSPServer * server, GstRTSPClient * client) +{ + if (exit_timeout_id == 0) { + g_print ("First Client connected. Disconnecting everyone in 10 seconds\n"); + exit_timeout_id = + g_timeout_add_seconds (10, (GSourceFunc) shutdown_timeout, server); + } +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; +#ifdef WITH_AUTH + GstRTSPAuth *auth; + GstRTSPToken *token; + gchar *basic; + GstRTSPPermissions *permissions; +#endif +#ifdef WITH_TLS + GTlsCertificate *cert; + GError *error = NULL; +#endif + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + +#ifdef WITH_AUTH + /* make a new authentication manager. it can be added to control access to all + * the factories on the server or on individual factories. */ + auth = gst_rtsp_auth_new (); +#ifdef WITH_TLS + cert = g_tls_certificate_new_from_pem ("-----BEGIN CERTIFICATE-----" + "MIICJjCCAY+gAwIBAgIBBzANBgkqhkiG9w0BAQUFADCBhjETMBEGCgmSJomT8ixk" + "ARkWA0NPTTEXMBUGCgmSJomT8ixkARkWB0VYQU1QTEUxHjAcBgNVBAsTFUNlcnRp" + "ZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAxMOY2EuZXhhbXBsZS5jb20xHTAbBgkq" + "hkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMB4XDTExMDExNzE5NDcxN1oXDTIxMDEx" + "NDE5NDcxN1owSzETMBEGCgmSJomT8ixkARkWA0NPTTEXMBUGCgmSJomT8ixkARkW" + "B0VYQU1QTEUxGzAZBgNVBAMTEnNlcnZlci5leGFtcGxlLmNvbTBcMA0GCSqGSIb3" + "DQEBAQUAA0sAMEgCQQDYScTxk55XBmbDM9zzwO+grVySE4rudWuzH2PpObIonqbf" + "hRoAalKVluG9jvbHI81eXxCdSObv1KBP1sbN5RzpAgMBAAGjIjAgMAkGA1UdEwQC" + "MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADgYEAYx6fMqT1" + "Gvo0jq88E8mc+bmp4LfXD4wJ7KxYeadQxt75HFRpj4FhFO3DOpVRFgzHlOEo3Fwk" + "PZOKjvkT0cbcoEq5whLH25dHoQxGoVQgFyAP5s+7Vp5AlHh8Y/vAoXeEVyy/RCIH" + "QkhUlAflfDMcrrYjsmwoOPSjhx6Mm/AopX4=" + "-----END CERTIFICATE-----" + "-----BEGIN PRIVATE KEY-----" + "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEA2EnE8ZOeVwZmwzPc" + "88DvoK1ckhOK7nVrsx9j6TmyKJ6m34UaAGpSlZbhvY72xyPNXl8QnUjm79SgT9bG" + "zeUc6QIDAQABAkBRFJZ32VbqWMP9OVwDJLiwC01AlYLnka0mIQZbT/2xq9dUc9GW" + "U3kiVw4lL8v/+sPjtTPCYYdzHHOyDen6znVhAiEA9qJT7BtQvRxCvGrAhr9MS022" + "tTdPbW829BoUtIeH64cCIQDggG5i48v7HPacPBIH1RaSVhXl8qHCpQD3qrIw3FMw" + "DwIga8PqH5Sf5sHedy2+CiK0V4MRfoU4c3zQ6kArI+bEgSkCIQCLA1vXBiE31B5s" + "bdHoYa1BXebfZVd+1Hd95IfEM5mbRwIgSkDuQwV55BBlvWph3U8wVIMIb4GStaH8" + "W535W8UBbEg=" "-----END PRIVATE KEY-----", -1, &error); + if (cert == NULL) { + g_printerr ("failed to parse PEM: %s\n", error->message); + return -1; + } + gst_rtsp_auth_set_tls_certificate (auth, cert); + g_object_unref (cert); +#endif + + /* make user token */ + token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + basic = gst_rtsp_auth_make_basic ("user", "password"); + gst_rtsp_auth_add_basic (auth, basic, token); + g_free (basic); + gst_rtsp_token_unref (token); + + /* configure in the server */ + gst_rtsp_server_set_auth (server, auth); +#endif + + /* get the mount points for this server, every server has a default object + * that be used to map uri mount points to media factories */ + mounts = gst_rtsp_server_get_mount_points (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, "( " + "videotestsrc ! video/x-raw,width=352,height=288,framerate=15/1 ! " + "x264enc ! rtph264pay name=pay0 pt=96 " + "audiotestsrc ! audio/x-raw,rate=8000 ! " + "alawenc ! rtppcmapay name=pay1 pt=97 " ")"); +#ifdef WITH_AUTH + /* add permissions for the user media role */ + permissions = gst_rtsp_permissions_new (); + gst_rtsp_permissions_add_role (permissions, "user", + GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, + GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL); + gst_rtsp_media_factory_set_permissions (factory, permissions); + gst_rtsp_permissions_unref (permissions); +#ifdef WITH_TLS + gst_rtsp_media_factory_set_profiles (factory, GST_RTSP_PROFILE_SAVP); +#endif +#endif + + /* attach the test factory to the /test url */ + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mounts); + + /* attach the server to the default maincontext */ + if (gst_rtsp_server_attach (server, NULL) == 0) + goto failed; + + g_signal_connect (server, "client-connected", (GCallback) client_connected, + NULL); + + /* add a timeout for the session cleanup */ + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + + /* start serving, this never stops */ +#ifdef WITH_TLS + g_print ("stream ready at rtsps://127.0.0.1:8554/test\n"); +#else + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); +#endif + g_main_loop_run (loop); + + return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } +} From e82ba1e52fa523866c3bba4da3092c9f5cce409e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 24 Jun 2018 12:45:49 +0200 Subject: [PATCH 1508/1776] Fix indentation --- gst/rtsp-server/rtsp-auth.c | 28 ++++++++++++++++------------ gst/rtsp-server/rtsp-media.c | 15 ++++++++++----- gst/rtsp-server/rtsp-sdp.c | 3 +-- gst/rtsp-server/rtsp-stream.c | 29 ++++++++++++++++++----------- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index 02c20e9b9f..c1223b574e 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -572,7 +572,7 @@ gst_rtsp_auth_add_digest (GstRTSPAuth * auth, const gchar * user, /* With auth lock taken */ static gboolean -update_digest_cb (gchar *key, GstRTSPDigestEntry *entry, GHashTable *digest) +update_digest_cb (gchar * key, GstRTSPDigestEntry * entry, GHashTable * digest) { g_hash_table_replace (digest, key, entry); @@ -596,8 +596,8 @@ update_digest_cb (gchar *key, GstRTSPDigestEntry *entry, GHashTable *digest) * Since: 1.16 */ gboolean -gst_rtsp_auth_parse_htdigest (GstRTSPAuth *auth, const gchar *path, - GstRTSPToken *token) +gst_rtsp_auth_parse_htdigest (GstRTSPAuth * auth, const gchar * path, + GstRTSPToken * token) { GstRTSPAuthPrivate *priv; gboolean ret = FALSE; @@ -605,7 +605,8 @@ gst_rtsp_auth_parse_htdigest (GstRTSPAuth *auth, const gchar *path, gchar *eol = NULL; gchar *contents = NULL; GError *error = NULL; - GHashTable *new_entries = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + GHashTable *new_entries = + g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gst_rtsp_digest_entry_free); @@ -615,7 +616,7 @@ gst_rtsp_auth_parse_htdigest (GstRTSPAuth *auth, const gchar *path, priv = auth->priv; if (!g_file_get_contents (path, &contents, NULL, &error)) { - GST_ERROR_OBJECT(auth, "Could not parse htdigest: %s", error->message); + GST_ERROR_OBJECT (auth, "Could not parse htdigest: %s", error->message); goto done; } @@ -636,7 +637,8 @@ gst_rtsp_auth_parse_htdigest (GstRTSPAuth *auth, const gchar *path, } if (strlen (strv[2]) != 32) { - GST_ERROR_OBJECT (auth, "Invalid htdigest format, hash is expected to be 32 characters long"); + GST_ERROR_OBJECT (auth, + "Invalid htdigest format, hash is expected to be 32 characters long"); g_strfreev (strv); goto done; } @@ -652,13 +654,14 @@ gst_rtsp_auth_parse_htdigest (GstRTSPAuth *auth, const gchar *path, /* We only update digest if the file was entirely valid */ g_mutex_lock (&priv->lock); - g_hash_table_foreach_steal (new_entries, (GHRFunc) update_digest_cb, priv->digest); + g_hash_table_foreach_steal (new_entries, (GHRFunc) update_digest_cb, + priv->digest); g_mutex_unlock (&priv->lock); done: if (error) g_clear_error (&error); - g_free(contents); + g_free (contents); g_hash_table_unref (new_entries); return ret; } @@ -899,7 +902,8 @@ static void default_generate_authenticate_header (GstRTSPAuth * auth, GstRTSPContext * ctx) { if (auth->priv->auth_methods & GST_RTSP_AUTH_BASIC) { - gchar *auth_header = g_strdup_printf("Basic realm=\"%s\"", auth->priv->realm); + gchar *auth_header = + g_strdup_printf ("Basic realm=\"%s\"", auth->priv->realm); gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_WWW_AUTHENTICATE, auth_header); g_free (auth_header); @@ -1233,7 +1237,7 @@ gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass) * Since: 1.16 */ void -gst_rtsp_auth_set_realm (GstRTSPAuth *auth, const gchar *realm) +gst_rtsp_auth_set_realm (GstRTSPAuth * auth, const gchar * realm) { g_return_if_fail (GST_IS_RTSP_AUTH (auth)); g_return_if_fail (realm != NULL); @@ -1252,9 +1256,9 @@ gst_rtsp_auth_set_realm (GstRTSPAuth *auth, const gchar *realm) * Since: 1.16 */ gchar * -gst_rtsp_auth_get_realm (GstRTSPAuth *auth) +gst_rtsp_auth_get_realm (GstRTSPAuth * auth) { g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), NULL); - return g_strdup(auth->priv->realm); + return g_strdup (auth->priv->realm); } diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 578c385405..48117c139e 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1539,7 +1539,8 @@ gst_rtsp_media_set_latency (GstRTSPMedia * media, guint latency) g_signal_emit_by_name (G_OBJECT (media->priv->rtpbin), "get-storage", i, &storage); if (storage) - g_object_set (storage, "size-time", (media->priv->latency + 50) * GST_MSECOND, NULL); + g_object_set (storage, "size-time", + (media->priv->latency + 50) * GST_MSECOND, NULL); } } @@ -3150,9 +3151,11 @@ request_fec_decoder (GstElement * rtpbin, guint sessid, GstRTSPMedia * media) } static void -new_storage_cb (GstElement * rtpbin, GObject * storage, guint sessid, GstRTSPMedia * media) +new_storage_cb (GstElement * rtpbin, GObject * storage, guint sessid, + GstRTSPMedia * media) { - g_object_set (storage, "size-time", (media->priv->latency + 50) * GST_MSECOND, NULL); + g_object_set (storage, "size-time", (media->priv->latency + 50) * GST_MSECOND, + NULL); } static gboolean @@ -3166,8 +3169,10 @@ start_prepare (GstRTSPMedia * media) if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARING) goto no_longer_preparing; - g_signal_connect (priv->rtpbin, "new-storage", G_CALLBACK (new_storage_cb), media); - g_signal_connect (priv->rtpbin, "request-fec-decoder", G_CALLBACK (request_fec_decoder), media); + g_signal_connect (priv->rtpbin, "new-storage", G_CALLBACK (new_storage_cb), + media); + g_signal_connect (priv->rtpbin, "request-fec-decoder", + G_CALLBACK (request_fec_decoder), media); /* link streams we already have, other streams might appear when we have * dynamic elements */ diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index da9f36f0f5..04329dd93f 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -438,8 +438,7 @@ gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info, gst_sdp_media_add_attribute (smedia, "rtpmap", tmp); g_free (tmp); - tmp = - g_strdup_printf ("%d apt=%d", ulpfec_pt, caps_pt); + tmp = g_strdup_printf ("%d apt=%d", ulpfec_pt, caps_pt); gst_sdp_media_add_attribute (smedia, "fmtp", tmp); g_free (tmp); } diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index e9be929bb1..a94c5bd418 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2374,7 +2374,7 @@ done: } static void -retrieve_ulpfec_pt (gpointer key, GstCaps *caps, GstElement *ulpfec_decoder) +retrieve_ulpfec_pt (gpointer key, GstCaps * caps, GstElement * ulpfec_decoder) { guint pt = GPOINTER_TO_INT (key); const GstStructure *s = gst_caps_get_structure (caps, 0); @@ -2389,7 +2389,8 @@ update_ulpfec_decoder_pt (GstRTSPStream * stream) if (!stream->priv->ulpfec_decoder) goto done; - g_hash_table_foreach (stream->priv->ptmap, (GHFunc) retrieve_ulpfec_pt, stream->priv->ulpfec_decoder); + g_hash_table_foreach (stream->priv->ptmap, (GHFunc) retrieve_ulpfec_pt, + stream->priv->ulpfec_decoder); done: return; @@ -5028,7 +5029,7 @@ gst_rtsp_stream_handle_keymgmt (GstRTSPStream * stream, const gchar * keymgmt) * Since: 1.16 */ guint -gst_rtsp_stream_get_ulpfec_pt (GstRTSPStream *stream) +gst_rtsp_stream_get_ulpfec_pt (GstRTSPStream * stream) { guint res; @@ -5069,15 +5070,19 @@ gst_rtsp_stream_set_ulpfec_pt (GstRTSPStream * stream, guint pt) * Since: 1.16 */ GstElement * -gst_rtsp_stream_request_ulpfec_decoder (GstRTSPStream * stream, GstElement *rtpbin, guint sessid) +gst_rtsp_stream_request_ulpfec_decoder (GstRTSPStream * stream, + GstElement * rtpbin, guint sessid) { GObject *internal_storage = NULL; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); - stream->priv->ulpfec_decoder = gst_object_ref (gst_element_factory_make ("rtpulpfecdec", NULL)); + stream->priv->ulpfec_decoder = + gst_object_ref (gst_element_factory_make ("rtpulpfecdec", NULL)); - g_signal_emit_by_name (G_OBJECT (rtpbin), "get-internal-storage", sessid, &internal_storage); - g_object_set (stream->priv->ulpfec_decoder, "storage", internal_storage, NULL); + g_signal_emit_by_name (G_OBJECT (rtpbin), "get-internal-storage", sessid, + &internal_storage); + g_object_set (stream->priv->ulpfec_decoder, "storage", internal_storage, + NULL); g_object_unref (internal_storage); update_ulpfec_decoder_pt (stream); @@ -5101,9 +5106,11 @@ gst_rtsp_stream_request_ulpfec_encoder (GstRTSPStream * stream, guint sessid) if (!stream->priv->ulpfec_percentage) return NULL; - stream->priv->ulpfec_encoder = gst_object_ref (gst_element_factory_make ("rtpulpfecenc", NULL)); + stream->priv->ulpfec_encoder = + gst_object_ref (gst_element_factory_make ("rtpulpfecenc", NULL)); - g_object_set (stream->priv->ulpfec_encoder, "pt", stream->priv->ulpfec_pt, "percentage", stream->priv->ulpfec_percentage, NULL); + g_object_set (stream->priv->ulpfec_encoder, "pt", stream->priv->ulpfec_pt, + "percentage", stream->priv->ulpfec_percentage, NULL); return stream->priv->ulpfec_encoder; } @@ -5117,7 +5124,7 @@ gst_rtsp_stream_request_ulpfec_encoder (GstRTSPStream * stream, guint sessid) * Since: 1.16 */ void -gst_rtsp_stream_set_ulpfec_percentage (GstRTSPStream *stream, guint percentage) +gst_rtsp_stream_set_ulpfec_percentage (GstRTSPStream * stream, guint percentage) { g_return_if_fail (GST_IS_RTSP_STREAM (stream)); @@ -5138,7 +5145,7 @@ gst_rtsp_stream_set_ulpfec_percentage (GstRTSPStream *stream, guint percentage) * Since: 1.16 */ guint -gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream *stream) +gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream * stream) { guint res; From 2eb4d1b8106b692a6ad0c909de6071c3285cb44c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 24 Jun 2018 12:44:26 +0200 Subject: [PATCH 1509/1776] Update for g_type_class_add_private() deprecation in recent GLib --- gst/rtsp-server/rtsp-address-pool.c | 7 +++---- gst/rtsp-server/rtsp-auth.c | 9 ++------- gst/rtsp-server/rtsp-client.c | 9 ++------- gst/rtsp-server/rtsp-media-factory-uri.c | 9 ++------- gst/rtsp-server/rtsp-media-factory.c | 10 +++------- gst/rtsp-server/rtsp-media.c | 9 ++------- gst/rtsp-server/rtsp-mount-points.c | 12 ++++-------- gst/rtsp-server/rtsp-server.c | 9 ++------- gst/rtsp-server/rtsp-session-media.c | 12 ++++-------- gst/rtsp-server/rtsp-session-pool.c | 12 ++++-------- gst/rtsp-server/rtsp-session.c | 11 +++-------- gst/rtsp-server/rtsp-stream-transport.c | 12 ++---------- gst/rtsp-server/rtsp-stream.c | 17 ++++++----------- gst/rtsp-server/rtsp-thread-pool.c | 10 +++------- 14 files changed, 42 insertions(+), 106 deletions(-) diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 1343839f3a..5b032bf0c4 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -129,7 +129,8 @@ typedef struct #define RANGE_IS_SINGLE(r) (memcmp ((r)->min.bytes, (r)->max.bytes, (r)->min.size) == 0) #define gst_rtsp_address_pool_parent_class parent_class -G_DEFINE_TYPE (GstRTSPAddressPool, gst_rtsp_address_pool, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPAddressPool, gst_rtsp_address_pool, + G_TYPE_OBJECT); static void gst_rtsp_address_pool_finalize (GObject * obj); @@ -142,8 +143,6 @@ gst_rtsp_address_pool_class_init (GstRTSPAddressPoolClass * klass) gobject_class->finalize = gst_rtsp_address_pool_finalize; - g_type_class_add_private (klass, sizeof (GstRTSPAddressPoolPrivate)); - GST_DEBUG_CATEGORY_INIT (rtsp_address_pool_debug, "rtspaddresspool", 0, "GstRTSPAddressPool"); } @@ -151,7 +150,7 @@ gst_rtsp_address_pool_class_init (GstRTSPAddressPoolClass * klass) static void gst_rtsp_address_pool_init (GstRTSPAddressPool * pool) { - pool->priv = GST_RTSP_ADDRESS_POOL_GET_PRIVATE (pool); + pool->priv = gst_rtsp_address_pool_get_instance_private (pool); g_mutex_init (&pool->priv->lock); } diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index c1223b574e..c0bcdb12fb 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -50,9 +50,6 @@ #include "rtsp-auth.h" -#define GST_RTSP_AUTH_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuthPrivate)) - struct _GstRTSPAuthPrivate { GMutex lock; @@ -132,15 +129,13 @@ static void default_generate_authenticate_header (GstRTSPAuth * auth, GstRTSPContext * ctx); -G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT); static void gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) { GObjectClass *gobject_class; - g_type_class_add_private (klass, sizeof (GstRTSPAuthPrivate)); - gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_auth_get_property; @@ -184,7 +179,7 @@ gst_rtsp_auth_init (GstRTSPAuth * auth) { GstRTSPAuthPrivate *priv; - auth->priv = priv = GST_RTSP_AUTH_GET_PRIVATE (auth); + auth->priv = priv = gst_rtsp_auth_get_instance_private (auth); g_mutex_init (&priv->lock); diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index fb6998c2ce..d76374eb2e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -51,9 +51,6 @@ #include "rtsp-sdp.h" #include "rtsp-params.h" -#define GST_RTSP_CLIENT_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_CLIENT, GstRTSPClientPrivate)) - typedef enum { TUNNEL_STATE_UNKNOWN, @@ -192,15 +189,13 @@ static GstRTSPStatusCode default_pre_signal_handler (GstRTSPClient * client, static gboolean pre_signal_accumulator (GSignalInvocationHint * ihint, GValue * return_accu, const GValue * handler_return, gpointer data); -G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); static void gst_rtsp_client_class_init (GstRTSPClientClass * klass) { GObjectClass *gobject_class; - g_type_class_add_private (klass, sizeof (GstRTSPClientPrivate)); - gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_client_get_property; @@ -584,7 +579,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) static void gst_rtsp_client_init (GstRTSPClient * client) { - GstRTSPClientPrivate *priv = GST_RTSP_CLIENT_GET_PRIVATE (client); + GstRTSPClientPrivate *priv = gst_rtsp_client_get_instance_private (client); client->priv = priv; diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 3598dde25a..7100b1647d 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -34,9 +34,6 @@ #include "rtsp-media-factory-uri.h" -#define GST_RTSP_MEDIA_FACTORY_URI_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY_URI, GstRTSPMediaFactoryURIPrivate)) - struct _GstRTSPMediaFactoryURIPrivate { GMutex lock; @@ -98,7 +95,7 @@ static void gst_rtsp_media_factory_uri_finalize (GObject * obj); static GstElement *rtsp_media_factory_uri_create_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url); -G_DEFINE_TYPE (GstRTSPMediaFactoryURI, gst_rtsp_media_factory_uri, +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPMediaFactoryURI, gst_rtsp_media_factory_uri, GST_TYPE_RTSP_MEDIA_FACTORY); static void @@ -107,8 +104,6 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass) GObjectClass *gobject_class; GstRTSPMediaFactoryClass *mediafactory_class; - g_type_class_add_private (klass, sizeof (GstRTSPMediaFactoryURIPrivate)); - gobject_class = G_OBJECT_CLASS (klass); mediafactory_class = GST_RTSP_MEDIA_FACTORY_CLASS (klass); @@ -188,7 +183,7 @@ static void gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory) { GstRTSPMediaFactoryURIPrivate *priv = - GST_RTSP_MEDIA_FACTORY_URI_GET_PRIVATE (factory); + gst_rtsp_media_factory_uri_get_instance_private (factory); FilterData data = { NULL, NULL, NULL }; GST_DEBUG_OBJECT (factory, "new"); diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 46c0becfa0..bbb6a91196 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -40,9 +40,6 @@ #include "rtsp-media-factory.h" -#define GST_RTSP_MEDIA_FACTORY_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY, GstRTSPMediaFactoryPrivate)) - #define GST_RTSP_MEDIA_FACTORY_GET_LOCK(f) (&(GST_RTSP_MEDIA_FACTORY_CAST(f)->priv->lock)) #define GST_RTSP_MEDIA_FACTORY_LOCK(f) (g_mutex_lock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f))) #define GST_RTSP_MEDIA_FACTORY_UNLOCK(f) (g_mutex_unlock(GST_RTSP_MEDIA_FACTORY_GET_LOCK(f))) @@ -136,15 +133,14 @@ static void default_configure (GstRTSPMediaFactory * factory, static GstElement *default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media); -G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPMediaFactory, gst_rtsp_media_factory, + G_TYPE_OBJECT); static void gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) { GObjectClass *gobject_class; - g_type_class_add_private (klass, sizeof (GstRTSPMediaFactoryPrivate)); - gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_media_factory_get_property; @@ -252,7 +248,7 @@ static void gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) { GstRTSPMediaFactoryPrivate *priv = - GST_RTSP_MEDIA_FACTORY_GET_PRIVATE (factory); + gst_rtsp_media_factory_get_instance_private (factory); factory->priv = priv; priv->launch = g_strdup (DEFAULT_LAUNCH); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 48117c139e..74d52803be 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -81,9 +81,6 @@ #include "rtsp-media.h" -#define GST_RTSP_MEDIA_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMediaPrivate)) - struct _GstRTSPMediaPrivate { GMutex lock; @@ -297,15 +294,13 @@ gst_rtsp_publish_clock_mode_get_type (void) return (GType) id; } -G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT); static void gst_rtsp_media_class_init (GstRTSPMediaClass * klass) { GObjectClass *gobject_class; - g_type_class_add_private (klass, sizeof (GstRTSPMediaPrivate)); - gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_media_get_property; @@ -429,7 +424,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) static void gst_rtsp_media_init (GstRTSPMedia * media) { - GstRTSPMediaPrivate *priv = GST_RTSP_MEDIA_GET_PRIVATE (media); + GstRTSPMediaPrivate *priv = gst_rtsp_media_get_instance_private (media); media->priv = priv; diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 53b4ffd85e..15685ba8ab 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -38,9 +38,6 @@ #include "rtsp-mount-points.h" -#define GST_RTSP_MOUNT_POINTS_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MOUNT_POINTS, GstRTSPMountPointsPrivate)) - typedef struct { gchar *path; @@ -97,7 +94,8 @@ struct _GstRTSPMountPointsPrivate gboolean dirty; }; -G_DEFINE_TYPE (GstRTSPMountPoints, gst_rtsp_mount_points, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPMountPoints, gst_rtsp_mount_points, + G_TYPE_OBJECT); GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug); #define GST_CAT_DEFAULT rtsp_media_debug @@ -111,8 +109,6 @@ gst_rtsp_mount_points_class_init (GstRTSPMountPointsClass * klass) { GObjectClass *gobject_class; - g_type_class_add_private (klass, sizeof (GstRTSPMountPointsPrivate)); - gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gst_rtsp_mount_points_finalize; @@ -126,11 +122,11 @@ gst_rtsp_mount_points_class_init (GstRTSPMountPointsClass * klass) static void gst_rtsp_mount_points_init (GstRTSPMountPoints * mounts) { - GstRTSPMountPointsPrivate *priv = GST_RTSP_MOUNT_POINTS_GET_PRIVATE (mounts); + GstRTSPMountPointsPrivate *priv; GST_DEBUG_OBJECT (mounts, "created"); - mounts->priv = priv; + mounts->priv = priv = gst_rtsp_mount_points_get_instance_private (mounts); g_mutex_init (&priv->lock); priv->mounts = g_sequence_new (data_item_free); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 91f4dfb05d..0a0b912fb8 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -58,9 +58,6 @@ #include "rtsp-server.h" #include "rtsp-client.h" -#define GST_RTSP_SERVER_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SERVER, GstRTSPServerPrivate)) - #define GST_RTSP_SERVER_GET_LOCK(server) (&(GST_RTSP_SERVER_CAST(server)->priv->lock)) #define GST_RTSP_SERVER_LOCK(server) (g_mutex_lock(GST_RTSP_SERVER_GET_LOCK(server))) #define GST_RTSP_SERVER_UNLOCK(server) (g_mutex_unlock(GST_RTSP_SERVER_GET_LOCK(server))) @@ -123,7 +120,7 @@ enum SIGNAL_LAST }; -G_DEFINE_TYPE (GstRTSPServer, gst_rtsp_server, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPServer, gst_rtsp_server, G_TYPE_OBJECT); GST_DEBUG_CATEGORY_STATIC (rtsp_server_debug); #define GST_CAT_DEFAULT rtsp_server_debug @@ -145,8 +142,6 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) { GObjectClass *gobject_class; - g_type_class_add_private (klass, sizeof (GstRTSPServerPrivate)); - gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_server_get_property; @@ -237,7 +232,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) static void gst_rtsp_server_init (GstRTSPServer * server) { - GstRTSPServerPrivate *priv = GST_RTSP_SERVER_GET_PRIVATE (server); + GstRTSPServerPrivate *priv = gst_rtsp_server_get_instance_private (server); server->priv = priv; diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index a1eb98ea06..c3bac97ccb 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -39,9 +39,6 @@ #include "rtsp-session.h" -#define GST_RTSP_SESSION_MEDIA_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION_MEDIA, GstRTSPSessionMediaPrivate)) - struct _GstRTSPSessionMediaPrivate { GMutex lock; @@ -65,15 +62,14 @@ GST_DEBUG_CATEGORY_STATIC (rtsp_session_media_debug); static void gst_rtsp_session_media_finalize (GObject * obj); -G_DEFINE_TYPE (GstRTSPSessionMedia, gst_rtsp_session_media, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPSessionMedia, gst_rtsp_session_media, + G_TYPE_OBJECT); static void gst_rtsp_session_media_class_init (GstRTSPSessionMediaClass * klass) { GObjectClass *gobject_class; - g_type_class_add_private (klass, sizeof (GstRTSPSessionMediaPrivate)); - gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gst_rtsp_session_media_finalize; @@ -85,9 +81,9 @@ gst_rtsp_session_media_class_init (GstRTSPSessionMediaClass * klass) static void gst_rtsp_session_media_init (GstRTSPSessionMedia * media) { - GstRTSPSessionMediaPrivate *priv = GST_RTSP_SESSION_MEDIA_GET_PRIVATE (media); + GstRTSPSessionMediaPrivate *priv; - media->priv = priv; + media->priv = priv = gst_rtsp_session_media_get_instance_private (media); g_mutex_init (&priv->lock); priv->state = GST_RTSP_STATE_INIT; diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 3915b8cbb1..8f45e28279 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -42,9 +42,6 @@ #include "rtsp-session-pool.h" -#define GST_RTSP_SESSION_POOL_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION_POOL, GstRTSPSessionPoolPrivate)) - struct _GstRTSPSessionPoolPrivate { GMutex lock; /* protects everything in this struct */ @@ -91,15 +88,14 @@ static gchar *create_session_id (GstRTSPSessionPool * pool); static GstRTSPSession *create_session (GstRTSPSessionPool * pool, const gchar * id); -G_DEFINE_TYPE (GstRTSPSessionPool, gst_rtsp_session_pool, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPSessionPool, gst_rtsp_session_pool, + G_TYPE_OBJECT); static void gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) { GObjectClass *gobject_class; - g_type_class_add_private (klass, sizeof (GstRTSPSessionPoolPrivate)); - gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_session_pool_get_property; @@ -128,9 +124,9 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) static void gst_rtsp_session_pool_init (GstRTSPSessionPool * pool) { - GstRTSPSessionPoolPrivate *priv = GST_RTSP_SESSION_POOL_GET_PRIVATE (pool); + GstRTSPSessionPoolPrivate *priv; - pool->priv = priv; + pool->priv = priv = gst_rtsp_session_pool_get_instance_private (pool); g_mutex_init (&priv->lock); priv->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 83a998527e..37945f853d 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -47,9 +47,6 @@ #include "rtsp-session.h" -#define GST_RTSP_SESSION_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION, GstRTSPSessionPrivate)) - struct _GstRTSPSessionPrivate { GMutex lock; /* protects everything but sessionid and create_time */ @@ -90,15 +87,13 @@ static void gst_rtsp_session_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_session_finalize (GObject * obj); -G_DEFINE_TYPE (GstRTSPSession, gst_rtsp_session, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPSession, gst_rtsp_session, G_TYPE_OBJECT); static void gst_rtsp_session_class_init (GstRTSPSessionClass * klass) { GObjectClass *gobject_class; - g_type_class_add_private (klass, sizeof (GstRTSPSessionPrivate)); - gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_session_get_property; @@ -127,9 +122,9 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass) static void gst_rtsp_session_init (GstRTSPSession * session) { - GstRTSPSessionPrivate *priv = GST_RTSP_SESSION_GET_PRIVATE (session); + GstRTSPSessionPrivate *priv; - session->priv = priv; + session->priv = priv = gst_rtsp_session_get_instance_private (session); GST_INFO ("init session %p", session); diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 9da62d87e8..7a6ba12c3c 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -43,9 +43,6 @@ #include "rtsp-stream-transport.h" -#define GST_RTSP_STREAM_TRANSPORT_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_STREAM_TRANSPORT, GstRTSPStreamTransportPrivate)) - struct _GstRTSPStreamTransportPrivate { GstRTSPStream *stream; @@ -78,7 +75,7 @@ GST_DEBUG_CATEGORY_STATIC (rtsp_stream_transport_debug); static void gst_rtsp_stream_transport_finalize (GObject * obj); -G_DEFINE_TYPE (GstRTSPStreamTransport, gst_rtsp_stream_transport, +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPStreamTransport, gst_rtsp_stream_transport, G_TYPE_OBJECT); static void @@ -86,8 +83,6 @@ gst_rtsp_stream_transport_class_init (GstRTSPStreamTransportClass * klass) { GObjectClass *gobject_class; - g_type_class_add_private (klass, sizeof (GstRTSPStreamTransportPrivate)); - gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gst_rtsp_stream_transport_finalize; @@ -99,10 +94,7 @@ gst_rtsp_stream_transport_class_init (GstRTSPStreamTransportClass * klass) static void gst_rtsp_stream_transport_init (GstRTSPStreamTransport * trans) { - GstRTSPStreamTransportPrivate *priv = - GST_RTSP_STREAM_TRANSPORT_GET_PRIVATE (trans); - - trans->priv = priv; + trans->priv = gst_rtsp_stream_transport_get_instance_private (trans); } static void diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index a94c5bd418..0e230a4bb0 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -59,9 +59,6 @@ #include "rtsp-stream.h" -#define GST_RTSP_STREAM_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_STREAM, GstRTSPStreamPrivate)) - struct _GstRTSPStreamPrivate { GMutex lock; @@ -211,15 +208,13 @@ static void gst_rtsp_stream_finalize (GObject * obj); static guint gst_rtsp_stream_signals[SIGNAL_LAST] = { 0 }; -G_DEFINE_TYPE (GstRTSPStream, gst_rtsp_stream, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPStream, gst_rtsp_stream, G_TYPE_OBJECT); static void gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) { GObjectClass *gobject_class; - g_type_class_add_private (klass, sizeof (GstRTSPStreamPrivate)); - gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_stream_get_property; @@ -259,7 +254,7 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) static void gst_rtsp_stream_init (GstRTSPStream * stream) { - GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); + GstRTSPStreamPrivate *priv = gst_rtsp_stream_get_instance_private (stream); GST_DEBUG ("new stream %p", stream); @@ -4016,7 +4011,7 @@ gst_rtsp_stream_update_crypto (GstRTSPStream * stream, GSocket * gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family) { - GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); + GstRTSPStreamPrivate *priv = stream->priv; GSocket *socket; const gchar *name; @@ -4050,7 +4045,7 @@ gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family) GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) { - GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); + GstRTSPStreamPrivate *priv = gst_rtsp_stream_get_instance_private (stream); GSocket *socket; const gchar *name; @@ -4083,7 +4078,7 @@ GSocket * gst_rtsp_stream_get_rtp_multicast_socket (GstRTSPStream * stream, GSocketFamily family) { - GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); + GstRTSPStreamPrivate *priv = gst_rtsp_stream_get_instance_private (stream); GSocket *socket; const gchar *name; @@ -4116,7 +4111,7 @@ GSocket * gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream * stream, GSocketFamily family) { - GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream); + GstRTSPStreamPrivate *priv = gst_rtsp_stream_get_instance_private (stream); GSocket *socket; const gchar *name; diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index a3cb850c12..4e14447778 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -184,9 +184,6 @@ gst_rtsp_thread_stop (GstRTSPThread * thread) gst_rtsp_thread_unref (thread); } -#define GST_RTSP_THREAD_POOL_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_THREAD_POOL, GstRTSPThreadPoolPrivate)) - struct _GstRTSPThreadPoolPrivate { GMutex lock; @@ -220,15 +217,14 @@ static gpointer do_loop (GstRTSPThread * thread); static GstRTSPThread *default_get_thread (GstRTSPThreadPool * pool, GstRTSPThreadType type, GstRTSPContext * ctx); -G_DEFINE_TYPE (GstRTSPThreadPool, gst_rtsp_thread_pool, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPThreadPool, gst_rtsp_thread_pool, + G_TYPE_OBJECT); static void gst_rtsp_thread_pool_class_init (GstRTSPThreadPoolClass * klass) { GObjectClass *gobject_class; - g_type_class_add_private (klass, sizeof (GstRTSPThreadPoolPrivate)); - gobject_class = G_OBJECT_CLASS (klass); gobject_class->get_property = gst_rtsp_thread_pool_get_property; @@ -261,7 +257,7 @@ gst_rtsp_thread_pool_init (GstRTSPThreadPool * pool) { GstRTSPThreadPoolPrivate *priv; - pool->priv = priv = GST_RTSP_THREAD_POOL_GET_PRIVATE (pool); + pool->priv = priv = gst_rtsp_thread_pool_get_instance_private (pool); g_mutex_init (&priv->lock); priv->max_threads = DEFAULT_MAX_THREADS; From 1a38de2b17e5f6e15d37e7b774ce1b26e9799b81 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Tue, 13 Feb 2018 11:04:36 +0100 Subject: [PATCH 1510/1776] rtsp-stream: Set the multicast TTL parameter on multicast udp sinks And not on unicast udp sinks https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-stream.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 0e230a4bb0..4be1ae3263 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -3820,10 +3820,12 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, if (tr->ttl > 0) { GST_INFO ("setting ttl-mc %d", tr->ttl); - if (priv->udpsink[0]) - g_object_set (G_OBJECT (priv->udpsink[0]), "ttl-mc", tr->ttl, NULL); - if (priv->udpsink[1]) - g_object_set (G_OBJECT (priv->udpsink[1]), "ttl-mc", tr->ttl, NULL); + if (priv->mcast_udpsink[0]) + g_object_set (G_OBJECT (priv->mcast_udpsink[0]), "ttl-mc", tr->ttl, + NULL); + if (priv->mcast_udpsink[1]) + g_object_set (G_OBJECT (priv->mcast_udpsink[1]), "ttl-mc", tr->ttl, + NULL); } } else { priv->transports = g_list_remove (priv->transports, trans); From dcb4533fedae3ac62bc25a916eb95927b7d69aec Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Wed, 14 Feb 2018 10:41:02 +0100 Subject: [PATCH 1511/1776] rtsp-stream: Update transport for multicast clients as well If a multicast client requests different transport settings than the existing one make sure that this new transport configuruation is propagated to the multicast udp sink. https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-stream.c | 54 +++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4be1ae3263..e5f6c6ffa6 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -3800,6 +3800,28 @@ gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer) return ret; } +/* must be called with lock */ +static inline void +add_client (GstElement * rtp_sink, GstElement * rtcp_sink, const gchar * host, + gint rtp_port, gint rtcp_port) +{ + if (rtp_sink != NULL) + g_signal_emit_by_name (rtp_sink, "add", host, rtp_port, NULL); + if (rtcp_sink != NULL) + g_signal_emit_by_name (rtcp_sink, "add", host, rtcp_port, NULL); +} + +/* must be called with lock */ +static void +remove_client (GstElement * rtp_sink, GstElement * rtcp_sink, + const gchar * host, gint rtp_port, gint rtcp_port) +{ + if (rtp_sink != NULL) + g_signal_emit_by_name (rtp_sink, "remove", host, rtp_port, NULL); + if (rtcp_sink != NULL) + g_signal_emit_by_name (rtcp_sink, "remove", host, rtcp_port, NULL); +} + /* must be called with lock */ static gboolean update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, @@ -3807,17 +3829,24 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, { GstRTSPStreamPrivate *priv = stream->priv; const GstRTSPTransport *tr; + gchar *dest; + gint min, max; tr = gst_rtsp_stream_transport_get_transport (trans); + dest = tr->destination; switch (tr->lower_transport) { case GST_RTSP_LOWER_TRANS_UDP_MCAST: { + min = tr->port.min; + max = tr->port.max; + if (add) { + GST_INFO ("adding %s:%d-%d", dest, min, max); if (!check_mcast_part_for_transport (stream, tr)) goto mcast_error; - priv->transports = g_list_prepend (priv->transports, trans); + /* FIXME: Is it ok to set ttl-mc if media is shared? */ if (tr->ttl > 0) { GST_INFO ("setting ttl-mc %d", tr->ttl); if (priv->mcast_udpsink[0]) @@ -3827,21 +3856,20 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, g_object_set (G_OBJECT (priv->mcast_udpsink[1]), "ttl-mc", tr->ttl, NULL); } + add_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min, + max); + priv->transports = g_list_prepend (priv->transports, trans); } else { + GST_INFO ("removing %s:%d-%d", dest, min, max); + remove_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, + min, max); priv->transports = g_list_remove (priv->transports, trans); } break; } case GST_RTSP_LOWER_TRANS_UDP: { - gchar *dest; - gint min, max; - - dest = tr->destination; - if (tr->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - min = tr->port.min; - max = tr->port.max; - } else if (priv->client_side) { + if (priv->client_side) { /* In client side mode the 'destination' is the RTSP server, so send * to those ports */ min = tr->server_port.min; @@ -3853,15 +3881,11 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, if (add) { GST_INFO ("adding %s:%d-%d", dest, min, max); - if (priv->udpsink[0]) - g_signal_emit_by_name (priv->udpsink[0], "add", dest, min, NULL); - g_signal_emit_by_name (priv->udpsink[1], "add", dest, max, NULL); + add_client (priv->udpsink[0], priv->udpsink[1], dest, min, max); priv->transports = g_list_prepend (priv->transports, trans); } else { GST_INFO ("removing %s:%d-%d", dest, min, max); - if (priv->udpsink[0]) - g_signal_emit_by_name (priv->udpsink[0], "remove", dest, min, NULL); - g_signal_emit_by_name (priv->udpsink[1], "remove", dest, max, NULL); + remove_client (priv->udpsink[0], priv->udpsink[1], dest, min, max); priv->transports = g_list_remove (priv->transports, trans); } priv->transports_cookie++; From 400705033512298bc75c225714e4378d4bb23d7d Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Tue, 13 Mar 2018 11:10:35 +0100 Subject: [PATCH 1512/1776] rtsp-stream: Don't require presence of sinks in _get_*_socket() Transport specific sink elements are added to the pipeline in PLAY request and sockets are already created in SETUP so it's actually wrong to require the presence of sinks in _get_*_socket() functions. https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-stream.c | 50 +++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index e5f6c6ffa6..c886cf3e27 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4039,19 +4039,20 @@ gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family) { GstRTSPStreamPrivate *priv = stream->priv; GSocket *socket; - const gchar *name; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 || family == G_SOCKET_FAMILY_IPV6, NULL); - g_return_val_if_fail (priv->udpsink[0], NULL); + g_mutex_lock (&priv->lock); if (family == G_SOCKET_FAMILY_IPV6) - name = "socket-v6"; + socket = priv->socket_v6[0]; else - name = "socket"; + socket = priv->socket_v4[0]; - g_object_get (priv->udpsink[0], name, &socket, NULL); + if (socket != NULL) + socket = g_object_ref (socket); + g_mutex_unlock (&priv->lock); return socket; } @@ -4071,21 +4072,22 @@ gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family) GSocket * gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) { - GstRTSPStreamPrivate *priv = gst_rtsp_stream_get_instance_private (stream); + GstRTSPStreamPrivate *priv = stream->priv; GSocket *socket; - const gchar *name; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 || family == G_SOCKET_FAMILY_IPV6, NULL); - g_return_val_if_fail (priv->udpsink[1], NULL); + g_mutex_lock (&priv->lock); if (family == G_SOCKET_FAMILY_IPV6) - name = "socket-v6"; + socket = priv->socket_v6[1]; else - name = "socket"; + socket = priv->socket_v4[1]; - g_object_get (priv->udpsink[1], name, &socket, NULL); + if (socket != NULL) + socket = g_object_ref (socket); + g_mutex_unlock (&priv->lock); return socket; } @@ -4104,21 +4106,22 @@ GSocket * gst_rtsp_stream_get_rtp_multicast_socket (GstRTSPStream * stream, GSocketFamily family) { - GstRTSPStreamPrivate *priv = gst_rtsp_stream_get_instance_private (stream); + GstRTSPStreamPrivate *priv = stream->priv; GSocket *socket; - const gchar *name; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 || family == G_SOCKET_FAMILY_IPV6, NULL); - g_return_val_if_fail (priv->mcast_udpsink[0], NULL); + g_mutex_lock (&priv->lock); if (family == G_SOCKET_FAMILY_IPV6) - name = "socket-v6"; + socket = priv->mcast_socket_v6[0]; else - name = "socket"; + socket = priv->mcast_socket_v4[0]; - g_object_get (priv->mcast_udpsink[0], name, &socket, NULL); + if (socket != NULL) + socket = g_object_ref (socket); + g_mutex_unlock (&priv->lock); return socket; } @@ -4137,21 +4140,22 @@ GSocket * gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream * stream, GSocketFamily family) { - GstRTSPStreamPrivate *priv = gst_rtsp_stream_get_instance_private (stream); + GstRTSPStreamPrivate *priv = stream->priv; GSocket *socket; - const gchar *name; g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 || family == G_SOCKET_FAMILY_IPV6, NULL); - g_return_val_if_fail (priv->mcast_udpsink[1], NULL); + g_mutex_lock (&priv->lock); if (family == G_SOCKET_FAMILY_IPV6) - name = "socket-v6"; + socket = priv->mcast_socket_v6[1]; else - name = "socket"; + socket = priv->mcast_socket_v4[1]; - g_object_get (priv->mcast_udpsink[1], name, &socket, NULL); + if (socket != NULL) + socket = g_object_ref (socket); + g_mutex_unlock (&priv->lock); return socket; } From 4d25e04bd75314e2433977490856bc58187edd31 Mon Sep 17 00:00:00 2001 From: Ulf Olsson Date: Wed, 1 Feb 2017 09:44:50 +0100 Subject: [PATCH 1513/1776] rtsp-stream: Emit a signal when the SRTP decoder is created https://bugzilla.gnome.org/show_bug.cgi?id=778080 --- gst/rtsp-server/rtsp-stream.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index c886cf3e27..6e03a68840 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -191,6 +191,7 @@ enum { SIGNAL_NEW_RTP_ENCODER, SIGNAL_NEW_RTCP_ENCODER, + SIGNAL_NEW_RTP_RTCP_DECODER, SIGNAL_LAST }; @@ -246,6 +247,11 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + gst_rtsp_stream_signals[SIGNAL_NEW_RTP_RTCP_DECODER] = + g_signal_new ("new-rtp-rtcp-decoder", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, + G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + GST_DEBUG_CATEGORY_INIT (rtsp_stream_debug, "rtspstream", 0, "GstRTSPStream"); ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); @@ -2279,6 +2285,10 @@ request_rtp_rtcp_decoder (GstElement * rtpbin, guint session, g_signal_connect (priv->srtpdec, "request-key", (GCallback) request_key, stream); + + g_signal_emit (stream, gst_rtsp_stream_signals[SIGNAL_NEW_RTP_RTCP_DECODER], + 0, priv->srtpdec); + } return gst_object_ref (priv->srtpdec); } From f110016ac6bb90a2cbadfd8275a0a997babf57e2 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 21 Mar 2018 10:56:51 +0100 Subject: [PATCH 1514/1776] rtsp-stream: Fix mismatch between allowed and configured protocols https://bugzilla.gnome.org/show_bug.cgi?id=796679 --- gst/rtsp-server/rtsp-stream.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 6e03a68840..092109c81c 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -78,7 +78,8 @@ struct _GstRTSPStreamPrivate * parts are present in the stream. */ gboolean is_complete; GstRTSPProfile profiles; - GstRTSPLowerTrans protocols; + GstRTSPLowerTrans allowed_protocols; + GstRTSPLowerTrans configured_protocols; /* pads on the rtpbin */ GstPad *send_rtp_sink; @@ -269,7 +270,8 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->dscp_qos = -1; priv->control = g_strdup (DEFAULT_CONTROL); priv->profiles = DEFAULT_PROFILES; - priv->protocols = DEFAULT_PROTOCOLS; + priv->allowed_protocols = DEFAULT_PROTOCOLS; + priv->configured_protocols = 0; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; g_mutex_init (&priv->lock); @@ -708,7 +710,7 @@ gst_rtsp_stream_is_transport_supported (GstRTSPStream * stream, if (!(transport->profile & priv->profiles)) goto unsupported_profile; - if (!(transport->lower_transport & priv->protocols)) + if (!(transport->lower_transport & priv->allowed_protocols)) goto unsupported_ltrans; g_mutex_unlock (&priv->lock); @@ -800,7 +802,7 @@ gst_rtsp_stream_set_protocols (GstRTSPStream * stream, priv = stream->priv; g_mutex_lock (&priv->lock); - priv->protocols = protocols; + priv->allowed_protocols = protocols; g_mutex_unlock (&priv->lock); } @@ -824,7 +826,7 @@ gst_rtsp_stream_get_protocols (GstRTSPStream * stream) priv = stream->priv; g_mutex_lock (&priv->lock); - res = priv->protocols; + res = priv->allowed_protocols; g_mutex_unlock (&priv->lock); return res; @@ -4471,9 +4473,9 @@ gst_rtsp_stream_query_position (GstRTSPStream * stream, gint64 * position) g_mutex_lock (&priv->lock); /* depending on the transport type, it should query corresponding sink */ - if (priv->protocols & GST_RTSP_LOWER_TRANS_UDP) + if (priv->configured_protocols & GST_RTSP_LOWER_TRANS_UDP) sink = priv->udpsink[0]; - else if (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) + else if (priv->configured_protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) sink = priv->mcast_udpsink[0]; else sink = priv->appsink[0]; @@ -4551,9 +4553,9 @@ gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop) g_mutex_lock (&priv->lock); /* depending on the transport type, it should query corresponding sink */ - if (priv->protocols & GST_RTSP_LOWER_TRANS_UDP) + if (priv->configured_protocols & GST_RTSP_LOWER_TRANS_UDP) sink = priv->udpsink[0]; - else if (priv->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) + else if (priv->configured_protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) sink = priv->mcast_udpsink[0]; else sink = priv->appsink[0]; @@ -4687,7 +4689,7 @@ gst_rtsp_stream_complete_stream (GstRTSPStream * stream, g_mutex_lock (&priv->lock); - if (!(priv->protocols & transport->lower_transport)) + if (!(priv->allowed_protocols & transport->lower_transport)) goto unallowed_transport; if (!create_receiver_part (stream, transport)) @@ -4697,6 +4699,8 @@ gst_rtsp_stream_complete_stream (GstRTSPStream * stream, if (!create_sender_part (stream, transport)) goto create_sender_error; + priv->configured_protocols |= transport->lower_transport; + priv->is_complete = TRUE; g_mutex_unlock (&priv->lock); From c1fab570d8e845685b7e890b2a588314382c1ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Wed, 27 Jun 2018 08:30:42 +0200 Subject: [PATCH 1515/1776] rtsp-stream: avoid pushing data on unlinked udpsrc pad during setup Fix race when setting up source elements. Since we set the source element(s) to PLAYING state before hooking them up to the downstream funnel, it's possible for the source element to receive packets before we actually get to linking it to the funnel, in which case buffers would be pushed out on an unlinked pad, causing it to error out and stop receiving more data. We fix this by blocking the source's srcpad until we have linked it. https://bugzilla.gnome.org/show_bug.cgi?id=796160 --- gst/rtsp-server/rtsp-stream.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 092109c81c..953735771d 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -3002,10 +3002,15 @@ plug_src (GstRTSPStream * stream, GstBin * bin, GstElement * src, { GstRTSPStreamPrivate *priv; GstPad *pad, *selpad; + gulong id = 0; priv = stream->priv; + pad = gst_element_get_static_pad (src, "src"); if (priv->srcpad) { + /* block pad so src can't push data while it's not yet linked */ + id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK | + GST_PAD_PROBE_TYPE_BUFFER, NULL, NULL, NULL); /* we set and keep these to playing so that they don't cause NO_PREROLL return * values. This is only relevant for PLAY pipelines */ gst_element_set_state (src, GST_STATE_PLAYING); @@ -3017,8 +3022,9 @@ plug_src (GstRTSPStream * stream, GstBin * bin, GstElement * src, /* and link to the funnel */ selpad = gst_element_get_request_pad (funnel, "sink_%u"); - pad = gst_element_get_static_pad (src, "src"); gst_pad_link (pad, selpad); + if (id != 0) + gst_pad_remove_probe (pad, id); gst_object_unref (pad); gst_object_unref (selpad); } From 604240f7eb3520a5b513399b55a86aa6b33f6433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis-Francis=20Ratt=C3=A9-Boulianne?= Date: Fri, 8 Jan 2016 18:12:14 -0500 Subject: [PATCH 1516/1776] client: Strip transport parts as whitespaces could be around commas https://bugzilla.gnome.org/show_bug.cgi?id=758428 --- gst/rtsp-server/rtsp-client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d76374eb2e..11931d739a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1788,6 +1788,7 @@ parse_transport (const char *transport, GstRTSPStream * stream, /* loop through the transports, try to parse */ for (i = 0; transports[i]; i++) { + g_strstrip (transports[i]); res = gst_rtsp_transport_parse (transports[i], tr); if (res != GST_RTSP_OK) { /* no valid transport, search some more */ From b6c3960f1153d092097d2a0ce1845de377032a43 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Wed, 11 Jul 2018 01:25:51 +1000 Subject: [PATCH 1517/1776] examples: Add test-appsrc2 Add an example of feeding both audio and video into an RTSP pipeline via appsrc. --- examples/.gitignore | 1 + examples/Makefile.am | 2 +- examples/test-appsrc2.c | 196 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 examples/test-appsrc2.c diff --git a/examples/.gitignore b/examples/.gitignore index d9df57c609..4a65f7420c 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,4 +1,5 @@ test-appsrc +test-appsrc2 test-cgroups test-launch test-mp4 diff --git a/examples/Makefile.am b/examples/Makefile.am index 6a70d728fe..66345c0043 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,6 +1,6 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ test-launch test-sdp test-uri test-auth test-auth-digest \ - test-multicast test-multicast2 test-appsrc \ + test-multicast test-multicast2 test-appsrc test-appsrc2 \ test-video-rtx test-record test-record-auth \ test-netclock test-netclock-client \ test-onvif-backchannel test-video-disconnect diff --git a/examples/test-appsrc2.c b/examples/test-appsrc2.c new file mode 100644 index 0000000000..da2513ae8f --- /dev/null +++ b/examples/test-appsrc2.c @@ -0,0 +1,196 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include + +typedef struct +{ + GstElement *generator_pipe; + GstElement *vid_appsink; + GstElement *vid_appsrc; + GstElement *aud_appsink; + GstElement *aud_appsrc; +} MyContext; + +/* called when we need to give data to an appsrc */ +static void +need_data (GstElement * appsrc, guint unused, MyContext * ctx) +{ + GstSample *sample; + GstFlowReturn ret; + + if (appsrc == ctx->vid_appsrc) + sample = gst_app_sink_pull_sample (GST_APP_SINK (ctx->vid_appsink)); + else + sample = gst_app_sink_pull_sample (GST_APP_SINK (ctx->aud_appsink)); + + if (sample) { + GstBuffer *buffer = gst_sample_get_buffer (sample); + GstSegment *seg = gst_sample_get_segment (sample); + GstClockTime pts, dts; + + /* Convert the PTS/DTS to running time so they start from 0 */ + pts = GST_BUFFER_PTS (buffer); + if (GST_CLOCK_TIME_IS_VALID (pts)) + pts = gst_segment_to_running_time (seg, GST_FORMAT_TIME, pts); + + dts = GST_BUFFER_DTS (buffer); + if (GST_CLOCK_TIME_IS_VALID (dts)) + dts = gst_segment_to_running_time (seg, GST_FORMAT_TIME, dts); + + if (buffer) { + /* Make writable so we can adjust the timestamps */ + buffer = gst_buffer_copy (buffer); + GST_BUFFER_PTS (buffer) = pts; + GST_BUFFER_DTS (buffer) = dts; + g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret); + } + + /* we don't need the appsink sample anymore */ + gst_sample_unref (sample); + } +} + +static void +ctx_free (MyContext * ctx) +{ + gst_element_set_state (ctx->generator_pipe, GST_STATE_NULL); + + gst_object_unref (ctx->generator_pipe); + gst_object_unref (ctx->vid_appsrc); + gst_object_unref (ctx->vid_appsink); + gst_object_unref (ctx->aud_appsrc); + gst_object_unref (ctx->aud_appsink); + + g_free (ctx); +} + +/* called when a new media pipeline is constructed. We can query the + * pipeline and configure our appsrc */ +static void +media_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media, + gpointer user_data) +{ + GstElement *element, *appsrc, *appsink; + GstCaps *caps; + MyContext *ctx; + + ctx = g_new0 (MyContext, 1); + /* This pipeline generates H264 video and PCM audio. The appsinks are kept small so that if delivery is slow, + * encoded buffers are dropped as needed. There's slightly more buffers (32) allowed for audio */ + ctx->generator_pipe = + gst_parse_launch + ("videotestsrc is-live=true ! x264enc speed-preset=superfast tune=zerolatency ! h264parse ! appsink name=vid max-buffers=1 drop=true " + "audiotestsrc is-live=true ! appsink name=aud max-buffers=32 drop=true", + NULL); + + /* make sure the data is freed when the media is gone */ + g_object_set_data_full (G_OBJECT (media), "rtsp-extra-data", ctx, + (GDestroyNotify) ctx_free); + + /* get the element (bin) used for providing the streams of the media */ + element = gst_rtsp_media_get_element (media); + + /* Find the 2 app sources (video / audio), and configure them, connect to the + * signals to request data */ + /* configure the caps of the video */ + caps = gst_caps_new_simple ("video/x-h264", + "stream-format", G_TYPE_STRING, "byte-stream", + "alignment", G_TYPE_STRING, "au", + "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, + "framerate", GST_TYPE_FRACTION, 15, 1, NULL); + ctx->vid_appsrc = appsrc = + gst_bin_get_by_name_recurse_up (GST_BIN (element), "videosrc"); + ctx->vid_appsink = appsink = + gst_bin_get_by_name (GST_BIN (ctx->generator_pipe), "vid"); + gst_util_set_object_arg (G_OBJECT (appsrc), "format", "time"); + g_object_set (G_OBJECT (appsrc), "caps", caps, NULL); + g_object_set (G_OBJECT (appsink), "caps", caps, NULL); + /* install the callback that will be called when a buffer is needed */ + g_signal_connect (appsrc, "need-data", (GCallback) need_data, ctx); + gst_caps_unref (caps); + + caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "S24BE", + "layout", G_TYPE_STRING, "interleaved", "rate", G_TYPE_INT, 48000, + "channels", G_TYPE_INT, 2, NULL); + ctx->aud_appsrc = appsrc = + gst_bin_get_by_name_recurse_up (GST_BIN (element), "audiosrc"); + ctx->aud_appsink = appsink = + gst_bin_get_by_name (GST_BIN (ctx->generator_pipe), "aud"); + gst_util_set_object_arg (G_OBJECT (appsrc), "format", "time"); + g_object_set (G_OBJECT (appsrc), "caps", caps, NULL); + g_object_set (G_OBJECT (appsink), "caps", caps, NULL); + g_signal_connect (appsrc, "need-data", (GCallback) need_data, ctx); + gst_caps_unref (caps); + + gst_element_set_state (ctx->generator_pipe, GST_STATE_PLAYING); + gst_object_unref (element); +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + + /* get the mount points for this server, every server has a default object + * that be used to map uri mount points to media factories */ + mounts = gst_rtsp_server_get_mount_points (server); + + /* make a media factory for a test stream. The default media factory can use + * gst-launch syntax to create pipelines. + * any launch line works as long as it contains elements named pay%d. Each + * element with pay%d names will be a stream */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, + "( appsrc name=videosrc ! h264parse ! rtph264pay name=pay0 pt=96 " + " appsrc name=audiosrc ! audioconvert ! rtpL24pay name=pay1 pt=97 )"); + + /* notify when our media is ready, This is called whenever someone asks for + * the media and a new pipeline with our appsrc is created */ + g_signal_connect (factory, "media-configure", (GCallback) media_configure, + NULL); + + /* attach the test factory to the /test url */ + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + /* don't need the ref to the mounts anymore */ + g_object_unref (mounts); + + /* attach the server to the default maincontext */ + gst_rtsp_server_attach (server, NULL); + + /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:8554/test\n"); + g_main_loop_run (loop); + + return 0; +} From 35e284a9464a759c32c551148265289535a66814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 10 Jul 2018 23:53:41 +0100 Subject: [PATCH 1518/1776] examples: fix build of new test-appsrc2 example Need to link against libgstapp-1.0. --- examples/Makefile.am | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/Makefile.am b/examples/Makefile.am index 66345c0043..6cbe72a6d3 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -15,6 +15,12 @@ noinst_PROGRAMS += test-cgroups LDADD += $(LIBCGROUP_LIBS) endif +test_appsrc2_CFLAGS = \ + $(AM_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) +test_appsrc2_LDADD = \ + $(LDADD) \ + $(GST_PLUGINS_BASE_LIBS) -lgstapp-1.0 test_netclock_CFLAGS = \ $(AM_CFLAGS) \ $(GST_NET_CFLAGS) From c2e3aa49f8f51d61852ccabb8168e317b1acf930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 10 Jul 2018 23:55:20 +0100 Subject: [PATCH 1519/1776] meson: add new test-appsrc2 example to meson build --- examples/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/meson.build b/examples/meson.build index 80da73acc0..332ea666b1 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -1,5 +1,6 @@ examples = [ 'test-appsrc', + 'test-appsrc2', 'test-auth', 'test-auth-digest', 'test-launch', @@ -22,7 +23,7 @@ foreach example : examples executable(example, '@0@.c'.format(example), c_args : rtspserver_args, include_directories : rtspserver_incs, - dependencies : [glib_dep, gst_dep, gstnet_dep, gst_rtsp_server_dep], + dependencies : [glib_dep, gst_dep, gstapp_dep, gstnet_dep, gst_rtsp_server_dep], install: false) endforeach From 318525570fc063de77f33270e418cc29efba8708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 10 Jul 2018 23:56:23 +0100 Subject: [PATCH 1520/1776] .gitignore: add another example binary --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2d4d543b41..db9a9f8cb6 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ stamp-h.in /examples/test-multicast /examples/test-multicast2 /examples/test-auth-digest +/examples/test-video-disconnect /test-driver /tests/check/gst/*.log From 1cd6c0340e54470ce04d2717ad8c924e04de816e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 12 Jul 2018 18:57:21 +0100 Subject: [PATCH 1521/1776] rtsp-onvif-media: fix g-ir-scanner warnings --- gst/rtsp-server/rtsp-onvif-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-onvif-media.c b/gst/rtsp-server/rtsp-onvif-media.c index 6e8fd1dbc3..dcd86f244c 100644 --- a/gst/rtsp-server/rtsp-onvif-media.c +++ b/gst/rtsp-server/rtsp-onvif-media.c @@ -284,7 +284,7 @@ out: /** * gst_rtsp_onvif_media_set_backchannel_bandwidth: - * @factory: a #GstRTSPMedia + * @media: a #GstRTSPMedia * @bandwidth: the bandwidth in bits per second * * Set the configured/supported bandwidth of the ONVIF backchannel pipeline in @@ -305,7 +305,7 @@ gst_rtsp_onvif_media_set_backchannel_bandwidth (GstRTSPOnvifMedia * media, /** * gst_rtsp_onvif_media_get_backchannel_bandwidth: - * @factory: a #GstRTSPMedia + * @media: a #GstRTSPMedia * * Get the configured/supported bandwidth of the ONVIF backchannel pipeline in * bits per second. From f304096994c5ee728c9cb0c97817a07596ddcd6a Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Fri, 29 Jun 2018 15:20:57 -0700 Subject: [PATCH 1522/1776] media-factory: unref clock in finalize https://bugzilla.gnome.org/show_bug.cgi?id=796724 --- gst/rtsp-server/rtsp-media-factory.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index bbb6a91196..6df726fc90 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -277,6 +277,8 @@ gst_rtsp_media_factory_finalize (GObject * obj) GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj); GstRTSPMediaFactoryPrivate *priv = factory->priv; + if (priv->clock) + gst_object_unref (priv->clock); if (priv->permissions) gst_rtsp_permissions_unref (priv->permissions); g_hash_table_unref (priv->medias); From 7f7a210b84025dd01af4f0b1d0c4bfa9eb1c6603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 12 Jul 2018 19:01:54 +0100 Subject: [PATCH 1523/1776] media-factory: unref old clock when setting new clock https://bugzilla.gnome.org/show_bug.cgi?id=796724 --- gst/rtsp-server/rtsp-media-factory.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 6df726fc90..a4f10ddeaf 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -1380,13 +1380,14 @@ void gst_rtsp_media_factory_set_clock (GstRTSPMediaFactory * factory, GstClock * clock) { - GstRTSPMediaFactoryPrivate *priv; + GstClock **clock_p; + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); g_return_if_fail (GST_IS_CLOCK (clock) || clock == NULL); GST_RTSP_MEDIA_FACTORY_LOCK (factory); - priv = factory->priv; - priv->clock = clock ? gst_object_ref (clock) : NULL; + clock_p = &factory->priv->clock; + gst_object_replace ((GstObject **) clock_p, (GstObject *) clock); GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); } @@ -1407,6 +1408,8 @@ gst_rtsp_media_factory_get_clock (GstRTSPMediaFactory * factory) GstRTSPMediaFactoryPrivate *priv; GstClock *ret; + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + GST_RTSP_MEDIA_FACTORY_LOCK (factory); priv = factory->priv; ret = priv->clock ? gst_object_ref (priv->clock) : NULL; From e99471a56b7b122cba2ca54298c054c936500ad7 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Mon, 16 Jul 2018 21:56:44 +0200 Subject: [PATCH 1524/1776] rtsp-media: add gst_rtsp_media_*_set_clock to docs https://bugzilla.gnome.org/show_bug.cgi?id=796814 --- docs/libs/gst-rtsp-server-sections.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 969abf60a9..08472c8adc 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -226,6 +226,7 @@ gst_rtsp_media_set_pipeline_state gst_rtsp_media_get_clock +gst_rtsp_media_set_clock gst_rtsp_media_get_base_time gst_rtsp_media_use_time_provider gst_rtsp_media_is_time_provider @@ -260,6 +261,9 @@ gst_rtsp_media_factory_set_permissions gst_rtsp_media_factory_add_role gst_rtsp_media_factory_add_role_from_structure +gst_rtsp_media_factory_get_clock +gst_rtsp_media_factory_set_clock + gst_rtsp_media_factory_set_shared gst_rtsp_media_factory_is_shared From 12c2dd6e1c725b6072b8b9fc06ddda0e2057b4b5 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Mon, 16 Jul 2018 21:57:08 +0200 Subject: [PATCH 1525/1776] rtsp-media: unref clock (if set) when finalizing https://bugzilla.gnome.org/show_bug.cgi?id=796814 --- gst/rtsp-server/rtsp-media.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 74d52803be..f23b4c5d46 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -475,6 +475,8 @@ gst_rtsp_media_finalize (GObject * obj) g_object_unref (priv->pool); if (priv->payloads) g_list_free (priv->payloads); + if (priv->clock) + gst_object_unref (priv->clock); g_free (priv->multicast_iface); g_mutex_clear (&priv->lock); g_cond_clear (&priv->cond); From 287345f6ac3becdcc1dbd2397d4cbe323ddf1879 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Thu, 28 Jun 2018 11:22:13 +0200 Subject: [PATCH 1526/1776] rtsp-client: Use fixed backlog size Change to using a fixed backlog size WATCH_BACKLOG_SIZE. Preparation for the next commit, which changes to a different way of avoiding both deadlocks and unlimited memory usage with the watch backlog. --- gst/rtsp-server/rtsp-client.c | 45 ----------------------------------- 1 file changed, 45 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 11931d739a..a48e918080 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -3175,11 +3175,7 @@ client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session, GST_INFO ("client %p: session %p removed", client, session); g_mutex_lock (&priv->lock); - if (priv->watch != NULL) - gst_rtsp_watch_set_send_backlog (priv->watch, 0, 0); client_unwatch_session (client, session, NULL); - if (priv->watch != NULL) - gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); g_mutex_unlock (&priv->lock); } @@ -3369,37 +3365,6 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) if (!check_request_requirements (ctx, &unsupported_reqs)) goto unsupported_requirement; - /* the backlog must be unlimited while processing requests. - * the causes of this are two cases of deadlocks while streaming over TCP: - * - * 1. consider the scenario where the media pipeline's streaming thread - * is blocking in the appsink (taking the appsink's preroll lock) because - * the backlog is full. when a PAUSE request is received by the RTSP - * client thread then the the state of the session media ought to change - * to PAUSED. while most elements in the pipeline can change state this - * can never happen for the appsink since its preroll lock is taken by - * another thread. - * - * 2. consider the scenario where the media pipeline's streaming thread - * is blocking in the appsink new_sample callback (taking the send lock - * in RTSP client) because the backlog is full. when e.g. a GET request - * is received by the RTSP client thread then a response ought to be sent - * but this can never happen since it requires taking the send lock - * already taken by another thread. - * - * the reason that the backlog is never emptied is that the source used - * for dequeing messages from the backlog is never dispatched because it - * is attached to the same mainloop as the source receving RTSP requests and - * therefore run by the RTSP client thread which is alreayd blocking. - * - * without significant changes the easiest way to cope with this is to - * not block indefinitely when the backlog is full, but rather let the - * backlog grow in size. this in effect means that there can not be any - * upper boundary on its size. - */ - if (priv->watch != NULL) - gst_rtsp_watch_set_send_backlog (priv->watch, 0, 0); - /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: @@ -3438,19 +3403,12 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) handle_record_request (client, ctx); break; case GST_RTSP_REDIRECT: - if (priv->watch != NULL) - gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); goto not_implemented; case GST_RTSP_INVALID: default: - if (priv->watch != NULL) - gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); goto bad_request; } - if (priv->watch != NULL) - gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); - done: if (ctx == &sctx) gst_rtsp_context_pop_current (ctx); @@ -3470,9 +3428,6 @@ not_supported: } invalid_command_for_version: { - if (priv->watch != NULL) - gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); - GST_ERROR ("client %p: invalid command for version", client); send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); goto done; From 12169f1e845a45db41cc7d416ca0f101fa607176 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Thu, 28 Jun 2018 11:22:21 +0200 Subject: [PATCH 1527/1776] Limit queued TCP data messages to one per stream Before, the watch backlog size in GstRTSPClient was changed dynamically between unlimited and a fixed size, trying to avoid both unlimited memory usage and deadlocks while waiting for place in the queue. (Some of the deadlocks were described in a long comment in handle_request().) In the previous commit, we changed to a fixed backlog size of 100. This is possible, because we now handle RTP/RTCP data messages differently from RTSP request/response messages. The data messages are messages tunneled over TCP. We allow at most one queued data message per stream in GstRTSPClient at a time, and successfully sent data messages are acked by sending a "message-sent" callback from the GstStreamTransport. Until that ack comes, the GstRTSPStream does not call pull_sample() on its appsink, and therefore the streaming thread in the pipeline will not be blocked inside GstRTSPClient, waiting for a place in the queue. pull_sample() is called when we have both an ack and a "new-sample" signal from the appsink. Then, we know there is a buffer to write. RTSP request/response messages are not acked in the same way as data messages. The rest of the 100 places in the queue are used for them. If the queue becomes full of request/response messages, we return an error and close the connection to the client. Change-Id: I275310bc90a219ceb2473c098261acc78be84c97 --- gst/rtsp-server/rtsp-client.c | 192 ++++++++++++++++++++---- gst/rtsp-server/rtsp-stream-transport.c | 52 +++++++ gst/rtsp-server/rtsp-stream-transport.h | 18 +++ gst/rtsp-server/rtsp-stream.c | 152 +++++++++++++++++-- 4 files changed, 372 insertions(+), 42 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a48e918080..1b33f039e9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -70,13 +70,15 @@ struct _GstRTSPClientPrivate GstRTSPConnection *connection; GstRTSPWatch *watch; GMainContext *watch_context; - guint close_seq; gchar *server_ip; gboolean is_ipv6; - GstRTSPClientSendFunc send_func; /* protected by send_lock */ - gpointer send_data; /* protected by send_lock */ - GDestroyNotify send_notify; /* protected by send_lock */ + /* protected by send_lock */ + GstRTSPClientSendFunc send_func; + gpointer send_data; + GDestroyNotify send_notify; + guint close_seq; + GArray *data_seqs; GstRTSPSessionPool *session_pool; gulong session_removed_id; @@ -105,11 +107,15 @@ struct _GstRTSPClientPrivate GstRTSPTunnelState tstate; }; +typedef struct +{ + guint8 channel; + guint seq; +} DataSeq; + static GMutex tunnels_lock; static GHashTable *tunnels; /* protected by tunnels_lock */ -/* FIXME make this configurable. We don't want to do this yet because it will - * be superceeded by a cache object later */ #define WATCH_BACKLOG_SIZE 100 #define DEFAULT_SESSION_POOL NULL @@ -587,6 +593,7 @@ gst_rtsp_client_init (GstRTSPClient * client) g_mutex_init (&priv->send_lock); g_mutex_init (&priv->watch_lock); priv->close_seq = 0; + priv->data_seqs = g_array_new (FALSE, FALSE, sizeof (DataSeq)); priv->drop_backlog = DEFAULT_DROP_BACKLOG; priv->transports = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, @@ -754,6 +761,7 @@ gst_rtsp_client_finalize (GObject * obj) g_assert (priv->sessions == NULL); g_assert (priv->session_removed_id == 0); + g_array_unref (priv->data_seqs); g_hash_table_unref (priv->transports); g_hash_table_unref (priv->pipelined_requests); @@ -1055,6 +1063,82 @@ no_prepare: } } +static inline DataSeq * +get_data_seq_element (GstRTSPClient * client, guint8 channel) +{ + GstRTSPClientPrivate *priv = client->priv; + GArray *data_seqs = priv->data_seqs; + gint i = 0; + + while (i < data_seqs->len) { + DataSeq *data_seq = &g_array_index (data_seqs, DataSeq, i); + if (data_seq->channel == channel) + return data_seq; + i++; + } + + return NULL; +} + +static void +add_data_seq (GstRTSPClient * client, guint8 channel) +{ + GstRTSPClientPrivate *priv = client->priv; + DataSeq data_seq = {.channel = channel,.seq = 0 }; + + if (get_data_seq_element (client, channel) == NULL) + g_array_append_val (priv->data_seqs, data_seq); +} + +static void +set_data_seq (GstRTSPClient * client, guint8 channel, guint seq) +{ + DataSeq *data_seq; + + data_seq = get_data_seq_element (client, channel); + g_assert_nonnull (data_seq); + data_seq->seq = seq; +} + +static guint +get_data_seq (GstRTSPClient * client, guint8 channel) +{ + DataSeq *data_seq; + + data_seq = get_data_seq_element (client, channel); + g_assert_nonnull (data_seq); + return data_seq->seq; +} + +static gboolean +get_data_channel (GstRTSPClient * client, guint seq, guint8 * channel) +{ + GstRTSPClientPrivate *priv = client->priv; + GArray *data_seqs = priv->data_seqs; + gint i = 0; + + while (i < data_seqs->len) { + DataSeq *data_seq = &g_array_index (data_seqs, DataSeq, i); + if (data_seq->seq == seq) { + *channel = data_seq->channel; + return TRUE; + } + i++; + } + + return FALSE; +} + +static gboolean +do_close (gpointer user_data) +{ + GstRTSPClient *client = user_data; + + gst_rtsp_client_close (client); + + return G_SOURCE_REMOVE; +} + static gboolean do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) { @@ -1074,6 +1158,11 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) gst_rtsp_message_take_body (&message, map_info.data, map_info.size); g_mutex_lock (&priv->send_lock); + if (get_data_seq (client, channel) != 0) { + GST_WARNING ("already a queued data message for channel %d", channel); + g_mutex_unlock (&priv->send_lock); + return FALSE; + } if (priv->send_func) ret = priv->send_func (client, &message, FALSE, priv->send_data); g_mutex_unlock (&priv->send_lock); @@ -1083,6 +1172,16 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) gst_rtsp_message_unset (&message); + if (!ret) { + GSource *idle_src; + + /* close in watch context */ + idle_src = g_idle_source_new (); + g_source_set_callback (idle_src, do_close, client, NULL); + g_source_attach (idle_src, priv->watch_context); + g_source_unref (idle_src); + } + return ret; } @@ -2355,6 +2454,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) g_hash_table_insert (priv->transports, GINT_TO_POINTER (ct->interleaved.max), trans); g_object_ref (trans); + add_data_seq (client, ct->interleaved.min); + add_data_seq (client, ct->interleaved.max); } /* create and serialize the server transport */ @@ -4058,33 +4159,48 @@ do_send_message (GstRTSPClient * client, GstRTSPMessage * message, gboolean close, gpointer user_data) { GstRTSPClientPrivate *priv = client->priv; + guint id = 0; GstRTSPResult ret; - GTimeVal time; - time.tv_sec = 1; - time.tv_usec = 0; + /* send the message */ + ret = gst_rtsp_watch_send_message (priv->watch, message, &id); + if (ret != GST_RTSP_OK) + goto error; - do { - /* send the response and store the seq number so we can wait until it's - * written to the client to close the connection */ - ret = - gst_rtsp_watch_send_message (priv->watch, message, - close ? &priv->close_seq : NULL); - if (ret == GST_RTSP_OK) - break; + /* if close flag is set, store the seq number so we can wait until it's + * written to the client to close the connection */ + if (close) + priv->close_seq = id; - if (ret != GST_RTSP_ENOMEM) + if (gst_rtsp_message_get_type (message) == GST_RTSP_MESSAGE_DATA) { + guint8 channel = 0; + GstRTSPResult r; + + r = gst_rtsp_message_parse_data (message, &channel); + if (r != GST_RTSP_OK) { + ret = r; goto error; + } - /* drop backlog */ - if (priv->drop_backlog) - break; + /* check if the message has been queued for transmission in watch */ + if (id) { + /* store the seq number so we can wait until it has been sent */ + GST_DEBUG_OBJECT (client, "wait for message %d, channel %d", id, channel); + set_data_seq (client, channel, id); + } else { + GstRTSPStreamTransport *trans; - /* queue was full, wait for more space */ - GST_DEBUG_OBJECT (client, "waiting for backlog"); - ret = gst_rtsp_watch_wait_backlog (priv->watch, &time); - GST_DEBUG_OBJECT (client, "Resend due to backlog full"); - } while (ret != GST_RTSP_EINTR); + trans = + g_hash_table_lookup (priv->transports, + GINT_TO_POINTER ((gint) channel)); + if (trans) { + GST_DEBUG_OBJECT (client, "emit 'message-sent' signal"); + g_mutex_unlock (&priv->send_lock); + gst_rtsp_stream_transport_message_sent (trans); + g_mutex_lock (&priv->send_lock); + } + } + } return ret == GST_RTSP_OK; @@ -4092,7 +4208,7 @@ do_send_message (GstRTSPClient * client, GstRTSPMessage * message, error: { GST_DEBUG_OBJECT (client, "got error %d", ret); - return ret == GST_RTSP_OK; + return FALSE; } } @@ -4108,13 +4224,33 @@ message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); GstRTSPClientPrivate *priv = client->priv; + GstRTSPStreamTransport *trans = NULL; + guint8 channel = 0; + gboolean close = FALSE; + + g_mutex_lock (&priv->send_lock); + + if (get_data_channel (client, cseq, &channel)) { + trans = g_hash_table_lookup (priv->transports, GINT_TO_POINTER (channel)); + set_data_seq (client, channel, 0); + } if (priv->close_seq && priv->close_seq == cseq) { GST_INFO ("client %p: send close message", client); + close = TRUE; priv->close_seq = 0; - gst_rtsp_client_close (client); } + g_mutex_unlock (&priv->send_lock); + + if (trans) { + GST_DEBUG_OBJECT (client, "emit 'message-sent' signal"); + gst_rtsp_stream_transport_message_sent (trans); + } + + if (close) + gst_rtsp_client_close (client); + return GST_RTSP_OK; } diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 7a6ba12c3c..99af1ae15a 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -35,6 +35,9 @@ * is received from the client. It will also call * gst_rtsp_stream_transport_set_timed_out() when a receiver has timed out. * + * A #GstRTSPClient will call gst_rtsp_stream_transport_message_sent() when it + * has sent a data message for the transport. + * * Last reviewed on 2013-07-16 (1.0.0) */ @@ -58,6 +61,10 @@ struct _GstRTSPStreamTransportPrivate gboolean active; gboolean timed_out; + GstRTSPMessageSentFunc message_sent; + gpointer ms_user_data; + GDestroyNotify ms_notify; + GstRTSPTransport *transport; GstRTSPUrl *url; @@ -109,6 +116,7 @@ gst_rtsp_stream_transport_finalize (GObject * obj) /* remove callbacks now */ gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL); gst_rtsp_stream_transport_set_keepalive (trans, NULL, NULL, NULL); + gst_rtsp_stream_transport_set_message_sent (trans, NULL, NULL, NULL); if (priv->stream) g_object_unref (priv->stream); @@ -223,6 +231,33 @@ gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans, priv->ka_notify = notify; } +/** + * gst_rtsp_stream_transport_set_message_sent: + * @trans: a #GstRTSPStreamTransport + * @message_sent: (scope notified): a callback called when a message has been sent + * @user_data: (closure): user data passed to callback + * @notify: (allow-none): called with the user_data when no longer needed + * + * Install a callback that will be called when a message has been sent on @trans. + */ +void +gst_rtsp_stream_transport_set_message_sent (GstRTSPStreamTransport * trans, + GstRTSPMessageSentFunc message_sent, gpointer user_data, + GDestroyNotify notify) +{ + GstRTSPStreamTransportPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); + + priv = trans->priv; + + priv->message_sent = message_sent; + if (priv->ms_notify) + priv->ms_notify (priv->ms_user_data); + priv->ms_user_data = user_data; + priv->ms_notify = notify; +} + /** * gst_rtsp_stream_transport_set_transport: @@ -510,6 +545,23 @@ gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport * trans) priv->keep_alive (priv->ka_user_data); } +/** + * gst_rtsp_stream_transport_message_sent: + * @trans: a #GstRTSPStreamTransport + * + * Signal the installed message_sent callback for @trans. + */ +void +gst_rtsp_stream_transport_message_sent (GstRTSPStreamTransport * trans) +{ + GstRTSPStreamTransportPrivate *priv; + + priv = trans->priv; + + if (priv->message_sent) + priv->message_sent (priv->ms_user_data); +} + /** * gst_rtsp_stream_transport_recv_data: * @trans: a #GstRTSPStreamTransport diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index f608b8ae42..48c565a71c 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -65,6 +65,15 @@ typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpo */ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); +/** + * GstRTSPMessageSentFunc: + * @user_data: user data + * + * Function registered with gst_rtsp_stream_transport_set_message_sent() + * and called when a message has been sent on the transport. + */ +typedef void (*GstRTSPMessageSentFunc) (gpointer user_data); + /** * GstRTSPStreamTransport: * @parent: parent instance @@ -128,9 +137,18 @@ void gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamT gpointer user_data, GDestroyNotify notify); +GST_RTSP_SERVER_API +void gst_rtsp_stream_transport_set_message_sent (GstRTSPStreamTransport *trans, + GstRTSPMessageSentFunc message_sent, + gpointer user_data, + GDestroyNotify notify); + GST_RTSP_SERVER_API void gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport *trans); +GST_RTSP_SERVER_API +void gst_rtsp_stream_transport_message_sent (GstRTSPStreamTransport *trans); + GST_RTSP_SERVER_API gboolean gst_rtsp_stream_transport_set_active (GstRTSPStreamTransport *trans, gboolean active); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 953735771d..bc6917dcbc 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -158,6 +158,9 @@ struct _GstRTSPStreamPrivate GList *tr_cache_rtcp; guint tr_cache_cookie_rtp; guint tr_cache_cookie_rtcp; + guint n_tcp_transports; + gboolean have_buffer[2]; + guint n_outstanding; gint dscp_qos; @@ -208,6 +211,10 @@ static void gst_rtsp_stream_set_property (GObject * object, guint propid, static void gst_rtsp_stream_finalize (GObject * obj); +static gboolean +update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, + gboolean add); + static guint gst_rtsp_stream_signals[SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPStream, gst_rtsp_stream, G_TYPE_OBJECT); @@ -2115,32 +2122,52 @@ clear_tr_cache (GstRTSPStreamPrivate * priv, gboolean is_rtp) } } -static GstFlowReturn -handle_new_sample (GstAppSink * sink, gpointer user_data) +static void +send_tcp_message (GstRTSPStream * stream, gint idx) { - GstRTSPStreamPrivate *priv; + GstRTSPStreamPrivate *priv = stream->priv; + GstAppSink *sink; GList *walk; GstSample *sample; GstBuffer *buffer; - GstRTSPStream *stream; gboolean is_rtp; - sample = gst_app_sink_pull_sample (sink); - if (!sample) - return GST_FLOW_OK; + g_mutex_lock (&priv->lock); + + if (priv->n_outstanding > 0 || !priv->have_buffer[idx]) { + g_mutex_unlock (&priv->lock); + return; + } + + priv->have_buffer[idx] = FALSE; + + if (priv->appsink[idx] == NULL) { + /* session expired */ + g_mutex_unlock (&priv->lock); + return; + } + + sink = GST_APP_SINK (priv->appsink[idx]); + sample = gst_app_sink_pull_sample (sink); + if (!sample) { + g_mutex_unlock (&priv->lock); + return; + } - stream = (GstRTSPStream *) user_data; - priv = stream->priv; buffer = gst_sample_get_buffer (sample); - is_rtp = GST_ELEMENT_CAST (sink) == priv->appsink[0]; + is_rtp = (idx == 0); - g_mutex_lock (&priv->lock); if (is_rtp) { if (priv->tr_cache_cookie_rtp != priv->transports_cookie) { clear_tr_cache (priv, is_rtp); for (walk = priv->transports; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; + const GstRTSPTransport *t = gst_rtsp_stream_transport_get_transport (tr); + + if (t->lower_transport != GST_RTSP_LOWER_TRANS_TCP) + continue; + priv->tr_cache_rtp = g_list_prepend (priv->tr_cache_rtp, g_object_ref (tr)); } @@ -2151,26 +2178,72 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) clear_tr_cache (priv, is_rtp); for (walk = priv->transports; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; + const GstRTSPTransport *t = gst_rtsp_stream_transport_get_transport (tr); + + if (t->lower_transport != GST_RTSP_LOWER_TRANS_TCP) + continue; + priv->tr_cache_rtcp = g_list_prepend (priv->tr_cache_rtcp, g_object_ref (tr)); } priv->tr_cache_cookie_rtcp = priv->transports_cookie; } } + + priv->n_outstanding += priv->n_tcp_transports; + g_mutex_unlock (&priv->lock); if (is_rtp) { for (walk = priv->tr_cache_rtp; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - gst_rtsp_stream_transport_send_rtp (tr, buffer); + if (!gst_rtsp_stream_transport_send_rtp (tr, buffer)) { + /* remove transport on send error */ + g_mutex_lock (&priv->lock); + priv->n_outstanding--; + update_transport (stream, tr, FALSE); + g_mutex_unlock (&priv->lock); + } } } else { for (walk = priv->tr_cache_rtcp; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - gst_rtsp_stream_transport_send_rtcp (tr, buffer); + if (!gst_rtsp_stream_transport_send_rtcp (tr, buffer)) { + /* remove transport on send error */ + g_mutex_lock (&priv->lock); + priv->n_outstanding--; + update_transport (stream, tr, FALSE); + g_mutex_unlock (&priv->lock); + } } } gst_sample_unref (sample); +} + +static GstFlowReturn +handle_new_sample (GstAppSink * sink, gpointer user_data) +{ + GstRTSPStream *stream = user_data; + GstRTSPStreamPrivate *priv = stream->priv; + int i; + int idx = -1; + + g_mutex_lock (&priv->lock); + + for (i = 0; i < 2; i++) + if (GST_ELEMENT_CAST (sink) == priv->appsink[i]) { + priv->have_buffer[i] = TRUE; + if (priv->n_outstanding == 0) { + /* send message */ + idx = i; + } + break; + } + + g_mutex_unlock (&priv->lock); + + if (idx != -1) + send_tcp_message (stream, idx); return GST_FLOW_OK; } @@ -2971,7 +3044,8 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport) } else if (is_tcp && !priv->appsink[i]) { /* make appsink */ priv->appsink[i] = gst_element_factory_make ("appsink", NULL); - g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL); + g_object_set (priv->appsink[i], "emit-signals", FALSE, "max-buffers", 1, + NULL); /* we need to set sync and preroll to FALSE for the sink to avoid * deadlock. This is only needed for sink sending RTCP data. */ @@ -3913,9 +3987,11 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, if (add) { GST_INFO ("adding TCP %s", tr->destination); priv->transports = g_list_prepend (priv->transports, trans); + priv->n_tcp_transports++; } else { GST_INFO ("removing TCP %s", tr->destination); priv->transports = g_list_remove (priv->transports, trans); + priv->n_tcp_transports--; } priv->transports_cookie++; break; @@ -3936,6 +4012,51 @@ mcast_error: } } +static void +on_message_sent (gpointer user_data) +{ + GstRTSPStream *stream = user_data; + GstRTSPStreamPrivate *priv = stream->priv; + gint idx = -1; + + GST_DEBUG_OBJECT (stream, "message send complete"); + + g_mutex_lock (&priv->lock); + + g_assert (priv->n_outstanding >= 0); + + if (priv->n_outstanding == 0) + goto no_outstanding; + + priv->n_outstanding--; + if (priv->n_outstanding == 0) { + gint i; + + /* iterate from 1 and down, so we prioritize RTCP over RTP */ + for (i = 1; i >= 0; i--) { + if (priv->have_buffer[i]) { + /* send message */ + idx = i; + break; + } + } + } + + g_mutex_unlock (&priv->lock); + + if (idx != -1) + send_tcp_message (stream, idx); + + return; + + /* ERRORS */ +no_outstanding: + { + GST_INFO ("no outstanding messages"); + g_mutex_unlock (&priv->lock); + return; + } +} /** * gst_rtsp_stream_add_transport: @@ -3965,6 +4086,9 @@ gst_rtsp_stream_add_transport (GstRTSPStream * stream, g_mutex_lock (&priv->lock); res = update_transport (stream, trans, TRUE); + if (res) + gst_rtsp_stream_transport_set_message_sent (trans, on_message_sent, stream, + NULL); g_mutex_unlock (&priv->lock); return res; From 37e75cb8ea2b04fd375fcb35de02b2bc4776a4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 23 Jul 2018 18:03:51 +0300 Subject: [PATCH 1528/1776] rtsp-stream: Slightly simplify locking --- gst/rtsp-server/rtsp-stream.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index bc6917dcbc..4aa06dde33 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2122,6 +2122,7 @@ clear_tr_cache (GstRTSPStreamPrivate * priv, gboolean is_rtp) } } +/* Must be called with priv->lock */ static void send_tcp_message (GstRTSPStream * stream, gint idx) { @@ -2132,10 +2133,7 @@ send_tcp_message (GstRTSPStream * stream, gint idx) GstBuffer *buffer; gboolean is_rtp; - g_mutex_lock (&priv->lock); - if (priv->n_outstanding > 0 || !priv->have_buffer[idx]) { - g_mutex_unlock (&priv->lock); return; } @@ -2143,14 +2141,12 @@ send_tcp_message (GstRTSPStream * stream, gint idx) if (priv->appsink[idx] == NULL) { /* session expired */ - g_mutex_unlock (&priv->lock); return; } sink = GST_APP_SINK (priv->appsink[idx]); sample = gst_app_sink_pull_sample (sink); if (!sample) { - g_mutex_unlock (&priv->lock); return; } @@ -2163,7 +2159,8 @@ send_tcp_message (GstRTSPStream * stream, gint idx) clear_tr_cache (priv, is_rtp); for (walk = priv->transports; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - const GstRTSPTransport *t = gst_rtsp_stream_transport_get_transport (tr); + const GstRTSPTransport *t = + gst_rtsp_stream_transport_get_transport (tr); if (t->lower_transport != GST_RTSP_LOWER_TRANS_TCP) continue; @@ -2178,7 +2175,8 @@ send_tcp_message (GstRTSPStream * stream, gint idx) clear_tr_cache (priv, is_rtp); for (walk = priv->transports; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - const GstRTSPTransport *t = gst_rtsp_stream_transport_get_transport (tr); + const GstRTSPTransport *t = + gst_rtsp_stream_transport_get_transport (tr); if (t->lower_transport != GST_RTSP_LOWER_TRANS_TCP) continue; @@ -2218,6 +2216,8 @@ send_tcp_message (GstRTSPStream * stream, gint idx) } } gst_sample_unref (sample); + + g_mutex_lock (&priv->lock); } static GstFlowReturn @@ -2240,11 +2240,11 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) break; } - g_mutex_unlock (&priv->lock); - if (idx != -1) send_tcp_message (stream, idx); + g_mutex_unlock (&priv->lock); + return GST_FLOW_OK; } @@ -4042,11 +4042,11 @@ on_message_sent (gpointer user_data) } } - g_mutex_unlock (&priv->lock); - if (idx != -1) send_tcp_message (stream, idx); + g_mutex_unlock (&priv->lock); + return; /* ERRORS */ From 3baf94ed55d3c58edf292d843a817fa6af3ca084 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Wed, 25 Jul 2018 17:22:20 +0530 Subject: [PATCH 1529/1776] meson: Convert common options to feature options These are necessary for gst-build to set options correctly. The remaining automagic option is cgroup support in examples. https://bugzilla.gnome.org/show_bug.cgi?id=795107 --- meson.build | 8 ++++---- meson_options.txt | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index 228b256593..91551c8a97 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('gst-rtsp-server', 'c', version : '1.15.0.1', - meson_version : '>= 0.46.0', + meson_version : '>= 0.47', default_options : ['warning_level=1', 'buildtype=debugoptimized']) gst_version = meson.project_version() @@ -115,9 +115,9 @@ gstapp_dep = dependency('gstreamer-app-1.0', version : gst_req, gstnet_dep = dependency('gstreamer-net-1.0', version : gst_req, fallback : ['gstreamer', 'gst_net_dep']) -gir = find_program('g-ir-scanner', required : false) +gir = find_program('g-ir-scanner', required : get_option('introspection')) gnome = import('gnome') -build_gir = gir.found() and not meson.is_cross_build() and get_option('introspection') +build_gir = gir.found() and not meson.is_cross_build() gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**);' + \ 'g_setenv("GST_REGISTRY_1.0", "@0@", TRUE);'.format(meson.current_build_dir() + '/gir_empty_registry.reg') + \ 'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \ @@ -128,7 +128,7 @@ subdir('gst') if get_option('tests') subdir('tests') endif -if get_option('examples') +if not get_option('examples').disabled() subdir('examples') endif subdir('pkgconfig') diff --git a/meson_options.txt b/meson_options.txt index c8c5282115..eb6f20f24f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,5 +1,5 @@ -option('introspection', type : 'boolean', value : true, yield : true, - description : 'Generate gobject-introspection bindings') +option('introspection', type : 'feature', value : 'auto', yield : true, + description : 'Generate gobject-introspection bindings') option('package-name', type : 'string', yield : true, description : 'package name to use in plugins') option('package-origin', type : 'string', @@ -7,5 +7,5 @@ option('package-origin', type : 'string', description : 'package origin URL to use in plugins') option('tests', type : 'boolean', value : true, description : 'Build and enable unit tests') -option('examples', type : 'boolean', value : true, yield : true, +option('examples', type : 'feature', value : 'auto', yield : true, description : 'Build the examples') From 12f8abb549e71053a49eb3c4a7bfd6d1d3e5318e Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 25 Jul 2018 19:54:55 +0200 Subject: [PATCH 1530/1776] rtsp-client: always allocate both IPV4 and IPV6 sockets multiudpsink does not support setting the socket* properties after it has started, which meant that rtsp-server could no longer serve on both IPV4 and IPV6 sockets since the patches from https://bugzilla.gnome.org/show_bug.cgi?id=757488 were merged. When first connecting an IPV6 client then an IPV4 client, multiudpsink fell back to using the IPV6 socket. When first connecting an IPV4 client, then an IPV6 client, multiudpsink errored out, released the IPV4 socket, then crashed when trying to send a message on NULL nevertheless, that is however a separate issue. This could probably be fixed by handling the setting of sockets in multiudpsink after it has started, that will however be a much more significant effort. For now, this commit simply partially reverts the behaviour of rtsp-stream: it will continue to only create the udpsinks when needed, as was the case since the patches were merged, it will however when creating them, always allocate both sockets and set them on the sink before it starts, as was the case prior to the patches. Transport configuration will only error out if the allocation of UDP sockets fails for the actual client's family, this also downgrades the GST_ERRORs in alloc_ports_one_family to GST_WARNINGs, as failing to allocate is no longer necessarily fatal. https://bugzilla.gnome.org/show_bug.cgi?id=796875 --- gst/rtsp-server/rtsp-client.c | 16 +++++++++++++--- gst/rtsp-server/rtsp-stream.c | 10 +++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1b33f039e9..92135f24e2 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1964,19 +1964,29 @@ default_configure_client_transport (GstRTSPClient * client, /* we have a valid transport now, set the destination of the client. */ if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST || ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP) { - /* allocate UDP ports */ GSocketFamily family; gboolean use_client_settings = FALSE; family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4; + if ((ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) && gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS) && (ct->destination != NULL)) use_client_settings = TRUE; - if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct, - use_client_settings)) + /* We need to allocate the sockets for both families before starting + * multiudpsink, otherwise multiudpsink won't accept new clients with + * a different family. + */ + /* FIXME: could be more adequately solved by making it possible + * to set a socket on multiudpsink after it has already been started */ + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, G_SOCKET_FAMILY_IPV4, ct, + use_client_settings) && family == G_SOCKET_FAMILY_IPV4) + goto error_allocating_ports; + + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, G_SOCKET_FAMILY_IPV6, ct, + use_client_settings) && family == G_SOCKET_FAMILY_IPV6) goto error_allocating_ports; if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4aa06dde33..3439ea3a0e 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1469,28 +1469,28 @@ again: /* ERRORS */ no_udp_protocol: { - GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: protocol error"); + GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: protocol error"); goto cleanup; } no_pool: { - GST_ERROR_OBJECT (stream, + GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: no address pool specified"); goto cleanup; } no_address: { - GST_ERROR_OBJECT (stream, "failed to acquire address from pool"); + GST_WARNING_OBJECT (stream, "failed to acquire address from pool"); goto cleanup; } no_ports: { - GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: no ports"); + GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: no ports"); goto cleanup; } socket_error: { - GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: socket error"); + GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: socket error"); goto cleanup; } cleanup: From 20dc49749c7ef37b23eec27aca41a355179b5919 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 6 Aug 2018 15:33:04 -0400 Subject: [PATCH 1531/1776] rtsp-server: Add gstreamer-base gir dir in autotools --- gst/rtsp-server/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 9bc1169a85..e2fff13d45 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -91,6 +91,7 @@ GstRtspServer-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@ -DIN_GOBJECT_INTROSPECTION=1 \ --c-include='gst/rtsp-server/rtsp-server.h' \ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ + --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_API_VERSION@` \ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_API_VERSION@` \ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-net-@GST_API_VERSION@` \ @@ -122,6 +123,7 @@ typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) --includedir=$(srcdir) \ --includedir=$(builddir) \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-net-@GST_API_VERSION@` \ From 33570944401747f44d8ebfec535350651413fb92 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 31 Jul 2018 21:17:41 +0200 Subject: [PATCH 1532/1776] rtsp-stream: avoid duplicating the first multicast client In dcb4533fedae3ac62bc25a916eb95927b7d69aec , we made it so clients were dynamically added and removed to the multicast udp sinks, as such we should no longer add a first client in set_multicast_socket_for_udpsink https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-stream.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 3439ea3a0e..b95ead95a1 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1157,8 +1157,6 @@ set_multicast_socket_for_udpsink (GstElement * udpsink, GSocket * socket, GST_INFO ("setting ttl-mc %d", mcast_ttl); g_object_set (G_OBJECT (udpsink), "ttl-mc", mcast_ttl, NULL); } - - g_signal_emit_by_name (udpsink, "add", addr_str, port, NULL); } From 7f0ae77e400fb8a0462a76a5dd2e63e12c4a2e52 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Tue, 24 Jul 2018 09:35:46 +0200 Subject: [PATCH 1533/1776] Add new API for setting/getting maximum multicast ttl value https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-client.c | 30 +-- gst/rtsp-server/rtsp-media-factory.c | 75 ++++++++ gst/rtsp-server/rtsp-media-factory.h | 7 + gst/rtsp-server/rtsp-media.c | 81 ++++++++ gst/rtsp-server/rtsp-media.h | 6 + gst/rtsp-server/rtsp-stream.c | 51 +++++ gst/rtsp-server/rtsp-stream.h | 6 + tests/check/gst/client.c | 267 +++++++++++++++------------ tests/check/gst/mediafactory.c | 58 ++++++ 9 files changed, 452 insertions(+), 129 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 92135f24e2..8f39ccd6fb 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1981,26 +1981,27 @@ default_configure_client_transport (GstRTSPClient * client, */ /* FIXME: could be more adequately solved by making it possible * to set a socket on multiudpsink after it has already been started */ - if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, G_SOCKET_FAMILY_IPV4, ct, - use_client_settings) && family == G_SOCKET_FAMILY_IPV4) + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, + G_SOCKET_FAMILY_IPV4, ct, use_client_settings) + && family == G_SOCKET_FAMILY_IPV4) goto error_allocating_ports; - if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, G_SOCKET_FAMILY_IPV6, ct, - use_client_settings) && family == G_SOCKET_FAMILY_IPV6) + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, + G_SOCKET_FAMILY_IPV6, ct, use_client_settings) + && family == G_SOCKET_FAMILY_IPV6) goto error_allocating_ports; if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - GstRTSPAddress *addr = NULL; + /* FIXME: the address has been successfully allocated, however, in + * the use_client_settings case we need to verify that the allocated + * address is the one requested by the client and if this address is + * an allowed destination. Verifying this via the address pool in not + * the proper way as the address pool should only be used for choosing + * the server-selected address/port pairs. */ - if (use_client_settings) { - /* the address has been successfully allocated, let's check if it's - * the one requested by the client */ - addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination, - ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl); + if (!use_client_settings) { + GstRTSPAddress *addr = NULL; - if (addr == NULL) - goto no_address; - } else { g_free (ct->destination); addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family); if (addr == NULL) @@ -2009,9 +2010,8 @@ default_configure_client_transport (GstRTSPClient * client, ct->port.min = addr->port; ct->port.max = addr->port + addr->n_ports - 1; ct->ttl = addr->ttl; + gst_rtsp_address_free (addr); } - - gst_rtsp_address_free (addr); } else { GstRTSPUrl *url; diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index a4f10ddeaf..53bce3ea1e 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -59,6 +59,7 @@ struct _GstRTSPMediaFactoryPrivate GstRTSPTransportMode transport_mode; gboolean stop_on_disconnect; gchar *multicast_iface; + guint max_mcast_ttl; GstClockTime rtx_time; guint latency; @@ -83,6 +84,7 @@ struct _GstRTSPMediaFactoryPrivate GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_LATENCY 200 +#define DEFAULT_MAX_MCAST_TTL 255 #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE #define DEFAULT_DO_RETRANSMISSION FALSE @@ -101,6 +103,7 @@ enum PROP_TRANSPORT_MODE, PROP_STOP_ON_DISCONNECT, PROP_CLOCK, + PROP_MAX_MCAST_TTL, PROP_LAST }; @@ -222,6 +225,12 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "medias of this factory", GST_TYPE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MAX_MCAST_TTL, + g_param_spec_uint ("max-mcast-ttl", "Maximum multicast ttl", + "The maximum time-to-live value of outgoing multicast packets", 1, + 255, DEFAULT_MAX_MCAST_TTL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, @@ -263,6 +272,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; + priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; g_mutex_init (&priv->lock); g_mutex_init (&priv->medias_lock); @@ -337,6 +347,9 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, case PROP_CLOCK: g_value_take_object (value, gst_rtsp_media_factory_get_clock (factory)); break; + case PROP_MAX_MCAST_TTL: + g_value_set_uint (value, + gst_rtsp_media_factory_get_max_mcast_ttl (factory)); default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -387,6 +400,9 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, case PROP_CLOCK: gst_rtsp_media_factory_set_clock (factory, g_value_get_object (value)); break; + case PROP_MAX_MCAST_TTL: + gst_rtsp_media_factory_set_max_mcast_ttl (factory, + g_value_get_uint (value)); default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1463,6 +1479,62 @@ gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory) return ret; } +/** + * gst_rtsp_media_factory_set_max_mcast_ttl: + * @factory: a #GstRTSPMedia + * @ttl: the new multicast ttl value + * + * Set the maximum time-to-live value of outgoing multicast packets. + * + * Returns: %TRUE if the requested ttl has been set successfully. + */ +gboolean +gst_rtsp_media_factory_set_max_mcast_ttl (GstRTSPMediaFactory * factory, + guint ttl) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + if (ttl == 0 || ttl > DEFAULT_MAX_MCAST_TTL) { + GST_WARNING_OBJECT (factory, "The requested mcast TTL value is not valid."); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + return FALSE; + } + priv->max_mcast_ttl = ttl; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return TRUE; +} + +/** + * gst_rtsp_media_factory_get_max_mcast_ttl: + * @factory: a #GstRTSPMedia + * + * Get the the maximum time-to-live value of outgoing multicast packets. + * + * Returns: the maximum time-to-live value of outgoing multicast packets. + */ +guint +gst_rtsp_media_factory_get_max_mcast_ttl (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + guint result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + result = priv->max_mcast_ttl; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} + static gchar * default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { @@ -1613,6 +1685,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstClock *clock; gchar *multicast_iface; GstRTSPPublishClockMode publish_clock_mode; + guint ttl; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -1628,6 +1701,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) stop_on_disconnect = priv->stop_on_disconnect; clock = priv->clock ? gst_object_ref (priv->clock) : NULL; publish_clock_mode = priv->publish_clock_mode; + ttl = priv->max_mcast_ttl; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_suspend_mode (media, suspend_mode); @@ -1642,6 +1716,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_transport_mode (media, transport_mode); gst_rtsp_media_set_stop_on_disconnect (media, stop_on_disconnect); gst_rtsp_media_set_publish_clock_mode (media, publish_clock_mode); + gst_rtsp_media_set_max_mcast_ttl (media, ttl); if (clock) { gst_rtsp_media_set_clock (media, clock); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 7fb7fccde8..46d7d5515e 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -239,6 +239,13 @@ void gst_rtsp_media_factory_set_publish_clock_mode (GstRTSPMe GST_RTSP_SERVER_API GstRTSPPublishClockMode gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory); +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_factory_set_max_mcast_ttl (GstRTSPMediaFactory * factory, + guint ttl); + +GST_RTSP_SERVER_API +guint gst_rtsp_media_factory_get_max_mcast_ttl (GstRTSPMediaFactory * factory); + /* creating the media from the factory and a url */ GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index f23b4c5d46..1073b89bce 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -98,6 +98,7 @@ struct _GstRTSPMediaPrivate guint buffer_size; GstRTSPAddressPool *pool; gchar *multicast_iface; + guint max_mcast_ttl; gboolean blocked; GstRTSPTransportMode transport_mode; gboolean stop_on_disconnect; @@ -158,6 +159,7 @@ struct _GstRTSPMediaPrivate #define DEFAULT_LATENCY 200 #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE +#define DEFAULT_MAX_MCAST_TTL 255 #define DEFAULT_DO_RETRANSMISSION FALSE @@ -180,6 +182,7 @@ enum PROP_TRANSPORT_MODE, PROP_STOP_ON_DISCONNECT, PROP_CLOCK, + PROP_MAX_MCAST_TTL, PROP_LAST }; @@ -375,6 +378,12 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "Clock to be used by the media pipeline", GST_TYPE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MAX_MCAST_TTL, + g_param_spec_uint ("max-mcast-ttl", "Maximum multicast ttl", + "The maximum time-to-live value of outgoing multicast packets", 1, + 255, DEFAULT_MAX_MCAST_TTL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, @@ -445,6 +454,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; + priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; } static void @@ -531,6 +541,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_CLOCK: g_value_take_object (value, gst_rtsp_media_get_clock (media)); break; + case PROP_MAX_MCAST_TTL: + g_value_set_uint (value, gst_rtsp_media_get_max_mcast_ttl (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -584,6 +597,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_CLOCK: gst_rtsp_media_set_clock (media, g_value_get_object (value)); break; + case PROP_MAX_MCAST_TTL: + gst_rtsp_media_set_max_mcast_ttl (media, g_value_get_uint (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1823,6 +1839,70 @@ gst_rtsp_media_get_multicast_iface (GstRTSPMedia * media) return result; } +/** + * gst_rtsp_media_set_max_mcast_ttl: + * @media: a #GstRTSPMedia + * @ttl: the new multicast ttl value + * + * Set the maximum time-to-live value of outgoing multicast packets. + * + * Returns: %TRUE if the requested ttl has been set successfully. + */ +gboolean +gst_rtsp_media_set_max_mcast_ttl (GstRTSPMedia * media, guint ttl) +{ + GstRTSPMediaPrivate *priv; + guint i; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + GST_LOG_OBJECT (media, "set max mcast ttl %u", ttl); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + + if (ttl == 0 || ttl > DEFAULT_MAX_MCAST_TTL) { + GST_WARNING_OBJECT (media, "The reqested mcast TTL value is not valid."); + g_mutex_unlock (&priv->lock); + return FALSE; + } + priv->max_mcast_ttl = ttl; + + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + gst_rtsp_stream_set_max_mcast_ttl (stream, ttl); + } + g_mutex_unlock (&priv->lock); + + return TRUE; +} + +/** + * gst_rtsp_media_get_max_mcast_ttl: + * @media: a #GstRTSPMedia + * + * Get the the maximum time-to-live value of outgoing multicast packets. + * + * Returns: the maximum time-to-live value of outgoing multicast packets. + */ +guint +gst_rtsp_media_get_max_mcast_ttl (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + guint res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->max_mcast_ttl; + g_mutex_unlock (&priv->lock); + + return res; +} + static GList * _find_payload_types (GstRTSPMedia * media) { @@ -2140,6 +2220,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, if (priv->pool) gst_rtsp_stream_set_address_pool (stream, priv->pool); gst_rtsp_stream_set_multicast_iface (stream, priv->multicast_iface); + gst_rtsp_stream_set_max_mcast_ttl (stream, priv->max_mcast_ttl); gst_rtsp_stream_set_profiles (stream, priv->profiles); gst_rtsp_stream_set_protocols (stream, priv->protocols); gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 84dfb14591..92b3866a94 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -314,6 +314,12 @@ void gst_rtsp_media_set_publish_clock_mode (GstRTSPMedia * me GST_RTSP_SERVER_API GstRTSPPublishClockMode gst_rtsp_media_get_publish_clock_mode (GstRTSPMedia * media); +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_set_max_mcast_ttl (GstRTSPMedia *media, guint ttl); + +GST_RTSP_SERVER_API +guint gst_rtsp_media_get_max_mcast_ttl (GstRTSPMedia *media); + /* prepare the media for playback */ GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index b95ead95a1..1a68fd5b13 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -145,6 +145,7 @@ struct _GstRTSPStreamPrivate GstRTSPAddress *mcast_addr_v6; gchar *multicast_iface; + guint max_mcast_ttl; /* the caps of the stream */ gulong caps_sig; @@ -181,6 +182,7 @@ struct _GstRTSPStreamPrivate #define DEFAULT_PROFILES GST_RTSP_PROFILE_AVP #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ GST_RTSP_LOWER_TRANS_TCP +#define DEFAULT_MAX_MCAST_TTL 255 enum { @@ -280,6 +282,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->allowed_protocols = DEFAULT_PROTOCOLS; priv->configured_protocols = 0; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; + priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; g_mutex_init (&priv->lock); @@ -1884,6 +1887,54 @@ gst_rtsp_stream_get_buffer_size (GstRTSPStream * stream) return buffer_size; } +/** + * gst_rtsp_stream_set_max_mcast_ttl: + * @stream: a #GstRTSPStream + * @ttl: the new multicast ttl value + * + * Set the maximum time-to-live value of outgoing multicast packets. + * + * Returns: %TRUE if the requested ttl has been set successfully. + * + */ +gboolean +gst_rtsp_stream_set_max_mcast_ttl (GstRTSPStream * stream, guint ttl) +{ + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + g_mutex_lock (&stream->priv->lock); + if (ttl == 0 || ttl > DEFAULT_MAX_MCAST_TTL) { + GST_WARNING_OBJECT (stream, "The reqested mcast TTL value is not valid."); + g_mutex_unlock (&stream->priv->lock); + return FALSE; + } + stream->priv->max_mcast_ttl = ttl; + g_mutex_unlock (&stream->priv->lock); + + return TRUE; +} + +/** + * gst_rtsp_stream_get_max_mcast_ttl: + * @stream: a #GstRTSPStream + * + * Get the the maximum time-to-live value of outgoing multicast packets. + * + * Returns: the maximum time-to-live value of outgoing multicast packets. + * + */ +guint +gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream * stream) +{ + guint ttl; + + g_mutex_lock (&stream->priv->lock); + ttl = stream->priv->max_mcast_ttl; + g_mutex_unlock (&stream->priv->lock); + + return ttl; +} + /* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 1f527a462d..1ee146dda7 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -292,6 +292,12 @@ void gst_rtsp_stream_set_publish_clock_mode (GstRTSPStream * GST_RTSP_SERVER_API GstRTSPPublishClockMode gst_rtsp_stream_get_publish_clock_mode (GstRTSPStream * stream); +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_set_max_mcast_ttl (GstRTSPStream *stream, guint ttl); + +GST_RTSP_SERVER_API +guint gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream *stream); + GST_RTSP_SERVER_API gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GstRTSPTransport * transport); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 4adf3d18c9..ab95509f93 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -525,7 +525,6 @@ test_setup_response_200_multicast (GstRTSPClient * client, session_pool = gst_rtsp_client_get_session_pool (client); fail_unless (session_pool != NULL); - fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 1); session = gst_rtsp_session_pool_find (session_pool, session_hdr_params[0]); g_strfreev (session_hdr_params); @@ -727,117 +726,6 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GST_END_TEST; -static gboolean -test_setup_response_461 (GstRTSPClient * client, - GstRTSPMessage * response, gboolean close, gpointer user_data) -{ - GstRTSPStatusCode code; - const gchar *reason; - GstRTSPVersion version; - gchar *str; - - fail_unless (expected_transport == NULL); - - fail_unless (gst_rtsp_message_get_type (response) == - GST_RTSP_MESSAGE_RESPONSE); - - fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, - &version) - == GST_RTSP_OK); - fail_unless (code == GST_RTSP_STS_UNSUPPORTED_TRANSPORT); - fail_unless (g_str_equal (reason, "Unsupported transport")); - fail_unless (version == GST_RTSP_VERSION_1_0); - - fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, - 0) == GST_RTSP_OK); - fail_unless (atoi (str) == cseq++); - - - return TRUE; -} - -GST_START_TEST (test_client_multicast_invalid_transport_specific) -{ - GstRTSPClient *client; - GstRTSPMessage request = { 0, }; - gchar *str; - GstRTSPSessionPool *session_pool; - GstRTSPContext ctx = { NULL }; - - client = setup_multicast_client (); - - ctx.client = client; - ctx.auth = gst_rtsp_auth_new (); - ctx.token = - gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, - G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, - "user", NULL); - gst_rtsp_context_push_current (&ctx); - - /* simple SETUP with a valid URI and multicast, but an invalid ip */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=0") == GST_RTSP_OK); - str = g_strdup_printf ("%d", cseq); - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - "RTP/AVP;multicast;destination=233.252.0.2;ttl=1;port=5000-5001;"); - - gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, - &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); - - session_pool = gst_rtsp_client_get_session_pool (client); - fail_unless (session_pool != NULL); - fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); - g_object_unref (session_pool); - - - /* simple SETUP with a valid URI and multicast, but an invalid prt */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=0") == GST_RTSP_OK); - str = g_strdup_printf ("%d", cseq); - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - "RTP/AVP;multicast;destination=233.252.0.1;ttl=1;port=6000-6001;"); - - gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, - &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); - - session_pool = gst_rtsp_client_get_session_pool (client); - fail_unless (session_pool != NULL); - fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); - g_object_unref (session_pool); - - - /* simple SETUP with a valid URI and multicast, but an invalid ttl */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=0") == GST_RTSP_OK); - str = g_strdup_printf ("%d", cseq); - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - "RTP/AVP;multicast;destination=233.252.0.1;ttl=2;port=5000-5001;"); - - gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, - &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); - - session_pool = gst_rtsp_client_get_session_pool (client); - fail_unless (session_pool != NULL); - fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); - g_object_unref (session_pool); - - teardown_client (client); - g_object_unref (ctx.auth); - gst_rtsp_token_unref (ctx.token); - gst_rtsp_context_pop_current (&ctx); -} - -GST_END_TEST; - GST_START_TEST (test_client_multicast_transport_specific) { GstRTSPClient *client; @@ -859,7 +747,7 @@ GST_START_TEST (test_client_multicast_transport_specific) expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" "ttl=1;port=5000-5001;mode=\"PLAY\""; - /* simple SETUP with a valid URI and multicast, but an invalid ip */ + /* simple SETUP with a valid URI */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); @@ -1031,6 +919,156 @@ GST_START_TEST (test_client_sdp_with_no_bitrate_tags) GST_END_TEST; +static void +mcast_transport_specific_two_clients (gboolean shared) +{ + GstRTSPClient *client, *client2; + GstRTSPMessage request = { 0, }; + gchar *str; + GstRTSPSessionPool *session_pool; + GstRTSPContext ctx = { NULL }; + GstRTSPContext ctx2 = { NULL }; + GstRTSPMountPoints *mount_points; + GstRTSPMediaFactory *factory; + GstRTSPAddressPool *address_pool; + GstRTSPThreadPool *thread_pool; + gchar *session_id1; + + mount_points = gst_rtsp_mount_points_new (); + factory = gst_rtsp_media_factory_new (); + if (shared) + gst_rtsp_media_factory_set_shared (factory, TRUE); + gst_rtsp_media_factory_set_max_mcast_ttl (factory, 5); + gst_rtsp_media_factory_set_launch (factory, + "audiotestsrc ! audio/x-raw,rate=44100 ! audioconvert ! rtpL16pay name=pay0"); + address_pool = gst_rtsp_address_pool_new (); + fail_unless (gst_rtsp_address_pool_add_range (address_pool, + "233.252.0.1", "233.252.0.1", 5000, 5001, 1)); + gst_rtsp_media_factory_set_address_pool (factory, address_pool); + gst_rtsp_media_factory_add_role (factory, "user", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); + gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); + session_pool = gst_rtsp_session_pool_new (); + thread_pool = gst_rtsp_thread_pool_new (); + + /* first multicast client with transport specific request */ + client = gst_rtsp_client_new (); + gst_rtsp_client_set_session_pool (client, session_pool); + gst_rtsp_client_set_mount_points (client, mount_points); + gst_rtsp_client_set_thread_pool (client, thread_pool); + + ctx.client = client; + ctx.auth = gst_rtsp_auth_new (); + ctx.token = + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_context_push_current (&ctx); + + expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + + /* send SETUP request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + expected_transport); + + gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, + NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + expected_transport = NULL; + + /* send PLAY request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + gst_rtsp_context_pop_current (&ctx); + session_id1 = session_id; + + /* second multicast client with transport specific request */ + cseq = 0; + client2 = gst_rtsp_client_new (); + gst_rtsp_client_set_session_pool (client2, session_pool); + gst_rtsp_client_set_mount_points (client2, mount_points); + gst_rtsp_client_set_thread_pool (client2, thread_pool); + + ctx2.client = client2; + ctx2.auth = gst_rtsp_auth_new (); + ctx2.token = + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_context_push_current (&ctx2); + + expected_transport = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; + + /* send SETUP request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + expected_transport); + + gst_rtsp_client_set_send_func (client2, test_setup_response_200_multicast, + NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client2, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + expected_transport = NULL; + + /* send PLAY request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + gst_rtsp_client_set_send_func (client2, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client2, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + send_teardown (client2); + gst_rtsp_context_pop_current (&ctx2); + + gst_rtsp_context_push_current (&ctx); + session_id = session_id1; + send_teardown (client); + gst_rtsp_context_pop_current (&ctx); + + teardown_client (client); + teardown_client (client2); + g_object_unref (ctx.auth); + g_object_unref (ctx2.auth); + gst_rtsp_token_unref (ctx.token); + gst_rtsp_token_unref (ctx2.token); + g_object_unref (mount_points); + g_object_unref (session_pool); + g_object_unref (address_pool); + g_object_unref (thread_pool); +} + +/* test if two multicast clients can choose different transport settings */ +GST_START_TEST + (test_client_multicast_transport_specific_two_clients_shared_media) { + mcast_transport_specific_two_clients (TRUE); +} + +GST_END_TEST; + static Suite * rtspclient_suite (void) { @@ -1046,12 +1084,13 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_transport_404); tcase_add_test (tc, test_client_multicast_transport); tcase_add_test (tc, test_client_multicast_ignore_transport_specific); - tcase_add_test (tc, test_client_multicast_invalid_transport_specific); tcase_add_test (tc, test_client_multicast_transport_specific); tcase_add_test (tc, test_client_sdp_with_max_bitrate_tag); tcase_add_test (tc, test_client_sdp_with_bitrate_tag); tcase_add_test (tc, test_client_sdp_with_max_bitrate_and_bitrate_tags); tcase_add_test (tc, test_client_sdp_with_no_bitrate_tags); + tcase_add_test (tc, + test_client_multicast_transport_specific_two_clients_shared_media); return s; } diff --git a/tests/check/gst/mediafactory.c b/tests/check/gst/mediafactory.c index b6b250beb7..ba1719ea04 100644 --- a/tests/check/gst/mediafactory.c +++ b/tests/check/gst/mediafactory.c @@ -314,6 +314,63 @@ GST_START_TEST (test_reset) GST_END_TEST; +GST_START_TEST (test_mcast_ttl) +{ + GstRTSPMediaFactory *factory; + GstElement *element; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPStream *stream; + + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_shared (factory, TRUE); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 " + " audiotestsrc ! audioconvert ! rtpL16pay name=pay1 )"); + + /* try to set an invalid ttl and make sure that the default ttl value (255) is + * set */ + gst_rtsp_media_factory_set_max_mcast_ttl (factory, 0); + fail_unless (gst_rtsp_media_factory_get_max_mcast_ttl (factory) == 255); + gst_rtsp_media_factory_set_max_mcast_ttl (factory, 300); + fail_unless (gst_rtsp_media_factory_get_max_mcast_ttl (factory) == 255); + + /* set a valid ttl value */ + gst_rtsp_media_factory_set_max_mcast_ttl (factory, 3); + fail_unless (gst_rtsp_media_factory_get_max_mcast_ttl (factory) == 3); + + element = gst_rtsp_media_factory_create_element (factory, url); + fail_unless (GST_IS_BIN (element)); + fail_if (GST_IS_PIPELINE (element)); + gst_object_unref (element); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + fail_unless (gst_rtsp_media_n_streams (media) == 2); + fail_unless (gst_rtsp_media_get_max_mcast_ttl (media) == 3); + + /* verify that the correct ttl value has been propageted to the media + * streams */ + stream = gst_rtsp_media_get_stream (media, 0); + fail_unless (stream != NULL); + fail_unless (gst_rtsp_stream_get_max_mcast_ttl (stream) == 3); + + stream = gst_rtsp_media_get_stream (media, 1); + fail_unless (stream != NULL); + fail_unless (gst_rtsp_stream_get_max_mcast_ttl (stream) == 3); + + g_object_unref (media); + + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + static Suite * rtspmediafactory_suite (void) { @@ -329,6 +386,7 @@ rtspmediafactory_suite (void) tcase_add_test (tc, test_addresspool); tcase_add_test (tc, test_permissions); tcase_add_test (tc, test_reset); + tcase_add_test (tc, test_mcast_ttl); return s; } From a9db3e7f092cfeb5475e9aa24b1e91906c141d52 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Fri, 23 Feb 2018 14:34:32 +0100 Subject: [PATCH 1534/1776] rtsp-stream: Don't require address pool in the transport specific case If "transport.client-settings" parameter is set to true, the client is allowed to specify destination, ports and ttl. There is no need for pre-configured address pool. https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-stream.c | 171 ++++++++++++++++++++++++---------- tests/check/gst/client.c | 51 +++++++++- 2 files changed, 168 insertions(+), 54 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 1a68fd5b13..0d17718d9d 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1326,11 +1326,11 @@ error: static gboolean alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GSocket * socket_out[2], GstRTSPAddress ** server_addr_out, - gboolean multicast, GstRTSPTransport * ct) + gboolean multicast, GstRTSPTransport * ct, gboolean use_transport_settings) { GstRTSPStreamPrivate *priv = stream->priv; GSocket *rtp_socket = NULL; - GSocket *rtcp_socket; + GSocket *rtcp_socket = NULL; gint tmp_rtp, tmp_rtcp; guint count; GList *rejected_addresses = NULL; @@ -1339,6 +1339,7 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GSocketAddress *rtp_sockaddr = NULL; GSocketAddress *rtcp_sockaddr = NULL; GstRTSPAddressPool *pool; + gboolean transport_settings_defined = FALSE; pool = priv->pool; count = 0; @@ -1346,6 +1347,30 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, /* Start with random port */ tmp_rtp = 0; + if (use_transport_settings) { + if (!multicast) + goto no_mcast; + + if (ct == NULL) + goto no_transport; + + /* multicast and transport specific case */ + if (ct->destination != NULL) { + tmp_rtp = ct->port.min; + tmp_rtcp = ct->port.max; + inetaddr = g_inet_address_new_from_string (ct->destination); + if (inetaddr == NULL) + goto destination_error; + if (!g_inet_address_get_is_multicast (inetaddr)) + goto destination_no_mcast; + g_object_unref (inetaddr); + inetaddr = g_inet_address_new_any (family); + + GST_DEBUG_OBJECT (stream, "use transport settings"); + transport_settings_defined = TRUE; + } + } + rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, NULL); if (!rtcp_socket) @@ -1364,55 +1389,60 @@ again: g_socket_set_multicast_loopback (rtp_socket, FALSE); } - if ((pool && gst_rtsp_address_pool_has_unicast_addresses (pool)) || multicast) { - GstRTSPAddressFlags flags; + if (!transport_settings_defined) { + if ((pool && gst_rtsp_address_pool_has_unicast_addresses (pool)) + || multicast) { + GstRTSPAddressFlags flags; - if (addr) - rejected_addresses = g_list_prepend (rejected_addresses, addr); + if (addr) + rejected_addresses = g_list_prepend (rejected_addresses, addr); - if (!pool) - goto no_pool; + if (!pool) + goto no_pool; - flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT; - if (multicast) - flags |= GST_RTSP_ADDRESS_FLAG_MULTICAST; - else - flags |= GST_RTSP_ADDRESS_FLAG_UNICAST; + flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT; + if (multicast) + flags |= GST_RTSP_ADDRESS_FLAG_MULTICAST; + else + flags |= GST_RTSP_ADDRESS_FLAG_UNICAST; - if (family == G_SOCKET_FAMILY_IPV6) - flags |= GST_RTSP_ADDRESS_FLAG_IPV6; - else - flags |= GST_RTSP_ADDRESS_FLAG_IPV4; + if (family == G_SOCKET_FAMILY_IPV6) + flags |= GST_RTSP_ADDRESS_FLAG_IPV6; + else + flags |= GST_RTSP_ADDRESS_FLAG_IPV4; - addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); + addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); - if (addr == NULL) - goto no_address; + if (addr == NULL) + goto no_address; - tmp_rtp = addr->port; + tmp_rtp = addr->port; - g_clear_object (&inetaddr); - /* FIXME: Does it really work with the IP_MULTICAST_ALL socket option and - * socket control message set in udpsrc? */ - if (multicast) - inetaddr = g_inet_address_new_any (family); - else - inetaddr = g_inet_address_new_from_string (addr->address); - } else { - if (tmp_rtp != 0) { - tmp_rtp += 2; - if (++count > 20) - goto no_ports; + g_clear_object (&inetaddr); + /* FIXME: Does it really work with the IP_MULTICAST_ALL socket option and + * socket control message set in udpsrc? */ + if (multicast) + inetaddr = g_inet_address_new_any (family); + else + inetaddr = g_inet_address_new_from_string (addr->address); + } else { + if (tmp_rtp != 0) { + tmp_rtp += 2; + if (++count > 20) + goto no_ports; + } + + if (inetaddr == NULL) + inetaddr = g_inet_address_new_any (family); } - - if (inetaddr == NULL) - inetaddr = g_inet_address_new_any (family); } rtp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtp); if (!g_socket_bind (rtp_socket, rtp_sockaddr, FALSE, NULL)) { GST_DEBUG_OBJECT (stream, "rtp bind() failed, will try again"); g_object_unref (rtp_sockaddr); + if (transport_settings_defined) + goto transport_settings_error; goto again; } g_object_unref (rtp_sockaddr); @@ -1423,17 +1453,22 @@ again: goto socket_error; } - tmp_rtp = - g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (rtp_sockaddr)); - g_object_unref (rtp_sockaddr); + if (!transport_settings_defined) { + tmp_rtp = + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (rtp_sockaddr)); - /* check if port is even */ - if ((tmp_rtp & 1) != 0) { - /* port not even, close and allocate another */ - tmp_rtp++; - g_clear_object (&rtp_socket); - goto again; + /* check if port is even. RFC 3550 encorages the use of an even/odd port + * pair, however it's not a strict requirement so this check is not done + * for the client selected ports. */ + if ((tmp_rtp & 1) != 0) { + /* port not even, close and allocate another */ + tmp_rtp++; + g_object_unref (rtp_sockaddr); + g_clear_object (&rtp_socket); + goto again; + } } + g_object_unref (rtp_sockaddr); /* set port */ tmp_rtcp = tmp_rtp + 1; @@ -1443,15 +1478,21 @@ again: GST_DEBUG_OBJECT (stream, "rctp bind() failed, will try again"); g_object_unref (rtcp_sockaddr); g_clear_object (&rtp_socket); + if (transport_settings_defined) + goto transport_settings_error; goto again; } g_object_unref (rtcp_sockaddr); if (!addr) { addr = g_slice_new0 (GstRTSPAddress); - addr->address = g_inet_address_to_string (inetaddr); addr->port = tmp_rtp; addr->n_ports = 2; + if (transport_settings_defined) + addr->address = g_strdup (ct->destination); + else + addr->address = g_inet_address_to_string (inetaddr); + addr->ttl = ct->ttl; } g_clear_object (&inetaddr); @@ -1468,6 +1509,28 @@ again: return TRUE; /* ERRORS */ +no_mcast: + { + GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: wrong transport"); + goto cleanup; + } +no_transport: + { + GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: no transport"); + goto cleanup; + } +destination_error: + { + GST_ERROR_OBJECT (stream, + "failed to allocate UDP ports: destination error"); + goto cleanup; + } +destination_no_mcast: + { + GST_ERROR_OBJECT (stream, + "failed to allocate UDP ports: destination not multicast address"); + goto cleanup; + } no_udp_protocol: { GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: protocol error"); @@ -1489,6 +1552,12 @@ no_ports: GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: no ports"); goto cleanup; } +transport_settings_error: + { + GST_ERROR_OBJECT (stream, + "failed to allocate UDP ports with requested transport settings"); + goto cleanup; + } socket_error: { GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: socket error"); @@ -1563,12 +1632,13 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, /* UDP unicast */ GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_UDP, ipv4"); ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, - priv->socket_v4, &priv->server_addr_v4, FALSE, ct); + priv->socket_v4, &priv->server_addr_v4, FALSE, ct, FALSE); } else { /* multicast */ GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_MCAST_UDP, ipv4"); ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, - priv->mcast_socket_v4, &priv->mcast_addr_v4, TRUE, ct); + priv->mcast_socket_v4, &priv->mcast_addr_v4, TRUE, ct, + use_transport_settings); } } else { /* IPv6 */ @@ -1576,13 +1646,14 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, /* unicast */ GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_UDP, ipv6"); ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, - priv->socket_v6, &priv->server_addr_v6, FALSE, ct); + priv->socket_v6, &priv->server_addr_v6, FALSE, ct, FALSE); } else { /* multicast */ GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_MCAST_UDP, ipv6"); ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, - priv->mcast_socket_v6, &priv->mcast_addr_v6, TRUE, ct); + priv->mcast_socket_v6, &priv->mcast_addr_v6, TRUE, ct, + use_transport_settings); } } g_mutex_unlock (&priv->lock); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index ab95509f93..d4fdd9ec1f 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -726,7 +726,8 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GST_END_TEST; -GST_START_TEST (test_client_multicast_transport_specific) +static void +multicast_transport_specific (void) { GstRTSPClient *client; GstRTSPMessage request = { 0, }; @@ -760,7 +761,6 @@ GST_START_TEST (test_client_multicast_transport_specific) fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - expected_transport = NULL; gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, NULL, NULL); @@ -769,14 +769,44 @@ GST_START_TEST (test_client_multicast_transport_specific) fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 1); g_object_unref (session_pool); - send_teardown (client); + /* send PLAY request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + send_teardown (client); teardown_client (client); g_object_unref (ctx.auth); gst_rtsp_token_unref (ctx.token); gst_rtsp_context_pop_current (&ctx); } +/* CASE: multicast address requested by the client exists in the address pool */ +GST_START_TEST (test_client_multicast_transport_specific) +{ + expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + multicast_transport_specific (); + expected_transport = NULL; +} + +GST_END_TEST; + +/* CASE: multicast address requested by the client does not exist in the address pool */ +GST_START_TEST (test_client_multicast_transport_specific_no_address_in_pool) +{ + expected_transport = "RTP/AVP;multicast;destination=234.252.0.3;" + "ttl=1;port=6000-6001;mode=\"PLAY\""; + multicast_transport_specific (); + expected_transport = NULL; +} + GST_END_TEST; static gboolean @@ -1061,7 +1091,8 @@ mcast_transport_specific_two_clients (gboolean shared) g_object_unref (thread_pool); } -/* test if two multicast clients can choose different transport settings */ +/* test if two multicast clients can choose different transport settings + * CASE: media is shared */ GST_START_TEST (test_client_multicast_transport_specific_two_clients_shared_media) { mcast_transport_specific_two_clients (TRUE); @@ -1069,6 +1100,15 @@ GST_START_TEST GST_END_TEST; +/* test if two multicast clients can choose different transport settings + * CASE: media is not shared */ +GST_START_TEST (test_client_multicast_transport_specific_two_clients) +{ + mcast_transport_specific_two_clients (FALSE); +} + +GST_END_TEST; + static Suite * rtspclient_suite (void) { @@ -1091,6 +1131,9 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_sdp_with_no_bitrate_tags); tcase_add_test (tc, test_client_multicast_transport_specific_two_clients_shared_media); + tcase_add_test (tc, test_client_multicast_transport_specific_two_clients); + tcase_add_test (tc, + test_client_multicast_transport_specific_no_address_in_pool); return s; } From 499e437e501215849d24cdaa157e0edf4de097d0 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Wed, 25 Jul 2018 15:33:18 +0200 Subject: [PATCH 1535/1776] stream: Choose the maximum ttl value provided by multicast clients The maximum ttl value provided so far by the multicast clients will be chosen and reported in the response to the current client request. https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-client.c | 57 +++++- gst/rtsp-server/rtsp-stream.c | 293 +++++++++++++++++++++++++++---- gst/rtsp-server/rtsp-stream.h | 13 ++ tests/check/gst/client.c | 319 +++++++++++++++++++++++++++++++--- tests/check/gst/stream.c | 91 ++++++++++ 5 files changed, 706 insertions(+), 67 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8f39ccd6fb..d4c5211985 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1972,8 +1972,13 @@ default_configure_client_transport (GstRTSPClient * client, if ((ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) && gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS) && - (ct->destination != NULL)) + (ct->destination != NULL)) { + + if (!gst_rtsp_stream_verify_mcast_ttl (ctx->stream, ct->ttl)) + goto error_ttl; + use_client_settings = TRUE; + } /* We need to allocate the sockets for both families before starting * multiudpsink, otherwise multiudpsink won't accept new clients with @@ -1992,14 +1997,29 @@ default_configure_client_transport (GstRTSPClient * client, goto error_allocating_ports; if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - /* FIXME: the address has been successfully allocated, however, in - * the use_client_settings case we need to verify that the allocated - * address is the one requested by the client and if this address is - * an allowed destination. Verifying this via the address pool in not - * the proper way as the address pool should only be used for choosing - * the server-selected address/port pairs. */ + if (use_client_settings) { + /* FIXME: the address has been successfully allocated, however, in + * the use_client_settings case we need to verify that the allocated + * address is the one requested by the client and if this address is + * an allowed destination. Verifying this via the address pool in not + * the proper way as the address pool should only be used for choosing + * the server-selected address/port pairs. */ + GSocket *rtp_socket; + guint ttl; - if (!use_client_settings) { + rtp_socket = + gst_rtsp_stream_get_rtp_multicast_socket (ctx->stream, family); + if (rtp_socket == NULL) + goto no_socket; + ttl = g_socket_get_multicast_ttl (rtp_socket); + g_object_unref (rtp_socket); + if (ct->ttl < ttl) { + /* use the maximum ttl that is requested by multicast clients */ + GST_DEBUG ("requested ttl %u, but keeping ttl %u", ct->ttl, ttl); + ct->ttl = ttl; + } + + } else { GstRTSPAddress *addr = NULL; g_free (ct->destination); @@ -2012,6 +2032,11 @@ default_configure_client_transport (GstRTSPClient * client, ct->ttl = addr->ttl; gst_rtsp_address_free (addr); } + + if (!gst_rtsp_stream_add_multicast_client_address (ctx->stream, + ct->destination, ct->port.min, ct->port.max, family)) + goto error_mcast_transport; + } else { GstRTSPUrl *url; @@ -2064,6 +2089,12 @@ default_configure_client_transport (GstRTSPClient * client, return TRUE; /* ERRORS */ +error_ttl: + { + GST_ERROR_OBJECT (client, + "Failed to allocate UDP ports: invalid ttl value"); + return FALSE; + } error_allocating_ports: { GST_ERROR_OBJECT (client, "Failed to allocate UDP ports"); @@ -2074,6 +2105,16 @@ no_address: GST_ERROR_OBJECT (client, "Failed to acquire address for stream"); return FALSE; } +no_socket: + { + GST_ERROR_OBJECT (client, "Failed to get UDP socket"); + return FALSE; + } +error_mcast_transport: + { + GST_ERROR_OBJECT (client, "Failed to add multicast client transport"); + return FALSE; + } } static GstRTSPTransport * diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 0d17718d9d..65f0f5d2c6 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -110,6 +110,7 @@ struct _GstRTSPStreamPrivate GstElement *mcast_udpsink[2]; GSocket *mcast_socket_v4[2]; GSocket *mcast_socket_v6[2]; + GList *mcast_clients; /* for TCP transport */ GstElement *appsrc[2]; @@ -292,6 +293,24 @@ gst_rtsp_stream_init (GstRTSPStream * stream) (GDestroyNotify) gst_caps_unref); } +typedef struct _UdpClientAddrInfo UdpClientAddrInfo; + +struct _UdpClientAddrInfo +{ + gchar *address; + guint rtp_port; + guint add_count; /* how often this address has been added */ +}; + +static void +free_mcast_client (gpointer data) +{ + UdpClientAddrInfo *client = data; + + g_free (client->address); + g_free (client); +} + static void gst_rtsp_stream_finalize (GObject * obj) { @@ -338,6 +357,7 @@ gst_rtsp_stream_finalize (GObject * obj) } g_free (priv->multicast_iface); + g_list_free_full (priv->mcast_clients, (GDestroyNotify) free_mcast_client); gst_object_unref (priv->payloader); if (priv->srcpad) @@ -1497,6 +1517,12 @@ again: g_clear_object (&inetaddr); + if (multicast && (ct->ttl > 0) && (ct->ttl <= priv->max_mcast_ttl)) { + GST_DEBUG ("setting mcast ttl to %d", ct->ttl); + g_socket_set_multicast_ttl (rtp_socket, ct->ttl); + g_socket_set_multicast_ttl (rtcp_socket, ct->ttl); + } + socket_out[0] = rtp_socket; socket_out[1] = rtcp_socket; *server_addr_out = addr; @@ -1579,6 +1605,100 @@ cleanup: } } +/* must be called with lock */ +static gboolean +add_mcast_client_addr (GstRTSPStream * stream, const gchar * destination, + guint rtp_port, guint rtcp_port) +{ + GstRTSPStreamPrivate *priv; + GList *walk; + UdpClientAddrInfo *client; + GInetAddress *inet; + + priv = stream->priv; + + if (destination == NULL) + return FALSE; + + inet = g_inet_address_new_from_string (destination); + if (inet == NULL) + goto invalid_address; + + if (!g_inet_address_get_is_multicast (inet)) { + g_object_unref (inet); + goto invalid_address; + } + g_object_unref (inet); + + for (walk = priv->mcast_clients; walk; walk = g_list_next (walk)) { + UdpClientAddrInfo *cli = walk->data; + + if ((g_strcmp0 (cli->address, destination) == 0) && + (cli->rtp_port == rtp_port)) { + GST_DEBUG ("requested destination already exists: %s:%u-%u", + destination, rtp_port, rtcp_port); + cli->add_count++; + return TRUE; + } + } + + client = g_new0 (UdpClientAddrInfo, 1); + client->address = g_strdup (destination); + client->rtp_port = rtp_port; + client->add_count = 1; + priv->mcast_clients = g_list_prepend (priv->mcast_clients, client); + + GST_DEBUG ("added mcast client %s:%u-%u", destination, rtp_port, rtcp_port); + + return TRUE; + +invalid_address: + { + GST_WARNING_OBJECT (stream, "Multicast address is invalid: %s", + destination); + return FALSE; + } +} + +/* must be called with lock */ +static gboolean +remove_mcast_client_addr (GstRTSPStream * stream, const gchar * destination, + guint rtp_port, guint rtcp_port) +{ + GstRTSPStreamPrivate *priv; + GList *walk; + + priv = stream->priv; + + if (destination == NULL) + goto no_destination; + + for (walk = priv->mcast_clients; walk; walk = g_list_next (walk)) { + UdpClientAddrInfo *cli = walk->data; + + if ((g_strcmp0 (cli->address, destination) == 0) && + (cli->rtp_port == rtp_port)) { + cli->add_count--; + + if (!cli->add_count) { + priv->mcast_clients = g_list_remove (priv->mcast_clients, cli); + free_mcast_client (cli); + } + return TRUE; + } + } + + GST_WARNING_OBJECT (stream, "Address not found"); + return FALSE; + +no_destination: + { + GST_WARNING_OBJECT (stream, "No destination has been provided"); + return FALSE; + } +} + + /** * gst_rtsp_stream_allocate_udp_sockets: * @stream: a #GstRTSPStream @@ -2006,6 +2126,29 @@ gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream * stream) return ttl; } +/** + * gst_rtsp_stream_verify_mcast_ttl: + * @stream: a #GstRTSPStream + * @ttl: a requested multicast ttl + * + * Check if the requested multicast ttl value is allowed. + * + * Returns: TRUE if the requested ttl value is allowed. + * + */ +gboolean +gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream * stream, guint ttl) +{ + gboolean res = FALSE; + + g_mutex_lock (&stream->priv->lock); + if ((ttl > 0) && (ttl <= stream->priv->max_mcast_ttl)) + res = TRUE; + g_mutex_unlock (&stream->priv->lock); + + return res; +} + /* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) @@ -3339,38 +3482,29 @@ udpsrc_error: } static gboolean -check_mcast_part_for_transport (GstRTSPStream * stream, - const GstRTSPTransport * tr) +check_mcast_client_addr (GstRTSPStream * stream, const GstRTSPTransport * tr) { GstRTSPStreamPrivate *priv = stream->priv; - GInetAddress *inetaddr; - GSocketFamily family; - GstRTSPAddress *mcast_addr; + GList *walk; - /* Check if it's a ipv4 or ipv6 transport */ - inetaddr = g_inet_address_new_from_string (tr->destination); - family = g_inet_address_get_family (inetaddr); - g_object_unref (inetaddr); - - /* Select fields corresponding to the family */ - if (family == G_SOCKET_FAMILY_IPV4) { - mcast_addr = priv->mcast_addr_v4; - } else { - mcast_addr = priv->mcast_addr_v6; - } - - /* We support only one mcast group per family, make sure this transport - * matches it. */ - if (!mcast_addr) + if (priv->mcast_clients == NULL) goto no_addr; - if (g_ascii_strcasecmp (tr->destination, mcast_addr->address) != 0 || - tr->port.min != mcast_addr->port || - tr->port.max != mcast_addr->port + mcast_addr->n_ports - 1 || - tr->ttl != mcast_addr->ttl) - goto wrong_addr; + if (tr == NULL) + goto no_transport; - return TRUE; + if (tr->destination == NULL) + goto no_destination; + + for (walk = priv->mcast_clients; walk; walk = g_list_next (walk)) { + UdpClientAddrInfo *cli = walk->data; + + if ((g_strcmp0 (cli->address, tr->destination) == 0) && + (cli->rtp_port == tr->port.min)) + return TRUE; + } + + return FALSE; no_addr: { @@ -3378,7 +3512,13 @@ no_addr: "has been reserved"); return FALSE; } -wrong_addr: +no_transport: + { + GST_WARNING_OBJECT (stream, "Adding mcast transport, but no transport " + "has been provided"); + return FALSE; + } +no_destination: { GST_WARNING_OBJECT (stream, "Adding mcast transport, but it doesn't match " "the reserved address"); @@ -4055,10 +4195,11 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, if (add) { GST_INFO ("adding %s:%d-%d", dest, min, max); - if (!check_mcast_part_for_transport (stream, tr)) + if (!check_mcast_client_addr (stream, tr)) goto mcast_error; + add_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min, + max); - /* FIXME: Is it ok to set ttl-mc if media is shared? */ if (tr->ttl > 0) { GST_INFO ("setting ttl-mc %d", tr->ttl); if (priv->mcast_udpsink[0]) @@ -4068,11 +4209,12 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, g_object_set (G_OBJECT (priv->mcast_udpsink[1]), "ttl-mc", tr->ttl, NULL); } - add_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min, - max); priv->transports = g_list_prepend (priv->transports, trans); } else { GST_INFO ("removing %s:%d-%d", dest, min, max); + if (!remove_mcast_client_addr (stream, dest, min, max)) + GST_WARNING_OBJECT (stream, + "Failed to remove multicast address: %s:%d-%d", dest, min, max); remove_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min, max); priv->transports = g_list_remove (priv->transports, trans); @@ -4422,6 +4564,95 @@ gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream * stream, return socket; } +/** + * gst_rtsp_stream_add_multicast_client_address: + * @stream: a #GstRTSPStream + * @destination: (transfer none): a multicast address to add + * @rtp_port: RTP port + * @rtcp_port: RTCP port + * @family: socket family + * + * Add multicast client address to stream. At this point, the sockets that + * will stream RTP and RTCP data to @destination are supposed to be + * allocated. + * + * Returns: %TRUE if @destination can be addedd and handled by @stream. + */ +gboolean +gst_rtsp_stream_add_multicast_client_address (GstRTSPStream * stream, + const gchar * destination, guint rtp_port, guint rtcp_port, + GSocketFamily family) +{ + GstRTSPStreamPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + g_return_val_if_fail (destination != NULL, FALSE); + + priv = stream->priv; + g_mutex_lock (&priv->lock); + if ((family == G_SOCKET_FAMILY_IPV4) && (priv->mcast_socket_v4[0] == NULL)) + goto socket_error; + else if ((family == G_SOCKET_FAMILY_IPV6) && + (priv->mcast_socket_v6[0] == NULL)) + goto socket_error; + + if (!add_mcast_client_addr (stream, destination, rtp_port, rtcp_port)) + goto add_addr_error; + g_mutex_unlock (&priv->lock); + + return TRUE; + +socket_error: + { + GST_WARNING_OBJECT (stream, + "Failed to add multicast address: no udp socket"); + g_mutex_unlock (&priv->lock); + return FALSE; + } +add_addr_error: + { + GST_WARNING_OBJECT (stream, + "Failed to add multicast address: invalid address"); + g_mutex_unlock (&priv->lock); + return FALSE; + } +} + +/** + * gst_rtsp_stream_get_multicast_client_addresses + * @stream: a #GstRTSPStream + * + * Get all multicast client addresses that RTP data will be sent to + * + * Returns: A comma separated list of host:port pairs with destinations + */ +gchar * +gst_rtsp_stream_get_multicast_client_addresses (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + GString *str; + GList *clients; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + priv = stream->priv; + str = g_string_new (""); + + g_mutex_lock (&priv->lock); + clients = priv->mcast_clients; + while (clients != NULL) { + UdpClientAddrInfo *client; + + client = (UdpClientAddrInfo *) clients->data; + clients = g_list_next (clients); + g_string_append_printf (str, "%s:%d%s", client->address, client->rtp_port, + (clients != NULL ? "," : "")); + } + g_mutex_unlock (&priv->lock); + + return g_string_free (str, FALSE); +} + /** * gst_rtsp_stream_set_seqnum: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 1ee146dda7..0c6804d536 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -233,6 +233,16 @@ GST_RTSP_SERVER_API GSocket * gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream *stream, GSocketFamily family); +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_add_multicast_client_address (GstRTSPStream * stream, + const gchar * destination, + guint rtp_port, + guint rtcp_port, + GSocketFamily family); + +GST_RTSP_SERVER_API +gchar * gst_rtsp_stream_get_multicast_client_addresses (GstRTSPStream * stream); + GST_RTSP_SERVER_API gboolean gst_rtsp_stream_update_crypto (GstRTSPStream * stream, guint ssrc, GstCaps * crypto); @@ -298,6 +308,9 @@ gboolean gst_rtsp_stream_set_max_mcast_ttl (GstRTSPStream *strea GST_RTSP_SERVER_API guint gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream *stream); +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream *stream, guint ttl); + GST_RTSP_SERVER_API gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GstRTSPTransport * transport); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index d4fdd9ec1f..d890b8218b 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -541,6 +541,35 @@ test_setup_response_200_multicast (GstRTSPClient * client, return TRUE; } +static gboolean +test_setup_response_461 (GstRTSPClient * client, + GstRTSPMessage * response, gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + gchar *str; + + fail_unless (expected_transport == NULL); + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_UNSUPPORTED_TRANSPORT); + fail_unless (g_str_equal (reason, "Unsupported transport")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, + 0) == GST_RTSP_OK); + fail_unless (atoi (str) == cseq++); + + + return TRUE; +} + static gboolean test_teardown_response_200 (GstRTSPClient * client, GstRTSPMessage * response, gboolean close, gpointer user_data) @@ -584,7 +613,7 @@ send_teardown (GstRTSPClient * client) } static GstRTSPClient * -setup_multicast_client (void) +setup_multicast_client (guint max_ttl) { GstRTSPClient *client; GstRTSPSessionPool *session_pool; @@ -611,6 +640,7 @@ setup_multicast_client (void) "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); gst_rtsp_client_set_mount_points (client, mount_points); + gst_rtsp_media_factory_set_max_mcast_ttl (factory, max_ttl); thread_pool = gst_rtsp_thread_pool_new (); gst_rtsp_client_set_thread_pool (client, thread_pool); @@ -629,7 +659,7 @@ GST_START_TEST (test_client_multicast_transport_404) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (); + client = setup_multicast_client (1); /* simple SETUP for non-existing url */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, @@ -662,7 +692,7 @@ GST_START_TEST (test_client_multicast_transport) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (); + client = setup_multicast_client (1); expected_session_timeout = 20; g_signal_connect (G_OBJECT (client), "new-session", @@ -699,7 +729,7 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (); + client = setup_multicast_client (1); /* simple SETUP with a valid URI and multicast and a specific dest, * but ignore it */ @@ -735,7 +765,7 @@ multicast_transport_specific (void) GstRTSPSessionPool *session_pool; GstRTSPContext ctx = { NULL }; - client = setup_multicast_client (); + client = setup_multicast_client (1); ctx.client = client; ctx.auth = gst_rtsp_auth_new (); @@ -950,9 +980,12 @@ GST_START_TEST (test_client_sdp_with_no_bitrate_tags) GST_END_TEST; static void -mcast_transport_specific_two_clients (gboolean shared) +mcast_transport_two_clients (gboolean shared, const gchar * transport1, + const gchar * expected_transport1, const gchar * addr1, + const gchar * transport2, const gchar * expected_transport2, + const gchar * addr2) { - GstRTSPClient *client, *client2; + GstRTSPClient *client1, *client2; GstRTSPMessage request = { 0, }; gchar *str; GstRTSPSessionPool *session_pool; @@ -963,6 +996,7 @@ mcast_transport_specific_two_clients (gboolean shared) GstRTSPAddressPool *address_pool; GstRTSPThreadPool *thread_pool; gchar *session_id1; + gchar *client_addr = NULL; mount_points = gst_rtsp_mount_points_new (); factory = gst_rtsp_media_factory_new (); @@ -983,12 +1017,12 @@ mcast_transport_specific_two_clients (gboolean shared) thread_pool = gst_rtsp_thread_pool_new (); /* first multicast client with transport specific request */ - client = gst_rtsp_client_new (); - gst_rtsp_client_set_session_pool (client, session_pool); - gst_rtsp_client_set_mount_points (client, mount_points); - gst_rtsp_client_set_thread_pool (client, thread_pool); + client1 = gst_rtsp_client_new (); + gst_rtsp_client_set_session_pool (client1, session_pool); + gst_rtsp_client_set_mount_points (client1, mount_points); + gst_rtsp_client_set_thread_pool (client1, thread_pool); - ctx.client = client; + ctx.client = client1; ctx.auth = gst_rtsp_auth_new (); ctx.token = gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, @@ -996,20 +1030,18 @@ mcast_transport_specific_two_clients (gboolean shared) "user", NULL); gst_rtsp_context_push_current (&ctx); - expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; + expected_transport = expected_transport1; /* send SETUP request */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - expected_transport); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport1); - gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, + gst_rtsp_client_set_send_func (client1, test_setup_response_200_multicast, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, + fail_unless (gst_rtsp_client_handle_message (client1, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); expected_transport = NULL; @@ -1020,10 +1052,17 @@ mcast_transport_specific_two_clients (gboolean shared) str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); - gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, + gst_rtsp_client_set_send_func (client1, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client1, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); + + /* check address */ + client_addr = gst_rtsp_stream_get_multicast_client_addresses (ctx.stream); + fail_if (client_addr == NULL); + fail_unless (g_str_equal (client_addr, addr1)); + g_free (client_addr); + gst_rtsp_context_pop_current (&ctx); session_id1 = session_id; @@ -1042,16 +1081,14 @@ mcast_transport_specific_two_clients (gboolean shared) "user", NULL); gst_rtsp_context_push_current (&ctx2); - expected_transport = "RTP/AVP;multicast;destination=233.252.0.2;" - "ttl=1;port=5002-5003;mode=\"PLAY\""; + expected_transport = expected_transport2; /* send SETUP request */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - expected_transport); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport2); gst_rtsp_client_set_send_func (client2, test_setup_response_200_multicast, NULL, NULL); @@ -1071,15 +1108,31 @@ mcast_transport_specific_two_clients (gboolean shared) &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); + /* check addresses */ + client_addr = gst_rtsp_stream_get_multicast_client_addresses (ctx2.stream); + fail_if (client_addr == NULL); + if (shared) { + if (g_str_equal (addr1, addr2)) { + fail_unless (g_str_equal (client_addr, addr1)); + } else { + gchar *addr_str = g_strdup_printf ("%s,%s", addr2, addr1); + fail_unless (g_str_equal (client_addr, addr_str)); + g_free (addr_str); + } + } else { + fail_unless (g_str_equal (client_addr, addr2)); + } + g_free (client_addr); + send_teardown (client2); gst_rtsp_context_pop_current (&ctx2); gst_rtsp_context_push_current (&ctx); session_id = session_id1; - send_teardown (client); + send_teardown (client1); gst_rtsp_context_pop_current (&ctx); - teardown_client (client); + teardown_client (client1); teardown_client (client2); g_object_unref (ctx.auth); g_object_unref (ctx2.auth); @@ -1095,7 +1148,19 @@ mcast_transport_specific_two_clients (gboolean shared) * CASE: media is shared */ GST_START_TEST (test_client_multicast_transport_specific_two_clients_shared_media) { - mcast_transport_specific_two_clients (TRUE); + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:5000"; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + const gchar *addr_client_2 = "233.252.0.2:5002"; + + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); } GST_END_TEST; @@ -1104,7 +1169,195 @@ GST_END_TEST; * CASE: media is not shared */ GST_START_TEST (test_client_multicast_transport_specific_two_clients) { - mcast_transport_specific_two_clients (FALSE); + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:5000"; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + const gchar *addr_client_2 = "233.252.0.2:5002"; + + mcast_transport_two_clients (FALSE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); +} + +GST_END_TEST; + +/* test if two multicast clients can choose the same transport settings. + * CASE: media is shared */ +GST_START_TEST + (test_client_multicast_transport_specific_two_clients_shared_media_same_transport) +{ + + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:5000"; + + const gchar *transport_client_2 = transport_client_1; + const gchar *expected_transport_2 = expected_transport_1; + const gchar *addr_client_2 = addr_client_1; + + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); +} + +GST_END_TEST; + +/* test if two multicast clients get the same transport settings without + * requesting specific transport. + * CASE: media is shared */ +GST_START_TEST (test_client_multicast_two_clients_shared_media) +{ + const gchar *transport_client_1 = "RTP/AVP;multicast;mode=\"PLAY\""; + const gchar *expected_transport_1 = + "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *addr_client_1 = "233.252.0.1:5000"; + + const gchar *transport_client_2 = transport_client_1; + const gchar *expected_transport_2 = expected_transport_1; + const gchar *addr_client_2 = addr_client_1; + + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); +} + +GST_END_TEST; + +/* test if two multicast clients get the different transport settings: the first client + * requests the specific transport configuration while the second client lets + * the server select the multicast address and the ports. + * CASE: media is shared */ +GST_START_TEST + (test_client_multicast_two_clients_first_specific_transport_shared_media) { + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:5000"; + + const gchar *transport_client_2 = "RTP/AVP;multicast;mode=\"PLAY\""; + const gchar *expected_transport_2 = expected_transport_1; + const gchar *addr_client_2 = addr_client_1; + + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); +} + +GST_END_TEST; +/* test if two multicast clients get the different transport settings: the first client lets + * the server select the multicast address and the ports while the second client requests + * the specific transport configuration. + * CASE: media is shared */ +GST_START_TEST + (test_client_multicast_two_clients_second_specific_transport_shared_media) { + const gchar *transport_client_1 = "RTP/AVP;multicast;mode=\"PLAY\""; + const gchar *expected_transport_1 = + "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *addr_client_1 = "233.252.0.1:5000"; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=2;port=5004-5005;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + const gchar *addr_client_2 = "233.252.0.2:5004"; + + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); +} + +GST_END_TEST; + +/* test if the maximum ttl multicast value is chosen by the server + * CASE: the first client provides the highest ttl value */ +GST_START_TEST (test_client_multicast_max_ttl_first_client) +{ + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=3;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:5000"; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; + const gchar *expected_transport_2 = + "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=3;port=5002-5003;mode=\"PLAY\""; + const gchar *addr_client_2 = "233.252.0.2:5002"; + + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); +} + +GST_END_TEST; + +/* test if the maximum ttl multicast value is chosen by the server + * CASE: the second client provides the highest ttl value */ +GST_START_TEST (test_client_multicast_max_ttl_second_client) +{ + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=2;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:5000"; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=4;port=5002-5003;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + const gchar *addr_client_2 = "233.252.0.2:5002"; + + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); +} + +GST_END_TEST; +GST_START_TEST (test_client_multicast_invalid_ttl) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + GstRTSPSessionPool *session_pool; + GstRTSPContext ctx = { NULL }; + + client = setup_multicast_client (3); + + ctx.client = client; + ctx.auth = gst_rtsp_auth_new (); + ctx.token = + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_context_push_current (&ctx); + + /* simple SETUP with an invalid ttl=0 */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast;destination=233.252.0.1;ttl=0;port=5000-5001;"); + + gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + session_pool = gst_rtsp_client_get_session_pool (client); + fail_unless (session_pool != NULL); + fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); + g_object_unref (session_pool); + + teardown_client (client); + g_object_unref (ctx.auth); + gst_rtsp_token_unref (ctx.token); + gst_rtsp_context_pop_current (&ctx); } GST_END_TEST; @@ -1132,8 +1385,18 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_transport_specific_two_clients_shared_media); tcase_add_test (tc, test_client_multicast_transport_specific_two_clients); + tcase_add_test (tc, + test_client_multicast_transport_specific_two_clients_shared_media_same_transport); + tcase_add_test (tc, test_client_multicast_two_clients_shared_media); + tcase_add_test (tc, + test_client_multicast_two_clients_first_specific_transport_shared_media); + tcase_add_test (tc, + test_client_multicast_two_clients_second_specific_transport_shared_media); tcase_add_test (tc, test_client_multicast_transport_specific_no_address_in_pool); + tcase_add_test (tc, test_client_multicast_max_ttl_first_client); + tcase_add_test (tc, test_client_multicast_max_ttl_second_client); + tcase_add_test (tc, test_client_multicast_invalid_ttl); return s; } diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index 7b59c0abc9..d71f1937f4 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -486,6 +486,95 @@ GST_START_TEST (test_tcp_transport) GST_END_TEST; +static void +check_multicast_client_address (const gchar * destination, guint port, + const gchar * expected_addr_str, gboolean expected_res) +{ + GstPad *srcpad; + GstElement *pay; + GstRTSPStream *stream; + GstBin *bin; + GstElement *rtpbin; + GstRTSPTransport *transport; + GstRTSPRange ports = { 0 }; + gchar *addr_str = NULL; + + srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); + fail_unless (srcpad != NULL); + gst_pad_set_active (srcpad, TRUE); + pay = gst_element_factory_make ("rtpgstpay", "testpayloader"); + fail_unless (pay != NULL); + stream = gst_rtsp_stream_new (0, pay, srcpad); + fail_unless (stream != NULL); + gst_object_unref (pay); + gst_object_unref (srcpad); + rtpbin = gst_element_factory_make ("rtpbin", "testrtpbin"); + fail_unless (rtpbin != NULL); + bin = GST_BIN (gst_bin_new ("testbin")); + fail_unless (bin != NULL); + fail_unless (gst_bin_add (bin, rtpbin)); + + fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + + fail_unless (gst_rtsp_transport_new (&transport) == GST_RTSP_OK); + transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST; + transport->destination = g_strdup (destination); + transport->ttl = 1; + ports.min = port; + ports.max = port + 1; + transport->port = ports; + + /* allocate ports */ + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, + G_SOCKET_FAMILY_IPV4, transport, TRUE) == expected_res); + + fail_unless (gst_rtsp_stream_add_multicast_client_address (stream, + destination, ports.min, ports.max, + G_SOCKET_FAMILY_IPV4) == expected_res); + + fail_unless (gst_rtsp_stream_complete_stream (stream, + transport) == expected_res); + + fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK); + addr_str = gst_rtsp_stream_get_multicast_client_addresses (stream); + + fail_unless (g_str_equal (addr_str, expected_addr_str)); + g_free (addr_str); + + fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); + + gst_object_unref (bin); + gst_object_unref (stream); +} + +/* test if the provided transport destination is correct. + * CASE: valid multicast address */ +GST_START_TEST (test_multicast_client_address) +{ + const gchar *addr = "233.252.0.1"; + guint port = 50000; + const gchar *expected_addr_str = "233.252.0.1:50000"; + gboolean expected_res = TRUE; + + check_multicast_client_address (addr, port, expected_addr_str, expected_res); +} + +GST_END_TEST; + +/* test if the provided transport destination is correct. + * CASE: invalid multicast address */ +GST_START_TEST (test_multicast_client_address_invalid) +{ + const gchar *addr = "1.2.3.4"; + guint port = 50000; + const gchar *expected_addr_str = ""; + gboolean expected_res = FALSE; + + check_multicast_client_address (addr, port, expected_addr_str, expected_res); +} + +GST_END_TEST; + static Suite * rtspstream_suite (void) { @@ -501,6 +590,8 @@ rtspstream_suite (void) tcase_add_test (tc, test_allocate_udp_ports_multicast); tcase_add_test (tc, test_allocate_udp_ports_client_settings); tcase_add_test (tc, test_tcp_transport); + tcase_add_test (tc, test_multicast_client_address); + tcase_add_test (tc, test_multicast_client_address_invalid); return s; } From 98b480fae9f477ef5ff7018951539bbd6981d3e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 14 Aug 2018 14:10:56 +0300 Subject: [PATCH 1536/1776] examples: Fix indentation --- examples/test-auth-digest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/test-auth-digest.c b/examples/test-auth-digest.c index f779c05774..e0e8915cdc 100644 --- a/examples/test-auth-digest.c +++ b/examples/test-auth-digest.c @@ -213,7 +213,8 @@ main (int argc, char *argv[]) g_print ("stream with admin2:power2 ready at rtsp://127.0.0.1:8554/test2\n"); if (htdigest_path) - g_print ("stream with htdigest users ready at rtsp://127.0.0.1:8554/test\n"); + g_print + ("stream with htdigest users ready at rtsp://127.0.0.1:8554/test\n"); g_main_loop_run (loop); From 29ae15f6f106abeb437ae823671c25fc6d79f540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 14 Aug 2018 14:25:14 +0300 Subject: [PATCH 1537/1776] Revert "stream: Choose the maximum ttl value provided by multicast clients" This reverts commit 499e437e501215849d24cdaa157e0edf4de097d0. Commits where accidentially squashed together --- gst/rtsp-server/rtsp-client.c | 57 +----- gst/rtsp-server/rtsp-stream.c | 293 ++++--------------------------- gst/rtsp-server/rtsp-stream.h | 13 -- tests/check/gst/client.c | 319 +++------------------------------- tests/check/gst/stream.c | 91 ---------- 5 files changed, 67 insertions(+), 706 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d4c5211985..8f39ccd6fb 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1972,13 +1972,8 @@ default_configure_client_transport (GstRTSPClient * client, if ((ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) && gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS) && - (ct->destination != NULL)) { - - if (!gst_rtsp_stream_verify_mcast_ttl (ctx->stream, ct->ttl)) - goto error_ttl; - + (ct->destination != NULL)) use_client_settings = TRUE; - } /* We need to allocate the sockets for both families before starting * multiudpsink, otherwise multiudpsink won't accept new clients with @@ -1997,29 +1992,14 @@ default_configure_client_transport (GstRTSPClient * client, goto error_allocating_ports; if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - if (use_client_settings) { - /* FIXME: the address has been successfully allocated, however, in - * the use_client_settings case we need to verify that the allocated - * address is the one requested by the client and if this address is - * an allowed destination. Verifying this via the address pool in not - * the proper way as the address pool should only be used for choosing - * the server-selected address/port pairs. */ - GSocket *rtp_socket; - guint ttl; + /* FIXME: the address has been successfully allocated, however, in + * the use_client_settings case we need to verify that the allocated + * address is the one requested by the client and if this address is + * an allowed destination. Verifying this via the address pool in not + * the proper way as the address pool should only be used for choosing + * the server-selected address/port pairs. */ - rtp_socket = - gst_rtsp_stream_get_rtp_multicast_socket (ctx->stream, family); - if (rtp_socket == NULL) - goto no_socket; - ttl = g_socket_get_multicast_ttl (rtp_socket); - g_object_unref (rtp_socket); - if (ct->ttl < ttl) { - /* use the maximum ttl that is requested by multicast clients */ - GST_DEBUG ("requested ttl %u, but keeping ttl %u", ct->ttl, ttl); - ct->ttl = ttl; - } - - } else { + if (!use_client_settings) { GstRTSPAddress *addr = NULL; g_free (ct->destination); @@ -2032,11 +2012,6 @@ default_configure_client_transport (GstRTSPClient * client, ct->ttl = addr->ttl; gst_rtsp_address_free (addr); } - - if (!gst_rtsp_stream_add_multicast_client_address (ctx->stream, - ct->destination, ct->port.min, ct->port.max, family)) - goto error_mcast_transport; - } else { GstRTSPUrl *url; @@ -2089,12 +2064,6 @@ default_configure_client_transport (GstRTSPClient * client, return TRUE; /* ERRORS */ -error_ttl: - { - GST_ERROR_OBJECT (client, - "Failed to allocate UDP ports: invalid ttl value"); - return FALSE; - } error_allocating_ports: { GST_ERROR_OBJECT (client, "Failed to allocate UDP ports"); @@ -2105,16 +2074,6 @@ no_address: GST_ERROR_OBJECT (client, "Failed to acquire address for stream"); return FALSE; } -no_socket: - { - GST_ERROR_OBJECT (client, "Failed to get UDP socket"); - return FALSE; - } -error_mcast_transport: - { - GST_ERROR_OBJECT (client, "Failed to add multicast client transport"); - return FALSE; - } } static GstRTSPTransport * diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 65f0f5d2c6..0d17718d9d 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -110,7 +110,6 @@ struct _GstRTSPStreamPrivate GstElement *mcast_udpsink[2]; GSocket *mcast_socket_v4[2]; GSocket *mcast_socket_v6[2]; - GList *mcast_clients; /* for TCP transport */ GstElement *appsrc[2]; @@ -293,24 +292,6 @@ gst_rtsp_stream_init (GstRTSPStream * stream) (GDestroyNotify) gst_caps_unref); } -typedef struct _UdpClientAddrInfo UdpClientAddrInfo; - -struct _UdpClientAddrInfo -{ - gchar *address; - guint rtp_port; - guint add_count; /* how often this address has been added */ -}; - -static void -free_mcast_client (gpointer data) -{ - UdpClientAddrInfo *client = data; - - g_free (client->address); - g_free (client); -} - static void gst_rtsp_stream_finalize (GObject * obj) { @@ -357,7 +338,6 @@ gst_rtsp_stream_finalize (GObject * obj) } g_free (priv->multicast_iface); - g_list_free_full (priv->mcast_clients, (GDestroyNotify) free_mcast_client); gst_object_unref (priv->payloader); if (priv->srcpad) @@ -1517,12 +1497,6 @@ again: g_clear_object (&inetaddr); - if (multicast && (ct->ttl > 0) && (ct->ttl <= priv->max_mcast_ttl)) { - GST_DEBUG ("setting mcast ttl to %d", ct->ttl); - g_socket_set_multicast_ttl (rtp_socket, ct->ttl); - g_socket_set_multicast_ttl (rtcp_socket, ct->ttl); - } - socket_out[0] = rtp_socket; socket_out[1] = rtcp_socket; *server_addr_out = addr; @@ -1605,100 +1579,6 @@ cleanup: } } -/* must be called with lock */ -static gboolean -add_mcast_client_addr (GstRTSPStream * stream, const gchar * destination, - guint rtp_port, guint rtcp_port) -{ - GstRTSPStreamPrivate *priv; - GList *walk; - UdpClientAddrInfo *client; - GInetAddress *inet; - - priv = stream->priv; - - if (destination == NULL) - return FALSE; - - inet = g_inet_address_new_from_string (destination); - if (inet == NULL) - goto invalid_address; - - if (!g_inet_address_get_is_multicast (inet)) { - g_object_unref (inet); - goto invalid_address; - } - g_object_unref (inet); - - for (walk = priv->mcast_clients; walk; walk = g_list_next (walk)) { - UdpClientAddrInfo *cli = walk->data; - - if ((g_strcmp0 (cli->address, destination) == 0) && - (cli->rtp_port == rtp_port)) { - GST_DEBUG ("requested destination already exists: %s:%u-%u", - destination, rtp_port, rtcp_port); - cli->add_count++; - return TRUE; - } - } - - client = g_new0 (UdpClientAddrInfo, 1); - client->address = g_strdup (destination); - client->rtp_port = rtp_port; - client->add_count = 1; - priv->mcast_clients = g_list_prepend (priv->mcast_clients, client); - - GST_DEBUG ("added mcast client %s:%u-%u", destination, rtp_port, rtcp_port); - - return TRUE; - -invalid_address: - { - GST_WARNING_OBJECT (stream, "Multicast address is invalid: %s", - destination); - return FALSE; - } -} - -/* must be called with lock */ -static gboolean -remove_mcast_client_addr (GstRTSPStream * stream, const gchar * destination, - guint rtp_port, guint rtcp_port) -{ - GstRTSPStreamPrivate *priv; - GList *walk; - - priv = stream->priv; - - if (destination == NULL) - goto no_destination; - - for (walk = priv->mcast_clients; walk; walk = g_list_next (walk)) { - UdpClientAddrInfo *cli = walk->data; - - if ((g_strcmp0 (cli->address, destination) == 0) && - (cli->rtp_port == rtp_port)) { - cli->add_count--; - - if (!cli->add_count) { - priv->mcast_clients = g_list_remove (priv->mcast_clients, cli); - free_mcast_client (cli); - } - return TRUE; - } - } - - GST_WARNING_OBJECT (stream, "Address not found"); - return FALSE; - -no_destination: - { - GST_WARNING_OBJECT (stream, "No destination has been provided"); - return FALSE; - } -} - - /** * gst_rtsp_stream_allocate_udp_sockets: * @stream: a #GstRTSPStream @@ -2126,29 +2006,6 @@ gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream * stream) return ttl; } -/** - * gst_rtsp_stream_verify_mcast_ttl: - * @stream: a #GstRTSPStream - * @ttl: a requested multicast ttl - * - * Check if the requested multicast ttl value is allowed. - * - * Returns: TRUE if the requested ttl value is allowed. - * - */ -gboolean -gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream * stream, guint ttl) -{ - gboolean res = FALSE; - - g_mutex_lock (&stream->priv->lock); - if ((ttl > 0) && (ttl <= stream->priv->max_mcast_ttl)) - res = TRUE; - g_mutex_unlock (&stream->priv->lock); - - return res; -} - /* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) @@ -3482,29 +3339,38 @@ udpsrc_error: } static gboolean -check_mcast_client_addr (GstRTSPStream * stream, const GstRTSPTransport * tr) +check_mcast_part_for_transport (GstRTSPStream * stream, + const GstRTSPTransport * tr) { GstRTSPStreamPrivate *priv = stream->priv; - GList *walk; + GInetAddress *inetaddr; + GSocketFamily family; + GstRTSPAddress *mcast_addr; - if (priv->mcast_clients == NULL) - goto no_addr; + /* Check if it's a ipv4 or ipv6 transport */ + inetaddr = g_inet_address_new_from_string (tr->destination); + family = g_inet_address_get_family (inetaddr); + g_object_unref (inetaddr); - if (tr == NULL) - goto no_transport; - - if (tr->destination == NULL) - goto no_destination; - - for (walk = priv->mcast_clients; walk; walk = g_list_next (walk)) { - UdpClientAddrInfo *cli = walk->data; - - if ((g_strcmp0 (cli->address, tr->destination) == 0) && - (cli->rtp_port == tr->port.min)) - return TRUE; + /* Select fields corresponding to the family */ + if (family == G_SOCKET_FAMILY_IPV4) { + mcast_addr = priv->mcast_addr_v4; + } else { + mcast_addr = priv->mcast_addr_v6; } - return FALSE; + /* We support only one mcast group per family, make sure this transport + * matches it. */ + if (!mcast_addr) + goto no_addr; + + if (g_ascii_strcasecmp (tr->destination, mcast_addr->address) != 0 || + tr->port.min != mcast_addr->port || + tr->port.max != mcast_addr->port + mcast_addr->n_ports - 1 || + tr->ttl != mcast_addr->ttl) + goto wrong_addr; + + return TRUE; no_addr: { @@ -3512,13 +3378,7 @@ no_addr: "has been reserved"); return FALSE; } -no_transport: - { - GST_WARNING_OBJECT (stream, "Adding mcast transport, but no transport " - "has been provided"); - return FALSE; - } -no_destination: +wrong_addr: { GST_WARNING_OBJECT (stream, "Adding mcast transport, but it doesn't match " "the reserved address"); @@ -4195,11 +4055,10 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, if (add) { GST_INFO ("adding %s:%d-%d", dest, min, max); - if (!check_mcast_client_addr (stream, tr)) + if (!check_mcast_part_for_transport (stream, tr)) goto mcast_error; - add_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min, - max); + /* FIXME: Is it ok to set ttl-mc if media is shared? */ if (tr->ttl > 0) { GST_INFO ("setting ttl-mc %d", tr->ttl); if (priv->mcast_udpsink[0]) @@ -4209,12 +4068,11 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, g_object_set (G_OBJECT (priv->mcast_udpsink[1]), "ttl-mc", tr->ttl, NULL); } + add_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min, + max); priv->transports = g_list_prepend (priv->transports, trans); } else { GST_INFO ("removing %s:%d-%d", dest, min, max); - if (!remove_mcast_client_addr (stream, dest, min, max)) - GST_WARNING_OBJECT (stream, - "Failed to remove multicast address: %s:%d-%d", dest, min, max); remove_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min, max); priv->transports = g_list_remove (priv->transports, trans); @@ -4564,95 +4422,6 @@ gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream * stream, return socket; } -/** - * gst_rtsp_stream_add_multicast_client_address: - * @stream: a #GstRTSPStream - * @destination: (transfer none): a multicast address to add - * @rtp_port: RTP port - * @rtcp_port: RTCP port - * @family: socket family - * - * Add multicast client address to stream. At this point, the sockets that - * will stream RTP and RTCP data to @destination are supposed to be - * allocated. - * - * Returns: %TRUE if @destination can be addedd and handled by @stream. - */ -gboolean -gst_rtsp_stream_add_multicast_client_address (GstRTSPStream * stream, - const gchar * destination, guint rtp_port, guint rtcp_port, - GSocketFamily family) -{ - GstRTSPStreamPrivate *priv; - - g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); - g_return_val_if_fail (destination != NULL, FALSE); - - priv = stream->priv; - g_mutex_lock (&priv->lock); - if ((family == G_SOCKET_FAMILY_IPV4) && (priv->mcast_socket_v4[0] == NULL)) - goto socket_error; - else if ((family == G_SOCKET_FAMILY_IPV6) && - (priv->mcast_socket_v6[0] == NULL)) - goto socket_error; - - if (!add_mcast_client_addr (stream, destination, rtp_port, rtcp_port)) - goto add_addr_error; - g_mutex_unlock (&priv->lock); - - return TRUE; - -socket_error: - { - GST_WARNING_OBJECT (stream, - "Failed to add multicast address: no udp socket"); - g_mutex_unlock (&priv->lock); - return FALSE; - } -add_addr_error: - { - GST_WARNING_OBJECT (stream, - "Failed to add multicast address: invalid address"); - g_mutex_unlock (&priv->lock); - return FALSE; - } -} - -/** - * gst_rtsp_stream_get_multicast_client_addresses - * @stream: a #GstRTSPStream - * - * Get all multicast client addresses that RTP data will be sent to - * - * Returns: A comma separated list of host:port pairs with destinations - */ -gchar * -gst_rtsp_stream_get_multicast_client_addresses (GstRTSPStream * stream) -{ - GstRTSPStreamPrivate *priv; - GString *str; - GList *clients; - - g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); - - priv = stream->priv; - str = g_string_new (""); - - g_mutex_lock (&priv->lock); - clients = priv->mcast_clients; - while (clients != NULL) { - UdpClientAddrInfo *client; - - client = (UdpClientAddrInfo *) clients->data; - clients = g_list_next (clients); - g_string_append_printf (str, "%s:%d%s", client->address, client->rtp_port, - (clients != NULL ? "," : "")); - } - g_mutex_unlock (&priv->lock); - - return g_string_free (str, FALSE); -} - /** * gst_rtsp_stream_set_seqnum: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 0c6804d536..1ee146dda7 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -233,16 +233,6 @@ GST_RTSP_SERVER_API GSocket * gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream *stream, GSocketFamily family); -GST_RTSP_SERVER_API -gboolean gst_rtsp_stream_add_multicast_client_address (GstRTSPStream * stream, - const gchar * destination, - guint rtp_port, - guint rtcp_port, - GSocketFamily family); - -GST_RTSP_SERVER_API -gchar * gst_rtsp_stream_get_multicast_client_addresses (GstRTSPStream * stream); - GST_RTSP_SERVER_API gboolean gst_rtsp_stream_update_crypto (GstRTSPStream * stream, guint ssrc, GstCaps * crypto); @@ -308,9 +298,6 @@ gboolean gst_rtsp_stream_set_max_mcast_ttl (GstRTSPStream *strea GST_RTSP_SERVER_API guint gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream *stream); -GST_RTSP_SERVER_API -gboolean gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream *stream, guint ttl); - GST_RTSP_SERVER_API gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GstRTSPTransport * transport); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index d890b8218b..d4fdd9ec1f 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -541,35 +541,6 @@ test_setup_response_200_multicast (GstRTSPClient * client, return TRUE; } -static gboolean -test_setup_response_461 (GstRTSPClient * client, - GstRTSPMessage * response, gboolean close, gpointer user_data) -{ - GstRTSPStatusCode code; - const gchar *reason; - GstRTSPVersion version; - gchar *str; - - fail_unless (expected_transport == NULL); - - fail_unless (gst_rtsp_message_get_type (response) == - GST_RTSP_MESSAGE_RESPONSE); - - fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, - &version) - == GST_RTSP_OK); - fail_unless (code == GST_RTSP_STS_UNSUPPORTED_TRANSPORT); - fail_unless (g_str_equal (reason, "Unsupported transport")); - fail_unless (version == GST_RTSP_VERSION_1_0); - - fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, - 0) == GST_RTSP_OK); - fail_unless (atoi (str) == cseq++); - - - return TRUE; -} - static gboolean test_teardown_response_200 (GstRTSPClient * client, GstRTSPMessage * response, gboolean close, gpointer user_data) @@ -613,7 +584,7 @@ send_teardown (GstRTSPClient * client) } static GstRTSPClient * -setup_multicast_client (guint max_ttl) +setup_multicast_client (void) { GstRTSPClient *client; GstRTSPSessionPool *session_pool; @@ -640,7 +611,6 @@ setup_multicast_client (guint max_ttl) "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); gst_rtsp_client_set_mount_points (client, mount_points); - gst_rtsp_media_factory_set_max_mcast_ttl (factory, max_ttl); thread_pool = gst_rtsp_thread_pool_new (); gst_rtsp_client_set_thread_pool (client, thread_pool); @@ -659,7 +629,7 @@ GST_START_TEST (test_client_multicast_transport_404) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (1); + client = setup_multicast_client (); /* simple SETUP for non-existing url */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, @@ -692,7 +662,7 @@ GST_START_TEST (test_client_multicast_transport) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (1); + client = setup_multicast_client (); expected_session_timeout = 20; g_signal_connect (G_OBJECT (client), "new-session", @@ -729,7 +699,7 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (1); + client = setup_multicast_client (); /* simple SETUP with a valid URI and multicast and a specific dest, * but ignore it */ @@ -765,7 +735,7 @@ multicast_transport_specific (void) GstRTSPSessionPool *session_pool; GstRTSPContext ctx = { NULL }; - client = setup_multicast_client (1); + client = setup_multicast_client (); ctx.client = client; ctx.auth = gst_rtsp_auth_new (); @@ -980,12 +950,9 @@ GST_START_TEST (test_client_sdp_with_no_bitrate_tags) GST_END_TEST; static void -mcast_transport_two_clients (gboolean shared, const gchar * transport1, - const gchar * expected_transport1, const gchar * addr1, - const gchar * transport2, const gchar * expected_transport2, - const gchar * addr2) +mcast_transport_specific_two_clients (gboolean shared) { - GstRTSPClient *client1, *client2; + GstRTSPClient *client, *client2; GstRTSPMessage request = { 0, }; gchar *str; GstRTSPSessionPool *session_pool; @@ -996,7 +963,6 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, GstRTSPAddressPool *address_pool; GstRTSPThreadPool *thread_pool; gchar *session_id1; - gchar *client_addr = NULL; mount_points = gst_rtsp_mount_points_new (); factory = gst_rtsp_media_factory_new (); @@ -1017,12 +983,12 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, thread_pool = gst_rtsp_thread_pool_new (); /* first multicast client with transport specific request */ - client1 = gst_rtsp_client_new (); - gst_rtsp_client_set_session_pool (client1, session_pool); - gst_rtsp_client_set_mount_points (client1, mount_points); - gst_rtsp_client_set_thread_pool (client1, thread_pool); + client = gst_rtsp_client_new (); + gst_rtsp_client_set_session_pool (client, session_pool); + gst_rtsp_client_set_mount_points (client, mount_points); + gst_rtsp_client_set_thread_pool (client, thread_pool); - ctx.client = client1; + ctx.client = client; ctx.auth = gst_rtsp_auth_new (); ctx.token = gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, @@ -1030,18 +996,20 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, "user", NULL); gst_rtsp_context_push_current (&ctx); - expected_transport = expected_transport1; + expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; /* send SETUP request */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport1); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + expected_transport); - gst_rtsp_client_set_send_func (client1, test_setup_response_200_multicast, + gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client1, + fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); expected_transport = NULL; @@ -1052,17 +1020,10 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); - gst_rtsp_client_set_send_func (client1, test_response_200, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client1, + gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - - /* check address */ - client_addr = gst_rtsp_stream_get_multicast_client_addresses (ctx.stream); - fail_if (client_addr == NULL); - fail_unless (g_str_equal (client_addr, addr1)); - g_free (client_addr); - gst_rtsp_context_pop_current (&ctx); session_id1 = session_id; @@ -1081,14 +1042,16 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, "user", NULL); gst_rtsp_context_push_current (&ctx2); - expected_transport = expected_transport2; + expected_transport = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; /* send SETUP request */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport2); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + expected_transport); gst_rtsp_client_set_send_func (client2, test_setup_response_200_multicast, NULL, NULL); @@ -1108,31 +1071,15 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - /* check addresses */ - client_addr = gst_rtsp_stream_get_multicast_client_addresses (ctx2.stream); - fail_if (client_addr == NULL); - if (shared) { - if (g_str_equal (addr1, addr2)) { - fail_unless (g_str_equal (client_addr, addr1)); - } else { - gchar *addr_str = g_strdup_printf ("%s,%s", addr2, addr1); - fail_unless (g_str_equal (client_addr, addr_str)); - g_free (addr_str); - } - } else { - fail_unless (g_str_equal (client_addr, addr2)); - } - g_free (client_addr); - send_teardown (client2); gst_rtsp_context_pop_current (&ctx2); gst_rtsp_context_push_current (&ctx); session_id = session_id1; - send_teardown (client1); + send_teardown (client); gst_rtsp_context_pop_current (&ctx); - teardown_client (client1); + teardown_client (client); teardown_client (client2); g_object_unref (ctx.auth); g_object_unref (ctx2.auth); @@ -1148,19 +1095,7 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, * CASE: media is shared */ GST_START_TEST (test_client_multicast_transport_specific_two_clients_shared_media) { - const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; - const gchar *expected_transport_1 = transport_client_1; - const gchar *addr_client_1 = "233.252.0.1:5000"; - - const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" - "ttl=1;port=5002-5003;mode=\"PLAY\""; - const gchar *expected_transport_2 = transport_client_2; - const gchar *addr_client_2 = "233.252.0.2:5002"; - - mcast_transport_two_clients (TRUE, transport_client_1, - expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); + mcast_transport_specific_two_clients (TRUE); } GST_END_TEST; @@ -1169,195 +1104,7 @@ GST_END_TEST; * CASE: media is not shared */ GST_START_TEST (test_client_multicast_transport_specific_two_clients) { - const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; - const gchar *expected_transport_1 = transport_client_1; - const gchar *addr_client_1 = "233.252.0.1:5000"; - - const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" - "ttl=1;port=5002-5003;mode=\"PLAY\""; - const gchar *expected_transport_2 = transport_client_2; - const gchar *addr_client_2 = "233.252.0.2:5002"; - - mcast_transport_two_clients (FALSE, transport_client_1, - expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); -} - -GST_END_TEST; - -/* test if two multicast clients can choose the same transport settings. - * CASE: media is shared */ -GST_START_TEST - (test_client_multicast_transport_specific_two_clients_shared_media_same_transport) -{ - - const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; - const gchar *expected_transport_1 = transport_client_1; - const gchar *addr_client_1 = "233.252.0.1:5000"; - - const gchar *transport_client_2 = transport_client_1; - const gchar *expected_transport_2 = expected_transport_1; - const gchar *addr_client_2 = addr_client_1; - - mcast_transport_two_clients (TRUE, transport_client_1, - expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); -} - -GST_END_TEST; - -/* test if two multicast clients get the same transport settings without - * requesting specific transport. - * CASE: media is shared */ -GST_START_TEST (test_client_multicast_two_clients_shared_media) -{ - const gchar *transport_client_1 = "RTP/AVP;multicast;mode=\"PLAY\""; - const gchar *expected_transport_1 = - "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; - const gchar *addr_client_1 = "233.252.0.1:5000"; - - const gchar *transport_client_2 = transport_client_1; - const gchar *expected_transport_2 = expected_transport_1; - const gchar *addr_client_2 = addr_client_1; - - mcast_transport_two_clients (TRUE, transport_client_1, - expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); -} - -GST_END_TEST; - -/* test if two multicast clients get the different transport settings: the first client - * requests the specific transport configuration while the second client lets - * the server select the multicast address and the ports. - * CASE: media is shared */ -GST_START_TEST - (test_client_multicast_two_clients_first_specific_transport_shared_media) { - const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; - const gchar *expected_transport_1 = transport_client_1; - const gchar *addr_client_1 = "233.252.0.1:5000"; - - const gchar *transport_client_2 = "RTP/AVP;multicast;mode=\"PLAY\""; - const gchar *expected_transport_2 = expected_transport_1; - const gchar *addr_client_2 = addr_client_1; - - mcast_transport_two_clients (TRUE, transport_client_1, - expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); -} - -GST_END_TEST; -/* test if two multicast clients get the different transport settings: the first client lets - * the server select the multicast address and the ports while the second client requests - * the specific transport configuration. - * CASE: media is shared */ -GST_START_TEST - (test_client_multicast_two_clients_second_specific_transport_shared_media) { - const gchar *transport_client_1 = "RTP/AVP;multicast;mode=\"PLAY\""; - const gchar *expected_transport_1 = - "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; - const gchar *addr_client_1 = "233.252.0.1:5000"; - - const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" - "ttl=2;port=5004-5005;mode=\"PLAY\""; - const gchar *expected_transport_2 = transport_client_2; - const gchar *addr_client_2 = "233.252.0.2:5004"; - - mcast_transport_two_clients (TRUE, transport_client_1, - expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); -} - -GST_END_TEST; - -/* test if the maximum ttl multicast value is chosen by the server - * CASE: the first client provides the highest ttl value */ -GST_START_TEST (test_client_multicast_max_ttl_first_client) -{ - const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=3;port=5000-5001;mode=\"PLAY\""; - const gchar *expected_transport_1 = transport_client_1; - const gchar *addr_client_1 = "233.252.0.1:5000"; - - const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" - "ttl=1;port=5002-5003;mode=\"PLAY\""; - const gchar *expected_transport_2 = - "RTP/AVP;multicast;destination=233.252.0.2;" - "ttl=3;port=5002-5003;mode=\"PLAY\""; - const gchar *addr_client_2 = "233.252.0.2:5002"; - - mcast_transport_two_clients (TRUE, transport_client_1, - expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); -} - -GST_END_TEST; - -/* test if the maximum ttl multicast value is chosen by the server - * CASE: the second client provides the highest ttl value */ -GST_START_TEST (test_client_multicast_max_ttl_second_client) -{ - const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=2;port=5000-5001;mode=\"PLAY\""; - const gchar *expected_transport_1 = transport_client_1; - const gchar *addr_client_1 = "233.252.0.1:5000"; - - const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" - "ttl=4;port=5002-5003;mode=\"PLAY\""; - const gchar *expected_transport_2 = transport_client_2; - const gchar *addr_client_2 = "233.252.0.2:5002"; - - mcast_transport_two_clients (TRUE, transport_client_1, - expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); -} - -GST_END_TEST; -GST_START_TEST (test_client_multicast_invalid_ttl) -{ - GstRTSPClient *client; - GstRTSPMessage request = { 0, }; - gchar *str; - GstRTSPSessionPool *session_pool; - GstRTSPContext ctx = { NULL }; - - client = setup_multicast_client (3); - - ctx.client = client; - ctx.auth = gst_rtsp_auth_new (); - ctx.token = - gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, - G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, - "user", NULL); - gst_rtsp_context_push_current (&ctx); - - /* simple SETUP with an invalid ttl=0 */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=0") == GST_RTSP_OK); - str = g_strdup_printf ("%d", cseq); - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - "RTP/AVP;multicast;destination=233.252.0.1;ttl=0;port=5000-5001;"); - - gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, - &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); - - session_pool = gst_rtsp_client_get_session_pool (client); - fail_unless (session_pool != NULL); - fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); - g_object_unref (session_pool); - - teardown_client (client); - g_object_unref (ctx.auth); - gst_rtsp_token_unref (ctx.token); - gst_rtsp_context_pop_current (&ctx); + mcast_transport_specific_two_clients (FALSE); } GST_END_TEST; @@ -1385,18 +1132,8 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_transport_specific_two_clients_shared_media); tcase_add_test (tc, test_client_multicast_transport_specific_two_clients); - tcase_add_test (tc, - test_client_multicast_transport_specific_two_clients_shared_media_same_transport); - tcase_add_test (tc, test_client_multicast_two_clients_shared_media); - tcase_add_test (tc, - test_client_multicast_two_clients_first_specific_transport_shared_media); - tcase_add_test (tc, - test_client_multicast_two_clients_second_specific_transport_shared_media); tcase_add_test (tc, test_client_multicast_transport_specific_no_address_in_pool); - tcase_add_test (tc, test_client_multicast_max_ttl_first_client); - tcase_add_test (tc, test_client_multicast_max_ttl_second_client); - tcase_add_test (tc, test_client_multicast_invalid_ttl); return s; } diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index d71f1937f4..7b59c0abc9 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -486,95 +486,6 @@ GST_START_TEST (test_tcp_transport) GST_END_TEST; -static void -check_multicast_client_address (const gchar * destination, guint port, - const gchar * expected_addr_str, gboolean expected_res) -{ - GstPad *srcpad; - GstElement *pay; - GstRTSPStream *stream; - GstBin *bin; - GstElement *rtpbin; - GstRTSPTransport *transport; - GstRTSPRange ports = { 0 }; - gchar *addr_str = NULL; - - srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); - fail_unless (srcpad != NULL); - gst_pad_set_active (srcpad, TRUE); - pay = gst_element_factory_make ("rtpgstpay", "testpayloader"); - fail_unless (pay != NULL); - stream = gst_rtsp_stream_new (0, pay, srcpad); - fail_unless (stream != NULL); - gst_object_unref (pay); - gst_object_unref (srcpad); - rtpbin = gst_element_factory_make ("rtpbin", "testrtpbin"); - fail_unless (rtpbin != NULL); - bin = GST_BIN (gst_bin_new ("testbin")); - fail_unless (bin != NULL); - fail_unless (gst_bin_add (bin, rtpbin)); - - fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); - - fail_unless (gst_rtsp_transport_new (&transport) == GST_RTSP_OK); - transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST; - transport->destination = g_strdup (destination); - transport->ttl = 1; - ports.min = port; - ports.max = port + 1; - transport->port = ports; - - /* allocate ports */ - fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, - G_SOCKET_FAMILY_IPV4, transport, TRUE) == expected_res); - - fail_unless (gst_rtsp_stream_add_multicast_client_address (stream, - destination, ports.min, ports.max, - G_SOCKET_FAMILY_IPV4) == expected_res); - - fail_unless (gst_rtsp_stream_complete_stream (stream, - transport) == expected_res); - - fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK); - addr_str = gst_rtsp_stream_get_multicast_client_addresses (stream); - - fail_unless (g_str_equal (addr_str, expected_addr_str)); - g_free (addr_str); - - fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); - - gst_object_unref (bin); - gst_object_unref (stream); -} - -/* test if the provided transport destination is correct. - * CASE: valid multicast address */ -GST_START_TEST (test_multicast_client_address) -{ - const gchar *addr = "233.252.0.1"; - guint port = 50000; - const gchar *expected_addr_str = "233.252.0.1:50000"; - gboolean expected_res = TRUE; - - check_multicast_client_address (addr, port, expected_addr_str, expected_res); -} - -GST_END_TEST; - -/* test if the provided transport destination is correct. - * CASE: invalid multicast address */ -GST_START_TEST (test_multicast_client_address_invalid) -{ - const gchar *addr = "1.2.3.4"; - guint port = 50000; - const gchar *expected_addr_str = ""; - gboolean expected_res = FALSE; - - check_multicast_client_address (addr, port, expected_addr_str, expected_res); -} - -GST_END_TEST; - static Suite * rtspstream_suite (void) { @@ -590,8 +501,6 @@ rtspstream_suite (void) tcase_add_test (tc, test_allocate_udp_ports_multicast); tcase_add_test (tc, test_allocate_udp_ports_client_settings); tcase_add_test (tc, test_tcp_transport); - tcase_add_test (tc, test_multicast_client_address); - tcase_add_test (tc, test_multicast_client_address_invalid); return s; } From 17335e99061b6f24fcddc78d1f8b4f0bd13cd5c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 14 Aug 2018 14:25:37 +0300 Subject: [PATCH 1538/1776] Revert "rtsp-stream: Don't require address pool in the transport specific case" This reverts commit a9db3e7f092cfeb5475e9aa24b1e91906c141d52. Commits where accidentially squashed together --- gst/rtsp-server/rtsp-stream.c | 173 ++++++++++------------------------ tests/check/gst/client.c | 51 +--------- 2 files changed, 55 insertions(+), 169 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 0d17718d9d..1a68fd5b13 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1326,11 +1326,11 @@ error: static gboolean alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GSocket * socket_out[2], GstRTSPAddress ** server_addr_out, - gboolean multicast, GstRTSPTransport * ct, gboolean use_transport_settings) + gboolean multicast, GstRTSPTransport * ct) { GstRTSPStreamPrivate *priv = stream->priv; GSocket *rtp_socket = NULL; - GSocket *rtcp_socket = NULL; + GSocket *rtcp_socket; gint tmp_rtp, tmp_rtcp; guint count; GList *rejected_addresses = NULL; @@ -1339,7 +1339,6 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GSocketAddress *rtp_sockaddr = NULL; GSocketAddress *rtcp_sockaddr = NULL; GstRTSPAddressPool *pool; - gboolean transport_settings_defined = FALSE; pool = priv->pool; count = 0; @@ -1347,30 +1346,6 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, /* Start with random port */ tmp_rtp = 0; - if (use_transport_settings) { - if (!multicast) - goto no_mcast; - - if (ct == NULL) - goto no_transport; - - /* multicast and transport specific case */ - if (ct->destination != NULL) { - tmp_rtp = ct->port.min; - tmp_rtcp = ct->port.max; - inetaddr = g_inet_address_new_from_string (ct->destination); - if (inetaddr == NULL) - goto destination_error; - if (!g_inet_address_get_is_multicast (inetaddr)) - goto destination_no_mcast; - g_object_unref (inetaddr); - inetaddr = g_inet_address_new_any (family); - - GST_DEBUG_OBJECT (stream, "use transport settings"); - transport_settings_defined = TRUE; - } - } - rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, NULL); if (!rtcp_socket) @@ -1389,60 +1364,55 @@ again: g_socket_set_multicast_loopback (rtp_socket, FALSE); } - if (!transport_settings_defined) { - if ((pool && gst_rtsp_address_pool_has_unicast_addresses (pool)) - || multicast) { - GstRTSPAddressFlags flags; + if ((pool && gst_rtsp_address_pool_has_unicast_addresses (pool)) || multicast) { + GstRTSPAddressFlags flags; - if (addr) - rejected_addresses = g_list_prepend (rejected_addresses, addr); + if (addr) + rejected_addresses = g_list_prepend (rejected_addresses, addr); - if (!pool) - goto no_pool; + if (!pool) + goto no_pool; - flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT; - if (multicast) - flags |= GST_RTSP_ADDRESS_FLAG_MULTICAST; - else - flags |= GST_RTSP_ADDRESS_FLAG_UNICAST; + flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT; + if (multicast) + flags |= GST_RTSP_ADDRESS_FLAG_MULTICAST; + else + flags |= GST_RTSP_ADDRESS_FLAG_UNICAST; - if (family == G_SOCKET_FAMILY_IPV6) - flags |= GST_RTSP_ADDRESS_FLAG_IPV6; - else - flags |= GST_RTSP_ADDRESS_FLAG_IPV4; + if (family == G_SOCKET_FAMILY_IPV6) + flags |= GST_RTSP_ADDRESS_FLAG_IPV6; + else + flags |= GST_RTSP_ADDRESS_FLAG_IPV4; - addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); + addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); - if (addr == NULL) - goto no_address; + if (addr == NULL) + goto no_address; - tmp_rtp = addr->port; + tmp_rtp = addr->port; - g_clear_object (&inetaddr); - /* FIXME: Does it really work with the IP_MULTICAST_ALL socket option and - * socket control message set in udpsrc? */ - if (multicast) - inetaddr = g_inet_address_new_any (family); - else - inetaddr = g_inet_address_new_from_string (addr->address); - } else { - if (tmp_rtp != 0) { - tmp_rtp += 2; - if (++count > 20) - goto no_ports; - } - - if (inetaddr == NULL) - inetaddr = g_inet_address_new_any (family); + g_clear_object (&inetaddr); + /* FIXME: Does it really work with the IP_MULTICAST_ALL socket option and + * socket control message set in udpsrc? */ + if (multicast) + inetaddr = g_inet_address_new_any (family); + else + inetaddr = g_inet_address_new_from_string (addr->address); + } else { + if (tmp_rtp != 0) { + tmp_rtp += 2; + if (++count > 20) + goto no_ports; } + + if (inetaddr == NULL) + inetaddr = g_inet_address_new_any (family); } rtp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtp); if (!g_socket_bind (rtp_socket, rtp_sockaddr, FALSE, NULL)) { GST_DEBUG_OBJECT (stream, "rtp bind() failed, will try again"); g_object_unref (rtp_sockaddr); - if (transport_settings_defined) - goto transport_settings_error; goto again; } g_object_unref (rtp_sockaddr); @@ -1453,23 +1423,18 @@ again: goto socket_error; } - if (!transport_settings_defined) { - tmp_rtp = - g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (rtp_sockaddr)); - - /* check if port is even. RFC 3550 encorages the use of an even/odd port - * pair, however it's not a strict requirement so this check is not done - * for the client selected ports. */ - if ((tmp_rtp & 1) != 0) { - /* port not even, close and allocate another */ - tmp_rtp++; - g_object_unref (rtp_sockaddr); - g_clear_object (&rtp_socket); - goto again; - } - } + tmp_rtp = + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (rtp_sockaddr)); g_object_unref (rtp_sockaddr); + /* check if port is even */ + if ((tmp_rtp & 1) != 0) { + /* port not even, close and allocate another */ + tmp_rtp++; + g_clear_object (&rtp_socket); + goto again; + } + /* set port */ tmp_rtcp = tmp_rtp + 1; @@ -1478,21 +1443,15 @@ again: GST_DEBUG_OBJECT (stream, "rctp bind() failed, will try again"); g_object_unref (rtcp_sockaddr); g_clear_object (&rtp_socket); - if (transport_settings_defined) - goto transport_settings_error; goto again; } g_object_unref (rtcp_sockaddr); if (!addr) { addr = g_slice_new0 (GstRTSPAddress); + addr->address = g_inet_address_to_string (inetaddr); addr->port = tmp_rtp; addr->n_ports = 2; - if (transport_settings_defined) - addr->address = g_strdup (ct->destination); - else - addr->address = g_inet_address_to_string (inetaddr); - addr->ttl = ct->ttl; } g_clear_object (&inetaddr); @@ -1509,28 +1468,6 @@ again: return TRUE; /* ERRORS */ -no_mcast: - { - GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: wrong transport"); - goto cleanup; - } -no_transport: - { - GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: no transport"); - goto cleanup; - } -destination_error: - { - GST_ERROR_OBJECT (stream, - "failed to allocate UDP ports: destination error"); - goto cleanup; - } -destination_no_mcast: - { - GST_ERROR_OBJECT (stream, - "failed to allocate UDP ports: destination not multicast address"); - goto cleanup; - } no_udp_protocol: { GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: protocol error"); @@ -1552,12 +1489,6 @@ no_ports: GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: no ports"); goto cleanup; } -transport_settings_error: - { - GST_ERROR_OBJECT (stream, - "failed to allocate UDP ports with requested transport settings"); - goto cleanup; - } socket_error: { GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: socket error"); @@ -1632,13 +1563,12 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, /* UDP unicast */ GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_UDP, ipv4"); ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, - priv->socket_v4, &priv->server_addr_v4, FALSE, ct, FALSE); + priv->socket_v4, &priv->server_addr_v4, FALSE, ct); } else { /* multicast */ GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_MCAST_UDP, ipv4"); ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, - priv->mcast_socket_v4, &priv->mcast_addr_v4, TRUE, ct, - use_transport_settings); + priv->mcast_socket_v4, &priv->mcast_addr_v4, TRUE, ct); } } else { /* IPv6 */ @@ -1646,14 +1576,13 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, /* unicast */ GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_UDP, ipv6"); ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, - priv->socket_v6, &priv->server_addr_v6, FALSE, ct, FALSE); + priv->socket_v6, &priv->server_addr_v6, FALSE, ct); } else { /* multicast */ GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_MCAST_UDP, ipv6"); ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, - priv->mcast_socket_v6, &priv->mcast_addr_v6, TRUE, ct, - use_transport_settings); + priv->mcast_socket_v6, &priv->mcast_addr_v6, TRUE, ct); } } g_mutex_unlock (&priv->lock); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index d4fdd9ec1f..ab95509f93 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -726,8 +726,7 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GST_END_TEST; -static void -multicast_transport_specific (void) +GST_START_TEST (test_client_multicast_transport_specific) { GstRTSPClient *client; GstRTSPMessage request = { 0, }; @@ -761,6 +760,7 @@ multicast_transport_specific (void) fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); + expected_transport = NULL; gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, NULL, NULL); @@ -769,44 +769,14 @@ multicast_transport_specific (void) fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 1); g_object_unref (session_pool); - /* send PLAY request */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, - "rtsp://localhost/test") == GST_RTSP_OK); - str = g_strdup_printf ("%d", cseq); - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); - gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, - &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); - send_teardown (client); + teardown_client (client); g_object_unref (ctx.auth); gst_rtsp_token_unref (ctx.token); gst_rtsp_context_pop_current (&ctx); } -/* CASE: multicast address requested by the client exists in the address pool */ -GST_START_TEST (test_client_multicast_transport_specific) -{ - expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; - multicast_transport_specific (); - expected_transport = NULL; -} - -GST_END_TEST; - -/* CASE: multicast address requested by the client does not exist in the address pool */ -GST_START_TEST (test_client_multicast_transport_specific_no_address_in_pool) -{ - expected_transport = "RTP/AVP;multicast;destination=234.252.0.3;" - "ttl=1;port=6000-6001;mode=\"PLAY\""; - multicast_transport_specific (); - expected_transport = NULL; -} - GST_END_TEST; static gboolean @@ -1091,8 +1061,7 @@ mcast_transport_specific_two_clients (gboolean shared) g_object_unref (thread_pool); } -/* test if two multicast clients can choose different transport settings - * CASE: media is shared */ +/* test if two multicast clients can choose different transport settings */ GST_START_TEST (test_client_multicast_transport_specific_two_clients_shared_media) { mcast_transport_specific_two_clients (TRUE); @@ -1100,15 +1069,6 @@ GST_START_TEST GST_END_TEST; -/* test if two multicast clients can choose different transport settings - * CASE: media is not shared */ -GST_START_TEST (test_client_multicast_transport_specific_two_clients) -{ - mcast_transport_specific_two_clients (FALSE); -} - -GST_END_TEST; - static Suite * rtspclient_suite (void) { @@ -1131,9 +1091,6 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_sdp_with_no_bitrate_tags); tcase_add_test (tc, test_client_multicast_transport_specific_two_clients_shared_media); - tcase_add_test (tc, test_client_multicast_transport_specific_two_clients); - tcase_add_test (tc, - test_client_multicast_transport_specific_no_address_in_pool); return s; } From 443c2b73e5526999a424a96950e14828fdced591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 14 Aug 2018 14:25:42 +0300 Subject: [PATCH 1539/1776] Revert "Add new API for setting/getting maximum multicast ttl value" This reverts commit 7f0ae77e400fb8a0462a76a5dd2e63e12c4a2e52. Commits where accidentially squashed together --- gst/rtsp-server/rtsp-client.c | 30 +-- gst/rtsp-server/rtsp-media-factory.c | 75 -------- gst/rtsp-server/rtsp-media-factory.h | 7 - gst/rtsp-server/rtsp-media.c | 81 -------- gst/rtsp-server/rtsp-media.h | 6 - gst/rtsp-server/rtsp-stream.c | 51 ----- gst/rtsp-server/rtsp-stream.h | 6 - tests/check/gst/client.c | 267 ++++++++++++--------------- tests/check/gst/mediafactory.c | 58 ------ 9 files changed, 129 insertions(+), 452 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8f39ccd6fb..92135f24e2 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1981,27 +1981,26 @@ default_configure_client_transport (GstRTSPClient * client, */ /* FIXME: could be more adequately solved by making it possible * to set a socket on multiudpsink after it has already been started */ - if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, - G_SOCKET_FAMILY_IPV4, ct, use_client_settings) - && family == G_SOCKET_FAMILY_IPV4) + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, G_SOCKET_FAMILY_IPV4, ct, + use_client_settings) && family == G_SOCKET_FAMILY_IPV4) goto error_allocating_ports; - if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, - G_SOCKET_FAMILY_IPV6, ct, use_client_settings) - && family == G_SOCKET_FAMILY_IPV6) + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, G_SOCKET_FAMILY_IPV6, ct, + use_client_settings) && family == G_SOCKET_FAMILY_IPV6) goto error_allocating_ports; if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - /* FIXME: the address has been successfully allocated, however, in - * the use_client_settings case we need to verify that the allocated - * address is the one requested by the client and if this address is - * an allowed destination. Verifying this via the address pool in not - * the proper way as the address pool should only be used for choosing - * the server-selected address/port pairs. */ + GstRTSPAddress *addr = NULL; - if (!use_client_settings) { - GstRTSPAddress *addr = NULL; + if (use_client_settings) { + /* the address has been successfully allocated, let's check if it's + * the one requested by the client */ + addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination, + ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl); + if (addr == NULL) + goto no_address; + } else { g_free (ct->destination); addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family); if (addr == NULL) @@ -2010,8 +2009,9 @@ default_configure_client_transport (GstRTSPClient * client, ct->port.min = addr->port; ct->port.max = addr->port + addr->n_ports - 1; ct->ttl = addr->ttl; - gst_rtsp_address_free (addr); } + + gst_rtsp_address_free (addr); } else { GstRTSPUrl *url; diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 53bce3ea1e..a4f10ddeaf 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -59,7 +59,6 @@ struct _GstRTSPMediaFactoryPrivate GstRTSPTransportMode transport_mode; gboolean stop_on_disconnect; gchar *multicast_iface; - guint max_mcast_ttl; GstClockTime rtx_time; guint latency; @@ -84,7 +83,6 @@ struct _GstRTSPMediaFactoryPrivate GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_LATENCY 200 -#define DEFAULT_MAX_MCAST_TTL 255 #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE #define DEFAULT_DO_RETRANSMISSION FALSE @@ -103,7 +101,6 @@ enum PROP_TRANSPORT_MODE, PROP_STOP_ON_DISCONNECT, PROP_CLOCK, - PROP_MAX_MCAST_TTL, PROP_LAST }; @@ -225,12 +222,6 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "medias of this factory", GST_TYPE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_MAX_MCAST_TTL, - g_param_spec_uint ("max-mcast-ttl", "Maximum multicast ttl", - "The maximum time-to-live value of outgoing multicast packets", 1, - 255, DEFAULT_MAX_MCAST_TTL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, @@ -272,7 +263,6 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; - priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; g_mutex_init (&priv->lock); g_mutex_init (&priv->medias_lock); @@ -347,9 +337,6 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, case PROP_CLOCK: g_value_take_object (value, gst_rtsp_media_factory_get_clock (factory)); break; - case PROP_MAX_MCAST_TTL: - g_value_set_uint (value, - gst_rtsp_media_factory_get_max_mcast_ttl (factory)); default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -400,9 +387,6 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, case PROP_CLOCK: gst_rtsp_media_factory_set_clock (factory, g_value_get_object (value)); break; - case PROP_MAX_MCAST_TTL: - gst_rtsp_media_factory_set_max_mcast_ttl (factory, - g_value_get_uint (value)); default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1479,62 +1463,6 @@ gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory) return ret; } -/** - * gst_rtsp_media_factory_set_max_mcast_ttl: - * @factory: a #GstRTSPMedia - * @ttl: the new multicast ttl value - * - * Set the maximum time-to-live value of outgoing multicast packets. - * - * Returns: %TRUE if the requested ttl has been set successfully. - */ -gboolean -gst_rtsp_media_factory_set_max_mcast_ttl (GstRTSPMediaFactory * factory, - guint ttl) -{ - GstRTSPMediaFactoryPrivate *priv; - - g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); - - priv = factory->priv; - - GST_RTSP_MEDIA_FACTORY_LOCK (factory); - if (ttl == 0 || ttl > DEFAULT_MAX_MCAST_TTL) { - GST_WARNING_OBJECT (factory, "The requested mcast TTL value is not valid."); - GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); - return FALSE; - } - priv->max_mcast_ttl = ttl; - GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); - - return TRUE; -} - -/** - * gst_rtsp_media_factory_get_max_mcast_ttl: - * @factory: a #GstRTSPMedia - * - * Get the the maximum time-to-live value of outgoing multicast packets. - * - * Returns: the maximum time-to-live value of outgoing multicast packets. - */ -guint -gst_rtsp_media_factory_get_max_mcast_ttl (GstRTSPMediaFactory * factory) -{ - GstRTSPMediaFactoryPrivate *priv; - guint result; - - g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0); - - priv = factory->priv; - - GST_RTSP_MEDIA_FACTORY_LOCK (factory); - result = priv->max_mcast_ttl; - GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); - - return result; -} - static gchar * default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { @@ -1685,7 +1613,6 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstClock *clock; gchar *multicast_iface; GstRTSPPublishClockMode publish_clock_mode; - guint ttl; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -1701,7 +1628,6 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) stop_on_disconnect = priv->stop_on_disconnect; clock = priv->clock ? gst_object_ref (priv->clock) : NULL; publish_clock_mode = priv->publish_clock_mode; - ttl = priv->max_mcast_ttl; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_suspend_mode (media, suspend_mode); @@ -1716,7 +1642,6 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_transport_mode (media, transport_mode); gst_rtsp_media_set_stop_on_disconnect (media, stop_on_disconnect); gst_rtsp_media_set_publish_clock_mode (media, publish_clock_mode); - gst_rtsp_media_set_max_mcast_ttl (media, ttl); if (clock) { gst_rtsp_media_set_clock (media, clock); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 46d7d5515e..7fb7fccde8 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -239,13 +239,6 @@ void gst_rtsp_media_factory_set_publish_clock_mode (GstRTSPMe GST_RTSP_SERVER_API GstRTSPPublishClockMode gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory); -GST_RTSP_SERVER_API -gboolean gst_rtsp_media_factory_set_max_mcast_ttl (GstRTSPMediaFactory * factory, - guint ttl); - -GST_RTSP_SERVER_API -guint gst_rtsp_media_factory_get_max_mcast_ttl (GstRTSPMediaFactory * factory); - /* creating the media from the factory and a url */ GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1073b89bce..f23b4c5d46 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -98,7 +98,6 @@ struct _GstRTSPMediaPrivate guint buffer_size; GstRTSPAddressPool *pool; gchar *multicast_iface; - guint max_mcast_ttl; gboolean blocked; GstRTSPTransportMode transport_mode; gboolean stop_on_disconnect; @@ -159,7 +158,6 @@ struct _GstRTSPMediaPrivate #define DEFAULT_LATENCY 200 #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE -#define DEFAULT_MAX_MCAST_TTL 255 #define DEFAULT_DO_RETRANSMISSION FALSE @@ -182,7 +180,6 @@ enum PROP_TRANSPORT_MODE, PROP_STOP_ON_DISCONNECT, PROP_CLOCK, - PROP_MAX_MCAST_TTL, PROP_LAST }; @@ -378,12 +375,6 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "Clock to be used by the media pipeline", GST_TYPE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_MAX_MCAST_TTL, - g_param_spec_uint ("max-mcast-ttl", "Maximum multicast ttl", - "The maximum time-to-live value of outgoing multicast packets", 1, - 255, DEFAULT_MAX_MCAST_TTL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, @@ -454,7 +445,6 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; - priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; } static void @@ -541,9 +531,6 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_CLOCK: g_value_take_object (value, gst_rtsp_media_get_clock (media)); break; - case PROP_MAX_MCAST_TTL: - g_value_set_uint (value, gst_rtsp_media_get_max_mcast_ttl (media)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -597,9 +584,6 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_CLOCK: gst_rtsp_media_set_clock (media, g_value_get_object (value)); break; - case PROP_MAX_MCAST_TTL: - gst_rtsp_media_set_max_mcast_ttl (media, g_value_get_uint (value)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1839,70 +1823,6 @@ gst_rtsp_media_get_multicast_iface (GstRTSPMedia * media) return result; } -/** - * gst_rtsp_media_set_max_mcast_ttl: - * @media: a #GstRTSPMedia - * @ttl: the new multicast ttl value - * - * Set the maximum time-to-live value of outgoing multicast packets. - * - * Returns: %TRUE if the requested ttl has been set successfully. - */ -gboolean -gst_rtsp_media_set_max_mcast_ttl (GstRTSPMedia * media, guint ttl) -{ - GstRTSPMediaPrivate *priv; - guint i; - - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - - GST_LOG_OBJECT (media, "set max mcast ttl %u", ttl); - - priv = media->priv; - - g_mutex_lock (&priv->lock); - - if (ttl == 0 || ttl > DEFAULT_MAX_MCAST_TTL) { - GST_WARNING_OBJECT (media, "The reqested mcast TTL value is not valid."); - g_mutex_unlock (&priv->lock); - return FALSE; - } - priv->max_mcast_ttl = ttl; - - for (i = 0; i < priv->streams->len; i++) { - GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); - gst_rtsp_stream_set_max_mcast_ttl (stream, ttl); - } - g_mutex_unlock (&priv->lock); - - return TRUE; -} - -/** - * gst_rtsp_media_get_max_mcast_ttl: - * @media: a #GstRTSPMedia - * - * Get the the maximum time-to-live value of outgoing multicast packets. - * - * Returns: the maximum time-to-live value of outgoing multicast packets. - */ -guint -gst_rtsp_media_get_max_mcast_ttl (GstRTSPMedia * media) -{ - GstRTSPMediaPrivate *priv; - guint res; - - g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - - priv = media->priv; - - g_mutex_lock (&priv->lock); - res = priv->max_mcast_ttl; - g_mutex_unlock (&priv->lock); - - return res; -} - static GList * _find_payload_types (GstRTSPMedia * media) { @@ -2220,7 +2140,6 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, if (priv->pool) gst_rtsp_stream_set_address_pool (stream, priv->pool); gst_rtsp_stream_set_multicast_iface (stream, priv->multicast_iface); - gst_rtsp_stream_set_max_mcast_ttl (stream, priv->max_mcast_ttl); gst_rtsp_stream_set_profiles (stream, priv->profiles); gst_rtsp_stream_set_protocols (stream, priv->protocols); gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 92b3866a94..84dfb14591 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -314,12 +314,6 @@ void gst_rtsp_media_set_publish_clock_mode (GstRTSPMedia * me GST_RTSP_SERVER_API GstRTSPPublishClockMode gst_rtsp_media_get_publish_clock_mode (GstRTSPMedia * media); -GST_RTSP_SERVER_API -gboolean gst_rtsp_media_set_max_mcast_ttl (GstRTSPMedia *media, guint ttl); - -GST_RTSP_SERVER_API -guint gst_rtsp_media_get_max_mcast_ttl (GstRTSPMedia *media); - /* prepare the media for playback */ GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 1a68fd5b13..b95ead95a1 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -145,7 +145,6 @@ struct _GstRTSPStreamPrivate GstRTSPAddress *mcast_addr_v6; gchar *multicast_iface; - guint max_mcast_ttl; /* the caps of the stream */ gulong caps_sig; @@ -182,7 +181,6 @@ struct _GstRTSPStreamPrivate #define DEFAULT_PROFILES GST_RTSP_PROFILE_AVP #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ GST_RTSP_LOWER_TRANS_TCP -#define DEFAULT_MAX_MCAST_TTL 255 enum { @@ -282,7 +280,6 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->allowed_protocols = DEFAULT_PROTOCOLS; priv->configured_protocols = 0; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; - priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; g_mutex_init (&priv->lock); @@ -1887,54 +1884,6 @@ gst_rtsp_stream_get_buffer_size (GstRTSPStream * stream) return buffer_size; } -/** - * gst_rtsp_stream_set_max_mcast_ttl: - * @stream: a #GstRTSPStream - * @ttl: the new multicast ttl value - * - * Set the maximum time-to-live value of outgoing multicast packets. - * - * Returns: %TRUE if the requested ttl has been set successfully. - * - */ -gboolean -gst_rtsp_stream_set_max_mcast_ttl (GstRTSPStream * stream, guint ttl) -{ - g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); - - g_mutex_lock (&stream->priv->lock); - if (ttl == 0 || ttl > DEFAULT_MAX_MCAST_TTL) { - GST_WARNING_OBJECT (stream, "The reqested mcast TTL value is not valid."); - g_mutex_unlock (&stream->priv->lock); - return FALSE; - } - stream->priv->max_mcast_ttl = ttl; - g_mutex_unlock (&stream->priv->lock); - - return TRUE; -} - -/** - * gst_rtsp_stream_get_max_mcast_ttl: - * @stream: a #GstRTSPStream - * - * Get the the maximum time-to-live value of outgoing multicast packets. - * - * Returns: the maximum time-to-live value of outgoing multicast packets. - * - */ -guint -gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream * stream) -{ - guint ttl; - - g_mutex_lock (&stream->priv->lock); - ttl = stream->priv->max_mcast_ttl; - g_mutex_unlock (&stream->priv->lock); - - return ttl; -} - /* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 1ee146dda7..1f527a462d 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -292,12 +292,6 @@ void gst_rtsp_stream_set_publish_clock_mode (GstRTSPStream * GST_RTSP_SERVER_API GstRTSPPublishClockMode gst_rtsp_stream_get_publish_clock_mode (GstRTSPStream * stream); -GST_RTSP_SERVER_API -gboolean gst_rtsp_stream_set_max_mcast_ttl (GstRTSPStream *stream, guint ttl); - -GST_RTSP_SERVER_API -guint gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream *stream); - GST_RTSP_SERVER_API gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GstRTSPTransport * transport); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index ab95509f93..4adf3d18c9 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -525,6 +525,7 @@ test_setup_response_200_multicast (GstRTSPClient * client, session_pool = gst_rtsp_client_get_session_pool (client); fail_unless (session_pool != NULL); + fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 1); session = gst_rtsp_session_pool_find (session_pool, session_hdr_params[0]); g_strfreev (session_hdr_params); @@ -726,6 +727,117 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GST_END_TEST; +static gboolean +test_setup_response_461 (GstRTSPClient * client, + GstRTSPMessage * response, gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + gchar *str; + + fail_unless (expected_transport == NULL); + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_UNSUPPORTED_TRANSPORT); + fail_unless (g_str_equal (reason, "Unsupported transport")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, + 0) == GST_RTSP_OK); + fail_unless (atoi (str) == cseq++); + + + return TRUE; +} + +GST_START_TEST (test_client_multicast_invalid_transport_specific) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + GstRTSPSessionPool *session_pool; + GstRTSPContext ctx = { NULL }; + + client = setup_multicast_client (); + + ctx.client = client; + ctx.auth = gst_rtsp_auth_new (); + ctx.token = + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_context_push_current (&ctx); + + /* simple SETUP with a valid URI and multicast, but an invalid ip */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast;destination=233.252.0.2;ttl=1;port=5000-5001;"); + + gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + session_pool = gst_rtsp_client_get_session_pool (client); + fail_unless (session_pool != NULL); + fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); + g_object_unref (session_pool); + + + /* simple SETUP with a valid URI and multicast, but an invalid prt */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast;destination=233.252.0.1;ttl=1;port=6000-6001;"); + + gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + session_pool = gst_rtsp_client_get_session_pool (client); + fail_unless (session_pool != NULL); + fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); + g_object_unref (session_pool); + + + /* simple SETUP with a valid URI and multicast, but an invalid ttl */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast;destination=233.252.0.1;ttl=2;port=5000-5001;"); + + gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + session_pool = gst_rtsp_client_get_session_pool (client); + fail_unless (session_pool != NULL); + fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); + g_object_unref (session_pool); + + teardown_client (client); + g_object_unref (ctx.auth); + gst_rtsp_token_unref (ctx.token); + gst_rtsp_context_pop_current (&ctx); +} + +GST_END_TEST; + GST_START_TEST (test_client_multicast_transport_specific) { GstRTSPClient *client; @@ -747,7 +859,7 @@ GST_START_TEST (test_client_multicast_transport_specific) expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" "ttl=1;port=5000-5001;mode=\"PLAY\""; - /* simple SETUP with a valid URI */ + /* simple SETUP with a valid URI and multicast, but an invalid ip */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); @@ -919,156 +1031,6 @@ GST_START_TEST (test_client_sdp_with_no_bitrate_tags) GST_END_TEST; -static void -mcast_transport_specific_two_clients (gboolean shared) -{ - GstRTSPClient *client, *client2; - GstRTSPMessage request = { 0, }; - gchar *str; - GstRTSPSessionPool *session_pool; - GstRTSPContext ctx = { NULL }; - GstRTSPContext ctx2 = { NULL }; - GstRTSPMountPoints *mount_points; - GstRTSPMediaFactory *factory; - GstRTSPAddressPool *address_pool; - GstRTSPThreadPool *thread_pool; - gchar *session_id1; - - mount_points = gst_rtsp_mount_points_new (); - factory = gst_rtsp_media_factory_new (); - if (shared) - gst_rtsp_media_factory_set_shared (factory, TRUE); - gst_rtsp_media_factory_set_max_mcast_ttl (factory, 5); - gst_rtsp_media_factory_set_launch (factory, - "audiotestsrc ! audio/x-raw,rate=44100 ! audioconvert ! rtpL16pay name=pay0"); - address_pool = gst_rtsp_address_pool_new (); - fail_unless (gst_rtsp_address_pool_add_range (address_pool, - "233.252.0.1", "233.252.0.1", 5000, 5001, 1)); - gst_rtsp_media_factory_set_address_pool (factory, address_pool); - gst_rtsp_media_factory_add_role (factory, "user", - "media.factory.access", G_TYPE_BOOLEAN, TRUE, - "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); - gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); - session_pool = gst_rtsp_session_pool_new (); - thread_pool = gst_rtsp_thread_pool_new (); - - /* first multicast client with transport specific request */ - client = gst_rtsp_client_new (); - gst_rtsp_client_set_session_pool (client, session_pool); - gst_rtsp_client_set_mount_points (client, mount_points); - gst_rtsp_client_set_thread_pool (client, thread_pool); - - ctx.client = client; - ctx.auth = gst_rtsp_auth_new (); - ctx.token = - gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, - G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, - "user", NULL); - gst_rtsp_context_push_current (&ctx); - - expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; - - /* send SETUP request */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=0") == GST_RTSP_OK); - str = g_strdup_printf ("%d", cseq); - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - expected_transport); - - gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, - NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, - &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); - expected_transport = NULL; - - /* send PLAY request */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, - "rtsp://localhost/test") == GST_RTSP_OK); - str = g_strdup_printf ("%d", cseq); - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); - gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, - &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); - gst_rtsp_context_pop_current (&ctx); - session_id1 = session_id; - - /* second multicast client with transport specific request */ - cseq = 0; - client2 = gst_rtsp_client_new (); - gst_rtsp_client_set_session_pool (client2, session_pool); - gst_rtsp_client_set_mount_points (client2, mount_points); - gst_rtsp_client_set_thread_pool (client2, thread_pool); - - ctx2.client = client2; - ctx2.auth = gst_rtsp_auth_new (); - ctx2.token = - gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, - G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, - "user", NULL); - gst_rtsp_context_push_current (&ctx2); - - expected_transport = "RTP/AVP;multicast;destination=233.252.0.2;" - "ttl=1;port=5002-5003;mode=\"PLAY\""; - - /* send SETUP request */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=0") == GST_RTSP_OK); - str = g_strdup_printf ("%d", cseq); - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - expected_transport); - - gst_rtsp_client_set_send_func (client2, test_setup_response_200_multicast, - NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client2, - &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); - expected_transport = NULL; - - /* send PLAY request */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, - "rtsp://localhost/test") == GST_RTSP_OK); - str = g_strdup_printf ("%d", cseq); - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); - gst_rtsp_client_set_send_func (client2, test_response_200, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client2, - &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); - - send_teardown (client2); - gst_rtsp_context_pop_current (&ctx2); - - gst_rtsp_context_push_current (&ctx); - session_id = session_id1; - send_teardown (client); - gst_rtsp_context_pop_current (&ctx); - - teardown_client (client); - teardown_client (client2); - g_object_unref (ctx.auth); - g_object_unref (ctx2.auth); - gst_rtsp_token_unref (ctx.token); - gst_rtsp_token_unref (ctx2.token); - g_object_unref (mount_points); - g_object_unref (session_pool); - g_object_unref (address_pool); - g_object_unref (thread_pool); -} - -/* test if two multicast clients can choose different transport settings */ -GST_START_TEST - (test_client_multicast_transport_specific_two_clients_shared_media) { - mcast_transport_specific_two_clients (TRUE); -} - -GST_END_TEST; - static Suite * rtspclient_suite (void) { @@ -1084,13 +1046,12 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_transport_404); tcase_add_test (tc, test_client_multicast_transport); tcase_add_test (tc, test_client_multicast_ignore_transport_specific); + tcase_add_test (tc, test_client_multicast_invalid_transport_specific); tcase_add_test (tc, test_client_multicast_transport_specific); tcase_add_test (tc, test_client_sdp_with_max_bitrate_tag); tcase_add_test (tc, test_client_sdp_with_bitrate_tag); tcase_add_test (tc, test_client_sdp_with_max_bitrate_and_bitrate_tags); tcase_add_test (tc, test_client_sdp_with_no_bitrate_tags); - tcase_add_test (tc, - test_client_multicast_transport_specific_two_clients_shared_media); return s; } diff --git a/tests/check/gst/mediafactory.c b/tests/check/gst/mediafactory.c index ba1719ea04..b6b250beb7 100644 --- a/tests/check/gst/mediafactory.c +++ b/tests/check/gst/mediafactory.c @@ -314,63 +314,6 @@ GST_START_TEST (test_reset) GST_END_TEST; -GST_START_TEST (test_mcast_ttl) -{ - GstRTSPMediaFactory *factory; - GstElement *element; - GstRTSPMedia *media; - GstRTSPUrl *url; - GstRTSPStream *stream; - - factory = gst_rtsp_media_factory_new (); - gst_rtsp_media_factory_set_shared (factory, TRUE); - fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", - &url) == GST_RTSP_OK); - - gst_rtsp_media_factory_set_launch (factory, - "( videotestsrc ! rtpvrawpay pt=96 name=pay0 " - " audiotestsrc ! audioconvert ! rtpL16pay name=pay1 )"); - - /* try to set an invalid ttl and make sure that the default ttl value (255) is - * set */ - gst_rtsp_media_factory_set_max_mcast_ttl (factory, 0); - fail_unless (gst_rtsp_media_factory_get_max_mcast_ttl (factory) == 255); - gst_rtsp_media_factory_set_max_mcast_ttl (factory, 300); - fail_unless (gst_rtsp_media_factory_get_max_mcast_ttl (factory) == 255); - - /* set a valid ttl value */ - gst_rtsp_media_factory_set_max_mcast_ttl (factory, 3); - fail_unless (gst_rtsp_media_factory_get_max_mcast_ttl (factory) == 3); - - element = gst_rtsp_media_factory_create_element (factory, url); - fail_unless (GST_IS_BIN (element)); - fail_if (GST_IS_PIPELINE (element)); - gst_object_unref (element); - - media = gst_rtsp_media_factory_construct (factory, url); - fail_unless (GST_IS_RTSP_MEDIA (media)); - - fail_unless (gst_rtsp_media_n_streams (media) == 2); - fail_unless (gst_rtsp_media_get_max_mcast_ttl (media) == 3); - - /* verify that the correct ttl value has been propageted to the media - * streams */ - stream = gst_rtsp_media_get_stream (media, 0); - fail_unless (stream != NULL); - fail_unless (gst_rtsp_stream_get_max_mcast_ttl (stream) == 3); - - stream = gst_rtsp_media_get_stream (media, 1); - fail_unless (stream != NULL); - fail_unless (gst_rtsp_stream_get_max_mcast_ttl (stream) == 3); - - g_object_unref (media); - - gst_rtsp_url_free (url); - g_object_unref (factory); -} - -GST_END_TEST; - static Suite * rtspmediafactory_suite (void) { @@ -386,7 +329,6 @@ rtspmediafactory_suite (void) tcase_add_test (tc, test_addresspool); tcase_add_test (tc, test_permissions); tcase_add_test (tc, test_reset); - tcase_add_test (tc, test_mcast_ttl); return s; } From d06f3af0be895a6b60e46af1689ddd64df4512e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 14 Aug 2018 14:25:53 +0300 Subject: [PATCH 1540/1776] Revert "rtsp-stream: avoid duplicating the first multicast client" This reverts commit 33570944401747f44d8ebfec535350651413fb92. Commits where accidentially squashed together --- gst/rtsp-server/rtsp-stream.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index b95ead95a1..3439ea3a0e 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1157,6 +1157,8 @@ set_multicast_socket_for_udpsink (GstElement * udpsink, GSocket * socket, GST_INFO ("setting ttl-mc %d", mcast_ttl); g_object_set (G_OBJECT (udpsink), "ttl-mc", mcast_ttl, NULL); } + + g_signal_emit_by_name (udpsink, "add", addr_str, port, NULL); } From c4141580228ff4c79cd87e970ed3b2650020a4f6 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 31 Jul 2018 21:17:41 +0200 Subject: [PATCH 1541/1776] rtsp-stream: avoid duplicating the first multicast client In dcb4533fedae3ac62bc25a916eb95927b7d69aec , we made it so clients were dynamically added and removed to the multicast udp sinks, as such we should no longer add a first client in set_multicast_socket_for_udpsink https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-stream.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 3439ea3a0e..b95ead95a1 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1157,8 +1157,6 @@ set_multicast_socket_for_udpsink (GstElement * udpsink, GSocket * socket, GST_INFO ("setting ttl-mc %d", mcast_ttl); g_object_set (G_OBJECT (udpsink), "ttl-mc", mcast_ttl, NULL); } - - g_signal_emit_by_name (udpsink, "add", addr_str, port, NULL); } From a7bb684e9b2d56b5f95f42b042501c17bbcbf094 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Tue, 24 Jul 2018 09:35:46 +0200 Subject: [PATCH 1542/1776] Add new API for setting/getting maximum multicast ttl value Change-Id: I5ef4758188c14785e17fb8fbf42a3dc0cb054233 https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-media-factory.c | 75 ++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 7 +++ gst/rtsp-server/rtsp-media.c | 81 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 6 +++ gst/rtsp-server/rtsp-stream.c | 51 ++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 6 +++ tests/check/gst/mediafactory.c | 58 ++++++++++++++++++++ 7 files changed, 284 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index a4f10ddeaf..53bce3ea1e 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -59,6 +59,7 @@ struct _GstRTSPMediaFactoryPrivate GstRTSPTransportMode transport_mode; gboolean stop_on_disconnect; gchar *multicast_iface; + guint max_mcast_ttl; GstClockTime rtx_time; guint latency; @@ -83,6 +84,7 @@ struct _GstRTSPMediaFactoryPrivate GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_LATENCY 200 +#define DEFAULT_MAX_MCAST_TTL 255 #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE #define DEFAULT_DO_RETRANSMISSION FALSE @@ -101,6 +103,7 @@ enum PROP_TRANSPORT_MODE, PROP_STOP_ON_DISCONNECT, PROP_CLOCK, + PROP_MAX_MCAST_TTL, PROP_LAST }; @@ -222,6 +225,12 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) "medias of this factory", GST_TYPE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MAX_MCAST_TTL, + g_param_spec_uint ("max-mcast-ttl", "Maximum multicast ttl", + "The maximum time-to-live value of outgoing multicast packets", 1, + 255, DEFAULT_MAX_MCAST_TTL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, @@ -263,6 +272,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; + priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; g_mutex_init (&priv->lock); g_mutex_init (&priv->medias_lock); @@ -337,6 +347,9 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, case PROP_CLOCK: g_value_take_object (value, gst_rtsp_media_factory_get_clock (factory)); break; + case PROP_MAX_MCAST_TTL: + g_value_set_uint (value, + gst_rtsp_media_factory_get_max_mcast_ttl (factory)); default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -387,6 +400,9 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, case PROP_CLOCK: gst_rtsp_media_factory_set_clock (factory, g_value_get_object (value)); break; + case PROP_MAX_MCAST_TTL: + gst_rtsp_media_factory_set_max_mcast_ttl (factory, + g_value_get_uint (value)); default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1463,6 +1479,62 @@ gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory) return ret; } +/** + * gst_rtsp_media_factory_set_max_mcast_ttl: + * @factory: a #GstRTSPMedia + * @ttl: the new multicast ttl value + * + * Set the maximum time-to-live value of outgoing multicast packets. + * + * Returns: %TRUE if the requested ttl has been set successfully. + */ +gboolean +gst_rtsp_media_factory_set_max_mcast_ttl (GstRTSPMediaFactory * factory, + guint ttl) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + if (ttl == 0 || ttl > DEFAULT_MAX_MCAST_TTL) { + GST_WARNING_OBJECT (factory, "The requested mcast TTL value is not valid."); + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + return FALSE; + } + priv->max_mcast_ttl = ttl; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return TRUE; +} + +/** + * gst_rtsp_media_factory_get_max_mcast_ttl: + * @factory: a #GstRTSPMedia + * + * Get the the maximum time-to-live value of outgoing multicast packets. + * + * Returns: the maximum time-to-live value of outgoing multicast packets. + */ +guint +gst_rtsp_media_factory_get_max_mcast_ttl (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + guint result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + result = priv->max_mcast_ttl; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} + static gchar * default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { @@ -1613,6 +1685,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstClock *clock; gchar *multicast_iface; GstRTSPPublishClockMode publish_clock_mode; + guint ttl; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -1628,6 +1701,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) stop_on_disconnect = priv->stop_on_disconnect; clock = priv->clock ? gst_object_ref (priv->clock) : NULL; publish_clock_mode = priv->publish_clock_mode; + ttl = priv->max_mcast_ttl; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_suspend_mode (media, suspend_mode); @@ -1642,6 +1716,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_transport_mode (media, transport_mode); gst_rtsp_media_set_stop_on_disconnect (media, stop_on_disconnect); gst_rtsp_media_set_publish_clock_mode (media, publish_clock_mode); + gst_rtsp_media_set_max_mcast_ttl (media, ttl); if (clock) { gst_rtsp_media_set_clock (media, clock); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 7fb7fccde8..46d7d5515e 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -239,6 +239,13 @@ void gst_rtsp_media_factory_set_publish_clock_mode (GstRTSPMe GST_RTSP_SERVER_API GstRTSPPublishClockMode gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory); +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_factory_set_max_mcast_ttl (GstRTSPMediaFactory * factory, + guint ttl); + +GST_RTSP_SERVER_API +guint gst_rtsp_media_factory_get_max_mcast_ttl (GstRTSPMediaFactory * factory); + /* creating the media from the factory and a url */ GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index f23b4c5d46..1073b89bce 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -98,6 +98,7 @@ struct _GstRTSPMediaPrivate guint buffer_size; GstRTSPAddressPool *pool; gchar *multicast_iface; + guint max_mcast_ttl; gboolean blocked; GstRTSPTransportMode transport_mode; gboolean stop_on_disconnect; @@ -158,6 +159,7 @@ struct _GstRTSPMediaPrivate #define DEFAULT_LATENCY 200 #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE +#define DEFAULT_MAX_MCAST_TTL 255 #define DEFAULT_DO_RETRANSMISSION FALSE @@ -180,6 +182,7 @@ enum PROP_TRANSPORT_MODE, PROP_STOP_ON_DISCONNECT, PROP_CLOCK, + PROP_MAX_MCAST_TTL, PROP_LAST }; @@ -375,6 +378,12 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) "Clock to be used by the media pipeline", GST_TYPE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MAX_MCAST_TTL, + g_param_spec_uint ("max-mcast-ttl", "Maximum multicast ttl", + "The maximum time-to-live value of outgoing multicast packets", 1, + 255, DEFAULT_MAX_MCAST_TTL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, @@ -445,6 +454,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; + priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; } static void @@ -531,6 +541,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_CLOCK: g_value_take_object (value, gst_rtsp_media_get_clock (media)); break; + case PROP_MAX_MCAST_TTL: + g_value_set_uint (value, gst_rtsp_media_get_max_mcast_ttl (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -584,6 +597,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_CLOCK: gst_rtsp_media_set_clock (media, g_value_get_object (value)); break; + case PROP_MAX_MCAST_TTL: + gst_rtsp_media_set_max_mcast_ttl (media, g_value_get_uint (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1823,6 +1839,70 @@ gst_rtsp_media_get_multicast_iface (GstRTSPMedia * media) return result; } +/** + * gst_rtsp_media_set_max_mcast_ttl: + * @media: a #GstRTSPMedia + * @ttl: the new multicast ttl value + * + * Set the maximum time-to-live value of outgoing multicast packets. + * + * Returns: %TRUE if the requested ttl has been set successfully. + */ +gboolean +gst_rtsp_media_set_max_mcast_ttl (GstRTSPMedia * media, guint ttl) +{ + GstRTSPMediaPrivate *priv; + guint i; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + GST_LOG_OBJECT (media, "set max mcast ttl %u", ttl); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + + if (ttl == 0 || ttl > DEFAULT_MAX_MCAST_TTL) { + GST_WARNING_OBJECT (media, "The reqested mcast TTL value is not valid."); + g_mutex_unlock (&priv->lock); + return FALSE; + } + priv->max_mcast_ttl = ttl; + + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + gst_rtsp_stream_set_max_mcast_ttl (stream, ttl); + } + g_mutex_unlock (&priv->lock); + + return TRUE; +} + +/** + * gst_rtsp_media_get_max_mcast_ttl: + * @media: a #GstRTSPMedia + * + * Get the the maximum time-to-live value of outgoing multicast packets. + * + * Returns: the maximum time-to-live value of outgoing multicast packets. + */ +guint +gst_rtsp_media_get_max_mcast_ttl (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + guint res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->max_mcast_ttl; + g_mutex_unlock (&priv->lock); + + return res; +} + static GList * _find_payload_types (GstRTSPMedia * media) { @@ -2140,6 +2220,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, if (priv->pool) gst_rtsp_stream_set_address_pool (stream, priv->pool); gst_rtsp_stream_set_multicast_iface (stream, priv->multicast_iface); + gst_rtsp_stream_set_max_mcast_ttl (stream, priv->max_mcast_ttl); gst_rtsp_stream_set_profiles (stream, priv->profiles); gst_rtsp_stream_set_protocols (stream, priv->protocols); gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 84dfb14591..92b3866a94 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -314,6 +314,12 @@ void gst_rtsp_media_set_publish_clock_mode (GstRTSPMedia * me GST_RTSP_SERVER_API GstRTSPPublishClockMode gst_rtsp_media_get_publish_clock_mode (GstRTSPMedia * media); +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_set_max_mcast_ttl (GstRTSPMedia *media, guint ttl); + +GST_RTSP_SERVER_API +guint gst_rtsp_media_get_max_mcast_ttl (GstRTSPMedia *media); + /* prepare the media for playback */ GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index b95ead95a1..1a68fd5b13 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -145,6 +145,7 @@ struct _GstRTSPStreamPrivate GstRTSPAddress *mcast_addr_v6; gchar *multicast_iface; + guint max_mcast_ttl; /* the caps of the stream */ gulong caps_sig; @@ -181,6 +182,7 @@ struct _GstRTSPStreamPrivate #define DEFAULT_PROFILES GST_RTSP_PROFILE_AVP #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ GST_RTSP_LOWER_TRANS_TCP +#define DEFAULT_MAX_MCAST_TTL 255 enum { @@ -280,6 +282,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->allowed_protocols = DEFAULT_PROTOCOLS; priv->configured_protocols = 0; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; + priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; g_mutex_init (&priv->lock); @@ -1884,6 +1887,54 @@ gst_rtsp_stream_get_buffer_size (GstRTSPStream * stream) return buffer_size; } +/** + * gst_rtsp_stream_set_max_mcast_ttl: + * @stream: a #GstRTSPStream + * @ttl: the new multicast ttl value + * + * Set the maximum time-to-live value of outgoing multicast packets. + * + * Returns: %TRUE if the requested ttl has been set successfully. + * + */ +gboolean +gst_rtsp_stream_set_max_mcast_ttl (GstRTSPStream * stream, guint ttl) +{ + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + g_mutex_lock (&stream->priv->lock); + if (ttl == 0 || ttl > DEFAULT_MAX_MCAST_TTL) { + GST_WARNING_OBJECT (stream, "The reqested mcast TTL value is not valid."); + g_mutex_unlock (&stream->priv->lock); + return FALSE; + } + stream->priv->max_mcast_ttl = ttl; + g_mutex_unlock (&stream->priv->lock); + + return TRUE; +} + +/** + * gst_rtsp_stream_get_max_mcast_ttl: + * @stream: a #GstRTSPStream + * + * Get the the maximum time-to-live value of outgoing multicast packets. + * + * Returns: the maximum time-to-live value of outgoing multicast packets. + * + */ +guint +gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream * stream) +{ + guint ttl; + + g_mutex_lock (&stream->priv->lock); + ttl = stream->priv->max_mcast_ttl; + g_mutex_unlock (&stream->priv->lock); + + return ttl; +} + /* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 1f527a462d..1ee146dda7 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -292,6 +292,12 @@ void gst_rtsp_stream_set_publish_clock_mode (GstRTSPStream * GST_RTSP_SERVER_API GstRTSPPublishClockMode gst_rtsp_stream_get_publish_clock_mode (GstRTSPStream * stream); +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_set_max_mcast_ttl (GstRTSPStream *stream, guint ttl); + +GST_RTSP_SERVER_API +guint gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream *stream); + GST_RTSP_SERVER_API gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GstRTSPTransport * transport); diff --git a/tests/check/gst/mediafactory.c b/tests/check/gst/mediafactory.c index b6b250beb7..ba1719ea04 100644 --- a/tests/check/gst/mediafactory.c +++ b/tests/check/gst/mediafactory.c @@ -314,6 +314,63 @@ GST_START_TEST (test_reset) GST_END_TEST; +GST_START_TEST (test_mcast_ttl) +{ + GstRTSPMediaFactory *factory; + GstElement *element; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPStream *stream; + + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_shared (factory, TRUE); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 " + " audiotestsrc ! audioconvert ! rtpL16pay name=pay1 )"); + + /* try to set an invalid ttl and make sure that the default ttl value (255) is + * set */ + gst_rtsp_media_factory_set_max_mcast_ttl (factory, 0); + fail_unless (gst_rtsp_media_factory_get_max_mcast_ttl (factory) == 255); + gst_rtsp_media_factory_set_max_mcast_ttl (factory, 300); + fail_unless (gst_rtsp_media_factory_get_max_mcast_ttl (factory) == 255); + + /* set a valid ttl value */ + gst_rtsp_media_factory_set_max_mcast_ttl (factory, 3); + fail_unless (gst_rtsp_media_factory_get_max_mcast_ttl (factory) == 3); + + element = gst_rtsp_media_factory_create_element (factory, url); + fail_unless (GST_IS_BIN (element)); + fail_if (GST_IS_PIPELINE (element)); + gst_object_unref (element); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + fail_unless (gst_rtsp_media_n_streams (media) == 2); + fail_unless (gst_rtsp_media_get_max_mcast_ttl (media) == 3); + + /* verify that the correct ttl value has been propageted to the media + * streams */ + stream = gst_rtsp_media_get_stream (media, 0); + fail_unless (stream != NULL); + fail_unless (gst_rtsp_stream_get_max_mcast_ttl (stream) == 3); + + stream = gst_rtsp_media_get_stream (media, 1); + fail_unless (stream != NULL); + fail_unless (gst_rtsp_stream_get_max_mcast_ttl (stream) == 3); + + g_object_unref (media); + + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + static Suite * rtspmediafactory_suite (void) { @@ -329,6 +386,7 @@ rtspmediafactory_suite (void) tcase_add_test (tc, test_addresspool); tcase_add_test (tc, test_permissions); tcase_add_test (tc, test_reset); + tcase_add_test (tc, test_mcast_ttl); return s; } From 308480e7624fba1e1b28685907c0b0d1556950fc Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Tue, 24 Jul 2018 14:02:40 +0200 Subject: [PATCH 1543/1776] client: Don't reserve multicast address in the client setting case When two multicast clients request specific transport configurations, and "transport.client-settings" parameter is set to true, it's wrong to actually require that these two clients request the same multicast group. Removed test_client_multicast_invalid_transport_specific test cases as they wrongly require that the requested destination address is supposed to be present in the address pool, also in the case when "transport.client-settings" parameter is set to true. Change-Id: I4580182ef35996caf644686d6139f72ec599c9fa https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-client.c | 20 ++- tests/check/gst/client.c | 267 +++++++++++++++++++--------------- 2 files changed, 162 insertions(+), 125 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 92135f24e2..01e63bf469 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1990,17 +1990,16 @@ default_configure_client_transport (GstRTSPClient * client, goto error_allocating_ports; if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - GstRTSPAddress *addr = NULL; + /* FIXME: the address has been successfully allocated, however, in + * the use_client_settings case we need to verify that the allocated + * address is the one requested by the client and if this address is + * an allowed destination. Verifying this via the address pool in not + * the proper way as the address pool should only be used for choosing + * the server-selected address/port pairs. */ - if (use_client_settings) { - /* the address has been successfully allocated, let's check if it's - * the one requested by the client */ - addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination, - ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl); + if (!use_client_settings) { + GstRTSPAddress *addr = NULL; - if (addr == NULL) - goto no_address; - } else { g_free (ct->destination); addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family); if (addr == NULL) @@ -2009,9 +2008,8 @@ default_configure_client_transport (GstRTSPClient * client, ct->port.min = addr->port; ct->port.max = addr->port + addr->n_ports - 1; ct->ttl = addr->ttl; + gst_rtsp_address_free (addr); } - - gst_rtsp_address_free (addr); } else { GstRTSPUrl *url; diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 4adf3d18c9..ab95509f93 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -525,7 +525,6 @@ test_setup_response_200_multicast (GstRTSPClient * client, session_pool = gst_rtsp_client_get_session_pool (client); fail_unless (session_pool != NULL); - fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 1); session = gst_rtsp_session_pool_find (session_pool, session_hdr_params[0]); g_strfreev (session_hdr_params); @@ -727,117 +726,6 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GST_END_TEST; -static gboolean -test_setup_response_461 (GstRTSPClient * client, - GstRTSPMessage * response, gboolean close, gpointer user_data) -{ - GstRTSPStatusCode code; - const gchar *reason; - GstRTSPVersion version; - gchar *str; - - fail_unless (expected_transport == NULL); - - fail_unless (gst_rtsp_message_get_type (response) == - GST_RTSP_MESSAGE_RESPONSE); - - fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, - &version) - == GST_RTSP_OK); - fail_unless (code == GST_RTSP_STS_UNSUPPORTED_TRANSPORT); - fail_unless (g_str_equal (reason, "Unsupported transport")); - fail_unless (version == GST_RTSP_VERSION_1_0); - - fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, - 0) == GST_RTSP_OK); - fail_unless (atoi (str) == cseq++); - - - return TRUE; -} - -GST_START_TEST (test_client_multicast_invalid_transport_specific) -{ - GstRTSPClient *client; - GstRTSPMessage request = { 0, }; - gchar *str; - GstRTSPSessionPool *session_pool; - GstRTSPContext ctx = { NULL }; - - client = setup_multicast_client (); - - ctx.client = client; - ctx.auth = gst_rtsp_auth_new (); - ctx.token = - gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, - G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, - "user", NULL); - gst_rtsp_context_push_current (&ctx); - - /* simple SETUP with a valid URI and multicast, but an invalid ip */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=0") == GST_RTSP_OK); - str = g_strdup_printf ("%d", cseq); - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - "RTP/AVP;multicast;destination=233.252.0.2;ttl=1;port=5000-5001;"); - - gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, - &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); - - session_pool = gst_rtsp_client_get_session_pool (client); - fail_unless (session_pool != NULL); - fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); - g_object_unref (session_pool); - - - /* simple SETUP with a valid URI and multicast, but an invalid prt */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=0") == GST_RTSP_OK); - str = g_strdup_printf ("%d", cseq); - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - "RTP/AVP;multicast;destination=233.252.0.1;ttl=1;port=6000-6001;"); - - gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, - &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); - - session_pool = gst_rtsp_client_get_session_pool (client); - fail_unless (session_pool != NULL); - fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); - g_object_unref (session_pool); - - - /* simple SETUP with a valid URI and multicast, but an invalid ttl */ - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=0") == GST_RTSP_OK); - str = g_strdup_printf ("%d", cseq); - gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - "RTP/AVP;multicast;destination=233.252.0.1;ttl=2;port=5000-5001;"); - - gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, - &request) == GST_RTSP_OK); - gst_rtsp_message_unset (&request); - - session_pool = gst_rtsp_client_get_session_pool (client); - fail_unless (session_pool != NULL); - fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); - g_object_unref (session_pool); - - teardown_client (client); - g_object_unref (ctx.auth); - gst_rtsp_token_unref (ctx.token); - gst_rtsp_context_pop_current (&ctx); -} - -GST_END_TEST; - GST_START_TEST (test_client_multicast_transport_specific) { GstRTSPClient *client; @@ -859,7 +747,7 @@ GST_START_TEST (test_client_multicast_transport_specific) expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" "ttl=1;port=5000-5001;mode=\"PLAY\""; - /* simple SETUP with a valid URI and multicast, but an invalid ip */ + /* simple SETUP with a valid URI */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); @@ -1031,6 +919,156 @@ GST_START_TEST (test_client_sdp_with_no_bitrate_tags) GST_END_TEST; +static void +mcast_transport_specific_two_clients (gboolean shared) +{ + GstRTSPClient *client, *client2; + GstRTSPMessage request = { 0, }; + gchar *str; + GstRTSPSessionPool *session_pool; + GstRTSPContext ctx = { NULL }; + GstRTSPContext ctx2 = { NULL }; + GstRTSPMountPoints *mount_points; + GstRTSPMediaFactory *factory; + GstRTSPAddressPool *address_pool; + GstRTSPThreadPool *thread_pool; + gchar *session_id1; + + mount_points = gst_rtsp_mount_points_new (); + factory = gst_rtsp_media_factory_new (); + if (shared) + gst_rtsp_media_factory_set_shared (factory, TRUE); + gst_rtsp_media_factory_set_max_mcast_ttl (factory, 5); + gst_rtsp_media_factory_set_launch (factory, + "audiotestsrc ! audio/x-raw,rate=44100 ! audioconvert ! rtpL16pay name=pay0"); + address_pool = gst_rtsp_address_pool_new (); + fail_unless (gst_rtsp_address_pool_add_range (address_pool, + "233.252.0.1", "233.252.0.1", 5000, 5001, 1)); + gst_rtsp_media_factory_set_address_pool (factory, address_pool); + gst_rtsp_media_factory_add_role (factory, "user", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); + gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); + session_pool = gst_rtsp_session_pool_new (); + thread_pool = gst_rtsp_thread_pool_new (); + + /* first multicast client with transport specific request */ + client = gst_rtsp_client_new (); + gst_rtsp_client_set_session_pool (client, session_pool); + gst_rtsp_client_set_mount_points (client, mount_points); + gst_rtsp_client_set_thread_pool (client, thread_pool); + + ctx.client = client; + ctx.auth = gst_rtsp_auth_new (); + ctx.token = + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_context_push_current (&ctx); + + expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + + /* send SETUP request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + expected_transport); + + gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, + NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + expected_transport = NULL; + + /* send PLAY request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + gst_rtsp_context_pop_current (&ctx); + session_id1 = session_id; + + /* second multicast client with transport specific request */ + cseq = 0; + client2 = gst_rtsp_client_new (); + gst_rtsp_client_set_session_pool (client2, session_pool); + gst_rtsp_client_set_mount_points (client2, mount_points); + gst_rtsp_client_set_thread_pool (client2, thread_pool); + + ctx2.client = client2; + ctx2.auth = gst_rtsp_auth_new (); + ctx2.token = + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_context_push_current (&ctx2); + + expected_transport = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; + + /* send SETUP request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + expected_transport); + + gst_rtsp_client_set_send_func (client2, test_setup_response_200_multicast, + NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client2, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + expected_transport = NULL; + + /* send PLAY request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + gst_rtsp_client_set_send_func (client2, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client2, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + send_teardown (client2); + gst_rtsp_context_pop_current (&ctx2); + + gst_rtsp_context_push_current (&ctx); + session_id = session_id1; + send_teardown (client); + gst_rtsp_context_pop_current (&ctx); + + teardown_client (client); + teardown_client (client2); + g_object_unref (ctx.auth); + g_object_unref (ctx2.auth); + gst_rtsp_token_unref (ctx.token); + gst_rtsp_token_unref (ctx2.token); + g_object_unref (mount_points); + g_object_unref (session_pool); + g_object_unref (address_pool); + g_object_unref (thread_pool); +} + +/* test if two multicast clients can choose different transport settings */ +GST_START_TEST + (test_client_multicast_transport_specific_two_clients_shared_media) { + mcast_transport_specific_two_clients (TRUE); +} + +GST_END_TEST; + static Suite * rtspclient_suite (void) { @@ -1046,12 +1084,13 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_transport_404); tcase_add_test (tc, test_client_multicast_transport); tcase_add_test (tc, test_client_multicast_ignore_transport_specific); - tcase_add_test (tc, test_client_multicast_invalid_transport_specific); tcase_add_test (tc, test_client_multicast_transport_specific); tcase_add_test (tc, test_client_sdp_with_max_bitrate_tag); tcase_add_test (tc, test_client_sdp_with_bitrate_tag); tcase_add_test (tc, test_client_sdp_with_max_bitrate_and_bitrate_tags); tcase_add_test (tc, test_client_sdp_with_no_bitrate_tags); + tcase_add_test (tc, + test_client_multicast_transport_specific_two_clients_shared_media); return s; } From 048e24a7c6761fb82ceb3672db91a2b8d13754e1 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Fri, 23 Feb 2018 14:34:32 +0100 Subject: [PATCH 1544/1776] rtsp-stream: Don't require address pool in the transport specific case If "transport.client-settings" parameter is set to true, the client is allowed to specify destination, ports and ttl. There is no need for pre-configured address pool. Change-Id: I6ae578fb5164d78e8ec1e2ee82dc4eaacd0912d1 https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-stream.c | 171 ++++++++++++++++++++++++---------- tests/check/gst/client.c | 51 +++++++++- 2 files changed, 168 insertions(+), 54 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 1a68fd5b13..0d17718d9d 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1326,11 +1326,11 @@ error: static gboolean alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GSocket * socket_out[2], GstRTSPAddress ** server_addr_out, - gboolean multicast, GstRTSPTransport * ct) + gboolean multicast, GstRTSPTransport * ct, gboolean use_transport_settings) { GstRTSPStreamPrivate *priv = stream->priv; GSocket *rtp_socket = NULL; - GSocket *rtcp_socket; + GSocket *rtcp_socket = NULL; gint tmp_rtp, tmp_rtcp; guint count; GList *rejected_addresses = NULL; @@ -1339,6 +1339,7 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, GSocketAddress *rtp_sockaddr = NULL; GSocketAddress *rtcp_sockaddr = NULL; GstRTSPAddressPool *pool; + gboolean transport_settings_defined = FALSE; pool = priv->pool; count = 0; @@ -1346,6 +1347,30 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, /* Start with random port */ tmp_rtp = 0; + if (use_transport_settings) { + if (!multicast) + goto no_mcast; + + if (ct == NULL) + goto no_transport; + + /* multicast and transport specific case */ + if (ct->destination != NULL) { + tmp_rtp = ct->port.min; + tmp_rtcp = ct->port.max; + inetaddr = g_inet_address_new_from_string (ct->destination); + if (inetaddr == NULL) + goto destination_error; + if (!g_inet_address_get_is_multicast (inetaddr)) + goto destination_no_mcast; + g_object_unref (inetaddr); + inetaddr = g_inet_address_new_any (family); + + GST_DEBUG_OBJECT (stream, "use transport settings"); + transport_settings_defined = TRUE; + } + } + rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, NULL); if (!rtcp_socket) @@ -1364,55 +1389,60 @@ again: g_socket_set_multicast_loopback (rtp_socket, FALSE); } - if ((pool && gst_rtsp_address_pool_has_unicast_addresses (pool)) || multicast) { - GstRTSPAddressFlags flags; + if (!transport_settings_defined) { + if ((pool && gst_rtsp_address_pool_has_unicast_addresses (pool)) + || multicast) { + GstRTSPAddressFlags flags; - if (addr) - rejected_addresses = g_list_prepend (rejected_addresses, addr); + if (addr) + rejected_addresses = g_list_prepend (rejected_addresses, addr); - if (!pool) - goto no_pool; + if (!pool) + goto no_pool; - flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT; - if (multicast) - flags |= GST_RTSP_ADDRESS_FLAG_MULTICAST; - else - flags |= GST_RTSP_ADDRESS_FLAG_UNICAST; + flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT; + if (multicast) + flags |= GST_RTSP_ADDRESS_FLAG_MULTICAST; + else + flags |= GST_RTSP_ADDRESS_FLAG_UNICAST; - if (family == G_SOCKET_FAMILY_IPV6) - flags |= GST_RTSP_ADDRESS_FLAG_IPV6; - else - flags |= GST_RTSP_ADDRESS_FLAG_IPV4; + if (family == G_SOCKET_FAMILY_IPV6) + flags |= GST_RTSP_ADDRESS_FLAG_IPV6; + else + flags |= GST_RTSP_ADDRESS_FLAG_IPV4; - addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); + addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); - if (addr == NULL) - goto no_address; + if (addr == NULL) + goto no_address; - tmp_rtp = addr->port; + tmp_rtp = addr->port; - g_clear_object (&inetaddr); - /* FIXME: Does it really work with the IP_MULTICAST_ALL socket option and - * socket control message set in udpsrc? */ - if (multicast) - inetaddr = g_inet_address_new_any (family); - else - inetaddr = g_inet_address_new_from_string (addr->address); - } else { - if (tmp_rtp != 0) { - tmp_rtp += 2; - if (++count > 20) - goto no_ports; + g_clear_object (&inetaddr); + /* FIXME: Does it really work with the IP_MULTICAST_ALL socket option and + * socket control message set in udpsrc? */ + if (multicast) + inetaddr = g_inet_address_new_any (family); + else + inetaddr = g_inet_address_new_from_string (addr->address); + } else { + if (tmp_rtp != 0) { + tmp_rtp += 2; + if (++count > 20) + goto no_ports; + } + + if (inetaddr == NULL) + inetaddr = g_inet_address_new_any (family); } - - if (inetaddr == NULL) - inetaddr = g_inet_address_new_any (family); } rtp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtp); if (!g_socket_bind (rtp_socket, rtp_sockaddr, FALSE, NULL)) { GST_DEBUG_OBJECT (stream, "rtp bind() failed, will try again"); g_object_unref (rtp_sockaddr); + if (transport_settings_defined) + goto transport_settings_error; goto again; } g_object_unref (rtp_sockaddr); @@ -1423,17 +1453,22 @@ again: goto socket_error; } - tmp_rtp = - g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (rtp_sockaddr)); - g_object_unref (rtp_sockaddr); + if (!transport_settings_defined) { + tmp_rtp = + g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (rtp_sockaddr)); - /* check if port is even */ - if ((tmp_rtp & 1) != 0) { - /* port not even, close and allocate another */ - tmp_rtp++; - g_clear_object (&rtp_socket); - goto again; + /* check if port is even. RFC 3550 encorages the use of an even/odd port + * pair, however it's not a strict requirement so this check is not done + * for the client selected ports. */ + if ((tmp_rtp & 1) != 0) { + /* port not even, close and allocate another */ + tmp_rtp++; + g_object_unref (rtp_sockaddr); + g_clear_object (&rtp_socket); + goto again; + } } + g_object_unref (rtp_sockaddr); /* set port */ tmp_rtcp = tmp_rtp + 1; @@ -1443,15 +1478,21 @@ again: GST_DEBUG_OBJECT (stream, "rctp bind() failed, will try again"); g_object_unref (rtcp_sockaddr); g_clear_object (&rtp_socket); + if (transport_settings_defined) + goto transport_settings_error; goto again; } g_object_unref (rtcp_sockaddr); if (!addr) { addr = g_slice_new0 (GstRTSPAddress); - addr->address = g_inet_address_to_string (inetaddr); addr->port = tmp_rtp; addr->n_ports = 2; + if (transport_settings_defined) + addr->address = g_strdup (ct->destination); + else + addr->address = g_inet_address_to_string (inetaddr); + addr->ttl = ct->ttl; } g_clear_object (&inetaddr); @@ -1468,6 +1509,28 @@ again: return TRUE; /* ERRORS */ +no_mcast: + { + GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: wrong transport"); + goto cleanup; + } +no_transport: + { + GST_ERROR_OBJECT (stream, "failed to allocate UDP ports: no transport"); + goto cleanup; + } +destination_error: + { + GST_ERROR_OBJECT (stream, + "failed to allocate UDP ports: destination error"); + goto cleanup; + } +destination_no_mcast: + { + GST_ERROR_OBJECT (stream, + "failed to allocate UDP ports: destination not multicast address"); + goto cleanup; + } no_udp_protocol: { GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: protocol error"); @@ -1489,6 +1552,12 @@ no_ports: GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: no ports"); goto cleanup; } +transport_settings_error: + { + GST_ERROR_OBJECT (stream, + "failed to allocate UDP ports with requested transport settings"); + goto cleanup; + } socket_error: { GST_WARNING_OBJECT (stream, "failed to allocate UDP ports: socket error"); @@ -1563,12 +1632,13 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, /* UDP unicast */ GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_UDP, ipv4"); ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, - priv->socket_v4, &priv->server_addr_v4, FALSE, ct); + priv->socket_v4, &priv->server_addr_v4, FALSE, ct, FALSE); } else { /* multicast */ GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_MCAST_UDP, ipv4"); ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV4, - priv->mcast_socket_v4, &priv->mcast_addr_v4, TRUE, ct); + priv->mcast_socket_v4, &priv->mcast_addr_v4, TRUE, ct, + use_transport_settings); } } else { /* IPv6 */ @@ -1576,13 +1646,14 @@ gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, /* unicast */ GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_UDP, ipv6"); ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, - priv->socket_v6, &priv->server_addr_v6, FALSE, ct); + priv->socket_v6, &priv->server_addr_v6, FALSE, ct, FALSE); } else { /* multicast */ GST_DEBUG_OBJECT (stream, "GST_RTSP_LOWER_TRANS_MCAST_UDP, ipv6"); ret = alloc_ports_one_family (stream, G_SOCKET_FAMILY_IPV6, - priv->mcast_socket_v6, &priv->mcast_addr_v6, TRUE, ct); + priv->mcast_socket_v6, &priv->mcast_addr_v6, TRUE, ct, + use_transport_settings); } } g_mutex_unlock (&priv->lock); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index ab95509f93..d4fdd9ec1f 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -726,7 +726,8 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GST_END_TEST; -GST_START_TEST (test_client_multicast_transport_specific) +static void +multicast_transport_specific (void) { GstRTSPClient *client; GstRTSPMessage request = { 0, }; @@ -760,7 +761,6 @@ GST_START_TEST (test_client_multicast_transport_specific) fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - expected_transport = NULL; gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, NULL, NULL); @@ -769,14 +769,44 @@ GST_START_TEST (test_client_multicast_transport_specific) fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 1); g_object_unref (session_pool); - send_teardown (client); + /* send PLAY request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + send_teardown (client); teardown_client (client); g_object_unref (ctx.auth); gst_rtsp_token_unref (ctx.token); gst_rtsp_context_pop_current (&ctx); } +/* CASE: multicast address requested by the client exists in the address pool */ +GST_START_TEST (test_client_multicast_transport_specific) +{ + expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + multicast_transport_specific (); + expected_transport = NULL; +} + +GST_END_TEST; + +/* CASE: multicast address requested by the client does not exist in the address pool */ +GST_START_TEST (test_client_multicast_transport_specific_no_address_in_pool) +{ + expected_transport = "RTP/AVP;multicast;destination=234.252.0.3;" + "ttl=1;port=6000-6001;mode=\"PLAY\""; + multicast_transport_specific (); + expected_transport = NULL; +} + GST_END_TEST; static gboolean @@ -1061,7 +1091,8 @@ mcast_transport_specific_two_clients (gboolean shared) g_object_unref (thread_pool); } -/* test if two multicast clients can choose different transport settings */ +/* test if two multicast clients can choose different transport settings + * CASE: media is shared */ GST_START_TEST (test_client_multicast_transport_specific_two_clients_shared_media) { mcast_transport_specific_two_clients (TRUE); @@ -1069,6 +1100,15 @@ GST_START_TEST GST_END_TEST; +/* test if two multicast clients can choose different transport settings + * CASE: media is not shared */ +GST_START_TEST (test_client_multicast_transport_specific_two_clients) +{ + mcast_transport_specific_two_clients (FALSE); +} + +GST_END_TEST; + static Suite * rtspclient_suite (void) { @@ -1091,6 +1131,9 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_sdp_with_no_bitrate_tags); tcase_add_test (tc, test_client_multicast_transport_specific_two_clients_shared_media); + tcase_add_test (tc, test_client_multicast_transport_specific_two_clients); + tcase_add_test (tc, + test_client_multicast_transport_specific_no_address_in_pool); return s; } From 4c6cecf5d659fc194f86e115737b3df1120d3914 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Wed, 25 Jul 2018 15:33:18 +0200 Subject: [PATCH 1545/1776] stream: Choose the maximum ttl value provided by multicast clients The maximum ttl value provided so far by the multicast clients will be chosen and reported in the response to the current client request. Change-Id: I5408646e3b5a0a224d907ae215bdea60c4f1905f https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-client.c | 47 +++++++-- gst/rtsp-server/rtsp-stream.c | 30 +++++- gst/rtsp-server/rtsp-stream.h | 3 + tests/check/gst/client.c | 186 +++++++++++++++++++++++++++++----- 4 files changed, 229 insertions(+), 37 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 01e63bf469..e89203def9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1972,8 +1972,13 @@ default_configure_client_transport (GstRTSPClient * client, if ((ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) && gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS) && - (ct->destination != NULL)) + (ct->destination != NULL)) { + + if (!gst_rtsp_stream_verify_mcast_ttl (ctx->stream, ct->ttl)) + goto error_ttl; + use_client_settings = TRUE; + } /* We need to allocate the sockets for both families before starting * multiudpsink, otherwise multiudpsink won't accept new clients with @@ -1990,14 +1995,29 @@ default_configure_client_transport (GstRTSPClient * client, goto error_allocating_ports; if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - /* FIXME: the address has been successfully allocated, however, in - * the use_client_settings case we need to verify that the allocated - * address is the one requested by the client and if this address is - * an allowed destination. Verifying this via the address pool in not - * the proper way as the address pool should only be used for choosing - * the server-selected address/port pairs. */ + if (use_client_settings) { + /* FIXME: the address has been successfully allocated, however, in + * the use_client_settings case we need to verify that the allocated + * address is the one requested by the client and if this address is + * an allowed destination. Verifying this via the address pool in not + * the proper way as the address pool should only be used for choosing + * the server-selected address/port pairs. */ + GSocket *rtp_socket; + guint ttl; - if (!use_client_settings) { + rtp_socket = + gst_rtsp_stream_get_rtp_multicast_socket (ctx->stream, family); + if (rtp_socket == NULL) + goto no_socket; + ttl = g_socket_get_multicast_ttl (rtp_socket); + g_object_unref (rtp_socket); + if (ct->ttl < ttl) { + /* use the maximum ttl that is requested by multicast clients */ + GST_DEBUG ("requested ttl %u, but keeping ttl %u", ct->ttl, ttl); + ct->ttl = ttl; + } + + } else { GstRTSPAddress *addr = NULL; g_free (ct->destination); @@ -2062,6 +2082,12 @@ default_configure_client_transport (GstRTSPClient * client, return TRUE; /* ERRORS */ +error_ttl: + { + GST_ERROR_OBJECT (client, + "Failed to allocate UDP ports: invalid ttl value"); + return FALSE; + } error_allocating_ports: { GST_ERROR_OBJECT (client, "Failed to allocate UDP ports"); @@ -2072,6 +2098,11 @@ no_address: GST_ERROR_OBJECT (client, "Failed to acquire address for stream"); return FALSE; } +no_socket: + { + GST_ERROR_OBJECT (client, "Failed to get UDP socket"); + return FALSE; + } } static GstRTSPTransport * diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 0d17718d9d..33b6ff10f0 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1497,6 +1497,12 @@ again: g_clear_object (&inetaddr); + if (multicast && (ct->ttl > 0) && (ct->ttl <= priv->max_mcast_ttl)) { + GST_DEBUG ("setting mcast ttl to %d", ct->ttl); + g_socket_set_multicast_ttl (rtp_socket, ct->ttl); + g_socket_set_multicast_ttl (rtcp_socket, ct->ttl); + } + socket_out[0] = rtp_socket; socket_out[1] = rtcp_socket; *server_addr_out = addr; @@ -2006,6 +2012,29 @@ gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream * stream) return ttl; } +/** + * gst_rtsp_stream_verify_mcast_ttl: + * @stream: a #GstRTSPStream + * @ttl: a requested multicast ttl + * + * Check if the requested multicast ttl value is allowed. + * + * Returns: TRUE if the requested ttl value is allowed. + * + */ +gboolean +gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream * stream, guint ttl) +{ + gboolean res = FALSE; + + g_mutex_lock (&stream->priv->lock); + if ((ttl > 0) && (ttl <= stream->priv->max_mcast_ttl)) + res = TRUE; + g_mutex_unlock (&stream->priv->lock); + + return res; +} + /* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) @@ -4058,7 +4087,6 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, if (!check_mcast_part_for_transport (stream, tr)) goto mcast_error; - /* FIXME: Is it ok to set ttl-mc if media is shared? */ if (tr->ttl > 0) { GST_INFO ("setting ttl-mc %d", tr->ttl); if (priv->mcast_udpsink[0]) diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 1ee146dda7..ea21858424 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -298,6 +298,9 @@ gboolean gst_rtsp_stream_set_max_mcast_ttl (GstRTSPStream *strea GST_RTSP_SERVER_API guint gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream *stream); +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream *stream, guint ttl); + GST_RTSP_SERVER_API gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GstRTSPTransport * transport); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index d4fdd9ec1f..a420f65706 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -541,6 +541,35 @@ test_setup_response_200_multicast (GstRTSPClient * client, return TRUE; } +static gboolean +test_setup_response_461 (GstRTSPClient * client, + GstRTSPMessage * response, gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + gchar *str; + + fail_unless (expected_transport == NULL); + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_UNSUPPORTED_TRANSPORT); + fail_unless (g_str_equal (reason, "Unsupported transport")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, + 0) == GST_RTSP_OK); + fail_unless (atoi (str) == cseq++); + + + return TRUE; +} + static gboolean test_teardown_response_200 (GstRTSPClient * client, GstRTSPMessage * response, gboolean close, gpointer user_data) @@ -584,7 +613,7 @@ send_teardown (GstRTSPClient * client) } static GstRTSPClient * -setup_multicast_client (void) +setup_multicast_client (guint max_ttl) { GstRTSPClient *client; GstRTSPSessionPool *session_pool; @@ -611,6 +640,7 @@ setup_multicast_client (void) "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); gst_rtsp_client_set_mount_points (client, mount_points); + gst_rtsp_media_factory_set_max_mcast_ttl (factory, max_ttl); thread_pool = gst_rtsp_thread_pool_new (); gst_rtsp_client_set_thread_pool (client, thread_pool); @@ -629,7 +659,7 @@ GST_START_TEST (test_client_multicast_transport_404) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (); + client = setup_multicast_client (1); /* simple SETUP for non-existing url */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, @@ -662,7 +692,7 @@ GST_START_TEST (test_client_multicast_transport) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (); + client = setup_multicast_client (1); expected_session_timeout = 20; g_signal_connect (G_OBJECT (client), "new-session", @@ -699,7 +729,7 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (); + client = setup_multicast_client (1); /* simple SETUP with a valid URI and multicast and a specific dest, * but ignore it */ @@ -735,7 +765,7 @@ multicast_transport_specific (void) GstRTSPSessionPool *session_pool; GstRTSPContext ctx = { NULL }; - client = setup_multicast_client (); + client = setup_multicast_client (1); ctx.client = client; ctx.auth = gst_rtsp_auth_new (); @@ -950,9 +980,11 @@ GST_START_TEST (test_client_sdp_with_no_bitrate_tags) GST_END_TEST; static void -mcast_transport_specific_two_clients (gboolean shared) +mcast_transport_specific_two_clients (gboolean shared, const gchar * transport1, + const gchar * expected_transport1, const gchar * transport2, + const gchar * expected_transport2) { - GstRTSPClient *client, *client2; + GstRTSPClient *client1, *client2; GstRTSPMessage request = { 0, }; gchar *str; GstRTSPSessionPool *session_pool; @@ -983,12 +1015,12 @@ mcast_transport_specific_two_clients (gboolean shared) thread_pool = gst_rtsp_thread_pool_new (); /* first multicast client with transport specific request */ - client = gst_rtsp_client_new (); - gst_rtsp_client_set_session_pool (client, session_pool); - gst_rtsp_client_set_mount_points (client, mount_points); - gst_rtsp_client_set_thread_pool (client, thread_pool); + client1 = gst_rtsp_client_new (); + gst_rtsp_client_set_session_pool (client1, session_pool); + gst_rtsp_client_set_mount_points (client1, mount_points); + gst_rtsp_client_set_thread_pool (client1, thread_pool); - ctx.client = client; + ctx.client = client1; ctx.auth = gst_rtsp_auth_new (); ctx.token = gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, @@ -996,20 +1028,18 @@ mcast_transport_specific_two_clients (gboolean shared) "user", NULL); gst_rtsp_context_push_current (&ctx); - expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; + expected_transport = expected_transport1; /* send SETUP request */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - expected_transport); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport1); - gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, + gst_rtsp_client_set_send_func (client1, test_setup_response_200_multicast, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, + fail_unless (gst_rtsp_client_handle_message (client1, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); expected_transport = NULL; @@ -1020,8 +1050,8 @@ mcast_transport_specific_two_clients (gboolean shared) str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); - gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, + gst_rtsp_client_set_send_func (client1, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client1, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); gst_rtsp_context_pop_current (&ctx); @@ -1042,16 +1072,14 @@ mcast_transport_specific_two_clients (gboolean shared) "user", NULL); gst_rtsp_context_push_current (&ctx2); - expected_transport = "RTP/AVP;multicast;destination=233.252.0.2;" - "ttl=1;port=5002-5003;mode=\"PLAY\""; + expected_transport = expected_transport2; /* send SETUP request */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - expected_transport); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport2); gst_rtsp_client_set_send_func (client2, test_setup_response_200_multicast, NULL, NULL); @@ -1076,10 +1104,10 @@ mcast_transport_specific_two_clients (gboolean shared) gst_rtsp_context_push_current (&ctx); session_id = session_id1; - send_teardown (client); + send_teardown (client1); gst_rtsp_context_pop_current (&ctx); - teardown_client (client); + teardown_client (client1); teardown_client (client2); g_object_unref (ctx.auth); g_object_unref (ctx2.auth); @@ -1095,7 +1123,16 @@ mcast_transport_specific_two_clients (gboolean shared) * CASE: media is shared */ GST_START_TEST (test_client_multicast_transport_specific_two_clients_shared_media) { - mcast_transport_specific_two_clients (TRUE); + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + + mcast_transport_specific_two_clients (TRUE, transport_client_1, + expected_transport_1, transport_client_2, expected_transport_2); } GST_END_TEST; @@ -1104,7 +1141,97 @@ GST_END_TEST; * CASE: media is not shared */ GST_START_TEST (test_client_multicast_transport_specific_two_clients) { - mcast_transport_specific_two_clients (FALSE); + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + + mcast_transport_specific_two_clients (FALSE, transport_client_1, + expected_transport_1, transport_client_2, expected_transport_2); +} + +GST_END_TEST; + +/* test if the maximum ttl multicast value is chosen by the server + * CASE: the first client provides the highest ttl value */ +GST_START_TEST (test_client_multicast_max_ttl_first_client) +{ + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=3;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; + const gchar *expected_transport_2 = + "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=3;port=5002-5003;mode=\"PLAY\""; + + mcast_transport_specific_two_clients (TRUE, transport_client_1, + expected_transport_1, transport_client_2, expected_transport_2); +} + +GST_END_TEST; + +/* test if the maximum ttl multicast value is chosen by the server + * CASE: the second client provides the highest ttl value */ +GST_START_TEST (test_client_multicast_max_ttl_second_client) +{ + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=2;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=4;port=5002-5003;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + + mcast_transport_specific_two_clients (TRUE, transport_client_1, + expected_transport_1, transport_client_2, expected_transport_2); +} + +GST_END_TEST; +GST_START_TEST (test_client_multicast_invalid_ttl) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + GstRTSPSessionPool *session_pool; + GstRTSPContext ctx = { NULL }; + + client = setup_multicast_client (3); + + ctx.client = client; + ctx.auth = gst_rtsp_auth_new (); + ctx.token = + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_context_push_current (&ctx); + + /* simple SETUP with an invalid ttl=0 */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast;destination=233.252.0.1;ttl=0;port=5000-5001;"); + + gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + session_pool = gst_rtsp_client_get_session_pool (client); + fail_unless (session_pool != NULL); + fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); + g_object_unref (session_pool); + + teardown_client (client); + g_object_unref (ctx.auth); + gst_rtsp_token_unref (ctx.token); + gst_rtsp_context_pop_current (&ctx); } GST_END_TEST; @@ -1134,6 +1261,9 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_transport_specific_two_clients); tcase_add_test (tc, test_client_multicast_transport_specific_no_address_in_pool); + tcase_add_test (tc, test_client_multicast_max_ttl_first_client); + tcase_add_test (tc, test_client_multicast_max_ttl_second_client); + tcase_add_test (tc, test_client_multicast_invalid_ttl); return s; } From cbe6ae3c48419be83e9ea49f49beff73449e33ff Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 26 Jul 2018 12:01:16 +0200 Subject: [PATCH 1546/1776] stream: Added a list of multicast client addresses When media is shared, the same media stream can be sent to multiple multicast groups. Currently, there is no API to retrieve multicast addresses from the stream. When calling gst_rtsp_stream_get_multicast_address() function, only the first multicast address is returned. With this patch, each multicast destination requested in SETUP will be stored in an internal list (call to gst_rtsp_stream_add_multicast_client_address()). The list of multicast groups requested by the clients can be retrieved by calling gst_rtsp_stream_get_multicast_client_addresses(). There still exist some problems with the current implementation in the multicast case: 1) The receiving part is currently only configured with regard to the first multicast client (see https://bugzilla.gnome.org/show_bug.cgi?id=796917). 2) Secondly, of security reasons, some constraints should be put on the requested multicast destinations (see https://bugzilla.gnome.org/show_bug.cgi?id=796916). Change-Id: I6b060746e472a0734cc2fd828ffe4ea2956733ea https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- gst/rtsp-server/rtsp-client.c | 10 ++ gst/rtsp-server/rtsp-stream.c | 263 ++++++++++++++++++++++++++++++---- gst/rtsp-server/rtsp-stream.h | 10 ++ tests/check/gst/client.c | 155 ++++++++++++++++++-- tests/check/gst/stream.c | 89 ++++++++++++ 5 files changed, 486 insertions(+), 41 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e89203def9..e7d17ca1c1 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2030,6 +2030,11 @@ default_configure_client_transport (GstRTSPClient * client, ct->ttl = addr->ttl; gst_rtsp_address_free (addr); } + + if (!gst_rtsp_stream_add_multicast_client_address (ctx->stream, + ct->destination, ct->port.min, ct->port.max, family)) + goto error_mcast_transport; + } else { GstRTSPUrl *url; @@ -2103,6 +2108,11 @@ no_socket: GST_ERROR_OBJECT (client, "Failed to get UDP socket"); return FALSE; } +error_mcast_transport: + { + GST_ERROR_OBJECT (client, "Failed to add multicast client transport"); + return FALSE; + } } static GstRTSPTransport * diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 33b6ff10f0..65f0f5d2c6 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -110,6 +110,7 @@ struct _GstRTSPStreamPrivate GstElement *mcast_udpsink[2]; GSocket *mcast_socket_v4[2]; GSocket *mcast_socket_v6[2]; + GList *mcast_clients; /* for TCP transport */ GstElement *appsrc[2]; @@ -292,6 +293,24 @@ gst_rtsp_stream_init (GstRTSPStream * stream) (GDestroyNotify) gst_caps_unref); } +typedef struct _UdpClientAddrInfo UdpClientAddrInfo; + +struct _UdpClientAddrInfo +{ + gchar *address; + guint rtp_port; + guint add_count; /* how often this address has been added */ +}; + +static void +free_mcast_client (gpointer data) +{ + UdpClientAddrInfo *client = data; + + g_free (client->address); + g_free (client); +} + static void gst_rtsp_stream_finalize (GObject * obj) { @@ -338,6 +357,7 @@ gst_rtsp_stream_finalize (GObject * obj) } g_free (priv->multicast_iface); + g_list_free_full (priv->mcast_clients, (GDestroyNotify) free_mcast_client); gst_object_unref (priv->payloader); if (priv->srcpad) @@ -1585,6 +1605,100 @@ cleanup: } } +/* must be called with lock */ +static gboolean +add_mcast_client_addr (GstRTSPStream * stream, const gchar * destination, + guint rtp_port, guint rtcp_port) +{ + GstRTSPStreamPrivate *priv; + GList *walk; + UdpClientAddrInfo *client; + GInetAddress *inet; + + priv = stream->priv; + + if (destination == NULL) + return FALSE; + + inet = g_inet_address_new_from_string (destination); + if (inet == NULL) + goto invalid_address; + + if (!g_inet_address_get_is_multicast (inet)) { + g_object_unref (inet); + goto invalid_address; + } + g_object_unref (inet); + + for (walk = priv->mcast_clients; walk; walk = g_list_next (walk)) { + UdpClientAddrInfo *cli = walk->data; + + if ((g_strcmp0 (cli->address, destination) == 0) && + (cli->rtp_port == rtp_port)) { + GST_DEBUG ("requested destination already exists: %s:%u-%u", + destination, rtp_port, rtcp_port); + cli->add_count++; + return TRUE; + } + } + + client = g_new0 (UdpClientAddrInfo, 1); + client->address = g_strdup (destination); + client->rtp_port = rtp_port; + client->add_count = 1; + priv->mcast_clients = g_list_prepend (priv->mcast_clients, client); + + GST_DEBUG ("added mcast client %s:%u-%u", destination, rtp_port, rtcp_port); + + return TRUE; + +invalid_address: + { + GST_WARNING_OBJECT (stream, "Multicast address is invalid: %s", + destination); + return FALSE; + } +} + +/* must be called with lock */ +static gboolean +remove_mcast_client_addr (GstRTSPStream * stream, const gchar * destination, + guint rtp_port, guint rtcp_port) +{ + GstRTSPStreamPrivate *priv; + GList *walk; + + priv = stream->priv; + + if (destination == NULL) + goto no_destination; + + for (walk = priv->mcast_clients; walk; walk = g_list_next (walk)) { + UdpClientAddrInfo *cli = walk->data; + + if ((g_strcmp0 (cli->address, destination) == 0) && + (cli->rtp_port == rtp_port)) { + cli->add_count--; + + if (!cli->add_count) { + priv->mcast_clients = g_list_remove (priv->mcast_clients, cli); + free_mcast_client (cli); + } + return TRUE; + } + } + + GST_WARNING_OBJECT (stream, "Address not found"); + return FALSE; + +no_destination: + { + GST_WARNING_OBJECT (stream, "No destination has been provided"); + return FALSE; + } +} + + /** * gst_rtsp_stream_allocate_udp_sockets: * @stream: a #GstRTSPStream @@ -3368,38 +3482,29 @@ udpsrc_error: } static gboolean -check_mcast_part_for_transport (GstRTSPStream * stream, - const GstRTSPTransport * tr) +check_mcast_client_addr (GstRTSPStream * stream, const GstRTSPTransport * tr) { GstRTSPStreamPrivate *priv = stream->priv; - GInetAddress *inetaddr; - GSocketFamily family; - GstRTSPAddress *mcast_addr; + GList *walk; - /* Check if it's a ipv4 or ipv6 transport */ - inetaddr = g_inet_address_new_from_string (tr->destination); - family = g_inet_address_get_family (inetaddr); - g_object_unref (inetaddr); - - /* Select fields corresponding to the family */ - if (family == G_SOCKET_FAMILY_IPV4) { - mcast_addr = priv->mcast_addr_v4; - } else { - mcast_addr = priv->mcast_addr_v6; - } - - /* We support only one mcast group per family, make sure this transport - * matches it. */ - if (!mcast_addr) + if (priv->mcast_clients == NULL) goto no_addr; - if (g_ascii_strcasecmp (tr->destination, mcast_addr->address) != 0 || - tr->port.min != mcast_addr->port || - tr->port.max != mcast_addr->port + mcast_addr->n_ports - 1 || - tr->ttl != mcast_addr->ttl) - goto wrong_addr; + if (tr == NULL) + goto no_transport; - return TRUE; + if (tr->destination == NULL) + goto no_destination; + + for (walk = priv->mcast_clients; walk; walk = g_list_next (walk)) { + UdpClientAddrInfo *cli = walk->data; + + if ((g_strcmp0 (cli->address, tr->destination) == 0) && + (cli->rtp_port == tr->port.min)) + return TRUE; + } + + return FALSE; no_addr: { @@ -3407,7 +3512,13 @@ no_addr: "has been reserved"); return FALSE; } -wrong_addr: +no_transport: + { + GST_WARNING_OBJECT (stream, "Adding mcast transport, but no transport " + "has been provided"); + return FALSE; + } +no_destination: { GST_WARNING_OBJECT (stream, "Adding mcast transport, but it doesn't match " "the reserved address"); @@ -4084,8 +4195,10 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, if (add) { GST_INFO ("adding %s:%d-%d", dest, min, max); - if (!check_mcast_part_for_transport (stream, tr)) + if (!check_mcast_client_addr (stream, tr)) goto mcast_error; + add_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min, + max); if (tr->ttl > 0) { GST_INFO ("setting ttl-mc %d", tr->ttl); @@ -4096,11 +4209,12 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, g_object_set (G_OBJECT (priv->mcast_udpsink[1]), "ttl-mc", tr->ttl, NULL); } - add_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min, - max); priv->transports = g_list_prepend (priv->transports, trans); } else { GST_INFO ("removing %s:%d-%d", dest, min, max); + if (!remove_mcast_client_addr (stream, dest, min, max)) + GST_WARNING_OBJECT (stream, + "Failed to remove multicast address: %s:%d-%d", dest, min, max); remove_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min, max); priv->transports = g_list_remove (priv->transports, trans); @@ -4450,6 +4564,95 @@ gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream * stream, return socket; } +/** + * gst_rtsp_stream_add_multicast_client_address: + * @stream: a #GstRTSPStream + * @destination: (transfer none): a multicast address to add + * @rtp_port: RTP port + * @rtcp_port: RTCP port + * @family: socket family + * + * Add multicast client address to stream. At this point, the sockets that + * will stream RTP and RTCP data to @destination are supposed to be + * allocated. + * + * Returns: %TRUE if @destination can be addedd and handled by @stream. + */ +gboolean +gst_rtsp_stream_add_multicast_client_address (GstRTSPStream * stream, + const gchar * destination, guint rtp_port, guint rtcp_port, + GSocketFamily family) +{ + GstRTSPStreamPrivate *priv; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + g_return_val_if_fail (destination != NULL, FALSE); + + priv = stream->priv; + g_mutex_lock (&priv->lock); + if ((family == G_SOCKET_FAMILY_IPV4) && (priv->mcast_socket_v4[0] == NULL)) + goto socket_error; + else if ((family == G_SOCKET_FAMILY_IPV6) && + (priv->mcast_socket_v6[0] == NULL)) + goto socket_error; + + if (!add_mcast_client_addr (stream, destination, rtp_port, rtcp_port)) + goto add_addr_error; + g_mutex_unlock (&priv->lock); + + return TRUE; + +socket_error: + { + GST_WARNING_OBJECT (stream, + "Failed to add multicast address: no udp socket"); + g_mutex_unlock (&priv->lock); + return FALSE; + } +add_addr_error: + { + GST_WARNING_OBJECT (stream, + "Failed to add multicast address: invalid address"); + g_mutex_unlock (&priv->lock); + return FALSE; + } +} + +/** + * gst_rtsp_stream_get_multicast_client_addresses + * @stream: a #GstRTSPStream + * + * Get all multicast client addresses that RTP data will be sent to + * + * Returns: A comma separated list of host:port pairs with destinations + */ +gchar * +gst_rtsp_stream_get_multicast_client_addresses (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + GString *str; + GList *clients; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + priv = stream->priv; + str = g_string_new (""); + + g_mutex_lock (&priv->lock); + clients = priv->mcast_clients; + while (clients != NULL) { + UdpClientAddrInfo *client; + + client = (UdpClientAddrInfo *) clients->data; + clients = g_list_next (clients); + g_string_append_printf (str, "%s:%d%s", client->address, client->rtp_port, + (clients != NULL ? "," : "")); + } + g_mutex_unlock (&priv->lock); + + return g_string_free (str, FALSE); +} + /** * gst_rtsp_stream_set_seqnum: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index ea21858424..0c6804d536 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -233,6 +233,16 @@ GST_RTSP_SERVER_API GSocket * gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream *stream, GSocketFamily family); +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_add_multicast_client_address (GstRTSPStream * stream, + const gchar * destination, + guint rtp_port, + guint rtcp_port, + GSocketFamily family); + +GST_RTSP_SERVER_API +gchar * gst_rtsp_stream_get_multicast_client_addresses (GstRTSPStream * stream); + GST_RTSP_SERVER_API gboolean gst_rtsp_stream_update_crypto (GstRTSPStream * stream, guint ssrc, GstCaps * crypto); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index a420f65706..d890b8218b 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -980,9 +980,10 @@ GST_START_TEST (test_client_sdp_with_no_bitrate_tags) GST_END_TEST; static void -mcast_transport_specific_two_clients (gboolean shared, const gchar * transport1, - const gchar * expected_transport1, const gchar * transport2, - const gchar * expected_transport2) +mcast_transport_two_clients (gboolean shared, const gchar * transport1, + const gchar * expected_transport1, const gchar * addr1, + const gchar * transport2, const gchar * expected_transport2, + const gchar * addr2) { GstRTSPClient *client1, *client2; GstRTSPMessage request = { 0, }; @@ -995,6 +996,7 @@ mcast_transport_specific_two_clients (gboolean shared, const gchar * transport1, GstRTSPAddressPool *address_pool; GstRTSPThreadPool *thread_pool; gchar *session_id1; + gchar *client_addr = NULL; mount_points = gst_rtsp_mount_points_new (); factory = gst_rtsp_media_factory_new (); @@ -1054,6 +1056,13 @@ mcast_transport_specific_two_clients (gboolean shared, const gchar * transport1, fail_unless (gst_rtsp_client_handle_message (client1, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); + + /* check address */ + client_addr = gst_rtsp_stream_get_multicast_client_addresses (ctx.stream); + fail_if (client_addr == NULL); + fail_unless (g_str_equal (client_addr, addr1)); + g_free (client_addr); + gst_rtsp_context_pop_current (&ctx); session_id1 = session_id; @@ -1099,6 +1108,22 @@ mcast_transport_specific_two_clients (gboolean shared, const gchar * transport1, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); + /* check addresses */ + client_addr = gst_rtsp_stream_get_multicast_client_addresses (ctx2.stream); + fail_if (client_addr == NULL); + if (shared) { + if (g_str_equal (addr1, addr2)) { + fail_unless (g_str_equal (client_addr, addr1)); + } else { + gchar *addr_str = g_strdup_printf ("%s,%s", addr2, addr1); + fail_unless (g_str_equal (client_addr, addr_str)); + g_free (addr_str); + } + } else { + fail_unless (g_str_equal (client_addr, addr2)); + } + g_free (client_addr); + send_teardown (client2); gst_rtsp_context_pop_current (&ctx2); @@ -1126,13 +1151,16 @@ GST_START_TEST const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" "ttl=1;port=5000-5001;mode=\"PLAY\""; const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:5000"; const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" "ttl=1;port=5002-5003;mode=\"PLAY\""; const gchar *expected_transport_2 = transport_client_2; + const gchar *addr_client_2 = "233.252.0.2:5002"; - mcast_transport_specific_two_clients (TRUE, transport_client_1, - expected_transport_1, transport_client_2, expected_transport_2); + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); } GST_END_TEST; @@ -1144,13 +1172,105 @@ GST_START_TEST (test_client_multicast_transport_specific_two_clients) const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" "ttl=1;port=5000-5001;mode=\"PLAY\""; const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:5000"; const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" "ttl=1;port=5002-5003;mode=\"PLAY\""; const gchar *expected_transport_2 = transport_client_2; + const gchar *addr_client_2 = "233.252.0.2:5002"; - mcast_transport_specific_two_clients (FALSE, transport_client_1, - expected_transport_1, transport_client_2, expected_transport_2); + mcast_transport_two_clients (FALSE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); +} + +GST_END_TEST; + +/* test if two multicast clients can choose the same transport settings. + * CASE: media is shared */ +GST_START_TEST + (test_client_multicast_transport_specific_two_clients_shared_media_same_transport) +{ + + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:5000"; + + const gchar *transport_client_2 = transport_client_1; + const gchar *expected_transport_2 = expected_transport_1; + const gchar *addr_client_2 = addr_client_1; + + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); +} + +GST_END_TEST; + +/* test if two multicast clients get the same transport settings without + * requesting specific transport. + * CASE: media is shared */ +GST_START_TEST (test_client_multicast_two_clients_shared_media) +{ + const gchar *transport_client_1 = "RTP/AVP;multicast;mode=\"PLAY\""; + const gchar *expected_transport_1 = + "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *addr_client_1 = "233.252.0.1:5000"; + + const gchar *transport_client_2 = transport_client_1; + const gchar *expected_transport_2 = expected_transport_1; + const gchar *addr_client_2 = addr_client_1; + + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); +} + +GST_END_TEST; + +/* test if two multicast clients get the different transport settings: the first client + * requests the specific transport configuration while the second client lets + * the server select the multicast address and the ports. + * CASE: media is shared */ +GST_START_TEST + (test_client_multicast_two_clients_first_specific_transport_shared_media) { + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:5000"; + + const gchar *transport_client_2 = "RTP/AVP;multicast;mode=\"PLAY\""; + const gchar *expected_transport_2 = expected_transport_1; + const gchar *addr_client_2 = addr_client_1; + + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); +} + +GST_END_TEST; +/* test if two multicast clients get the different transport settings: the first client lets + * the server select the multicast address and the ports while the second client requests + * the specific transport configuration. + * CASE: media is shared */ +GST_START_TEST + (test_client_multicast_two_clients_second_specific_transport_shared_media) { + const gchar *transport_client_1 = "RTP/AVP;multicast;mode=\"PLAY\""; + const gchar *expected_transport_1 = + "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *addr_client_1 = "233.252.0.1:5000"; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=2;port=5004-5005;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + const gchar *addr_client_2 = "233.252.0.2:5004"; + + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); } GST_END_TEST; @@ -1162,15 +1282,18 @@ GST_START_TEST (test_client_multicast_max_ttl_first_client) const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" "ttl=3;port=5000-5001;mode=\"PLAY\""; const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:5000"; const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" "ttl=1;port=5002-5003;mode=\"PLAY\""; const gchar *expected_transport_2 = "RTP/AVP;multicast;destination=233.252.0.2;" "ttl=3;port=5002-5003;mode=\"PLAY\""; + const gchar *addr_client_2 = "233.252.0.2:5002"; - mcast_transport_specific_two_clients (TRUE, transport_client_1, - expected_transport_1, transport_client_2, expected_transport_2); + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); } GST_END_TEST; @@ -1182,13 +1305,16 @@ GST_START_TEST (test_client_multicast_max_ttl_second_client) const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" "ttl=2;port=5000-5001;mode=\"PLAY\""; const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:5000"; const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" "ttl=4;port=5002-5003;mode=\"PLAY\""; const gchar *expected_transport_2 = transport_client_2; + const gchar *addr_client_2 = "233.252.0.2:5002"; - mcast_transport_specific_two_clients (TRUE, transport_client_1, - expected_transport_1, transport_client_2, expected_transport_2); + mcast_transport_two_clients (TRUE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2); } GST_END_TEST; @@ -1259,6 +1385,13 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_transport_specific_two_clients_shared_media); tcase_add_test (tc, test_client_multicast_transport_specific_two_clients); + tcase_add_test (tc, + test_client_multicast_transport_specific_two_clients_shared_media_same_transport); + tcase_add_test (tc, test_client_multicast_two_clients_shared_media); + tcase_add_test (tc, + test_client_multicast_two_clients_first_specific_transport_shared_media); + tcase_add_test (tc, + test_client_multicast_two_clients_second_specific_transport_shared_media); tcase_add_test (tc, test_client_multicast_transport_specific_no_address_in_pool); tcase_add_test (tc, test_client_multicast_max_ttl_first_client); diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index 7b59c0abc9..d77180e775 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -486,6 +486,93 @@ GST_START_TEST (test_tcp_transport) GST_END_TEST; +static void +check_multicast_client_address (const gchar * destination, guint port, + const gchar * expected_addr_str, gboolean expected_res) +{ + GstPad *srcpad; + GstElement *pay; + GstRTSPStream *stream; + GstBin *bin; + GstElement *rtpbin; + GstRTSPTransport *transport; + GstRTSPRange ports = { 0 }; + gchar *addr_str = NULL; + + srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); + fail_unless (srcpad != NULL); + gst_pad_set_active (srcpad, TRUE); + pay = gst_element_factory_make ("rtpgstpay", "testpayloader"); + fail_unless (pay != NULL); + stream = gst_rtsp_stream_new (0, pay, srcpad); + fail_unless (stream != NULL); + gst_object_unref (pay); + gst_object_unref (srcpad); + rtpbin = gst_element_factory_make ("rtpbin", "testrtpbin"); + fail_unless (rtpbin != NULL); + bin = GST_BIN (gst_bin_new ("testbin")); + fail_unless (bin != NULL); + fail_unless (gst_bin_add (bin, rtpbin)); + + fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + + fail_unless (gst_rtsp_transport_new (&transport) == GST_RTSP_OK); + transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST; + transport->destination = g_strdup (destination); + transport->ttl = 1; + ports.min = port; + ports.max = port + 1; + transport->port = ports; + + /* allocate ports */ + fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream, + G_SOCKET_FAMILY_IPV4, transport, TRUE) == expected_res); + + fail_unless (gst_rtsp_stream_add_multicast_client_address (stream, + destination, ports.min, ports.max, G_SOCKET_FAMILY_IPV4) == expected_res); + + fail_unless (gst_rtsp_stream_complete_stream (stream, transport) == expected_res); + + fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK); + addr_str = gst_rtsp_stream_get_multicast_client_addresses (stream); + + fail_unless (g_str_equal (addr_str, expected_addr_str)); + g_free (addr_str); + + fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); + + gst_object_unref (bin); + gst_object_unref (stream); +} + +/* test if the provided transport destination is correct. + * CASE: valid multicast address */ +GST_START_TEST (test_multicast_client_address) +{ + const gchar *addr = "233.252.0.1"; + guint port = 50000; + const gchar *expected_addr_str = "233.252.0.1:50000"; + gboolean expected_res = TRUE; + + check_multicast_client_address (addr, port, expected_addr_str, expected_res); +} + +GST_END_TEST; + +/* test if the provided transport destination is correct. + * CASE: invalid multicast address */ +GST_START_TEST (test_multicast_client_address_invalid) +{ + const gchar *addr = "1.2.3.4"; + guint port = 50000; + const gchar *expected_addr_str = ""; + gboolean expected_res = FALSE; + + check_multicast_client_address (addr, port, expected_addr_str, expected_res); +} + +GST_END_TEST; + static Suite * rtspstream_suite (void) { @@ -501,6 +588,8 @@ rtspstream_suite (void) tcase_add_test (tc, test_allocate_udp_ports_multicast); tcase_add_test (tc, test_allocate_udp_ports_client_settings); tcase_add_test (tc, test_tcp_transport); + tcase_add_test (tc, test_multicast_client_address); + tcase_add_test (tc, test_multicast_client_address_invalid); return s; } From bd76c2f9c583cd0dd525682a337fcaa9c0a0e9c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 14 Aug 2018 14:31:55 +0300 Subject: [PATCH 1547/1776] Fix indentation again --- gst/rtsp-server/rtsp-client.c | 10 ++++++---- tests/check/gst/stream.c | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e7d17ca1c1..d4c5211985 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1986,12 +1986,14 @@ default_configure_client_transport (GstRTSPClient * client, */ /* FIXME: could be more adequately solved by making it possible * to set a socket on multiudpsink after it has already been started */ - if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, G_SOCKET_FAMILY_IPV4, ct, - use_client_settings) && family == G_SOCKET_FAMILY_IPV4) + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, + G_SOCKET_FAMILY_IPV4, ct, use_client_settings) + && family == G_SOCKET_FAMILY_IPV4) goto error_allocating_ports; - if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, G_SOCKET_FAMILY_IPV6, ct, - use_client_settings) && family == G_SOCKET_FAMILY_IPV6) + if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, + G_SOCKET_FAMILY_IPV6, ct, use_client_settings) + && family == G_SOCKET_FAMILY_IPV6) goto error_allocating_ports; if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index d77180e775..d71f1937f4 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -529,9 +529,11 @@ check_multicast_client_address (const gchar * destination, guint port, G_SOCKET_FAMILY_IPV4, transport, TRUE) == expected_res); fail_unless (gst_rtsp_stream_add_multicast_client_address (stream, - destination, ports.min, ports.max, G_SOCKET_FAMILY_IPV4) == expected_res); + destination, ports.min, ports.max, + G_SOCKET_FAMILY_IPV4) == expected_res); - fail_unless (gst_rtsp_stream_complete_stream (stream, transport) == expected_res); + fail_unless (gst_rtsp_stream_complete_stream (stream, + transport) == expected_res); fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK); addr_str = gst_rtsp_stream_get_multicast_client_addresses (stream); From f0e1c6ad80aa4af1b926feed32671706191cd77e Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Wed, 15 Aug 2018 18:57:27 +0530 Subject: [PATCH 1548/1776] meson: There is no gstreamer-plugins-good-1.0.pc There is no installed version of that, only an uninstalled version. --- tests/check/meson.build | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/check/meson.build b/tests/check/meson.build index de2f1289f0..71db67f99e 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -7,12 +7,10 @@ pluginsdirs = [] if gst_dep.type_name() == 'pkgconfig' pbase = dependency('gstreamer-plugins-base-' + api_version, required : false) pbad = dependency('gstreamer-plugins-bad-' + api_version, required : false) - pgood = dependency('gstreamer-plugins-good-' + api_version, required : false) pluginsdirs = [gst_dep.get_pkgconfig_variable('pluginsdir'), pbase.get_pkgconfig_variable('pluginsdir'), - pbad.get_pkgconfig_variable('pluginsdir'), - pgood.get_pkgconfig_variable('pluginsdir')] + pbad.get_pkgconfig_variable('pluginsdir')] endif test_c_args = [ From 990d5dde86a04f64b9da663eb54e2e46bd8b6c69 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Fri, 17 Aug 2018 09:54:27 +0200 Subject: [PATCH 1549/1776] rtsp-client: Add unit test of SETUP for RTSP/RTP/TCP Allow regex for matching transport header against expected pattern. https://bugzilla.gnome.org/show_bug.cgi?id=796988 --- tests/check/gst/client.c | 89 +++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 24 deletions(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index d890b8218b..6368c1538f 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -135,6 +135,20 @@ test_response_551 (GstRTSPClient * client, GstRTSPMessage * response, return TRUE; } +static void +create_connection (GstRTSPConnection ** conn) +{ + GSocket *sock; + GError *error = NULL; + + sock = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_TCP, &error); + g_assert_no_error (error); + fail_unless (gst_rtsp_connection_create_from_socket (sock, "127.0.0.1", 444, + NULL, conn) == GST_RTSP_OK); + g_object_unref (sock); +} + static GstRTSPClient * setup_client (const gchar * launch_line) { @@ -291,8 +305,6 @@ GST_START_TEST (test_request) GstRTSPMessage request = { 0, }; gchar *str; GstRTSPConnection *conn; - GSocket *sock; - GError *error = NULL; client = gst_rtsp_client_new (); @@ -325,13 +337,8 @@ GST_START_TEST (test_request) /* OPTIONS with an absolute path instead of an absolute url */ /* set host information */ - sock = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, - G_SOCKET_PROTOCOL_TCP, &error); - g_assert_no_error (error); - gst_rtsp_connection_create_from_socket (sock, "localhost", 444, NULL, &conn); + create_connection (&conn); fail_unless (gst_rtsp_client_set_connection (client, conn)); - g_object_unref (sock); - fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS, "/test") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); @@ -472,13 +479,14 @@ GST_END_TEST; static const gchar *expected_transport = NULL; static gboolean -test_setup_response_200_multicast (GstRTSPClient * client, - GstRTSPMessage * response, gboolean close, gpointer user_data) +test_setup_response_200 (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) { GstRTSPStatusCode code; const gchar *reason; GstRTSPVersion version; gchar *str; + gchar *pattern; GstRTSPSessionPool *session_pool; GstRTSPSession *session; gchar **session_hdr_params; @@ -502,7 +510,10 @@ test_setup_response_200_multicast (GstRTSPClient * client, fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_TRANSPORT, &str, 0) == GST_RTSP_OK); - fail_unless_equals_string (str, expected_transport); + pattern = g_strdup_printf ("^%s$", expected_transport); + fail_unless (g_regex_match_simple (pattern, str, 0, 0), + "Transport '%s' doesn't match pattern '%s'", str, pattern); + g_free (pattern); fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &str, 0) == GST_RTSP_OK); @@ -529,6 +540,8 @@ test_setup_response_200_multicast (GstRTSPClient * client, g_strfreev (session_hdr_params); /* remember session id to be able to send teardown */ + if (session_id) + g_free (session_id); session_id = g_strdup (gst_rtsp_session_get_sessionid (session)); fail_unless (session_id != NULL); @@ -612,6 +625,39 @@ send_teardown (GstRTSPClient * client) session_id = NULL; } +GST_START_TEST (test_setup_tcp) +{ + GstRTSPClient *client; + GstRTSPConnection *conn; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = setup_client (NULL); + create_connection (&conn); + fail_unless (gst_rtsp_client_set_connection (client, conn)); + + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP/TCP;unicast"); + + gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); + expected_transport = + "RTP/AVP/TCP;unicast;interleaved=0-1;ssrc=.*;mode=\"PLAY\""; + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + + gst_rtsp_message_unset (&request); + + send_teardown (client); + teardown_client (client); +} + +GST_END_TEST; + static GstRTSPClient * setup_multicast_client (guint max_ttl) { @@ -708,8 +754,7 @@ GST_START_TEST (test_client_multicast_transport) expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" "ttl=1;port=5000-5001;mode=\"PLAY\""; - gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, - NULL, NULL); + gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); @@ -742,8 +787,7 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" "ttl=1;port=5000-5001;mode=\"PLAY\""; - gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, - NULL, NULL); + gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); @@ -786,14 +830,12 @@ multicast_transport_specific (void) gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, expected_transport); - gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, - NULL, NULL); + gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, - NULL, NULL); + gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); session_pool = gst_rtsp_client_get_session_pool (client); fail_unless (session_pool != NULL); fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 1); @@ -1039,8 +1081,7 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport1); - gst_rtsp_client_set_send_func (client1, test_setup_response_200_multicast, - NULL, NULL); + gst_rtsp_client_set_send_func (client1, test_setup_response_200, NULL, NULL); fail_unless (gst_rtsp_client_handle_message (client1, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); @@ -1064,7 +1105,7 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, g_free (client_addr); gst_rtsp_context_pop_current (&ctx); - session_id1 = session_id; + session_id1 = g_strdup (session_id); /* second multicast client with transport specific request */ cseq = 0; @@ -1090,8 +1131,7 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport2); - gst_rtsp_client_set_send_func (client2, test_setup_response_200_multicast, - NULL, NULL); + gst_rtsp_client_set_send_func (client2, test_setup_response_200, NULL, NULL); fail_unless (gst_rtsp_client_handle_message (client2, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); @@ -1374,6 +1414,7 @@ rtspclient_suite (void) tcase_add_test (tc, test_request); tcase_add_test (tc, test_options); tcase_add_test (tc, test_describe); + tcase_add_test (tc, test_setup_tcp); tcase_add_test (tc, test_client_multicast_transport_404); tcase_add_test (tc, test_client_multicast_transport); tcase_add_test (tc, test_client_multicast_ignore_transport_specific); From a2e182c3b41cf7a149d099d65e32ac512dd60dc3 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Fri, 17 Aug 2018 09:54:27 +0200 Subject: [PATCH 1550/1776] rtsp-client: Avoid reuse of channel numbers for interleaved If a (strange) client would reuse interleaved channel numbers in multiple SETUP requests, we should not accept them. The channel numbers are used for looking up stream transports in the priv->transports hash table, and transports disappear from the table if channel numbers are reused. RFC 7826 (RTSP 2.0), Section 18.54, clarifies that it is OK for the server to change the channel numbers suggested by the client. https://bugzilla.gnome.org/show_bug.cgi?id=796988 --- gst/rtsp-server/rtsp-client.c | 15 +++++++++ tests/check/gst/client.c | 61 +++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d4c5211985..2e124f8739 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2084,6 +2084,16 @@ default_configure_client_transport (GstRTSPClient * client, gst_rtsp_session_media_alloc_channels (ctx->sessmedia, &ct->interleaved); } + /* alloc new channels if they are already taken */ + while (g_hash_table_contains (priv->transports, + GINT_TO_POINTER (ct->interleaved.min)) + || g_hash_table_contains (priv->transports, + GINT_TO_POINTER (ct->interleaved.max))) { + gst_rtsp_session_media_alloc_channels (ctx->sessmedia, + &ct->interleaved); + if (ct->interleaved.max > 255) + goto error_allocating_channels; + } } } return TRUE; @@ -2115,6 +2125,11 @@ error_mcast_transport: GST_ERROR_OBJECT (client, "Failed to add multicast client transport"); return FALSE; } +error_allocating_channels: + { + GST_ERROR_OBJECT (client, "Failed to allocate interleaved channels"); + return FALSE; + } } static GstRTSPTransport * diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 6368c1538f..aa7893c737 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -21,6 +21,13 @@ #include +#define VIDEO_PIPELINE "videotestsrc ! " \ + "video/x-raw,width=352,height=288 ! " \ + "rtpgstpay name=pay0 pt=96" +#define AUDIO_PIPELINE "audiotestsrc ! " \ + "audio/x-raw,rate=8000 ! " \ + "rtpgstpay name=pay1 pt=97" + static gchar *session_id; static gint cseq; static guint expected_session_timeout = 60; @@ -167,7 +174,7 @@ setup_client (const gchar * launch_line) factory = gst_rtsp_media_factory_new (); if (launch_line == NULL) gst_rtsp_media_factory_set_launch (factory, - "videotestsrc ! video/x-raw,width=352,height=288 ! rtpgstpay name=pay0 pt=96"); + "( " VIDEO_PIPELINE " " AUDIO_PIPELINE " )"); else gst_rtsp_media_factory_set_launch (factory, launch_line); @@ -637,7 +644,7 @@ GST_START_TEST (test_setup_tcp) fail_unless (gst_rtsp_client_set_connection (client, conn)); fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test") == GST_RTSP_OK); + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); g_free (str); @@ -658,6 +665,55 @@ GST_START_TEST (test_setup_tcp) GST_END_TEST; +GST_START_TEST (test_setup_tcp_two_streams_same_channels) +{ + GstRTSPClient *client; + GstRTSPConnection *conn; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = setup_client (NULL); + create_connection (&conn); + fail_unless (gst_rtsp_client_set_connection (client, conn)); + + /* test SETUP of a video stream with 0-1 as interleaved channels */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP/TCP;unicast;interleaved=0-1"); + gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); + expected_transport = + "RTP/AVP/TCP;unicast;interleaved=0-1;ssrc=.*;mode=\"PLAY\""; + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + /* test SETUP of an audio stream with *the same* interleaved channels. + * we expect the server to allocate new channel numbers */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=1") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP/TCP;unicast;interleaved=0-1"); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); + expected_transport = + "RTP/AVP/TCP;unicast;interleaved=2-3;ssrc=.*;mode=\"PLAY\""; + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + send_teardown (client); + teardown_client (client); +} + +GST_END_TEST; + static GstRTSPClient * setup_multicast_client (guint max_ttl) { @@ -1415,6 +1471,7 @@ rtspclient_suite (void) tcase_add_test (tc, test_options); tcase_add_test (tc, test_describe); tcase_add_test (tc, test_setup_tcp); + tcase_add_test (tc, test_setup_tcp_two_streams_same_channels); tcase_add_test (tc, test_client_multicast_transport_404); tcase_add_test (tc, test_client_multicast_transport); tcase_add_test (tc, test_client_multicast_ignore_transport_specific); From 5bd835a196288b7c405466498a1b502414a1174e Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Fri, 31 Aug 2018 17:20:47 +1000 Subject: [PATCH 1551/1776] meson: add pkg-config file for the rtspclientsink plugin --- gst/rtsp-sink/meson.build | 1 + meson.build | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/gst/rtsp-sink/meson.build b/gst/rtsp-sink/meson.build index b8fe2f0c64..ad3f40e6e3 100644 --- a/gst/rtsp-sink/meson.build +++ b/gst/rtsp-sink/meson.build @@ -10,3 +10,4 @@ rtspsink = library('gstrtspclientsink', dependencies : [gstrtsp_dep, gstsdp_dep, gst_rtsp_server_dep], install : true, install_dir : plugins_install_dir) +pkgconfig.generate(rtspsink, install_dir : plugins_pkgconfig_install_dir) diff --git a/meson.build b/meson.build index 91551c8a97..be0674c434 100644 --- a/meson.build +++ b/meson.build @@ -124,6 +124,13 @@ gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**);' + 'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \ 'gst_init(NULL,NULL);' ] +pkgconfig = import('pkgconfig') +plugins_pkgconfig_install_dir = join_paths(plugins_install_dir, 'pkgconfig') +if get_option('default_library') == 'shared' + # If we don't build static plugins there is no need to generate pc files + plugins_pkgconfig_install_dir = disabler() +endif + subdir('gst') if get_option('tests') subdir('tests') From 8a7f5cfe5f514923df7b190af63a2a8e94940ea8 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Fri, 31 Aug 2018 14:42:15 +0530 Subject: [PATCH 1552/1776] meson: Maintain macOS ABI through dylib versioning Requires Meson 0.48, but the feature will be ignored on older versions so it's safe to add it without bumping the requirement. Documentation: https://github.com/mesonbuild/meson/blob/master/docs/markdown/Reference-manual.md#shared_library --- gst/rtsp-server/meson.build | 1 + meson.build | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index c2d7b37036..d0fbde1dba 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -51,6 +51,7 @@ gst_rtsp_server = library('gstrtspserver-@0@'.format(api_version), c_args: rtspserver_args, version : libversion, soversion : soversion, + darwin_versions : osxversion, install : true, dependencies : gst_rtsp_server_deps) diff --git a/meson.build b/meson.build index be0674c434..2d79283838 100644 --- a/meson.build +++ b/meson.build @@ -21,7 +21,9 @@ api_version = '1.0' soversion = 0 # maintaining compatibility with the previous libtool versioning # current = minor * 100 + micro -libversion = '@0@.@1@.0'.format(soversion, gst_version_minor * 100 + gst_version_micro) +curversion = gst_version_minor * 100 + gst_version_micro +libversion = '@0@.@1@.0'.format(soversion, curversion) +osxversion = curversion + 1 plugins_install_dir = '@0@/gstreamer-1.0'.format(get_option('libdir')) From 517757791e1245ae9f7aa72d496b7f16c31d84f9 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Sat, 1 Sep 2018 11:21:15 +0530 Subject: [PATCH 1553/1776] meson: Use feature option for tests option This was somehow missed the last time around. --- meson.build | 7 ++++++- meson_options.txt | 2 +- tests/check/meson.build | 4 ---- tests/meson.build | 3 ++- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index 2d79283838..77be55f908 100644 --- a/meson.build +++ b/meson.build @@ -116,6 +116,11 @@ gstapp_dep = dependency('gstreamer-app-1.0', version : gst_req, fallback : ['gst-plugins-base', 'app_dep']) gstnet_dep = dependency('gstreamer-net-1.0', version : gst_req, fallback : ['gstreamer', 'gst_net_dep']) +if host_machine.system() != 'windows' + gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, + required : get_option('tests'), + fallback : ['gstreamer', 'gst_check_dep']) +endif gir = find_program('g-ir-scanner', required : get_option('introspection')) gnome = import('gnome') @@ -134,7 +139,7 @@ if get_option('default_library') == 'shared' endif subdir('gst') -if get_option('tests') +if not get_option('tests').disabled() subdir('tests') endif if not get_option('examples').disabled() diff --git a/meson_options.txt b/meson_options.txt index eb6f20f24f..40d676fe40 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -5,7 +5,7 @@ option('package-name', type : 'string', yield : true, option('package-origin', type : 'string', value : 'Unknown package origin', yield : true, description : 'package origin URL to use in plugins') -option('tests', type : 'boolean', value : true, +option('tests', type : 'feature', value : 'auto', yield : true, description : 'Build and enable unit tests') option('examples', type : 'feature', value : 'auto', yield : true, description : 'Build the examples') diff --git a/tests/check/meson.build b/tests/check/meson.build index 71db67f99e..fb9eb9be0a 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -1,8 +1,4 @@ # FIXME: something is wrong with plugin paths / whitelisting here -gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, - fallback : ['gstreamer', 'gst_check_dep']) - - pluginsdirs = [] if gst_dep.type_name() == 'pkgconfig' pbase = dependency('gstreamer-plugins-base-' + api_version, required : false) diff --git a/tests/meson.build b/tests/meson.build index f87683d9ef..5374bcba45 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,4 +1,5 @@ -if host_machine.system() != 'windows' +# FIXME: make check work on windows +if host_machine.system() != 'windows' and gstcheck_dep.found() subdir('check') endif From 46d8bb28815f55d19c17b01222ac56a7ea3ebd80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 19 Sep 2018 12:10:14 +0100 Subject: [PATCH 1554/1776] meson: re-arrange options --- meson_options.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/meson_options.txt b/meson_options.txt index 40d676fe40..5b31724426 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,11 +1,14 @@ +# Common feature options +option('examples', type : 'feature', value : 'auto', yield : true, + description : 'Build the examples') +option('tests', type : 'feature', value : 'auto', yield : true, + description : 'Build and enable unit tests') option('introspection', type : 'feature', value : 'auto', yield : true, description : 'Generate gobject-introspection bindings') + +# Common options option('package-name', type : 'string', yield : true, description : 'package name to use in plugins') option('package-origin', type : 'string', value : 'Unknown package origin', yield : true, description : 'package origin URL to use in plugins') -option('tests', type : 'feature', value : 'auto', yield : true, - description : 'Build and enable unit tests') -option('examples', type : 'feature', value : 'auto', yield : true, - description : 'Build the examples') From ffebe3dd8444d6d4582ce75561f8b9ca586b089e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 19 Sep 2018 12:17:57 +0100 Subject: [PATCH 1555/1776] meson: add option to disable build of rtspclientsink plugin --- gst/meson.build | 5 ++++- meson_options.txt | 3 +++ tests/check/meson.build | 5 ++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/gst/meson.build b/gst/meson.build index 229c861eed..59cb3e4750 100644 --- a/gst/meson.build +++ b/gst/meson.build @@ -1,2 +1,5 @@ subdir('rtsp-server') -subdir('rtsp-sink') + +if not get_option('rtspclientsink').disabled() + subdir('rtsp-sink') +endif diff --git a/meson_options.txt b/meson_options.txt index 5b31724426..9f3e9a1c0a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,6 @@ +# Feature options for plugins with no external deps +option('rtspclientsink', type : 'feature', value : 'auto') + # Common feature options option('examples', type : 'feature', value : 'auto', yield : true, description : 'Build the examples') diff --git a/tests/check/meson.build b/tests/check/meson.build index fb9eb9be0a..78d083f331 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -23,7 +23,6 @@ rtsp_server_tests = [ 'gst/media', 'gst/permissions', 'gst/rtspserver', - 'gst/rtspclientsink', 'gst/sessionmedia', 'gst/sessionpool', 'gst/stream', @@ -31,6 +30,10 @@ rtsp_server_tests = [ 'gst/token', ] +if not get_option('rtspclientsink').disabled() + rtsp_server_tests += ['gst/rtspclientsink'] +endif + foreach test_name : rtsp_server_tests env = environment() env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') From a44a729acb22d66601e05cc360f5dfcc3960b118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 19 Sep 2018 12:21:30 +0100 Subject: [PATCH 1556/1776] meson: add gobject-cast-checks, glib-asserts, glib-checks options --- meson.build | 25 +++++++++++++++++++++++++ meson_options.txt | 6 ++++++ 2 files changed, 31 insertions(+) diff --git a/meson.build b/meson.build index 77be55f908..88b0ec75ee 100644 --- a/meson.build +++ b/meson.build @@ -13,6 +13,7 @@ gst_version_micro = version_arr[2].to_int() else gst_version_nano = 0 endif +gst_version_is_dev = gst_version_minor % 2 == 1 and gst_version_micro < 90 glib_req = '>= 2.40.0' gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor) @@ -43,6 +44,30 @@ if cc.has_argument('-fno-strict-aliasing') add_project_arguments('-fno-strict-aliasing', language: 'c') endif +# Define G_DISABLE_DEPRECATED for development versions +if gst_version_is_dev + message('Disabling deprecated GLib API') + add_project_arguments('-DG_DISABLE_DEPRECATED', language: 'c') +endif + +cast_checks = get_option('gobject-cast-checks') +if cast_checks.disabled() or (cast_checks.auto() and not gst_version_is_dev) + message('Disabling GLib cast checks') + add_project_arguments('-DG_DISABLE_CAST_CHECKS', language: 'c') +endif + +glib_asserts = get_option('glib-asserts') +if glib_asserts.disabled() or (glib_asserts.auto() and not gst_version_is_dev) + message('Disabling GLib asserts') + add_project_arguments('-DG_DISABLE_ASSERT', language: 'c') +endif + +glib_checks = get_option('glib-checks') +if glib_checks.disabled() or (glib_checks.auto() and not gst_version_is_dev) + message('Disabling GLib checks') + add_project_arguments('-DG_DISABLE_CHECKS', language: 'c') +endif + cdata = configuration_data() cdata.set_quoted('GETTEXT_PACKAGE', 'gst-rtsp-server-1.0') cdata.set_quoted('PACKAGE', 'gst-rtsp-server') diff --git a/meson_options.txt b/meson_options.txt index 9f3e9a1c0a..24de52de1a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -8,6 +8,12 @@ option('tests', type : 'feature', value : 'auto', yield : true, description : 'Build and enable unit tests') option('introspection', type : 'feature', value : 'auto', yield : true, description : 'Generate gobject-introspection bindings') +option('gobject-cast-checks', type : 'feature', value : 'auto', yield : true, + description: 'Enable run-time GObject cast checks (auto = enabled for development, disabled for stable releases)') +option('glib-asserts', type : 'feature', value : 'enabled', yield : true, + description: 'Enable GLib assertion (auto = enabled for development, disabled for stable releases)') +option('glib-checks', type : 'feature', value : 'enabled', yield : true, + description: 'Enable GLib checks such as API guards (auto = enabled for development, disabled for stable releases)') # Common options option('package-name', type : 'string', yield : true, From ff51e9a68d0b140a03de5b0d9c72283006e7b215 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 19 Sep 2018 14:31:56 +0200 Subject: [PATCH 1557/1776] rtsp-media-factory: Add missing break statements This resulted in warnings/assertions whenever one accessed the max-mcast-ttl property. CID #1439515 CID #1439523 --- gst/rtsp-server/rtsp-media-factory.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 53bce3ea1e..57ced467f7 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -350,6 +350,7 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, case PROP_MAX_MCAST_TTL: g_value_set_uint (value, gst_rtsp_media_factory_get_max_mcast_ttl (factory)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -403,6 +404,7 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, case PROP_MAX_MCAST_TTL: gst_rtsp_media_factory_set_max_mcast_ttl (factory, g_value_get_uint (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } From 62d4c0b179555fa0189d2c8a8e2d81da04a5bc3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 24 Sep 2018 09:36:21 +0100 Subject: [PATCH 1558/1776] libs: fix API export/import and 'inconsistent linkage' on MSVC Export rtsp-server library API in headers when we're building the library itself, otherwise import the API from the headers. This fixes linker warnings on Windows when building with MSVC. Fix up some missing config.h includes when building the lib which is needed to get the export api define from config.h https://bugzilla.gnome.org/show_bug.cgi?id=797185 --- configure.ac | 8 +++++++- gst/rtsp-server/Makefile.am | 2 +- gst/rtsp-server/meson.build | 2 +- gst/rtsp-server/rtsp-address-pool.c | 3 +++ gst/rtsp-server/rtsp-auth.c | 3 +++ gst/rtsp-server/rtsp-client.c | 3 +++ gst/rtsp-server/rtsp-context.c | 3 +++ gst/rtsp-server/rtsp-media-factory-uri.c | 3 +++ gst/rtsp-server/rtsp-media-factory.c | 3 +++ gst/rtsp-server/rtsp-media.c | 3 +++ gst/rtsp-server/rtsp-mount-points.c | 4 ++++ gst/rtsp-server/rtsp-params.c | 3 +++ gst/rtsp-server/rtsp-permissions.c | 3 +++ gst/rtsp-server/rtsp-sdp.c | 3 +++ gst/rtsp-server/rtsp-server-prelude.h | 6 +++++- gst/rtsp-server/rtsp-server.c | 4 ++++ gst/rtsp-server/rtsp-session-media.c | 3 +++ gst/rtsp-server/rtsp-session-pool.c | 3 +++ gst/rtsp-server/rtsp-session.c | 3 +++ gst/rtsp-server/rtsp-stream-transport.c | 3 +++ gst/rtsp-server/rtsp-stream.c | 3 +++ gst/rtsp-server/rtsp-thread-pool.c | 3 +++ gst/rtsp-server/rtsp-token.c | 3 +++ meson.build | 13 +++++++++++-- 24 files changed, 84 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 9d6790b517..214da35cd5 100644 --- a/configure.ac +++ b/configure.ac @@ -258,7 +258,13 @@ fi AC_SUBST(DEPRECATED_CFLAGS) VISIBILITY_CFLAGS="" -AS_COMPILER_FLAG([-fvisibility=hidden], [VISIBILITY_CFLAGS="-fvisibility=hidden"]) +AS_COMPILER_FLAG([-fvisibility=hidden], [ + VISIBILITY_CFLAGS="-fvisibility=hidden" + AC_DEFINE(GST_API_EXPORT, [extern __attribute__ ((visibility ("default")))], [public symbol export define]) +], [ + VISIBILITY_CFLAGS="" + AC_DEFINE(GST_API_EXPORT, [extern], [public symbol export define]) +]) AC_SUBST(VISIBILITY_CFLAGS) dnl disable strict aliasing diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index e2fff13d45..d08de4e6d0 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -59,7 +59,7 @@ libgstrtspserver_@GST_API_VERSION@_la_SOURCES = \ libgstrtspserver_@GST_API_VERSION@_la_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) $(GST_NET_CFLAGS) \ - $(GST_BASE_CFLAGS) $(GST_CFLAGS) + $(GST_BASE_CFLAGS) $(GST_CFLAGS) -DBUILDING_GST_RTSP_SERVER libgstrtspserver_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) libgstrtspserver_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_NET_LIBS) $(GST_BASE_LIBS) \ diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index d0fbde1dba..b798b889b7 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -48,7 +48,7 @@ gst_rtsp_server_deps = [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_ gst_rtsp_server = library('gstrtspserver-@0@'.format(api_version), rtsp_server_sources, include_directories : rtspserver_incs, - c_args: rtspserver_args, + c_args: rtspserver_args + ['-DBUILDING_GST_RTSP_SERVER'], version : libversion, soversion : soversion, darwin_versions : osxversion, diff --git a/gst/rtsp-server/rtsp-address-pool.c b/gst/rtsp-server/rtsp-address-pool.c index 5b032bf0c4..da3e82b40c 100644 --- a/gst/rtsp-server/rtsp-address-pool.c +++ b/gst/rtsp-server/rtsp-address-pool.c @@ -36,6 +36,9 @@ * * Last reviewed on 2013-07-16 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index c0bcdb12fb..e691196507 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -45,6 +45,9 @@ * * Last reviewed on 2013-07-16 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 2e124f8739..a55aae489e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -40,6 +40,9 @@ * * Last reviewed on 2013-07-11 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include diff --git a/gst/rtsp-server/rtsp-context.c b/gst/rtsp-server/rtsp-context.c index def64f22bd..4f08407d98 100644 --- a/gst/rtsp-server/rtsp-context.c +++ b/gst/rtsp-server/rtsp-context.c @@ -23,6 +23,9 @@ * * Last reviewed on 2013-07-11 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include "rtsp-context.h" diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 7100b1647d..93ed9d7b72 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -29,6 +29,9 @@ * * Last reviewed on 2013-07-11 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 57ced467f7..904124d1f3 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -37,6 +37,9 @@ * * Last reviewed on 2013-07-11 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include "rtsp-media-factory.h" diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1073b89bce..b39fc93a0a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -62,6 +62,9 @@ * * Last reviewed on 2013-07-11 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 15685ba8ab..76794851ee 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -34,6 +34,10 @@ * * Last reviewed on 2013-07-11 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include "rtsp-mount-points.h" diff --git a/gst/rtsp-server/rtsp-params.c b/gst/rtsp-server/rtsp-params.c index 6025722760..5fa27afbc6 100644 --- a/gst/rtsp-server/rtsp-params.c +++ b/gst/rtsp-server/rtsp-params.c @@ -23,6 +23,9 @@ * * Last reviewed on 2013-07-11 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include diff --git a/gst/rtsp-server/rtsp-permissions.c b/gst/rtsp-server/rtsp-permissions.c index 1667db746f..eb125489f6 100644 --- a/gst/rtsp-server/rtsp-permissions.c +++ b/gst/rtsp-server/rtsp-permissions.c @@ -36,6 +36,9 @@ * * Last reviewed on 2013-07-15 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 04329dd93f..6d552f2212 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -26,6 +26,9 @@ * * Last reviewed on 2013-07-11 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include diff --git a/gst/rtsp-server/rtsp-server-prelude.h b/gst/rtsp-server/rtsp-server-prelude.h index 4f0dca8d36..ac4ad2ce78 100644 --- a/gst/rtsp-server/rtsp-server-prelude.h +++ b/gst/rtsp-server/rtsp-server-prelude.h @@ -25,7 +25,11 @@ #include #ifndef GST_RTSP_SERVER_API -#define GST_RTSP_SERVER_API GST_EXPORT +# ifdef BUILDING_GST_RTSP_SERVER +# define GST_RTSP_SERVER_API GST_API_EXPORT /* from config.h */ +# else +# define GST_RTSP_SERVER_API GST_API_IMPORT +# endif #endif #endif /* __GST_RTSP_SERVER_PRELUDE_H__ */ diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 0a0b912fb8..de409e0346 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -52,6 +52,10 @@ * * Last reviewed on 2013-07-11 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index c3bac97ccb..26b7143988 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -34,6 +34,9 @@ * * Last reviewed on 2013-07-16 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 8f45e28279..b09db93d45 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -39,6 +39,9 @@ * * Last reviewed on 2013-07-11 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include "rtsp-session-pool.h" diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 37945f853d..e399349a73 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -42,6 +42,9 @@ * * Last reviewed on 2013-07-11 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 99af1ae15a..a258025f79 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -40,6 +40,9 @@ * * Last reviewed on 2013-07-16 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 65f0f5d2c6..81054e0423 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -45,6 +45,9 @@ * * Last reviewed on 2013-07-16 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index 4e14447778..6c53a01a67 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -46,6 +46,9 @@ * * Last reviewed on 2013-07-11 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include diff --git a/gst/rtsp-server/rtsp-token.c b/gst/rtsp-server/rtsp-token.c index 733546fbdf..4062d30c06 100644 --- a/gst/rtsp-server/rtsp-token.c +++ b/gst/rtsp-server/rtsp-token.c @@ -35,6 +35,9 @@ * * Last reviewed on 2013-07-15 (1.0.0) */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include diff --git a/meson.build b/meson.build index 88b0ec75ee..6b748c3ac0 100644 --- a/meson.build +++ b/meson.build @@ -30,15 +30,25 @@ plugins_install_dir = '@0@/gstreamer-1.0'.format(get_option('libdir')) cc = meson.get_compiler('c') +cdata = configuration_data() + if cc.has_link_argument('-Wl,-Bsymbolic-functions') add_project_link_arguments('-Wl,-Bsymbolic-functions', language : 'c') endif # Symbol visibility -if cc.has_argument('-fvisibility=hidden') +if cc.get_id() == 'msvc' + export_define = '__declspec(dllexport) extern' +elif cc.has_argument('-fvisibility=hidden') add_project_arguments('-fvisibility=hidden', language: 'c') + export_define = 'extern __attribute__ ((visibility ("default")))' +else + export_define = 'extern' endif +# Passing this through the command line would be too messy +cdata.set('GST_API_EXPORT', export_define) + # Disable strict aliasing if cc.has_argument('-fno-strict-aliasing') add_project_arguments('-fno-strict-aliasing', language: 'c') @@ -68,7 +78,6 @@ if glib_checks.disabled() or (glib_checks.auto() and not gst_version_is_dev) add_project_arguments('-DG_DISABLE_CHECKS', language: 'c') endif -cdata = configuration_data() cdata.set_quoted('GETTEXT_PACKAGE', 'gst-rtsp-server-1.0') cdata.set_quoted('PACKAGE', 'gst-rtsp-server') cdata.set_quoted('VERSION', gst_version) From c394de2348c4cc3add2a9fc9cff30733d95c93b7 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 6 Sep 2018 16:17:33 +0200 Subject: [PATCH 1559/1776] New property for socket binding to mcast addresses By default the multicast sockets are bound to INADDR_ANY, as it's not allowed to bind sockets to multicast addresses in Windows. This default behaviour can be changed by setting bind-mcast-address property on the media-factory object. https://bugzilla.gnome.org/show_bug.cgi?id=797059 --- gst/rtsp-server/rtsp-media-factory.c | 70 ++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 6 +++ gst/rtsp-server/rtsp-media.c | 72 +++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 5 ++ gst/rtsp-server/rtsp-stream.c | 60 +++++++++++++++++++-- gst/rtsp-server/rtsp-stream.h | 6 +++ tests/check/gst/client.c | 81 +++++++++++++++++++++++----- tests/check/gst/mediafactory.c | 50 +++++++++++++++++ 8 files changed, 333 insertions(+), 17 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 904124d1f3..27825e02da 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -63,6 +63,7 @@ struct _GstRTSPMediaFactoryPrivate gboolean stop_on_disconnect; gchar *multicast_iface; guint max_mcast_ttl; + gboolean bind_mcast_address; GstClockTime rtx_time; guint latency; @@ -88,6 +89,7 @@ struct _GstRTSPMediaFactoryPrivate #define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_LATENCY 200 #define DEFAULT_MAX_MCAST_TTL 255 +#define DEFAULT_BIND_MCAST_ADDRESS FALSE #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE #define DEFAULT_DO_RETRANSMISSION FALSE @@ -107,6 +109,7 @@ enum PROP_STOP_ON_DISCONNECT, PROP_CLOCK, PROP_MAX_MCAST_TTL, + PROP_BIND_MCAST_ADDRESS, PROP_LAST }; @@ -234,6 +237,13 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) 255, DEFAULT_MAX_MCAST_TTL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BIND_MCAST_ADDRESS, + g_param_spec_boolean ("bind-mcast-address", "Bind mcast address", + "Whether the multicast sockets should be bound to multicast addresses " + "or INADDR_ANY", + DEFAULT_BIND_MCAST_ADDRESS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, @@ -276,6 +286,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; + priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS; g_mutex_init (&priv->lock); g_mutex_init (&priv->medias_lock); @@ -354,6 +365,10 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_uint (value, gst_rtsp_media_factory_get_max_mcast_ttl (factory)); break; + case PROP_BIND_MCAST_ADDRESS: + g_value_set_boolean (value, + gst_rtsp_media_factory_is_bind_mcast_address (factory)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -408,6 +423,10 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_max_mcast_ttl (factory, g_value_get_uint (value)); break; + case PROP_BIND_MCAST_ADDRESS: + gst_rtsp_media_factory_set_bind_mcast_address (factory, + g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1540,6 +1559,54 @@ gst_rtsp_media_factory_get_max_mcast_ttl (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_set_bind_mcast_address: + * @factory: a #GstRTSPMediaFactory + * @bind_mcast_addr: the new value + * + * Decide whether the multicast socket should be bound to a multicast address or + * INADDR_ANY. + */ +void +gst_rtsp_media_factory_set_bind_mcast_address (GstRTSPMediaFactory * factory, + gboolean bind_mcast_addr) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv->bind_mcast_address = bind_mcast_addr; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_is_bind_mcast_address: + * @factory: a #GstRTSPMediaFactory + * + * Check if multicast sockets are configured to be bound to multicast addresses. + * + * Returns: %TRUE if multicast sockets are configured to be bound to multicast addresses. + */ +gboolean +gst_rtsp_media_factory_is_bind_mcast_address (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + gboolean result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + result = priv->bind_mcast_address; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} + static gchar * default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { @@ -1691,6 +1758,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gchar *multicast_iface; GstRTSPPublishClockMode publish_clock_mode; guint ttl; + gboolean bind_mcast; /* configure the sharedness */ GST_RTSP_MEDIA_FACTORY_LOCK (factory); @@ -1707,6 +1775,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) clock = priv->clock ? gst_object_ref (priv->clock) : NULL; publish_clock_mode = priv->publish_clock_mode; ttl = priv->max_mcast_ttl; + bind_mcast = priv->bind_mcast_address; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); gst_rtsp_media_set_suspend_mode (media, suspend_mode); @@ -1722,6 +1791,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_stop_on_disconnect (media, stop_on_disconnect); gst_rtsp_media_set_publish_clock_mode (media, publish_clock_mode); gst_rtsp_media_set_max_mcast_ttl (media, ttl); + gst_rtsp_media_set_bind_mcast_address (media, bind_mcast); if (clock) { gst_rtsp_media_set_clock (media, clock); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 46d7d5515e..65edbaa0b8 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -246,6 +246,12 @@ gboolean gst_rtsp_media_factory_set_max_mcast_ttl (GstRTSPMediaFa GST_RTSP_SERVER_API guint gst_rtsp_media_factory_get_max_mcast_ttl (GstRTSPMediaFactory * factory); +GST_RTSP_SERVER_API +void gst_rtsp_media_factory_set_bind_mcast_address (GstRTSPMediaFactory * factory, + gboolean bind_mcast_addr); +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_factory_is_bind_mcast_address (GstRTSPMediaFactory * factory); + /* creating the media from the factory and a url */ GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b39fc93a0a..15ab6a7a3c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -102,6 +102,7 @@ struct _GstRTSPMediaPrivate GstRTSPAddressPool *pool; gchar *multicast_iface; guint max_mcast_ttl; + gboolean bind_mcast_address; gboolean blocked; GstRTSPTransportMode transport_mode; gboolean stop_on_disconnect; @@ -163,6 +164,7 @@ struct _GstRTSPMediaPrivate #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE #define DEFAULT_MAX_MCAST_TTL 255 +#define DEFAULT_BIND_MCAST_ADDRESS FALSE #define DEFAULT_DO_RETRANSMISSION FALSE @@ -186,6 +188,7 @@ enum PROP_STOP_ON_DISCONNECT, PROP_CLOCK, PROP_MAX_MCAST_TTL, + PROP_BIND_MCAST_ADDRESS, PROP_LAST }; @@ -387,6 +390,13 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) 255, DEFAULT_MAX_MCAST_TTL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BIND_MCAST_ADDRESS, + g_param_spec_boolean ("bind-mcast-address", "Bind mcast address", + "Whether the multicast sockets should be bound to multicast addresses " + "or INADDR_ANY", + DEFAULT_BIND_MCAST_ADDRESS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, @@ -458,6 +468,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; + priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS; } static void @@ -547,6 +558,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_MAX_MCAST_TTL: g_value_set_uint (value, gst_rtsp_media_get_max_mcast_ttl (media)); break; + case PROP_BIND_MCAST_ADDRESS: + g_value_set_boolean (value, gst_rtsp_media_is_bind_mcast_address (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -603,6 +617,10 @@ gst_rtsp_media_set_property (GObject * object, guint propid, case PROP_MAX_MCAST_TTL: gst_rtsp_media_set_max_mcast_ttl (media, g_value_get_uint (value)); break; + case PROP_BIND_MCAST_ADDRESS: + gst_rtsp_media_set_bind_mcast_address (media, + g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1906,6 +1924,59 @@ gst_rtsp_media_get_max_mcast_ttl (GstRTSPMedia * media) return res; } +/** + * gst_rtsp_media_set_bind_mcast_address: + * @media: a #GstRTSPMedia + * @bind_mcast_addr: the new value + * + * Decide whether the multicast socket should be bound to a multicast address or + * INADDR_ANY. + */ +void +gst_rtsp_media_set_bind_mcast_address (GstRTSPMedia * media, + gboolean bind_mcast_addr) +{ + GstRTSPMediaPrivate *priv; + guint i; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->bind_mcast_address = bind_mcast_addr; + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + gst_rtsp_stream_set_bind_mcast_address (stream, bind_mcast_addr); + } + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_is_bind_mcast_address: + * @media: a #GstRTSPMedia + * + * Check if multicast sockets are configured to be bound to multicast addresses. + * + * Returns: %TRUE if multicast sockets are configured to be bound to multicast addresses. + */ +gboolean +gst_rtsp_media_is_bind_mcast_address (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + gboolean result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + result = priv->bind_mcast_address; + g_mutex_unlock (&priv->lock); + + return result; +} + static GList * _find_payload_types (GstRTSPMedia * media) { @@ -2224,6 +2295,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, gst_rtsp_stream_set_address_pool (stream, priv->pool); gst_rtsp_stream_set_multicast_iface (stream, priv->multicast_iface); gst_rtsp_stream_set_max_mcast_ttl (stream, priv->max_mcast_ttl); + gst_rtsp_stream_set_bind_mcast_address (stream, priv->bind_mcast_address); gst_rtsp_stream_set_profiles (stream, priv->profiles); gst_rtsp_stream_set_protocols (stream, priv->protocols); gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 92b3866a94..c7728c6fe4 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -320,6 +320,11 @@ gboolean gst_rtsp_media_set_max_mcast_ttl (GstRTSPMedia *media, GST_RTSP_SERVER_API guint gst_rtsp_media_get_max_mcast_ttl (GstRTSPMedia *media); +GST_RTSP_SERVER_API +void gst_rtsp_media_set_bind_mcast_address (GstRTSPMedia *media, gboolean bind_mcast_addr); +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_is_bind_mcast_address (GstRTSPMedia *media); + /* prepare the media for playback */ GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 81054e0423..18ec2925c0 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -150,6 +150,7 @@ struct _GstRTSPStreamPrivate gchar *multicast_iface; guint max_mcast_ttl; + gboolean bind_mcast_address; /* the caps of the stream */ gulong caps_sig; @@ -187,6 +188,7 @@ struct _GstRTSPStreamPrivate #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \ GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_MAX_MCAST_TTL 255 +#define DEFAULT_BIND_MCAST_ADDRESS FALSE enum { @@ -287,6 +289,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->configured_protocols = 0; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; + priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS; g_mutex_init (&priv->lock); @@ -1381,13 +1384,19 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, if (ct->destination != NULL) { tmp_rtp = ct->port.min; tmp_rtcp = ct->port.max; + + /* check if the provided address is a multicast address */ inetaddr = g_inet_address_new_from_string (ct->destination); if (inetaddr == NULL) goto destination_error; if (!g_inet_address_get_is_multicast (inetaddr)) goto destination_no_mcast; - g_object_unref (inetaddr); - inetaddr = g_inet_address_new_any (family); + + + if (!priv->bind_mcast_address) { + g_clear_object (&inetaddr); + inetaddr = g_inet_address_new_any (family); + } GST_DEBUG_OBJECT (stream, "use transport settings"); transport_settings_defined = TRUE; @@ -1444,10 +1453,10 @@ again: g_clear_object (&inetaddr); /* FIXME: Does it really work with the IP_MULTICAST_ALL socket option and * socket control message set in udpsrc? */ - if (multicast) - inetaddr = g_inet_address_new_any (family); - else + if (priv->bind_mcast_address || !multicast) inetaddr = g_inet_address_new_from_string (addr->address); + else + inetaddr = g_inet_address_new_any (family); } else { if (tmp_rtp != 0) { tmp_rtp += 2; @@ -2152,6 +2161,47 @@ gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream * stream, guint ttl) return res; } +/** + * gst_rtsp_stream_set_bind_mcast_address: + * @stream: a #GstRTSPStream, + * @bind_mcast_addr: the new value + * + * Decide whether the multicast socket should be bound to a multicast address or + * INADDR_ANY. + */ +void +gst_rtsp_stream_set_bind_mcast_address (GstRTSPStream * stream, + gboolean bind_mcast_addr) +{ + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + g_mutex_lock (&stream->priv->lock); + stream->priv->bind_mcast_address = bind_mcast_addr; + g_mutex_unlock (&stream->priv->lock); +} + +/** + * gst_rtsp_stream_is_bind_mcast_address: + * @stream: a #GstRTSPStream + * + * Check if multicast sockets are configured to be bound to multicast addresses. + * + * Returns: %TRUE if multicast sockets are configured to be bound to multicast addresses. + */ +gboolean +gst_rtsp_stream_is_bind_mcast_address (GstRTSPStream * stream) +{ + gboolean result; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + g_mutex_lock (&stream->priv->lock); + result = stream->priv->bind_mcast_address; + g_mutex_unlock (&stream->priv->lock); + + return result; +} + /* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 0c6804d536..7910bb05d7 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -311,6 +311,12 @@ guint gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream *stream); GST_RTSP_SERVER_API gboolean gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream *stream, guint ttl); +GST_RTSP_SERVER_API +void gst_rtsp_stream_set_bind_mcast_address (GstRTSPStream * stream, gboolean bind_mcast_addr); + +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_is_bind_mcast_address (GstRTSPStream * stream); + GST_RTSP_SERVER_API gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GstRTSPTransport * transport); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index aa7893c737..b2e0dd3847 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -875,9 +875,6 @@ multicast_transport_specific (void) "user", NULL); gst_rtsp_context_push_current (&ctx); - expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; - /* simple SETUP with a valid URI */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); @@ -1081,7 +1078,7 @@ static void mcast_transport_two_clients (gboolean shared, const gchar * transport1, const gchar * expected_transport1, const gchar * addr1, const gchar * transport2, const gchar * expected_transport2, - const gchar * addr2) + const gchar * addr2, gboolean bind_mcast_address) { GstRTSPClient *client1, *client2; GstRTSPMessage request = { 0, }; @@ -1101,6 +1098,7 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, if (shared) gst_rtsp_media_factory_set_shared (factory, TRUE); gst_rtsp_media_factory_set_max_mcast_ttl (factory, 5); + gst_rtsp_media_factory_set_bind_mcast_address (factory, bind_mcast_address); gst_rtsp_media_factory_set_launch (factory, "audiotestsrc ! audio/x-raw,rate=44100 ! audioconvert ! rtpL16pay name=pay0"); address_pool = gst_rtsp_address_pool_new (); @@ -1256,7 +1254,7 @@ GST_START_TEST mcast_transport_two_clients (TRUE, transport_client_1, expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); + expected_transport_2, addr_client_2, FALSE); } GST_END_TEST; @@ -1277,11 +1275,59 @@ GST_START_TEST (test_client_multicast_transport_specific_two_clients) mcast_transport_two_clients (FALSE, transport_client_1, expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); + expected_transport_2, addr_client_2, FALSE); } GST_END_TEST; +/* test if two multicast clients can choose the same ports but different + * multicast destinations + * CASE: media is not shared */ +GST_START_TEST (test_client_multicast_transport_specific_two_clients_same_ports) +{ + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=9000-9001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.1:9000"; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=9000-9001;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + const gchar *addr_client_2 = "233.252.0.2:9000"; + + /* configure the multicast socket to be bound to the requested multicast address instead of INADDR_ANY. + * The clients request the same rtp/rtcp borts and having the socket that are bound to ANY would result + * in bind() failure */ + gboolean allow_bind_mcast_address = TRUE; + + mcast_transport_two_clients (FALSE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2, allow_bind_mcast_address); +} + +GST_END_TEST; + +/* test if two multicast clients can choose the same multicast destination but different + * ports + * CASE: media is not shared */ +GST_START_TEST + (test_client_multicast_transport_specific_two_clients_same_destination) { + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=9002-9003;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + const gchar *addr_client_1 = "233.252.0.2:9002"; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=9004-9005;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + const gchar *addr_client_2 = "233.252.0.2:9004"; + + mcast_transport_two_clients (FALSE, transport_client_1, + expected_transport_1, addr_client_1, transport_client_2, + expected_transport_2, addr_client_2, FALSE); +} + +GST_END_TEST; /* test if two multicast clients can choose the same transport settings. * CASE: media is shared */ GST_START_TEST @@ -1299,7 +1345,7 @@ GST_START_TEST mcast_transport_two_clients (TRUE, transport_client_1, expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); + expected_transport_2, addr_client_2, FALSE); } GST_END_TEST; @@ -1321,7 +1367,7 @@ GST_START_TEST (test_client_multicast_two_clients_shared_media) mcast_transport_two_clients (TRUE, transport_client_1, expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); + expected_transport_2, addr_client_2, FALSE); } GST_END_TEST; @@ -1343,7 +1389,7 @@ GST_START_TEST mcast_transport_two_clients (TRUE, transport_client_1, expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); + expected_transport_2, addr_client_2, FALSE); } GST_END_TEST; @@ -1366,7 +1412,7 @@ GST_START_TEST mcast_transport_two_clients (TRUE, transport_client_1, expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); + expected_transport_2, addr_client_2, FALSE); } GST_END_TEST; @@ -1389,7 +1435,7 @@ GST_START_TEST (test_client_multicast_max_ttl_first_client) mcast_transport_two_clients (TRUE, transport_client_1, expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); + expected_transport_2, addr_client_2, FALSE); } GST_END_TEST; @@ -1410,7 +1456,7 @@ GST_START_TEST (test_client_multicast_max_ttl_second_client) mcast_transport_two_clients (TRUE, transport_client_1, expected_transport_1, addr_client_1, transport_client_2, - expected_transport_2, addr_client_2); + expected_transport_2, addr_client_2, FALSE); } GST_END_TEST; @@ -1483,6 +1529,17 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_transport_specific_two_clients_shared_media); tcase_add_test (tc, test_client_multicast_transport_specific_two_clients); +#ifndef G_OS_WIN32 + tcase_add_test (tc, + test_client_multicast_transport_specific_two_clients_same_ports); +#else + /* skip the test on windows as the test restricts the multicast sockets to multicast traffic only, + * by specifying the multicast IP as the bind address and this currently doesn't work on Windows */ + tcase_skip_broken_test (tc, + test_client_multicast_transport_specific_two_clients_same_ports); +#endif + tcase_add_test (tc, + test_client_multicast_transport_specific_two_clients_same_destination); tcase_add_test (tc, test_client_multicast_transport_specific_two_clients_shared_media_same_transport); tcase_add_test (tc, test_client_multicast_two_clients_shared_media); diff --git a/tests/check/gst/mediafactory.c b/tests/check/gst/mediafactory.c index ba1719ea04..2fc453cfdc 100644 --- a/tests/check/gst/mediafactory.c +++ b/tests/check/gst/mediafactory.c @@ -371,6 +371,55 @@ GST_START_TEST (test_mcast_ttl) GST_END_TEST; + +GST_START_TEST (test_allow_bind_mcast) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPStream *stream; + + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_shared (factory, TRUE); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 " + " audiotestsrc ! audioconvert ! rtpL16pay name=pay1 )"); + + /* verify that by default binding sockets to multicast addresses is not enabled */ + fail_unless (gst_rtsp_media_factory_is_bind_mcast_address (factory) == FALSE); + + /* allow multicast sockets to be bound to multicast addresses */ + gst_rtsp_media_factory_set_bind_mcast_address (factory, TRUE); + /* verify that the socket binding to multicast address has been enabled */ + fail_unless (gst_rtsp_media_factory_is_bind_mcast_address (factory) == TRUE); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + + /* verify that the correct socket binding configuration has been propageted to the media */ + fail_unless (gst_rtsp_media_is_bind_mcast_address (media) == TRUE); + + fail_unless (gst_rtsp_media_n_streams (media) == 2); + + /* verify that the correct socket binding configuration has been propageted to the media streams */ + stream = gst_rtsp_media_get_stream (media, 0); + fail_unless (stream != NULL); + fail_unless (gst_rtsp_stream_is_bind_mcast_address (stream) == TRUE); + + stream = gst_rtsp_media_get_stream (media, 1); + fail_unless (stream != NULL); + fail_unless (gst_rtsp_stream_is_bind_mcast_address (stream) == TRUE); + + g_object_unref (media); + gst_rtsp_url_free (url); + g_object_unref (factory); +} + +GST_END_TEST; + static Suite * rtspmediafactory_suite (void) { @@ -387,6 +436,7 @@ rtspmediafactory_suite (void) tcase_add_test (tc, test_permissions); tcase_add_test (tc, test_reset); tcase_add_test (tc, test_mcast_ttl); + tcase_add_test (tc, test_allow_bind_mcast); return s; } From 982efec468201b458f057c1ec50faefb9b991020 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 27 Sep 2018 19:57:13 +0200 Subject: [PATCH 1560/1776] tests: client: Avoid bind() failures in tests https://bugzilla.gnome.org/show_bug.cgi?id=797059 --- tests/check/gst/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index b2e0dd3847..6c5240e934 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -927,7 +927,7 @@ GST_END_TEST; GST_START_TEST (test_client_multicast_transport_specific_no_address_in_pool) { expected_transport = "RTP/AVP;multicast;destination=234.252.0.3;" - "ttl=1;port=6000-6001;mode=\"PLAY\""; + "ttl=1;port=10002-10004;mode=\"PLAY\""; multicast_transport_specific (); expected_transport = NULL; } From 7b5e232a9ed1c414fef5d5426cbf382b06d57350 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Wed, 12 Sep 2018 11:55:15 +0200 Subject: [PATCH 1561/1776] onvif: encapsulate onvif part into a bin ...and thus do not let onvif affect pipelines latency https://bugzilla.gnome.org/show_bug.cgi?id=797174 --- gst/rtsp-server/Makefile.am | 1 + gst/rtsp-server/meson.build | 1 + gst/rtsp-server/rtsp-latency-bin.c | 357 +++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-latency-bin.h | 59 +++++ gst/rtsp-server/rtsp-onvif-media.c | 23 +- 5 files changed, 439 insertions(+), 2 deletions(-) create mode 100644 gst/rtsp-server/rtsp-latency-bin.c create mode 100644 gst/rtsp-server/rtsp-latency-bin.h diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index d08de4e6d0..7009c56e8b 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -31,6 +31,7 @@ c_sources = \ rtsp-params.c \ rtsp-sdp.c \ rtsp-thread-pool.c \ + rtsp-latency-bin.c \ rtsp-media.c \ rtsp-media-factory.c \ rtsp-media-factory-uri.c \ diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index b798b889b7..143385f989 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -3,6 +3,7 @@ rtsp_server_sources = [ 'rtsp-auth.c', 'rtsp-client.c', 'rtsp-context.c', + 'rtsp-latency-bin.c', 'rtsp-media.c', 'rtsp-media-factory.c', 'rtsp-media-factory-uri.c', diff --git a/gst/rtsp-server/rtsp-latency-bin.c b/gst/rtsp-server/rtsp-latency-bin.c new file mode 100644 index 0000000000..6a12fbe9de --- /dev/null +++ b/gst/rtsp-server/rtsp-latency-bin.c @@ -0,0 +1,357 @@ +/* GStreamer + * Copyright (C) 2018 Ognyan Tonchev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "rtsp-latency-bin.h" + +#define GST_RTSP_LATENCY_BIN_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_RTSP_LATENCY_BIN_TYPE, GstRTSPLatencyBinPrivate)) + +struct _GstRTSPLatencyBinPrivate +{ + GstPad *sinkpad; + GstElement *element; +}; + +enum +{ + PROP_0, + PROP_ELEMENT, + PROP_LAST +}; + +GST_DEBUG_CATEGORY_STATIC (rtsp_latency_bin_debug); +#define GST_CAT_DEFAULT rtsp_latency_bin_debug + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static void gst_rtsp_latency_bin_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec); +static void gst_rtsp_latency_bin_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec); +static gboolean gst_rtsp_latency_bin_element_query (GstElement * element, + GstQuery * query); +static gboolean gst_rtsp_latency_bin_element_event (GstElement * element, + GstEvent * event); +static void gst_rtsp_latency_bin_message_handler (GstBin * bin, + GstMessage * message); +static gboolean gst_rtsp_latency_bin_add_element (GstRTSPLatencyBin * + latency_bin, GstElement * element); +static GstStateChangeReturn gst_rtsp_latency_bin_change_state (GstElement * + element, GstStateChange transition); + +G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPLatencyBin, gst_rtsp_latency_bin, + GST_TYPE_BIN); + +static void +gst_rtsp_latency_bin_class_init (GstRTSPLatencyBinClass * klass) +{ + GObjectClass *gobject_klass = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_klass = GST_ELEMENT_CLASS (klass); + GstBinClass *gstbin_klass = GST_BIN_CLASS (klass); + + GST_DEBUG_CATEGORY_INIT (rtsp_latency_bin_debug, + "rtsplatencybin", 0, "GstRTSPLatencyBin"); + + gobject_klass->get_property = gst_rtsp_latency_bin_get_property; + gobject_klass->set_property = gst_rtsp_latency_bin_set_property; + + g_object_class_install_property (gobject_klass, PROP_ELEMENT, + g_param_spec_object ("element", "The Element", + "The GstElement to prevent from affecting piplines latency", + GST_TYPE_ELEMENT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + + gstelement_klass->change_state = + GST_DEBUG_FUNCPTR (gst_rtsp_latency_bin_change_state); + gstelement_klass->query = + GST_DEBUG_FUNCPTR (gst_rtsp_latency_bin_element_query); + gstelement_klass->send_event = + GST_DEBUG_FUNCPTR (gst_rtsp_latency_bin_element_event); + + gstbin_klass->handle_message = + GST_DEBUG_FUNCPTR (gst_rtsp_latency_bin_message_handler); +} + +static void +gst_rtsp_latency_bin_init (GstRTSPLatencyBin * latency_bin) +{ + GST_OBJECT_FLAG_SET (latency_bin, GST_ELEMENT_FLAG_SINK); +} + +static void +gst_rtsp_latency_bin_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec) +{ + GstRTSPLatencyBin *latency_bin = GST_RTSP_LATENCY_BIN (object); + GstRTSPLatencyBinPrivate *priv = + GST_RTSP_LATENCY_BIN_GET_PRIVATE (latency_bin); + + switch (propid) { + case PROP_ELEMENT: + g_value_set_object (value, priv->element); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static void +gst_rtsp_latency_bin_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec) +{ + GstRTSPLatencyBin *latency_bin = GST_RTSP_LATENCY_BIN (object); + + switch (propid) { + case PROP_ELEMENT: + if (!gst_rtsp_latency_bin_add_element (latency_bin, + g_value_get_object (value))) { + GST_WARNING_OBJECT (latency_bin, "Could not add the element"); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static gboolean +gst_rtsp_latency_bin_add_element (GstRTSPLatencyBin * latency_bin, + GstElement * element) +{ + GstRTSPLatencyBinPrivate *priv = + GST_RTSP_LATENCY_BIN_GET_PRIVATE (latency_bin); + GstPad *pad; + GstPadTemplate *templ; + + GST_DEBUG_OBJECT (latency_bin, "Adding element to latencybin : %s", + GST_ELEMENT_NAME (element)); + + if (!element) { + goto no_element; + } + + /* add the element to ourself */ + gst_object_ref (element); + gst_bin_add (GST_BIN (latency_bin), element); + priv->element = element; + + /* add ghost pad first */ + templ = gst_static_pad_template_get (&sinktemplate); + priv->sinkpad = gst_ghost_pad_new_no_target_from_template ("sink", templ); + gst_object_unref (templ); + g_assert (priv->sinkpad); + + gst_element_add_pad (GST_ELEMENT (latency_bin), priv->sinkpad); + + /* and link it to our element */ + pad = gst_element_get_static_pad (element, "sink"); + if (!pad) { + goto no_sink_pad; + } + + if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (priv->sinkpad), pad)) { + goto set_target_failed; + } + + gst_object_unref (pad); + + return TRUE; + + /* ERRORs */ +no_element: + { + GST_WARNING_OBJECT (latency_bin, "No element, not adding"); + return FALSE; + } +no_sink_pad: + { + GST_WARNING_OBJECT (latency_bin, "The element has no sink pad"); + return FALSE; + } +set_target_failed: + { + GST_WARNING_OBJECT (latency_bin, "Could not set target pad"); + gst_object_unref (pad); + return FALSE; + } +} + + +static gboolean +gst_rtsp_latency_bin_element_query (GstElement * element, + GstQuery * query) +{ + gboolean ret = TRUE; + + GST_LOG_OBJECT (element, "got query %s", GST_QUERY_TYPE_NAME (query)); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_LATENCY: + /* ignoring latency query, we do not want our element to affect latency on + * the rest of the pipeline */ + GST_DEBUG_OBJECT (element, "ignoring latency query"); + gst_query_set_latency (query, FALSE, 0, -1); + break; + default: + ret = + GST_ELEMENT_CLASS (gst_rtsp_latency_bin_parent_class)->query ( + GST_ELEMENT (element), query); + break; + } + + return ret; +} + +static gboolean +gst_rtsp_latency_bin_element_event (GstElement * element, + GstEvent * event) +{ + gboolean ret = TRUE; + + GST_LOG_OBJECT (element, "got event %s", GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_LATENCY: + /* ignoring latency event, we will configure latency on our element when + * going to PLAYING */ + GST_DEBUG_OBJECT (element, "ignoring latency event"); + gst_event_unref (event); + break; + default: + ret = GST_ELEMENT_CLASS ( + gst_rtsp_latency_bin_parent_class)->send_event ( + GST_ELEMENT (element), event); + break; + } + + return ret; +} + +static gboolean +gst_rtsp_latency_bin_recalculate_latency (GstRTSPLatencyBin * latency_bin) +{ + GstRTSPLatencyBinPrivate *priv = + GST_RTSP_LATENCY_BIN_GET_PRIVATE (latency_bin); + GstEvent *latency; + GstQuery *query; + GstClockTime min_latency; + + GST_DEBUG_OBJECT (latency_bin, "Recalculating latency"); + + if (!priv->element) { + GST_WARNING_OBJECT (latency_bin, "We do not have an element"); + return FALSE; + } + + query = gst_query_new_latency (); + + if (!gst_element_query (priv->element, query)) { + GST_WARNING_OBJECT (latency_bin, "Latency query failed"); + gst_query_unref (query); + return FALSE; + } + + gst_query_parse_latency (query, NULL, &min_latency, NULL); + gst_query_unref (query); + + GST_LOG_OBJECT (latency_bin, "Got min_latency from stream: %" + GST_TIME_FORMAT, GST_TIME_ARGS (min_latency)); + + latency = gst_event_new_latency (min_latency); + if (!gst_element_send_event (priv->element, latency)) { + GST_WARNING_OBJECT (latency_bin, "Sending latency event to stream failed"); + return FALSE; + } + + return TRUE; +} + +static void +gst_rtsp_latency_bin_message_handler (GstBin * bin, GstMessage * message) +{ + GstRTSPLatencyBin *latency_bin = GST_RTSP_LATENCY_BIN (bin); + + GST_LOG_OBJECT (bin, "Got message %s", GST_MESSAGE_TYPE_NAME (message)); + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_LATENCY:{ + if (!gst_rtsp_latency_bin_recalculate_latency (latency_bin)) { + GST_WARNING_OBJECT (latency_bin, "Could not recalculate latency"); + } + break; + } + default: + GST_BIN_CLASS (gst_rtsp_latency_bin_parent_class)->handle_message ( + bin, message); + break; + } +} + +static GstStateChangeReturn +gst_rtsp_latency_bin_change_state (GstElement * element, GstStateChange + transition) +{ + GstRTSPLatencyBin *latency_bin = GST_RTSP_LATENCY_BIN (element); + GstStateChangeReturn ret; + + GST_LOG_OBJECT (latency_bin, "Changing state %s", + gst_state_change_get_name (transition)); + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + case GST_STATE_CHANGE_PLAYING_TO_PLAYING: + if (!gst_rtsp_latency_bin_recalculate_latency (latency_bin)) { + GST_WARNING_OBJECT (latency_bin, "Could not recalculate latency"); + } + default: + break; + } + + ret = GST_ELEMENT_CLASS (gst_rtsp_latency_bin_parent_class)->change_state + (element, transition); + + return ret; +} + +/** + * gst_rtsp_latency_bin_new: + * @element: (transfer full): a #GstElement + * + * Create a bin that encapsulates an @element and prevents it from affecting + * latency on the whole pipeline. + * + * Returns: A newly created #GstRTSPLatencyBin element, or %NULL on failure + */ +GstElement * +gst_rtsp_latency_bin_new (GstElement * element) +{ + GstElement *gst_rtsp_latency_bin; + + g_return_val_if_fail (element, NULL); + + gst_rtsp_latency_bin = g_object_new (GST_RTSP_LATENCY_BIN_TYPE, "element", + element, NULL); + gst_object_unref (element); + return gst_rtsp_latency_bin; +} diff --git a/gst/rtsp-server/rtsp-latency-bin.h b/gst/rtsp-server/rtsp-latency-bin.h new file mode 100644 index 0000000000..455e7c5713 --- /dev/null +++ b/gst/rtsp-server/rtsp-latency-bin.h @@ -0,0 +1,59 @@ +/* GStreamer + * Copyright (C) 2018 Ognyan Tonchev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_RTSP_LATENCY_BIN_H__ +#define __GST_RTSP_LATENCY_BIN_H__ + +#include +#include "rtsp-server-prelude.h" + +G_BEGIN_DECLS + +typedef struct _GstRTSPLatencyBin GstRTSPLatencyBin; +typedef struct _GstRTSPLatencyBinClass GstRTSPLatencyBinClass; +typedef struct _GstRTSPLatencyBinPrivate GstRTSPLatencyBinPrivate; + +#define GST_RTSP_LATENCY_BIN_TYPE (gst_rtsp_latency_bin_get_type ()) +#define IS_GST_RTSP_LATENCY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_RTSP_LATENCY_BIN_TYPE)) +#define IS_GST_RTSP_LATENCY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_RTSP_LATENCY_BIN_TYPE)) +#define GST_RTSP_LATENCY_BIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_RTSP_LATENCY_BIN_TYPE, GstRTSPLatencyBinClass)) +#define GST_RTSP_LATENCY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_RTSP_LATENCY_BIN_TYPE, GstRTSPLatencyBin)) +#define GST_RTSP_LATENCY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_RTSP_LATENCY_BIN_TYPE, GstRTSPLatencyBinClass)) +#define GST_RTSP_LATENCY_BIN_CAST(obj) ((GstRTSPLatencyBin*)(obj)) +#define GST_RTSP_LATENCY_BIN_CLASS_CAST(klass) ((GstRTSPLatencyBinClass*)(klass)) + +struct _GstRTSPLatencyBin { + GstBin parent; + + GstRTSPLatencyBinPrivate *priv; +}; + +struct _GstRTSPLatencyBinClass { + GstBinClass parent_class; +}; + +GST_RTSP_SERVER_API +GType gst_rtsp_latency_bin_get_type (void); + +GST_RTSP_SERVER_API +GstElement * gst_rtsp_latency_bin_new (GstElement * element); + +G_END_DECLS + +#endif /* __GST_RTSP_LATENCY_BIN_H__ */ diff --git a/gst/rtsp-server/rtsp-onvif-media.c b/gst/rtsp-server/rtsp-onvif-media.c index dcd86f244c..29fdec294c 100644 --- a/gst/rtsp-server/rtsp-onvif-media.c +++ b/gst/rtsp-server/rtsp-onvif-media.c @@ -42,6 +42,7 @@ #endif #include "rtsp-onvif-media.h" +#include "rtsp-latency-bin.h" struct GstRTSPOnvifMediaPrivate { @@ -251,6 +252,7 @@ gboolean gst_rtsp_onvif_media_collect_backchannel (GstRTSPOnvifMedia * media) { GstElement *element, *backchannel_bin = NULL; + GstElement *latency_bin; GstPad *pad = NULL; gboolean ret = FALSE; @@ -265,11 +267,28 @@ gst_rtsp_onvif_media_collect_backchannel (GstRTSPOnvifMedia * media) if (!backchannel_bin) goto out; - pad = gst_element_get_static_pad (backchannel_bin, "sink"); + /* We don't want the backchannel element, which is a receiver, to affect + * latency on the complete pipeline. That's why we remove it from the + * pipeline and add it to a @GstRTSPLatencyBin which will prevent it from + * messing up pipelines latency. The extra reference is needed so that it + * is not freed in case the pipeline holds the the only ref to it. + * + * TODO: a more generic solution should be implemented in + * gst_rtsp_media_collect_streams() where all receivers are encapsulated + * in a @GstRTSPLatencyBin in cases when there are senders too. */ + gst_object_ref (backchannel_bin); + gst_bin_remove (GST_BIN (element), backchannel_bin); + + latency_bin = gst_rtsp_latency_bin_new (backchannel_bin); + g_assert (latency_bin); + + gst_bin_add (GST_BIN (element), latency_bin); + + pad = gst_element_get_static_pad (latency_bin, "sink"); if (!pad) goto out; - gst_rtsp_media_create_stream (GST_RTSP_MEDIA (media), backchannel_bin, pad); + gst_rtsp_media_create_stream (GST_RTSP_MEDIA (media), latency_bin, pad); ret = TRUE; out: From 22ced50da5a6a19031fb395d49601171b7375645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 4 Oct 2018 14:31:59 +0100 Subject: [PATCH 1562/1776] autotools: fix distcheck --- gst/rtsp-server/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 7009c56e8b..59e214a267 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -50,7 +50,8 @@ c_sources = \ rtsp-onvif-media-factory.c \ rtsp-onvif-media.c -noinst_HEADERS = +noinst_HEADERS = \ + rtsp-latency-bin.h lib_LTLIBRARIES = \ libgstrtspserver-@GST_API_VERSION@.la From ebafccb65abead1456428a85a08c2a7121f73b02 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 20 Oct 2018 16:14:53 +0200 Subject: [PATCH 1563/1776] rtsp-client: Remove timeout GSource on cleanup Avoids ending up with races where a timeout would still be around *after* a client was gone. This could happen rather easily in RTSP-over-HTTP mode on a local connection, where each RTSP message would be sent as a different HTTP connection with the same tunnelid. If not properly removed, that timeout would then try to free again a client (and its contents). --- gst/rtsp-server/rtsp-client.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a55aae489e..be12782a4c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -782,6 +782,14 @@ gst_rtsp_client_finalize (GObject * obj) clean_cached_media (client, TRUE); + if (priv->rtsp_ctrl_timeout_id != 0) { + GST_DEBUG ("Killing leftover timeout GSource for client %p", client); + g_source_destroy (g_main_context_find_source_by_id (priv->watch_context, + priv->rtsp_ctrl_timeout_id)); + priv->rtsp_ctrl_timeout_id = 0; + priv->rtsp_ctrl_timeout_cnt = 0; + } + g_free (priv->server_ip); g_mutex_clear (&priv->lock); g_mutex_clear (&priv->send_lock); From 7cfd59820af4bbd69f682dd91cd6c37f7c38b501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Thu, 18 Oct 2018 07:25:05 +0200 Subject: [PATCH 1564/1776] rtsp-stream: use idle source in on_message_sent When the underlying layers are running on_message_sent, this sometimes causes the underlying layer to send more data, which will cause the underlying layer to run callback on_message_sent again. This can go on and on. To break this chain, we introduce an idle source that takes care of sending data if there are more to send when running callback https://bugzilla.gnome.org/show_bug.cgi?id=797289 --- gst/rtsp-server/rtsp-client.c | 1 + gst/rtsp-server/rtsp-latency-bin.c | 22 ++++----- gst/rtsp-server/rtsp-stream.c | 76 ++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-stream.h | 3 ++ 4 files changed, 87 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index be12782a4c..70196a1091 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2533,6 +2533,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) g_object_ref (trans); add_data_seq (client, ct->interleaved.min); add_data_seq (client, ct->interleaved.max); + gst_rtsp_stream_set_watch_context (stream, priv->watch_context); } /* create and serialize the server transport */ diff --git a/gst/rtsp-server/rtsp-latency-bin.c b/gst/rtsp-server/rtsp-latency-bin.c index 6a12fbe9de..cf7cdf1c33 100644 --- a/gst/rtsp-server/rtsp-latency-bin.c +++ b/gst/rtsp-server/rtsp-latency-bin.c @@ -126,7 +126,7 @@ gst_rtsp_latency_bin_set_property (GObject * object, guint propid, switch (propid) { case PROP_ELEMENT: if (!gst_rtsp_latency_bin_add_element (latency_bin, - g_value_get_object (value))) { + g_value_get_object (value))) { GST_WARNING_OBJECT (latency_bin, "Could not add the element"); } break; @@ -199,8 +199,7 @@ set_target_failed: static gboolean -gst_rtsp_latency_bin_element_query (GstElement * element, - GstQuery * query) +gst_rtsp_latency_bin_element_query (GstElement * element, GstQuery * query) { gboolean ret = TRUE; @@ -215,8 +214,8 @@ gst_rtsp_latency_bin_element_query (GstElement * element, break; default: ret = - GST_ELEMENT_CLASS (gst_rtsp_latency_bin_parent_class)->query ( - GST_ELEMENT (element), query); + GST_ELEMENT_CLASS (gst_rtsp_latency_bin_parent_class)->query + (GST_ELEMENT (element), query); break; } @@ -224,8 +223,7 @@ gst_rtsp_latency_bin_element_query (GstElement * element, } static gboolean -gst_rtsp_latency_bin_element_event (GstElement * element, - GstEvent * event) +gst_rtsp_latency_bin_element_event (GstElement * element, GstEvent * event) { gboolean ret = TRUE; @@ -239,9 +237,9 @@ gst_rtsp_latency_bin_element_event (GstElement * element, gst_event_unref (event); break; default: - ret = GST_ELEMENT_CLASS ( - gst_rtsp_latency_bin_parent_class)->send_event ( - GST_ELEMENT (element), event); + ret = + GST_ELEMENT_CLASS (gst_rtsp_latency_bin_parent_class)->send_event + (GST_ELEMENT (element), event); break; } @@ -302,8 +300,8 @@ gst_rtsp_latency_bin_message_handler (GstBin * bin, GstMessage * message) break; } default: - GST_BIN_CLASS (gst_rtsp_latency_bin_parent_class)->handle_message ( - bin, message); + GST_BIN_CLASS (gst_rtsp_latency_bin_parent_class)->handle_message (bin, + message); break; } } diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 18ec2925c0..60c13301d8 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -181,6 +181,7 @@ struct _GstRTSPStreamPrivate GHashTable *ptmap; GstRTSPPublishClockMode publish_clock_mode; + GMainContext *watch_context; }; #define DEFAULT_CONTROL NULL @@ -297,6 +298,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream) NULL, (GDestroyNotify) gst_caps_unref); priv->ptmap = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) gst_caps_unref); + priv->watch_context = NULL; } typedef struct _UdpClientAddrInfo UdpClientAddrInfo; @@ -376,6 +378,9 @@ gst_rtsp_stream_finalize (GObject * obj) g_hash_table_unref (priv->keys); g_hash_table_destroy (priv->ptmap); + if (priv->watch_context) + g_main_context_unref (priv->watch_context); + G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); } @@ -4327,12 +4332,37 @@ mcast_error: } } +static gboolean +cb_send_tcp_message (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv = stream->priv; + gint idx = -1; + gint i; + + g_mutex_lock (&priv->lock); + + /* iterate from 1 and down, so we prioritize RTCP over RTP */ + for (i = 1; i >= 0; i--) { + if (priv->have_buffer[i]) { + /* send message */ + idx = i; + break; + } + } + + if (idx != -1) + send_tcp_message (stream, idx); + g_mutex_unlock (&priv->lock); + return G_SOURCE_REMOVE; +} + static void on_message_sent (gpointer user_data) { GstRTSPStream *stream = user_data; GstRTSPStreamPrivate *priv = stream->priv; gint idx = -1; + GSource *idle_src; GST_DEBUG_OBJECT (stream, "message send complete"); @@ -4357,9 +4387,24 @@ on_message_sent (gpointer user_data) } } - if (idx != -1) - send_tcp_message (stream, idx); - + if (idx != -1) { + /* When appsink running this callback we want to send as much as we can + * But when idle callback or watch callback is running we will first + * queue an idle probe. This so we prevent a loop to occur were callback + * is sending more data that then call the callback that sends more data + * and so on. If the loop occur then it will starve out handling off + * other events that are handled by watch's context. */ + if (priv->watch_context && g_main_context_is_owner (priv->watch_context)) { + /* underlaying layer is running this callback */ + idle_src = g_idle_source_new (); + g_source_set_callback (idle_src, (GSourceFunc) cb_send_tcp_message, + g_object_ref (stream), g_object_unref); + g_source_attach (idle_src, priv->watch_context); + } else { + /* appsink is running this callback */ + send_tcp_message (stream, idx); + } + } g_mutex_unlock (&priv->lock); return; @@ -5728,3 +5773,28 @@ gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream * stream) return res; } + +/** + * gst_rtsp_stream_set_watch_context: + * @stream: a #GstRTSPStream + * @context: a #GMainContext + * + * Sets stream private watch_context. + * + */ +void +gst_rtsp_stream_set_watch_context (GstRTSPStream * stream, + GMainContext * context) +{ + GstRTSPStreamPrivate *priv; + priv = stream->priv; + + g_mutex_lock (&priv->lock); + if (priv->watch_context != NULL) { + g_main_context_unref (priv->watch_context); + priv->watch_context = NULL; + } + if (context) + priv->watch_context = g_main_context_ref (context); + g_mutex_unlock (&priv->lock); +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 7910bb05d7..53ad57c942 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -354,6 +354,9 @@ void gst_rtsp_stream_set_ulpfec_percentage (GstRTSPStream *stream, GST_RTSP_SERVER_API guint gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream *stream); +GST_RTSP_SERVER_API +void gst_rtsp_stream_set_watch_context (GstRTSPStream * stream, GMainContext * context); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object From 84a7f459a14748180c636c2bbf7b7479c5d25f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 1 Nov 2018 10:18:22 +0200 Subject: [PATCH 1565/1776] Include ONVIF types from single-include rtsp-server.h ... by actually making it a single-include header and moving everything related to the GstRTSPServer type to rtsp-server-object.h instead. Otherwise there are too many circular includes. https://bugzilla.gnome.org/show_bug.cgi?id=797361 --- gst/rtsp-server/Makefile.am | 1 + gst/rtsp-server/meson.build | 1 + gst/rtsp-server/rtsp-context.h | 2 +- gst/rtsp-server/rtsp-onvif-server.c | 1 + gst/rtsp-server/rtsp-onvif-server.h | 2 +- gst/rtsp-server/rtsp-server-object.h | 205 ++++++++++++++++++++++++++ gst/rtsp-server/rtsp-server-prelude.h | 9 ++ gst/rtsp-server/rtsp-server.c | 3 +- gst/rtsp-server/rtsp-server.h | 169 +-------------------- gst/rtsp-server/rtsp-session.h | 2 +- 10 files changed, 227 insertions(+), 168 deletions(-) create mode 100644 gst/rtsp-server/rtsp-server-object.h diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 59e214a267..112e529968 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -18,6 +18,7 @@ public_headers = \ rtsp-token.h \ rtsp-client.h \ rtsp-server.h \ + rtsp-server-object.h \ rtsp-server-prelude.h \ rtsp-onvif-server.h \ rtsp-onvif-client.h \ diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index 143385f989..27cf384c2e 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -41,6 +41,7 @@ rtsp_server_headers = [ 'rtsp-token.h', 'rtsp-client.h', 'rtsp-server.h', + 'rtsp-server-object.h', 'rtsp-server-prelude.h', ] install_headers(rtsp_server_headers, subdir : 'gstreamer-1.0/gst/rtsp-server') diff --git a/gst/rtsp-server/rtsp-context.h b/gst/rtsp-server/rtsp-context.h index dcd2f9b85e..c4567f9b09 100644 --- a/gst/rtsp-server/rtsp-context.h +++ b/gst/rtsp-server/rtsp-context.h @@ -30,7 +30,7 @@ G_BEGIN_DECLS typedef struct _GstRTSPContext GstRTSPContext; #include "rtsp-server-prelude.h" -#include "rtsp-server.h" +#include "rtsp-server-object.h" #include "rtsp-media.h" #include "rtsp-media-factory.h" #include "rtsp-session-media.h" diff --git a/gst/rtsp-server/rtsp-onvif-server.c b/gst/rtsp-server/rtsp-onvif-server.c index 3c3c6f4992..704d8b284b 100644 --- a/gst/rtsp-server/rtsp-onvif-server.c +++ b/gst/rtsp-server/rtsp-onvif-server.c @@ -35,6 +35,7 @@ #include "config.h" #endif +#include "rtsp-context.h" #include "rtsp-onvif-server.h" #include "rtsp-onvif-client.h" diff --git a/gst/rtsp-server/rtsp-onvif-server.h b/gst/rtsp-server/rtsp-onvif-server.h index f9d8e4899f..f9f1836ea8 100644 --- a/gst/rtsp-server/rtsp-onvif-server.h +++ b/gst/rtsp-server/rtsp-onvif-server.h @@ -21,7 +21,7 @@ #define __GST_RTSP_ONVIF_SERVER_H__ #include -#include "rtsp-server.h" +#include "rtsp-server-object.h" #define GST_TYPE_RTSP_ONVIF_SERVER (gst_rtsp_onvif_server_get_type ()) #define GST_IS_RTSP_ONVIF_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_ONVIF_SERVER)) diff --git a/gst/rtsp-server/rtsp-server-object.h b/gst/rtsp-server/rtsp-server-object.h new file mode 100644 index 0000000000..9827f99893 --- /dev/null +++ b/gst/rtsp-server/rtsp-server-object.h @@ -0,0 +1,205 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_RTSP_SERVER_H__ +#define __GST_RTSP_SERVER_H__ + +#include + +G_BEGIN_DECLS + +#include "rtsp-server-prelude.h" +#include "rtsp-session-pool.h" +#include "rtsp-session.h" +#include "rtsp-media.h" +#include "rtsp-stream.h" +#include "rtsp-stream-transport.h" +#include "rtsp-address-pool.h" +#include "rtsp-thread-pool.h" +#include "rtsp-client.h" +#include "rtsp-context.h" +#include "rtsp-mount-points.h" +#include "rtsp-media-factory.h" +#include "rtsp-permissions.h" +#include "rtsp-auth.h" +#include "rtsp-token.h" +#include "rtsp-session-media.h" +#include "rtsp-sdp.h" +#include "rtsp-media-factory-uri.h" +#include "rtsp-params.h" + +typedef struct _GstRTSPServer GstRTSPServer; +typedef struct _GstRTSPServerClass GstRTSPServerClass; +typedef struct _GstRTSPServerPrivate GstRTSPServerPrivate; + +#define GST_TYPE_RTSP_SERVER (gst_rtsp_server_get_type ()) +#define GST_IS_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SERVER)) +#define GST_IS_RTSP_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SERVER)) +#define GST_RTSP_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_SERVER, GstRTSPServerClass)) +#define GST_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_SERVER, GstRTSPServer)) +#define GST_RTSP_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_SERVER, GstRTSPServerClass)) +#define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj)) +#define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass)) + +/** + * GstRTSPServer: + * + * This object listens on a port, creates and manages the clients connected to + * it. + */ +struct _GstRTSPServer { + GObject parent; + + /*< private >*/ + GstRTSPServerPrivate *priv; + gpointer _gst_reserved[GST_PADDING]; +}; + +/** + * GstRTSPServerClass: + * @create_client: Create, configure a new GstRTSPClient + * object that handles the new connection on @socket. The default + * implementation will create a GstRTSPClient and will configure the + * mount-points, auth, session-pool and thread-pool on the client. + * @client_connected: emitted when a new client connected. + * + * The RTSP server class structure + */ +struct _GstRTSPServerClass { + GObjectClass parent_class; + + GstRTSPClient * (*create_client) (GstRTSPServer *server); + + /* signals */ + void (*client_connected) (GstRTSPServer *server, GstRTSPClient *client); + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + +GST_RTSP_SERVER_API +GType gst_rtsp_server_get_type (void); + +GST_RTSP_SERVER_API +GstRTSPServer * gst_rtsp_server_new (void); + +GST_RTSP_SERVER_API +void gst_rtsp_server_set_address (GstRTSPServer *server, const gchar *address); + +GST_RTSP_SERVER_API +gchar * gst_rtsp_server_get_address (GstRTSPServer *server); + +GST_RTSP_SERVER_API +void gst_rtsp_server_set_service (GstRTSPServer *server, const gchar *service); + +GST_RTSP_SERVER_API +gchar * gst_rtsp_server_get_service (GstRTSPServer *server); + +GST_RTSP_SERVER_API +void gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog); + +GST_RTSP_SERVER_API +gint gst_rtsp_server_get_backlog (GstRTSPServer *server); + +GST_RTSP_SERVER_API +int gst_rtsp_server_get_bound_port (GstRTSPServer *server); + +GST_RTSP_SERVER_API +void gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool); + +GST_RTSP_SERVER_API +GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *server); + +GST_RTSP_SERVER_API +void gst_rtsp_server_set_mount_points (GstRTSPServer *server, GstRTSPMountPoints *mounts); + +GST_RTSP_SERVER_API +GstRTSPMountPoints * gst_rtsp_server_get_mount_points (GstRTSPServer *server); + +GST_RTSP_SERVER_API +void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); + +GST_RTSP_SERVER_API +GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server); + +GST_RTSP_SERVER_API +void gst_rtsp_server_set_thread_pool (GstRTSPServer *server, GstRTSPThreadPool *pool); + +GST_RTSP_SERVER_API +GstRTSPThreadPool * gst_rtsp_server_get_thread_pool (GstRTSPServer *server); + +GST_RTSP_SERVER_API +gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket *socket, + const gchar * ip, gint port, + const gchar *initial_buffer); + +GST_RTSP_SERVER_API +gboolean gst_rtsp_server_io_func (GSocket *socket, GIOCondition condition, + GstRTSPServer *server); + +GST_RTSP_SERVER_API +GSocket * gst_rtsp_server_create_socket (GstRTSPServer *server, + GCancellable *cancellable, + GError **error); + +GST_RTSP_SERVER_API +GSource * gst_rtsp_server_create_source (GstRTSPServer *server, + GCancellable * cancellable, + GError **error); + +GST_RTSP_SERVER_API +guint gst_rtsp_server_attach (GstRTSPServer *server, + GMainContext *context); + +/** + * GstRTSPServerClientFilterFunc: + * @server: a #GstRTSPServer object + * @client: a #GstRTSPClient in @server + * @user_data: user data that has been given to gst_rtsp_server_client_filter() + * + * This function will be called by the gst_rtsp_server_client_filter(). An + * implementation should return a value of #GstRTSPFilterResult. + * + * When this function returns #GST_RTSP_FILTER_REMOVE, @client will be removed + * from @server. + * + * A return value of #GST_RTSP_FILTER_KEEP will leave @client untouched in + * @server. + * + * A value of #GST_RTSP_FILTER_REF will add @client to the result #GList of + * gst_rtsp_server_client_filter(). + * + * Returns: a #GstRTSPFilterResult. + */ +typedef GstRTSPFilterResult (*GstRTSPServerClientFilterFunc) (GstRTSPServer *server, + GstRTSPClient *client, + gpointer user_data); + +GST_RTSP_SERVER_API +GList * gst_rtsp_server_client_filter (GstRTSPServer *server, + GstRTSPServerClientFilterFunc func, + gpointer user_data); + +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPServer, gst_object_unref) +#endif + +G_END_DECLS + +#endif /* __GST_RTSP_SERVER_H__ */ diff --git a/gst/rtsp-server/rtsp-server-prelude.h b/gst/rtsp-server/rtsp-server-prelude.h index ac4ad2ce78..8aff8c4934 100644 --- a/gst/rtsp-server/rtsp-server-prelude.h +++ b/gst/rtsp-server/rtsp-server-prelude.h @@ -32,4 +32,13 @@ # endif #endif +/* Do *not* use these defines outside of rtsp-server. Use G_DEPRECATED instead. */ +#ifdef GST_DISABLE_DEPRECATED +#define GST_RTSP_SERVER_DEPRECATED GST_RTSP_SERVER_API +#define GST_RTSP_SERVER_DEPRECATED_FOR(f) GST_RTSP_SERVER_API +#else +#define GST_RTSP_SERVER_DEPRECATED G_DEPRECATED GST_RTSP_SERVER_API +#define GST_RTSP_SERVER_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) GST_RTSP_SERVER_API +#endif + #endif /* __GST_RTSP_SERVER_PRELUDE_H__ */ diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index de409e0346..47b718737a 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -59,7 +59,8 @@ #include #include -#include "rtsp-server.h" +#include "rtsp-context.h" +#include "rtsp-server-object.h" #include "rtsp-client.h" #define GST_RTSP_SERVER_GET_LOCK(server) (&(GST_RTSP_SERVER_CAST(server)->priv->lock)) diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 7364864875..cda2a665a9 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -24,19 +24,6 @@ G_BEGIN_DECLS -/* Do *not* use these defines outside of rtsp-server. Use G_DEPRECATED instead. */ -#ifdef GST_DISABLE_DEPRECATED -#define GST_RTSP_SERVER_DEPRECATED GST_RTSP_SERVER_API -#define GST_RTSP_SERVER_DEPRECATED_FOR(f) GST_RTSP_SERVER_API -#else -#define GST_RTSP_SERVER_DEPRECATED G_DEPRECATED GST_RTSP_SERVER_API -#define GST_RTSP_SERVER_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) GST_RTSP_SERVER_API -#endif - -typedef struct _GstRTSPServer GstRTSPServer; -typedef struct _GstRTSPServerClass GstRTSPServerClass; -typedef struct _GstRTSPServerPrivate GstRTSPServerPrivate; - #include "rtsp-server-prelude.h" #include "rtsp-session-pool.h" #include "rtsp-session.h" @@ -57,158 +44,12 @@ typedef struct _GstRTSPServerPrivate GstRTSPServerPrivate; #include "rtsp-sdp.h" #include "rtsp-media-factory-uri.h" #include "rtsp-params.h" +#include "rtsp-server-object.h" -#define GST_TYPE_RTSP_SERVER (gst_rtsp_server_get_type ()) -#define GST_IS_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SERVER)) -#define GST_IS_RTSP_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SERVER)) -#define GST_RTSP_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_SERVER, GstRTSPServerClass)) -#define GST_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_SERVER, GstRTSPServer)) -#define GST_RTSP_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_SERVER, GstRTSPServerClass)) -#define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj)) -#define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass)) - -/** - * GstRTSPServer: - * - * This object listens on a port, creates and manages the clients connected to - * it. - */ -struct _GstRTSPServer { - GObject parent; - - /*< private >*/ - GstRTSPServerPrivate *priv; - gpointer _gst_reserved[GST_PADDING]; -}; - -/** - * GstRTSPServerClass: - * @create_client: Create, configure a new GstRTSPClient - * object that handles the new connection on @socket. The default - * implementation will create a GstRTSPClient and will configure the - * mount-points, auth, session-pool and thread-pool on the client. - * @client_connected: emitted when a new client connected. - * - * The RTSP server class structure - */ -struct _GstRTSPServerClass { - GObjectClass parent_class; - - GstRTSPClient * (*create_client) (GstRTSPServer *server); - - /* signals */ - void (*client_connected) (GstRTSPServer *server, GstRTSPClient *client); - - /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE]; -}; - -GST_RTSP_SERVER_API -GType gst_rtsp_server_get_type (void); - -GST_RTSP_SERVER_API -GstRTSPServer * gst_rtsp_server_new (void); - -GST_RTSP_SERVER_API -void gst_rtsp_server_set_address (GstRTSPServer *server, const gchar *address); - -GST_RTSP_SERVER_API -gchar * gst_rtsp_server_get_address (GstRTSPServer *server); - -GST_RTSP_SERVER_API -void gst_rtsp_server_set_service (GstRTSPServer *server, const gchar *service); - -GST_RTSP_SERVER_API -gchar * gst_rtsp_server_get_service (GstRTSPServer *server); - -GST_RTSP_SERVER_API -void gst_rtsp_server_set_backlog (GstRTSPServer *server, gint backlog); - -GST_RTSP_SERVER_API -gint gst_rtsp_server_get_backlog (GstRTSPServer *server); - -GST_RTSP_SERVER_API -int gst_rtsp_server_get_bound_port (GstRTSPServer *server); - -GST_RTSP_SERVER_API -void gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool); - -GST_RTSP_SERVER_API -GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *server); - -GST_RTSP_SERVER_API -void gst_rtsp_server_set_mount_points (GstRTSPServer *server, GstRTSPMountPoints *mounts); - -GST_RTSP_SERVER_API -GstRTSPMountPoints * gst_rtsp_server_get_mount_points (GstRTSPServer *server); - -GST_RTSP_SERVER_API -void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); - -GST_RTSP_SERVER_API -GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server); - -GST_RTSP_SERVER_API -void gst_rtsp_server_set_thread_pool (GstRTSPServer *server, GstRTSPThreadPool *pool); - -GST_RTSP_SERVER_API -GstRTSPThreadPool * gst_rtsp_server_get_thread_pool (GstRTSPServer *server); - -GST_RTSP_SERVER_API -gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket *socket, - const gchar * ip, gint port, - const gchar *initial_buffer); - -GST_RTSP_SERVER_API -gboolean gst_rtsp_server_io_func (GSocket *socket, GIOCondition condition, - GstRTSPServer *server); - -GST_RTSP_SERVER_API -GSocket * gst_rtsp_server_create_socket (GstRTSPServer *server, - GCancellable *cancellable, - GError **error); - -GST_RTSP_SERVER_API -GSource * gst_rtsp_server_create_source (GstRTSPServer *server, - GCancellable * cancellable, - GError **error); - -GST_RTSP_SERVER_API -guint gst_rtsp_server_attach (GstRTSPServer *server, - GMainContext *context); - -/** - * GstRTSPServerClientFilterFunc: - * @server: a #GstRTSPServer object - * @client: a #GstRTSPClient in @server - * @user_data: user data that has been given to gst_rtsp_server_client_filter() - * - * This function will be called by the gst_rtsp_server_client_filter(). An - * implementation should return a value of #GstRTSPFilterResult. - * - * When this function returns #GST_RTSP_FILTER_REMOVE, @client will be removed - * from @server. - * - * A return value of #GST_RTSP_FILTER_KEEP will leave @client untouched in - * @server. - * - * A value of #GST_RTSP_FILTER_REF will add @client to the result #GList of - * gst_rtsp_server_client_filter(). - * - * Returns: a #GstRTSPFilterResult. - */ -typedef GstRTSPFilterResult (*GstRTSPServerClientFilterFunc) (GstRTSPServer *server, - GstRTSPClient *client, - gpointer user_data); - -GST_RTSP_SERVER_API -GList * gst_rtsp_server_client_filter (GstRTSPServer *server, - GstRTSPServerClientFilterFunc func, - gpointer user_data); - -#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPServer, gst_object_unref) -#endif +#include "rtsp-onvif-client.h" +#include "rtsp-onvif-media-factory.h" +#include "rtsp-onvif-media.h" +#include "rtsp-onvif-server.h" G_END_DECLS diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index 62d653a247..e2a46e6817 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -20,7 +20,7 @@ #include #include -#include "rtsp-server.h" /* for GST_RTSP_SERVER_DEPRECATED_FOR */ +#include "rtsp-server-prelude.h" /* for GST_RTSP_SERVER_DEPRECATED_FOR */ #ifndef __GST_RTSP_SESSION_H__ #define __GST_RTSP_SESSION_H__ From d525000f6a1929fd4c3e5d3eb5988a64fbd2e43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 1 Nov 2018 10:23:02 +0200 Subject: [PATCH 1566/1776] Mark all ONVIF-specific subclasses as Since 1.14 --- gst/rtsp-server/rtsp-onvif-client.h | 5 +++++ gst/rtsp-server/rtsp-onvif-media-factory.h | 5 +++++ gst/rtsp-server/rtsp-onvif-media.h | 5 +++++ gst/rtsp-server/rtsp-onvif-server.h | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/gst/rtsp-server/rtsp-onvif-client.h b/gst/rtsp-server/rtsp-onvif-client.h index 5514209922..2692cbf8c6 100644 --- a/gst/rtsp-server/rtsp-onvif-client.h +++ b/gst/rtsp-server/rtsp-onvif-client.h @@ -35,6 +35,11 @@ typedef struct GstRTSPOnvifClientClass GstRTSPOnvifClientClass; typedef struct GstRTSPOnvifClient GstRTSPOnvifClient; +/** + * GstRTSPOnvifClient: + * + * Since: 1.14 + */ struct GstRTSPOnvifClientClass { GstRTSPClientClass parent; diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.h b/gst/rtsp-server/rtsp-onvif-media-factory.h index 778b8f9cc2..25de214a87 100644 --- a/gst/rtsp-server/rtsp-onvif-media-factory.h +++ b/gst/rtsp-server/rtsp-onvif-media-factory.h @@ -36,6 +36,11 @@ typedef struct GstRTSPOnvifMediaFactoryClass GstRTSPOnvifMediaFactoryClass; typedef struct GstRTSPOnvifMediaFactory GstRTSPOnvifMediaFactory; typedef struct GstRTSPOnvifMediaFactoryPrivate GstRTSPOnvifMediaFactoryPrivate; +/** + * GstRTSPOnvifMediaFactory: + * + * Since: 1.14 + */ struct GstRTSPOnvifMediaFactoryClass { GstRTSPMediaFactoryClass parent; diff --git a/gst/rtsp-server/rtsp-onvif-media.h b/gst/rtsp-server/rtsp-onvif-media.h index 3997c3ea06..95418c073a 100644 --- a/gst/rtsp-server/rtsp-onvif-media.h +++ b/gst/rtsp-server/rtsp-onvif-media.h @@ -36,6 +36,11 @@ typedef struct GstRTSPOnvifMediaClass GstRTSPOnvifMediaClass; typedef struct GstRTSPOnvifMedia GstRTSPOnvifMedia; typedef struct GstRTSPOnvifMediaPrivate GstRTSPOnvifMediaPrivate; +/** + * GstRTSPOnvifMedia: + * + * Since: 1.14 + */ struct GstRTSPOnvifMediaClass { GstRTSPMediaClass parent; diff --git a/gst/rtsp-server/rtsp-onvif-server.h b/gst/rtsp-server/rtsp-onvif-server.h index f9f1836ea8..0594ba1c03 100644 --- a/gst/rtsp-server/rtsp-onvif-server.h +++ b/gst/rtsp-server/rtsp-onvif-server.h @@ -35,6 +35,11 @@ typedef struct GstRTSPOnvifServerClass GstRTSPOnvifServerClass; typedef struct GstRTSPOnvifServer GstRTSPOnvifServer; +/** + * GstRTSPOnvifServer: + * + * Since: 1.14 + */ struct GstRTSPOnvifServerClass { GstRTSPServerClass parent; From 5392cbba8a0895e6c2ab38b4b8f8d727c68690f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 1 Nov 2018 11:29:01 +0200 Subject: [PATCH 1567/1776] rtsp-server: Declare GstRTSPServer struct before anything else It's needed by all kinds of other headers, including the ones that are required for defining the GstRTSPServer struct itself and its API. --- gst/rtsp-server/rtsp-server-object.h | 14 +++++++------- gst/rtsp-server/rtsp-server.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-server-object.h b/gst/rtsp-server/rtsp-server-object.h index 9827f99893..118764ea1d 100644 --- a/gst/rtsp-server/rtsp-server-object.h +++ b/gst/rtsp-server/rtsp-server-object.h @@ -17,13 +17,17 @@ * Boston, MA 02110-1301, USA. */ -#ifndef __GST_RTSP_SERVER_H__ -#define __GST_RTSP_SERVER_H__ +#ifndef __GST_RTSP_SERVER_OBJECT_H__ +#define __GST_RTSP_SERVER_OBJECT_H__ #include G_BEGIN_DECLS +typedef struct _GstRTSPServer GstRTSPServer; +typedef struct _GstRTSPServerClass GstRTSPServerClass; +typedef struct _GstRTSPServerPrivate GstRTSPServerPrivate; + #include "rtsp-server-prelude.h" #include "rtsp-session-pool.h" #include "rtsp-session.h" @@ -44,10 +48,6 @@ G_BEGIN_DECLS #include "rtsp-media-factory-uri.h" #include "rtsp-params.h" -typedef struct _GstRTSPServer GstRTSPServer; -typedef struct _GstRTSPServerClass GstRTSPServerClass; -typedef struct _GstRTSPServerPrivate GstRTSPServerPrivate; - #define GST_TYPE_RTSP_SERVER (gst_rtsp_server_get_type ()) #define GST_IS_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SERVER)) #define GST_IS_RTSP_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SERVER)) @@ -202,4 +202,4 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPServer, gst_object_unref) G_END_DECLS -#endif /* __GST_RTSP_SERVER_H__ */ +#endif /* __GST_RTSP_SERVER_OBJECT_H__ */ diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index cda2a665a9..1dd1a23242 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -25,6 +25,7 @@ G_BEGIN_DECLS #include "rtsp-server-prelude.h" +#include "rtsp-server-object.h" #include "rtsp-session-pool.h" #include "rtsp-session.h" #include "rtsp-media.h" @@ -44,7 +45,6 @@ G_BEGIN_DECLS #include "rtsp-sdp.h" #include "rtsp-media-factory-uri.h" #include "rtsp-params.h" -#include "rtsp-server-object.h" #include "rtsp-onvif-client.h" #include "rtsp-onvif-media-factory.h" From 961de06be2523ddfb78eb6759bcc30e25b90c6b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 1 Nov 2018 12:49:51 +0200 Subject: [PATCH 1568/1776] Add ONVIF subclass headers to the installed headers in meson.build too --- gst/rtsp-server/meson.build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index 27cf384c2e..7463ee63b3 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -43,6 +43,10 @@ rtsp_server_headers = [ 'rtsp-server.h', 'rtsp-server-object.h', 'rtsp-server-prelude.h', + 'rtsp-onvif-server.h', + 'rtsp-onvif-client.h', + 'rtsp-onvif-media-factory.h', + 'rtsp-onvif-media.h', ] install_headers(rtsp_server_headers, subdir : 'gstreamer-1.0/gst/rtsp-server') From f43df76ee7874a4d1b8176bcab1b4fe20c05c478 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 1 Nov 2018 14:20:16 +0100 Subject: [PATCH 1569/1776] meson: add new onvif types --- gst/rtsp-server/meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index 7463ee63b3..6e40cc64de 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -19,6 +19,10 @@ rtsp_server_sources = [ 'rtsp-stream-transport.c', 'rtsp-thread-pool.c', 'rtsp-token.c', + 'rtsp-onvif-server.c', + 'rtsp-onvif-client.c', + 'rtsp-onvif-media-factory.c', + 'rtsp-onvif-media.c', ] rtsp_server_headers = [ @@ -48,6 +52,7 @@ rtsp_server_headers = [ 'rtsp-onvif-media-factory.h', 'rtsp-onvif-media.h', ] + install_headers(rtsp_server_headers, subdir : 'gstreamer-1.0/gst/rtsp-server') gst_rtsp_server_deps = [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_dep] From 8b4df97f9d635e0ba10fd2d0cbbfcdab2b18f90b Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 5 Nov 2018 05:56:35 +0000 Subject: [PATCH 1570/1776] Update git locations to gitlab --- .gitmodules | 2 +- gst-rtsp-server.doap | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 3ff9d95ea0..0ab838765a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "common"] path = common - url = https://anongit.freedesktop.org/git/gstreamer/common.git + url = https://gitlab.freedesktop.org/gstreamer/common.git diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 7e7c171d8c..5103fe4409 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -25,8 +25,8 @@ RTSP server library based on GStreamer - - + + From 2065298d6d2f391ba8ca4d19fa07010565f3665a Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Mon, 12 Nov 2018 16:06:39 +0200 Subject: [PATCH 1571/1776] Add Gitlab CI configuration This commit adds a .gitlab-ci.yml file, which uses a feature to fetch the config from a centralized repository. The intent is to have all the gstreamer modules use the same configuration. The configuration is currently hosted at the gst-ci repository under the gitlab/ci_template.yml path. Part of https://gitlab.freedesktop.org/gstreamer/gstreamer-project/issues/29 --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000..c61aa7a529 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1 @@ +include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml" From 1c4d3b36fbb8ac95e056bbae6a08bb67c429047c Mon Sep 17 00:00:00 2001 From: Linus Svensson Date: Tue, 6 Nov 2018 18:10:56 +0100 Subject: [PATCH 1572/1776] rtsp-stream: Plug memory leak Attaching a GSource to a context will increase the refcount. The idle source will never be free'd since the initial reference is never dropped. --- gst/rtsp-server/rtsp-stream.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 60c13301d8..9ae66a06f5 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4400,6 +4400,7 @@ on_message_sent (gpointer user_data) g_source_set_callback (idle_src, (GSourceFunc) cb_send_tcp_message, g_object_ref (stream), g_object_unref); g_source_attach (idle_src, priv->watch_context); + g_source_unref (idle_src); } else { /* appsink is running this callback */ send_tcp_message (stream, idx); From 185385924d458261a35178221f3c230f730dba70 Mon Sep 17 00:00:00 2001 From: Linus Svensson Date: Tue, 6 Nov 2018 18:21:54 +0100 Subject: [PATCH 1573/1776] rtsp-stream: Use seqnum-offset for rtpinfo The sequence number in the rtpinfo is supposed to be the first RTP sequence number. The "seqnum" property on a payloader is supposed to be the number from the last processed RTP packet. The sequence number for payloaders that inherit gstrtpbasepayload will not be correct in case of buffer lists. In order to fix the seqnum property on the payloaders gst-rtsp-server must get the sequence number for rtpinfo elsewhere and "seqnum-offset" from the "stats" property contains the value of the very first RTP packet in a stream. The server will, however, try to look at the last simple in the sink element and only use properties on the payloader in case there no sink elements yet, and by looking at the last sample of the sink gives the server full control of which RTP packet it looks at. If the payloader does not have the "stats" property, "seqnum" is still used since "seqnum-offset" is only present in as part of "stats" and this is still an issue not solved with this patch. Needed for gst-plugins-base!17 --- gst/rtsp-server/rtsp-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 9ae66a06f5..83291d6a2a 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4006,7 +4006,7 @@ stats: goto no_stats; if (seq) - gst_structure_get_uint (stats, "seqnum", seq); + gst_structure_get_uint (stats, "seqnum-offset", seq); if (rtptime) gst_structure_get_uint (stats, "timestamp", rtptime); From d4a8834ffef3ad75920968d6d6f20c16066c7263 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Sat, 17 Nov 2018 16:11:53 +0100 Subject: [PATCH 1574/1776] tests: rtspserver: Add shared media test case for TCP --- tests/check/gst/rtspserver.c | 44 +++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index b8b1608a96..d342a436d3 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -192,7 +192,7 @@ start_server (gboolean set_shared_factory) } static void -start_tcp_server (void) +start_tcp_server (gboolean set_shared_factory) { GstRTSPMountPoints *mounts; gchar *service; @@ -206,6 +206,7 @@ start_tcp_server (void) gst_rtsp_media_factory_set_launch (factory, "( " VIDEO_PIPELINE " " AUDIO_PIPELINE " )"); gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); + gst_rtsp_media_factory_set_shared (factory, set_shared_factory); g_object_unref (mounts); /* set port to any */ @@ -1236,7 +1237,7 @@ GST_START_TEST (test_play_tcp) GstRTSPTransport *video_transport = NULL; GstRTSPTransport *audio_transport = NULL; - start_tcp_server (); + start_tcp_server (FALSE); conn = connect_to_server (test_port, TEST_MOUNT_POINT); @@ -1910,7 +1911,7 @@ GST_END_TEST; GST_START_TEST (test_play_smpte_range_tcp) { - start_tcp_server (); + start_tcp_server (FALSE); do_test_play_tcp_full ("npt=5-"); do_test_play_tcp_full ("smpte=0:00:00-"); @@ -1925,14 +1926,21 @@ GST_START_TEST (test_play_smpte_range_tcp) GST_END_TEST; static gpointer -thread_func (gpointer data) +thread_func_udp (gpointer data) { do_test_play_full (NULL, GST_RTSP_LOWER_TRANS_UDP, (GMutex *) data); return NULL; } -/* Test adding and removing clients to a 'Shared' media. */ -GST_START_TEST (test_shared) +static gpointer +thread_func_tcp (gpointer data) +{ + do_test_play_tcp_full (NULL); + return NULL; +} + +static void +test_shared (gpointer (thread_func) (gpointer data)) { GMutex lock1, lock2, lock3, lock4; GThread *thread1, *thread2, *thread3, *thread4; @@ -1944,7 +1952,10 @@ GST_START_TEST (test_shared) g_mutex_init (&lock3); g_mutex_init (&lock4); - start_server (TRUE); + if (thread_func == thread_func_tcp) + start_tcp_server (TRUE); + else + start_server (TRUE); /* Start the first receiver thread. */ g_mutex_lock (&lock1); @@ -1981,6 +1992,22 @@ GST_START_TEST (test_shared) iterate (); } +/* Test adding and removing clients to a 'Shared' media. + * CASE: unicast UDP */ +GST_START_TEST (test_shared_udp) +{ + test_shared (thread_func_udp); +} + +GST_END_TEST; + +/* Test adding and removing clients to a 'Shared' media. + * CASE: unicast TCP */ +GST_START_TEST (test_shared_tcp) +{ + test_shared (thread_func_tcp); +} + GST_END_TEST; GST_START_TEST (test_announce_without_sdp) @@ -2407,7 +2434,8 @@ rtspserver_suite (void) tcase_add_test (tc, test_play_specific_server_port); tcase_add_test (tc, test_play_smpte_range); tcase_add_test (tc, test_play_smpte_range_tcp); - tcase_add_test (tc, test_shared); + tcase_add_test (tc, test_shared_udp); + tcase_add_test (tc, test_shared_tcp); tcase_add_test (tc, test_announce_without_sdp); tcase_add_test (tc, test_record_tcp); tcase_add_test (tc, test_multiple_transports); From 146b3da17482d57d79359c7bd554fd9ca8377a59 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Sat, 17 Nov 2018 18:18:27 +0100 Subject: [PATCH 1575/1776] rtsp-media: Don't block streams before seeking Before the seek operation is performed on media, it's required that its pipeline is prepared <=> the pipeline is in the PAUSED state. At this stage, all transport parts (transport sinks) have been successfully added to the pipeline and there is no need for blocking the streams. --- gst/rtsp-server/rtsp-media.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 15ab6a7a3c..50de511163 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2628,7 +2628,8 @@ gst_rtsp_media_get_status (GstRTSPMedia * media) * @flags: The minimal set of #GstSeekFlags to use * * Seek the pipeline of @media to @range. @media must be prepared with - * gst_rtsp_media_prepare(). + * gst_rtsp_media_prepare(). In order to perform the seek operation, + * the pipeline must contain all needed transport parts (transport sinks). * * Returns: %TRUE on success. */ @@ -2737,8 +2738,6 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, res = TRUE; } else { gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); - if (priv->blocked) - media_streams_set_blocked (media, TRUE); /* FIXME, we only do forwards playback, no trick modes yet */ res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME, From 4370f3a9012476b824dfaf8bd89f0fae0afa5212 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Sat, 17 Nov 2018 19:19:54 +0100 Subject: [PATCH 1576/1776] rtsp-media: Update priv->blocked when linked streams are unblocked. Media is considered to be blocked when all streams that belong to that media are blocked. This patch solves the problem of inconsistent updates of priv->blocked that are not synchronized with the media state. --- gst/rtsp-server/rtsp-media.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 50de511163..490c73da73 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2572,6 +2572,9 @@ media_unblock_linked (GstRTSPMedia * media) GstRTSPMediaPrivate *priv = media->priv; GST_DEBUG ("media %p unblocking linked streams", media); + /* media is not blocked any longer, as it contains active streams, + * streams that are complete */ + priv->blocked = FALSE; g_ptr_array_foreach (priv->streams, (GFunc) stream_unblock, media); } From be4635cf2f42d7039d731481b4fe43febed01a98 Mon Sep 17 00:00:00 2001 From: Ingo Randolf Date: Tue, 20 Nov 2018 11:07:48 +0100 Subject: [PATCH 1577/1776] examples: test-appsrc: fix buffer leak --- examples/test-appsrc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/test-appsrc.c b/examples/test-appsrc.c index 33ce15bb39..340f190033 100644 --- a/examples/test-appsrc.c +++ b/examples/test-appsrc.c @@ -50,6 +50,7 @@ need_data (GstElement * appsrc, guint unused, MyContext * ctx) ctx->timestamp += GST_BUFFER_DURATION (buffer); g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret); + gst_buffer_unref(buffer); } /* called when a new media pipeline is constructed. We can query the From ce2b418811fb0f2340485aca0dc3ab073e5e7aca Mon Sep 17 00:00:00 2001 From: Ingo Randolf Date: Tue, 20 Nov 2018 19:12:09 +0100 Subject: [PATCH 1578/1776] examples: test-appsrc: fix coding style error --- examples/test-appsrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/test-appsrc.c b/examples/test-appsrc.c index 340f190033..c8c2d0b813 100644 --- a/examples/test-appsrc.c +++ b/examples/test-appsrc.c @@ -50,7 +50,7 @@ need_data (GstElement * appsrc, guint unused, MyContext * ctx) ctx->timestamp += GST_BUFFER_DURATION (buffer); g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret); - gst_buffer_unref(buffer); + gst_buffer_unref (buffer); } /* called when a new media pipeline is constructed. We can query the From 5b86dc34eef2f4bf5770e3ec5f4d6e91af0182f5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 5 Dec 2018 17:24:59 -0300 Subject: [PATCH 1579/1776] Automatic update of common submodule From ed78bee to 59cb678 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index ed78bee437..59cb678164 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit ed78bee437dcbe22e6eef0031d9a29d157c0461f +Subproject commit 59cb678164719ff59dcf6c8b93df4617a1075d11 From 3be1b9bba8a165a62008871eff3e9cfcb1338910 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Wed, 5 Dec 2018 15:07:25 +0100 Subject: [PATCH 1580/1776] Add source elements to the pipeline before activation In plug_src we changed the element state before adding it to the owner container. This prevented the pipeline from intercepting a GST_STREAM_STATUS_TYPE_CREATE message from the pad in order to assign a custom task pool. Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/53 --- gst/rtsp-server/rtsp-stream.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 83291d6a2a..33eeb50d59 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -3401,6 +3401,9 @@ plug_src (GstRTSPStream * stream, GstBin * bin, GstElement * src, priv = stream->priv; + /* add src */ + gst_bin_add (bin, src); + pad = gst_element_get_static_pad (src, "src"); if (priv->srcpad) { /* block pad so src can't push data while it's not yet linked */ @@ -3412,9 +3415,6 @@ plug_src (GstRTSPStream * stream, GstBin * bin, GstElement * src, gst_element_set_locked_state (src, TRUE); } - /* add src */ - gst_bin_add (bin, src); - /* and link to the funnel */ selpad = gst_element_get_request_pad (funnel, "sink_%u"); gst_pad_link (pad, selpad); From d5ccb5a7d0fc76460c646811a558c2304ac03f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 17 Jan 2019 02:26:48 +0000 Subject: [PATCH 1581/1776] Release 1.15.1 --- ChangeLog | 1037 +++++++++++++++++++++++++++++++++++++++++ NEWS | 1047 ++++++++++++++++++++++++++++++++++++++++-- RELEASE | 34 +- configure.ac | 12 +- gst-rtsp-server.doap | 10 + meson.build | 2 +- 6 files changed, 2083 insertions(+), 59 deletions(-) diff --git a/ChangeLog b/ChangeLog index 789baa10f2..445134e0d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,1040 @@ +=== release 1.15.1 === + +2019-01-17 02:26:48 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + * meson.build: + Release 1.15.1 + +2018-12-05 15:07:25 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + Add source elements to the pipeline before activation + In plug_src we changed the element state before adding it to + the owner container. This prevented the pipeline from intercepting + a GST_STREAM_STATUS_TYPE_CREATE message from the pad in order + to assign a custom task pool. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/53 + +2018-12-05 17:24:59 -0300 Thibault Saunier + + * common: + Automatic update of common submodule + From ed78bee to 59cb678 + +2018-11-20 19:12:09 +0100 Ingo Randolf + + * examples/test-appsrc.c: + examples: test-appsrc: fix coding style error + +2018-11-20 11:07:48 +0100 Ingo Randolf + + * examples/test-appsrc.c: + examples: test-appsrc: fix buffer leak + +2018-11-17 19:19:54 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Update priv->blocked when linked streams are unblocked. + Media is considered to be blocked when all streams that belong to + that media are blocked. + This patch solves the problem of inconsistent updates of + priv->blocked that are not synchronized with the media state. + +2018-11-17 18:18:27 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Don't block streams before seeking + Before the seek operation is performed on media, it's required that + its pipeline is prepared <=> the pipeline is in the PAUSED state. + At this stage, all transport parts (transport sinks) have been successfully + added to the pipeline and there is no need for blocking the streams. + +2018-11-17 16:11:53 +0100 Patricia Muscalu + + * tests/check/gst/rtspserver.c: + tests: rtspserver: Add shared media test case for TCP + +2018-11-06 18:21:54 +0100 Linus Svensson + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Use seqnum-offset for rtpinfo + The sequence number in the rtpinfo is supposed to be the first RTP + sequence number. The "seqnum" property on a payloader is supposed to be + the number from the last processed RTP packet. The sequence number for + payloaders that inherit gstrtpbasepayload will not be correct in case of + buffer lists. In order to fix the seqnum property on the payloaders + gst-rtsp-server must get the sequence number for rtpinfo elsewhere and + "seqnum-offset" from the "stats" property contains the value of the + very first RTP packet in a stream. The server will, however, try to look + at the last simple in the sink element and only use properties on the + payloader in case there no sink elements yet, and by looking at the last + sample of the sink gives the server full control of which RTP packet it + looks at. If the payloader does not have the "stats" property, "seqnum" + is still used since "seqnum-offset" is only present in as part of + "stats" and this is still an issue not solved with this patch. + Needed for gst-plugins-base!17 + +2018-11-06 18:10:56 +0100 Linus Svensson + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Plug memory leak + Attaching a GSource to a context will increase the refcount. The idle + source will never be free'd since the initial reference is never + dropped. + +2018-11-12 16:06:39 +0200 Jordan Petridis + + * .gitlab-ci.yml: + Add Gitlab CI configuration + This commit adds a .gitlab-ci.yml file, which uses a feature + to fetch the config from a centralized repository. The intent is + to have all the gstreamer modules use the same configuration. + The configuration is currently hosted at the gst-ci repository + under the gitlab/ci_template.yml path. + Part of https://gitlab.freedesktop.org/gstreamer/gstreamer-project/issues/29 + +2018-11-05 05:56:35 +0000 Matthew Waters + + * .gitmodules: + * gst-rtsp-server.doap: + Update git locations to gitlab + +2018-11-01 14:20:16 +0100 Mathieu Duponchelle + + * gst/rtsp-server/meson.build: + meson: add new onvif types + +2018-11-01 12:49:51 +0200 Sebastian Dröge + + * gst/rtsp-server/meson.build: + Add ONVIF subclass headers to the installed headers in meson.build too + +2018-11-01 11:29:01 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-server-object.h: + * gst/rtsp-server/rtsp-server.h: + rtsp-server: Declare GstRTSPServer struct before anything else + It's needed by all kinds of other headers, including the ones that are + required for defining the GstRTSPServer struct itself and its API. + +2018-11-01 10:23:02 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-onvif-client.h: + * gst/rtsp-server/rtsp-onvif-media-factory.h: + * gst/rtsp-server/rtsp-onvif-media.h: + * gst/rtsp-server/rtsp-onvif-server.h: + Mark all ONVIF-specific subclasses as Since 1.14 + +2018-11-01 10:18:22 +0200 Sebastian Dröge + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/meson.build: + * gst/rtsp-server/rtsp-context.h: + * gst/rtsp-server/rtsp-onvif-server.c: + * gst/rtsp-server/rtsp-onvif-server.h: + * gst/rtsp-server/rtsp-server-object.h: + * gst/rtsp-server/rtsp-server-prelude.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-server.h: + * gst/rtsp-server/rtsp-session.h: + Include ONVIF types from single-include rtsp-server.h + ... by actually making it a single-include header and moving everything + related to the GstRTSPServer type to rtsp-server-object.h instead. + Otherwise there are too many circular includes. + https://bugzilla.gnome.org/show_bug.cgi?id=797361 + +2018-10-18 07:25:05 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-latency-bin.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-stream: use idle source in on_message_sent + When the underlying layers are running on_message_sent, this sometimes + causes the underlying layer to send more data, which will cause the + underlying layer to run callback on_message_sent again. This can go on + and on. + To break this chain, we introduce an idle source that takes care of + sending data if there are more to send when running callback + https://bugzilla.gnome.org/show_bug.cgi?id=797289 + +2018-10-20 16:14:53 +0200 Edward Hervey + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Remove timeout GSource on cleanup + Avoids ending up with races where a timeout would still be around + *after* a client was gone. This could happen rather easily in + RTSP-over-HTTP mode on a local connection, where each RTSP message + would be sent as a different HTTP connection with the same tunnelid. + If not properly removed, that timeout would then try to free again + a client (and its contents). + +2018-10-04 14:31:59 +0100 Tim-Philipp Müller + + * gst/rtsp-server/Makefile.am: + autotools: fix distcheck + +2018-09-12 11:55:15 +0200 Ognyan Tonchev + + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/meson.build: + * gst/rtsp-server/rtsp-latency-bin.c: + * gst/rtsp-server/rtsp-latency-bin.h: + * gst/rtsp-server/rtsp-onvif-media.c: + onvif: encapsulate onvif part into a bin + ...and thus do not let onvif affect pipelines latency + https://bugzilla.gnome.org/show_bug.cgi?id=797174 + +2018-09-27 19:57:13 +0200 Patricia Muscalu + + * tests/check/gst/client.c: + tests: client: Avoid bind() failures in tests + https://bugzilla.gnome.org/show_bug.cgi?id=797059 + +2018-09-06 16:17:33 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/client.c: + * tests/check/gst/mediafactory.c: + New property for socket binding to mcast addresses + By default the multicast sockets are bound to INADDR_ANY, + as it's not allowed to bind sockets to multicast addresses + in Windows. This default behaviour can be changed by setting + bind-mcast-address property on the media-factory object. + https://bugzilla.gnome.org/show_bug.cgi?id=797059 + +2018-09-24 09:36:21 +0100 Tim-Philipp Müller + + * configure.ac: + * gst/rtsp-server/Makefile.am: + * gst/rtsp-server/meson.build: + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-context.c: + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-params.c: + * gst/rtsp-server/rtsp-permissions.c: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-server-prelude.h: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-thread-pool.c: + * gst/rtsp-server/rtsp-token.c: + * meson.build: + libs: fix API export/import and 'inconsistent linkage' on MSVC + Export rtsp-server library API in headers when we're building the + library itself, otherwise import the API from the headers. + This fixes linker warnings on Windows when building with MSVC. + Fix up some missing config.h includes when building the lib which + is needed to get the export api define from config.h + https://bugzilla.gnome.org/show_bug.cgi?id=797185 + +2018-09-19 14:31:56 +0200 Edward Hervey + + * gst/rtsp-server/rtsp-media-factory.c: + rtsp-media-factory: Add missing break statements + This resulted in warnings/assertions whenever one accessed the + max-mcast-ttl property. + CID #1439515 + CID #1439523 + +2018-09-19 12:21:30 +0100 Tim-Philipp Müller + + * meson.build: + * meson_options.txt: + meson: add gobject-cast-checks, glib-asserts, glib-checks options + +2018-09-19 12:17:57 +0100 Tim-Philipp Müller + + * gst/meson.build: + * meson_options.txt: + * tests/check/meson.build: + meson: add option to disable build of rtspclientsink plugin + +2018-09-19 12:10:14 +0100 Tim-Philipp Müller + + * meson_options.txt: + meson: re-arrange options + +2018-09-01 11:21:15 +0530 Nirbheek Chauhan + + * meson.build: + * meson_options.txt: + * tests/check/meson.build: + * tests/meson.build: + meson: Use feature option for tests option + This was somehow missed the last time around. + +2018-08-31 14:42:15 +0530 Nirbheek Chauhan + + * gst/rtsp-server/meson.build: + * meson.build: + meson: Maintain macOS ABI through dylib versioning + Requires Meson 0.48, but the feature will be ignored on older versions + so it's safe to add it without bumping the requirement. + Documentation: + https://github.com/mesonbuild/meson/blob/master/docs/markdown/Reference-manual.md#shared_library + +2018-08-31 17:20:47 +1000 Matthew Waters + + * gst/rtsp-sink/meson.build: + * meson.build: + meson: add pkg-config file for the rtspclientsink plugin + +2018-08-17 09:54:27 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-client.c: + * tests/check/gst/client.c: + rtsp-client: Avoid reuse of channel numbers for interleaved + If a (strange) client would reuse interleaved channel numbers in + multiple SETUP requests, we should not accept them. The channel + numbers are used for looking up stream transports in the + priv->transports hash table, and transports disappear from the table + if channel numbers are reused. + RFC 7826 (RTSP 2.0), Section 18.54, clarifies that it is OK for the + server to change the channel numbers suggested by the client. + https://bugzilla.gnome.org/show_bug.cgi?id=796988 + +2018-08-17 09:54:27 +0200 David Svensson Fors + + * tests/check/gst/client.c: + rtsp-client: Add unit test of SETUP for RTSP/RTP/TCP + Allow regex for matching transport header against expected pattern. + https://bugzilla.gnome.org/show_bug.cgi?id=796988 + +2018-08-15 18:57:27 +0530 Nirbheek Chauhan + + * tests/check/meson.build: + meson: There is no gstreamer-plugins-good-1.0.pc + There is no installed version of that, only an uninstalled version. + +2018-08-14 14:31:55 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + * tests/check/gst/stream.c: + Fix indentation again + +2018-07-26 12:01:16 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/client.c: + * tests/check/gst/stream.c: + stream: Added a list of multicast client addresses + When media is shared, the same media stream can be sent + to multiple multicast groups. Currently, there is no API + to retrieve multicast addresses from the stream. + When calling gst_rtsp_stream_get_multicast_address() function, + only the first multicast address is returned. + With this patch, each multicast destination requested in SETUP + will be stored in an internal list (call to + gst_rtsp_stream_add_multicast_client_address()). + The list of multicast groups requested by the clients can be + retrieved by calling gst_rtsp_stream_get_multicast_client_addresses(). + There still exist some problems with the current implementation + in the multicast case: + 1) The receiving part is currently only configured with + regard to the first multicast client (see + https://bugzilla.gnome.org/show_bug.cgi?id=796917). + 2) Secondly, of security reasons, some constraints should be + put on the requested multicast destinations (see + https://bugzilla.gnome.org/show_bug.cgi?id=796916). + Change-Id: I6b060746e472a0734cc2fd828ffe4ea2956733ea + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-07-25 15:33:18 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/client.c: + stream: Choose the maximum ttl value provided by multicast clients + The maximum ttl value provided so far by the multicast clients + will be chosen and reported in the response to the current + client request. + Change-Id: I5408646e3b5a0a224d907ae215bdea60c4f1905f + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-02-23 14:34:32 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/client.c: + rtsp-stream: Don't require address pool in the transport specific case + If "transport.client-settings" parameter is set to true, the client is + allowed to specify destination, ports and ttl. + There is no need for pre-configured address pool. + Change-Id: I6ae578fb5164d78e8ec1e2ee82dc4eaacd0912d1 + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-07-24 14:02:40 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + * tests/check/gst/client.c: + client: Don't reserve multicast address in the client setting case + When two multicast clients request specific transport + configurations, and "transport.client-settings" parameter is + set to true, it's wrong to actually require that these two + clients request the same multicast group. + Removed test_client_multicast_invalid_transport_specific test + cases as they wrongly require that the requested destination + address is supposed to be present in the address pool, also in + the case when "transport.client-settings" parameter is set to true. + Change-Id: I4580182ef35996caf644686d6139f72ec599c9fa + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-07-24 09:35:46 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/mediafactory.c: + Add new API for setting/getting maximum multicast ttl value + Change-Id: I5ef4758188c14785e17fb8fbf42a3dc0cb054233 + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-07-31 21:17:41 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: avoid duplicating the first multicast client + In dcb4533fedae3ac62bc25a916eb95927b7d69aec , we made it so + clients were dynamically added and removed to the multicast + udp sinks, as such we should no longer add a first client in + set_multicast_socket_for_udpsink + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-08-14 14:25:53 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + Revert "rtsp-stream: avoid duplicating the first multicast client" + This reverts commit 33570944401747f44d8ebfec535350651413fb92. + Commits where accidentially squashed together + +2018-08-14 14:25:42 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/client.c: + * tests/check/gst/mediafactory.c: + Revert "Add new API for setting/getting maximum multicast ttl value" + This reverts commit 7f0ae77e400fb8a0462a76a5dd2e63e12c4a2e52. + Commits where accidentially squashed together + +2018-08-14 14:25:37 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/client.c: + Revert "rtsp-stream: Don't require address pool in the transport specific case" + This reverts commit a9db3e7f092cfeb5475e9aa24b1e91906c141d52. + Commits where accidentially squashed together + +2018-08-14 14:25:14 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/client.c: + * tests/check/gst/stream.c: + Revert "stream: Choose the maximum ttl value provided by multicast clients" + This reverts commit 499e437e501215849d24cdaa157e0edf4de097d0. + Commits where accidentially squashed together + +2018-08-14 14:10:56 +0300 Sebastian Dröge + + * examples/test-auth-digest.c: + examples: Fix indentation + +2018-07-25 15:33:18 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/client.c: + * tests/check/gst/stream.c: + stream: Choose the maximum ttl value provided by multicast clients + The maximum ttl value provided so far by the multicast clients + will be chosen and reported in the response to the current + client request. + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-02-23 14:34:32 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/client.c: + rtsp-stream: Don't require address pool in the transport specific case + If "transport.client-settings" parameter is set to true, the client is + allowed to specify destination, ports and ttl. + There is no need for pre-configured address pool. + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-07-24 09:35:46 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/client.c: + * tests/check/gst/mediafactory.c: + Add new API for setting/getting maximum multicast ttl value + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-07-31 21:17:41 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: avoid duplicating the first multicast client + In dcb4533fedae3ac62bc25a916eb95927b7d69aec , we made it so + clients were dynamically added and removed to the multicast + udp sinks, as such we should no longer add a first client in + set_multicast_socket_for_udpsink + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-08-06 15:33:04 -0400 Thibault Saunier + + * gst/rtsp-server/Makefile.am: + rtsp-server: Add gstreamer-base gir dir in autotools + +2018-07-25 19:54:55 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-client: always allocate both IPV4 and IPV6 sockets + multiudpsink does not support setting the socket* properties + after it has started, which meant that rtsp-server could no + longer serve on both IPV4 and IPV6 sockets since the patches + from https://bugzilla.gnome.org/show_bug.cgi?id=757488 were + merged. + When first connecting an IPV6 client then an IPV4 client, + multiudpsink fell back to using the IPV6 socket. + When first connecting an IPV4 client, then an IPV6 client, + multiudpsink errored out, released the IPV4 socket, then + crashed when trying to send a message on NULL nevertheless, + that is however a separate issue. + This could probably be fixed by handling the setting of + sockets in multiudpsink after it has started, that will + however be a much more significant effort. + For now, this commit simply partially reverts the behaviour + of rtsp-stream: it will continue to only create the udpsinks + when needed, as was the case since the patches were merged, + it will however when creating them, always allocate both + sockets and set them on the sink before it starts, as was + the case prior to the patches. + Transport configuration will only error out if the allocation + of UDP sockets fails for the actual client's family, this + also downgrades the GST_ERRORs in alloc_ports_one_family + to GST_WARNINGs, as failing to allocate is no longer + necessarily fatal. + https://bugzilla.gnome.org/show_bug.cgi?id=796875 + +2018-07-25 17:22:20 +0530 Nirbheek Chauhan + + * meson.build: + * meson_options.txt: + meson: Convert common options to feature options + These are necessary for gst-build to set options correctly. The + remaining automagic option is cgroup support in examples. + https://bugzilla.gnome.org/show_bug.cgi?id=795107 + +2018-07-23 18:03:51 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Slightly simplify locking + +2018-06-28 11:22:21 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.c: + Limit queued TCP data messages to one per stream + Before, the watch backlog size in GstRTSPClient was changed + dynamically between unlimited and a fixed size, trying to avoid both + unlimited memory usage and deadlocks while waiting for place in the + queue. (Some of the deadlocks were described in a long comment in + handle_request().) + In the previous commit, we changed to a fixed backlog size of 100. + This is possible, because we now handle RTP/RTCP data messages differently + from RTSP request/response messages. + The data messages are messages tunneled over TCP. We allow at most one + queued data message per stream in GstRTSPClient at a time, and + successfully sent data messages are acked by sending a "message-sent" + callback from the GstStreamTransport. Until that ack comes, the + GstRTSPStream does not call pull_sample() on its appsink, and + therefore the streaming thread in the pipeline will not be blocked + inside GstRTSPClient, waiting for a place in the queue. + pull_sample() is called when we have both an ack and a "new-sample" + signal from the appsink. Then, we know there is a buffer to write. + RTSP request/response messages are not acked in the same way as data + messages. The rest of the 100 places in the queue are used for + them. If the queue becomes full of request/response messages, we + return an error and close the connection to the client. + Change-Id: I275310bc90a219ceb2473c098261acc78be84c97 + +2018-06-28 11:22:13 +0200 David Svensson Fors + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Use fixed backlog size + Change to using a fixed backlog size WATCH_BACKLOG_SIZE. + Preparation for the next commit, which changes to a different way of + avoiding both deadlocks and unlimited memory usage with the watch + backlog. + +2018-07-16 21:57:08 +0200 Carlos Rafael Giani + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: unref clock (if set) when finalizing + https://bugzilla.gnome.org/show_bug.cgi?id=796814 + +2018-07-16 21:56:44 +0200 Carlos Rafael Giani + + * docs/libs/gst-rtsp-server-sections.txt: + rtsp-media: add gst_rtsp_media_*_set_clock to docs + https://bugzilla.gnome.org/show_bug.cgi?id=796814 + +2018-07-12 19:01:54 +0100 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-media-factory.c: + media-factory: unref old clock when setting new clock + https://bugzilla.gnome.org/show_bug.cgi?id=796724 + +2018-06-29 15:20:57 -0700 Brendan Shanks + + * gst/rtsp-server/rtsp-media-factory.c: + media-factory: unref clock in finalize + https://bugzilla.gnome.org/show_bug.cgi?id=796724 + +2018-07-12 18:57:21 +0100 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-onvif-media.c: + rtsp-onvif-media: fix g-ir-scanner warnings + +2018-07-10 23:56:23 +0100 Tim-Philipp Müller + + * .gitignore: + .gitignore: add another example binary + +2018-07-10 23:55:20 +0100 Tim-Philipp Müller + + * examples/meson.build: + meson: add new test-appsrc2 example to meson build + +2018-07-10 23:53:41 +0100 Tim-Philipp Müller + + * examples/Makefile.am: + examples: fix build of new test-appsrc2 example + Need to link against libgstapp-1.0. + +2018-07-11 01:25:51 +1000 Jan Schmidt + + * examples/.gitignore: + * examples/Makefile.am: + * examples/test-appsrc2.c: + examples: Add test-appsrc2 + Add an example of feeding both audio and video into an RTSP + pipeline via appsrc. + +2016-01-08 18:12:14 -0500 Louis-Francis Ratté-Boulianne + + * gst/rtsp-server/rtsp-client.c: + client: Strip transport parts as whitespaces could be around commas + https://bugzilla.gnome.org/show_bug.cgi?id=758428 + +2018-06-27 08:30:42 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: avoid pushing data on unlinked udpsrc pad during setup + Fix race when setting up source elements. + Since we set the source element(s) to PLAYING state before hooking + them up to the downstream funnel, it's possible for the source element + to receive packets before we actually get to linking it to the funnel, + in which case buffers would be pushed out on an unlinked pad, causing + it to error out and stop receiving more data. + We fix this by blocking the source's srcpad until we have linked it. + https://bugzilla.gnome.org/show_bug.cgi?id=796160 + +2018-03-21 10:56:51 +0100 Ognyan Tonchev + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Fix mismatch between allowed and configured protocols + https://bugzilla.gnome.org/show_bug.cgi?id=796679 + +2017-02-01 09:44:50 +0100 Ulf Olsson + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Emit a signal when the SRTP decoder is created + https://bugzilla.gnome.org/show_bug.cgi?id=778080 + +2018-03-13 11:10:35 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Don't require presence of sinks in _get_*_socket() + Transport specific sink elements are added to the pipeline + in PLAY request and sockets are already created in SETUP so + it's actually wrong to require the presence of sinks in + _get_*_socket() functions. + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-02-14 10:41:02 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Update transport for multicast clients as well + If a multicast client requests different transport settings + than the existing one make sure that this new transport + configuruation is propagated to the multicast udp sink. + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-02-13 11:04:36 +0100 Patricia Muscalu + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Set the multicast TTL parameter on multicast udp sinks + And not on unicast udp sinks + https://bugzilla.gnome.org/show_bug.cgi?id=793441 + +2018-06-24 12:44:26 +0200 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-address-pool.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-thread-pool.c: + Update for g_type_class_add_private() deprecation in recent GLib + +2018-06-24 12:45:49 +0200 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-stream.c: + Fix indentation + +2018-06-22 23:17:08 +1000 Jan Schmidt + + * examples/Makefile.am: + * examples/test-video-disconnect.c: + examples: Add test-video-disconnect example + Simple example which cuts off all clients 10 seconds + after the first one connects. + +2018-06-20 04:37:11 +0200 Mathieu Duponchelle + + * docs/libs/gst-rtsp-server-sections.txt: + * examples/test-auth-digest.c: + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-auth.h: + rtsp-auth: Add support for parsing .htdigest files + Passwords are usually not stored in clear text, but instead + stored already hashed in a .htdigest file. + Add support for parsing such files, add API to allow setting + a custom realm in RTSPAuth, and update the digest example. + https://bugzilla.gnome.org/show_bug.cgi?id=796637 + +2018-06-19 14:53:02 +1000 Matthew Waters + + * gst/rtsp-sink/gstrtspclientsink.c: + * gst/rtsp-sink/gstrtspclientsink.h: + rtspclientsink: fix waiting for multiple streams + We were previously only ever waiting for a single stream to notify it's + blocked status through GstRTSPStreamBlocking. Actually count streams to + wait for. + Fixes rtspclientsink sending SDP's without out some of the input + streams. + https://bugzilla.gnome.org/show_bug.cgi?id=796624 + +2018-06-20 04:30:04 +0200 Mathieu Duponchelle + + * docs/libs/gst-rtsp-server-sections.txt: + docs: add missing auth methods + +2018-06-20 00:10:18 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: only create funnel if it didn't exist already. + This precented using multiple protocols for the same stream. + https://bugzilla.gnome.org/show_bug.cgi?id=796634 + +2018-06-20 01:35:47 +0200 Mathieu Duponchelle + + * examples/meson.build: + meson: build auth-digest example + +2018-06-05 08:44:44 +0200 Patricia Muscalu + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-stream-transport.c: + Get payloader stats only for the sending streams + Get/set payloader properties only for streams that actually + contain a payloader element. + https://bugzilla.gnome.org/show_bug.cgi?id=796523 + +2018-05-18 14:53:49 +0200 Edward Hervey + + * gst/rtsp-server/Makefile.am: + Makefile: Don't hardcode libtool for g-i build + Similar to the other commits in core/base/bad + +2018-05-08 14:13:31 +0200 Johan Bjäreholt + + * gst/rtsp-server/rtsp-onvif-media-factory.h: + rtsp-onvif-media-factory: export gst_rtsp_onvif_media_factory_requires_backchannel + https://bugzilla.gnome.org/show_bug.cgi?id=796229 + +2018-05-09 04:09:02 +1000 Jan Schmidt + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Don't deadlock in preroll on early close + If the connection is closed very early, the flushing + marker might not get set and rtspclientsink can get + deadlocked waiting for preroll forever. + https://bugzilla.gnome.org/show_bug.cgi?id=786961 + +2018-05-05 19:51:52 +0530 Nirbheek Chauhan + + * meson.build: + * meson_options.txt: + meson: Update option names to omit disable_ and with- prefixes + Also yield common options to the outer project (gst-build in our case) + so that they don't have to be set manually. + +2018-04-25 11:00:32 +0100 Tim-Philipp Müller + + * meson.build: + meson: use -Wl,-Bsymbolic-functions where supported + Just like the autotools build. + +2018-04-22 20:09:01 +0100 Tim-Philipp Müller + + * configure.ac: + * tests/check/Makefile.am: + configure: check for -good and -bad plugins only in uninstalled setup + Avoids confusing configure messages looking or a -good .pc file + that doesn't exist. + Also use plugindir variables that common macros set while at it. + https://bugzilla.gnome.org/show_bug.cgi?id=795466 + +2018-04-17 11:03:11 +0200 Joakim Johansson + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Fix session timeout + When streaming data over TCP then is not the keep-alive + functionality working. + The reason is that the function do_send_data have changed + to boolean but the code is still checking the received result + from send_func with GST_RTSP_OK. + The result is that a successful send_func will always lead to + that do_send_data is returning false and the keep-alive will + not be updated. + https://bugzilla.gnome.org/show_bug.cgi?id=795321 + +2018-04-02 22:49:35 +0200 Mathieu Duponchelle + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * gst/rtsp-sink/gstrtspclientsink.c: + * gst/rtsp-sink/gstrtspclientsink.h: + Implement support for ULP Forward Error Correction + In this initial commit, interface is only exposed for RECORD, + further work will be needed in rtspsrc to support this for + PLAY. + https://bugzilla.gnome.org/show_bug.cgi?id=794911 + +2018-04-17 17:47:30 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-onvif-media.c: + Revert "rtsp-server: Switch around sendonly/recvonly attributes" + This reverts commit 3d275b1345b76151418e3f56ed014d9089ac1a57. + While RFC 3264 (SDP) says that sendonly/recvonly are from the point of view of + the requester, the actual RTSP RFCs (RFC 2326 / 7826) disagree and say + the opposite, just like the ONVIF standard. + Let's follow those RFCs as we're doing RTSP here, and add a property at + a later time if needed to switch to the SDP RFC behaviour. + https://bugzilla.gnome.org/show_bug.cgi?id=793964 + +2018-04-16 10:53:52 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 3fa2c9e to ed78bee + +2018-04-04 10:06:06 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/rtspclientsink.c: + gst: Run everything through gst-indent again + +2018-04-03 08:57:47 +0200 Branko Subasic + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/media.c: + rtsp-media: query the position on active streams if media is complete + If the media is complete, i.e. one or more streams have been configured + with sinks, then we want to query the position on those streams only. + A query on an incomplete stream may return a position that originates from + an earlier preroll. + https://bugzilla.gnome.org/show_bug.cgi?id=794964 + +2018-04-02 12:35:04 +0100 Tim-Philipp Müller + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: make sure not to use freed string + Set transport string to NULL after freeing it, so that + at worst we get a NULL pointer if constructing a new + transport string fails (which shouldn't really fail here). + Also check return value of that, just in case. + CID 1433768. + +2018-03-30 23:34:01 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: do not free string passed to take_header + +2018-03-30 23:10:10 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: do not take lock in request_aux_receiver + Added it right before pushing the previous commit, it is + incorrect and deadlocks because this function gets called + from the join_bin thread, which already holds the lock, + that's the reason why request_aux_sender didn't take the + lock either. + +2018-03-29 22:49:26 +0200 Mathieu Duponchelle + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-server: add API to enable retransmission requests + "do-retransmission" was previously set when rtx-time != 0, + which made no sense as do-retransmission is used to enable + the sending of retransmission requests, where as rtx-time + is used by the peer to enable storing of buffers in order + to respond to retransmission requests. + rtsp-media now also provides a callback for the + request-aux-receiver signal. + https://bugzilla.gnome.org/show_bug.cgi?id=794822 + +2018-03-29 16:18:42 +0200 Mathieu Duponchelle + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: add rtx ssrc to mikey's crypto sessions + https://bugzilla.gnome.org/show_bug.cgi?id=794813 + +2018-03-29 16:15:45 +0200 Mathieu Duponchelle + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Handle the KeyMgmt header in ANNOUNCE response + This in order to be able to decrypt the RTCP backchannel + https://bugzilla.gnome.org/show_bug.cgi?id=794813 + +2018-03-29 16:12:26 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Send KeyMgmt header in ANNOUNCE response + When sending back an encrypted RTCP back channel, it is useful + for the client to know the encryption key. + https://bugzilla.gnome.org/show_bug.cgi?id=794813 + +2018-03-29 16:06:31 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-stream: extract handle_keymgmt from rtsp-client + rtspclientsink will also need to parse KeyMgmt headers + sent by the server to decrypt the RTCP backchannel stream + https://bugzilla.gnome.org/show_bug.cgi?id=794813 + +2018-03-29 02:51:02 +0200 Mathieu Duponchelle + + * gst/rtsp-sink/gstrtspclientsink.c: + * tests/check/gst/rtspclientsink.c: + rtspclientsink: Fix client ports for the RTCP backchannel + This was broken since the work for delayed transport creation + was merged: the creation of the transports string depends on + calling stream_get_server_port, which only starts returning + something meaningful after a call to stream_allocate_udp_sockets + has been made, this function expects a transport that we parse + from the transport string ... + Significant refactoring is in order, but does not look entirely + trivial, for now we put a band aid on and create a second transport + string after the stream has been completed, to pass it in + the request headers instead of the previous, incomplete one. + https://bugzilla.gnome.org/show_bug.cgi?id=794789 + +2018-02-15 13:26:16 +0100 Göran Jönsson + + * gst/rtsp-server/rtsp-client.c: + rtsp-client:Error handling when equal http session cookie + There are some clients that are sending same session cookie on random + basis. + https://bugzilla.gnome.org/show_bug.cgi?id=753616 + +2018-03-20 16:21:37 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-media-factory-uri.c: + rtsp-media-factory-uri: Fix compilation with latest GLib + rtsp-media-factory-uri.c: In function ‘rtsp_media_factory_uri_create_element’: + rtsp-media-factory-uri.c:621:17: error: assignment from incompatible pointer type [-Werror=incompatible-pointer-types] + data->factory = g_object_ref (factory); + ^ + +2018-03-20 10:21:36 +0000 Tim-Philipp Müller + + * NEWS: + * RELEASE: + * configure.ac: + * meson.build: + Back to development + === release 1.14.0 === 2018-03-19 20:27:04 +0000 Tim-Philipp Müller diff --git a/NEWS b/NEWS index 5366a0dfcd..1e860c47a6 100644 --- a/NEWS +++ b/NEWS @@ -3,23 +3,19 @@ GSTREAMER 1.16 RELEASE NOTES -GStreamer 1.16 has not been released yet. It is scheduled for release -around September 2018. +GStreamer 1.16 has not been released yet. It is scheduled for release in +January/February 2019. -1.15.0.1 is the unstable development version that is being developed in +1.15.x is the unstable development version that is being developed in the git master branch and which will eventually result in 1.16. -The plan for the 1.16 development cycle is yet to be confirmed, but it -is expected that feature freeze will be around August 2017 followed by -several 1.15 pre-releases and the new 1.16 stable release in September. - 1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. See https://gstreamer.freedesktop.org/releases/1.16/ for the latest version of this document. -_Last updated: Tuesday 20 March 2018, 01:30 UTC (log)_ +_Last updated: Monday 14 January 2019, 13:00 UTC (log)_ Introduction @@ -34,63 +30,705 @@ other improvements. Highlights -- this section will be completed in due course +- GStreamer WebRTC stack gained support for data channels for + peer-to-peer communication based on SCTP, BUNDLE support, as well as + support for multiple TURN servers. + +- AV1 video codec support for Matroska and QuickTime/MP4 containers + and more configuration options and supported input formats for the + AOMedia AV1 encoder + +- Support for Closed Captions and other Ancillary Data in video + +- Spport for planar (non-interleaved) raw audio + +- GstVideoAggregator, compositor and OpenGL mixer elements are now in + -base + +- New alternate fields interlace mode where each buffer carries a + single field + +- WebM and Matroska ContentEncryption support in the Matroska demuxer + +- new WebKit WPE-based web browser source element + +- Video4Linux: HEVC encoding and decoding, JPEG encoding, and improved + dmabuf import/export + +- Hardware-accelerated Nvidia video decoder gained support for VP8/VP9 + decoding, whilst the encoder gained support for H.265/HEVC encoding. + +- Many improvements to the Intel Media SDK based hardware-accelerated + video decoder and encoder plugin (msdk): dmabuf import/export for + zero-copy integration with other components; VP9 decoding; 10-bit + HEVC encoding; video post-processing (vpp) support including + deinterlacing; and the video decoder now handles dynamic resolution + changes. + +- The ASS/SSA subtitle overlay renderer can now handle multiple + subtitles that overlap in time and will show them on screen + simultaneously + +- The Meson build is now feature-complete (*) and it is now the + recommended build system on all platforms. The Autotools build is + scheduled to be removed in the next cycle. + +- The GStreamer Rust bindings and Rust plugins module are now + officially part of upstream GStreamer. + +- Many performance improvements Major new features and changes Noteworthy new API -- this section will be filled in in due course +- GstAggregator has a new "min-upstream-latency" property that forces + a minimum aggregate latency for the input branches of an aggregator. + This is useful for dynamic pipelines where branches with a higher + latency might be added later after the pipeline is already up and + running and where a change in the latency would be disruptive. This + only applies to the case where at least one of the input branches is + live though, it won’t force the aggregator into live mode in the + absence of any live inputs. + +- GstBaseSink gained a "processing-deadline" property and + setter/getter API to configure a processing deadline for live + pipelines. The processing deadline is the acceptable amount of time + to process the media in a live pipeline before it reaches the sink. + This is on top of the systemic latency that is normally reported by + the latency query. This defaults to 20ms and should make pipelines + such as “v4lsrc ! xvimagesink” not claim that all frames are late in + the QoS events. Ideally, this should replace max_lateness for most + applications. + +- RTCP Extended Reports (XR) parsing according to RFC 3611: + Loss/Duplicate RLE, Packet Receipt Times, Receiver Reference Time, + Delay since the last Receiver (DLRR), Statistics Summary, and VoIP + Metrics reports. + +- a new mode for interlaced video was added where each buffer carries + a single field of interlaced video, with buffer flags indicating + whether the field is the top field or bottom field. Top and bottom + fields are expected to alternate in this mode. Caps for this + interlace mode must also carry a format:Interlaced caps feature to + ensure backwards compatibility. + +- The video library has gained support for three new raw pixel + formats: + + - Y410: packed 4:4:4 YUV, 10 bits per channel + - Y210: packed 4:2:2 YUV, 10 bits per channel + - NV12_10LE40: fully-packed 10-bit variant of NV12_10LE32, + i.e. without the padding bits + +- GstRTPSourceMeta is a new meta that can be used to transport + information about the origin of depayloaded or decoded RTP buffers, + e.g. when mixing audio from multiple sources into a single stream. A + new "source-info" property on the RTP depayloader base class + determines whether depayloaders should put this meta on outgoing + buffers. Similarly, the same property on RTP payloaders determines + whether they should use the information from this meta to construct + the CSRCs list on outgoing RTP buffers. + +- gst_sdp_message_from_text() is a convenience constructor to parse + SDPs from a string which is particularly useful for language + bindings. + +Support for Planar (Non-Interleaved) Raw Audio + +Raw audio samples are usually passed around in interleaved form in +GStreamer, which means that if there are multiple audio channels the +samples for each channel are interleaved in memory, e.g. +|LEFT|RIGHT|LEFT|RIGHT|LEFT|RIGHT| for stereo audio. A non-interleaved +or planar arrangement in memory would look like +|LEFT|LEFT|LEFT|RIGHT|RIGHT|RIGHT| instead, possibly with +|LEFT|LEFT|LEFT| and |RIGHT|RIGHT|RIGHT| residing in separate memory +chunks or separated by some padding. + +GStreamer has always had signalling for non-interleaved audio, but it +was never actually properly implemented in any elements. audioconvert +would advertise support for it, but wasn’t actually able to handle it. + +With this release we now have full support for non-interleaved audio as +well, which means more efficient integration with external APIs that +handle audio this way, but also more efficient processing of certain +operations like interleaving multiple 1-channel streams into a +multi-channel stream which can be done without memory copies now. + +New API to support this has been added to the GStreamer Audio support +library: There is now a new GstAudioMeta which describes how data is +laid out inside the buffer, and buffers with non-interleaved audio must +always carry this meta. To access the non-interleaved audio samples you +must map such buffers with gst_audio_buffer_map() which works much like +gst_buffer_map() or gst_video_frame_map() in that it will populate a +little GstAudioBuffer helper structure passed to it with the number of +samples, the number of planes and pointers to the start of each plane in +memory. This function can also be used to map interleaved audio buffers +in which case there will be only one plane of interleaved samples. + +Of course support for this has also been implemented in the various +audio helper and conversion APIs, base classes, and in elements such as +audioconvert, audioresample, audiotestsrc, audiorate. + +Support for Closed Captions and Other Ancillary Data in Video + +The video support library has gained support for detecting and +extracting Ancillary Data from videos as per the SMPTE S291M +specification, including: + +- a VBI (Video Blanking Interval) parser that can detect and extract + Ancillary Data from Vertical Blanking Interval lines of component + signals. This is currently supported for videos in v210 and UYVY + format. + +- a new GstMeta for closed captions: GstVideoCaptionMeta. This + supports the two types of closed captions, CEA-608 and CEA-708, + along with the four different ways they can be transported (other + systems are a superset of those). + +- a VBI (Video Blanking Interval) encoder for writing ancillary data + to the Vertical Blanking Interval lines of component signals. + +The new closedcaption plugin in gst-plugins-bad then makes use of all +this new infrastructure and provides the following elements: + +- cccombiner: a closed caption combiner that takes a closed captions + stream and another stream and adds the closed captions as + GstVideoCaptionMeta to the buffers of the other stream. + +- ccextractor: a closed caption extractor which will take + GstVideoCaptionMeta from input buffers and output them as a separate + closed captions stream. + +- ccconverter: a closed caption converter that can convert between + different formats + +- line21decoder: extract line21 closed captions from SD video streams + +- cc708overlay: decodes CEA 608/708 captions and overlays them on + video + +Additionally, the following elements have also gained Closed Caption +support: + +- qtdemux and qtmux support CEA 608/708 Closed Caption tracks + +- mpegvideoparse extracts Closed Captions from MPEG-2 video streams + +- decklinkvideosink can output closed captions and decklinkvideosrc + can extract closed captions + +- playbin and playbin3 learned how to autoplug CEA 608/708 CC overlay + elements + +The rsclosedcaption plugin in the Rust plugins collection includes a +MacCaption (MCC) file parser and encoder. New Elements -- this section will be filled in in due course +- overlaycomposition: New element that allows applications to draw + GstVideoOverlayCompositions on a stream. The element will emit the + "draw" signal for each video buffer, and the application then + generates an overlay for that frame (or not). This is much more + performant than e.g. cairooverlay for many use cases, e.g. because + pixel format conversions can be avoided or the blitting of the + overlay can be delegated to downstream elements (such as + gloverlaycompositor). It’s particularly useful for cases where only + a small section of the video frame should be drawn on. + +- gloverlaycompositor: New OpenGL-based compositor element that + flattens any overlays from GstVideoOverlayCompositionMetas into the + video stream. + +- glalpha: New element that adds an alpha channel to a video stream. + The values of the alpha channel can either be set to a constant or + can be dynamically calculated via chroma keying. It is similar to + the existing alpha element but based on OpenGL. Calculations are + done in floating point so results may not be identical to the output + of the existing alpha element. + +- rtpfunnel funnels together rtp-streams into a single session. Use + cases include multiplexing and bundle. webrtcbin uses it to + implement BUNDLE support. + +- testsrcbin is a source element that provides an audio and/or video + stream and also announces them using the recently-introduced + GstStream API. This is useful for testing elements such as playbin3 + or uridecodebin3 etc. + +- New closed caption elements: cccombiner, ccextractor, ccconverter, + line21decoder and cc708overlay (see above) + +- wpesrc: new source element acting as a Web Browser based on WebKit + WPE + +- Two new OpenCV-based elements: cameracalibrate and cameraundistort + who can communicate to figure out distortion correction parameters + for a camera and correct for the distortion. + +- new sctp plugin based on usrsctp with sctpenc and sctpdec elements New element features and additions -- this section will be filled in in due course +- playbin3, playbin and playsink have gained a new "text-offset" + property to adjust the positioning of the selected subtitle stream + vis-a-vis the audio and video streams. This uses subtitleoverlay’s + new "subtitle-ts-offset" property. GstPlayer has gained matching API + for this, namely gst_player_get_text_video_offset(). + +- playbin3 buffering improvements: in network playback scenarios there + may be multiple inputs to decodebin3, and buffering will be done + before decodebin3 using queue2 or downloadbuffer elements inside + urisourcebin. Since this is before any parsers or demuxers there may + not be any bitrate information available for the various streams, so + it was difficult to configure the buffering there smartly within + global constraints. This was improved now: The queue2 elements + inside urisourcebin will now use the new bitrate query to figure out + a bitrate estimate for the stream if no bitrate was provided by + upstream, and urisourcebin will use the bitrates of the individual + queues to distribute the globally-set "buffer-size" budget in bytes + to the various queues. urisourcebin also gained "low-watermark" and + "high-watermark" properties which will be proxied to the internal + queues, as well as a read-only "statistics" property which allows + querying of the minimum/maximum/average byte and time levels of the + queues inside the urisourcebin in question. + +- splitmuxsink has gained a couple of new features: + + - new "async-finalize" mode: This mode is useful for muxers or + outputs that can take a long time to finalize a file. Instead of + blocking the whole upstream pipeline while the muxer is doing + its stuff, we can unlink it and spawn a new muxer + sink + combination to continue running normally. This requires us to + receive the muxer and sink (if needed) as factories via the new + "muxer-factory" and "sink-factory" properties, optionally + accompanied by their respective properties structures (set via + the new "muxer-properties" and "sink-properties" properties). + There are also new "muxer-added" and "sink-added" signals in + case custom code has to be called for them to configure them. + + - "split-at-running-time" action signal: When called by the user, + this action signal ends the current file (and starts a new one) + as soon as the given running time is reached. If called multiple + times, running times are queued up and processed in the order + they were given. + + - "split-after" action signal to finish outputting the current GOP + to the current file and then start a new file as soon as the GOP + is finished and a new GOP is opened (unlike the existing + "split-now" which immediately finishes the current file and + writes the current GOP into the next newly-started file). + + - "reset-muxer" property: when unset, the muxer is reset using + flush events instead of setting its state to NULL and back. This + means the muxer can keep state across resets, e.g. mpegtsmux + will keep the continuity counter continuous across segments as + required by hlssink2. + +- qtdemux gained PIFF track encryption box support in addition to the + already-existing PIFF sample encryption support, and also allows + applications to select which encryption system to use via a + "drm-preferred-decryption-system-id" context in case there are + multiple options. + +- qtmux: the "start-gap-threshold" property determines now whether an + edit list will be created to account for small gaps or offsets at + the beginning of a stream in case the start timestamps of tracks + don’t line up perfectly. Previously the threshold was hard-coded to + 1% of the (video) frame duration, now it is 0 by default (so edit + list will be created even for small differences), but fully + configurable. + +- rtpjitterbuffer has improved end-of-stream handling + +- rtpmp4vpay will be prefered over rtpmp4gpay for MPEG-4 video in + autoplugging scenarios now + +- rtspsrc now allows applications to send RTSP SET_PARAMETER and + GET_PARAMETER requests using action signals. + +- rtspsrc also has a small (100ms) configurable teardown delay by + default to try and make sure an RTSP TEARDOWN request gets sent out + when the source element shuts down. This will block the downward + PAUSED to READY state change for a short time, but can be unset + where it’s a problem. Some servers only allow a limited number of + concurren clients, so if no proper TEARDOWN is sent clients may have + problems connecting to the server for a while. + +- souphttpsrc behaves better with low bitrate streams now. Before it + would increase the read block size too quickly which could lead to + it not reading any data from the socket for a very long time with + low bitrate streams that are output live downstream. This could lead + to servers kicking off the client. + +- filesink: do internal buffering to avoid performance regression with + small writes since we bypass libc buffering by using writev() + +- identity: add "eos-after" property and fix "error-after" property + when the element is reused + +- input-selector: lets context queries pass through, so that + e.g. upstream OpenGL elements can use contexts and displays + advertised by downstream elements + +- queue2: avoid ping-pong between 0% and 100% buffering messages if + upstream is pushing buffers larger than one of its limits, plus + performance optimisations + +- opusdec: new "phase-inversion" property to control phase inversion. + When enabled, this will slightly increase stereo quality, but + produces a stream that when downmixed to mono will suffer audio + distortions. + +- The x265enc HEVC encoder also exposes a "key-int-max" property to + configure the maximum allowed GOP size now. + +- decklinkvideosink has seen stability improvements for long-running + pipelines (potential crash due to overflow of leaked clock refcount) + and clock-slaving improvements when performing flushing seeks + (causing stalls in the output timeline), pausing and/or buffering. + +- srtpdec, srtpenc: add support for MKIs which allow multiple keys to + be used with a single SRTP stream + +- The srt Secure Reliable Transport plugin has integrated server and + client elements srt{client,server}{src,sink} into one (srtsrc and + srtsink), since SRT connection mode can be changed by uri + parameters. + +- h264parse and h265parse will handle SEI recovery point messages and + mark recovery points as keyframes as well (in addition to IDR + frames) + +- webrtcbin: "add-turn-server" action signal to pass multiple ICE + relays (TURN servers). + +- The removesilence element has received various new features and + properties, such as a + "threshold"1 property, detecting silence only after minimum silence time/buffers, a“silent”property to control bus message notifications as well as a“squash”` + property. + +- AOMedia AV1 decoder gained support for 10/12bit decoding whilst the + AV1 encoder supports more image formats and subsamplings now and + acquired support for rate control and profile related configuration. + +- The Fraunhofer fdkaac plugin can now be built against the 2.0.0 + version API and has improved multichannel support + +- kmssink now supports unpadded 24-bit RGB and can configure mode + setting from video info, which enables display of multi-planar + formats such as I420 or NV12 with modesetting. It has also gained a + number of new properties: The "restore-crtc" property does what it + says on the tin and is enabled by default. "plane-properties" and + "connector-properties" can be used to pass custom properties to the + DRM. + +- waylandsink has a "fullscreen" property now. Plugin and library moves -- this section will be filled in in due course +- The stereo element was moved from -bad into the existing audiofx + plugin in -good. If you get duplicate type registration warnings + when upgrading, check that you don’t have a stale gststereo plugin + lying about somewhere. + +GstVideoAggregator, compositor, and OpenGL mixer elements moved from -bad to -base + +GstVideoAggregator is a new base class for raw video mixers and muxers +and is based on [GstAggregator][aggregator]. It provides defined-latency +mixing of raw video inputs and ensures that the pipeline won’t stall +even if one of the input streams stops producing data. + +As part of the move to stabilise the API there were some last-minute API +changes and clean-ups, but those should mostly affect internal elements. +Most notably, the "ignore-eos" pad property was renamed to +"repeat-after-eos" and the conversion code was moved to a +GstVideoAggregatorConvertPad subclass to avoid code duplication, make +things less awkward for subclasses like the OpenGL-based video mixer, +and make the API more consistent with the audio aggregator API. + +It is used by the compositor element, which is a replacement for +‘videomixer’ which did not handle live inputs very well. compositor +should behave much better in that respect and generally behave as one +would expected in most scenarios. + +The compositor element has gained support for per-pad blending mode +operators (SOURCE, OVER, ADD) which determines what operator to use for +blending this pad over the previous ones. This can be used to implement +crossfading. + +A number of OpenGL-based video mixer elements (glvideomixer, glmixerbin, +glvideomixerelement, glstereomix, glmosaic) which are built on top of +GstVideoAggregator have also been moved from -bad to -base now. These +elements have been merged into the existing OpenGL plugin, so if you get +duplicate type registration warnings when upgrading, check that you +don’t have a stale gstopenglmixers plugin lying about somewhere. Plugin removals -- this section will be filled in in due course +The following plugins have been removed from gst-plugins-bad: + +- The experimental daala plugin has been removed, since it’s not so + useful now that all effort is focused on AV1 instead, and it had to + be enabled explicitly with --enable-experimental anyway. + +- The spc plugin has been removed. It has been replaced by the gme + plugin. + +- The acmmp3dec and acmenc plugins for Windows have been removed. ACM + is an ancient legacy API and there was no point in keeping them + around for a licensed mp3 decoder now that mp3 patents have expired + and we have a decoder in -good. We also didn’t ship these in our + cerbero-built Windows packages, so it’s unlikely that they’ll be + missed. Miscellaneous API additions -- this section will be filled in in due course +- GstBitwriter: new generic bit writer API to complement the existing + bit reader + +- gst_buffer_new_wrapped_bytes() creates a wrap buffer from a GBytes + +- gst_caps_set_features_simple() sets a caps feature on all the + structures of a GstCaps + +- New GST_QUERY_BITRATE query: This allows determining from downstream + what the expected bitrate of a stream may be which is useful in + queue2 for setting time based limits when upstream does not provide + timing information. tsdemux, qtdemux and matroskademux have basic + support for this query on their sink pads. + +- elements: there is a new “Hardware” class specifier. Elements + interacting with hardware devices should specify this classifier in + their element factory class metadata. This is useful to advertise as + one might need to put such elements into READY state to test if the + hardware is present in the system for example. + +- protection: Add a new definition for unspecified system protection + +- take functions for various mini objects that didn’t have them yet: + gst_query_take(), gst_message_take(), gst_tag_list_take(), + gst_buffer_list_take(). Unlike the various _replace() functions + _take() does not increase the reference count but takes ownership of + the mini object passed. + +- clear functions for various mini object types and GstObject which + unrefs the object or mini object (if non-NULL) and sets the variable + pointed to to NULL: gst_clear_structure(), gst_clear_tag_list(), + gst_clear_query(), gst_clear_message(), gst_clear_event(), + gst_clear_caps(), gst_clear_buffer_list(), gst_clear_buffer(), + gst_clear_mini_object(), gst_clear_object() + +- miniobject: new API gst_mini_object_add_parent() and + gst_mini_object_remove_parent()to set parent pointers on mini objects to ensure correct writability: Every container of miniobjects now needs to store itself as parent in the child object, and remove itself again later. A mini object is then only writable if there is at most one parent, that parent is writable itself, and the reference count of the mini object is 1.GstBuffer(for memories),GstBufferList(for buffers),GstSample(for caps, buffer, bufferlist), andGstVideoOverlayComposition` + were updated accordingly. Without this it was possible to have + e.g. a buffer list with a refcount of 2 used in two places at once + that both modify the same buffer with refcount 1 at the same time + wrongly thinking it is writable even though it’s really not. + +- poll: add API to watch for POLLPRI and stop treating POLLPRI as a + read. This is useful to wait for video4linux events which are + signalled via POLLPRI. + +- sample: new API to update the contents of a GstSample and make it + writable: gst_sample_set_buffer(), gst_sample_set_caps(), + gst_sample_set_segment(), gst_sample_set_info(), plus + gst_sample_is_writable() and gst_sample_make_writable(). This makes + it possible to reuse a sample object and avoid unnecessary memory + allocations, for example in appsink. + +- ClockIDs now keep a weak reference to underlying clock to avoid + crashes in basesink in corner cases where a clock goes away while + the ClockID is still in use, plus some new API + (gst_clock_id_get_clock(), gst_clock_id_uses_clock()) to check the + clock a ClockID is linked to. + +- The GstCheck unit test library gained a + fail_unless_equals_clocktime() convenience macro as well as some new + GstHarness API for for proposing meta APIs from the allocation + query: gst_harness_add_propose_allocation_meta(). ASSERT_CRITICAL() + checks in unit tests are now skipped if GStreamer was compiled with + GST_DISABLE_GLIB_CHECKS. + +- gst_audio_buffer_truncate() convenience function to truncate a raw + audio buffer + + +Miscellaneous performance and memory optimisations + +As always there have been many performance and memory usage improvements +across all components and modules. Some of them (such as dmabuf +import/export) have already been mentioned elsewhere so won’t be +repeated here. + +The following list is only a small snapshot of some of the more +interesting optimisations that haven’t been mentioned in other contexts +yet: + +- The GstVideoEncoder and GstVideoDecoder base classes now release the + STREAM_LOCK when pushing out buffers, which means (multi-threaded) + encoders and decoders can now receive and continue to process input + buffers whilst waiting for downstream elements in the pipeline to + process the buffer that was pushed out. This increases throughput + and reduces processing latency, also and especially for + hardware-accelerated encoder/decoder elements. + +- GstQueueArray has seen a few API additions + (gst_queue_array_peek_nth(), gst_queue_array_set_clear_func(), + gst_queue_array_clear()) so that it can be used in other places like + GstAdapter instead of a GList, which reduces allocations and + improves performance. + +- appsink now reuses the sample object in pull_sample() if possible + +- rtpsession only starts the RTCP thread when it’s actually needed now + +- udpsrc uses a buffer pool now and the GstUdpSrc object structure was + optimised for better cache performance GstPlayer -- this section will be filled in in due course +- API was added to fine-tune the synchronisation offset between + subtitles and video Miscellaneous changes -- this section will be filled in in due course +- As a result of moving to different FFmpeg APIs, encoder and decoder + elements exposed by the GStreamer FFmpeg wrapper plugin (gst-libav) + may have seen possibly incompatible changes to property names and/or + types, and not all properties exposed might be functional. We are + still reviewing the new properties and aim to minimise breaking + changes at least for the most commonly-used properties, so please + report any issues you run into! OpenGL integration -- this section will be filled in in due course +- The OpenGL mixer elements have been moved from -bad to + gst-plugins-base (see above) + +- The Mesa GBM backend now supports headless mode + +- gloverlaycompositor: New OpenGL-based compositor element that + flattens any overlays from GstVideoOverlayCompositionMetas into the + video stream. + +- glalpha: New element that adds an alpha channel to a video stream. + The values of the alpha channel can either be set to a constant or + can be dynamically calculated via chroma keying. It is similar to + the existing alpha element but based on OpenGL. Calculations are + done in floating point so results may not be identical to the output + of the existing alpha element. + +- glupload: Implement direct dmabuf uploader, the idea being that some + GPUs (like the Vivante series) can actually perform the YUV->RGB + conversion internally, so no custom conversion shaders are needed. + To make use of this feature, we need an additional uploader that can + import DMABUF FDs and also directly pass the pixel format, relying + on the GPU to do the conversion. Tracing framework and debugging improvements -- this section will be filled in in due course +- There is now a GDB PRETTY PRINTER FOR VARIOUS GSTREAMER TYPES: For + GstObject pointers the type and name is added, e.g. + 0x5555557e4110 [GstDecodeBin|decodebin0]. For GstMiniObject pointers + the object type is added, e.g. 0x7fffe001fc50 [GstBuffer]. For + GstClockTime and GstClockTimeDiff the time is also printed in human + readable form, e.g. 150116219955 [+0:02:30.116219955]. + +- GDB EXTENSION WITH TWO CUSTOM GDB COMMANDS gst-dot AND gst-print: + + - gst-dot creates dot files that a very close to what + GST_DEBUG_BIN_TO_DOT_FILE() produces, but object properties and + buffer contents such as codec-data in caps are not available. + + - gst-print produces high-level information about a GStreamer + object. This is currently limited to pads for GstElements and + events for the pads. The output may look like this: + + (gdb) gst-print pad.object.parent + GstMatroskaDemux (matroskademux0) { + SinkPad (sink, pull) { + } + SrcPad (video_0, push) { + events: + stream-start: + stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/001:1274058367 + caps: video/x-theora + width: 1920 + height: 800 + pixel-aspect-ratio: 1/1 + framerate: 24/1 + streamheader: < 0x5555557c7d30 [GstBuffer], 0x5555557c7e40 [GstBuffer], 0x7fffe00141d0 [GstBuffer] > + segment: time + rate: 1 + tag: global + container-format: Matroska + } + SrcPad (audio_0, push) { + events: + stream-start: + stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/002:1551204875 + caps: audio/mpeg + mpegversion: 4 + framed: true + stream-format: raw + codec_data: 0x7fffe0014500 [GstBuffer] + level: 2 + base-profile: lc + profile: lc + channels: 2 + rate: 44100 + segment: time + rate: 1 + tag: global + container-format: Matroska + tag: stream + audio-codec: MPEG-4 AAC audio + language-code: en + } + } + +- gst_structure_to_string() now serialises the actual value of + pointers when serialising GstStructures instead of claiming they’re + NULL. This makes debug logging in various places less confusing, + because it’s clear now that structure fields actually hold valid + objects. Such object pointer values will never be deserialised + however. Tools -- this section will be filled in in due course +- gst-inspect-1.0 has coloured output now and will automatically use a + pager if the output does not fit on a page. This only works in a + unix environment and if the output is not piped. If you don’t like + the colours you can disable them by setting the + GST_INSPECT_NO_COLORS=1 environment variable or passing the + --no-colors command line option. GStreamer RTSP server -- this section will be filled in in due course +- Improved backlog handling when using TCP interleaved for data + transport. Before there was a fixed maximum size for backlog + messages, which was prone to deadlocks and made it difficult to + control memory usage with the watch backlog. The RTSP server now + limits queued TCP data messages to one per stream, moving queuing of + the data into the pipeline and leaving the RTSP connection + responsive to RTSP messages in both directions, preventing all those + problems. + +- Initial ULP Forward Error Correction support in rtspclientsink and + for RECORD mode in the server. + +- API to explicitly enable retransmission requests (RTX) + +- Lots of multicast-related fixes + +- rtsp-auth: Add support for parsing .htdigest files GStreamer VAAPI @@ -110,34 +748,350 @@ GStreamer validate GStreamer Python Bindings -- this section will be filled in in due course +- add binding for gst_pad_set_caps() + +- pygobject dependency requirement was bumped to >= 3.8 + +- new audiotestsrc, audioplot, and mixer plugin examples, and a + dynamic pipeline example + + +GStreamer C# Bindings + +- bindings for the GstWebRTC library + + +GStreamer Rust Bindings + +The GStreamer Rust bindings are now officially part of the GStreamer +project and are also maintained in the GStreamer GitLab. + +The releases will generally not be synchronized with the releases of +other GStreamer parts due to dependencies on other projects. + +Also unlike the other GStreamer libraries, the bindings will not commit +to full API stability but instead will follow the approach that is +generally taken by Rust projects, e.g.: + +1) 0.12.X will be completely API compatible with all other 0.12.Y + versions. +2) 0.12.X+1 will contain bugfixes and compatible new feature additions. +3) 0.13.0 will _not_ be backwards compatible with 0.12.X but projects + will be able to stay at 0.12.X without any problems as long as they + don’t need newer features. + +The current stable release is 0.12.2 and the next release series will be +0.13, probably around March 2019. + +At this point the bindings cover most of GStreamer core (except for most +notably GstAllocator and GstMemory), and most parts of the app, audio, +base, check, editing-services, gl, net. pbutils, player, rtsp, +rtsp-server, sdp, video and webrtc libraries. + +Also included is support for creating subclasses of the following types +and writing GStreamer plugins: + +- gst::Element +- gst::Bin and gst::Pipeline +- gst::URIHandler and gst::ChildProxy +- gst::Pad, gst::GhostPad +- gst_base::Aggregator and gst_base::AggregatorPad +- gst_base::BaseSrc and gst_base::BaseSink +- gst_base::BaseTransform + +Changes to 0.12.X since 0.12.0 + +Fixed + +- PTP clock constructor actually creates a PTP instead of NTP clock + +Added + +- Bindings for GStreamer Editing Services +- Bindings for GStreamer Check testing library +- Bindings for the encoding profile API (encodebin) + +- VideoFrame, VideoInfo, AudioInfo, StructureRef implements Send and + Sync now +- VideoFrame has a function to get the raw FFI pointer +- From impls from the Error/Success enums to the combined enums like + FlowReturn +- Bin-to-dot file functions were added to the Bin trait +- gst_base::Adapter implements SendUnique now +- More complete bindings for the gst_video::VideoOverlay interface, + especially + gst_video::is_video_overlay_prepare_window_handle_message() + +Changed + +- All references were updated from GitHub to freedesktop.org GitLab +- Fix various links in the README.md +- Link to the correct location for the documentation +- Remove GitLab badge as that only works with gitlab.com currently + +Changes in git master for 0.13 + +Fixed + +- gst::tag::Album is the album tag now instead of artist sortname + +Added + +- Subclassing infrastructure was moved directly into the bindings, + making the gst-plugin crate deprecated. This involves many API + changes but generally cleans up code and makes it more flexible. + Take a look at the gst-plugins-rs crate for various examples. + +- Bindings for CapsFeatures and Meta +- Bindings for + ParentBufferMeta,VideoMetaandVideoOverlayCompositionMeta` +- Bindings for VideoOverlayComposition and VideoOverlayRectangle +- Bindings for VideoTimeCode + +- UniqueFlowCombiner and UniqueAdapter wrappers that make use of the + Rust compile-time mutability checks and expose more API in a safe + way, and as a side-effect implement Sync and Send now + +- More complete bindings for Allocation Query +- pbutils functions for codec descriptions +- TagList::iter() for iterating over all tags while getting a single + value per tag. The old ::iter_tag_list() function was renamed to + ::iter_generic() and still provides access to each value for a tag +- Bus::iter() and Bus::iter_timed() iterators around the corresponding + ::pop*() functions + +- serde serialization of Value can also handle Buffer now + +- Extensive comments to all examples with explanations +- Transmuxing example showing how to use typefind, multiqueue and + dynamic pads +- basic-tutorial-12 was ported and added + +Changed + +- Rust 1.31 is the minimum supported Rust version now +- Update to latest gir code generator and glib bindings + +- Functions returning e.g. gst::FlowReturn or other “combined” enums + were changed to return split enums like + Result to allow usage of the + standard Rust error handling. + +- MiniObject subclasses are now newtype wrappers around the underlying + GstRc wrapper. This does not change the API in any breaking + way for the current usages, but allows MiniObjects to also be + implemented in other crates and makes sure rustdoc places the + documentation in the right places. + +- BinExt extension trait was renamed to GstBinExt to prevent conflicts + with gtk::Bin if both are imported + +- Buffer::from_slice() can’t possible return None + +- Various clippy warnings + + +GStreamer Rust Plugins + +Like the GStreamer Rust bindings, the Rust plugins are now officially +part of the GStreamer project and are also maintained in the GStreamer +GitLab. + +In the 0.3.x versions this contained infrastructure for writing +GStreamer plugins in Rust, and a set of plugins. + +In git master that infrastructure was moved to the GLib and GStreamer +bindings directly, together with many other improvements that were made +possible by this, so the gst-plugins-rs repository only contains +GStreamer elements now. + +Elements included are: + +- Tutorials plugin: identity, rgb2gray and sinesrc with extensive + comments + +- rsaudioecho, a port of the audiofx element + +- rsfilesrc, rsfilesink + +- rsflvdemux, a FLV demuxer. Not feature-equivalent with flvdemux yet + +- threadshare plugin: ts-appsrc, ts-proxysrc/sink, ts-queue, ts-udpsrc + and ts-tcpclientsrc elements that use a fixed number of threads and + share them between instances. For more background about these + elements see Sebastian’s talk “When adding more threads adds more + problems - Thread-sharing between elements in GStreamer” at the + GStreamer Conference 2017. + +- rshttpsrc, a HTTP source around the hyper/reqwest Rust libraries. + Not feature-equivalent with souphttpsrc yet. + +- togglerecord, an element that allows to start/stop recording at any + time and keeps all audio/video streams in sync. + +- mccparse and mccenc, parsers and encoders for the MCC closed caption + file format. + +Changes to 0.3.X since 0.3.0 + +- All references were updated from GitHub to freedesktop.org GitLab +- Fix various links in the README.md +- Link to the correct location for the documentation + +Changes in git master for 0.4 + +- togglerecord: Switch to parking_lot crate for mutexes/condition + variables for lower overhead +- Merge threadshare plugin here +- New closedcaption plugin with mccparse and mccenc elements +- New identity element for the tutorials plugin + +- Register plugins statically in tests instead of relying on the + plugin loader to find the shared library in a specific place + +- Update to the latest API changes in the GLib and GStreamer bindings +- Update to the latest versions of all crates Build and Dependencies -- this section will be filled in in due course +- The MESON BUILD SYSTEM BUILD IS NOW FEATURE-COMPLETE (*) and it is + now the recommended build system on all platforms and also used by + Cerbero to build GStreamer on all platforms. The Autotools build is + scheduled to be removed in the next cycle. Developers who currently + use gst-uninstalled should move to gst-build. The build option + naming has been cleaned up and made consistent and there are now + feature options to enable/disable plugins and various other features + on a case-by-case basis. (*) with the exception of plugin docs which + will be handled differently in future + +- Symbol export in libraries is now controlled via explicit exports + using symbol visibility or export defines where supported, to ensure + consistency across all platforms. This also allows libraries to have + exports that vary based on detected platform features and configure + options as is the case with the GStreamer OpenGL integration library + for example. A few symbols that had been exported by accident in + earlier versions may no longer be exported. These symbols will not + have had declarations in any public header files then though and + would not have been usable. + +- The GStreamer FFmpeg wrapper plugin (gst-libav) now depends on + FFmpeg 4.x and uses the new FFmpeg 4.x API and stopped relying on + ancient API that was removed with the FFmpeg 4.x release. This means + that it is no longer possible to build this module against an older + system-provided FFmpeg 3.x version. Use the internal FFmpeg 4.x copy + instead if you build using autotools, or use gst-libav 1.14.x + instead which targets the FFmpeg 3.x API and _should_ work fine in + combination with a newer GStreamer. It’s difficult for us to support + both old and new FFmpeg APIs at the same time, apologies for any + inconvenience caused. + +- Hardware-accelerated Nvidia video encoder/decoder plugins nvdec and + nvenc can be built against CUDA Toolkit versions 9 and 10.0 now. The + dynlink interface has been dropped since it’s deprecated in 10.0. + +- The (optional) OpenCV requirement has been bumped to >= 3.0.0 and + the plugin can also be built against OpenCV 4.x now. + +- New sctp plugin based on usrsctp (for WebRTC data channels) -Platform-specific improvements +Platform-specific changes and improvements Android -- this section will be filled in in due course +- The way that GIO modules are named has changed due to upstream GLib + natively adding support for loading static GIO modules. This means + that any GStreamer application using gnutls for SSL/TLS on the + Android or iOS platforms (or any other setup using static libraries) + will fail to link looking for the g_io_module_gnutls_load_static() + function. The new function name is now + g_io_gnutls_load(gpointer data). data can be NULL for a static + library. Look at this commit for the necessary change in the + examples. macOS and iOS -- this section will be filled in in due course +- macOS binaries should be fully relocatable now + +- The way that GIO modules are named has changed due to upstream GLib + natively adding support for loading static GIO modules. This means + that any GStreamer application using gnutls for SSL/TLS on the + Android or iOS platforms (or any other setup using static libraries) + will fail to link looking for the g_io_module_gnutls_load_static() + function. The new function name is now + g_io_gnutls_load(gpointer data). data can be NULL for a static + library. Look at this commit for the necessary change in the + examples. Windows -- this section will be filled in in due course +- The webrtcdsp element is shipped again as part of the Windows binary + packages, the build system issue has been resolved. + +- ‘Inconsistent DLL linkage’ warnings when building with MSVC have + been fixed + +- Hardware-accelerated Nvidia video encoder/decoder plugins nvdec and + nvenc build on Windows now, also with MSVC and using Meson. + +- The ksvideosrc camera capture plugin supports 16-bit grayscale video + now + +- The wasapisrc audio capture element implements loopback recording + from another output device or sink + +- wasapisink recover from low buffer levels in shared mode and some + exclusive mode fixes + +- dshowsrc now implements the GstDeviceMonitor interface Contributors -- this section will be filled in in due course +Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, Alex Ashley, +Alexey Chernov, Alicia Boya García, Amit Pandya, Andoni Morales +Alastruey, Andreas Frisch, Andre McCurdy, Andy Green, Anthony Violo, +Antoine Jacoutot, Antonio Ospite, Arun Raghavan, Aurelien Jarno, +Aurélien Zanelli, ayaka, Bananahemic, Bastian Köcher, Branko Subasic, +Brendan Shanks, Carlos Rafael Giani, Christoph Reiter, Corentin Noël, +Daeseok Youn, Daniel Drake, Daniel Klamt, Dardo D Kleiner, David Ing, +David Svensson Fors, Devarsh Thakkar, Dimitrios Katsaros, Edward Hervey, +Emilio Pozuelo Monfort, Enrique Ocaña González, Ezequiel Garcia, Fabien +Dessenne, Fabrizio Gennari, Florent Thiéry, Francisco Velazquez, +Freyr666, Garima Gaur, Gary Bisson, George Kiagiadakis, Georg Lippitsch, +Georg Ottinger, Geunsik Lim, Göran Jönsson, Guillaume Desmottes, H1Gdev, +Haihao Xiang, Haihua Hu, Harshad Khedkar, Havard Graff, He Junyan, +Hoonhee Lee, Hosang Lee, Hyunjun Ko, Ingo Randolf, Iñigo Huguet, James +Stevenson, Jan Alexander Steffens, Jan Schmidt, Jerome Laheurte, Jimmy +Ohn, Joakim Johansson, Jochen Henneberg, Johan Bjäreholt, John-Mark +Bell, John Nikolaides, Jonathan Karlsson, Jonny Lamb, Jordan Petridis, +Josep Torra, Joshua M. Doe, Jos van Egmond, Juan Navarro, Jun Xie, +Junyan He, Justin Kim, Kai Kang, Kim Tae Soo, Kirill Marinushkin, Kyrylo +Polezhaiev, Lars Petter Endresen, Linus Svensson, Louis-Francis +Ratté-Boulianne, Luis de Bethencourt, Luz Paz, Lyon Wang, Maciej Wolny, +Marc-André Lureau, Marc Leeman, Marcos Kintschner, Marian Mihailescu, +Marinus Schraal, Mark Nauwelaerts, Marouen Ghodhbane, Martin Kelly, +Matej Knopp, Mathieu Duponchelle, Matteo Valdina, Matthew Waters, +Matthias Fend, memeka, Michael Drake, Michael Gruner, Michael Olbrich, +Michael Tretter, Miguel Paris, Mike Wey, Mikhail Fludkov, Naveen +Cherukuri, Nicola Murino, Nicolas Dufresne, Niels De Graef, Nirbheek +Chauhan, Norbert Wesp, Ognyan Tonchev, Olivier Crête, Omar Akkila, +Patricia Muscalu, Patrick Radizi, Patrik Nilsson, Paul Kocialkowski, Per +Forlin, Peter Körner, Peter Seiderer, Petr Kulhavy, Philippe Normand, +Philippe Renon, Philipp Zabel, Pierre Labastie, Roland Jon, Roman +Sivriver, Rosen Penev, Russel Winder, Sam Gigliotti, Sean-Der, Sebastian +Dröge, Seungha Yang, Sjoerd Simons, Snir Sheriber, Song Bing, Soon, +Thean Siew, Sreerenj Balachandran, Stefan Ringel, Stephane Cerveau, +Stian Selnes, Suhas Nayak, Takeshi Sato, Thiago Santos, Thibault +Saunier, Thomas Bluemel, Tianhao Liu, Tim-Philipp Müller, Tomasz +Andrzejak, Tomislav Tustonić, U. Artie Eoff, Ulf Olsson, Varunkumar +Allagadapa, Víctor Guzmán, Víctor Manuel Jáquez Leal, Vincenzo Bono, +Vineeth T M, Vivia Nikolaidou, Wang Fei, wangzq, Whoopie, Wim Taymans, +Wind Yuan, Wonchul Lee, Xabier Rodriguez Calvar, Xavier Claessens, +Haihao Xiang, Yacine Bandou, Yeongjin Jeong, Yuji Kuwabara, Zeeshan Ali, -... and many others who have contributed bug reports, translations, sent +… and many others who have contributed bug reports, translations, sent suggestions or helped testing. @@ -165,30 +1119,41 @@ the git 1.16 branch, which is a stable branch. 1.16.0 -1.16.0 is scheduled to be released around September 2018. +1.16.0 is scheduled to be released around January/February 2019. Known Issues -- The webrtcdsp element is currently not shipped as part of the - Windows binary packages due to a build system issue. +- possibly breaking/incompatible changes to properties of wrapped + FFmpeg decoders and encoders (see above). + +- The way that GIO modules are named has changed due to upstream GLib + natively adding support for loading static GIO modules. This means + that any GStreamer application using gnutls for SSL/TLS on the + Android or iOS platforms (or any other setup using static libraries) + will fail to link looking for the g_io_module_gnutls_load_static() + function. The new function name is now + g_io_gnutls_load(gpointer data). See Android/iOS sections above for + further details. Schedule for 1.18 -Our next major feature release will be 1.16, and 1.15 will be the -unstable development version leading up to the stable 1.16 release. The -development of 1.15/1.16 will happen in the git master branch. +Our next major feature release will be 1.18, and 1.17 will be the +unstable development version leading up to the stable 1.18 release. The +development of 1.17/1.18 will happen in the git master branch. -The plan for the 1.16 development cycle is yet to be confirmed, but it -is expected that feature freeze will be around August 2017 followed by -several 1.15 pre-releases and the new 1.16 stable release in September. +The plan for the 1.18 development cycle is yet to be confirmed, but it +is expected that feature freeze will be around July 2019 followed by +several 1.17 pre-releases and the new 1.18 stable release in +August/September. -1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, -1.6, 1.4, 1.2 and 1.0 release series. +1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, +1.8, 1.6, 1.4, 1.2 and 1.0 release series. ------------------------------------------------------------------------ -_These release notes have been prepared by Tim-Philipp Müller._ +_These release notes have been prepared by Tim-Philipp Müller with_ +_contributions from Sebastian Dröge._ _License: CC BY-SA 4.0_ diff --git a/RELEASE b/RELEASE index e8b15b2d7d..3957adc62d 100644 --- a/RELEASE +++ b/RELEASE @@ -1,6 +1,6 @@ -This is GStreamer gst-rtsp-server 1.15.0.1. +This is GStreamer gst-rtsp-server 1.15.1. -GStreamer 1.15 is the development version leading up to the next major +GStreamer 1.15 is the development branch leading up to the next major stable version which will be 1.16. The 1.15 development series adds new features on top of the 1.14 series and is @@ -11,8 +11,8 @@ Full release notes will one day be found at: https://gstreamer.freedesktop.org/releases/1.16/ -Binaries for Android, iOS, Mac OS X and Windows will be provided shortly -after the release. +Binaries for Android, iOS, Mac OS X and Windows will usually be provided +shortly after the release. This module will not be very useful by itself and should be used in conjunction with other GStreamer modules for a complete multimedia experience. @@ -57,7 +57,7 @@ You can find source releases of gstreamer in the download directory: https://gstreamer.freedesktop.org/src/gstreamer/ The git repository and details how to clone it can be found at -http://cgit.freedesktop.org/gstreamer/gstreamer/ +https://cgit.freedesktop.org/gstreamer/gstreamer/ ==== Homepage ==== @@ -65,10 +65,16 @@ The project's website is https://gstreamer.freedesktop.org/ ==== Support and Bugs ==== -We use GNOME's bugzilla for bug reports and feature requests: -http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer +We have recently moved from GNOME Bugzilla to GitLab on freedesktop.org +for bug reports and feature requests: -Please submit patches via bugzilla as well. + https://gitlab.freedesktop.org/gstreamer + +Please submit patches via GitLab as well, in form of Merge Requests. See + + https://gstreamer.freedesktop.org/documentation/contribute/ + +for more details. For help and support, please subscribe to and send questions to the gstreamer-devel mailing list (see below for details). @@ -77,8 +83,14 @@ There is also a #gstreamer IRC channel on the Freenode IRC network. ==== Developers ==== -GStreamer is stored in Git, hosted at git.freedesktop.org, and can be cloned -from there (see link above). +GStreamer source code repositories can be found on GitLab on freedesktop.org: + + https://gitlab.freedesktop.org/gstreamer + +and can also be cloned from there and this is also where you can submit +Merge Requests or file issues for bugs or feature requests. Interested developers of the core library, plugins, and applications should -subscribe to the gstreamer-devel list. +subscribe to the gstreamer-devel list: + + https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel diff --git a/configure.ac b/configure.ac index 214da35cd5..14b026176b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.15.0.1], +AC_INIT([GStreamer RTSP Server Library], [1.15.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1500, 0, 1500) +AS_LIBTOOL(GST, 1501, 0, 1501) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.15.0.1 -GSTPB_REQ=1.15.0.1 -GSTPG_REQ=1.15.0.1 -GSTPD_REQ=1.15.0.1 +GST_REQ=1.15.1 +GSTPB_REQ=1.15.1 +GSTPG_REQ=1.15.1 +GSTPD_REQ=1.15.1 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 5103fe4409..a1638d0248 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.15.1 + master + + 2019-01-17 + + + + 1.14.0 diff --git a/meson.build b/meson.build index 6b748c3ac0..2ca3014ee3 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.15.0.1', + version : '1.15.1', meson_version : '>= 0.47', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From ae32203cb09df5c877a8bc68179dbf165715ec52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Wir=C3=A9en?= Date: Thu, 27 Dec 2018 11:28:17 +0100 Subject: [PATCH 1582/1776] rtsp-media: Fix race codition in finish_unprepare The previous fix for race condition around finish_unprepare where the function could be called twice assumed that the status wouldn't change during execution of the function. This assumption is incorrect as the state may change, for example if an error message arrives from the pipeline bus. Instead a flag keeping track on whether the finish_unprepare function is currently executing is introduced and checked. Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/59 --- gst/rtsp-server/rtsp-media.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 490c73da73..e95b0dede8 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -115,6 +115,7 @@ struct _GstRTSPMediaPrivate gint prepare_count; gint n_active; gboolean complete; + gboolean finishing_unprepare; /* the pipeline for the media */ GstElement *pipeline; @@ -3618,6 +3619,10 @@ finish_unprepare (GstRTSPMedia * media) gint i; GList *walk; + if (priv->finishing_unprepare) + return; + priv->finishing_unprepare = TRUE; + GST_DEBUG ("shutting down"); /* release the lock on shutdown, otherwise pad_added_cb might try to @@ -3628,9 +3633,6 @@ finish_unprepare (GstRTSPMedia * media) media_streams_set_blocked (media, FALSE); - if (priv->status != GST_RTSP_MEDIA_STATUS_UNPREPARING) - return; - for (i = 0; i < priv->streams->len; i++) { GstRTSPStream *stream; @@ -3683,6 +3685,8 @@ finish_unprepare (GstRTSPMedia * media) GST_DEBUG ("stop thread"); gst_rtsp_thread_stop (priv->thread); } + + priv->finishing_unprepare = FALSE; } /* called with state-lock */ From a48711fa9d277a8e50ea6be7fb53a1808bb7ef72 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 29 Jan 2019 14:42:35 +0100 Subject: [PATCH 1583/1776] rtsp-stream: Use cached address when allocating sockets If an address/port was previously decided upon (ex: multicast in the SDP), then use that instead of re-creating another one Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/57 --- gst/rtsp-server/rtsp-stream.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 33eeb50d59..8484ef9ec3 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1076,7 +1076,8 @@ no_address: * won't release the address from the pool. * * Returns: (nullable): the #GstRTSPAddress of @stream or %NULL when - * the address could be reserved. gst_rtsp_address_free() after usage. + * the address could not be reserved. gst_rtsp_address_free() after + * usage. */ GstRTSPAddress * gst_rtsp_stream_reserve_address (GstRTSPStream * stream, @@ -1448,7 +1449,10 @@ again: else flags |= GST_RTSP_ADDRESS_FLAG_IPV4; - addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); + if (*server_addr_out) + addr = *server_addr_out; + else + addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); if (addr == NULL) goto no_address; From 621e140a8efd081a243c732940d886cb363a1399 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 4 Dec 2018 14:12:04 +0100 Subject: [PATCH 1584/1776] client: Fix crash in close handler The close handler could trigger a crash because it invalidated the watch_context while still leaving a source attached to it which would be cleaned up at a later point. --- gst/rtsp-server/rtsp-client.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 70196a1091..ce9cbce4e3 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -178,6 +178,8 @@ static void gst_rtsp_client_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_client_finalize (GObject * obj); +static void rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv); + static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media); static gboolean handle_sdp (GstRTSPClient * client, GstRTSPContext * ctx, GstRTSPMedia * media, GstSDPMessage * sdp); @@ -1229,6 +1231,7 @@ gst_rtsp_client_close (GstRTSPClient * client) g_source_destroy ((GSource *) priv->watch); priv->watch = NULL; gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + rtsp_ctrl_timeout_remove (priv); g_main_context_unref (priv->watch_context); priv->watch_context = NULL; } From d708f9736b550d69f30277592d99b287c152001a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 27 Jun 2018 12:17:07 +0200 Subject: [PATCH 1585/1776] rtsp-server: Add support for buffer lists This adds new functions for passing buffer lists through the different layers without breaking API/ABI, and enables the appsink to actually provide buffer lists. This should already reduce CPU usage and potentially context switches a bit by passing a whole buffer list from the appsink instead of individual buffers. As a next step it would be necessary to a) Add support for a vector of data for the GstRTSPMessage body b) Add support for sending multiple messages at once to the GstRTSPWatch and let it be handled internally c) Adding API to GOutputStream that works like writev() Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/29 --- docs/libs/gst-rtsp-server-sections.txt | 6 +- gst/rtsp-server/rtsp-client.c | 27 ++++- gst/rtsp-server/rtsp-media.c | 5 +- gst/rtsp-server/rtsp-stream-transport.c | 129 ++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream-transport.h | 31 ++++++ gst/rtsp-server/rtsp-stream.c | 38 +++++-- gst/rtsp-sink/gstrtspclientsink.c | 25 +++++ 7 files changed, 250 insertions(+), 11 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 08472c8adc..369a57af8d 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -680,6 +680,8 @@ gst_rtsp_stream_transport_get_rtpinfo GstRTSPSendFunc gst_rtsp_stream_transport_set_callbacks +GstRTSPSendListFunc +gst_rtsp_stream_transport_set_list_callbacks GstRTSPKeepAliveFunc gst_rtsp_stream_transport_set_keepalive @@ -690,8 +692,10 @@ gst_rtsp_stream_transport_set_active gst_rtsp_stream_transport_set_timed_out gst_rtsp_stream_transport_is_timed_out -gst_rtsp_stream_transport_send_rtcp gst_rtsp_stream_transport_send_rtp +gst_rtsp_stream_transport_send_rtp_list +gst_rtsp_stream_transport_send_rtcp +gst_rtsp_stream_transport_send_rtcp_list GST_RTSP_STREAM_TRANSPORT_CAST diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index ce9cbce4e3..cce9222869 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1198,6 +1198,27 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) return ret; } +static gboolean +do_send_data_list (GstBufferList * buffer_list, guint8 channel, + GstRTSPClient * client) +{ + gboolean ret = TRUE; + guint i, n = gst_buffer_list_length (buffer_list); + + /* TODO: Needs support for a) queueing up multiple messages on the + * GstRTSPWatch in do_send_data() above and b) for one message having a body + * consisting of multiple parts here */ + for (i = 0; i < n; i++) { + GstBuffer *buffer = gst_buffer_list_get (buffer_list, i); + + ret = do_send_data (buffer, channel, client); + if (!ret) + break; + } + + return ret; +} + /** * gst_rtsp_client_close: * @client: a #GstRTSPClient @@ -2527,6 +2548,9 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_stream_transport_set_callbacks (trans, (GstRTSPSendFunc) do_send_data, (GstRTSPSendFunc) do_send_data, client, NULL); + gst_rtsp_stream_transport_set_list_callbacks (trans, + (GstRTSPSendListFunc) do_send_data_list, + (GstRTSPSendListFunc) do_send_data_list, client, NULL); g_hash_table_insert (priv->transports, GINT_TO_POINTER (ct->interleaved.min), trans); @@ -4628,7 +4652,8 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) /* create watch for the connection and attach */ priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs, g_object_ref (client), (GDestroyNotify) client_watch_notify); - gst_rtsp_client_set_send_func (client, do_send_message, priv->watch, + gst_rtsp_client_set_send_func (client, do_send_message, + g_source_ref ((GSource *) priv->watch), (GDestroyNotify) gst_rtsp_watch_unref); gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e95b0dede8..bfcba34e9c 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2260,8 +2260,9 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, } g_object_set (appsrc, "block", TRUE, "format", GST_FORMAT_TIME, "is-live", - TRUE, NULL); - g_object_set (appsink, "sync", FALSE, "async", FALSE, NULL); + TRUE, "emit-signals", FALSE, NULL); + g_object_set (appsink, "sync", FALSE, "async", FALSE, "emit-signals", + FALSE, "buffer-list", TRUE, NULL); data = g_new0 (AppSinkSrcData, 1); data->appsink = appsink; diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index a258025f79..7c439e28a9 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -58,6 +58,11 @@ struct _GstRTSPStreamTransportPrivate gpointer user_data; GDestroyNotify notify; + GstRTSPSendListFunc send_rtp_list; + GstRTSPSendListFunc send_rtcp_list; + gpointer list_user_data; + GDestroyNotify list_notify; + GstRTSPKeepAliveFunc keep_alive; gpointer ka_user_data; GDestroyNotify ka_notify; @@ -207,6 +212,38 @@ gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport * trans, priv->notify = notify; } +/** + * gst_rtsp_stream_transport_set_list_callbacks: + * @trans: a #GstRTSPStreamTransport + * @send_rtp_list: (scope notified): a callback called when RTP should be sent + * @send_rtcp_list: (scope notified): a callback called when RTCP should be sent + * @user_data: (closure): user data passed to callbacks + * @notify: (allow-none): called with the user_data when no longer needed. + * + * Install callbacks that will be called when data for a stream should be sent + * to a client. This is usually used when sending RTP/RTCP over TCP. + * + * Since: 1.16 + */ +void +gst_rtsp_stream_transport_set_list_callbacks (GstRTSPStreamTransport * trans, + GstRTSPSendListFunc send_rtp_list, GstRTSPSendListFunc send_rtcp_list, + gpointer user_data, GDestroyNotify notify) +{ + GstRTSPStreamTransportPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); + + priv = trans->priv; + + priv->send_rtp_list = send_rtp_list; + priv->send_rtcp_list = send_rtcp_list; + if (priv->list_notify) + priv->list_notify (priv->list_user_data); + priv->list_user_data = user_data; + priv->list_notify = notify; +} + /** * gst_rtsp_stream_transport_set_keepalive: * @trans: a #GstRTSPStreamTransport @@ -531,6 +568,98 @@ gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport * trans, return res; } +/** + * gst_rtsp_stream_transport_send_rtp_list: + * @trans: a #GstRTSPStreamTransport + * @buffer_list: (transfer none): a #GstBufferList + * + * Send @buffer_list to the installed RTP callback for @trans. + * + * Returns: %TRUE on success + * + * Since: 1.16 + */ +gboolean +gst_rtsp_stream_transport_send_rtp_list (GstRTSPStreamTransport * trans, + GstBufferList * buffer_list) +{ + GstRTSPStreamTransportPrivate *priv; + gboolean res = FALSE; + + g_return_val_if_fail (GST_IS_BUFFER_LIST (buffer_list), FALSE); + + priv = trans->priv; + + if (priv->send_rtp_list) { + res = + priv->send_rtp_list (buffer_list, priv->transport->interleaved.min, + priv->list_user_data); + } else if (priv->send_rtp) { + guint n = gst_buffer_list_length (buffer_list), i; + + for (i = 0; i < n; i++) { + GstBuffer *buffer = gst_buffer_list_get (buffer_list, i); + + res = + priv->send_rtp (buffer, priv->transport->interleaved.min, + priv->user_data); + if (!res) + break; + } + } + + if (res) + gst_rtsp_stream_transport_keep_alive (trans); + + return res; +} + +/** + * gst_rtsp_stream_transport_send_rtcp_list: + * @trans: a #GstRTSPStreamTransport + * @buffer_list: (transfer none): a #GstBuffer + * + * Send @buffer_list to the installed RTCP callback for @trans. + * + * Returns: %TRUE on success + * + * Since: 1.16 + */ +gboolean +gst_rtsp_stream_transport_send_rtcp_list (GstRTSPStreamTransport * trans, + GstBufferList * buffer_list) +{ + GstRTSPStreamTransportPrivate *priv; + gboolean res = FALSE; + + g_return_val_if_fail (GST_IS_BUFFER_LIST (buffer_list), FALSE); + + priv = trans->priv; + + if (priv->send_rtcp_list) { + res = + priv->send_rtcp_list (buffer_list, priv->transport->interleaved.max, + priv->list_user_data); + } else if (priv->send_rtcp) { + guint n = gst_buffer_list_length (buffer_list), i; + + for (i = 0; i < n; i++) { + GstBuffer *buffer = gst_buffer_list_get (buffer_list, i); + + res = + priv->send_rtcp (buffer, priv->transport->interleaved.max, + priv->user_data); + if (!res) + break; + } + } + + if (res) + gst_rtsp_stream_transport_keep_alive (trans); + + return res; +} + /** * gst_rtsp_stream_transport_keep_alive: * @trans: a #GstRTSPStreamTransport diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 48c565a71c..2b507b01d3 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -56,6 +56,22 @@ typedef struct _GstRTSPStreamTransportPrivate GstRTSPStreamTransportPrivate; * Returns: %TRUE on success */ typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); + +/** + * GstRTSPSendListFunc: + * @buffer_list: a #GstBufferList + * @channel: a channel + * @user_data: user data + * + * Function registered with gst_rtsp_stream_transport_set_callbacks() and + * called when @buffer_list must be sent on @channel. + * + * Returns: %TRUE on success + * + * Since: 1.16 + */ +typedef gboolean (*GstRTSPSendListFunc) (GstBufferList *buffer_list, guint8 channel, gpointer user_data); + /** * GstRTSPKeepAliveFunc: * @user_data: user data @@ -131,6 +147,13 @@ void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamT gpointer user_data, GDestroyNotify notify); +GST_RTSP_SERVER_API +void gst_rtsp_stream_transport_set_list_callbacks (GstRTSPStreamTransport *trans, + GstRTSPSendListFunc send_rtp_list, + GstRTSPSendListFunc send_rtcp_list, + gpointer user_data, + GDestroyNotify notify); + GST_RTSP_SERVER_API void gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport *trans, GstRTSPKeepAliveFunc keep_alive, @@ -170,6 +193,14 @@ GST_RTSP_SERVER_API gboolean gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport *trans, GstBuffer *buffer); +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_transport_send_rtp_list (GstRTSPStreamTransport *trans, + GstBufferList *buffer_list); + +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_transport_send_rtcp_list(GstRTSPStreamTransport *trans, + GstBufferList *buffer_list); + GST_RTSP_SERVER_API GstFlowReturn gst_rtsp_stream_transport_recv_data (GstRTSPStreamTransport *trans, guint channel, GstBuffer *buffer); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 8484ef9ec3..b9d2e7f286 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2456,6 +2456,8 @@ send_tcp_message (GstRTSPStream * stream, gint idx) GList *walk; GstSample *sample; GstBuffer *buffer; + GstBufferList *buffer_list; + guint n_messages = 0; gboolean is_rtp; if (priv->n_outstanding > 0 || !priv->have_buffer[idx]) { @@ -2476,6 +2478,14 @@ send_tcp_message (GstRTSPStream * stream, gint idx) } buffer = gst_sample_get_buffer (sample); + buffer_list = gst_sample_get_buffer_list (sample); + + /* We will get one message-sent notification per message, + * i.e. per buffer that is actually sent out */ + if (buffer) + n_messages += 1; + if (buffer_list) + n_messages += gst_buffer_list_length (buffer_list); is_rtp = (idx == 0); @@ -2513,17 +2523,24 @@ send_tcp_message (GstRTSPStream * stream, gint idx) } } - priv->n_outstanding += priv->n_tcp_transports; + priv->n_outstanding += n_messages * priv->n_tcp_transports; g_mutex_unlock (&priv->lock); if (is_rtp) { for (walk = priv->tr_cache_rtp; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - if (!gst_rtsp_stream_transport_send_rtp (tr, buffer)) { + gboolean send_ret = TRUE; + + if (buffer) + send_ret = gst_rtsp_stream_transport_send_rtp (tr, buffer); + if (buffer_list) + send_ret = gst_rtsp_stream_transport_send_rtp_list (tr, buffer_list); + + if (!send_ret) { /* remove transport on send error */ g_mutex_lock (&priv->lock); - priv->n_outstanding--; + priv->n_outstanding -= n_messages; update_transport (stream, tr, FALSE); g_mutex_unlock (&priv->lock); } @@ -2531,10 +2548,17 @@ send_tcp_message (GstRTSPStream * stream, gint idx) } else { for (walk = priv->tr_cache_rtcp; walk; walk = g_list_next (walk)) { GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - if (!gst_rtsp_stream_transport_send_rtcp (tr, buffer)) { + gboolean send_ret = TRUE; + + if (buffer) + send_ret = gst_rtsp_stream_transport_send_rtcp (tr, buffer); + if (buffer_list) + send_ret = gst_rtsp_stream_transport_send_rtcp_list (tr, buffer_list); + + if (!send_ret) { /* remove transport on send error */ g_mutex_lock (&priv->lock); - priv->n_outstanding--; + priv->n_outstanding -= n_messages; update_transport (stream, tr, FALSE); g_mutex_unlock (&priv->lock); } @@ -3369,8 +3393,8 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport) } else if (is_tcp && !priv->appsink[i]) { /* make appsink */ priv->appsink[i] = gst_element_factory_make ("appsink", NULL); - g_object_set (priv->appsink[i], "emit-signals", FALSE, "max-buffers", 1, - NULL); + g_object_set (priv->appsink[i], "emit-signals", FALSE, "buffer-list", + TRUE, "max-buffers", 1, NULL); /* we need to set sync and preroll to FALSE for the sink to avoid * deadlock. This is only needed for sink sending RTCP data. */ diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 175b4ea705..3e309c1416 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -3850,6 +3850,27 @@ do_send_data (GstBuffer * buffer, guint8 channel, return res == GST_RTSP_OK; } +static gboolean +do_send_data_list (GstBufferList * buffer_list, guint8 channel, + GstRTSPStreamContext * context) +{ + gboolean ret = TRUE; + guint i, n = gst_buffer_list_length (buffer_list); + + /* TODO: Needs support for a) queueing up multiple messages on the + * GstRTSPWatch in do_send_data() above and b) for one message having a body + * consisting of multiple parts here */ + for (i = 0; i < n; i++) { + GstBuffer *buffer = gst_buffer_list_get (buffer_list, i); + + ret = do_send_data (buffer, channel, context); + if (!ret) + break; + } + + return ret; +} + static GstRTSPResult gst_rtsp_client_sink_setup_streams (GstRTSPClientSink * sink, gboolean async) { @@ -4147,6 +4168,10 @@ gst_rtsp_client_sink_setup_streams (GstRTSPClientSink * sink, gboolean async) gst_rtsp_stream_transport_set_callbacks (context->stream_transport, (GstRTSPSendFunc) do_send_data, (GstRTSPSendFunc) do_send_data, context, NULL); + gst_rtsp_stream_transport_set_list_callbacks + (context->stream_transport, + (GstRTSPSendListFunc) do_send_data_list, + (GstRTSPSendListFunc) do_send_data_list, context, NULL); } /* The stream_transport now owns the transport */ From c372643e1ec8b4970c74456d42ac47622388272d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 17 Sep 2018 22:18:46 +0300 Subject: [PATCH 1586/1776] rtsp-client: Add support for sending buffer lists directly Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/29 --- docs/libs/gst-rtsp-server-sections.txt | 2 + gst/rtsp-server/rtsp-client.c | 171 ++++++++++++++++++++++--- gst/rtsp-server/rtsp-client.h | 27 ++++ gst/rtsp-server/rtsp-stream.c | 6 +- 4 files changed, 186 insertions(+), 20 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 369a57af8d..c1627da451 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -118,6 +118,8 @@ gst_rtsp_client_attach GstRTSPClientSendFunc gst_rtsp_client_set_send_func +GstRTSPClientSendMessagesFunc +gst_rtsp_client_set_send_messages_func gst_rtsp_client_handle_message gst_rtsp_client_send_message diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index cce9222869..020f2fab2c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -80,6 +80,9 @@ struct _GstRTSPClientPrivate GstRTSPClientSendFunc send_func; gpointer send_data; GDestroyNotify send_notify; + GstRTSPClientSendMessagesFunc send_messages_func; + gpointer send_messages_data; + GDestroyNotify send_messages_notify; guint close_seq; GArray *data_seqs; @@ -753,6 +756,7 @@ gst_rtsp_client_finalize (GObject * obj) if (priv->watch) gst_rtsp_watch_set_flushing (priv->watch, TRUE); gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); if (priv->watch) g_source_destroy ((GSource *) priv->watch); @@ -1158,17 +1162,10 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) GstRTSPClientPrivate *priv = client->priv; GstRTSPMessage message = { 0 }; gboolean ret = TRUE; - GstMapInfo map_info; - guint8 *data; - guint usize; gst_rtsp_message_init_data (&message, channel); - /* FIXME, need some sort of iovec RTSPMessage here */ - if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) - return FALSE; - - gst_rtsp_message_take_body (&message, map_info.data, map_info.size); + gst_rtsp_message_set_body_buffer (&message, buffer); g_mutex_lock (&priv->send_lock); if (get_data_seq (client, channel) != 0) { @@ -1180,9 +1177,6 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) ret = priv->send_func (client, &message, FALSE, priv->send_data); g_mutex_unlock (&priv->send_lock); - gst_rtsp_message_steal_body (&message, &data, &usize); - gst_buffer_unmap (buffer, &map_info); - gst_rtsp_message_unset (&message); if (!ret) { @@ -1202,18 +1196,50 @@ static gboolean do_send_data_list (GstBufferList * buffer_list, guint8 channel, GstRTSPClient * client) { + GstRTSPClientPrivate *priv = client->priv; gboolean ret = TRUE; guint i, n = gst_buffer_list_length (buffer_list); + GstRTSPMessage *messages; - /* TODO: Needs support for a) queueing up multiple messages on the - * GstRTSPWatch in do_send_data() above and b) for one message having a body - * consisting of multiple parts here */ + g_mutex_lock (&priv->send_lock); + if (get_data_seq (client, channel) != 0) { + GST_WARNING ("already a queued data message for channel %d", channel); + g_mutex_unlock (&priv->send_lock); + return FALSE; + } + + messages = g_newa (GstRTSPMessage, n); + memset (messages, 0, sizeof (GstRTSPMessage) * n); for (i = 0; i < n; i++) { GstBuffer *buffer = gst_buffer_list_get (buffer_list, i); + gst_rtsp_message_init_data (&messages[i], channel); + gst_rtsp_message_set_body_buffer (&messages[i], buffer); + } - ret = do_send_data (buffer, channel, client); - if (!ret) - break; + if (priv->send_messages_func) { + ret = + priv->send_messages_func (client, messages, n, FALSE, priv->send_data); + } else if (priv->send_func) { + for (i = 0; i < n; i++) { + ret = priv->send_func (client, &messages[i], FALSE, priv->send_data); + if (!ret) + break; + } + } + g_mutex_unlock (&priv->send_lock); + + for (i = 0; i < n; i++) { + gst_rtsp_message_unset (&messages[i]); + } + + if (!ret) { + GSource *idle_src; + + /* close in watch context */ + idle_src = g_idle_source_new (); + g_source_set_callback (idle_src, do_close, client, NULL); + g_source_attach (idle_src, priv->watch_context); + g_source_unref (idle_src); } return ret; @@ -1252,6 +1278,7 @@ gst_rtsp_client_close (GstRTSPClient * client) g_source_destroy ((GSource *) priv->watch); priv->watch = NULL; gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); rtsp_ctrl_timeout_remove (priv); g_main_context_unref (priv->watch_context); priv->watch_context = NULL; @@ -4184,6 +4211,47 @@ gst_rtsp_client_set_send_func (GstRTSPClient * client, old_notify (old_data); } +/** + * gst_rtsp_client_set_send_messages_func: + * @client: a #GstRTSPClient + * @func: (scope notified): a #GstRTSPClientSendMessagesFunc + * @user_data: (closure): user data passed to @func + * @notify: (allow-none): called when @user_data is no longer in use + * + * Set @func as the callback that will be called when new messages needs to be + * sent to the client. @user_data is passed to @func and @notify is called when + * @user_data is no longer in use. + * + * By default, the client will send the messages on the #GstRTSPConnection that + * was configured with gst_rtsp_client_attach() was called. + * + * Since: 1.16 + */ +void +gst_rtsp_client_set_send_messages_func (GstRTSPClient * client, + GstRTSPClientSendMessagesFunc func, gpointer user_data, + GDestroyNotify notify) +{ + GstRTSPClientPrivate *priv; + GDestroyNotify old_notify; + gpointer old_data; + + g_return_if_fail (GST_IS_RTSP_CLIENT (client)); + + priv = client->priv; + + g_mutex_lock (&priv->send_lock); + priv->send_messages_func = func; + old_notify = priv->send_messages_notify; + old_data = priv->send_messages_data; + priv->send_messages_notify = notify; + priv->send_messages_data = user_data; + g_mutex_unlock (&priv->send_lock); + + if (old_notify) + old_notify (old_data); +} + /** * gst_rtsp_client_handle_message: * @client: a #GstRTSPClient @@ -4317,6 +4385,71 @@ error: } } +static gboolean +do_send_messages (GstRTSPClient * client, GstRTSPMessage * messages, + guint n_messages, gboolean close, gpointer user_data) +{ + GstRTSPClientPrivate *priv = client->priv; + guint id = 0; + GstRTSPResult ret; + guint i; + + /* send the message */ + ret = gst_rtsp_watch_send_messages (priv->watch, messages, n_messages, &id); + if (ret != GST_RTSP_OK) + goto error; + + /* if close flag is set, store the seq number so we can wait until it's + * written to the client to close the connection */ + if (close) + priv->close_seq = id; + + for (i = 0; i < n_messages; i++) { + if (gst_rtsp_message_get_type (&messages[i]) == GST_RTSP_MESSAGE_DATA) { + guint8 channel = 0; + GstRTSPResult r; + + /* We assume that all data messages in the list are for the + * same channel */ + r = gst_rtsp_message_parse_data (&messages[i], &channel); + if (r != GST_RTSP_OK) { + ret = r; + goto error; + } + + /* check if the message has been queued for transmission in watch */ + if (id) { + /* store the seq number so we can wait until it has been sent */ + GST_DEBUG_OBJECT (client, "wait for message %d, channel %d", id, + channel); + set_data_seq (client, channel, id); + } else { + GstRTSPStreamTransport *trans; + + trans = + g_hash_table_lookup (priv->transports, + GINT_TO_POINTER ((gint) channel)); + if (trans) { + GST_DEBUG_OBJECT (client, "emit 'message-sent' signal"); + g_mutex_unlock (&priv->send_lock); + gst_rtsp_stream_transport_message_sent (trans); + g_mutex_lock (&priv->send_lock); + } + } + break; + } + } + + return ret == GST_RTSP_OK; + + /* ERRORS */ +error: + { + GST_DEBUG_OBJECT (client, "got error %d", ret); + return FALSE; + } +} + static GstRTSPResult message_received (GstRTSPWatch * watch, GstRTSPMessage * message, gpointer user_data) @@ -4378,6 +4511,7 @@ closed (GstRTSPWatch * watch, gpointer user_data) gst_rtsp_watch_set_flushing (watch, TRUE); g_mutex_lock (&priv->watch_lock); gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); g_mutex_unlock (&priv->watch_lock); return GST_RTSP_OK; @@ -4517,6 +4651,7 @@ handle_tunnel (GstRTSPClient * client) g_source_destroy ((GSource *) priv->watch); priv->watch = NULL; gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); } return GST_RTSP_STS_OK; @@ -4655,6 +4790,8 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) gst_rtsp_client_set_send_func (client, do_send_message, g_source_ref ((GSource *) priv->watch), (GDestroyNotify) gst_rtsp_watch_unref); + gst_rtsp_client_set_send_messages_func (client, do_send_messages, priv->watch, + (GDestroyNotify) gst_rtsp_watch_unref); gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE); diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 01846bc249..ebf6aeca27 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -61,6 +61,27 @@ typedef gboolean (*GstRTSPClientSendFunc) (GstRTSPClient *client, gboolean close, gpointer user_data); +/** + * GstRTSPClientSendMessagesFunc: + * @client: a #GstRTSPClient + * @messages: #GstRTSPMessage + * @n_messages: number of messages + * @close: close the connection + * @user_data: user data when registering the callback + * + * This callback is called when @client wants to send @messages. When @close is + * %TRUE, the connection should be closed when the message has been sent. + * + * Returns: %TRUE on success. + * + * Since: 1.16 + */ +typedef gboolean (*GstRTSPClientSendMessagesFunc) (GstRTSPClient *client, + GstRTSPMessage *messages, + guint n_messages, + gboolean close, + gpointer user_data); + /** * GstRTSPClient: * @@ -195,6 +216,12 @@ void gst_rtsp_client_set_send_func (GstRTSPClient *client, gpointer user_data, GDestroyNotify notify); +GST_RTSP_SERVER_API +void gst_rtsp_client_set_send_messages_func (GstRTSPClient *client, + GstRTSPClientSendMessagesFunc func, + gpointer user_data, + GDestroyNotify notify); + GST_RTSP_SERVER_API GstRTSPResult gst_rtsp_client_handle_message (GstRTSPClient *client, GstRTSPMessage *message); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index b9d2e7f286..11612578b4 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2480,12 +2480,12 @@ send_tcp_message (GstRTSPStream * stream, gint idx) buffer = gst_sample_get_buffer (sample); buffer_list = gst_sample_get_buffer_list (sample); - /* We will get one message-sent notification per message, - * i.e. per buffer that is actually sent out */ + /* We will get one message-sent notification per buffer or + * complete buffer-list. We handle each buffer-list as a unit */ if (buffer) n_messages += 1; if (buffer_list) - n_messages += gst_buffer_list_length (buffer_list); + n_messages += 1; is_rtp = (idx == 0); From 4be7424de5f6828427231d3f30f2c745d61e0be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 25 Jan 2019 14:22:42 +0200 Subject: [PATCH 1587/1776] rtsp-client: Only allow to set either a send_func or send_messages_func but not both And route all messages through the send_func if no send_messages_func was provided. We otherwise break backwards compatibility. --- gst/rtsp-server/rtsp-client.c | 81 ++++++++--------------------------- 1 file changed, 18 insertions(+), 63 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 020f2fab2c..e48440e72f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -900,8 +900,11 @@ send_message (GstRTSPClient * client, GstRTSPContext * ctx, 0, ctx, message); g_mutex_lock (&priv->send_lock); - if (priv->send_func) + if (priv->send_messages_func) { + priv->send_messages_func (client, message, 1, close, priv->send_data); + } else if (priv->send_func) { priv->send_func (client, message, close, priv->send_data); + } g_mutex_unlock (&priv->send_lock); gst_rtsp_message_unset (message); @@ -1173,8 +1176,12 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) g_mutex_unlock (&priv->send_lock); return FALSE; } - if (priv->send_func) + if (priv->send_messages_func) { + ret = + priv->send_messages_func (client, &message, 1, FALSE, priv->send_data); + } else if (priv->send_func) { ret = priv->send_func (client, &message, FALSE, priv->send_data); + } g_mutex_unlock (&priv->send_lock); gst_rtsp_message_unset (&message); @@ -4186,6 +4193,9 @@ gst_rtsp_client_get_connection (GstRTSPClient * client) * * By default, the client will send the messages on the #GstRTSPConnection that * was configured with gst_rtsp_client_attach() was called. + * + * It is only allowed to set either a `send_func` or a `send_messages_func` + * but not both at the same time. */ void gst_rtsp_client_set_send_func (GstRTSPClient * client, @@ -4200,6 +4210,7 @@ gst_rtsp_client_set_send_func (GstRTSPClient * client, priv = client->priv; g_mutex_lock (&priv->send_lock); + g_assert (func == NULL || priv->send_messages_func == NULL); priv->send_func = func; old_notify = priv->send_notify; old_data = priv->send_data; @@ -4225,6 +4236,9 @@ gst_rtsp_client_set_send_func (GstRTSPClient * client, * By default, the client will send the messages on the #GstRTSPConnection that * was configured with gst_rtsp_client_attach() was called. * + * It is only allowed to set either a `send_func` or a `send_messages_func` + * but not both at the same time. + * * Since: 1.16 */ void @@ -4241,6 +4255,7 @@ gst_rtsp_client_set_send_messages_func (GstRTSPClient * client, priv = client->priv; g_mutex_lock (&priv->send_lock); + g_assert (func == NULL || priv->send_func == NULL); priv->send_messages_func = func; old_notify = priv->send_messages_notify; old_data = priv->send_messages_data; @@ -4327,64 +4342,6 @@ gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession * session, return GST_RTSP_OK; } -static gboolean -do_send_message (GstRTSPClient * client, GstRTSPMessage * message, - gboolean close, gpointer user_data) -{ - GstRTSPClientPrivate *priv = client->priv; - guint id = 0; - GstRTSPResult ret; - - /* send the message */ - ret = gst_rtsp_watch_send_message (priv->watch, message, &id); - if (ret != GST_RTSP_OK) - goto error; - - /* if close flag is set, store the seq number so we can wait until it's - * written to the client to close the connection */ - if (close) - priv->close_seq = id; - - if (gst_rtsp_message_get_type (message) == GST_RTSP_MESSAGE_DATA) { - guint8 channel = 0; - GstRTSPResult r; - - r = gst_rtsp_message_parse_data (message, &channel); - if (r != GST_RTSP_OK) { - ret = r; - goto error; - } - - /* check if the message has been queued for transmission in watch */ - if (id) { - /* store the seq number so we can wait until it has been sent */ - GST_DEBUG_OBJECT (client, "wait for message %d, channel %d", id, channel); - set_data_seq (client, channel, id); - } else { - GstRTSPStreamTransport *trans; - - trans = - g_hash_table_lookup (priv->transports, - GINT_TO_POINTER ((gint) channel)); - if (trans) { - GST_DEBUG_OBJECT (client, "emit 'message-sent' signal"); - g_mutex_unlock (&priv->send_lock); - gst_rtsp_stream_transport_message_sent (trans); - g_mutex_lock (&priv->send_lock); - } - } - } - - return ret == GST_RTSP_OK; - - /* ERRORS */ -error: - { - GST_DEBUG_OBJECT (client, "got error %d", ret); - return FALSE; - } -} - static gboolean do_send_messages (GstRTSPClient * client, GstRTSPMessage * messages, guint n_messages, gboolean close, gpointer user_data) @@ -4787,9 +4744,7 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) /* create watch for the connection and attach */ priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs, g_object_ref (client), (GDestroyNotify) client_watch_notify); - gst_rtsp_client_set_send_func (client, do_send_message, - g_source_ref ((GSource *) priv->watch), - (GDestroyNotify) gst_rtsp_watch_unref); + gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); gst_rtsp_client_set_send_messages_func (client, do_send_messages, priv->watch, (GDestroyNotify) gst_rtsp_watch_unref); From afb27f91cfec706d2a4dbf8a6c787504731035a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Wed, 16 Jan 2019 12:59:11 +0100 Subject: [PATCH 1588/1776] rtsp-server: remove recursive behavior Introduce a threadpool to send rtp and rtcp to avoid recursive behavior. --- gst/rtsp-server/rtsp-client.c | 1 - gst/rtsp-server/rtsp-stream.c | 115 +++++++++++++--------------------- gst/rtsp-server/rtsp-stream.h | 3 - 3 files changed, 43 insertions(+), 76 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index e48440e72f..3a839ec8c4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2594,7 +2594,6 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) g_object_ref (trans); add_data_seq (client, ct->interleaved.min); add_data_seq (client, ct->interleaved.max); - gst_rtsp_stream_set_watch_context (stream, priv->watch_context); } /* create and serialize the server transport */ diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 11612578b4..b8759fc77a 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -181,7 +181,7 @@ struct _GstRTSPStreamPrivate GHashTable *ptmap; GstRTSPPublishClockMode publish_clock_mode; - GMainContext *watch_context; + GThreadPool *send_pool; }; #define DEFAULT_CONTROL NULL @@ -298,7 +298,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream) NULL, (GDestroyNotify) gst_caps_unref); priv->ptmap = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) gst_caps_unref); - priv->watch_context = NULL; + priv->send_pool = NULL; } typedef struct _UdpClientAddrInfo UdpClientAddrInfo; @@ -334,6 +334,8 @@ gst_rtsp_stream_finalize (GObject * obj) /* we really need to be unjoined now */ g_return_if_fail (priv->joined_bin == NULL); + if (priv->send_pool) + g_thread_pool_free (priv->send_pool, TRUE, TRUE); if (priv->mcast_addr_v4) gst_rtsp_address_free (priv->mcast_addr_v4); if (priv->mcast_addr_v6) @@ -378,9 +380,6 @@ gst_rtsp_stream_finalize (GObject * obj) g_hash_table_unref (priv->keys); g_hash_table_destroy (priv->ptmap); - if (priv->watch_context) - g_main_context_unref (priv->watch_context); - G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); } @@ -2569,6 +2568,34 @@ send_tcp_message (GstRTSPStream * stream, gint idx) g_mutex_lock (&priv->lock); } +static void +send_thread_main (gpointer data, gpointer user_data) +{ + GstRTSPStream *stream = user_data; + GstRTSPStreamPrivate *priv = stream->priv; + gint idx; + gint i; + + g_mutex_lock (&priv->lock); + do { + idx = -1; + /* iterate from 1 and down, so we prioritize RTCP over RTP */ + for (i = 1; i >= 0; i--) { + if (priv->have_buffer[i]) { + /* send message */ + idx = i; + break; + } + } + + if (idx != -1 && priv->n_outstanding == 0) + send_tcp_message (stream, idx); + } while (idx != -1 && priv->n_outstanding == 0); + + GST_DEBUG_OBJECT (stream, "send thread done"); + g_mutex_unlock (&priv->lock); +} + static GstFlowReturn handle_new_sample (GstAppSink * sink, gpointer user_data) { @@ -2579,6 +2606,12 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) g_mutex_lock (&priv->lock); + if (priv->send_pool == NULL) { + GST_DEBUG_OBJECT (stream, "create thread pool"); + priv->send_pool = + g_thread_pool_new (send_thread_main, user_data, 1, TRUE, NULL); + } + for (i = 0; i < 2; i++) if (GST_ELEMENT_CAST (sink) == priv->appsink[i]) { priv->have_buffer[i] = TRUE; @@ -4360,37 +4393,12 @@ mcast_error: } } -static gboolean -cb_send_tcp_message (GstRTSPStream * stream) -{ - GstRTSPStreamPrivate *priv = stream->priv; - gint idx = -1; - gint i; - - g_mutex_lock (&priv->lock); - - /* iterate from 1 and down, so we prioritize RTCP over RTP */ - for (i = 1; i >= 0; i--) { - if (priv->have_buffer[i]) { - /* send message */ - idx = i; - break; - } - } - - if (idx != -1) - send_tcp_message (stream, idx); - g_mutex_unlock (&priv->lock); - return G_SOURCE_REMOVE; -} - static void on_message_sent (gpointer user_data) { GstRTSPStream *stream = user_data; GstRTSPStreamPrivate *priv = stream->priv; gint idx = -1; - GSource *idle_src; GST_DEBUG_OBJECT (stream, "message send complete"); @@ -4416,24 +4424,12 @@ on_message_sent (gpointer user_data) } if (idx != -1) { - /* When appsink running this callback we want to send as much as we can - * But when idle callback or watch callback is running we will first - * queue an idle probe. This so we prevent a loop to occur were callback - * is sending more data that then call the callback that sends more data - * and so on. If the loop occur then it will starve out handling off - * other events that are handled by watch's context. */ - if (priv->watch_context && g_main_context_is_owner (priv->watch_context)) { - /* underlaying layer is running this callback */ - idle_src = g_idle_source_new (); - g_source_set_callback (idle_src, (GSourceFunc) cb_send_tcp_message, - g_object_ref (stream), g_object_unref); - g_source_attach (idle_src, priv->watch_context); - g_source_unref (idle_src); - } else { - /* appsink is running this callback */ - send_tcp_message (stream, idx); - } + gint dummy; + + GST_DEBUG_OBJECT (stream, "start thread"); + g_thread_pool_push (priv->send_pool, &dummy, NULL); } + g_mutex_unlock (&priv->lock); return; @@ -5802,28 +5798,3 @@ gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream * stream) return res; } - -/** - * gst_rtsp_stream_set_watch_context: - * @stream: a #GstRTSPStream - * @context: a #GMainContext - * - * Sets stream private watch_context. - * - */ -void -gst_rtsp_stream_set_watch_context (GstRTSPStream * stream, - GMainContext * context) -{ - GstRTSPStreamPrivate *priv; - priv = stream->priv; - - g_mutex_lock (&priv->lock); - if (priv->watch_context != NULL) { - g_main_context_unref (priv->watch_context); - priv->watch_context = NULL; - } - if (context) - priv->watch_context = g_main_context_ref (context); - g_mutex_unlock (&priv->lock); -} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 53ad57c942..7910bb05d7 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -354,9 +354,6 @@ void gst_rtsp_stream_set_ulpfec_percentage (GstRTSPStream *stream, GST_RTSP_SERVER_API guint gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream *stream); -GST_RTSP_SERVER_API -void gst_rtsp_stream_set_watch_context (GstRTSPStream * stream, GMainContext * context); - /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object From 7e01dfd151c35868ac679ca12f30caaefa9bbb8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Tue, 19 Feb 2019 09:45:08 +0100 Subject: [PATCH 1589/1776] rtsp-media: Fix multicast use case with common media Use case client 1: SETUP client 1: PLAY client 2: SETUP client 1: TEARDOWN client 2: PLAY client 2: TEARDOWN --- gst/rtsp-server/rtsp-media.c | 6 +- tests/check/gst/client.c | 207 +++++++++++++++++++++++++++++++++++ 2 files changed, 211 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index bfcba34e9c..be98afdf6a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -4434,8 +4434,10 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, /* we just activated the first media, do the playing state change */ if (old_active == 0 && activate) do_state = TRUE; - /* if we have no more active media, do the downward state changes */ - else if (priv->n_active == 0) + /* if we have no more active media and prepare count is not indicate + * that there are new session/sessions ongoing, + * do the downward state changes */ + else if (priv->n_active == 0 && priv->prepare_count <= 1) do_state = TRUE; else do_state = FALSE; diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 6c5240e934..cbe846efcf 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -1238,6 +1238,167 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, g_object_unref (thread_pool); } +/* CASE: media is shared. + * client 1: SETUP ---> + * client 1: PLAY ---> + * client 2: SETUP ---> + * client 1: TEARDOWN ---> + * client 2: PLAY ---> + * client 2: TEARDOWN ---> + */ +static void +mcast_transport_two_clients_teardown_play (const gchar * transport1, + const gchar * expected_transport1, const gchar * transport2, + const gchar * expected_transport2, gboolean bind_mcast_address, + gboolean is_shared) +{ + GstRTSPClient *client1, *client2; + GstRTSPMessage request = { 0, }; + gchar *str; + GstRTSPSessionPool *session_pool; + GstRTSPContext ctx = { NULL }; + GstRTSPContext ctx2 = { NULL }; + GstRTSPMountPoints *mount_points; + GstRTSPMediaFactory *factory; + GstRTSPAddressPool *address_pool; + GstRTSPThreadPool *thread_pool; + gchar *session_id1, *session_id2; + + mount_points = gst_rtsp_mount_points_new (); + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_shared (factory, is_shared); + gst_rtsp_media_factory_set_max_mcast_ttl (factory, 5); + gst_rtsp_media_factory_set_bind_mcast_address (factory, bind_mcast_address); + gst_rtsp_media_factory_set_launch (factory, + "audiotestsrc ! audio/x-raw,rate=44100 ! audioconvert ! rtpL16pay name=pay0"); + address_pool = gst_rtsp_address_pool_new (); + if (is_shared) + fail_unless (gst_rtsp_address_pool_add_range (address_pool, + "233.252.0.1", "233.252.0.1", 5000, 5001, 1)); + else + fail_unless (gst_rtsp_address_pool_add_range (address_pool, + "233.252.0.1", "233.252.0.1", 5000, 5003, 1)); + gst_rtsp_media_factory_set_address_pool (factory, address_pool); + gst_rtsp_media_factory_add_role (factory, "user", + "media.factory.access", G_TYPE_BOOLEAN, TRUE, + "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); + gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); + session_pool = gst_rtsp_session_pool_new (); + thread_pool = gst_rtsp_thread_pool_new (); + + /* client 1 configuration */ + client1 = gst_rtsp_client_new (); + gst_rtsp_client_set_session_pool (client1, session_pool); + gst_rtsp_client_set_mount_points (client1, mount_points); + gst_rtsp_client_set_thread_pool (client1, thread_pool); + + ctx.client = client1; + ctx.auth = gst_rtsp_auth_new (); + ctx.token = + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_context_push_current (&ctx); + + expected_transport = expected_transport1; + + /* client 1 sends SETUP request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport1); + + gst_rtsp_client_set_send_func (client1, test_setup_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client1, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + expected_transport = NULL; + + + /* client 1 sends PLAY request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + gst_rtsp_client_set_send_func (client1, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client1, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + gst_rtsp_context_pop_current (&ctx); + session_id1 = g_strdup (session_id); + + /* client 2 configuration */ + cseq = 0; + client2 = gst_rtsp_client_new (); + gst_rtsp_client_set_session_pool (client2, session_pool); + gst_rtsp_client_set_mount_points (client2, mount_points); + gst_rtsp_client_set_thread_pool (client2, thread_pool); + + ctx2.client = client2; + ctx2.auth = gst_rtsp_auth_new (); + ctx2.token = + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_context_push_current (&ctx2); + + expected_transport = expected_transport2; + + /* client 2 sends SETUP request */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport2); + + gst_rtsp_client_set_send_func (client2, test_setup_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client2, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + expected_transport = NULL; + + session_id2 = g_strdup (session_id); + g_free (session_id); + gst_rtsp_context_pop_current (&ctx2); + + /* the first client sends TEARDOWN request */ + gst_rtsp_context_push_current (&ctx); + session_id = session_id1; + send_teardown (client1); + gst_rtsp_context_pop_current (&ctx); + teardown_client (client1); + + /* the second client sends PLAY request */ + gst_rtsp_context_push_current (&ctx2); + session_id = session_id2; + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + gst_rtsp_client_set_send_func (client2, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client2, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + /* client 2 sends TEARDOWN request */ + send_teardown (client2); + gst_rtsp_context_pop_current (&ctx2); + + teardown_client (client2); + g_object_unref (ctx.auth); + g_object_unref (ctx2.auth); + gst_rtsp_token_unref (ctx.token); + gst_rtsp_token_unref (ctx2.token); + g_object_unref (mount_points); + g_object_unref (session_pool); + g_object_unref (address_pool); + g_object_unref (thread_pool); +} + /* test if two multicast clients can choose different transport settings * CASE: media is shared */ GST_START_TEST @@ -1372,6 +1533,48 @@ GST_START_TEST (test_client_multicast_two_clients_shared_media) GST_END_TEST; +/* test if it's possible to play the shared media, after one of the clients + * has terminated its session. + */ +GST_START_TEST (test_client_multicast_two_clients_shared_media_teardown_play) +{ + const gchar *transport_client_1 = "RTP/AVP;multicast;mode=\"PLAY\""; + const gchar *expected_transport_1 = + "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + + const gchar *transport_client_2 = transport_client_1; + const gchar *expected_transport_2 = expected_transport_1; + + mcast_transport_two_clients_teardown_play (transport_client_1, + expected_transport_1, transport_client_2, expected_transport_2, FALSE, + TRUE); +} + +GST_END_TEST; + +/* test if it's possible to play the shared media, after one of the clients + * has terminated its session. + */ +GST_START_TEST + (test_client_multicast_two_clients_not_shared_media_teardown_play) { + const gchar *transport_client_1 = "RTP/AVP;multicast;mode=\"PLAY\""; + const gchar *expected_transport_1 = + "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + + const gchar *transport_client_2 = transport_client_1; + const gchar *expected_transport_2 = + "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; + + mcast_transport_two_clients_teardown_play (transport_client_1, + expected_transport_1, transport_client_2, expected_transport_2, FALSE, + FALSE); +} + +GST_END_TEST; + /* test if two multicast clients get the different transport settings: the first client * requests the specific transport configuration while the second client lets * the server select the multicast address and the ports. @@ -1543,6 +1746,10 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_transport_specific_two_clients_shared_media_same_transport); tcase_add_test (tc, test_client_multicast_two_clients_shared_media); + tcase_add_test (tc, + test_client_multicast_two_clients_shared_media_teardown_play); + tcase_add_test (tc, + test_client_multicast_two_clients_not_shared_media_teardown_play); tcase_add_test (tc, test_client_multicast_two_clients_first_specific_transport_shared_media); tcase_add_test (tc, From 14d0b77df67c0beff0a4095ecacceaedd28143dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 26 Feb 2019 11:58:53 +0000 Subject: [PATCH 1590/1776] Release 1.15.2 --- ChangeLog | 101 ++++++++++++++ NEWS | 307 +++++++++++++++++++++++++++++-------------- RELEASE | 2 +- configure.ac | 12 +- gst-rtsp-server.doap | 10 ++ meson.build | 2 +- 6 files changed, 330 insertions(+), 104 deletions(-) diff --git a/ChangeLog b/ChangeLog index 445134e0d6..0fbd9497f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,104 @@ +=== release 1.15.2 === + +2019-02-26 11:58:53 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + * meson.build: + Release 1.15.2 + +2019-02-19 09:45:08 +0100 Göran Jönsson + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/client.c: + rtsp-media: Fix multicast use case with common media + Use case + client 1: SETUP + client 1: PLAY + client 2: SETUP + client 1: TEARDOWN + client 2: PLAY + client 2: TEARDOWN + +2019-01-16 12:59:11 +0100 Göran Jönsson + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + rtsp-server: remove recursive behavior + Introduce a threadpool to send rtp and rtcp to avoid recursive behavior. + +2019-01-25 14:22:42 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Only allow to set either a send_func or send_messages_func but not both + And route all messages through the send_func if no send_messages_func + was provided. + We otherwise break backwards compatibility. + +2018-09-17 22:18:46 +0300 Sebastian Dröge + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-stream.c: + rtsp-client: Add support for sending buffer lists directly + Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/29 + +2018-06-27 12:17:07 +0200 Sebastian Dröge + + * docs/libs/gst-rtsp-server-sections.txt: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-sink/gstrtspclientsink.c: + rtsp-server: Add support for buffer lists + This adds new functions for passing buffer lists through the different + layers without breaking API/ABI, and enables the appsink to actually + provide buffer lists. + This should already reduce CPU usage and potentially context switches a + bit by passing a whole buffer list from the appsink instead of + individual buffers. As a next step it would be necessary to + a) Add support for a vector of data for the GstRTSPMessage body + b) Add support for sending multiple messages at once to the + GstRTSPWatch and let it be handled internally + c) Adding API to GOutputStream that works like writev() + Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/29 + +2018-12-04 14:12:04 +0100 Benjamin Berg + + * gst/rtsp-server/rtsp-client.c: + client: Fix crash in close handler + The close handler could trigger a crash because it invalidated the + watch_context while still leaving a source attached to it which would be + cleaned up at a later point. + +2019-01-29 14:42:35 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Use cached address when allocating sockets + If an address/port was previously decided upon (ex: multicast in the + SDP), then use that instead of re-creating another one + Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/57 + +2018-12-27 11:28:17 +0100 Lars Wiréen + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Fix race codition in finish_unprepare + The previous fix for race condition around finish_unprepare where the + function could be called twice assumed that the status wouldn't change + during execution of the function. This assumption is incorrect as the + state may change, for example if an error message arrives from the + pipeline bus. + Instead a flag keeping track on whether the finish_unprepare function + is currently executing is introduced and checked. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/59 + === release 1.15.1 === 2019-01-17 02:26:48 +0000 Tim-Philipp Müller diff --git a/NEWS b/NEWS index 1e860c47a6..6457a5d996 100644 --- a/NEWS +++ b/NEWS @@ -15,7 +15,7 @@ the git master branch and which will eventually result in 1.16. See https://gstreamer.freedesktop.org/releases/1.16/ for the latest version of this document. -_Last updated: Monday 14 January 2019, 13:00 UTC (log)_ +_Last updated: Monday 25 January 2019, 15:00 UTC (log)_ Introduction @@ -24,8 +24,8 @@ The GStreamer team is proud to announce a new major feature release in the stable 1.x API series of your favourite cross-platform multimedia framework! -As always, this release is again packed with new features, bug fixes and -other improvements. +As always, this release is again packed with many new features, bug +fixes and other improvements. Highlights @@ -40,7 +40,7 @@ Highlights - Support for Closed Captions and other Ancillary Data in video -- Spport for planar (non-interleaved) raw audio +- Support for planar (non-interleaved) raw audio - GstVideoAggregator, compositor and OpenGL mixer elements are now in -base @@ -98,14 +98,17 @@ Noteworthy new API to process the media in a live pipeline before it reaches the sink. This is on top of the systemic latency that is normally reported by the latency query. This defaults to 20ms and should make pipelines - such as “v4lsrc ! xvimagesink” not claim that all frames are late in - the QoS events. Ideally, this should replace max_lateness for most - applications. + such as v4l2src ! xvimagesink not claim that all frames are late in + the QoS events. Ideally, this should replace the "max-lateness" + property for most applications. - RTCP Extended Reports (XR) parsing according to RFC 3611: Loss/Duplicate RLE, Packet Receipt Times, Receiver Reference Time, Delay since the last Receiver (DLRR), Statistics Summary, and VoIP - Metrics reports. + Metrics reports. This only provides the ability to parse such + packets, generation of XR packets is not supported yet and XR + packets are not automatically parsed by rtpbin / rtpsession but must + be actively handled by the application. - a new mode for interlaced video was added where each buffer carries a single field of interlaced video, with buffer flags indicating @@ -146,9 +149,10 @@ or planar arrangement in memory would look like |LEFT|LEFT|LEFT| and |RIGHT|RIGHT|RIGHT| residing in separate memory chunks or separated by some padding. -GStreamer has always had signalling for non-interleaved audio, but it -was never actually properly implemented in any elements. audioconvert -would advertise support for it, but wasn’t actually able to handle it. +GStreamer has always had signalling for non-interleaved audio since +version 1.0, but it was never actually properly implemented in any +elements. audioconvert would advertise support for it, but wasn’t +actually able to handle it correctly. With this release we now have full support for non-interleaved audio as well, which means more efficient integration with external APIs that @@ -177,18 +181,18 @@ The video support library has gained support for detecting and extracting Ancillary Data from videos as per the SMPTE S291M specification, including: -- a VBI (Video Blanking Interval) parser that can detect and extract - Ancillary Data from Vertical Blanking Interval lines of component - signals. This is currently supported for videos in v210 and UYVY - format. +- a VBI (Vertical Blanking Interval) parser that can detect and + extract Ancillary Data from Vertical Blanking Interval lines of + component signals. This is currently supported for videos in v210 + and UYVY format. - a new GstMeta for closed captions: GstVideoCaptionMeta. This supports the two types of closed captions, CEA-608 and CEA-708, along with the four different ways they can be transported (other systems are a superset of those). -- a VBI (Video Blanking Interval) encoder for writing ancillary data - to the Vertical Blanking Interval lines of component signals. +- a VBI (Vertical Blanking Interval) encoder for writing ancillary + data to the Vertical Blanking Interval lines of component signals. The new closedcaption plugin in gst-plugins-bad then makes use of all this new infrastructure and provides the following elements: @@ -222,6 +226,9 @@ support: - playbin and playbin3 learned how to autoplug CEA 608/708 CC overlay elements +- the externally maintained ajavideosrc element for AJA capture cards + has support for extracting closed captions + The rsclosedcaption plugin in the Rust plugins collection includes a MacCaption (MCC) file parser and encoder. @@ -239,7 +246,7 @@ New Elements - gloverlaycompositor: New OpenGL-based compositor element that flattens any overlays from GstVideoOverlayCompositionMetas into the - video stream. + video stream. This element is also always part of glimagesink. - glalpha: New element that adds an alpha channel to a video stream. The values of the alpha channel can either be set to a constant or @@ -248,7 +255,7 @@ New Elements done in floating point so results may not be identical to the output of the existing alpha element. -- rtpfunnel funnels together rtp-streams into a single session. Use +- rtpfunnel funnels together RTP streams into a single session. Use cases include multiplexing and bundle. webrtcbin uses it to implement BUNDLE support. @@ -264,10 +271,12 @@ New Elements WPE - Two new OpenCV-based elements: cameracalibrate and cameraundistort - who can communicate to figure out distortion correction parameters + that can communicate to figure out distortion correction parameters for a camera and correct for the distortion. -- new sctp plugin based on usrsctp with sctpenc and sctpdec elements +- New sctp plugin based on usrsctp with sctpenc and sctpdec elements. + These elements are used inside webrtcbin for implementing data + channels. New element features and additions @@ -348,12 +357,12 @@ New element features and additions - rtspsrc now allows applications to send RTSP SET_PARAMETER and GET_PARAMETER requests using action signals. -- rtspsrc also has a small (100ms) configurable teardown delay by - default to try and make sure an RTSP TEARDOWN request gets sent out - when the source element shuts down. This will block the downward - PAUSED to READY state change for a short time, but can be unset - where it’s a problem. Some servers only allow a limited number of - concurren clients, so if no proper TEARDOWN is sent clients may have +- rtspsrc has a small (100ms) configurable teardown delay by default + to try and make sure an RTSP TEARDOWN request gets sent out when the + source element shuts down. This will block the downward PAUSED to + READY state change for a short time, but can be disabled where it’s + a problem. Some servers only allow a limited number of concurrent + clients, so if no proper TEARDOWN is sent new clients may have problems connecting to the server for a while. - souphttpsrc behaves better with low bitrate streams now. Before it @@ -364,6 +373,7 @@ New element features and additions - filesink: do internal buffering to avoid performance regression with small writes since we bypass libc buffering by using writev() + instead of fwrite() - identity: add "eos-after" property and fix "error-after" property when the element is reused @@ -405,9 +415,9 @@ New element features and additions relays (TURN servers). - The removesilence element has received various new features and - properties, such as a - "threshold"1 property, detecting silence only after minimum silence time/buffers, a“silent”property to control bus message notifications as well as a“squash”` - property. + properties, such as a "threshold" property, detecting silence only + after minimum silence time/buffers, a "silent" property to control + bus message notifications as well as a "squash" property. - AOMedia AV1 decoder gained support for 10/12bit decoding whilst the AV1 encoder supports more image formats and subsamplings now and @@ -430,15 +440,15 @@ Plugin and library moves - The stereo element was moved from -bad into the existing audiofx plugin in -good. If you get duplicate type registration warnings - when upgrading, check that you don’t have a stale gststereo plugin - lying about somewhere. + when upgrading, check that you don’t have a stale stereoplugin lying + about somewhere. GstVideoAggregator, compositor, and OpenGL mixer elements moved from -bad to -base GstVideoAggregator is a new base class for raw video mixers and muxers -and is based on [GstAggregator][aggregator]. It provides defined-latency -mixing of raw video inputs and ensures that the pipeline won’t stall -even if one of the input streams stops producing data. +and is based on GstAggregator. It provides defined-latency mixing of raw +video inputs and ensures that the pipeline won’t stall even if one of +the input streams stops producing data. As part of the move to stabilise the API there were some last-minute API changes and clean-ups, but those should mostly affect internal elements. @@ -456,14 +466,15 @@ would expected in most scenarios. The compositor element has gained support for per-pad blending mode operators (SOURCE, OVER, ADD) which determines what operator to use for blending this pad over the previous ones. This can be used to implement -crossfading. +crossfading and the available operators can be extended in the future as +needed. A number of OpenGL-based video mixer elements (glvideomixer, glmixerbin, glvideomixerelement, glstereomix, glmosaic) which are built on top of GstVideoAggregator have also been moved from -bad to -base now. These elements have been merged into the existing OpenGL plugin, so if you get duplicate type registration warnings when upgrading, check that you -don’t have a stale gstopenglmixers plugin lying about somewhere. +don’t have a stale openglmixers plugin lying about somewhere. Plugin removals @@ -477,11 +488,11 @@ The following plugins have been removed from gst-plugins-bad: plugin. - The acmmp3dec and acmenc plugins for Windows have been removed. ACM - is an ancient legacy API and there was no point in keeping them - around for a licensed mp3 decoder now that mp3 patents have expired - and we have a decoder in -good. We also didn’t ship these in our - cerbero-built Windows packages, so it’s unlikely that they’ll be - missed. + is an ancient legacy API and there was no point in keeping the + plugins around for a licensed MP3 decoder now that the MP3 patents + have expired and we have a decoder in -good. We also didn’t ship + these in our cerbero-built Windows packages, so it’s unlikely that + they’ll be missed. Miscellaneous API additions @@ -506,7 +517,8 @@ Miscellaneous API additions one might need to put such elements into READY state to test if the hardware is present in the system for example. -- protection: Add a new definition for unspecified system protection +- protection: Add a new definition for unspecified system protection, + GST_PROTECTION_UNSPECIFIED_SYSTEM_ID - take functions for various mini objects that didn’t have them yet: gst_query_take(), gst_message_take(), gst_tag_list_take(), @@ -522,11 +534,18 @@ Miscellaneous API additions gst_clear_mini_object(), gst_clear_object() - miniobject: new API gst_mini_object_add_parent() and - gst_mini_object_remove_parent()to set parent pointers on mini objects to ensure correct writability: Every container of miniobjects now needs to store itself as parent in the child object, and remove itself again later. A mini object is then only writable if there is at most one parent, that parent is writable itself, and the reference count of the mini object is 1.GstBuffer(for memories),GstBufferList(for buffers),GstSample(for caps, buffer, bufferlist), andGstVideoOverlayComposition` - were updated accordingly. Without this it was possible to have - e.g. a buffer list with a refcount of 2 used in two places at once - that both modify the same buffer with refcount 1 at the same time - wrongly thinking it is writable even though it’s really not. + gst_mini_object_remove_parent() to set parent pointers on mini + objects to ensure correct writability: Every container of + miniobjects now needs to store itself as parent in the child object, + and remove itself again later. A mini object is then only writable + if there is at most one parent, that parent is writable itself, and + the reference count of the mini object is 1. GstBuffer (for + memories), GstBufferList (for buffers), GstSample (for caps, buffer, + bufferlist), and GstVideoOverlayComposition were updated + accordingly. Without this it was possible to have e.g. a buffer list + with a refcount of 2 used in two places at once that both modify the + same buffer with refcount 1 at the same time wrongly thinking it is + writable even though it’s really not. - poll: add API to watch for POLLPRI and stop treating POLLPRI as a read. This is useful to wait for video4linux events which are @@ -596,7 +615,7 @@ GstPlayer Miscellaneous changes -- As a result of moving to different FFmpeg APIs, encoder and decoder +- As a result of moving to newer FFmpeg APIs, encoder and decoder elements exposed by the GStreamer FFmpeg wrapper plugin (gst-libav) may have seen possibly incompatible changes to property names and/or types, and not all properties exposed might be functional. We are @@ -649,48 +668,48 @@ Tracing framework and debugging improvements object. This is currently limited to pads for GstElements and events for the pads. The output may look like this: - (gdb) gst-print pad.object.parent - GstMatroskaDemux (matroskademux0) { - SinkPad (sink, pull) { + (gdb) gst-print pad.object.parent + GstMatroskaDemux (matroskademux0) { + SinkPad (sink, pull) { + } + SrcPad (video_0, push) { + events: + stream-start: + stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/001:1274058367 + caps: video/x-theora + width: 1920 + height: 800 + pixel-aspect-ratio: 1/1 + framerate: 24/1 + streamheader: < 0x5555557c7d30 [GstBuffer], 0x5555557c7e40 [GstBuffer], 0x7fffe00141d0 [GstBuffer] > + segment: time + rate: 1 + tag: global + container-format: Matroska + } + SrcPad (audio_0, push) { + events: + stream-start: + stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/002:1551204875 + caps: audio/mpeg + mpegversion: 4 + framed: true + stream-format: raw + codec_data: 0x7fffe0014500 [GstBuffer] + level: 2 + base-profile: lc + profile: lc + channels: 2 + rate: 44100 + segment: time + rate: 1 + tag: global + container-format: Matroska + tag: stream + audio-codec: MPEG-4 AAC audio + language-code: en + } } - SrcPad (video_0, push) { - events: - stream-start: - stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/001:1274058367 - caps: video/x-theora - width: 1920 - height: 800 - pixel-aspect-ratio: 1/1 - framerate: 24/1 - streamheader: < 0x5555557c7d30 [GstBuffer], 0x5555557c7e40 [GstBuffer], 0x7fffe00141d0 [GstBuffer] > - segment: time - rate: 1 - tag: global - container-format: Matroska - } - SrcPad (audio_0, push) { - events: - stream-start: - stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/002:1551204875 - caps: audio/mpeg - mpegversion: 4 - framed: true - stream-format: raw - codec_data: 0x7fffe0014500 [GstBuffer] - level: 2 - base-profile: lc - profile: lc - channels: 2 - rate: 44100 - segment: time - rate: 1 - tag: global - container-format: Matroska - tag: stream - audio-codec: MPEG-4 AAC audio - language-code: en - } - } - gst_structure_to_string() now serialises the actual value of pointers when serialising GstStructures instead of claiming they’re @@ -704,10 +723,10 @@ Tools - gst-inspect-1.0 has coloured output now and will automatically use a pager if the output does not fit on a page. This only works in a - unix environment and if the output is not piped. If you don’t like - the colours you can disable them by setting the - GST_INSPECT_NO_COLORS=1 environment variable or passing the - --no-colors command line option. + UNIX environment and if the output is not piped, and on Windows 10 + build 16257 or newer. If you don’t like the colours you can disable + them by setting the GST_INSPECT_NO_COLORS=1 environment variable or + passing the --no-color command line option. GStreamer RTSP server @@ -736,6 +755,29 @@ GStreamer VAAPI - this section will be filled in in due course +GStreamer OMX + +- Add support of NV16 format to video encoders input. + +- Video decoders now handle the ALLOCATION query to tell upstream + about the number of buffers they require. Video encoders will also + use this query to adjust their number of allocated buffers + preventing starvation when using dynamic buffer mode. + +- The OMX_PERFORMANCE debug category has been renamed to OMX_API_TRACE + and can now be used to track a widder variety of interactions + between OMX and GStreamer. + +- Video encoders will now detect frame rate only changes and will + inform OMX about it rather than doing a full format reset. + +- Various Zynq UltraScale+ specific improvements: + - Video encoders are now able to import dmabuf from upstream. + - Support for HEVC range extension profiles and more AVC profiles. + - We can now request video encoders to generate an IDR using the + force key unit event. + + GStreamer Editing Services and NLE - this section will be filled in in due course @@ -858,7 +900,7 @@ Added value per tag. The old ::iter_tag_list() function was renamed to ::iter_generic() and still provides access to each value for a tag - Bus::iter() and Bus::iter_timed() iterators around the corresponding - ::pop*() functions + ::pop\*() functions - serde serialization of Value can also handle Buffer now @@ -995,11 +1037,78 @@ Build and Dependencies - New sctp plugin based on usrsctp (for WebRTC data channels) +Cerbero + +Cerbero is a meta build system used to build GStreamer plus dependencies +on platforms where dependencies are not readily available, such as +Windows, Android, iOS and macOS. + +Cerbero has seen a number of improvements: + +- Cerbero has been ported to Python 3 and requires Python 3.5 or newer + now + +- Source tarballs are now protected by checksums in the recipes to + guard against download errors and malicious takeover of projects or + websites. In addition, downloads are only allowed via secure + transports now and plain HTTP, FTP and git:// transports are not + allowed anymore. + +- There is now a new fetch-bootstrap command which downloads sources + required for bootstrapping, with an optional --build-tools-only + argument to match the bootstrap --build-tools-only command. + +- The bootstrap, build, package and bundle-source commands gained a + new --offline switch that ensures that only sources from the cache + are used and never downloaded via the network. This is useful in + combination with the fetch and fetch-bootstrap commands that acquire + sources ahead of time before any build steps are executed. This + allows more control over the sources used and when sources are + updated, and is particularly useful for build environments that + don’t have network access. + +- bootstrap --assume-yes will automatically say ‘yes’ to any + interactive prompts during the bootstrap stage, such as those from + apt-get or yum. + +- bootstrap --system-only will only bootstrap the system without build + tools. + +- Manifest support: The build manifest can be used in continuous + integration (CI) systems to fixate the Git revision of certain + projects so that all builds of a pipeline are on the same reference. + This is used in GStreamer’s gitlab CI for example. It can also be + used in order to re-produce a specific build. To set a manifest, you + can set manifest = 'my_manifest.xml' in your configuration file, or + use the --manifest command line option. The command line option will + take precendence over anything specific in the configuration file. + +- The new build-deps command can be used to build only the + dependencies of a recipe, without the recipe itself. + +- new --list-variants command to list available variants + +- variants can now be set on the command line via the -v option as a + comma-separated list. This overrides any variants set in any + configuration files. + +- new qt5, intelmsdk and nvidia variants for enabling Qt5 and hardware + codec support. See the Enabling Optional Features with Variants + section in the Cerbero documentation for more details how to enable + and use these variants. + +- A new -t / --timestamp command line switch makes commands print + timestamps + Platform-specific changes and improvements Android +- toolchain: update compiler to clang and NDKr18. NDK r18 removed the + armv5 target and only has Android platforms that target at least + armv7 so the armv5 target is not useful anymore. + - The way that GIO modules are named has changed due to upstream GLib natively adding support for loading static GIO modules. This means that any GStreamer application using gnutls for SSL/TLS on the @@ -1010,9 +1119,15 @@ Android library. Look at this commit for the necessary change in the examples. +- various build issues on Android have been fixed. + macOS and iOS -- macOS binaries should be fully relocatable now +- various build issues on iOS have been fixed. + +- the minimum required iOS version is now 9.0. The difference in + adoption between 8.0 and 9.0 is 0.1% and the bump to 9.0 fixes some + build issues. - The way that GIO modules are named has changed due to upstream GLib natively adding support for loading static GIO modules. This means diff --git a/RELEASE b/RELEASE index 3957adc62d..e9f57f9252 100644 --- a/RELEASE +++ b/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-rtsp-server 1.15.1. +This is GStreamer gst-rtsp-server 1.15.2. GStreamer 1.15 is the development branch leading up to the next major stable version which will be 1.16. diff --git a/configure.ac b/configure.ac index 14b026176b..1d965cd77a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.15.1], +AC_INIT([GStreamer RTSP Server Library], [1.15.2], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1501, 0, 1501) +AS_LIBTOOL(GST, 1502, 0, 1502) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.15.1 -GSTPB_REQ=1.15.1 -GSTPG_REQ=1.15.1 -GSTPD_REQ=1.15.1 +GST_REQ=1.15.2 +GSTPB_REQ=1.15.2 +GSTPG_REQ=1.15.2 +GSTPD_REQ=1.15.2 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index a1638d0248..dc8bdb4840 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.15.2 + master + + 2019-02-26 + + + + 1.15.1 diff --git a/meson.build b/meson.build index 2ca3014ee3..e27c6d9475 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.15.1', + version : '1.15.2', meson_version : '>= 0.47', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From f0a986118641b7e2b8d0978803508c7a85a7c93d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 4 Mar 2019 09:13:30 +0000 Subject: [PATCH 1591/1776] Back to development --- NEWS | 8 ++++---- RELEASE | 2 +- configure.ac | 10 +++++----- meson.build | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/NEWS b/NEWS index 6457a5d996..e6f8c3dbe7 100644 --- a/NEWS +++ b/NEWS @@ -4,7 +4,7 @@ GSTREAMER 1.16 RELEASE NOTES GStreamer 1.16 has not been released yet. It is scheduled for release in -January/February 2019. +March 2019. 1.15.x is the unstable development version that is being developed in the git master branch and which will eventually result in 1.16. @@ -15,7 +15,7 @@ the git master branch and which will eventually result in 1.16. See https://gstreamer.freedesktop.org/releases/1.16/ for the latest version of this document. -_Last updated: Monday 25 January 2019, 15:00 UTC (log)_ +_Last updated: Wednesday 27 January 2019, 00:30 UTC (log)_ Introduction @@ -1234,7 +1234,7 @@ the git 1.16 branch, which is a stable branch. 1.16.0 -1.16.0 is scheduled to be released around January/February 2019. +1.16.0 is scheduled to be released in March 2019. Known Issues @@ -1269,6 +1269,6 @@ August/September. ------------------------------------------------------------------------ _These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge._ +_contributions from Sebastian Dröge and Guillaume Desmottes._ _License: CC BY-SA 4.0_ diff --git a/RELEASE b/RELEASE index e9f57f9252..2a5f7c8bdf 100644 --- a/RELEASE +++ b/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-rtsp-server 1.15.2. +This is GStreamer gst-rtsp-server 1.15.2.1. GStreamer 1.15 is the development branch leading up to the next major stable version which will be 1.16. diff --git a/configure.ac b/configure.ac index 1d965cd77a..16b91f3838 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.15.2], +AC_INIT([GStreamer RTSP Server Library], [1.15.2.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -56,10 +56,10 @@ dnl sets GST_LT_LDFLAGS AS_LIBTOOL(GST, 1502, 0, 1502) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.15.2 -GSTPB_REQ=1.15.2 -GSTPG_REQ=1.15.2 -GSTPD_REQ=1.15.2 +GST_REQ=1.15.2.1 +GSTPB_REQ=1.15.2.1 +GSTPG_REQ=1.15.2.1 +GSTPD_REQ=1.15.2.1 dnl *** autotools stuff **** diff --git a/meson.build b/meson.build index e27c6d9475..2eb2e35916 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.15.2', + version : '1.15.2.1', meson_version : '>= 0.47', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 1fd49d36d16ce3dfcb5cf52884c5f9ef3cbcf9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Thu, 14 Mar 2019 07:37:26 +0100 Subject: [PATCH 1592/1776] rtsp-media: Handle set state when preparing. Handle the situation when a call to gst_rtsp_media_set_state is done when media status is preparing. Also add unit test for this scenario. The unit test simulate on a media level when two clients share a (live) media. Both clients have done SETUP and got responses. Now client 1 is doing play and client 2 is just closing the connection. Then without patch there are a problem when client1 is calling gst_rtsp_media_unsuspend in handle_play_request. And client2 is doing closing connection we can end up in a call to gst_rtsp_media_set_state when priv->status == GST_RTSP_MEDIA_STATUS_PREPARING and all the logic for shut down media is jumped over . With this patch and this scenario we wait until priv->status == GST_RTSP_MEDIA_STATUS_PREPARED and then continue to execute after that and now we will execute the logic for shut down media. --- gst/rtsp-server/rtsp-media.c | 7 ++ tests/check/gst/media.c | 168 +++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index be98afdf6a..719f284e9b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -4376,6 +4376,13 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, priv = media->priv; g_rec_mutex_lock (&priv->state_lock); + + if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING + && gst_rtsp_media_is_shared (media)) { + g_rec_mutex_unlock (&priv->state_lock); + gst_rtsp_media_get_status (media); + g_rec_mutex_lock (&priv->state_lock); + } if (priv->status == GST_RTSP_MEDIA_STATUS_ERROR) goto error_status; if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED && diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 20527fcd98..5ae704ce9b 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -402,6 +402,173 @@ GST_START_TEST (test_media_prepare) GST_END_TEST; +enum _SyncState +{ + SYNC_STATE_INIT, + SYNC_STATE_1, + SYNC_STATE_2, + SYNC_STATE_RACE +}; +typedef enum _SyncState SyncState; + +struct _help_thread_data +{ + GstRTSPThreadPool *pool; + GstRTSPMedia *media; + GstRTSPTransport *transport; + GstRTSPStream *stream; + SyncState *state; + GMutex *sync_mutex; + GCond *sync_cond; +}; +typedef struct _help_thread_data help_thread_data; + +static gpointer +help_thread_main (gpointer user_data) +{ + help_thread_data *data; + GstRTSPThread *thread; + GPtrArray *transports; + GstRTSPStreamTransport *stream_transport; + + data = (help_thread_data *) user_data; + GST_INFO ("Another thread sharing media"); + + /* wait SYNC_STATE_1 */ + g_mutex_lock (data->sync_mutex); + while (*data->state < SYNC_STATE_1) + g_cond_wait (data->sync_cond, data->sync_mutex); + g_mutex_unlock (data->sync_mutex); + + /* prepare */ + thread = gst_rtsp_thread_pool_get_thread (data->pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_unless (gst_rtsp_media_prepare (data->media, thread)); + + /* set SYNC_STATE_2 */ + g_mutex_lock (data->sync_mutex); + *data->state = SYNC_STATE_2; + g_cond_signal (data->sync_cond); + g_mutex_unlock (data->sync_mutex); + + /* wait SYNC_STATE_RACE */ + g_mutex_lock (data->sync_mutex); + while (*data->state < SYNC_STATE_RACE) + g_cond_wait (data->sync_cond, data->sync_mutex); + g_mutex_unlock (data->sync_mutex); + + /* set state */ + transports = g_ptr_array_new_with_free_func (g_object_unref); + fail_unless (transports != NULL); + stream_transport = + gst_rtsp_stream_transport_new (data->stream, data->transport); + fail_unless (stream_transport != NULL); + g_ptr_array_add (transports, stream_transport); + fail_unless (gst_rtsp_media_set_state (data->media, GST_STATE_NULL, + transports)); + + /* clean up */ + GST_INFO ("Thread exit"); + fail_unless (gst_rtsp_media_unprepare (data->media)); + g_ptr_array_unref (transports); + return NULL; +} + +GST_START_TEST (test_media_shared_race_test_unsuspend_vs_set_state_null) +{ + help_thread_data data; + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + GThread *sharing_media_thread; + GstRTSPTransport *transport; + GstRTSPStream *stream; + SyncState state = SYNC_STATE_INIT; + GMutex sync_mutex; + GCond sync_cond; + + g_mutex_init (&sync_mutex); + g_cond_init (&sync_cond); + + pool = gst_rtsp_thread_pool_new (); + + /* test non-reusable media first */ + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_shared (factory, TRUE); + fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); + + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc ! rtpvrawpay pt=96 name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + fail_unless (GST_IS_RTSP_MEDIA (media)); + fail_unless (gst_rtsp_media_n_streams (media) == 1); + gst_rtsp_media_set_suspend_mode (media, GST_RTSP_SUSPEND_MODE_RESET); + + stream = gst_rtsp_media_get_stream (media, 0); + fail_unless (stream != NULL); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + fail_unless (gst_rtsp_media_prepare (media, thread)); + + /* help thread */ + data.pool = pool; + data.media = media; + data.stream = stream; + data.state = &state; + data.sync_mutex = &sync_mutex; + data.sync_cond = &sync_cond; + sharing_media_thread = g_thread_new ("new thread", help_thread_main, &data); + fail_unless (sharing_media_thread != NULL); + + /* set state SYNC_STATE_1 */ + g_mutex_lock (&sync_mutex); + state = SYNC_STATE_1; + g_cond_signal (&sync_cond); + g_mutex_unlock (&sync_mutex); + + /* wait SYNC_STATE_2 */ + g_mutex_lock (&sync_mutex); + while (state < SYNC_STATE_2) + g_cond_wait (&sync_cond, &sync_mutex); + g_mutex_unlock (&sync_mutex); + + gst_rtsp_media_suspend (media); + + fail_unless (gst_rtsp_transport_new (&transport) == GST_RTSP_OK); + transport->lower_transport = GST_RTSP_LOWER_TRANS_TCP; + fail_unless (gst_rtsp_stream_complete_stream (stream, transport)); + data.transport = transport; + + /* set state SYNC_STATE_RACE let the race begin unsuspend <-> set state GST_STATE_NULL */ + g_mutex_lock (&sync_mutex); + state = SYNC_STATE_RACE; + g_cond_signal (&sync_cond); + g_mutex_unlock (&sync_mutex); + + fail_unless (gst_rtsp_media_unsuspend (media)); + + /* sync end of other thread */ + g_thread_join (sharing_media_thread); + + /* clean up */ + g_cond_clear (&sync_cond); + g_mutex_clear (&sync_mutex); + fail_unless (gst_rtsp_media_unprepare (media)); + g_object_unref (media); + gst_rtsp_url_free (url); + g_object_unref (factory); + g_object_unref (pool); + gst_rtsp_thread_pool_cleanup (); +} + +GST_END_TEST; + + #define FLAG_HAVE_CAPS GST_ELEMENT_FLAG_LAST static void on_notify_caps (GstPad * pad, GParamSpec * pspec, GstElement * pay) @@ -663,6 +830,7 @@ rtspmedia_suite (void) tcase_add_test (tc, test_media_seek_one_active_stream); tcase_add_test (tc, test_media); tcase_add_test (tc, test_media_prepare); + tcase_add_test (tc, test_media_shared_race_test_unsuspend_vs_set_state_null); tcase_add_test (tc, test_media_reusable); tcase_add_test (tc, test_media_dyn_prepare); tcase_add_test (tc, test_media_take_pipeline); From 48d7d5846fa14bb167109504f17d2cdc4b24dd32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 21 Mar 2019 11:49:10 +0000 Subject: [PATCH 1593/1776] meson: pass -Wno-unused to compiler if gstreamer debug system is disabled --- meson.build | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/meson.build b/meson.build index 2eb2e35916..d463fb6ccb 100644 --- a/meson.build +++ b/meson.build @@ -156,6 +156,22 @@ if host_machine.system() != 'windows' fallback : ['gstreamer', 'gst_check_dep']) endif +# Disable compiler warnings for unused variables and args if gst debug system is disabled +if gst_dep.type_name() == 'internal' + gst_debug_disabled = not subproject('gstreamer').get_variable('gst_debug') +else + # We can't check that in the case of subprojects as we won't + # be able to build against an internal dependency (which is not built yet) + gst_debug_disabled = cc.has_header_symbol('gst/gstconfig.h', 'GST_DISABLE_GST_DEBUG', dependencies: gst_dep) +endif + +if gst_debug_disabled + message('GStreamer debug system is disabled') + add_project_arguments(cc.get_supported_arguments(['-Wno-unused']), language: 'c') +else + message('GStreamer debug system is enabled') +endif + gir = find_program('g-ir-scanner', required : get_option('introspection')) gnome = import('gnome') build_gir = gir.found() and not meson.is_cross_build() From 6f43461592b43d9d6e73d86d595813f73e7387ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 23 Mar 2019 19:15:48 +0000 Subject: [PATCH 1594/1776] g-i: silence 'nested extern' compiler warnings when building scanner binary We need a nested extern in our init section for the scanner binary so we can call gst_init to make sure GStreamer types are initialised (they are not all lazy init via get_type functions, but some are in exported variables). There doesn't seem to be any other mechanism to achieve this, so just remove that warning, it's not important at all. --- meson.build | 1 - 1 file changed, 1 deletion(-) diff --git a/meson.build b/meson.build index d463fb6ccb..8c84c319c4 100644 --- a/meson.build +++ b/meson.build @@ -118,7 +118,6 @@ warning_flags = [ '-Wformat-security', '-Wold-style-definition', '-Waggregate-return', - '-Wnested-externs', '-Winit-self', '-Wmissing-include-dirs', '-Waddress', From 0becf0b67d2050c01fc65f09a058473173375e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 23 Mar 2019 19:16:17 +0000 Subject: [PATCH 1595/1776] g-i: pass --quiet to g-ir-scanner This suppresses the annoying 'g-ir-scanner: link: cc ..' output that we get even if everything works just fine. We still get g-ir-scanner warnings and compiler warnings if we pass this option. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 8c84c319c4..4dea4fb4cf 100644 --- a/meson.build +++ b/meson.build @@ -178,7 +178,7 @@ gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**);' + 'g_setenv("GST_REGISTRY_1.0", "@0@", TRUE);'.format(meson.current_build_dir() + '/gir_empty_registry.reg') + \ 'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \ 'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \ - 'gst_init(NULL,NULL);' ] + 'gst_init(NULL,NULL);', '--quiet'] pkgconfig = import('pkgconfig') plugins_pkgconfig_install_dir = join_paths(plugins_install_dir, 'pkgconfig') From a9d3bcc03ed59d9c1b463503acbbe1df5a7be21a Mon Sep 17 00:00:00 2001 From: Erlend Eriksen Date: Thu, 28 Mar 2019 00:27:37 +0100 Subject: [PATCH 1596/1776] session pool: fix missing klass-> in klass->create_session --- gst/rtsp-server/rtsp-session-pool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index b09db93d45..43ae44e9f2 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -386,7 +386,7 @@ gst_rtsp_session_pool_create (GstRTSPSessionPool * pool) } else { /* not found, create session and insert it in the pool */ if (klass->create_session) - result = create_session (pool, id); + result = klass->create_session (pool, id); if (result == NULL) goto too_many_sessions; /* take additional ref for the pool */ From d09b7c8e4f33f45d0c227d1b2c25f8686729357d Mon Sep 17 00:00:00 2001 From: Ulf Olsson Date: Wed, 10 Apr 2019 10:32:53 +0200 Subject: [PATCH 1597/1776] rtsp-stream: Add support for GCM (RFC 7714) Follow-up to !198 --- gst/rtsp-server/rtsp-stream.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index b8759fc77a..e6721a2d8a 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -5424,6 +5424,7 @@ mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy) /* now override the defaults with what is in the Security Policy */ if (sp != NULL) { guint len; + guint enc_alg = GST_MIKEY_ENC_AES_CM_128; /* collect all the params and go over them */ len = gst_mikey_payload_sp_get_n_params (sp); @@ -5433,14 +5434,18 @@ mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy) switch (param->type) { case GST_MIKEY_SP_SRTP_ENC_ALG: + enc_alg = param->val[0]; switch (param->val[0]) { - case 0: + case GST_MIKEY_ENC_NULL: srtp_cipher = "null"; break; - case 2: - case 1: + case GST_MIKEY_ENC_AES_CM_128: + case GST_MIKEY_ENC_AES_KW_128: srtp_cipher = "aes-128-icm"; break; + case GST_MIKEY_ENC_AES_GCM_128: + srtp_cipher = "aes-128-gcm"; + break; default: break; } @@ -5448,10 +5453,20 @@ mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy) case GST_MIKEY_SP_SRTP_ENC_KEY_LEN: switch (param->val[0]) { case AES_128_KEY_LEN: - srtp_cipher = "aes-128-icm"; + if (enc_alg == GST_MIKEY_ENC_AES_CM_128 || + enc_alg == GST_MIKEY_ENC_AES_KW_128) { + srtp_cipher = "aes-128-icm"; + } else if (enc_alg == GST_MIKEY_ENC_AES_GCM_128) { + srtp_cipher = "aes-128-gcm"; + } break; case AES_256_KEY_LEN: - srtp_cipher = "aes-256-icm"; + if (enc_alg == GST_MIKEY_ENC_AES_CM_128 || + enc_alg == GST_MIKEY_ENC_AES_KW_128) { + srtp_cipher = "aes-256-icm"; + } else if (enc_alg == GST_MIKEY_ENC_AES_GCM_128) { + srtp_cipher = "aes-256-gcm"; + } break; default: break; @@ -5459,11 +5474,10 @@ mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy) break; case GST_MIKEY_SP_SRTP_AUTH_ALG: switch (param->val[0]) { - case 0: + case GST_MIKEY_MAC_NULL: srtp_auth = "null"; break; - case 2: - case 1: + case GST_MIKEY_MAC_HMAC_SHA_1_160: srtp_auth = "hmac-sha1-80"; break; default: From cd467121623bf16a4a6eb47029f147dceb1e2be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 11 Apr 2019 00:35:55 +0100 Subject: [PATCH 1598/1776] Release 1.15.90 --- ChangeLog | 78 +++++++++++++++++++++++++++++++++++ NEWS | 98 +++++++++++++++++++++++++------------------- RELEASE | 2 +- configure.ac | 12 +++--- gst-rtsp-server.doap | 10 +++++ meson.build | 2 +- 6 files changed, 152 insertions(+), 50 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0fbd9497f1..6452861dc1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,81 @@ +=== release 1.15.90 === + +2019-04-11 00:35:55 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + * meson.build: + Release 1.15.90 + +2019-04-10 10:32:53 +0200 Ulf Olsson + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Add support for GCM (RFC 7714) + Follow-up to !198 + +2019-03-28 00:27:37 +0100 Erlend Eriksen + + * gst/rtsp-server/rtsp-session-pool.c: + session pool: fix missing klass-> in klass->create_session + +2019-03-23 19:16:17 +0000 Tim-Philipp Müller + + * meson.build: + g-i: pass --quiet to g-ir-scanner + This suppresses the annoying 'g-ir-scanner: link: cc ..' output + that we get even if everything works just fine. + We still get g-ir-scanner warnings and compiler warnings if + we pass this option. + +2019-03-23 19:15:48 +0000 Tim-Philipp Müller + + * meson.build: + g-i: silence 'nested extern' compiler warnings when building scanner binary + We need a nested extern in our init section for the scanner binary + so we can call gst_init to make sure GStreamer types are initialised + (they are not all lazy init via get_type functions, but some are in + exported variables). There doesn't seem to be any other mechanism to + achieve this, so just remove that warning, it's not important at all. + +2019-03-21 11:49:10 +0000 Tim-Philipp Müller + + * meson.build: + meson: pass -Wno-unused to compiler if gstreamer debug system is disabled + +2019-03-14 07:37:26 +0100 Göran Jönsson + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/media.c: + rtsp-media: Handle set state when preparing. + Handle the situation when a call to gst_rtsp_media_set_state is done + when media status is preparing. + Also add unit test for this scenario. + The unit test simulate on a media level when two clients share a (live) + media. + Both clients have done SETUP and got responses. Now client 1 is doing + play and client 2 is just closing the connection. + Then without patch there are a problem when + client1 is calling gst_rtsp_media_unsuspend in handle_play_request. + And client2 is doing closing connection we can end up in a call + to gst_rtsp_media_set_state when + priv->status == GST_RTSP_MEDIA_STATUS_PREPARING and all the logic for + shut down media is jumped over . + With this patch and this scenario we wait until + priv->status == GST_RTSP_MEDIA_STATUS_PREPARED and then continue to + execute after that and now we will execute the logic for + shut down media. + +2019-03-04 09:13:30 +0000 Tim-Philipp Müller + + * NEWS: + * RELEASE: + * configure.ac: + * meson.build: + Back to development + === release 1.15.2 === 2019-02-26 11:58:53 +0000 Tim-Philipp Müller diff --git a/NEWS b/NEWS index e6f8c3dbe7..16402a590e 100644 --- a/NEWS +++ b/NEWS @@ -4,7 +4,7 @@ GSTREAMER 1.16 RELEASE NOTES GStreamer 1.16 has not been released yet. It is scheduled for release in -March 2019. +April 2019. 1.15.x is the unstable development version that is being developed in the git master branch and which will eventually result in 1.16. @@ -15,7 +15,7 @@ the git master branch and which will eventually result in 1.16. See https://gstreamer.freedesktop.org/releases/1.16/ for the latest version of this document. -_Last updated: Wednesday 27 January 2019, 00:30 UTC (log)_ +_Last updated: Wednesday 10 April 2019, 00:50 UTC (log)_ Introduction @@ -648,6 +648,15 @@ OpenGL integration import DMABUF FDs and also directly pass the pixel format, relying on the GPU to do the conversion. +- The OpenGL library no longer restores the OpenGL viewport. This is a + performance optimization to not require performing multiple + expensive glGet*() function calls per frame. This affects any + application or plugin use of the following functions and objects: + - glcolorconvert library object (not the element) + - glviewconvert library object (not the element) + - gst_gl_framebuffer_draw_to_texture() + - custom GstGLWindow implementations + Tracing framework and debugging improvements @@ -1164,47 +1173,51 @@ Windows Contributors -Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, Alex Ashley, -Alexey Chernov, Alicia Boya García, Amit Pandya, Andoni Morales -Alastruey, Andreas Frisch, Andre McCurdy, Andy Green, Anthony Violo, -Antoine Jacoutot, Antonio Ospite, Arun Raghavan, Aurelien Jarno, +Aaron Boxer, Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, +Alex Ashley, Alexey Chernov, Alicia Boya García, Amit Pandya, Andoni +Morales Alastruey, Andreas Frisch, Andre McCurdy, Andy Green, Anthony +Violo, Antoine Jacoutot, Antonio Ospite, Arun Raghavan, Aurelien Jarno, Aurélien Zanelli, ayaka, Bananahemic, Bastian Köcher, Branko Subasic, -Brendan Shanks, Carlos Rafael Giani, Christoph Reiter, Corentin Noël, -Daeseok Youn, Daniel Drake, Daniel Klamt, Dardo D Kleiner, David Ing, -David Svensson Fors, Devarsh Thakkar, Dimitrios Katsaros, Edward Hervey, -Emilio Pozuelo Monfort, Enrique Ocaña González, Ezequiel Garcia, Fabien -Dessenne, Fabrizio Gennari, Florent Thiéry, Francisco Velazquez, -Freyr666, Garima Gaur, Gary Bisson, George Kiagiadakis, Georg Lippitsch, -Georg Ottinger, Geunsik Lim, Göran Jönsson, Guillaume Desmottes, H1Gdev, -Haihao Xiang, Haihua Hu, Harshad Khedkar, Havard Graff, He Junyan, -Hoonhee Lee, Hosang Lee, Hyunjun Ko, Ingo Randolf, Iñigo Huguet, James -Stevenson, Jan Alexander Steffens, Jan Schmidt, Jerome Laheurte, Jimmy -Ohn, Joakim Johansson, Jochen Henneberg, Johan Bjäreholt, John-Mark -Bell, John Nikolaides, Jonathan Karlsson, Jonny Lamb, Jordan Petridis, -Josep Torra, Joshua M. Doe, Jos van Egmond, Juan Navarro, Jun Xie, +Brendan Shanks, Carlos Rafael Giani, Charlie Turner, Christoph Reiter, +Corentin Noël, Daeseok Youn, Damian Vicino, Dan Kegel, Daniel Drake, +Daniel Klamt, Danilo Spinella, Dardo D Kleiner, David Ing, David +Svensson Fors, Devarsh Thakkar, Dimitrios Katsaros, Edward Hervey, +Emilio Pozuelo Monfort, Enrique Ocaña González, Erlend Eriksen, Ezequiel +Garcia, Fabien Dessenne, Fabrizio Gennari, Florent Thiéry, Francisco +Velazquez, Freyr666, Garima Gaur, Gary Bisson, George Kiagiadakis, Georg +Lippitsch, Georg Ottinger, Geunsik Lim, Göran Jönsson, Guillaume +Desmottes, H1Gdev, Haihao Xiang, Haihua Hu, Harshad Khedkar, Havard +Graff, He Junyan, Hoonhee Lee, Hosang Lee, Hyunjun Ko, Ilya Smelykh, +Ingo Randolf, Iñigo Huguet, Jakub Adam, James Stevenson, Jan Alexander +Steffens, Jan Schmidt, Jerome Laheurte, Jimmy Ohn, Joakim Johansson, +Jochen Henneberg, Johan Bjäreholt, John-Mark Bell, John Bassett, John +Nikolaides, Jonathan Karlsson, Jonny Lamb, Jordan Petridis, Josep Torra, +Joshua M. Doe, Jos van Egmond, Juan Navarro, Julian Bouzas, Jun Xie, Junyan He, Justin Kim, Kai Kang, Kim Tae Soo, Kirill Marinushkin, Kyrylo Polezhaiev, Lars Petter Endresen, Linus Svensson, Louis-Francis -Ratté-Boulianne, Luis de Bethencourt, Luz Paz, Lyon Wang, Maciej Wolny, -Marc-André Lureau, Marc Leeman, Marcos Kintschner, Marian Mihailescu, -Marinus Schraal, Mark Nauwelaerts, Marouen Ghodhbane, Martin Kelly, -Matej Knopp, Mathieu Duponchelle, Matteo Valdina, Matthew Waters, -Matthias Fend, memeka, Michael Drake, Michael Gruner, Michael Olbrich, -Michael Tretter, Miguel Paris, Mike Wey, Mikhail Fludkov, Naveen -Cherukuri, Nicola Murino, Nicolas Dufresne, Niels De Graef, Nirbheek -Chauhan, Norbert Wesp, Ognyan Tonchev, Olivier Crête, Omar Akkila, -Patricia Muscalu, Patrick Radizi, Patrik Nilsson, Paul Kocialkowski, Per -Forlin, Peter Körner, Peter Seiderer, Petr Kulhavy, Philippe Normand, -Philippe Renon, Philipp Zabel, Pierre Labastie, Roland Jon, Roman -Sivriver, Rosen Penev, Russel Winder, Sam Gigliotti, Sean-Der, Sebastian -Dröge, Seungha Yang, Sjoerd Simons, Snir Sheriber, Song Bing, Soon, -Thean Siew, Sreerenj Balachandran, Stefan Ringel, Stephane Cerveau, -Stian Selnes, Suhas Nayak, Takeshi Sato, Thiago Santos, Thibault -Saunier, Thomas Bluemel, Tianhao Liu, Tim-Philipp Müller, Tomasz -Andrzejak, Tomislav Tustonić, U. Artie Eoff, Ulf Olsson, Varunkumar -Allagadapa, Víctor Guzmán, Víctor Manuel Jáquez Leal, Vincenzo Bono, -Vineeth T M, Vivia Nikolaidou, Wang Fei, wangzq, Whoopie, Wim Taymans, -Wind Yuan, Wonchul Lee, Xabier Rodriguez Calvar, Xavier Claessens, -Haihao Xiang, Yacine Bandou, Yeongjin Jeong, Yuji Kuwabara, Zeeshan Ali, +Ratté-Boulianne, Lucas Stach, Luis de Bethencourt, Luz Paz, Lyon Wang, +Maciej Wolny, Marc-André Lureau, Marc Leeman, Marco Trevisan (Treviño), +Marcos Kintschner, Marian Mihailescu, Marinus Schraal, Mark Nauwelaerts, +Marouen Ghodhbane, Martin Kelly, Matej Knopp, Mathieu Duponchelle, +Matteo Valdina, Matthew Waters, Matthias Fend, memeka, Michael Drake, +Michael Gruner, Michael Olbrich, Michael Tretter, Miguel Paris, Mike +Wey, Mikhail Fludkov, Naveen Cherukuri, Nicola Murino, Nicolas Dufresne, +Niels De Graef, Nirbheek Chauhan, Norbert Wesp, Ognyan Tonchev, Olivier +Crête, Omar Akkila, Pat DeSantis, Patricia Muscalu, Patrick Radizi, +Patrik Nilsson, Paul Kocialkowski, Per Forlin, Peter Körner, Peter +Seiderer, Petr Kulhavy, Philippe Normand, Philippe Renon, Philipp Zabel, +Pierre Labastie, Piotr Drąg, Roland Jon, Roman Sivriver, Roman Shpuntov, +Rosen Penev, Russel Winder, Sam Gigliotti, Santiago Carot-Nemesio, +Sean-Der, Sebastian Dröge, Seungha Yang, Shi Yan, Sjoerd Simons, Snir +Sheriber, Song Bing, Soon, Thean Siew, Sreerenj Balachandran, Stefan +Ringel, Stephane Cerveau, Stian Selnes, Suhas Nayak, Takeshi Sato, +Thiago Santos, Thibault Saunier, Thomas Bluemel, Tianhao Liu, +Tim-Philipp Müller, Tobias Ronge, Tomasz Andrzejak, Tomislav Tustonić, +U. Artie Eoff, Ulf Olsson, Varunkumar Allagadapa, Víctor Guzmán, Víctor +Manuel Jáquez Leal, Vincenzo Bono, Vineeth T M, Vivia Nikolaidou, Wang +Fei, wangzq, Whoopie, Wim Taymans, Wind Yuan, Wonchul Lee, Xabier +Rodriguez Calvar, Xavier Claessens, Haihao Xiang, Yacine Bandou, +Yeongjin Jeong, Yuji Kuwabara, Zeeshan Ali, … and many others who have contributed bug reports, translations, sent suggestions or helped testing. @@ -1234,7 +1247,7 @@ the git 1.16 branch, which is a stable branch. 1.16.0 -1.16.0 is scheduled to be released in March 2019. +1.16.0 is scheduled to be released in April 2019. Known Issues @@ -1269,6 +1282,7 @@ August/September. ------------------------------------------------------------------------ _These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge and Guillaume Desmottes._ +_contributions from Sebastian Dröge, Guillaume Desmottes and Matthew +Waters._ _License: CC BY-SA 4.0_ diff --git a/RELEASE b/RELEASE index 2a5f7c8bdf..78dc1a65ba 100644 --- a/RELEASE +++ b/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-rtsp-server 1.15.2.1. +This is GStreamer gst-rtsp-server 1.15.90. GStreamer 1.15 is the development branch leading up to the next major stable version which will be 1.16. diff --git a/configure.ac b/configure.ac index 16b91f3838..300649719a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.15.2.1], +AC_INIT([GStreamer RTSP Server Library], [1.15.90], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1502, 0, 1502) +AS_LIBTOOL(GST, 1590, 0, 1590) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.15.2.1 -GSTPB_REQ=1.15.2.1 -GSTPG_REQ=1.15.2.1 -GSTPD_REQ=1.15.2.1 +GST_REQ=1.15.90 +GSTPB_REQ=1.15.90 +GSTPG_REQ=1.15.90 +GSTPD_REQ=1.15.90 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index dc8bdb4840..ec24f5e504 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.15.90 + master + + 2019-04-11 + + + + 1.15.2 diff --git a/meson.build b/meson.build index 4dea4fb4cf..8fd4dfc147 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.15.2.1', + version : '1.15.90', meson_version : '>= 0.47', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 3cfe88632fc4896dcf4107baae06c9f165d54bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Tue, 2 Apr 2019 08:05:03 +0200 Subject: [PATCH 1599/1776] rtsp_server: Free thread pool before clean transport cache If not waiting for free thread pool before clean transport caches, there can be a crash if a thread is executing in transport list loop in function send_tcp_message. Also add a check if priv->send_pool in on_message_sent to avoid that a new thread is pushed during wait of free thread pool. This is possible since when waiting for free thread pool mutex have to be unlocked. --- gst/rtsp-server/rtsp-stream.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index e6721a2d8a..e6ba6c1d59 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -3836,6 +3836,16 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, if (priv->transports != NULL) goto transports_not_removed; + if (priv->send_pool) { + GThreadPool *slask; + + slask = priv->send_pool; + priv->send_pool = NULL; + g_mutex_unlock (&priv->lock); + g_thread_pool_free (slask, TRUE, TRUE); + g_mutex_lock (&priv->lock); + } + clear_tr_cache (priv, TRUE); clear_tr_cache (priv, FALSE); @@ -4426,8 +4436,10 @@ on_message_sent (gpointer user_data) if (idx != -1) { gint dummy; - GST_DEBUG_OBJECT (stream, "start thread"); - g_thread_pool_push (priv->send_pool, &dummy, NULL); + if (priv->send_pool) { + GST_DEBUG_OBJECT (stream, "start thread"); + g_thread_pool_push (priv->send_pool, &dummy, NULL); + } } g_mutex_unlock (&priv->lock); From 0f0a10525a941d93aac6d1661bf0ec2a13d5ac82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Apr 2019 20:33:01 +0300 Subject: [PATCH 1600/1776] rtspclientsink: Notify the stream transport about each written message Otherwise it will never try to send us the next one: it tries to keep exactly one message in-flight all the time. In gst-rtsp-server this is done asynchronously via the GstRTSPWatch but in the client sink we always write data out synchronously. --- gst/rtsp-sink/gstrtspclientsink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 3e309c1416..9b87ea361f 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -3847,6 +3847,8 @@ do_send_data (GstBuffer * buffer, guint8 channel, gst_rtsp_message_unset (&message); + gst_rtsp_stream_transport_message_sent (context->stream_transport); + return res == GST_RTSP_OK; } From 70e0d0b27e01e6ea522d56cfe06894bec75fd31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 19 Apr 2019 00:34:54 +0100 Subject: [PATCH 1601/1776] Release 1.16.0 --- ChangeLog | 32 ++++++ NEWS | 262 ++++++++++++++++++++++++++++++------------- RELEASE | 11 +- configure.ac | 12 +- gst-rtsp-server.doap | 10 ++ meson.build | 2 +- 6 files changed, 239 insertions(+), 90 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6452861dc1..0cbc6ee9bb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +=== release 1.16.0 === + +2019-04-19 00:34:54 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-rtsp-server.doap: + * meson.build: + Release 1.16.0 + +2019-04-15 20:33:01 +0300 Sebastian Dröge + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Notify the stream transport about each written message + Otherwise it will never try to send us the next one: it tries to keep + exactly one message in-flight all the time. + In gst-rtsp-server this is done asynchronously via the GstRTSPWatch but + in the client sink we always write data out synchronously. + +2019-04-02 08:05:03 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-stream.c: + rtsp_server: Free thread pool before clean transport cache + If not waiting for free thread pool before clean transport caches, there + can be a crash if a thread is executing in transport list loop in + function send_tcp_message. + Also add a check if priv->send_pool in on_message_sent to avoid that a + new thread is pushed during wait of free thread pool. This is possible + since when waiting for free thread pool mutex have to be unlocked. + === release 1.15.90 === 2019-04-11 00:35:55 +0100 Tim-Philipp Müller diff --git a/NEWS b/NEWS index 16402a590e..816a3aae85 100644 --- a/NEWS +++ b/NEWS @@ -3,19 +3,12 @@ GSTREAMER 1.16 RELEASE NOTES -GStreamer 1.16 has not been released yet. It is scheduled for release in -April 2019. - -1.15.x is the unstable development version that is being developed in -the git master branch and which will eventually result in 1.16. - -1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, -1.6, 1.4, 1.2 and 1.0 release series. +GStreamer 1.16.0 was originally released on 19 April 2019. See https://gstreamer.freedesktop.org/releases/1.16/ for the latest version of this document. -_Last updated: Wednesday 10 April 2019, 00:50 UTC (log)_ +_Last updated: Friday 19 April 2019, 00:00 UTC (log)_ Introduction @@ -76,6 +69,10 @@ Highlights - The GStreamer Rust bindings and Rust plugins module are now officially part of upstream GStreamer. +- The GStreamer Editing Services gained a gesdemux element that allows + directly playing back serialized edit list with playbin or + (uri)decodebin + - Many performance improvements @@ -208,7 +205,8 @@ this new infrastructure and provides the following elements: - ccconverter: a closed caption converter that can convert between different formats -- line21decoder: extract line21 closed captions from SD video streams +- line21encoder, line21decoder: inject/extract line21 closed captions + to/from SD video streams - cc708overlay: decodes CEA 608/708 captions and overlays them on video @@ -218,7 +216,11 @@ support: - qtdemux and qtmux support CEA 608/708 Closed Caption tracks -- mpegvideoparse extracts Closed Captions from MPEG-2 video streams +- mpegvideoparse, h264parse extracts Closed Captions from MPEG-2/H.264 + video streams + +- avviddec, avvidenc, x264enc got support for extracting/injecting + Closed Captions - decklinkvideosink can output closed captions and decklinkvideosrc can extract closed captions @@ -265,7 +267,7 @@ New Elements or uridecodebin3 etc. - New closed caption elements: cccombiner, ccextractor, ccconverter, - line21decoder and cc708overlay (see above) + line21encoder, line21decoder and cc708overlay (see above) - wpesrc: new source element acting as a Web Browser based on WebKit WPE @@ -402,6 +404,9 @@ New element features and additions - srtpdec, srtpenc: add support for MKIs which allow multiple keys to be used with a single SRTP stream +- srtpdec, srtpenc: add support for AES-GCM and also add support for + it in gst-rtsp-server and rtspsrc. + - The srt Secure Reliable Transport plugin has integrated server and client elements srt{client,server}{src,sink} into one (srtsrc and srtsink), since SRT connection mode can be changed by uri @@ -434,7 +439,24 @@ New element features and additions "connector-properties" can be used to pass custom properties to the DRM. -- waylandsink has a "fullscreen" property now. +- waylandsink has a "fullscreen" property now and supports the + XDG-Shell protocol. + +- decklinkvideosink, decklinkvideosrc support selecting between + half/full duplex + +- The vulkan plugin gained support for macOS and iOS via MoltenVK in + addition to the existing support for X11 and Wayland + +- imagefreeze has a new num-buffers property to limit the number of + buffers that are produced and to send an EOS event afterwards + +- webrtcbin has a new, introspectable get-transceiver signal in + addition to the old get-transceivers signal that couldn’t be used + from bindings + +- Support for per-element latency information was added to the latency + tracer Plugin and library moves @@ -574,6 +596,18 @@ Miscellaneous API additions - gst_audio_buffer_truncate() convenience function to truncate a raw audio buffer +- GstDiscoverer has support for caching the results of discovery in + the default cache directory. This can be enabled with the use-cache + property and is disabled by default. + +- GstMeta that are attached to GstBuffers are now always stored in the + order in which they were added. + +- Additional support for signalling ONVIF specific features were + added: the SEEK event can store a trickmode-interval now and support + for the Rate-Control and Frames RTSP headers was added to the RTSP + library. + Miscellaneous performance and memory optimisations @@ -677,49 +711,6 @@ Tracing framework and debugging improvements object. This is currently limited to pads for GstElements and events for the pads. The output may look like this: - (gdb) gst-print pad.object.parent - GstMatroskaDemux (matroskademux0) { - SinkPad (sink, pull) { - } - SrcPad (video_0, push) { - events: - stream-start: - stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/001:1274058367 - caps: video/x-theora - width: 1920 - height: 800 - pixel-aspect-ratio: 1/1 - framerate: 24/1 - streamheader: < 0x5555557c7d30 [GstBuffer], 0x5555557c7e40 [GstBuffer], 0x7fffe00141d0 [GstBuffer] > - segment: time - rate: 1 - tag: global - container-format: Matroska - } - SrcPad (audio_0, push) { - events: - stream-start: - stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/002:1551204875 - caps: audio/mpeg - mpegversion: 4 - framed: true - stream-format: raw - codec_data: 0x7fffe0014500 [GstBuffer] - level: 2 - base-profile: lc - profile: lc - channels: 2 - rate: 44100 - segment: time - rate: 1 - tag: global - container-format: Matroska - tag: stream - audio-codec: MPEG-4 AAC audio - language-code: en - } - } - - gst_structure_to_string() now serialises the actual value of pointers when serialising GstStructures instead of claiming they’re NULL. This makes debug logging in various places less confusing, @@ -761,7 +752,35 @@ GStreamer RTSP server GStreamer VAAPI -- this section will be filled in in due course +- Support Wayland’s display for context sharing, so the application + can pass its own wl_display in order to be used for the VAAPI + display creation. + +- A lot of work to support new Intel hardware using media-driver as VA + backend. + +- For non-x86 devices, VAAPI display can instantiate, through DRM, + with no PCI bus. This enables the usage of libva-v4l2-request + driver. + +- Added support for XDG-shell protocol as wl_shell replacement which + is currently deprecated. This change add as dependency + wayland-protocol. + +- GstVaapiFilter, GstVaapiWindow, and GstVaapiDecoder classes now + inherit from GstObject, gaining all the GStreamer’s instrumentation + support. + +- The metadata now specifies the plugin as Hardware class. + +- H264 decoder is more stable with problematic streams. + +- In H265 decoder added support for profiles main-422-10 (P010_10LE), + main-444 (AYUV) and main-444-10 (Y410) + +- JPEG decoder handles dynamic resolution changes. + +- More specification adherence in H264 and H265 encoders. GStreamer OMX @@ -789,12 +808,111 @@ GStreamer OMX GStreamer Editing Services and NLE -- this section will be filled in in due course +- Added a gesdemux element, it is an auto pluggable element that + allows decoding edit list like files supported by GES + +- Added gessrc which wraps a GESTimeline as a standard source element + (implementing the ges protocol handler) + +- Added basic support for videorate::rate property potentially + allowing changing playback speed + +- Layer priority is now fully automatic and they should be moved with + the new ges_timeline_move_layer method, ges_layer_set_priority is + now deprecated. + +- Added a ges_timeline_element_get_layer_priority so we can simply get + all information about GESTimelineElement position in the timeline + +- GESVideoSource now auto orientates the images if it is defined in a + meta (overridable). + +- Added some PyGObject overrides to make the API more pythonic + +- The threading model has been made more explicit with safe guard to + make sure not thread safe APIs are not used from the wrong threads. + It is also now possible to properly handle in what thread the API + should be used. + +- Optimized GESClip and GESTrackElement creation + +- Added a way to compile out the old, unused and deprecated + GESPitiviFormatter + +- Re implemented the timeline editing API making it faster and making + the code much more maintainable + +- Simplified usage of nlecomposition outside GES by removing quirks in + it API usage and removing the need to treat it specially from an + application perspective. + +- ges-launch-1.0: + + - Added support to add titles to the timeline + - Enhance the help auto generating it from the code + +- Deprecate ges_timeline_load_from_uri as loading the timeline should + be done through a project now + +- MANY leaks have been plugged and the unit testsuite is now “leak + free” GStreamer validate -- this section will be filled in in due course +- Added an action type to verify the checksum of the sink last-sample + +- Added an include keyword to validate scenarios + +- Added the notion of variable in scenarios, with the set-vars keyword + +- Started adding support for “performance” like tests by allowing to + define the number of dropped buffers or the minimum buffer frequency + on a specific pad + +- Added a validateflow plugin which allows defining the data flow to + be seen on a particular pad and verifying that following runs match + the expectations + +- Added support for appsrc based test definition so we can instrument + the data pushed into the pipeline from scenarios + +- Added a mockdecryptor allowing adding tests with on encrypted files, + the element will potentially be instrumented with a validate + scenario + +- gst-validate-launcher: + + - Cleaned up output + + - Changed the default for “muting” tests as user doesn’t expect + hundreds of windows to show up when running the testsuite + + - Fixed the outputted xunit files to be compatible with GitLab + + - Added support to run tests on media files in push mode (using + pushfile://) + + - Added support for running inside gst-build + + - Added support for running ssim tests on rendered files + + - Added a way to simply define tests on pipelines through a simple + .json file + + - Added a python app to easily run python testsuite reusing all + the launcher features + + - Added flatpak knowledge so we can print backtrace even when + running from within flatpak + + - Added a way to automatically generated “known issues” + suppressions lines + + - Added a way to rerun tests to check if they are flaky and added + a way to tolerate tests known to be flaky + + - Add a way to output html log files GStreamer Python Bindings @@ -1223,20 +1341,6 @@ Yeongjin Jeong, Yuji Kuwabara, Zeeshan Ali, suggestions or helped testing. -Bugs fixed in 1.16 - -- this section will be filled in in due course - -More than XXX bugs have been fixed during the development of 1.16. - -This list does not include issues that have been cherry-picked into the -stable 1.16 branch and fixed there as well, all fixes that ended up in -the 1.16 branch are also included in 1.16. - -This list also does not include issues that have been fixed without a -bug report in bugzilla, so the actual number of fixes is much higher. - - Stable 1.16 branch After the 1.16.0 release there will be several 1.16.x bug-fix releases @@ -1247,7 +1351,7 @@ the git 1.16 branch, which is a stable branch. 1.16.0 -1.16.0 is scheduled to be released in April 2019. +1.16.0 was released on 19 April 2019. Known Issues @@ -1272,9 +1376,9 @@ unstable development version leading up to the stable 1.18 release. The development of 1.17/1.18 will happen in the git master branch. The plan for the 1.18 development cycle is yet to be confirmed, but it -is expected that feature freeze will be around July 2019 followed by -several 1.17 pre-releases and the new 1.18 stable release in -August/September. +is possible that the next cycle will be a short one in which case +feature freeze would be perhaps around August 2019 with a new 1.18 +stable release in September. 1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. @@ -1282,7 +1386,7 @@ August/September. ------------------------------------------------------------------------ _These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge, Guillaume Desmottes and Matthew -Waters._ +_contributions from Sebastian Dröge, Guillaume Desmottes, Matthew +Waters, _ _Thibault Saunier, and Víctor Manuel Jáquez Leal._ _License: CC BY-SA 4.0_ diff --git a/RELEASE b/RELEASE index 78dc1a65ba..ae7fffa502 100644 --- a/RELEASE +++ b/RELEASE @@ -1,9 +1,12 @@ -This is GStreamer gst-rtsp-server 1.15.90. +This is GStreamer gst-rtsp-server 1.16.0. -GStreamer 1.15 is the development branch leading up to the next major -stable version which will be 1.16. +The GStreamer team is thrilled to announce a new major feature release in the +stable 1.0 API series of your favourite cross-platform multimedia framework! -The 1.15 development series adds new features on top of the 1.14 series and is +As always, this release is again packed with new features, bug fixes and +other improvements. + +The 1.16 release series adds new features on top of the 1.14 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. diff --git a/configure.ac b/configure.ac index 300649719a..2d536503cd 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.15.90], +AC_INIT([GStreamer RTSP Server Library], [1.16.0], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1590, 0, 1590) +AS_LIBTOOL(GST, 1600, 0, 1600) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.15.90 -GSTPB_REQ=1.15.90 -GSTPG_REQ=1.15.90 -GSTPD_REQ=1.15.90 +GST_REQ=1.16.0 +GSTPB_REQ=1.16.0 +GSTPG_REQ=1.16.0 +GSTPD_REQ=1.16.0 dnl *** autotools stuff **** diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index ec24f5e504..430c0b2fd3 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.16.0 + master + + 2019-04-19 + + + + 1.15.90 diff --git a/meson.build b/meson.build index 8fd4dfc147..2802b1d853 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.15.90', + version : '1.16.0', meson_version : '>= 0.47', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From f586450b99f82b61abf3b1ca0793e484ca2aa0a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 19 Apr 2019 10:40:29 +0100 Subject: [PATCH 1602/1776] Back to development --- RELEASE | 2 +- configure.ac | 12 ++++++------ meson.build | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/RELEASE b/RELEASE index ae7fffa502..c4759f66c4 100644 --- a/RELEASE +++ b/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-rtsp-server 1.16.0. +This is GStreamer gst-rtsp-server 1.17.0.1. The GStreamer team is thrilled to announce a new major feature release in the stable 1.0 API series of your favourite cross-platform multimedia framework! diff --git a/configure.ac b/configure.ac index 2d536503cd..b5c52ce2ce 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.69) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.16.0], +AC_INIT([GStreamer RTSP Server Library], [1.17.0.1], [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], [gst-rtsp-server]) AG_GST_INIT @@ -53,13 +53,13 @@ dnl 1.2.5 => 205 dnl 1.10.9 (who knows) => 1009 dnl dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1600, 0, 1600) +AS_LIBTOOL(GST, 1700, 0, 1700) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.16.0 -GSTPB_REQ=1.16.0 -GSTPG_REQ=1.16.0 -GSTPD_REQ=1.16.0 +GST_REQ=1.17.0.1 +GSTPB_REQ=1.17.0.1 +GSTPG_REQ=1.17.0.1 +GSTPD_REQ=1.17.0.1 dnl *** autotools stuff **** diff --git a/meson.build b/meson.build index 2802b1d853..c29989e120 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.16.0', + version : '1.17.0.1', meson_version : '>= 0.47', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From b578628dc1e1ac979c43dce9fa1766e54594c533 Mon Sep 17 00:00:00 2001 From: Kristofer Bjorkstrom Date: Wed, 27 Mar 2019 16:21:03 +0100 Subject: [PATCH 1603/1776] rtsp-client: Handle Content-Length limitation Add functionality to limit the Content-Length. API addition, Enhancement. Define an appropriate request size limit and reject requests exceeding the limit with response status 413 Request Entity Too Large Related to !182 --- gst/rtsp-server/rtsp-client.c | 88 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-client.h | 6 ++ gst/rtsp-server/rtsp-server-object.h | 6 ++ gst/rtsp-server/rtsp-server.c | 80 +++++++++++++++++++++++++ 4 files changed, 180 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 3a839ec8c4..38201899f7 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -103,6 +103,8 @@ struct _GstRTSPClientPrivate gboolean drop_backlog; + guint content_length_limit; + guint rtsp_ctrl_timeout_id; guint rtsp_ctrl_timeout_cnt; @@ -609,6 +611,7 @@ gst_rtsp_client_init (GstRTSPClient * client) priv->pipelined_requests = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); priv->tstate = TUNNEL_STATE_UNKNOWN; + priv->content_length_limit = G_MAXUINT; } static GstRTSPFilterResult @@ -3983,6 +3986,57 @@ gst_rtsp_client_get_mount_points (GstRTSPClient * client) return result; } +/** + * gst_rtsp_client_set_content_length_limit: + * @client: a #GstRTSPClient + * @limit: Content-Length limit + * + * Configure @client to use the specified Content-Length limit. + * + * Define an appropriate request size limit and reject requests exceeding the + * limit with response status 413 Request Entity Too Large + * + * Since: 1.18 + */ +void +gst_rtsp_client_set_content_length_limit (GstRTSPClient * client, guint limit) +{ + GstRTSPClientPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_CLIENT (client)); + + priv = client->priv; + g_mutex_lock (&priv->lock); + priv->content_length_limit = limit; + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_client_get_content_length_limit: + * @client: a #GstRTSPClient + * + * Get the Content-Length limit of @client. + * + * Returns: the Content-Length limit. + * + * Since: 1.18 + */ +guint +gst_rtsp_client_get_content_length_limit (GstRTSPClient * client) +{ + GstRTSPClientPrivate *priv; + glong content_length_limit; + + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), -1); + priv = client->priv; + + g_mutex_lock (&priv->lock); + content_length_limit = priv->content_length_limit; + g_mutex_unlock (&priv->lock); + + return content_length_limit; +} + /** * gst_rtsp_client_set_auth: * @client: a #GstRTSPClient @@ -4122,6 +4176,8 @@ gst_rtsp_client_set_connection (GstRTSPClient * client, priv = client->priv; + gst_rtsp_connection_set_content_length_limit (conn, + priv->content_length_limit); read_socket = gst_rtsp_connection_get_read_socket (conn); if (!(address = g_socket_get_local_address (read_socket, &error))) @@ -4492,7 +4548,39 @@ error_full (GstRTSPWatch * watch, GstRTSPResult result, { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); gchar *str; + GstRTSPContext sctx = { NULL }, *ctx; + GstRTSPClientPrivate *priv; + GstRTSPMessage response = { 0 }; + priv = client->priv; + if (!(ctx = gst_rtsp_context_get_current ())) { + ctx = &sctx; + ctx->auth = priv->auth; + gst_rtsp_context_push_current (ctx); + } + + ctx->conn = priv->connection; + ctx->client = client; + ctx->request = message; + ctx->method = GST_RTSP_INVALID; + ctx->response = &response; + + /* only return error response if it is a request */ + if (!message || message->type != GST_RTSP_MESSAGE_REQUEST) + goto done; + + if (result == GST_RTSP_ENOMEM) { + send_generic_response (client, GST_RTSP_STS_REQUEST_ENTITY_TOO_LARGE, ctx); + goto done; + } + if (result == GST_RTSP_EPARSE) { + send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + goto done; + } + +done: + if (ctx == &sctx) + gst_rtsp_context_pop_current (ctx); str = gst_rtsp_strresult (result); GST_INFO ("client %p: error when handling message %p with id %d: %s", diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index ebf6aeca27..59a0a7f687 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -185,6 +185,12 @@ void gst_rtsp_client_set_mount_points (GstRTSPClient *client, GST_RTSP_SERVER_API GstRTSPMountPoints * gst_rtsp_client_get_mount_points (GstRTSPClient *client); +GST_RTSP_SERVER_API +void gst_rtsp_client_set_content_length_limit (GstRTSPClient *client, guint limit); + +GST_RTSP_SERVER_API +guint gst_rtsp_client_get_content_length_limit (GstRTSPClient *client); + GST_RTSP_SERVER_API void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth); diff --git a/gst/rtsp-server/rtsp-server-object.h b/gst/rtsp-server/rtsp-server-object.h index 118764ea1d..4f44f3a500 100644 --- a/gst/rtsp-server/rtsp-server-object.h +++ b/gst/rtsp-server/rtsp-server-object.h @@ -132,6 +132,12 @@ void gst_rtsp_server_set_mount_points (GstRTSPServer *serve GST_RTSP_SERVER_API GstRTSPMountPoints * gst_rtsp_server_get_mount_points (GstRTSPServer *server); +GST_RTSP_SERVER_API +void gst_rtsp_server_set_content_length_limit (GstRTSPServer * server, guint limit); + +GST_RTSP_SERVER_API +guint gst_rtsp_server_get_content_length_limit (GstRTSPServer * server); + GST_RTSP_SERVER_API void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 47b718737a..dd5d6d2e29 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -84,6 +84,9 @@ struct _GstRTSPServerPrivate /* mount points for this server */ GstRTSPMountPoints *mount_points; + /* request size limit */ + guint content_length_limit; + /* authentication manager */ GstRTSPAuth *auth; @@ -116,6 +119,7 @@ enum PROP_SESSION_POOL, PROP_MOUNT_POINTS, + PROP_CONTENT_LENGTH_LIMIT, PROP_LAST }; @@ -223,6 +227,19 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) GST_TYPE_RTSP_MOUNT_POINTS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * RTSPServer::content-length-limit: + * + * Define an appropriate request size limit and reject requests exceeding the + * limit. + * + * Since: 1.18 + */ + g_object_class_install_property (gobject_class, PROP_CONTENT_LENGTH_LIMIT, + g_param_spec_uint ("content-length-limit", "Limitation of Content-Length", + "Limitation of Content-Length", + 0, G_MAXUINT, G_MAXUINT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED] = g_signal_new ("client-connected", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPServerClass, client_connected), @@ -248,6 +265,7 @@ gst_rtsp_server_init (GstRTSPServer * server) priv->backlog = DEFAULT_BACKLOG; priv->session_pool = gst_rtsp_session_pool_new (); priv->mount_points = gst_rtsp_mount_points_new (); + priv->content_length_limit = G_MAXUINT; priv->thread_pool = gst_rtsp_thread_pool_new (); } @@ -600,6 +618,57 @@ gst_rtsp_server_get_mount_points (GstRTSPServer * server) return result; } +/** + * gst_rtsp_server_set_content_length_limit + * @server: a #GstRTSPServer + * Configure @server to use the specified Content-Length limit. + * + * Define an appropriate request size limit and reject requests exceeding the + * limit. + * + * Since: 1.18 + */ +void +gst_rtsp_server_set_content_length_limit (GstRTSPServer * server, guint limit) +{ + GstRTSPServerPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_SERVER (server)); + + priv = server->priv; + + GST_RTSP_SERVER_LOCK (server); + priv->content_length_limit = limit; + GST_RTSP_SERVER_UNLOCK (server); +} + +/** + * gst_rtsp_server_get_content_length_limit: + * @server: a #GstRTSPServer + * + * Get the Content-Length limit of @server. + * + * Returns: the Content-Length limit. + * + * Since: 1.18 + */ +guint +gst_rtsp_server_get_content_length_limit (GstRTSPServer * server) +{ + GstRTSPServerPrivate *priv; + guint result; + + g_return_val_if_fail (GST_IS_RTSP_SERVER (server), G_MAXUINT); + + priv = server->priv; + + GST_RTSP_SERVER_LOCK (server); + result = priv->content_length_limit; + GST_RTSP_SERVER_UNLOCK (server); + + return result; +} + /** * gst_rtsp_server_set_auth: * @server: a #GstRTSPServer @@ -739,6 +808,10 @@ gst_rtsp_server_get_property (GObject * object, guint propid, case PROP_MOUNT_POINTS: g_value_take_object (value, gst_rtsp_server_get_mount_points (server)); break; + case PROP_CONTENT_LENGTH_LIMIT: + g_value_set_uint (value, + gst_rtsp_server_get_content_length_limit (server)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -766,6 +839,10 @@ gst_rtsp_server_set_property (GObject * object, guint propid, case PROP_MOUNT_POINTS: gst_rtsp_server_set_mount_points (server, g_value_get_object (value)); break; + case PROP_CONTENT_LENGTH_LIMIT: + gst_rtsp_server_set_content_length_limit (server, + g_value_get_uint (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1073,6 +1150,9 @@ default_create_client (GstRTSPServer * server) gst_rtsp_client_set_session_pool (client, priv->session_pool); /* set the mount points that this client should use */ gst_rtsp_client_set_mount_points (client, priv->mount_points); + /* Set content-length limit */ + gst_rtsp_client_set_content_length_limit (GST_RTSP_CLIENT (client), + priv->content_length_limit); /* set authentication manager */ gst_rtsp_client_set_auth (client, priv->auth); /* set threadpool */ From c4653ef38b23d0e1dd1c96fc9fd56421a3f731fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Apr 2019 20:51:30 +0300 Subject: [PATCH 1604/1776] rtspclientsink: Use write_messages() API to send buffer lists in one go And to write messages with multiple memories also via writev(). --- gst/rtsp-sink/gstrtspclientsink.c | 76 ++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 9b87ea361f..8d4b25d07c 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -1906,6 +1906,26 @@ gst_rtsp_client_sink_connection_send (GstRTSPClientSink * sink, return ret; } +static GstRTSPResult +gst_rtsp_client_sink_connection_send_messages (GstRTSPClientSink * sink, + GstRTSPConnInfo * conninfo, GstRTSPMessage * messages, guint n_messages, + GTimeVal * timeout) +{ + GstRTSPResult ret; + + if (conninfo->connection) { + g_mutex_lock (&conninfo->send_lock); + ret = + gst_rtsp_connection_send_messages (conninfo->connection, messages, + n_messages, timeout); + g_mutex_unlock (&conninfo->send_lock); + } else { + ret = GST_RTSP_ERROR; + } + + return ret; +} + static GstRTSPResult gst_rtsp_client_sink_connection_receive (GstRTSPClientSink * sink, GstRTSPConnInfo * conninfo, GstRTSPMessage * message, GTimeVal * timeout) @@ -2792,25 +2812,27 @@ no_user_pass: static GstRTSPResult gst_rtsp_client_sink_try_send (GstRTSPClientSink * sink, - GstRTSPConnInfo * conninfo, GstRTSPMessage * request, - GstRTSPMessage * response, GstRTSPStatusCode * code) + GstRTSPConnInfo * conninfo, GstRTSPMessage * requests, + guint n_requests, GstRTSPMessage * response, GstRTSPStatusCode * code) { GstRTSPResult res; GstRTSPStatusCode thecode; gchar *content_base = NULL; gint try = 0; + g_assert (n_requests == 1 || response == NULL); + again: GST_DEBUG_OBJECT (sink, "sending message"); - if (sink->debug) - gst_rtsp_message_dump (request); + if (sink->debug && n_requests == 1) + gst_rtsp_message_dump (&requests[0]); g_mutex_lock (&sink->send_lock); res = - gst_rtsp_client_sink_connection_send (sink, conninfo, request, - sink->ptcp_timeout); + gst_rtsp_client_sink_connection_send_messages (sink, conninfo, requests, + n_requests, sink->ptcp_timeout); if (res < 0) { g_mutex_unlock (&sink->send_lock); goto send_error; @@ -2998,7 +3020,7 @@ gst_rtsp_client_sink_send (GstRTSPClientSink * sink, GstRTSPConnInfo * conninfo, method = request->type_data.request.method; if ((res = - gst_rtsp_client_sink_try_send (sink, conninfo, request, response, + gst_rtsp_client_sink_try_send (sink, conninfo, request, 1, response, &int_code)) < 0) goto error; @@ -3826,25 +3848,15 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClientSink *sink = context->parent; GstRTSPMessage message = { 0 }; GstRTSPResult res = GST_RTSP_OK; - GstMapInfo map_info; - guint8 *data; - guint usize; gst_rtsp_message_init_data (&message, channel); - /* FIXME, need some sort of iovec RTSPMessage here */ - if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) - return FALSE; - - gst_rtsp_message_take_body (&message, map_info.data, map_info.size); + gst_rtsp_message_set_body_buffer (&message, buffer); res = - gst_rtsp_client_sink_try_send (sink, &sink->conninfo, &message, + gst_rtsp_client_sink_try_send (sink, &sink->conninfo, &message, 1, NULL, NULL); - gst_rtsp_message_steal_body (&message, &data, &usize); - gst_buffer_unmap (buffer, &map_info); - gst_rtsp_message_unset (&message); gst_rtsp_stream_transport_message_sent (context->stream_transport); @@ -3856,21 +3868,31 @@ static gboolean do_send_data_list (GstBufferList * buffer_list, guint8 channel, GstRTSPStreamContext * context) { - gboolean ret = TRUE; + GstRTSPClientSink *sink = context->parent; + GstRTSPResult res = GST_RTSP_OK; guint i, n = gst_buffer_list_length (buffer_list); + GstRTSPMessage *messages = g_newa (GstRTSPMessage, n); + + memset (messages, 0, n * sizeof (GstRTSPMessage)); - /* TODO: Needs support for a) queueing up multiple messages on the - * GstRTSPWatch in do_send_data() above and b) for one message having a body - * consisting of multiple parts here */ for (i = 0; i < n; i++) { GstBuffer *buffer = gst_buffer_list_get (buffer_list, i); - ret = do_send_data (buffer, channel, context); - if (!ret) - break; + gst_rtsp_message_init_data (&messages[i], channel); + + gst_rtsp_message_set_body_buffer (&messages[i], buffer); } - return ret; + res = + gst_rtsp_client_sink_try_send (sink, &sink->conninfo, messages, n, + NULL, NULL); + + for (i = 0; i < n; i++) { + gst_rtsp_message_unset (&messages[i]); + gst_rtsp_stream_transport_message_sent (context->stream_transport); + } + + return res == GST_RTSP_OK; } static GstRTSPResult From 640c5bba41e6227d16f96c65796512264d522acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Apr 2019 20:54:24 +0300 Subject: [PATCH 1605/1776] rtspclientsink: Set async-handling=false for the internal bins Without this we can easily run into a race condition with async state changes: - the pipeline is doing an async state change - we set the internal bins to PLAYING but that's ignored because an async state change is currently pending - the async state change finishes but does not change the state of the internal bins because of locked_state==TRUE - the internal bins stay in PAUSED forever --- gst/rtsp-sink/gstrtspclientsink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 8d4b25d07c..c37449487f 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -878,6 +878,7 @@ gst_rtsp_client_sink_init (GstRTSPClientSink * sink) g_cond_init (&sink->open_conn_cond); sink->internal_bin = (GstBin *) gst_bin_new ("rtspbin"); + g_object_set (sink->internal_bin, "async-handling", TRUE, NULL); gst_element_set_locked_state (GST_ELEMENT_CAST (sink->internal_bin), TRUE); gst_bin_add (GST_BIN (sink), GST_ELEMENT_CAST (sink->internal_bin)); From 802a648723b77fe726fa14dd5846d6b0af960cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 23 Apr 2019 14:38:05 +0300 Subject: [PATCH 1606/1776] rtsp-server: Add various missing Since: 1.16 markers --- gst/rtsp-server/rtsp-media-factory.c | 8 ++++++++ gst/rtsp-server/rtsp-media.c | 8 ++++++++ gst/rtsp-server/rtsp-stream-transport.c | 2 ++ gst/rtsp-server/rtsp-stream.c | 11 +++++++++++ 4 files changed, 29 insertions(+) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 27825e02da..58c8d39ebc 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -1511,6 +1511,8 @@ gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory) * Set the maximum time-to-live value of outgoing multicast packets. * * Returns: %TRUE if the requested ttl has been set successfully. + * + * Since: 1.16 */ gboolean gst_rtsp_media_factory_set_max_mcast_ttl (GstRTSPMediaFactory * factory, @@ -1541,6 +1543,8 @@ gst_rtsp_media_factory_set_max_mcast_ttl (GstRTSPMediaFactory * factory, * Get the the maximum time-to-live value of outgoing multicast packets. * * Returns: the maximum time-to-live value of outgoing multicast packets. + * + * Since: 1.16 */ guint gst_rtsp_media_factory_get_max_mcast_ttl (GstRTSPMediaFactory * factory) @@ -1566,6 +1570,8 @@ gst_rtsp_media_factory_get_max_mcast_ttl (GstRTSPMediaFactory * factory) * * Decide whether the multicast socket should be bound to a multicast address or * INADDR_ANY. + * + * Since: 1.16 */ void gst_rtsp_media_factory_set_bind_mcast_address (GstRTSPMediaFactory * factory, @@ -1589,6 +1595,8 @@ gst_rtsp_media_factory_set_bind_mcast_address (GstRTSPMediaFactory * factory, * Check if multicast sockets are configured to be bound to multicast addresses. * * Returns: %TRUE if multicast sockets are configured to be bound to multicast addresses. + * + * Since: 1.16 */ gboolean gst_rtsp_media_factory_is_bind_mcast_address (GstRTSPMediaFactory * factory) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 719f284e9b..141cba91f9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1869,6 +1869,8 @@ gst_rtsp_media_get_multicast_iface (GstRTSPMedia * media) * Set the maximum time-to-live value of outgoing multicast packets. * * Returns: %TRUE if the requested ttl has been set successfully. + * + * Since: 1.16 */ gboolean gst_rtsp_media_set_max_mcast_ttl (GstRTSPMedia * media, guint ttl) @@ -1907,6 +1909,8 @@ gst_rtsp_media_set_max_mcast_ttl (GstRTSPMedia * media, guint ttl) * Get the the maximum time-to-live value of outgoing multicast packets. * * Returns: the maximum time-to-live value of outgoing multicast packets. + * + * Since: 1.16 */ guint gst_rtsp_media_get_max_mcast_ttl (GstRTSPMedia * media) @@ -1932,6 +1936,8 @@ gst_rtsp_media_get_max_mcast_ttl (GstRTSPMedia * media) * * Decide whether the multicast socket should be bound to a multicast address or * INADDR_ANY. + * + * Since: 1.16 */ void gst_rtsp_media_set_bind_mcast_address (GstRTSPMedia * media, @@ -1960,6 +1966,8 @@ gst_rtsp_media_set_bind_mcast_address (GstRTSPMedia * media, * Check if multicast sockets are configured to be bound to multicast addresses. * * Returns: %TRUE if multicast sockets are configured to be bound to multicast addresses. + * + * Since: 1.16 */ gboolean gst_rtsp_media_is_bind_mcast_address (GstRTSPMedia * media) diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 7c439e28a9..1791034c39 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -682,6 +682,8 @@ gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport * trans) * @trans: a #GstRTSPStreamTransport * * Signal the installed message_sent callback for @trans. + * + * Since: 1.16 */ void gst_rtsp_stream_transport_message_sent (GstRTSPStreamTransport * trans) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index e6ba6c1d59..ce4c70c89d 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2107,6 +2107,7 @@ gst_rtsp_stream_get_buffer_size (GstRTSPStream * stream) * * Returns: %TRUE if the requested ttl has been set successfully. * + * Since: 1.16 */ gboolean gst_rtsp_stream_set_max_mcast_ttl (GstRTSPStream * stream, guint ttl) @@ -2133,6 +2134,7 @@ gst_rtsp_stream_set_max_mcast_ttl (GstRTSPStream * stream, guint ttl) * * Returns: the maximum time-to-live value of outgoing multicast packets. * + * Since: 1.16 */ guint gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream * stream) @@ -2155,6 +2157,7 @@ gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream * stream) * * Returns: TRUE if the requested ttl value is allowed. * + * Since: 1.16 */ gboolean gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream * stream, guint ttl) @@ -2176,6 +2179,8 @@ gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream * stream, guint ttl) * * Decide whether the multicast socket should be bound to a multicast address or * INADDR_ANY. + * + * Since: 1.16 */ void gst_rtsp_stream_set_bind_mcast_address (GstRTSPStream * stream, @@ -2195,6 +2200,8 @@ gst_rtsp_stream_set_bind_mcast_address (GstRTSPStream * stream, * Check if multicast sockets are configured to be bound to multicast addresses. * * Returns: %TRUE if multicast sockets are configured to be bound to multicast addresses. + * + * Since: 1.16 */ gboolean gst_rtsp_stream_is_bind_mcast_address (GstRTSPStream * stream) @@ -4712,6 +4719,8 @@ gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream * stream, * allocated. * * Returns: %TRUE if @destination can be addedd and handled by @stream. + * + * Since: 1.16 */ gboolean gst_rtsp_stream_add_multicast_client_address (GstRTSPStream * stream, @@ -4760,6 +4769,8 @@ add_addr_error: * Get all multicast client addresses that RTP data will be sent to * * Returns: A comma separated list of host:port pairs with destinations + * + * Since: 1.16 */ gchar * gst_rtsp_stream_get_multicast_client_addresses (GstRTSPStream * stream) From 8d3bef4c1e8edfc54455a5c4878cac8f39945c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 23 Apr 2019 15:01:32 +0300 Subject: [PATCH 1607/1776] rtsp-server: Add various Since: 1.14 markers --- gst/rtsp-server/rtsp-media.c | 8 +++++++- gst/rtsp-server/rtsp-sdp.c | 14 ++++++++++++++ gst/rtsp-server/rtsp-session-media.c | 2 ++ gst/rtsp-server/rtsp-stream.c | 15 +++++++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 141cba91f9..b238561678 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2645,6 +2645,8 @@ gst_rtsp_media_get_status (GstRTSPMedia * media) * the pipeline must contain all needed transport parts (transport sinks). * * Returns: %TRUE on success. + * + * Since: 1.14 */ gboolean gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, @@ -4554,7 +4556,7 @@ gst_rtsp_media_get_transport_mode (GstRTSPMedia * media) } /** - * gst_rtsp_media_get_seekable: + * gst_rtsp_media_seekable: * @media: a #GstRTSPMedia * * Check if the pipeline for @media seek and up to what point in time, @@ -4563,6 +4565,8 @@ gst_rtsp_media_get_transport_mode (GstRTSPMedia * media) * Returns: -1 if the stream is not seekable, 0 if seekable only to the beginning * and > 0 to indicate the longest duration between any two random access points. * %G_MAXINT64 means any value is possible. + * + * Since: 1.14 */ GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia * media) @@ -4592,6 +4596,8 @@ gst_rtsp_media_seekable (GstRTSPMedia * media) * SETUP. * * Returns: %TRUE if the media pipeline has been sucessfully updated. + * + * Since: 1.14 */ gboolean gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GPtrArray * transports) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 6d552f2212..701cea5c1e 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -184,6 +184,20 @@ cleanup: } } +/** + * gst_rtsp_sdp_make_media: + * @sdp: a #GstRTSPMessage + * @info: a #GstSDPInfo + * @stream: a #GstRTSPStream + * @caps: a #GstCaps + * @profile: a #GstRTSPProfile + * + * Creates a #GstSDPMedia from the parameters and stores it in @sdp. + * + * Returns: %TRUE on success + * + * Since: 1.14 + */ gboolean gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream * stream, GstCaps * caps, GstRTSPProfile profile) diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 26b7143988..6b4bb149b2 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -416,6 +416,8 @@ gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx) * * Returns: (transfer full) (element-type GstRTSPStreamTransport): a * list of #GstRTSPStreamTransport, g_ptr_array_unref () after usage. + * + * Since: 1.14 */ GPtrArray * gst_rtsp_session_media_get_transports (GstRTSPSessionMedia * media) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index ce4c70c89d..68a1202fbf 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4646,6 +4646,7 @@ gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family) * Get the multicast RTP socket from @stream for a @family. * * Returns: (transfer full) (nullable): the multicast RTP socket or %NULL if no + * * socket could be allocated for @family. Unref after usage */ GSocket * @@ -4681,6 +4682,8 @@ gst_rtsp_stream_get_rtp_multicast_socket (GstRTSPStream * stream, * * Returns: (transfer full) (nullable): the multicast RTCP socket or %NULL if no * socket could be allocated for @family. Unref after usage + * + * Since: 1.14 */ GSocket * gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream * stream, @@ -5032,6 +5035,8 @@ gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked) * Unblocks the dataflow on @stream if it is linked. * * Returns: %TRUE on success + * + * Since: 1.14 */ gboolean gst_rtsp_stream_unblock_linked (GstRTSPStream * stream) @@ -5248,6 +5253,8 @@ gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop) * Checks whether the individual @stream is seekable. * * Returns: %TRUE if @stream is seekable, else %FALSE. + * + * Since: 1.14 */ gboolean gst_rtsp_stream_seekable (GstRTSPStream * stream) @@ -5302,6 +5309,8 @@ beach: * SETUP. * * Returns: %TRUE if the stream has been sucessfully updated. + * + * Since: 1.14 */ gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, @@ -5352,6 +5361,8 @@ unallowed_transport: * seek operations on it. * * Returns: %TRUE if the stream contains at least one sink element. + * + * Since: 1.14 */ gboolean gst_rtsp_stream_is_complete (GstRTSPStream * stream) @@ -5376,6 +5387,8 @@ gst_rtsp_stream_is_complete (GstRTSPStream * stream) * Checks whether the stream is a sender. * * Returns: %TRUE if the stream is a sender and %FALSE otherwise. + * + * Since: 1.14 */ gboolean gst_rtsp_stream_is_sender (GstRTSPStream * stream) @@ -5400,6 +5413,8 @@ gst_rtsp_stream_is_sender (GstRTSPStream * stream) * Checks whether the stream is a receiver. * * Returns: %TRUE if the stream is a receiver and %FALSE otherwise. + * + * Since: 1.14 */ gboolean gst_rtsp_stream_is_receiver (GstRTSPStream * stream) From abf6be1d7a7bbad5811181d1610bee17b28e4c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 23 Apr 2019 15:09:34 +0300 Subject: [PATCH 1608/1776] rtsp-server: Fix various Since markers --- gst/rtsp-server/rtsp-auth.c | 2 +- gst/rtsp-server/rtsp-client.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index e691196507..f676b804e4 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -323,7 +323,7 @@ gst_rtsp_auth_get_tls_certificate (GstRTSPAuth * auth) * If set to %NULL (the default), then peer certificate validation will always * set the %G_TLS_CERTIFICATE_UNKNOWN_CA error. * - * Since 1.6 + * Since: 1.6 */ void gst_rtsp_auth_set_tls_database (GstRTSPAuth * auth, GTlsDatabase * database) diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 59a0a7f687..8dbc3ddcd1 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -108,7 +108,7 @@ struct _GstRTSPClient { * @params_get: get parameters. This function should also initialize the * RTSP response(ctx->response) via a call to gst_rtsp_message_init_response() * @tunnel_http_response: called when a response to the GET request is about to - * be sent for a tunneled connection. The response can be modified. Since 1.4 + * be sent for a tunneled connection. The response can be modified. Since: 1.4 * * The client class structure. */ From 5b039416db66d0cb9986850830245a9fe8742ffb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 22 Oct 2018 11:29:24 +0200 Subject: [PATCH 1609/1776] docs: Port to hotdoc --- .gitignore | 1 + Makefile.am | 6 +- configure.ac | 7 - docs/Makefile.am | 20 -- docs/gst_plugins_cache.json | 452 ++++++++++++++++++++++++++++++++++++ docs/index.md | 1 + docs/meson.build | 87 +++++++ docs/plugin-index.md | 1 + docs/plugin-sitemap.txt | 1 + docs/sitemap.md | 2 + docs/sitemap.txt | 1 + docs/version.entities.in | 2 - gst/rtsp-server/meson.build | 1 + gst/rtsp-sink/meson.build | 1 + meson.build | 4 +- meson_options.txt | 2 + 16 files changed, 554 insertions(+), 35 deletions(-) delete mode 100644 docs/Makefile.am create mode 100644 docs/gst_plugins_cache.json create mode 100644 docs/index.md create mode 100644 docs/meson.build create mode 100644 docs/plugin-index.md create mode 100644 docs/plugin-sitemap.txt create mode 100644 docs/sitemap.md create mode 100644 docs/sitemap.txt delete mode 100644 docs/version.entities.in diff --git a/.gitignore b/.gitignore index db9a9f8cb6..6aaeba18e7 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,4 @@ stamp-h.in /tests/test-reuse /po +/build diff --git a/Makefile.am b/Makefile.am index 4489fc93ce..7b92d927fc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,3 @@ -DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc - if BUILD_EXAMPLES SUBDIRS_EXAMPLES = examples else @@ -16,16 +14,14 @@ SUBDIRS = \ gst \ common \ pkgconfig \ - docs \ $(SUBDIRS_EXAMPLES) \ $(SUBDIRS_TESTS) -DIST_SUBDIRS = gst common pkgconfig docs examples tests +DIST_SUBDIRS = gst common pkgconfig examples tests EXTRA_DIST = \ ChangeLog autogen.sh depcomp \ AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \ - docs/design/gst-rtp-server-design \ gst-rtsp-server.doap \ $(shell find "$(top_srcdir)" -type f -name meson.build ! -path "$(top_srcdir)/$(PACKAGE_TARNAME)-*" ) \ meson_options.txt diff --git a/configure.ac b/configure.ac index b5c52ce2ce..b1be5cea23 100644 --- a/configure.ac +++ b/configure.ac @@ -131,10 +131,6 @@ AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") dnl check for gobject-introspection GOBJECT_INTROSPECTION_CHECK([1.31.1]) -dnl check for documentation tools -AG_GST_DOCBOOK_CHECK -GTK_DOC_CHECK([1.12]) - dnl *** checks for libraries *** dnl check for pthreads @@ -352,9 +348,6 @@ tests/check/Makefile pkgconfig/Makefile pkgconfig/gstreamer-rtsp-server.pc pkgconfig/gstreamer-rtsp-server-uninstalled.pc -docs/Makefile -docs/version.entities -docs/libs/Makefile ]) AC_OUTPUT diff --git a/docs/Makefile.am b/docs/Makefile.am deleted file mode 100644 index 9f9f150bb3..0000000000 --- a/docs/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -if ENABLE_GTK_DOC -DOCS_SUBDIRS = libs -else -DOCS_SUBDIRS = -endif - -SUBDIRS = $(DOCS_SUBDIRS) -DIST_SUBDIRS = libs - -EXTRA_DIST = \ - version.entities.in - -upload: - @if test "x$(SUBDIRS)" != x; then \ - for a in $(SUBDIRS); do \ - cd $$a; \ - make upload; \ - cd ..; \ - done; \ - fi diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json new file mode 100644 index 0000000000..b405482e98 --- /dev/null +++ b/docs/gst_plugins_cache.json @@ -0,0 +1,452 @@ +{ + "rtspclientsink": { + "description": "RTSP client sink element", + "elements": { + "rtspclientsink": { + "author": "Jan Schmidt ", + "description": "Send data over the network via RTSP RECORD(RFC 2326)", + "hierarchy": [ + "GstRTSPClientSink", + "GstBin", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Sink/Network", + "long-name": "RTSP RECORD client", + "name": "rtspclientsink", + "pad-templates": { + "sink_%%u": { + "caps": "ANY", + "direction": "sink", + "presence": "request" + }, + "stream_%%u": { + "caps": "ANY", + "direction": "sink", + "presence": "request" + } + }, + "properties": { + "async-handling": { + "blurb": "The bin will handle Asynchronous state changes", + "construct": false, + "construct-only": false, + "default": "false", + "type-name": "gboolean", + "writable": true + }, + "debug": { + "blurb": "Dump request and response messages to stdout", + "construct": false, + "construct-only": false, + "default": "false", + "type-name": "gboolean", + "writable": true + }, + "do-rtsp-keep-alive": { + "blurb": "Send RTSP keep alive packets, disable for old incompatible server.", + "construct": false, + "construct-only": false, + "default": "true", + "type-name": "gboolean", + "writable": true + }, + "latency": { + "blurb": "Amount of ms to buffer", + "construct": false, + "construct-only": false, + "default": "2000", + "max": "-1", + "min": "0", + "type-name": "guint", + "writable": true + }, + "location": { + "blurb": "Location of the RTSP url to read", + "construct": false, + "construct-only": false, + "default": "NULL", + "type-name": "gchararray", + "writable": true + }, + "message-forward": { + "blurb": "Forwards all children messages", + "construct": false, + "construct-only": false, + "default": "false", + "type-name": "gboolean", + "writable": true + }, + "multicast-iface": { + "blurb": "The network interface on which to join the multicast group", + "construct": false, + "construct-only": false, + "default": "NULL", + "type-name": "gchararray", + "writable": true + }, + "name": { + "blurb": "The name of the object", + "construct": true, + "construct-only": false, + "default": "rtspclientsink0", + "hotdoc-fixed-default": true, + "type-name": "gchararray", + "writable": true + }, + "ntp-time-source": { + "blurb": "NTP time source for RTCP packets", + "construct": false, + "construct-only": false, + "default": "ntp (0)", + "enum": true, + "type-name": "GstRTSPClientSinkNtpTimeSource", + "values": [ + { + "desc": "NTP time based on realtime clock", + "name": "ntp", + "value": "0" + }, + { + "desc": "UNIX time based on realtime clock", + "name": "unix", + "value": "1" + }, + { + "desc": "Running time based on pipeline clock", + "name": "running-time", + "value": "2" + }, + { + "desc": "Pipeline clock time", + "name": "clock-time", + "value": "3" + } + ], + "writable": true + }, + "parent": { + "blurb": "The parent of the object", + "construct": false, + "construct-only": false, + "type-name": "GstObject", + "writable": true + }, + "port-range": { + "blurb": "Client port range that can be used to receive RTCP data, eg. 3000-3005 (NULL = no restrictions)", + "construct": false, + "construct-only": false, + "default": "NULL", + "type-name": "gchararray", + "writable": true + }, + "profiles": { + "blurb": "Allowed RTSP profiles", + "construct": false, + "construct-only": false, + "default": "avp", + "type-name": "GstRTSPProfile", + "values": [ + { + "desc": "GST_RTSP_PROFILE_UNKNOWN", + "name": "unknown", + "value": "0x00000000" + }, + { + "desc": "GST_RTSP_PROFILE_AVP", + "name": "avp", + "value": "0x00000001" + }, + { + "desc": "GST_RTSP_PROFILE_SAVP", + "name": "savp", + "value": "0x00000002" + }, + { + "desc": "GST_RTSP_PROFILE_AVPF", + "name": "avpf", + "value": "0x00000004" + }, + { + "desc": "GST_RTSP_PROFILE_SAVPF", + "name": "savpf", + "value": "0x00000008" + } + ], + "writable": true + }, + "protocols": { + "blurb": "Allowed lower transport protocols", + "construct": false, + "construct-only": false, + "default": "tcp+udp-mcast+udp", + "type-name": "GstRTSPLowerTrans", + "values": [ + { + "desc": "GST_RTSP_LOWER_TRANS_UNKNOWN", + "name": "unknown", + "value": "0x00000000" + }, + { + "desc": "GST_RTSP_LOWER_TRANS_UDP", + "name": "udp", + "value": "0x00000001" + }, + { + "desc": "GST_RTSP_LOWER_TRANS_UDP_MCAST", + "name": "udp-mcast", + "value": "0x00000002" + }, + { + "desc": "GST_RTSP_LOWER_TRANS_TCP", + "name": "tcp", + "value": "0x00000004" + }, + { + "desc": "GST_RTSP_LOWER_TRANS_HTTP", + "name": "http", + "value": "0x00000010" + }, + { + "desc": "GST_RTSP_LOWER_TRANS_TLS", + "name": "tls", + "value": "0x00000020" + } + ], + "writable": true + }, + "proxy": { + "blurb": "Proxy settings for HTTP tunneling. Format: [http://][user:passwd@]host[:port]", + "construct": false, + "construct-only": false, + "default": "NULL", + "type-name": "gchararray", + "writable": true + }, + "proxy-id": { + "blurb": "HTTP proxy URI user id for authentication", + "construct": false, + "construct-only": false, + "default": "NULL", + "type-name": "gchararray", + "writable": true + }, + "proxy-pw": { + "blurb": "HTTP proxy URI user password for authentication", + "construct": false, + "construct-only": false, + "default": "NULL", + "type-name": "gchararray", + "writable": true + }, + "retry": { + "blurb": "Max number of retries when allocating RTP ports.", + "construct": false, + "construct-only": false, + "default": "20", + "max": "65535", + "min": "0", + "type-name": "guint", + "writable": true + }, + "rtp-blocksize": { + "blurb": "RTP package size to suggest to server (0 = disabled)", + "construct": false, + "construct-only": false, + "default": "0", + "max": "65536", + "min": "0", + "type-name": "guint", + "writable": true + }, + "rtx-time": { + "blurb": "Amount of ms to buffer for retransmission. 0 disables retransmission", + "construct": false, + "construct-only": false, + "default": "500", + "max": "-1", + "min": "0", + "type-name": "guint", + "writable": true + }, + "sdes": { + "blurb": "The SDES items of this session", + "construct": false, + "construct-only": false, + "type-name": "GstStructure", + "writable": true + }, + "tcp-timeout": { + "blurb": "Fail after timeout microseconds on TCP connections (0 = disabled)", + "construct": false, + "construct-only": false, + "default": "20000000", + "max": "18446744073709551615", + "min": "0", + "type-name": "guint64", + "writable": true + }, + "timeout": { + "blurb": "Retry TCP transport after UDP timeout microseconds (0 = disabled)", + "construct": false, + "construct-only": false, + "default": "5000000", + "max": "18446744073709551615", + "min": "0", + "type-name": "guint64", + "writable": true + }, + "tls-database": { + "blurb": "TLS database with anchor certificate authorities used to validate the server certificate", + "construct": false, + "construct-only": false, + "type-name": "GTlsDatabase", + "writable": true + }, + "tls-interaction": { + "blurb": "A GTlsInteraction object to prompt the user for password or certificate", + "construct": false, + "construct-only": false, + "type-name": "GTlsInteraction", + "writable": true + }, + "tls-validation-flags": { + "blurb": "TLS certificate validation flags used to validate the server certificate", + "construct": false, + "construct-only": false, + "default": "validate-all", + "type-name": "GTlsCertificateFlags", + "values": [ + { + "desc": "G_TLS_CERTIFICATE_UNKNOWN_CA", + "name": "unknown-ca", + "value": "0x00000001" + }, + { + "desc": "G_TLS_CERTIFICATE_BAD_IDENTITY", + "name": "bad-identity", + "value": "0x00000002" + }, + { + "desc": "G_TLS_CERTIFICATE_NOT_ACTIVATED", + "name": "not-activated", + "value": "0x00000004" + }, + { + "desc": "G_TLS_CERTIFICATE_EXPIRED", + "name": "expired", + "value": "0x00000008" + }, + { + "desc": "G_TLS_CERTIFICATE_REVOKED", + "name": "revoked", + "value": "0x00000010" + }, + { + "desc": "G_TLS_CERTIFICATE_INSECURE", + "name": "insecure", + "value": "0x00000020" + }, + { + "desc": "G_TLS_CERTIFICATE_GENERIC_ERROR", + "name": "generic-error", + "value": "0x00000040" + }, + { + "desc": "G_TLS_CERTIFICATE_VALIDATE_ALL", + "name": "validate-all", + "value": "0x0000007f" + } + ], + "writable": true + }, + "udp-buffer-size": { + "blurb": "Size of the kernel UDP receive buffer in bytes, 0=default", + "construct": false, + "construct-only": false, + "default": "524288", + "max": "2147483647", + "min": "0", + "type-name": "gint", + "writable": true + }, + "udp-reconnect": { + "blurb": "Reconnect to the server if RTSP connection is closed when doing UDP", + "construct": false, + "construct-only": false, + "default": "true", + "type-name": "gboolean", + "writable": true + }, + "user-agent": { + "blurb": "The User-Agent string to send to the server", + "construct": false, + "construct-only": false, + "default": "GStreamer/1.15.0.1", + "type-name": "gchararray", + "writable": true + }, + "user-id": { + "blurb": "RTSP location URI user id for authentication", + "construct": false, + "construct-only": false, + "default": "NULL", + "type-name": "gchararray", + "writable": true + }, + "user-pw": { + "blurb": "RTSP location URI user password for authentication", + "construct": false, + "construct-only": false, + "default": "NULL", + "type-name": "gchararray", + "writable": true + } + }, + "rank": "none", + "signals": { + "accept-certificate": { + "args": [ + "GTlsConnection", + "GTlsCertificate", + "GTlsCertificateFlags" + ], + "retval": "gboolean" + }, + "handle-request": { + "args": [ + "gpointer", + "gpointer" + ], + "retval": "void" + }, + "new-manager": { + "args": [ + "GstElement" + ], + "retval": "void" + }, + "new-payloader": { + "args": [ + "GstElement" + ], + "retval": "void" + }, + "request-rtcp-key": { + "args": [ + "guint" + ], + "retval": "GstCaps" + } + } + } + }, + "filename": "libgstrtspclientsink.so", + "license": "LGPL", + "package": "GStreamer RTSP Server Library git", + "source": "gst-rtsp-server", + "url": "Unknown package origin" + } +} \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000000..b38638be78 --- /dev/null +++ b/docs/index.md @@ -0,0 +1 @@ +# GStreamer RTSP Server diff --git a/docs/meson.build b/docs/meson.build new file mode 100644 index 0000000000..ccfb7a15d0 --- /dev/null +++ b/docs/meson.build @@ -0,0 +1,87 @@ +build_hotdoc = false + +if meson.is_cross_build() + if get_option('doc').enabled() + error('Documentation enabled but building the doc while cross building is not supported yet.') + endif + + message('Documentation not built as building the docmentation while cross building is not supported yet.') + subdir_done() +endif + +required_hotdoc_extensions = ['gi-extension', 'gst-extension'] +if gst_dep.type_name() == 'internal' + gst_proj = subproject('gstreamer') + plugins_cache_generator = gst_proj.get_variable('plugins_cache_generator') +else + required_hotdoc_extensions += ['gst-extension'] + plugins_cache_generator = find_program(join_paths(gst_dep.get_pkgconfig_variable('libexecdir'), 'gstreamer-' + api_version, 'gst-plugins-doc-cache-generator'), + required: false) +endif + +plugins_cache = join_paths(meson.current_source_dir(), 'gst_plugins_cache.json') +if plugins_cache_generator.found() + plugins_doc_dep = custom_target('rtsp-server-plugins-doc-cache', + build_by_default: true, + command: [plugins_cache_generator, plugins_cache, '@OUTPUT@', '@INPUT@'], + input: plugins, + output: 'gst_plugins_cache.json', + ) +else + warning('GStreamer plugin inspector for documentation not found, can\'t update the cache') +endif + +hotdoc_p = find_program('hotdoc', required: get_option('doc')) +if not hotdoc_p.found() + message('Hotdoc not found, not building the documentation') + subdir_done() +endif + +hotdoc = import('hotdoc') +foreach extension: required_hotdoc_extensions + if not hotdoc.has_extensions(extension) + if get_option('doc').enabled() + error('Documentation enabled but @0@ missing'.format(extension)) + endif + + message('@0@ extension not found, not building documentation'.format(extension)) + subdir_done() + endif +endforeach + +if not build_gir + if get_option('doc').enabled() + error('Documentation enabled but introspection not built.') + endif + + message('Introspection not built, can\'t build the documentation') + subdir_done() +endif + +build_hotdoc = true +hotdoc = import('hotdoc') + +libs_doc = [hotdoc.generate_doc('gst-rtsp-server', + project_version: api_version, + gi_c_sources: ['../gst/rtsp-server/*.[hc]'], + gi_sources: rtsp_server_gir[0].full_path(), + sitemap: 'sitemap.txt', + index: 'index.md', + gi_index: 'index.md', + gi_smart_index: true, + gi_order_generated_subpages: true, +)] + +plugins_doc = [hotdoc.generate_doc('rtspclientsink', + project_version: api_version, + sitemap: 'plugin-sitemap.txt', + index: 'plugin-index.md', + gst_index: 'plugin-index.md', + gst_c_sources: ['../gst/rtsp-sink/*.[ch]'], + gst_dl_sources: [rtspsink.full_path()], + gst_smart_index: true, + dependencies: gst_rtsp_server_deps + [rtspsink], + gst_cache_file: plugins_cache, + gst_plugin_name: 'rtspclientsink', +)] +doc = libs_doc[0] \ No newline at end of file diff --git a/docs/plugin-index.md b/docs/plugin-index.md new file mode 100644 index 0000000000..091e6bd049 --- /dev/null +++ b/docs/plugin-index.md @@ -0,0 +1 @@ +# rtspclientsink diff --git a/docs/plugin-sitemap.txt b/docs/plugin-sitemap.txt new file mode 100644 index 0000000000..058a2713a4 --- /dev/null +++ b/docs/plugin-sitemap.txt @@ -0,0 +1 @@ +gst-index diff --git a/docs/sitemap.md b/docs/sitemap.md new file mode 100644 index 0000000000..09c1f9c157 --- /dev/null +++ b/docs/sitemap.md @@ -0,0 +1,2 @@ +gi-index + gst-index diff --git a/docs/sitemap.txt b/docs/sitemap.txt new file mode 100644 index 0000000000..4f91fcd8a3 --- /dev/null +++ b/docs/sitemap.txt @@ -0,0 +1 @@ +gi-index diff --git a/docs/version.entities.in b/docs/version.entities.in deleted file mode 100644 index 286989f56e..0000000000 --- a/docs/version.entities.in +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index 6e40cc64de..bfe0aebc21 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -79,6 +79,7 @@ if build_gir install : true, extra_args : gst_gir_extra_args, includes : ['Gst-1.0', 'GstRtsp-1.0', 'GstNet-1.0'], + sources_top_dir: meson.current_source_dir(), dependencies : gst_rtsp_server_deps, ) rtsp_server_gen_sources += [rtsp_server_gir] diff --git a/gst/rtsp-sink/meson.build b/gst/rtsp-sink/meson.build index ad3f40e6e3..c67d168269 100644 --- a/gst/rtsp-sink/meson.build +++ b/gst/rtsp-sink/meson.build @@ -11,3 +11,4 @@ rtspsink = library('gstrtspclientsink', install : true, install_dir : plugins_install_dir) pkgconfig.generate(rtspsink, install_dir : plugins_pkgconfig_install_dir) +plugins += [rtspsink] diff --git a/meson.build b/meson.build index c29989e120..eb8a4e4920 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('gst-rtsp-server', 'c', version : '1.17.0.1', - meson_version : '>= 0.47', + meson_version : '>= 0.48', default_options : ['warning_level=1', 'buildtype=debugoptimized']) gst_version = meson.project_version() @@ -187,6 +187,7 @@ if get_option('default_library') == 'shared' plugins_pkgconfig_install_dir = disabler() endif +plugins = [] subdir('gst') if not get_option('tests').disabled() subdir('tests') @@ -195,3 +196,4 @@ if not get_option('examples').disabled() subdir('examples') endif subdir('pkgconfig') +subdir('docs') diff --git a/meson_options.txt b/meson_options.txt index 24de52de1a..4bd238dc32 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -21,3 +21,5 @@ option('package-name', type : 'string', yield : true, option('package-origin', type : 'string', value : 'Unknown package origin', yield : true, description : 'package origin URL to use in plugins') +option('doc', type : 'feature', value : 'auto', yield: true, + description: 'Enable documentation.') From f4b20b010dbeb9c846e19bb6aabb439a1f2c1e47 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 23 Apr 2019 12:30:02 -0400 Subject: [PATCH 1610/1776] doc: Fix some docstrings --- docs/meson.build | 2 +- gst/rtsp-server/rtsp-context.c | 2 +- gst/rtsp-server/rtsp-session-pool.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/meson.build b/docs/meson.build index ccfb7a15d0..789da4b261 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -5,7 +5,7 @@ if meson.is_cross_build() error('Documentation enabled but building the doc while cross building is not supported yet.') endif - message('Documentation not built as building the docmentation while cross building is not supported yet.') + message('Documentation not built as building it while cross building is not supported yet.') subdir_done() endif diff --git a/gst/rtsp-server/rtsp-context.c b/gst/rtsp-server/rtsp-context.c index 4f08407d98..7c88153d68 100644 --- a/gst/rtsp-server/rtsp-context.c +++ b/gst/rtsp-server/rtsp-context.c @@ -56,7 +56,7 @@ gst_rtsp_context_get_current (void) /** * gst_rtsp_context_push_current: - * @ctx: a ##GstRTSPContext + * @ctx: a #GstRTSPContext * * Pushes @ctx onto the context stack. The current * context can then be received using gst_rtsp_context_get_current(). diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index 43ae44e9f2..ad3c67e23f 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -547,8 +547,7 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool) * locked so no further actions on @pool can be performed from @func. * * If @func returns #GST_RTSP_FILTER_REMOVE, the session will be set to the - * expired state with gst_rtsp_session_set_expired() and removed from - * @pool. + * expired state and removed from @pool. * * If @func returns #GST_RTSP_FILTER_KEEP, the session will remain in @pool. * From 89cc9e9201f124d39ee1a1f84a259f72a941c7b5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 May 2019 22:59:57 -0400 Subject: [PATCH 1611/1776] docs: Update plugins documentation cache --- docs/gst_plugins_cache.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index b405482e98..caa966d182 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -91,7 +91,7 @@ "blurb": "The name of the object", "construct": true, "construct-only": false, - "default": "rtspclientsink0", + "default": "NULL", "hotdoc-fixed-default": true, "type-name": "gchararray", "writable": true @@ -381,10 +381,11 @@ "writable": true }, "user-agent": { + "unstable-values": true, "blurb": "The User-Agent string to send to the server", "construct": false, "construct-only": false, - "default": "GStreamer/1.15.0.1", + "default": "GStreamer/@GSTREAMER_VERSION@", "type-name": "gchararray", "writable": true }, From ef88a27317859be41c343790bd2465fbb0d543e9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 16 May 2019 09:23:53 -0400 Subject: [PATCH 1612/1776] docs: Stop building the doc cache by default And update the cache Fixes https://gitlab.freedesktop.org/gstreamer/gst-docs/issues/36 --- docs/gst_plugins_cache.json | 2 +- docs/meson.build | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index caa966d182..cf27b24816 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -444,7 +444,7 @@ } } }, - "filename": "libgstrtspclientsink.so", + "filename": "gstrtspclientsink", "license": "LGPL", "package": "GStreamer RTSP Server Library git", "source": "gst-rtsp-server", diff --git a/docs/meson.build b/docs/meson.build index 789da4b261..efcb6f1510 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -22,7 +22,6 @@ endif plugins_cache = join_paths(meson.current_source_dir(), 'gst_plugins_cache.json') if plugins_cache_generator.found() plugins_doc_dep = custom_target('rtsp-server-plugins-doc-cache', - build_by_default: true, command: [plugins_cache_generator, plugins_cache, '@OUTPUT@', '@INPUT@'], input: plugins, output: 'gst_plugins_cache.json', @@ -84,4 +83,4 @@ plugins_doc = [hotdoc.generate_doc('rtspclientsink', gst_cache_file: plugins_cache, gst_plugin_name: 'rtspclientsink', )] -doc = libs_doc[0] \ No newline at end of file +doc = libs_doc[0] From da225337807caed50fd954b2346d7bb38897ae8c Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 29 May 2019 23:20:09 +0200 Subject: [PATCH 1613/1776] doc: remove xml from comments --- gst/rtsp-sink/gstrtspclientsink.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index c37449487f..8ddf70a2a2 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -62,12 +62,11 @@ * The new-payloader signal is fired when a payloader is created, in case * an app wants to do custom configuration (such as for MTU). * - * - * Example launch line + * ## Example launch line + * * |[ * gst-launch-1.0 videotestsrc ! jpegenc ! rtspclientsink location=rtsp://some.server/url * ]| Establish a connection to an RTSP server and send JPEG encoded video packets - * */ /* FIXMEs From 768975f71ba6b00170292f0c0b25b0057997c1a7 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 31 May 2019 18:53:36 +0200 Subject: [PATCH 1614/1776] docs: remove obsolete gtk-doc related files --- docs/libs/.gitignore | 22 - docs/libs/Makefile.am | 103 --- docs/libs/gst-rtsp-server-docs.sgml | 53 -- docs/libs/gst-rtsp-server-sections.txt | 881 ------------------------- docs/libs/gst-rtsp-server.types | 52 -- 5 files changed, 1111 deletions(-) delete mode 100644 docs/libs/.gitignore delete mode 100644 docs/libs/Makefile.am delete mode 100644 docs/libs/gst-rtsp-server-docs.sgml delete mode 100644 docs/libs/gst-rtsp-server-sections.txt delete mode 100644 docs/libs/gst-rtsp-server.types diff --git a/docs/libs/.gitignore b/docs/libs/.gitignore deleted file mode 100644 index 511b34c4e1..0000000000 --- a/docs/libs/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -*.stamp -html -tmpl -xml -Makefile -Makefile.in -*-decl.txt -*-decl-list.txt -*-presed-scan.c -*-undeclared.txt -*-undocumented.txt -*-unused.txt -*-overrides.txt -*.args -*.hierarchy -*.interfaces -*.prerequisites -*.signals -doc-registry.xml - -*-unused.sgml -*.bak diff --git a/docs/libs/Makefile.am b/docs/libs/Makefile.am deleted file mode 100644 index 38d8837b04..0000000000 --- a/docs/libs/Makefile.am +++ /dev/null @@ -1,103 +0,0 @@ -GST_DOC_SCANOBJ = $(top_srcdir)/common/gstdoc-scangobj - -## Process this file with automake to produce Makefile.in - -# The name of the module, e.g. 'glib'. -MODULE=gst-rtsp-server -DOC_MODULE=$(MODULE) - -# for upload-doc.mak -DOC=$(MODULE) -FORMATS=html -html: html-build.stamp -include $(top_srcdir)/common/upload-doc.mak - -# generated basefiles -#basefiles = \ -## $(DOC_MODULE).types \ -# $(DOC_MODULE)-sections.txt \ -# $(DOC_MODULE)-docs.sgml - -# ugly hack to make -unused.sgml work -#unused-build.stamp: -# BUILDDIR=`pwd` && \ -# cd $(srcdir)/tmpl && \ -# ln -sf gstreamer-libs-unused.sgml \ -# $$BUILDDIR/tmpl/gstreamer-libs-@GST_API_VERSION@-unused.sgml -# touch unused-build.stamp - -# these rules are added to create parallel docs using GST_API_VERSION -#$(basefiles): gstreamer-libs-@GST_API_VERSION@%: gstreamer-libs% -# cp $< $@ - -#CLEANFILES = $(basefiles) - -# The top-level SGML file. Change it if you want. -DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml - -# The directory containing the source code. Relative to $(top_srcdir). -# gtk-doc will search all .c & .h files beneath here for inline comments -# documenting functions and macros. -DOC_SOURCE_DIR = $(top_srcdir)/gst/rtsp-server/ -DOC_BUILD_DIR=$(top_builddir)/gst/rtsp-server/ - -SCAN_OPTIONS= - -# FIXME : -# there's something wrong with gstreamer-sections.txt not being in the dist -# maybe it doesn't resolve; we're adding it below for now -#EXTRA_DIST = gstreamer.types.in gstreamer.hierarchy $(DOC_MODULE)-sections.txt gstreamer-sections.txt $(DOC_MAIN_SGML_FILE) - -# Extra options to supply to gtkdoc-mkdb. -MKDB_OPTIONS=--sgml-mode --source-suffixes=c,h,cc,m - -# Extra options to supply to gtkdoc-fixref. -FIXXREF_OPTIONS=--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html \ - --extra-dir=$(GST_PREFIX)/share/gtk-doc/html \ - --extra-dir=$(GSTPB_PREFIX)/share/gtk-doc/html - -# Used for dependencies. -HFILE_GLOB=$(DOC_SOURCE_DIR)/*.h -CFILE_GLOB=$(DOC_SOURCE_DIR)/*.c - -SCANOBJ_DEPS = \ - $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la - -# Extra options to supply to gtkdoc-scan. -SCANOBJ_OPTIONS=--type-init-func="g_type_init();gst_init(&argc,&argv)" - -# Header files to ignore when scanning. -IGNORE_HFILES = -IGNORE_CFILES = - -# we add all .h files of elements that have signals/args we want -# sadly this also pulls in the private methods - maybe we should -# move those around in the source ? -# also, we should add some stuff here conditionally based on whether -# or not the plugin will actually build -# but I'm not sure about that - it might be this Just Works given that -# the registry won't have the element - -EXTRA_HFILES = - -# Images to copy into HTML directory. -HTML_IMAGES = - -# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). -content_files = - -# Other files to distribute. -extra_files = - -# CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib -# contains GtkObjects/GObjects and you want to document signals and properties. -GTKDOC_CFLAGS = -I$(top_srcdir) $(GST_PLUGINS_BASE_CFLAGS) \ - $(GST_BASE_CFLAGS) $(GST_CFLAGS) -GTKDOC_LIBS = $(SCANOBJ_DEPS) $(GST_PLUGINS_BASE_LIBS) \ - $(GST_BASE_LIBS) $(GST_LIBS) $(GCOV_LIBS) - -# If you need to override some of the declarations, place them in this file -# and uncomment this line. -DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt - -include $(top_srcdir)/common/gtk-doc.mak diff --git a/docs/libs/gst-rtsp-server-docs.sgml b/docs/libs/gst-rtsp-server-docs.sgml deleted file mode 100644 index 26c2a51011..0000000000 --- a/docs/libs/gst-rtsp-server-docs.sgml +++ /dev/null @@ -1,53 +0,0 @@ - - -%version-entities; -]> - - - - GStreamer RTSP Server Reference Manual - - for GStreamer RTSP Server &GST_VERSION; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Object Hierarchy - - - - - API Index - - - - - diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt deleted file mode 100644 index c1627da451..0000000000 --- a/docs/libs/gst-rtsp-server-sections.txt +++ /dev/null @@ -1,881 +0,0 @@ -
-rtsp-address-pool -GstRTSPAddressPool - - -GST_RTSP_ADDRESS_POOL_ANY_IPV4 -GST_RTSP_ADDRESS_POOL_ANY_IPV6 -GstRTSPAddress -GstRTSPAddressFlags -gst_rtsp_address_copy -gst_rtsp_address_free - - -GstRTSPAddressPool -GstRTSPAddressPoolClass -GstRTSPAddressPoolResult -gst_rtsp_address_pool_new -gst_rtsp_address_pool_clear -gst_rtsp_address_pool_dump -gst_rtsp_address_pool_add_range -gst_rtsp_address_pool_has_unicast_addresses -gst_rtsp_address_pool_acquire_address -gst_rtsp_address_pool_reserve_address - -GST_RTSP_ADDRESS_POOL_CAST -GST_RTSP_ADDRESS_POOL_CLASS_CAST -GST_IS_RTSP_ADDRESS_POOL -GST_IS_RTSP_ADDRESS_POOL_CLASS -GST_RTSP_ADDRESS_POOL -GST_RTSP_ADDRESS_POOL_CLASS -GST_RTSP_ADDRESS_POOL_GET_CLASS -GST_TYPE_RTSP_ADDRESS_POOL -GstRTSPAddressPoolPrivate -gst_rtsp_address_get_type -gst_rtsp_address_pool_get_type -
- -
-rtsp-auth -GstRTSPAuth -GstRTSPAuth -GstRTSPAuthClass -gst_rtsp_auth_new - -gst_rtsp_auth_get_tls_certificate -gst_rtsp_auth_set_tls_certificate -gst_rtsp_auth_get_tls_database -gst_rtsp_auth_set_tls_database -gst_rtsp_auth_get_tls_authentication_mode -gst_rtsp_auth_set_tls_authentication_mode -gst_rtsp_auth_set_realm -gst_rtsp_auth_get_realm -gst_rtsp_auth_make_basic -gst_rtsp_auth_add_basic -gst_rtsp_auth_remove_basic -gst_rtsp_auth_add_digest -gst_rtsp_auth_remove_digest -gst_rtsp_auth_parse_htdigest -gst_rtsp_auth_check -gst_rtsp_auth_get_default_token -gst_rtsp_auth_set_default_token -gst_rtsp_auth_get_supported_methods -gst_rtsp_auth_set_supported_methods - - -GST_RTSP_AUTH_CHECK_CONNECT -GST_RTSP_AUTH_CHECK_URL -GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS -GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT -GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS - - -GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE -GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS - - -GST_RTSP_PERM_MEDIA_FACTORY_ACCESS -GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT - -GST_RTSP_AUTH_CAST -GST_RTSP_AUTH_CLASS_CAST -GST_IS_RTSP_AUTH -GST_IS_RTSP_AUTH_CLASS -GST_RTSP_AUTH -GST_RTSP_AUTH_CLASS -GST_RTSP_AUTH_GET_CLASS -GST_TYPE_RTSP_AUTH -GstRTSPAuthPrivate -gst_rtsp_auth_get_type -
- -
-rtsp-client -GstRTSPClient - -GstRTSPClient -GstRTSPClientClass - -gst_rtsp_client_new -gst_rtsp_client_close - -gst_rtsp_client_get_session_pool -gst_rtsp_client_set_session_pool - -gst_rtsp_client_get_mount_points -gst_rtsp_client_set_mount_points - -gst_rtsp_client_get_auth -gst_rtsp_client_set_auth - -gst_rtsp_client_get_thread_pool -gst_rtsp_client_set_thread_pool - -gst_rtsp_client_get_connection -gst_rtsp_client_set_connection - -gst_rtsp_client_attach - -GstRTSPClientSendFunc -gst_rtsp_client_set_send_func -GstRTSPClientSendMessagesFunc -gst_rtsp_client_set_send_messages_func - -gst_rtsp_client_handle_message -gst_rtsp_client_send_message - -GstRTSPClientSessionFilterFunc -gst_rtsp_client_session_filter - -GST_RTSP_CLIENT_CAST -GST_RTSP_CLIENT_CLASS_CAST -GST_IS_RTSP_CLIENT -GST_IS_RTSP_CLIENT_CLASS -GST_RTSP_CLIENT -GST_RTSP_CLIENT_CLASS -GST_RTSP_CLIENT_GET_CLASS -GST_TYPE_RTSP_CLIENT -GstRTSPClientPrivate -gst_rtsp_client_get_type -
- -
-rtsp-context -GstRTSPContext -GstRTSPContext -gst_rtsp_context_get_current -gst_rtsp_context_push_current -gst_rtsp_context_pop_current - -GST_TYPE_RTSP_CONTEXT -gst_rtsp_context_get_type -
- -
-rtsp-media -GstRTSPMedia -GstRTSPMedia -GstRTSPMediaClass -gst_rtsp_media_new -gst_rtsp_media_get_element -gst_rtsp_media_take_pipeline - -gst_rtsp_media_set_permissions -gst_rtsp_media_get_permissions - -gst_rtsp_media_set_shared -gst_rtsp_media_is_shared - -gst_rtsp_media_set_reusable -gst_rtsp_media_is_reusable - -gst_rtsp_media_set_profiles -gst_rtsp_media_get_profiles - -gst_rtsp_media_set_protocols -gst_rtsp_media_get_protocols - -gst_rtsp_media_set_eos_shutdown -gst_rtsp_media_is_eos_shutdown - -gst_rtsp_media_set_address_pool -gst_rtsp_media_get_address_pool - -gst_rtsp_media_set_buffer_size -gst_rtsp_media_get_buffer_size - -gst_rtsp_media_set_retransmission_time -gst_rtsp_media_get_retransmission_time - -gst_rtsp_media_set_do_retransmission -gst_rtsp_media_get_do_retransmission - -gst_rtsp_media_set_latency -gst_rtsp_media_get_latency - -gst_rtsp_media_setup_sdp -gst_rtsp_media_setup_sdp_full -gst_rtsp_media_handle_sdp -gst_rtsp_media_handle_sdp_full - - -gst_rtsp_media_prepare -gst_rtsp_media_unprepare -GstRTSPMediaStatus -gst_rtsp_media_get_status - - -gst_rtsp_media_set_suspend_mode -gst_rtsp_media_get_suspend_mode - -GstRTSPSuspendMode -gst_rtsp_media_suspend -gst_rtsp_media_unsuspend - - -gst_rtsp_media_collect_streams -gst_rtsp_media_create_stream -gst_rtsp_media_n_streams -gst_rtsp_media_get_stream -gst_rtsp_media_find_stream - - -gst_rtsp_media_seek -gst_rtsp_media_get_range_string - -gst_rtsp_media_set_state -gst_rtsp_media_set_pipeline_state - - -gst_rtsp_media_get_clock -gst_rtsp_media_set_clock -gst_rtsp_media_get_base_time -gst_rtsp_media_use_time_provider -gst_rtsp_media_is_time_provider -gst_rtsp_media_get_time_provider - -GST_RTSP_MEDIA_CAST -GST_RTSP_MEDIA_CLASS_CAST -GST_IS_RTSP_MEDIA -GST_IS_RTSP_MEDIA_CLASS -GST_RTSP_MEDIA -GST_RTSP_MEDIA_CLASS -GST_RTSP_MEDIA_GET_CLASS -GST_TYPE_RTSP_MEDIA -GstRTSPMediaPrivate -gst_rtsp_media_get_type -GST_TYPE_RTSP_SUSPEND_MODE -gst_rtsp_suspend_mode_get_type -
- -
-rtsp-media-factory -GstRTSPMediaFactory -GstRTSPMediaFactory -GstRTSPMediaFactoryClass -gst_rtsp_media_factory_new - -gst_rtsp_media_factory_get_launch -gst_rtsp_media_factory_set_launch - -gst_rtsp_media_factory_get_permissions -gst_rtsp_media_factory_set_permissions -gst_rtsp_media_factory_add_role -gst_rtsp_media_factory_add_role_from_structure - -gst_rtsp_media_factory_get_clock -gst_rtsp_media_factory_set_clock - -gst_rtsp_media_factory_set_shared -gst_rtsp_media_factory_is_shared - -gst_rtsp_media_factory_is_eos_shutdown -gst_rtsp_media_factory_set_eos_shutdown - -gst_rtsp_media_factory_get_protocols -gst_rtsp_media_factory_set_protocols - -gst_rtsp_media_factory_get_transport_mode -gst_rtsp_media_factory_set_transport_mode - -gst_rtsp_media_factory_set_profiles -gst_rtsp_media_factory_get_profiles - -gst_rtsp_media_factory_get_address_pool -gst_rtsp_media_factory_set_address_pool - -gst_rtsp_media_factory_get_buffer_size -gst_rtsp_media_factory_set_buffer_size - -gst_rtsp_media_factory_get_suspend_mode -gst_rtsp_media_factory_set_suspend_mode - -gst_rtsp_media_factory_set_retransmission_time -gst_rtsp_media_factory_get_retransmission_time - -gst_rtsp_media_factory_set_do_retransmission -gst_rtsp_media_factory_get_do_retransmission - -gst_rtsp_media_factory_set_latency -gst_rtsp_media_factory_get_latency - -gst_rtsp_media_factory_set_media_gtype -gst_rtsp_media_factory_get_media_gtype - -gst_rtsp_media_factory_construct -gst_rtsp_media_factory_construct_full -gst_rtsp_media_factory_create_element -gst_rtsp_media_factory_create_element_full - - -GST_RTSP_MEDIA_FACTORY_CAST -GST_RTSP_MEDIA_FACTORY_CLASS_CAST -GST_IS_RTSP_MEDIA_FACTORY -GST_IS_RTSP_MEDIA_FACTORY_CLASS -GST_RTSP_MEDIA_FACTORY -GST_RTSP_MEDIA_FACTORY_CLASS -GST_RTSP_MEDIA_FACTORY_GET_CLASS -GST_TYPE_RTSP_MEDIA_FACTORY -GstRTSPMediaFactoryPrivate -gst_rtsp_media_factory_get_type -
- -
-rtsp-media-factory-uri -GstRTSPMediaFactoryURI -GstRTSPMediaFactoryURI -GstRTSPMediaFactoryURIClass -gst_rtsp_media_factory_uri_new -gst_rtsp_media_factory_uri_set_uri -gst_rtsp_media_factory_uri_get_uri - -GST_RTSP_MEDIA_FACTORY_URI_CAST -GST_RTSP_MEDIA_FACTORY_URI_CLASS_CAST -GST_IS_RTSP_MEDIA_FACTORY_URI -GST_IS_RTSP_MEDIA_FACTORY_URI_CLASS -GST_RTSP_MEDIA_FACTORY_URI -GST_RTSP_MEDIA_FACTORY_URI_CLASS -GST_RTSP_MEDIA_FACTORY_URI_GET_CLASS -GST_TYPE_RTSP_MEDIA_FACTORY_URI -GstRTSPMediaFactoryURIPrivate -gst_rtsp_media_factory_uri_get_type -
- -
-rtsp-mount-points -GstRTSPMountPoints -GstRTSPMountPoints -GstRTSPMountPointsClass -gst_rtsp_mount_points_new -gst_rtsp_mount_points_add_factory -gst_rtsp_mount_points_remove_factory -gst_rtsp_mount_points_match -gst_rtsp_mount_points_make_path - -GST_RTSP_MOUNT_POINTS_CAST -GST_RTSP_MOUNT_POINTS_CLASS_CAST -GST_IS_RTSP_MOUNT_POINTS -GST_IS_RTSP_MOUNT_POINTS_CLASS -GST_RTSP_MOUNT_POINTS -GST_RTSP_MOUNT_POINTS_CLASS -GST_RTSP_MOUNT_POINTS_GET_CLASS -GST_TYPE_RTSP_MOUNT_POINTS -GstRTSPMountPointsPrivate -gst_rtsp_mount_points_get_type -
- -
-rtsp-params -GstRTSPParams -gst_rtsp_params_get -gst_rtsp_params_set -
- -
-rtsp-permissions -GstRTSPPermissions -GstRTSPPermissions -gst_rtsp_permissions_new -gst_rtsp_permissions_ref -gst_rtsp_permissions_unref -gst_rtsp_permissions_add_role -gst_rtsp_permissions_add_role_valist -gst_rtsp_permissions_add_role_empty -gst_rtsp_permissions_add_role_from_structure -gst_rtsp_permissions_add_permission_for_role -gst_rtsp_permissions_remove_role -gst_rtsp_permissions_get_role -gst_rtsp_permissions_is_allowed - -GST_RTSP_PERMISSIONS_CAST -GST_IS_RTSP_PERMISSIONS -GST_RTSP_PERMISSIONS -GST_TYPE_RTSP_PERMISSIONS -gst_rtsp_permissions_get_type -
- -
-rtsp-sdp -GstRTSPSdp -GstSDPInfo -gst_rtsp_sdp_from_media -
- -
-rtsp-server -GstRTSPServer -GstRTSPServer -GstRTSPServerClass - -gst_rtsp_server_new - -gst_rtsp_server_get_address -gst_rtsp_server_set_address - -gst_rtsp_server_get_service -gst_rtsp_server_set_service - -gst_rtsp_server_get_backlog -gst_rtsp_server_set_backlog - -gst_rtsp_server_get_bound_port - -gst_rtsp_server_get_mount_points -gst_rtsp_server_set_mount_points - -gst_rtsp_server_get_session_pool -gst_rtsp_server_set_session_pool - -gst_rtsp_server_get_thread_pool -gst_rtsp_server_set_thread_pool - -gst_rtsp_server_get_auth -gst_rtsp_server_set_auth - -gst_rtsp_server_transfer_connection -gst_rtsp_server_io_func -gst_rtsp_server_create_socket -gst_rtsp_server_create_source -gst_rtsp_server_attach - -GstRTSPServerClientFilterFunc -gst_rtsp_server_client_filter - - -GST_IS_RTSP_SERVER -GST_RTSP_SERVER_CAST -GST_RTSP_SERVER_CLASS_CAST -GST_IS_RTSP_SERVER_CLASS -GST_RTSP_SERVER -GST_RTSP_SERVER_CLASS -GST_RTSP_SERVER_GET_CLASS -GST_TYPE_RTSP_SERVER -GstRTSPServerPrivate -gst_rtsp_server_get_type -
- -
-rtsp-session -GstRTSPSession -GstRTSPSession -GstRTSPSessionClass - -gst_rtsp_session_new -gst_rtsp_session_get_sessionid - -gst_rtsp_session_get_header - -gst_rtsp_session_set_timeout -gst_rtsp_session_get_timeout - -gst_rtsp_session_touch -gst_rtsp_session_prevent_expire -gst_rtsp_session_allow_expire -gst_rtsp_session_next_timeout -gst_rtsp_session_is_expired - -gst_rtsp_session_manage_media -gst_rtsp_session_release_media - -gst_rtsp_session_get_media - -GstRTSPFilterResult -GstRTSPSessionFilterFunc -gst_rtsp_session_filter - -GST_RTSP_SESSION_CAST -GST_RTSP_SESSION_CLASS_CAST -GST_IS_RTSP_SESSION -GST_IS_RTSP_SESSION_CLASS -GST_RTSP_SESSION -GST_RTSP_SESSION_CLASS -GST_RTSP_SESSION_GET_CLASS -GST_TYPE_RTSP_SESSION -GstRTSPSessionPrivate -gst_rtsp_session_get_type -
- -
-rtsp-session-media -GstRTSPSessionMedia -GstRTSPSessionMedia -GstRTSPSessionMediaClass -gst_rtsp_session_media_new -gst_rtsp_session_media_matches - -gst_rtsp_session_media_get_media -gst_rtsp_session_media_get_base_time -gst_rtsp_session_media_get_rtpinfo - -gst_rtsp_session_media_set_state - -gst_rtsp_session_media_get_rtsp_state -gst_rtsp_session_media_set_rtsp_state - -gst_rtsp_session_media_get_transport -gst_rtsp_session_media_set_transport - -gst_rtsp_session_media_alloc_channels - -GST_RTSP_SESSION_MEDIA_CAST -GST_RTSP_SESSION_MEDIA_CLASS_CAST -GST_IS_RTSP_SESSION_MEDIA -GST_IS_RTSP_SESSION_MEDIA_CLASS -GST_RTSP_SESSION_MEDIA -GST_RTSP_SESSION_MEDIA_CLASS -GST_RTSP_SESSION_MEDIA_GET_CLASS -GST_TYPE_RTSP_SESSION_MEDIA -GstRTSPSessionMediaPrivate -gst_rtsp_session_media_get_type -
- -
-rtsp-session-pool -GstRTSPSessionPool -GstRTSPSessionPool -GstRTSPSessionPoolClass -gst_rtsp_session_pool_new - -gst_rtsp_session_pool_get_max_sessions -gst_rtsp_session_pool_set_max_sessions - -gst_rtsp_session_pool_get_n_sessions - -gst_rtsp_session_pool_create -gst_rtsp_session_pool_find -gst_rtsp_session_pool_remove - -gst_rtsp_session_pool_cleanup - -GstRTSPSessionPoolFunc -gst_rtsp_session_pool_create_watch - -GstRTSPSessionPoolFilterFunc -gst_rtsp_session_pool_filter - -GST_RTSP_SESSION_POOL_CAST -GST_RTSP_SESSION_POOL_CLASS_CAST -GST_IS_RTSP_SESSION_POOL -GST_IS_RTSP_SESSION_POOL_CLASS -GST_RTSP_SESSION_POOL -GST_RTSP_SESSION_POOL_CLASS -GST_RTSP_SESSION_POOL_GET_CLASS -GST_TYPE_RTSP_SESSION_POOL -GstRTSPSessionPoolPrivate -gst_rtsp_session_pool_get_type -
- -
-rtsp-stream -GstRTSPStream -GstRTSPStream -GstRTSPStreamClass -gst_rtsp_stream_new - -gst_rtsp_stream_get_index -gst_rtsp_stream_get_srcpad - -gst_rtsp_stream_get_control -gst_rtsp_stream_set_control -gst_rtsp_stream_has_control - -gst_rtsp_stream_get_mtu -gst_rtsp_stream_set_mtu - -gst_rtsp_stream_get_dscp_qos -gst_rtsp_stream_set_dscp_qos - -gst_rtsp_stream_set_profiles -gst_rtsp_stream_get_profiles - -gst_rtsp_stream_get_protocols -gst_rtsp_stream_set_protocols - -gst_rtsp_stream_get_retransmission_time -gst_rtsp_stream_set_retransmission_time - -gst_rtsp_stream_set_buffer_size -gst_rtsp_stream_get_buffer_size - -gst_rtsp_stream_set_seqnum_offset -gst_rtsp_stream_get_current_seqnum - -gst_rtsp_stream_is_transport_supported - -gst_rtsp_stream_get_address_pool -gst_rtsp_stream_set_address_pool -gst_rtsp_stream_reserve_address - -gst_rtsp_stream_join_bin -gst_rtsp_stream_leave_bin - -gst_rtsp_stream_get_server_port -gst_rtsp_stream_get_multicast_address -gst_rtsp_stream_get_rtpsession -gst_rtsp_stream_get_ssrc -gst_rtsp_stream_get_rtpinfo -gst_rtsp_stream_get_caps -gst_rtsp_stream_get_pt - -gst_rtsp_stream_recv_rtcp -gst_rtsp_stream_recv_rtp - -gst_rtsp_stream_add_transport -gst_rtsp_stream_remove_transport - -gst_rtsp_stream_get_rtp_socket -gst_rtsp_stream_get_rtcp_socket - -gst_rtsp_stream_set_blocked -gst_rtsp_stream_is_blocking - -gst_rtsp_stream_query_stop -gst_rtsp_stream_query_position - -gst_rtsp_stream_update_crypto - -gst_rtsp_stream_set_pt_map -gst_rtsp_stream_request_aux_sender -gst_rtsp_stream_request_aux_receiver - -gst_rtsp_stream_seekable - -GstRTSPStreamTransportFilterFunc -gst_rtsp_stream_transport_filter - -gst_rtsp_stream_set_ulpfec_pt -gst_rtsp_stream_get_ulpfec_pt -gst_rtsp_stream_set_ulpfec_percentage -gst_rtsp_stream_get_ulpfec_percentage -gst_rtsp_stream_request_ulpfec_decoder -gst_rtsp_stream_request_ulpfec_encoder - - -GST_RTSP_STREAM_CAST -GST_RTSP_STREAM_CLASS_CAST -GST_IS_RTSP_STREAM -GST_IS_RTSP_STREAM_CLASS -GST_RTSP_STREAM -GST_RTSP_STREAM_CLASS -GST_RTSP_STREAM_GET_CLASS -GST_TYPE_RTSP_STREAM -GstRTSPStreamPrivate -gst_rtsp_stream_get_type -
- -
-rtsp-stream-transport -GstRTSPStreamTransport -GstRTSPStreamTransport -GstRTSPStreamTransportClass -gst_rtsp_stream_transport_new - -gst_rtsp_stream_transport_get_stream - -gst_rtsp_stream_transport_get_transport -gst_rtsp_stream_transport_set_transport - -gst_rtsp_stream_transport_get_url -gst_rtsp_stream_transport_set_url - -gst_rtsp_stream_transport_get_rtpinfo - -GstRTSPSendFunc -gst_rtsp_stream_transport_set_callbacks -GstRTSPSendListFunc -gst_rtsp_stream_transport_set_list_callbacks - -GstRTSPKeepAliveFunc -gst_rtsp_stream_transport_set_keepalive -gst_rtsp_stream_transport_keep_alive - -gst_rtsp_stream_transport_set_active - -gst_rtsp_stream_transport_set_timed_out -gst_rtsp_stream_transport_is_timed_out - -gst_rtsp_stream_transport_send_rtp -gst_rtsp_stream_transport_send_rtp_list -gst_rtsp_stream_transport_send_rtcp -gst_rtsp_stream_transport_send_rtcp_list - - -GST_RTSP_STREAM_TRANSPORT_CAST -GST_RTSP_STREAM_TRANSPORT_CLASS_CAST -GST_IS_RTSP_STREAM_TRANSPORT -GST_IS_RTSP_STREAM_TRANSPORT_CLASS -GST_RTSP_STREAM_TRANSPORT -GST_RTSP_STREAM_TRANSPORT_CLASS -GST_RTSP_STREAM_TRANSPORT_GET_CLASS -GST_TYPE_RTSP_STREAM_TRANSPORT -GstRTSPStreamTransportPrivate -gst_rtsp_stream_transport_get_type -
- -
-rtsp-thread-pool -GstRTSPThreadPool - -GstRTSPThreadType -GstRTSPThread - -gst_rtsp_thread_new -gst_rtsp_thread_ref -gst_rtsp_thread_unref -gst_rtsp_thread_reuse -gst_rtsp_thread_stop - - -GstRTSPThreadPool -GstRTSPThreadPoolClass -gst_rtsp_thread_pool_new - -gst_rtsp_thread_pool_get_max_threads -gst_rtsp_thread_pool_set_max_threads - -gst_rtsp_thread_pool_get_thread -gst_rtsp_thread_pool_cleanup - -GST_RTSP_THREAD_CAST -GST_RTSP_THREAD_POOL_CAST -GST_RTSP_THREAD_POOL_CLASS_CAST -GST_IS_RTSP_THREAD -GST_IS_RTSP_THREAD_POOL -GST_IS_RTSP_THREAD_POOL_CLASS -GST_RTSP_THREAD -GST_RTSP_THREAD_POOL -GST_RTSP_THREAD_POOL_CLASS -GST_RTSP_THREAD_POOL_GET_CLASS -GST_TYPE_RTSP_THREAD -GST_TYPE_RTSP_THREAD_POOL -GstRTSPThreadPoolPrivate -gst_rtsp_thread_get_type -gst_rtsp_thread_pool_get_type -
- -
-rtsp-token -GstRTSPToken -GstRTSPToken -gst_rtsp_token_new_empty -gst_rtsp_token_new -gst_rtsp_token_new_valist -gst_rtsp_token_ref -gst_rtsp_token_unref -gst_rtsp_token_get_structure -gst_rtsp_token_writable_structure -gst_rtsp_token_set_string -gst_rtsp_token_get_string -gst_rtsp_token_set_bool -gst_rtsp_token_is_allowed - -GST_RTSP_TOKEN_CAST -GST_IS_RTSP_TOKEN -GST_RTSP_TOKEN -GST_TYPE_RTSP_TOKEN -gst_rtsp_token_get_type -
- -
-rtsp-onvif-server -GstRTSPOnvifServer -GstRTSPOnvifServer -GstRTSPOnvifServerClass - -gst_rtsp_onvif_server_new - -GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT - -gst_rtsp_onvif_server_get_type -GST_TYPE_RTSP_ONVIF_SERVER -GST_RTSP_ONVIF_SERVER -GST_RTSP_ONVIF_SERVER_CAST -GST_RTSP_ONVIF_SERVER_CLASS -GST_RTSP_ONVIF_SERVER_CLASS_CAST -GST_RTSP_ONVIF_SERVER_GET_CLASS -GST_IS_RTSP_ONVIF_SERVER -GST_IS_RTSP_ONVIF_SERVER_CLASS -
- -
-rtsp-onvif-server -GstRTSPOnvifServer -GstRTSPOnvifServer -GstRTSPOnvifServerClass - -gst_rtsp_onvif_server_new - -gst_rtsp_onvif_server_get_type -GST_TYPE_RTSP_ONVIF_SERVER -GST_RTSP_ONVIF_SERVER -GST_RTSP_ONVIF_SERVER_CAST -GST_RTSP_ONVIF_SERVER_CLASS -GST_RTSP_ONVIF_SERVER_CLASS_CAST -GST_RTSP_ONVIF_SERVER_GET_CLASS -GST_IS_RTSP_ONVIF_SERVER -GST_IS_RTSP_ONVIF_SERVER_CLASS -
- -
-rtsp-onvif-client -GstRTSPOnvifClient -GstRTSPOnvifClient -GstRTSPOnvifClientClass - -gst_rtsp_onvif_client_get_type -GST_TYPE_RTSP_ONVIF_CLIENT -GST_RTSP_ONVIF_CLIENT -GST_RTSP_ONVIF_CLIENT_CAST -GST_RTSP_ONVIF_CLIENT_CLASS -GST_RTSP_ONVIF_CLIENT_CLASS_CAST -GST_RTSP_ONVIF_CLIENT_GET_CLASS -GST_IS_RTSP_ONVIF_CLIENT -GST_IS_RTSP_ONVIF_CLIENT_CLASS -
- -
-rtsp-onvif-media-factory -GstRTSPOnvifMediaFactory -GstRTSPOnvifMediaFactory -GstRTSPOnvifMediaFactoryClass - -gst_rtsp_onvif_media_factory_new -gst_rtsp_onvif_media_factory_has_backchannel_support -gst_rtsp_onvif_media_factory_set_backchannel_bandwidth -gst_rtsp_onvif_media_factory_get_backchannel_bandwidth -gst_rtsp_onvif_media_factory_set_backchannel_launch -gst_rtsp_onvif_media_factory_get_backchannel_launch - -GstRTSPOnvifMediaFactoryPrivate -gst_rtsp_onvif_media_factory_get_type -GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY -GST_RTSP_ONVIF_MEDIA_FACTORY -GST_RTSP_ONVIF_MEDIA_FACTORY_CAST -GST_RTSP_ONVIF_MEDIA_FACTORY_CLASS -GST_RTSP_ONVIF_MEDIA_FACTORY_CLASS_CAST -GST_RTSP_ONVIF_MEDIA_FACTORY_GET_CLASS -GST_IS_RTSP_ONVIF_MEDIA_FACTORY -GST_IS_RTSP_ONVIF_MEDIA_FACTORY_CLASS -
- -
-rtsp-onvif-media -GstRTSPOnvifMedia -GstRTSPOnvifMedia -GstRTSPOnvifMediaClass - -gst_rtsp_onvif_media_collect_backchannel -gst_rtsp_onvif_media_get_backchannel_bandwidth -gst_rtsp_onvif_media_set_backchannel_bandwidth - -GstRTSPOnvifMediaPrivate -gst_rtsp_onvif_media_get_type -GST_TYPE_RTSP_ONVIF_MEDIA -GST_RTSP_ONVIF_MEDIA -GST_RTSP_ONVIF_MEDIA_CAST -GST_RTSP_ONVIF_MEDIA_CLASS -GST_RTSP_ONVIF_MEDIA_CLASS_CAST -GST_RTSP_ONVIF_MEDIA_GET_CLASS -GST_IS_RTSP_ONVIF_MEDIA -GST_IS_RTSP_ONVIF_MEDIA_CLASS -
diff --git a/docs/libs/gst-rtsp-server.types b/docs/libs/gst-rtsp-server.types deleted file mode 100644 index 9e4aa4cc10..0000000000 --- a/docs/libs/gst-rtsp-server.types +++ /dev/null @@ -1,52 +0,0 @@ -#include - -#include -gst_rtsp_auth_get_type - -#include -gst_rtsp_mount_points_get_type - -#include -gst_rtsp_media_factory_get_type - -#include -gst_rtsp_media_get_type - -#include -gst_rtsp_server_get_type - -#include -gst_rtsp_session_pool_get_type - -#include -gst_rtsp_session_get_type - -#include -gst_rtsp_client_get_type - -#include -gst_rtsp_address_pool_get_type - -#include -gst_rtsp_context_get_type - -#include -gst_rtsp_media_factory_uri_get_type - -#include -gst_rtsp_permissions_get_type - -#include -gst_rtsp_session_media_get_type - -#include -gst_rtsp_stream_transport_get_type - -#include -gst_rtsp_stream_get_type - -#include -gst_rtsp_thread_pool_get_type - -#include -gst_rtsp_token_get_type From e788fc4e88f727a77920d8ad2ef5fd4460d41ce0 Mon Sep 17 00:00:00 2001 From: Niels De Graef Date: Sun, 2 Jun 2019 21:39:33 +0200 Subject: [PATCH 1615/1776] meson: Bump minimal GLib version to 2.44 This means we can use some newer features and get rid of some boilerplate code using the G_DECLARE_* macros. As discussed on IRC, 2.44 is old enough by now to start depending on it. --- configure.ac | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index b1be5cea23..154164af92 100644 --- a/configure.ac +++ b/configure.ac @@ -149,7 +149,7 @@ dnl *** checks for library functions *** dnl *** checks for dependancy libraries *** dnl GLib is required -GLIB_REQ=2.40.0 +GLIB_REQ=2.44.0 AC_SUBST([GLIB_REQ]) AG_GST_GLIB_CHECK([$GLIB_REQ]) diff --git a/meson.build b/meson.build index eb8a4e4920..e1e3b1dbe1 100644 --- a/meson.build +++ b/meson.build @@ -15,7 +15,7 @@ else endif gst_version_is_dev = gst_version_minor % 2 == 1 and gst_version_micro < 90 -glib_req = '>= 2.40.0' +glib_req = '>= 2.44.0' gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor) api_version = '1.0' From 421ac851504812ad640c58f92c04123254905b9b Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Thu, 27 Sep 2018 19:09:01 +0200 Subject: [PATCH 1616/1776] rtsp-media: allow specifying rate when seeking Add new function gst_rtsp_media_seek_full_with_rate() which allows the caller to specify the rate for the seek. Also added functions in rtsp-stream and rtsp-media for retreiving current rate and applied rate. https://bugzilla.gnome.org/show_bug.cgi?id=754575 --- gst/rtsp-server/rtsp-media.c | 136 ++++++++++++++++++++++++++-------- gst/rtsp-server/rtsp-media.h | 11 +++ gst/rtsp-server/rtsp-stream.c | 64 ++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 5 ++ tests/check/gst/media.c | 25 ++++++- 5 files changed, 209 insertions(+), 32 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b238561678..e03359e66d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -50,7 +50,8 @@ * #GstRTSPSession and #GstRTSPSessionMedia. * * The state of the media can be controlled with gst_rtsp_media_set_state (). - * Seeking can be done with gst_rtsp_media_seek(). + * Seeking can be done with gst_rtsp_media_seek(), or gst_rtsp_media_seek_full() + * or gst_rtsp_media_seek_full_with_rate() for finer control of the seek. * * With gst_rtsp_media_unprepare() the pipeline is stopped and shut down. When * gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to @@ -2554,6 +2555,51 @@ conversion_failed: } } +/** + * gst_rtsp_media_get_rates: + * @media: a #GstRTSPMedia + * @rate (allow-none): the rate of the current segment + * @applied_rate (allow-none): the applied_rate of the current segment + * + * Get the rate and applied_rate of the current segment. + * + * Returns: %FALSE if looking up the rate and applied rate failed. Otherwise + * %TRUE is returned and @rate and @applied_rate are set to the rate and + * applied_rate of the current segment. + * Since: 1.18 + */ +gboolean +gst_rtsp_media_get_rates (GstRTSPMedia * media, gdouble * rate, + gdouble * applied_rate) +{ + GstRTSPMediaPrivate *priv; + GstRTSPStream *stream; + gboolean result = TRUE; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + if (!rate && !applied_rate) { + GST_WARNING_OBJECT (media, "rate and applied_rate are both NULL"); + return FALSE; + } + + priv = media->priv; + + g_mutex_lock (&priv->lock); + + g_assert (priv->streams->len > 0); + stream = g_ptr_array_index (priv->streams, 0); + if (!gst_rtsp_stream_get_rates (stream, rate, applied_rate)) { + GST_WARNING_OBJECT (media, + "failed to obtain rate and applied_rate from first stream"); + result = FALSE; + } + + g_mutex_unlock (&priv->lock); + + return result; +} + static void stream_update_blocked (GstRTSPStream * stream, GstRTSPMedia * media) { @@ -2635,22 +2681,24 @@ gst_rtsp_media_get_status (GstRTSPMedia * media) } /** - * gst_rtsp_media_seek_full: + * gst_rtsp_media_seek_full_with_rate: * @media: a #GstRTSPMedia * @range: (transfer none): a #GstRTSPTimeRange * @flags: The minimal set of #GstSeekFlags to use + * @rate: the rate to use in the seek * - * Seek the pipeline of @media to @range. @media must be prepared with - * gst_rtsp_media_prepare(). In order to perform the seek operation, - * the pipeline must contain all needed transport parts (transport sinks). + * Seek the pipeline of @media to @range with the given @flags and @rate. + * @media must be prepared with gst_rtsp_media_prepare(). + * In order to perform the seek operation, the pipeline must contain all + * needed transport parts (transport sinks). * * Returns: %TRUE on success. * - * Since: 1.14 + * Since: 1.18 */ gboolean -gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, - GstSeekFlags flags) +gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media, + GstRTSPTimeRange * range, GstSeekFlags flags, gdouble rate) { GstRTSPMediaClass *klass; GstRTSPMediaPrivate *priv; @@ -2658,12 +2706,15 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, GstClockTime start, stop; GstSeekType start_type, stop_type; gint64 current_position; + gboolean force_seek; klass = GST_RTSP_MEDIA_GET_CLASS (media); g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); - g_return_val_if_fail (range != NULL, FALSE); - g_return_val_if_fail (klass->convert_range != NULL, FALSE); + /* if there's a range then klass->convert_range must be set */ + g_return_val_if_fail (range == NULL || klass->convert_range != NULL, FALSE); + + GST_DEBUG ("flags=%x rate=%f", flags, rate); priv = media->priv; @@ -2689,15 +2740,21 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, } start_type = stop_type = GST_SEEK_TYPE_NONE; + start = stop = GST_CLOCK_TIME_NONE; - if (!klass->convert_range (media, range, GST_RTSP_RANGE_NPT)) - goto not_supported; - gst_rtsp_range_get_times (range, &start, &stop); + /* if caller provided a range convert it to NPT format + * if no range provided the seek is assumed to be the same position but with + * e.g. the rate changed */ + if (range != NULL) { + if (!klass->convert_range (media, range, GST_RTSP_RANGE_NPT)) + goto not_supported; + gst_rtsp_range_get_times (range, &start, &stop); - GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, - GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); - GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, - GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop)); + GST_INFO ("got %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, + GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); + GST_INFO ("current %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, + GST_TIME_ARGS (priv->range_start), GST_TIME_ARGS (priv->range_stop)); + } current_position = -1; if (klass->query_position) @@ -2713,24 +2770,24 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, else if (stop != GST_CLOCK_TIME_NONE) stop_type = GST_SEEK_TYPE_SET; - if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE) { - gboolean had_flags = flags != 0; + /* we force a seek if any seek flag is set, or if the the rate + * is non-standard, i.e. not 1.0 */ + force_seek = flags != GST_SEEK_FLAG_NONE || rate != 1.0; + + if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE || force_seek) { + gboolean had_flags = flags != GST_SEEK_FLAG_NONE; GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); /* depends on the current playing state of the pipeline. We might need to * queue this until we get EOS. */ - if (had_flags) - flags |= GST_SEEK_FLAG_FLUSH; - else - flags = GST_SEEK_FLAG_FLUSH; - + flags |= GST_SEEK_FLAG_FLUSH; /* if range start was not supplied we must continue from current position. * but since we're doing a flushing seek, let us query the current position * so we end up at exactly the same position after the seek. */ - if (range->min.type == GST_RTSP_TIME_END) { /* Yepp, that's right! */ + if (range == NULL || range->min.type == GST_RTSP_TIME_END) { if (current_position == -1) { GST_WARNING ("current position unknown"); } else { @@ -2748,14 +2805,14 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, flags |= GST_SEEK_FLAG_KEY_UNIT; } - if (start == current_position && stop_type == GST_SEEK_TYPE_NONE) { - GST_DEBUG ("not seeking because no position change"); + if (start == current_position && stop_type == GST_SEEK_TYPE_NONE && + !force_seek) { + GST_DEBUG ("no position change, no flags set by caller, so not seeking"); res = TRUE; } else { gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); - /* FIXME, we only do forwards playback, no trick modes yet */ - res = gst_element_seek (priv->pipeline, 1.0, GST_FORMAT_TIME, + res = gst_element_seek (priv->pipeline, rate, GST_FORMAT_TIME, flags, start_type, start, stop_type, stop); /* and block for the seek to complete */ @@ -2819,6 +2876,23 @@ preroll_failed: } } +/** + * gst_rtsp_media_seek_full: + * @media: a #GstRTSPMedia + * @range: (transfer none): a #GstRTSPTimeRange + * @flags: The minimal set of #GstSeekFlags to use + * + * Seek the pipeline of @media to @range with the given @flags. + * @media must be prepared with gst_rtsp_media_prepare(). + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, + GstSeekFlags flags) +{ + return gst_rtsp_media_seek_full_with_rate (media, range, flags, 1.0); +} /** * gst_rtsp_media_seek: @@ -2833,10 +2907,10 @@ preroll_failed: gboolean gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) { - return gst_rtsp_media_seek_full (media, range, 0); + return gst_rtsp_media_seek_full_with_rate (media, range, GST_SEEK_FLAG_NONE, + 1.0); } - static void stream_collect_blocking (GstRTSPStream * stream, gboolean * blocked) { diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index c7728c6fe4..0af6574682 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -387,6 +387,12 @@ gboolean gst_rtsp_media_seek_full (GstRTSPMedia *media, GstRTSPTimeRange *range, GstSeekFlags flags); +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_seek_full_with_rate (GstRTSPMedia *media, + GstRTSPTimeRange *range, + GstSeekFlags flags, + gdouble rate); + GST_RTSP_SERVER_API GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia *media); @@ -395,6 +401,11 @@ gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, gboolean play, GstRTSPRangeUnit unit); +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_get_rates (GstRTSPMedia * media, + gdouble * rate, + gdouble * applied_rate); + GST_RTSP_SERVER_API gboolean gst_rtsp_media_set_state (GstRTSPMedia *media, GstState state, GPtrArray *transports); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 68a1202fbf..1c88cefb11 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4127,6 +4127,70 @@ no_stats: } } +/** + * gst_rtsp_stream_get_rates: + * @stream: a #GstRTSPStream + * @rate: (allow-none): the configured rate + * @applied_rate: (allow-none): the configured applied_rate + * + * Retrieve the current rate and/or applied_rate. + * + * Returns: %TRUE if rate and/or applied_rate could be determined. + * Since: 1.18 + */ +gboolean +gst_rtsp_stream_get_rates (GstRTSPStream * stream, gdouble * rate, + gdouble * applied_rate) +{ + GstRTSPStreamPrivate *priv; + GstEvent *event; + const GstSegment *segment; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE); + + if (!rate && !applied_rate) { + GST_WARNING_OBJECT (stream, "rate and applied_rate are both NULL"); + return FALSE; + } + + priv = stream->priv; + + g_mutex_lock (&priv->lock); + + if (!priv->send_rtp_sink) + goto no_rtp_sink_pad; + + event = gst_pad_get_sticky_event (priv->send_rtp_sink, GST_EVENT_SEGMENT, 0); + if (!event) + goto no_sticky_event; + + gst_event_parse_segment (event, &segment); + if (rate) + *rate = segment->rate; + if (applied_rate) + *applied_rate = segment->applied_rate; + + gst_event_unref (event); + g_mutex_unlock (&priv->lock); + + return TRUE; + +/* ERRORS */ +no_rtp_sink_pad: + { + GST_WARNING_OBJECT (stream, "no send_rtp_sink pad yet"); + g_mutex_unlock (&priv->lock); + return FALSE; + } +no_sticky_event: + { + GST_WARNING_OBJECT (stream, "no segment event on send_rtp_sink pad"); + g_mutex_unlock (&priv->lock); + return FALSE; + } + +} + /** * gst_rtsp_stream_get_caps: * @stream: a #GstRTSPStream diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 7910bb05d7..424a0230ee 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -198,6 +198,11 @@ gboolean gst_rtsp_stream_get_rtpinfo (GstRTSPStream *stream, guint *clock_rate, GstClockTime *running_time); +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_get_rates (GstRTSPStream * stream, + gdouble * rate, + gdouble * applied_rate); + GST_RTSP_SERVER_API GstCaps * gst_rtsp_stream_get_caps (GstRTSPStream *stream); diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 5ae704ce9b..bcde9c30f9 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -60,6 +60,8 @@ GST_START_TEST (test_media_seek) GstRTSPThreadPool *pool; GstRTSPThread *thread; GstRTSPTransport *transport; + gdouble rate = 0; + gdouble applied_rate = 0; factory = gst_rtsp_media_factory_new (); fail_if (gst_rtsp_media_factory_is_shared (factory)); @@ -98,9 +100,30 @@ GST_START_TEST (test_media_seek) str = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT); fail_unless (g_str_equal (str, "npt=5-")); + g_free (str); + + /* seeking without rate should result in rate == 1.0 */ + fail_unless (gst_rtsp_media_seek (media, range)); + fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate)); + fail_unless (rate == 1.0); + fail_unless (applied_rate == 1.0); + + /* seeking with rate set to 1.5 should result in rate == 1.5 */ + fail_unless (gst_rtsp_media_seek_full_with_rate (media, range, + GST_SEEK_FLAG_NONE, 1.5)); + fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate)); + fail_unless (rate == 1.5); + fail_unless (applied_rate == 1.0); + + /* seeking with rate set to -2.0 should result in rate == -2.0 */ + fail_unless (gst_rtsp_range_parse ("npt=5-10", &range) == GST_RTSP_OK); + fail_unless (gst_rtsp_media_seek_full_with_rate (media, range, + GST_SEEK_FLAG_NONE, -2.0)); + fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate)); + fail_unless (rate == -2.0); + fail_unless (applied_rate == 1.0); gst_rtsp_range_free (range); - g_free (str); fail_unless (gst_rtsp_media_unprepare (media)); g_object_unref (media); From 65d9aa327cd1844934836249cd4463edf09c725d Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Mon, 1 Oct 2018 18:51:49 +0200 Subject: [PATCH 1617/1776] rtsp-client: allow sub classes to adjust the seek Adds a new virtual function, adjust_play_mode(), that allows sub classes to adjust the seek done on the media. The sub class can modify the values of the the seek flags and the rate. https://bugzilla.gnome.org/show_bug.cgi?id=754575 --- gst/rtsp-server/rtsp-client.c | 118 +++++++++++++++++++++++----------- gst/rtsp-server/rtsp-client.h | 11 +++- 2 files changed, 91 insertions(+), 38 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 38201899f7..6f58b37c07 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1730,6 +1730,83 @@ make_base_url (GstRTSPClient * client, GstRTSPUrl * url, const gchar * path) return result; } +static GstRTSPStatusCode +setup_play_mode (GstRTSPClient * client, GstRTSPContext * ctx, + GstRTSPRangeUnit * unit) +{ + gchar *str; + GstRTSPResult res; + GstRTSPTimeRange *range = NULL; + gdouble rate = 1.0; + GstSeekFlags flags = GST_SEEK_FLAG_NONE; + GstRTSPClientClass *klass = GST_RTSP_CLIENT_GET_CLASS (client); + GstRTSPStatusCode status; + + /* parse the range header if we have one */ + res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0); + if (res == GST_RTSP_OK) { + gchar *seek_style = NULL; + + res = gst_rtsp_range_parse (str, &range); + if (res != GST_RTSP_OK) + goto parse_range_failed; + + *unit = range->unit; + + /* parse seek style header, if present */ + res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_SEEK_STYLE, + &seek_style, 0); + + if (res == GST_RTSP_OK) { + if (g_strcmp0 (seek_style, "RAP") == 0) + flags = GST_SEEK_FLAG_ACCURATE; + else if (g_strcmp0 (seek_style, "CoRAP") == 0) + flags = GST_SEEK_FLAG_KEY_UNIT; + else if (g_strcmp0 (seek_style, "First-Prior") == 0) + flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_BEFORE; + else if (g_strcmp0 (seek_style, "Next") == 0) + flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_AFTER; + else + GST_FIXME_OBJECT (client, "Add support for seek style %s", seek_style); + } + } + + /* give the application a chance to tweak range, flags, or rate */ + if (klass->adjust_play_mode != NULL) { + status = klass->adjust_play_mode (client, ctx, &range, &flags, &rate); + if (status != GST_RTSP_STS_OK) + goto adjust_play_mode_failed; + } + + /* now do the seek with the seek options */ + (void) gst_rtsp_media_seek_full_with_rate (ctx->media, range, flags, rate); + if (range != NULL) + gst_rtsp_range_free (range); + + if (gst_rtsp_media_get_status (ctx->media) == GST_RTSP_MEDIA_STATUS_ERROR) + goto seek_failed; + + return GST_RTSP_STS_OK; + +parse_range_failed: + { + GST_ERROR ("client %p: failed parsing range header", client); + return GST_RTSP_STS_BAD_REQUEST; + } +adjust_play_mode_failed: + { + GST_ERROR ("client %p: sub class returned bad code (%d)", client, status); + if (range != NULL) + gst_rtsp_range_free (range); + return status; + } +seek_failed: + { + GST_ERROR ("client %p: seek failed", client); + return GST_RTSP_STS_SERVICE_UNAVAILABLE; + } +} + static gboolean handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) { @@ -1740,8 +1817,6 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPStatusCode code; GstRTSPUrl *uri; gchar *str; - GstRTSPTimeRange *range; - GstRTSPResult res; GstRTSPState rtspstate; GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT; gchar *path, *rtpinfo; @@ -1799,38 +1874,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!gst_rtsp_media_unsuspend (media)) goto unsuspend_failed; - /* parse the range header if we have one */ - res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0); - if (res == GST_RTSP_OK) { - if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) { - GstRTSPMediaStatus media_status; - GstSeekFlags flags = 0; - - if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_SEEK_STYLE, - &seek_style, 0)) { - if (g_strcmp0 (seek_style, "RAP") == 0) - flags = GST_SEEK_FLAG_ACCURATE; - else if (g_strcmp0 (seek_style, "CoRAP") == 0) - flags = GST_SEEK_FLAG_KEY_UNIT; - else if (g_strcmp0 (seek_style, "First-Prior") == 0) - flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_BEFORE; - else if (g_strcmp0 (seek_style, "Next") == 0) - flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_AFTER; - else - GST_FIXME_OBJECT (client, "Add support for seek style %s", - seek_style); - } - - /* we have a range, seek to the position */ - unit = range->unit; - gst_rtsp_media_seek_full (media, range, flags); - gst_rtsp_range_free (range); - - media_status = gst_rtsp_media_get_status (media); - if (media_status == GST_RTSP_MEDIA_STATUS_ERROR) - goto seek_failed; - } - } + code = setup_play_mode (client, ctx, &unit); + if (code != GST_RTSP_STS_OK) + goto invalid_mode; /* grab RTPInfo from the media now */ rtpinfo = gst_rtsp_session_media_get_rtpinfo (sessmedia); @@ -1918,10 +1964,10 @@ unsuspend_failed: send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); return FALSE; } -seek_failed: +invalid_mode: { GST_ERROR ("client %p: seek failed", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + send_generic_response (client, code, ctx); return FALSE; } unsupported_mode: diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 8dbc3ddcd1..2e47203eb2 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -107,6 +107,9 @@ struct _GstRTSPClient { * RTSP response(ctx->response) via a call to gst_rtsp_message_init_response() * @params_get: get parameters. This function should also initialize the * RTSP response(ctx->response) via a call to gst_rtsp_message_init_response() + * @make_path_from_uri: called to create path from uri. + * @adjust_play_mode: called to give the application the possibility to adjust + * the range, seek flags, and/or rate. Since 1.18 * @tunnel_http_response: called when a response to the GET request is about to * be sent for a tunneled connection. The response can be modified. Since: 1.4 * @@ -125,7 +128,11 @@ struct _GstRTSPClientClass { GstRTSPResult (*params_set) (GstRTSPClient *client, GstRTSPContext *ctx); GstRTSPResult (*params_get) (GstRTSPClient *client, GstRTSPContext *ctx); gchar * (*make_path_from_uri) (GstRTSPClient *client, const GstRTSPUrl *uri); - + GstRTSPStatusCode (*adjust_play_mode) (GstRTSPClient * client, + GstRTSPContext * context, + GstRTSPTimeRange ** range, + GstSeekFlags * flags, + gdouble * rate); /* signals */ void (*closed) (GstRTSPClient *client); void (*new_session) (GstRTSPClient *client, GstRTSPSession *session); @@ -162,7 +169,7 @@ struct _GstRTSPClientClass { GstRTSPStatusCode (*pre_record_request) (GstRTSPClient *client, GstRTSPContext *ctx); /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE-16]; + gpointer _gst_reserved[GST_PADDING_LARGE-17]; }; GST_RTSP_SERVER_API From bc745896012a72f327ad1d135d695336b88bd1d3 Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Fri, 12 Oct 2018 08:53:04 +0200 Subject: [PATCH 1618/1776] rtsp-client: add support for Scale and Speed header Add support for the RTSP Scale and Speed headers by setting the rate in the seek to (scale*speed). We then check the resulting segment for rate and applied rate, and use them as values for the Speed and Scale headers respectively. https://bugzilla.gnome.org/show_bug.cgi?id=754575 --- gst/rtsp-server/rtsp-client.c | 150 ++++++++++++++++++++++-- gst/rtsp-server/rtsp-media.c | 55 +++++---- gst/rtsp-server/rtsp-media.h | 3 + tests/check/gst/client.c | 211 +++++++++++++++++++++++++++++++++- 4 files changed, 386 insertions(+), 33 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 6f58b37c07..d3c484b70b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1730,9 +1730,97 @@ make_base_url (GstRTSPClient * client, GstRTSPUrl * url, const gchar * path) return result; } +/* Check if the given header of type double is present and, if so, + * put it's value in the supplied variable. + */ +static GstRTSPStatusCode +parse_header_value_double (GstRTSPClient * client, GstRTSPContext * ctx, + GstRTSPHeaderField header, gboolean * present, gdouble * value) +{ + GstRTSPResult res; + gchar *str; + gchar *end; + + res = gst_rtsp_message_get_header (ctx->request, header, &str, 0); + if (res == GST_RTSP_OK) { + *value = g_ascii_strtod (str, &end); + if (end == str) + goto parse_header_failed; + + GST_DEBUG ("client %p: got '%s', value %f", client, + gst_rtsp_header_as_text (header), *value); + *present = TRUE; + } else { + *present = FALSE; + } + + return GST_RTSP_STS_OK; + +parse_header_failed: + { + GST_ERROR ("client %p: failed parsing '%s' header", client, + gst_rtsp_header_as_text (header)); + return GST_RTSP_STS_BAD_REQUEST; + } +} + +/* Parse scale and speed headers, if present, and set the rate to + * (rate * scale * speed) */ +static GstRTSPStatusCode +parse_scale_and_speed (GstRTSPClient * client, GstRTSPContext * ctx, + gboolean * scale_present, gboolean * speed_present, gdouble * rate) +{ + gdouble scale = 1.0; + gdouble speed = 1.0; + GstRTSPStatusCode status; + + GST_DEBUG ("got rate %f", *rate); + + status = parse_header_value_double (client, ctx, GST_RTSP_HDR_SCALE, + scale_present, &scale); + if (status != GST_RTSP_STS_OK) + return status; + + if (scale_present) { + GST_DEBUG ("got Scale %f", scale); + if (scale == 0) + goto bad_scale_value; + *rate *= scale; + } + + GST_DEBUG ("rate after parsing Scale %f", *rate); + + status = parse_header_value_double (client, ctx, GST_RTSP_HDR_SPEED, + speed_present, &speed); + if (status != GST_RTSP_STS_OK) + return status; + + if (speed_present) { + GST_DEBUG ("got Speed %f", speed); + if (speed <= 0) + goto bad_speed_value; + *rate *= speed; + } + + GST_DEBUG ("rate after parsing Speed %f", *rate); + + return status; + +bad_scale_value: + { + GST_ERROR ("client %p: bad 'Scale' header value (%f)", client, scale); + return GST_RTSP_STS_BAD_REQUEST; + } +bad_speed_value: + { + GST_ERROR ("client %p: bad 'Speed' header value (%f)", client, speed); + return GST_RTSP_STS_BAD_REQUEST; + } +} + static GstRTSPStatusCode setup_play_mode (GstRTSPClient * client, GstRTSPContext * ctx, - GstRTSPRangeUnit * unit) + GstRTSPRangeUnit * unit, gboolean * scale_present, gboolean * speed_present) { gchar *str; GstRTSPResult res; @@ -1740,7 +1828,7 @@ setup_play_mode (GstRTSPClient * client, GstRTSPContext * ctx, gdouble rate = 1.0; GstSeekFlags flags = GST_SEEK_FLAG_NONE; GstRTSPClientClass *klass = GST_RTSP_CLIENT_GET_CLASS (client); - GstRTSPStatusCode status; + GstRTSPStatusCode rtsp_status_code; /* parse the range header if we have one */ res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0); @@ -1771,10 +1859,21 @@ setup_play_mode (GstRTSPClient * client, GstRTSPContext * ctx, } } + /* check for scale and/or speed headers + * we will set the seek rate to (speed * scale) and let the media decide + * the resulting scale and speed. in the response we will use rate and applied + * rate from the resulting segment as values for the speed and scale headers + * respectively */ + rtsp_status_code = parse_scale_and_speed (client, ctx, scale_present, + speed_present, &rate); + if (rtsp_status_code != GST_RTSP_STS_OK) + goto scale_speed_failed; + /* give the application a chance to tweak range, flags, or rate */ if (klass->adjust_play_mode != NULL) { - status = klass->adjust_play_mode (client, ctx, &range, &flags, &rate); - if (status != GST_RTSP_STS_OK) + rtsp_status_code = + klass->adjust_play_mode (client, ctx, &range, &flags, &rate); + if (rtsp_status_code != GST_RTSP_STS_OK) goto adjust_play_mode_failed; } @@ -1793,12 +1892,20 @@ parse_range_failed: GST_ERROR ("client %p: failed parsing range header", client); return GST_RTSP_STS_BAD_REQUEST; } -adjust_play_mode_failed: +scale_speed_failed: { - GST_ERROR ("client %p: sub class returned bad code (%d)", client, status); if (range != NULL) gst_rtsp_range_free (range); - return status; + GST_ERROR ("client %p: failed parsing Scale or Speed headers", client); + return rtsp_status_code; + } +adjust_play_mode_failed: + { + GST_ERROR ("client %p: sub class returned bad code (%d)", client, + rtsp_status_code); + if (range != NULL) + gst_rtsp_range_free (range); + return rtsp_status_code; } seek_failed: { @@ -1824,6 +1931,10 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *seek_style = NULL; GstRTSPStatusCode sig_result; GPtrArray *transports; + gboolean scale_present; + gboolean speed_present; + gdouble rate; + gdouble applied_rate; if (!(session = ctx->session)) goto no_session; @@ -1874,7 +1985,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!gst_rtsp_media_unsuspend (media)) goto unsuspend_failed; - code = setup_play_mode (client, ctx, &unit); + code = setup_play_mode (client, ctx, &unit, &scale_present, &speed_present); if (code != GST_RTSP_STS_OK) goto invalid_mode; @@ -1899,6 +2010,23 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (str) gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RANGE, str); + if (!gst_rtsp_media_is_receive_only (media)) { + /* the scale and speed headers must always be added if they were present in + * the request. however, even if they were not, we still add them if + * applied_rate or rate deviate from the "normal", i.e. 1.0 */ + if (!gst_rtsp_media_get_rates (media, &rate, &applied_rate)) + goto get_rates_error; + g_assert (rate != 0 && applied_rate != 0); + + if (scale_present || applied_rate != 1.0) + gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_SCALE, + g_strdup_printf ("%1.3f", applied_rate)); + + if (speed_present || rate != 1.0) + gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_SPEED, + g_strdup_printf ("%1.3f", rate)); + } + send_message (client, ctx, ctx->response, FALSE); /* start playing after sending the response */ @@ -1976,6 +2104,12 @@ unsupported_mode: send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); return FALSE; } +get_rates_error: + { + GST_ERROR ("client %p: failed obtaining rate and applied_rate", client); + send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx); + return FALSE; + } } static void diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e03359e66d..6946211ec4 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -732,25 +732,6 @@ default_create_rtpbin (GstRTSPMedia * media) return rtpbin; } -static gboolean -is_receive_only (GstRTSPMedia * media) -{ - GstRTSPMediaPrivate *priv = media->priv; - gboolean recive_only = TRUE; - guint i; - - for (i = 0; i < priv->streams->len; i++) { - GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); - if (gst_rtsp_stream_is_sender (stream) || - !gst_rtsp_stream_is_receiver (stream)) { - recive_only = FALSE; - break; - } - } - - return recive_only; -} - /* must be called with state lock */ static void check_seekable (GstRTSPMedia * media) @@ -759,7 +740,7 @@ check_seekable (GstRTSPMedia * media) GstRTSPMediaPrivate *priv = media->priv; /* Update the seekable state of the pipeline in case it changed */ - if (is_receive_only (media)) { + if (gst_rtsp_media_is_receive_only (media)) { /* TODO: Seeking for "receive-only"? */ priv->seekable = -1; } else { @@ -2984,8 +2965,9 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) GST_DEBUG ("%p: went from %s to %s (pending %s)", media, gst_element_state_get_name (old), gst_element_state_get_name (new), gst_element_state_get_name (pending)); - if (priv->no_more_pads_pending == 0 && is_receive_only (media) && - old == GST_STATE_READY && new == GST_STATE_PAUSED) { + if (priv->no_more_pads_pending == 0 + && gst_rtsp_media_is_receive_only (media) && old == GST_STATE_READY + && new == GST_STATE_PAUSED) { GST_INFO ("%p: went to PAUSED, prepared now", media); collect_media_stats (media); @@ -3459,7 +3441,7 @@ start_prepare (GstRTSPMedia * media) g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers); } - if (priv->nb_dynamic_elements == 0 && is_receive_only (media)) { + if (priv->nb_dynamic_elements == 0 && gst_rtsp_media_is_receive_only (media)) { /* If we are receive_only (RECORD), do not try to preroll, to avoid * a second ASYNC state change failing */ priv->is_live = TRUE; @@ -4286,7 +4268,7 @@ default_unsuspend (GstRTSPMedia * media) switch (priv->suspend_mode) { case GST_RTSP_SUSPEND_MODE_NONE: - if (is_receive_only (media)) + if (gst_rtsp_media_is_receive_only (media)) break; if (media_streams_blocking (media)) { gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); @@ -4713,3 +4695,28 @@ gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GPtrArray * transports) return TRUE; } + +/** + * gst_rtsp_media_is_receive_only: + * + * Returns: %TRUE if @media is receive-only, %FALSE otherwise. + * Since: 1.18 + */ +gboolean +gst_rtsp_media_is_receive_only (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + gboolean receive_only = TRUE; + guint i; + + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + if (gst_rtsp_stream_is_sender (stream) || + !gst_rtsp_stream_is_receiver (stream)) { + receive_only = FALSE; + break; + } + } + + return receive_only; +} diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 0af6574682..58d5aa40af 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -417,6 +417,9 @@ void gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media, GST_RTSP_SERVER_API gboolean gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GPtrArray * transports); +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_is_receive_only (GstRTSPMedia * media); + #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPMedia, gst_object_unref) #endif diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index cbe846efcf..5f10c4372a 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -32,6 +32,10 @@ static gchar *session_id; static gint cseq; static guint expected_session_timeout = 60; static const gchar *expected_unsupported_header; +static const gchar *expected_scale_header; +static const gchar *expected_speed_header; +static gdouble fake_rate_value = 0; +static gdouble fake_applied_rate_value = 0; static gboolean test_response_200 (GstRTSPClient * client, GstRTSPMessage * response, @@ -1707,7 +1711,211 @@ GST_START_TEST (test_client_multicast_invalid_ttl) GST_END_TEST; -static Suite * +static gboolean +test_response_scale_speed (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + gchar *header_value; + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_OK); + fail_unless (g_str_equal (reason, "OK")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_RANGE, + &header_value, 0) == GST_RTSP_OK); + + if (expected_scale_header != NULL) { + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_SCALE, + &header_value, 0) == GST_RTSP_OK); + ck_assert_str_eq (header_value, expected_scale_header); + } else { + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_SCALE, + &header_value, 0) == GST_RTSP_ENOTIMPL); + } + + if (expected_speed_header != NULL) { + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_SPEED, + &header_value, 0) == GST_RTSP_OK); + ck_assert_str_eq (header_value, expected_speed_header); + } else { + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_SPEED, + &header_value, 0) == GST_RTSP_ENOTIMPL); + } + + return TRUE; +} + +/* Probe that tweaks segment events according to the values of the + * fake_rate_value and fake_applied_rate_value variables. Used to simulate + * seek results with different combinations of rate and applied rate. + */ +static GstPadProbeReturn +rate_tweaking_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) +{ + GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info); + GstSegment segment; + + if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { + GST_DEBUG ("got segment event %" GST_PTR_FORMAT, event); + gst_event_copy_segment (event, &segment); + if (fake_applied_rate_value) + segment.applied_rate = fake_applied_rate_value; + if (fake_rate_value) + segment.rate = fake_rate_value; + gst_event_unref (event); + info->data = gst_event_new_segment (&segment); + GST_DEBUG ("forwarding segment event %" GST_PTR_FORMAT, + GST_EVENT (info->data)); + } + + return GST_PAD_PROBE_OK; +} + +static void +attach_rate_tweaking_probe (void) +{ + GstRTSPContext *ctx; + GstRTSPMedia *media; + GstRTSPStream *stream; + GstPad *srcpad; + + fail_unless ((ctx = gst_rtsp_context_get_current ()) != NULL); + + media = ctx->media; + fail_unless (media != NULL); + stream = gst_rtsp_media_get_stream (media, 0); + fail_unless (stream != NULL); + + srcpad = gst_rtsp_stream_get_srcpad (stream); + fail_unless (srcpad != NULL); + + GST_DEBUG ("adding rate_tweaking_probe"); + + gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + rate_tweaking_probe, NULL, NULL); +} + +static void +do_test_scale_and_speed (const gchar * scale, const gchar * speed) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + GstRTSPContext ctx = { NULL }; + + client = setup_multicast_client (1); + + ctx.client = client; + ctx.auth = gst_rtsp_auth_new (); + ctx.token = + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_context_push_current (&ctx); + + expected_session_timeout = 20; + g_signal_connect (G_OBJECT (client), "new-session", + G_CALLBACK (new_session_cb), NULL); + + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast"); + expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + expected_transport = NULL; + expected_session_timeout = 60; + + if (fake_applied_rate_value || fake_rate_value) + attach_rate_tweaking_probe (); + + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + + if (scale != NULL) + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SCALE, scale); + if (speed != NULL) + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SPEED, speed); + + gst_rtsp_client_set_send_func (client, test_response_scale_speed, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + send_teardown (client); + teardown_client (client); + g_object_unref (ctx.auth); + gst_rtsp_token_unref (ctx.token); + gst_rtsp_context_pop_current (&ctx); + +} + +GST_START_TEST (test_scale_and_speed) +{ + /* no scale/speed requested, no scale/speed should be received */ + expected_scale_header = NULL; + expected_speed_header = NULL; + do_test_scale_and_speed (NULL, NULL); + + /* scale requested, scale should be received */ + fake_applied_rate_value = 2; + fake_rate_value = 1; + expected_scale_header = "2.000"; + expected_speed_header = NULL; + do_test_scale_and_speed ("2.000", NULL); + + /* speed requested, speed should be received */ + fake_applied_rate_value = 0; + fake_rate_value = 0; + expected_scale_header = NULL; + expected_speed_header = "2.000"; + do_test_scale_and_speed (NULL, "2.000"); + + /* both requested, both should be received */ + fake_applied_rate_value = 2; + fake_rate_value = 2; + expected_scale_header = "2.000"; + expected_speed_header = "2.000"; + do_test_scale_and_speed ("2", "2"); + + /* scale requested but media doesn't handle scaling so both should be + * received, with scale set to 1.000 and speed set to (requested scale + * requested speed) */ + fake_applied_rate_value = 0; + fake_rate_value = 5; + expected_scale_header = "1.000"; + expected_speed_header = "5.000"; + do_test_scale_and_speed ("5", NULL); + + /* both requested but media only handles scaling so both should be received, + * with scale set to (requested scale * requested speed) and speed set to 1.00 + */ + fake_rate_value = 1.000; + fake_applied_rate_value = 4.000; + expected_scale_header = "4.000"; + expected_speed_header = "1.000"; + do_test_scale_and_speed ("2", "2"); +} + +GST_END_TEST static Suite * rtspclient_suite (void) { Suite *s = suite_create ("rtspclient"); @@ -1759,6 +1967,7 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_max_ttl_first_client); tcase_add_test (tc, test_client_multicast_max_ttl_second_client); tcase_add_test (tc, test_client_multicast_invalid_ttl); + tcase_add_test (tc, test_scale_and_speed); return s; } From f31f79f60eae1cb66db7288fadabf5a6135726a5 Mon Sep 17 00:00:00 2001 From: Nikita Bobkov Date: Tue, 13 Nov 2018 21:28:45 +0100 Subject: [PATCH 1619/1776] Reverse playback support GStreamer plays segment from stop to start when doing reverse playback. RTSP implies that media should be played from start of Range header to its stop. Hence we swap start and stop times before passing them to gst_element_seek. Also make gst_rtsp_stream_query_stop always return value that can be used as stop time of Range header. --- gst/rtsp-server/rtsp-media.c | 14 +++++++++++--- gst/rtsp-server/rtsp-stream.c | 7 ++++++- tests/check/gst/media.c | 2 +- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 6946211ec4..e8686fd5dd 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2746,9 +2746,7 @@ gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media, if (start != GST_CLOCK_TIME_NONE) start_type = GST_SEEK_TYPE_SET; - if (priv->range_stop == stop) - stop = GST_CLOCK_TIME_NONE; - else if (stop != GST_CLOCK_TIME_NONE) + if (stop != GST_CLOCK_TIME_NONE) stop_type = GST_SEEK_TYPE_SET; /* we force a seek if any seek flag is set, or if the the rate @@ -2793,6 +2791,16 @@ gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media, } else { gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); + if (rate < 0.0) { + GstClockTime temp_time = start; + GstSeekType temp_type = start_type; + + start = stop; + start_type = stop_type; + stop = temp_time; + stop_type = temp_type; + } + res = gst_element_seek (priv->pipeline, rate, GST_FORMAT_TIME, flags, start_type, start, stop_type, stop); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 1c88cefb11..80f0217e5c 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -5270,6 +5270,9 @@ gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop) if (sink) { GstQuery *query; GstFormat format; + gdouble rate; + gint64 start_value; + gint64 stop_value; query = gst_query_new_segment (GST_FORMAT_TIME); if (!gst_element_query (sink, query)) { @@ -5278,9 +5281,11 @@ gst_rtsp_stream_query_stop (GstRTSPStream * stream, gint64 * stop) gst_object_unref (sink); return FALSE; } - gst_query_parse_segment (query, NULL, &format, NULL, stop); + gst_query_parse_segment (query, &rate, &format, &start_value, &stop_value); if (format != GST_FORMAT_TIME) *stop = -1; + else + *stop = rate > 0.0 ? stop_value : start_value; gst_query_unref (query); gst_object_unref (sink); } else if (pad) { diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index bcde9c30f9..58b3e0477c 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -116,7 +116,7 @@ GST_START_TEST (test_media_seek) fail_unless (applied_rate == 1.0); /* seeking with rate set to -2.0 should result in rate == -2.0 */ - fail_unless (gst_rtsp_range_parse ("npt=5-10", &range) == GST_RTSP_OK); + fail_unless (gst_rtsp_range_parse ("npt=10-5", &range) == GST_RTSP_OK); fail_unless (gst_rtsp_media_seek_full_with_rate (media, range, GST_SEEK_FLAG_NONE, -2.0)); fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate)); From b9cc3e867a0de8a50314411efc7e3e9ba1332632 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 7 Nov 2018 00:32:29 +0100 Subject: [PATCH 1620/1776] client: compare booleans, not pointers to them --- gst/rtsp-server/rtsp-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d3c484b70b..55c2da802d 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1781,7 +1781,7 @@ parse_scale_and_speed (GstRTSPClient * client, GstRTSPContext * ctx, if (status != GST_RTSP_STS_OK) return status; - if (scale_present) { + if (*scale_present) { GST_DEBUG ("got Scale %f", scale); if (scale == 0) goto bad_scale_value; @@ -1795,7 +1795,7 @@ parse_scale_and_speed (GstRTSPClient * client, GstRTSPContext * ctx, if (status != GST_RTSP_STS_OK) return status; - if (speed_present) { + if (*speed_present) { GST_DEBUG ("got Speed %f", speed); if (speed <= 0) goto bad_speed_value; From 52d20df0f4c8a78227180e9ce945c5163d740658 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 7 Nov 2018 00:33:01 +0100 Subject: [PATCH 1621/1776] client: Scale implies TRICK_MODE --- gst/rtsp-server/rtsp-client.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 55c2da802d..05937613a4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1768,7 +1768,8 @@ parse_header_failed: * (rate * scale * speed) */ static GstRTSPStatusCode parse_scale_and_speed (GstRTSPClient * client, GstRTSPContext * ctx, - gboolean * scale_present, gboolean * speed_present, gdouble * rate) + gboolean * scale_present, gboolean * speed_present, gdouble * rate, + GstSeekFlags * flags) { gdouble scale = 1.0; gdouble speed = 1.0; @@ -1786,6 +1787,9 @@ parse_scale_and_speed (GstRTSPClient * client, GstRTSPContext * ctx, if (scale == 0) goto bad_scale_value; *rate *= scale; + + if (ABS (scale) != 1.0) + *flags |= GST_SEEK_FLAG_TRICKMODE; } GST_DEBUG ("rate after parsing Scale %f", *rate); @@ -1865,7 +1869,7 @@ setup_play_mode (GstRTSPClient * client, GstRTSPContext * ctx, * rate from the resulting segment as values for the speed and scale headers * respectively */ rtsp_status_code = parse_scale_and_speed (client, ctx, scale_present, - speed_present, &rate); + speed_present, &rate, &flags); if (rtsp_status_code != GST_RTSP_STS_OK) goto scale_speed_failed; From 7640cb8f2111975038a92ee52be5fc0f96ecaf40 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 5 Nov 2018 15:34:20 +0100 Subject: [PATCH 1622/1776] rtsp-client: add gst_rtsp_client_get_stream_transport() This will be used in the onvif tests in order to validate the data transmitted over TCP: for streaming to continue after a data message has been provided to client->send_func, the client is responsible for marking the message as sent on the relevant stream transport. --- gst/rtsp-server/rtsp-client.c | 20 ++++++++++++++++++++ gst/rtsp-server/rtsp-client.h | 3 +++ 2 files changed, 23 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 05937613a4..596f54b595 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -4581,6 +4581,26 @@ gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession * session, return GST_RTSP_OK; } +/** + * gst_rtsp_client_get_stream_transport: + * + * This is useful when providing a send function through + * gst_rtsp_client_set_send_func() when doing RTSP over TCP: + * the send function must call gst_rtsp_stream_transport_message_sent () + * on the appropriate transport when data has been received for streaming + * to continue. + * + * Returns: (transfer none) (nullable): the #GstRTSPStreamTransport associated with @channel. + * + * Since: 1.18 + */ +GstRTSPStreamTransport * +gst_rtsp_client_get_stream_transport (GstRTSPClient * self, guint8 channel) +{ + return g_hash_table_lookup (self->priv->transports, + GINT_TO_POINTER ((gint) channel)); +} + static gboolean do_send_messages (GstRTSPClient * client, GstRTSPMessage * messages, guint n_messages, gboolean close, gpointer user_data) diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 2e47203eb2..de958cccd0 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -272,6 +272,9 @@ GList * gst_rtsp_client_session_filter (GstRTSPClient *client, GstRTSPClientSessionFilterFunc func, gpointer user_data); +GST_RTSP_SERVER_API +GstRTSPStreamTransport * gst_rtsp_client_get_stream_transport (GstRTSPClient *client, + guint8 channel); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC From 0f498eabf4439499a13f1de2b6c23dd64d844a83 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 5 Apr 2019 00:48:07 +0200 Subject: [PATCH 1623/1776] onvif: Implement and test the Streaming Specification https://www.onvif.org/specs/stream/ONVIF-Streaming-Spec.pdf --- gst/rtsp-server/rtsp-client.c | 22 +- gst/rtsp-server/rtsp-client.h | 14 +- gst/rtsp-server/rtsp-media.c | 89 +- gst/rtsp-server/rtsp-media.h | 15 +- gst/rtsp-server/rtsp-onvif-client.c | 119 ++ gst/rtsp-server/rtsp-onvif-client.h | 3 + gst/rtsp-server/rtsp-onvif-media-factory.c | 37 + gst/rtsp-server/rtsp-onvif-media-factory.h | 6 + gst/rtsp-server/rtsp-onvif-media.c | 10 + gst/rtsp-server/rtsp-onvif-server.h | 1 + gst/rtsp-server/rtsp-stream.c | 66 + gst/rtsp-server/rtsp-stream.h | 6 + tests/check/gst/media.c | 8 +- tests/check/gst/onvif.c | 1353 ++++++++++++++++++++ tests/check/meson.build | 1 + 15 files changed, 1727 insertions(+), 23 deletions(-) create mode 100644 tests/check/gst/onvif.c diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 596f54b595..ec608815d6 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1833,6 +1833,8 @@ setup_play_mode (GstRTSPClient * client, GstRTSPContext * ctx, GstSeekFlags flags = GST_SEEK_FLAG_NONE; GstRTSPClientClass *klass = GST_RTSP_CLIENT_GET_CLASS (client); GstRTSPStatusCode rtsp_status_code; + GstClockTime trickmode_interval = 0; + gboolean enable_rate_control = TRUE; /* parse the range header if we have one */ res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0); @@ -1876,13 +1878,17 @@ setup_play_mode (GstRTSPClient * client, GstRTSPContext * ctx, /* give the application a chance to tweak range, flags, or rate */ if (klass->adjust_play_mode != NULL) { rtsp_status_code = - klass->adjust_play_mode (client, ctx, &range, &flags, &rate); + klass->adjust_play_mode (client, ctx, &range, &flags, &rate, + &trickmode_interval, &enable_rate_control); if (rtsp_status_code != GST_RTSP_STS_OK) goto adjust_play_mode_failed; } + gst_rtsp_media_set_rate_control (ctx->media, enable_rate_control); + /* now do the seek with the seek options */ - (void) gst_rtsp_media_seek_full_with_rate (ctx->media, range, flags, rate); + gst_rtsp_media_seek_trickmode (ctx->media, range, flags, rate, + trickmode_interval); if (range != NULL) gst_rtsp_range_free (range); @@ -2031,6 +2037,12 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) g_strdup_printf ("%1.3f", rate)); } + if (klass->adjust_play_response) { + code = klass->adjust_play_response (client, ctx); + if (code != GST_RTSP_STS_OK) + goto adjust_play_response_failed; + } + send_message (client, ctx, ctx->response, FALSE); /* start playing after sending the response */ @@ -2114,6 +2126,12 @@ get_rates_error: send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx); return FALSE; } +adjust_play_response_failed: + { + GST_ERROR ("client %p: failed to adjust play response", client); + send_generic_response (client, code, ctx); + return FALSE; + } } static void diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index de958cccd0..604a042399 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -109,7 +109,10 @@ struct _GstRTSPClient { * RTSP response(ctx->response) via a call to gst_rtsp_message_init_response() * @make_path_from_uri: called to create path from uri. * @adjust_play_mode: called to give the application the possibility to adjust - * the range, seek flags, and/or rate. Since 1.18 + * the range, seek flags, rate and rate-control. Since 1.18 + * @adjust_play_response: called to give the implementation the possibility to + * adjust the response to a play request, for example if extra headers were + * parsed when #GstRTSPClientClass.adjust_play_mode was called. Since 1.18 * @tunnel_http_response: called when a response to the GET request is about to * be sent for a tunneled connection. The response can be modified. Since: 1.4 * @@ -132,7 +135,12 @@ struct _GstRTSPClientClass { GstRTSPContext * context, GstRTSPTimeRange ** range, GstSeekFlags * flags, - gdouble * rate); + gdouble * rate, + GstClockTime * trickmode_interval, + gboolean * enable_rate_control); + GstRTSPStatusCode (*adjust_play_response) (GstRTSPClient * client, + GstRTSPContext * context); + /* signals */ void (*closed) (GstRTSPClient *client); void (*new_session) (GstRTSPClient *client, GstRTSPSession *session); @@ -169,7 +177,7 @@ struct _GstRTSPClientClass { GstRTSPStatusCode (*pre_record_request) (GstRTSPClient *client, GstRTSPContext *ctx); /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE-17]; + gpointer _gst_reserved[GST_PADDING_LARGE-18]; }; GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e8686fd5dd..4c672ddfc2 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -51,7 +51,7 @@ * * The state of the media can be controlled with gst_rtsp_media_set_state (). * Seeking can be done with gst_rtsp_media_seek(), or gst_rtsp_media_seek_full() - * or gst_rtsp_media_seek_full_with_rate() for finer control of the seek. + * or gst_rtsp_media_seek_trickmode() for finer control of the seek. * * With gst_rtsp_media_unprepare() the pipeline is stopped and shut down. When * gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to @@ -146,6 +146,7 @@ struct _GstRTSPMediaPrivate gboolean do_retransmission; /* protected by lock */ guint latency; /* protected by lock */ GstClock *clock; /* protected by lock */ + gboolean do_rate_control; /* protected by lock */ GstRTSPPublishClockMode publish_clock_mode; /* Dynamic element handling */ @@ -167,6 +168,7 @@ struct _GstRTSPMediaPrivate #define DEFAULT_STOP_ON_DISCONNECT TRUE #define DEFAULT_MAX_MCAST_TTL 255 #define DEFAULT_BIND_MCAST_ADDRESS FALSE +#define DEFAULT_DO_RATE_CONTROL TRUE #define DEFAULT_DO_RETRANSMISSION FALSE @@ -471,6 +473,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS; + priv->do_rate_control = DEFAULT_DO_RATE_CONTROL; } static void @@ -2293,6 +2296,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time); gst_rtsp_stream_set_buffer_size (stream, priv->buffer_size); gst_rtsp_stream_set_publish_clock_mode (stream, priv->publish_clock_mode); + gst_rtsp_stream_set_rate_control (stream, priv->do_rate_control); g_ptr_array_add (priv->streams, stream); @@ -2662,13 +2666,15 @@ gst_rtsp_media_get_status (GstRTSPMedia * media) } /** - * gst_rtsp_media_seek_full_with_rate: + * gst_rtsp_media_seek_trickmode: * @media: a #GstRTSPMedia * @range: (transfer none): a #GstRTSPTimeRange * @flags: The minimal set of #GstSeekFlags to use * @rate: the rate to use in the seek + * @trickmode_interval: The trickmode interval to use for KEY_UNITS trick mode * - * Seek the pipeline of @media to @range with the given @flags and @rate. + * Seek the pipeline of @media to @range with the given @flags and @rate, + * and @trickmode_interval. * @media must be prepared with gst_rtsp_media_prepare(). * In order to perform the seek operation, the pipeline must contain all * needed transport parts (transport sinks). @@ -2678,8 +2684,9 @@ gst_rtsp_media_get_status (GstRTSPMedia * media) * Since: 1.18 */ gboolean -gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media, - GstRTSPTimeRange * range, GstSeekFlags flags, gdouble rate) +gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, + GstRTSPTimeRange * range, GstSeekFlags flags, gdouble rate, + GstClockTime trickmode_interval) { GstRTSPMediaClass *klass; GstRTSPMediaPrivate *priv; @@ -2789,6 +2796,8 @@ gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media, GST_DEBUG ("no position change, no flags set by caller, so not seeking"); res = TRUE; } else { + GstEvent *seek_event; + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); if (rate < 0.0) { @@ -2801,8 +2810,12 @@ gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media, stop_type = temp_type; } - res = gst_element_seek (priv->pipeline, rate, GST_FORMAT_TIME, - flags, start_type, start, stop_type, stop); + seek_event = gst_event_new_seek (rate, GST_FORMAT_TIME, flags, start_type, + start, stop_type, stop); + + gst_event_set_seek_trickmode_interval (seek_event, trickmode_interval); + + res = gst_element_send_event (priv->pipeline, seek_event); /* and block for the seek to complete */ GST_INFO ("done seeking %d", res); @@ -2880,7 +2893,7 @@ gboolean gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, GstSeekFlags flags) { - return gst_rtsp_media_seek_full_with_rate (media, range, flags, 1.0); + return gst_rtsp_media_seek_trickmode (media, range, flags, 1.0, 0); } /** @@ -2896,8 +2909,8 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, gboolean gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range) { - return gst_rtsp_media_seek_full_with_rate (media, range, GST_SEEK_FLAG_NONE, - 1.0); + return gst_rtsp_media_seek_trickmode (media, range, GST_SEEK_FLAG_NONE, + 1.0, 0); } static void @@ -4728,3 +4741,59 @@ gst_rtsp_media_is_receive_only (GstRTSPMedia * media) return receive_only; } + +/** + * gst_rtsp_media_set_rate_control: + * + * Define whether @media will follow the Rate-Control=no behaviour as specified + * in the ONVIF replay spec. + * + * Since: 1.18 + */ +void +gst_rtsp_media_set_rate_control (GstRTSPMedia * media, gboolean enabled) +{ + GstRTSPMediaPrivate *priv; + guint i; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + GST_LOG_OBJECT (media, "%s rate control", enabled ? "Enabling" : "Disabling"); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->do_rate_control = enabled; + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + + gst_rtsp_stream_set_rate_control (stream, enabled); + + } + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_get_rate_control: + * + * Returns: whether @media will follow the Rate-Control=no behaviour as specified + * in the ONVIF replay spec. + * + * Since: 1.18 + */ +gboolean +gst_rtsp_media_get_rate_control (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->do_rate_control; + g_mutex_unlock (&priv->lock); + + return res; +} diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 58d5aa40af..987a8ad017 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -388,10 +388,11 @@ gboolean gst_rtsp_media_seek_full (GstRTSPMedia *media, GstSeekFlags flags); GST_RTSP_SERVER_API -gboolean gst_rtsp_media_seek_full_with_rate (GstRTSPMedia *media, - GstRTSPTimeRange *range, - GstSeekFlags flags, - gdouble rate); +gboolean gst_rtsp_media_seek_trickmode (GstRTSPMedia *media, + GstRTSPTimeRange *range, + GstSeekFlags flags, + gdouble rate, + GstClockTime trickmode_interval); GST_RTSP_SERVER_API GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia *media); @@ -420,6 +421,12 @@ gboolean gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GP GST_RTSP_SERVER_API gboolean gst_rtsp_media_is_receive_only (GstRTSPMedia * media); +GST_RTSP_SERVER_API +void gst_rtsp_media_set_rate_control (GstRTSPMedia * media, gboolean enabled); + +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_get_rate_control (GstRTSPMedia * media); + #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPMedia, gst_object_unref) #endif diff --git a/gst/rtsp-server/rtsp-onvif-client.c b/gst/rtsp-server/rtsp-onvif-client.c index 2fb50fa04f..36b7ee3c75 100644 --- a/gst/rtsp-server/rtsp-onvif-client.c +++ b/gst/rtsp-server/rtsp-onvif-client.c @@ -37,11 +37,14 @@ gst_rtsp_onvif_client_check_requirements (GstRTSPClient * client, GstRTSPMediaFactory *factory = NULL; gchar *path = NULL; gboolean has_backchannel = FALSE; + gboolean has_replay = FALSE; GString *unsupported = g_string_new (""); while (*requirements) { if (strcmp (*requirements, GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT) == 0) { has_backchannel = TRUE; + } else if (strcmp (*requirements, GST_RTSP_ONVIF_REPLAY_REQUIREMENT) == 0) { + has_replay = TRUE; } else { if (unsupported->len) g_string_append (unsupported, ", "); @@ -75,6 +78,22 @@ gst_rtsp_onvif_client_check_requirements (GstRTSPClient * client, } } + if (has_replay && !GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory)) { + if (unsupported->len) + g_string_append (unsupported, ", "); + g_string_append (unsupported, GST_RTSP_ONVIF_REPLAY_REQUIREMENT); + } else if (has_replay) { + GstRTSPOnvifMediaFactory *onvif_factory = + GST_RTSP_ONVIF_MEDIA_FACTORY (factory); + + if (!gst_rtsp_onvif_media_factory_has_replay_support (onvif_factory)) { + if (unsupported->len) + g_string_append (unsupported, ", "); + g_string_append (unsupported, GST_RTSP_ONVIF_REPLAY_REQUIREMENT); + } + } + + out: if (path) g_free (path); @@ -86,15 +105,115 @@ out: return g_string_free (unsupported, FALSE); } +static GstRTSPStatusCode +gst_rtsp_onvif_client_adjust_play_mode (GstRTSPClient * client, + GstRTSPContext * ctx, GstRTSPTimeRange ** range, GstSeekFlags * flags, + gdouble * rate, GstClockTime * trickmode_interval, + gboolean * enable_rate_control) +{ + GstRTSPStatusCode ret = GST_RTSP_STS_BAD_REQUEST; + gchar **split = NULL; + gchar *str; + + if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_FRAMES, + &str, 0) == GST_RTSP_OK) { + + split = g_strsplit (str, "/", 2); + + if (!g_strcmp0 (split[0], "intra")) { + if (split[1]) { + guint64 interval; + gchar *end; + + interval = g_ascii_strtoull (split[1], &end, 10); + + if (!end || *end != '\0') { + GST_ERROR ("Unexpected interval value %s", split[1]); + goto done; + } + + *trickmode_interval = interval * GST_MSECOND; + } + *flags |= GST_SEEK_FLAG_TRICKMODE_KEY_UNITS; + } else if (!g_strcmp0 (split[0], "predicted")) { + if (split[1]) { + GST_ERROR ("Predicted frames mode does not allow an interval (%s)", + str); + goto done; + } + *flags |= GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED; + } else { + GST_ERROR ("Invalid frames mode (%s)", str); + goto done; + } + } + + if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RATE_CONTROL, + &str, 0) == GST_RTSP_OK) { + if (!g_strcmp0 (str, "no")) { + *enable_rate_control = FALSE; + } else if (!g_strcmp0 (str, "yes")) { + *enable_rate_control = TRUE; + } else { + GST_ERROR ("Invalid rate control header: %s", str); + goto done; + } + } + + ret = GST_RTSP_STS_OK; + +done: + if (split) + g_strfreev (split); + return ret; +} + +static GstRTSPStatusCode +gst_rtsp_onvif_client_adjust_play_response (GstRTSPClient * client, + GstRTSPContext * ctx) +{ + GstRTSPStatusCode ret = GST_RTSP_STS_OK; + gchar *str; + + if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RATE_CONTROL, + &str, 0) == GST_RTSP_OK) { + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_RATE_CONTROL, + gst_rtsp_media_get_rate_control (ctx->media) ? "yes" : "no"); + } + + return ret; +} + static void gst_rtsp_onvif_client_class_init (GstRTSPOnvifClientClass * klass) { GstRTSPClientClass *client_klass = (GstRTSPClientClass *) klass; client_klass->check_requirements = gst_rtsp_onvif_client_check_requirements; + client_klass->adjust_play_mode = gst_rtsp_onvif_client_adjust_play_mode; + client_klass->adjust_play_response = + gst_rtsp_onvif_client_adjust_play_response; } static void gst_rtsp_onvif_client_init (GstRTSPOnvifClient * client) { } + +/** + * gst_rtsp_onvif_client_new: + * + * Create a new #GstRTSPOnvifClient instance. + * + * Returns: (transfer full): a new #GstRTSPOnvifClient + * Since: 1.18 + */ +GstRTSPClient * +gst_rtsp_onvif_client_new (void) +{ + GstRTSPClient *result; + + result = g_object_new (GST_TYPE_RTSP_ONVIF_CLIENT, NULL); + + return result; +} diff --git a/gst/rtsp-server/rtsp-onvif-client.h b/gst/rtsp-server/rtsp-onvif-client.h index 2692cbf8c6..8230f23c59 100644 --- a/gst/rtsp-server/rtsp-onvif-client.h +++ b/gst/rtsp-server/rtsp-onvif-client.h @@ -59,4 +59,7 @@ struct GstRTSPOnvifClient GST_RTSP_SERVER_API GType gst_rtsp_onvif_client_get_type (void); +GST_RTSP_SERVER_API +GstRTSPClient * gst_rtsp_onvif_client_new (void); + #endif /* __GST_RTSP_ONVIF_CLIENT_H__ */ diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.c b/gst/rtsp-server/rtsp-onvif-media-factory.c index 7da567091c..ff05cdfb7e 100644 --- a/gst/rtsp-server/rtsp-onvif-media-factory.c +++ b/gst/rtsp-server/rtsp-onvif-media-factory.c @@ -50,6 +50,7 @@ struct GstRTSPOnvifMediaFactoryPrivate GMutex lock; gchar *backchannel_launch; guint backchannel_bandwidth; + gboolean has_replay_support; }; G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPOnvifMediaFactory, @@ -447,6 +448,42 @@ gst_rtsp_onvif_media_factory_has_backchannel_support (GstRTSPOnvifMediaFactory * return FALSE; } +/** + * gst_rtsp_onvif_media_factory_has_replay_support: + * + * Returns: %TRUE if ONVIF replay is supported by the media factory. + * + * Since: 1.18 + */ +gboolean +gst_rtsp_onvif_media_factory_has_replay_support (GstRTSPOnvifMediaFactory * + factory) +{ + gboolean has_replay_support; + + g_mutex_lock (&factory->priv->lock); + has_replay_support = factory->priv->has_replay_support; + g_mutex_unlock (&factory->priv->lock); + + return has_replay_support; +} + +/** + * gst_rtsp_onvif_media_factory_set_replay_support: + * + * Set to %TRUE if ONVIF replay is supported by the media factory. + * + * Since: 1.18 + */ +void +gst_rtsp_onvif_media_factory_set_replay_support (GstRTSPOnvifMediaFactory * + factory, gboolean has_replay_support) +{ + g_mutex_lock (&factory->priv->lock); + factory->priv->has_replay_support = has_replay_support; + g_mutex_unlock (&factory->priv->lock); +} + /** * gst_rtsp_onvif_media_factory_set_backchannel_bandwidth: * @factory: a #GstRTSPMediaFactory diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.h b/gst/rtsp-server/rtsp-onvif-media-factory.h index 25de214a87..bbfcabe7db 100644 --- a/gst/rtsp-server/rtsp-onvif-media-factory.h +++ b/gst/rtsp-server/rtsp-onvif-media-factory.h @@ -74,6 +74,12 @@ gchar * gst_rtsp_onvif_media_factory_get_backchannel_launch (GstRTSPOnvifMediaFa GST_RTSP_SERVER_API gboolean gst_rtsp_onvif_media_factory_has_backchannel_support (GstRTSPOnvifMediaFactory * factory); +GST_RTSP_SERVER_API +gboolean gst_rtsp_onvif_media_factory_has_replay_support (GstRTSPOnvifMediaFactory * factory); + +GST_RTSP_SERVER_API +void gst_rtsp_onvif_media_factory_set_replay_support (GstRTSPOnvifMediaFactory * factory, gboolean has_replay_support); + GST_RTSP_SERVER_API void gst_rtsp_onvif_media_factory_set_backchannel_bandwidth (GstRTSPOnvifMediaFactory * factory, guint bandwidth); GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-onvif-media.c b/gst/rtsp-server/rtsp-onvif-media.c index 29fdec294c..04eb406fad 100644 --- a/gst/rtsp-server/rtsp-onvif-media.c +++ b/gst/rtsp-server/rtsp-onvif-media.c @@ -131,6 +131,16 @@ gst_rtsp_onvif_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp, if (res) { GstSDPMedia *smedia = &g_array_index (sdp->medias, GstSDPMedia, sdp->medias->len - 1); + gchar *x_onvif_track, *media_str; + + media_str = + g_ascii_strup (gst_structure_get_string (s, "media"), -1); + x_onvif_track = + g_strdup_printf ("%s%03d", media_str, sdp->medias->len - 1); + gst_sdp_media_add_attribute (smedia, "x-onvif-track", + x_onvif_track); + g_free (x_onvif_track); + g_free (media_str); if (sinkpad) { GstRTSPOnvifMedia *onvif_media = GST_RTSP_ONVIF_MEDIA (media); diff --git a/gst/rtsp-server/rtsp-onvif-server.h b/gst/rtsp-server/rtsp-onvif-server.h index 0594ba1c03..b04c9b4d5c 100644 --- a/gst/rtsp-server/rtsp-onvif-server.h +++ b/gst/rtsp-server/rtsp-onvif-server.h @@ -62,6 +62,7 @@ GST_RTSP_SERVER_API GstRTSPServer *gst_rtsp_onvif_server_new (void); #define GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT "www.onvif.org/ver20/backchannel" +#define GST_RTSP_ONVIF_REPLAY_REQUIREMENT "onvif-replay" #include "rtsp-onvif-client.h" #include "rtsp-onvif-media-factory.h" diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 80f0217e5c..4dfd4352fd 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -130,6 +130,9 @@ struct _GstRTSPStreamPrivate guint rtx_pt; GstClockTime rtx_time; + /* rate control */ + gboolean do_rate_control; + /* Forward Error Correction with RFC 5109 */ GstElement *ulpfec_decoder; GstElement *ulpfec_encoder; @@ -190,6 +193,7 @@ struct _GstRTSPStreamPrivate GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_MAX_MCAST_TTL 255 #define DEFAULT_BIND_MCAST_ADDRESS FALSE +#define DEFAULT_DO_RATE_CONTROL TRUE enum { @@ -291,6 +295,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS; + priv->do_rate_control = DEFAULT_DO_RATE_CONTROL; g_mutex_init (&priv->lock); @@ -3378,6 +3383,11 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport) return FALSE; } + if (g_object_class_find_property (G_OBJECT_GET_CLASS (priv->payloader), + "onvif-no-rate-control")) + g_object_set (priv->payloader, "onvif-no-rate-control", + !priv->do_rate_control, NULL); + for (i = 0; i < 2; i++) { gboolean link_tee = FALSE; /* For the sender we create this bit of pipeline for both @@ -3436,6 +3446,9 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport) g_object_set (priv->appsink[i], "emit-signals", FALSE, "buffer-list", TRUE, "max-buffers", 1, NULL); + if (i == 0) + g_object_set (priv->appsink[i], "sync", priv->do_rate_control, NULL); + /* we need to set sync and preroll to FALSE for the sink to avoid * deadlock. This is only needed for sink sending RTCP data. */ if (i == 1) @@ -3765,6 +3778,9 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, g_signal_connect (priv->session, "on-sender-ssrc-active", (GCallback) on_sender_ssrc_active, stream); + g_object_set (priv->session, "disable-sr-timestamp", !priv->do_rate_control, + NULL); + if (priv->srcpad) { /* be notified of caps changes */ priv->caps_sig = g_signal_connect (priv->send_src[0], "notify::caps", @@ -5919,3 +5935,53 @@ gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream * stream) return res; } + +/** + * gst_rtsp_stream_set_rate_control: + * + * Define whether @stream will follow the Rate-Control=no behaviour as specified + * in the ONVIF replay spec. + * + * Since: 1.18 + */ +void +gst_rtsp_stream_set_rate_control (GstRTSPStream * stream, gboolean enabled) +{ + GST_DEBUG_OBJECT (stream, "%s rate control", + enabled ? "Enabling" : "Disabling"); + + g_mutex_lock (&stream->priv->lock); + stream->priv->do_rate_control = enabled; + if (stream->priv->appsink[0]) + g_object_set (stream->priv->appsink[0], "sync", enabled, NULL); + if (stream->priv->payloader + && g_object_class_find_property (G_OBJECT_GET_CLASS (stream->priv-> + payloader), "onvif-no-rate-control")) + g_object_set (stream->priv->payloader, "onvif-no-rate-control", !enabled, + NULL); + if (stream->priv->session) { + g_object_set (stream->priv->session, "disable-sr-timestamp", !enabled, + NULL); + } + g_mutex_unlock (&stream->priv->lock); +} + +/** + * gst_rtsp_stream_get_rate_control: + * + * Returns: whether @stream will follow the Rate-Control=no behaviour as specified + * in the ONVIF replay spec. + * + * Since: 1.18 + */ +gboolean +gst_rtsp_stream_get_rate_control (GstRTSPStream * stream) +{ + gboolean ret; + + g_mutex_lock (&stream->priv->lock); + ret = stream->priv->do_rate_control; + g_mutex_unlock (&stream->priv->lock); + + return ret; +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 424a0230ee..dcb5d7a9a4 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -359,6 +359,12 @@ void gst_rtsp_stream_set_ulpfec_percentage (GstRTSPStream *stream, GST_RTSP_SERVER_API guint gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream *stream); +GST_RTSP_SERVER_API +void gst_rtsp_stream_set_rate_control (GstRTSPStream * stream, gboolean enabled); + +GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_get_rate_control (GstRTSPStream * stream); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 58b3e0477c..8a41854baa 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -109,16 +109,16 @@ GST_START_TEST (test_media_seek) fail_unless (applied_rate == 1.0); /* seeking with rate set to 1.5 should result in rate == 1.5 */ - fail_unless (gst_rtsp_media_seek_full_with_rate (media, range, - GST_SEEK_FLAG_NONE, 1.5)); + fail_unless (gst_rtsp_media_seek_trickmode (media, range, + GST_SEEK_FLAG_NONE, 1.5, 0)); fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate)); fail_unless (rate == 1.5); fail_unless (applied_rate == 1.0); /* seeking with rate set to -2.0 should result in rate == -2.0 */ fail_unless (gst_rtsp_range_parse ("npt=10-5", &range) == GST_RTSP_OK); - fail_unless (gst_rtsp_media_seek_full_with_rate (media, range, - GST_SEEK_FLAG_NONE, -2.0)); + fail_unless (gst_rtsp_media_seek_trickmode (media, range, + GST_SEEK_FLAG_NONE, -2.0, 0)); fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate)); fail_unless (rate == -2.0); fail_unless (applied_rate == 1.0); diff --git a/tests/check/gst/onvif.c b/tests/check/gst/onvif.c new file mode 100644 index 0000000000..beb276fbf4 --- /dev/null +++ b/tests/check/gst/onvif.c @@ -0,0 +1,1353 @@ +/* GStreamer + * Copyright (C) 2018 Mathieu Duponchelle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Test source implementation */ + +#define FRAME_DURATION (GST_MSECOND) + +typedef struct +{ + GstPushSrc element; + + GstSegment *segment; + /* In milliseconds */ + guint trickmode_interval; + GstClockTime ntp_offset; +} TestSrc; + +typedef struct +{ + GstPushSrcClass parent_class; +} TestSrcClass; + +/** + * video/x-dumdum is a very simple encoded video format: + * + * - It has I-frames, P-frames and B-frames for the purpose + * of testing trick modes, and is infinitely scalable, mimicking server-side + * trick modes that would have the server reencode when a trick mode seek with + * an absolute rate different from 1.0 is requested. + * + * - The only source capable of outputting this format, `TestSrc`, happens + * to always output frames following this pattern: + * + * IBBBBPBBBBI + * + * Its framerate is 1000 / 1, each Group of Pictures is thus 10 milliseconds + * long. The first frame in the stream dates back to January the first, + * 1900, at exactly midnight. There are no gaps in the stream. + * + * A nice side effect of this for testing purposes is that as the resolution + * of UTC (clock=) seeks is a hundredth of a second, this coincides with the + * alignment of our Group of Pictures, which means we don't have to worry + * about synchronization points. + * + * - Size is used to distinguish the various frame types: + * + * * I frames: 20 bytes + * * P frames: 10 bytes + * * B frames: 5 bytes + * + */ + +#define TEST_CAPS "video/x-dumdum" + +typedef enum +{ + FRAME_TYPE_I, + FRAME_TYPE_P, + FRAME_TYPE_B, +} FrameType; + +static FrameType +frame_type_for_index (guint64 index) +{ + FrameType ret; + + if (index % 10 == 0) + ret = FRAME_TYPE_I; + else if (index % 5 == 0) + ret = FRAME_TYPE_P; + else + ret = FRAME_TYPE_B; + + return ret; +} + +static GstStaticPadTemplate test_src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (TEST_CAPS) + ); + +GType test_src_get_type (void); + +#define test_src_parent_class parent_class +G_DEFINE_TYPE (TestSrc, test_src, GST_TYPE_PUSH_SRC); + +#define ROUND_UP_TO_10(x) (((x + 10 - 1) / 10) * 10) +#define ROUND_DOWN_TO_10(x) (x - (x % 10)) + +/* + * For now, the theoretical range of our test source is infinite. + * + * When creating a buffer, we use the current segment position to + * determine the PTS, and simply increment it afterwards. + * + * When the stop time of a buffer we have created reaches segment->stop, + * GstBaseSrc will take care of sending an EOS for us, which rtponviftimestamp + * will translate to setting the T flag in the RTP header extension. + */ +static GstFlowReturn +test_src_create (GstPushSrc * psrc, GstBuffer ** buffer) +{ + GstFlowReturn ret = GST_FLOW_OK; + gsize buf_size; + TestSrc *src = (TestSrc *) psrc; + GstClockTime pts, duration; + FrameType ftype; + guint64 n_frames; + + if (src->segment->rate < 1.0) { + if (src->segment->position < src->segment->start) { + ret = GST_FLOW_EOS; + goto done; + } + } else if ((src->segment->position >= src->segment->stop)) { + ret = GST_FLOW_EOS; + goto done; + } + + pts = src->segment->position; + duration = FRAME_DURATION; + + if ((src->segment->flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) { + duration = + MAX (duration * 10, + duration * ROUND_UP_TO_10 (src->trickmode_interval)); + } else if ((src->segment-> + flags & GST_SEGMENT_FLAG_TRICKMODE_FORWARD_PREDICTED)) { + duration *= 5; + } + + n_frames = gst_util_uint64_scale (src->segment->position, 1000, GST_SECOND); + + ftype = frame_type_for_index (n_frames); + + switch (ftype) { + case FRAME_TYPE_I: + buf_size = 20; + break; + case FRAME_TYPE_P: + buf_size = 10; + break; + case FRAME_TYPE_B: + buf_size = 5; + break; + } + + *buffer = gst_buffer_new_allocate (NULL, buf_size, NULL); + + if (ftype != FRAME_TYPE_I) { + GST_BUFFER_FLAG_SET (*buffer, GST_BUFFER_FLAG_DELTA_UNIT); + } + + GST_BUFFER_PTS (*buffer) = pts; + GST_BUFFER_DURATION (*buffer) = duration; + + src->segment->position = pts + duration; + + if (!GST_CLOCK_TIME_IS_VALID (src->ntp_offset)) { + GstClock *clock = gst_system_clock_obtain (); + GstClockTime clock_time = gst_clock_get_time (clock); + guint64 real_time = g_get_real_time (); + GstStructure *s; + GstEvent *onvif_event; + + real_time *= 1000; + real_time += (G_GUINT64_CONSTANT (2208988800) * GST_SECOND); + src->ntp_offset = real_time - clock_time; + + s = gst_structure_new ("GstNtpOffset", + "ntp-offset", G_TYPE_UINT64, src->ntp_offset, + "discont", G_TYPE_BOOLEAN, FALSE, NULL); + + onvif_event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s); + + gst_element_send_event (GST_ELEMENT (src), onvif_event); + } + + if (src->segment->rate < 1.0) { + guint64 next_n_frames = + gst_util_uint64_scale (src->segment->position, 1000, GST_SECOND); + + if (src->segment->position > src->segment->stop + || next_n_frames / 10 > n_frames / 10) { + GstStructure *s; + GstEvent *onvif_event; + guint n_gops; + + n_gops = MAX (1, ((int) src->trickmode_interval / 10)); + + next_n_frames = (n_frames / 10 - n_gops) * 10; + + src->segment->position = next_n_frames * GST_MSECOND; + s = gst_structure_new ("GstNtpOffset", + "ntp-offset", G_TYPE_UINT64, src->ntp_offset, + "discont", G_TYPE_BOOLEAN, TRUE, NULL); + + onvif_event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s); + + gst_element_send_event (GST_ELEMENT (src), onvif_event); + } + } + +done: + return ret; +} + +static void +test_src_init (TestSrc * src) +{ + gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME); + gst_base_src_set_automatic_eos (GST_BASE_SRC (src), FALSE); + src->segment = NULL; + src->ntp_offset = GST_CLOCK_TIME_NONE; +} + +/* + * We support seeking, both this method and GstBaseSrc.do_seek must + * be implemented for GstBaseSrc to report TRUE in the seeking query. + */ +static gboolean +test_src_is_seekable (GstBaseSrc * bsrc) +{ + return TRUE; +} + +/* Extremely simple seek handling for now, we simply update our + * segment, which will cause test_src_create to timestamp output + * buffers as expected. + */ +static gboolean +test_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment) +{ + TestSrc *src = (TestSrc *) bsrc; + + if ((segment->flags & GST_SEGMENT_FLAG_TRICKMODE + && ABS (segment->rate) != 1.0)) { + segment->applied_rate = segment->rate; + segment->stop = + segment->start + ((segment->stop - + segment->start) / ABS (segment->rate)); + segment->rate = segment->rate > 0 ? 1.0 : -1.0; + } + + if (src->segment) + gst_segment_free (src->segment); + + src->segment = gst_segment_copy (segment); + + if (src->segment->rate < 0) { + guint64 n_frames = + ROUND_DOWN_TO_10 (gst_util_uint64_scale (src->segment->stop, 1000, + GST_SECOND)); + + src->segment->position = n_frames * GST_MSECOND; + } + + return TRUE; +} + +static gboolean +test_src_event (GstBaseSrc * bsrc, GstEvent * event) +{ + TestSrc *src = (TestSrc *) bsrc; + + if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) { + GstClockTime interval; + + gst_event_parse_seek_trickmode_interval (event, &interval); + + src->trickmode_interval = interval / 1000000; + } + + return GST_BASE_SRC_CLASS (parent_class)->event (bsrc, event); +} + +static void +test_src_class_init (TestSrcClass * klass) +{ + gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass), + &test_src_template); + GST_PUSH_SRC_CLASS (klass)->create = test_src_create; + GST_BASE_SRC_CLASS (klass)->is_seekable = test_src_is_seekable; + GST_BASE_SRC_CLASS (klass)->do_seek = test_src_do_seek; + GST_BASE_SRC_CLASS (klass)->event = test_src_event; +} + +static GstElement * +test_src_new (void) +{ + return g_object_new (test_src_get_type (), NULL); +} + +/* Test media factory */ + +typedef struct +{ + GstRTSPMediaFactory factory; +} TestMediaFactory; + +typedef struct +{ + GstRTSPMediaFactoryClass parent_class; +} TestMediaFactoryClass; + +GType test_media_factory_get_type (void); + +G_DEFINE_TYPE (TestMediaFactory, test_media_factory, + GST_TYPE_RTSP_MEDIA_FACTORY); + +#define MAKE_AND_ADD(var, pipe, name, label, elem_name) \ +G_STMT_START { \ + if (G_UNLIKELY (!(var = (gst_element_factory_make (name, elem_name))))) { \ + GST_ERROR ("Could not create element %s", name); \ + goto label; \ + } \ + if (G_UNLIKELY (!gst_bin_add (GST_BIN_CAST (pipe), var))) { \ + GST_ERROR ("Could not add element %s", name); \ + goto label; \ + } \ +} G_STMT_END + +static GstElement * +test_media_factory_create_element (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url) +{ + GstElement *ret = gst_bin_new (NULL); + GstElement *pbin = gst_bin_new ("pay0"); + GstElement *src, *pay, *onvifts, *queue; + GstPad *sinkpad, *srcpad; + GstPadLinkReturn link_ret; + + src = test_src_new (); + gst_bin_add (GST_BIN (ret), src); + MAKE_AND_ADD (pay, pbin, "rtpgstpay", fail, NULL); + MAKE_AND_ADD (onvifts, pbin, "rtponviftimestamp", fail, NULL); + MAKE_AND_ADD (queue, pbin, "queue", fail, NULL); + + gst_bin_add (GST_BIN (ret), pbin); + if (!gst_element_link_many (pay, onvifts, queue, NULL)) + goto fail; + + sinkpad = gst_element_get_static_pad (pay, "sink"); + gst_element_add_pad (pbin, gst_ghost_pad_new ("sink", sinkpad)); + gst_object_unref (sinkpad); + + sinkpad = gst_element_get_static_pad (pbin, "sink"); + srcpad = gst_element_get_static_pad (src, "src"); + link_ret = gst_pad_link (srcpad, sinkpad); + gst_object_unref (srcpad); + gst_object_unref (sinkpad); + + if (link_ret != GST_PAD_LINK_OK) + goto fail; + + srcpad = gst_element_get_static_pad (queue, "src"); + gst_element_add_pad (pbin, gst_ghost_pad_new ("src", srcpad)); + gst_object_unref (srcpad); + + g_object_set (pay, "timestamp-offset", 0, NULL); + g_object_set (onvifts, "set-t-bit", TRUE, NULL); + +done: + return ret; + +fail: + gst_object_unref (ret); + ret = NULL; + goto done; +} + +static void +test_media_factory_init (TestMediaFactory * factory) +{ +} + +static void +test_media_factory_class_init (TestMediaFactoryClass * klass) +{ + GST_RTSP_MEDIA_FACTORY_CLASS (klass)->create_element = + test_media_factory_create_element; +} + +static GstRTSPMediaFactory * +test_media_factory_new (void) +{ + GstRTSPMediaFactory *result; + + result = g_object_new (test_media_factory_get_type (), NULL); + + return result; +} + +/* Actual tests implementation */ + +static gchar *session_id; +static gint cseq; +static gboolean terminal_frame; +static gboolean received_rtcp; + +static GstSDPMessage * +sdp_from_message (GstRTSPMessage * msg) +{ + GstSDPMessage *sdp_message; + guint8 *body = NULL; + guint body_size; + + fail_unless (gst_rtsp_message_get_body (msg, &body, + &body_size) == GST_RTSP_OK); + fail_unless (gst_sdp_message_new (&sdp_message) == GST_SDP_OK); + fail_unless (gst_sdp_message_parse_buffer (body, body_size, + sdp_message) == GST_SDP_OK); + + return sdp_message; +} + +static gboolean +test_response_x_onvif_track (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + GstSDPMessage *sdp = sdp_from_message (response); + guint medias_len = gst_sdp_message_medias_len (sdp); + guint i; + + fail_unless_equals_int (medias_len, 1); + + for (i = 0; i < medias_len; i++) { + const GstSDPMedia *smedia = gst_sdp_message_get_media (sdp, i); + gchar *x_onvif_track = g_strdup_printf ("APPLICATION%03d", i); + + fail_unless_equals_string (gst_sdp_media_get_attribute_val (smedia, + "x-onvif-track"), x_onvif_track); + } + + gst_sdp_message_free (sdp); + + return TRUE; +} + +static gboolean +test_setup_response_200 (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + gchar *str; + GstRTSPSessionPool *session_pool; + GstRTSPSession *session; + gchar **session_hdr_params; + + fail_unless_equals_int (gst_rtsp_message_get_type (response), + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless_equals_int (code, GST_RTSP_STS_OK); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, + 0) == GST_RTSP_OK); + fail_unless (atoi (str) == cseq++); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, + &str, 0) == GST_RTSP_OK); + session_hdr_params = g_strsplit (str, ";", -1); + + /* session-id value */ + fail_unless (session_hdr_params[0] != NULL); + + session_pool = gst_rtsp_client_get_session_pool (client); + fail_unless (session_pool != NULL); + + session = gst_rtsp_session_pool_find (session_pool, session_hdr_params[0]); + g_strfreev (session_hdr_params); + + /* remember session id to be able to send teardown */ + if (session_id) + g_free (session_id); + session_id = g_strdup (gst_rtsp_session_get_sessionid (session)); + fail_unless (session_id != NULL); + + fail_unless (session != NULL); + g_object_unref (session); + + g_object_unref (session_pool); + + return TRUE; +} + +static gboolean +test_response_200 (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + + fail_unless_equals_int (gst_rtsp_message_get_type (response), + GST_RTSP_MESSAGE_RESPONSE); + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless_equals_int (code, GST_RTSP_STS_OK); + + return TRUE; +} + +typedef struct +{ + guint32 previous_ts; + gint32 expected_ts_interval; + gint32 expected_i_frame_ts_interval; + guint expected_n_buffers; + guint n_buffers; + guint expected_n_i_frames; + guint n_i_frames; + guint expected_n_p_frames; + guint n_p_frames; + guint expected_n_b_frames; + guint n_b_frames; + guint expected_n_clean_points; + guint n_clean_points; + gboolean timestamped_rtcp; +} RTPCheckData; + +#define EXTENSION_ID 0xABAC +#define EXTENSION_SIZE 3 + +static gboolean +test_play_response_200_and_check_data (GstRTSPClient * client, + GstRTSPMessage * response, gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + RTPCheckData *check = (RTPCheckData *) user_data; + + /* We check data in the same send function because client->send_func cannot + * be changed from client->send_func + */ + if (gst_rtsp_message_get_type (response) == GST_RTSP_MESSAGE_DATA) { + GstRTSPStreamTransport *trans; + guint8 channel = 42; + + gst_rtsp_message_parse_data (response, &channel); + fail_unless (trans = + gst_rtsp_client_get_stream_transport (client, channel)); + + if (channel == 0) { /* RTP */ + GstBuffer *buf; + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + guint8 *body = NULL; + guint body_size; + guint8 *data; + guint16 bits; + guint wordlen; + guint8 flags; + gint32 expected_interval; + gboolean is_custom_event = FALSE; + + fail_unless (gst_rtsp_message_get_body (response, &body, + &body_size) == GST_RTSP_OK); + + buf = gst_rtp_buffer_new_copy_data (body, body_size); + + switch (body_size) { + case 115: /* Ignore our serialized custom events */ + is_custom_event = TRUE; + break; + case 56: + expected_interval = check->expected_i_frame_ts_interval; + check->n_i_frames += 1; + break; + case 46: + expected_interval = check->expected_ts_interval; + check->n_p_frames += 1; + break; + case 41: + expected_interval = check->expected_ts_interval; + check->n_b_frames += 1; + break; + default: + fail ("Invalid body size %u", body_size); + } + + if (!is_custom_event) { + fail_unless (gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp)); + + if (check->previous_ts) { + fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp) - + check->previous_ts, expected_interval); + } + + check->previous_ts = gst_rtp_buffer_get_timestamp (&rtp); + check->n_buffers += 1; + + fail_unless (gst_rtp_buffer_get_extension_data (&rtp, &bits, + (gpointer) & data, &wordlen)); + + fail_unless (bits == EXTENSION_ID && wordlen == EXTENSION_SIZE); + + flags = GST_READ_UINT8 (data + 8); + + gst_rtp_buffer_unmap (&rtp); + + if (flags & (1 << 7)) { + check->n_clean_points += 1; + } + + /* T flag is set, we are done */ + if (flags & (1 << 4)) { + fail_unless_equals_int (check->expected_n_buffers, check->n_buffers); + fail_unless_equals_int (check->expected_n_i_frames, + check->n_i_frames); + fail_unless_equals_int (check->expected_n_p_frames, + check->n_p_frames); + fail_unless_equals_int (check->expected_n_b_frames, + check->n_b_frames); + fail_unless_equals_int (check->expected_n_clean_points, + check->n_clean_points); + + terminal_frame = TRUE; + + } + } + + gst_buffer_unref (buf); + } else if (channel == 1) { /* RTCP */ + GstBuffer *buf; + guint8 *body = NULL; + guint body_size; + GstRTCPPacket packet; + GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT; + guint32 ssrc, rtptime, packet_count, octet_count; + guint64 ntptime; + + received_rtcp = TRUE; + fail_unless (gst_rtsp_message_get_body (response, &body, + &body_size) == GST_RTSP_OK); + + buf = gst_rtp_buffer_new_copy_data (body, body_size); + gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp); + gst_rtcp_buffer_get_first_packet (&rtcp, &packet); + + gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, &rtptime, + &packet_count, &octet_count); + + if (check->timestamped_rtcp) { + fail_unless (rtptime != 0); + fail_unless (ntptime != 0); + } else { + fail_unless (rtptime == 0); + fail_unless (ntptime == 0); + } + + gst_rtcp_buffer_unmap (&rtcp); + gst_buffer_unref (buf); + } + + gst_rtsp_stream_transport_message_sent (trans); + + if (terminal_frame && received_rtcp) { + g_mutex_lock (&check_mutex); + g_cond_broadcast (&check_cond); + g_mutex_unlock (&check_mutex); + } + + return TRUE; + } + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_OK); + + return TRUE; +} + +static gboolean +test_teardown_response_200 (GstRTSPClient * client, + GstRTSPMessage * response, gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + + /* We might still be seeing stray RTCP messages */ + if (gst_rtsp_message_get_type (response) == GST_RTSP_MESSAGE_DATA) + return TRUE; + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_OK); + fail_unless (g_str_equal (reason, "OK")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + return TRUE; +} + +static void +send_teardown (GstRTSPClient * client) +{ + GstRTSPMessage request = { 0, }; + gchar *str; + + fail_unless (session_id != NULL); + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_TEARDOWN, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + gst_rtsp_client_set_send_func (client, test_teardown_response_200, + NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + g_free (session_id); + session_id = NULL; +} + +static GstRTSPClient * +setup_client (const gchar * launch_line) +{ + GstRTSPClient *client; + GstRTSPSessionPool *session_pool; + GstRTSPMountPoints *mount_points; + GstRTSPMediaFactory *factory; + GstRTSPThreadPool *thread_pool; + + client = gst_rtsp_onvif_client_new (); + + session_pool = gst_rtsp_session_pool_new (); + gst_rtsp_client_set_session_pool (client, session_pool); + + mount_points = gst_rtsp_mount_points_new (); + factory = test_media_factory_new (); + + gst_rtsp_media_factory_set_media_gtype (factory, GST_TYPE_RTSP_ONVIF_MEDIA); + + gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); + gst_rtsp_client_set_mount_points (client, mount_points); + + thread_pool = gst_rtsp_thread_pool_new (); + gst_rtsp_client_set_thread_pool (client, thread_pool); + + g_object_unref (mount_points); + g_object_unref (session_pool); + g_object_unref (thread_pool); + + return client; +} + +static void +teardown_client (GstRTSPClient * client) +{ + gst_rtsp_client_set_thread_pool (client, NULL); + g_object_unref (client); +} + +/** + * https://www.onvif.org/specs/stream/ONVIF-Streaming-Spec.pdf + * 6.2 RTSP describe + */ +GST_START_TEST (test_x_onvif_track) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = setup_client (NULL); + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + + gst_rtsp_client_set_send_func (client, test_response_x_onvif_track, NULL, + NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + teardown_client (client); +} + +GST_END_TEST; + +static void +create_connection (GstRTSPConnection ** conn) +{ + GSocket *sock; + GError *error = NULL; + + sock = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_TCP, &error); + g_assert_no_error (error); + fail_unless (gst_rtsp_connection_create_from_socket (sock, "127.0.0.1", 444, + NULL, conn) == GST_RTSP_OK); + g_object_unref (sock); +} + +static void +test_seek (const gchar * range, const gchar * speed, const gchar * scale, + const gchar * frames, const gchar * rate_control, RTPCheckData * rtp_check) +{ + GstRTSPClient *client; + GstRTSPConnection *conn; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = setup_client (NULL); + create_connection (&conn); + fail_unless (gst_rtsp_client_set_connection (client, conn)); + + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP/TCP;unicast"); + + gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_RANGE, range); + + if (scale) { + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SCALE, scale); + } + + if (speed) { + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SPEED, speed); + } + + if (frames) { + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_FRAMES, frames); + } + + if (rate_control) { + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_RATE_CONTROL, + rate_control); + } + + gst_rtsp_client_set_send_func (client, test_play_response_200_and_check_data, + rtp_check, NULL); + + terminal_frame = FALSE; + received_rtcp = FALSE; + + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + g_mutex_lock (&check_mutex); + g_cond_wait (&check_cond, &check_mutex); + g_mutex_unlock (&check_mutex); + + send_teardown (client); + + teardown_client (client); +} + +GST_START_TEST (test_src_seek_simple) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = 90; + rtp_check.expected_i_frame_ts_interval = 90; + rtp_check.expected_n_buffers = 100; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 10; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 10; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 80; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 10; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = TRUE; + + test_seek ("clock=19000101T010000.00Z-19000101T010000.10Z", NULL, NULL, NULL, + NULL, &rtp_check); +} + +GST_END_TEST; + +/** + * https://www.onvif.org/specs/stream/ONVIF-Streaming-Spec.pdf + * 6.4 RTSP Feature Tag + */ +GST_START_TEST (test_onvif_replay) +{ + GstRTSPClient *client; + GstRTSPConnection *conn; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = setup_client (NULL); + create_connection (&conn); + fail_unless (gst_rtsp_client_set_connection (client, conn)); + + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + + gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP/TCP;unicast"); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, "onvif-replay"); + + gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + send_teardown (client); + teardown_client (client); +} + +GST_END_TEST; + +GST_START_TEST (test_speed_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = 45; + rtp_check.expected_i_frame_ts_interval = 45; + rtp_check.expected_n_buffers = 100; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 10; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 10; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 80; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 10; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = TRUE; + + test_seek ("clock=19000101T010000.00Z-19000101T010000.10Z", "2.0", NULL, NULL, + NULL, &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_scale_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = 90; + rtp_check.expected_i_frame_ts_interval = 90; + rtp_check.expected_n_buffers = 50; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 5; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 5; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 40; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 5; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = TRUE; + + test_seek ("clock=19000101T010000.00Z-19000101T010000.10Z", NULL, "2.0", NULL, + NULL, &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_intra_frames_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = 900; + rtp_check.expected_i_frame_ts_interval = 900; + rtp_check.expected_n_buffers = 10; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 10; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 0; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 0; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 10; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = TRUE; + + test_seek ("clock=19000101T010000.00Z-19000101T010000.10Z", NULL, NULL, + "intra", NULL, &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_intra_frames_with_interval_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = 1800; + rtp_check.expected_i_frame_ts_interval = 1800; + rtp_check.expected_n_buffers = 5; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 5; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 0; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 0; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 5; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = TRUE; + + test_seek ("clock=19000101T010000.00Z-19000101T010000.10Z", NULL, NULL, + "intra/20", NULL, &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_predicted_frames_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = 450; + rtp_check.expected_i_frame_ts_interval = 450; + rtp_check.expected_n_buffers = 20; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 10; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 10; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 0; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 10; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = TRUE; + + test_seek ("clock=19000101T010000.00Z-19000101T010000.10Z", NULL, NULL, + "predicted", NULL, &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_reverse_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = -90; + rtp_check.expected_i_frame_ts_interval = 1710; + rtp_check.expected_n_buffers = 100; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 10; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 10; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 80; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 10; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = TRUE; + + test_seek ("clock=19000101T010000.10Z-19000101T010000.00Z", NULL, "-1.0", + NULL, NULL, &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_speed_reverse_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = -45; + rtp_check.expected_i_frame_ts_interval = 855; + rtp_check.expected_n_buffers = 100; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 10; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 10; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 80; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 10; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = TRUE; + + test_seek ("clock=19000101T010000.10Z-19000101T010000.00Z", "2.0", "-1.0", + NULL, NULL, &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_scale_reverse_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = -90; + rtp_check.expected_i_frame_ts_interval = 1710; + rtp_check.expected_n_buffers = 50; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 5; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 5; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 40; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 5; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = TRUE; + + test_seek ("clock=19000101T010001.10Z-19000101T010001.00Z", NULL, "-2.0", + NULL, NULL, &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_intra_frames_reverse_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = 0; + rtp_check.expected_i_frame_ts_interval = 900; + rtp_check.expected_n_buffers = 10; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 10; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 0; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 0; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 10; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = TRUE; + + test_seek ("clock=19000101T010001.10Z-19000101T010001.00Z", NULL, "-1.0", + "intra", NULL, &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_predicted_frames_reverse_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = -450; + rtp_check.expected_i_frame_ts_interval = 1350; + rtp_check.expected_n_buffers = 20; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 10; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 10; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 0; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 10; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = TRUE; + + test_seek ("clock=19000101T010001.10Z-19000101T010001.00Z", NULL, "-1.0", + "predicted", NULL, &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_intra_frames_with_interval_reverse_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = 0; + rtp_check.expected_i_frame_ts_interval = 1800; + rtp_check.expected_n_buffers = 5; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 5; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 0; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 0; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 5; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = TRUE; + + test_seek ("clock=19000101T010001.10Z-19000101T010001.00Z", NULL, "-1.0", + "intra/20", NULL, &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_rate_control_no_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = 90; + rtp_check.expected_i_frame_ts_interval = 90; + rtp_check.expected_n_buffers = 100; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 10; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 10; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 80; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 10; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = FALSE; + + test_seek ("clock=19000101T010000.00Z-19000101T010000.10Z", NULL, NULL, NULL, + "no", &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_rate_control_no_reverse_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = 90; + rtp_check.expected_i_frame_ts_interval = -1710; + rtp_check.expected_n_buffers = 100; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 10; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 10; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 80; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 10; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = FALSE; + + test_seek ("clock=19000101T010000.10Z-19000101T010000.00Z", NULL, "-1.0", + NULL, "no", &rtp_check); +} + +GST_END_TEST; + +GST_START_TEST (test_rate_control_no_frames_trick_mode) +{ + RTPCheckData rtp_check; + + rtp_check.previous_ts = 0; + rtp_check.expected_ts_interval = 900; + rtp_check.expected_i_frame_ts_interval = 900; + rtp_check.expected_n_buffers = 10; + rtp_check.n_buffers = 0; + rtp_check.expected_n_i_frames = 10; + rtp_check.n_i_frames = 0; + rtp_check.expected_n_p_frames = 0; + rtp_check.n_p_frames = 0; + rtp_check.expected_n_b_frames = 0; + rtp_check.n_b_frames = 0; + rtp_check.expected_n_clean_points = 10; + rtp_check.n_clean_points = 0; + rtp_check.timestamped_rtcp = FALSE; + + test_seek ("clock=19000101T010000.00Z-19000101T010000.10Z", NULL, NULL, + "intra", "no", &rtp_check); +} + +GST_END_TEST; +static Suite * +onvif_suite (void) +{ + Suite *s = suite_create ("onvif"); + TCase *tc = tcase_create ("general"); + + suite_add_tcase (s, tc); + + tcase_add_test (tc, test_x_onvif_track); + tcase_add_test (tc, test_onvif_replay); + tcase_add_test (tc, test_src_seek_simple); + tcase_add_test (tc, test_speed_trick_mode); + tcase_add_test (tc, test_scale_trick_mode); + tcase_add_test (tc, test_intra_frames_trick_mode); + tcase_add_test (tc, test_predicted_frames_trick_mode); + tcase_add_test (tc, test_intra_frames_with_interval_trick_mode); + tcase_add_test (tc, test_reverse_trick_mode); + tcase_add_test (tc, test_speed_reverse_trick_mode); + tcase_add_test (tc, test_scale_reverse_trick_mode); + tcase_add_test (tc, test_intra_frames_reverse_trick_mode); + tcase_add_test (tc, test_predicted_frames_reverse_trick_mode); + tcase_add_test (tc, test_intra_frames_with_interval_reverse_trick_mode); + tcase_add_test (tc, test_rate_control_no_trick_mode); + tcase_add_test (tc, test_rate_control_no_reverse_trick_mode); + tcase_add_test (tc, test_rate_control_no_frames_trick_mode); + + return s; +} + +GST_CHECK_MAIN (onvif); diff --git a/tests/check/meson.build b/tests/check/meson.build index 78d083f331..d241611741 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -28,6 +28,7 @@ rtsp_server_tests = [ 'gst/stream', 'gst/threadpool', 'gst/token', + 'gst/onvif', ] if not get_option('rtspclientsink').disabled() From b545c10e8fffbbc34d47c894c8ab669452d3c53c Mon Sep 17 00:00:00 2001 From: Michael Bunk Date: Fri, 7 Jun 2019 10:51:19 +0200 Subject: [PATCH 1624/1776] Fix typos --- docs/README | 14 +++++++------- gst/rtsp-server/rtsp-media-factory-uri.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/README b/docs/README index e1cdc9c3a0..baf7f0b22f 100644 --- a/docs/README +++ b/docs/README @@ -294,7 +294,7 @@ can build simple server applications with it. When a client performs a PLAY request, its configured destination UDP ports are added to the GstRTSPStream target destinations, at which point data will be sent to the client. The corresponding GstRTSPMedia object will be set to the - PLAYING state if it was not allready in order to send the data to the + PLAYING state if it was not already in order to send the data to the destination. The server needs to prepare an RTP-Info header field in the PLAY response, @@ -320,7 +320,7 @@ can build simple server applications with it. * session management The server has to react to clients that suddenly disappear because of network - problems or otherwise. It needs to make sure that it can reasonable free the + problems or otherwise. It needs to make sure that it can reasonably free the resources that are used by the various objects in use for streaming when the client appears to be gone. @@ -331,7 +331,7 @@ can build simple server applications with it. Various ways exist to detect activity from a client: - RTSP keepalive requests. When a client is receiving RTP data, the RTSP TCP - connection is largely unused. It is the client's responsability to + connection is largely unused. It is the client's responsibility to periodically send keep-alive requests over the TCP channel. Whenever a keep-alive request is received by the server (any request that @@ -359,7 +359,7 @@ can build simple server applications with it. expired and call gst_rtsp_session_pool_cleanup() to remove them. When a session is removed from the sessionpool and its last reference is - unreffef, all related objects and media are destroyed as if a TEARDOWN happened + unreffed, all related objects and media are destroyed as if a TEARDOWN happened from the client. @@ -397,9 +397,9 @@ can build simple server applications with it. to a user. - GstRTSPPermissions: a generic list of roles and matching permissions. These - can be attached to media and facties currently. + can be attached to media and factories currently. - An Auth implementation will usually authenticate a user, using method such as + An Auth implementation will usually authenticate a user, using a method such as Basic authentication or client certificates or perhaps simply use the IP address. The result of the authentication of the user will be a GstRTSPToken that is made current in the context of the ongoing request. @@ -477,7 +477,7 @@ GstRTSPAddressPool GstRTSPThreadPool - a pool of threads used for various server tasks such as handling clients and - managin media pipelines. + managing media pipelines. GstRTSPAuth diff --git a/gst/rtsp-server/rtsp-media-factory-uri.h b/gst/rtsp-server/rtsp-media-factory-uri.h index cd0e9d53db..2980670cd5 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.h +++ b/gst/rtsp-server/rtsp-media-factory-uri.h @@ -43,7 +43,7 @@ typedef struct _GstRTSPMediaFactoryURIPrivate GstRTSPMediaFactoryURIPrivate; /** * GstRTSPMediaFactoryURI: * - * A media factory that creates a pipeline to play and uri. + * A media factory that creates a pipeline to play any uri. */ struct _GstRTSPMediaFactoryURI { GstRTSPMediaFactory parent; From ab37286300baac65e6ccfca2101007a00a49a292 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 12 Jun 2019 22:19:27 +0200 Subject: [PATCH 1625/1776] rtsp-media: make sure streams are blocked when sending seek The recent ONVIF work exposed a race condition when dealing with multiple streams: one of the sinks may preroll before other streams have started flushing. This led to the pipeline posting async-done prematurely, when some streams were actually still in the middle of performing a flushing seek. The newly-added code looks up a sticky segment event on the first stream in order to respond to the PLAY request with accurate Scale and Speed headers. In the failure condition, the first stream was flushing, and thus had no sticky segment event, leading to the PLAY request failing, and in turn the test. --- gst/rtsp-server/rtsp-media.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4c672ddfc2..bd3fcaab91 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2797,6 +2797,7 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, res = TRUE; } else { GstEvent *seek_event; + gboolean unblock = FALSE; gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); @@ -2815,8 +2816,21 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, gst_event_set_seek_trickmode_interval (seek_event, trickmode_interval); + if (!media->priv->blocked) { + /* Prevent a race condition with multiple streams, + * where one stream may have time to preroll before others + * have even started flushing, causing async-done to be + * posted too early. + */ + media_streams_set_blocked (media, TRUE); + unblock = TRUE; + } + res = gst_element_send_event (priv->pipeline, seek_event); + if (unblock) + media_streams_set_blocked (media, FALSE); + /* and block for the seek to complete */ GST_INFO ("done seeking %d", res); if (!res) From 7b2adb015dd4e022b7ec34fe2da8eb766c23522d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 25 Jun 2019 13:19:44 +0100 Subject: [PATCH 1626/1776] onvif-media: fix "void function returning a value" compiler warning --- gst/rtsp-server/rtsp-onvif-media-factory.c | 4 +--- gst/rtsp-server/rtsp-onvif-media.c | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.c b/gst/rtsp-server/rtsp-onvif-media-factory.c index ff05cdfb7e..dbd461a5ab 100644 --- a/gst/rtsp-server/rtsp-onvif-media-factory.c +++ b/gst/rtsp-server/rtsp-onvif-media-factory.c @@ -331,9 +331,7 @@ gst_rtsp_onvif_media_factory_finalize (GObject * object) g_mutex_clear (&factory->priv->lock); - return - G_OBJECT_CLASS (gst_rtsp_onvif_media_factory_parent_class)->finalize - (object); + G_OBJECT_CLASS (gst_rtsp_onvif_media_factory_parent_class)->finalize (object); } static void diff --git a/gst/rtsp-server/rtsp-onvif-media.c b/gst/rtsp-server/rtsp-onvif-media.c index 04eb406fad..0b29f898df 100644 --- a/gst/rtsp-server/rtsp-onvif-media.c +++ b/gst/rtsp-server/rtsp-onvif-media.c @@ -222,7 +222,7 @@ gst_rtsp_onvif_media_finalize (GObject * object) g_mutex_clear (&media->priv->lock); - return G_OBJECT_CLASS (gst_rtsp_onvif_media_parent_class)->finalize (object); + G_OBJECT_CLASS (gst_rtsp_onvif_media_parent_class)->finalize (object); } static void From d1d404912e4979444d5f3853af1a4b6d9c43a96c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Fri, 28 Jun 2019 12:28:41 +0200 Subject: [PATCH 1627/1776] rtsp-stream: Not wait on receiver streams when pre-rolling Without this patch there are problem pre-rolling when using audio back channel. Without this patch a probe will be created for all streams including the stream for audio backchannel. To pre-roll all this pads have to receive data. Since the stream for audio backchannel is a receiver this will never happen. The solution is to never create any probes for streams that are for incomming data and instead set them as blocking already from beginning. --- gst/rtsp-server/rtsp-stream.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4dfd4352fd..4a5efcf77b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -5062,6 +5062,11 @@ set_blocked (GstRTSPStream * stream, gboolean blocked) priv = stream->priv; if (blocked) { + /* if receiver */ + if (priv->sinkpad) { + priv->blocking = TRUE; + return; + } for (i = 0; i < 2; i++) { if (priv->blocked_id[i] != 0) continue; From 571f119feaf5129cc789ada38cd6404d60fef2aa Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 15 Jul 2019 17:06:42 +0200 Subject: [PATCH 1628/1776] onvif tests: use g_cond_wait() correctly g_cond_wait() has to be called in a loop until required conditions are met Fixes #71 --- tests/check/gst/onvif.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/check/gst/onvif.c b/tests/check/gst/onvif.c index beb276fbf4..087a2f7983 100644 --- a/tests/check/gst/onvif.c +++ b/tests/check/gst/onvif.c @@ -894,7 +894,8 @@ test_seek (const gchar * range, const gchar * speed, const gchar * scale, gst_rtsp_message_unset (&request); g_mutex_lock (&check_mutex); - g_cond_wait (&check_cond, &check_mutex); + while (!terminal_frame || !received_rtcp) + g_cond_wait (&check_cond, &check_mutex); g_mutex_unlock (&check_mutex); send_teardown (client); From 507e6f1db276bfb51307eec12facefd73dd246c1 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 17 Jul 2019 15:51:08 +0200 Subject: [PATCH 1629/1776] client test: expect any port in transport setup_multicast_client sets a 5000-5010 range for the client ports, it is incorrect to expect the transport to always use 5000-5001 Fixes #73 --- tests/check/gst/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 5f10c4372a..80ed9352da 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -1833,7 +1833,7 @@ do_test_scale_and_speed (const gchar * scale, const gchar * speed) gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, "RTP/AVP;multicast"); expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; + "ttl=1;port=.*;mode=\"PLAY\""; gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); From 446315b36c5c4c813abc9f22f6624ca1a58e13e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 22 Jul 2019 19:32:43 +0300 Subject: [PATCH 1630/1776] rtsp-media: Try to get dynamic payloaders by name from their bin first First try "pay", then "pay_%s" (where %s == pad name). And only then fall back to the code that simply takes the first payloader that is found. The current code usually works (but is racy) because it will always take the payloader that was last added (due to g_list_prepend() when adding elements) in pad-added and that's usually the correct one. But if a new payloader is added between pad-added and us trying to get it, we would get the wrong payloader. --- gst/rtsp-server/rtsp-media-factory-uri.c | 6 ++- gst/rtsp-server/rtsp-media.c | 59 ++++++++++++++++++------ 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 93ed9d7b72..67cdc3e30b 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -465,7 +465,7 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) GstCaps *caps; GstPad *sinkpad, *srcpad, *ghostpad; GstElement *convert; - gchar *padname; + gchar *padname, *payloader_name; GST_DEBUG ("added pad %s:%s", GST_DEBUG_PAD_NAME (pad)); @@ -521,7 +521,9 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) GST_DEBUG ("found payloader factory %s", gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory))); - payloader = gst_element_factory_create (factory, NULL); + payloader_name = g_strdup_printf ("pay_%s", padname); + payloader = gst_element_factory_create (factory, payloader_name); + g_free (payloader_name); if (payloader == NULL) goto no_payloader; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index bd3fcaab91..a4124811cb 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -235,7 +235,7 @@ static gboolean default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp); static gboolean wait_preroll (GstRTSPMedia * media); -static GstElement *find_payload_element (GstElement * payloader); +static GstElement *find_payload_element (GstElement * payloader, GstPad * pad); static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 }; @@ -2046,7 +2046,7 @@ gst_rtsp_media_collect_streams (GstRTSPMedia * media) pad = gst_element_get_static_pad (elem, "src"); /* find the real payload element in case elem is a GstBin */ - pay = find_payload_element (elem); + pay = find_payload_element (elem, pad); /* create the stream */ if (pay == NULL) { @@ -2213,7 +2213,8 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, g_mutex_lock (&priv->lock); idx = priv->streams->len; - GST_DEBUG ("media %p: creating stream with index %d", media, idx); + GST_DEBUG ("media %p: creating stream with index %d and payloader %" + GST_PTR_FORMAT, media, idx, payloader); if (GST_PAD_IS_SRC (pad)) name = g_strdup_printf ("src_%u", idx); @@ -3148,27 +3149,57 @@ watch_destroyed (GstRTSPMedia * media) g_object_unref (media); } +static gboolean +is_payloader (GstElement * element) +{ + GstElementClass *eclass = GST_ELEMENT_GET_CLASS (element); + const gchar *klass; + + klass = gst_element_class_get_metadata (eclass, GST_ELEMENT_METADATA_KLASS); + if (klass == NULL) + return FALSE; + + if (strstr (klass, "Payloader") && strstr (klass, "RTP")) { + return TRUE; + } + + return FALSE; +} + static GstElement * -find_payload_element (GstElement * payloader) +find_payload_element (GstElement * payloader, GstPad * pad) { GstElement *pay = NULL; if (GST_IS_BIN (payloader)) { GstIterator *iter; GValue item = { 0 }; + gchar *pad_name, *payloader_name; + GstElement *element; + + if ((element = gst_bin_get_by_name (GST_BIN (payloader), "pay"))) { + if (is_payloader (element)) + return element; + gst_object_unref (element); + } + + pad_name = gst_object_get_name (GST_OBJECT (pad)); + payloader_name = g_strdup_printf ("pay_%s", pad_name); + g_free (pad_name); + if ((element = gst_bin_get_by_name (GST_BIN (payloader), payloader_name))) { + g_free (payloader_name); + if (is_payloader (element)) + return element; + gst_object_unref (element); + } else { + g_free (payloader_name); + } iter = gst_bin_iterate_recurse (GST_BIN (payloader)); while (gst_iterator_next (iter, &item) == GST_ITERATOR_OK) { - GstElement *element = (GstElement *) g_value_get_object (&item); - GstElementClass *eclass = GST_ELEMENT_GET_CLASS (element); - const gchar *klass; + element = (GstElement *) g_value_get_object (&item); - klass = - gst_element_class_get_metadata (eclass, GST_ELEMENT_METADATA_KLASS); - if (klass == NULL) - continue; - - if (strstr (klass, "Payloader") && strstr (klass, "RTP")) { + if (is_payloader (element)) { pay = gst_object_ref (element); g_value_unset (&item); break; @@ -3192,7 +3223,7 @@ pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media) GstElement *pay; /* find the real payload element */ - pay = find_payload_element (element); + pay = find_payload_element (element, pad); stream = gst_rtsp_media_create_stream (media, pay, pad); gst_object_unref (pay); From 72504eee99f88e1a87ba16ab3ef9ff75962680cb Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 27 Jul 2019 05:14:28 +0200 Subject: [PATCH 1631/1776] rtsp-client: define all seek accuracy flags from setup_play_mode We then pass those to adjust_play_mode, which needs to operate on the "final" seek flags, as previously the code in rtsp-media was assuming that accuracy seek flags (accurate / key_unit) should not be set if the flags passed to the seek method were already set. --- gst/rtsp-server/rtsp-client.c | 6 ++++++ gst/rtsp-server/rtsp-media.c | 15 ++++----------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index ec608815d6..964e06bfeb 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1862,7 +1862,13 @@ setup_play_mode (GstRTSPClient * client, GstRTSPContext * ctx, flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_AFTER; else GST_FIXME_OBJECT (client, "Add support for seek style %s", seek_style); + } else if (range->min.type == GST_RTSP_TIME_END) { + flags = GST_SEEK_FLAG_ACCURATE; + } else { + flags = GST_SEEK_FLAG_KEY_UNIT; } + } else { + flags = GST_SEEK_FLAG_ACCURATE; } /* check for scale and/or speed headers diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index a4124811cb..bc5458b29a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -243,6 +243,8 @@ static gboolean check_complete (GstRTSPMedia * media); #define C_ENUM(v) ((gint) v) +#define TRICKMODE_FLAGS (GST_SEEK_FLAG_TRICKMODE | GST_SEEK_FLAG_TRICKMODE_KEY_UNITS | GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED) + GType gst_rtsp_suspend_mode_get_type (void) { @@ -2757,13 +2759,11 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, if (stop != GST_CLOCK_TIME_NONE) stop_type = GST_SEEK_TYPE_SET; - /* we force a seek if any seek flag is set, or if the the rate + /* we force a seek if any trickmode flag is set, or if the rate * is non-standard, i.e. not 1.0 */ - force_seek = flags != GST_SEEK_FLAG_NONE || rate != 1.0; + force_seek = (flags & TRICKMODE_FLAGS) || rate != 1.0; if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE || force_seek) { - gboolean had_flags = flags != GST_SEEK_FLAG_NONE; - GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); @@ -2782,14 +2782,7 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, GST_TIME_ARGS (current_position)); start = current_position; start_type = GST_SEEK_TYPE_SET; - if (!had_flags) - flags |= GST_SEEK_FLAG_ACCURATE; } - } else { - /* only set keyframe flag when modifying start */ - if (start_type != GST_SEEK_TYPE_NONE) - if (!had_flags) - flags |= GST_SEEK_FLAG_KEY_UNIT; } if (start == current_position && stop_type == GST_SEEK_TYPE_NONE && From 0bdae677d30e37cc704a3790fd60883fac9d0812 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 27 Jul 2019 05:14:49 +0200 Subject: [PATCH 1632/1776] examples: add ONVIF client / server example --- examples/meson.build | 2 + examples/test-onvif-client.c | 693 +++++++++++++++++++++++++++++++++++ examples/test-onvif-server.c | 667 +++++++++++++++++++++++++++++++++ 3 files changed, 1362 insertions(+) create mode 100644 examples/test-onvif-client.c create mode 100644 examples/test-onvif-server.c diff --git a/examples/meson.build b/examples/meson.build index 332ea666b1..2bacd48274 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -10,6 +10,8 @@ examples = [ 'test-netclock', 'test-netclock-client', 'test-ogg', + 'test-onvif-client', + 'test-onvif-server', 'test-readme', 'test-record-auth', 'test-record', diff --git a/examples/test-onvif-client.c b/examples/test-onvif-client.c new file mode 100644 index 0000000000..28fe102d50 --- /dev/null +++ b/examples/test-onvif-client.c @@ -0,0 +1,693 @@ +/* GStreamer + * Copyright (C) 2019 Mathieu Duponchelle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +typedef struct +{ + gchar *range; + gdouble speed; + gchar *frames; + gchar *rate_control; + gboolean reverse; +} SeekParameters; + +typedef struct +{ + GstElement *src; + GstElement *sink; + GstElement *pipe; + SeekParameters *seek_params; + GMainLoop *loop; + GIOChannel *io; + gboolean new_range; + guint io_watch_id; + gboolean reset_sync; +} Context; + +typedef struct +{ + const gchar *name; + gboolean has_argument; + const gchar *help; + gboolean (*func) (Context * ctx, gchar * arg, gboolean * async); +} Command; + +static gboolean cmd_help (Context * ctx, gchar * arg, gboolean * async); +static gboolean cmd_pause (Context * ctx, gchar * arg, gboolean * async); +static gboolean cmd_play (Context * ctx, gchar * arg, gboolean * async); +static gboolean cmd_reverse (Context * ctx, gchar * arg, gboolean * async); +static gboolean cmd_range (Context * ctx, gchar * arg, gboolean * async); +static gboolean cmd_speed (Context * ctx, gchar * arg, gboolean * async); +static gboolean cmd_frames (Context * ctx, gchar * arg, gboolean * async); +static gboolean cmd_rate_control (Context * ctx, gchar * arg, gboolean * async); +static gboolean cmd_step_forward (Context * ctx, gchar * arg, gboolean * async); + +static Command commands[] = { + {"help", FALSE, "Display list of valid commands", cmd_help}, + {"pause", FALSE, "Pause playback", cmd_pause}, + {"play", FALSE, "Resume playback", cmd_play}, + {"reverse", FALSE, "Reverse playback direction", cmd_reverse}, + {"range", TRUE, + "Seek to the specified range, example: \"range: 19000101T000000Z-19000101T000200Z\"", + cmd_range}, + {"speed", TRUE, "Set the playback speed, example: \"speed: 1.0\"", cmd_speed}, + {"frames", TRUE, + "Set the frames trickmode, example: \"frames: intra\", \"frames: predicted\", \"frames: intra/1000\"", + cmd_frames}, + {"rate-control", TRUE, + "Set the rate control mode, example: \"rate-control: no\"", + cmd_rate_control}, + {"s", FALSE, "Step to the following frame (in current playback direction)", + cmd_step_forward}, + {NULL}, +}; + +static gchar *rtsp_address; + +#define MAKE_AND_ADD(var, pipe, name, label, elem_name) \ +G_STMT_START { \ + if (G_UNLIKELY (!(var = (gst_element_factory_make (name, elem_name))))) { \ + GST_ERROR ("Could not create element %s", name); \ + goto label; \ + } \ + if (G_UNLIKELY (!gst_bin_add (GST_BIN_CAST (pipe), var))) { \ + GST_ERROR ("Could not add element %s", name); \ + goto label; \ + } \ +} G_STMT_END + +#define DEFAULT_RANGE "19000101T000000Z-19000101T000200Z" +#define DEFAULT_SPEED 1.0 +#define DEFAULT_FRAMES "none" +#define DEFAULT_RATE_CONTROL "yes" +#define DEFAULT_REVERSE FALSE + +static void +pad_added_cb (GstElement * src, GstPad * srcpad, GstElement * peer) +{ + GstPad *sinkpad = gst_element_get_static_pad (peer, "sink"); + + gst_pad_link (srcpad, sinkpad); + + gst_object_unref (sinkpad); +} + +static gboolean +setup (Context * ctx) +{ + GstElement *onvifparse, *queue, *vdepay, *vdec, *vconv, *toverlay, *tee, + *vqueue; + gboolean ret = FALSE; + + MAKE_AND_ADD (ctx->src, ctx->pipe, "rtspsrc", done, NULL); + MAKE_AND_ADD (queue, ctx->pipe, "queue", done, NULL); + MAKE_AND_ADD (onvifparse, ctx->pipe, "rtponvifparse", done, NULL); + MAKE_AND_ADD (vdepay, ctx->pipe, "rtph264depay", done, NULL); + MAKE_AND_ADD (vdec, ctx->pipe, "avdec_h264", done, NULL); + MAKE_AND_ADD (vconv, ctx->pipe, "videoconvert", done, NULL); + MAKE_AND_ADD (toverlay, ctx->pipe, "timeoverlay", done, NULL); + MAKE_AND_ADD (tee, ctx->pipe, "tee", done, NULL); + MAKE_AND_ADD (vqueue, ctx->pipe, "queue", done, NULL); + MAKE_AND_ADD (ctx->sink, ctx->pipe, "xvimagesink", done, NULL); + + g_object_set (ctx->src, "location", rtsp_address, NULL); + g_object_set (ctx->src, "onvif-mode", TRUE, NULL); + g_object_set (ctx->src, "tcp-timeout", 0, NULL); + g_object_set (toverlay, "show-times-as-dates", TRUE, NULL); + + g_object_set (toverlay, "datetime-format", "%a %d, %b %Y - %T", NULL); + + g_signal_connect (ctx->src, "pad-added", G_CALLBACK (pad_added_cb), queue); + + if (!gst_element_link_many (queue, onvifparse, vdepay, vdec, vconv, toverlay, + tee, vqueue, ctx->sink, NULL)) { + goto done; + } + + g_object_set (ctx->src, "onvif-rate-control", FALSE, "is-live", FALSE, NULL); + + if (!g_strcmp0 (ctx->seek_params->rate_control, "no")) { + g_object_set (ctx->sink, "sync", FALSE, NULL); + } + + ret = TRUE; + +done: + return ret; +} + +static GstEvent * +translate_seek_parameters (Context * ctx, SeekParameters * seek_params) +{ + GstEvent *ret = NULL; + gchar *range_str = NULL; + GstRTSPTimeRange *rtsp_range; + GstSeekType start_type, stop_type; + GstClockTime start, stop; + gdouble rate; + GstSeekFlags flags; + gchar **split = NULL; + GstClockTime trickmode_interval = 0; + gint64 cur_pos; + + range_str = g_strdup_printf ("clock=%s", seek_params->range); + + if (gst_rtsp_range_parse (range_str, &rtsp_range) != GST_RTSP_OK) { + GST_ERROR ("Failed to parse range %s", range_str); + goto done; + } + + gst_rtsp_range_get_times (rtsp_range, &start, &stop); + + if (start > stop) { + GST_ERROR ("Invalid range, start > stop: %s", seek_params->range); + goto done; + } + + start_type = GST_SEEK_TYPE_SET; + stop_type = GST_SEEK_TYPE_SET; + + if (!ctx->new_range) { + gst_element_query_position (ctx->pipe, GST_FORMAT_TIME, &cur_pos); + if (seek_params->reverse) { + stop_type = GST_SEEK_TYPE_SET; + stop = cur_pos; + } else { + start_type = GST_SEEK_TYPE_SET; + start = cur_pos; + } + } + + ctx->new_range = FALSE; + + flags = GST_SEEK_FLAG_FLUSH; + + split = g_strsplit (seek_params->frames, "/", 2); + + if (!g_strcmp0 (split[0], "intra")) { + if (split[1]) { + guint64 interval; + gchar *end; + + interval = g_ascii_strtoull (split[1], &end, 10); + + if (!end || *end != '\0') { + GST_ERROR ("Unexpected interval value %s", split[1]); + goto done; + } + + trickmode_interval = interval * GST_MSECOND; + } + flags |= GST_SEEK_FLAG_TRICKMODE_KEY_UNITS; + } else if (!g_strcmp0 (split[0], "predicted")) { + if (split[1]) { + GST_ERROR ("Predicted frames mode does not allow an interval (%s)", + seek_params->frames); + goto done; + } + flags |= GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED; + } else if (g_strcmp0 (split[0], "none")) { + GST_ERROR ("Invalid frames mode (%s)", seek_params->frames); + goto done; + } + + if (seek_params->reverse) { + rate = -1.0 * seek_params->speed; + } else { + rate = 1.0 * seek_params->speed; + } + + ret = gst_event_new_seek (rate, GST_FORMAT_TIME, flags, + start_type, start, stop_type, stop); + + if (trickmode_interval) + gst_event_set_seek_trickmode_interval (ret, trickmode_interval); + +done: + if (split) + g_strfreev (split); + g_free (range_str); + return ret; +} + +static void prompt_on (Context * ctx); +static void prompt_off (Context * ctx); + +static gboolean +cmd_help (Context * ctx, gchar * arg, gboolean * async) +{ + gboolean ret = TRUE; + guint i; + + *async = FALSE; + + for (i = 0; commands[i].name; i++) { + g_print ("%s: %s\n", commands[i].name, commands[i].help); + } + + return ret; +} + +static gboolean +cmd_pause (Context * ctx, gchar * arg, gboolean * async) +{ + gboolean ret; + GstStateChangeReturn state_ret; + + g_print ("Pausing\n"); + + state_ret = gst_element_set_state (ctx->pipe, GST_STATE_PAUSED); + + *async = state_ret == GST_STATE_CHANGE_ASYNC; + ret = state_ret != GST_STATE_CHANGE_FAILURE; + + return ret; +} + +static gboolean +cmd_play (Context * ctx, gchar * arg, gboolean * async) +{ + gboolean ret; + GstStateChangeReturn state_ret; + + g_print ("Playing\n"); + + state_ret = gst_element_set_state (ctx->pipe, GST_STATE_PLAYING); + + *async = state_ret == GST_STATE_CHANGE_ASYNC; + ret = state_ret != GST_STATE_CHANGE_FAILURE; + + return ret; +} + +static gboolean +do_seek (Context * ctx) +{ + gboolean ret = FALSE; + GstEvent *event; + + if (!(event = translate_seek_parameters (ctx, ctx->seek_params))) { + GST_ERROR ("Failed to create seek event"); + goto done; + } + + if (ctx->seek_params->reverse) + g_object_set (ctx->src, "onvif-rate-control", FALSE, NULL); + + if (ctx->reset_sync) { + g_object_set (ctx->sink, "sync", TRUE, NULL); + ctx->reset_sync = FALSE; + } + + if (!gst_element_send_event (ctx->src, event)) { + GST_ERROR ("Failed to seek rtspsrc"); + g_main_loop_quit (ctx->loop); + goto done; + } + + ret = TRUE; + +done: + return ret; +} + +static gboolean +cmd_reverse (Context * ctx, gchar * arg, gboolean * async) +{ + gboolean ret = TRUE; + + g_print ("Reversing playback direction\n"); + + ctx->seek_params->reverse = !ctx->seek_params->reverse; + + ret = do_seek (ctx); + + *async = ret == TRUE; + + return ret; +} + +static gboolean +cmd_range (Context * ctx, gchar * arg, gboolean * async) +{ + gboolean ret = TRUE; + + g_print ("Switching to new range\n"); + + g_free (ctx->seek_params->range); + ctx->seek_params->range = g_strdup (arg); + ctx->new_range = TRUE; + + ret = do_seek (ctx); + + *async = ret == TRUE; + + return ret; +} + +static gboolean +cmd_speed (Context * ctx, gchar * arg, gboolean * async) +{ + gboolean ret = FALSE; + gchar *endptr = NULL; + gdouble new_speed; + + new_speed = g_ascii_strtod (arg, &endptr); + + g_print ("Switching gears\n"); + + if (endptr == NULL || *endptr != '\0' || new_speed <= 0.0) { + GST_ERROR ("Invalid value for speed: %s", arg); + goto done; + } + + ctx->seek_params->speed = new_speed; + ret = do_seek (ctx); + +done: + *async = ret == TRUE; + return ret; +} + +static gboolean +cmd_frames (Context * ctx, gchar * arg, gboolean * async) +{ + gboolean ret = TRUE; + + g_print ("Changing Frames trickmode\n"); + + g_free (ctx->seek_params->frames); + ctx->seek_params->frames = g_strdup (arg); + ret = do_seek (ctx); + *async = ret == TRUE; + + return ret; +} + +static gboolean +cmd_rate_control (Context * ctx, gchar * arg, gboolean * async) +{ + gboolean ret = FALSE; + + *async = FALSE; + + if (!g_strcmp0 (arg, "no")) { + g_object_set (ctx->sink, "sync", FALSE, NULL); + ret = TRUE; + } else if (!g_strcmp0 (arg, "yes")) { + /* TODO: there probably is a solution that doesn't involve sending + * a request to the server to reset our position */ + ctx->reset_sync = TRUE; + ret = do_seek (ctx); + *async = TRUE; + } else { + GST_ERROR ("Invalid rate-control: %s", arg); + goto done; + } + + ret = TRUE; + +done: + return ret; +} + +static gboolean +cmd_step_forward (Context * ctx, gchar * arg, gboolean * async) +{ + gboolean ret = FALSE; + GstEvent *event; + + event = gst_event_new_step (GST_FORMAT_BUFFERS, 1, 1.0, TRUE, FALSE); + + g_print ("Stepping\n"); + + if (!gst_element_send_event (ctx->sink, event)) { + GST_ERROR ("Failed to step forward"); + goto done; + } + + ret = TRUE; + +done: + *async = ret == TRUE; + return ret; +} + +static void +handle_command (Context * ctx, gchar * cmd) +{ + gchar **split; + guint i; + gboolean valid_command = FALSE; + + split = g_strsplit (cmd, ":", 0); + + cmd = g_strstrip (split[0]); + + if (cmd == NULL || *cmd == '\0') { + g_print ("> "); + goto done; + } + + for (i = 0; commands[i].name; i++) { + if (!g_strcmp0 (commands[i].name, cmd)) { + valid_command = TRUE; + if (commands[i].has_argument && g_strv_length (split) != 2) { + g_print ("Command %s expects exactly one argument:\n%s: %s\n", cmd, + commands[i].name, commands[i].help); + } else if (!commands[i].has_argument && g_strv_length (split) != 1) { + g_print ("Command %s expects no argument:\n%s: %s\n", cmd, + commands[i].name, commands[i].help); + } else { + gboolean async = FALSE; + + if (commands[i].func (ctx, + commands[i].has_argument ? g_strstrip (split[1]) : NULL, &async) + && async) + prompt_off (ctx); + else + g_print ("> "); + } + break; + } + } + + if (!valid_command) { + g_print ("Invalid command %s\n> ", cmd); + } + +done: + g_strfreev (split); +} + +static gboolean +io_callback (GIOChannel * io, GIOCondition condition, Context * ctx) +{ + gboolean ret = TRUE; + gchar *str; + GError *error = NULL; + + switch (condition) { + case G_IO_PRI: + case G_IO_IN: + switch (g_io_channel_read_line (io, &str, NULL, NULL, &error)) { + case G_IO_STATUS_ERROR: + GST_ERROR ("Failed to read commands from stdin: %s", error->message); + g_clear_error (&error); + g_main_loop_quit (ctx->loop); + break; + case G_IO_STATUS_EOF: + g_print ("EOF received, bye\n"); + g_main_loop_quit (ctx->loop); + break; + case G_IO_STATUS_AGAIN: + break; + case G_IO_STATUS_NORMAL: + handle_command (ctx, str); + g_free (str); + break; + } + break; + case G_IO_ERR: + case G_IO_HUP: + GST_ERROR ("Failed to read commands from stdin"); + g_main_loop_quit (ctx->loop); + break; + case G_IO_OUT: + default: + break; + } + + return ret; +} + +static void +prompt_on (Context * ctx) +{ + g_assert (!ctx->io); + ctx->io = g_io_channel_unix_new (STDIN_FILENO); + ctx->io_watch_id = + g_io_add_watch (ctx->io, G_IO_IN, (GIOFunc) io_callback, ctx); + g_print ("> "); +} + +static void +prompt_off (Context * ctx) +{ + g_assert (ctx->io); + g_source_remove (ctx->io_watch_id); + g_io_channel_unref (ctx->io); + ctx->io = NULL; +} + +static gboolean +bus_message_cb (GstBus * bus, GstMessage * message, Context * ctx) +{ + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_STATE_CHANGED:{ + GstState olds, news, pendings; + + if (GST_MESSAGE_SRC (message) == GST_OBJECT (ctx->pipe)) { + gst_message_parse_state_changed (message, &olds, &news, &pendings); + GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (ctx->pipe), + GST_DEBUG_GRAPH_SHOW_ALL, "playing"); + } + break; + } + case GST_MESSAGE_ERROR:{ + GError *error = NULL; + gchar *debug; + + gst_message_parse_error (message, &error, &debug); + + gst_printerr ("Error: %s (%s)\n", error->message, debug); + g_clear_error (&error); + g_free (debug); + g_main_loop_quit (ctx->loop); + break; + } + case GST_MESSAGE_LATENCY:{ + gst_bin_recalculate_latency (GST_BIN (ctx->pipe)); + break; + } + case GST_MESSAGE_ASYNC_DONE:{ + prompt_on (ctx); + } + default: + break; + } + + return TRUE; +} + +int +main (int argc, char **argv) +{ + GOptionContext *optctx; + Context ctx; + GstBus *bus; + gint ret = 1; + GError *error = NULL; + const gchar *range; + const gchar *frames; + const gchar *rate_control; + SeekParameters seek_params = + { NULL, DEFAULT_SPEED, NULL, NULL, DEFAULT_REVERSE }; + GOptionEntry entries[] = { + {"range", 0, 0, G_OPTION_ARG_STRING, &range, + "Range to seek (default: " DEFAULT_RANGE ")", "RANGE"}, + {"speed", 0, 0, G_OPTION_ARG_DOUBLE, &seek_params.speed, + "Speed to request (default: 1.0)", "SPEED"}, + {"frames", 0, 0, G_OPTION_ARG_STRING, &frames, + "Frames to request (default: none)", "FRAMES"}, + {"rate-control", 0, 0, G_OPTION_ARG_STRING, &rate_control, + "Apply rate control on the client side (default: yes)", "RATE_CONTROL"}, + {"reverse", 0, 0, G_OPTION_ARG_NONE, &seek_params.reverse, + "Playback direction", ""}, + {NULL} + }; + + optctx = g_option_context_new (" - ONVIF RTSP Client"); + g_option_context_add_main_entries (optctx, entries, NULL); + g_option_context_add_group (optctx, gst_init_get_option_group ()); + if (!g_option_context_parse (optctx, &argc, &argv, &error)) { + g_printerr ("Error parsing options: %s\n", error->message); + g_option_context_free (optctx); + g_clear_error (&error); + return -1; + } + if (argc < 2) { + g_print ("%s\n", g_option_context_get_help (optctx, TRUE, NULL)); + return 1; + } + rtsp_address = argv[1]; + g_option_context_free (optctx); + + seek_params.range = g_strdup (range ? range : DEFAULT_RANGE); + seek_params.frames = g_strdup (frames ? frames : DEFAULT_FRAMES); + seek_params.rate_control = + g_strdup (rate_control ? rate_control : DEFAULT_RATE_CONTROL); + + if (seek_params.speed <= 0.0) { + GST_ERROR ("SPEED must be a positive number"); + return 1; + } + + ctx.seek_params = &seek_params; + ctx.new_range = TRUE; + ctx.reset_sync = FALSE; + + ctx.pipe = gst_pipeline_new (NULL); + if (!setup (&ctx)) { + g_printerr ("Damn\n"); + goto done; + } + + g_print ("Type help for the list of available commands\n"); + + do_seek (&ctx); + + ctx.loop = g_main_loop_new (NULL, FALSE); + + bus = gst_pipeline_get_bus (GST_PIPELINE (ctx.pipe)); + gst_bus_add_watch (bus, (GstBusFunc) bus_message_cb, &ctx); + + /* This will make rtspsrc progress to the OPEN state, at which point we can seek it */ + if (!gst_element_set_state (ctx.pipe, GST_STATE_PLAYING)) + goto done; + + g_main_loop_run (ctx.loop); + + g_main_loop_unref (ctx.loop); + + gst_bus_remove_watch (bus); + gst_object_unref (bus); + gst_element_set_state (ctx.pipe, GST_STATE_NULL); + gst_object_unref (ctx.pipe); + + ret = 0; + +done: + g_free (seek_params.range); + g_free (seek_params.frames); + g_free (seek_params.rate_control); + return ret; +} diff --git a/examples/test-onvif-server.c b/examples/test-onvif-server.c new file mode 100644 index 0000000000..ae6ce68a5c --- /dev/null +++ b/examples/test-onvif-server.c @@ -0,0 +1,667 @@ +/* GStreamer + * Copyright (C) 2019 Mathieu Duponchelle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +GST_DEBUG_CATEGORY_STATIC (onvif_server_debug); +#define GST_CAT_DEFAULT (onvif_server_debug) + +#define MAKE_AND_ADD(var, pipe, name, label, elem_name) \ +G_STMT_START { \ + if (G_UNLIKELY (!(var = (gst_element_factory_make (name, elem_name))))) { \ + GST_ERROR ("Could not create element %s", name); \ + goto label; \ + } \ + if (G_UNLIKELY (!gst_bin_add (GST_BIN_CAST (pipe), var))) { \ + GST_ERROR ("Could not add element %s", name); \ + goto label; \ + } \ +} G_STMT_END + +/* This simulates an archive of recordings running from 01-01-1900 to 01-01-2000. + * + * This is implemented by repeating the file provided at the command line, with + * an empty interval of 5 seconds in-between. We intercept relevant events to + * translate them, and update the timestamps on the output buffers. + */ + +#define INTERVAL (5 * GST_SECOND) + +/* January the first, 2000 */ +#define END_DATE 3155673600 * GST_SECOND + + +G_DECLARE_FINAL_TYPE (ReplayBin, replay_bin, REPLAY, BIN, GstBin); + +static gchar *filename; + +struct _ReplayBin +{ + GstBin parent; + + GstEvent *incoming_seek; + GstEvent *outgoing_seek; + GstClockTime trickmode_interval; + + GstSegment segment; + const GstSegment *incoming_segment; + gboolean sent_segment; + GstClockTime ts_offset; + gint64 remainder; + GstClockTime min_pts; +}; + +G_DEFINE_TYPE (ReplayBin, replay_bin, GST_TYPE_BIN); + +static void +replay_bin_init (ReplayBin * self) +{ + self->incoming_seek = NULL; + self->outgoing_seek = NULL; + self->trickmode_interval = 0; + self->ts_offset = 0; + self->sent_segment = FALSE; + self->min_pts = GST_CLOCK_TIME_NONE; +} + +static void +replay_bin_class_init (ReplayBinClass * klass) +{ +} + +static GstElement * +replay_bin_new (void) +{ + return GST_ELEMENT (g_object_new (replay_bin_get_type (), NULL)); +} + +static void +demux_pad_added_cb (GstElement * demux, GstPad * pad, GstGhostPad * ghost) +{ + GstCaps *caps = gst_pad_get_current_caps (pad); + GstStructure *s = gst_caps_get_structure (caps, 0); + + if (gst_structure_has_name (s, "video/x-h264")) { + gst_ghost_pad_set_target (ghost, pad); + } + + gst_caps_unref (caps); +} + +static void +query_seekable (GstPad * ghost, gint64 * start, gint64 * stop) +{ + GstPad *target; + GstQuery *query; + GstFormat format; + gboolean seekable; + + target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost)); + + query = gst_query_new_seeking (GST_FORMAT_TIME); + + gst_pad_query (target, query); + + gst_query_parse_seeking (query, &format, &seekable, start, stop); + + g_assert (seekable); + + gst_object_unref (target); +} + +static GstEvent * +translate_seek (ReplayBin * self, GstPad * pad, GstEvent * ievent) +{ + GstEvent *oevent = NULL; + gdouble rate; + GstFormat format; + GstSeekFlags flags; + GstSeekType start_type, stop_type; + gint64 start, stop; + gint64 istart, istop; /* Incoming */ + gint64 ustart, ustop; /* Upstream */ + gint64 ostart, ostop; /* Outgoing */ + guint32 seqnum = gst_event_get_seqnum (ievent); + + gst_event_parse_seek (ievent, &rate, &format, &flags, &start_type, &start, + &stop_type, &stop); + + if (!GST_CLOCK_TIME_IS_VALID (stop)) + stop = END_DATE; + + gst_event_parse_seek_trickmode_interval (ievent, &self->trickmode_interval); + + istart = start; + istop = stop; + + query_seekable (pad, &ustart, &ustop); + + if (rate > 0) { + /* First, from where we should seek the file */ + ostart = istart % (ustop + INTERVAL); + + /* This may end up in our empty interval */ + if (ostart > ustop) { + istart += ostart - ustop; + ostart = 0; + } + + /* Then, up to where we should seek it */ + ostop = MIN (ustop, ostart + (istop - istart)); + } else { + /* First up to where we should seek the file */ + ostop = istop % (ustop + INTERVAL); + + GST_ERROR ("Ostop is %" GST_TIME_FORMAT, GST_TIME_ARGS (ostop)); + + /* This may end up in our empty interval */ + if (ostop > ustop) { + istop -= ostop - ustop; + ostop = ustop; + } + + ostart = MAX (0, ostop - (istop - istart)); + } + + /* We may be left with nothing to actually play, in this + * case we won't seek upstream, and emit the expected events + * ourselves */ + if (istart > istop) { + GstSegment segment; + GstEvent *event; + gboolean update; + + event = gst_event_new_flush_start (); + gst_event_set_seqnum (event, seqnum); + gst_pad_push_event (pad, event); + + event = gst_event_new_flush_stop (TRUE); + gst_event_set_seqnum (event, seqnum); + gst_pad_push_event (pad, event); + + gst_segment_init (&segment, format); + gst_segment_do_seek (&segment, rate, format, flags, start_type, start, + stop_type, stop, &update); + + event = gst_event_new_segment (&segment); + gst_event_set_seqnum (event, seqnum); + gst_pad_push_event (pad, event); + + event = gst_event_new_eos (); + gst_event_set_seqnum (event, seqnum); + gst_pad_push_event (pad, event); + + goto done; + } + + /* Lastly, how much will remain to play back (this remainder includes the interval) */ + if (stop - start > ostop - ostart) + self->remainder = (stop - start) - (ostop - ostart); + + flags |= GST_SEEK_FLAG_SEGMENT; + + oevent = + gst_event_new_seek (rate, format, flags, start_type, ostart, stop_type, + ostop); + gst_event_set_seek_trickmode_interval (oevent, self->trickmode_interval); + gst_event_set_seqnum (oevent, seqnum); + + GST_ERROR ("Translated event to %" GST_PTR_FORMAT " (remainder: %ld)", oevent, + self->remainder); + +done: + return oevent; +} + +static gboolean +replay_bin_event_func (GstPad * pad, GstObject * parent, GstEvent * event) +{ + ReplayBin *self = REPLAY_BIN (parent); + gboolean ret = TRUE; + gboolean forward = TRUE; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK: + { + GST_ERROR ("Processing seek event %" GST_PTR_FORMAT, event); + + self->incoming_seek = event; + + gst_event_replace (&self->outgoing_seek, NULL); + self->sent_segment = FALSE; + + event = translate_seek (self, pad, event); + + if (!event) + forward = FALSE; + else + self->outgoing_seek = gst_event_ref (event); + break; + } + default: + break; + } + + if (forward) + return gst_pad_event_default (pad, parent, event); + else + return ret; +} + +static gboolean +replay_bin_query_func (GstPad * pad, GstObject * parent, GstQuery * query) +{ + ReplayBin *self = REPLAY_BIN (parent); + gboolean ret = TRUE; + gboolean forward = TRUE; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_SEEKING: + /* We are seekable from the beginning till the end of time */ + gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, + GST_CLOCK_TIME_NONE); + forward = FALSE; + break; + case GST_QUERY_SEGMENT: + gst_query_set_segment (query, self->segment.rate, self->segment.format, + self->segment.start, self->segment.stop); + forward = FALSE; + default: + break; + } + + GST_DEBUG ("Processed query %" GST_PTR_FORMAT, query); + + if (forward) + return gst_pad_query_default (pad, parent, query); + else + return ret; +} + +static GstEvent * +translate_segment (GstPad * pad, GstEvent * ievent) +{ + ReplayBin *self = REPLAY_BIN (GST_OBJECT_PARENT (pad)); + GstEvent *ret; + gdouble irate, orate; + GstFormat iformat, oformat; + GstSeekFlags iflags, oflags; + GstSeekType istart_type, ostart_type, istop_type, ostop_type; + gint64 istart, ostart, istop, ostop; + gboolean update; + + gst_event_parse_segment (ievent, &self->incoming_segment); + + if (!self->outgoing_seek) { + GstSegment segment; + gboolean update; + + gst_segment_init (&segment, GST_FORMAT_TIME); + + gst_segment_do_seek (&segment, 1.0, GST_FORMAT_TIME, 0, GST_SEEK_TYPE_SET, + 0, GST_SEEK_TYPE_SET, END_DATE, &update); + + ret = gst_event_new_segment (&segment); + gst_event_unref (ievent); + goto done; + } + + if (!self->sent_segment) { + gst_event_parse_seek (self->incoming_seek, &irate, &iformat, &iflags, + &istart_type, &istart, &istop_type, &istop); + gst_event_parse_seek (self->outgoing_seek, &orate, &oformat, &oflags, + &ostart_type, &ostart, &ostop_type, &ostop); + + if (istop == -1) + istop = END_DATE; + + if (self->incoming_segment->rate > 0) + self->ts_offset = istart - ostart; + else + self->ts_offset = istop - ostop; + + istart += self->incoming_segment->start - ostart; + istop += self->incoming_segment->stop - ostop; + + gst_segment_init (&self->segment, self->incoming_segment->format); + + gst_segment_do_seek (&self->segment, self->incoming_segment->rate, + self->incoming_segment->format, self->incoming_segment->flags, + GST_SEEK_TYPE_SET, (guint64) istart, GST_SEEK_TYPE_SET, (guint64) istop, + &update); + + self->min_pts = istart; + + ret = gst_event_new_segment (&self->segment); + + self->sent_segment = TRUE; + + gst_event_unref (ievent); + + GST_ERROR ("Translated segment: %" GST_PTR_FORMAT ", ts_offset: %lu", ret, + self->ts_offset); + } else { + ret = NULL; + } + +done: + return ret; +} + +static void +handle_segment_done (ReplayBin * self, GstPad * pad) +{ + GstEvent *event; + + if (self->remainder < INTERVAL) { + self->remainder = 0; + event = gst_event_new_eos (); + gst_event_set_seqnum (event, gst_event_get_seqnum (self->incoming_seek)); + gst_pad_push_event (pad, event); + } else { + gint64 ustart, ustop; + gint64 ostart, ostop; + GstPad *target; + GstStructure *s; + + /* Signify the end of a contiguous section of recording */ + s = gst_structure_new ("GstNtpOffset", + "ntp-offset", G_TYPE_UINT64, 0, "discont", G_TYPE_BOOLEAN, TRUE, NULL); + + event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s); + + gst_pad_push_event (pad, event); + + query_seekable (pad, &ustart, &ustop); + + self->remainder -= INTERVAL; + + if (self->incoming_segment->rate > 0) { + ostart = 0; + ostop = MIN (ustop, self->remainder); + } else { + ostart = MAX (ustop - self->remainder, 0); + ostop = ustop; + } + + self->remainder = MAX (self->remainder - ostop - ostart, 0); + + event = + gst_event_new_seek (self->segment.rate, self->segment.format, + self->segment.flags & ~GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, ostart, + GST_SEEK_TYPE_SET, ostop); + gst_event_set_seek_trickmode_interval (event, self->trickmode_interval); + + if (self->incoming_segment->rate > 0) + self->ts_offset += INTERVAL + ustop; + else + self->ts_offset -= INTERVAL + ustop; + + GST_DEBUG ("New offset: %ld", self->ts_offset); + + GST_DEBUG ("Seeking to %" GST_PTR_FORMAT, event); + target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); + gst_pad_send_event (target, event); + gst_object_unref (target); + } +} + +static GstPadProbeReturn +replay_bin_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer unused) +{ + ReplayBin *self = REPLAY_BIN (GST_OBJECT_PARENT (pad)); + GstPadProbeReturn ret = GST_PAD_PROBE_OK; + + GST_DEBUG ("Probed %" GST_PTR_FORMAT, info->data); + + switch (GST_EVENT_TYPE (info->data)) { + case GST_EVENT_SEGMENT: + { + GstEvent *translated; + + GST_DEBUG ("Probed segment %" GST_PTR_FORMAT, info->data); + + translated = translate_segment (pad, GST_EVENT (info->data)); + if (translated) + info->data = translated; + else + ret = GST_PAD_PROBE_HANDLED; + + break; + } + case GST_EVENT_SEGMENT_DONE: + { + handle_segment_done (self, pad); + ret = GST_PAD_PROBE_HANDLED; + break; + } + default: + break; + } + + return ret; +} + +static GstPadProbeReturn +replay_bin_buffer_probe (GstPad * pad, GstPadProbeInfo * info, gpointer unused) +{ + ReplayBin *self = REPLAY_BIN (GST_OBJECT_PARENT (pad)); + GstPadProbeReturn ret = GST_PAD_PROBE_OK; + + if (GST_BUFFER_PTS (info->data) > self->incoming_segment->stop) { + ret = GST_PAD_PROBE_DROP; + goto done; + } + + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (info->data))) + GST_BUFFER_PTS (info->data) += self->ts_offset; + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (info->data))) + GST_BUFFER_DTS (info->data) += self->ts_offset; + + /* + if (GST_BUFFER_PTS (info->data) < self->min_pts) { + GST_ERROR ("Retimestamping for the greater good"); + GST_BUFFER_PTS (info->data) = self->min_pts; + self->min_pts += 1; + } + */ + + GST_LOG ("Pushing buffer %" GST_PTR_FORMAT, info->data); + +done: + return ret; +} + +static GstElement * +create_replay_bin (GstElement * parent) +{ + GstElement *ret, *src, *demux; + GstPad *ghost; + + ret = replay_bin_new (); + if (!gst_bin_add (GST_BIN (parent), ret)) { + gst_object_unref (ret); + goto fail; + } + + MAKE_AND_ADD (src, ret, "filesrc", fail, NULL); + MAKE_AND_ADD (demux, ret, "qtdemux", fail, NULL); + + ghost = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC); + gst_element_add_pad (ret, ghost); + + gst_pad_set_event_function (ghost, replay_bin_event_func); + gst_pad_add_probe (ghost, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + replay_bin_event_probe, NULL, NULL); + gst_pad_add_probe (ghost, GST_PAD_PROBE_TYPE_BUFFER, replay_bin_buffer_probe, + NULL, NULL); + gst_pad_set_query_function (ghost, replay_bin_query_func); + + if (!gst_element_link (src, demux)) + goto fail; + + g_object_set (src, "location", filename, NULL); + g_signal_connect (demux, "pad-added", G_CALLBACK (demux_pad_added_cb), ghost); + +done: + return ret; + +fail: + ret = NULL; + goto done; +} + +/* A simple factory to set up our replay bin */ + +G_DECLARE_FINAL_TYPE (OnvifFactory, onvif_factory, ONVIF, FACTORY, + GstRTSPMediaFactory); + +struct _OnvifFactory +{ + GstRTSPMediaFactory parent; +}; + +G_DEFINE_TYPE (OnvifFactory, onvif_factory, GST_TYPE_RTSP_MEDIA_FACTORY); + +static void +onvif_factory_init (OnvifFactory * factory) +{ +} + +static GstElement * +onvif_factory_create_element (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url) +{ + GstElement *replay_bin, *q1, *parse, *pay, *onvifts, *q2; + GstElement *ret = gst_bin_new (NULL); + GstElement *pbin = gst_bin_new ("pay0"); + GstPad *sinkpad, *srcpad; + + if (!(replay_bin = create_replay_bin (ret))) + goto fail; + + MAKE_AND_ADD (q1, pbin, "queue", fail, NULL); + MAKE_AND_ADD (parse, pbin, "h264parse", fail, NULL); + MAKE_AND_ADD (pay, pbin, "rtph264pay", fail, NULL); + MAKE_AND_ADD (onvifts, pbin, "rtponviftimestamp", fail, NULL); + MAKE_AND_ADD (q2, pbin, "queue", fail, NULL); + + gst_bin_add (GST_BIN (ret), pbin); + + if (!gst_element_link_many (q1, parse, pay, onvifts, q2, NULL)) + goto fail; + + sinkpad = gst_element_get_static_pad (q1, "sink"); + gst_element_add_pad (pbin, gst_ghost_pad_new ("sink", sinkpad)); + gst_object_unref (sinkpad); + + if (!gst_element_link (replay_bin, pbin)) + goto fail; + + srcpad = gst_element_get_static_pad (q2, "src"); + gst_element_add_pad (pbin, gst_ghost_pad_new ("src", srcpad)); + gst_object_unref (srcpad); + + g_object_set (onvifts, "set-t-bit", TRUE, "set-e-bit", TRUE, "ntp-offset", 0, + "drop-out-of-segment", FALSE, NULL); + + gst_element_set_clock (onvifts, gst_system_clock_obtain ()); + +done: + return ret; + +fail: + gst_object_unref (ret); + ret = NULL; + goto done; +} + +static void +onvif_factory_class_init (OnvifFactoryClass * klass) +{ + GstRTSPMediaFactoryClass *mf_class = GST_RTSP_MEDIA_FACTORY_CLASS (klass); + + mf_class->create_element = onvif_factory_create_element; +} + +static GstRTSPMediaFactory * +onvif_factory_new (void) +{ + GstRTSPMediaFactory *result; + + result = + GST_RTSP_MEDIA_FACTORY (g_object_new (onvif_factory_get_type (), NULL)); + + return result; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + GOptionContext *optctx; + GError *error = NULL; + gchar *service; + + optctx = g_option_context_new (" - ONVIF RTSP Server, MP4"); + g_option_context_add_group (optctx, gst_init_get_option_group ()); + if (!g_option_context_parse (optctx, &argc, &argv, &error)) { + g_printerr ("Error parsing options: %s\n", error->message); + g_option_context_free (optctx); + g_clear_error (&error); + return -1; + } + if (argc < 2) { + g_print ("%s\n", g_option_context_get_help (optctx, TRUE, NULL)); + return 1; + } + filename = argv[1]; + g_option_context_free (optctx); + + GST_DEBUG_CATEGORY_INIT (onvif_server_debug, "onvif-server", 0, + "ONVIF server"); + + loop = g_main_loop_new (NULL, FALSE); + + server = gst_rtsp_onvif_server_new (); + + mounts = gst_rtsp_server_get_mount_points (server); + + factory = onvif_factory_new (); + gst_rtsp_media_factory_set_media_gtype (factory, GST_TYPE_RTSP_ONVIF_MEDIA); + + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + g_object_unref (mounts); + + gst_rtsp_server_attach (server, NULL); + + service = gst_rtsp_server_get_service (server); + g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", service); + g_free (service); + g_main_loop_run (loop); + + return 0; +} From df1f9f38cefac17568980c0c5285b000f4719151 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 7 Aug 2019 21:04:33 +0200 Subject: [PATCH 1633/1776] test-onvif-server: downgrade logging --- examples/test-onvif-server.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/examples/test-onvif-server.c b/examples/test-onvif-server.c index ae6ce68a5c..260456b0d2 100644 --- a/examples/test-onvif-server.c +++ b/examples/test-onvif-server.c @@ -171,8 +171,6 @@ translate_seek (ReplayBin * self, GstPad * pad, GstEvent * ievent) /* First up to where we should seek the file */ ostop = istop % (ustop + INTERVAL); - GST_ERROR ("Ostop is %" GST_TIME_FORMAT, GST_TIME_ARGS (ostop)); - /* This may end up in our empty interval */ if (ostop > ustop) { istop -= ostop - ustop; @@ -225,7 +223,7 @@ translate_seek (ReplayBin * self, GstPad * pad, GstEvent * ievent) gst_event_set_seek_trickmode_interval (oevent, self->trickmode_interval); gst_event_set_seqnum (oevent, seqnum); - GST_ERROR ("Translated event to %" GST_PTR_FORMAT " (remainder: %ld)", oevent, + GST_DEBUG ("Translated event to %" GST_PTR_FORMAT " (remainder: %ld)", oevent, self->remainder); done: @@ -242,7 +240,7 @@ replay_bin_event_func (GstPad * pad, GstObject * parent, GstEvent * event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { - GST_ERROR ("Processing seek event %" GST_PTR_FORMAT, event); + GST_DEBUG ("Processing seek event %" GST_PTR_FORMAT, event); self->incoming_seek = event; @@ -357,7 +355,7 @@ translate_segment (GstPad * pad, GstEvent * ievent) gst_event_unref (ievent); - GST_ERROR ("Translated segment: %" GST_PTR_FORMAT ", ts_offset: %lu", ret, + GST_DEBUG ("Translated segment: %" GST_PTR_FORMAT ", ts_offset: %lu", ret, self->ts_offset); } else { ret = NULL; @@ -477,14 +475,6 @@ replay_bin_buffer_probe (GstPad * pad, GstPadProbeInfo * info, gpointer unused) if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (info->data))) GST_BUFFER_DTS (info->data) += self->ts_offset; - /* - if (GST_BUFFER_PTS (info->data) < self->min_pts) { - GST_ERROR ("Retimestamping for the greater good"); - GST_BUFFER_PTS (info->data) = self->min_pts; - self->min_pts += 1; - } - */ - GST_LOG ("Pushing buffer %" GST_PTR_FORMAT, info->data); done: From 859e59b94432ea2ec9c374be4004546208adbced Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 8 Aug 2019 15:52:53 +0200 Subject: [PATCH 1634/1776] test-onvif-client: STDIN_FILENO is not portable If not defined, define it to _fileno(stdin) on Windows, 0 everywhere else --- examples/test-onvif-client.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/test-onvif-client.c b/examples/test-onvif-client.c index 28fe102d50..2df63d1506 100644 --- a/examples/test-onvif-client.c +++ b/examples/test-onvif-client.c @@ -539,6 +539,14 @@ io_callback (GIOChannel * io, GIOCondition condition, Context * ctx) return ret; } +#ifndef STDIN_FILENO +#ifdef G_OS_WIN32 +#define STDIN_FILENO _fileno(stdin) +#else /* !G_OS_WIN32 */ +#define STDIN_FILENO 0 +#endif /* G_OS_WIN32 */ +#endif /* STDIN_FILENO */ + static void prompt_on (Context * ctx) { From 7073ade1a6a7efd84ba9f0a1a4bb7ba8626e9b1e Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 12 Aug 2019 18:03:36 +0200 Subject: [PATCH 1635/1776] rtsp-media: add missing Since tag --- gst/rtsp-server/rtsp-media.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index bc5458b29a..4aaed7ce6e 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2896,6 +2896,7 @@ preroll_failed: * @media must be prepared with gst_rtsp_media_prepare(). * * Returns: %TRUE on success. + * Since: 1.18 */ gboolean gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range, From c2deb7f64b5e6853ef65847796c7728fb438475e Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 16 Aug 2019 13:38:01 -0400 Subject: [PATCH 1636/1776] test-onvif-client: stdin is not defined in MSVC --- examples/test-onvif-client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/test-onvif-client.c b/examples/test-onvif-client.c index 2df63d1506..0468850dc1 100644 --- a/examples/test-onvif-client.c +++ b/examples/test-onvif-client.c @@ -17,6 +17,8 @@ * Boston, MA 02110-1301, USA. */ +#include + #include #include From b2d5e4db52dc3187347e869babbf61808670c262 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Fri, 23 Aug 2019 16:21:36 +1000 Subject: [PATCH 1637/1776] meson: Don't generate doc cache when no plugins are enabled Fixes gst-build with -Dauto-features=disabled -Drtsp_server=enabled --- docs/meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/meson.build b/docs/meson.build index efcb6f1510..100bbb4a72 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -20,7 +20,9 @@ else endif plugins_cache = join_paths(meson.current_source_dir(), 'gst_plugins_cache.json') -if plugins_cache_generator.found() +if plugins.length() == 0 + message('All rtsp-server plugins have been disabled') +elif plugins_cache_generator.found() plugins_doc_dep = custom_target('rtsp-server-plugins-doc-cache', command: [plugins_cache_generator, plugins_cache, '@OUTPUT@', '@INPUT@'], input: plugins, From 4319e17b0e983245e17dd498f8e47f3c8bdc3e4a Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 26 Aug 2019 22:24:12 +1000 Subject: [PATCH 1638/1776] examples/onvif-server: fix werror build with clang ../subprojects/gst-rtsp-server/examples/test-onvif-server.c:346:65: warning: implicit conversion from enumeration type 'const GstSegmentFlags' to different enumeration type 'GstSeekFlags' [-Wenum-conversion] self->incoming_segment->format, self->incoming_segment->flags, ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~ ../subprojects/gst-rtsp-server/examples/test-onvif-server.c:53:1: warning: unused function 'REPLAY_IS_BIN' [-Wunused-function] G_DECLARE_FINAL_TYPE (ReplayBin, replay_bin, REPLAY, BIN, GstBin); ^ /usr/include/glib-2.0/gobject/gtype.h:1407:26: note: expanded from macro 'G_DECLARE_FINAL_TYPE' static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \ ^ :77:1: note: expanded from here REPLAY_IS_BIN ^ ../subprojects/gst-rtsp-server/examples/test-onvif-server.c:525:1: warning: unused function 'ONVIF_FACTORY' [-Wunused-function] G_DECLARE_FINAL_TYPE (OnvifFactory, onvif_factory, ONVIF, FACTORY, ^ /usr/include/glib-2.0/gobject/gtype.h:1405:33: note: expanded from macro 'G_DECLARE_FINAL_TYPE' static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \ ^ :9:1: note: expanded from here ONVIF_FACTORY ^ ../subprojects/gst-rtsp-server/examples/test-onvif-server.c:525:1: warning: unused function 'ONVIF_IS_FACTORY' [-Wunused-function] /usr/include/glib-2.0/gobject/gtype.h:1407:26: note: expanded from macro 'G_DECLARE_FINAL_TYPE' static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \ ^ :12:1: note: expanded from here ONVIF_IS_FACTORY ^ --- examples/test-onvif-server.c | 14 +++++--------- examples/test-onvif-server.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 examples/test-onvif-server.h diff --git a/examples/test-onvif-server.c b/examples/test-onvif-server.c index 260456b0d2..95041693fe 100644 --- a/examples/test-onvif-server.c +++ b/examples/test-onvif-server.c @@ -22,6 +22,8 @@ #include +#include "test-onvif-server.h" + GST_DEBUG_CATEGORY_STATIC (onvif_server_debug); #define GST_CAT_DEFAULT (onvif_server_debug) @@ -49,9 +51,6 @@ G_STMT_START { \ /* January the first, 2000 */ #define END_DATE 3155673600 * GST_SECOND - -G_DECLARE_FINAL_TYPE (ReplayBin, replay_bin, REPLAY, BIN, GstBin); - static gchar *filename; struct _ReplayBin @@ -343,9 +342,9 @@ translate_segment (GstPad * pad, GstEvent * ievent) gst_segment_init (&self->segment, self->incoming_segment->format); gst_segment_do_seek (&self->segment, self->incoming_segment->rate, - self->incoming_segment->format, self->incoming_segment->flags, - GST_SEEK_TYPE_SET, (guint64) istart, GST_SEEK_TYPE_SET, (guint64) istop, - &update); + self->incoming_segment->format, + (GstSeekFlags) self->incoming_segment->flags, GST_SEEK_TYPE_SET, + (guint64) istart, GST_SEEK_TYPE_SET, (guint64) istop, &update); self->min_pts = istart; @@ -522,9 +521,6 @@ fail: /* A simple factory to set up our replay bin */ -G_DECLARE_FINAL_TYPE (OnvifFactory, onvif_factory, ONVIF, FACTORY, - GstRTSPMediaFactory); - struct _OnvifFactory { GstRTSPMediaFactory parent; diff --git a/examples/test-onvif-server.h b/examples/test-onvif-server.h new file mode 100644 index 0000000000..13d5f00dec --- /dev/null +++ b/examples/test-onvif-server.h @@ -0,0 +1,32 @@ +/* GStreamer + * Copyright (C) 2019 Mathieu Duponchelle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE (ReplayBin, replay_bin, REPLAY, BIN, GstBin); + +G_DECLARE_FINAL_TYPE (OnvifFactory, onvif_factory, ONVIF, FACTORY, + GstRTSPMediaFactory); + +G_END_DECLS From 16bc937ed95c85c9d02a314a3b065eebc575a97c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Wed, 21 Aug 2019 14:57:25 +0200 Subject: [PATCH 1639/1776] Use complete streams for scale and speed. Without this patch it's always stream0 that is used to get segment event that is used to set scale and speed. This even if client not doing SETUP for stream0. At least in suspend mode reset this not working since then it's just random if send_rtp_sink have got any segment event. There are no check if send_rtp_sink for stream0 got any data before media is prerolled after PLAY request. --- gst/rtsp-server/rtsp-client.c | 2 +- gst/rtsp-server/rtsp-media.c | 64 ++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-media.h | 3 ++ tests/check/gst/rtspserver.c | 73 +++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 964e06bfeb..5dac08b9d1 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2026,7 +2026,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (str) gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RANGE, str); - if (!gst_rtsp_media_is_receive_only (media)) { + if (gst_rtsp_media_has_completed_sender (media)) { /* the scale and speed headers must always be added if they were present in * the request. however, even if they were not, we still add them if * applied_rate or rate deviate from the "normal", i.e. 1.0 */ diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4aaed7ce6e..35a9ec0cfd 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2562,7 +2562,10 @@ gst_rtsp_media_get_rates (GstRTSPMedia * media, gdouble * rate, { GstRTSPMediaPrivate *priv; GstRTSPStream *stream; + gdouble save_rate, save_applied_rate; gboolean result = TRUE; + gboolean first_stream = TRUE; + gint i; g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); @@ -2576,11 +2579,34 @@ gst_rtsp_media_get_rates (GstRTSPMedia * media, gdouble * rate, g_mutex_lock (&priv->lock); g_assert (priv->streams->len > 0); - stream = g_ptr_array_index (priv->streams, 0); - if (!gst_rtsp_stream_get_rates (stream, rate, applied_rate)) { + for (i = 0; i < priv->streams->len; i++) { + stream = g_ptr_array_index (priv->streams, i); + if (gst_rtsp_stream_is_complete (stream)) { + if (gst_rtsp_stream_get_rates (stream, rate, applied_rate)) { + if (first_stream) { + save_rate = *rate; + save_applied_rate = *applied_rate; + first_stream = FALSE; + } else { + if (save_rate != *rate || save_applied_rate != *applied_rate) { + /* diffrent rate or applied_rate, weird */ + g_assert (FALSE); + result = FALSE; + break; + } + } + } else { + /* complete stream withot rate and applied_rate, weird */ + g_assert (FALSE); + result = FALSE; + break; + } + } + } + + if (!result) { GST_WARNING_OBJECT (media, - "failed to obtain rate and applied_rate from first stream"); - result = FALSE; + "failed to obtain consistent rate and applied_rate"); } g_mutex_unlock (&priv->lock); @@ -4781,6 +4807,36 @@ gst_rtsp_media_is_receive_only (GstRTSPMedia * media) return receive_only; } +/** + * gst_rtsp_media_has_completed_sender: + * + * See gst_rtsp_stream_is_complete(), gst_rtsp_stream_is_sender(). + * + * Returns: whether @media has at least one complete sender stream. + * Since: 1.18 + */ +gboolean +gst_rtsp_media_has_completed_sender (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + gboolean sender = FALSE; + guint i; + + g_mutex_lock (&priv->lock); + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + if (gst_rtsp_stream_is_complete (stream)) + if (gst_rtsp_stream_is_sender (stream) || + !gst_rtsp_stream_is_receiver (stream)) { + sender = TRUE; + break; + } + } + g_mutex_unlock (&priv->lock); + + return sender; +} + /** * gst_rtsp_media_set_rate_control: * diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 987a8ad017..5379f65e64 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -421,6 +421,9 @@ gboolean gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GP GST_RTSP_SERVER_API gboolean gst_rtsp_media_is_receive_only (GstRTSPMedia * media); +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_has_completed_sender (GstRTSPMedia * media); + GST_RTSP_SERVER_API void gst_rtsp_media_set_rate_control (GstRTSPMedia * media, gboolean enabled); diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index d342a436d3..f3bd5d0676 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -2401,6 +2401,78 @@ GST_START_TEST (test_multiple_transports) GST_END_TEST; +GST_START_TEST (test_suspend_mode_reset_only_audio) +{ + GstRTSPMountPoints *mounts; + gchar *service; + GstRTSPMediaFactory *factory; + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *audio_control; + GstRTSPRange client_port; + gchar *session = NULL; + GstRTSPTransport *audio_transport = NULL; + GSocket *rtp_socket, *rtcp_socket; + + mounts = gst_rtsp_server_get_mount_points (server); + + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_suspend_mode (factory, + GST_RTSP_SUSPEND_MODE_RESET); + gst_rtsp_media_factory_set_launch (factory, + "( " VIDEO_PIPELINE " " AUDIO_PIPELINE " )"); + gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); + g_object_unref (mounts); + + /* set port to any */ + gst_rtsp_server_set_service (server, "0"); + + /* attach to default main context */ + source_id = gst_rtsp_server_attach (server, NULL); + fail_if (source_id == 0); + + /* get port */ + service = gst_rtsp_server_get_service (server); + test_port = atoi (service); + fail_unless (test_port != 0); + g_free (service); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 1); + audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports_full (&client_port, &rtp_socket, &rtcp_socket); + + /* do SETUP for audio */ + fail_unless (do_setup (conn, audio_control, &client_port, &session, + &audio_transport) == GST_RTSP_STS_OK); + + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_PLAY, + session) == GST_RTSP_STS_OK); + + /* send TEARDOWN request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session) == GST_RTSP_STS_OK); + + /* clean up and iterate so the clean-up can finish */ + g_free (session); + gst_rtsp_transport_free (audio_transport); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + + stop_server (); + iterate (); +} + +GST_END_TEST; + static Suite * rtspserver_suite (void) { @@ -2439,6 +2511,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_announce_without_sdp); tcase_add_test (tc, test_record_tcp); tcase_add_test (tc, test_multiple_transports); + tcase_add_test (tc, test_suspend_mode_reset_only_audio); return s; } From 513c0fcb95709be0f863bb4671432a3101850e7e Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 29 Aug 2019 21:37:24 +0200 Subject: [PATCH 1640/1776] test-onvif-client: perform accurate seeks See https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/merge_requests/336 Also, modify how we compute the position: position queries in PAUSED mode fail to account for the newly-prerolled frame, leading to frame skips when performing seeks in that state. Instead, compute the current position from the last sample. --- examples/test-onvif-client.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/examples/test-onvif-client.c b/examples/test-onvif-client.c index 0468850dc1..eefbbd130d 100644 --- a/examples/test-onvif-client.c +++ b/examples/test-onvif-client.c @@ -156,6 +156,27 @@ done: return ret; } +static GstClockTime +get_current_position (Context * ctx, gboolean reverse) +{ + GstSample *sample; + GstBuffer *buffer; + GstClockTime ret; + + g_object_get (ctx->sink, "last-sample", &sample, NULL); + + buffer = gst_sample_get_buffer (sample); + + ret = GST_BUFFER_PTS (buffer); + + if (reverse && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) + ret += GST_BUFFER_DURATION (buffer); + + gst_sample_unref (sample); + + return ret; +} + static GstEvent * translate_seek_parameters (Context * ctx, SeekParameters * seek_params) { @@ -188,19 +209,22 @@ translate_seek_parameters (Context * ctx, SeekParameters * seek_params) stop_type = GST_SEEK_TYPE_SET; if (!ctx->new_range) { + GstClockTime current_position = + get_current_position (ctx, seek_params->reverse); gst_element_query_position (ctx->pipe, GST_FORMAT_TIME, &cur_pos); + if (seek_params->reverse) { stop_type = GST_SEEK_TYPE_SET; - stop = cur_pos; + stop = current_position; } else { start_type = GST_SEEK_TYPE_SET; - start = cur_pos; + start = current_position; } } ctx->new_range = FALSE; - flags = GST_SEEK_FLAG_FLUSH; + flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE; split = g_strsplit (seek_params->frames, "/", 2); From f834700efff651a83442207395c626f5aacbbbfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristofer=20Bj=C3=B6rkstr=C3=B6m?= Date: Fri, 30 Aug 2019 14:00:52 +0200 Subject: [PATCH 1641/1776] rtsp-client: RTP Info must exist in PLAY response If RTP Info is missing. Then return GST_RTSP_STS_INTERNAL_SERVER_ERROR Fixes #76 --- gst/rtsp-server/rtsp-client.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 5dac08b9d1..7c3ea5c7db 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2006,7 +2006,8 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) goto invalid_mode; /* grab RTPInfo from the media now */ - rtpinfo = gst_rtsp_session_media_get_rtpinfo (sessmedia); + if (!(rtpinfo = gst_rtsp_session_media_get_rtpinfo (sessmedia))) + goto rtp_info_error; /* construct the response now */ code = GST_RTSP_STS_OK; @@ -2014,9 +2015,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_status_as_text (code), ctx->request); /* add the RTP-Info header */ - if (rtpinfo) - gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO, - rtpinfo); + gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO, rtpinfo); if (seek_style) gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_SEEK_STYLE, seek_style); @@ -2138,6 +2137,12 @@ adjust_play_response_failed: send_generic_response (client, code, ctx); return FALSE; } +rtp_info_error: + { + GST_ERROR ("client %p: failed to add RTP-Info", client); + send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx); + return FALSE; + } } static void From 9cba1f77087db514617ddc6327a4ca2cb6299677 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 5 Sep 2019 16:23:26 +0200 Subject: [PATCH 1642/1776] test-onvif-client: remove unused query --- examples/test-onvif-client.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/test-onvif-client.c b/examples/test-onvif-client.c index eefbbd130d..16d5f696cd 100644 --- a/examples/test-onvif-client.c +++ b/examples/test-onvif-client.c @@ -189,7 +189,6 @@ translate_seek_parameters (Context * ctx, SeekParameters * seek_params) GstSeekFlags flags; gchar **split = NULL; GstClockTime trickmode_interval = 0; - gint64 cur_pos; range_str = g_strdup_printf ("clock=%s", seek_params->range); @@ -211,7 +210,6 @@ translate_seek_parameters (Context * ctx, SeekParameters * seek_params) if (!ctx->new_range) { GstClockTime current_position = get_current_position (ctx, seek_params->reverse); - gst_element_query_position (ctx->pipe, GST_FORMAT_TIME, &cur_pos); if (seek_params->reverse) { stop_type = GST_SEEK_TYPE_SET; From d7ae39657dc0b40c4344da267d09f35135d7bc40 Mon Sep 17 00:00:00 2001 From: Kristofer Date: Wed, 25 Sep 2019 09:14:08 +0000 Subject: [PATCH 1643/1776] rtsp-client: RTP Info exists conditionally in PLAY If RTP Info is missing and it is not a receiver only, eg. audio backchannel. Then return GST_RTSP_STS_INTERNAL_SERVER_ERROR. In rfc2326 it says RTP-info is req. but in RFC7826 it is conditional. Since 1.14 there is audio backchannel support. Thus RTP-info is conditional now. When audio backchannel only mode, there is no RTP-info. Fixes #82 --- gst/rtsp-server/rtsp-client.c | 9 ++-- tests/check/gst/client.c | 95 +++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 7c3ea5c7db..c7e1620263 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1942,7 +1942,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *str; GstRTSPState rtspstate; GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT; - gchar *path, *rtpinfo; + gchar *path, *rtpinfo = NULL; gint matched; gchar *seek_style = NULL; GstRTSPStatusCode sig_result; @@ -2006,7 +2006,8 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) goto invalid_mode; /* grab RTPInfo from the media now */ - if (!(rtpinfo = gst_rtsp_session_media_get_rtpinfo (sessmedia))) + if (!gst_rtsp_media_is_receive_only (media) && + !(rtpinfo = gst_rtsp_session_media_get_rtpinfo (sessmedia))) goto rtp_info_error; /* construct the response now */ @@ -2015,7 +2016,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_status_as_text (code), ctx->request); /* add the RTP-Info header */ - gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO, rtpinfo); + if (rtpinfo) + gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO, + rtpinfo); if (seek_style) gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_SEEK_STYLE, seek_style); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 80ed9352da..c860417bc7 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -58,6 +58,51 @@ test_response_200 (GstRTSPClient * client, GstRTSPMessage * response, return TRUE; } +static gboolean +test_response_play_200 (GstRTSPClient * client, GstRTSPMessage * response, + gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + gchar *str; + gchar **session_hdr_params; + gchar *pattern; + + fail_unless_equals_int (gst_rtsp_message_get_type (response), + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless_equals_int (code, GST_RTSP_STS_OK); + fail_unless_equals_string (reason, "OK"); + fail_unless_equals_int (version, GST_RTSP_VERSION_1_0); + + /* Verify mandatory headers according to RFC 2326 */ + /* verify mandatory CSeq header */ + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, + 0) == GST_RTSP_OK); + fail_unless (atoi (str) == cseq++); + + /* verify mandatory Session header */ + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, + &str, 0) == GST_RTSP_OK); + session_hdr_params = g_strsplit (str, ";", -1); + fail_unless (session_hdr_params[0] != NULL); + g_strfreev (session_hdr_params); + + /* verify mandatory RTP-Info header */ + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_RTP_INFO, + &str, 0) == GST_RTSP_OK); + pattern = g_strdup_printf ("^url=rtsp://.+;seq=[0-9]+;rtptime=[0-9]+"); + fail_unless (g_regex_match_simple (pattern, str, 0, 0), + "GST_RTSP_HDR_RTP_INFO '%s' doesn't match pattern '%s'", str, pattern); + g_free (pattern); + + return TRUE; +} + static gboolean test_response_400 (GstRTSPClient * client, GstRTSPMessage * response, gboolean close, gpointer user_data) @@ -1915,6 +1960,55 @@ GST_START_TEST (test_scale_and_speed) do_test_scale_and_speed ("2", "2"); } +GST_END_TEST +GST_START_TEST (test_client_play) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + GstRTSPContext ctx = { NULL }; + + client = setup_multicast_client (1); + + ctx.client = client; + ctx.auth = gst_rtsp_auth_new (); + ctx.token = + gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_context_push_current (&ctx); + + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast"); + /* destination is from adress pool */ + expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=.*;mode=\"PLAY\""; + gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + expected_transport = NULL; + + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, + "rtsp://localhost/test") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); + gst_rtsp_client_set_send_func (client, test_response_play_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + send_teardown (client); + teardown_client (client); + g_object_unref (ctx.auth); + gst_rtsp_token_unref (ctx.token); + gst_rtsp_context_pop_current (&ctx); +} + GST_END_TEST static Suite * rtspclient_suite (void) { @@ -1968,6 +2062,7 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_max_ttl_second_client); tcase_add_test (tc, test_client_multicast_invalid_ttl); tcase_add_test (tc, test_scale_and_speed); + tcase_add_test (tc, test_client_play); return s; } From 7e1edcf1a4eb71fd699a5fef0f810d1e3ef3c278 Mon Sep 17 00:00:00 2001 From: Kristofer Bjorkstrom Date: Mon, 30 Sep 2019 15:13:15 +0200 Subject: [PATCH 1644/1776] rtsp-client: RTP Info when completed_sender Change condition that should be fulfilled regarding RTPInfo. Replace !gst_rtsp_media_is_receive_only with gst_rtsp_media_has_completed_sender. It is more correct to actually look for a sender pipeline that is complete. Only then a RTPInfo should exist. gst_rtsp_media_is_receive_only gives different answears depending on state of server. If Describe is called wth URL+options for backchannel SDP will give only audio and only backchannel a=sendonly If Describe is called on URL+options that gives both audio and video direction from server to client, pipelines are created. Thus receive_only will return false, even though Setup only would setup backchannel. RTP-Info is only for outgoing streams. Thus one should look if outgoing streams are complete. --- gst/rtsp-server/rtsp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index c7e1620263..0b7b556d9e 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2006,7 +2006,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) goto invalid_mode; /* grab RTPInfo from the media now */ - if (!gst_rtsp_media_is_receive_only (media) && + if (gst_rtsp_media_has_completed_sender (media) && !(rtpinfo = gst_rtsp_session_media_get_rtpinfo (sessmedia))) goto rtp_info_error; From 18f4f4e5095fc41c59638710dc6477c240158704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Wed, 11 Sep 2019 07:08:37 +0200 Subject: [PATCH 1645/1776] rtsp-media: Wait on async when needed. Wait on asyn-done when needed in gst_rtsp_media_seek_trickmode. In the unit test the pause from adjust_play_mode will cause a preroll and after that async-done will be produced. Without this patch there are no one consuming this async-done and when later when seek fluch is done in gst_rtsp_media_seek_trickmode then it wait for async-done. But then it wrongly find the async-done prodused by adjus_play_mode and continue executing without waiting for the preroll to finish. --- gst/rtsp-server/rtsp-media.c | 47 +++++++++++-- tests/check/gst/rtspserver.c | 126 +++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 35a9ec0cfd..45463f6652 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -152,6 +152,7 @@ struct _GstRTSPMediaPrivate /* Dynamic element handling */ guint nb_dynamic_elements; guint no_more_pads_pending; + gboolean expected_async_done; }; #define DEFAULT_SHARED FALSE @@ -476,6 +477,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS; priv->do_rate_control = DEFAULT_DO_RATE_CONTROL; + priv->expected_async_done = FALSE; } static void @@ -2819,6 +2821,30 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, GstEvent *seek_event; gboolean unblock = FALSE; + /* Handle expected async-done before waiting on next async-done. + * + * Since the seek further down in code will cause a preroll and + * a async-done will be generated it's important to wait on async-done + * if that is expected. Otherwise there is the risk that the waiting + * for async-done after the seek is detecting the expected async-done + * instead of the one that corresponds to the seek. Then execution + * continue and act as if the pipeline is prerolled, but it's not. + * + * During wait_preroll message GST_MESSAGE_ASYNC_DONE will come + * and then the state will change from preparing to prepared */ + if (priv->expected_async_done) { + GST_DEBUG (" expected to get async-done, waiting "); + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); + g_rec_mutex_unlock (&priv->state_lock); + + /* wait until pipeline is prerolled */ + if (!wait_preroll (media)) + goto preroll_failed_expected_async_done; + + g_rec_mutex_lock (&priv->state_lock); + GST_DEBUG (" got expected async-done"); + } + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); if (rate < 0.0) { @@ -2910,6 +2936,11 @@ preroll_failed: GST_WARNING ("failed to preroll after seek"); return FALSE; } +preroll_failed_expected_async_done: + { + GST_WARNING ("failed to preroll"); + return FALSE; + } } /** @@ -3118,6 +3149,8 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) case GST_MESSAGE_STREAM_STATUS: break; case GST_MESSAGE_ASYNC_DONE: + if (priv->expected_async_done) + priv->expected_async_done = FALSE; if (priv->complete) { /* receive the final ASYNC_DONE, that is posted by the media pipeline * after all the transport parts have been successfully added to @@ -4459,6 +4492,8 @@ static void media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) { GstRTSPMediaPrivate *priv = media->priv; + GstStateChangeReturn set_state_ret; + priv->expected_async_done = FALSE; if (state == GST_STATE_NULL) { gst_rtsp_media_unprepare (media); @@ -4474,11 +4509,15 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) /* make sure pads are not blocking anymore when going to PLAYING */ media_unblock_linked (media); - set_state (media, state); - - /* and suspend after pause */ - if (state == GST_STATE_PAUSED) + if (state == GST_STATE_PAUSED) { + set_state_ret = set_state (media, state); + if (set_state_ret == GST_STATE_CHANGE_ASYNC) + priv->expected_async_done = TRUE; + /* and suspend after pause */ gst_rtsp_media_suspend (media); + } else { + set_state (media, state); + } } } } diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index f3bd5d0676..da6df2d72f 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -483,6 +483,16 @@ do_simple_request (GstRTSPConnection * conn, GstRTSPMethod method, NULL, NULL, NULL, NULL, NULL); } +/* send an rtsp request with a method,session and range in, + * and receive response. range_in is the Range in req header */ +static GstRTSPStatusCode +do_simple_request_rangein (GstRTSPConnection * conn, GstRTSPMethod method, + const gchar * session, const gchar * rangein) +{ + return do_request (conn, method, NULL, session, NULL, rangein, NULL, + NULL, NULL, NULL, NULL, NULL); +} + /* send a DESCRIBE request and receive response. returns a received * GstSDPMessage that must be freed by the caller */ static GstSDPMessage * @@ -2473,6 +2483,121 @@ GST_START_TEST (test_suspend_mode_reset_only_audio) GST_END_TEST; + +static GstRTSPStatusCode +adjust_play_mode (GstRTSPClient * client, GstRTSPContext * ctx, + GstRTSPTimeRange ** range, GstSeekFlags * flags, gdouble * rate, + GstClockTime * trickmode_interval, gboolean * enable_rate_control) +{ + GstRTSPState rtspstate; + + rtspstate = gst_rtsp_session_media_get_rtsp_state (ctx->sessmedia); + if (rtspstate == GST_RTSP_STATE_PLAYING) { + if (!gst_rtsp_session_media_set_state (ctx->sessmedia, GST_STATE_PAUSED)) + return GST_RTSP_STS_INTERNAL_SERVER_ERROR; + + if (!gst_rtsp_media_unsuspend (ctx->media)) + return GST_RTSP_STS_INTERNAL_SERVER_ERROR; + } + + return GST_RTSP_STS_OK; +} + +GST_START_TEST (test_double_play) +{ + GstRTSPMountPoints *mounts; + gchar *service; + GstRTSPMediaFactory *factory; + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + const gchar *audio_control; + GstRTSPRange client_port; + gchar *session = NULL; + GstRTSPTransport *audio_transport = NULL; + GstRTSPTransport *video_transport = NULL; + GSocket *rtp_socket, *rtcp_socket; + GstRTSPClient *client; + GstRTSPClientClass *klass; + + client = gst_rtsp_client_new (); + klass = GST_RTSP_CLIENT_GET_CLASS (client); + klass->adjust_play_mode = adjust_play_mode; + + mounts = gst_rtsp_server_get_mount_points (server); + + factory = gst_rtsp_media_factory_new (); + gst_rtsp_media_factory_set_launch (factory, + "( " VIDEO_PIPELINE " " AUDIO_PIPELINE " )"); + gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory); + g_object_unref (mounts); + + + /* set port to any */ + gst_rtsp_server_set_service (server, "0"); + + /* attach to default main context */ + source_id = gst_rtsp_server_attach (server, NULL); + fail_if (source_id == 0); + + /* get port */ + service = gst_rtsp_server_get_service (server); + test_port = atoi (service); + fail_unless (test_port != 0); + g_free (service); + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + sdp_media = gst_sdp_message_get_media (sdp_message, 1); + audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports_full (&client_port, &rtp_socket, &rtcp_socket); + + /* do SETUP for video */ + fail_unless (do_setup (conn, video_control, &client_port, &session, + &video_transport) == GST_RTSP_STS_OK); + + /* do SETUP for audio */ + fail_unless (do_setup (conn, audio_control, &client_port, &session, + &audio_transport) == GST_RTSP_STS_OK); + + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_simple_request_rangein (conn, GST_RTSP_PLAY, + session, "npt=0-") == GST_RTSP_STS_OK); + + /* let it play for a while, so it needs to seek + * for next play (npt=0-) */ + g_usleep (30000); + + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_simple_request_rangein (conn, GST_RTSP_PLAY, + session, "npt=0-") == GST_RTSP_STS_OK); + + /* send TEARDOWN request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN, + session) == GST_RTSP_STS_OK); + + /* clean up and iterate so the clean-up can finish */ + g_free (session); + gst_rtsp_transport_free (video_transport); + gst_rtsp_transport_free (audio_transport); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + + stop_server (); + iterate (); +} + +GST_END_TEST; + + static Suite * rtspserver_suite (void) { @@ -2512,6 +2637,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_record_tcp); tcase_add_test (tc, test_multiple_transports); tcase_add_test (tc, test_suspend_mode_reset_only_audio); + tcase_add_test (tc, test_double_play); return s; } From e16867b1618460452d0a637b2ba64e6d88e0c7c9 Mon Sep 17 00:00:00 2001 From: David Svensson Fors Date: Mon, 29 Oct 2018 17:02:41 +0100 Subject: [PATCH 1646/1776] rtsp-media: Unblock all streams When unsuspending and going to PLAYING, unblock all streams instead of only those that are linked (the linked streams are the ones for which SETUP has been called). GST_FLOW_NOT_LINKED will be returned when pushing buffers on unlinked streams. This change is because playback using single-threaded demuxers like matroska-demux could be blocked if SETUP was not called for all media. Demuxers that use GstFlowCombiner (including gstoggdemux, gstavidemux, gstflvdemux, qtdemux, and matroska-demux) will handle GST_FLOW_NOT_LINKED automatically. Fixes #39 --- gst/rtsp-server/rtsp-media.c | 16 ++++++++-------- tests/check/gst/rtspserver.c | 4 ++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 45463f6652..345559d7c3 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2635,15 +2635,15 @@ media_streams_set_blocked (GstRTSPMedia * media, gboolean blocked) static void stream_unblock (GstRTSPStream * stream, GstRTSPMedia * media) { - gst_rtsp_stream_unblock_linked (stream); + gst_rtsp_stream_set_blocked (stream, FALSE); } static void -media_unblock_linked (GstRTSPMedia * media) +media_unblock (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; - GST_DEBUG ("media %p unblocking linked streams", media); + GST_DEBUG ("media %p unblocking streams", media); /* media is not blocked any longer, as it contains active streams, * streams that are complete */ priv->blocked = FALSE; @@ -4393,8 +4393,8 @@ default_unsuspend (GstRTSPMedia * media) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); /* at this point the media pipeline has been updated and contain all * specific transport parts: all active streams contain at least one sink - * element and it's safe to unblock any blocked streams that are active */ - media_unblock_linked (media); + * element and it's safe to unblock all blocked streams */ + media_unblock (media); } else { /* streams are not blocked and media is suspended from PAUSED */ gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); @@ -4414,8 +4414,8 @@ default_unsuspend (GstRTSPMedia * media) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); /* at this point the media pipeline has been updated and contain all * specific transport parts: all active streams contain at least one sink - * element and it's safe to unblock any blocked streams that are active */ - media_unblock_linked (media); + * element and it's safe to unblock all blocked streams */ + media_unblock (media); if (!start_preroll (media)) goto start_failed; @@ -4507,7 +4507,7 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) } else { if (state == GST_STATE_PLAYING) /* make sure pads are not blocking anymore when going to PLAYING */ - media_unblock_linked (media); + media_unblock (media); if (state == GST_STATE_PAUSED) { set_state_ret = set_state (media, state); diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index da6df2d72f..0a0eec4351 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -30,10 +30,14 @@ #include "rtsp-server.h" +#define ERRORIGNORE "errorignore ignore-error=false ignore-notlinked=true " \ + "ignore-notnegotiated=false convert-to=ok" #define VIDEO_PIPELINE "videotestsrc ! " \ + ERRORIGNORE " ! " \ "video/x-raw,width=352,height=288 ! " \ "rtpgstpay name=pay0 pt=96" #define AUDIO_PIPELINE "audiotestsrc ! " \ + ERRORIGNORE " ! " \ "audio/x-raw,rate=8000 ! " \ "rtpgstpay name=pay1 pt=97" From f1d2a0cae9a791ce07c753faaf82a6cdefecd373 Mon Sep 17 00:00:00 2001 From: Adam x Nilsson Date: Tue, 17 Sep 2019 13:45:57 +0200 Subject: [PATCH 1647/1776] rtsp-media: Use lock in gst_rtsp_media_is_receive_only --- gst/rtsp-server/rtsp-media.c | 65 ++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 345559d7c3..c0da7202d0 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -739,6 +739,26 @@ default_create_rtpbin (GstRTSPMedia * media) return rtpbin; } +/* Must be called with priv->lock */ +static gboolean +is_receive_only (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + gboolean receive_only = TRUE; + guint i; + + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + if (gst_rtsp_stream_is_sender (stream) || + !gst_rtsp_stream_is_receiver (stream)) { + receive_only = FALSE; + break; + } + } + + return receive_only; +} + /* must be called with state lock */ static void check_seekable (GstRTSPMedia * media) @@ -746,8 +766,9 @@ check_seekable (GstRTSPMedia * media) GstQuery *query; GstRTSPMediaPrivate *priv = media->priv; + g_mutex_lock (&priv->lock); /* Update the seekable state of the pipeline in case it changed */ - if (gst_rtsp_media_is_receive_only (media)) { + if (is_receive_only (media)) { /* TODO: Seeking for "receive-only"? */ priv->seekable = -1; } else { @@ -759,6 +780,7 @@ check_seekable (GstRTSPMedia * media) if (gst_rtsp_stream_get_publish_clock_mode (stream) == GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET) { priv->seekable = -1; + g_mutex_unlock (&priv->lock); return; } } @@ -785,7 +807,7 @@ check_seekable (GstRTSPMedia * media) } GST_DEBUG_OBJECT (media, "seekable:%" G_GINT64_FORMAT, priv->seekable); - + g_mutex_unlock (&priv->lock); gst_query_unref (query); } @@ -807,7 +829,7 @@ check_complete (GstRTSPMedia * media) return FALSE; } -/* must be called with state lock */ +/* must be called with state lock and private lock */ static void collect_media_stats (GstRTSPMedia * media) { @@ -815,8 +837,9 @@ collect_media_stats (GstRTSPMedia * media) gint64 position = 0, stop = -1; if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED && - priv->status != GST_RTSP_MEDIA_STATUS_PREPARING) + priv->status != GST_RTSP_MEDIA_STATUS_PREPARING) { return; + } priv->range.unit = GST_RTSP_RANGE_NPT; @@ -876,8 +899,9 @@ collect_media_stats (GstRTSPMedia * media) priv->range.max.seconds = ((gdouble) stop) / GST_SECOND; priv->range_stop = stop; } - + g_mutex_unlock (&priv->lock); check_seekable (media); + g_mutex_lock (&priv->lock); } } @@ -2509,9 +2533,8 @@ gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play, priv->status != GST_RTSP_MEDIA_STATUS_SUSPENDED) goto not_prepared; - g_mutex_lock (&priv->lock); - /* Update the range value with current position/duration */ + g_mutex_lock (&priv->lock); collect_media_stats (media); /* make copy */ @@ -3056,7 +3079,9 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) && gst_rtsp_media_is_receive_only (media) && old == GST_STATE_READY && new == GST_STATE_PAUSED) { GST_INFO ("%p: went to PAUSED, prepared now", media); + g_mutex_lock (&priv->lock); collect_media_stats (media); + g_mutex_unlock (&priv->lock); if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); @@ -3138,7 +3163,9 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) if (priv->blocked && media_streams_blocking (media) && priv->no_more_pads_pending == 0) { GST_DEBUG_OBJECT (GST_MESSAGE_SRC (message), "media is blocking"); + g_mutex_lock (&priv->lock); collect_media_stats (media); + g_mutex_unlock (&priv->lock); if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); @@ -4632,7 +4659,7 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, /* we just activated the first media, do the playing state change */ if (old_active == 0 && activate) do_state = TRUE; - /* if we have no more active media and prepare count is not indicate + /* if we have no more active media and prepare count is not indicate * that there are new session/sessions ongoing, * do the downward state changes */ else if (priv->n_active == 0 && priv->prepare_count <= 1) @@ -4653,9 +4680,11 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, /* remember where we are */ if (state != GST_STATE_NULL && (state == GST_STATE_PAUSED || - old_active != priv->n_active)) + old_active != priv->n_active)) { + g_mutex_lock (&priv->lock); collect_media_stats (media); - + g_mutex_unlock (&priv->lock); + } g_rec_mutex_unlock (&priv->state_lock); return TRUE; @@ -4831,17 +4860,11 @@ gboolean gst_rtsp_media_is_receive_only (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; - gboolean receive_only = TRUE; - guint i; + gboolean receive_only; - for (i = 0; i < priv->streams->len; i++) { - GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); - if (gst_rtsp_stream_is_sender (stream) || - !gst_rtsp_stream_is_receiver (stream)) { - receive_only = FALSE; - break; - } - } + g_mutex_lock (&priv->lock); + receive_only = is_receive_only (media); + g_mutex_unlock (&priv->lock); return receive_only; } @@ -4850,7 +4873,7 @@ gst_rtsp_media_is_receive_only (GstRTSPMedia * media) * gst_rtsp_media_has_completed_sender: * * See gst_rtsp_stream_is_complete(), gst_rtsp_stream_is_sender(). - * + * * Returns: whether @media has at least one complete sender stream. * Since: 1.18 */ From 19f9373113d70875d625e01c7f415d6b9982cbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Mon, 7 Oct 2019 10:07:54 +0200 Subject: [PATCH 1648/1776] rtspserver: Remove memleak in test test_double_play --- tests/check/gst/rtspserver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 0a0eec4351..82d007f9f7 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -2589,6 +2589,8 @@ GST_START_TEST (test_double_play) session) == GST_RTSP_STS_OK); /* clean up and iterate so the clean-up can finish */ + g_object_unref (rtp_socket); + g_object_unref (rtcp_socket); g_free (session); gst_rtsp_transport_free (video_transport); gst_rtsp_transport_free (audio_transport); From 3ff0ca988749c897af892281a7710a69b3f14060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Mon, 7 Oct 2019 10:14:52 +0200 Subject: [PATCH 1649/1776] media: remove memleak in test test_media_seek --- tests/check/gst/media.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 8a41854baa..2cb2ba6d52 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -115,6 +115,8 @@ GST_START_TEST (test_media_seek) fail_unless (rate == 1.5); fail_unless (applied_rate == 1.0); + gst_rtsp_range_free (range); + /* seeking with rate set to -2.0 should result in rate == -2.0 */ fail_unless (gst_rtsp_range_parse ("npt=10-5", &range) == GST_RTSP_OK); fail_unless (gst_rtsp_media_seek_trickmode (media, range, From e1760eeb5113202bff35c7aa3a9af7298bc395eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Mon, 7 Oct 2019 10:27:36 +0200 Subject: [PATCH 1650/1776] client: fix test mem leak in attach_rate_tweaking_probe --- tests/check/gst/client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index c860417bc7..dd7f5eeba2 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -1847,6 +1847,7 @@ attach_rate_tweaking_probe (void) gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, rate_tweaking_probe, NULL, NULL); + gst_object_unref (srcpad); } static void From 6b3bd23e40e0194fabebde18885377081139b9fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 24 May 2019 14:32:50 +0200 Subject: [PATCH 1651/1776] Remove autotools build Replaced by Meson. Maybe we can now use the meson pkgconfig module for .pc files? (Does it support uninstalled now?) --- .gitignore | 71 +------ .gitmodules | 3 - Makefile.am | 95 ---------- autogen.sh | 124 ------------ common | 1 - configure.ac | 364 ------------------------------------ docs/.gitignore | 1 - examples/.gitignore | 17 -- examples/Makefile.am | 44 ----- gst/Makefile.am | 1 - gst/rtsp-server/.gitignore | 2 - gst/rtsp-server/Makefile.am | 136 -------------- gst/rtsp-sink/Makefile.am | 17 -- pkgconfig/.gitignore | 1 - pkgconfig/Makefile.am | 25 --- tests/.gitignore | 1 - tests/Makefile.am | 11 -- tests/check/Makefile.am | 64 ------- 18 files changed, 2 insertions(+), 976 deletions(-) delete mode 100644 .gitmodules delete mode 100644 Makefile.am delete mode 100755 autogen.sh delete mode 160000 common delete mode 100644 configure.ac delete mode 100644 docs/.gitignore delete mode 100644 examples/.gitignore delete mode 100644 examples/Makefile.am delete mode 100644 gst/Makefile.am delete mode 100644 gst/rtsp-server/.gitignore delete mode 100644 gst/rtsp-server/Makefile.am delete mode 100644 gst/rtsp-sink/Makefile.am delete mode 100644 pkgconfig/.gitignore delete mode 100644 pkgconfig/Makefile.am delete mode 100644 tests/.gitignore delete mode 100644 tests/Makefile.am delete mode 100644 tests/check/Makefile.am diff --git a/.gitignore b/.gitignore index 6aaeba18e7..7fa61a72f3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,71 +1,4 @@ -*.[oa] -*.pyc -*.gcda -*.gcno -*.la -*.lo -*.loT -*.sw[po] -*.tar.* *~ -*.gc?? -.deps -.libs -ABOUT-NLS -INSTALL -Makefile -Makefile.in -aclocal.m4 -autom4te.cache -autoregen.sh -compile -config.guess -config.h -config.h.in -config.log -config.rpath -config.status -config.sub -configure -depcomp -install-sh -libtool -ltmain.sh -missing -stamp-h1 -tags -stamp-h.in -.dirstamp - -/m4/*m4 - -/gst/rtsp-server/GstRtspServer-1.0.gir -/gst/rtsp-server/GstRtspServer-1.0.typelib - -/examples/test-multicast -/examples/test-multicast2 -/examples/test-auth-digest -/examples/test-video-disconnect - -/test-driver -/tests/check/gst/*.log -/tests/check/gst/*.trs -/tests/check/test-suite.log -/tests/check/gst/addresspool -/tests/check/gst/client -/tests/check/gst/media -/tests/check/gst/mediafactory -/tests/check/gst/mountpoints -/tests/check/gst/permissions -/tests/check/gst/rtspserver -/tests/check/gst/sessionmedia -/tests/check/gst/sessionpool -/tests/check/gst/stream -/tests/check/gst/threadpool -/tests/check/gst/token -/tests/check/gst/rtspclientsink -/tests/check/test-registry.reg -/tests/test-reuse - -/po /build +/_build +/b/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 0ab838765a..0000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "common"] - path = common - url = https://gitlab.freedesktop.org/gstreamer/common.git diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 7b92d927fc..0000000000 --- a/Makefile.am +++ /dev/null @@ -1,95 +0,0 @@ -if BUILD_EXAMPLES -SUBDIRS_EXAMPLES = examples -else -SUBDIRS_EXAMPLES = -endif - -if BUILD_TESTS -SUBDIRS_TESTS = tests -else -SUBDIRS_TESTS = -endif - -SUBDIRS = \ - gst \ - common \ - pkgconfig \ - $(SUBDIRS_EXAMPLES) \ - $(SUBDIRS_TESTS) - -DIST_SUBDIRS = gst common pkgconfig examples tests - -EXTRA_DIST = \ - ChangeLog autogen.sh depcomp \ - AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \ - gst-rtsp-server.doap \ - $(shell find "$(top_srcdir)" -type f -name meson.build ! -path "$(top_srcdir)/$(PACKAGE_TARNAME)-*" ) \ - meson_options.txt - -ACLOCAL_AMFLAGS = -I m4 -I common/m4 - -DISTCLEANFILES = _stdint.h - -include $(top_srcdir)/common/release.mak -include $(top_srcdir)/common/po.mak - -include $(top_srcdir)/common/coverage/lcov.mak - -check-valgrind: - $(MAKE) -C tests/check check-valgrind - -if HAVE_CHECK -check-torture: - $(MAKE) -C tests/check torture -build-checks: - $(MAKE) -C tests/check build-checks -else -check-torture: - true -build-checks: - true -endif - -# cruft: plugins that have been merged or moved or renamed -CRUFT_FILES = \ - $(top_builddir)/gst-rtsp.spec \ - $(top_builddir)/common/shave \ - $(top_builddir)/common/shave-libtool \ - $(top_builddir)/common/m4/codeset.m4 \ - $(top_builddir)/common/m4/gettext.m4 \ - $(top_builddir)/common/m4/glibc2.m4 \ - $(top_builddir)/common/m4/glibc21.m4 \ - $(top_builddir)/common/m4/iconv.m4 \ - $(top_builddir)/common/m4/intdiv0.m4 \ - $(top_builddir)/common/m4/intl.m4 \ - $(top_builddir)/common/m4/intldir.m4 \ - $(top_builddir)/common/m4/intlmacosx.m4 \ - $(top_builddir)/common/m4/intmax.m4 \ - $(top_builddir)/common/m4/inttypes-pri.m4 \ - $(top_builddir)/common/m4/inttypes_h.m4 \ - $(top_builddir)/common/m4/lcmessage.m4 \ - $(top_builddir)/common/m4/lib-ld.m4 \ - $(top_builddir)/common/m4/lib-link.m4 \ - $(top_builddir)/common/m4/lib-prefix.m4 \ - $(top_builddir)/common/m4/libtool.m4 \ - $(top_builddir)/common/m4/lock.m4 \ - $(top_builddir)/common/m4/longlong.m4 \ - $(top_builddir)/common/m4/ltoptions.m4 \ - $(top_builddir)/common/m4/ltsugar.m4 \ - $(top_builddir)/common/m4/ltversion.m4 \ - $(top_builddir)/common/m4/lt~obsolete.m4 \ - $(top_builddir)/common/m4/nls.m4 \ - $(top_builddir)/common/m4/po.m4 \ - $(top_builddir)/common/m4/printf-posix.m4 \ - $(top_builddir)/common/m4/progtest.m4 \ - $(top_builddir)/common/m4/size_max.m4 \ - $(top_builddir)/common/m4/stdint_h.m4 \ - $(top_builddir)/common/m4/uintmax_t.m4 \ - $(top_builddir)/common/m4/visibility.m4 \ - $(top_builddir)/common/m4/wchar_t.m4 \ - $(top_builddir)/common/m4/wint_t.m4 \ - $(top_builddir)/common/m4/xsize.m4 - -include $(top_srcdir)/common/cruft.mak - -all-local: check-cruft diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index 2d4b05b1cd..0000000000 --- a/autogen.sh +++ /dev/null @@ -1,124 +0,0 @@ -#!/bin/sh -# -# gst-rtsp-server autogen.sh -# -# Run this to generate all the initial makefiles, etc. -# -# This file has been generated from common/autogen.sh.in via common/update-autogen - - -test -n "$srcdir" || srcdir=`dirname "$0"` -test -n "$srcdir" || srcdir=. - -olddir=`pwd` -cd "$srcdir" - -package=gst-rtsp-server -srcfile=gst-rtsp-server.doap - -# Make sure we have common -if test ! -f common/gst-autogen.sh; -then - echo "+ Setting up common submodule" - git submodule init -fi -git submodule update - -# source helper functions -if test ! -f common/gst-autogen.sh; -then - echo There is something wrong with your source tree. - echo You are missing common/gst-autogen.sh - exit 1 -fi -. common/gst-autogen.sh - -# install pre-commit hook for doing clean commits -if test ! \( -x .git/hooks/pre-commit -a -L .git/hooks/pre-commit \); -then - rm -f .git/hooks/pre-commit - if ! ln -s ../../common/hooks/pre-commit.hook .git/hooks/pre-commit 2> /dev/null - then - echo "Failed to create commit hook symlink, copying instead ..." - cp common/hooks/pre-commit.hook .git/hooks/pre-commit - fi -fi - -# GNU gettext automake support doesn't get along with git. -# https://bugzilla.gnome.org/show_bug.cgi?id=661128 -if test -d po ; then - touch -t 200001010000 po/gst-rtsp-server-1.0.pot -fi - -CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc' - -if test "x$package" = "xgstreamer"; then - CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --enable-failing-tests --enable-poisoning" -elif test "x$package" = "xgst-plugins-bad"; then - CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-player-tests" -fi - -autogen_options $@ - -printf "+ check for build tools" -if test -z "$NOCHECK"; then - echo - - printf " checking for autoreconf ... " - echo - which "autoreconf" 2>/dev/null || { - echo "not found! Please install the autoconf package." - exit 1 - } - - printf " checking for pkg-config ... " - echo - which "pkg-config" 2>/dev/null || { - echo "not found! Please install pkg-config." - exit 1 - } -else - echo ": skipped version checks" -fi - -# if no arguments specified then this will be printed -if test -z "$*" && test -z "$NOCONFIGURE"; then - echo "+ checking for autogen.sh options" - echo " This autogen script will automatically run ./configure as:" - echo " ./configure $CONFIGURE_DEF_OPT" - echo " To pass any additional options, please specify them on the $0" - echo " command line." -fi - -toplevel_check $srcfile - -# autopoint -if test -d po && grep ^AM_GNU_GETTEXT_VERSION configure.ac >/dev/null ; then - tool_run "autopoint" "--force" -fi - -# aclocal -if test -f acinclude.m4; then rm acinclude.m4; fi - -autoreconf --force --install || exit 1 - -test -n "$NOCONFIGURE" && { - echo "+ skipping configure stage for package $package, as requested." - echo "+ autogen.sh done." - exit 0 -} - -cd "$olddir" - -echo "+ running configure ... " -test ! -z "$CONFIGURE_DEF_OPT" && echo " default flags: $CONFIGURE_DEF_OPT" -test ! -z "$CONFIGURE_EXT_OPT" && echo " external flags: $CONFIGURE_EXT_OPT" -echo - -echo "$srcdir/configure" $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT -"$srcdir/configure" $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT || { - echo " configure failed" - exit 1 -} - -echo "Now type 'make' to compile $package." diff --git a/common b/common deleted file mode 160000 index 59cb678164..0000000000 --- a/common +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 59cb678164719ff59dcf6c8b93df4617a1075d11 diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 154164af92..0000000000 --- a/configure.ac +++ /dev/null @@ -1,364 +0,0 @@ -AC_PREREQ(2.69) -dnl initialize autoconf -dnl when going to/from release please set the nano (fourth number) right ! -dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT([GStreamer RTSP Server Library], [1.17.0.1], - [http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer], - [gst-rtsp-server]) -AG_GST_INIT - -dnl initialize automake -AM_INIT_AUTOMAKE([-Wno-portability 1.14 no-dist-gzip dist-xz tar-ustar subdir-objects]) - -dnl define PACKAGE_VERSION_* variables -AS_VERSION - -dnl check if this is a release version -AS_NANO(GST_GIT="no", GST_GIT="yes") - -dnl can autoconf find the source ? -AC_CONFIG_SRCDIR([gst/rtsp-server/rtsp-server.c]) - -dnl define the output header for config -AC_CONFIG_HEADERS([config.h]) - -dnl AM_MAINTAINER_MODE only provides the option to configure to enable it -AM_MAINTAINER_MODE([enable]) - -dnl sets host_* variables -AC_CANONICAL_HOST - -dnl use pretty build output with automake >= 1.11 -m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])], - [AM_DEFAULT_VERBOSITY=1 - AC_SUBST(AM_DEFAULT_VERBOSITY)]) - -dnl our libraries and install dirs use major.minor as a version -dnl GST_API_VERSION=$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR -dnl we override it here if we need to for the release candidate of new series -GST_API_VERSION=1.0 -AC_SUBST(GST_API_VERSION) - -dnl CURRENT, REVISION, AGE -dnl - library source changed -> increment REVISION -dnl - interfaces added/removed/changed -> increment CURRENT, REVISION = 0 -dnl - interfaces added -> increment AGE -dnl - interfaces removed -> AGE = 0 -dnl -dnl Keep CURRENT as MINOR * 100 + MICRO -dnl Ex : 1.0.0 => 0 -dnl 1.0.3 => 3 -dnl 1.1.0 => 100 -dnl 1.2.5 => 205 -dnl 1.10.9 (who knows) => 1009 -dnl -dnl sets GST_LT_LDFLAGS -AS_LIBTOOL(GST, 1700, 0, 1700) - -dnl *** required versions of GStreamer stuff *** -GST_REQ=1.17.0.1 -GSTPB_REQ=1.17.0.1 -GSTPG_REQ=1.17.0.1 -GSTPD_REQ=1.17.0.1 - -dnl *** autotools stuff **** - -dnl allow for different autotools -AS_AUTOTOOLS_ALTERNATE - -dnl Add parameters for aclocal -AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4") -AC_CONFIG_MACRO_DIR([m4]) - -dnl set up gettext -dnl the version check needs to stay here because autopoint greps for it -#AM_GNU_GETTEXT_VERSION([0.17]) -#AM_GNU_GETTEXT([external]) -#AG_GST_GETTEXT([gst-rtsp-server-$GST_API_VERSION]) - -dnl *** check for arguments to configure *** - -AG_GST_ARG_DISABLE_FATAL_WARNINGS -AG_GST_ARG_ENABLE_EXTRA_CHECKS - -AG_GST_ARG_DEBUG -AG_GST_ARG_VALGRIND -AG_GST_ARG_GCOV -AG_GST_ARG_WITH_PKG_CONFIG_PATH -AG_GST_ARG_WITH_PACKAGE_NAME -AG_GST_ARG_WITH_PACKAGE_ORIGIN - -AG_GST_ARG_EXAMPLES - -AG_GST_PKG_CONFIG_PATH - -AG_GST_SET_PACKAGE_RELEASE_DATETIME_WITH_NANO([$PACKAGE_VERSION_NANO], - ["${srcdir}/gst-rtsp-server.doap"], - [$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR.$PACKAGE_VERSION_MICRO]) - -dnl building of tests -AC_ARG_ENABLE(tests, - AS_HELP_STRING([--disable-tests],[disable building test apps]), - [ - case "${enableval}" in - yes) BUILD_TESTS=yes ;; - no) BUILD_TESTS=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --disable-tests) ;; - esac - ], -[BUILD_TESTS=yes]) dnl Default value -AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes") - -dnl *** checks for platform *** - -dnl * hardware/architecture * - -dnl *** checks for programs *** - -dnl find a compiler -AC_PROG_CC -AC_PROG_CC_STDC - -dnl check if the compiler supports '-c' and '-o' options -AM_PROG_CC_C_O - -dnl find an assembler -AM_PROG_AS - -AC_PATH_PROG(VALGRIND_PATH, valgrind, no) -AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") - -dnl check for gobject-introspection -GOBJECT_INTROSPECTION_CHECK([1.31.1]) - -dnl *** checks for libraries *** - -dnl check for pthreads -AX_PTHREAD - -dnl *** checks for header files *** - -dnl *** checks for types/defines *** - -dnl *** checks for structures *** - -dnl *** checks for compiler characteristics *** - -dnl *** checks for library functions *** - -dnl *** checks for dependancy libraries *** - -dnl GLib is required -GLIB_REQ=2.44.0 -AC_SUBST([GLIB_REQ]) -AG_GST_GLIB_CHECK([$GLIB_REQ]) - -dnl checks for gstreamer -dnl uninstalled is selected preferentially -- see pkg-config(1) -AG_GST_CHECK_GST($GST_API_VERSION, [$GST_REQ], [yes]) - -GST_TOOLS_DIR=`$PKG_CONFIG --variable=toolsdir gstreamer-$GST_API_VERSION` -if test -z $GST_TOOLS_DIR; then - AC_MSG_ERROR([no tools dir defined in GStreamer pkg-config file; core upgrade needed.]) -fi -AC_SUBST(GST_TOOLS_DIR) - -GST_PLUGINS_DIR=`$PKG_CONFIG gstreamer-$GST_API_VERSION --variable pluginsdir` -AC_SUBST(GST_PLUGINS_DIR) -AC_MSG_NOTICE(Using GStreamer Core Plugins in $GST_PLUGINS_DIR) - -AG_GST_CHECK_GST_BASE($GST_API_VERSION, [$GST_REQ], [yes]) - -AG_GST_CHECK_GST_NET($GST_API_VERSION, [$GST_REQ], yes) - -AG_GST_CHECK_GST_PLUGINS_BASE($GST_API_VERSION, [$GSTPB_REQ], [yes]) - -dnl check for uninstalled plugin directories for unit tests -AG_GST_CHECK_UNINSTALLED_SETUP([ - AG_GST_CHECK_GST_PLUGINS_GOOD($GST_API_VERSION, [$GSTPB_REQ]) - AG_GST_CHECK_GST_PLUGINS_BAD($GST_API_VERSION, [$GSTPB_REQ]) -]) - -AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) -AM_CONDITIONAL(HAVE_CHECK, test "x$HAVE_GST_CHECK" = "xyes") - -dnl Check for -Bsymbolic-functions linker flag used to avoid -dnl intra-library PLT jumps, if available. -AC_ARG_ENABLE(Bsymbolic, - [AS_HELP_STRING([--disable-Bsymbolic],[avoid linking with -Bsymbolic])],, - [SAVED_LDFLAGS="${LDFLAGS}" SAVED_LIBS="${LIBS}" - AC_MSG_CHECKING([for -Bsymbolic-functions linker flag]) - LDFLAGS=-Wl,-Bsymbolic-functions - LIBS= - AC_TRY_LINK([], [return 0], - AC_MSG_RESULT(yes) - enable_Bsymbolic=yes, - AC_MSG_RESULT(no) - enable_Bsymbolic=no) - LDFLAGS="${SAVED_LDFLAGS}" LIBS="${SAVED_LIBS}"]) - -dnl *** set variables based on configure arguments *** - -dnl set license and copyright notice -GST_LICENSE="LGPL" -AC_DEFINE_UNQUOTED(GST_LICENSE, "$GST_LICENSE", [GStreamer license]) -AC_SUBST(GST_LICENSE) - -dnl set location of plugin directory -AG_GST_SET_PLUGINDIR - -dnl set release date/time (and check that release version is in doap file) -AG_GST_SET_PACKAGE_RELEASE_DATETIME_WITH_NANO([$PACKAGE_VERSION_NANO], - ["${srcdir}/gst-rtsp-server.doap"], - [$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR.$PACKAGE_VERSION_MICRO]) - -# set by AG_GST_PARSE_SUBSYSTEM_DISABLES above -dnl make sure it doesn't complain about unused variables if debugging is disabled -NO_WARNINGS="" -AG_GST_CHECK_GST_DEBUG_DISABLED([NO_WARNINGS="-Wno-unused"], [NO_WARNINGS=""]) - -dnl define an ERROR_CFLAGS Makefile variable -AG_GST_SET_ERROR_CFLAGS($FATAL_WARNINGS, [-Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wundef -Wwrite-strings -Wformat-nonliteral -Wformat-security -Wold-style-definition -Winit-self -Wmissing-include-dirs -Waddress -Waggregate-return -Wno-multichar -Wnested-externs $NO_WARNINGS]) - -dnl define correct level for debugging messages -AG_GST_SET_LEVEL_DEFAULT($GST_GIT) - -dnl used in examples -AG_GST_DEFAULT_ELEMENTS - -dnl *** finalize CFLAGS, LDFLAGS, LIBS - -dnl Overview: -dnl GST_OPTION_CFLAGS: common flags for profiling, debugging, errors, ... -dnl GST_*: flags shared by built objects to link against GStreamer -dnl GST_ALL_LDFLAGS: linker flags shared by all -dnl GST_LIB_LDFLAGS: additional linker flags for all libaries -dnl GST_LT_LDFLAGS: library versioning of our libraries -dnl GST_PLUGIN_LDFLAGS: flags to be used for all plugins - -dnl GST_OPTION_CFLAGS -if test "x$USE_DEBUG" = xyes; then - PROFILE_CFLAGS="-g" -fi -AC_SUBST(PROFILE_CFLAGS) - -# GST_DISABLE_DEPRECATED: hide the visibility of deprecated -# functionality from the API that gstreamer uses -# GST_REMOVE_DEPRECATED: don't compile deprecated functionality (breaks ABI) -if test "x$PACKAGE_VERSION_NANO" = "x1"; then - dnl Define _only_ when compiling from git (not for pre-releases or releases) - DEPRECATED_CFLAGS="-DGST_DISABLE_DEPRECATED" -else - DEPRECATED_CFLAGS="" -fi -AC_SUBST(DEPRECATED_CFLAGS) - -VISIBILITY_CFLAGS="" -AS_COMPILER_FLAG([-fvisibility=hidden], [ - VISIBILITY_CFLAGS="-fvisibility=hidden" - AC_DEFINE(GST_API_EXPORT, [extern __attribute__ ((visibility ("default")))], [public symbol export define]) -], [ - VISIBILITY_CFLAGS="" - AC_DEFINE(GST_API_EXPORT, [extern], [public symbol export define]) -]) -AC_SUBST(VISIBILITY_CFLAGS) - -dnl disable strict aliasing -AS_COMPILER_FLAG([-fno-strict-aliasing], [EXTRA_CFLAGS="-fno-strict-aliasing"]) -AC_SUBST(EXTRA_CFLAGS) - -dnl every flag in GST_OPTION_CFLAGS can be overridden at make time -GST_OPTION_CFLAGS="\$(WARNING_CFLAGS) \$(ERROR_CFLAGS) \$(DEBUG_CFLAGS) \$(PROFILE_CFLAGS) \$(GCOV_CFLAGS) \$(OPT_CFLAGS) \$(DEPRECATED_CFLAGS)" -AC_SUBST(GST_OPTION_CFLAGS) - -dnl FIXME: do we want to rename to GST_ALL_* ? -dnl prefer internal headers to already installed ones -dnl add GST_OPTION_CFLAGS, but overridable -GST_CFLAGS="$GST_CFLAGS $EXTRA_CFLAGS \$(GST_STATIC_CFLAGS) \$(GST_OPTION_CFLAGS) \$(VISIBILITY_CFLAGS)" -AC_SUBST(GST_CFLAGS) -AC_SUBST(GST_LIBS) - -dnl GST_ALL_* -dnl vars common to for all internal objects (core libs, elements, applications) -dnl CFLAGS: -dnl - src and build dirs need to be added because every piece that gets built -dnl will need the GStreamer source and generated headers -GST_ALL_CFLAGS="-I\$(top_srcdir) -I\$(top_builddir) $GST_PLUGINS_BASE_CFLAGS $GST_CFLAGS \$(GST_OPTION_CFLAGS)" -AC_SUBST([GST_ALL_CFLAGS]) - -dnl FIXME: check if LTLIBINTL is needed everywhere -dnl I presume it is given that it contains the symbols that _() stuff maps to -GST_ALL_LIBS="$GST_LIBS $LTLIBINTL \$(GCOV_LIBS)" -AC_SUBST([GST_ALL_LIBS]) - -dnl LDFLAGS really should only contain flags, not libs - they get added before -dnl whatevertarget_LIBS and -L flags here affect the rest of the linking -GST_ALL_LDFLAGS="-no-undefined" -if test "x${enable_Bsymbolic}" = "xyes"; then - GST_ALL_LDFLAGS="$GST_ALL_LDFLAGS -Wl,-Bsymbolic-functions" -fi - -AC_SUBST(GST_ALL_LDFLAGS) - -dnl GST_LIB_LDFLAGS -dnl linker flags shared by all libraries -dnl LDFLAGS modifier defining exported symbols from built libraries -GST_LIB_LDFLAGS="" -AC_SUBST(GST_LIB_LDFLAGS) - -dnl GST_OBJ_* -dnl default vars for all internal objects built on libgstrtspserver -dnl includes GST_ALL_* -GST_OBJ_CFLAGS="\$(GST_ALL_CFLAGS)" -AC_SUBST([GST_OBJ_CFLAGS]) -GST_OBJ_LIBS="\$(top_builddir)/gst/rtsp-server/libgstrtspserver-$GST_API_VERSION.la \$(GST_ALL_LIBS)" -AC_SUBST([GST_OBJ_LIBS]) - -dnl If only building static libraries, define GST_STATIC_COMPILATION. This is -dnl needed only on Windows, but it doesn't hurt to have it everywhere. -if test x$enable_static = xyes -a x$enable_shared = xno; then - GST_STATIC_CFLAGS="-DGST_STATIC_COMPILATION" -fi -AC_SUBST(GST_STATIC_CFLAGS) - -GST_PLUGIN_LDFLAGS="-module -avoid-version $GST_ALL_LDFLAGS" -AC_SUBST(GST_PLUGIN_LDFLAGS) - -PKG_CHECK_MODULES(LIBCGROUP, libcgroup >= 0.26, HAVE_LIBCGROUP="yes", HAVE_LIBCGROUP="no") -AC_SUBST(LIBCGROUP_CFLAGS) -AC_SUBST(LIBCGROUP_LIBS) -AM_CONDITIONAL(HAVE_LIBCGROUP, test "x$HAVE_LIBCGROUP" = "xyes") - -dnl this really should only contain flags, not libs - they get added before -dnl whatevertarget_LIBS and -L flags here affect the rest of the linking - -dnl *** output files *** - -dnl keep this alphabetic per directory, please -AC_CONFIG_FILES([ -Makefile -common/Makefile -common/m4/Makefile -gst/Makefile -gst/rtsp-server/Makefile -gst/rtsp-sink/Makefile -examples/Makefile -tests/Makefile -tests/check/Makefile -pkgconfig/Makefile -pkgconfig/gstreamer-rtsp-server.pc -pkgconfig/gstreamer-rtsp-server-uninstalled.pc -]) -AC_OUTPUT - -echo " - -Configuration - Version : ${VERSION} - Source code location : ${srcdir} - Prefix : ${prefix} - Compiler : ${CC} - CGroups example : ${HAVE_LIBCGROUP} - -gst-rtsp-server configured. Type 'make' to build. -" diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index e5a7abe44d..0000000000 --- a/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -version.entities diff --git a/examples/.gitignore b/examples/.gitignore deleted file mode 100644 index 4a65f7420c..0000000000 --- a/examples/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -test-appsrc -test-appsrc2 -test-cgroups -test-launch -test-mp4 -test-ogg -test-readme -test-record -test-record-auth -test-sdp -test-video -test-video-rtx -test-uri -test-auth -test-netclock -test-netclock-client -test-onvif-backchannel diff --git a/examples/Makefile.am b/examples/Makefile.am deleted file mode 100644 index 6cbe72a6d3..0000000000 --- a/examples/Makefile.am +++ /dev/null @@ -1,44 +0,0 @@ -noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \ - test-launch test-sdp test-uri test-auth test-auth-digest \ - test-multicast test-multicast2 test-appsrc test-appsrc2 \ - test-video-rtx test-record test-record-auth \ - test-netclock test-netclock-client \ - test-onvif-backchannel test-video-disconnect - -#INCLUDES = -I$(top_srcdir) -I$(srcdir) - -AM_CFLAGS = $(GST_OBJ_CFLAGS) -LDADD = $(GST_OBJ_LIBS) $(GIO_LIBS) - -if HAVE_LIBCGROUP -noinst_PROGRAMS += test-cgroups -LDADD += $(LIBCGROUP_LIBS) -endif - -test_appsrc2_CFLAGS = \ - $(AM_CFLAGS) \ - $(GST_PLUGINS_BASE_CFLAGS) -test_appsrc2_LDADD = \ - $(LDADD) \ - $(GST_PLUGINS_BASE_LIBS) -lgstapp-1.0 -test_netclock_CFLAGS = \ - $(AM_CFLAGS) \ - $(GST_NET_CFLAGS) -test_netclock_LDADD = \ - $(LDADD) \ - $(GST_NET_LIBS) - -test_netclock_client_CFLAGS = \ - $(AM_CFLAGS) \ - $(GST_NET_CFLAGS) -test_netclock_client_LDADD = \ - $(LDADD) \ - $(GST_NET_LIBS) - -test_onvif_backchannel_CFLAGS = \ - $(AM_CFLAGS) \ - $(GST_PLUGINS_BASE_CFLAGS) -test_onvif_backchannel_LDADD = \ - $(LDADD) \ - $(GST_PLUGINS_BASE_LIBS) -lgstrtsp-1.0 -lgstsdp-1.0 - diff --git a/gst/Makefile.am b/gst/Makefile.am deleted file mode 100644 index a97a8b8db5..0000000000 --- a/gst/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = rtsp-server rtsp-sink diff --git a/gst/rtsp-server/.gitignore b/gst/rtsp-server/.gitignore deleted file mode 100644 index 6091a86a2e..0000000000 --- a/gst/rtsp-server/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -GstRtspServer-0.11.gir -GstRtspServer-0.11.typelib diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am deleted file mode 100644 index 112e529968..0000000000 --- a/gst/rtsp-server/Makefile.am +++ /dev/null @@ -1,136 +0,0 @@ -public_headers = \ - rtsp-auth.h \ - rtsp-address-pool.h \ - rtsp-context.h \ - rtsp-params.h \ - rtsp-sdp.h \ - rtsp-thread-pool.h \ - rtsp-media.h \ - rtsp-media-factory.h \ - rtsp-media-factory-uri.h \ - rtsp-mount-points.h \ - rtsp-permissions.h \ - rtsp-stream.h \ - rtsp-stream-transport.h \ - rtsp-session.h \ - rtsp-session-media.h \ - rtsp-session-pool.h \ - rtsp-token.h \ - rtsp-client.h \ - rtsp-server.h \ - rtsp-server-object.h \ - rtsp-server-prelude.h \ - rtsp-onvif-server.h \ - rtsp-onvif-client.h \ - rtsp-onvif-media-factory.h \ - rtsp-onvif-media.h - -c_sources = \ - rtsp-auth.c \ - rtsp-address-pool.c \ - rtsp-context.c \ - rtsp-params.c \ - rtsp-sdp.c \ - rtsp-thread-pool.c \ - rtsp-latency-bin.c \ - rtsp-media.c \ - rtsp-media-factory.c \ - rtsp-media-factory-uri.c \ - rtsp-mount-points.c \ - rtsp-permissions.c \ - rtsp-stream.c \ - rtsp-stream-transport.c \ - rtsp-session.c \ - rtsp-session-media.c \ - rtsp-session-pool.c \ - rtsp-token.c \ - rtsp-client.c \ - rtsp-server.c \ - rtsp-onvif-server.c \ - rtsp-onvif-client.c \ - rtsp-onvif-media-factory.c \ - rtsp-onvif-media.c - -noinst_HEADERS = \ - rtsp-latency-bin.h - -lib_LTLIBRARIES = \ - libgstrtspserver-@GST_API_VERSION@.la - -libgstrtspserver_@GST_API_VERSION@_la_SOURCES = \ - $(c_sources) - -libgstrtspserver_@GST_API_VERSION@_la_CFLAGS = \ - $(GST_PLUGINS_BASE_CFLAGS) $(GST_NET_CFLAGS) \ - $(GST_BASE_CFLAGS) $(GST_CFLAGS) -DBUILDING_GST_RTSP_SERVER -libgstrtspserver_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) -libgstrtspserver_@GST_API_VERSION@_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) $(GST_NET_LIBS) $(GST_BASE_LIBS) \ - -lgstrtp-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ \ - -lgstsdp-@GST_API_VERSION@ \ - -lgstapp-@GST_API_VERSION@ \ - $(GST_LIBS) $(GIO_LIBS) $(LIBM) - -libgstrtspserver_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/rtsp-server -libgstrtspserver_@GST_API_VERSION@include_HEADERS = $(public_headers) - -CLEANFILES = - -if HAVE_INTROSPECTION -BUILT_GIRSOURCES = GstRtspServer-@GST_API_VERSION@.gir - -gir_headers=$(patsubst %,$(srcdir)/%, $(libgstrtspserver_@GST_API_VERSION@include_HEADERS)) -gir_sources=$(patsubst %,$(srcdir)/%, $(libgstrtspserver_@GST_API_VERSION@_la_SOURCES)) - -GstRtspServer-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@GST_API_VERSION@.la - $(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \ - CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" CC="$(CC)" PKG_CONFIG="$(PKG_CONFIG)" DLLTOOL="$(DLLTOOL)" \ - $(INTROSPECTION_SCANNER) -v --namespace GstRtspServer \ - --nsversion=@GST_API_VERSION@ \ - --strip-prefix=Gst \ - --warn-all \ - -I$(top_srcdir) \ - -I$(top_builddir) \ - -DIN_GOBJECT_INTROSPECTION=1 \ - --c-include='gst/rtsp-server/rtsp-server.h' \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_API_VERSION@` \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_API_VERSION@` \ - --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-net-@GST_API_VERSION@` \ - --library=libgstrtspserver-@GST_API_VERSION@.la \ - --include=Gst-@GST_API_VERSION@ \ - --include=GstRtsp-@GST_API_VERSION@ \ - --include=GstNet-@GST_API_VERSION@ \ - --libtool="${LIBTOOL}" \ - --pkg gstreamer-@GST_API_VERSION@ \ - --pkg gstreamer-rtsp-@GST_API_VERSION@ \ - --pkg gstreamer-net-@GST_API_VERSION@ \ - --pkg-export gstreamer-rtsp-server-@GST_API_VERSION@ \ - --output $@ \ - $(gir_headers) \ - $(gir_sources) - -# INTROSPECTION_GIRDIR/INTROSPECTION_TYPELIBDIR aren't the right place to -# install anything - we need to install inside our prefix. -girdir = $(datadir)/gir-1.0 -gir_DATA = $(BUILT_GIRSOURCES) - -typelibsdir = $(libdir)/girepository-1.0/ - -typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) - -%.typelib: %.gir $(INTROSPECTION_COMPILER) - $(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \ - $(INTROSPECTION_COMPILER) \ - --includedir=$(srcdir) \ - --includedir=$(builddir) \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-@GST_API_VERSION@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-@GST_API_VERSION@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-net-@GST_API_VERSION@` \ - $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) - -CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA) -endif diff --git a/gst/rtsp-sink/Makefile.am b/gst/rtsp-sink/Makefile.am deleted file mode 100644 index f8092e5ba9..0000000000 --- a/gst/rtsp-sink/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ -plugin_LTLIBRARIES = libgstrtspclientsink.la - -libgstrtspclientsink_la_SOURCES = gstrtspclientsink.c plugin.c - -libgstrtspclientsink_la_CFLAGS = -I$(top_srcdir) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS) - -# FIXME: Hack to avoid having to add GETTEXT_PACKAGE to gst-rtsp -libgstrtspclientsink_la_CFLAGS += -D"GETTEXT_PACKAGE=gst-rtsp-server-1.0" - -libgstrtspclientsink_la_LIBADD = $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - -lgstrtp-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ \ - -lgstsdp-@GST_API_VERSION@ $(GST_NET_LIBS) $(GST_LIBS) \ - $(GIO_LIBS) -libgstrtspclientsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) - -noinst_HEADERS = gstrtspclientsink.h diff --git a/pkgconfig/.gitignore b/pkgconfig/.gitignore deleted file mode 100644 index 6fd0ef029e..0000000000 --- a/pkgconfig/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.pc diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am deleted file mode 100644 index cf36182e0d..0000000000 --- a/pkgconfig/Makefile.am +++ /dev/null @@ -1,25 +0,0 @@ -pcfiles = \ - gstreamer-rtsp-server-@GST_API_VERSION@.pc - -pcfiles_uninstalled = \ - gstreamer-rtsp-server-@GST_API_VERSION@-uninstalled.pc - -all-local: $(pcfiles) $(pcfiles_uninstalled) - -### how to generate pc files -%-@GST_API_VERSION@.pc: %.pc - cp $< $@ -%-@GST_API_VERSION@-uninstalled.pc: %-uninstalled.pc -### the uninstalled libdir is depend of the build system used so set it here -### rather than hardcoding it in the file directly. - $(AM_V_GEN) sed \ - -e "s|[@]rtspserverlibdir[@]|$(abs_top_builddir)/gst/rtsp-server/.libs|" \ - $< > $@.tmp && mv $@.tmp $@ - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = $(pcfiles) - -EXTRA_DIST = \ - gstreamer-rtsp-server.pc.in \ - gstreamer-rtsp-server-uninstalled.pc.in -CLEANFILES = $(pcfiles) $(pcfiles_uninstalled) diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index 58b8c22377..0000000000 --- a/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -test-cleanup diff --git a/tests/Makefile.am b/tests/Makefile.am deleted file mode 100644 index f653107024..0000000000 --- a/tests/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -noinst_PROGRAMS = test-cleanup test-reuse - -AM_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) -AM_CPPFLAGS = -I$(top_srcdir) -I$(srcdir) -AM_LDFLAGS = \ - $(GST_LIBS) \ - $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la - -SUBDIRS = check - -DIST_SUBDIRS = check diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am deleted file mode 100644 index 574297cfb4..0000000000 --- a/tests/check/Makefile.am +++ /dev/null @@ -1,64 +0,0 @@ -include $(top_srcdir)/common/check.mak - -CHECK_REGISTRY = $(top_builddir)/tests/check/test-registry.reg -TEST_FILES_DIRECTORY = $(top_srcdir)/tests/files - -REGISTRY_ENVIRONMENT = \ - GST_REGISTRY_1_0=$(CHECK_REGISTRY) - -AM_TESTS_ENVIRONMENT += \ - GST_STATE_IGNORE_ELEMENTS="$(STATE_IGNORE_ELEMENTS)" \ - $(REGISTRY_ENVIRONMENT) \ - GST_PLUGIN_SYSTEM_PATH_1_0= \ - GST_PLUGIN_PATH_1_0=$(GST_PLUGINS_DIR):$(GST_PLUGINS_BASE_DIR):$(GST_PLUGINS_GOOD_DIR):$(GST_PLUGINS_BAD_DIR):$(top_builddir)/gst \ - GST_PLUGIN_LOADING_WHITELIST="gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad:gst-rtsp-server" - - -# ths core dumps of some machines have PIDs appended -CLEANFILES = core.* test-registry.* - -clean-local: clean-local-check - -$(CHECK_REGISTRY): - $(TESTS_ENVIRONMENT) - -TESTS = $(check_PROGRAMS) - -check_PROGRAMS = \ - gst/rtspserver \ - gst/client \ - gst/mountpoints \ - gst/mediafactory \ - gst/media \ - gst/stream \ - gst/addresspool \ - gst/threadpool \ - gst/permissions \ - gst/token \ - gst/sessionmedia \ - gst/sessionpool \ - gst/rtspclientsink - -# these tests don't even pass -noinst_PROGRAMS = - -AM_CFLAGS = -I$(top_srcdir)/gst/rtsp-server \ - $(GST_PLUGINS_BASE_CFLAGS) \ - $(GST_BASE_CFLAGS) \ - $(GIO_CFLAGS) \ - $(GST_CFLAGS) \ - $(GST_CHECK_CFLAGS) \ - -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ - -DGST_CHECK_TEST_ENVIRONMENT_BEACON="\"GST_PLUGIN_LOADING_WHITELIST\"" \ - -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS $(PTHREAD_CFLAGS) -AM_CXXFLAGS = $(GST_CXXFLAGS) $(GST_CHECK_CFLAGS) \ - -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ - -DGST_CHECK_TEST_ENVIRONMENT_BEACON="\"GST_PLUGIN_LOADING_WHITELIST\"" \ - -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS -LDADD = $(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_API_VERSION@.la \ - $(GST_PLUGINS_BASE_LIBS) -lgstrtp-@GST_API_VERSION@ \ - -lgstrtsp-@GST_API_VERSION@ -lgstsdp-@GST_API_VERSION@ \ - $(GST_BASE_LIBS) $(GIO_LIBS) \ - $(GST_LIBS) $(GST_CHECK_LIBS) $(GST_RTSP_SERVER_LIBS) - -SUPPRESSIONS = $(top_srcdir)/common/gst.supp From 0b1b6670c8b73ad0311f90a6387bdd372cea5896 Mon Sep 17 00:00:00 2001 From: Adam x Nilsson Date: Mon, 7 Oct 2019 12:13:47 +0200 Subject: [PATCH 1652/1776] rtsp-stream : fix race condition in send_tcp_message If one thread is inside the send_tcp_message function and are done sending rtp or rtcp messages so the n_outstanding variable is zero however have not exit the loop sending the messages. While sending its messages, transports have been added or removed to the transport list, so the cache should be updated. If now an additional thread comes to the function send_tcp_message and trying to send rtp messages it will first destroy the rtp cache that is still being iterated trough by the first thread. Fixes #81 --- gst/rtsp-server/rtsp-stream.c | 108 ++++++++++++---------------------- 1 file changed, 38 insertions(+), 70 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4a5efcf77b..e13bfbd04e 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -163,10 +163,8 @@ struct _GstRTSPStreamPrivate guint n_active; GList *transports; guint transports_cookie; - GList *tr_cache_rtp; - GList *tr_cache_rtcp; - guint tr_cache_cookie_rtp; - guint tr_cache_cookie_rtcp; + GPtrArray *tr_cache; + guint tr_cache_cookie; guint n_tcp_transports; gboolean have_buffer[2]; guint n_outstanding; @@ -2445,17 +2443,11 @@ on_sender_ssrc_active (GObject * session, GObject * source, } static void -clear_tr_cache (GstRTSPStreamPrivate * priv, gboolean is_rtp) +clear_tr_cache (GstRTSPStreamPrivate * priv) { - if (is_rtp) { - g_list_foreach (priv->tr_cache_rtp, (GFunc) g_object_unref, NULL); - g_list_free (priv->tr_cache_rtp); - priv->tr_cache_rtp = NULL; - } else { - g_list_foreach (priv->tr_cache_rtcp, (GFunc) g_object_unref, NULL); - g_list_free (priv->tr_cache_rtcp); - priv->tr_cache_rtcp = NULL; - } + if (priv->tr_cache) + g_ptr_array_unref (priv->tr_cache); + priv->tr_cache = NULL; } /* Must be called with priv->lock */ @@ -2470,6 +2462,7 @@ send_tcp_message (GstRTSPStream * stream, gint idx) GstBufferList *buffer_list; guint n_messages = 0; gboolean is_rtp; + GPtrArray *transports; if (priv->n_outstanding > 0 || !priv->have_buffer[idx]) { return; @@ -2500,71 +2493,46 @@ send_tcp_message (GstRTSPStream * stream, gint idx) is_rtp = (idx == 0); - if (is_rtp) { - if (priv->tr_cache_cookie_rtp != priv->transports_cookie) { - clear_tr_cache (priv, is_rtp); - for (walk = priv->transports; walk; walk = g_list_next (walk)) { - GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - const GstRTSPTransport *t = - gst_rtsp_stream_transport_get_transport (tr); + if (priv->tr_cache_cookie != priv->transports_cookie) { + clear_tr_cache (priv); + priv->tr_cache = + g_ptr_array_new_full (priv->n_tcp_transports, g_object_unref); - if (t->lower_transport != GST_RTSP_LOWER_TRANS_TCP) - continue; + for (walk = priv->transports; walk; walk = g_list_next (walk)) { + GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; + const GstRTSPTransport *t = gst_rtsp_stream_transport_get_transport (tr); - priv->tr_cache_rtp = - g_list_prepend (priv->tr_cache_rtp, g_object_ref (tr)); - } - priv->tr_cache_cookie_rtp = priv->transports_cookie; - } - } else { - if (priv->tr_cache_cookie_rtcp != priv->transports_cookie) { - clear_tr_cache (priv, is_rtp); - for (walk = priv->transports; walk; walk = g_list_next (walk)) { - GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - const GstRTSPTransport *t = - gst_rtsp_stream_transport_get_transport (tr); - - if (t->lower_transport != GST_RTSP_LOWER_TRANS_TCP) - continue; - - priv->tr_cache_rtcp = - g_list_prepend (priv->tr_cache_rtcp, g_object_ref (tr)); - } - priv->tr_cache_cookie_rtcp = priv->transports_cookie; + if (t->lower_transport != GST_RTSP_LOWER_TRANS_TCP) + continue; + + g_ptr_array_add (priv->tr_cache, g_object_ref (tr)); } + priv->tr_cache_cookie = priv->transports_cookie; } + transports = priv->tr_cache; + g_ptr_array_ref (transports); priv->n_outstanding += n_messages * priv->n_tcp_transports; g_mutex_unlock (&priv->lock); - if (is_rtp) { - for (walk = priv->tr_cache_rtp; walk; walk = g_list_next (walk)) { - GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; + if (transports) { + for (gint index = 0; index < transports->len; index++) { + GstRTSPStreamTransport *tr = + (GstRTSPStreamTransport *) g_ptr_array_index (transports, index); gboolean send_ret = TRUE; - if (buffer) - send_ret = gst_rtsp_stream_transport_send_rtp (tr, buffer); - if (buffer_list) - send_ret = gst_rtsp_stream_transport_send_rtp_list (tr, buffer_list); - - if (!send_ret) { - /* remove transport on send error */ - g_mutex_lock (&priv->lock); - priv->n_outstanding -= n_messages; - update_transport (stream, tr, FALSE); - g_mutex_unlock (&priv->lock); - } - } - } else { - for (walk = priv->tr_cache_rtcp; walk; walk = g_list_next (walk)) { - GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - gboolean send_ret = TRUE; - - if (buffer) - send_ret = gst_rtsp_stream_transport_send_rtcp (tr, buffer); - if (buffer_list) - send_ret = gst_rtsp_stream_transport_send_rtcp_list (tr, buffer_list); + if (is_rtp) { + if (buffer) + send_ret = gst_rtsp_stream_transport_send_rtp (tr, buffer); + if (buffer_list) + send_ret = gst_rtsp_stream_transport_send_rtp_list (tr, buffer_list); + } else { + if (buffer) + send_ret = gst_rtsp_stream_transport_send_rtcp (tr, buffer); + if (buffer_list) + send_ret = gst_rtsp_stream_transport_send_rtcp_list (tr, buffer_list); + } if (!send_ret) { /* remove transport on send error */ @@ -2574,6 +2542,7 @@ send_tcp_message (GstRTSPStream * stream, gint idx) g_mutex_unlock (&priv->lock); } } + g_ptr_array_unref (transports); } gst_sample_unref (sample); @@ -3869,8 +3838,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, g_mutex_lock (&priv->lock); } - clear_tr_cache (priv, TRUE); - clear_tr_cache (priv, FALSE); + clear_tr_cache (priv); GST_INFO ("stream %p leaving bin", stream); From 74b19b3709d16e39644e0823fed114314845ad15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Tue, 15 Oct 2019 07:33:29 +0200 Subject: [PATCH 1653/1776] rtsp-session: add property extra-timeout Extra time to add to the timeout, in seconds. This only affects the time until a session is considered timed out and is not signalled in the RTSP request responses. Only the value of the timeout property is signalled in the request responses. --- gst/rtsp-server/rtsp-session.c | 48 +++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index e399349a73..7889697bc2 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -64,6 +64,7 @@ struct _GstRTSPSessionPrivate GList *medias; guint medias_cookie; + guint extra_time_timeout; }; #undef DEBUG @@ -71,6 +72,7 @@ struct _GstRTSPSessionPrivate #define DEFAULT_TIMEOUT 60 #define NO_TIMEOUT -1 #define DEFAULT_ALWAYS_VISIBLE FALSE +#define DEFAULT_EXTRA_TIMEOUT 5 enum { @@ -78,6 +80,7 @@ enum PROP_SESSIONID, PROP_TIMEOUT, PROP_TIMEOUT_ALWAYS_VISIBLE, + PROP_EXTRA_TIME_TIMEOUT, PROP_LAST }; @@ -118,6 +121,28 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass) "timeout always visible in header", DEFAULT_ALWAYS_VISIBLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPSession::extra-timeout: + * + * Extra time to add to the timeout, in seconds. This only affects the + * time until a session is considered timed out and is not signalled + * in the RTSP request responses. Only the value of the timeout + * property is signalled in the request responses. + * + * Default value is 5 seconds. + * If the application is using a buffer that is configured to hold + * amount of data equal to the sessiontimeout, extra-timeout can be + * set to zero to prevent loss of data + * + * Since: 1.18 + */ + g_object_class_install_property (gobject_class, PROP_EXTRA_TIME_TIMEOUT, + g_param_spec_uint ("extra-timeout", + "Add extra time to timeout ", "Add extra time to timeout", 0, + G_MAXUINT, DEFAULT_EXTRA_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0, "GstRTSPSession"); } @@ -134,6 +159,7 @@ gst_rtsp_session_init (GstRTSPSession * session) g_mutex_init (&priv->lock); g_mutex_init (&priv->last_access_lock); priv->timeout = DEFAULT_TIMEOUT; + priv->extra_time_timeout = DEFAULT_EXTRA_TIMEOUT; gst_rtsp_session_touch (session); } @@ -177,6 +203,9 @@ gst_rtsp_session_get_property (GObject * object, guint propid, case PROP_TIMEOUT_ALWAYS_VISIBLE: g_value_set_boolean (value, priv->timeout_always_visible); break; + case PROP_EXTRA_TIME_TIMEOUT: + g_value_set_uint (value, priv->extra_time_timeout); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -202,6 +231,11 @@ gst_rtsp_session_set_property (GObject * object, guint propid, priv->timeout_always_visible = g_value_get_boolean (value); g_mutex_unlock (&priv->lock); break; + case PROP_EXTRA_TIME_TIMEOUT: + g_mutex_lock (&priv->lock); + priv->extra_time_timeout = g_value_get_uint (value); + g_mutex_unlock (&priv->lock); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -651,8 +685,11 @@ gst_rtsp_session_next_timeout_usec (GstRTSPSession * session, gint64 now) last_access = GST_USECOND * (priv->last_access_monotonic_time); - /* add timeout allow for 5 seconds of extra time */ - last_access += priv->timeout * GST_SECOND + (5 * GST_SECOND); + /* add timeout allow for priv->extra_time_timeout + * seconds of extra time */ + last_access += priv->timeout * GST_SECOND + + (priv->extra_time_timeout * GST_SECOND); + g_mutex_unlock (&priv->last_access_lock); now_ns = GST_USECOND * now; @@ -701,8 +738,11 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) last_access = GST_USECOND * (priv->last_access_real_time); - /* add timeout allow for 5 seconds of extra time */ - last_access += priv->timeout * GST_SECOND + (5 * GST_SECOND); + /* add timeout allow for priv->extra_time_timeout + * seconds of extra time */ + last_access += priv->timeout * GST_SECOND + + (priv->extra_time_timeout * GST_SECOND); + g_mutex_unlock (&priv->last_access_lock); now_ns = GST_TIMEVAL_TO_TIME (*now); From 1a01d20e405380f3b7f555e88dd2c3b812f5e14d Mon Sep 17 00:00:00 2001 From: Kristofer Date: Wed, 16 Oct 2019 13:20:54 +0000 Subject: [PATCH 1654/1776] rtsp-client: Lock shared media For shared media we got race conditions. Concurrently rtsp clients might suspend or unsuspend the shared media and thus change the state without the clients expecting that. By introducing a lock that can be taken by callers such as rtsp_client one can force rtsp clients calling, eg. PLAY, SETUP and that uses shared media, to handle the media sequentially thus allowing one client to finish its rtsp call before another client calls on the same media. https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/86 Fixes #86 --- gst/rtsp-server/rtsp-client.c | 87 +++++++++++++++++++++++++++++++---- gst/rtsp-server/rtsp-media.c | 69 +++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 6 +++ 3 files changed, 154 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 0b7b556d9e..1cac54f41a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1356,6 +1356,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPClientClass *klass; GstRTSPSession *session; GstRTSPSessionMedia *sessmedia; + GstRTSPMedia *media; GstRTSPStatusCode code; gchar *path; gint matched; @@ -1386,6 +1387,10 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; + media = gst_rtsp_session_media_get_media (sessmedia); + g_object_ref (media); + gst_rtsp_media_lock (media); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_TEARDOWN_REQUEST], 0, ctx, &sig_result); if (sig_result != GST_RTSP_STS_OK) { @@ -1414,6 +1419,9 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_session_pool_remove (priv->session_pool, session); } + gst_rtsp_media_unlock (media); + g_object_unref (media); + return TRUE; /* ERRORS */ @@ -1449,6 +1457,8 @@ sig_failed: GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); send_generic_response (client, sig_result, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } } @@ -1617,6 +1627,8 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) g_free (path); media = gst_rtsp_session_media_get_media (sessmedia); + g_object_ref (media); + gst_rtsp_media_lock (media); n = gst_rtsp_media_n_streams (media); for (i = 0; i < n; i++) { GstRTSPStream *stream = gst_rtsp_media_get_stream (media, i); @@ -1655,6 +1667,9 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST], 0, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); + return TRUE; /* ERRORS */ @@ -1690,6 +1705,8 @@ sig_failed: GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); send_generic_response (client, sig_result, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } invalid_state: @@ -1697,12 +1714,16 @@ invalid_state: GST_ERROR ("client %p: not PLAYING or RECORDING", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } not_supported: { GST_ERROR ("client %p: pausing not supported", client); send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } } @@ -1974,6 +1995,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); + g_object_ref (media); + gst_rtsp_media_lock (media); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_PLAY_REQUEST], 0, ctx, &sig_result); if (sig_result != GST_RTSP_STS_OK) { @@ -2060,6 +2084,9 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST], 0, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); + return TRUE; /* ERRORS */ @@ -2094,6 +2121,8 @@ sig_failed: GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); send_generic_response (client, sig_result, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } invalid_state: @@ -2101,6 +2130,8 @@ invalid_state: GST_ERROR ("client %p: not PLAYING or READY", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } pipeline_error: @@ -2108,42 +2139,56 @@ pipeline_error: GST_ERROR ("client %p: failed to configure the pipeline", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } unsuspend_failed: { GST_ERROR ("client %p: unsuspend failed", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } invalid_mode: { GST_ERROR ("client %p: seek failed", client); send_generic_response (client, code, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } unsupported_mode: { GST_ERROR ("client %p: media does not support PLAY", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } get_rates_error: { GST_ERROR ("client %p: failed obtaining rate and applied_rate", client); send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } adjust_play_response_failed: { GST_ERROR ("client %p: failed to adjust play response", client); send_generic_response (client, code, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } rtp_info_error: { GST_ERROR ("client %p: failed to add RTP-Info", client); send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } } @@ -2648,13 +2693,17 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) /* get a handle to the configuration of the media in the session */ media = find_media (client, ctx, path, &matched); /* need to suspend the media, if the protocol has changed */ - if (media != NULL) + if (media != NULL) { + gst_rtsp_media_lock (media); gst_rtsp_media_suspend (media); + } } else { - if ((media = gst_rtsp_session_media_get_media (sessmedia))) + if ((media = gst_rtsp_session_media_get_media (sessmedia))) { g_object_ref (media); - else + gst_rtsp_media_lock (media); + } else { goto media_not_found; + } } /* no media, not found then */ if (media == NULL) @@ -2870,12 +2919,14 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY); break; } + + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], 0, ctx); + + gst_rtsp_media_unlock (media); g_object_unref (media); g_object_unref (session); g_free (path); - g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], 0, ctx); - return TRUE; /* ERRORS */ @@ -2913,6 +2964,7 @@ control_not_found: { GST_ERROR ("client %p: no control in path '%s'", client, path); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + gst_rtsp_media_unlock (media); g_object_unref (media); goto cleanup_session; } @@ -2921,6 +2973,7 @@ stream_not_found: GST_ERROR ("client %p: stream '%s' not found", client, GST_STR_NULL (control)); send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + gst_rtsp_media_unlock (media); g_object_unref (media); goto cleanup_session; } @@ -2929,6 +2982,7 @@ sig_failed: GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); send_generic_response (client, sig_result, ctx); + gst_rtsp_media_unlock (media); g_object_unref (media); goto cleanup_path; } @@ -2936,6 +2990,7 @@ service_unavailable: { GST_ERROR ("client %p: can't create session", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + gst_rtsp_media_unlock (media); g_object_unref (media); goto cleanup_session; } @@ -2948,6 +3003,7 @@ sessmedia_unavailable: configure_media_failed_no_reply: { GST_ERROR ("client %p: configure_media failed", client); + gst_rtsp_media_unlock (media); g_object_unref (media); /* error reply is already sent */ goto cleanup_session; @@ -2991,8 +3047,10 @@ keymgmt_error: { cleanup_transport: gst_rtsp_transport_free (ct); - if (media) + if (media) { + gst_rtsp_media_unlock (media); g_object_unref (media); + } cleanup_session: if (new_session) gst_rtsp_session_pool_remove (priv->session_pool, session); @@ -3105,6 +3163,8 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!(media = find_media (client, ctx, path, NULL))) goto no_media; + gst_rtsp_media_lock (media); + if (!(gst_rtsp_media_get_transport_mode (media) & GST_RTSP_TRANSPORT_MODE_PLAY)) goto unsupported_mode; @@ -3115,7 +3175,6 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) /* we suspend after the describe */ gst_rtsp_media_suspend (media); - g_object_unref (media); gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request); @@ -3140,6 +3199,9 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST], 0, ctx); + gst_rtsp_media_unlock (media); + g_object_unref (media); + return TRUE; /* ERRORS */ @@ -3180,6 +3242,7 @@ unsupported_mode: GST_ERROR ("client %p: media does not support DESCRIBE", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); g_free (path); + gst_rtsp_media_unlock (media); g_object_unref (media); return FALSE; } @@ -3188,6 +3251,7 @@ no_sdp: GST_ERROR ("client %p: can't create SDP", client); send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_free (path); + gst_rtsp_media_unlock (media); g_object_unref (media); return FALSE; } @@ -3284,6 +3348,7 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) goto no_media; ctx->media = media; + gst_rtsp_media_lock (media); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_ANNOUNCE_REQUEST], 0, ctx, &sig_result); @@ -3319,7 +3384,6 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) /* we suspend after the announce */ gst_rtsp_media_suspend (media); - g_object_unref (media); send_message (client, ctx, ctx->response, FALSE); @@ -3328,6 +3392,9 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_sdp_message_free (sdp); g_free (path); + gst_rtsp_media_unlock (media); + g_object_unref (media); + return TRUE; no_uri: @@ -3382,6 +3449,8 @@ sig_failed: gst_rtsp_status_as_text (sig_result)); send_generic_response (client, sig_result, ctx); gst_sdp_message_free (sdp); + gst_rtsp_media_unlock (media); + g_object_unref (media); return FALSE; } unsupported_mode: @@ -3389,6 +3458,7 @@ unsupported_mode: GST_ERROR ("client %p: media does not support ANNOUNCE", client); send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); g_free (path); + gst_rtsp_media_unlock (media); g_object_unref (media); gst_sdp_message_free (sdp); return FALSE; @@ -3398,6 +3468,7 @@ unhandled_sdp: GST_ERROR ("client %p: can't handle SDP", client); send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, ctx); g_free (path); + gst_rtsp_media_unlock (media); g_object_unref (media); gst_sdp_message_free (sdp); return FALSE; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c0da7202d0..8f1e438b2a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -90,6 +90,12 @@ struct _GstRTSPMediaPrivate GMutex lock; GCond cond; + /* the global lock is used to lock the entire media. This is needed by callers + such as rtsp_client to protect the media when it is shared by many clients. + The lock prevents that concurrenting clients messes up media. + Typically the lock is taken in external API calls such as SETUP */ + GMutex global_lock; + /* protected by lock */ GstRTSPPermissions *permissions; gboolean shared; @@ -459,6 +465,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->streams = g_ptr_array_new_with_free_func (g_object_unref); g_mutex_init (&priv->lock); + g_mutex_init (&priv->global_lock); g_cond_init (&priv->cond); g_rec_mutex_init (&priv->state_lock); @@ -512,6 +519,7 @@ gst_rtsp_media_finalize (GObject * obj) gst_object_unref (priv->clock); g_free (priv->multicast_iface); g_mutex_clear (&priv->lock); + g_mutex_clear (&priv->global_lock); g_cond_clear (&priv->cond); g_rec_mutex_clear (&priv->state_lock); @@ -3994,6 +4002,54 @@ get_clock_unlocked (GstRTSPMedia * media) return gst_pipeline_get_clock (GST_PIPELINE_CAST (media->priv->pipeline)); } +/** + * gst_rtsp_media_lock: + * @media: a #GstRTSPMedia + * + * Lock the entire media. This is needed by callers such as rtsp_client to + * protect the media when it is shared by many clients. + * The lock prevents that concurrent clients alters the shared media, + * while one client already is working with it. + * Typically the lock is taken in external RTSP API calls that uses shared media + * such as DESCRIBE, SETUP, ANNOUNCE, TEARDOWN, PLAY, PAUSE. + * + * As best practice take the lock as soon as the function get hold of a shared + * media object. Release the lock right before the function returns. + * + * Since: 1.18 + */ +void +gst_rtsp_media_lock (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + g_mutex_lock (&priv->global_lock); +} + +/** + * gst_rtsp_media_unlock: + * @media: a #GstRTSPMedia + * + * Unlock the media. + * + * Since: 1.18 + */ +void +gst_rtsp_media_unlock (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + g_mutex_unlock (&priv->global_lock); +} + /** * gst_rtsp_media_get_clock: * @media: a #GstRTSPMedia @@ -4369,6 +4425,14 @@ gst_rtsp_media_suspend (GstRTSPMedia * media) GST_FIXME ("suspend for dynamic pipelines needs fixing"); + /* this typically can happen for shared media. */ + if (priv->prepare_count > 1 && + priv->status == GST_RTSP_MEDIA_STATUS_SUSPENDED) { + goto done; + } else if (priv->prepare_count > 1) { + goto prepared_by_other_client; + } + g_rec_mutex_lock (&priv->state_lock); if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) goto not_prepared; @@ -4390,6 +4454,11 @@ done: return TRUE; /* ERRORS */ +prepared_by_other_client: + { + GST_WARNING ("media %p was prepared by other client", media); + return FALSE; + } not_prepared: { g_rec_mutex_unlock (&priv->state_lock); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 5379f65e64..d44f24c533 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -364,6 +364,12 @@ GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia *media, /* dealing with the media */ +GST_RTSP_SERVER_API +void gst_rtsp_media_lock (GstRTSPMedia *media); + +GST_RTSP_SERVER_API +void gst_rtsp_media_unlock (GstRTSPMedia *media); + GST_RTSP_SERVER_API GstClock * gst_rtsp_media_get_clock (GstRTSPMedia *media); From d9a182c476947da85290c9d9c2b7df2a4f183bdb Mon Sep 17 00:00:00 2001 From: Muhammet Ilendemli Date: Thu, 17 Oct 2019 12:15:42 +0200 Subject: [PATCH 1655/1776] rtsp-client: Generate correct URI for MIKEY in ANNOUNCE responses Instead of hardcoding the URI, take the actual URI (and especially the correct port) from the RTSP context. Fixes #84 --- gst/rtsp-server/rtsp-client.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1cac54f41a..996af70033 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -3370,16 +3370,18 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) n_streams = gst_rtsp_media_n_streams (media); for (i = 0; i < n_streams; i++) { GstRTSPStream *stream = gst_rtsp_media_get_stream (media, i); - gchar *location = - g_strdup_printf ("rtsp://%s%s:8554/stream=%d", priv->server_ip, path, - i); - gchar *keymgmt = stream_make_keymgmt (client, location, stream); + gchar *uri, *location, *keymgmt; + + uri = gst_rtsp_url_get_request_uri (ctx->uri); + location = g_strdup_printf ("%s/stream=%d", uri, i); + keymgmt = stream_make_keymgmt (client, location, stream); if (keymgmt) gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_KEYMGMT, keymgmt); g_free (location); + g_free (uri); } /* we suspend after the announce */ From d519f4740231d87a218e0b8df949dc904a3d0058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Fri, 18 Oct 2019 09:19:59 +0200 Subject: [PATCH 1656/1776] rtsp-session: clean up comment extra-timeout --- gst/rtsp-server/rtsp-session.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 7889697bc2..73671b6aea 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -125,15 +125,15 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass) * GstRTSPSession::extra-timeout: * * Extra time to add to the timeout, in seconds. This only affects the - * time until a session is considered timed out and is not signalled - * in the RTSP request responses. Only the value of the timeout + * time until a session is considered timed out and is not signalled + * in the RTSP request responses. Only the value of the timeout * property is signalled in the request responses. - * + * * Default value is 5 seconds. - * If the application is using a buffer that is configured to hold - * amount of data equal to the sessiontimeout, extra-timeout can be - * set to zero to prevent loss of data - * + * If the application is using a buffer that is configured to hold + * amount of data equal to the sessiontimeout, extra-timeout can be + * set to zero to prevent loss of data + * * Since: 1.18 */ g_object_class_install_property (gobject_class, PROP_EXTRA_TIME_TIMEOUT, From 95ce953e34cd0e9f5d42ce7900a9572e7bc8ca47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 18 Oct 2019 00:42:12 +0100 Subject: [PATCH 1657/1776] meson: build gir even when cross-compiling if introspection was enabled explicitly This can be made to work in certain circumstances when cross-compiling, so default to not building g-i stuff when cross-compiling, but allow it if introspection was enabled explicitly via -Dintrospection=enabled. See gstreamer/gstreamer#454 and gstreamer/gstreamer#381. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index e1e3b1dbe1..3f45f0e539 100644 --- a/meson.build +++ b/meson.build @@ -173,7 +173,7 @@ endif gir = find_program('g-ir-scanner', required : get_option('introspection')) gnome = import('gnome') -build_gir = gir.found() and not meson.is_cross_build() +build_gir = gir.found() and (not meson.is_cross_build() or get_option('introspection').enabled()) gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**);' + \ 'g_setenv("GST_REGISTRY_1.0", "@0@", TRUE);'.format(meson.current_build_dir() + '/gir_empty_registry.reg') + \ 'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \ From dd32924eb020b01fdec511c9f10a283383312488 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 15 Oct 2019 19:08:32 +0200 Subject: [PATCH 1658/1776] stream: refactor TCP backpressure handling The previous implementation stopped sending TCP messages to all clients when a single one stopped consuming them, which obviously created problems for shared media. Instead, we now manage a backlog in stream-transport, and slow clients are removed once this backlog exceeds a maximum duration, currently hardcoded. Fixes #80 --- gst/rtsp-server/rtsp-client.c | 10 + gst/rtsp-server/rtsp-server-internal.h | 55 ++++++ gst/rtsp-server/rtsp-stream-transport.c | 180 +++++++++++++++++- gst/rtsp-server/rtsp-stream-transport.h | 5 +- gst/rtsp-server/rtsp-stream.c | 232 ++++++++++++++++-------- 5 files changed, 406 insertions(+), 76 deletions(-) create mode 100644 gst/rtsp-server/rtsp-server-internal.h diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 996af70033..727e9426b6 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -53,6 +53,7 @@ #include "rtsp-client.h" #include "rtsp-sdp.h" #include "rtsp-params.h" +#include "rtsp-server-internal.h" typedef enum { @@ -1202,6 +1203,12 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) return ret; } +static gboolean +do_check_back_pressure (guint8 channel, GstRTSPClient * client) +{ + return get_data_seq (client, channel) != 0; +} + static gboolean do_send_data_list (GstBufferList * buffer_list, guint8 channel, GstRTSPClient * client) @@ -2854,6 +2861,9 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) (GstRTSPSendListFunc) do_send_data_list, (GstRTSPSendListFunc) do_send_data_list, client, NULL); + gst_rtsp_stream_transport_set_back_pressure_callback (trans, + (GstRTSPBackPressureFunc) do_check_back_pressure, client, NULL); + g_hash_table_insert (priv->transports, GINT_TO_POINTER (ct->interleaved.min), trans); g_object_ref (trans); diff --git a/gst/rtsp-server/rtsp-server-internal.h b/gst/rtsp-server/rtsp-server-internal.h new file mode 100644 index 0000000000..6650b875f0 --- /dev/null +++ b/gst/rtsp-server/rtsp-server-internal.h @@ -0,0 +1,55 @@ +/* GStreamer + * Copyright (C) 2019 Mathieu Duponchelle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_RTSP_SERVER_INTERNAL_H__ +#define __GST_RTSP_SERVER_INTERNAL_H__ + +#include + +G_BEGIN_DECLS + +#include "rtsp-stream-transport.h" + +/* Internal GstRTSPStreamTransport interface */ + +typedef gboolean (*GstRTSPBackPressureFunc) (guint8 channel, gpointer user_data); + +gboolean gst_rtsp_stream_transport_backlog_push (GstRTSPStreamTransport *trans, + GstBuffer *buffer, + GstBufferList *buffer_list, + gboolean is_rtp); + +gboolean gst_rtsp_stream_transport_backlog_pop (GstRTSPStreamTransport *trans, + GstBuffer **buffer, + GstBufferList **buffer_list, + gboolean *is_rtp); + +gboolean gst_rtsp_stream_transport_backlog_is_empty (GstRTSPStreamTransport *trans); + +void gst_rtsp_stream_transport_set_back_pressure_callback (GstRTSPStreamTransport *trans, + GstRTSPBackPressureFunc back_pressure_func, + gpointer user_data, + GDestroyNotify notify); + +gboolean gst_rtsp_stream_transport_check_back_pressure (GstRTSPStreamTransport *trans, + guint8 channel); + +G_END_DECLS + +#endif /* __GST_RTSP_SERVER_INTERNAL_H__ */ diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 1791034c39..ff53283e33 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -48,6 +48,7 @@ #include #include "rtsp-stream-transport.h" +#include "rtsp-server-internal.h" struct _GstRTSPStreamTransportPrivate { @@ -63,6 +64,10 @@ struct _GstRTSPStreamTransportPrivate gpointer list_user_data; GDestroyNotify list_notify; + GstRTSPBackPressureFunc back_pressure_func; + gpointer back_pressure_func_data; + GDestroyNotify back_pressure_func_notify; + GstRTSPKeepAliveFunc keep_alive; gpointer ka_user_data; GDestroyNotify ka_notify; @@ -77,8 +82,23 @@ struct _GstRTSPStreamTransportPrivate GstRTSPUrl *url; GObject *rtpsource; + + /* TCP backlog */ + GstClockTime first_rtp_timestamp; + GstQueueArray *items; }; +#define MAX_BACKLOG_DURATION (10 * GST_SECOND) +#define MAX_BACKLOG_SIZE 100 + +typedef struct +{ + GstBuffer *buffer; + GstBufferList *buffer_list; + gboolean is_rtp; +} BackLogItem; + + enum { PROP_0, @@ -106,10 +126,21 @@ gst_rtsp_stream_transport_class_init (GstRTSPStreamTransportClass * klass) 0, "GstRTSPStreamTransport"); } +static void +clear_backlog_item (BackLogItem * item) +{ + gst_clear_buffer (&item->buffer); + gst_clear_buffer_list (&item->buffer_list); +} + static void gst_rtsp_stream_transport_init (GstRTSPStreamTransport * trans) { trans->priv = gst_rtsp_stream_transport_get_instance_private (trans); + trans->priv->items = gst_queue_array_new_for_struct (sizeof (BackLogItem), 0); + trans->priv->first_rtp_timestamp = GST_CLOCK_TIME_NONE; + gst_queue_array_set_clear_func (trans->priv->items, + (GDestroyNotify) clear_backlog_item); } static void @@ -135,6 +166,8 @@ gst_rtsp_stream_transport_finalize (GObject * obj) if (priv->url) gst_rtsp_url_free (priv->url); + gst_queue_array_free (priv->items); + G_OBJECT_CLASS (gst_rtsp_stream_transport_parent_class)->finalize (obj); } @@ -244,6 +277,39 @@ gst_rtsp_stream_transport_set_list_callbacks (GstRTSPStreamTransport * trans, priv->list_notify = notify; } +void +gst_rtsp_stream_transport_set_back_pressure_callback (GstRTSPStreamTransport * + trans, GstRTSPBackPressureFunc back_pressure_func, gpointer user_data, + GDestroyNotify notify) +{ + GstRTSPStreamTransportPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); + + priv = trans->priv; + + priv->back_pressure_func = back_pressure_func; + if (priv->back_pressure_func_notify) + priv->back_pressure_func_notify (priv->back_pressure_func_data); + priv->back_pressure_func_data = user_data; + priv->back_pressure_func_notify = notify; +} + +gboolean +gst_rtsp_stream_transport_check_back_pressure (GstRTSPStreamTransport * trans, + guint8 channel) +{ + GstRTSPStreamTransportPrivate *priv; + gboolean ret = FALSE; + + priv = trans->priv; + + if (priv->back_pressure_func) + ret = priv->back_pressure_func (channel, priv->back_pressure_func_data); + + return ret; +} + /** * gst_rtsp_stream_transport_set_keepalive: * @trans: a #GstRTSPStreamTransport @@ -693,7 +759,7 @@ gst_rtsp_stream_transport_message_sent (GstRTSPStreamTransport * trans) priv = trans->priv; if (priv->message_sent) - priv->message_sent (priv->ms_user_data); + priv->message_sent (trans, priv->ms_user_data); } /** @@ -729,3 +795,115 @@ gst_rtsp_stream_transport_recv_data (GstRTSPStreamTransport * trans, } return res; } + +static GstClockTime +get_backlog_item_timestamp (BackLogItem * item) +{ + GstClockTime ret = GST_CLOCK_TIME_NONE; + + if (item->buffer) { + ret = GST_BUFFER_DTS_OR_PTS (item->buffer); + } else if (item->buffer_list) { + g_assert (gst_buffer_list_length (item->buffer_list) > 0); + ret = GST_BUFFER_DTS_OR_PTS (gst_buffer_list_get (item->buffer_list, 0)); + } + + return ret; +} + +static GstClockTime +get_first_backlog_timestamp (GstRTSPStreamTransport * trans) +{ + GstRTSPStreamTransportPrivate *priv = trans->priv; + GstClockTime ret = GST_CLOCK_TIME_NONE; + guint i, l; + + l = gst_queue_array_get_length (priv->items); + + for (i = 0; i < l; i++) { + BackLogItem *item = (BackLogItem *) + gst_queue_array_peek_nth_struct (priv->items, i); + + if (item->is_rtp) { + ret = get_backlog_item_timestamp (item); + break; + } + } + + return ret; +} + +/* Not MT-safe, caller should ensure consistent locking. Ownership + * of @buffer and @buffer_list is transfered to the transport */ +gboolean +gst_rtsp_stream_transport_backlog_push (GstRTSPStreamTransport * trans, + GstBuffer * buffer, GstBufferList * buffer_list, gboolean is_rtp) +{ + gboolean ret = TRUE; + BackLogItem item = { 0, }; + GstClockTime item_timestamp; + GstRTSPStreamTransportPrivate *priv; + + priv = trans->priv; + + if (buffer) + item.buffer = buffer; + if (buffer_list) + item.buffer_list = buffer_list; + item.is_rtp = is_rtp; + + gst_queue_array_push_tail_struct (priv->items, &item); + + item_timestamp = get_backlog_item_timestamp (&item); + + if (is_rtp && priv->first_rtp_timestamp != GST_CLOCK_TIME_NONE) { + GstClockTimeDiff queue_duration; + + g_assert (GST_CLOCK_TIME_IS_VALID (item_timestamp)); + + queue_duration = GST_CLOCK_DIFF (priv->first_rtp_timestamp, item_timestamp); + + g_assert (queue_duration >= 0); + + if (queue_duration > MAX_BACKLOG_DURATION && + gst_queue_array_get_length (priv->items) > MAX_BACKLOG_SIZE) { + ret = FALSE; + } + } else if (is_rtp) { + priv->first_rtp_timestamp = item_timestamp; + } + + return ret; +} + +/* Not MT-safe, caller should ensure consistent locking. Ownership + * of @buffer and @buffer_list is transfered back to the caller */ +gboolean +gst_rtsp_stream_transport_backlog_pop (GstRTSPStreamTransport * trans, + GstBuffer ** buffer, GstBufferList ** buffer_list, gboolean * is_rtp) +{ + BackLogItem *item; + GstRTSPStreamTransportPrivate *priv; + + g_return_val_if_fail (!gst_rtsp_stream_transport_backlog_is_empty (trans), + FALSE); + + priv = trans->priv; + + item = (BackLogItem *) gst_queue_array_pop_head_struct (priv->items); + + priv->first_rtp_timestamp = get_first_backlog_timestamp (trans); + + *buffer = item->buffer; + *buffer_list = item->buffer_list; + *is_rtp = item->is_rtp; + + return TRUE; +} + +/* Not MT-safe, caller should ensure consistent locking. */ +gboolean +gst_rtsp_stream_transport_backlog_is_empty (GstRTSPStreamTransport * trans) +{ + return gst_queue_array_is_empty (trans->priv->items); +} diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index 2b507b01d3..f878858db1 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -88,7 +89,7 @@ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); * Function registered with gst_rtsp_stream_transport_set_message_sent() * and called when a message has been sent on the transport. */ -typedef void (*GstRTSPMessageSentFunc) (gpointer user_data); +typedef void (*GstRTSPMessageSentFunc) (GstRTSPStreamTransport *trans, gpointer user_data); /** * GstRTSPStreamTransport: @@ -183,8 +184,6 @@ void gst_rtsp_stream_transport_set_timed_out (GstRTSPStreamT GST_RTSP_SERVER_API gboolean gst_rtsp_stream_transport_is_timed_out (GstRTSPStreamTransport *trans); - - GST_RTSP_SERVER_API gboolean gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport *trans, GstBuffer *buffer); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index e13bfbd04e..b00315f351 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -43,7 +43,26 @@ * stream should be sent to. Use gst_rtsp_stream_remove_transport() to remove * the destination again. * - * Last reviewed on 2013-07-16 (1.0.0) + * Each #GstRTSPStreamTransport spawns one queue that will serve as a backlog of a + * controllable maximum size when the reflux from the TCP connection's backpressure + * starts spilling all over. + * + * Unlike the backlog in rtspconnection, which we have decided should only contain + * at most one RTP and one RTCP data message in order to allow control messages to + * go through unobstructed, this backlog only consists of data messages, allowing + * us to fill it up without concern. + * + * When multiple TCP transports exist, for example in the context of a shared media, + * we only pop samples from our appsinks when at least one of the transports doesn't + * experience back pressure: this allows us to pace our sample popping to the speed + * of the fastest client. + * + * When a sample is popped, it is either sent directly on transports that don't + * experience backpressure, or queued on the transport's backlog otherwise. Samples + * are then popped from that backlog when the transport reports it has sent the message. + * + * Once the backlog reaches an overly large duration, the transport is dropped as + * the client was deemed too slow. */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -61,6 +80,7 @@ #include #include "rtsp-stream.h" +#include "rtsp-server-internal.h" struct _GstRTSPStreamPrivate { @@ -167,7 +187,6 @@ struct _GstRTSPStreamPrivate guint tr_cache_cookie; guint n_tcp_transports; gboolean have_buffer[2]; - guint n_outstanding; gint dscp_qos; @@ -2450,13 +2469,93 @@ clear_tr_cache (GstRTSPStreamPrivate * priv) priv->tr_cache = NULL; } +/* With lock taken */ +static gboolean +any_transport_ready (GstRTSPStream * stream, guint8 channel) +{ + gboolean ret = TRUE; + GstRTSPStreamPrivate *priv = stream->priv; + GPtrArray *transports; + gint index; + + transports = priv->tr_cache; + + if (!transports) + goto done; + + for (index = 0; index < transports->len; index++) { + GstRTSPStreamTransport *tr = g_ptr_array_index (transports, index); + if (!gst_rtsp_stream_transport_check_back_pressure (tr, channel)) { + ret = TRUE; + break; + } else { + ret = FALSE; + } + } + +done: + return ret; +} + +/* Must be called *without* priv->lock */ +static void +push_data (GstRTSPStream * stream, GstRTSPStreamTransport * trans, + GstBuffer * buffer, GstBufferList * buffer_list, gboolean is_rtp) +{ + GstRTSPStreamPrivate *priv = stream->priv; + gboolean send_ret = TRUE; + + if (is_rtp) { + if (buffer) + send_ret = gst_rtsp_stream_transport_send_rtp (trans, buffer); + if (buffer_list) + send_ret = gst_rtsp_stream_transport_send_rtp_list (trans, buffer_list); + } else { + if (buffer) + send_ret = gst_rtsp_stream_transport_send_rtcp (trans, buffer); + if (buffer_list) + send_ret = gst_rtsp_stream_transport_send_rtcp_list (trans, buffer_list); + } + + if (!send_ret) { + /* remove transport on send error */ + g_mutex_lock (&priv->lock); + update_transport (stream, trans, FALSE); + g_mutex_unlock (&priv->lock); + } +} + +/* With priv->lock */ +static void +ensure_cached_transports (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv = stream->priv; + GList *walk; + + if (priv->tr_cache_cookie != priv->transports_cookie) { + clear_tr_cache (priv); + priv->tr_cache = + g_ptr_array_new_full (priv->n_tcp_transports, g_object_unref); + + for (walk = priv->transports; walk; walk = g_list_next (walk)) { + GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; + const GstRTSPTransport *t = gst_rtsp_stream_transport_get_transport (tr); + + if (t->lower_transport != GST_RTSP_LOWER_TRANS_TCP) + continue; + + g_ptr_array_add (priv->tr_cache, g_object_ref (tr)); + } + priv->tr_cache_cookie = priv->transports_cookie; + } +} + /* Must be called with priv->lock */ static void send_tcp_message (GstRTSPStream * stream, gint idx) { GstRTSPStreamPrivate *priv = stream->priv; GstAppSink *sink; - GList *walk; GstSample *sample; GstBuffer *buffer; GstBufferList *buffer_list; @@ -2464,9 +2563,13 @@ send_tcp_message (GstRTSPStream * stream, gint idx) gboolean is_rtp; GPtrArray *transports; - if (priv->n_outstanding > 0 || !priv->have_buffer[idx]) { + if (!priv->have_buffer[idx]) + return; + + ensure_cached_transports (stream); + + if (!any_transport_ready (stream, idx)) return; - } priv->have_buffer[idx] = FALSE; @@ -2493,52 +2596,38 @@ send_tcp_message (GstRTSPStream * stream, gint idx) is_rtp = (idx == 0); - if (priv->tr_cache_cookie != priv->transports_cookie) { - clear_tr_cache (priv); - priv->tr_cache = - g_ptr_array_new_full (priv->n_tcp_transports, g_object_unref); - - for (walk = priv->transports; walk; walk = g_list_next (walk)) { - GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data; - const GstRTSPTransport *t = gst_rtsp_stream_transport_get_transport (tr); - - if (t->lower_transport != GST_RTSP_LOWER_TRANS_TCP) - continue; - - g_ptr_array_add (priv->tr_cache, g_object_ref (tr)); - } - priv->tr_cache_cookie = priv->transports_cookie; - } - transports = priv->tr_cache; g_ptr_array_ref (transports); - priv->n_outstanding += n_messages * priv->n_tcp_transports; g_mutex_unlock (&priv->lock); if (transports) { - for (gint index = 0; index < transports->len; index++) { - GstRTSPStreamTransport *tr = - (GstRTSPStreamTransport *) g_ptr_array_index (transports, index); - gboolean send_ret = TRUE; + gint index; - if (is_rtp) { - if (buffer) - send_ret = gst_rtsp_stream_transport_send_rtp (tr, buffer); - if (buffer_list) - send_ret = gst_rtsp_stream_transport_send_rtp_list (tr, buffer_list); + for (index = 0; index < transports->len; index++) { + GstRTSPStreamTransport *tr = g_ptr_array_index (transports, index); + + if (gst_rtsp_stream_transport_backlog_is_empty (tr) + && !gst_rtsp_stream_transport_check_back_pressure (tr, idx)) { + push_data (stream, tr, buffer, buffer_list, is_rtp); } else { - if (buffer) - send_ret = gst_rtsp_stream_transport_send_rtcp (tr, buffer); - if (buffer_list) - send_ret = gst_rtsp_stream_transport_send_rtcp_list (tr, buffer_list); - } + GstBuffer *buf_ref = NULL; + GstBufferList *buflist_ref = NULL; - if (!send_ret) { - /* remove transport on send error */ g_mutex_lock (&priv->lock); - priv->n_outstanding -= n_messages; - update_transport (stream, tr, FALSE); + + if (buffer) + buf_ref = gst_buffer_ref (buffer); + if (buffer_list) + buflist_ref = gst_buffer_list_ref (buffer_list); + + if (!gst_rtsp_stream_transport_backlog_push (tr, + buf_ref, buflist_ref, is_rtp)) { + GST_WARNING_OBJECT (stream, + "Dropping slow transport %" GST_PTR_FORMAT, tr); + update_transport (stream, tr, FALSE); + } + g_mutex_unlock (&priv->lock); } } @@ -2558,6 +2647,7 @@ send_thread_main (gpointer data, gpointer user_data) gint i; g_mutex_lock (&priv->lock); + do { idx = -1; /* iterate from 1 and down, so we prioritize RTCP over RTP */ @@ -2569,9 +2659,9 @@ send_thread_main (gpointer data, gpointer user_data) } } - if (idx != -1 && priv->n_outstanding == 0) + if (idx != -1) send_tcp_message (stream, idx); - } while (idx != -1 && priv->n_outstanding == 0); + } while (idx != -1); GST_DEBUG_OBJECT (stream, "send thread done"); g_mutex_unlock (&priv->lock); @@ -2596,10 +2686,7 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) for (i = 0; i < 2; i++) if (GST_ELEMENT_CAST (sink) == priv->appsink[i]) { priv->have_buffer[i] = TRUE; - if (priv->n_outstanding == 0) { - /* send message */ - idx = i; - } + idx = i; break; } @@ -4459,25 +4546,36 @@ mcast_error: } static void -on_message_sent (gpointer user_data) +on_message_sent (GstRTSPStreamTransport * trans, gpointer user_data) { GstRTSPStream *stream = user_data; GstRTSPStreamPrivate *priv = stream->priv; gint idx = -1; + gint i; GST_DEBUG_OBJECT (stream, "message send complete"); g_mutex_lock (&priv->lock); - g_assert (priv->n_outstanding >= 0); + if (!gst_rtsp_stream_transport_backlog_is_empty (trans)) { + GstBuffer *buffer; + GstBufferList *buffer_list; + gboolean is_rtp; + gboolean popped; - if (priv->n_outstanding == 0) - goto no_outstanding; + popped = + gst_rtsp_stream_transport_backlog_pop (trans, &buffer, &buffer_list, + &is_rtp); - priv->n_outstanding--; - if (priv->n_outstanding == 0) { - gint i; + g_assert (popped == TRUE); + g_mutex_unlock (&priv->lock); + + push_data (stream, trans, buffer, buffer_list, is_rtp); + + gst_clear_buffer (&buffer); + gst_clear_buffer_list (&buffer_list); + } else { /* iterate from 1 and down, so we prioritize RTCP over RTP */ for (i = 1; i >= 0; i--) { if (priv->have_buffer[i]) { @@ -4486,27 +4584,17 @@ on_message_sent (gpointer user_data) break; } } - } - if (idx != -1) { - gint dummy; + if (idx != -1) { + gint dummy; - if (priv->send_pool) { - GST_DEBUG_OBJECT (stream, "start thread"); - g_thread_pool_push (priv->send_pool, &dummy, NULL); + if (priv->send_pool) { + GST_DEBUG_OBJECT (stream, "start thread"); + g_thread_pool_push (priv->send_pool, &dummy, NULL); + } } - } - g_mutex_unlock (&priv->lock); - - return; - - /* ERRORS */ -no_outstanding: - { - GST_INFO ("no outstanding messages"); g_mutex_unlock (&priv->lock); - return; } } @@ -5928,8 +6016,8 @@ gst_rtsp_stream_set_rate_control (GstRTSPStream * stream, gboolean enabled) if (stream->priv->appsink[0]) g_object_set (stream->priv->appsink[0], "sync", enabled, NULL); if (stream->priv->payloader - && g_object_class_find_property (G_OBJECT_GET_CLASS (stream->priv-> - payloader), "onvif-no-rate-control")) + && g_object_class_find_property (G_OBJECT_GET_CLASS (stream-> + priv->payloader), "onvif-no-rate-control")) g_object_set (stream->priv->payloader, "onvif-no-rate-control", !enabled, NULL); if (stream->priv->session) { From f7bbd9dd86c93644b7f2b15e4fc451dea1e17b68 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 5 Sep 2019 19:51:06 -0400 Subject: [PATCH 1659/1776] GstRTSPMountPoints: Remove any existing factory before adding a new one The documentation of gst_rtsp_mount_points_add_factory() says "Any previous mount point will be freed" which was true when it was implemented using a GHashTable. But in 2012 it got rewrote using a GSequence and since then it could have 2 factories for the same path. Which one gets used is random, depending on the sorting order of 2 identical items. --- gst/rtsp-server/rtsp-mount-points.c | 36 ++++++++++++++++++----------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 76794851ee..10119839db 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -302,6 +302,27 @@ gst_rtsp_mount_points_match (GstRTSPMountPoints * mounts, return result; } +static void +gst_rtsp_mount_points_remove_factory_unlocked (GstRTSPMountPoints * mounts, + const gchar * path) +{ + GstRTSPMountPointsPrivate *priv = mounts->priv; + DataItem item; + GSequenceIter *iter; + + item.path = (gchar *) path; + + if (priv->dirty) { + g_sequence_sort (priv->mounts, data_item_compare, mounts); + priv->dirty = FALSE; + } + iter = g_sequence_lookup (priv->mounts, &item, data_item_compare, mounts); + if (iter) { + g_sequence_remove (iter); + priv->dirty = TRUE; + } +} + /** * gst_rtsp_mount_points_add_factory: * @mounts: a #GstRTSPMountPoints @@ -333,6 +354,7 @@ gst_rtsp_mount_points_add_factory (GstRTSPMountPoints * mounts, GST_INFO ("adding media factory %p for path %s", factory, path); g_mutex_lock (&priv->lock); + gst_rtsp_mount_points_remove_factory_unlocked (mounts, path); g_sequence_append (priv->mounts, item); priv->dirty = TRUE; g_mutex_unlock (&priv->lock); @@ -350,27 +372,15 @@ gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints * mounts, const gchar * path) { GstRTSPMountPointsPrivate *priv; - DataItem item; - GSequenceIter *iter; g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts)); g_return_if_fail (path != NULL); priv = mounts->priv; - item.path = (gchar *) path; - GST_INFO ("removing media factory for path %s", path); g_mutex_lock (&priv->lock); - if (priv->dirty) { - g_sequence_sort (priv->mounts, data_item_compare, mounts); - priv->dirty = FALSE; - } - iter = g_sequence_lookup (priv->mounts, &item, data_item_compare, mounts); - if (iter) { - g_sequence_remove (iter); - priv->dirty = TRUE; - } + gst_rtsp_mount_points_remove_factory_unlocked (mounts, path); g_mutex_unlock (&priv->lock); } From 45e77ecdd7acbc58fdb8a4062487f7fd8e453cd3 Mon Sep 17 00:00:00 2001 From: Niels De Graef Date: Thu, 29 Aug 2019 07:34:26 +0200 Subject: [PATCH 1660/1776] Don't pass default GLib marshallers for signals By passing NULL to `g_signal_new` instead of a marshaller, GLib will actually internally optimize the signal (if the marshaller is available in GLib itself) by also setting the valist marshaller. This makes the signal emission a bit more performant than the regular marshalling, which still needs to box into `GValue` and call libffi in case of a generic marshaller. Note that for custom marshallers, one would use `g_signal_set_va_marshaller()` with the valist marshaller instead. --- gst/rtsp-server/rtsp-auth.c | 2 +- gst/rtsp-server/rtsp-client.c | 88 +++++++++++----------------- gst/rtsp-server/rtsp-media-factory.c | 4 +- gst/rtsp-server/rtsp-media.c | 21 ++++--- gst/rtsp-server/rtsp-server.c | 3 +- gst/rtsp-server/rtsp-session-pool.c | 4 +- gst/rtsp-server/rtsp-stream.c | 9 +-- gst/rtsp-sink/gstrtspclientsink.c | 11 ++-- 8 files changed, 59 insertions(+), 83 deletions(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index f676b804e4..c562ce6bcf 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -172,7 +172,7 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass) G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPAuthClass, accept_certificate), - g_signal_accumulator_true_handled, NULL, g_cclosure_marshal_generic, + g_signal_accumulator_true_handled, NULL, NULL, G_TYPE_BOOLEAN, 3, G_TYPE_TLS_CONNECTION, G_TYPE_TLS_CERTIFICATE, G_TYPE_TLS_CERTIFICATE_FLAGS); } diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 727e9426b6..cf469dde8f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -257,13 +257,13 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_CLOSED] = g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL, - g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE); + G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL, NULL, + G_TYPE_NONE, 0, G_TYPE_NONE); gst_rtsp_client_signals[SIGNAL_NEW_SESSION] = g_signal_new ("new-session", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstRTSPClientClass, new_session), NULL, NULL, - g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION); + G_STRUCT_OFFSET (GstRTSPClientClass, new_session), NULL, NULL, NULL, + G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION); /** * GstRTSPClient::pre-options-request: @@ -278,9 +278,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_PRE_OPTIONS_REQUEST] = g_signal_new ("pre-options-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - pre_options_request), pre_signal_accumulator, NULL, - g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, - GST_TYPE_RTSP_CONTEXT); + pre_options_request), pre_signal_accumulator, NULL, NULL, + GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::options-request: @@ -290,8 +289,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST] = g_signal_new ("options-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, options_request), - NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, - GST_TYPE_RTSP_CONTEXT); + NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::pre-describe-request: @@ -306,9 +304,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_PRE_DESCRIBE_REQUEST] = g_signal_new ("pre-describe-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - pre_describe_request), pre_signal_accumulator, NULL, - g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, - GST_TYPE_RTSP_CONTEXT); + pre_describe_request), pre_signal_accumulator, NULL, NULL, + GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::describe-request: @@ -318,8 +315,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST] = g_signal_new ("describe-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, describe_request), - NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, - GST_TYPE_RTSP_CONTEXT); + NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::pre-setup-request: @@ -334,9 +330,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_PRE_SETUP_REQUEST] = g_signal_new ("pre-setup-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - pre_setup_request), pre_signal_accumulator, NULL, - g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, - GST_TYPE_RTSP_CONTEXT); + pre_setup_request), pre_signal_accumulator, NULL, NULL, + GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::setup-request: @@ -346,8 +341,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST] = g_signal_new ("setup-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, setup_request), - NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, - GST_TYPE_RTSP_CONTEXT); + NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::pre-play-request: @@ -363,8 +357,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) g_signal_new ("pre-play-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, pre_play_request), pre_signal_accumulator, NULL, - g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, - GST_TYPE_RTSP_CONTEXT); + NULL, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::play-request: @@ -374,8 +367,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST] = g_signal_new ("play-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, play_request), - NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, - GST_TYPE_RTSP_CONTEXT); + NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::pre-pause-request: @@ -390,9 +382,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_PRE_PAUSE_REQUEST] = g_signal_new ("pre-pause-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - pre_pause_request), pre_signal_accumulator, NULL, - g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, - GST_TYPE_RTSP_CONTEXT); + pre_pause_request), pre_signal_accumulator, NULL, NULL, + GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::pause-request: @@ -402,8 +393,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST] = g_signal_new ("pause-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, pause_request), - NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, - GST_TYPE_RTSP_CONTEXT); + NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::pre-teardown-request: @@ -418,9 +408,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_PRE_TEARDOWN_REQUEST] = g_signal_new ("pre-teardown-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - pre_teardown_request), pre_signal_accumulator, NULL, - g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, - GST_TYPE_RTSP_CONTEXT); + pre_teardown_request), pre_signal_accumulator, NULL, NULL, + GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::teardown-request: @@ -430,8 +419,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST] = g_signal_new ("teardown-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, teardown_request), - NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, - GST_TYPE_RTSP_CONTEXT); + NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::pre-set-parameter-request: @@ -446,8 +434,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_PRE_SET_PARAMETER_REQUEST] = g_signal_new ("pre-set-parameter-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - pre_set_parameter_request), pre_signal_accumulator, NULL, - g_cclosure_marshal_generic, + pre_set_parameter_request), pre_signal_accumulator, NULL, NULL, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); /** @@ -458,7 +445,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST] = g_signal_new ("set-parameter-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - set_parameter_request), NULL, NULL, g_cclosure_marshal_generic, + set_parameter_request), NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); /** @@ -474,9 +461,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_PRE_GET_PARAMETER_REQUEST] = g_signal_new ("pre-get-parameter-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - pre_get_parameter_request), pre_signal_accumulator, NULL, - g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, - GST_TYPE_RTSP_CONTEXT); + pre_get_parameter_request), pre_signal_accumulator, NULL, NULL, + GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::get-parameter-request: @@ -486,7 +472,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST] = g_signal_new ("get-parameter-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - get_parameter_request), NULL, NULL, g_cclosure_marshal_generic, + get_parameter_request), NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); /** @@ -497,7 +483,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE] = g_signal_new ("handle-response", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - handle_response), NULL, NULL, g_cclosure_marshal_generic, + handle_response), NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); /** @@ -509,7 +495,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE] = g_signal_new ("send-message", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - send_message), NULL, NULL, g_cclosure_marshal_generic, + send_message), NULL, NULL, NULL, G_TYPE_NONE, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_POINTER); /** @@ -525,9 +511,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_PRE_ANNOUNCE_REQUEST] = g_signal_new ("pre-announce-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - pre_announce_request), pre_signal_accumulator, NULL, - g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, - GST_TYPE_RTSP_CONTEXT); + pre_announce_request), pre_signal_accumulator, NULL, NULL, + GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::announce-request: @@ -537,8 +522,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST] = g_signal_new ("announce-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, announce_request), - NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, - GST_TYPE_RTSP_CONTEXT); + NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::pre-record-request: @@ -553,9 +537,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_PRE_RECORD_REQUEST] = g_signal_new ("pre-record-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - pre_record_request), pre_signal_accumulator, NULL, - g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, - GST_TYPE_RTSP_CONTEXT); + pre_record_request), pre_signal_accumulator, NULL, NULL, + GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::record-request: @@ -565,8 +548,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST] = g_signal_new ("record-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, record_request), - NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, - GST_TYPE_RTSP_CONTEXT); + NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); /** * GstRTSPClient::check-requirements: @@ -583,7 +565,7 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) gst_rtsp_client_signals[SIGNAL_CHECK_REQUIREMENTS] = g_signal_new ("check-requirements", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, - check_requirements), NULL, NULL, g_cclosure_marshal_generic, + check_requirements), NULL, NULL, NULL, G_TYPE_STRING, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_STRV); tunnels = diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 58c8d39ebc..ec15d9d556 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -247,13 +247,13 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, - media_constructed), NULL, NULL, g_cclosure_marshal_generic, + media_constructed), NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA); gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE] = g_signal_new ("media-configure", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, - media_configure), NULL, NULL, g_cclosure_marshal_generic, + media_configure), NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA); klass->gen_key = default_gen_key; diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 8f1e438b2a..4516d536b8 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -412,34 +412,33 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, - g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_STREAM); + G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, NULL, + G_TYPE_NONE, 1, GST_TYPE_RTSP_STREAM); gst_rtsp_media_signals[SIGNAL_REMOVED_STREAM] = g_signal_new ("removed-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, removed_stream), - NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, - GST_TYPE_RTSP_STREAM); + NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_STREAM); gst_rtsp_media_signals[SIGNAL_PREPARED] = g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL, - g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE); + G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL, NULL, + G_TYPE_NONE, 0, G_TYPE_NONE); gst_rtsp_media_signals[SIGNAL_UNPREPARED] = g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL, - g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE); + G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL, NULL, + G_TYPE_NONE, 0, G_TYPE_NONE); gst_rtsp_media_signals[SIGNAL_TARGET_STATE] = g_signal_new ("target-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, target_state), - NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT); + NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); gst_rtsp_media_signals[SIGNAL_NEW_STATE] = g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL, - g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT); + G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_INT); GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index dd5d6d2e29..9d3cb584dc 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -243,8 +243,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass) gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED] = g_signal_new ("client-connected", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPServerClass, client_connected), - NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, - GST_TYPE_RTSP_CLIENT); + NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CLIENT); klass->create_client = default_create_client; diff --git a/gst/rtsp-server/rtsp-session-pool.c b/gst/rtsp-server/rtsp-session-pool.c index ad3c67e23f..e55c49fdff 100644 --- a/gst/rtsp-server/rtsp-session-pool.c +++ b/gst/rtsp-server/rtsp-session-pool.c @@ -114,8 +114,8 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass) gst_rtsp_session_pool_signals[SIGNAL_SESSION_REMOVED] = g_signal_new ("session-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPSessionPoolClass, - session_removed), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, - 1, GST_TYPE_RTSP_SESSION); + session_removed), NULL, NULL, NULL, G_TYPE_NONE, 1, + GST_TYPE_RTSP_SESSION); klass->create_session_id = create_session_id; klass->create_session = create_session; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index b00315f351..b89dc24608 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -277,18 +277,15 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass) gst_rtsp_stream_signals[SIGNAL_NEW_RTP_ENCODER] = g_signal_new ("new-rtp-encoder", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, - G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); gst_rtsp_stream_signals[SIGNAL_NEW_RTCP_ENCODER] = g_signal_new ("new-rtcp-encoder", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, - G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); gst_rtsp_stream_signals[SIGNAL_NEW_RTP_RTCP_DECODER] = g_signal_new ("new-rtp-rtcp-decoder", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, - G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); GST_DEBUG_CATEGORY_INIT (rtsp_stream_debug, "rtspstream", 0, "GstRTSPStream"); diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 8ddf70a2a2..85f379e931 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -739,8 +739,7 @@ gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) */ gst_rtsp_client_sink_signals[SIGNAL_HANDLE_REQUEST] = g_signal_new ("handle-request", G_TYPE_FROM_CLASS (klass), 0, - 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, - G_TYPE_POINTER, G_TYPE_POINTER); + 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); /** * GstRTSPClientSink::new-manager: @@ -753,8 +752,8 @@ gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) */ gst_rtsp_client_sink_signals[SIGNAL_NEW_MANAGER] = g_signal_new_class_handler ("new-manager", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, 0, NULL, NULL, - g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, GST_TYPE_ELEMENT); /** * GstRTSPClientSink::new-payloader: @@ -767,8 +766,8 @@ gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) */ gst_rtsp_client_sink_signals[SIGNAL_NEW_PAYLOADER] = g_signal_new_class_handler ("new-payloader", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, 0, NULL, NULL, - g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, GST_TYPE_ELEMENT); /** * GstRTSPClientSink::request-rtcp-key: From c2d182de057b4e21e7541b2149c673bbed82c74e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Imets?= Date: Wed, 6 Nov 2019 14:17:48 +0100 Subject: [PATCH 1661/1776] client test: add scale and speed negative tests Negative tests for scale and speed should be done as well, verify that the response code is "400 Bad request" when a bad request is done. --- tests/check/gst/client.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index dd7f5eeba2..6bf654419d 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -1851,7 +1851,8 @@ attach_rate_tweaking_probe (void) } static void -do_test_scale_and_speed (const gchar * scale, const gchar * speed) +do_test_scale_and_speed (const gchar * scale, const gchar * speed, + GstRTSPStatusCode expected_response_code) { GstRTSPClient *client; GstRTSPMessage request = { 0, }; @@ -1901,7 +1902,12 @@ do_test_scale_and_speed (const gchar * scale, const gchar * speed) if (speed != NULL) gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SPEED, speed); - gst_rtsp_client_set_send_func (client, test_response_scale_speed, NULL, NULL); + if (expected_response_code == GST_RTSP_STS_BAD_REQUEST) + gst_rtsp_client_set_send_func (client, test_response_400, NULL, NULL); + else + gst_rtsp_client_set_send_func (client, test_response_scale_speed, NULL, + NULL); + fail_unless (gst_rtsp_client_handle_message (client, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); @@ -1919,28 +1925,28 @@ GST_START_TEST (test_scale_and_speed) /* no scale/speed requested, no scale/speed should be received */ expected_scale_header = NULL; expected_speed_header = NULL; - do_test_scale_and_speed (NULL, NULL); + do_test_scale_and_speed (NULL, NULL, GST_RTSP_STS_OK); /* scale requested, scale should be received */ fake_applied_rate_value = 2; fake_rate_value = 1; expected_scale_header = "2.000"; expected_speed_header = NULL; - do_test_scale_and_speed ("2.000", NULL); + do_test_scale_and_speed ("2.000", NULL, GST_RTSP_STS_OK); /* speed requested, speed should be received */ fake_applied_rate_value = 0; fake_rate_value = 0; expected_scale_header = NULL; expected_speed_header = "2.000"; - do_test_scale_and_speed (NULL, "2.000"); + do_test_scale_and_speed (NULL, "2.000", GST_RTSP_STS_OK); /* both requested, both should be received */ fake_applied_rate_value = 2; fake_rate_value = 2; expected_scale_header = "2.000"; expected_speed_header = "2.000"; - do_test_scale_and_speed ("2", "2"); + do_test_scale_and_speed ("2", "2", GST_RTSP_STS_OK); /* scale requested but media doesn't handle scaling so both should be * received, with scale set to 1.000 and speed set to (requested scale @@ -1949,7 +1955,7 @@ GST_START_TEST (test_scale_and_speed) fake_rate_value = 5; expected_scale_header = "1.000"; expected_speed_header = "5.000"; - do_test_scale_and_speed ("5", NULL); + do_test_scale_and_speed ("5", NULL, GST_RTSP_STS_OK); /* both requested but media only handles scaling so both should be received, * with scale set to (requested scale * requested speed) and speed set to 1.00 @@ -1958,7 +1964,22 @@ GST_START_TEST (test_scale_and_speed) fake_applied_rate_value = 4.000; expected_scale_header = "4.000"; expected_speed_header = "1.000"; - do_test_scale_and_speed ("2", "2"); + do_test_scale_and_speed ("2", "2", GST_RTSP_STS_OK); + + /* test invalid values */ + fake_applied_rate_value = 0; + fake_rate_value = 0; + expected_scale_header = NULL; + expected_speed_header = NULL; + + /* scale or speed not decimal values */ + do_test_scale_and_speed ("x", NULL, GST_RTSP_STS_BAD_REQUEST); + do_test_scale_and_speed (NULL, "y", GST_RTSP_STS_BAD_REQUEST); + + /* scale or speed illegal decimal values */ + do_test_scale_and_speed ("0", NULL, GST_RTSP_STS_BAD_REQUEST); + do_test_scale_and_speed (NULL, "0", GST_RTSP_STS_BAD_REQUEST); + do_test_scale_and_speed (NULL, "-2", GST_RTSP_STS_BAD_REQUEST); } GST_END_TEST From 9c5ca231a64e460ac5c4f282bd0dacfbb6b3f33e Mon Sep 17 00:00:00 2001 From: Adam x Nilsson Date: Fri, 1 Nov 2019 12:01:41 +0100 Subject: [PATCH 1662/1776] rtsp-stream: Removing invalid transports returns false When removing transports an assertion was that the transports passed in for removal are present in the list, however that can't be assumed. As an example if a transport was removed from a thread running send_tcp_message, the main thread can try to remove the same transport again if it gets a handle_pause_request. This will not effect the transport list but it will effect n_tcp_transports as it will be decrement and then have the wrong value. --- gst/rtsp-server/rtsp-stream-transport.c | 9 +--- gst/rtsp-server/rtsp-stream.c | 17 +++++-- tests/check/gst/stream.c | 68 +++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 12 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index ff53283e33..4521fe5dba 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -28,7 +28,7 @@ * to handle the RTP and RTCP packets from the stream, for example when they * need to be sent over TCP. * - * With gst_rtsp_stream_transport_set_active() the transports are added and + * With gst_rtsp_stream_transport_set_active() the transports are added and * removed from the stream. * * A #GstRTSPStream will call gst_rtsp_stream_transport_keep_alive() when RTCP @@ -71,7 +71,6 @@ struct _GstRTSPStreamTransportPrivate GstRTSPKeepAliveFunc keep_alive; gpointer ka_user_data; GDestroyNotify ka_notify; - gboolean active; gboolean timed_out; GstRTSPMessageSentFunc message_sent; @@ -526,17 +525,11 @@ gst_rtsp_stream_transport_set_active (GstRTSPStreamTransport * trans, priv = trans->priv; - if (priv->active == active) - return FALSE; - if (active) res = gst_rtsp_stream_add_transport (priv->stream, trans); else res = gst_rtsp_stream_remove_transport (priv->stream, trans); - if (res) - priv->active = active; - return res; } diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index b89dc24608..4d17776b59 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4451,10 +4451,18 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, const GstRTSPTransport *tr; gchar *dest; gint min, max; + GList *tr_element; tr = gst_rtsp_stream_transport_get_transport (trans); dest = tr->destination; + tr_element = g_list_find (priv->transports, trans); + + if (add && tr_element) + return TRUE; + else if (!add && !tr_element) + return FALSE; + switch (tr->lower_transport) { case GST_RTSP_LOWER_TRANS_UDP_MCAST: { @@ -4483,9 +4491,9 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, if (!remove_mcast_client_addr (stream, dest, min, max)) GST_WARNING_OBJECT (stream, "Failed to remove multicast address: %s:%d-%d", dest, min, max); + priv->transports = g_list_delete_link (priv->transports, tr_element); remove_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min, max); - priv->transports = g_list_remove (priv->transports, trans); } break; } @@ -4507,8 +4515,8 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, priv->transports = g_list_prepend (priv->transports, trans); } else { GST_INFO ("removing %s:%d-%d", dest, min, max); + priv->transports = g_list_delete_link (priv->transports, tr_element); remove_client (priv->udpsink[0], priv->udpsink[1], dest, min, max); - priv->transports = g_list_remove (priv->transports, trans); } priv->transports_cookie++; break; @@ -4520,7 +4528,7 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, priv->n_tcp_transports++; } else { GST_INFO ("removing TCP %s", tr->destination); - priv->transports = g_list_remove (priv->transports, trans); + priv->transports = g_list_delete_link (priv->transports, tr_element); priv->n_tcp_transports--; } priv->transports_cookie++; @@ -4601,7 +4609,8 @@ on_message_sent (GstRTSPStreamTransport * trans, gpointer user_data) * @trans: (transfer none): a #GstRTSPStreamTransport * * Add the transport in @trans to @stream. The media of @stream will - * then also be send to the values configured in @trans. + * then also be send to the values configured in @trans. Adding the + * same transport twice will not add it a second time. * * @stream must be joined to a bin. * diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index d71f1937f4..112e80fc38 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -575,6 +575,72 @@ GST_START_TEST (test_multicast_client_address_invalid) GST_END_TEST; +static void +add_transports (gboolean add_twice) +{ + GstRTSPTransport *transport; + GstRTSPStream *stream; + GstRTSPStreamTransport *tr; + GstPad *srcpad; + GstElement *pay; + GstBin *bin; + GstElement *rtpbin; + + fail_unless (gst_rtsp_transport_new (&transport) == GST_RTSP_OK); + transport->lower_transport = GST_RTSP_LOWER_TRANS_TCP; + transport->destination = g_strdup ("127.0.0.1"); + srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC); + fail_unless (srcpad != NULL); + pay = gst_element_factory_make ("rtpgstpay", "testpayloader"); + fail_unless (pay != NULL); + stream = gst_rtsp_stream_new (0, pay, srcpad); + fail_unless (stream != NULL); + gst_object_unref (pay); + gst_object_unref (srcpad); + rtpbin = gst_element_factory_make ("rtpbin", "testrtpbin"); + fail_unless (rtpbin != NULL); + bin = GST_BIN (gst_bin_new ("testbin")); + fail_unless (bin != NULL); + fail_unless (gst_bin_add (bin, rtpbin)); + + /* TCP transport */ + gst_rtsp_stream_set_protocols (stream, GST_RTSP_LOWER_TRANS_TCP); + fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL)); + + tr = gst_rtsp_stream_transport_new (stream, transport); + fail_unless (tr); + + if (add_twice) { + fail_unless (gst_rtsp_stream_add_transport (stream, tr)); + fail_unless (gst_rtsp_stream_add_transport (stream, tr)); + fail_unless (gst_rtsp_stream_remove_transport (stream, tr)); + } else { + fail_unless (gst_rtsp_stream_add_transport (stream, tr)); + fail_unless (gst_rtsp_stream_remove_transport (stream, tr)); + fail_if (gst_rtsp_stream_remove_transport (stream, tr)); + } + + fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK); + fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin)); + gst_object_unref (bin); + gst_object_unref (stream); +} + + +GST_START_TEST (test_add_transport_twice) +{ + add_transports (TRUE); +} + +GST_END_TEST; + +GST_START_TEST (test_remove_transport_twice) +{ + add_transports (FALSE); +} + +GST_END_TEST; + static Suite * rtspstream_suite (void) { @@ -592,6 +658,8 @@ rtspstream_suite (void) tcase_add_test (tc, test_tcp_transport); tcase_add_test (tc, test_multicast_client_address); tcase_add_test (tc, test_multicast_client_address_invalid); + tcase_add_test (tc, test_add_transport_twice); + tcase_add_test (tc, test_remove_transport_twice); return s; } From 5ceb2cf83f1d92384ec8588c522920c91da547df Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 27 Nov 2019 15:22:35 +0100 Subject: [PATCH 1663/1776] rtsp-sdp: Don't try to use non-initialized values Only attempt to use the various timing values iif gst_rtsp_stream_get_info() returns TRUE. Also avoid the whole clock signalling block if we're not dealing with senders. CID: 1439524 CID: 1439536 CID: 1439520 --- gst/rtsp-server/rtsp-sdp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 701cea5c1e..9a2a247b40 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -295,7 +295,7 @@ gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info, } /* RFC 7273 clock signalling */ - { + if (gst_rtsp_stream_is_sender (stream)) { GstBin *joined_bin = gst_rtsp_stream_get_joined_bin (stream); GstClock *clock = gst_element_get_clock (GST_ELEMENT_CAST (joined_bin)); gchar *ts_refclk = NULL; @@ -305,9 +305,9 @@ gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPPublishClockMode publish_clock_mode = gst_rtsp_stream_get_publish_clock_mode (stream); - if (gst_rtsp_stream_is_sender (stream)) - gst_rtsp_stream_get_rtpinfo (stream, &rtptime, NULL, &clock_rate, - &running_time); + if (!gst_rtsp_stream_get_rtpinfo (stream, &rtptime, NULL, &clock_rate, + &running_time)) + goto clock_signalling_cleanup; base_time = gst_element_get_base_time (GST_ELEMENT_CAST (joined_bin)); g_assert (base_time != GST_CLOCK_TIME_NONE); clock_time = running_time + base_time; @@ -374,6 +374,7 @@ gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info, } } } + clock_signalling_cleanup: if (clock) gst_object_unref (clock); From 8de843733d5fc41a53839c1f1e35829142eea586 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 21 Nov 2019 17:12:45 +0100 Subject: [PATCH 1664/1776] rtsp-client: Revitalize dead code Leftover from 65d9aa327cd1844934836249cd4463edf09c725d CID: 1455379 --- gst/rtsp-server/rtsp-client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index cf469dde8f..d542af8e6c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1877,6 +1877,10 @@ setup_play_mode (GstRTSPClient * client, GstRTSPContext * ctx, } else { flags = GST_SEEK_FLAG_KEY_UNIT; } + + if (seek_style) + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_SEEK_STYLE, + seek_style); } else { flags = GST_SEEK_FLAG_ACCURATE; } @@ -1954,7 +1958,6 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT; gchar *path, *rtpinfo = NULL; gint matched; - gchar *seek_style = NULL; GstRTSPStatusCode sig_result; GPtrArray *transports; gboolean scale_present; @@ -2032,9 +2035,6 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) if (rtpinfo) gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO, rtpinfo); - if (seek_style) - gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_SEEK_STYLE, - seek_style); /* add the range */ str = gst_rtsp_media_get_range_string (media, TRUE, unit); From faf8f87a020fefdbfdbe5475c6762423067d85e5 Mon Sep 17 00:00:00 2001 From: Kristofer Bjorkstrom Date: Fri, 6 Dec 2019 10:44:35 +0100 Subject: [PATCH 1665/1776] rtsp-media: Force seek when flush flag is set The commit "rtsp-client: define all seek accuracy flags from setup_play_mode" changed the behaviour of when doing a seek. Before that commit, having the flush flag set would result in a seek (forced seek). Even if no seek was needed. One reason to force seek is to flush old buffers created in Describe requests. Thus adding force seek also for flush flag will result in play request with fresh buffers. --- gst/rtsp-server/rtsp-media.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 4516d536b8..260ee6d4cc 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2817,9 +2817,10 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, if (stop != GST_CLOCK_TIME_NONE) stop_type = GST_SEEK_TYPE_SET; - /* we force a seek if any trickmode flag is set, or if the rate - * is non-standard, i.e. not 1.0 */ - force_seek = (flags & TRICKMODE_FLAGS) || rate != 1.0; + /* we force a seek if any trickmode flag is set, or if the flush flag is set or + * the rate is non-standard, i.e. not 1.0 */ + force_seek = (flags & TRICKMODE_FLAGS) || (flags & GST_SEEK_FLAG_FLUSH) || + rate != 1.0; if (start != GST_CLOCK_TIME_NONE || stop != GST_CLOCK_TIME_NONE || force_seek) { GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, From 8d4a9f37e506929808106b361dc6af02ee8d1984 Mon Sep 17 00:00:00 2001 From: Adam x Nilsson Date: Mon, 9 Dec 2019 14:17:05 +0100 Subject: [PATCH 1666/1776] gstrtspclientsink: unref transports when closing bin Fixes #91 --- gst/rtsp-sink/gstrtspclientsink.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 85f379e931..60b6e52e1b 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -3360,8 +3360,11 @@ gst_rtsp_client_sink_close (GstRTSPClientSink * sink, gboolean async, for (walk = sink->contexts; walk; walk = g_list_next (walk)) { GstRTSPStreamContext *context = (GstRTSPStreamContext *) walk->data; - if (context->stream_transport) + if (context->stream_transport) { gst_rtsp_stream_transport_set_active (context->stream_transport, FALSE); + gst_object_unref (context->stream_transport); + context->stream_transport = NULL; + } if (context->joined) { gst_rtsp_stream_leave_bin (context->stream, GST_BIN (sink->internal_bin), From a547e2b3c867aad406a4862563b5614777630084 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Thu, 12 Dec 2019 17:56:18 +0100 Subject: [PATCH 1667/1776] rtsp-auth: fix default token leak --- gst/rtsp-server/rtsp-auth.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index c562ce6bcf..ad0be07dd9 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -214,6 +214,8 @@ gst_rtsp_auth_finalize (GObject * obj) g_hash_table_unref (priv->basic); g_hash_table_unref (priv->digest); g_hash_table_unref (priv->nonces); + if (priv->default_token) + gst_rtsp_token_unref (priv->default_token); g_mutex_clear (&priv->lock); g_free (priv->realm); From 75b03ddf5ea094970248622143246883cf353197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 10 Dec 2019 18:39:32 -0500 Subject: [PATCH 1668/1776] rtsp-session & client: Remove deprecated GTimeVal GTimeVal won't work past 2038 --- gst/rtsp-server/rtsp-session.c | 4 +++ gst/rtsp-server/rtsp-session.h | 2 ++ gst/rtsp-sink/gstrtspclientsink.c | 51 ++++++++++++------------------- gst/rtsp-sink/gstrtspclientsink.h | 3 +- 4 files changed, 27 insertions(+), 33 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index 73671b6aea..f2fbbc9a99 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -717,6 +717,7 @@ gst_rtsp_session_next_timeout_usec (GstRTSPSession * session, gint64 now) * Deprecated: Use gst_rtsp_session_next_timeout_usec() instead. */ #ifndef GST_REMOVE_DEPRECATED +G_GNUC_BEGIN_IGNORE_DEPRECATIONS gint gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) { @@ -755,6 +756,7 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) return res; } +G_GNUC_END_IGNORE_DEPRECATIONS #endif /** @@ -791,6 +793,7 @@ gst_rtsp_session_is_expired_usec (GstRTSPSession * session, gint64 now) * Deprecated: Use gst_rtsp_session_is_expired_usec() instead. */ #ifndef GST_REMOVE_DEPRECATED +G_GNUC_BEGIN_IGNORE_DEPRECATIONS gboolean gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) { @@ -801,4 +804,5 @@ gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) return res; } +G_GNUC_END_IGNORE_DEPRECATIONS #endif diff --git a/gst/rtsp-server/rtsp-session.h b/gst/rtsp-server/rtsp-session.h index e2a46e6817..56063f41a2 100644 --- a/gst/rtsp-server/rtsp-session.h +++ b/gst/rtsp-server/rtsp-session.h @@ -117,11 +117,13 @@ gint gst_rtsp_session_next_timeout_usec (GstRTSPSession *se GST_RTSP_SERVER_API gboolean gst_rtsp_session_is_expired_usec (GstRTSPSession *session, gint64 now); +G_GNUC_BEGIN_IGNORE_DEPRECATIONS GST_RTSP_SERVER_DEPRECATED_FOR(gst_rtsp_session_next_timeout_usec) gint gst_rtsp_session_next_timeout (GstRTSPSession *session, GTimeVal *now); GST_RTSP_SERVER_DEPRECATED_FOR(gst_rtsp_session_is_expired_usec) gboolean gst_rtsp_session_is_expired (GstRTSPSession *session, GTimeVal *now); +G_GNUC_END_IGNORE_DEPRECATIONS /* handle media in a session */ diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 60b6e52e1b..19f9cda441 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -1550,13 +1550,7 @@ static void gst_rtsp_client_sink_set_tcp_timeout (GstRTSPClientSink * rtsp_client_sink, guint64 timeout) { - rtsp_client_sink->tcp_timeout.tv_sec = timeout / G_USEC_PER_SEC; - rtsp_client_sink->tcp_timeout.tv_usec = timeout % G_USEC_PER_SEC; - - if (timeout != 0) - rtsp_client_sink->ptcp_timeout = &rtsp_client_sink->tcp_timeout; - else - rtsp_client_sink->ptcp_timeout = NULL; + rtsp_client_sink->tcp_timeout = timeout; } static void @@ -1709,14 +1703,8 @@ gst_rtsp_client_sink_get_property (GObject * object, guint prop_id, g_value_set_uint64 (value, rtsp_client_sink->udp_timeout); break; case PROP_TCP_TIMEOUT: - { - guint64 timeout; - - timeout = rtsp_client_sink->tcp_timeout.tv_sec * G_USEC_PER_SEC + - rtsp_client_sink->tcp_timeout.tv_usec; - g_value_set_uint64 (value, timeout); + g_value_set_uint64 (value, rtsp_client_sink->tcp_timeout); break; - } case PROP_LATENCY: g_value_set_uint (value, rtsp_client_sink->latency); break; @@ -1890,13 +1878,14 @@ gst_rtsp_client_sink_cleanup (GstRTSPClientSink * sink) static GstRTSPResult gst_rtsp_client_sink_connection_send (GstRTSPClientSink * sink, - GstRTSPConnInfo * conninfo, GstRTSPMessage * message, GTimeVal * timeout) + GstRTSPConnInfo * conninfo, GstRTSPMessage * message, gint64 timeout) { GstRTSPResult ret; if (conninfo->connection) { g_mutex_lock (&conninfo->send_lock); - ret = gst_rtsp_connection_send (conninfo->connection, message, timeout); + ret = + gst_rtsp_connection_send_usec (conninfo->connection, message, timeout); g_mutex_unlock (&conninfo->send_lock); } else { ret = GST_RTSP_ERROR; @@ -1908,14 +1897,14 @@ gst_rtsp_client_sink_connection_send (GstRTSPClientSink * sink, static GstRTSPResult gst_rtsp_client_sink_connection_send_messages (GstRTSPClientSink * sink, GstRTSPConnInfo * conninfo, GstRTSPMessage * messages, guint n_messages, - GTimeVal * timeout) + gint64 timeout) { GstRTSPResult ret; if (conninfo->connection) { g_mutex_lock (&conninfo->send_lock); ret = - gst_rtsp_connection_send_messages (conninfo->connection, messages, + gst_rtsp_connection_send_messages_usec (conninfo->connection, messages, n_messages, timeout); g_mutex_unlock (&conninfo->send_lock); } else { @@ -1927,13 +1916,14 @@ gst_rtsp_client_sink_connection_send_messages (GstRTSPClientSink * sink, static GstRTSPResult gst_rtsp_client_sink_connection_receive (GstRTSPClientSink * sink, - GstRTSPConnInfo * conninfo, GstRTSPMessage * message, GTimeVal * timeout) + GstRTSPConnInfo * conninfo, GstRTSPMessage * message, gint64 timeout) { GstRTSPResult ret; if (conninfo->connection) { g_mutex_lock (&conninfo->recv_lock); - ret = gst_rtsp_connection_receive (conninfo->connection, message, timeout); + ret = gst_rtsp_connection_receive_usec (conninfo->connection, message, + timeout); g_mutex_unlock (&conninfo->recv_lock); } else { ret = GST_RTSP_ERROR; @@ -2014,8 +2004,8 @@ gst_rtsp_conninfo_connect (GstRTSPClientSink * sink, GstRTSPConnInfo * info, ("Connecting to %s", info->location)); GST_DEBUG_OBJECT (sink, "connecting (%s)...", info->location); if ((res = - gst_rtsp_connection_connect (info->connection, - sink->ptcp_timeout)) < 0) + gst_rtsp_connection_connect_usec (info->connection, + sink->tcp_timeout)) < 0) goto could_not_connect; info->connected = TRUE; @@ -2150,7 +2140,7 @@ gst_rtsp_client_sink_handle_request (GstRTSPClientSink * sink, if (sink->debug) gst_rtsp_message_dump (&response); - res = gst_rtsp_client_sink_connection_send (sink, conninfo, &response, NULL); + res = gst_rtsp_client_sink_connection_send (sink, conninfo, &response, 0); if (res < 0) goto send_error; @@ -2201,8 +2191,7 @@ gst_rtsp_client_sink_send_keep_alive (GstRTSPClientSink * sink) gst_rtsp_message_dump (&request); res = - gst_rtsp_client_sink_connection_send (sink, &sink->conninfo, - &request, NULL); + gst_rtsp_client_sink_connection_send (sink, &sink->conninfo, &request, 0); if (res < 0) goto send_error; @@ -2237,13 +2226,13 @@ gst_rtsp_client_sink_loop_rx (GstRTSPClientSink * sink) gint retry = 0; while (TRUE) { - GTimeVal tv_timeout; + gint64 timeout; /* get the next timeout interval */ - gst_rtsp_connection_next_timeout (sink->conninfo.connection, &tv_timeout); + timeout = gst_rtsp_connection_next_timeout_usec (sink->conninfo.connection); GST_DEBUG_OBJECT (sink, "doing receive with timeout %d seconds", - (gint) tv_timeout.tv_sec); + (gint) timeout / G_USEC_PER_SEC); gst_rtsp_message_unset (&message); @@ -2252,7 +2241,7 @@ gst_rtsp_client_sink_loop_rx (GstRTSPClientSink * sink) * keep-alive request to keep the session open. */ res = gst_rtsp_client_sink_connection_receive (sink, - &sink->conninfo, &message, &tv_timeout); + &sink->conninfo, &message, timeout); switch (res) { case GST_RTSP_OK: @@ -2831,7 +2820,7 @@ again: res = gst_rtsp_client_sink_connection_send_messages (sink, conninfo, requests, - n_requests, sink->ptcp_timeout); + n_requests, sink->tcp_timeout); if (res < 0) { g_mutex_unlock (&sink->send_lock); goto send_error; @@ -2847,7 +2836,7 @@ again: next: res = gst_rtsp_client_sink_connection_receive (sink, conninfo, response, - sink->ptcp_timeout); + sink->tcp_timeout); g_mutex_unlock (&sink->send_lock); diff --git a/gst/rtsp-sink/gstrtspclientsink.h b/gst/rtsp-sink/gstrtspclientsink.h index f7845c03fa..e736b68f46 100644 --- a/gst/rtsp-sink/gstrtspclientsink.h +++ b/gst/rtsp-sink/gstrtspclientsink.h @@ -162,8 +162,7 @@ struct _GstRTSPClientSink { gboolean debug; guint retry; guint64 udp_timeout; - GTimeVal tcp_timeout; - GTimeVal *ptcp_timeout; + gint64 tcp_timeout; guint latency; gboolean do_rtsp_keep_alive; gchar *proxy_host; From 73b4929803fc9beab257d565eff6768cc52f2e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 10 Dec 2019 19:16:51 -0500 Subject: [PATCH 1669/1776] rtsp-session: Butcher the file to please gst-indent in the CI This should be reverted once the CI has an updated gst-indent. --- gst/rtsp-server/rtsp-session.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-session.c b/gst/rtsp-server/rtsp-session.c index f2fbbc9a99..b21d615e46 100644 --- a/gst/rtsp-server/rtsp-session.c +++ b/gst/rtsp-server/rtsp-session.c @@ -717,8 +717,7 @@ gst_rtsp_session_next_timeout_usec (GstRTSPSession * session, gint64 now) * Deprecated: Use gst_rtsp_session_next_timeout_usec() instead. */ #ifndef GST_REMOVE_DEPRECATED -G_GNUC_BEGIN_IGNORE_DEPRECATIONS -gint +G_GNUC_BEGIN_IGNORE_DEPRECATIONS gint gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) { GstRTSPSessionPrivate *priv; @@ -756,9 +755,9 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now) return res; } + G_GNUC_END_IGNORE_DEPRECATIONS #endif - /** * gst_rtsp_session_is_expired_usec: * @session: a #GstRTSPSession @@ -768,7 +767,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS * * Returns: %TRUE if @session timed out */ -gboolean + gboolean gst_rtsp_session_is_expired_usec (GstRTSPSession * session, gint64 now) { gboolean res; @@ -793,8 +792,7 @@ gst_rtsp_session_is_expired_usec (GstRTSPSession * session, gint64 now) * Deprecated: Use gst_rtsp_session_is_expired_usec() instead. */ #ifndef GST_REMOVE_DEPRECATED -G_GNUC_BEGIN_IGNORE_DEPRECATIONS -gboolean +G_GNUC_BEGIN_IGNORE_DEPRECATIONS gboolean gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) { gboolean res; @@ -804,5 +802,6 @@ gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now) return res; } + G_GNUC_END_IGNORE_DEPRECATIONS #endif From e0a4355d6bf80c0fbebc874351884b21c1d21ca1 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 9 Jan 2020 14:10:44 +0100 Subject: [PATCH 1670/1776] rtsp-stream: fix checking of TCP backpressure The internal index of our appsinks, while it can be used to determine whether a message is RTP or RTCP, is not necessarily the same as the interleaved channel. Let the stream-transport determine the channel to check backpressure for, the same way it determines the channel according to whether it is sending RTP or RTCP. --- gst/rtsp-server/rtsp-server-internal.h | 2 +- gst/rtsp-server/rtsp-stream-transport.c | 8 +++++++- gst/rtsp-server/rtsp-stream.c | 10 +++++----- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-server/rtsp-server-internal.h b/gst/rtsp-server/rtsp-server-internal.h index 6650b875f0..13defeefef 100644 --- a/gst/rtsp-server/rtsp-server-internal.h +++ b/gst/rtsp-server/rtsp-server-internal.h @@ -48,7 +48,7 @@ void gst_rtsp_stream_transport_set_back_pressure_callback (G GDestroyNotify notify); gboolean gst_rtsp_stream_transport_check_back_pressure (GstRTSPStreamTransport *trans, - guint8 channel); + gboolean is_rtp); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 4521fe5dba..e30e44096c 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -296,13 +296,19 @@ gst_rtsp_stream_transport_set_back_pressure_callback (GstRTSPStreamTransport * gboolean gst_rtsp_stream_transport_check_back_pressure (GstRTSPStreamTransport * trans, - guint8 channel) + gboolean is_rtp) { GstRTSPStreamTransportPrivate *priv; gboolean ret = FALSE; + guint8 channel; priv = trans->priv; + if (is_rtp) + channel = priv->transport->interleaved.min; + else + channel = priv->transport->interleaved.max; + if (priv->back_pressure_func) ret = priv->back_pressure_func (channel, priv->back_pressure_func_data); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 4d17776b59..7c0a61368a 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2468,7 +2468,7 @@ clear_tr_cache (GstRTSPStreamPrivate * priv) /* With lock taken */ static gboolean -any_transport_ready (GstRTSPStream * stream, guint8 channel) +any_transport_ready (GstRTSPStream * stream, gboolean is_rtp) { gboolean ret = TRUE; GstRTSPStreamPrivate *priv = stream->priv; @@ -2482,7 +2482,7 @@ any_transport_ready (GstRTSPStream * stream, guint8 channel) for (index = 0; index < transports->len; index++) { GstRTSPStreamTransport *tr = g_ptr_array_index (transports, index); - if (!gst_rtsp_stream_transport_check_back_pressure (tr, channel)) { + if (!gst_rtsp_stream_transport_check_back_pressure (tr, is_rtp)) { ret = TRUE; break; } else { @@ -2565,7 +2565,9 @@ send_tcp_message (GstRTSPStream * stream, gint idx) ensure_cached_transports (stream); - if (!any_transport_ready (stream, idx)) + is_rtp = (idx == 0); + + if (!any_transport_ready (stream, is_rtp)) return; priv->have_buffer[idx] = FALSE; @@ -2591,8 +2593,6 @@ send_tcp_message (GstRTSPStream * stream, gint idx) if (buffer_list) n_messages += 1; - is_rtp = (idx == 0); - transports = priv->tr_cache; g_ptr_array_ref (transports); From 0ed32e0d536ea5851fe2e5a71dcc46884c3f39f6 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Sat, 11 Jan 2020 22:58:48 +0100 Subject: [PATCH 1671/1776] rtsp-stream: check for NULL transports prior to ref'ing --- gst/rtsp-server/rtsp-stream.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 7c0a61368a..30203ad3f5 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2594,7 +2594,8 @@ send_tcp_message (GstRTSPStream * stream, gint idx) n_messages += 1; transports = priv->tr_cache; - g_ptr_array_ref (transports); + if (transports) + g_ptr_array_ref (transports); g_mutex_unlock (&priv->lock); From aa8126b23961b6d57cf9a80a2214cfcc028a61a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Imets?= Date: Tue, 17 Dec 2019 16:08:19 +0100 Subject: [PATCH 1672/1776] rtsp-client: add property post-session-timeout This is a TCP connection timeout for client connections, in seconds. If a positive value is set for this property, the client connection will be kept alive for this amount of seconds after the last session timeout. For negative values of this property the connection timeout handling is delegated to the system (just as it was before). Fixes #83 --- gst/rtsp-server/rtsp-client.c | 70 ++++++++++++++++++++++++ tests/check/gst/rtspserver.c | 100 ++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d542af8e6c..b7b6f18cb4 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -103,6 +103,7 @@ struct _GstRTSPClientPrivate guint sessions_cookie; gboolean drop_backlog; + gint post_session_timeout; guint content_length_limit; @@ -130,6 +131,7 @@ static GHashTable *tunnels; /* protected by tunnels_lock */ #define DEFAULT_SESSION_POOL NULL #define DEFAULT_MOUNT_POINTS NULL #define DEFAULT_DROP_BACKLOG TRUE +#define DEFAULT_POST_SESSION_TIMEOUT -1 #define RTSP_CTRL_CB_INTERVAL 1 #define RTSP_CTRL_TIMEOUT_VALUE 60 @@ -140,6 +142,7 @@ enum PROP_SESSION_POOL, PROP_MOUNT_POINTS, PROP_DROP_BACKLOG, + PROP_POST_SESSION_TIMEOUT, PROP_LAST }; @@ -255,6 +258,26 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) "Drop data when the backlog queue is full", DEFAULT_DROP_BACKLOG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPClient::post-session-timeout: + * + * An extra tcp timeout ( > 0) after session timeout, in seconds. + * The tcp connection will be kept alive until this timeout happens to give + * the client a possibility to reuse the connection. + * 0 means that the connection will be closed immediately after the session + * timeout. + * + * Default value is -1 seconds, meaning that we let the system close + * the connection. + * + * Since: 1.18 + */ + g_object_class_install_property (gobject_class, PROP_POST_SESSION_TIMEOUT, + g_param_spec_int ("post-session-timeout", "Post Session Timeout", + "An extra TCP connection timeout after session timeout", G_MININT, + G_MAXINT, DEFAULT_POST_SESSION_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_client_signals[SIGNAL_CLOSED] = g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL, NULL, @@ -588,6 +611,7 @@ gst_rtsp_client_init (GstRTSPClient * client) priv->close_seq = 0; priv->data_seqs = g_array_new (FALSE, FALSE, sizeof (DataSeq)); priv->drop_backlog = DEFAULT_DROP_BACKLOG; + priv->post_session_timeout = DEFAULT_POST_SESSION_TIMEOUT; priv->transports = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); @@ -807,6 +831,9 @@ gst_rtsp_client_get_property (GObject * object, guint propid, case PROP_DROP_BACKLOG: g_value_set_boolean (value, priv->drop_backlog); break; + case PROP_POST_SESSION_TIMEOUT: + g_value_set_int (value, priv->post_session_timeout); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -831,6 +858,11 @@ gst_rtsp_client_set_property (GObject * object, guint propid, priv->drop_backlog = g_value_get_boolean (value); g_mutex_unlock (&priv->lock); break; + case PROP_POST_SESSION_TIMEOUT: + g_mutex_lock (&priv->lock); + priv->post_session_timeout = g_value_get_int (value); + g_mutex_unlock (&priv->lock); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -2531,6 +2563,23 @@ rtsp_ctrl_timeout_cb (gpointer user_data) return res; } +static gboolean +rtsp_ctrl_connection_timeout_cb (gpointer user_data) +{ + GstRTSPClient *client = (GstRTSPClient *) user_data; + GstRTSPClientPrivate *priv = client->priv; + + GST_DEBUG ("rtsp control connection timeout id=%u expired, closing client.", + priv->rtsp_ctrl_timeout_id); + g_mutex_lock (&priv->lock); + priv->rtsp_ctrl_timeout_id = 0; + priv->rtsp_ctrl_timeout_cnt = 0; + g_mutex_unlock (&priv->lock); + gst_rtsp_client_close (client); + + return G_SOURCE_REMOVE; +} + static void rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv) { @@ -3694,12 +3743,33 @@ client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session, GstRTSPClient * client) { GstRTSPClientPrivate *priv = client->priv; + GSource *timer_src; GST_INFO ("client %p: session %p removed", client, session); g_mutex_lock (&priv->lock); client_unwatch_session (client, session, NULL); g_mutex_unlock (&priv->lock); + + if (!priv->sessions && priv->rtsp_ctrl_timeout_id == 0) { + if (priv->post_session_timeout > 0) { + g_mutex_lock (&priv->lock); + + timer_src = g_timeout_source_new_seconds (priv->post_session_timeout); + g_source_set_callback (timer_src, rtsp_ctrl_connection_timeout_cb, + client, NULL); + priv->rtsp_ctrl_timeout_cnt = 0; + priv->rtsp_ctrl_timeout_id = g_source_attach (timer_src, + priv->watch_context); + g_source_unref (timer_src); + GST_DEBUG ("rtsp control setting up connection timeout id=%u.", + priv->rtsp_ctrl_timeout_id); + + g_mutex_unlock (&priv->lock); + } else if (priv->post_session_timeout == 0) { + gst_rtsp_client_close (client); + } + } } /* Check for Require headers. Returns TRUE if there are no Require headers, diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 82d007f9f7..9b691b2314 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1643,6 +1643,105 @@ GST_START_TEST (test_play_multithreaded_timeout_session) GST_END_TEST; +static void +new_connection_and_session_timeout_one (GstRTSPClient * client, + GstRTSPSession * session, gpointer user_data) +{ + gint ps_timeout = 0; + + g_object_set (G_OBJECT (client), "post-session-timeout", 1, NULL); + g_object_get (G_OBJECT (client), "post-session-timeout", &ps_timeout, NULL); + fail_unless_equals_int (ps_timeout, 1); + + g_object_set (G_OBJECT (session), "extra-timeout", 0, NULL); + gst_rtsp_session_set_timeout (session, 1); + + g_signal_handlers_disconnect_by_func (client, + new_connection_and_session_timeout_one, user_data); +} + +GST_START_TEST (test_play_timeout_connection) +{ + GstRTSPConnection *conn; + GstSDPMessage *sdp_message = NULL; + const GstSDPMedia *sdp_media; + const gchar *video_control; + GstRTSPRange client_port; + gchar *session = NULL; + GstRTSPTransport *video_transport = NULL; + GstRTSPSessionPool *pool; + GstRTSPThreadPool *thread_pool; + GstRTSPMessage *request; + GstRTSPMessage *response; + + thread_pool = gst_rtsp_server_get_thread_pool (server); + g_object_unref (thread_pool); + + pool = gst_rtsp_server_get_session_pool (server); + g_signal_connect (server, "client-connected", + G_CALLBACK (session_connected_new_session_cb), + new_connection_and_session_timeout_one); + + start_server (FALSE); + + + conn = connect_to_server (test_port, TEST_MOUNT_POINT); + + gst_rtsp_connection_set_remember_session_id (conn, FALSE); + + sdp_message = do_describe (conn, TEST_MOUNT_POINT); + + /* get control strings from DESCRIBE response */ + fail_unless (gst_sdp_message_medias_len (sdp_message) == 2); + sdp_media = gst_sdp_message_get_media (sdp_message, 0); + video_control = gst_sdp_media_get_attribute_val (sdp_media, "control"); + + get_client_ports (&client_port); + + /* do SETUP for video and audio */ + fail_unless (do_setup (conn, video_control, &client_port, &session, + &video_transport) == GST_RTSP_STS_OK); + fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 1); + /* send PLAY request and check that we get 200 OK */ + fail_unless (do_simple_request (conn, GST_RTSP_PLAY, + session) == GST_RTSP_STS_OK); + sleep (2); + fail_unless (gst_rtsp_session_pool_cleanup (pool) == 1); + sleep (2); + + request = create_request (conn, GST_RTSP_TEARDOWN, NULL); + + /* add headers */ + if (session) { + gst_rtsp_message_add_header (request, GST_RTSP_HDR_SESSION, session); + } + + /* send request */ + fail_unless (send_request (conn, request)); + gst_rtsp_message_free (request); + + iterate (); + + /* read response */ + response = read_response (conn); + fail_unless (response == NULL); + + if (response) { + gst_rtsp_message_free (response); + } + + /* clean up and iterate so the clean-up can finish */ + g_object_unref (pool); + g_free (session); + gst_rtsp_transport_free (video_transport); + gst_sdp_message_free (sdp_message); + gst_rtsp_connection_free (conn); + + stop_server (); + iterate (); +} + +GST_END_TEST; GST_START_TEST (test_no_session_timeout) { @@ -2631,6 +2730,7 @@ rtspserver_suite (void) tcase_add_test (tc, test_play_multithreaded_block_in_describe); tcase_add_test (tc, test_play_multithreaded_timeout_client); tcase_add_test (tc, test_play_multithreaded_timeout_session); + tcase_add_test (tc, test_play_timeout_connection); tcase_add_test (tc, test_no_session_timeout); tcase_add_test (tc, test_play_one_active_stream); tcase_add_test (tc, test_play_disconnect); From b4948f69a03846559ceb0cdc41bed8ea84690474 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Thu, 23 Jan 2020 16:41:26 +0200 Subject: [PATCH 1673/1776] rtsp-latency-bin: replace G_TYPE_INSTANCE_GET_PRIVATE as it's been deprecated from glib ``` Deprecated: 2.58: Use %G_ADD_PRIVATE and the generated `your_type_get_instance_private()` function instead ``` --- gst/rtsp-server/rtsp-latency-bin.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/gst/rtsp-server/rtsp-latency-bin.c b/gst/rtsp-server/rtsp-latency-bin.c index cf7cdf1c33..c297ab63ee 100644 --- a/gst/rtsp-server/rtsp-latency-bin.c +++ b/gst/rtsp-server/rtsp-latency-bin.c @@ -23,9 +23,6 @@ #include #include "rtsp-latency-bin.h" -#define GST_RTSP_LATENCY_BIN_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_RTSP_LATENCY_BIN_TYPE, GstRTSPLatencyBinPrivate)) - struct _GstRTSPLatencyBinPrivate { GstPad *sinkpad; @@ -106,7 +103,7 @@ gst_rtsp_latency_bin_get_property (GObject * object, guint propid, { GstRTSPLatencyBin *latency_bin = GST_RTSP_LATENCY_BIN (object); GstRTSPLatencyBinPrivate *priv = - GST_RTSP_LATENCY_BIN_GET_PRIVATE (latency_bin); + gst_rtsp_latency_bin_get_instance_private (latency_bin); switch (propid) { case PROP_ELEMENT: @@ -140,7 +137,7 @@ gst_rtsp_latency_bin_add_element (GstRTSPLatencyBin * latency_bin, GstElement * element) { GstRTSPLatencyBinPrivate *priv = - GST_RTSP_LATENCY_BIN_GET_PRIVATE (latency_bin); + gst_rtsp_latency_bin_get_instance_private (latency_bin); GstPad *pad; GstPadTemplate *templ; @@ -250,7 +247,7 @@ static gboolean gst_rtsp_latency_bin_recalculate_latency (GstRTSPLatencyBin * latency_bin) { GstRTSPLatencyBinPrivate *priv = - GST_RTSP_LATENCY_BIN_GET_PRIVATE (latency_bin); + gst_rtsp_latency_bin_get_instance_private (latency_bin); GstEvent *latency; GstQuery *query; GstClockTime min_latency; From 90f7e851f43e83d2f8759675f0c8e9f289a8b3cf Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 15 Jan 2020 17:06:41 +0100 Subject: [PATCH 1674/1776] rtsp-client: make closing more thread safe + Take the watch lock prior to using priv->watch + Flush both the watch and connection before closing / unreffing gst_rtsp_connection_close() is not threadsafe on its own, this is a workaround at the client level, where we control both the watch and the connection --- gst/rtsp-server/rtsp-client.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b7b6f18cb4..1339bd976b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1292,6 +1292,13 @@ gst_rtsp_client_close (GstRTSPClient * client) GST_DEBUG ("client %p: closing connection", client); + g_mutex_lock (&priv->watch_lock); + + /* Work around the lack of thread safety of gst_rtsp_connection_close */ + if (priv->watch) { + gst_rtsp_watch_set_flushing (priv->watch, TRUE); + } + if (priv->connection) { if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) { g_mutex_lock (&tunnels_lock); @@ -1299,11 +1306,10 @@ gst_rtsp_client_close (GstRTSPClient * client) g_hash_table_remove (tunnels, tunnelid); g_mutex_unlock (&tunnels_lock); } + gst_rtsp_connection_flush (priv->connection, TRUE); gst_rtsp_connection_close (priv->connection); } - /* connection is now closed, destroy the watch which will also cause the - * closed signal to be emitted */ if (priv->watch) { GST_DEBUG ("client %p: destroying watch", client); g_source_destroy ((GSource *) priv->watch); @@ -1314,6 +1320,8 @@ gst_rtsp_client_close (GstRTSPClient * client) g_main_context_unref (priv->watch_context); priv->watch_context = NULL; } + + g_mutex_unlock (&priv->watch_lock); } static gchar * From 7b5dbb0561e26533fe2eedb41ef0a65956f1b839 Mon Sep 17 00:00:00 2001 From: Marc Leeman Date: Mon, 3 Feb 2020 12:30:14 +0000 Subject: [PATCH 1675/1776] rtsp-media: fix default latency --- gst/rtsp-server/rtsp-media.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 260ee6d4cc..c5743dc940 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -377,7 +377,7 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) g_object_class_install_property (gobject_class, PROP_LATENCY, g_param_spec_uint ("latency", "Latency", "Latency used for receiving media in milliseconds", 0, G_MAXUINT, - DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + DEFAULT_LATENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_TRANSPORT_MODE, g_param_spec_flags ("transport-mode", "Transport Mode", @@ -2853,14 +2853,14 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, gboolean unblock = FALSE; /* Handle expected async-done before waiting on next async-done. - * + * * Since the seek further down in code will cause a preroll and * a async-done will be generated it's important to wait on async-done * if that is expected. Otherwise there is the risk that the waiting * for async-done after the seek is detecting the expected async-done * instead of the one that corresponds to the seek. Then execution * continue and act as if the pipeline is prerolled, but it's not. - * + * * During wait_preroll message GST_MESSAGE_ASYNC_DONE will come * and then the state will change from preparing to prepared */ if (priv->expected_async_done) { From c1ca88cd345f63fee8dff28380a510d01576c38b Mon Sep 17 00:00:00 2001 From: Bastian Bouchardon Date: Wed, 5 Feb 2020 16:51:14 +0100 Subject: [PATCH 1676/1776] Add initialization for context and params (gchar *) Insert define (DEFAULT_*) into help to have to modify only the constants --- examples/test-onvif-client.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/examples/test-onvif-client.c b/examples/test-onvif-client.c index 16d5f696cd..3a1b7003b9 100644 --- a/examples/test-onvif-client.c +++ b/examples/test-onvif-client.c @@ -634,24 +634,27 @@ int main (int argc, char **argv) { GOptionContext *optctx; - Context ctx; + Context ctx = { 0, }; GstBus *bus; gint ret = 1; GError *error = NULL; - const gchar *range; - const gchar *frames; - const gchar *rate_control; + const gchar *range = NULL; + const gchar *frames = NULL; + const gchar *rate_control = NULL; + gchar *default_speed = + g_strdup_printf ("Speed to request (default: %.1f)", DEFAULT_SPEED); SeekParameters seek_params = { NULL, DEFAULT_SPEED, NULL, NULL, DEFAULT_REVERSE }; GOptionEntry entries[] = { {"range", 0, 0, G_OPTION_ARG_STRING, &range, "Range to seek (default: " DEFAULT_RANGE ")", "RANGE"}, {"speed", 0, 0, G_OPTION_ARG_DOUBLE, &seek_params.speed, - "Speed to request (default: 1.0)", "SPEED"}, + default_speed, "SPEED"}, {"frames", 0, 0, G_OPTION_ARG_STRING, &frames, - "Frames to request (default: none)", "FRAMES"}, + "Frames to request (default: " DEFAULT_FRAMES ")", "FRAMES"}, {"rate-control", 0, 0, G_OPTION_ARG_STRING, &rate_control, - "Apply rate control on the client side (default: yes)", "RATE_CONTROL"}, + "Apply rate control on the client side (default: " + DEFAULT_RATE_CONTROL ")", "RATE_CONTROL"}, {"reverse", 0, 0, G_OPTION_ARG_NONE, &seek_params.reverse, "Playback direction", ""}, {NULL} @@ -721,5 +724,6 @@ done: g_free (seek_params.range); g_free (seek_params.frames); g_free (seek_params.rate_control); + g_free (default_speed); return ret; } From a2ba3639a5ad3f69f8e77a50708275a4190002c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 22 Feb 2020 00:41:32 +0200 Subject: [PATCH 1677/1776] rtsp-media: Sink pipeline in gst_rtsp_media_take_pipeline() It's taken ownership of by the media, and returned with `transfer none` from the GstRTSPMedia::create_pipeline() vfunc. If we don't sink it first then any bindings will wrongly take ownership of the pipeline once it arrives in bindings code. --- gst/rtsp-server/rtsp-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c5743dc940..38c38ae8db 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -956,7 +956,7 @@ gst_rtsp_media_get_element (GstRTSPMedia * media) /** * gst_rtsp_media_take_pipeline: * @media: a #GstRTSPMedia - * @pipeline: (transfer full): a #GstPipeline + * @pipeline: (transfer floating): a #GstPipeline * * Set @pipeline as the #GstPipeline for @media. Ownership is * taken of @pipeline. @@ -976,7 +976,7 @@ gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline) g_mutex_lock (&priv->lock); old = priv->pipeline; - priv->pipeline = GST_ELEMENT_CAST (pipeline); + priv->pipeline = gst_object_ref_sink (GST_ELEMENT_CAST (pipeline)); nettime = priv->nettime; priv->nettime = NULL; g_mutex_unlock (&priv->lock); From 50ecbb15965639c89e5c127e749e1e2eef5d0302 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 5 Feb 2020 20:28:19 +0100 Subject: [PATCH 1678/1776] rtsp-stream: properly protect TCP backlog access Fixes #97 We cannot hold stream->lock while pushing data, but need to consistently check the state of the backlog both from the send_tcp_message function and the on_message_sent function, which may or may not be called from the same thread. This commit introduces internal API to allow for potentially recursive locking of transport streams, addressing a race condition where the RTSP stream could push items out of order when popping them from the backlog. --- gst/rtsp-server/rtsp-server-internal.h | 4 ++++ gst/rtsp-server/rtsp-stream-transport.c | 28 ++++++++++++++++++++++--- gst/rtsp-server/rtsp-stream.c | 18 +++++++++------- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-server-internal.h b/gst/rtsp-server/rtsp-server-internal.h index 13defeefef..03b02e2b20 100644 --- a/gst/rtsp-server/rtsp-server-internal.h +++ b/gst/rtsp-server/rtsp-server-internal.h @@ -42,6 +42,10 @@ gboolean gst_rtsp_stream_transport_backlog_pop (GstRTSPStreamT gboolean gst_rtsp_stream_transport_backlog_is_empty (GstRTSPStreamTransport *trans); +void gst_rtsp_stream_transport_lock_backlog (GstRTSPStreamTransport * trans); + +void gst_rtsp_stream_transport_unlock_backlog (GstRTSPStreamTransport * trans); + void gst_rtsp_stream_transport_set_back_pressure_callback (GstRTSPStreamTransport *trans, GstRTSPBackPressureFunc back_pressure_func, gpointer user_data, diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index e30e44096c..8ce16ddcd5 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -85,6 +85,7 @@ struct _GstRTSPStreamTransportPrivate /* TCP backlog */ GstClockTime first_rtp_timestamp; GstQueueArray *items; + GRecMutex backlog_lock; }; #define MAX_BACKLOG_DURATION (10 * GST_SECOND) @@ -140,6 +141,7 @@ gst_rtsp_stream_transport_init (GstRTSPStreamTransport * trans) trans->priv->first_rtp_timestamp = GST_CLOCK_TIME_NONE; gst_queue_array_set_clear_func (trans->priv->items, (GDestroyNotify) clear_backlog_item); + g_rec_mutex_init (&trans->priv->backlog_lock); } static void @@ -167,6 +169,8 @@ gst_rtsp_stream_transport_finalize (GObject * obj) gst_queue_array_free (priv->items); + g_rec_mutex_clear (&priv->backlog_lock); + G_OBJECT_CLASS (gst_rtsp_stream_transport_parent_class)->finalize (obj); } @@ -832,7 +836,8 @@ get_first_backlog_timestamp (GstRTSPStreamTransport * trans) return ret; } -/* Not MT-safe, caller should ensure consistent locking. Ownership +/* Not MT-safe, caller should ensure consistent locking (see + * gst_rtsp_stream_transport_lock_backlog()). Ownership * of @buffer and @buffer_list is transfered to the transport */ gboolean gst_rtsp_stream_transport_backlog_push (GstRTSPStreamTransport * trans, @@ -875,7 +880,8 @@ gst_rtsp_stream_transport_backlog_push (GstRTSPStreamTransport * trans, return ret; } -/* Not MT-safe, caller should ensure consistent locking. Ownership +/* Not MT-safe, caller should ensure consistent locking (see + * gst_rtsp_stream_transport_lock_backlog()). Ownership * of @buffer and @buffer_list is transfered back to the caller */ gboolean gst_rtsp_stream_transport_backlog_pop (GstRTSPStreamTransport * trans, @@ -900,9 +906,25 @@ gst_rtsp_stream_transport_backlog_pop (GstRTSPStreamTransport * trans, return TRUE; } -/* Not MT-safe, caller should ensure consistent locking. */ +/* Not MT-safe, caller should ensure consistent locking. + * See gst_rtsp_stream_transport_lock_backlog() */ gboolean gst_rtsp_stream_transport_backlog_is_empty (GstRTSPStreamTransport * trans) { return gst_queue_array_is_empty (trans->priv->items); } + +/* Internal API, protects access to the TCP backlog. Safe to + * call recursively */ +void +gst_rtsp_stream_transport_lock_backlog (GstRTSPStreamTransport * trans) +{ + g_rec_mutex_lock (&trans->priv->backlog_lock); +} + +/* See gst_rtsp_stream_transport_lock_backlog() */ +void +gst_rtsp_stream_transport_unlock_backlog (GstRTSPStreamTransport * trans) +{ + g_rec_mutex_unlock (&trans->priv->backlog_lock); +} diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 30203ad3f5..7fd171d356 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -202,6 +202,7 @@ struct _GstRTSPStreamPrivate GstRTSPPublishClockMode publish_clock_mode; GThreadPool *send_pool; + guint32 last_seqnum; }; #define DEFAULT_CONTROL NULL @@ -2605,6 +2606,8 @@ send_tcp_message (GstRTSPStream * stream, gint idx) for (index = 0; index < transports->len; index++) { GstRTSPStreamTransport *tr = g_ptr_array_index (transports, index); + gst_rtsp_stream_transport_lock_backlog (tr); + if (gst_rtsp_stream_transport_backlog_is_empty (tr) && !gst_rtsp_stream_transport_check_back_pressure (tr, idx)) { push_data (stream, tr, buffer, buffer_list, is_rtp); @@ -2612,8 +2615,6 @@ send_tcp_message (GstRTSPStream * stream, gint idx) GstBuffer *buf_ref = NULL; GstBufferList *buflist_ref = NULL; - g_mutex_lock (&priv->lock); - if (buffer) buf_ref = gst_buffer_ref (buffer); if (buffer_list) @@ -2623,11 +2624,13 @@ send_tcp_message (GstRTSPStream * stream, gint idx) buf_ref, buflist_ref, is_rtp)) { GST_WARNING_OBJECT (stream, "Dropping slow transport %" GST_PTR_FORMAT, tr); + g_mutex_lock (&priv->lock); update_transport (stream, tr, FALSE); + g_mutex_unlock (&priv->lock); } - - g_mutex_unlock (&priv->lock); } + + gst_rtsp_stream_transport_unlock_backlog (tr); } g_ptr_array_unref (transports); } @@ -4561,7 +4564,7 @@ on_message_sent (GstRTSPStreamTransport * trans, gpointer user_data) GST_DEBUG_OBJECT (stream, "message send complete"); - g_mutex_lock (&priv->lock); + gst_rtsp_stream_transport_lock_backlog (trans); if (!gst_rtsp_stream_transport_backlog_is_empty (trans)) { GstBuffer *buffer; @@ -4575,13 +4578,12 @@ on_message_sent (GstRTSPStreamTransport * trans, gpointer user_data) g_assert (popped == TRUE); - g_mutex_unlock (&priv->lock); - push_data (stream, trans, buffer, buffer_list, is_rtp); gst_clear_buffer (&buffer); gst_clear_buffer_list (&buffer_list); } else { + g_mutex_lock (&priv->lock); /* iterate from 1 and down, so we prioritize RTCP over RTP */ for (i = 1; i >= 0; i--) { if (priv->have_buffer[i]) { @@ -4602,6 +4604,8 @@ on_message_sent (GstRTSPStreamTransport * trans, gpointer user_data) g_mutex_unlock (&priv->lock); } + + gst_rtsp_stream_transport_unlock_backlog (trans); } /** From 54b6b3bcab504b28ce48c557ed735871e9c1bdc9 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 6 Feb 2020 22:46:18 +0100 Subject: [PATCH 1679/1776] rtsp-stream: marshal calls to send_tcp_message to a single thread In order to address the race condition pointed out at https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/merge_requests/108#note_403579 we get rid of the send thread pool, and instead spawn and manage a single thread to pull samples from app sinks and add them to the transport's backlogs. Additionally, we now also always go through the backlogs in order to simplify the logic. --- gst/rtsp-server/rtsp-stream.c | 226 ++++++++++++++++++++-------------- 1 file changed, 131 insertions(+), 95 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 7fd171d356..dc484e30a2 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -190,6 +190,18 @@ struct _GstRTSPStreamPrivate gint dscp_qos; + /* Sending logic for TCP */ + GThread *send_thread; + GCond send_cond; + GMutex send_lock; + /* @send_lock is released when pushing data out, we use + * a cookie to decide whether we should wait on @send_cond + * before checking the transports' backlogs again + */ + guint send_cookie; + /* Used to control shutdown of @send_thread */ + gboolean continue_sending; + /* stream blocking */ gulong blocked_id[2]; gboolean blocking; @@ -314,6 +326,11 @@ gst_rtsp_stream_init (GstRTSPStream * stream) g_mutex_init (&priv->lock); + priv->continue_sending = TRUE; + priv->send_cookie = 0; + g_cond_init (&priv->send_cond); + g_mutex_init (&priv->send_lock); + priv->keys = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) gst_caps_unref); priv->ptmap = g_hash_table_new_full (NULL, NULL, NULL, @@ -400,6 +417,9 @@ gst_rtsp_stream_finalize (GObject * obj) g_hash_table_unref (priv->keys); g_hash_table_destroy (priv->ptmap); + g_mutex_clear (&priv->send_lock); + g_cond_clear (&priv->send_cond); + G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); } @@ -2548,6 +2568,33 @@ ensure_cached_transports (GstRTSPStream * stream) } } +/* Must be called *without* priv->lock */ +static void +check_transport_backlog (GstRTSPStream * stream, GstRTSPStreamTransport * trans) +{ + gst_rtsp_stream_transport_lock_backlog (trans); + + if (!gst_rtsp_stream_transport_backlog_is_empty (trans)) { + GstBuffer *buffer; + GstBufferList *buffer_list; + gboolean is_rtp; + gboolean popped; + + popped = + gst_rtsp_stream_transport_backlog_pop (trans, &buffer, &buffer_list, + &is_rtp); + + g_assert (popped == TRUE); + + push_data (stream, trans, buffer, buffer_list, is_rtp); + + gst_clear_buffer (&buffer); + gst_clear_buffer_list (&buffer_list); + } + + gst_rtsp_stream_transport_unlock_backlog (trans); +} + /* Must be called with priv->lock */ static void send_tcp_message (GstRTSPStream * stream, gint idx) @@ -2598,6 +2645,33 @@ send_tcp_message (GstRTSPStream * stream, gint idx) if (transports) g_ptr_array_ref (transports); + if (transports) { + gint index; + + for (index = 0; index < transports->len; index++) { + GstRTSPStreamTransport *tr = g_ptr_array_index (transports, index); + GstBuffer *buf_ref = NULL; + GstBufferList *buflist_ref = NULL; + + gst_rtsp_stream_transport_lock_backlog (tr); + + if (buffer) + buf_ref = gst_buffer_ref (buffer); + if (buffer_list) + buflist_ref = gst_buffer_list_ref (buffer_list); + + if (!gst_rtsp_stream_transport_backlog_push (tr, + buf_ref, buflist_ref, is_rtp)) { + GST_ERROR_OBJECT (stream, + "Dropping slow transport %" GST_PTR_FORMAT, tr); + update_transport (stream, tr, FALSE); + } + + gst_rtsp_stream_transport_unlock_backlog (tr); + } + } + gst_sample_unref (sample); + g_mutex_unlock (&priv->lock); if (transports) { @@ -2606,51 +2680,32 @@ send_tcp_message (GstRTSPStream * stream, gint idx) for (index = 0; index < transports->len; index++) { GstRTSPStreamTransport *tr = g_ptr_array_index (transports, index); - gst_rtsp_stream_transport_lock_backlog (tr); - - if (gst_rtsp_stream_transport_backlog_is_empty (tr) - && !gst_rtsp_stream_transport_check_back_pressure (tr, idx)) { - push_data (stream, tr, buffer, buffer_list, is_rtp); - } else { - GstBuffer *buf_ref = NULL; - GstBufferList *buflist_ref = NULL; - - if (buffer) - buf_ref = gst_buffer_ref (buffer); - if (buffer_list) - buflist_ref = gst_buffer_list_ref (buffer_list); - - if (!gst_rtsp_stream_transport_backlog_push (tr, - buf_ref, buflist_ref, is_rtp)) { - GST_WARNING_OBJECT (stream, - "Dropping slow transport %" GST_PTR_FORMAT, tr); - g_mutex_lock (&priv->lock); - update_transport (stream, tr, FALSE); - g_mutex_unlock (&priv->lock); - } - } - - gst_rtsp_stream_transport_unlock_backlog (tr); + check_transport_backlog (stream, tr); } g_ptr_array_unref (transports); } - gst_sample_unref (sample); g_mutex_lock (&priv->lock); } -static void -send_thread_main (gpointer data, gpointer user_data) +static gpointer +send_func (GstRTSPStream * stream) { - GstRTSPStream *stream = user_data; GstRTSPStreamPrivate *priv = stream->priv; - gint idx; - gint i; + gboolean cont = TRUE; - g_mutex_lock (&priv->lock); + g_mutex_lock (&priv->send_lock); + + while (cont) { + int i; + int idx = -1; + guint cookie; + + cookie = priv->send_cookie; + g_mutex_unlock (&priv->send_lock); + + g_mutex_lock (&priv->lock); - do { - idx = -1; /* iterate from 1 and down, so we prioritize RTCP over RTP */ for (i = 1; i >= 0; i--) { if (priv->have_buffer[i]) { @@ -2660,12 +2715,22 @@ send_thread_main (gpointer data, gpointer user_data) } } - if (idx != -1) + if (idx != -1) { send_tcp_message (stream, idx); - } while (idx != -1); + } - GST_DEBUG_OBJECT (stream, "send thread done"); - g_mutex_unlock (&priv->lock); + g_mutex_unlock (&priv->lock); + + g_mutex_lock (&priv->send_lock); + while (cookie == priv->send_cookie) { + g_cond_wait (&priv->send_cond, &priv->send_lock); + } + cont = priv->continue_sending; + } + + g_mutex_unlock (&priv->send_lock); + + return NULL; } static GstFlowReturn @@ -2674,28 +2739,27 @@ handle_new_sample (GstAppSink * sink, gpointer user_data) GstRTSPStream *stream = user_data; GstRTSPStreamPrivate *priv = stream->priv; int i; - int idx = -1; g_mutex_lock (&priv->lock); - if (priv->send_pool == NULL) { - GST_DEBUG_OBJECT (stream, "create thread pool"); - priv->send_pool = - g_thread_pool_new (send_thread_main, user_data, 1, TRUE, NULL); - } - - for (i = 0; i < 2; i++) + for (i = 0; i < 2; i++) { if (GST_ELEMENT_CAST (sink) == priv->appsink[i]) { priv->have_buffer[i] = TRUE; - idx = i; break; } + } - if (idx != -1) - send_tcp_message (stream, idx); + if (priv->send_thread == NULL) { + priv->send_thread = g_thread_new (NULL, (GThreadFunc) send_func, user_data); + } g_mutex_unlock (&priv->lock); + g_mutex_lock (&priv->send_lock); + priv->send_cookie++; + g_cond_signal (&priv->send_cond); + g_mutex_unlock (&priv->send_lock); + return GST_FLOW_OK; } @@ -3904,6 +3968,16 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv = stream->priv; + g_mutex_lock (&priv->send_lock); + priv->continue_sending = FALSE; + priv->send_cookie++; + g_cond_signal (&priv->send_cond); + g_mutex_unlock (&priv->send_lock); + + if (priv->send_thread) { + g_thread_join (priv->send_thread); + } + g_mutex_lock (&priv->lock); if (priv->joined_bin == NULL) goto was_not_joined; @@ -4557,55 +4631,17 @@ mcast_error: static void on_message_sent (GstRTSPStreamTransport * trans, gpointer user_data) { - GstRTSPStream *stream = user_data; + GstRTSPStream *stream = GST_RTSP_STREAM (user_data); GstRTSPStreamPrivate *priv = stream->priv; - gint idx = -1; - gint i; GST_DEBUG_OBJECT (stream, "message send complete"); - gst_rtsp_stream_transport_lock_backlog (trans); + check_transport_backlog (stream, trans); - if (!gst_rtsp_stream_transport_backlog_is_empty (trans)) { - GstBuffer *buffer; - GstBufferList *buffer_list; - gboolean is_rtp; - gboolean popped; - - popped = - gst_rtsp_stream_transport_backlog_pop (trans, &buffer, &buffer_list, - &is_rtp); - - g_assert (popped == TRUE); - - push_data (stream, trans, buffer, buffer_list, is_rtp); - - gst_clear_buffer (&buffer); - gst_clear_buffer_list (&buffer_list); - } else { - g_mutex_lock (&priv->lock); - /* iterate from 1 and down, so we prioritize RTCP over RTP */ - for (i = 1; i >= 0; i--) { - if (priv->have_buffer[i]) { - /* send message */ - idx = i; - break; - } - } - - if (idx != -1) { - gint dummy; - - if (priv->send_pool) { - GST_DEBUG_OBJECT (stream, "start thread"); - g_thread_pool_push (priv->send_pool, &dummy, NULL); - } - } - - g_mutex_unlock (&priv->lock); - } - - gst_rtsp_stream_transport_unlock_backlog (trans); + g_mutex_lock (&priv->send_lock); + priv->send_cookie++; + g_cond_signal (&priv->send_cond); + g_mutex_unlock (&priv->send_lock); } /** @@ -6027,8 +6063,8 @@ gst_rtsp_stream_set_rate_control (GstRTSPStream * stream, gboolean enabled) if (stream->priv->appsink[0]) g_object_set (stream->priv->appsink[0], "sync", enabled, NULL); if (stream->priv->payloader - && g_object_class_find_property (G_OBJECT_GET_CLASS (stream-> - priv->payloader), "onvif-no-rate-control")) + && g_object_class_find_property (G_OBJECT_GET_CLASS (stream->priv-> + payloader), "onvif-no-rate-control")) g_object_set (stream->priv->payloader, "onvif-no-rate-control", !enabled, NULL); if (stream->priv->session) { From fa41cbe9a428677163b88cf1dc8948c6be200835 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 14 Feb 2020 14:59:25 +0100 Subject: [PATCH 1680/1776] rtsp-stream: clear backlog when removing transport This ensures we don't end up calling any of transports' callbacks with a potentially unreffed user_data (in practice, a client that may have been removed) --- gst/rtsp-server/rtsp-server-internal.h | 2 ++ gst/rtsp-server/rtsp-stream-transport.c | 28 +++++++++++++++++++++---- gst/rtsp-server/rtsp-stream.c | 5 +++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-server-internal.h b/gst/rtsp-server/rtsp-server-internal.h index 03b02e2b20..056814fbb9 100644 --- a/gst/rtsp-server/rtsp-server-internal.h +++ b/gst/rtsp-server/rtsp-server-internal.h @@ -42,6 +42,8 @@ gboolean gst_rtsp_stream_transport_backlog_pop (GstRTSPStreamT gboolean gst_rtsp_stream_transport_backlog_is_empty (GstRTSPStreamTransport *trans); +void gst_rtsp_stream_transport_clear_backlog (GstRTSPStreamTransport * trans); + void gst_rtsp_stream_transport_lock_backlog (GstRTSPStreamTransport * trans); void gst_rtsp_stream_transport_unlock_backlog (GstRTSPStreamTransport * trans); diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index 8ce16ddcd5..ac0e2572d5 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -882,7 +882,8 @@ gst_rtsp_stream_transport_backlog_push (GstRTSPStreamTransport * trans, /* Not MT-safe, caller should ensure consistent locking (see * gst_rtsp_stream_transport_lock_backlog()). Ownership - * of @buffer and @buffer_list is transfered back to the caller */ + * of @buffer and @buffer_list is transfered back to the caller, + * if either of those is NULL the underlying object is unreffed */ gboolean gst_rtsp_stream_transport_backlog_pop (GstRTSPStreamTransport * trans, GstBuffer ** buffer, GstBufferList ** buffer_list, gboolean * is_rtp) @@ -899,9 +900,18 @@ gst_rtsp_stream_transport_backlog_pop (GstRTSPStreamTransport * trans, priv->first_rtp_timestamp = get_first_backlog_timestamp (trans); - *buffer = item->buffer; - *buffer_list = item->buffer_list; - *is_rtp = item->is_rtp; + if (buffer) + *buffer = item->buffer; + else if (item->buffer) + gst_buffer_unref (item->buffer); + + if (buffer_list) + *buffer_list = item->buffer_list; + else if (item->buffer_list) + gst_buffer_list_unref (item->buffer_list); + + if (is_rtp) + *is_rtp = item->is_rtp; return TRUE; } @@ -914,6 +924,16 @@ gst_rtsp_stream_transport_backlog_is_empty (GstRTSPStreamTransport * trans) return gst_queue_array_is_empty (trans->priv->items); } +/* Not MT-safe, caller should ensure consistent locking. + * See gst_rtsp_stream_transport_lock_backlog() */ +void +gst_rtsp_stream_transport_clear_backlog (GstRTSPStreamTransport * trans) +{ + while (!gst_rtsp_stream_transport_backlog_is_empty (trans)) { + gst_rtsp_stream_transport_backlog_pop (trans, NULL, NULL, NULL); + } +} + /* Internal API, protects access to the TCP backlog. Safe to * call recursively */ void diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index dc484e30a2..ad18f14605 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4607,6 +4607,11 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, } else { GST_INFO ("removing TCP %s", tr->destination); priv->transports = g_list_delete_link (priv->transports, tr_element); + + gst_rtsp_stream_transport_lock_backlog (trans); + gst_rtsp_stream_transport_clear_backlog (trans); + gst_rtsp_stream_transport_unlock_backlog (trans); + priv->n_tcp_transports--; } priv->transports_cookie++; From 8410c69da98a5ca3f2813b4eecc24e800a4712ad Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 14 Feb 2020 14:59:43 +0100 Subject: [PATCH 1681/1776] rtsp-stream: fix deadlock on transport removal We cannot take the RTSPStream lock while holding a transport backlog lock, as remove_transport may be called externally, which will take first the RTSPStream lock then the transport backlog lock. --- gst/rtsp-server/rtsp-stream.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index ad18f14605..7204e9c85f 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2516,11 +2516,10 @@ done: } /* Must be called *without* priv->lock */ -static void +static gboolean push_data (GstRTSPStream * stream, GstRTSPStreamTransport * trans, GstBuffer * buffer, GstBufferList * buffer_list, gboolean is_rtp) { - GstRTSPStreamPrivate *priv = stream->priv; gboolean send_ret = TRUE; if (is_rtp) { @@ -2535,12 +2534,7 @@ push_data (GstRTSPStream * stream, GstRTSPStreamTransport * trans, send_ret = gst_rtsp_stream_transport_send_rtcp_list (trans, buffer_list); } - if (!send_ret) { - /* remove transport on send error */ - g_mutex_lock (&priv->lock); - update_transport (stream, trans, FALSE); - g_mutex_unlock (&priv->lock); - } + return send_ret; } /* With priv->lock */ @@ -2572,6 +2566,9 @@ ensure_cached_transports (GstRTSPStream * stream) static void check_transport_backlog (GstRTSPStream * stream, GstRTSPStreamTransport * trans) { + GstRTSPStreamPrivate *priv = stream->priv; + gboolean send_ret = TRUE; + gst_rtsp_stream_transport_lock_backlog (trans); if (!gst_rtsp_stream_transport_backlog_is_empty (trans)) { @@ -2586,13 +2583,20 @@ check_transport_backlog (GstRTSPStream * stream, GstRTSPStreamTransport * trans) g_assert (popped == TRUE); - push_data (stream, trans, buffer, buffer_list, is_rtp); + send_ret = push_data (stream, trans, buffer, buffer_list, is_rtp); gst_clear_buffer (&buffer); gst_clear_buffer_list (&buffer_list); } gst_rtsp_stream_transport_unlock_backlog (trans); + + if (!send_ret) { + /* remove transport on send error */ + g_mutex_lock (&priv->lock); + update_transport (stream, trans, FALSE); + g_mutex_unlock (&priv->lock); + } } /* Must be called with priv->lock */ From daa18dc867cc4b1df4cde47af411747c87fb0ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Mon, 9 Mar 2020 14:17:34 +0100 Subject: [PATCH 1682/1776] rtsp-client: Use watch_context before unref Move the usage of priv->watch_context to beginning of function gst_rtsp_client_finalize. Instead of use it after g_main_context_unref (priv->watch_context). --- gst/rtsp-server/rtsp-client.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 1339bd976b..24c2da4943 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -763,6 +763,14 @@ gst_rtsp_client_finalize (GObject * obj) GST_INFO ("finalize client %p", client); + if (priv->rtsp_ctrl_timeout_id != 0) { + GST_DEBUG ("Killing leftover timeout GSource for client %p", client); + g_source_destroy (g_main_context_find_source_by_id (priv->watch_context, + priv->rtsp_ctrl_timeout_id)); + priv->rtsp_ctrl_timeout_id = 0; + priv->rtsp_ctrl_timeout_cnt = 0; + } + if (priv->watch) gst_rtsp_watch_set_flushing (priv->watch, TRUE); gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); @@ -798,14 +806,6 @@ gst_rtsp_client_finalize (GObject * obj) clean_cached_media (client, TRUE); - if (priv->rtsp_ctrl_timeout_id != 0) { - GST_DEBUG ("Killing leftover timeout GSource for client %p", client); - g_source_destroy (g_main_context_find_source_by_id (priv->watch_context, - priv->rtsp_ctrl_timeout_id)); - priv->rtsp_ctrl_timeout_id = 0; - priv->rtsp_ctrl_timeout_cnt = 0; - } - g_free (priv->server_ip); g_mutex_clear (&priv->lock); g_mutex_clear (&priv->send_lock); From 44ccca3086dd81081d72ca0b21d0ecdde962fb1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 23 Mar 2020 16:06:43 +0200 Subject: [PATCH 1683/1776] rtsp-auth: Fix NULL pointer dereference when handling an invalid basic Authorization header When using the basic authentication scheme, we wouldn't validate that the authorization field of the credentials is not NULL and pass it on to g_hash_table_lookup(). g_str_hash() however is not NULL-safe and will dereference the NULL pointer and crash. A specially crafted (read: invalid) RTSP header can cause this to happen. As a solution, check for the authorization to be not NULL before continuing processing it and if it is simply fail authentication. This fixes CVE-2020-6095 and TALOS-2020-1018. Discovered by Peter Wang of Cisco ASIG. --- gst/rtsp-server/rtsp-auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c index ad0be07dd9..b6286e173c 100644 --- a/gst/rtsp-server/rtsp-auth.c +++ b/gst/rtsp-server/rtsp-auth.c @@ -871,7 +871,7 @@ default_authenticate (GstRTSPAuth * auth, GstRTSPContext * ctx) GST_DEBUG_OBJECT (auth, "check Basic auth"); g_mutex_lock (&priv->lock); - if ((token = + if ((*credential)->authorization && (token = g_hash_table_lookup (priv->basic, (*credential)->authorization))) { GST_DEBUG_OBJECT (auth, "setting token %p", token); From a696d980b5c0bf91c845e2afce40eb3b70bc910c Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Mon, 23 Mar 2020 14:51:28 +0100 Subject: [PATCH 1684/1776] rtsp-stream: use mcast_udpsink[0] last-sample if available for rtpinfo Otherwise no sink is found for multicast sreams and the less accurate fallback is used to determine the current sequence number and timestamp. --- gst/rtsp-server/rtsp-stream.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 7204e9c85f..aabb3b0a33 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4161,11 +4161,13 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, * This will have a more accurate sequence number and timestamp, as between * the payloader and the sink there can be some queues */ - if (priv->udpsink[0] || priv->appsink[0]) { + if (priv->udpsink[0] || priv->mcast_udpsink[0] || priv->appsink[0]) { GstSample *last_sample; if (priv->udpsink[0]) g_object_get (priv->udpsink[0], "last-sample", &last_sample, NULL); + else if (priv->mcast_udpsink[0]) + g_object_get (priv->mcast_udpsink[0], "last-sample", &last_sample, NULL); else g_object_get (priv->appsink[0], "last-sample", &last_sample, NULL); From f2b82c28a3534eed327b3c0cd8da0d85e15812dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 27 Apr 2020 13:49:55 +0300 Subject: [PATCH 1685/1776] rtsp-client: If the TEARDOWN response can be sent directly, directly close the client Instead of closing it never at all. Previously there was only code that closed the client asynchronously if sending the response happened asynchrously at a later time. Thanks to Christian M for debugging this issue. Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/102 Part-of: --- gst/rtsp-server/rtsp-client.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 24c2da4943..023269610f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -4784,8 +4784,12 @@ do_send_messages (GstRTSPClient * client, GstRTSPMessage * messages, guint id = 0; GstRTSPResult ret; guint i; + gboolean closed = FALSE; /* send the message */ + if (close) + GST_INFO ("client %p: sending close message", client); + ret = gst_rtsp_watch_send_messages (priv->watch, messages, n_messages, &id); if (ret != GST_RTSP_OK) goto error; @@ -4794,6 +4798,10 @@ do_send_messages (GstRTSPClient * client, GstRTSPMessage * messages, * written to the client to close the connection */ if (close) priv->close_seq = id; + /* if the returned id is 0 then the TEARDOWN was already sent directly and + * we don't have to wait for it asynchronously */ + if (closed && id == 0) + closed = TRUE; for (i = 0; i < n_messages; i++) { if (gst_rtsp_message_get_type (&messages[i]) == GST_RTSP_MESSAGE_DATA) { @@ -4831,6 +4839,13 @@ do_send_messages (GstRTSPClient * client, GstRTSPMessage * messages, } } + if (closed) { + GST_INFO ("client %p: sent close message", client); + g_mutex_unlock (&priv->send_lock); + gst_rtsp_client_close (client); + g_mutex_lock (&priv->send_lock); + } + return ret == GST_RTSP_OK; /* ERRORS */ @@ -4865,7 +4880,7 @@ message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) } if (priv->close_seq && priv->close_seq == cseq) { - GST_INFO ("client %p: send close message", client); + GST_INFO ("client %p: sent close message", client); close = TRUE; priv->close_seq = 0; } From d33057a031ded9ce52b0113523113211f279b963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 27 Apr 2020 19:47:15 +0300 Subject: [PATCH 1686/1776] rtsp-client: Don't ever close the client connection directly when a session is torn down There might be other sessions that are running over the same RTSP connection and we should not simply close the client directly if one of them is torn down. By default the connection will be closed once the client closes it or the OS does. This behaviour can be adjusted with the post-session-timeout property, which allows to close it automatically from the server side after all sessions are gone and the given timeout is reached. This reverts the previous commit. Part-of: --- gst/rtsp-server/rtsp-client.c | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 023269610f..9d15db0738 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -84,7 +84,6 @@ struct _GstRTSPClientPrivate GstRTSPClientSendMessagesFunc send_messages_func; gpointer send_messages_data; GDestroyNotify send_messages_notify; - guint close_seq; GArray *data_seqs; GstRTSPSessionPool *session_pool; @@ -608,7 +607,6 @@ gst_rtsp_client_init (GstRTSPClient * client) g_mutex_init (&priv->lock); g_mutex_init (&priv->send_lock); g_mutex_init (&priv->watch_lock); - priv->close_seq = 0; priv->data_seqs = g_array_new (FALSE, FALSE, sizeof (DataSeq)); priv->drop_backlog = DEFAULT_DROP_BACKLOG; priv->post_session_timeout = DEFAULT_POST_SESSION_TIMEOUT; @@ -4784,7 +4782,6 @@ do_send_messages (GstRTSPClient * client, GstRTSPMessage * messages, guint id = 0; GstRTSPResult ret; guint i; - gboolean closed = FALSE; /* send the message */ if (close) @@ -4794,15 +4791,6 @@ do_send_messages (GstRTSPClient * client, GstRTSPMessage * messages, if (ret != GST_RTSP_OK) goto error; - /* if close flag is set, store the seq number so we can wait until it's - * written to the client to close the connection */ - if (close) - priv->close_seq = id; - /* if the returned id is 0 then the TEARDOWN was already sent directly and - * we don't have to wait for it asynchronously */ - if (closed && id == 0) - closed = TRUE; - for (i = 0; i < n_messages; i++) { if (gst_rtsp_message_get_type (&messages[i]) == GST_RTSP_MESSAGE_DATA) { guint8 channel = 0; @@ -4839,13 +4827,6 @@ do_send_messages (GstRTSPClient * client, GstRTSPMessage * messages, } } - if (closed) { - GST_INFO ("client %p: sent close message", client); - g_mutex_unlock (&priv->send_lock); - gst_rtsp_client_close (client); - g_mutex_lock (&priv->send_lock); - } - return ret == GST_RTSP_OK; /* ERRORS */ @@ -4870,7 +4851,6 @@ message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) GstRTSPClientPrivate *priv = client->priv; GstRTSPStreamTransport *trans = NULL; guint8 channel = 0; - gboolean close = FALSE; g_mutex_lock (&priv->send_lock); @@ -4878,13 +4858,6 @@ message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) trans = g_hash_table_lookup (priv->transports, GINT_TO_POINTER (channel)); set_data_seq (client, channel, 0); } - - if (priv->close_seq && priv->close_seq == cseq) { - GST_INFO ("client %p: sent close message", client); - close = TRUE; - priv->close_seq = 0; - } - g_mutex_unlock (&priv->send_lock); if (trans) { @@ -4892,9 +4865,6 @@ message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) gst_rtsp_stream_transport_message_sent (trans); } - if (close) - gst_rtsp_client_close (client); - return GST_RTSP_OK; } From 680ddb9fd35b49c4db570943be192fc100641d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 27 Apr 2020 23:25:22 +0300 Subject: [PATCH 1687/1776] rtsp-client: Combine the pre-session and post-session timeout They previously used the same state but different mechanisms and functions, which was difficult to follow, error prone and simply confusing. Also adjust the test for the post-session timeout a bit to be less racy now that the timing has slightly changed. Part-of: --- gst/rtsp-server/rtsp-client.c | 39 +++++++++++++---------------------- tests/check/gst/rtspserver.c | 2 +- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 9d15db0738..9653be240a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -106,6 +106,7 @@ struct _GstRTSPClientPrivate guint content_length_limit; + gboolean had_session; guint rtsp_ctrl_timeout_id; guint rtsp_ctrl_timeout_cnt; @@ -2554,7 +2555,10 @@ rtsp_ctrl_timeout_cb (gpointer user_data) priv->rtsp_ctrl_timeout_cnt += RTSP_CTRL_CB_INTERVAL; - if (priv->rtsp_ctrl_timeout_cnt > RTSP_CTRL_TIMEOUT_VALUE) { + if ((!priv->had_session + && priv->rtsp_ctrl_timeout_cnt > RTSP_CTRL_TIMEOUT_VALUE) + || (priv->had_session + && priv->rtsp_ctrl_timeout_cnt > priv->post_session_timeout)) { GST_DEBUG ("rtsp control session timeout id=%u expired, closing client.", priv->rtsp_ctrl_timeout_id); g_mutex_lock (&priv->lock); @@ -2569,23 +2573,6 @@ rtsp_ctrl_timeout_cb (gpointer user_data) return res; } -static gboolean -rtsp_ctrl_connection_timeout_cb (gpointer user_data) -{ - GstRTSPClient *client = (GstRTSPClient *) user_data; - GstRTSPClientPrivate *priv = client->priv; - - GST_DEBUG ("rtsp control connection timeout id=%u expired, closing client.", - priv->rtsp_ctrl_timeout_id); - g_mutex_lock (&priv->lock); - priv->rtsp_ctrl_timeout_id = 0; - priv->rtsp_ctrl_timeout_cnt = 0; - g_mutex_unlock (&priv->lock); - gst_rtsp_client_close (client); - - return G_SOURCE_REMOVE; -} - static void rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv) { @@ -2807,6 +2794,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) g_strdup (pipelined_request_id), g_strdup (gst_rtsp_session_get_sessionid (session))); } + /* Remember that we had at least one session in the past */ + priv->had_session = TRUE; rtsp_ctrl_timeout_remove (priv); if (!klass->configure_client_media (client, media, stream, ctx)) @@ -3755,26 +3744,26 @@ client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session, g_mutex_lock (&priv->lock); client_unwatch_session (client, session, NULL); - g_mutex_unlock (&priv->lock); if (!priv->sessions && priv->rtsp_ctrl_timeout_id == 0) { if (priv->post_session_timeout > 0) { - g_mutex_lock (&priv->lock); - - timer_src = g_timeout_source_new_seconds (priv->post_session_timeout); - g_source_set_callback (timer_src, rtsp_ctrl_connection_timeout_cb, - client, NULL); + timer_src = g_timeout_source_new_seconds (RTSP_CTRL_CB_INTERVAL); + g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client, NULL); priv->rtsp_ctrl_timeout_cnt = 0; priv->rtsp_ctrl_timeout_id = g_source_attach (timer_src, priv->watch_context); g_source_unref (timer_src); GST_DEBUG ("rtsp control setting up connection timeout id=%u.", priv->rtsp_ctrl_timeout_id); - g_mutex_unlock (&priv->lock); } else if (priv->post_session_timeout == 0) { + g_mutex_unlock (&priv->lock); gst_rtsp_client_close (client); + } else { + g_mutex_unlock (&priv->lock); } + } else { + g_mutex_unlock (&priv->lock); } } diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 9b691b2314..34c1dc48be 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -1707,7 +1707,7 @@ GST_START_TEST (test_play_timeout_connection) session) == GST_RTSP_STS_OK); sleep (2); fail_unless (gst_rtsp_session_pool_cleanup (pool) == 1); - sleep (2); + sleep (3); request = create_request (conn, GST_RTSP_TEARDOWN, NULL); From 4188dbb99bd11807a6ee6e091a0eaa81ae08f066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 28 Apr 2020 23:16:18 +0300 Subject: [PATCH 1688/1776] rtsp-client: Clean up watch/watch context and related state consistently And assert that it was cleaned up properly before the client is finalized. If something is still around when the client is shut down then something went very wrong before. Part-of: --- gst/rtsp-server/rtsp-client.c | 36 ++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 9653be240a..a9572642d3 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -762,25 +762,15 @@ gst_rtsp_client_finalize (GObject * obj) GST_INFO ("finalize client %p", client); - if (priv->rtsp_ctrl_timeout_id != 0) { - GST_DEBUG ("Killing leftover timeout GSource for client %p", client); - g_source_destroy (g_main_context_find_source_by_id (priv->watch_context, - priv->rtsp_ctrl_timeout_id)); - priv->rtsp_ctrl_timeout_id = 0; - priv->rtsp_ctrl_timeout_cnt = 0; - } + /* the watch and related state should be cleared before finalize + * as the watch actually holds a strong reference to the client */ + g_assert (priv->watch == NULL); + g_assert (priv->watch_context == NULL); + g_assert (priv->rtsp_ctrl_timeout_id == 0); - if (priv->watch) - gst_rtsp_watch_set_flushing (priv->watch, TRUE); gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); - if (priv->watch) - g_source_destroy ((GSource *) priv->watch); - - if (priv->watch_context) - g_main_context_unref (priv->watch_context); - /* all sessions should have been removed by now. We keep a ref to * the client object for the session removed handler. The ref is * dropped when the last session is removed from the list. */ @@ -1316,6 +1306,9 @@ gst_rtsp_client_close (GstRTSPClient * client) gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); rtsp_ctrl_timeout_remove (priv); + } + + if (priv->watch_context) { g_main_context_unref (priv->watch_context); priv->watch_context = NULL; } @@ -5049,6 +5042,12 @@ handle_tunnel (GstRTSPClient * client) priv->watch = NULL; gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); + rtsp_ctrl_timeout_remove (priv); + } + + if (priv->watch_context) { + g_main_context_unref (priv->watch_context); + priv->watch_context = NULL; } return GST_RTSP_STS_OK; @@ -5145,8 +5144,15 @@ client_watch_notify (GstRTSPClient * client) GST_INFO ("client %p: watch destroyed", client); priv->watch = NULL; /* remove all sessions if the media says so and so drop the extra client ref */ + gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); + gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); rtsp_ctrl_timeout_remove (priv); gst_rtsp_client_session_filter (client, cleanup_session, &closed); + if (priv->watch_context) { + g_main_context_unref (priv->watch_context); + priv->watch_context = NULL; + } + if (closed) g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL); g_object_unref (client); From e7802c1be78f42d9f311c8332a25ca3fb33e6232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 28 Apr 2020 23:33:49 +0300 Subject: [PATCH 1689/1776] rtsp-client: Store the timeout source by pointer instead of id That way we don't have to retrieve it again from the main context when destroying it but can directly do so. Part-of: --- gst/rtsp-server/rtsp-client.c | 42 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a9572642d3..b3fbefcba8 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -107,7 +107,7 @@ struct _GstRTSPClientPrivate guint content_length_limit; gboolean had_session; - guint rtsp_ctrl_timeout_id; + GSource *rtsp_ctrl_timeout; guint rtsp_ctrl_timeout_cnt; /* The version currently being used */ @@ -766,7 +766,7 @@ gst_rtsp_client_finalize (GObject * obj) * as the watch actually holds a strong reference to the client */ g_assert (priv->watch == NULL); g_assert (priv->watch_context == NULL); - g_assert (priv->rtsp_ctrl_timeout_id == 0); + g_assert (priv->rtsp_ctrl_timeout == NULL); gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); @@ -2552,10 +2552,11 @@ rtsp_ctrl_timeout_cb (gpointer user_data) && priv->rtsp_ctrl_timeout_cnt > RTSP_CTRL_TIMEOUT_VALUE) || (priv->had_session && priv->rtsp_ctrl_timeout_cnt > priv->post_session_timeout)) { - GST_DEBUG ("rtsp control session timeout id=%u expired, closing client.", - priv->rtsp_ctrl_timeout_id); + GST_DEBUG ("rtsp control session timeout %p expired, closing client.", + priv->rtsp_ctrl_timeout); g_mutex_lock (&priv->lock); - priv->rtsp_ctrl_timeout_id = 0; + g_source_unref (priv->rtsp_ctrl_timeout); + priv->rtsp_ctrl_timeout = NULL; priv->rtsp_ctrl_timeout_cnt = 0; g_mutex_unlock (&priv->lock); gst_rtsp_client_close (client); @@ -2571,12 +2572,12 @@ rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv) { g_mutex_lock (&priv->lock); - if (priv->rtsp_ctrl_timeout_id != 0) { - g_source_destroy (g_main_context_find_source_by_id (priv->watch_context, - priv->rtsp_ctrl_timeout_id)); - GST_DEBUG ("rtsp control session removed timeout id=%u.", - priv->rtsp_ctrl_timeout_id); - priv->rtsp_ctrl_timeout_id = 0; + if (priv->rtsp_ctrl_timeout != NULL) { + GST_DEBUG ("rtsp control session removed timeout %p.", + priv->rtsp_ctrl_timeout); + g_source_destroy (priv->rtsp_ctrl_timeout); + g_source_unref (priv->rtsp_ctrl_timeout); + priv->rtsp_ctrl_timeout = NULL; priv->rtsp_ctrl_timeout_cnt = 0; } @@ -3738,16 +3739,15 @@ client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session, g_mutex_lock (&priv->lock); client_unwatch_session (client, session, NULL); - if (!priv->sessions && priv->rtsp_ctrl_timeout_id == 0) { + if (!priv->sessions && priv->rtsp_ctrl_timeout == NULL) { if (priv->post_session_timeout > 0) { timer_src = g_timeout_source_new_seconds (RTSP_CTRL_CB_INTERVAL); g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client, NULL); priv->rtsp_ctrl_timeout_cnt = 0; - priv->rtsp_ctrl_timeout_id = g_source_attach (timer_src, - priv->watch_context); - g_source_unref (timer_src); - GST_DEBUG ("rtsp control setting up connection timeout id=%u.", - priv->rtsp_ctrl_timeout_id); + g_source_attach (timer_src, priv->watch_context); + priv->rtsp_ctrl_timeout = timer_src; + GST_DEBUG ("rtsp control setting up connection timeout %p.", + priv->rtsp_ctrl_timeout); g_mutex_unlock (&priv->lock); } else if (priv->post_session_timeout == 0) { g_mutex_unlock (&priv->lock); @@ -5206,10 +5206,10 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) timer_src = g_timeout_source_new_seconds (RTSP_CTRL_CB_INTERVAL); g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client, NULL); - priv->rtsp_ctrl_timeout_id = g_source_attach (timer_src, priv->watch_context); - g_source_unref (timer_src); - GST_DEBUG ("rtsp control setting up session timeout id=%u.", - priv->rtsp_ctrl_timeout_id); + g_source_attach (timer_src, priv->watch_context); + priv->rtsp_ctrl_timeout = timer_src; + GST_DEBUG ("rtsp control setting up session timeout %p.", + priv->rtsp_ctrl_timeout); g_mutex_unlock (&priv->lock); From 65bfa84d7accd821aa153a2cea821806d22e1967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 1 May 2020 10:42:17 +0300 Subject: [PATCH 1690/1776] rtsp-stream-transport: Fix accidental API/ABI breakage with message_sent callbacks The old API is preserved now and new API was added that provides the additional parameter to the callback. Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/104 Part-of: --- gst/rtsp-server/rtsp-stream-transport.c | 38 +++++++++++++++++++++++-- gst/rtsp-server/rtsp-stream-transport.h | 24 +++++++++++++--- gst/rtsp-server/rtsp-stream.c | 4 +-- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream-transport.c b/gst/rtsp-server/rtsp-stream-transport.c index ac0e2572d5..d293a95138 100644 --- a/gst/rtsp-server/rtsp-stream-transport.c +++ b/gst/rtsp-server/rtsp-stream-transport.c @@ -77,6 +77,10 @@ struct _GstRTSPStreamTransportPrivate gpointer ms_user_data; GDestroyNotify ms_notify; + GstRTSPMessageSentFuncFull message_sent_full; + gpointer msf_user_data; + GDestroyNotify msf_notify; + GstRTSPTransport *transport; GstRTSPUrl *url; @@ -373,6 +377,34 @@ gst_rtsp_stream_transport_set_message_sent (GstRTSPStreamTransport * trans, priv->ms_notify = notify; } +/** + * gst_rtsp_stream_transport_set_message_sent_full: + * @trans: a #GstRTSPStreamTransport + * @message_sent: (scope notified): a callback called when a message has been sent + * @user_data: (closure): user data passed to callback + * @notify: (allow-none): called with the user_data when no longer needed + * + * Install a callback that will be called when a message has been sent on @trans. + * + * Since: 1.18 + */ +void +gst_rtsp_stream_transport_set_message_sent_full (GstRTSPStreamTransport * trans, + GstRTSPMessageSentFuncFull message_sent, gpointer user_data, + GDestroyNotify notify) +{ + GstRTSPStreamTransportPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans)); + + priv = trans->priv; + + priv->message_sent_full = message_sent; + if (priv->msf_notify) + priv->msf_notify (priv->msf_user_data); + priv->msf_user_data = user_data; + priv->msf_notify = notify; +} /** * gst_rtsp_stream_transport_set_transport: @@ -750,7 +782,7 @@ gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport * trans) * gst_rtsp_stream_transport_message_sent: * @trans: a #GstRTSPStreamTransport * - * Signal the installed message_sent callback for @trans. + * Signal the installed message_sent / message_sent_full callback for @trans. * * Since: 1.16 */ @@ -761,8 +793,10 @@ gst_rtsp_stream_transport_message_sent (GstRTSPStreamTransport * trans) priv = trans->priv; + if (priv->message_sent_full) + priv->message_sent_full (trans, priv->msf_user_data); if (priv->message_sent) - priv->message_sent (trans, priv->ms_user_data); + priv->message_sent (priv->ms_user_data); } /** diff --git a/gst/rtsp-server/rtsp-stream-transport.h b/gst/rtsp-server/rtsp-stream-transport.h index f878858db1..d8516c027e 100644 --- a/gst/rtsp-server/rtsp-stream-transport.h +++ b/gst/rtsp-server/rtsp-stream-transport.h @@ -89,7 +89,18 @@ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); * Function registered with gst_rtsp_stream_transport_set_message_sent() * and called when a message has been sent on the transport. */ -typedef void (*GstRTSPMessageSentFunc) (GstRTSPStreamTransport *trans, gpointer user_data); +typedef void (*GstRTSPMessageSentFunc) (gpointer user_data); + +/** + * GstRTSPMessageSentFuncFull: + * @user_data: user data + * + * Function registered with gst_rtsp_stream_transport_set_message_sent_full() + * and called when a message has been sent on the transport. + * + * Since: 1.18 + */ +typedef void (*GstRTSPMessageSentFuncFull) (GstRTSPStreamTransport *trans, gpointer user_data); /** * GstRTSPStreamTransport: @@ -163,11 +174,16 @@ void gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamT GST_RTSP_SERVER_API void gst_rtsp_stream_transport_set_message_sent (GstRTSPStreamTransport *trans, - GstRTSPMessageSentFunc message_sent, - gpointer user_data, - GDestroyNotify notify); + GstRTSPMessageSentFunc message_sent, + gpointer user_data, + GDestroyNotify notify); GST_RTSP_SERVER_API +void gst_rtsp_stream_transport_set_message_sent_full (GstRTSPStreamTransport *trans, + GstRTSPMessageSentFuncFull message_sent, + gpointer user_data, + GDestroyNotify notify); +GST_RTSP_SERVER_API void gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport *trans); GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index aabb3b0a33..411498061c 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4685,8 +4685,8 @@ gst_rtsp_stream_add_transport (GstRTSPStream * stream, g_mutex_lock (&priv->lock); res = update_transport (stream, trans, TRUE); if (res) - gst_rtsp_stream_transport_set_message_sent (trans, on_message_sent, stream, - NULL); + gst_rtsp_stream_transport_set_message_sent_full (trans, on_message_sent, + stream, NULL); g_mutex_unlock (&priv->lock); return res; From f0928c5c1fe30aebe3a04db93e0ecd7b58509603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 3 May 2020 10:17:41 +0000 Subject: [PATCH 1691/1776] examples: test-onvif-server: fix compiler warnings on raspbian Fix printf format for 64-bit variables. Part-of: --- examples/test-onvif-server.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/test-onvif-server.c b/examples/test-onvif-server.c index 95041693fe..f6b37df236 100644 --- a/examples/test-onvif-server.c +++ b/examples/test-onvif-server.c @@ -222,8 +222,8 @@ translate_seek (ReplayBin * self, GstPad * pad, GstEvent * ievent) gst_event_set_seek_trickmode_interval (oevent, self->trickmode_interval); gst_event_set_seqnum (oevent, seqnum); - GST_DEBUG ("Translated event to %" GST_PTR_FORMAT " (remainder: %ld)", oevent, - self->remainder); + GST_DEBUG ("Translated event to %" GST_PTR_FORMAT + " (remainder: %" G_GINT64_FORMAT ")", oevent, self->remainder); done: return oevent; @@ -354,8 +354,8 @@ translate_segment (GstPad * pad, GstEvent * ievent) gst_event_unref (ievent); - GST_DEBUG ("Translated segment: %" GST_PTR_FORMAT ", ts_offset: %lu", ret, - self->ts_offset); + GST_DEBUG ("Translated segment: %" GST_PTR_FORMAT ", " + "ts_offset: %" G_GUINT64_FORMAT, ret, self->ts_offset); } else { ret = NULL; } @@ -413,7 +413,8 @@ handle_segment_done (ReplayBin * self, GstPad * pad) else self->ts_offset -= INTERVAL + ustop; - GST_DEBUG ("New offset: %ld", self->ts_offset); + GST_DEBUG ("New offset: %" GST_TIME_FORMAT, + GST_TIME_ARGS (self->ts_offset)); GST_DEBUG ("Seeking to %" GST_PTR_FORMAT, event); target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); From 8052957c24ffbfd368bea54cd0a3d5bf2b8890d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 3 May 2020 16:29:31 +0300 Subject: [PATCH 1692/1776] rtsp-media: Mark out parameters accordingly in gst_rtsp_media_get_rates() And the same for gst_rtsp_stream_get_rates(). Part-of: --- gst/rtsp-server/rtsp-media.c | 4 ++-- gst/rtsp-server/rtsp-stream.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 38c38ae8db..e99ecae1fe 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2578,8 +2578,8 @@ conversion_failed: /** * gst_rtsp_media_get_rates: * @media: a #GstRTSPMedia - * @rate (allow-none): the rate of the current segment - * @applied_rate (allow-none): the applied_rate of the current segment + * @rate: (optional) (out caller-allocates): the rate of the current segment + * @applied_rate: (optional) (out caller-allocates): the applied_rate of the current segment * * Get the rate and applied_rate of the current segment. * diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 411498061c..c3b35864d3 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -4282,8 +4282,8 @@ no_stats: /** * gst_rtsp_stream_get_rates: * @stream: a #GstRTSPStream - * @rate: (allow-none): the configured rate - * @applied_rate: (allow-none): the configured applied_rate + * @rate: (optional) (out caller-allocates): the configured rate + * @applied_rate: (optional) (out caller-allocates): the configured applied_rate * * Retrieve the current rate and/or applied_rate. * From 5d8abd9bfd3bbf8ae31b0c8970bf1338dc56a593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 14 May 2020 10:08:32 +0300 Subject: [PATCH 1693/1776] rtsp-client: Fix some race conditions around timeout source removal We always need to take the lock while accessing it as otherwise another thread might've removed it in the meantime. Also when destroying and creating a new one, ensure that the mutex is not shortly unlocked in between as during that time another one might potentially be created already. Part-of: --- gst/rtsp-server/rtsp-client.c | 46 ++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index b3fbefcba8..32f2f0dde5 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -2539,6 +2539,27 @@ make_server_transport (GstRTSPClient * client, GstRTSPMedia * media, return st; } +static void +rtsp_ctrl_timeout_remove_unlocked (GstRTSPClientPrivate * priv) +{ + if (priv->rtsp_ctrl_timeout != NULL) { + GST_DEBUG ("rtsp control session removed timeout %p.", + priv->rtsp_ctrl_timeout); + g_source_destroy (priv->rtsp_ctrl_timeout); + g_source_unref (priv->rtsp_ctrl_timeout); + priv->rtsp_ctrl_timeout = NULL; + priv->rtsp_ctrl_timeout_cnt = 0; + } +} + +static void +rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv) +{ + g_mutex_lock (&priv->lock); + rtsp_ctrl_timeout_remove_unlocked (priv); + g_mutex_unlock (&priv->lock); +} + static gboolean rtsp_ctrl_timeout_cb (gpointer user_data) { @@ -2552,12 +2573,10 @@ rtsp_ctrl_timeout_cb (gpointer user_data) && priv->rtsp_ctrl_timeout_cnt > RTSP_CTRL_TIMEOUT_VALUE) || (priv->had_session && priv->rtsp_ctrl_timeout_cnt > priv->post_session_timeout)) { + g_mutex_lock (&priv->lock); GST_DEBUG ("rtsp control session timeout %p expired, closing client.", priv->rtsp_ctrl_timeout); - g_mutex_lock (&priv->lock); - g_source_unref (priv->rtsp_ctrl_timeout); - priv->rtsp_ctrl_timeout = NULL; - priv->rtsp_ctrl_timeout_cnt = 0; + rtsp_ctrl_timeout_remove_unlocked (priv); g_mutex_unlock (&priv->lock); gst_rtsp_client_close (client); @@ -2567,23 +2586,6 @@ rtsp_ctrl_timeout_cb (gpointer user_data) return res; } -static void -rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv) -{ - g_mutex_lock (&priv->lock); - - if (priv->rtsp_ctrl_timeout != NULL) { - GST_DEBUG ("rtsp control session removed timeout %p.", - priv->rtsp_ctrl_timeout); - g_source_destroy (priv->rtsp_ctrl_timeout); - g_source_unref (priv->rtsp_ctrl_timeout); - priv->rtsp_ctrl_timeout = NULL; - priv->rtsp_ctrl_timeout_cnt = 0; - } - - g_mutex_unlock (&priv->lock); -} - static gchar * stream_make_keymgmt (GstRTSPClient * client, const gchar * location, GstRTSPStream * stream) @@ -5201,8 +5203,8 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) /* Setting up a timeout for the RTSP control channel until a session * is up where it is handling timeouts. */ - rtsp_ctrl_timeout_remove (priv); /* removing old if any */ g_mutex_lock (&priv->lock); + rtsp_ctrl_timeout_remove_unlocked (priv); /* removing old if any */ timer_src = g_timeout_source_new_seconds (RTSP_CTRL_CB_INTERVAL); g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client, NULL); From 6459a61e8f5ece3f18163780aa7bc1027b45b059 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Tue, 3 Mar 2015 14:42:07 +0100 Subject: [PATCH 1694/1776] media-factory: complete DSCP QoS setting support add dscp_qos setting support at factory and media level to setup IP DSCP field of bounded UDP sinks. Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/6 Part-of: --- gst/rtsp-server/rtsp-media-factory.c | 74 ++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 6 +++ gst/rtsp-server/rtsp-media.c | 79 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 6 ++- 4 files changed, 164 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index ec15d9d556..a2d091d4cd 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -58,6 +58,7 @@ struct _GstRTSPMediaFactoryPrivate GstRTSPProfile profiles; GstRTSPLowerTrans protocols; guint buffer_size; + gint dscp_qos; GstRTSPAddressPool *pool; GstRTSPTransportMode transport_mode; gboolean stop_on_disconnect; @@ -93,6 +94,7 @@ struct _GstRTSPMediaFactoryPrivate #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE #define DEFAULT_DO_RETRANSMISSION FALSE +#define DEFAULT_DSCP_QOS (-1) enum { @@ -110,6 +112,7 @@ enum PROP_CLOCK, PROP_MAX_MCAST_TTL, PROP_BIND_MCAST_ADDRESS, + PROP_DSCP_QOS, PROP_LAST }; @@ -244,6 +247,11 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) DEFAULT_BIND_MCAST_ADDRESS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DSCP_QOS, + g_param_spec_int ("dscp-qos", "DSCP QoS", + "The IP DSCP field to use", -1, 63, + DEFAULT_DSCP_QOS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] = g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, @@ -287,6 +295,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS; + priv->dscp_qos = DEFAULT_DSCP_QOS; g_mutex_init (&priv->lock); g_mutex_init (&priv->medias_lock); @@ -369,6 +378,9 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, g_value_set_boolean (value, gst_rtsp_media_factory_is_bind_mcast_address (factory)); break; + case PROP_DSCP_QOS: + g_value_set_int (value, gst_rtsp_media_factory_get_dscp_qos (factory)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -427,6 +439,9 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, gst_rtsp_media_factory_set_bind_mcast_address (factory, g_value_get_boolean (value)); break; + case PROP_DSCP_QOS: + gst_rtsp_media_factory_set_dscp_qos (factory, g_value_get_int (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -813,6 +828,62 @@ gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_set_dscp_qos: + * @factory: a #GstRTSPMediaFactory + * @dscp_qos: a new dscp qos value (0-63, or -1 to disable) + * + * Configure the media dscp qos to @dscp_qos. + * + * Since: 1.18 + */ +void +gst_rtsp_media_factory_set_dscp_qos (GstRTSPMediaFactory * factory, + gint dscp_qos) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + if (dscp_qos < -1 || dscp_qos > 63) { + GST_WARNING_OBJECT (factory, "trying to set illegal dscp qos %d", dscp_qos); + return; + } + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv->dscp_qos = dscp_qos; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_dscp_qos: + * @factory: a #GstRTSPMediaFactory + * + * Get the configured media DSCP QoS. + * + * Returns: the media DSCP QoS value or -1 if disabled. + * + * Since: 1.18 + */ +gint +gst_rtsp_media_factory_get_dscp_qos (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + guint result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + result = priv->dscp_qos; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} + /** * gst_rtsp_media_factory_set_address_pool: * @factory: a #GstRTSPMediaFactory @@ -1754,6 +1825,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) GstRTSPMediaFactoryPrivate *priv = factory->priv; gboolean shared, eos_shutdown, stop_on_disconnect; guint size; + gint dscp_qos; GstRTSPSuspendMode suspend_mode; GstRTSPProfile profiles; GstRTSPLowerTrans protocols; @@ -1774,6 +1846,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) shared = priv->shared; eos_shutdown = priv->eos_shutdown; size = priv->buffer_size; + dscp_qos = priv->dscp_qos; profiles = priv->profiles; protocols = priv->protocols; rtx_time = priv->rtx_time; @@ -1790,6 +1863,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_shared (media, shared); gst_rtsp_media_set_eos_shutdown (media, eos_shutdown); gst_rtsp_media_set_buffer_size (media, size); + gst_rtsp_media_set_dscp_qos (media, dscp_qos); gst_rtsp_media_set_profiles (media, profiles); gst_rtsp_media_set_protocols (media, protocols); gst_rtsp_media_set_retransmission_time (media, rtx_time); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 65edbaa0b8..dd08498264 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -252,6 +252,12 @@ void gst_rtsp_media_factory_set_bind_mcast_address (GstRTSPMedi GST_RTSP_SERVER_API gboolean gst_rtsp_media_factory_is_bind_mcast_address (GstRTSPMediaFactory * factory); +GST_RTSP_SERVER_API +void gst_rtsp_media_factory_set_dscp_qos (GstRTSPMediaFactory * factory, + gint dscp_qos); +GST_RTSP_SERVER_API +gint gst_rtsp_media_factory_get_dscp_qos (GstRTSPMediaFactory * factory); + /* creating the media from the factory and a url */ GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e99ecae1fe..dab4704abc 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -106,6 +106,7 @@ struct _GstRTSPMediaPrivate gboolean reused; gboolean eos_shutdown; guint buffer_size; + gint dscp_qos; GstRTSPAddressPool *pool; gchar *multicast_iface; guint max_mcast_ttl; @@ -169,6 +170,7 @@ struct _GstRTSPMediaPrivate GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_EOS_SHUTDOWN FALSE #define DEFAULT_BUFFER_SIZE 0x80000 +#define DEFAULT_DSCP_QOS (-1) #define DEFAULT_TIME_PROVIDER FALSE #define DEFAULT_LATENCY 200 #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY @@ -200,6 +202,7 @@ enum PROP_CLOCK, PROP_MAX_MCAST_TTL, PROP_BIND_MCAST_ADDRESS, + PROP_DSCP_QOS, PROP_LAST }; @@ -410,6 +413,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) DEFAULT_BIND_MCAST_ADDRESS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DSCP_QOS, + g_param_spec_int ("dscp-qos", "DSCP QoS", + "The IP DSCP field to use for each related stream", -1, 63, + DEFAULT_DSCP_QOS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_rtsp_media_signals[SIGNAL_NEW_STREAM] = g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, NULL, @@ -483,6 +491,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS; priv->do_rate_control = DEFAULT_DO_RATE_CONTROL; + priv->dscp_qos = DEFAULT_DSCP_QOS; priv->expected_async_done = FALSE; } @@ -577,6 +586,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid, case PROP_BIND_MCAST_ADDRESS: g_value_set_boolean (value, gst_rtsp_media_is_bind_mcast_address (media)); break; + case PROP_DSCP_QOS: + g_value_set_int (value, gst_rtsp_media_get_dscp_qos (media)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -637,6 +649,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid, gst_rtsp_media_set_bind_mcast_address (media, g_value_get_boolean (value)); break; + case PROP_DSCP_QOS: + gst_rtsp_media_set_dscp_qos (media, g_value_get_int (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1411,6 +1426,70 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) return res; } +static void +do_set_dscp_qos (GstRTSPStream * stream, gint * dscp_qos) +{ + gst_rtsp_stream_set_dscp_qos (stream, *dscp_qos); +} + +/** + * gst_rtsp_media_set_dscp_qos: + * @media: a #GstRTSPMedia + * @dscp_qos: a new dscp qos value (0-63, or -1 to disable) + * + * Configure the dscp qos of attached streams to @dscp_qos. + * + * Since: 1.18 + */ +void +gst_rtsp_media_set_dscp_qos (GstRTSPMedia * media, gint dscp_qos) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + GST_LOG_OBJECT (media, "set DSCP QoS %d", dscp_qos); + + if (dscp_qos < -1 || dscp_qos > 63) { + GST_WARNING_OBJECT (media, "trying to set illegal dscp qos %d", dscp_qos); + return; + } + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->dscp_qos = dscp_qos; + g_ptr_array_foreach (priv->streams, (GFunc) do_set_dscp_qos, &dscp_qos); + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_get_dscp_qos: + * @media: a #GstRTSPMedia + * + * Get the configured DSCP QoS of attached media. + * + * Returns: the DSCP QoS value of attached streams or -1 if disabled. + * + * Since: 1.18 + */ +gint +gst_rtsp_media_get_dscp_qos (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + gint res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE); + + priv = media->priv; + + g_mutex_unlock (&priv->lock); + res = priv->dscp_qos; + g_mutex_unlock (&priv->lock); + + return res; +} + /** * gst_rtsp_media_set_stop_on_disconnect: * @media: a #GstRTSPMedia diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index d44f24c533..9c2494a64e 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -307,7 +307,6 @@ GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media, GST_RTSP_SERVER_API void gst_rtsp_media_set_clock (GstRTSPMedia *media, GstClock * clock); - GST_RTSP_SERVER_API void gst_rtsp_media_set_publish_clock_mode (GstRTSPMedia * media, GstRTSPPublishClockMode mode); @@ -325,6 +324,11 @@ void gst_rtsp_media_set_bind_mcast_address (GstRTSPMedia *medi GST_RTSP_SERVER_API gboolean gst_rtsp_media_is_bind_mcast_address (GstRTSPMedia *media); +GST_RTSP_SERVER_API +void gst_rtsp_media_set_dscp_qos (GstRTSPMedia * media, gint dscp_qos); +GST_RTSP_SERVER_API +gint gst_rtsp_media_get_dscp_qos (GstRTSPMedia * media); + /* prepare the media for playback */ GST_RTSP_SERVER_API From ba7d568bb3103840abc086db657564817a73b03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristofer=20Bj=C3=B6rkstr=C3=B6m?= Date: Mon, 25 May 2020 13:49:45 +0200 Subject: [PATCH 1695/1776] rtsp-client: Fix race condition in rtsp ctrl timeout by WeakRef client There was a race condition where client was being finalized and concurrently in some other thread the rtsp ctrl timout was relying on client data that was being freed. When rtsp ctrl timeout is setup, a WeakRef on Client is set. Part-of: --- gst/rtsp-server/rtsp-client.c | 69 +++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 32f2f0dde5..f533c67b38 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -187,7 +187,7 @@ static void gst_rtsp_client_set_property (GObject * object, guint propid, const GValue * value, GParamSpec * pspec); static void gst_rtsp_client_finalize (GObject * obj); -static void rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv); +static void rtsp_ctrl_timeout_remove (GstRTSPClient * client); static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media); static gboolean handle_sdp (GstRTSPClient * client, GstRTSPContext * ctx, @@ -1305,7 +1305,7 @@ gst_rtsp_client_close (GstRTSPClient * client) priv->watch = NULL; gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); - rtsp_ctrl_timeout_remove (priv); + rtsp_ctrl_timeout_remove (client); } if (priv->watch_context) { @@ -2553,36 +2553,56 @@ rtsp_ctrl_timeout_remove_unlocked (GstRTSPClientPrivate * priv) } static void -rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv) +rtsp_ctrl_timeout_remove (GstRTSPClient * client) { - g_mutex_lock (&priv->lock); - rtsp_ctrl_timeout_remove_unlocked (priv); - g_mutex_unlock (&priv->lock); + g_mutex_lock (&client->priv->lock); + rtsp_ctrl_timeout_remove_unlocked (client->priv); + g_mutex_unlock (&client->priv->lock); +} + +static void +rtsp_ctrl_timeout_destroy_notify (gpointer user_data) +{ + GWeakRef *client_weak_ref = (GWeakRef *) user_data; + + g_weak_ref_clear (client_weak_ref); + g_free (client_weak_ref); } static gboolean rtsp_ctrl_timeout_cb (gpointer user_data) { gboolean res = G_SOURCE_CONTINUE; - GstRTSPClient *client = (GstRTSPClient *) user_data; - GstRTSPClientPrivate *priv = client->priv; + GstRTSPClientPrivate *priv; + GWeakRef *client_weak_ref = (GWeakRef *) user_data; + GstRTSPClient *client = (GstRTSPClient *) g_weak_ref_get (client_weak_ref); + if (client == NULL) { + return G_SOURCE_REMOVE; + } + + priv = client->priv; + g_mutex_lock (&priv->lock); priv->rtsp_ctrl_timeout_cnt += RTSP_CTRL_CB_INTERVAL; - if ((!priv->had_session - && priv->rtsp_ctrl_timeout_cnt > RTSP_CTRL_TIMEOUT_VALUE) + if ((priv->rtsp_ctrl_timeout_cnt > RTSP_CTRL_TIMEOUT_VALUE) || (priv->had_session && priv->rtsp_ctrl_timeout_cnt > priv->post_session_timeout)) { - g_mutex_lock (&priv->lock); GST_DEBUG ("rtsp control session timeout %p expired, closing client.", priv->rtsp_ctrl_timeout); - rtsp_ctrl_timeout_remove_unlocked (priv); - g_mutex_unlock (&priv->lock); - gst_rtsp_client_close (client); + rtsp_ctrl_timeout_remove_unlocked (client->priv); res = G_SOURCE_REMOVE; } + g_mutex_unlock (&priv->lock); + + if (res == G_SOURCE_REMOVE) { + gst_rtsp_client_close (client); + } + + g_object_unref (client); + return res; } @@ -2792,7 +2812,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) } /* Remember that we had at least one session in the past */ priv->had_session = TRUE; - rtsp_ctrl_timeout_remove (priv); + rtsp_ctrl_timeout_remove (client); if (!klass->configure_client_media (client, media, stream, ctx)) goto configure_media_failed_no_reply; @@ -3743,8 +3763,12 @@ client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session, if (!priv->sessions && priv->rtsp_ctrl_timeout == NULL) { if (priv->post_session_timeout > 0) { + GWeakRef *client_weak_ref = g_new (GWeakRef, 1); timer_src = g_timeout_source_new_seconds (RTSP_CTRL_CB_INTERVAL); - g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client, NULL); + + g_weak_ref_init (client_weak_ref, client); + g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client_weak_ref, + rtsp_ctrl_timeout_destroy_notify); priv->rtsp_ctrl_timeout_cnt = 0; g_source_attach (timer_src, priv->watch_context); priv->rtsp_ctrl_timeout = timer_src; @@ -5044,7 +5068,7 @@ handle_tunnel (GstRTSPClient * client) priv->watch = NULL; gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); - rtsp_ctrl_timeout_remove (priv); + rtsp_ctrl_timeout_remove (client); } if (priv->watch_context) { @@ -5148,7 +5172,7 @@ client_watch_notify (GstRTSPClient * client) /* remove all sessions if the media says so and so drop the extra client ref */ gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); - rtsp_ctrl_timeout_remove (priv); + rtsp_ctrl_timeout_remove (client); gst_rtsp_client_session_filter (client, cleanup_session, &closed); if (priv->watch_context) { g_main_context_unref (priv->watch_context); @@ -5180,6 +5204,7 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) GstRTSPClientPrivate *priv; GSource *timer_src; guint res; + GWeakRef *client_weak_ref = g_new (GWeakRef, 1); g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0); priv = client->priv; @@ -5204,10 +5229,14 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) /* Setting up a timeout for the RTSP control channel until a session * is up where it is handling timeouts. */ g_mutex_lock (&priv->lock); - rtsp_ctrl_timeout_remove_unlocked (priv); /* removing old if any */ + + /* remove old timeout if any */ + rtsp_ctrl_timeout_remove_unlocked (client->priv); timer_src = g_timeout_source_new_seconds (RTSP_CTRL_CB_INTERVAL); - g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client, NULL); + g_weak_ref_init (client_weak_ref, client); + g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client_weak_ref, + rtsp_ctrl_timeout_destroy_notify); g_source_attach (timer_src, priv->watch_context); priv->rtsp_ctrl_timeout = timer_src; GST_DEBUG ("rtsp control setting up session timeout %p.", From 0526a5c9bb07642f8d3bb050835723dc91758292 Mon Sep 17 00:00:00 2001 From: Ludvig Rappe Date: Mon, 4 May 2020 13:43:00 +0200 Subject: [PATCH 1696/1776] rtsp-media: update expected_async_done during suspend Set expected_async_done to FALSE in default_suspend() if a state change occurs and the return value from set_target_state() is something other than GST_STATE_CHANGE_ASYNC. Without this change there is a risk that expected_async_done will be TRUE even though no asynchronous state change is taking place. This could happen if the pipeline is set to PAUSED using media_set_pipeline_state_locked(), an asynchronous state change starts and then the media is suspended (which could result in a state change, aborting the asynchronous state change). If the media is suspended before the asynchronous state change ends then expected_async_done will be TRUE but no asynchronous state change is taking place. Part-of: --- gst/rtsp-server/rtsp-media.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index dab4704abc..1493ecc67d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -4444,7 +4444,7 @@ static gboolean default_suspend (GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; - GstStateChangeReturn ret; + GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE; switch (priv->suspend_mode) { case GST_RTSP_SUSPEND_MODE_NONE: @@ -4472,6 +4472,12 @@ default_suspend (GstRTSPMedia * media) break; } + /* If we use any suspend mode that changes the state then we must update + * expected_async_done, since we might not be doing an asyncronous state + * change anymore. */ + if (ret != GST_STATE_CHANGE_FAILURE && ret != GST_STATE_CHANGE_ASYNC) + priv->expected_async_done = FALSE; + return TRUE; /* ERRORS */ From ae58f7d771998539087a975b2b8a3942f9b7d516 Mon Sep 17 00:00:00 2001 From: Ludvig Rappe Date: Tue, 26 May 2020 15:31:22 +0200 Subject: [PATCH 1697/1776] rtsp-media: wait for all GstRTSPStreamBlocking messages Make sure rtsp-media have received a GstRTSPStreamBlocking message from each active stream when checking if all streams are blocked. Without this change there will be a race condition when using two or more streams and rtsp-media receives a GstRTSPStreamBlocking message from one of the streams. This is because rtsp-media then checks if all streams are blocked by calling gst_rtsp_stream_is_blocking() for each stream. This function call returns TRUE if the stream has sent a GstRTSPStreamBlocking message, however, rtsp-media may have yet to receive this message. This would then result in that rtsp-media erroneously thinks it is blocking all streams which could result in rtsp-media changing state, from PREPARING to PREPARED. In the case of a preroll, this could result in that rtsp-media thinks that the pipeline is prerolled even though that might not be the case. Part-of: --- gst/rtsp-server/rtsp-media.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 1493ecc67d..b17ced155f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -114,6 +114,7 @@ struct _GstRTSPMediaPrivate gboolean blocked; GstRTSPTransportMode transport_mode; gboolean stop_on_disconnect; + guint blocking_msg_received; GstElement *element; GRecMutex state_lock; /* locking order: state lock, lock */ @@ -493,6 +494,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->do_rate_control = DEFAULT_DO_RATE_CONTROL; priv->dscp_qos = DEFAULT_DSCP_QOS; priv->expected_async_done = FALSE; + priv->blocking_msg_received = 0; } static void @@ -2739,6 +2741,9 @@ media_streams_set_blocked (GstRTSPMedia * media, gboolean blocked) GST_DEBUG ("media %p set blocked %d", media, blocked); priv->blocked = blocked; g_ptr_array_foreach (priv->streams, (GFunc) stream_update_blocked, media); + + if (!blocked) + priv->blocking_msg_received = 0; } static void @@ -2757,6 +2762,7 @@ media_unblock (GstRTSPMedia * media) * streams that are complete */ priv->blocked = FALSE; g_ptr_array_foreach (priv->streams, (GFunc) stream_unblock, media); + priv->blocking_msg_received = 0; } static void @@ -3140,6 +3146,25 @@ set_target_state (GstRTSPMedia * media, GstState state, gboolean do_state) return ret; } +static void +stream_collect_active (GstRTSPStream * stream, guint * active_streams) +{ + if (gst_rtsp_stream_is_complete (stream)) + (*active_streams)++; +} + +static guint +nbr_active_streams (GstRTSPMedia * media) +{ + guint ret = 0; + + g_ptr_array_foreach (media->priv->streams, (GFunc) stream_collect_active, + &ret); + + return ret; +} + + /* called with state-lock */ /* called with state-lock */ static gboolean default_handle_message (GstRTSPMedia * media, GstMessage * message) @@ -3247,8 +3272,11 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) s = gst_message_get_structure (message); if (gst_structure_has_name (s, "GstRTSPStreamBlocking")) { GST_DEBUG ("media received blocking message"); + priv->blocking_msg_received++; if (priv->blocked && media_streams_blocking (media) && - priv->no_more_pads_pending == 0) { + priv->no_more_pads_pending == 0 && + (priv->blocking_msg_received == nbr_active_streams (media) || + priv->blocking_msg_received == priv->streams->len)) { GST_DEBUG_OBJECT (GST_MESSAGE_SRC (message), "media is blocking"); g_mutex_lock (&priv->lock); collect_media_stats (media); @@ -3256,6 +3284,8 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARING) gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); + + priv->blocking_msg_received = 0; } } break; From fe5d29ee3fdc56ba64c6243d6a96eeee8609e4ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 27 May 2020 17:29:18 +0100 Subject: [PATCH 1698/1776] tests: pick up rtsp-server plugins from build directory only Part-of: --- tests/check/meson.build | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/check/meson.build b/tests/check/meson.build index d241611741..0c20c6f85d 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -1,4 +1,3 @@ -# FIXME: something is wrong with plugin paths / whitelisting here pluginsdirs = [] if gst_dep.type_name() == 'pkgconfig' pbase = dependency('gstreamer-plugins-base-' + api_version, required : false) @@ -39,7 +38,7 @@ foreach test_name : rtsp_server_tests env = environment() env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') env.set('GST_STATE_IGNORE_ELEMENTS', '') - env.set('GST_PLUGIN_LOADING_WHITELIST', 'gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad:gst-rtsp-server') + env.set('GST_PLUGIN_LOADING_WHITELIST', 'gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad:gst-rtsp-server@' + meson.build_root()) env.set('CK_DEFAULT_TIMEOUT', '120') env.set('GST_REGISTRY', '@0@/@1@.registry'.format(meson.current_build_dir(), test_name)) env.set('GST_PLUGIN_PATH_1_0', [meson.build_root()] + pluginsdirs) From 92215f2f37d23a78319999b46f2a825d6b54d507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 27 May 2020 17:32:02 +0100 Subject: [PATCH 1699/1776] tests: gst-plugins-base and -bad plugins are required for the unit tests Make hard requirement until we have more fine-grained control in the unit tests. Of course the presence of the .pc file doesn't imply that the plugins we need are actually there, but it's at least a step in the right direction. Part-of: --- tests/check/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/check/meson.build b/tests/check/meson.build index 0c20c6f85d..c382400940 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -1,7 +1,7 @@ pluginsdirs = [] if gst_dep.type_name() == 'pkgconfig' - pbase = dependency('gstreamer-plugins-base-' + api_version, required : false) - pbad = dependency('gstreamer-plugins-bad-' + api_version, required : false) + pbase = dependency('gstreamer-plugins-base-' + api_version, required: true) + pbad = dependency('gstreamer-plugins-bad-' + api_version, required: true) pluginsdirs = [gst_dep.get_pkgconfig_variable('pluginsdir'), pbase.get_pkgconfig_variable('pluginsdir'), From f9348a5e69972acb2cec3d514ef06cdee80bcb24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 27 May 2020 17:33:24 +0100 Subject: [PATCH 1700/1776] tests: fix meson test env setup to make sure we use the right gst-plugin-scanner If core is built as a subproject (e.g. as in gst-build), make sure to use the gst-plugin-scanner from the built subproject. Without this, gstreamer might accidentally use the gst-plugin-scanner from the install prefix if that exists, which in turn might drag in gst library versions we didn't mean to drag in. Those gst library versions might then be older than what our current build needs, and might cause our newly-built plugins to get blacklisted in the test registry because they rely on a symbol that the wrongly-pulled in gst lib doesn't have. This should fix running of unit tests in gst-build when invoking meson test or ninja test from outside the devenv for the case where there is an older or different-version gst-plugin-scanner installed in the install prefix. In case no gst-plugin-scanner is installed in the install prefix, this will fix "GStreamer-WARNING: External plugin loader failed. This most likely means that the plugin loader helper binary was not found or could not be run. You might need to set the GST_PLUGIN_SCANNER environment variable if your setup is unusual." warnings when running the unit tests. In the case where we find GStreamer core via pkg-config we use a newly-added pkg-config var "pluginscannerdir" to get the right directory. This has the benefit of working transparently for both installed and uninstalled pkg-config files/setups. Part-of: --- tests/check/meson.build | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/check/meson.build b/tests/check/meson.build index c382400940..e7bd95c499 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -6,7 +6,12 @@ if gst_dep.type_name() == 'pkgconfig' pluginsdirs = [gst_dep.get_pkgconfig_variable('pluginsdir'), pbase.get_pkgconfig_variable('pluginsdir'), pbad.get_pkgconfig_variable('pluginsdir')] + + gst_plugin_scanner_dir = gst_dep.get_pkgconfig_variable('pluginscannerdir') +else + gst_plugin_scanner_dir = subproject('gstreamer').get_variable('gst_scanner_dir') endif +gst_plugin_scanner_path = join_paths(gst_plugin_scanner_dir, 'gst-plugin-scanner') test_c_args = [ '-UG_DISABLE_ASSERT', @@ -40,8 +45,9 @@ foreach test_name : rtsp_server_tests env.set('GST_STATE_IGNORE_ELEMENTS', '') env.set('GST_PLUGIN_LOADING_WHITELIST', 'gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad:gst-rtsp-server@' + meson.build_root()) env.set('CK_DEFAULT_TIMEOUT', '120') - env.set('GST_REGISTRY', '@0@/@1@.registry'.format(meson.current_build_dir(), test_name)) + env.set('GST_REGISTRY', join_paths(meson.current_build_dir(), '@0@.registry'.format(test_name))) env.set('GST_PLUGIN_PATH_1_0', [meson.build_root()] + pluginsdirs) + env.set('GST_PLUGIN_SCANNER_1_0', gst_plugin_scanner_path) fname = '@0@.c'.format(test_name) test_name = test_name.underscorify() From a33e756d2cedd1751a8dba25396c3a19993aa618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 27 May 2020 17:43:43 +0100 Subject: [PATCH 1701/1776] tests: put registry into tests/check not the gst/ subdir Underscorify the test name before setting GST_REGISTRY, so the registry actually ends up in the current build dir and not some subdir. For consistency with the other modules, but should also avoid problems on windows. Also fix indentation of environment block. Part-of: --- tests/check/meson.build | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/check/meson.build b/tests/check/meson.build index e7bd95c499..26904307d7 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -40,17 +40,18 @@ if not get_option('rtspclientsink').disabled() endif foreach test_name : rtsp_server_tests - env = environment() - env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') - env.set('GST_STATE_IGNORE_ELEMENTS', '') - env.set('GST_PLUGIN_LOADING_WHITELIST', 'gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad:gst-rtsp-server@' + meson.build_root()) - env.set('CK_DEFAULT_TIMEOUT', '120') - env.set('GST_REGISTRY', join_paths(meson.current_build_dir(), '@0@.registry'.format(test_name))) - env.set('GST_PLUGIN_PATH_1_0', [meson.build_root()] + pluginsdirs) - env.set('GST_PLUGIN_SCANNER_1_0', gst_plugin_scanner_path) - fname = '@0@.c'.format(test_name) test_name = test_name.underscorify() + + env = environment() + env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') + env.set('GST_STATE_IGNORE_ELEMENTS', '') + env.set('GST_PLUGIN_LOADING_WHITELIST', 'gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad:gst-rtsp-server@' + meson.build_root()) + env.set('CK_DEFAULT_TIMEOUT', '120') + env.set('GST_REGISTRY', join_paths(meson.current_build_dir(), '@0@.registry'.format(test_name))) + env.set('GST_PLUGIN_PATH_1_0', [meson.build_root()] + pluginsdirs) + env.set('GST_PLUGIN_SCANNER_1_0', gst_plugin_scanner_path) + exe = executable(test_name, fname, include_directories : rtspserver_incs, c_args : rtspserver_args + test_c_args, From b61f1081b2075a152e230f9bd4192f4a7c16de16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 27 May 2020 23:38:06 +0100 Subject: [PATCH 1702/1776] meson: gir: remove bogus sources_top_dir kwarg Doesn't actually exist. Was fixed differently in Meson so that the user doesn't have to specify it. Part-of: --- gst/rtsp-server/meson.build | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index bfe0aebc21..6e40cc64de 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -79,7 +79,6 @@ if build_gir install : true, extra_args : gst_gir_extra_args, includes : ['Gst-1.0', 'GstRtsp-1.0', 'GstNet-1.0'], - sources_top_dir: meson.current_source_dir(), dependencies : gst_rtsp_server_deps, ) rtsp_server_gen_sources += [rtsp_server_gir] From 1a99533be89ef4438908715dfc32b52581a2b588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 30 May 2020 23:23:51 +0300 Subject: [PATCH 1703/1776] plugins: Use gst_type_mark_as_plugin_api() for all non-element plugin types --- gst/rtsp-sink/gstrtspclientsink.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 19f9cda441..e4544e5e4a 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -820,6 +820,9 @@ gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) "Jan Schmidt "); gstbin_class->handle_message = gst_rtsp_client_sink_handle_message; + + gst_type_mark_as_plugin_api (GST_TYPE_RTSP_CLIENT_SINK_PAD); + gst_type_mark_as_plugin_api (GST_TYPE_RTSP_CLIENT_SINK_NTP_TIME_SOURCE); } static void From 6482651caf30cd093cb0a5e4adeffffaf0f80ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 27 May 2020 17:00:05 +0300 Subject: [PATCH 1704/1776] docs: Update gst_plugins_cache.json --- docs/gst_plugins_cache.json | 355 +++++++++++++++++------------------- 1 file changed, 165 insertions(+), 190 deletions(-) diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index cf27b24816..8ee812e144 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -13,19 +13,18 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy", + "GstURIHandler" + ], "klass": "Sink/Network", "long-name": "RTSP RECORD client", - "name": "rtspclientsink", "pad-templates": { "sink_%%u": { "caps": "ANY", "direction": "sink", - "presence": "request" - }, - "stream_%%u": { - "caps": "ANY", - "direction": "sink", - "presence": "request" + "presence": "request", + "type": "GstRtspClientSinkPad" } }, "properties": { @@ -34,7 +33,8 @@ "construct": false, "construct-only": false, "default": "false", - "type-name": "gboolean", + "readable": true, + "type": "gboolean", "writable": true }, "debug": { @@ -42,7 +42,8 @@ "construct": false, "construct-only": false, "default": "false", - "type-name": "gboolean", + "readable": true, + "type": "gboolean", "writable": true }, "do-rtsp-keep-alive": { @@ -50,7 +51,8 @@ "construct": false, "construct-only": false, "default": "true", - "type-name": "gboolean", + "readable": true, + "type": "gboolean", "writable": true }, "latency": { @@ -60,7 +62,8 @@ "default": "2000", "max": "-1", "min": "0", - "type-name": "guint", + "readable": true, + "type": "guint", "writable": true }, "location": { @@ -68,7 +71,8 @@ "construct": false, "construct-only": false, "default": "NULL", - "type-name": "gchararray", + "readable": true, + "type": "gchararray", "writable": true }, "message-forward": { @@ -76,7 +80,8 @@ "construct": false, "construct-only": false, "default": "false", - "type-name": "gboolean", + "readable": true, + "type": "gboolean", "writable": true }, "multicast-iface": { @@ -84,16 +89,8 @@ "construct": false, "construct-only": false, "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "readable": true, + "type": "gchararray", "writable": true }, "ntp-time-source": { @@ -101,37 +98,8 @@ "construct": false, "construct-only": false, "default": "ntp (0)", - "enum": true, - "type-name": "GstRTSPClientSinkNtpTimeSource", - "values": [ - { - "desc": "NTP time based on realtime clock", - "name": "ntp", - "value": "0" - }, - { - "desc": "UNIX time based on realtime clock", - "name": "unix", - "value": "1" - }, - { - "desc": "Running time based on pipeline clock", - "name": "running-time", - "value": "2" - }, - { - "desc": "Pipeline clock time", - "name": "clock-time", - "value": "3" - } - ], - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "readable": true, + "type": "GstRTSPClientSinkNtpTimeSource", "writable": true }, "port-range": { @@ -139,7 +107,8 @@ "construct": false, "construct-only": false, "default": "NULL", - "type-name": "gchararray", + "readable": true, + "type": "gchararray", "writable": true }, "profiles": { @@ -147,34 +116,8 @@ "construct": false, "construct-only": false, "default": "avp", - "type-name": "GstRTSPProfile", - "values": [ - { - "desc": "GST_RTSP_PROFILE_UNKNOWN", - "name": "unknown", - "value": "0x00000000" - }, - { - "desc": "GST_RTSP_PROFILE_AVP", - "name": "avp", - "value": "0x00000001" - }, - { - "desc": "GST_RTSP_PROFILE_SAVP", - "name": "savp", - "value": "0x00000002" - }, - { - "desc": "GST_RTSP_PROFILE_AVPF", - "name": "avpf", - "value": "0x00000004" - }, - { - "desc": "GST_RTSP_PROFILE_SAVPF", - "name": "savpf", - "value": "0x00000008" - } - ], + "readable": true, + "type": "GstRTSPProfile", "writable": true }, "protocols": { @@ -182,39 +125,8 @@ "construct": false, "construct-only": false, "default": "tcp+udp-mcast+udp", - "type-name": "GstRTSPLowerTrans", - "values": [ - { - "desc": "GST_RTSP_LOWER_TRANS_UNKNOWN", - "name": "unknown", - "value": "0x00000000" - }, - { - "desc": "GST_RTSP_LOWER_TRANS_UDP", - "name": "udp", - "value": "0x00000001" - }, - { - "desc": "GST_RTSP_LOWER_TRANS_UDP_MCAST", - "name": "udp-mcast", - "value": "0x00000002" - }, - { - "desc": "GST_RTSP_LOWER_TRANS_TCP", - "name": "tcp", - "value": "0x00000004" - }, - { - "desc": "GST_RTSP_LOWER_TRANS_HTTP", - "name": "http", - "value": "0x00000010" - }, - { - "desc": "GST_RTSP_LOWER_TRANS_TLS", - "name": "tls", - "value": "0x00000020" - } - ], + "readable": true, + "type": "GstRTSPLowerTrans", "writable": true }, "proxy": { @@ -222,7 +134,8 @@ "construct": false, "construct-only": false, "default": "NULL", - "type-name": "gchararray", + "readable": true, + "type": "gchararray", "writable": true }, "proxy-id": { @@ -230,7 +143,8 @@ "construct": false, "construct-only": false, "default": "NULL", - "type-name": "gchararray", + "readable": true, + "type": "gchararray", "writable": true }, "proxy-pw": { @@ -238,7 +152,8 @@ "construct": false, "construct-only": false, "default": "NULL", - "type-name": "gchararray", + "readable": true, + "type": "gchararray", "writable": true }, "retry": { @@ -248,7 +163,8 @@ "default": "20", "max": "65535", "min": "0", - "type-name": "guint", + "readable": true, + "type": "guint", "writable": true }, "rtp-blocksize": { @@ -258,7 +174,8 @@ "default": "0", "max": "65536", "min": "0", - "type-name": "guint", + "readable": true, + "type": "guint", "writable": true }, "rtx-time": { @@ -268,14 +185,16 @@ "default": "500", "max": "-1", "min": "0", - "type-name": "guint", + "readable": true, + "type": "guint", "writable": true }, "sdes": { "blurb": "The SDES items of this session", "construct": false, "construct-only": false, - "type-name": "GstStructure", + "readable": true, + "type": "GstStructure", "writable": true }, "tcp-timeout": { @@ -285,7 +204,8 @@ "default": "20000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "readable": true, + "type": "guint64", "writable": true }, "timeout": { @@ -295,21 +215,24 @@ "default": "5000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "readable": true, + "type": "guint64", "writable": true }, "tls-database": { "blurb": "TLS database with anchor certificate authorities used to validate the server certificate", "construct": false, "construct-only": false, - "type-name": "GTlsDatabase", + "readable": true, + "type": "GTlsDatabase", "writable": true }, "tls-interaction": { "blurb": "A GTlsInteraction object to prompt the user for password or certificate", "construct": false, "construct-only": false, - "type-name": "GTlsInteraction", + "readable": true, + "type": "GTlsInteraction", "writable": true }, "tls-validation-flags": { @@ -317,49 +240,8 @@ "construct": false, "construct-only": false, "default": "validate-all", - "type-name": "GTlsCertificateFlags", - "values": [ - { - "desc": "G_TLS_CERTIFICATE_UNKNOWN_CA", - "name": "unknown-ca", - "value": "0x00000001" - }, - { - "desc": "G_TLS_CERTIFICATE_BAD_IDENTITY", - "name": "bad-identity", - "value": "0x00000002" - }, - { - "desc": "G_TLS_CERTIFICATE_NOT_ACTIVATED", - "name": "not-activated", - "value": "0x00000004" - }, - { - "desc": "G_TLS_CERTIFICATE_EXPIRED", - "name": "expired", - "value": "0x00000008" - }, - { - "desc": "G_TLS_CERTIFICATE_REVOKED", - "name": "revoked", - "value": "0x00000010" - }, - { - "desc": "G_TLS_CERTIFICATE_INSECURE", - "name": "insecure", - "value": "0x00000020" - }, - { - "desc": "G_TLS_CERTIFICATE_GENERIC_ERROR", - "name": "generic-error", - "value": "0x00000040" - }, - { - "desc": "G_TLS_CERTIFICATE_VALIDATE_ALL", - "name": "validate-all", - "value": "0x0000007f" - } - ], + "readable": true, + "type": "GTlsCertificateFlags", "writable": true }, "udp-buffer-size": { @@ -369,7 +251,8 @@ "default": "524288", "max": "2147483647", "min": "0", - "type-name": "gint", + "readable": true, + "type": "gint", "writable": true }, "udp-reconnect": { @@ -377,16 +260,17 @@ "construct": false, "construct-only": false, "default": "true", - "type-name": "gboolean", + "readable": true, + "type": "gboolean", "writable": true }, "user-agent": { - "unstable-values": true, "blurb": "The User-Agent string to send to the server", "construct": false, "construct-only": false, - "default": "GStreamer/@GSTREAMER_VERSION@", - "type-name": "gchararray", + "default": "GStreamer/1.17.0.1", + "readable": true, + "type": "gchararray", "writable": true }, "user-id": { @@ -394,7 +278,8 @@ "construct": false, "construct-only": false, "default": "NULL", - "type-name": "gchararray", + "readable": true, + "type": "gchararray", "writable": true }, "user-pw": { @@ -402,7 +287,8 @@ "construct": false, "construct-only": false, "default": "NULL", - "type-name": "gchararray", + "readable": true, + "type": "gchararray", "writable": true } }, @@ -410,44 +296,133 @@ "signals": { "accept-certificate": { "args": [ - "GTlsConnection", - "GTlsCertificate", - "GTlsCertificateFlags" + { + "name": "arg0", + "type": "GTlsConnection" + }, + { + "name": "arg1", + "type": "GTlsCertificate" + }, + { + "name": "arg2", + "type": "GTlsCertificateFlags" + } ], - "retval": "gboolean" + "return-type": "gboolean", + "when": "last" }, "handle-request": { "args": [ - "gpointer", - "gpointer" + { + "name": "arg0", + "type": "gpointer" + }, + { + "name": "arg1", + "type": "gpointer" + } ], - "retval": "void" + "return-type": "void" }, "new-manager": { "args": [ - "GstElement" + { + "name": "arg0", + "type": "GstElement" + } ], - "retval": "void" + "return-type": "void", + "when": "first" }, "new-payloader": { "args": [ - "GstElement" + { + "name": "arg0", + "type": "GstElement" + } ], - "retval": "void" + "return-type": "void", + "when": "first" }, "request-rtcp-key": { "args": [ - "guint" + { + "name": "arg0", + "type": "guint" + } ], - "retval": "GstCaps" + "return-type": "GstCaps", + "when": "last" } } } }, "filename": "gstrtspclientsink", "license": "LGPL", + "other-types": { + "GstRTSPClientSinkNtpTimeSource": { + "kind": "enum", + "values": [ + { + "desc": "NTP time based on realtime clock", + "name": "ntp", + "value": "0" + }, + { + "desc": "UNIX time based on realtime clock", + "name": "unix", + "value": "1" + }, + { + "desc": "Running time based on pipeline clock", + "name": "running-time", + "value": "2" + }, + { + "desc": "Pipeline clock time", + "name": "clock-time", + "value": "3" + } + ] + }, + "GstRtspClientSinkPad": { + "hierarchy": [ + "GstRtspClientSinkPad", + "GstGhostPad", + "GstProxyPad", + "GstPad", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "kind": "object", + "properties": { + "payloader": { + "blurb": "The payloader element to use (NULL = default automatically selected)", + "construct": false, + "construct-only": false, + "readable": true, + "type": "GstElement", + "writable": true + }, + "ulpfec-percentage": { + "blurb": "The percentage of ULP redundancy to apply", + "construct": false, + "construct-only": false, + "default": "0", + "max": "100", + "min": "0", + "readable": true, + "type": "guint", + "writable": true + } + } + } + }, "package": "GStreamer RTSP Server Library git", "source": "gst-rtsp-server", + "tracers": {}, "url": "Unknown package origin" } } \ No newline at end of file From 11f4fe79d71e8058c6ee208e72353e61486a0899 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 3 Jun 2020 18:36:25 -0400 Subject: [PATCH 1705/1776] doc: Require hotdoc >= 0.11.0 --- docs/meson.build | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/meson.build b/docs/meson.build index 100bbb4a72..a9953d854c 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -38,6 +38,17 @@ if not hotdoc_p.found() subdir_done() endif +hotdoc_req = '>= 0.11.0' +hotdoc_version = run_command(hotdoc_p, '--version').stdout() +if not hotdoc_version.version_compare(hotdoc_req) + if get_option('doc').enabled() + error('Hotdoc version @0@ not found, got @1@'.format(hotdoc_req, hotdoc_version)) + else + message('Hotdoc version @0@ not found, got @1@'.format(hotdoc_req, hotdoc_version)) + subdir_done() + endif +endif + hotdoc = import('hotdoc') foreach extension: required_hotdoc_extensions if not hotdoc.has_extensions(extension) From 7e598e9184bf68d1b94b8c0b99c90e2657a78441 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 6 Jun 2020 00:41:51 +0200 Subject: [PATCH 1706/1776] plugins: uddate gst_type_mark_as_plugin_api() calls --- gst/rtsp-sink/gstrtspclientsink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index e4544e5e4a..38536ce124 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -821,8 +821,8 @@ gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) gstbin_class->handle_message = gst_rtsp_client_sink_handle_message; - gst_type_mark_as_plugin_api (GST_TYPE_RTSP_CLIENT_SINK_PAD); - gst_type_mark_as_plugin_api (GST_TYPE_RTSP_CLIENT_SINK_NTP_TIME_SOURCE); + gst_type_mark_as_plugin_api (GST_TYPE_RTSP_CLIENT_SINK_PAD, 0); + gst_type_mark_as_plugin_api (GST_TYPE_RTSP_CLIENT_SINK_NTP_TIME_SOURCE, 0); } static void From 77eead287405ce5a20ca91756c7dc4ecb8f385ec Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 8 Jun 2020 09:45:15 +0200 Subject: [PATCH 1707/1776] tests: enforce I420 format Test was not enforcing a video format on videotestsrc. I420 was picked as it was the first format in GST_VIDEO_FORMATS_ALL which will no longer be true (gst-plugins-base!689). Part-of: --- tests/check/gst/rtspserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/check/gst/rtspserver.c b/tests/check/gst/rtspserver.c index 34c1dc48be..ed2cce233f 100644 --- a/tests/check/gst/rtspserver.c +++ b/tests/check/gst/rtspserver.c @@ -34,7 +34,7 @@ "ignore-notnegotiated=false convert-to=ok" #define VIDEO_PIPELINE "videotestsrc ! " \ ERRORIGNORE " ! " \ - "video/x-raw,width=352,height=288 ! " \ + "video/x-raw,format=I420,width=352,height=288 ! " \ "rtpgstpay name=pay0 pt=96" #define AUDIO_PIPELINE "audiotestsrc ! " \ ERRORIGNORE " ! " \ From e9e15579e6025edcbe06805026bf51667c9f1336 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Jun 2020 10:59:34 -0400 Subject: [PATCH 1708/1776] docs: Update plugins cache --- docs/gst_plugins_cache.json | 90 +++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index 8ee812e144..fbb300c998 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -30,263 +30,347 @@ "properties": { "async-handling": { "blurb": "The bin will handle Asynchronous state changes", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", + "mutable": "playing", "readable": true, "type": "gboolean", "writable": true }, "debug": { "blurb": "Dump request and response messages to stdout", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", + "mutable": "playing", "readable": true, "type": "gboolean", "writable": true }, "do-rtsp-keep-alive": { "blurb": "Send RTSP keep alive packets, disable for old incompatible server.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", + "mutable": "playing", "readable": true, "type": "gboolean", "writable": true }, "latency": { "blurb": "Amount of ms to buffer", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "2000", "max": "-1", "min": "0", + "mutable": "playing", "readable": true, "type": "guint", "writable": true }, "location": { "blurb": "Location of the RTSP url to read", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", + "mutable": "playing", "readable": true, "type": "gchararray", "writable": true }, "message-forward": { "blurb": "Forwards all children messages", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", + "mutable": "playing", "readable": true, "type": "gboolean", "writable": true }, "multicast-iface": { "blurb": "The network interface on which to join the multicast group", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", + "mutable": "playing", "readable": true, "type": "gchararray", "writable": true }, "ntp-time-source": { "blurb": "NTP time source for RTCP packets", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "ntp (0)", + "mutable": "playing", "readable": true, "type": "GstRTSPClientSinkNtpTimeSource", "writable": true }, "port-range": { "blurb": "Client port range that can be used to receive RTCP data, eg. 3000-3005 (NULL = no restrictions)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", + "mutable": "playing", "readable": true, "type": "gchararray", "writable": true }, "profiles": { "blurb": "Allowed RTSP profiles", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "avp", + "mutable": "playing", "readable": true, "type": "GstRTSPProfile", "writable": true }, "protocols": { "blurb": "Allowed lower transport protocols", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "tcp+udp-mcast+udp", + "mutable": "playing", "readable": true, "type": "GstRTSPLowerTrans", "writable": true }, "proxy": { "blurb": "Proxy settings for HTTP tunneling. Format: [http://][user:passwd@]host[:port]", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", + "mutable": "playing", "readable": true, "type": "gchararray", "writable": true }, "proxy-id": { "blurb": "HTTP proxy URI user id for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", + "mutable": "playing", "readable": true, "type": "gchararray", "writable": true }, "proxy-pw": { "blurb": "HTTP proxy URI user password for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", + "mutable": "playing", "readable": true, "type": "gchararray", "writable": true }, "retry": { "blurb": "Max number of retries when allocating RTP ports.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "20", "max": "65535", "min": "0", + "mutable": "playing", "readable": true, "type": "guint", "writable": true }, "rtp-blocksize": { "blurb": "RTP package size to suggest to server (0 = disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "65536", "min": "0", + "mutable": "playing", "readable": true, "type": "guint", "writable": true }, "rtx-time": { "blurb": "Amount of ms to buffer for retransmission. 0 disables retransmission", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "500", "max": "-1", "min": "0", + "mutable": "playing", "readable": true, "type": "guint", "writable": true }, "sdes": { "blurb": "The SDES items of this session", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, + "mutable": "playing", "readable": true, "type": "GstStructure", "writable": true }, "tcp-timeout": { "blurb": "Fail after timeout microseconds on TCP connections (0 = disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "20000000", "max": "18446744073709551615", "min": "0", + "mutable": "playing", "readable": true, "type": "guint64", "writable": true }, "timeout": { "blurb": "Retry TCP transport after UDP timeout microseconds (0 = disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "5000000", "max": "18446744073709551615", "min": "0", + "mutable": "playing", "readable": true, "type": "guint64", "writable": true }, "tls-database": { "blurb": "TLS database with anchor certificate authorities used to validate the server certificate", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, + "mutable": "playing", "readable": true, "type": "GTlsDatabase", "writable": true }, "tls-interaction": { "blurb": "A GTlsInteraction object to prompt the user for password or certificate", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, + "mutable": "playing", "readable": true, "type": "GTlsInteraction", "writable": true }, "tls-validation-flags": { "blurb": "TLS certificate validation flags used to validate the server certificate", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "validate-all", + "mutable": "playing", "readable": true, "type": "GTlsCertificateFlags", "writable": true }, "udp-buffer-size": { "blurb": "Size of the kernel UDP receive buffer in bytes, 0=default", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "524288", "max": "2147483647", "min": "0", + "mutable": "playing", "readable": true, "type": "gint", "writable": true }, "udp-reconnect": { "blurb": "Reconnect to the server if RTSP connection is closed when doing UDP", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", + "mutable": "playing", "readable": true, "type": "gboolean", "writable": true }, "user-agent": { "blurb": "The User-Agent string to send to the server", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "GStreamer/1.17.0.1", + "mutable": "playing", "readable": true, "type": "gchararray", "writable": true }, "user-id": { "blurb": "RTSP location URI user id for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", + "mutable": "playing", "readable": true, "type": "gchararray", "writable": true }, "user-pw": { "blurb": "RTSP location URI user password for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", + "mutable": "playing", "readable": true, "type": "gchararray", "writable": true @@ -400,19 +484,25 @@ "properties": { "payloader": { "blurb": "The payloader element to use (NULL = default automatically selected)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, + "mutable": "playing", "readable": true, "type": "GstElement", "writable": true }, "ulpfec-percentage": { "blurb": "The percentage of ULP redundancy to apply", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "100", "min": "0", + "mutable": "playing", "readable": true, "type": "guint", "writable": true From ec5aa720d77840030ceeac22f37ea4c61f3b595b Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 10 Jun 2020 13:45:04 +0200 Subject: [PATCH 1709/1776] onvif-media-factory: define autoptr cleanup function And have the factory in the onvif-server example inherit from GstRTSPOnvifMediaFactory. Part-of: --- examples/test-onvif-server.c | 2 +- examples/test-onvif-server.h | 2 +- gst/rtsp-server/rtsp-onvif-media-factory.h | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/test-onvif-server.c b/examples/test-onvif-server.c index f6b37df236..2a8a9cf218 100644 --- a/examples/test-onvif-server.c +++ b/examples/test-onvif-server.c @@ -524,7 +524,7 @@ fail: struct _OnvifFactory { - GstRTSPMediaFactory parent; + GstRTSPOnvifMediaFactory parent; }; G_DEFINE_TYPE (OnvifFactory, onvif_factory, GST_TYPE_RTSP_MEDIA_FACTORY); diff --git a/examples/test-onvif-server.h b/examples/test-onvif-server.h index 13d5f00dec..a3c98d9aec 100644 --- a/examples/test-onvif-server.h +++ b/examples/test-onvif-server.h @@ -27,6 +27,6 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (ReplayBin, replay_bin, REPLAY, BIN, GstBin); G_DECLARE_FINAL_TYPE (OnvifFactory, onvif_factory, ONVIF, FACTORY, - GstRTSPMediaFactory); + GstRTSPOnvifMediaFactory); G_END_DECLS diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.h b/gst/rtsp-server/rtsp-onvif-media-factory.h index bbfcabe7db..7ff9dc3469 100644 --- a/gst/rtsp-server/rtsp-onvif-media-factory.h +++ b/gst/rtsp-server/rtsp-onvif-media-factory.h @@ -88,4 +88,8 @@ guint gst_rtsp_onvif_media_factory_get_backchannel_bandwidth (GstRTSPOnvifMediaF GST_RTSP_SERVER_API gboolean gst_rtsp_onvif_media_factory_requires_backchannel (GstRTSPMediaFactory * factory, GstRTSPContext * ctx); +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPOnvifMediaFactory, gst_object_unref) +#endif + #endif /* __GST_RTSP_ONVIF_MEDIA_FACTORY_H__ */ From e16cbc217e019b4c74e52ff75ae815995ca06ce2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 9 Jun 2020 15:21:24 -0400 Subject: [PATCH 1710/1776] docs: Update plugins cache --- docs/gst_plugins_cache.json | 60 ++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index fbb300c998..b8382088cc 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -35,7 +35,7 @@ "construct-only": false, "controllable": false, "default": "false", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gboolean", "writable": true @@ -47,7 +47,7 @@ "construct-only": false, "controllable": false, "default": "false", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gboolean", "writable": true @@ -59,7 +59,7 @@ "construct-only": false, "controllable": false, "default": "true", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gboolean", "writable": true @@ -73,7 +73,7 @@ "default": "2000", "max": "-1", "min": "0", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "guint", "writable": true @@ -85,7 +85,7 @@ "construct-only": false, "controllable": false, "default": "NULL", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gchararray", "writable": true @@ -97,7 +97,7 @@ "construct-only": false, "controllable": false, "default": "false", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gboolean", "writable": true @@ -109,7 +109,7 @@ "construct-only": false, "controllable": false, "default": "NULL", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gchararray", "writable": true @@ -121,7 +121,7 @@ "construct-only": false, "controllable": false, "default": "ntp (0)", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "GstRTSPClientSinkNtpTimeSource", "writable": true @@ -133,7 +133,7 @@ "construct-only": false, "controllable": false, "default": "NULL", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gchararray", "writable": true @@ -145,7 +145,7 @@ "construct-only": false, "controllable": false, "default": "avp", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "GstRTSPProfile", "writable": true @@ -157,7 +157,7 @@ "construct-only": false, "controllable": false, "default": "tcp+udp-mcast+udp", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "GstRTSPLowerTrans", "writable": true @@ -169,7 +169,7 @@ "construct-only": false, "controllable": false, "default": "NULL", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gchararray", "writable": true @@ -181,7 +181,7 @@ "construct-only": false, "controllable": false, "default": "NULL", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gchararray", "writable": true @@ -193,7 +193,7 @@ "construct-only": false, "controllable": false, "default": "NULL", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gchararray", "writable": true @@ -207,7 +207,7 @@ "default": "20", "max": "65535", "min": "0", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "guint", "writable": true @@ -221,7 +221,7 @@ "default": "0", "max": "65536", "min": "0", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "guint", "writable": true @@ -235,7 +235,7 @@ "default": "500", "max": "-1", "min": "0", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "guint", "writable": true @@ -246,7 +246,7 @@ "construct": false, "construct-only": false, "controllable": false, - "mutable": "playing", + "mutable": "null", "readable": true, "type": "GstStructure", "writable": true @@ -260,7 +260,7 @@ "default": "20000000", "max": "18446744073709551615", "min": "0", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "guint64", "writable": true @@ -274,7 +274,7 @@ "default": "5000000", "max": "18446744073709551615", "min": "0", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "guint64", "writable": true @@ -285,7 +285,7 @@ "construct": false, "construct-only": false, "controllable": false, - "mutable": "playing", + "mutable": "null", "readable": true, "type": "GTlsDatabase", "writable": true @@ -296,7 +296,7 @@ "construct": false, "construct-only": false, "controllable": false, - "mutable": "playing", + "mutable": "null", "readable": true, "type": "GTlsInteraction", "writable": true @@ -308,7 +308,7 @@ "construct-only": false, "controllable": false, "default": "validate-all", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "GTlsCertificateFlags", "writable": true @@ -322,7 +322,7 @@ "default": "524288", "max": "2147483647", "min": "0", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gint", "writable": true @@ -334,7 +334,7 @@ "construct-only": false, "controllable": false, "default": "true", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gboolean", "writable": true @@ -346,7 +346,7 @@ "construct-only": false, "controllable": false, "default": "GStreamer/1.17.0.1", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gchararray", "writable": true @@ -358,7 +358,7 @@ "construct-only": false, "controllable": false, "default": "NULL", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gchararray", "writable": true @@ -370,7 +370,7 @@ "construct-only": false, "controllable": false, "default": "NULL", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "gchararray", "writable": true @@ -488,7 +488,7 @@ "construct": false, "construct-only": false, "controllable": false, - "mutable": "playing", + "mutable": "null", "readable": true, "type": "GstElement", "writable": true @@ -502,7 +502,7 @@ "default": "0", "max": "100", "min": "0", - "mutable": "playing", + "mutable": "null", "readable": true, "type": "guint", "writable": true From ef408ee1675d469e630695926c528080380fbb69 Mon Sep 17 00:00:00 2001 From: Lenny Jorissen Date: Fri, 12 Jun 2020 15:38:45 +0200 Subject: [PATCH 1711/1776] test-onvif-server: cast ntp-offset property value to 64 bit Part-of: --- examples/test-onvif-server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/test-onvif-server.c b/examples/test-onvif-server.c index 2a8a9cf218..bcd48afdfb 100644 --- a/examples/test-onvif-server.c +++ b/examples/test-onvif-server.c @@ -568,8 +568,8 @@ onvif_factory_create_element (GstRTSPMediaFactory * factory, gst_element_add_pad (pbin, gst_ghost_pad_new ("src", srcpad)); gst_object_unref (srcpad); - g_object_set (onvifts, "set-t-bit", TRUE, "set-e-bit", TRUE, "ntp-offset", 0, - "drop-out-of-segment", FALSE, NULL); + g_object_set (onvifts, "set-t-bit", TRUE, "set-e-bit", TRUE, "ntp-offset", + G_GUINT64_CONSTANT (0), "drop-out-of-segment", FALSE, NULL); gst_element_set_clock (onvifts, gst_system_clock_obtain ()); From e4624197dacd5981e996f517c14d1ed59b77651c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Jun 2020 18:17:40 +0300 Subject: [PATCH 1712/1776] rtsp-media: Remove duplicated media_unblock() function It does literally the same as media_streams_set_blocked(FALSE). Part-of: --- gst/rtsp-server/rtsp-media.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b17ced155f..2cc30f6ac4 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2746,25 +2746,6 @@ media_streams_set_blocked (GstRTSPMedia * media, gboolean blocked) priv->blocking_msg_received = 0; } -static void -stream_unblock (GstRTSPStream * stream, GstRTSPMedia * media) -{ - gst_rtsp_stream_set_blocked (stream, FALSE); -} - -static void -media_unblock (GstRTSPMedia * media) -{ - GstRTSPMediaPrivate *priv = media->priv; - - GST_DEBUG ("media %p unblocking streams", media); - /* media is not blocked any longer, as it contains active streams, - * streams that are complete */ - priv->blocked = FALSE; - g_ptr_array_foreach (priv->streams, (GFunc) stream_unblock, media); - priv->blocking_msg_received = 0; -} - static void gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status) { @@ -4605,7 +4586,7 @@ default_unsuspend (GstRTSPMedia * media) /* at this point the media pipeline has been updated and contain all * specific transport parts: all active streams contain at least one sink * element and it's safe to unblock all blocked streams */ - media_unblock (media); + media_streams_set_blocked (media, FALSE); } else { /* streams are not blocked and media is suspended from PAUSED */ gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); @@ -4626,7 +4607,7 @@ default_unsuspend (GstRTSPMedia * media) /* at this point the media pipeline has been updated and contain all * specific transport parts: all active streams contain at least one sink * element and it's safe to unblock all blocked streams */ - media_unblock (media); + media_streams_set_blocked (media, FALSE); if (!start_preroll (media)) goto start_failed; @@ -4716,9 +4697,10 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) if (priv->buffering) { GST_INFO ("Buffering busy, delay state change"); } else { - if (state == GST_STATE_PLAYING) + if (state == GST_STATE_PLAYING) { /* make sure pads are not blocking anymore when going to PLAYING */ - media_unblock (media); + media_streams_set_blocked (media, FALSE); + } if (state == GST_STATE_PAUSED) { set_state_ret = set_state (media, state); @@ -4840,6 +4822,9 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, } } + if (activate) + media_streams_set_blocked (media, FALSE); + /* we just activated the first media, do the playing state change */ if (old_active == 0 && activate) do_state = TRUE; From b681200673b46246a051a45f494878513285886e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Jun 2020 18:29:13 +0300 Subject: [PATCH 1713/1776] rtsp-media: Make sure to also unblock pads when going to PLAYING while buffering The pad probes are not needed anymore at this point and later when reaching buffering 100% only the state is changed, no unblocking happens. Part-of: --- gst/rtsp-server/rtsp-media.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 2cc30f6ac4..c6004b988b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -4692,16 +4692,17 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state) } else { GST_INFO ("state %s media %p", gst_element_state_get_name (state), media); set_target_state (media, state, FALSE); + + if (state == GST_STATE_PLAYING) { + /* make sure pads are not blocking anymore when going to PLAYING */ + media_streams_set_blocked (media, FALSE); + } + /* when we are buffering, don't update the state yet, this will be done * when buffering finishes */ if (priv->buffering) { GST_INFO ("Buffering busy, delay state change"); } else { - if (state == GST_STATE_PLAYING) { - /* make sure pads are not blocking anymore when going to PLAYING */ - media_streams_set_blocked (media, FALSE); - } - if (state == GST_STATE_PAUSED) { set_state_ret = set_state (media, state); if (set_state_ret == GST_STATE_CHANGE_ASYNC) From 5562656ec07c0dc5cc64ac2f177637b0828e8d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Jun 2020 19:45:21 +0300 Subject: [PATCH 1714/1776] rtsp-media: Fix misleading comment Part-of: --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index c6004b988b..dad251fc3d 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -4791,7 +4791,7 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state, deactivate = TRUE; break; case GST_STATE_PAUSED: - /* we're going from PLAYING to PAUSED, READY or NULL, deactivate */ + /* we're going from PLAYING to PAUSED, deactivate */ if (priv->target_state == GST_STATE_PLAYING) deactivate = TRUE; break; From fb8004a6ebfbad1bc16c17d9bf0a845d2f760ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Jun 2020 19:45:38 +0300 Subject: [PATCH 1715/1776] rtsp-media: Add/configure transports when completing the pipeline Otherwise the transports are not set up yet during the PLAY request handling when unsuspending (and thus unblocking) the media. In case of live pipelines this then causes the first few packets to go to the sinks before they know what to do with them, and they simply discard them which is rather suboptimal in case of keyframes. For non-live pipelines this is not a problem because the sink will still be PAUSED and as such not send out the data yet but wait until it goes to PLAYING, which is late enough. Adding the transports multiple times is not a problem: if the transport is already added it won't be added another time and TRUE will be returned. This fixes a regression introduced by a7732a68e8bc6b4ba15629c652056c240c624ff0 before 1.14.0. Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/107 Part-of: --- gst/rtsp-server/rtsp-media.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index dad251fc3d..e42cbb29a8 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -5012,6 +5012,11 @@ gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GPtrArray * transports) g_mutex_unlock (&priv->lock); return FALSE; } + + if (!gst_rtsp_stream_add_transport (stream, transport)) { + g_mutex_unlock (&priv->lock); + return FALSE; + } } priv->complete = TRUE; From f9f649ea6a08720015f2af1adbb39921abf6a61e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 19 Jun 2020 19:24:38 +0100 Subject: [PATCH 1716/1776] Release 1.17.1 --- ChangeLog | 1161 +++++++++++++++++++++++++++++++ NEWS | 1300 ++--------------------------------- RELEASE | 15 +- docs/gst_plugins_cache.json | 4 +- gst-rtsp-server.doap | 12 +- meson.build | 2 +- 6 files changed, 1255 insertions(+), 1239 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0cbc6ee9bb..7aff7c37f3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,1164 @@ +=== release 1.17.1 === + +2020-06-19 19:24:38 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-rtsp-server.doap: + * meson.build: + Release 1.17.1 + +2020-06-15 19:45:38 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Add/configure transports when completing the pipeline + Otherwise the transports are not set up yet during the PLAY request + handling when unsuspending (and thus unblocking) the media. + In case of live pipelines this then causes the first few packets to go + to the sinks before they know what to do with them, and they simply + discard them which is rather suboptimal in case of keyframes. + For non-live pipelines this is not a problem because the sink will still + be PAUSED and as such not send out the data yet but wait until it goes + to PLAYING, which is late enough. + Adding the transports multiple times is not a problem: if the transport + is already added it won't be added another time and TRUE will be + returned. + This fixes a regression introduced by a7732a68e8bc6b4ba15629c652056c240c624ff0 + before 1.14.0. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/107 + Part-of: + +2020-06-15 19:45:21 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Fix misleading comment + Part-of: + +2020-06-15 18:29:13 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Make sure to also unblock pads when going to PLAYING while buffering + The pad probes are not needed anymore at this point and later when + reaching buffering 100% only the state is changed, no unblocking + happens. + Part-of: + +2020-06-15 18:17:40 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Remove duplicated media_unblock() function + It does literally the same as media_streams_set_blocked(FALSE). + Part-of: + +2020-06-12 15:38:45 +0200 Lenny Jorissen + + * examples/test-onvif-server.c: + test-onvif-server: cast ntp-offset property value to 64 bit + Part-of: + +2020-06-09 15:21:24 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + docs: Update plugins cache + +2020-06-10 13:45:04 +0200 Mathieu Duponchelle + + * examples/test-onvif-server.c: + * examples/test-onvif-server.h: + * gst/rtsp-server/rtsp-onvif-media-factory.h: + onvif-media-factory: define autoptr cleanup function + And have the factory in the onvif-server example inherit from + GstRTSPOnvifMediaFactory. + Part-of: + +2020-06-08 10:59:34 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + docs: Update plugins cache + +2020-06-08 09:45:15 +0200 Guillaume Desmottes + + * tests/check/gst/rtspserver.c: + tests: enforce I420 format + Test was not enforcing a video format on videotestsrc. I420 was picked as it + was the first format in GST_VIDEO_FORMATS_ALL which will no longer be + true (gst-plugins-base!689). + Part-of: + +2020-06-06 00:41:51 +0200 Mathieu Duponchelle + + * gst/rtsp-sink/gstrtspclientsink.c: + plugins: uddate gst_type_mark_as_plugin_api() calls + +2020-06-03 18:36:25 -0400 Thibault Saunier + + * docs/meson.build: + doc: Require hotdoc >= 0.11.0 + +2020-05-27 17:00:05 +0300 Sebastian Dröge + + * docs/gst_plugins_cache.json: + docs: Update gst_plugins_cache.json + +2020-05-30 23:23:51 +0300 Sebastian Dröge + + * gst/rtsp-sink/gstrtspclientsink.c: + plugins: Use gst_type_mark_as_plugin_api() for all non-element plugin types + +2020-05-27 23:38:06 +0100 Tim-Philipp Müller + + * gst/rtsp-server/meson.build: + meson: gir: remove bogus sources_top_dir kwarg + Doesn't actually exist. Was fixed differently in Meson + so that the user doesn't have to specify it. + Part-of: + +2020-05-27 17:43:43 +0100 Tim-Philipp Müller + + * tests/check/meson.build: + tests: put registry into tests/check not the gst/ subdir + Underscorify the test name before setting GST_REGISTRY, + so the registry actually ends up in the current build dir + and not some subdir. + For consistency with the other modules, but should also + avoid problems on windows. + Also fix indentation of environment block. + Part-of: + +2020-05-27 17:33:24 +0100 Tim-Philipp Müller + + * tests/check/meson.build: + tests: fix meson test env setup to make sure we use the right gst-plugin-scanner + If core is built as a subproject (e.g. as in gst-build), make sure to use + the gst-plugin-scanner from the built subproject. Without this, gstreamer + might accidentally use the gst-plugin-scanner from the install prefix if + that exists, which in turn might drag in gst library versions we didn't + mean to drag in. Those gst library versions might then be older than + what our current build needs, and might cause our newly-built plugins + to get blacklisted in the test registry because they rely on a symbol + that the wrongly-pulled in gst lib doesn't have. + This should fix running of unit tests in gst-build when invoking + meson test or ninja test from outside the devenv for the case where + there is an older or different-version gst-plugin-scanner installed + in the install prefix. + In case no gst-plugin-scanner is installed in the install prefix, this + will fix "GStreamer-WARNING: External plugin loader failed. This most + likely means that the plugin loader helper binary was not found or + could not be run. You might need to set the GST_PLUGIN_SCANNER + environment variable if your setup is unusual." warnings when running + the unit tests. + In the case where we find GStreamer core via pkg-config we use + a newly-added pkg-config var "pluginscannerdir" to get the right + directory. This has the benefit of working transparently for both + installed and uninstalled pkg-config files/setups. + Part-of: + +2020-05-27 17:32:02 +0100 Tim-Philipp Müller + + * tests/check/meson.build: + tests: gst-plugins-base and -bad plugins are required for the unit tests + Make hard requirement until we have more fine-grained control + in the unit tests. Of course the presence of the .pc file doesn't + imply that the plugins we need are actually there, but it's at + least a step in the right direction. + Part-of: + +2020-05-27 17:29:18 +0100 Tim-Philipp Müller + + * tests/check/meson.build: + tests: pick up rtsp-server plugins from build directory only + Part-of: + +2020-05-26 15:31:22 +0200 Ludvig Rappe + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: wait for all GstRTSPStreamBlocking messages + Make sure rtsp-media have received a GstRTSPStreamBlocking message from + each active stream when checking if all streams are blocked. + Without this change there will be a race condition when using two or + more streams and rtsp-media receives a GstRTSPStreamBlocking message + from one of the streams. This is because rtsp-media then checks if all + streams are blocked by calling gst_rtsp_stream_is_blocking() for each + stream. This function call returns TRUE if the stream has sent a + GstRTSPStreamBlocking message, however, rtsp-media may have yet to + receive this message. This would then result in that rtsp-media + erroneously thinks it is blocking all streams which could result in + rtsp-media changing state, from PREPARING to PREPARED. In the case of a + preroll, this could result in that rtsp-media thinks that the pipeline + is prerolled even though that might not be the case. + Part-of: + +2020-05-04 13:43:00 +0200 Ludvig Rappe + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: update expected_async_done during suspend + Set expected_async_done to FALSE in default_suspend() if a state change + occurs and the return value from set_target_state() is something other + than GST_STATE_CHANGE_ASYNC. + Without this change there is a risk that expected_async_done will be + TRUE even though no asynchronous state change is taking place. This + could happen if the pipeline is set to PAUSED using + media_set_pipeline_state_locked(), an asynchronous state change starts + and then the media is suspended (which could result in a state change, + aborting the asynchronous state change). If the media is suspended + before the asynchronous state change ends then expected_async_done will + be TRUE but no asynchronous state change is taking place. + Part-of: + +2020-05-25 13:49:45 +0200 Kristofer Björkström + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Fix race condition in rtsp ctrl timeout by WeakRef client + There was a race condition where client was being finalized and + concurrently in some other thread the rtsp ctrl timout was relying on + client data that was being freed. + When rtsp ctrl timeout is setup, a WeakRef on Client is set. + Part-of: + +2015-03-03 14:42:07 +0100 Gregor Boirie + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + media-factory: complete DSCP QoS setting support + add dscp_qos setting support at factory and media level to setup IP DSCP + field of bounded UDP sinks. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/6 + Part-of: + +2020-05-14 10:08:32 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Fix some race conditions around timeout source removal + We always need to take the lock while accessing it as otherwise another + thread might've removed it in the meantime. Also when destroying and + creating a new one, ensure that the mutex is not shortly unlocked in + between as during that time another one might potentially be created + already. + Part-of: + +2020-05-03 16:29:31 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-media: Mark out parameters accordingly in gst_rtsp_media_get_rates() + And the same for gst_rtsp_stream_get_rates(). + Part-of: + +2020-05-03 10:17:41 +0000 Tim-Philipp Müller + + * examples/test-onvif-server.c: + examples: test-onvif-server: fix compiler warnings on raspbian + Fix printf format for 64-bit variables. + Part-of: + +2020-05-01 10:42:17 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream-transport: Fix accidental API/ABI breakage with message_sent callbacks + The old API is preserved now and new API was added that provides the + additional parameter to the callback. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/104 + Part-of: + +2020-04-28 23:33:49 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Store the timeout source by pointer instead of id + That way we don't have to retrieve it again from the main context when + destroying it but can directly do so. + Part-of: + +2020-04-28 23:16:18 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Clean up watch/watch context and related state consistently + And assert that it was cleaned up properly before the client is + finalized. If something is still around when the client is shut down + then something went very wrong before. + Part-of: + +2020-04-27 23:25:22 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + * tests/check/gst/rtspserver.c: + rtsp-client: Combine the pre-session and post-session timeout + They previously used the same state but different mechanisms and + functions, which was difficult to follow, error prone and simply + confusing. + Also adjust the test for the post-session timeout a bit to be less racy + now that the timing has slightly changed. + Part-of: + +2020-04-27 19:47:15 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Don't ever close the client connection directly when a session is torn down + There might be other sessions that are running over the same RTSP + connection and we should not simply close the client directly if one of + them is torn down. + By default the connection will be closed once the client closes it or + the OS does. This behaviour can be adjusted with the + post-session-timeout property, which allows to close it automatically + from the server side after all sessions are gone and the given timeout + is reached. + This reverts the previous commit. + Part-of: + +2020-04-27 13:49:55 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: If the TEARDOWN response can be sent directly, directly close the client + Instead of closing it never at all. Previously there was only code that + closed the client asynchronously if sending the response happened + asynchrously at a later time. + Thanks to Christian M for debugging this issue. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/102 + Part-of: + +2020-03-23 14:51:28 +0100 Michael Olbrich + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: use mcast_udpsink[0] last-sample if available for rtpinfo + Otherwise no sink is found for multicast sreams and the less accurate + fallback is used to determine the current sequence number and timestamp. + +2020-03-23 16:06:43 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-auth.c: + rtsp-auth: Fix NULL pointer dereference when handling an invalid basic Authorization header + When using the basic authentication scheme, we wouldn't validate that + the authorization field of the credentials is not NULL and pass it on + to g_hash_table_lookup(). g_str_hash() however is not NULL-safe and will + dereference the NULL pointer and crash. + A specially crafted (read: invalid) RTSP header can cause this to + happen. + As a solution, check for the authorization to be not NULL before + continuing processing it and if it is simply fail authentication. + This fixes CVE-2020-6095 and TALOS-2020-1018. + Discovered by Peter Wang of Cisco ASIG. + +2020-03-09 14:17:34 +0100 Göran Jönsson + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Use watch_context before unref + Move the usage of priv->watch_context to beginning of function + gst_rtsp_client_finalize. Instead of use it after + g_main_context_unref (priv->watch_context). + +2020-02-14 14:59:43 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: fix deadlock on transport removal + We cannot take the RTSPStream lock while holding a transport backlog + lock, as remove_transport may be called externally, which will + take first the RTSPStream lock then the transport backlog lock. + +2020-02-14 14:59:25 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-server-internal.h: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: clear backlog when removing transport + This ensures we don't end up calling any of transports' callbacks + with a potentially unreffed user_data (in practice, a client that + may have been removed) + +2020-02-06 22:46:18 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: marshal calls to send_tcp_message to a single thread + In order to address the race condition pointed out at + https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/merge_requests/108#note_403579 + we get rid of the send thread pool, and instead spawn and manage + a single thread to pull samples from app sinks and add them to + the transport's backlogs. + Additionally, we now also always go through the backlogs in order + to simplify the logic. + +2020-02-05 20:28:19 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-server-internal.h: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: properly protect TCP backlog access + Fixes #97 + We cannot hold stream->lock while pushing data, but need + to consistently check the state of the backlog both from + the send_tcp_message function and the on_message_sent function, + which may or may not be called from the same thread. + This commit introduces internal API to allow for potentially + recursive locking of transport streams, addressing a race + condition where the RTSP stream could push items out of order + when popping them from the backlog. + +2020-02-22 00:41:32 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Sink pipeline in gst_rtsp_media_take_pipeline() + It's taken ownership of by the media, and returned with `transfer none` + from the GstRTSPMedia::create_pipeline() vfunc. If we don't sink it + first then any bindings will wrongly take ownership of the pipeline once + it arrives in bindings code. + +2020-02-05 16:51:14 +0100 Bastian Bouchardon + + * examples/test-onvif-client.c: + Add initialization for context and params (gchar *) Insert define (DEFAULT_*) into help to have to modify only the constants + +2020-02-03 12:30:14 +0000 Marc Leeman + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: fix default latency + +2020-01-15 17:06:41 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: make closing more thread safe + + Take the watch lock prior to using priv->watch + + Flush both the watch and connection before closing / unreffing + gst_rtsp_connection_close() is not threadsafe on its own, this is + a workaround at the client level, where we control both the watch + and the connection + +2020-01-23 16:41:26 +0200 Jordan Petridis + + * gst/rtsp-server/rtsp-latency-bin.c: + rtsp-latency-bin: replace G_TYPE_INSTANCE_GET_PRIVATE as it's been deprecated + from glib + ``` + Deprecated: 2.58: Use %G_ADD_PRIVATE and the generated + `your_type_get_instance_private()` function instead + ``` + +2019-12-17 16:08:19 +0100 Zoltán Imets + + * gst/rtsp-server/rtsp-client.c: + * tests/check/gst/rtspserver.c: + rtsp-client: add property post-session-timeout + This is a TCP connection timeout for client connections, in seconds. + If a positive value is set for this property, the client connection + will be kept alive for this amount of seconds after the last session + timeout. For negative values of this property the connection timeout + handling is delegated to the system (just as it was before). + Fixes #83 + +2020-01-11 22:58:48 +0100 Mark Nauwelaerts + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: check for NULL transports prior to ref'ing + +2020-01-09 14:10:44 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-server-internal.h: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: fix checking of TCP backpressure + The internal index of our appsinks, while it can be used to + determine whether a message is RTP or RTCP, is not necessarily + the same as the interleaved channel. Let the stream-transport + determine the channel to check backpressure for, the same way + it determines the channel according to whether it is sending + RTP or RTCP. + +2019-12-10 19:16:51 -0500 Olivier Crête + + * gst/rtsp-server/rtsp-session.c: + rtsp-session: Butcher the file to please gst-indent in the CI + This should be reverted once the CI has an updated gst-indent. + +2019-12-10 18:39:32 -0500 Olivier Crête + + * gst/rtsp-server/rtsp-session.c: + * gst/rtsp-server/rtsp-session.h: + * gst/rtsp-sink/gstrtspclientsink.c: + * gst/rtsp-sink/gstrtspclientsink.h: + rtsp-session & client: Remove deprecated GTimeVal + GTimeVal won't work past 2038 + +2019-12-12 17:56:18 +0100 Nicola Murino + + * gst/rtsp-server/rtsp-auth.c: + rtsp-auth: fix default token leak + +2019-12-09 14:17:05 +0100 Adam x Nilsson + + * gst/rtsp-sink/gstrtspclientsink.c: + gstrtspclientsink: unref transports when closing bin + Fixes #91 + +2019-12-06 10:44:35 +0100 Kristofer Bjorkstrom + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Force seek when flush flag is set + The commit "rtsp-client: define all seek accuracy flags from + setup_play_mode" changed the behaviour of when doing a seek. + Before that commit, having the flush flag set would result in a seek + (forced seek). + Even if no seek was needed. One reason to force seek is to flush old buffers + created in Describe requests. + Thus adding force seek also for flush flag will result in play request + with fresh buffers. + +2019-11-21 17:12:45 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Revitalize dead code + Leftover from 65d9aa327cd1844934836249cd4463edf09c725d + CID: 1455379 + +2019-11-27 15:22:35 +0100 Edward Hervey + + * gst/rtsp-server/rtsp-sdp.c: + rtsp-sdp: Don't try to use non-initialized values + Only attempt to use the various timing values iif gst_rtsp_stream_get_info() + returns TRUE. Also avoid the whole clock signalling block if we're not + dealing with senders. + CID: 1439524 + CID: 1439536 + CID: 1439520 + +2019-11-01 12:01:41 +0100 Adam x Nilsson + + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/stream.c: + rtsp-stream: Removing invalid transports returns false + When removing transports an assertion was that the transports passed in + for removal are present in the list, however that can't be assumed. + As an example if a transport was removed from a thread running + send_tcp_message, the main thread can try to remove the same transport + again if it gets a handle_pause_request. This will not effect the + transport list but it will effect n_tcp_transports as it will be + decrement and then have the wrong value. + +2019-11-06 14:17:48 +0100 Zoltán Imets + + * tests/check/gst/client.c: + client test: add scale and speed negative tests + Negative tests for scale and speed should be done as well, verify that + the response code is "400 Bad request" when a bad request is done. + +2019-08-29 07:34:26 +0200 Niels De Graef + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-server.c: + * gst/rtsp-server/rtsp-session-pool.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-sink/gstrtspclientsink.c: + Don't pass default GLib marshallers for signals + By passing NULL to `g_signal_new` instead of a marshaller, GLib will + actually internally optimize the signal (if the marshaller is available + in GLib itself) by also setting the valist marshaller. This makes the + signal emission a bit more performant than the regular marshalling, + which still needs to box into `GValue` and call libffi in case of a + generic marshaller. + Note that for custom marshallers, one would use + `g_signal_set_va_marshaller()` with the valist marshaller instead. + +2019-09-05 19:51:06 -0400 Xavier Claessens + + * gst/rtsp-server/rtsp-mount-points.c: + GstRTSPMountPoints: Remove any existing factory before adding a new one + The documentation of gst_rtsp_mount_points_add_factory() says "Any + previous mount point will be freed" which was true when it was + implemented using a GHashTable. But in 2012 it got rewrote using a + GSequence and since then it could have 2 factories for the same path. + Which one gets used is random, depending on the sorting order of 2 + identical items. + +2019-10-15 19:08:32 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-server-internal.h: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream-transport.h: + * gst/rtsp-server/rtsp-stream.c: + stream: refactor TCP backpressure handling + The previous implementation stopped sending TCP messages to + all clients when a single one stopped consuming them, which + obviously created problems for shared media. + Instead, we now manage a backlog in stream-transport, and slow + clients are removed once this backlog exceeds a maximum duration, + currently hardcoded. + Fixes #80 + +2019-10-18 00:42:12 +0100 Tim-Philipp Müller + + * meson.build: + meson: build gir even when cross-compiling if introspection was enabled explicitly + This can be made to work in certain circumstances when + cross-compiling, so default to not building g-i stuff + when cross-compiling, but allow it if introspection was + enabled explicitly via -Dintrospection=enabled. + See gstreamer/gstreamer#454 and gstreamer/gstreamer#381. + +2019-10-18 09:19:59 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-session.c: + rtsp-session: clean up comment extra-timeout + +2019-10-17 12:15:42 +0200 Muhammet Ilendemli + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Generate correct URI for MIKEY in ANNOUNCE responses + Instead of hardcoding the URI, take the actual URI (and especially the correct port) + from the RTSP context. + Fixes #84 + +2019-10-16 13:20:54 +0000 Kristofer + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + rtsp-client: Lock shared media + For shared media we got race conditions. Concurrently rtsp clients might + suspend or unsuspend the shared media and thus change the state without + the clients expecting that. + By introducing a lock that can be taken by callers such as rtsp_client + one can force rtsp clients calling, eg. PLAY, SETUP and that uses shared media, + to handle the media sequentially thus allowing one client to finish its + rtsp call before another client calls on the same media. + https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/86 + Fixes #86 + +2019-10-15 07:33:29 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-session.c: + rtsp-session: add property extra-timeout + Extra time to add to the timeout, in seconds. This only + affects the time until a session is considered timed out + and is not signalled in the RTSP request responses. + Only the value of the timeout property is signalled in the + request responses. + +2019-10-07 12:13:47 +0200 Adam x Nilsson + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream : fix race condition in send_tcp_message + If one thread is inside the send_tcp_message function and are done + sending rtp or rtcp messages so the n_outstanding variable is zero + however have not exit the loop sending the messages. While sending its + messages, transports have been added or removed to the transport list, + so the cache should be updated. If now an additional thread comes to + the function send_tcp_message and trying to send rtp messages it will + first destroy the rtp cache that is still being iterated trough by the + first thread. + Fixes #81 + +2019-05-24 14:32:50 +0200 Tim-Philipp Müller + + * .gitignore: + * .gitmodules: + * Makefile.am: + * autogen.sh: + * common: + * configure.ac: + * docs/.gitignore: + * examples/.gitignore: + * examples/Makefile.am: + * gst/Makefile.am: + * gst/rtsp-server/.gitignore: + * gst/rtsp-server/Makefile.am: + * gst/rtsp-sink/Makefile.am: + * pkgconfig/.gitignore: + * pkgconfig/Makefile.am: + * tests/.gitignore: + * tests/Makefile.am: + * tests/check/Makefile.am: + Remove autotools build + Replaced by Meson. + Maybe we can now use the meson pkgconfig module + for .pc files? (Does it support uninstalled now?) + +2019-10-07 10:27:36 +0200 Göran Jönsson + + * tests/check/gst/client.c: + client: fix test mem leak in attach_rate_tweaking_probe + +2019-10-07 10:14:52 +0200 Göran Jönsson + + * tests/check/gst/media.c: + media: remove memleak in test test_media_seek + +2019-10-07 10:07:54 +0200 Göran Jönsson + + * tests/check/gst/rtspserver.c: + rtspserver: Remove memleak in test test_double_play + +2019-09-17 13:45:57 +0200 Adam x Nilsson + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Use lock in gst_rtsp_media_is_receive_only + +2018-10-29 17:02:41 +0100 David Svensson Fors + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/rtspserver.c: + rtsp-media: Unblock all streams + When unsuspending and going to PLAYING, unblock all streams instead of + only those that are linked (the linked streams are the ones for which + SETUP has been called). GST_FLOW_NOT_LINKED will be returned when + pushing buffers on unlinked streams. + This change is because playback using single-threaded demuxers like + matroska-demux could be blocked if SETUP was not called for all media. + Demuxers that use GstFlowCombiner (including gstoggdemux, gstavidemux, + gstflvdemux, qtdemux, and matroska-demux) will handle + GST_FLOW_NOT_LINKED automatically. + Fixes #39 + +2019-09-11 07:08:37 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-media.c: + * tests/check/gst/rtspserver.c: + rtsp-media: Wait on async when needed. + Wait on asyn-done when needed in gst_rtsp_media_seek_trickmode. + In the unit test the pause from adjust_play_mode will cause a preroll + and after that async-done will be produced. + Without this patch there are no one consuming this async-done and when + later when seek fluch is done in gst_rtsp_media_seek_trickmode then it + wait for async-done. But then it wrongly find the async-done prodused by + adjus_play_mode and continue executing without waiting for the preroll + to finish. + +2019-09-30 15:13:15 +0200 Kristofer Bjorkstrom + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: RTP Info when completed_sender + Change condition that should be fulfilled regarding RTPInfo. + Replace !gst_rtsp_media_is_receive_only with + gst_rtsp_media_has_completed_sender. It is more correct to actually look + for a sender pipeline that is complete. Only then a RTPInfo should + exist. + gst_rtsp_media_is_receive_only gives different answears depending on + state of server. + If Describe is called wth URL+options for backchannel SDP will give only + audio and only backchannel a=sendonly + If Describe is called on URL+options that gives both audio and video + direction from server to client, pipelines are created. Thus + receive_only will return false, even though Setup only would setup + backchannel. + RTP-Info is only for outgoing streams. Thus one should look if outgoing + streams are complete. + +2019-09-25 09:14:08 +0000 Kristofer + + * gst/rtsp-server/rtsp-client.c: + * tests/check/gst/client.c: + rtsp-client: RTP Info exists conditionally in PLAY + If RTP Info is missing and it is not a receiver only, eg. audio + backchannel. Then return GST_RTSP_STS_INTERNAL_SERVER_ERROR. + In rfc2326 it says RTP-info is req. but in RFC7826 it is conditional. + Since 1.14 there is audio backchannel support. Thus RTP-info is + conditional now. When audio backchannel only mode, there is no RTP-info. + Fixes #82 + +2019-09-05 16:23:26 +0200 Mathieu Duponchelle + + * examples/test-onvif-client.c: + test-onvif-client: remove unused query + +2019-08-30 14:00:52 +0200 Kristofer Björkström + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: RTP Info must exist in PLAY response + If RTP Info is missing. Then return GST_RTSP_STS_INTERNAL_SERVER_ERROR + Fixes #76 + +2019-08-29 21:37:24 +0200 Mathieu Duponchelle + + * examples/test-onvif-client.c: + test-onvif-client: perform accurate seeks + See https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/merge_requests/336 + Also, modify how we compute the position: position queries in + PAUSED mode fail to account for the newly-prerolled frame, leading + to frame skips when performing seeks in that state. Instead, + compute the current position from the last sample. + +2019-08-21 14:57:25 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * tests/check/gst/rtspserver.c: + Use complete streams for scale and speed. + Without this patch it's always stream0 that is used to get segment event + that is used to set scale and speed. This even if client not doing SETUP + for stream0. At least in suspend mode reset this not working since then + it's just random if send_rtp_sink have got any segment event. There are + no check if send_rtp_sink for stream0 got any data before media is + prerolled after PLAY request. + +2019-08-26 22:24:12 +1000 Matthew Waters + + * examples/test-onvif-server.c: + * examples/test-onvif-server.h: + examples/onvif-server: fix werror build with clang + ../subprojects/gst-rtsp-server/examples/test-onvif-server.c:346:65: warning: implicit conversion from enumeration type 'const GstSegmentFlags' to different enumeration type 'GstSeekFlags' [-Wenum-conversion] + self->incoming_segment->format, self->incoming_segment->flags, + ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~ + ../subprojects/gst-rtsp-server/examples/test-onvif-server.c:53:1: warning: unused function 'REPLAY_IS_BIN' [-Wunused-function] + G_DECLARE_FINAL_TYPE (ReplayBin, replay_bin, REPLAY, BIN, GstBin); + ^ + /usr/include/glib-2.0/gobject/gtype.h:1407:26: note: expanded from macro 'G_DECLARE_FINAL_TYPE' + static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \ + ^ + :77:1: note: expanded from here + REPLAY_IS_BIN + ^ + ../subprojects/gst-rtsp-server/examples/test-onvif-server.c:525:1: warning: unused function 'ONVIF_FACTORY' [-Wunused-function] + G_DECLARE_FINAL_TYPE (OnvifFactory, onvif_factory, ONVIF, FACTORY, + ^ + /usr/include/glib-2.0/gobject/gtype.h:1405:33: note: expanded from macro 'G_DECLARE_FINAL_TYPE' + static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \ + ^ + :9:1: note: expanded from here + ONVIF_FACTORY + ^ + ../subprojects/gst-rtsp-server/examples/test-onvif-server.c:525:1: warning: unused function 'ONVIF_IS_FACTORY' [-Wunused-function] + /usr/include/glib-2.0/gobject/gtype.h:1407:26: note: expanded from macro 'G_DECLARE_FINAL_TYPE' + static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \ + ^ + :12:1: note: expanded from here + ONVIF_IS_FACTORY + ^ + +2019-08-23 16:21:36 +1000 Matthew Waters + + * docs/meson.build: + meson: Don't generate doc cache when no plugins are enabled + Fixes gst-build with -Dauto-features=disabled -Drtsp_server=enabled + +2019-08-16 13:38:01 -0400 Xavier Claessens + + * examples/test-onvif-client.c: + test-onvif-client: stdin is not defined in MSVC + +2019-08-12 18:03:36 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: add missing Since tag + +2019-08-08 15:52:53 +0200 Mathieu Duponchelle + + * examples/test-onvif-client.c: + test-onvif-client: STDIN_FILENO is not portable + If not defined, define it to _fileno(stdin) on Windows, 0 + everywhere else + +2019-08-07 21:04:33 +0200 Mathieu Duponchelle + + * examples/test-onvif-server.c: + test-onvif-server: downgrade logging + +2019-07-27 05:14:49 +0200 Mathieu Duponchelle + + * examples/meson.build: + * examples/test-onvif-client.c: + * examples/test-onvif-server.c: + examples: add ONVIF client / server example + +2019-07-27 05:14:28 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + rtsp-client: define all seek accuracy flags from setup_play_mode + We then pass those to adjust_play_mode, which needs to operate + on the "final" seek flags, as previously the code in rtsp-media + was assuming that accuracy seek flags (accurate / key_unit) should + not be set if the flags passed to the seek method were already set. + +2019-07-22 19:32:43 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-media-factory-uri.c: + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Try to get dynamic payloaders by name from their bin first + First try "pay", then "pay_%s" (where %s == pad name). And only then + fall back to the code that simply takes the first payloader that is + found. + The current code usually works (but is racy) because it will always take + the payloader that was last added (due to g_list_prepend() when adding + elements) in pad-added and that's usually the correct one. But if a new + payloader is added between pad-added and us trying to get it, we would + get the wrong payloader. + +2019-07-17 15:51:08 +0200 Mathieu Duponchelle + + * tests/check/gst/client.c: + client test: expect any port in transport + setup_multicast_client sets a 5000-5010 range for the client + ports, it is incorrect to expect the transport to always use + 5000-5001 + Fixes #73 + +2019-07-15 17:06:42 +0200 Mathieu Duponchelle + + * tests/check/gst/onvif.c: + onvif tests: use g_cond_wait() correctly + g_cond_wait() has to be called in a loop until required conditions + are met + Fixes #71 + +2019-06-28 12:28:41 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: Not wait on receiver streams when pre-rolling + Without this patch there are problem pre-rolling when using audio back + channel. + Without this patch a probe will be created for all streams including + the stream for audio backchannel. To pre-roll all this pads have to + receive data. Since the stream for audio backchannel is a receiver this + will never happen. + The solution is to never create any probes for streams that are for + incomming data and instead set them as blocking already from beginning. + +2019-06-25 13:19:44 +0100 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-onvif-media-factory.c: + * gst/rtsp-server/rtsp-onvif-media.c: + onvif-media: fix "void function returning a value" compiler warning + +2019-06-12 22:19:27 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: make sure streams are blocked when sending seek + The recent ONVIF work exposed a race condition when dealing with + multiple streams: one of the sinks may preroll before other streams + have started flushing. This led to the pipeline posting async-done + prematurely, when some streams were actually still in the middle + of performing a flushing seek. The newly-added code looks up a + sticky segment event on the first stream in order to respond to + the PLAY request with accurate Scale and Speed headers. In the + failure condition, the first stream was flushing, and thus had + no sticky segment event, leading to the PLAY request failing, + and in turn the test. + +2019-06-07 10:51:19 +0200 Michael Bunk + + * docs/README: + * gst/rtsp-server/rtsp-media-factory-uri.h: + Fix typos + +2019-04-05 00:48:07 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-onvif-client.c: + * gst/rtsp-server/rtsp-onvif-client.h: + * gst/rtsp-server/rtsp-onvif-media-factory.c: + * gst/rtsp-server/rtsp-onvif-media-factory.h: + * gst/rtsp-server/rtsp-onvif-media.c: + * gst/rtsp-server/rtsp-onvif-server.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/media.c: + * tests/check/gst/onvif.c: + * tests/check/meson.build: + onvif: Implement and test the Streaming Specification + https://www.onvif.org/specs/stream/ONVIF-Streaming-Spec.pdf + +2018-11-05 15:34:20 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + rtsp-client: add gst_rtsp_client_get_stream_transport() + This will be used in the onvif tests in order to validate the + data transmitted over TCP: for streaming to continue after a + data message has been provided to client->send_func, the client + is responsible for marking the message as sent on the relevant + stream transport. + +2018-11-07 00:33:01 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-client.c: + client: Scale implies TRICK_MODE + +2018-11-07 00:32:29 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-client.c: + client: compare booleans, not pointers to them + +2018-11-13 21:28:45 +0100 Nikita Bobkov + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/media.c: + Reverse playback support + GStreamer plays segment from stop to start when doing reverse playback. + RTSP implies that media should be played from start of Range header to + its stop. Hence we swap start and stop times before passing them to + gst_element_seek. + Also make gst_rtsp_stream_query_stop always return value that can be + used as stop time of Range header. + +2018-10-12 08:53:04 +0200 Branko Subasic + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * tests/check/gst/client.c: + rtsp-client: add support for Scale and Speed header + Add support for the RTSP Scale and Speed headers by setting the rate in + the seek to (scale*speed). We then check the resulting segment for rate + and applied rate, and use them as values for the Speed and Scale headers + respectively. + https://bugzilla.gnome.org/show_bug.cgi?id=754575 + +2018-10-01 18:51:49 +0200 Branko Subasic + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + rtsp-client: allow sub classes to adjust the seek + Adds a new virtual function, adjust_play_mode(), that allows + sub classes to adjust the seek done on the media. The sub class can + modify the values of the the seek flags and the rate. + https://bugzilla.gnome.org/show_bug.cgi?id=754575 + +2018-09-27 19:09:01 +0200 Branko Subasic + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-media.h: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * tests/check/gst/media.c: + rtsp-media: allow specifying rate when seeking + Add new function gst_rtsp_media_seek_full_with_rate() which allows the + caller to specify the rate for the seek. Also added functions in + rtsp-stream and rtsp-media for retreiving current rate and applied rate. + https://bugzilla.gnome.org/show_bug.cgi?id=754575 + +2019-06-02 21:39:33 +0200 Niels De Graef + + * configure.ac: + * meson.build: + meson: Bump minimal GLib version to 2.44 + This means we can use some newer features and get rid of some + boilerplate code using the G_DECLARE_* macros. + As discussed on IRC, 2.44 is old enough by now to start depending on it. + +2019-05-31 18:53:36 +0200 Mathieu Duponchelle + + * docs/libs/.gitignore: + * docs/libs/Makefile.am: + * docs/libs/gst-rtsp-server-docs.sgml: + * docs/libs/gst-rtsp-server-sections.txt: + * docs/libs/gst-rtsp-server.types: + docs: remove obsolete gtk-doc related files + +2019-05-29 23:20:09 +0200 Mathieu Duponchelle + + * gst/rtsp-sink/gstrtspclientsink.c: + doc: remove xml from comments + +2019-05-16 09:23:53 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + * docs/meson.build: + docs: Stop building the doc cache by default + And update the cache + Fixes https://gitlab.freedesktop.org/gstreamer/gst-docs/issues/36 + +2019-05-13 22:59:57 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + docs: Update plugins documentation cache + +2019-04-23 12:30:02 -0400 Thibault Saunier + + * docs/meson.build: + * gst/rtsp-server/rtsp-context.c: + * gst/rtsp-server/rtsp-session-pool.c: + doc: Fix some docstrings + +2018-10-22 11:29:24 +0200 Thibault Saunier + + * .gitignore: + * Makefile.am: + * configure.ac: + * docs/Makefile.am: + * docs/gst_plugins_cache.json: + * docs/index.md: + * docs/meson.build: + * docs/plugin-index.md: + * docs/plugin-sitemap.txt: + * docs/sitemap.md: + * docs/sitemap.txt: + * docs/version.entities.in: + * gst/rtsp-server/meson.build: + * gst/rtsp-sink/meson.build: + * meson.build: + * meson_options.txt: + docs: Port to hotdoc + +2019-04-23 15:09:34 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-auth.c: + * gst/rtsp-server/rtsp-client.h: + rtsp-server: Fix various Since markers + +2019-04-23 15:01:32 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-sdp.c: + * gst/rtsp-server/rtsp-session-media.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-server: Add various Since: 1.14 markers + +2019-04-23 14:38:05 +0300 Sebastian Dröge + + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream-transport.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-server: Add various missing Since: 1.16 markers + +2019-04-15 20:54:24 +0300 Sebastian Dröge + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Set async-handling=false for the internal bins + Without this we can easily run into a race condition with async state changes: + - the pipeline is doing an async state change + - we set the internal bins to PLAYING but that's ignored because an + async state change is currently pending + - the async state change finishes but does not change the state of the + internal bins because of locked_state==TRUE + - the internal bins stay in PAUSED forever + +2019-04-15 20:51:30 +0300 Sebastian Dröge + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Use write_messages() API to send buffer lists in one go + And to write messages with multiple memories also via writev(). + +2019-03-27 16:21:03 +0100 Kristofer Bjorkstrom + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-client.h: + * gst/rtsp-server/rtsp-server-object.h: + * gst/rtsp-server/rtsp-server.c: + rtsp-client: Handle Content-Length limitation + Add functionality to limit the Content-Length. + API addition, Enhancement. + Define an appropriate request size limit and reject requests + exceeding the limit with response status 413 Request Entity Too Large + Related to !182 + +2019-04-19 10:40:29 +0100 Tim-Philipp Müller + + * RELEASE: + * configure.ac: + * meson.build: + Back to development + === release 1.16.0 === 2019-04-19 00:34:54 +0100 Tim-Philipp Müller diff --git a/NEWS b/NEWS index 816a3aae85..a4e7232a19 100644 --- a/NEWS +++ b/NEWS @@ -1,14 +1,30 @@ -GSTREAMER 1.16 RELEASE NOTES +GSTREAMER 1.18 RELEASE NOTES -GStreamer 1.16.0 was originally released on 19 April 2019. +THESE RELEASE NOTES ARE A PLACEHOLDER, PLEASE BEAR WITH US WHILE WE +FINISH WRITING UP THE REAL THING. -See https://gstreamer.freedesktop.org/releases/1.16/ for the latest +GStreamer 1.18.0 has not yet been released. It is scheduled for release +in summer 2020 now. + +1.17.x is the unstable development series that is currently being +developed in the git master branch and which will eventually result in +1.18, and 1.17.1 is the current development release in that series. + +The schedule for the 1.18 development cycle is yet to be confirmed, but +it is expected that feature freeze will be in June/July 2020, followed +by several 1.17 pre-releases and then a new 1.18 stable release in +July/August 2020. + +1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, +1.8, 1.6, 1.4, 1.2 and 1.0 release series. + +See https://gstreamer.freedesktop.org/releases/1.18/ for the latest version of this document. -_Last updated: Friday 19 April 2019, 00:00 UTC (log)_ +_Last updated: Thursday 18 June 2020, 16:00 UTC (log)_ Introduction @@ -23,1146 +39,133 @@ fixes and other improvements. Highlights -- GStreamer WebRTC stack gained support for data channels for - peer-to-peer communication based on SCTP, BUNDLE support, as well as - support for multiple TURN servers. - -- AV1 video codec support for Matroska and QuickTime/MP4 containers - and more configuration options and supported input formats for the - AOMedia AV1 encoder - -- Support for Closed Captions and other Ancillary Data in video - -- Support for planar (non-interleaved) raw audio - -- GstVideoAggregator, compositor and OpenGL mixer elements are now in - -base - -- New alternate fields interlace mode where each buffer carries a - single field - -- WebM and Matroska ContentEncryption support in the Matroska demuxer - -- new WebKit WPE-based web browser source element - -- Video4Linux: HEVC encoding and decoding, JPEG encoding, and improved - dmabuf import/export - -- Hardware-accelerated Nvidia video decoder gained support for VP8/VP9 - decoding, whilst the encoder gained support for H.265/HEVC encoding. - -- Many improvements to the Intel Media SDK based hardware-accelerated - video decoder and encoder plugin (msdk): dmabuf import/export for - zero-copy integration with other components; VP9 decoding; 10-bit - HEVC encoding; video post-processing (vpp) support including - deinterlacing; and the video decoder now handles dynamic resolution - changes. - -- The ASS/SSA subtitle overlay renderer can now handle multiple - subtitles that overlap in time and will show them on screen - simultaneously - -- The Meson build is now feature-complete (*) and it is now the - recommended build system on all platforms. The Autotools build is - scheduled to be removed in the next cycle. - -- The GStreamer Rust bindings and Rust plugins module are now - officially part of upstream GStreamer. - -- The GStreamer Editing Services gained a gesdemux element that allows - directly playing back serialized edit list with playbin or - (uri)decodebin - -- Many performance improvements +- FIXME Major new features and changes Noteworthy new API -- GstAggregator has a new "min-upstream-latency" property that forces - a minimum aggregate latency for the input branches of an aggregator. - This is useful for dynamic pipelines where branches with a higher - latency might be added later after the pipeline is already up and - running and where a change in the latency would be disruptive. This - only applies to the case where at least one of the input branches is - live though, it won’t force the aggregator into live mode in the - absence of any live inputs. - -- GstBaseSink gained a "processing-deadline" property and - setter/getter API to configure a processing deadline for live - pipelines. The processing deadline is the acceptable amount of time - to process the media in a live pipeline before it reaches the sink. - This is on top of the systemic latency that is normally reported by - the latency query. This defaults to 20ms and should make pipelines - such as v4l2src ! xvimagesink not claim that all frames are late in - the QoS events. Ideally, this should replace the "max-lateness" - property for most applications. - -- RTCP Extended Reports (XR) parsing according to RFC 3611: - Loss/Duplicate RLE, Packet Receipt Times, Receiver Reference Time, - Delay since the last Receiver (DLRR), Statistics Summary, and VoIP - Metrics reports. This only provides the ability to parse such - packets, generation of XR packets is not supported yet and XR - packets are not automatically parsed by rtpbin / rtpsession but must - be actively handled by the application. - -- a new mode for interlaced video was added where each buffer carries - a single field of interlaced video, with buffer flags indicating - whether the field is the top field or bottom field. Top and bottom - fields are expected to alternate in this mode. Caps for this - interlace mode must also carry a format:Interlaced caps feature to - ensure backwards compatibility. - -- The video library has gained support for three new raw pixel - formats: - - - Y410: packed 4:4:4 YUV, 10 bits per channel - - Y210: packed 4:2:2 YUV, 10 bits per channel - - NV12_10LE40: fully-packed 10-bit variant of NV12_10LE32, - i.e. without the padding bits - -- GstRTPSourceMeta is a new meta that can be used to transport - information about the origin of depayloaded or decoded RTP buffers, - e.g. when mixing audio from multiple sources into a single stream. A - new "source-info" property on the RTP depayloader base class - determines whether depayloaders should put this meta on outgoing - buffers. Similarly, the same property on RTP payloaders determines - whether they should use the information from this meta to construct - the CSRCs list on outgoing RTP buffers. - -- gst_sdp_message_from_text() is a convenience constructor to parse - SDPs from a string which is particularly useful for language - bindings. - -Support for Planar (Non-Interleaved) Raw Audio - -Raw audio samples are usually passed around in interleaved form in -GStreamer, which means that if there are multiple audio channels the -samples for each channel are interleaved in memory, e.g. -|LEFT|RIGHT|LEFT|RIGHT|LEFT|RIGHT| for stereo audio. A non-interleaved -or planar arrangement in memory would look like -|LEFT|LEFT|LEFT|RIGHT|RIGHT|RIGHT| instead, possibly with -|LEFT|LEFT|LEFT| and |RIGHT|RIGHT|RIGHT| residing in separate memory -chunks or separated by some padding. - -GStreamer has always had signalling for non-interleaved audio since -version 1.0, but it was never actually properly implemented in any -elements. audioconvert would advertise support for it, but wasn’t -actually able to handle it correctly. - -With this release we now have full support for non-interleaved audio as -well, which means more efficient integration with external APIs that -handle audio this way, but also more efficient processing of certain -operations like interleaving multiple 1-channel streams into a -multi-channel stream which can be done without memory copies now. - -New API to support this has been added to the GStreamer Audio support -library: There is now a new GstAudioMeta which describes how data is -laid out inside the buffer, and buffers with non-interleaved audio must -always carry this meta. To access the non-interleaved audio samples you -must map such buffers with gst_audio_buffer_map() which works much like -gst_buffer_map() or gst_video_frame_map() in that it will populate a -little GstAudioBuffer helper structure passed to it with the number of -samples, the number of planes and pointers to the start of each plane in -memory. This function can also be used to map interleaved audio buffers -in which case there will be only one plane of interleaved samples. - -Of course support for this has also been implemented in the various -audio helper and conversion APIs, base classes, and in elements such as -audioconvert, audioresample, audiotestsrc, audiorate. - -Support for Closed Captions and Other Ancillary Data in Video - -The video support library has gained support for detecting and -extracting Ancillary Data from videos as per the SMPTE S291M -specification, including: - -- a VBI (Vertical Blanking Interval) parser that can detect and - extract Ancillary Data from Vertical Blanking Interval lines of - component signals. This is currently supported for videos in v210 - and UYVY format. - -- a new GstMeta for closed captions: GstVideoCaptionMeta. This - supports the two types of closed captions, CEA-608 and CEA-708, - along with the four different ways they can be transported (other - systems are a superset of those). - -- a VBI (Vertical Blanking Interval) encoder for writing ancillary - data to the Vertical Blanking Interval lines of component signals. - -The new closedcaption plugin in gst-plugins-bad then makes use of all -this new infrastructure and provides the following elements: - -- cccombiner: a closed caption combiner that takes a closed captions - stream and another stream and adds the closed captions as - GstVideoCaptionMeta to the buffers of the other stream. - -- ccextractor: a closed caption extractor which will take - GstVideoCaptionMeta from input buffers and output them as a separate - closed captions stream. - -- ccconverter: a closed caption converter that can convert between - different formats - -- line21encoder, line21decoder: inject/extract line21 closed captions - to/from SD video streams - -- cc708overlay: decodes CEA 608/708 captions and overlays them on - video - -Additionally, the following elements have also gained Closed Caption -support: - -- qtdemux and qtmux support CEA 608/708 Closed Caption tracks - -- mpegvideoparse, h264parse extracts Closed Captions from MPEG-2/H.264 - video streams - -- avviddec, avvidenc, x264enc got support for extracting/injecting - Closed Captions - -- decklinkvideosink can output closed captions and decklinkvideosrc - can extract closed captions - -- playbin and playbin3 learned how to autoplug CEA 608/708 CC overlay - elements - -- the externally maintained ajavideosrc element for AJA capture cards - has support for extracting closed captions - -The rsclosedcaption plugin in the Rust plugins collection includes a -MacCaption (MCC) file parser and encoder. +- FIXME New Elements -- overlaycomposition: New element that allows applications to draw - GstVideoOverlayCompositions on a stream. The element will emit the - "draw" signal for each video buffer, and the application then - generates an overlay for that frame (or not). This is much more - performant than e.g. cairooverlay for many use cases, e.g. because - pixel format conversions can be avoided or the blitting of the - overlay can be delegated to downstream elements (such as - gloverlaycompositor). It’s particularly useful for cases where only - a small section of the video frame should be drawn on. - -- gloverlaycompositor: New OpenGL-based compositor element that - flattens any overlays from GstVideoOverlayCompositionMetas into the - video stream. This element is also always part of glimagesink. - -- glalpha: New element that adds an alpha channel to a video stream. - The values of the alpha channel can either be set to a constant or - can be dynamically calculated via chroma keying. It is similar to - the existing alpha element but based on OpenGL. Calculations are - done in floating point so results may not be identical to the output - of the existing alpha element. - -- rtpfunnel funnels together RTP streams into a single session. Use - cases include multiplexing and bundle. webrtcbin uses it to - implement BUNDLE support. - -- testsrcbin is a source element that provides an audio and/or video - stream and also announces them using the recently-introduced - GstStream API. This is useful for testing elements such as playbin3 - or uridecodebin3 etc. - -- New closed caption elements: cccombiner, ccextractor, ccconverter, - line21encoder, line21decoder and cc708overlay (see above) - -- wpesrc: new source element acting as a Web Browser based on WebKit - WPE - -- Two new OpenCV-based elements: cameracalibrate and cameraundistort - that can communicate to figure out distortion correction parameters - for a camera and correct for the distortion. - -- New sctp plugin based on usrsctp with sctpenc and sctpdec elements. - These elements are used inside webrtcbin for implementing data - channels. +- FIXME New element features and additions -- playbin3, playbin and playsink have gained a new "text-offset" - property to adjust the positioning of the selected subtitle stream - vis-a-vis the audio and video streams. This uses subtitleoverlay’s - new "subtitle-ts-offset" property. GstPlayer has gained matching API - for this, namely gst_player_get_text_video_offset(). - -- playbin3 buffering improvements: in network playback scenarios there - may be multiple inputs to decodebin3, and buffering will be done - before decodebin3 using queue2 or downloadbuffer elements inside - urisourcebin. Since this is before any parsers or demuxers there may - not be any bitrate information available for the various streams, so - it was difficult to configure the buffering there smartly within - global constraints. This was improved now: The queue2 elements - inside urisourcebin will now use the new bitrate query to figure out - a bitrate estimate for the stream if no bitrate was provided by - upstream, and urisourcebin will use the bitrates of the individual - queues to distribute the globally-set "buffer-size" budget in bytes - to the various queues. urisourcebin also gained "low-watermark" and - "high-watermark" properties which will be proxied to the internal - queues, as well as a read-only "statistics" property which allows - querying of the minimum/maximum/average byte and time levels of the - queues inside the urisourcebin in question. - -- splitmuxsink has gained a couple of new features: - - - new "async-finalize" mode: This mode is useful for muxers or - outputs that can take a long time to finalize a file. Instead of - blocking the whole upstream pipeline while the muxer is doing - its stuff, we can unlink it and spawn a new muxer + sink - combination to continue running normally. This requires us to - receive the muxer and sink (if needed) as factories via the new - "muxer-factory" and "sink-factory" properties, optionally - accompanied by their respective properties structures (set via - the new "muxer-properties" and "sink-properties" properties). - There are also new "muxer-added" and "sink-added" signals in - case custom code has to be called for them to configure them. - - - "split-at-running-time" action signal: When called by the user, - this action signal ends the current file (and starts a new one) - as soon as the given running time is reached. If called multiple - times, running times are queued up and processed in the order - they were given. - - - "split-after" action signal to finish outputting the current GOP - to the current file and then start a new file as soon as the GOP - is finished and a new GOP is opened (unlike the existing - "split-now" which immediately finishes the current file and - writes the current GOP into the next newly-started file). - - - "reset-muxer" property: when unset, the muxer is reset using - flush events instead of setting its state to NULL and back. This - means the muxer can keep state across resets, e.g. mpegtsmux - will keep the continuity counter continuous across segments as - required by hlssink2. - -- qtdemux gained PIFF track encryption box support in addition to the - already-existing PIFF sample encryption support, and also allows - applications to select which encryption system to use via a - "drm-preferred-decryption-system-id" context in case there are - multiple options. - -- qtmux: the "start-gap-threshold" property determines now whether an - edit list will be created to account for small gaps or offsets at - the beginning of a stream in case the start timestamps of tracks - don’t line up perfectly. Previously the threshold was hard-coded to - 1% of the (video) frame duration, now it is 0 by default (so edit - list will be created even for small differences), but fully - configurable. - -- rtpjitterbuffer has improved end-of-stream handling - -- rtpmp4vpay will be prefered over rtpmp4gpay for MPEG-4 video in - autoplugging scenarios now - -- rtspsrc now allows applications to send RTSP SET_PARAMETER and - GET_PARAMETER requests using action signals. - -- rtspsrc has a small (100ms) configurable teardown delay by default - to try and make sure an RTSP TEARDOWN request gets sent out when the - source element shuts down. This will block the downward PAUSED to - READY state change for a short time, but can be disabled where it’s - a problem. Some servers only allow a limited number of concurrent - clients, so if no proper TEARDOWN is sent new clients may have - problems connecting to the server for a while. - -- souphttpsrc behaves better with low bitrate streams now. Before it - would increase the read block size too quickly which could lead to - it not reading any data from the socket for a very long time with - low bitrate streams that are output live downstream. This could lead - to servers kicking off the client. - -- filesink: do internal buffering to avoid performance regression with - small writes since we bypass libc buffering by using writev() - instead of fwrite() - -- identity: add "eos-after" property and fix "error-after" property - when the element is reused - -- input-selector: lets context queries pass through, so that - e.g. upstream OpenGL elements can use contexts and displays - advertised by downstream elements - -- queue2: avoid ping-pong between 0% and 100% buffering messages if - upstream is pushing buffers larger than one of its limits, plus - performance optimisations - -- opusdec: new "phase-inversion" property to control phase inversion. - When enabled, this will slightly increase stereo quality, but - produces a stream that when downmixed to mono will suffer audio - distortions. - -- The x265enc HEVC encoder also exposes a "key-int-max" property to - configure the maximum allowed GOP size now. - -- decklinkvideosink has seen stability improvements for long-running - pipelines (potential crash due to overflow of leaked clock refcount) - and clock-slaving improvements when performing flushing seeks - (causing stalls in the output timeline), pausing and/or buffering. - -- srtpdec, srtpenc: add support for MKIs which allow multiple keys to - be used with a single SRTP stream - -- srtpdec, srtpenc: add support for AES-GCM and also add support for - it in gst-rtsp-server and rtspsrc. - -- The srt Secure Reliable Transport plugin has integrated server and - client elements srt{client,server}{src,sink} into one (srtsrc and - srtsink), since SRT connection mode can be changed by uri - parameters. - -- h264parse and h265parse will handle SEI recovery point messages and - mark recovery points as keyframes as well (in addition to IDR - frames) - -- webrtcbin: "add-turn-server" action signal to pass multiple ICE - relays (TURN servers). - -- The removesilence element has received various new features and - properties, such as a "threshold" property, detecting silence only - after minimum silence time/buffers, a "silent" property to control - bus message notifications as well as a "squash" property. - -- AOMedia AV1 decoder gained support for 10/12bit decoding whilst the - AV1 encoder supports more image formats and subsamplings now and - acquired support for rate control and profile related configuration. - -- The Fraunhofer fdkaac plugin can now be built against the 2.0.0 - version API and has improved multichannel support - -- kmssink now supports unpadded 24-bit RGB and can configure mode - setting from video info, which enables display of multi-planar - formats such as I420 or NV12 with modesetting. It has also gained a - number of new properties: The "restore-crtc" property does what it - says on the tin and is enabled by default. "plane-properties" and - "connector-properties" can be used to pass custom properties to the - DRM. - -- waylandsink has a "fullscreen" property now and supports the - XDG-Shell protocol. - -- decklinkvideosink, decklinkvideosrc support selecting between - half/full duplex - -- The vulkan plugin gained support for macOS and iOS via MoltenVK in - addition to the existing support for X11 and Wayland - -- imagefreeze has a new num-buffers property to limit the number of - buffers that are produced and to send an EOS event afterwards - -- webrtcbin has a new, introspectable get-transceiver signal in - addition to the old get-transceivers signal that couldn’t be used - from bindings - -- Support for per-element latency information was added to the latency - tracer +- FIXME Plugin and library moves -- The stereo element was moved from -bad into the existing audiofx - plugin in -good. If you get duplicate type registration warnings - when upgrading, check that you don’t have a stale stereoplugin lying - about somewhere. - -GstVideoAggregator, compositor, and OpenGL mixer elements moved from -bad to -base - -GstVideoAggregator is a new base class for raw video mixers and muxers -and is based on GstAggregator. It provides defined-latency mixing of raw -video inputs and ensures that the pipeline won’t stall even if one of -the input streams stops producing data. - -As part of the move to stabilise the API there were some last-minute API -changes and clean-ups, but those should mostly affect internal elements. -Most notably, the "ignore-eos" pad property was renamed to -"repeat-after-eos" and the conversion code was moved to a -GstVideoAggregatorConvertPad subclass to avoid code duplication, make -things less awkward for subclasses like the OpenGL-based video mixer, -and make the API more consistent with the audio aggregator API. - -It is used by the compositor element, which is a replacement for -‘videomixer’ which did not handle live inputs very well. compositor -should behave much better in that respect and generally behave as one -would expected in most scenarios. - -The compositor element has gained support for per-pad blending mode -operators (SOURCE, OVER, ADD) which determines what operator to use for -blending this pad over the previous ones. This can be used to implement -crossfading and the available operators can be extended in the future as -needed. - -A number of OpenGL-based video mixer elements (glvideomixer, glmixerbin, -glvideomixerelement, glstereomix, glmosaic) which are built on top of -GstVideoAggregator have also been moved from -bad to -base now. These -elements have been merged into the existing OpenGL plugin, so if you get -duplicate type registration warnings when upgrading, check that you -don’t have a stale openglmixers plugin lying about somewhere. +- FIXME Plugin removals The following plugins have been removed from gst-plugins-bad: -- The experimental daala plugin has been removed, since it’s not so - useful now that all effort is focused on AV1 instead, and it had to - be enabled explicitly with --enable-experimental anyway. - -- The spc plugin has been removed. It has been replaced by the gme - plugin. - -- The acmmp3dec and acmenc plugins for Windows have been removed. ACM - is an ancient legacy API and there was no point in keeping the - plugins around for a licensed MP3 decoder now that the MP3 patents - have expired and we have a decoder in -good. We also didn’t ship - these in our cerbero-built Windows packages, so it’s unlikely that - they’ll be missed. +- FIXME Miscellaneous API additions -- GstBitwriter: new generic bit writer API to complement the existing - bit reader - -- gst_buffer_new_wrapped_bytes() creates a wrap buffer from a GBytes - -- gst_caps_set_features_simple() sets a caps feature on all the - structures of a GstCaps - -- New GST_QUERY_BITRATE query: This allows determining from downstream - what the expected bitrate of a stream may be which is useful in - queue2 for setting time based limits when upstream does not provide - timing information. tsdemux, qtdemux and matroskademux have basic - support for this query on their sink pads. - -- elements: there is a new “Hardware” class specifier. Elements - interacting with hardware devices should specify this classifier in - their element factory class metadata. This is useful to advertise as - one might need to put such elements into READY state to test if the - hardware is present in the system for example. - -- protection: Add a new definition for unspecified system protection, - GST_PROTECTION_UNSPECIFIED_SYSTEM_ID - -- take functions for various mini objects that didn’t have them yet: - gst_query_take(), gst_message_take(), gst_tag_list_take(), - gst_buffer_list_take(). Unlike the various _replace() functions - _take() does not increase the reference count but takes ownership of - the mini object passed. - -- clear functions for various mini object types and GstObject which - unrefs the object or mini object (if non-NULL) and sets the variable - pointed to to NULL: gst_clear_structure(), gst_clear_tag_list(), - gst_clear_query(), gst_clear_message(), gst_clear_event(), - gst_clear_caps(), gst_clear_buffer_list(), gst_clear_buffer(), - gst_clear_mini_object(), gst_clear_object() - -- miniobject: new API gst_mini_object_add_parent() and - gst_mini_object_remove_parent() to set parent pointers on mini - objects to ensure correct writability: Every container of - miniobjects now needs to store itself as parent in the child object, - and remove itself again later. A mini object is then only writable - if there is at most one parent, that parent is writable itself, and - the reference count of the mini object is 1. GstBuffer (for - memories), GstBufferList (for buffers), GstSample (for caps, buffer, - bufferlist), and GstVideoOverlayComposition were updated - accordingly. Without this it was possible to have e.g. a buffer list - with a refcount of 2 used in two places at once that both modify the - same buffer with refcount 1 at the same time wrongly thinking it is - writable even though it’s really not. - -- poll: add API to watch for POLLPRI and stop treating POLLPRI as a - read. This is useful to wait for video4linux events which are - signalled via POLLPRI. - -- sample: new API to update the contents of a GstSample and make it - writable: gst_sample_set_buffer(), gst_sample_set_caps(), - gst_sample_set_segment(), gst_sample_set_info(), plus - gst_sample_is_writable() and gst_sample_make_writable(). This makes - it possible to reuse a sample object and avoid unnecessary memory - allocations, for example in appsink. - -- ClockIDs now keep a weak reference to underlying clock to avoid - crashes in basesink in corner cases where a clock goes away while - the ClockID is still in use, plus some new API - (gst_clock_id_get_clock(), gst_clock_id_uses_clock()) to check the - clock a ClockID is linked to. - -- The GstCheck unit test library gained a - fail_unless_equals_clocktime() convenience macro as well as some new - GstHarness API for for proposing meta APIs from the allocation - query: gst_harness_add_propose_allocation_meta(). ASSERT_CRITICAL() - checks in unit tests are now skipped if GStreamer was compiled with - GST_DISABLE_GLIB_CHECKS. - -- gst_audio_buffer_truncate() convenience function to truncate a raw - audio buffer - -- GstDiscoverer has support for caching the results of discovery in - the default cache directory. This can be enabled with the use-cache - property and is disabled by default. - -- GstMeta that are attached to GstBuffers are now always stored in the - order in which they were added. - -- Additional support for signalling ONVIF specific features were - added: the SEEK event can store a trickmode-interval now and support - for the Rate-Control and Frames RTSP headers was added to the RTSP - library. +- FIXME Miscellaneous performance and memory optimisations As always there have been many performance and memory usage improvements -across all components and modules. Some of them (such as dmabuf -import/export) have already been mentioned elsewhere so won’t be -repeated here. +across all components and modules. Some of them have already been +mentioned elsewhere so won’t be repeated here. The following list is only a small snapshot of some of the more interesting optimisations that haven’t been mentioned in other contexts yet: -- The GstVideoEncoder and GstVideoDecoder base classes now release the - STREAM_LOCK when pushing out buffers, which means (multi-threaded) - encoders and decoders can now receive and continue to process input - buffers whilst waiting for downstream elements in the pipeline to - process the buffer that was pushed out. This increases throughput - and reduces processing latency, also and especially for - hardware-accelerated encoder/decoder elements. - -- GstQueueArray has seen a few API additions - (gst_queue_array_peek_nth(), gst_queue_array_set_clear_func(), - gst_queue_array_clear()) so that it can be used in other places like - GstAdapter instead of a GList, which reduces allocations and - improves performance. - -- appsink now reuses the sample object in pull_sample() if possible - -- rtpsession only starts the RTCP thread when it’s actually needed now - -- udpsrc uses a buffer pool now and the GstUdpSrc object structure was - optimised for better cache performance +- FIXME GstPlayer -- API was added to fine-tune the synchronisation offset between - subtitles and video +- FIXME Miscellaneous changes -- As a result of moving to newer FFmpeg APIs, encoder and decoder - elements exposed by the GStreamer FFmpeg wrapper plugin (gst-libav) - may have seen possibly incompatible changes to property names and/or - types, and not all properties exposed might be functional. We are - still reviewing the new properties and aim to minimise breaking - changes at least for the most commonly-used properties, so please - report any issues you run into! +- FIXME OpenGL integration -- The OpenGL mixer elements have been moved from -bad to - gst-plugins-base (see above) - -- The Mesa GBM backend now supports headless mode - -- gloverlaycompositor: New OpenGL-based compositor element that - flattens any overlays from GstVideoOverlayCompositionMetas into the - video stream. - -- glalpha: New element that adds an alpha channel to a video stream. - The values of the alpha channel can either be set to a constant or - can be dynamically calculated via chroma keying. It is similar to - the existing alpha element but based on OpenGL. Calculations are - done in floating point so results may not be identical to the output - of the existing alpha element. - -- glupload: Implement direct dmabuf uploader, the idea being that some - GPUs (like the Vivante series) can actually perform the YUV->RGB - conversion internally, so no custom conversion shaders are needed. - To make use of this feature, we need an additional uploader that can - import DMABUF FDs and also directly pass the pixel format, relying - on the GPU to do the conversion. - -- The OpenGL library no longer restores the OpenGL viewport. This is a - performance optimization to not require performing multiple - expensive glGet*() function calls per frame. This affects any - application or plugin use of the following functions and objects: - - glcolorconvert library object (not the element) - - glviewconvert library object (not the element) - - gst_gl_framebuffer_draw_to_texture() - - custom GstGLWindow implementations +- FIXME Tracing framework and debugging improvements -- There is now a GDB PRETTY PRINTER FOR VARIOUS GSTREAMER TYPES: For - GstObject pointers the type and name is added, e.g. - 0x5555557e4110 [GstDecodeBin|decodebin0]. For GstMiniObject pointers - the object type is added, e.g. 0x7fffe001fc50 [GstBuffer]. For - GstClockTime and GstClockTimeDiff the time is also printed in human - readable form, e.g. 150116219955 [+0:02:30.116219955]. - -- GDB EXTENSION WITH TWO CUSTOM GDB COMMANDS gst-dot AND gst-print: - - - gst-dot creates dot files that a very close to what - GST_DEBUG_BIN_TO_DOT_FILE() produces, but object properties and - buffer contents such as codec-data in caps are not available. - - - gst-print produces high-level information about a GStreamer - object. This is currently limited to pads for GstElements and - events for the pads. The output may look like this: - -- gst_structure_to_string() now serialises the actual value of - pointers when serialising GstStructures instead of claiming they’re - NULL. This makes debug logging in various places less confusing, - because it’s clear now that structure fields actually hold valid - objects. Such object pointer values will never be deserialised - however. +- FIXME Tools -- gst-inspect-1.0 has coloured output now and will automatically use a - pager if the output does not fit on a page. This only works in a - UNIX environment and if the output is not piped, and on Windows 10 - build 16257 or newer. If you don’t like the colours you can disable - them by setting the GST_INSPECT_NO_COLORS=1 environment variable or - passing the --no-color command line option. +- FIXME GStreamer RTSP server -- Improved backlog handling when using TCP interleaved for data - transport. Before there was a fixed maximum size for backlog - messages, which was prone to deadlocks and made it difficult to - control memory usage with the watch backlog. The RTSP server now - limits queued TCP data messages to one per stream, moving queuing of - the data into the pipeline and leaving the RTSP connection - responsive to RTSP messages in both directions, preventing all those - problems. - -- Initial ULP Forward Error Correction support in rtspclientsink and - for RECORD mode in the server. - -- API to explicitly enable retransmission requests (RTX) - -- Lots of multicast-related fixes - -- rtsp-auth: Add support for parsing .htdigest files +- FIXME GStreamer VAAPI -- Support Wayland’s display for context sharing, so the application - can pass its own wl_display in order to be used for the VAAPI - display creation. - -- A lot of work to support new Intel hardware using media-driver as VA - backend. - -- For non-x86 devices, VAAPI display can instantiate, through DRM, - with no PCI bus. This enables the usage of libva-v4l2-request - driver. - -- Added support for XDG-shell protocol as wl_shell replacement which - is currently deprecated. This change add as dependency - wayland-protocol. - -- GstVaapiFilter, GstVaapiWindow, and GstVaapiDecoder classes now - inherit from GstObject, gaining all the GStreamer’s instrumentation - support. - -- The metadata now specifies the plugin as Hardware class. - -- H264 decoder is more stable with problematic streams. - -- In H265 decoder added support for profiles main-422-10 (P010_10LE), - main-444 (AYUV) and main-444-10 (Y410) - -- JPEG decoder handles dynamic resolution changes. - -- More specification adherence in H264 and H265 encoders. +- FIXME GStreamer OMX -- Add support of NV16 format to video encoders input. - -- Video decoders now handle the ALLOCATION query to tell upstream - about the number of buffers they require. Video encoders will also - use this query to adjust their number of allocated buffers - preventing starvation when using dynamic buffer mode. - -- The OMX_PERFORMANCE debug category has been renamed to OMX_API_TRACE - and can now be used to track a widder variety of interactions - between OMX and GStreamer. - -- Video encoders will now detect frame rate only changes and will - inform OMX about it rather than doing a full format reset. - -- Various Zynq UltraScale+ specific improvements: - - Video encoders are now able to import dmabuf from upstream. - - Support for HEVC range extension profiles and more AVC profiles. - - We can now request video encoders to generate an IDR using the - force key unit event. +- FIXME GStreamer Editing Services and NLE -- Added a gesdemux element, it is an auto pluggable element that - allows decoding edit list like files supported by GES - -- Added gessrc which wraps a GESTimeline as a standard source element - (implementing the ges protocol handler) - -- Added basic support for videorate::rate property potentially - allowing changing playback speed - -- Layer priority is now fully automatic and they should be moved with - the new ges_timeline_move_layer method, ges_layer_set_priority is - now deprecated. - -- Added a ges_timeline_element_get_layer_priority so we can simply get - all information about GESTimelineElement position in the timeline - -- GESVideoSource now auto orientates the images if it is defined in a - meta (overridable). - -- Added some PyGObject overrides to make the API more pythonic - -- The threading model has been made more explicit with safe guard to - make sure not thread safe APIs are not used from the wrong threads. - It is also now possible to properly handle in what thread the API - should be used. - -- Optimized GESClip and GESTrackElement creation - -- Added a way to compile out the old, unused and deprecated - GESPitiviFormatter - -- Re implemented the timeline editing API making it faster and making - the code much more maintainable - -- Simplified usage of nlecomposition outside GES by removing quirks in - it API usage and removing the need to treat it specially from an - application perspective. - -- ges-launch-1.0: - - - Added support to add titles to the timeline - - Enhance the help auto generating it from the code - -- Deprecate ges_timeline_load_from_uri as loading the timeline should - be done through a project now - -- MANY leaks have been plugged and the unit testsuite is now “leak - free” +- FIXME GStreamer validate -- Added an action type to verify the checksum of the sink last-sample - -- Added an include keyword to validate scenarios - -- Added the notion of variable in scenarios, with the set-vars keyword - -- Started adding support for “performance” like tests by allowing to - define the number of dropped buffers or the minimum buffer frequency - on a specific pad - -- Added a validateflow plugin which allows defining the data flow to - be seen on a particular pad and verifying that following runs match - the expectations - -- Added support for appsrc based test definition so we can instrument - the data pushed into the pipeline from scenarios - -- Added a mockdecryptor allowing adding tests with on encrypted files, - the element will potentially be instrumented with a validate - scenario - -- gst-validate-launcher: - - - Cleaned up output - - - Changed the default for “muting” tests as user doesn’t expect - hundreds of windows to show up when running the testsuite - - - Fixed the outputted xunit files to be compatible with GitLab - - - Added support to run tests on media files in push mode (using - pushfile://) - - - Added support for running inside gst-build - - - Added support for running ssim tests on rendered files - - - Added a way to simply define tests on pipelines through a simple - .json file - - - Added a python app to easily run python testsuite reusing all - the launcher features - - - Added flatpak knowledge so we can print backtrace even when - running from within flatpak - - - Added a way to automatically generated “known issues” - suppressions lines - - - Added a way to rerun tests to check if they are flaky and added - a way to tolerate tests known to be flaky - - - Add a way to output html log files +- FIXME GStreamer Python Bindings -- add binding for gst_pad_set_caps() - -- pygobject dependency requirement was bumped to >= 3.8 - -- new audiotestsrc, audioplot, and mixer plugin examples, and a - dynamic pipeline example +- FIXME GStreamer C# Bindings -- bindings for the GstWebRTC library +- FIXME GStreamer Rust Bindings -The GStreamer Rust bindings are now officially part of the GStreamer -project and are also maintained in the GStreamer GitLab. - -The releases will generally not be synchronized with the releases of -other GStreamer parts due to dependencies on other projects. - -Also unlike the other GStreamer libraries, the bindings will not commit -to full API stability but instead will follow the approach that is -generally taken by Rust projects, e.g.: - -1) 0.12.X will be completely API compatible with all other 0.12.Y - versions. -2) 0.12.X+1 will contain bugfixes and compatible new feature additions. -3) 0.13.0 will _not_ be backwards compatible with 0.12.X but projects - will be able to stay at 0.12.X without any problems as long as they - don’t need newer features. - -The current stable release is 0.12.2 and the next release series will be -0.13, probably around March 2019. - -At this point the bindings cover most of GStreamer core (except for most -notably GstAllocator and GstMemory), and most parts of the app, audio, -base, check, editing-services, gl, net. pbutils, player, rtsp, -rtsp-server, sdp, video and webrtc libraries. - -Also included is support for creating subclasses of the following types -and writing GStreamer plugins: - -- gst::Element -- gst::Bin and gst::Pipeline -- gst::URIHandler and gst::ChildProxy -- gst::Pad, gst::GhostPad -- gst_base::Aggregator and gst_base::AggregatorPad -- gst_base::BaseSrc and gst_base::BaseSink -- gst_base::BaseTransform - -Changes to 0.12.X since 0.12.0 - -Fixed - -- PTP clock constructor actually creates a PTP instead of NTP clock - -Added - -- Bindings for GStreamer Editing Services -- Bindings for GStreamer Check testing library -- Bindings for the encoding profile API (encodebin) - -- VideoFrame, VideoInfo, AudioInfo, StructureRef implements Send and - Sync now -- VideoFrame has a function to get the raw FFI pointer -- From impls from the Error/Success enums to the combined enums like - FlowReturn -- Bin-to-dot file functions were added to the Bin trait -- gst_base::Adapter implements SendUnique now -- More complete bindings for the gst_video::VideoOverlay interface, - especially - gst_video::is_video_overlay_prepare_window_handle_message() - -Changed - -- All references were updated from GitHub to freedesktop.org GitLab -- Fix various links in the README.md -- Link to the correct location for the documentation -- Remove GitLab badge as that only works with gitlab.com currently - -Changes in git master for 0.13 - -Fixed - -- gst::tag::Album is the album tag now instead of artist sortname - -Added - -- Subclassing infrastructure was moved directly into the bindings, - making the gst-plugin crate deprecated. This involves many API - changes but generally cleans up code and makes it more flexible. - Take a look at the gst-plugins-rs crate for various examples. - -- Bindings for CapsFeatures and Meta -- Bindings for - ParentBufferMeta,VideoMetaandVideoOverlayCompositionMeta` -- Bindings for VideoOverlayComposition and VideoOverlayRectangle -- Bindings for VideoTimeCode - -- UniqueFlowCombiner and UniqueAdapter wrappers that make use of the - Rust compile-time mutability checks and expose more API in a safe - way, and as a side-effect implement Sync and Send now - -- More complete bindings for Allocation Query -- pbutils functions for codec descriptions -- TagList::iter() for iterating over all tags while getting a single - value per tag. The old ::iter_tag_list() function was renamed to - ::iter_generic() and still provides access to each value for a tag -- Bus::iter() and Bus::iter_timed() iterators around the corresponding - ::pop\*() functions - -- serde serialization of Value can also handle Buffer now - -- Extensive comments to all examples with explanations -- Transmuxing example showing how to use typefind, multiqueue and - dynamic pads -- basic-tutorial-12 was ported and added - -Changed - -- Rust 1.31 is the minimum supported Rust version now -- Update to latest gir code generator and glib bindings - -- Functions returning e.g. gst::FlowReturn or other “combined” enums - were changed to return split enums like - Result to allow usage of the - standard Rust error handling. - -- MiniObject subclasses are now newtype wrappers around the underlying - GstRc wrapper. This does not change the API in any breaking - way for the current usages, but allows MiniObjects to also be - implemented in other crates and makes sure rustdoc places the - documentation in the right places. - -- BinExt extension trait was renamed to GstBinExt to prevent conflicts - with gtk::Bin if both are imported - -- Buffer::from_slice() can’t possible return None - -- Various clippy warnings +- FIXME GStreamer Rust Plugins -Like the GStreamer Rust bindings, the Rust plugins are now officially -part of the GStreamer project and are also maintained in the GStreamer -GitLab. - -In the 0.3.x versions this contained infrastructure for writing -GStreamer plugins in Rust, and a set of plugins. - -In git master that infrastructure was moved to the GLib and GStreamer -bindings directly, together with many other improvements that were made -possible by this, so the gst-plugins-rs repository only contains -GStreamer elements now. - -Elements included are: - -- Tutorials plugin: identity, rgb2gray and sinesrc with extensive - comments - -- rsaudioecho, a port of the audiofx element - -- rsfilesrc, rsfilesink - -- rsflvdemux, a FLV demuxer. Not feature-equivalent with flvdemux yet - -- threadshare plugin: ts-appsrc, ts-proxysrc/sink, ts-queue, ts-udpsrc - and ts-tcpclientsrc elements that use a fixed number of threads and - share them between instances. For more background about these - elements see Sebastian’s talk “When adding more threads adds more - problems - Thread-sharing between elements in GStreamer” at the - GStreamer Conference 2017. - -- rshttpsrc, a HTTP source around the hyper/reqwest Rust libraries. - Not feature-equivalent with souphttpsrc yet. - -- togglerecord, an element that allows to start/stop recording at any - time and keeps all audio/video streams in sync. - -- mccparse and mccenc, parsers and encoders for the MCC closed caption - file format. - -Changes to 0.3.X since 0.3.0 - -- All references were updated from GitHub to freedesktop.org GitLab -- Fix various links in the README.md -- Link to the correct location for the documentation - -Changes in git master for 0.4 - -- togglerecord: Switch to parking_lot crate for mutexes/condition - variables for lower overhead -- Merge threadshare plugin here -- New closedcaption plugin with mccparse and mccenc elements -- New identity element for the tutorials plugin - -- Register plugins statically in tests instead of relying on the - plugin loader to find the shared library in a specific place - -- Update to the latest API changes in the GLib and GStreamer bindings -- Update to the latest versions of all crates +- FIXME Build and Dependencies -- The MESON BUILD SYSTEM BUILD IS NOW FEATURE-COMPLETE (*) and it is - now the recommended build system on all platforms and also used by - Cerbero to build GStreamer on all platforms. The Autotools build is - scheduled to be removed in the next cycle. Developers who currently - use gst-uninstalled should move to gst-build. The build option - naming has been cleaned up and made consistent and there are now - feature options to enable/disable plugins and various other features - on a case-by-case basis. (*) with the exception of plugin docs which - will be handled differently in future +- The Autotools build system has finally been removed in favour of the + Meson build system. Developers who currently use gst-uninstalled + should move to gst-build. -- Symbol export in libraries is now controlled via explicit exports - using symbol visibility or export defines where supported, to ensure - consistency across all platforms. This also allows libraries to have - exports that vary based on detected platform features and configure - options as is the case with the GStreamer OpenGL integration library - for example. A few symbols that had been exported by accident in - earlier versions may no longer be exported. These symbols will not - have had declarations in any public header files then though and - would not have been usable. +- API and plugin documentation are no longer built with gtk_doc. The + gtk_doc documentation has been removed in favour of a new unified + documentation module built with hotdoc. The intention is to + distribute the generated documentation in form of tarballs alongside + releases. -- The GStreamer FFmpeg wrapper plugin (gst-libav) now depends on - FFmpeg 4.x and uses the new FFmpeg 4.x API and stopped relying on - ancient API that was removed with the FFmpeg 4.x release. This means - that it is no longer possible to build this module against an older - system-provided FFmpeg 3.x version. Use the internal FFmpeg 4.x copy - instead if you build using autotools, or use gst-libav 1.14.x - instead which targets the FFmpeg 3.x API and _should_ work fine in - combination with a newer GStreamer. It’s difficult for us to support - both old and new FFmpeg APIs at the same time, apologies for any - inconvenience caused. - -- Hardware-accelerated Nvidia video encoder/decoder plugins nvdec and - nvenc can be built against CUDA Toolkit versions 9 and 10.0 now. The - dynlink interface has been dropped since it’s deprecated in 10.0. - -- The (optional) OpenCV requirement has been bumped to >= 3.0.0 and - the plugin can also be built against OpenCV 4.x now. - -- New sctp plugin based on usrsctp (for WebRTC data channels) +- FIXME Cerbero @@ -1172,221 +175,66 @@ Windows, Android, iOS and macOS. Cerbero has seen a number of improvements: -- Cerbero has been ported to Python 3 and requires Python 3.5 or newer - now - -- Source tarballs are now protected by checksums in the recipes to - guard against download errors and malicious takeover of projects or - websites. In addition, downloads are only allowed via secure - transports now and plain HTTP, FTP and git:// transports are not - allowed anymore. - -- There is now a new fetch-bootstrap command which downloads sources - required for bootstrapping, with an optional --build-tools-only - argument to match the bootstrap --build-tools-only command. - -- The bootstrap, build, package and bundle-source commands gained a - new --offline switch that ensures that only sources from the cache - are used and never downloaded via the network. This is useful in - combination with the fetch and fetch-bootstrap commands that acquire - sources ahead of time before any build steps are executed. This - allows more control over the sources used and when sources are - updated, and is particularly useful for build environments that - don’t have network access. - -- bootstrap --assume-yes will automatically say ‘yes’ to any - interactive prompts during the bootstrap stage, such as those from - apt-get or yum. - -- bootstrap --system-only will only bootstrap the system without build - tools. - -- Manifest support: The build manifest can be used in continuous - integration (CI) systems to fixate the Git revision of certain - projects so that all builds of a pipeline are on the same reference. - This is used in GStreamer’s gitlab CI for example. It can also be - used in order to re-produce a specific build. To set a manifest, you - can set manifest = 'my_manifest.xml' in your configuration file, or - use the --manifest command line option. The command line option will - take precendence over anything specific in the configuration file. - -- The new build-deps command can be used to build only the - dependencies of a recipe, without the recipe itself. - -- new --list-variants command to list available variants - -- variants can now be set on the command line via the -v option as a - comma-separated list. This overrides any variants set in any - configuration files. - -- new qt5, intelmsdk and nvidia variants for enabling Qt5 and hardware - codec support. See the Enabling Optional Features with Variants - section in the Cerbero documentation for more details how to enable - and use these variants. - -- A new -t / --timestamp command line switch makes commands print - timestamps +- FIXME Platform-specific changes and improvements Android -- toolchain: update compiler to clang and NDKr18. NDK r18 removed the - armv5 target and only has Android platforms that target at least - armv7 so the armv5 target is not useful anymore. - -- The way that GIO modules are named has changed due to upstream GLib - natively adding support for loading static GIO modules. This means - that any GStreamer application using gnutls for SSL/TLS on the - Android or iOS platforms (or any other setup using static libraries) - will fail to link looking for the g_io_module_gnutls_load_static() - function. The new function name is now - g_io_gnutls_load(gpointer data). data can be NULL for a static - library. Look at this commit for the necessary change in the - examples. - -- various build issues on Android have been fixed. +- FIXME macOS and iOS -- various build issues on iOS have been fixed. - -- the minimum required iOS version is now 9.0. The difference in - adoption between 8.0 and 9.0 is 0.1% and the bump to 9.0 fixes some - build issues. - -- The way that GIO modules are named has changed due to upstream GLib - natively adding support for loading static GIO modules. This means - that any GStreamer application using gnutls for SSL/TLS on the - Android or iOS platforms (or any other setup using static libraries) - will fail to link looking for the g_io_module_gnutls_load_static() - function. The new function name is now - g_io_gnutls_load(gpointer data). data can be NULL for a static - library. Look at this commit for the necessary change in the - examples. +- FIXME Windows -- The webrtcdsp element is shipped again as part of the Windows binary - packages, the build system issue has been resolved. +- toolchain upgrade -- ‘Inconsistent DLL linkage’ warnings when building with MSVC have - been fixed - -- Hardware-accelerated Nvidia video encoder/decoder plugins nvdec and - nvenc build on Windows now, also with MSVC and using Meson. - -- The ksvideosrc camera capture plugin supports 16-bit grayscale video - now - -- The wasapisrc audio capture element implements loopback recording - from another output device or sink - -- wasapisink recover from low buffer levels in shared mode and some - exclusive mode fixes - -- dshowsrc now implements the GstDeviceMonitor interface +- FIXME Contributors -Aaron Boxer, Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, -Alex Ashley, Alexey Chernov, Alicia Boya García, Amit Pandya, Andoni -Morales Alastruey, Andreas Frisch, Andre McCurdy, Andy Green, Anthony -Violo, Antoine Jacoutot, Antonio Ospite, Arun Raghavan, Aurelien Jarno, -Aurélien Zanelli, ayaka, Bananahemic, Bastian Köcher, Branko Subasic, -Brendan Shanks, Carlos Rafael Giani, Charlie Turner, Christoph Reiter, -Corentin Noël, Daeseok Youn, Damian Vicino, Dan Kegel, Daniel Drake, -Daniel Klamt, Danilo Spinella, Dardo D Kleiner, David Ing, David -Svensson Fors, Devarsh Thakkar, Dimitrios Katsaros, Edward Hervey, -Emilio Pozuelo Monfort, Enrique Ocaña González, Erlend Eriksen, Ezequiel -Garcia, Fabien Dessenne, Fabrizio Gennari, Florent Thiéry, Francisco -Velazquez, Freyr666, Garima Gaur, Gary Bisson, George Kiagiadakis, Georg -Lippitsch, Georg Ottinger, Geunsik Lim, Göran Jönsson, Guillaume -Desmottes, H1Gdev, Haihao Xiang, Haihua Hu, Harshad Khedkar, Havard -Graff, He Junyan, Hoonhee Lee, Hosang Lee, Hyunjun Ko, Ilya Smelykh, -Ingo Randolf, Iñigo Huguet, Jakub Adam, James Stevenson, Jan Alexander -Steffens, Jan Schmidt, Jerome Laheurte, Jimmy Ohn, Joakim Johansson, -Jochen Henneberg, Johan Bjäreholt, John-Mark Bell, John Bassett, John -Nikolaides, Jonathan Karlsson, Jonny Lamb, Jordan Petridis, Josep Torra, -Joshua M. Doe, Jos van Egmond, Juan Navarro, Julian Bouzas, Jun Xie, -Junyan He, Justin Kim, Kai Kang, Kim Tae Soo, Kirill Marinushkin, Kyrylo -Polezhaiev, Lars Petter Endresen, Linus Svensson, Louis-Francis -Ratté-Boulianne, Lucas Stach, Luis de Bethencourt, Luz Paz, Lyon Wang, -Maciej Wolny, Marc-André Lureau, Marc Leeman, Marco Trevisan (Treviño), -Marcos Kintschner, Marian Mihailescu, Marinus Schraal, Mark Nauwelaerts, -Marouen Ghodhbane, Martin Kelly, Matej Knopp, Mathieu Duponchelle, -Matteo Valdina, Matthew Waters, Matthias Fend, memeka, Michael Drake, -Michael Gruner, Michael Olbrich, Michael Tretter, Miguel Paris, Mike -Wey, Mikhail Fludkov, Naveen Cherukuri, Nicola Murino, Nicolas Dufresne, -Niels De Graef, Nirbheek Chauhan, Norbert Wesp, Ognyan Tonchev, Olivier -Crête, Omar Akkila, Pat DeSantis, Patricia Muscalu, Patrick Radizi, -Patrik Nilsson, Paul Kocialkowski, Per Forlin, Peter Körner, Peter -Seiderer, Petr Kulhavy, Philippe Normand, Philippe Renon, Philipp Zabel, -Pierre Labastie, Piotr Drąg, Roland Jon, Roman Sivriver, Roman Shpuntov, -Rosen Penev, Russel Winder, Sam Gigliotti, Santiago Carot-Nemesio, -Sean-Der, Sebastian Dröge, Seungha Yang, Shi Yan, Sjoerd Simons, Snir -Sheriber, Song Bing, Soon, Thean Siew, Sreerenj Balachandran, Stefan -Ringel, Stephane Cerveau, Stian Selnes, Suhas Nayak, Takeshi Sato, -Thiago Santos, Thibault Saunier, Thomas Bluemel, Tianhao Liu, -Tim-Philipp Müller, Tobias Ronge, Tomasz Andrzejak, Tomislav Tustonić, -U. Artie Eoff, Ulf Olsson, Varunkumar Allagadapa, Víctor Guzmán, Víctor -Manuel Jáquez Leal, Vincenzo Bono, Vineeth T M, Vivia Nikolaidou, Wang -Fei, wangzq, Whoopie, Wim Taymans, Wind Yuan, Wonchul Lee, Xabier -Rodriguez Calvar, Xavier Claessens, Haihao Xiang, Yacine Bandou, -Yeongjin Jeong, Yuji Kuwabara, Zeeshan Ali, +- FIXME … and many others who have contributed bug reports, translations, sent suggestions or helped testing. -Stable 1.16 branch +Stable 1.18 branch -After the 1.16.0 release there will be several 1.16.x bug-fix releases +After the 1.18.0 release there will be several 1.18.x bug-fix releases which will contain bug fixes which have been deemed suitable for a stable branch, but no new features or intrusive changes will be added to -a bug-fix release usually. The 1.16.x bug-fix releases will be made from -the git 1.16 branch, which is a stable branch. +a bug-fix release usually. The 1.18.x bug-fix releases will be made from +the git 1.18 branch, which will be a stable branch. -1.16.0 +1.18.0 -1.16.0 was released on 19 April 2019. +1.18.0 has not been released yet. Known Issues -- possibly breaking/incompatible changes to properties of wrapped - FFmpeg decoders and encoders (see above). - -- The way that GIO modules are named has changed due to upstream GLib - natively adding support for loading static GIO modules. This means - that any GStreamer application using gnutls for SSL/TLS on the - Android or iOS platforms (or any other setup using static libraries) - will fail to link looking for the g_io_module_gnutls_load_static() - function. The new function name is now - g_io_gnutls_load(gpointer data). See Android/iOS sections above for - further details. +- FIXME -Schedule for 1.18 +Schedule for 1.20 -Our next major feature release will be 1.18, and 1.17 will be the -unstable development version leading up to the stable 1.18 release. The -development of 1.17/1.18 will happen in the git master branch. +Our next major feature release will be 1.20, and 1.19 will be the +unstable development version leading up to the stable 1.20 release. The +development of 1.19/1.20 will happen in the git master branch. -The plan for the 1.18 development cycle is yet to be confirmed, but it -is possible that the next cycle will be a short one in which case -feature freeze would be perhaps around August 2019 with a new 1.18 -stable release in September. +The plan for the 1.20 development cycle is yet to be confirmed. -1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, -1.8, 1.6, 1.4, 1.2 and 1.0 release series. +1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, +1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. ------------------------------------------------------------------------ _These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge, Guillaume Desmottes, Matthew -Waters, _ _Thibault Saunier, and Víctor Manuel Jáquez Leal._ +_contributions from … (FIXME)_ _License: CC BY-SA 4.0_ diff --git a/RELEASE b/RELEASE index c4759f66c4..77c4533e76 100644 --- a/RELEASE +++ b/RELEASE @@ -1,18 +1,15 @@ -This is GStreamer gst-rtsp-server 1.17.0.1. +This is GStreamer gst-rtsp-server 1.17.1. -The GStreamer team is thrilled to announce a new major feature release in the -stable 1.0 API series of your favourite cross-platform multimedia framework! +GStreamer 1.17 is the development branch leading up to the next major +stable version which will be 1.18. -As always, this release is again packed with new features, bug fixes and -other improvements. - -The 1.16 release series adds new features on top of the 1.14 series and is +The 1.17 development series adds new features on top of the 1.16 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. Full release notes will one day be found at: - https://gstreamer.freedesktop.org/releases/1.16/ + https://gstreamer.freedesktop.org/releases/1.18/ Binaries for Android, iOS, Mac OS X and Windows will usually be provided shortly after the release. @@ -60,7 +57,7 @@ You can find source releases of gstreamer in the download directory: https://gstreamer.freedesktop.org/src/gstreamer/ The git repository and details how to clone it can be found at -https://cgit.freedesktop.org/gstreamer/gstreamer/ +https://gitlab.freedesktop.org/gstreamer/ ==== Homepage ==== diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index b8382088cc..e05b899028 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -345,7 +345,7 @@ "construct": false, "construct-only": false, "controllable": false, - "default": "GStreamer/1.17.0.1", + "default": "GStreamer/1.17.1", "mutable": "null", "readable": true, "type": "gchararray", @@ -510,7 +510,7 @@ } } }, - "package": "GStreamer RTSP Server Library git", + "package": "GStreamer RTSP Server Library", "source": "gst-rtsp-server", "tracers": {}, "url": "Unknown package origin" diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 430c0b2fd3..d09320b95c 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -16,7 +16,7 @@ RTSP server library based on GStreamer RTSP server library based on GStreamer - + C @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.17.1 + master + + 2020-06-19 + + + + 1.16.0 diff --git a/meson.build b/meson.build index 3f45f0e539..26a2342cd3 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.17.0.1', + version : '1.17.1', meson_version : '>= 0.48', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 7174f04103d01efe793b2469ce98835e37e5f4c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 20 Jun 2020 00:28:28 +0100 Subject: [PATCH 1717/1776] Back to development --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 26a2342cd3..bee7f9c23f 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.17.1', + version : '1.17.1.1', meson_version : '>= 0.48', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 1c74592806df4785cd96eef12066a654b7661764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 22 Jun 2020 12:33:32 +0300 Subject: [PATCH 1718/1776] rtspclientsink: Don't call gst_ghost_pad_construct() anymore It's deprecated, unneeded and doesn't do anything anymore. Part-of: --- gst/rtsp-sink/gstrtspclientsink.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 38536ce124..59c21252ef 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -227,7 +227,6 @@ gst_rtsp_client_sink_pad_new (const GstPadTemplate * pad_tmpl, ret = g_object_new (GST_TYPE_RTSP_CLIENT_SINK_PAD, "direction", GST_PAD_SINK, "template", pad_tmpl, "name", name, NULL); - gst_ghost_pad_construct (GST_GHOST_PAD_CAST (ret)); return GST_PAD (ret); } From 0696b699aba9e0c36e08df51cec661e33f6de9f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 22 Jun 2020 20:04:45 +0300 Subject: [PATCH 1719/1776] docs: Fix version in the plugins cache Part-of: --- docs/gst_plugins_cache.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index e05b899028..e4871e39c8 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -345,7 +345,7 @@ "construct": false, "construct-only": false, "controllable": false, - "default": "GStreamer/1.17.1", + "default": "GStreamer/1.17.1.1", "mutable": "null", "readable": true, "type": "gchararray", From 289350572dc5f452d00c99fe65c5f5e29200fec9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 19 Jun 2020 22:55:54 -0400 Subject: [PATCH 1720/1776] doc: Stop documenting properties from parents --- docs/gst_plugins_cache.json | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index e4871e39c8..ce38d11064 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -28,18 +28,6 @@ } }, "properties": { - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", - "conditionally-available": false, - "construct": false, - "construct-only": false, - "controllable": false, - "default": "false", - "mutable": "null", - "readable": true, - "type": "gboolean", - "writable": true - }, "debug": { "blurb": "Dump request and response messages to stdout", "conditionally-available": false, @@ -90,18 +78,6 @@ "type": "gchararray", "writable": true }, - "message-forward": { - "blurb": "Forwards all children messages", - "conditionally-available": false, - "construct": false, - "construct-only": false, - "controllable": false, - "default": "false", - "mutable": "null", - "readable": true, - "type": "gboolean", - "writable": true - }, "multicast-iface": { "blurb": "The network interface on which to join the multicast group", "conditionally-available": false, From ab4952a786192f3b531a637f8fe0d9c5e6163008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 3 Jul 2020 00:33:54 +0100 Subject: [PATCH 1721/1776] Release 1.17.2 --- ChangeLog | 35 +++++++++++++++++++++++++++++++++++ NEWS | 4 ++-- RELEASE | 2 +- docs/gst_plugins_cache.json | 2 +- gst-rtsp-server.doap | 10 ++++++++++ meson.build | 2 +- 6 files changed, 50 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7aff7c37f3..340ab61076 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +=== release 1.17.2 === + +2020-07-03 00:33:54 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-rtsp-server.doap: + * meson.build: + Release 1.17.2 + +2020-06-19 22:55:54 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + doc: Stop documenting properties from parents + +2020-06-22 20:04:45 +0300 Sebastian Dröge + + * docs/gst_plugins_cache.json: + docs: Fix version in the plugins cache + Part-of: + +2020-06-22 12:33:32 +0300 Sebastian Dröge + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Don't call gst_ghost_pad_construct() anymore + It's deprecated, unneeded and doesn't do anything anymore. + Part-of: + +2020-06-20 00:28:28 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + === release 1.17.1 === 2020-06-19 19:24:38 +0100 Tim-Philipp Müller @@ -5,6 +39,7 @@ * ChangeLog: * NEWS: * RELEASE: + * docs/gst_plugins_cache.json: * gst-rtsp-server.doap: * meson.build: Release 1.17.1 diff --git a/NEWS b/NEWS index a4e7232a19..39b682a8c8 100644 --- a/NEWS +++ b/NEWS @@ -11,7 +11,7 @@ in summer 2020 now. 1.17.x is the unstable development series that is currently being developed in the git master branch and which will eventually result in -1.18, and 1.17.1 is the current development release in that series. +1.18, and 1.17.2 is the current development release in that series. The schedule for the 1.18 development cycle is yet to be confirmed, but it is expected that feature freeze will be in June/July 2020, followed @@ -24,7 +24,7 @@ July/August 2020. See https://gstreamer.freedesktop.org/releases/1.18/ for the latest version of this document. -_Last updated: Thursday 18 June 2020, 16:00 UTC (log)_ +_Last updated: Wednesday 1 July 2020, 23:50 UTC (log)_ Introduction diff --git a/RELEASE b/RELEASE index 77c4533e76..2d326990d4 100644 --- a/RELEASE +++ b/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-rtsp-server 1.17.1. +This is GStreamer gst-rtsp-server 1.17.2. GStreamer 1.17 is the development branch leading up to the next major stable version which will be 1.18. diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index ce38d11064..4f56b67607 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -321,7 +321,7 @@ "construct": false, "construct-only": false, "controllable": false, - "default": "GStreamer/1.17.1.1", + "default": "GStreamer/1.17.2", "mutable": "null", "readable": true, "type": "gchararray", diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index d09320b95c..778732c547 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.17.2 + master + + 2020-07-03 + + + + 1.17.1 diff --git a/meson.build b/meson.build index bee7f9c23f..8d0ea6e1d7 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.17.1.1', + version : '1.17.2', meson_version : '>= 0.48', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 60d8ed7d4f23eea9b41c9ed316b45c75aefec419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 3 Jul 2020 02:04:04 +0100 Subject: [PATCH 1722/1776] Back to development --- docs/gst_plugins_cache.json | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index 4f56b67607..4c4c9326d5 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -321,7 +321,7 @@ "construct": false, "construct-only": false, "controllable": false, - "default": "GStreamer/1.17.2", + "default": "GStreamer/1.17.2.1", "mutable": "null", "readable": true, "type": "gchararray", diff --git a/meson.build b/meson.build index 8d0ea6e1d7..a4ff4181b5 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.17.2', + version : '1.17.2.1', meson_version : '>= 0.48', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 34590b342ec28c1621e4ba543e20188dd9b1fbaa Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 2 Jul 2020 23:52:47 +0200 Subject: [PATCH 1723/1776] rtsp-stream: explicitly set caps on udpsrc elements This causes them to send caps events before data flow, which is usually a pretty correct thing to do! Not doing so manifested in a bug where ssrcdemux wouldn't forward the caps it had received with an extra ssrc field, as it hadn't received any caps event. Fixes #85 Part-of: --- gst/rtsp-server/rtsp-stream.c | 61 ++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index c3b35864d3..7ef3511a72 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -3635,13 +3635,17 @@ static gboolean create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * transport) { + gboolean ret = FALSE; GstRTSPStreamPrivate *priv; GstPad *pad; GstBin *bin; gboolean tcp; gboolean udp; gboolean mcast; + gboolean secure; gint i; + GstCaps *rtp_caps; + GstCaps *rtcp_caps; GST_DEBUG_OBJECT (stream, "create receiver part"); priv = stream->priv; @@ -3650,6 +3654,20 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * tcp = transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP; udp = transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP; mcast = transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST; + secure = (priv->profiles & GST_RTSP_PROFILE_SAVP) + || (priv->profiles & GST_RTSP_PROFILE_SAVPF); + + if (secure) { + rtp_caps = gst_caps_new_empty_simple ("application/x-srtp"); + rtcp_caps = gst_caps_new_empty_simple ("application/x-srtcp"); + } else { + rtp_caps = gst_caps_new_empty_simple ("application/x-rtp"); + rtcp_caps = gst_caps_new_empty_simple ("application/x-rtcp"); + } + + GST_DEBUG_OBJECT (stream, + "RTP caps: %" GST_PTR_FORMAT " RTCP caps: %" GST_PTR_FORMAT, rtp_caps, + rtcp_caps); for (i = 0; i < 2; i++) { /* For the receiver we create this bit of pipeline for both @@ -3696,7 +3714,13 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * GST_DEBUG_OBJECT (stream, "udp IPv4, create and configure udpsources"); if (!create_and_configure_udpsource (&priv->udpsrc_v4[i], priv->socket_v4[i])) - goto udpsrc_error; + goto done; + + if (i == 0) { + g_object_set (priv->udpsrc_v4[i], "caps", rtp_caps, NULL); + } else { + g_object_set (priv->udpsrc_v4[i], "caps", rtcp_caps, NULL); + } plug_src (stream, bin, priv->udpsrc_v4[i], priv->funnel[i]); } @@ -3705,7 +3729,13 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * GST_DEBUG_OBJECT (stream, "udp IPv6, create and configure udpsources"); if (!create_and_configure_udpsource (&priv->udpsrc_v6[i], priv->socket_v6[i])) - goto udpsrc_error; + goto done; + + if (i == 0) { + g_object_set (priv->udpsrc_v6[i], "caps", rtp_caps, NULL); + } else { + g_object_set (priv->udpsrc_v6[i], "caps", rtcp_caps, NULL); + } plug_src (stream, bin, priv->udpsrc_v6[i], priv->funnel[i]); } @@ -3714,7 +3744,14 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * GST_DEBUG_OBJECT (stream, "mcast IPv4, create and configure udpsources"); if (!create_and_configure_udpsource (&priv->mcast_udpsrc_v4[i], priv->mcast_socket_v4[i])) - goto mcast_udpsrc_error; + goto done; + + if (i == 0) { + g_object_set (priv->mcast_udpsrc_v4[i], "caps", rtp_caps, NULL); + } else { + g_object_set (priv->mcast_udpsrc_v4[i], "caps", rtcp_caps, NULL); + } + plug_src (stream, bin, priv->mcast_udpsrc_v4[i], priv->funnel[i]); } @@ -3722,7 +3759,14 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * GST_DEBUG_OBJECT (stream, "mcast IPv6, create and configure udpsources"); if (!create_and_configure_udpsource (&priv->mcast_udpsrc_v6[i], priv->mcast_socket_v6[i])) - goto mcast_udpsrc_error; + goto done; + + if (i == 0) { + g_object_set (priv->mcast_udpsrc_v6[i], "caps", rtp_caps, NULL); + } else { + g_object_set (priv->mcast_udpsrc_v6[i], "caps", rtcp_caps, NULL); + } + plug_src (stream, bin, priv->mcast_udpsrc_v6[i], priv->funnel[i]); } @@ -3738,11 +3782,12 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * gst_element_sync_state_with_parent (priv->funnel[i]); } - return TRUE; + ret = TRUE; -mcast_udpsrc_error: -udpsrc_error: - return FALSE; +done: + gst_caps_unref (rtp_caps); + gst_caps_unref (rtcp_caps); + return ret; } static gboolean From af290ae0e013ca7a656946a1962228d15a7b85ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 8 Jul 2020 17:28:57 +0100 Subject: [PATCH 1724/1776] meson: set release date from .doap file for releases Part-of: --- meson.build | 18 +++++++- .../extract-release-date-from-doap-file.py | 45 +++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100755 scripts/extract-release-date-from-doap-file.py diff --git a/meson.build b/meson.build index a4ff4181b5..fe57b5669e 100644 --- a/meson.build +++ b/meson.build @@ -103,8 +103,6 @@ endif cdata.set_quoted('GST_PACKAGE_NAME', gst_package_name) cdata.set_quoted('GST_PACKAGE_ORIGIN', get_option('package-origin')) -configure_file(output : 'config.h', configuration : cdata) - rtspserver_args = ['-DHAVE_CONFIG_H'] warning_flags = [ @@ -197,3 +195,19 @@ if not get_option('examples').disabled() endif subdir('pkgconfig') subdir('docs') + +# Set release date +if gst_version_nano == 0 + extract_release_date = find_program('scripts/extract-release-date-from-doap-file.py') + run_result = run_command(extract_release_date, gst_version, files('gst-rtsp-server.doap')) + if run_result.returncode() == 0 + release_date = run_result.stdout().strip() + cdata.set_quoted('GST_PACKAGE_RELEASE_DATETIME', release_date) + message('Package release date: ' + release_date) + else + # Error out if our release can't be found in the .doap file + error(run_result.stderr()) + endif +endif + +configure_file(output: 'config.h', configuration: cdata) diff --git a/scripts/extract-release-date-from-doap-file.py b/scripts/extract-release-date-from-doap-file.py new file mode 100755 index 0000000000..f09b60e9d0 --- /dev/null +++ b/scripts/extract-release-date-from-doap-file.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# +# extract-release-date-from-doap-file.py VERSION DOAP-FILE +# +# Extract release date for the given release version from a DOAP file +# +# Copyright (C) 2020 Tim-Philipp Müller +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +import sys +import xml.etree.ElementTree as ET + +if len(sys.argv) != 3: + sys.exit('Usage: {} VERSION DOAP-FILE'.format(sys.argv[0])) + +release_version = sys.argv[1] +doap_fn = sys.argv[2] + +tree = ET.parse(doap_fn) +root = tree.getroot() + +namespaces = {'doap': 'http://usefulinc.com/ns/doap#'} + +for v in root.findall('doap:release/doap:Version', namespaces=namespaces): + if v.findtext('doap:revision', namespaces=namespaces) == release_version: + release_date = v.findtext('doap:created', namespaces=namespaces) + if release_date: + print(release_date) + sys.exit(0) + +sys.exit('Could not find a release with version {} in {}'.format(release_version, doap_fn)) From e55515188da3265f5a8a8f4999a7d717b7dbd1ea Mon Sep 17 00:00:00 2001 From: Srimanta Panda Date: Wed, 15 Jul 2020 11:19:40 +0200 Subject: [PATCH 1725/1776] rtsp-sdp: Fix resource leak in mikey messsage Fixed a resource leak for mikey message while adding crypto session failed. Part-of: --- gst/rtsp-server/rtsp-sdp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c index 9a2a247b40..29f480447c 100644 --- a/gst/rtsp-server/rtsp-sdp.c +++ b/gst/rtsp-server/rtsp-sdp.c @@ -280,8 +280,10 @@ gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info, mikey_msg = gst_mikey_message_new_from_caps (caps); if (mikey_msg) { /* add policy '0' for all sending SSRC */ - if (!mikey_add_crypto_sessions (stream, mikey_msg)) + if (!mikey_add_crypto_sessions (stream, mikey_msg)) { + gst_mikey_message_unref (mikey_msg); goto crypto_sessions_error; + } base64 = gst_mikey_message_base64_encode (mikey_msg); if (base64) { From 3254b992aae9b91cabe7d9860b83b343d7896c83 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Mon, 3 Aug 2020 19:34:30 +0300 Subject: [PATCH 1726/1776] rtsp-thread-pool.c: fix clang 10 warning clang 10 is complaining about incompatible types due to the glib typesystem. ``` ../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-thread-pool.c:534:10: error: incompatible pointer types passing 'typeof ((((void *)0))) *' (aka 'void **') to parameter of type 'GThreadPool **' (aka 'struct _GThreadPool **') [-Werror,-Wincompatible-pointer-types] ``` Part-of: --- gst/rtsp-server/rtsp-thread-pool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index 6c53a01a67..7bfee10837 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -531,7 +531,7 @@ gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool * pool, if (G_UNLIKELY (!g_atomic_pointer_get (&klass->pool))) { GThreadPool *t_pool; t_pool = g_thread_pool_new ((GFunc) do_loop, klass, -1, FALSE, NULL); - if (!g_atomic_pointer_compare_and_exchange (&klass->pool, NULL, t_pool)) + if (!g_atomic_pointer_compare_and_exchange (&klass->pool, (GThreadPool *) NULL, t_pool)) g_thread_pool_free (t_pool, FALSE, TRUE); } From e3e946c0b0e50c912266939f5a4854298c8877b7 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Mon, 3 Aug 2020 19:34:30 +0300 Subject: [PATCH 1727/1776] rtsp-thread-pool.c: fix clang 10 warning clang 10 is complaining about incompatible types due to the glib typesystem. ``` ../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-thread-pool.c:534:10: error: incompatible pointer types passing 'typeof ((((void *)0))) *' (aka 'void **') to parameter of type 'GThreadPool **' (aka 'struct _GThreadPool **') [-Werror,-Wincompatible-pointer-types] ``` Part-of: --- gst/rtsp-server/rtsp-thread-pool.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-thread-pool.c b/gst/rtsp-server/rtsp-thread-pool.c index 7bfee10837..2921464f89 100644 --- a/gst/rtsp-server/rtsp-thread-pool.c +++ b/gst/rtsp-server/rtsp-thread-pool.c @@ -531,7 +531,8 @@ gst_rtsp_thread_pool_get_thread (GstRTSPThreadPool * pool, if (G_UNLIKELY (!g_atomic_pointer_get (&klass->pool))) { GThreadPool *t_pool; t_pool = g_thread_pool_new ((GFunc) do_loop, klass, -1, FALSE, NULL); - if (!g_atomic_pointer_compare_and_exchange (&klass->pool, (GThreadPool *) NULL, t_pool)) + if (!g_atomic_pointer_compare_and_exchange (&klass->pool, + (GThreadPool *) NULL, t_pool)) g_thread_pool_free (t_pool, FALSE, TRUE); } From 1984e679bd9f8eb4847229f9666649f33e5d073e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 20 Aug 2020 16:15:06 +0100 Subject: [PATCH 1728/1776] Release 1.17.90 --- ChangeLog | 67 +++++++++++++++++++++++++++++++++++++ NEWS | 49 +++++---------------------- RELEASE | 2 +- docs/gst_plugins_cache.json | 2 +- gst-rtsp-server.doap | 10 ++++++ meson.build | 2 +- 6 files changed, 89 insertions(+), 43 deletions(-) diff --git a/ChangeLog b/ChangeLog index 340ab61076..656cd3021b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,69 @@ +=== release 1.17.90 === + +2020-08-20 16:15:06 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-rtsp-server.doap: + * meson.build: + Release 1.17.90 + +2020-08-03 19:34:30 +0300 Jordan Petridis + + * gst/rtsp-server/rtsp-thread-pool.c: + rtsp-thread-pool.c: fix clang 10 warning + clang 10 is complaining about incompatible types due to the + glib typesystem. + ``` + ../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-thread-pool.c:534:10: error: incompatible pointer types passing 'typeof ((((void *)0))) *' (aka 'void **') to parameter of type 'GThreadPool **' (aka 'struct _GThreadPool **') [-Werror,-Wincompatible-pointer-types] + ``` + Part-of: + +2020-08-03 19:34:30 +0300 Jordan Petridis + + * gst/rtsp-server/rtsp-thread-pool.c: + rtsp-thread-pool.c: fix clang 10 warning + clang 10 is complaining about incompatible types due to the + glib typesystem. + ``` + ../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-thread-pool.c:534:10: error: incompatible pointer types passing 'typeof ((((void *)0))) *' (aka 'void **') to parameter of type 'GThreadPool **' (aka 'struct _GThreadPool **') [-Werror,-Wincompatible-pointer-types] + ``` + Part-of: + +2020-07-15 11:19:40 +0200 Srimanta Panda + + * gst/rtsp-server/rtsp-sdp.c: + rtsp-sdp: Fix resource leak in mikey messsage + Fixed a resource leak for mikey message while adding crypto session + failed. + Part-of: + +2020-07-08 17:28:57 +0100 Tim-Philipp Müller + + * meson.build: + * scripts/extract-release-date-from-doap-file.py: + meson: set release date from .doap file for releases + Part-of: + +2020-07-02 23:52:47 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: explicitly set caps on udpsrc elements + This causes them to send caps events before data flow, which is + usually a pretty correct thing to do! + Not doing so manifested in a bug where ssrcdemux wouldn't forward + the caps it had received with an extra ssrc field, as it hadn't + received any caps event. + Fixes #85 + Part-of: + +2020-07-03 02:04:04 +0100 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * meson.build: + Back to development + === release 1.17.2 === 2020-07-03 00:33:54 +0100 Tim-Philipp Müller @@ -5,6 +71,7 @@ * ChangeLog: * NEWS: * RELEASE: + * docs/gst_plugins_cache.json: * gst-rtsp-server.doap: * meson.build: Release 1.17.2 diff --git a/NEWS b/NEWS index 39b682a8c8..c216f07fea 100644 --- a/NEWS +++ b/NEWS @@ -1,22 +1,14 @@ +GStreamer 1.18 Release Notes - -GSTREAMER 1.18 RELEASE NOTES - - -THESE RELEASE NOTES ARE A PLACEHOLDER, PLEASE BEAR WITH US WHILE WE -FINISH WRITING UP THE REAL THING. +These release notes are a placeholder, please bear with us while we +finish writing up the real thing. GStreamer 1.18.0 has not yet been released. It is scheduled for release -in summer 2020 now. +in late August / early September 2020. 1.17.x is the unstable development series that is currently being developed in the git master branch and which will eventually result in -1.18, and 1.17.2 is the current development release in that series. - -The schedule for the 1.18 development cycle is yet to be confirmed, but -it is expected that feature freeze will be in June/July 2020, followed -by several 1.17 pre-releases and then a new 1.18 stable release in -July/August 2020. +1.18, and 1.17.90 is the current 1.18 pre-release in that series. 1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. @@ -24,8 +16,7 @@ July/August 2020. See https://gstreamer.freedesktop.org/releases/1.18/ for the latest version of this document. -_Last updated: Wednesday 1 July 2020, 23:50 UTC (log)_ - +Last updated: Wednesday 20 August 2020, 11:00 UTC (log) Introduction @@ -36,12 +27,10 @@ framework! As always, this release is again packed with many new features, bug fixes and other improvements. - Highlights - FIXME - Major new features and changes Noteworthy new API @@ -66,12 +55,10 @@ The following plugins have been removed from gst-plugins-bad: - FIXME - Miscellaneous API additions - FIXME - Miscellaneous performance and memory optimisations As always there have been many performance and memory usage improvements @@ -88,7 +75,6 @@ GstPlayer - FIXME - Miscellaneous changes - FIXME @@ -97,62 +83,50 @@ OpenGL integration - FIXME - Tracing framework and debugging improvements - FIXME - Tools - FIXME - GStreamer RTSP server - FIXME - GStreamer VAAPI - FIXME - GStreamer OMX - FIXME - GStreamer Editing Services and NLE - FIXME - GStreamer validate - FIXME - GStreamer Python Bindings - FIXME - GStreamer C# Bindings - FIXME - GStreamer Rust Bindings - FIXME - GStreamer Rust Plugins - FIXME - Build and Dependencies - The Autotools build system has finally been removed in favour of the @@ -177,7 +151,6 @@ Cerbero has seen a number of improvements: - FIXME - Platform-specific changes and improvements Android @@ -194,7 +167,6 @@ Windows - FIXME - Contributors - FIXME @@ -202,7 +174,6 @@ Contributors … and many others who have contributed bug reports, translations, sent suggestions or helped testing. - Stable 1.18 branch After the 1.18.0 release there will be several 1.18.x bug-fix releases @@ -215,12 +186,10 @@ the git 1.18 branch, which will be a stable branch. 1.18.0 has not been released yet. - Known Issues - FIXME - Schedule for 1.20 Our next major feature release will be 1.20, and 1.19 will be the @@ -234,7 +203,7 @@ The plan for the 1.20 development cycle is yet to be confirmed. ------------------------------------------------------------------------ -_These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from … (FIXME)_ +These release notes have been prepared by Tim-Philipp Müller with +contributions from … (FIXME) -_License: CC BY-SA 4.0_ +License: CC BY-SA 4.0 diff --git a/RELEASE b/RELEASE index 2d326990d4..632e998130 100644 --- a/RELEASE +++ b/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-rtsp-server 1.17.2. +This is GStreamer gst-rtsp-server 1.17.90. GStreamer 1.17 is the development branch leading up to the next major stable version which will be 1.18. diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index 4c4c9326d5..45fbab3b43 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -321,7 +321,7 @@ "construct": false, "construct-only": false, "controllable": false, - "default": "GStreamer/1.17.2.1", + "default": "GStreamer/1.17.90", "mutable": "null", "readable": true, "type": "gchararray", diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 778732c547..787833a163 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.17.90 + master + + 2020-08-20 + + + + 1.17.2 diff --git a/meson.build b/meson.build index fe57b5669e..74f29b81c4 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.17.2.1', + version : '1.17.90', meson_version : '>= 0.48', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 12eef972482ab3243743ae1bda1c40fc4411782c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 8 Sep 2020 00:08:29 +0100 Subject: [PATCH 1729/1776] Release 1.18.0 --- .gitlab-ci.yml | 2 +- ChangeLog | 12 + NEWS | 2117 ++++++++++++++++++++++++++++++++++- RELEASE | 13 +- docs/gst_plugins_cache.json | 2 +- gst-rtsp-server.doap | 10 + meson.build | 2 +- 7 files changed, 2089 insertions(+), 69 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c61aa7a529..944ad035e4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1 +1 @@ -include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml" +include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/1.18/gitlab/ci_template.yml" diff --git a/ChangeLog b/ChangeLog index 656cd3021b..19b8cce367 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +=== release 1.18.0 === + +2020-09-08 00:08:29 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-rtsp-server.doap: + * meson.build: + Release 1.18.0 + === release 1.17.90 === 2020-08-20 16:15:06 +0100 Tim-Philipp Müller @@ -5,6 +16,7 @@ * ChangeLog: * NEWS: * RELEASE: + * docs/gst_plugins_cache.json: * gst-rtsp-server.doap: * meson.build: Release 1.17.90 diff --git a/NEWS b/NEWS index c216f07fea..dba9c7c471 100644 --- a/NEWS +++ b/NEWS @@ -1,22 +1,11 @@ GStreamer 1.18 Release Notes -These release notes are a placeholder, please bear with us while we -finish writing up the real thing. - -GStreamer 1.18.0 has not yet been released. It is scheduled for release -in late August / early September 2020. - -1.17.x is the unstable development series that is currently being -developed in the git master branch and which will eventually result in -1.18, and 1.17.90 is the current 1.18 pre-release in that series. - -1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, -1.8, 1.6, 1.4, 1.2 and 1.0 release series. +GStreamer 1.18.0 was originally released on 7 September 2020. See https://gstreamer.freedesktop.org/releases/1.18/ for the latest version of this document. -Last updated: Wednesday 20 August 2020, 11:00 UTC (log) +Last updated: Monday 7 September 2020, 10:30 UTC (log) Introduction @@ -29,37 +18,1052 @@ fixes and other improvements. Highlights -- FIXME +- GstTranscoder: new high level API for applications to transcode + media files from one format to another + +- High Dynamic Range (HDR) video information representation and + signalling enhancements + +- Instant playback rate change support + +- Active Format Description (AFD) and Bar Data support + +- ONVIF trick modes support in both GStreamer RTSP server and client + +- Hardware-accelerated video decoding on Windows via DXVA2 / + Direct3D11 + +- Microsoft Media Foundation plugin for video capture and + hardware-accelerated video encoding on Windows + +- qmlgloverlay: New overlay element that renders a QtQuick scene over + the top of an input video stream + +- New imagesequencesrc element to easily create a video stream from a + sequence of jpeg or png images + +- dashsink: Add new sink to produce DASH content + +- dvbsubenc: DVB Subtitle encoder element + +- TV broadcast compliant MPEG-TS muxing with constant bitrate muxing + and SCTE-35 support + +- rtmp2: new RTMP client source and sink element implementation + +- svthevcenc: new SVT-HEVC-based H.265 video encoder + +- vaapioverlay compositor element using VA-API + +- rtpmanager support for Google’s Transport-Wide Congestion Control + (twcc) RTP extension + +- splitmuxsink and splitmuxsrc gained support for auxiliary video + streams + +- webrtcbin now contains some initial support for renegotiation + involving stream addition and removal + +- New RTP source and sink elements to easily set up RTP streaming via + rtp:// URIs + +- New Audio Video Transport Protocol (AVTP) plugin for Time-Sensitive + Applications + +- Support for the Video Services Forum’s Reliable Internet Stream + Transport (RIST) TR-06-1 Simple Profile + +- Universal Windows Platform (UWP) support + +- rpicamsrc element for capturing from the Raspberry Pi camera + +- RTSP Server TCP interleaved backpressure handling improvements as + well as support for Scale/Speed headers + +- GStreamer Editing Services gained support for nested timelines, + per-clip speed rate control and the OpenTimelineIO format. + +- Autotools build system has been removed in favour of Meson Major new features and changes -Noteworthy new API +Noteworthy new features and API -- FIXME +Instant playback rate changes -New Elements +Changing the playback rate as quickly as possible so far always required +a flushing seek. This generally works, but has the disadvantage of +flushing all data from the playback pipeline and requiring the demuxer +or parser to do a full-blown seek including resetting its internal state +and resetting the position of the data source. It might also require +considerable decoding effort to get to the right position to resume +playback from at the higher rate. -- FIXME +This release adds a new mechanism to achieve quasi-instant rate changes +in certain playback pipelines without interrupting the flow of data in +the pipeline. This is activated by sending a seek with the +GST_SEEK_FLAG_INSTANT_RATE_CHANGE flag and start_type = stop_type = +GST_SEEK_TYPE_NONE. This flag does not work for all pipelines, in which +case it is necessary to fall back to sending a full flushing seek to +change the playback rate. When using this flag, the seek event is only +allowed to change the current rate and can modify the trickmode flags +(e.g. keyframe only or not), but it is not possible to change the +current playback position, playback direction or do a flush. + +This is particularly useful for streaming use cases like HLS or DASH +where the streaming download should not be interrupted when changing +rate. + +Instant rate changing is handled in the pipeline in a specific sequence +which is detailed in the seeking design docs. Most elements don’t need +to worry about this, only elements that sync to the clock need some +special handling which is implemented in the GstBaseSink base class, so +should be taken care of automatically in most normal playback pipelines +and sink elements. + +See Jan’s GStreamer Conference 2019 talk “Changing Playback Rate +Instantly” for more information. + +You can try this feature by passing the -i command line option to +gst-play-1.0. It is supported at least by qtdemux, tsdemux, hlsdemux, +and dashdemux. + +Google Transport-Wide Congestion Control + +rtpmanager now supports the parsing and generating of RTCP messages for +the Google Transport-Wide Congestion Control RTP Extension, as described +in: +https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01. + +This “just” provides the required plumbing/infrastructure, it does not +actually make effect any actual congestion control on the sender side, +but rather provides information for applications to use to make such +decisions. + +See Håvard’s “Google Transport-Wide Congestion Control” talk for more +information about this feature. + +GstTranscoder: a new high-level transcoding API for applications + +The new GstTranscoder library, along with transcodebin and +uritranscodebin elements, provides high level API for applications to +transcode media files from one format to another. Watch Thibault’s talk +“GstTranscoder: A High Level API to Quickly Implement Transcoding +Capabilities in your Applications” for more information. + +This also comes with a gst-transcoder-1.0 command line utility to +transcode one URI into another URI based on the specified encoding +profile. + +Active Format Description (AFD) and Bar Data support + +The GstVideo Ancillary Data API has gained support for Active Format +Description (AFD) and Bar data. + +This includes various two new buffer metas: GstVideoAFDMeta and +GstVideoBarMeta. + +GStreamer now also parses and extracts AFD/Bar data in the h264/h265 +video parsers, and supports both capturing them and outputting them in +the decklink elements. See Aaron’s lightning talk at the GStreamer +Conference for more background. + +ONVIF trick modes support in both GStreamer RTSP server and client + +- Support for the various trick modes described in section 6 of the + ONVIF streaming spec has been implemented in both gst-rtsp-server + and rtspsrc. +- Various new properties in rtspsrc must be set to take advantage of + the ONVIF support +- Examples are available here: test-onvif-server.c and + test-onvif-client.c +- Watch Mathieu Duponchelle’s talk “Implementing a Trickmode Player + with ONVIF, RTSP and GStreamer” for more information and a live + demo. + +GStreamer Codecs library with decoder base classes + +This introduces a new library in gst-plugins-bad which contains a set of +base classes that handle bitstream parsing and state tracking for the +purpose of decoding different codecs. Currently H264, H265, VP8 and VP9 +are supported. These bases classes are meant primarily for internal use +in GStreamer and are used in various decoder elements in connection with +low level decoding APIs like DXVA, NVDEC, VAAPI and V4L2 State Less +decoders. The new library is named gstreamer-codecs-1.0 / +libgstcodecs-1.0 and is not yet guaranteed to be API stable across major +versions. + +MPEG-TS muxing improvements + +The GStreamer MPEG-TS muxer has seen major improvements on various +fronts in this cycle: + +- It has been ported to the GstAggregator base class which means it + can work in defined-latency mode with live input sources and + continue streaming if one of the inputs stops producing data. + +- atscmux, a new ATSC-specific tsmux subclass + +- Constant Bit Rate (CBR) muxing support via the new bitrate property + which allows setting the target bitrate in bps. If this is set the + muxer will insert null packets as padding to achieve the desired + multiplex-wide constant bitrate. + +- compliance fixes for TV broadcasting use cases (esp. ATSC). See + Jan’s talk “TV Broadcast compliant MPEG-TS” for details. + +- Streams can now be added and removed at runtime: Until now, any + streams in tsmux had to be present when the element started + outputting its first buffer. Now they can appear at any point during + the stream, or even disappear and reappear later using the same PID. + +- new pcr-interval property allows applications to configure the + desired interval instead of hardcoding it + +- basic SCTE-35 support. This is enabled by setting the scte-35-pid + property on the muxer. Sending SCTE-35 commands is then done by + creating the appropriate SCTE-35 GstMpegtsSection and sending them + on the muxer. + +- MPEG-2 AAC handling improvements + +New elements + +- New qmlgloverlay element for rendering a QtQuick scene over the top + of a video stream. qmlgloverlay requires that Qt support adopting an + external OpenGL context and is known to work on X11 and Windows. + Wayland is known not to work due to limitations within Qt. Check out + the example to see how it works. + +- The clocksync element is a generic element that can be placed in a + pipeline to synchronise passing buffers to the clock at that point. + This is similar to identity sync=true, but because it isn’t + GstBaseTransform-based, it can process GstBufferLists without + breaking them into separate GstBuffers. It is also more discoverable + than the identity option. Note that you do not need to insert this + element into your pipeline to make GStreamer sync to the pipeline + clock, this is usually handled automatically by the elements in the + pipeline (sources and sinks mostly). This element is useful to feed + non-live input such as local files into elements that expect live + input such as webrtcbin.` + +- New imagesequencesrc element to easily create a video stream from a + sequence of JPEG or PNG images (or any other encoding where the type + can be detected), basically a multifilesrc made specifically for + image sequences. + +- rpicamsrc element for capturing raw or encoded video (H.264, MJPEG) + from the Raspberry Pi camera. This works much like the popular + raspivid command line utility but outputs data nicely timestamped + and formatted in order to integrate nicely with other GStreamer + elements. Also comes with a device provider so applications can + discover the camera if available. + +- aatv and cacatv video filters that transform video ASCII art style + +- avtp: new Audio Video Transport Protocol (AVTP) plugin for Linux. + See Andre Guedes’ talk “Audio/Video Bridging (AVB) support in + GStreamer” for more details. + +- clockselect: a pipeline element that enables clock selection/forcing + via gst-launch pipeline syntax. + +- dashsink: Add new sink to produce DASH content. See Stéphane’s talk + or blog post for details. + +- dvbsubenc: a DVB subtitle encoder element + +- microdns: a libmicrodns-based mdns device provider to discover RTSP + cameras on the local network + +- mlaudiosink: new audio sink element for the Magic Leap platform, + accompanied by an MLSDK implementation in the amc plugin + +- msdkvp9enc: VP9 encoder element for the Intel MediaSDK + +- rist: new plugin implementing support for the Video Services Forum’s + Reliable Internet Stream Transport (RIST) TR-06-1 Simple Profile. + See Nicolas’ blog post “GStreamer support for the RIST + Specification” for more details. + +- rtmp2: new RTMP client source and sink elements with fully + asynchronous network operations, better robustness and additional + features such as handling ping and stats messages, and adobe-style + authentication. The new rtmp2src and rtmp2sink elements should be + API-compatible with the old rtmpsrc / rtmpsink elements and should + work as drop-in replacements. + +- new RTP source and sink elements to easily set up RTP streaming via + rtp:// URIs: The rtpsink and rtpsrc elements add an URI interface so + that streams can be decoded with decodebin using rtp:// URIs. These + can be used as follows: ``` gst-launch-1.0 videotestsrc ! x264enc ! + rtph264pay config-interval=3 ! rtpsink uri=rtp://239.1.1.1:1234 + + gst-launch-1.0 videotestsrc ! x264enc ! rtph264pay config-interval=1 + ! rtpsink uri=rtp://239.1.2.3:5000 gst-launch-1.0 rtpsrc + uri=rtp://239.1.2.3:5000?encoding-name=H264 ! rtph264depay ! + avdec_h264 ! videoconvert ! xvimagesink + + gst-launch-1.0 videotestsrc ! avenc_mpeg4 ! rtpmp4vpay + config-interval=1 ! rtpsink uri=rtp://239.1.2.3:5000 gst-launch-1.0 + rtpsrc uri=rtp://239.1.2.3:5000?encoding-name=MP4V-ES ! rtpmp4vdepay + ! avdec_mpeg4 ! videoconvert ! xvimagesink ``` + +- svthevcenc: new SVT-HEVC-based H.265 video encoder + +- switchbin: new helper element which chooses between a set of + processing chains (paths) based on input caps, and changes the + active chain if new caps arrive. Paths are child objects, which are + accessed by the GstChildProxy interface. See the switchbin + documentation for a usage example. + +- vah264dec: new experimental va plugin with an element for H.264 + decoding with VA-API using GStreamer’s new stateless decoder + infrastructure (see Linux section below). + +- v4l2codecs: introduce an V4L2 CODECs Accelerator supporting the new + CODECs uAPI in the Linux kernel (see Linux section below) + +- zxing new plugin to detect QR codes and barcodes, based on libzxing + +- also see the Rust plugins section below which contains plenty of new + exciting plugins written in Rust! New element features and additions -- FIXME +GStreamer core + +- filesink: Add a new “full” buffer mode. Previously the default and + full modes were the same. Now the default mode is like before: it + accumulates all buffers in a buffer list until the threshold is + reached and then writes them all out, potentially in multiple + writes. The new full mode works by always copying memory to a single + memory area and writing everything out with a single write once the + threshold is reached. + +- multiqueue: Add stats property and + current-level-{buffers, bytes, time} pad properties to query the + current levels of the corresponding internal queue. + +Plugins Base + +- alsa: implement a device provider + +- alsasrc: added use-driver-timestamp property to force use of + pipeline timestamps (and disable driver timestamps) if so desired + +- audioconvert: fix changing the mix-matrix property at runtime + +- appsrc: added support for segment forwarding or custom GstSegments + via GstSample, enabled via the handle-segment-change property. This + only works for segments in TIME format for now. + +- compositor: various performance optimisations, checkerboard drawing + fixes, and support for VUYA format + +- encodebin: Fix and refactor smart encoding; ensure that a single + segment is pushed into encoders; improve force-key-unit event + handling. + +- opusenc: Add low delay option (audio-type=restricted-lowdelay) to + disable the SILK layer and achieve only 5ms delay. + +- opusdec: add stats property to retrieve various decoder statistics. + +- uridecodebin3: Let decodebin3 do its stream selection if no one + answers + +- decodebin3: Avoid overriding explicit user selection of streams + +- playbin: add flag to force use of software decoders over any + hardware decoders that might also be available + +- playbin3, playbin: propagate sink context + +- rawvideoparse: Fix tiling support, allow setting colorimetry + +- subparse: output plain utf8 text instead of pango-markup formatted + text if downstream requires it, useful for interop with elements + that only accept utf8-formatted subtitles such as muxers or closed + caption converters. + +- tcpserversrc, tcpclientsrc: add stats property with TCP connection + stats (some are only available on Linux though) + +- timeoverlay: add show-times-as-dates, datetime-format and + datetime-epoch properties to display times with dates + +- videorate: Fix changing rate property during playback; reverse + playback fixes; update QoS events taking into account our rate + +- videoscale: pass through and transform size sensitive metas instead + of just dropping them + +Plugins Good + +- avidemux can handle H.265 video now. Our advice remains to + immediately cease all contact and communication with anyone who + hands you H.265 video in an AVI container, however. + +- avimux: Add support for S24LE and S32LE raw audio and v210 raw video + formats; support more than 2 channels of raw audio. + +- souphttpsrc: disable session sharing and cookie jar when the cookies + property is set; correctly handle seeks past the end of the content + +- deinterlace: new YADIF deinterlace method which should provide + better quality than the existing methods and is LGPL licensed; + alternate fields are supported as input to the deinterlacer as well + now, and there were also fixes for switching the deinterlace mode on + the fly. + +- flvmux: in streamable mode allow adding new pads even if the initial + header has already been written. Old clients will only process the + initial stream, new clients will get a header with the new streams. + The skip-backwards-streams property can be used to force flvmux to + skip and drop a few buffers rather than produce timestamps that go + backward and confuse librtmp-based clients. There’s also better + handling for timestamp rollover when streaming for a long time. + +- imagefreeze: Add live mode, which can be enabled via the new is-live + property. In this mode frames will only be output in PLAYING state + according to the negotiated framerate, skipping frames if the output + can’t keep up (e.g. because it’s blocked downstream). This makes it + possible to actually use imagefreeze in live pipelines without + having to manually ensure somehow that it starts outputting at the + current running time and without still risking to fall behind + without recovery. + +- matroskademux, qtdemux: Provide audio lead-in for some lossy formats + when doing accurate seeks, to make sure we can actually decode + samples at the desired position. This is especially important for + non-linear audio/video editing use-cases. + +- matroskademux, matroskamux: Handle interlaced field order (tff, bff) + +- matroskamux: + + - new offset-to-zero property to offset all streams to start at + zero. This takes the timestamp of the earliest stream and + offsets it so that it starts at 0. Some software (VLC, + ffmpeg-based) does not properly handle Matroska files that start + at timestamps much bigger than zero, which could happen with + live streams. + - added a creation-time property to explicitly set the creation + time to write into the file headers. Useful when remuxing, for + example, but also for live feeds where the DateUTC header can be + set a UTC timestamp corresponding to the beginning of the file. + - the muxer now also always waits for caps on sparse streams, and + warns if caps arrive after the header has already been sent, + otherwise the subtitle track might be silently absent in the + final file. This might affect applications that send sparse data + into matroskamux via an appsrc element, which will usually not + send out the initial caps before it sends out the first buffer. + +- pulseaudio: device provider improvements: fix discovery of + newly-added devices and hide the alsa device provider if we provide + alsa devices + +- qtdemux: raw audio handling improvements, support for AC4 audio, and + key-units trickmode interval support + +- qtmux: + + - was ported to the GstAggregator base class which allows for + better handling of live inputs, but might entail minor + behavioural changes for sparse inputs if inputs are not live. + - has also gained a force-create-timecode-trak property to create + a timecode trak in non-mov flavors, which may not be supported + by Apple but is supported by other software such as Final Cut + Pro X + - also a force-chunks property to force the creation of chunks + even in single-stream files, which is required for Apple ProRes + certification. + - also supports 8k resolutions in prefill mode with ProRes. + +- rtpbin gained a request-jitterbuffer signal which allows + applications to plug in their own jitterbuffer implementation such + as the threadsharing jitterbuffer from the Rust plugins, for + example. + +- rtprtxsend: add clock-rate-map property to allow generic RTP input + caps without a clock-rate whilst still supporting the max-size-time + property for bundled streams. + +- rtpssrcdemux: introduce max-streams property to guard against + attacks where the sender changes SSRC for every RTP packet. + +- rtph264pay, rtph264pay: implement STAP-A and various aggregation + modes controled by the new aggegrate-mode property: none to not + aggregate NAL units (as before), zero-latency to aggregate NAL units + until a VCL or suffix unit is included, or max to aggregate all NAL + units with the same timestamp (which adds one frame of latency). The + default has been kept at none for backwards compatibility reasons + and because various RTP/RTSP implementions don’t handle aggregation + well. For WebRTC use cases this should be set to zero-latency, + however. + +- rtpmp4vpay: add support for config-interval=-1 to resend headers + with each IDR keyframe, like other video payloaders. + +- rtpvp8depay: Add wait-for-keyframe property for waiting until the + next keyframe after packet loss. Useful if the video stream was not + encoded with error resilience enabled, in which case packet loss + tends to cause very bad artefacts when decoding, and waiting for the + next keyframe instead improves user experience considerably. + +- splitmuxsink and splitmuxsrc can now handle auxiliary video streams + in addition to the primary video stream. The primary video stream is + still used to select fragment cut points at keyframe boundaries. + Auxilliary video streams may be broken up at any packet - so + fragments may not start with a keyframe for those streams. + +- splitmuxsink: + + - new muxer-preset and sink-preset properties for setting + muxer/sink presets + - a new start-index property to set the initial fragment id + - and a new muxer-pad-map property which explicitly maps + splitmuxsink pads to the muxer pads they should connect to, + overriding the implicit logic that tries to match pads but + yields arbitrary names. + - Also includes the actual sink element in the fragment-opened and + fragment-closed element messages now, which is especially useful + for sinks without a location property or when finalisation of + the fragments is done asynchronously. + +- videocrop: add support for Y444, Y41B and Y42B pixel formats + +- vp8enc, vp9enc: change default value of VP8E_SET_STATIC_THRESHOLD + from 0 to 1 which matches what Google WebRTC does and results in + lower CPU usage; also added a new bit-per-pixel property to select a + better default bitrate + +- v4l2: add support for ABGR, xBGR, RGBA, and RGBx formats and for + handling interlaced video in alternate fields interlace mode (one + field per buffer instead of one frame per picture with both fields + interleaved) + +- v4l2: Profile and level probing support for H264, H265, MPEG-4, + MPEG-2, VP8, and VP9 video encoders and decoders + +Plugins Ugly + +- asfdemux: extract more metadata: disc number and disc count + +- x264enc: + + - respect YouTube bitrate recommendation when user sets the + YouTube profile preset + - separate high-10 video formats from 8-bit formats to improve + depth negotiation and only advertise suitable input raw formats + for the desired output depth + - forward downstream colorimetry and chroma-site restrictions to + upstream elements + - support more color primaries/mappings + +Plugins Bad + +- av1enc: add threads, row-mt and tile-{columns,rows} properties for + this AOMedia AV1 encoder + +- ccconverter: implement support for CDP framerate conversions + +- ccextractor: Add remove-caption-meta property to remove caption + metas from the outgoing video buffers + +- decklink: add support for 2K DCI video modes, widescreen NTSC/PAL, + and for parsing/outputting AFD/Bar data. Also implement a simple + device provider for Decklink devices. + +- dtlsrtpenc: add rtp-sync property which synchronises RTP streams to + the pipeline clock before passing them to funnel for merging with + RTCP. + +- fdkaac: also decode MPEG-2 AAC; encoder now supports more + multichannel/surround sound layouts + +- hlssink2: add action signals for custom playlist/fragment handling: + Instead of always going through the file system API we allow the + application to modify the behaviour. For the playlist itself and + fragments, the application can provide a GOutputStream. In addition + the sink notifies the application whenever a fragment can be + deleted. + +- interlace: can now output data in alternate fields mode; added field + switching mode for 2:2 field pattern + +- iqa: Add a mode property to enable strict mode that checks that all + the input streams have the exact same number of frames; also + implement the child proxy interface + +- mpeg2enc: add disable-encode-retries property for lower CPU usage + +- mpeg4videoparse: allow re-sending codec config at IDR via + config-interval=-1 + +- mpegtsparse: new alignment property to determine number of TS + packets per output buffer, useful for feeding an MPEG-TS stream for + sending via udpsink. This can be used in combination with the + split-on-rai property that makes sure to start a new output buffer + for any TS packet with the Random Access Indicator set. Also set + delta unit buffer flag on non-random-access buffers. + +- mpegdemux: add an ignore-scr property to ignore the SCR in + non-compliant MPEG-PS streams with a broken SCR, which will work as + long as PTS/DTS in the PES header is consistently increasing. + +- tsdemux: + + - add an ignore-pcr property to ignore MPEG-TS streams with broken + PCR streams on which we can’t reliably recover correct + timestamps. + - new latency property to allow applications to lower the + advertised worst-case latency of 700ms if they know their + streams support this (must have timestamps in higher frequency + than required by the spec) + - support for AC4 audio + +- msdk - Intel Media SDK plugin for hardware-accelerated video + decoding and encoding on Windows and Linux: + + - mappings for more video formats: Y210, Y410, P012_LE, Y212_LE + - encoders now support bitrate changes and input format changes in + playing state + - msdkh264enc, msdkh265enc: add support for CEA708 closed caption + insertion + - msdkh264enc, msdkh265enc: set Region of Interest (ROI) region + from ROI metas + - msdkh264enc, msdkh265enc: new tune property to enable low-power + mode + - msdkh265enc: add support 12-bit 4:2:0 encoding and 8-bit 4:2:2 + encoding and VUYA, Y210, and Y410 as input formats + - msdkh265enc: add support for screen content coding extension + - msdkh265dec: add support for main-12/main-12-intra, + main-422-10/main-422-10-intra 10bit, + main-422-10/main-422-10-intra 8bit, + main-422-12/main-422-12-intra, main-444-10/main-444-10-intra, + main-444-12/main-444-12-intra, and main-444 profiles + - msdkvp9dec: add support for 12-bit 4:4:4 + - msdkvpp: add support for Y410 and Y210 formats, cropping via + properties, and a new video-direction property. + +- mxf: Add support for CEA-708 CDP from S436 essence tracks. mxfdemux + can now handle Apple ProRes + +- nvdec: add H264 + H265 stateless codec implementation nvh264sldec + and nvh265sldec with fewer features but improved latency. You can + set the environment variable GST_USE_NV_STATELESS_CODEC=h264 to use + the stateless decoder variant as nvh264dec instead of the “normal” + NVDEC decoder implementation. + +- nvdec: add support for 12-bit 4:4:4/4:2:0 and 10-bit 4:2:0 decoding + +- nvenc: + + - add more rate-control options, support for B-frame encoding (if + device supports it), an aud property to toggle Access Unit + Delimiter insertion, and qp-{min,max,const}-{i,p,b} properties. + - the weighted-pred property enables weighted prediction. + - support for more input formats, namely 8-bit and 10-bit RGB + formats (BGRA, RGBA, RGB10A2, BGR10A2) and YV12 and VUYA. + - on-the-fly resolution changes are now supported as well. + - in case there are multiple GPUs on the system, there are also + per-GPU elements registered now, since different devices will + have different capabilities. + - nvh265enc can now support 10-bit YUV 4:4:4 encoding and 8-bit + 4:4:4 / 10-bit 4:2:0 formats up to 8K resolution (with some + devices). In case of HDR content HDR related SEI nals will be + inserted automatically. + +- openjpeg: enable multi-threaded decoding and add support for + sub-frame encoding (for lower latency) + +- rtponviftimestamp: add opt-out “drop-out-of-segment” property + +- spanplc: new stats property + +- srt: add support for IPv6 and for using hostnames instead of IP + addresses; add streamid property, but also allow passing the id via + the stream URI; add wait-for-connection property to srtsink + +- timecodestamper: this element was rewritten with an updated API + (properties); it has gained many new properties, seeking support and + support for linear timecode (LTC) from an audio stream. + +- uvch264src now comes with a device provider to advertise available + camera sources that support this interface (mostly Logitech C920s) + +- wpe: Add software rendering support and support for mouse scroll + events + +- x265enc: support more 8/10/12 bits 4:2:0, 4:2:2 and 4:4:4 profiles; + add support for mastering display info and content light level + encoding SEIs + +gst-libav + +- Add mapping for SpeedHQ video codec used by NDI + +- Add mapping for aptX and aptX-HD + +- avivf_mux: support VP9 and AV1 + +- avvidenc: shift output buffer timestamps and output segment by 1h + just like x264enc does, to allow for negative DTS. + +- avviddec: Limit default number of decoder threads on systems with + more than 16 cores, as the number of threads used in avdec has a + direct impact on the latency of the decoder, which is of as many + frames as threads, so a large numbers of threads can make for + latency levels that can be problematic in some applications. + +- avviddec: Add thread-type property that allows applications to + specify the preferred multithreading method (auto, frame, slice). + Note that thread-type=frame may introduce additional latency + especially in live pipelines, since it introduces a decoding delay + of number of thread frames. Plugin and library moves -- FIXME +- There were no plugin moves or library moves in this cycle. + +- The rpicamsrc element was moved into -good from an external + repository on github. Plugin removals -The following plugins have been removed from gst-plugins-bad: +The following elements or plugins have been removed: -- FIXME +- The yadif video deinterlacing plugin from gst-plugins-bad, which was + one of the few GPL licensed plugins, has been removed in favour of + deinterlace method=yadif. + +- The avdec_cdgraphics CD Graphics video decoder element from + gst-libav was never usable in GStreamer and we now have a cdgdec + element written in Rust in gst-plugins-rs to replace it. + +- The VDPAU plugin has been unmaintained and unsupported for a very + long time and does not have the feature set we expect from + hardware-accelerated video decoders. It’s been superseded by the + nvcodec plugin leveraging NVIDIA’s NVDEC API. Miscellaneous API additions -- FIXME +GStreamer core -Miscellaneous performance and memory optimisations +- gst_task_resume(): This new API allows resuming a task if it was + paused, while leaving it in stopped state if it was stopped or not + started yet. This can be useful for callback-based driver workflows, + where you basically want to pause and resume the task when buffers + are notified while avoiding the race with a gst_task_stop() coming + from another thread. + +- info: add printf extensions GST_TIMEP_FORMAT and GST_STIMEP_FORMAT + for printing GstClockTime/GstClockTimeDiff pointers, which is much + more convenient to use in debug log statements than the usual + GST_TIME_FORMAT-followed-by-GST_TIME_ARGS dance. Also add an + explicit GST_STACK_TRACE_SHOW_NONE enum value. + +- gst_element_get_current_clock_time() and + gst_element_get_current_running_time(): new helper functions for + getting an element clock’s time, and the clock time minus base time, + respectively. Useful when adding additional input branches to + elements such as compositor, audiomixer, flvmux, interleave or + input-selector to determine initial pad offsets and such. + +- seeking: Add GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED to just skip + B-frames during trick mode, showing both keyframes + P-frame, and + add support for it in h264parse and h265parse. + +- elementfactory: add GST_ELEMENT_FACTORY_TYPE_HARDWARE to allow + elements to advertise that they are hardware-based or interact with + hardware. This has multiple applications: + + - it makes it possible to easily differentiate hardware and + software based element implementations such as audio or video + encoders and decoders. This is useful in order to force the use + of software decoders for specific use cases, or to check if a + selected decoder is actually hardware-accelerated or not. + - elements interacting with hardware and their respective drivers + typically don’t know the actually supported capabilities until + the element is set into at least READY state and can open a + device handle and probe the hardware. + +- gst_uri_from_string_escaped(): identical to gst_uri_from_string() + except that the userinfo and fragment components of the URI will not + be unescaped while parsing. This is needed for correctly parsing + usernames or passwords with : in them . + +- paramspecs: new GstParamSpec flag GST_PARAM_CONDITIONALLY_AVAILABLE + to indicate that a property might not always exist. + +- gst_bin_iterate_all_by_element_factory_name() finds elements in a + bin by factory name + +- pad: gst_pad_get_single_internal_link() is a new convenience + function to return the single internal link of a pad, which is + useful e.g. to retrieve the output pad of a new multiqueue request + pad. + +- datetime: Add constructors to create datetimes with timestamps in + microseconds, gst_date_time_new_from_unix_epoch_local_time_usecs() + and gst_date_time_new_from_unix_epoch_utc_usecs(). + +- gst_debug_log_get_lines() gets debug log lines formatted in the same + way the default log handler would print them + +- GstSystemClock: Add GST_CLOCK_TYPE_TAI as GStreamer abstraction for + CLOCK_TAI, to support transmission offloading features where network + packets are timestamped with the time they are deemed to be actually + transmitted. Useful in combination with the new AVTP plugin. + +- miscellaneous utility functions: gst_clear_uri(), + gst_structure_take(). + +- harness: Added gst_harness_pull_until_eos() + +- GstBaseSrc: + + - gst_base_src_new_segment() allows subclasses to update the + segment to be used at runtime from the ::create() function. This + deprecates gst_base_src_new_seamless_segment() + - gst_base_src_negotiate() allows subclasses to trigger format + renegotiation at runtime from inside the ::create() or ::alloc() + function + +- GstBaseSink: new stats property and gst_base_sink_get_stats() method + to retrieve various statistics such as average frame rate and + dropped/rendered buffers. + +- GstBaseTransform: gst_base_transform_reconfigure() is now public + API, useful for subclasses that need to completely re-implement the + ::submit_input_buffer() virtual method + +- GstAggregator: + + - gst_aggregator_update_segment() allows subclasses to update the + output segment at runtime. Subclasses should use this function + rather than push a segment event onto the source pad directly. + - new sample selection API: + - subclasses should now call gst_aggregator_selected_samples() + from their ::aggregate() implementation to signal that they + have selected the next samples they will aggregate + - GstAggregator will then emit the samples-selected signal + where handlers can then look up samples per pad via + gst_aggregator_peek_next_sample(). + - This is useful for example to atomically update input pad + properties in mixer subclasses such as compositor. + Applications can now update properties with precise control + of when these changes will take effect, and for which input + buffer(s). + - gst_aggregator_finish_buffer_list() allows subclasses to push + out a buffer list, improving efficiency in some cases. + - a ::negotiate() virtual method was added, for consistency with + other base classes and to allow subclasses to completely + override the negotiation behaviour. + - the new ::sink_event_pre_queue() and ::sink_query_pre_queue() + virtual methods allow subclasses to intercept or handle + serialized events and queries before they’re queued up + internally. + +GStreamer Plugins Base Libraries + +Audio library + +- audioaggregator, audiomixer: new output-buffer-duration-fraction + property which allows use cases such as keeping the buffers output + by compositor on one branch and audiomixer on another perfectly + aligned, by requiring the compositor to output a n/d frame rate, and + setting output-buffer-duration-fraction to d/n on the audiomixer. + +- GstAudioDecoder: new max-errors property so applications can + configure at what point the decoder should error out, or tell it to + just keep going + +- gst_audio_make_raw_caps() and gst_audio_formats_raw() are + bindings-friendly versions of the GST_AUDIO_CAPS_MAKE() C macro. + +- gst_audio_info_from_caps() now handles encoded audio formats as well + +PbUtils library + +- GstEncodingProfile: + - Do not restrict number of similar profiles in a container + - add GstValue serialization function +- codec utils now support more H.264/H.265 profiles/levels and have + improved extension handling + +RTP library + +- rtpbasepayloader: Add scale-rtptime property for scaling RTP + timestamp according to the segment rate (equivalent to RTSP speed + parameter). This is useful for ONVIF trickmodes via RTSP. + +- rtpbasepayload: add experimental property for embedding twcc + sequencenumbers for Transport-Wide Congestion Control (gated behind + the GST_RTP_ENABLE_EXPERIMENTAL_TWCC_PROPERTY environment + variable) - more generic API for enabling this is expected to land + in the next development cycle. + +- rtcpbuffer: add RTPFB_TYPE_TWCC for Transport-Wide Congestion + Control + +- rtpbuffer: add + gst_rtp_buffer_get_extension_onebyte_header_from_bytes()``, so that one can parse theGBytes` + returned by gst_rtp_buffer_get_extension_bytes() + +- rtpbasedepayload: Add max-reorder property to make the + previously-hardcoded value when to consider a sender to have + restarted configurable. In some scenarios it’s particularly useful + to set max-reorder=0 to disable the behaviour that the depayloader + will drop packets: when max-reorder is set to 0 all + reordered/duplicate packets are considered coming from a restarted + sender. + +RTSP library + +- add gst_rtsp_url_get_request_uri_with_control() to create request + uri combined with control url + +- GstRTSPConnection: add the possibility to limit the Content-Length + for RTSP messages via + gst_rtsp_connection_set_content_length_limit(). The same + functionality is also exposed in gst-rtsp-server. + +SDP library + +- add support for parsing the extmap attribute from caps and storing + inside caps The extmap attribute allows mapping RTP extension header + IDs to well-known RTP extension header specifications. See RFC8285 + for details. + +Tags library + +- update to latest iso-code and support more languages + +- add tags for acoustid id & acoustid fingerprint, plus MusicBrainz ID + handling fixes + +Video library + +- High Dynamic Range (HDR) video information representation and + signalling enhancements: + + - New APIs for HDR video information representation and + signalling: + - GstVideoMasteringDisplayInfo: display color volume info as + per SMPTE ST 2086 + - GstVideoContentLightLevel: content light level specified in + CEA-861.3, Appendix A. + - plus functions to serialise/deserialise and add them to or + parse them from caps + - gst_video_color_{matrix,primaries,transfer}_{to,from}_iso(): + new utilility functions for conversion from/to ISO/IEC + 23001-8 + - add ARIB STD-B67 transfer chracteristic function + - add SMPTE ST 2084 support and BT 2100 colorimetry + - define bt2020-10 transfer characteristics for clarity: + bt707, bt2020-10, and bt2020-12 transfer characteristics are + functionally identical but have their own unique values in + the specification. + - h264parse, h265parse: Parse mastering display info and content + light level from SEIs. + - matroskademux: parse HDR metadata + - matroskamux: Write MasteringMetadata and Max{CLL,FALL}. Enable + muxing with HDR meta data if upstream provided it + - avviddec: Extract HDR information if any and map bt2020-10, PQ + and HLG transfer functions + +- added bt601 transfer function (for completeness) + +- support for more pixel formats: + + - Y412 (packed 12 bits 4:4:4:4) + - Y212 (packed 12 bits 4:2:2) + - P012 (semi-planar 4:2:0) + - P016_{LE,BE} (semi-planar 16 bits 4:2:0) + - Y444_16{LE,BE} (planar 16 bits 4:4:4) + - RGB10A2_LE (packed 10-bit RGB with 2-bit alpha channel) + - NV12_32L32 (NV12 with 32x32 tiles in linear order) + - NV12_4L4 (NV12 with 4x4 tiles in linear order) + +- GstVideoDecoder: + + - new max-errors property so applications can configure at what + point the decoder should error out, or tell it to just keep + going + + - new qos property to disable dropping frames because of QoS, and + post QoS messages on the bus when dropping frames. This is + useful for example in a scenario where the decoded video is + tee-ed off to go into a live sink that syncs to the clock in one + branch, and an encoding and save to file pipeline in the other + branch. In that case one wouldn’t want QoS events from the video + sink make the decoder drop frames because that would also leave + gaps in the encoding branch then. + +- GstVideoEncoder: + + - gst_video_encoder_finish_subframe() is new API to push out + subframes (e.g. slices), so encoders can split the encoding into + subframes, which can be useful to reduce the overall end-to-end + latency as we no longer need to wait for the full frame to be + encoded to start decoding or sending out the data. + - new min-force-key-unit-interval property allows configuring the + minimum interval between force-key-unit requests and prevents a + big bitrate increase if a lot of key-units are requested in a + short period of time (as might happen in live streaming RTP + pipelines when packet loss is detected). + - various force-key-unit event handling fixes + +- GstVideoAggregator, compositor, glvideomixer: expose + max-last-buffer-repeat property on pads. This can be used to have a + compositor display either the background or a stream on a lower + zorder after a live input stream freezes for a certain amount of + time, for example because of network issues. + +- gst_video_format_info_component() is new API to find out which + components are packed into a given plane, which is useful to prevent + us from assuming a 1-1 mapping between planes and components. + +- gst_video_make_raw_caps() and gst_video_formats_raw() are + bindings-friendly versions of the GST_VIDEO_CAPS_MAKE() C macro. + +- video-blend: Add support for blending on top of 16 bit per component + formats, which makes sure we can support every currently supported + raw video format for blending subtitles or logos on top of video. + +- GST_VIDEO_BUFFER_IS_TOP_FIELD() and + GST_VIDEO_BUFFER_IS_BOTTOM_FIELD() convenience macros to check + whether the video buffer contains only the top field or bottom field + of an interlaced picture. + +- GstVideoMeta now includes an alignment field with the + GstVideoAlignment so buffer producers can explicitly specify the + exact geometry of the planes, allowing users to easily know the + padded size and height of each plane. Default values will be used if + this is not set. + + Use gst_video_meta_set_alignment() to set the alignment and + gst_video_meta_get_plane_size() or gst_video_meta_get_plane_height() + to compute the plane sizes or plane heights based on the information + in the video meta. + +- gst_video_info_align_full() works like gst_video_info_align() but + also retrieves the plane sizes. + +MPEG-TS library + +- support for SCTE-35 sections + +- extend support for ATSC tables: + + - System Time Table (STT) + - Master Guide Table (MGT) + - Rating Region Table (RRT) + +Miscellaneous performance, latency and memory optimisations As always there have been many performance and memory usage improvements across all components and modules. Some of them have already been @@ -69,63 +1073,654 @@ The following list is only a small snapshot of some of the more interesting optimisations that haven’t been mentioned in other contexts yet: -- FIXME +- caps negotiation, structure and GValue performance optimizations -GstPlayer +- systemclock: clock waiting performance improvements (moved from + GstPoll to GCond for waiting), especially on Windows. -- FIXME +- rtpsession: add support for buffer lists on the recv path for better + performance with higher packet rate streams. -Miscellaneous changes +- rtpjitterbuffer: internal timer handling has been rewritten for + better performance, see Nicolas’ talk “Revisiting RTP Jitter Buffer + Timers” for more details. -- FIXME +- H.264/H.265 parsers and RTP payloaders/depayloaders have been + optimised for latency to make sure data is processed and pushed out + as quickly as possible + +- video-scaler: correctness and performance improvements, esp. for + interlaced formats and GBRA + +- GstVideoEncoder has gained new API to push out subframes + (e.g. slices), so encoders can split the encoding into subframes, + which can be useful to reduce the overall end-to-end latency as we + no longer need to wait for the full frame to be encoded to start + decoding or sending out the data. + + This is complemented by the new GST_VIDEO_BUFFER_FLAG_MARKER which + is a video-specific buffer flag to mark the end of a video frame, so + elements can know that they have received all data for a frame + without waiting for the beginning of the next frame. This is similar + to how the RTP marker flag is used in many RTP video mappings. + + The video encoder base class now also releases the internal stream + lock before pushing out data, so as to not block the input side of + things from processing more data in the meantime. + +Miscellaneous other changes and enhancements + +- it is now possible to modify the initial rank of plugin features + without modifying the source code or writing code to do so + programmatically via the GST_PLUGIN_FEATURE_RANK environment + variable. Users can adjust the rank of plugin(s) by passing a + comma-separated list of feature:rank pairs where rank can be a + numerical value or one of NONE, MARGINAL, SECONDARY, PRIMARY, and + MAX. Example: GST_PLUGIN_FEATURE_RANK=myh264dec:MAX,avdec_h264:NONE + sets the rank of the myh264dec element feature to the maximum and + that of avdec_h264 to 0 (none), thus ensuring that myh264dec is + prefered as H264 decoder in an autoplugging context. + +- GstDeviceProvider now does a static probe on start as fallback for + providers that don’t support dynamic probing to make things easier + for users + +WebRTC + +- webrtcbin now contains initial support for renegotiation involving + stream addition and removal. There are a number of caveats to this + initial renegotiation support and many complex scenarios are known + to require some work. + +- webrtcbin now exposes the internal ICE object for advanced + configuration options. Using the internal ICE object, it is possible + to toggle UDP or TCP connection usage as well as provide local + network addresses. + +- Fix a number of call flows within webrtcbin’s GstPromise handling + where a promise was never replied to. This has been fixed and now a + promise will always receive a reply. + +- webrtcbin now exposes a latency property for configuring the + internal rtpjitterbuffer latency and buffering when receiving + streams. + +- webrtcbin now only synchronises the RTP part of a stream, allowing + RTCP messages to skip synchronisation entirely. + +- Fixed most of the webrtcbin state properties (connection-state, + ice-connection-state, signaling-state, but not ice-gathering-state + as that requires newer API in libnice and will be fixed in the next + release series) to advance through the state values correctly. Also + implemented DTLS connection states in the DTLS elements so that + peer-connection-state is not always new. + +- webrtcbin now accounts for the a=ice-lite attribute in a remote SDP + offer and will configure the internal ICE implementation + accordingly. + +- webrtcbin will now resolve .local candidate addresses using the + system DNS resolver. .local candidate addresses are now produced by + web browsers to help protect the privacy of users. + +- webrtcbin will now add candidates found in the SDP to the internal + ICE agent. This was previously unsupported and required using the + add-ice-candidate signal manually from the application. + +- webrtcbin will now correctly parse a TURN URI that contains a + username or password with a : in it. + +- The GStreamer WebRTC library gained a GstWebRTCDataChannel object + roughly matching the interface exposed by the WebRTC specification + to allow for easier binding generation and use of data channels. OpenGL integration -- FIXME +GStreamer OpenGL bindings/build related changes + +- The GStreamer OpenGL library (libgstgl) now ships pkg-config files + for platform-specific API where libgstgl provides a public + integration interface and a pkg-config file for a dependency on the + detected OpenGL headers. The new list of pkg-config files in + addition to the original gstreamer-gl-1.0 are gstreamer-gl-x11-1.0, + gstreamer-gl-wayland-1.0, gstreamer-gl-egl-1.0, and + gstreamer-gl-prototypes-1.0 (for OpenGL headers when including + gst/gl/gstglfuncs.h). + +- GStreamer OpenGL now ships some platform-specific introspection data + for platforms that have a public interface. This should allow for + easier integration with bindings involving platform specific + functionality. The new introspection data files are named + GstGLX11-1.0, GstGLWayland-1.0, and GstGLEGL-1.0. + +GStreamer OpenGL Features + +- The iOS implementation no longer accesses UIKit objects off the main + thread fixing a loud warning message when used in iOS applications. + +- Support for mouse and keyboard handling using the GstNavigation + interface was added for the wayland implementation complementing the + already existing support for the X11 and Windows implementations. + +- A new helper base class for source elements, GstGLBaseSrc is + provided to ease writing source elements producing OpenGL video + frames. + +- Support for some more 12-bit and 16-bit video formats (Y412_LE, + Y412_BE, Y212_LE, Y212_BE, P012_LE, P012_BE, P016, NV16, NV61) was + added to glcolorconvert. + +- glupload can now import dma-buf’s into external-oes textures. + +- A new display type for EGLDevice-based systems was added. It is + currently opt-in by using either the GST_GL_PLATFORM=egl-device + environment variable or manual construction + (gst_gl_display_egl_device_new*()) due to compatibility issues with + some platforms. + +- Support was added for WinRT/UWP using the ANGLE project for running + OpenGL-based pipelines within a UWP application. + +- Various elements now support changing the GstGLDisplay to be used at + runtime in simple cases. This is primarily helpful for changing or + adding an OpenGL-based video sink that must share an OpenGL context + with an external source to an already running pipeline. + +GStreamer Vulkan integration + +- There is now a GStreamer Vulkan library to provide integration + points and helpers with applications and external GStreamer Vulkan + based elements. The structure of the library is modelled similarly + to the already existing GStreamer OpenGL library. Please note that + the API is still unstable and may change in future releases, + particularly around memory handling. The GStreamer Vulkan library + contains objects for sharing the vkInstance, vkDevice, vkQueue, + vkImage, VkMemory, etc with other elements and/or the application as + well as some helper objects for using Vulkan in an application or + element. + +- Added support for building and running on/for the Android and + Windows systems to complement the existing XCB, Wayland, MacOS, and + iOS implementations. + +- XCB gained support for mouse/keyboard events using the GstNavigation + API. + +- New vulkancolorconvert element for converting between color formats. + vulkancolorconvert can currently convert to/from all 8-bit RGBA + formats as well as 8-bit RGBA formats to/from the YUV formats AYUV, + NV12, and YUY2. + +- New vulkanviewconvert element for converting between stereo view + layouts. vulkanviewconvert can currently convert between all of the + single memory formats (side-by-side, top-bottom, column-interleaved, + row-interleaved, checkerboard, left, right, mono). + +- New vulkanimageidentity element for a blit from the input vulkan + image/s to a new vulkan image/s. + +- The vulkansink element can now scale the input image to the output + window/surface size where that information is available. + +- The vulkanupload element can now configure a transfer from system + memory to VulkanImage-based memory. Previously, this required two + vulkanupload elements. Tracing framework and debugging improvements -- FIXME +- gst_tracing_get_active_tracers() returns a list of active tracer + objects. This can be used to interact with tracers at runtime using + GObject API such as action signals. This has been implemented in the + leaks tracer for snapshotting and retrieving leaked/active objects + at runtime. + +- The leaks tracer can now be interacted with programmatically at + runtime via GObject action signals: + + - get-live-object returns a list of live (allocated) traced + objects + - log-live-objects logs a list of live objects into the debug log. + This is the same as sending the SIGUSR1 signal on unix systems, + but works on all operating systems including Windows. + - activity-start-tracking, activity-get-checkpoint, + activity-log-checkpoint, activity-stop-tracking: add support for + tracking and checkpointing objects, similar to what was + previously available via SIGUSR2 on unix systems, but works on + all operating systems including Windows. + +- various GStreamer gdb debug helper improvements: + + - new ‘gst-pipeline-tree’ command + - more gdb helper functions: gst_element_pad(), gst_pipeline() and + gst_bin_get() + - support for queries and buffers + - print more info for segment events, print event seqnums, object + pointers and structures + - improve gst-print command to show more pad and element + information Tools -- FIXME +gst-launch-1.0 + +- now prints the pipeline position and duration if available when the + pipeline is advancing. This is hopefully more user-friendly and + gives visual feedback on the terminal that the pipeline is actually + up and running. This can be disabled with the --no-position command + line option. + +- the parse-launch pipeline syntax now has support for presets: + use@preset=" after an element to load a preset. + +gst-inspect-1.0 + +- new --color command line option to force coloured output even if not + connected to a tty + +gst-tester-1.0 (new) + +- gst-tester-1.0 is a new tool for plugin developers to launch + .validatetest files with TAP compatible output, meaning it can + easily and cleanly be integrated with the meson test harness. It + allows you to use gst-validate (from the gst-devtools module) to + write integration tests in any GStreamer repository whilst keeping + the tests as close as possible to the code. The tool transparently + handles gst-validate being installed or not: if it is not installed + those integration tests will simply be skipped. + +gst-play-1.0 + +- interactive keyboard controls now also work on Windows + +gst-transcoder-1.0 (new) + +- gst-transcoder-1.0 is a new command line tool to transcode one URI + into another URI based on the specified encoding profile using the + new GstTranscoder API (see above). GStreamer RTSP server -- FIXME +- Fix issue where the first few packets (i.e. keyframes) could + sometimes be dropped if the rtsp media pipeline had a live input. + This was a regression from GStreamer 1.14. There are more fixes + pending for that which will hopefully land in 1.18.1. + +- Fix backpressure handling when sending data in TCP interleave mode + where RTSP requests and responses and RTP/RTCP packets flow over the + same RTSP TCP connection: The previous implementation would at some + point stop sending data to other clients when a single client + stopped consuming data or did not consume data fast enough. This + obviously created problems for shared media, where the same stream + from a single producer pipeline is sent to multiple clients. Instead + we now manage a backlog in the server’s stream-transport component + and remove slow clients once this backlog exceeds a maximum duration + (which is currently hardcoded). + +- Onvif Streaming Specification trick modes support (see section at + the beginning) + +- Scale/Speed header support: Speed will deliver the data at the + requested speed, which means increasing the data bandwidth for + speeds > 1.0. Scale will attempt to do the same without affecting + the overall bandwidth requirement vis-a-vis normal playback speed + (e.g. it might drop data for fast-forward playback). + +- rtspclientsink: send buffer lists in one go for better performance GStreamer VAAPI -- FIXME +- A lot of work was done adding support for media-driver (iHD), the + new VAAPI driver for Intel, mostly for Gen9 onwards. + +- Available color formats and frame sizes are now detected at run-time + according to the context configuration. + +- Gallium drivers have been re-enabled in the allowed drivers list + +- Improved the mapping between VA formats and GStreamer formats by + generating a mapping table at run-time since even among different + drivers the mapping might be different, particularly for RGB with + little endianness. + +- The experimental Flexible Encoding Infrastructure (FEI) elements + have been removed since they were not really actively maintained or + tested. + +- Enhanced the juggling of DMABuf buffers and VASurface metas + +- New vaapioverlay element: a compositor element using VA VPP blend + capabilities to accelerate overlaying and compositing. Example + pipeline: + + gst-launch-1.0 -vf videotestsrc ! vaapipostproc ! tee name=testsrc ! queue \ + ! vaapioverlay sink_1::xpos=300 sink_1::alpha=0.75 name=overlay ! vaapisink \ + testsrc. ! queue ! overlay. + +vaapipostproc + +- added video-orientation support, supporting frame mirroring and + rotation + +- added cropping support, either via properties (crop-left, + crop-right, crop-bottom and crop-top) or buffer meta. + +- new skin-tone-enhancenment-level property which is the iHD + replacement of the i965 driver’s sink-tone-level. Both are + incompatible with each other, so both were kept. + +- handle video colorimetry + +- support HDR10 tone mapping + +vaapisink + +- resurrected wayland backend for non-weston compositors by extracting + the DMABuf from the VASurface and rendering it. + +- merged the video overlay API for wayland. Now applications can + define the “window” to render on. + +- demoted the vaapisink element to secondary rank since libva + considers rendering as a second-class feature. + +VAAPI Encoders + +- new common target-percentage property which is the desired target + percentage of bitrate for variable rate control. + +- encoders now extract their caps from the driver at registration + time. + +- vaapivp9enc: added support for low power mode and support for + profile 2 (profile 0 by default) + +- vaapih264enc: new max-qp property that sets the maximum quantization + value. Support for ICQ and QBVR bitrate control mode, adding a + quality-factor property for these modes. Support baseline profile as + constrained-baseline + +- vaapih265enc: + + - support for main-444 and main-12 encoding profiles. + - new max-qp property that sets the maximum quantization value. + - support for ICQ and QBVR bitrate control mode, adding a + quality-factor property for these modes. + - handle SCC profiles. + - num-tile-cols and num-tile-row properties to specify the number + of tiles to use. + - the low-delay-b property was deprecated and is now determined + automatically. + - improved profile selection through caps. + +VAAPI Decoders + +- Decoder surfaces are not bound to their context any longer and can + thus be created and used dynamically, removing the deadlock + headache. + +- Reverse playback is now fluid + +- Forward Region-of-Interest (ROI) metas downstream + +- GLTextureUploadMeta uses DMABuf when GEM is not available. Now + Gallium drivers can use this meta for rendering with EGL. + +- vaapivp9dec: support for 4:2:2 and 4:4:4 chroma type streams + +- vaapih265dec: skip all pictures prior to the first I-frame. Enable + passing range extension flags to the driver. Handle SCC profiles. + +- vaapijpegdec: support for 4:0:0, 4:1:1, 4:2:2 and 4:4:4 chroma types + pictures + +- vaapih264dec: handle baseline streams as constrained-baseline if + possible and make it more tolerant when encountering unknown NALs GStreamer OMX -- FIXME +- omxvideoenc: use new video encoder subframe API to push out slices + as soon as they’re ready + +- omxh264enc, omxh265enc: negotiate subframe mode via caps. To enable + it, force downstream caps to video/x-h264,alignment=nal or + video/x-h265,alignment=nal. + +- omxh264enc: Add ref-frames property + +- Zynq ultrascale+ specific video encoder/decoder improvements: + + - GRAY8 format support + - support for alternate fields interlacing mode + - video encoder: look-ahead, long-term-ref, and long-term-freq + properties GStreamer Editing Services and NLE -- FIXME +- Added nested timelines and subproject support so that GES projects + can be used as clips, potentially serializing nested projects in the + main file or referencing external project files. + +- Implemented an OpenTimelineIO GES formatter. This means GES and + GStreamer can now load and save projects in all the formats + supported by otio. + +- Implemented a GESMarkerList object which allow setting timed + metadata on any GES object. + +- Fixed audio rendering issues during clip transition by ensuring that + a single segment is pushed into encoders. + +- The GESUriClipAsset API is now MT safe. + +- Added ges_meta_container_register_static_meta() to allow fixing a + type for a specific metadata without actually setting a value. + +- The framepositioner element now handles resizing the project and + keeps the same positioning when the aspect ratio is not changed . + +- Reworked the documentation, making it more comprehensive and much + more detailed. + +- Added APIs to retrieve natural size and framerate of a clip (for + example in the case of URIClip it is the framerate/size of the + underlying file). + +- ges_container_edit() is now deprecated and GESTimelineElement gained + the ges_timeline_element_edit() method so the editing API is now + usable from any element in the timeline. + +- GESProject::loading was added so applications can be notified about + when a new timeline starts loading. + +- Implemented the GstStream API in GESTimeline. + +- Added a way to add a timeoverlay inside the test source (potentially + with timecodes). + +- Added APIs to convert times to frame numbers and vice versa: + + - ges_timeline_get_frame_time() + + - ges_timeline_get_frame_at() + + - ges_clip_asset_get_frame_time() + + - ges_clip_get_timeline_time_from_source_frame() + + Quite a few validate tests have been implemented to check the + behavior for various demuxer/codec formats + +- Added ges_layer_set_active_for_tracks() which allows muting layers + for the specified tracks + +- Deprecated GESImageSource and GESMultiFileSource now that we have + imagesequencesrc which handles the imagesequence “protocol” + +- Stopped exposing ‘deinterlacing’ children properties for clip types + where they do not make sense. + +- Added support for simple time remapping effects GStreamer validate -- FIXME +- Introduced the concept of “Test files” allowing to implement “all + included” test cases, meaning that inside the file the following can + be defined: + + - The application arguments + - The validate configurations + - The validate scenario + + This replaces the previous big dictionary file in + gst-validate-launcher to implement specific test cases. + + We set several variables inside the files (as well as inside + scenarios and config files) to make them relocatable. + + The file format has been enhanced so it is easier to read and write, + for example line ending with a coma or (curly) brackets can now be + used as continuation marker so you do not need to add \ at the end + of lines to write a structure on several lines. + +- Support the imagesequence “protocol” and added integration tests for + it. + +- Added action types to allow the scenario to run the Test Clock for + better reproducibility of tests. + +- Support generating tests to check that seeking is frame accurate + (base on ssim). + +- Added ways to record buffers checksum (in different ways) in the + validateflow module. + +- Added vp9 encoding tests. + +- Enhanced seeking action types implementation to allow support for + segment seeks. + +- Output improvements: + + - Logs are now in markdown formats (and bat is used to dump them + if available). + - File format issues in scenarios/configs/tests files are nicely + reported with the line numbers now. GStreamer Python Bindings -- FIXME +- Python 2.x is no longer supported + +- Support mapping buffers without any memcpy: + + - Added a ContextManager to make the API more pythonic + + with buf.map(Gst.MapFlags.READ | Gst.MapFlags.WRITE) as info: + info.data[42] = 0 + +- Added high-level helper API for constructing pipelines: + + - Gst.Bin.make_and_add(factory_name, instance_name=None) + - Gst.Element.link_many(element, ...) GStreamer C# Bindings -- FIXME +- Bind gst_buffer_new_wrapped() manually to fix memory handling. -GStreamer Rust Bindings +- Fix gst_promise_new_with_change_func() where bindgen didn’t properly + detect the func as a closure. -- FIXME +- Declare GstVideoOverlayComposition and GstVideoOverlayRectangle as + opaque type and subclasses of Gst.MiniObject. This changes the API + but without this all usage will cause memory corruption or simply + not work. -GStreamer Rust Plugins +- on Windows, look for gstreamer, glib and gobject DLLs using the MSVC + naming convention (i.e. gstvideo-1.0-0.dll instead of + libgstvideo-1.0-0.dll). -- FIXME + The names of these DLLs have to be hardcoded in the bindings, and + most C# users will probably be using the Microsoft toolchain anyway. + + This means that the MSVC compiler is now required to build the + bindings, MingW will no longer work out of the box. + +GStreamer Rust Bindings and Rust Plugins + +The GStreamer Rust bindings are released separately with a different +release cadence that’s tied to gtk-rs, but the latest release has +already been updated for the new GStreamer 1.18 API, so there’s +absolutely no excuse why your next GStreamer application can’t be +written in Rust anymore. + +gst-plugins-rs, the module containing GStreamer plugins written in Rust, +has also seen lots of activity with many new elements and plugins. + +What follows is a list of elements and plugins available in +gst-plugins-rs, so people don’t miss out on all those potentially useful +elements that have no C equivalent. + +Rust audio plugins + +- audiornnoise: New element for audio denoising which implements the + noise removal algorithm of the Xiph RNNoise library, in Rust +- rsaudioecho: Port of the audioecho element from gst-plugins-good + rsaudioloudnorm: Live audio loudness normalization element based on + the FFmpeg af_loudnorm filter +- claxondec: FLAC lossless audio codec decoder element based on the + pure-Rust claxon implementation +- csoundfilter: Audio filter that can use any filter defined via the + Csound audio programming language +- lewtondec: Vorbis audio decoder element based on the pure-Rust + lewton implementation + +Rust video plugins + +- cdgdec/cdgparse: Decoder and parser for the CD+G video codec based + on a pure-Rust CD+G implementation, used for example by karaoke CDs +- cea608overlay: CEA-608 Closed Captions overlay element +- cea608tott: CEA-608 Closed Captions to timed-text (e.g. VTT or SRT + subtitles) converter +- tttocea608: CEA-608 Closed Captions from timed-text converter +- mccenc/mccparse: MacCaption Closed Caption format encoder and parser +- sccenc/sccparse: Scenarist Closed Caption format encoder and parser +- dav1dec: AV1 video decoder based on the dav1d decoder implementation + by the VLC project +- rav1enc: AV1 video encoder based on the fast and pure-Rust rav1e + encoder implementation +- rsflvdemux: Alternative to the flvdemux FLV demuxer element from + gst-plugins-good, not feature-equivalent yet +- rsgifenc/rspngenc: GIF/PNG encoder elements based on the pure-Rust + implementations by the image-rs project + +Rust text plugins + +- textwrap: Element for line-wrapping timed text (e.g. subtitles) for + better screen-fitting, including hyphenation support for some + languages + +Rust network plugins + +- reqwesthttpsrc: HTTP(S) source element based on the Rust + reqwest/hyper HTTP implementations and almost feature-equivalent + with the main GStreamer HTTP source souphttpsrc +- s3src/s3sink: Source/sink element for the Amazon S3 cloud storage +- awstranscriber: Live audio to timed text transcription element using + the Amazon AWS Transcribe API + +Generic Rust plugins + +- sodiumencrypter/sodiumdecrypter: Encryption/decryption element based + on libsodium/NaCl +- togglerecord: Recording element that allows to pause/resume + recordings easily and considers keyframe boundaries +- fallbackswitch/fallbacksrc: Elements for handling potentially + failing (network) sources, restarting them on errors/timeout and + showing a fallback stream instead +- threadshare: Set of elements that provide alternatives for various + existing GStreamer elements but allow to share the streaming threads + between each other to reduce the number of threads +- rsfilesrc/rsfilesink: File source/sink elements as replacements for + the existing filesrc/filesink elements Build and Dependencies @@ -135,11 +1730,67 @@ Build and Dependencies - API and plugin documentation are no longer built with gtk_doc. The gtk_doc documentation has been removed in favour of a new unified - documentation module built with hotdoc. The intention is to - distribute the generated documentation in form of tarballs alongside - releases. + documentation module built with hotdoc (also see “Documentation + improvements” section below). Distributors should use the + documentation release tarball instead of trying to package hotdoc + and building the documentation from scratch. -- FIXME +- gst-plugins-bad now includes an internal copy of libusrsctp, as + there are problems in usrsctp with global shared state, lack of API + stability guarantees, and the absence of any kind of release + process. We also can’t rely on distros shipping a version with the + fixes we need. Both firefox and Chrome bundle their own copies too. + It is still possible to build against an external copy of usrsctp if + so desired. + +- nvcodec no longer needs the NVIDIA NVDEC/NVENC SDKs available at + build time, only at runtime. This allows distributions to ship this + plugin by default and it will just start to work when the required + run-time SDK libraries are installed by the user, without users + needing to build and install the plugin from source. + +- the gst-editing-services tarball is now named gst-editing-services + for consistency (used to be gstreamer-editing-services). + +- the gst-validate tarball has been superseded by the gst-devtools + tarball for consistency with the git module name. + +gst-build + +gst-build is a meta-module and serves primarily as our uninstalled +development environment. It makes it easy to build most of GStreamer, +but unlike Cerbero it only comes with a limited number of external +dependencies that can be built as subprojects if they are not found on +the system. + +gst-build is based on Meson and replaces the old autotools +gst-uninstalled script. + +- The ‘uninstalled’ target has been renamed to ‘devenv’ + +- Experimental gstreamer-full library containing all built plugins and + their deps when building with -Ddefault_library=static. A monolithic + library is easier to distribute, and may be required in some + environments. GStreamer core, GLib and GObject are always included, + but external dependencies are still dynamically linked. The + gst-full-libraries meson option allows adding other GStreamer + libraries to the gstreamer-full build. This is an experiment for now + and its behaviour or API may still change in future releases. + +- Add glib-networking as a subproject when glib is a subproject and + load gio modules in the devenv, tls option control whether to use + openssl or gnutls. + +- git-worktree: Allow multiple worktrees for subproject branches + +- Guard against meson being run from inside the uninstalled devenv, as + this might have unexpected consequences. + +- our ffmpeg and x264 meson ports have been updated to the latest + stable version (you might need to update the subprojects checkout + manually though, or just remove the checkouts so meson checks out + the latest version again; improvements for this are pending in + meson, but not merged yet). Cerbero @@ -147,29 +1798,373 @@ Cerbero is a meta build system used to build GStreamer plus dependencies on platforms where dependencies are not readily available, such as Windows, Android, iOS and macOS. -Cerbero has seen a number of improvements: +General improvements -- FIXME +- Recipe build steps are done in parallel wherever possible. This + leads to massive improvements in overall build time. +- Several recipes were ported to Meson, which improved build times +- Moved from using both GnuTLS and OpenSSL to only OpenSSL +- Moved from yasm to nasm for all assembly compilation +- Support zsh when running the cerbero shell command +- Numerous version upgrades for dependencies +- Default to xz for tarball binary packages. bz2 can be selected with + the --compress-method option to package. +- Added boolean variant for controlling the optimization level: + -v optimization +- Ship .pc pkgconfig files for all plugins in the binary packages +- CMake and nasm will only be built by Cerbero if the system versions + are unusable +- The nvcodec variant was removed and the nvcodec plugin is built by + default now (as it no longer requires the SDK to be installed at + build time, only at runtime) + +macOS / iOS + +- Minimum iOS SDK version bumped to 11.0 +- Minimum macOS SDK version bumped to 10.11 +- No longer need to manually add support for newer iOS SDK versions +- Added Vulkan elements via MoltenVK +- Build times were improved by code-signing all build tools +- macOS framework ships all gstreamer libraries instead of an outdated + subset +- Ship pkg-config in the macOS framework package +- fontconfig: Fix EXC_BAD_ACCESS crash on iOS ARM64 +- Improved App Store compatibility by setting LC_VERSION_MIN_MACOSX, + fixing relocations, and improved bitcode support + +Windows + +- MinGW-GCC toolchain was updated to 8.2. It uses the Universal CRT + instead of MSVCRT which eliminates cross-CRT issues in the Visual + Studio build. +- Require Windows 7 or newer for running binaries produced by Cerbero +- Require Windows x86_64 for running Cerbero to build binary packages +- Cerbero no longer uses C:/gstreamer/1.0 as a prefix when building. + That prefix is reserved for use by the MSI installers. +- Several recipes can now be buit with Visual Studio instead of MinGW. + Ported to meson: opus, libsrtp, harfbuzz, cairo, openh264, libsoup, + libusrsctp. Existing build system: libvpx, openssl. +- Support building using Visual Studio for 32-bit x86. Previously we + only supported building for 32-bit x86 using the MinGW toolchain. +- Fixed annoying msgmerge popups in the middle of cerbero builds +- Added configuration options vs_install_path and vs_install_version + for specifying custom search locations for older Visual Studio + versions that do not support vswhere. You can set these in + ~/.cerbero/cerbero.cbc where ~ is the MSYS homedir, not your Windows + homedir. +- New Windows-specific plugins: d3d11, mediafoundation, wasapi2 +- Numerous compatibility and reliability fixes when running Cerbero on + Windows, especially non-English locales +- proxy-libintl now exports the same symbols as gettext, which makes + it a drop-in replacement +- New mapping variant for selecting the Visual Studio CRT to use: + -v vscrt=. Valid values are md, mdd, and auto (default). A + separate prefix is used when building with either md (release) or + mdd (debug), and the outputted package will have +debug in the + filename. This variant is also used for selecting the correct Qt + libraries (debug vs release) to use when building with -v qt5 on + Windows. +- Support cross-compile on Windows to Windows ARM64 and ARMv7 +- Support cross-compile on Windows to the Universal Windows Platform + (UWP). Only the subset of plugins that can be built entirely with + Visual Studio will be selected in this case. To do so, use the + config/cross-uwp-universal.cbc configuration, which will build + ARM64, x86, and x86_64 binaries linked to the release CRT, with + optimizations enabled, and debugging turned on. You can combine this + with -v vscrt=mdd to produce binaries linked to the debug CRT. You + can turn off optimizations with the -v nooptimization variant. + +Windows MSI installer + +- Require Windows 7 or newer for running GStreamer +- Fixed some issues with shipping of pkg-config in the Windows + installers +- Plugin PDB debug files are now shipped in the development package, + not the runtime package +- Ship installers for 32-bit binaries built with Visual Studio +- Ship debug and release “universal” (ARM64, X86, and X86_64) tarballs + built for the Universal Windows Platform +- Windows MSI installers now install into separate prefixes when + building with MSVC and MinGW. Previously both would be installed + into C:/gstreamer/1.0/x86 or C:/gstreamer/1.0/x86_64. Now, the + installation prefixes are: + + ---------------------------------------------------------------------------------------------------------------- + Target Path Build options + --------------------------- ------------------------------------ ----------------------------------------------- + MinGW 32-bit C:/gstreamer/1.0/mingw_x86 -c config/win32.cbc + + MinGW 64-bit C:/gstreamer/1.0/mingw_x86_64 -c config/win64.cbc + + MSVC 32-bit C:/gstreamer/1.0/msvc_x86 -c config/win32.cbc -v visualstudio + + MSVC 64-bit C:/gstreamer/1.0/msvc_x86_64 -c config/win64.cbc -v visualstudio + + MSVC 32-bit (debug) C:/gstreamer/1.0/msvc-debug_x86 -c config/win32.cbc -v visualstudio,vscrt=mdd + + MSVC 64-bit (debug) C:/gstreamer/1.0/msvc-debug_x86_64 -c config/win64.cbc -v visualstudio,vscrt=mdd + ---------------------------------------------------------------------------------------------------------------- + +Note: UWP binary packages are tarballs, not MSI installers. + +Linux + +- Support creating MSI installers using WiX when cross-compiling to + Windows +- Support running cross-windows binaries with Wine when using the + shell and runit cerbero commands +- Added bash-completion support inside the cerbero shell on Linux +- Require a system-wide installation of openssl on Linux +- Added variant -v vaapi to build gstreamer-vaapi and the new gstva + plugin +- Debian packaging was disabled because it does not work. Help in + fixing this is appreciated. +- Trimmed the list of packages needed for bootstrap on Linux + +Android + +- Updated to NDK r21 +- Support Vulkan +- Support Qt 5.14+ binary package layout Platform-specific changes and improvements Android -- FIXME +- opensles: Remove hard-coded buffer-/latency-time values and allow + openslessink to handle 48kHz streams. + +- photography interface and camera source: Add additional settings + relevant to Android such as: Exposure mode property, extra colour + tone values (aqua, emboss, sketch, neon), extra scene modes + (backlight, flowers, AR, HDR), and missing virtual methods for + exposure mode, analog gain, lens focus, colour temperature, min & + max exposure time. Add new effects and scene modes to Camera + parameters. macOS and iOS -- FIXME +- vtdec can now output to Vulkan-backed memory for zerocopy support + with the Vulkan elements. Windows -- toolchain upgrade +- d3d11videosink: new Direct3D11-based video sink with support for + HDR10 rendering if supported. -- FIXME +- Hardware-accelerated video decoding on Windows via DXVA2 / + Direct3D11 using native Windows APIs rather than per-vendor SDKs + (like MSDK for Intel or NVCODEC for NVidia). Plus modern Direct3D11 + integration rather than the almost 20-year old Direct3D9 from + Windows XP times used in d3dvideosink. Formats supported for + decoding are H.264, H.265, VP8, and VP9, and zero-copy operation + should be supported in combination with the new d3d11videosink. See + Seungha’s blog post “Windows DXVA2 (via Direct3D 11) Support in + GStreamer 1.17” for more details. + +- Microsoft Media Foundation plugin for hardware-accelerated video + encoding on Windows using native Windows APIs rather than per-vendor + SDKs. Formats supported for encoding are H.264, H.265 and VP9. Also + includes audio encoders for AAC and MP3. See Seungha’s blog post + “Bringing Microsoft Media Foundation to GStreamer” for some more + details about this. + +- new mfvideosrc video capture source element using the latest Windows + APIs rather than ancient APIs used by ksvideosrc/winks. ksvideosrc + should be considered deprecated going forward. + +- d3d11: add d3d11convert, a color space conversion and rescaling + element using shaders, and introduce d3d11upload and d3d11download + elements that work just like glupload and gldownload but for D3D11. + +- Universal Windows Platform (UWP) support, including official + GStreamer binary packages for it. Check out Nirbheek’s latest blog + post “GStreamer 1.18 supports the Universal Windows Platform” for + more details. + +- systemclock correctness and reliability fixes, and also don’t start + the system clock at 0 any longer (which shouldn’t make any + difference to anyone, as absolute clock time values are supposed to + be meaningless in themselves, only the rate of increase matters). + +- toolchain specific plugin registry: the registry cache is now named + differently for MSVC and MinGW toolchains/packages, which should + avoid problems when switching between binaries built with a + different toolchain. + +- new wasapi2 plugin mainly to support UWP applications. The core + logic of this plugin is almost identical to existing wasapi plugin, + but the main target is Windows 10 and UWP. This plugin uses WinRT + APIs, so will likely not work on Windows 8 or older. Unlike the + existing wasapi plugin, this plugin supports automatic stream + routing (auto fallback when device was removed) and device level + mute/volume control. Exclusive streaming mode is not supported, + however, and loopback features are not implemented yet. It is also + only possible to build this plugin with MSVC and the Windows 10 SDK, + it can’t be cross-compiled with the MingW toolchain. + +- new dxgiscreencapsrc element which uses the Desktop Duplication API + to capture the desktop screen at high speed. This is only supported + on Windows 8 or later. Compared to the existing elements + dxgiscreencapsrc offers much better performance, works in High DPI + environments and draws an accurate mouse cursor. + +- d3dvideosink was downgraded to secondary rank, d3d11videosink is + preferred now. Support OverlayComposition for GPU overlay + compositing of subtitles and logos. + +- debug log output fixes, esp. with a non-UTF8 locale/codepage + +- speex, jack: fixed crashes on Windows caused by cross-CRT issues + +- gst-play-1.0 interactive keyboard controls now also work on Windows + +Linux + +- kmssink: Add support for P010 and P016 formats + +- vah264dec: new experimental va plugin with an element for H.264 + decoding with VA-API. This novel approach, different from + gstreamer-vaapi, uses the gstcodecs library for decoder state + handling, which it is hoped will make for cleaner code because it + uses VA-API without further layers or wrappers. Check out Víctor’s + blog post “New VA-API H.264 decoder in gst-plugins-bad” for the full + lowdown and the limitations of this new plugin, and how to give it a + spin. + +- v4l2codecs: introduce a V4L2 CODECs Accelerator. This plugin will + support the new CODECs uAPI in the Linux kernel, which consists of + an accelerator interface similar to DXVA, NVDEC, VDPAU and VAAPI. So + far H.264 and VP8 are supported. This is used on certain embedded + systems such as i.mx8m, rk3288, rk3399, Allwinner H-series SoCs. + +Documentation improvements + +- unified documentation containing tutorials, API docs, plugin docs, + etc. all under one roof, shipped in form of a documentation release + tarball containing both devhelp and html documentation. + +- all documentation is now generated using hotdoc, gtk-doc is no + longer used. Distributors should use the above-mentioned + documentation release tarball instead of trying to package hotdoc + and building the documentation from scratch. + +- there is now documentation for wrapper plugins like gst-libav and + frei0r, as well as tracer plugins. + +- for more info, check out Thibault’s “GStreamer Documentation” + lightning talk from the 2019 GStreamer Conference. + +- new API for plugins to support the documentation system: + + - new GParamSpecFlag GST_PARAM_DOC_SHOW_DEFAULT to make + gst-inspect-1.0 (and the documentation) show the paramspec’s + default value rather than the actually set value as default + - GstPadTemplate getter and setter for “documentation caps”, + gst_pad_template_set_documentation_caps() and + gst_pad_template_get_documentation_caps(): This can be used in + elements where the caps of pad templates are dynamically + generated and/or dependent on the environment, to override the + caps shown in the documentation (usually to advertise the full + set of possible caps). + - gst_type_mark_as_plugin_api() for marking types as plugin API, + used for plugin-internal types like enums, flags, pad + subclasses, boxed types, and such. + +Possibly Breaking Changes + +- GstVideo: the canonical list of raw video formats (for use in caps) + has been reordered, so video elements such as videotestsrc or + videoconvert might negotiate to a different format now than before. + The new format might be a higher-quality format or require more + processing overhead, which might affect pipeline performance. + +- mpegtsdemux used to wrongly advertise H.264 and H.265 video + elementary streams as alignment=nal. This has now been fixed and + changed to alignment=none, which means an h264parse or h265parse + element is now required after tsdemux for some pipelines where there + wasn’t one before, e.g. in transmuxing scenarios (tsdemux ! tsmux). + Pipelines without such a parser may now fail to link or error out at + runtime. As parsers after demuxers and before muxers have been + generally required for a long time now it is hoped that this will + only affect a small number of applications or pipelines. + +- The Android opensles audio source and sink used to have hard-coded + buffer-/latency-time values of 20ms. This is no longer needed with + newer Android versions and has now been removed. This means a higher + or lower value might now be negotiated by default, which can affect + pipeline performance and latency. + +Known Issues + +- None in particular Contributors -- FIXME +Aaron Boxer, Adam Duskett, Adam x Nilsson, Adrian Negreanu, Akinobu +Mita, Alban Browaeys, Alcaro, Alexander Lapajne, Alexandru Băluț, Alex +Ashley, Alex Hoenig, Alicia Boya García, Alistair Buxton, Ali Yousuf, +Ambareesh “Amby” Balaji, Amr Mahdi, Andoni Morales Alastruey, Andreas +Frisch, Andre Guedes, Andrew Branson, Andrey Sazonov, Antonio Ospite, +aogun, Arun Raghavan, Askar Safin, AsociTon, A. Wilcox, Axel Mårtensson, +Ayush Mittal, Bastian Bouchardon, Benjamin Otte, Bilal Elmoussaoui, +Brady J. Garvin, Branko Subasic, Camilo Celis Guzman, Carlos Rafael +Giani, Charlie Turner, Cheng-Chang Wu, Chris Ayoup, Chris Lord, +Christoph Reiter, cketti, Damian Hobson-Garcia, Daniel Klamt, Daniel +Molkentin, Danny Smith, David Bender, David Gunzinger, David Ing, David +Svensson Fors, David Trussel, Debarshi Ray, Derek Lesho, Devarsh +Thakkar, dhilshad, Dimitrios Katsaros, Dmitriy Purgin, Dmitry Shusharin, +Dominique Leuenberger, Dong Il Park, Doug Nazar, dudengke, Dylan McCall, +Dylan Yip, Ederson de Souza, Edward Hervey, Eero Nurkkala, Eike Hein, +ekwange, Eric Marks, Fabian Greffrath, Fabian Orccon, Fabio D’Urso, +Fabrice Bellet, Fabrice Fontaine, Fanchao L, Felix Yan, Fernando +Herrrera, Francisco Javier Velázquez-García, Freyr, Fuwei Tang, Gaurav +Kalra, George Kiagiadakis, Georgii Staroselskii, Georg Lippitsch, Georg +Ottinger, gla, Göran Jönsson, Gordon Hart, Gregor Boirie, Guillaume +Desmottes, Guillermo Rodríguez, Haakon Sporsheim, Haihao Xiang, Haihua +Hu, Havard Graff, Håvard Graff, Heinrich Kruger, He Junyan, Henry +Wilkes, Hosang Lee, Hou Qi, Hu Qian, Hyunjun Ko, ibauer, Ignacio Casal +Quinteiro, Ilya Smelykh, Jake Barnes, Jakub Adam, James Cowgill, James +Westman, Jan Alexander Steffens, Jan Schmidt, Jan Tojnar, Javier Celaya, +Jeffy Chen, Jennifer Berringer, Jens Göpfert, Jérôme Laheurte, Jim +Mason, Jimmy Ohn, J. Kim, Joakim Johansson, Jochen Henneberg, Johan +Bjäreholt, Johan Sternerup, John Bassett, Jonas Holmberg, Jonas Larsson, +Jonathan Matthew, Jordan Petridis, Jose Antonio Santos Cadenas, Josep +Torra, Jose Quaresma, Josh Matthews, Joshua M. Doe, Juan Navarro, +Juergen Werner, Julian Bouzas, Julien Isorce, Jun-ichi OKADA, Justin +Chadwell, Justin Kim, Keri Henare, Kevin JOLY, Kevin King, Kevin Song, +Knut Andre Tidemann, Kristofer Björkström, krivoguzovVlad, Kyrylo +Polezhaiev, Lenny Jorissen, Linus Svensson, Loïc Le Page, Loïc Minier, +Lucas Stach, Ludvig Rappe, Luka Blaskovic, luke.lin, Luke Yelavich, +Marcin Kolny, Marc Leeman, Marco Felsch, Marcos Kintschner, Marek +Olejnik, Mark Nauwelaerts, Markus Ebner, Martin Liska, Martin Theriault, +Mart Raudsepp, Matej Knopp, Mathieu Duponchelle, Mats Lindestam, Matthew +Read, Matthew Waters, Matus Gajdos, Maxim Paymushkin, Maxim P. +Dementiev, Michael Bunk, Michael Gruner, Michael Olbrich, Miguel París +Díaz, Mikhail Fludkov, Milian Wolff, Millan Castro, Muhammet Ilendemli, +Nacho García, Nayana Topolsky, Nian Yan, Nicola Murino, Nicolas +Dufresne, Nicolas Pernas Maradei, Niels De Graef, Nikita Bobkov, Niklas +Hambüchen, Nirbheek Chauhan, Ognyan Tonchev, okuoku, Oleksandr +Kvl,Olivier Crête, Ondřej Hruška, Pablo Marcos Oltra, Patricia Muscalu, +Peter Seiderer, Peter Workman, Philippe Normand, Philippe Renon, Philipp +Zabel, Pieter Willem Jordaan, Piotr Drąg, Ralf Sippl, Randy Li, Rasmus +Thomsen, Ratchanan Srirattanamet, Raul Tambre, Ray Tiley, Richard +Kreckel, Rico Tzschichholz, R Kh, Robert Rosengren, Robert Tiemann, +Roman Shpuntov, Roman Sivriver, Ruben Gonzalez, Rubén Gonzalez, +rubenrua, Ryan Huang, Sam Gigliotti, Santiago Carot-Nemesio, Saunier +Thibault, Scott Kanowitz, Sebastian Dröge, Sebastiano Barrera, Seppo +Yli-Olli, Sergey Nazaryev, Seungha Yang, Shinya Saito, Silvio +Lazzeretti, Simon Arnling Bååth, Siwon Kang, sohwan.park, Song Bing, +Soohyun Lee, Srimanta Panda, Stefano Buora, Stefan Sauer, Stéphane +Cerveau, Stian Selnes, Sumaid Syed, Swayamjeet, Thiago Santos, Thibault +Saunier, Thomas Bluemel, Thomas Coldrick, Thor Andreassen, Tim-Philipp +Müller, Ting-Wei Lan, Tobias Ronge, trilene, Tulio Beloqui, U. Artie +Eoff, VaL Doroshchuk, Varunkumar Allagadapa, Vedang Patel, Veerabadhran +G, Víctor Manuel Jáquez Leal, Vivek R, Vivia Nikolaidou, Wangfei, Wang +Zhanjun, Wim Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier +Claessens, Xidorn Quan, Xu Guangxin, Yan Wang, Yatin Maan, Yeongjin +Jeong, yychao, Zebediah Figura, Zeeshan Ali, Zeid Bekli, Zhiyuan Sraf, +Zoltán Imets, … and many others who have contributed bug reports, translations, sent suggestions or helped testing. @@ -184,11 +2179,7 @@ the git 1.18 branch, which will be a stable branch. 1.18.0 -1.18.0 has not been released yet. - -Known Issues - -- FIXME +1.18.0 was released on 7 September 2020. Schedule for 1.20 @@ -196,7 +2187,9 @@ Our next major feature release will be 1.20, and 1.19 will be the unstable development version leading up to the stable 1.20 release. The development of 1.19/1.20 will happen in the git master branch. -The plan for the 1.20 development cycle is yet to be confirmed. +The plan for the 1.20 development cycle is yet to be confirmed, but it +is now expected that feature freeze will take place some time in January +2021, with the first 1.20 stable release around February/March 2021. 1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. @@ -204,6 +2197,8 @@ The plan for the 1.20 development cycle is yet to be confirmed. ------------------------------------------------------------------------ These release notes have been prepared by Tim-Philipp Müller with -contributions from … (FIXME) +contributions from Mathieu Duponchelle, Matthew Waters, Nirbheek +Chauhan, Sebastian Dröge, Thibault Saunier, and Víctor Manuel Jáquez +Leal. License: CC BY-SA 4.0 diff --git a/RELEASE b/RELEASE index 632e998130..b68f1e77b9 100644 --- a/RELEASE +++ b/RELEASE @@ -1,13 +1,16 @@ -This is GStreamer gst-rtsp-server 1.17.90. +This is GStreamer gst-rtsp-server 1.18.0. -GStreamer 1.17 is the development branch leading up to the next major -stable version which will be 1.18. +The GStreamer team is thrilled to announce a new major feature release +of your favourite cross-platform multimedia framework! -The 1.17 development series adds new features on top of the 1.16 series and is +As always, this release is again packed with new features, bug fixes and +other improvements. + +The 1.18 release series adds new features on top of the 1.16 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. -Full release notes will one day be found at: +Full release notes can be found at: https://gstreamer.freedesktop.org/releases/1.18/ diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index 45fbab3b43..7e5afa0741 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -321,7 +321,7 @@ "construct": false, "construct-only": false, "controllable": false, - "default": "GStreamer/1.17.90", + "default": "GStreamer/1.18.0", "mutable": "null", "readable": true, "type": "gchararray", diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 787833a163..cd72528bf2 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.18.0 + master + + 2020-09-08 + + + + 1.17.90 diff --git a/meson.build b/meson.build index 74f29b81c4..acf137bc43 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.17.90', + version : '1.18.0', meson_version : '>= 0.48', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From 3b08c08cf93fc2e5677f756b5009c3953c454c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 8 Sep 2020 16:58:58 +0100 Subject: [PATCH 1730/1776] Back to development --- docs/gst_plugins_cache.json | 2 +- meson.build | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index 7e5afa0741..a6cf43aa91 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -321,7 +321,7 @@ "construct": false, "construct-only": false, "controllable": false, - "default": "GStreamer/1.18.0", + "default": "GStreamer/1.19.0.1", "mutable": "null", "readable": true, "type": "gchararray", diff --git a/meson.build b/meson.build index acf137bc43..6bd6d1eebe 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('gst-rtsp-server', 'c', - version : '1.18.0', - meson_version : '>= 0.48', + version : '1.19.0.1', + meson_version : '>= 0.54', default_options : ['warning_level=1', 'buildtype=debugoptimized']) gst_version = meson.project_version() From 17edff4926287826a39221723e56cacd77f4308f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 8 Sep 2020 17:30:49 +0100 Subject: [PATCH 1731/1776] ci: include template from gst-ci master branch again --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 944ad035e4..c61aa7a529 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1 +1 @@ -include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/1.18/gitlab/ci_template.yml" +include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml" From 883ddc72bb5bc57c95a9e167814d1ac53fe1b443 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 25 Aug 2020 16:10:36 +0200 Subject: [PATCH 1732/1776] rtsp-media: do not unblock on unsuspend rtsp_media_unsuspend() is called from handle_play_request() before sending the play response. Unblocking the streams here was causing data to be sent out before the client was ready to handle it, with obvious side effects such as initial packets getting discarded, causing decoding errors. Instead we can simply let the media streams be unblocked when the state of the media is set to PLAYING, which occurs after sending the play response. Part-of: --- gst/rtsp-server/rtsp-media.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index e42cbb29a8..b8bc97b006 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -4582,21 +4582,14 @@ default_unsuspend (GstRTSPMedia * media) if (gst_rtsp_media_is_receive_only (media)) break; if (media_streams_blocking (media)) { - gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING); - /* at this point the media pipeline has been updated and contain all - * specific transport parts: all active streams contain at least one sink - * element and it's safe to unblock all blocked streams */ - media_streams_set_blocked (media, FALSE); - } else { - /* streams are not blocked and media is suspended from PAUSED */ - gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); - } - g_rec_mutex_unlock (&priv->state_lock); - if (gst_rtsp_media_get_status (media) == GST_RTSP_MEDIA_STATUS_ERROR) { + g_rec_mutex_unlock (&priv->state_lock); + if (gst_rtsp_media_get_status (media) == GST_RTSP_MEDIA_STATUS_ERROR) { + g_rec_mutex_lock (&priv->state_lock); + goto preroll_failed; + } g_rec_mutex_lock (&priv->state_lock); - goto preroll_failed; } - g_rec_mutex_lock (&priv->state_lock); + gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); break; case GST_RTSP_SUSPEND_MODE_PAUSE: gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED); From 5699ada939bec5a1317d4a7d1fb6e0afd70fad7e Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 21 Aug 2020 03:02:40 +0200 Subject: [PATCH 1733/1776] rtsp-stream: preroll on gap events This allows negotiating a SDP with all streams present, but only start sending packets at some later point in time Part-of: --- gst/rtsp-server/rtsp-stream.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 7ef3511a72..fecb1839f7 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -5179,35 +5179,47 @@ pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) GstRTSPStreamPrivate *priv; GstRTSPStream *stream; GstBuffer *buffer = NULL; + GstPadProbeReturn ret = GST_PAD_PROBE_OK; stream = user_data; priv = stream->priv; - GST_DEBUG_OBJECT (pad, "now blocking"); - g_mutex_lock (&priv->lock); - priv->blocking = TRUE; if ((info->type & GST_PAD_PROBE_TYPE_BUFFER)) { buffer = gst_pad_probe_info_get_buffer (info); + priv->position = GST_BUFFER_TIMESTAMP (buffer); } else if ((info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST)) { GstBufferList *list = gst_pad_probe_info_get_buffer_list (info); buffer = gst_buffer_list_get (list, 0); + priv->position = GST_BUFFER_TIMESTAMP (buffer); + } else if ((info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)) { + if (GST_EVENT_TYPE (info->data) == GST_EVENT_GAP) { + gst_event_parse_gap (info->data, &priv->position, NULL); + } else { + ret = GST_PAD_PROBE_PASS; + g_mutex_unlock (&priv->lock); + goto done; + } } else { g_assert_not_reached (); } - g_assert (buffer); - priv->position = GST_BUFFER_TIMESTAMP (buffer); - GST_DEBUG_OBJECT (stream, "buffer position: %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); + priv->blocking = TRUE; + + GST_DEBUG_OBJECT (pad, "Now blocking"); + + GST_DEBUG_OBJECT (stream, "position: %" GST_TIME_FORMAT, + GST_TIME_ARGS (priv->position)); + g_mutex_unlock (&priv->lock); gst_element_post_message (priv->payloader, gst_message_new_element (GST_OBJECT_CAST (priv->payloader), gst_structure_new_empty ("GstRTSPStreamBlocking"))); - return GST_PAD_PROBE_OK; +done: + return ret; } static void @@ -5233,7 +5245,8 @@ set_blocked (GstRTSPStream * stream, gboolean blocked) priv->blocking = FALSE; priv->blocked_id[i] = gst_pad_add_probe (priv->send_src[i], GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER | - GST_PAD_PROBE_TYPE_BUFFER_LIST, pad_blocking, + GST_PAD_PROBE_TYPE_BUFFER_LIST | + GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, pad_blocking, g_object_ref (stream), g_object_unref); } } From 3b9eaa092e74da2c63fe6a98f5942bf100511dde Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 5 Sep 2020 00:30:42 +0200 Subject: [PATCH 1734/1776] rtsp-media: set a 0 storage size for TCP receivers ulpfec correction is obviously useless when receiving a stream over TCP, and in TCP modes the rtp storage receives non timestamped buffers, causing it to queue buffers indefinitely, until the queue grows so large that sanity checks kick in and warnings start to get emitted. Part-of: --- gst/rtsp-server/rtsp-media.c | 41 +++++++++++++++----------- gst/rtsp-server/rtsp-server-internal.h | 2 ++ gst/rtsp-server/rtsp-stream.c | 14 +++++++++ 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b8bc97b006..8159697c8e 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -84,6 +84,7 @@ #define HMAC_80_KEY_LEN 10 #include "rtsp-media.h" +#include "rtsp-server-internal.h" struct _GstRTSPMediaPrivate { @@ -1645,6 +1646,25 @@ gst_rtsp_media_get_do_retransmission (GstRTSPMedia * media) return res; } +static void +update_stream_storage_size (GstRTSPMedia * media, GstRTSPStream * stream, + guint sessid) +{ + GObject *storage = NULL; + + g_signal_emit_by_name (G_OBJECT (media->priv->rtpbin), "get-storage", + sessid, &storage); + + if (storage) { + guint size_time = 0; + + if (!gst_rtsp_stream_is_tcp_receiver (stream)) + size_time = (media->priv->latency + 50) * GST_MSECOND; + + g_object_set (storage, "size-time", size_time, NULL); + } +} + /** * gst_rtsp_media_set_latency: * @media: a #GstRTSPMedia @@ -1670,13 +1690,8 @@ gst_rtsp_media_set_latency (GstRTSPMedia * media, guint latency) g_object_set (priv->rtpbin, "latency", latency, NULL); for (i = 0; i < media->priv->streams->len; i++) { - GObject *storage = NULL; - - g_signal_emit_by_name (G_OBJECT (media->priv->rtpbin), "get-storage", - i, &storage); - if (storage) - g_object_set (storage, "size-time", - (media->priv->latency + 50) * GST_MSECOND, NULL); + GstRTSPStream *stream = g_ptr_array_index (media->priv->streams, i); + update_stream_storage_size (media, stream, i); } } @@ -3617,14 +3632,6 @@ request_fec_decoder (GstElement * rtpbin, guint sessid, GstRTSPMedia * media) return res; } -static void -new_storage_cb (GstElement * rtpbin, GObject * storage, guint sessid, - GstRTSPMedia * media) -{ - g_object_set (storage, "size-time", (media->priv->latency + 50) * GST_MSECOND, - NULL); -} - static gboolean start_prepare (GstRTSPMedia * media) { @@ -3636,8 +3643,6 @@ start_prepare (GstRTSPMedia * media) if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARING) goto no_longer_preparing; - g_signal_connect (priv->rtpbin, "new-storage", G_CALLBACK (new_storage_cb), - media); g_signal_connect (priv->rtpbin, "request-fec-decoder", G_CALLBACK (request_fec_decoder), media); @@ -5010,6 +5015,8 @@ gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GPtrArray * transports) g_mutex_unlock (&priv->lock); return FALSE; } + + update_stream_storage_size (media, stream, i); } priv->complete = TRUE; diff --git a/gst/rtsp-server/rtsp-server-internal.h b/gst/rtsp-server/rtsp-server-internal.h index 056814fbb9..008b7552dc 100644 --- a/gst/rtsp-server/rtsp-server-internal.h +++ b/gst/rtsp-server/rtsp-server-internal.h @@ -56,6 +56,8 @@ void gst_rtsp_stream_transport_set_back_pressure_callback (G gboolean gst_rtsp_stream_transport_check_back_pressure (GstRTSPStreamTransport *trans, gboolean is_rtp); +gboolean gst_rtsp_stream_is_tcp_receiver (GstRTSPStream * stream); + G_END_DECLS #endif /* __GST_RTSP_SERVER_INTERNAL_H__ */ diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index fecb1839f7..323076585e 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -3790,6 +3790,20 @@ done: return ret; } +gboolean +gst_rtsp_stream_is_tcp_receiver (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + gboolean ret = FALSE; + + priv = stream->priv; + g_mutex_lock (&priv->lock); + ret = (priv->sinkpad != NULL && priv->appsrc[0] != NULL); + g_mutex_unlock (&priv->lock); + + return ret; +} + static gboolean check_mcast_client_addr (GstRTSPStream * stream, const GstRTSPTransport * tr) { From c747711ac5562e53f90ed96e87776a2e6b9806ba Mon Sep 17 00:00:00 2001 From: Guiqin Zou Date: Fri, 11 Sep 2020 15:46:41 +0200 Subject: [PATCH 1735/1776] rtsp-media: Get rates only on sender streams When play a media with both sender and receiver stream, like ONVIF back channel audio in, gst_rtsp_media_get_rates call gst_rtsp_stream_get_rates for each stream to set the rates. But gst_rtsp_stream_get_rates return false for the receiver steam, which lead a g_assert crash. Instead to get rates on all streams, now just get rates on sender streams. Part-of: --- gst/rtsp-server/rtsp-media.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 8159697c8e..7a7a2f12e6 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2709,7 +2709,8 @@ gst_rtsp_media_get_rates (GstRTSPMedia * media, gdouble * rate, g_assert (priv->streams->len > 0); for (i = 0; i < priv->streams->len; i++) { stream = g_ptr_array_index (priv->streams, i); - if (gst_rtsp_stream_is_complete (stream)) { + if (gst_rtsp_stream_is_complete (stream) + && gst_rtsp_stream_is_sender (stream)) { if (gst_rtsp_stream_get_rates (stream, rate, applied_rate)) { if (first_stream) { save_rate = *rate; From 1589cb737b1c1b805009bc2d840e65189242780b Mon Sep 17 00:00:00 2001 From: David Phung Date: Mon, 28 Sep 2020 22:03:47 +0200 Subject: [PATCH 1736/1776] rtsp-media: Plug memory leak The get-storage signal of rtpbin increases the ref count of the storage. So we have to unref it after usage. Part-of: --- gst/rtsp-server/rtsp-media.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 7a7a2f12e6..eb9ead1f13 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1662,6 +1662,8 @@ update_stream_storage_size (GstRTSPMedia * media, GstRTSPStream * stream, size_time = (media->priv->latency + 50) * GST_MSECOND; g_object_set (storage, "size-time", size_time, NULL); + + g_object_unref (storage); } } From 6a1e121a54898ce22f418a1bbaf02090ad6e6199 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sun, 27 Sep 2020 20:09:22 +0900 Subject: [PATCH 1737/1776] examples: Add an example for loop playback This demo example shows a way of file loop playback of a given source. Note that client seek request is not properly implemented yet. Part-of: --- examples/meson.build | 1 + examples/test-replay-server.c | 931 ++++++++++++++++++++++++++++++++++ examples/test-replay-server.h | 36 ++ 3 files changed, 968 insertions(+) create mode 100644 examples/test-replay-server.c create mode 100644 examples/test-replay-server.h diff --git a/examples/meson.build b/examples/meson.build index 2bacd48274..9352f4ea58 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -15,6 +15,7 @@ examples = [ 'test-readme', 'test-record-auth', 'test-record', + 'test-replay-server', 'test-sdp', 'test-uri', 'test-video', diff --git a/examples/test-replay-server.c b/examples/test-replay-server.c new file mode 100644 index 0000000000..493ca7ede5 --- /dev/null +++ b/examples/test-replay-server.c @@ -0,0 +1,931 @@ +/* GStreamer + * Copyright (C) 2019 Mathieu Duponchelle + * Copyright (C) 2020 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +#include "test-replay-server.h" + +GST_DEBUG_CATEGORY_STATIC (replay_server_debug); +#define GST_CAT_DEFAULT (replay_server_debug) + +static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw"); +static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw"); + +static GList + * gst_rtsp_media_factory_replay_get_demuxers (GstRTSPMediaFactoryReplay * + factory); +static GList + * gst_rtsp_media_factory_replay_get_payloaders (GstRTSPMediaFactoryReplay * + factory); +static GList + * gst_rtsp_media_factory_replay_get_decoders (GstRTSPMediaFactoryReplay * + factory); + +typedef struct +{ + GstPad *srcpad; + gulong block_id; +} GstReplayBinPad; + +static void +gst_replay_bin_pad_unblock_and_free (GstReplayBinPad * pad) +{ + if (pad->srcpad && pad->block_id) { + GST_DEBUG_OBJECT (pad->srcpad, "Unblock"); + gst_pad_remove_probe (pad->srcpad, pad->block_id); + pad->block_id = 0; + } + + gst_clear_object (&pad->srcpad); + g_free (pad); +} + +/* NOTE: this bin implementation is almost completely taken from rtsp-media-factory-uri + * but this example doesn't use the GstRTSPMediaFactoryURI object so that + * we can handle events and messages ourselves. + * Specifically, + * - Handle segment-done message for looping given source + * - Drop all incoming seek event because client seek is not implemented + * and do initial segment seeking on no-more-pads signal + */ +struct _GstReplayBin +{ + GstBin parent; + + gint64 num_loops; + + GstCaps *raw_vcaps; + GstCaps *raw_acaps; + + guint pt; + + /* without ref */ + GstElement *uridecodebin; + GstElement *inner_bin; + + /* holds ref */ + GstRTSPMediaFactoryReplay *factory; + + GMutex lock; + + GList *srcpads; +}; + +static void gst_replay_bin_dispose (GObject * object); +static void gst_replay_bin_finalize (GObject * object); +static void gst_replay_bin_handle_message (GstBin * bin, GstMessage * message); + +static gboolean autoplug_continue_cb (GstElement * dbin, GstPad * pad, + GstCaps * caps, GstReplayBin * self); +static void pad_added_cb (GstElement * dbin, GstPad * pad, GstReplayBin * self); +static void no_more_pads_cb (GstElement * uribin, GstReplayBin * self); + +#define gst_replay_bin_parent_class bin_parent_class +G_DEFINE_TYPE (GstReplayBin, gst_replay_bin, GST_TYPE_BIN); + +static void +gst_replay_bin_class_init (GstReplayBinClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstBinClass *bin_class = GST_BIN_CLASS (klass); + + gobject_class->dispose = gst_replay_bin_dispose; + gobject_class->finalize = gst_replay_bin_finalize; + + bin_class->handle_message = GST_DEBUG_FUNCPTR (gst_replay_bin_handle_message); +} + +static void +gst_replay_bin_init (GstReplayBin * self) +{ + self->raw_vcaps = gst_static_caps_get (&raw_video_caps); + self->raw_acaps = gst_static_caps_get (&raw_audio_caps); + + self->uridecodebin = gst_element_factory_make ("uridecodebin", NULL); + if (!self->uridecodebin) { + GST_ERROR_OBJECT (self, "uridecodebin is unavailable"); + return; + } + + /* our bin will dynamically expose payloaded pads */ + self->inner_bin = gst_bin_new ("dynpay0"); + gst_bin_add (GST_BIN_CAST (self), self->inner_bin); + gst_bin_add (GST_BIN_CAST (self->inner_bin), self->uridecodebin); + + g_signal_connect (self->uridecodebin, "autoplug-continue", + G_CALLBACK (autoplug_continue_cb), self); + g_signal_connect (self->uridecodebin, "pad-added", + G_CALLBACK (pad_added_cb), self); + g_signal_connect (self->uridecodebin, "no-more-pads", + G_CALLBACK (no_more_pads_cb), self); + + self->pt = 96; + + g_mutex_init (&self->lock); +} + +static void +gst_replay_bin_dispose (GObject * object) +{ + GstReplayBin *self = GST_REPLAY_BIN (object); + + GST_DEBUG_OBJECT (self, "dispose"); + + gst_clear_caps (&self->raw_vcaps); + gst_clear_caps (&self->raw_acaps); + gst_clear_object (&self->factory); + + if (self->srcpads) { + g_list_free_full (self->srcpads, + (GDestroyNotify) gst_replay_bin_pad_unblock_and_free); + self->srcpads = NULL; + } + + G_OBJECT_CLASS (bin_parent_class)->dispose (object); +} + +static void +gst_replay_bin_finalize (GObject * object) +{ + GstReplayBin *self = GST_REPLAY_BIN (object); + + g_mutex_clear (&self->lock); + + G_OBJECT_CLASS (bin_parent_class)->finalize (object); +} + +static gboolean +send_eos_foreach_srcpad (GstElement * element, GstPad * pad, gpointer user_data) +{ + GST_DEBUG_OBJECT (pad, "Sending EOS to downstream"); + gst_pad_push_event (pad, gst_event_new_eos ()); + + return TRUE; +} + +static void +gst_replay_bin_do_segment_seek (GstElement * element, GstReplayBin * self) +{ + gboolean ret; + + ret = gst_element_seek (element, 1.0, GST_FORMAT_TIME, + GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT, + GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1); + + if (!ret) { + GST_WARNING_OBJECT (self, "segment seeking failed"); + gst_element_foreach_src_pad (element, + (GstElementForeachPadFunc) send_eos_foreach_srcpad, NULL); + } +} + +static void +gst_replay_bin_handle_message (GstBin * bin, GstMessage * message) +{ + GstReplayBin *self = GST_REPLAY_BIN (bin); + + if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_SEGMENT_DONE) { + gboolean next_loop = TRUE; + + GST_DEBUG_OBJECT (self, "Have segment done message"); + + g_mutex_lock (&self->lock); + if (self->num_loops != -1) { + self->num_loops--; + + if (self->num_loops < 1) + next_loop = FALSE; + } + + if (next_loop) { + /* Send seek event from non-streaming thread */ + gst_element_call_async (GST_ELEMENT_CAST (self->uridecodebin), + (GstElementCallAsyncFunc) gst_replay_bin_do_segment_seek, self, NULL); + } else { + gst_element_foreach_src_pad (GST_ELEMENT_CAST (self->uridecodebin), + (GstElementForeachPadFunc) send_eos_foreach_srcpad, NULL); + } + + g_mutex_unlock (&self->lock); + } + + GST_BIN_CLASS (bin_parent_class)->handle_message (bin, message); +} + +static GstElementFactory * +find_payloader (GstReplayBin * self, GstCaps * caps) +{ + GList *list; + GstElementFactory *factory = NULL; + gboolean autoplug_more = FALSE; + GList *demuxers = NULL; + GList *payloaders = NULL; + + demuxers = gst_rtsp_media_factory_replay_get_demuxers (self->factory); + + /* first find a demuxer that can link */ + list = gst_element_factory_list_filter (demuxers, caps, GST_PAD_SINK, FALSE); + + if (list) { + GstStructure *structure = gst_caps_get_structure (caps, 0); + gboolean parsed = FALSE; + gint mpegversion = 0; + + if (!gst_structure_get_boolean (structure, "parsed", &parsed) && + gst_structure_has_name (structure, "audio/mpeg") && + gst_structure_get_int (structure, "mpegversion", &mpegversion) && + (mpegversion == 2 || mpegversion == 4)) { + /* for AAC it's framed=true instead of parsed=true */ + gst_structure_get_boolean (structure, "framed", &parsed); + } + + /* Avoid plugging parsers in a loop. This is not 100% correct, as some + * parsers don't set parsed=true in caps. We should do something like + * decodebin does and track decode chains and elements plugged in those + * chains... + */ + if (parsed) { + GList *walk; + const gchar *klass; + + for (walk = list; walk; walk = walk->next) { + factory = GST_ELEMENT_FACTORY (walk->data); + klass = gst_element_factory_get_metadata (factory, + GST_ELEMENT_METADATA_KLASS); + if (strstr (klass, "Parser")) + /* caps have parsed=true, so skip this parser to avoid loops */ + continue; + + autoplug_more = TRUE; + break; + } + } else { + /* caps don't have parsed=true set and we have a demuxer/parser */ + autoplug_more = TRUE; + } + + gst_plugin_feature_list_free (list); + } + + if (autoplug_more) + /* we have a demuxer, try that one first */ + return NULL; + + payloaders = gst_rtsp_media_factory_replay_get_payloaders (self->factory); + + /* no demuxer try a depayloader */ + list = gst_element_factory_list_filter (payloaders, + caps, GST_PAD_SINK, FALSE); + + if (list == NULL) { + GList *decoders = + gst_rtsp_media_factory_replay_get_decoders (self->factory); + /* no depayloader, try a decoder, we'll get to a payloader for a decoded + * video or audio format, worst case. */ + list = gst_element_factory_list_filter (decoders, + caps, GST_PAD_SINK, FALSE); + + if (list != NULL) { + /* we have a decoder, try that one first */ + gst_plugin_feature_list_free (list); + return NULL; + } + } + + if (list != NULL) { + factory = GST_ELEMENT_FACTORY_CAST (list->data); + g_object_ref (factory); + gst_plugin_feature_list_free (list); + } + + return factory; +} + +static gboolean +autoplug_continue_cb (GstElement * dbin, GstPad * pad, GstCaps * caps, + GstReplayBin * self) +{ + GstElementFactory *factory; + + GST_DEBUG_OBJECT (self, "found pad %s:%s of caps %" GST_PTR_FORMAT, + GST_DEBUG_PAD_NAME (pad), caps); + + if (!(factory = find_payloader (self, caps))) + goto no_factory; + + /* we found a payloader, stop autoplugging so we can plug the + * payloader. */ + GST_DEBUG_OBJECT (self, "found factory %s", + gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory))); + gst_object_unref (factory); + + return FALSE; + +no_factory: + { + /* no payloader, continue autoplugging */ + GST_DEBUG_OBJECT (self, "no payloader found for caps %" GST_PTR_FORMAT, + caps); + return TRUE; + } +} + +static GstPadProbeReturn +replay_bin_sink_probe (GstPad * pad, GstPadProbeInfo * info, + GstReplayBin * self) +{ + GstPadProbeReturn ret = GST_PAD_PROBE_OK; + + if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info))) { + GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK: + /* Ideally this shouldn't happen because we are responsing + * seeking query with non-seekable */ + GST_DEBUG_OBJECT (pad, "Drop seek event"); + ret = GST_PAD_PROBE_DROP; + break; + default: + break; + } + } else if (GST_IS_QUERY (GST_PAD_PROBE_INFO_DATA (info))) { + GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_SEEKING: + { + /* FIXME: client seek is not implemented */ + gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, 0, + GST_CLOCK_TIME_NONE); + ret = GST_PAD_PROBE_HANDLED; + break; + } + case GST_QUERY_SEGMENT: + /* client seeking is not considered in here */ + gst_query_set_segment (query, + 1.0, GST_FORMAT_TIME, 0, GST_CLOCK_TIME_NONE); + ret = GST_PAD_PROBE_HANDLED; + break; + default: + break; + } + } + + return ret; +} + +static GstPadProbeReturn +replay_bin_src_block (GstPad * pad, GstPadProbeInfo * info, GstReplayBin * self) +{ + GST_DEBUG_OBJECT (pad, "Block pad"); + + return GST_PAD_PROBE_OK; +} + +static void +pad_added_cb (GstElement * dbin, GstPad * pad, GstReplayBin * self) +{ + GstElementFactory *factory; + GstElement *payloader; + GstCaps *caps; + GstPad *sinkpad, *srcpad, *ghostpad; + GstPad *dpad = pad; + GstElement *convert; + gchar *padname, *payloader_name; + GstElement *inner_bin = self->inner_bin; + GstReplayBinPad *bin_pad; + + GST_DEBUG_OBJECT (self, "added pad %s:%s", GST_DEBUG_PAD_NAME (pad)); + + /* ref to make refcounting easier later */ + gst_object_ref (pad); + padname = gst_pad_get_name (pad); + + /* get pad caps first, then call get_caps, then fail */ + if ((caps = gst_pad_get_current_caps (pad)) == NULL) + if ((caps = gst_pad_query_caps (pad, NULL)) == NULL) + goto no_caps; + + /* check for raw caps */ + if (gst_caps_can_intersect (caps, self->raw_vcaps)) { + /* we have raw video caps, insert converter */ + convert = gst_element_factory_make ("videoconvert", NULL); + } else if (gst_caps_can_intersect (caps, self->raw_acaps)) { + /* we have raw audio caps, insert converter */ + convert = gst_element_factory_make ("audioconvert", NULL); + } else { + convert = NULL; + } + + if (convert) { + gst_bin_add (GST_BIN_CAST (inner_bin), convert); + gst_element_sync_state_with_parent (convert); + + sinkpad = gst_element_get_static_pad (convert, "sink"); + gst_pad_link (pad, sinkpad); + gst_object_unref (sinkpad); + + /* unref old pad, we reffed before */ + gst_object_unref (pad); + + /* continue with new pad and caps */ + pad = gst_element_get_static_pad (convert, "src"); + if ((caps = gst_pad_get_current_caps (pad)) == NULL) + if ((caps = gst_pad_query_caps (pad, NULL)) == NULL) + goto no_caps; + } + + if (!(factory = find_payloader (self, caps))) + goto no_factory; + + gst_caps_unref (caps); + + /* we have a payloader now */ + GST_DEBUG_OBJECT (self, "found payloader factory %s", + gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory))); + + payloader_name = g_strdup_printf ("pay_%s", padname); + payloader = gst_element_factory_create (factory, payloader_name); + g_free (payloader_name); + if (payloader == NULL) + goto no_payloader; + + g_object_set (payloader, "pt", self->pt, NULL); + self->pt++; + + if (g_object_class_find_property (G_OBJECT_GET_CLASS (payloader), + "buffer-list")) + g_object_set (payloader, "buffer-list", TRUE, NULL); + + /* add the payloader to the pipeline */ + gst_bin_add (GST_BIN_CAST (inner_bin), payloader); + gst_element_sync_state_with_parent (payloader); + + /* link the pad to the sinkpad of the payloader */ + sinkpad = gst_element_get_static_pad (payloader, "sink"); + gst_pad_link (pad, sinkpad); + gst_object_unref (pad); + + /* Add pad probe to handle events */ + gst_pad_add_probe (sinkpad, + GST_PAD_PROBE_TYPE_EVENT_UPSTREAM | GST_PAD_PROBE_TYPE_QUERY_UPSTREAM, + (GstPadProbeCallback) replay_bin_sink_probe, self, NULL); + gst_object_unref (sinkpad); + + /* block data for initial segment seeking */ + bin_pad = g_new0 (GstReplayBinPad, 1); + + /* Move owenership of pad to this struct */ + bin_pad->srcpad = gst_object_ref (dpad); + bin_pad->block_id = + gst_pad_add_probe (dpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, + (GstPadProbeCallback) replay_bin_src_block, self, NULL); + g_mutex_lock (&self->lock); + self->srcpads = g_list_append (self->srcpads, bin_pad); + g_mutex_unlock (&self->lock); + + /* now expose the srcpad of the payloader as a ghostpad with the same name + * as the uridecodebin pad name. */ + srcpad = gst_element_get_static_pad (payloader, "src"); + ghostpad = gst_ghost_pad_new (padname, srcpad); + gst_object_unref (srcpad); + g_free (padname); + + gst_pad_set_active (ghostpad, TRUE); + gst_element_add_pad (inner_bin, ghostpad); + + return; + + /* ERRORS */ +no_caps: + { + GST_WARNING ("could not get caps from pad"); + g_free (padname); + gst_object_unref (pad); + return; + } +no_factory: + { + GST_DEBUG ("no payloader found"); + g_free (padname); + gst_caps_unref (caps); + gst_object_unref (pad); + return; + } +no_payloader: + { + GST_ERROR ("could not create payloader from factory"); + g_free (padname); + gst_caps_unref (caps); + gst_object_unref (pad); + return; + } +} + +static void +gst_replay_bin_do_initial_segment_seek (GstElement * element, + GstReplayBin * self) +{ + gboolean ret; + GstQuery *query; + gboolean seekable; + + query = gst_query_new_seeking (GST_FORMAT_TIME); + ret = gst_element_query (element, query); + + if (!ret) { + GST_WARNING_OBJECT (self, "Cannot query seeking"); + gst_query_unref (query); + goto done; + } + + gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL); + gst_query_unref (query); + + if (!seekable) { + GST_WARNING_OBJECT (self, "Source is not seekable"); + ret = FALSE; + goto done; + } + + ret = gst_element_seek (element, 1.0, GST_FORMAT_TIME, + GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH, + GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1); + + if (!ret) + GST_WARNING_OBJECT (self, "segment seeking failed"); + +done: + /* Unblock all pads then */ + g_mutex_lock (&self->lock); + if (self->srcpads) { + g_list_free_full (self->srcpads, + (GDestroyNotify) gst_replay_bin_pad_unblock_and_free); + self->srcpads = NULL; + } + g_mutex_unlock (&self->lock); + + if (!ret) { + GST_WARNING_OBJECT (self, "Sending eos to all pads"); + gst_element_foreach_src_pad (element, + (GstElementForeachPadFunc) send_eos_foreach_srcpad, NULL); + } +} + +static void +no_more_pads_cb (GstElement * uribin, GstReplayBin * self) +{ + GST_DEBUG_OBJECT (self, "no-more-pads"); + gst_element_no_more_pads (GST_ELEMENT_CAST (self->inner_bin)); + + /* Flush seeking from streaming thread might not be good idea. + * Do this from another (non-streaming) thread */ + gst_element_call_async (GST_ELEMENT_CAST (self->uridecodebin), + (GstElementCallAsyncFunc) gst_replay_bin_do_initial_segment_seek, + self, NULL); +} + +static GstElement * +gst_replay_bin_new (const gchar * uri, gint64 num_loops, + GstRTSPMediaFactoryReplay * factory, const gchar * name) +{ + GstReplayBin *self; + + g_return_val_if_fail (uri != NULL, NULL); + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL); + + if (!name) + name = "GstRelayBin"; + + self = GST_REPLAY_BIN (g_object_new (GST_TYPE_REPLAY_BIN, + "name", name, NULL)); + + if (!self->uridecodebin) { + gst_object_unref (self); + return NULL; + } + + g_object_set (self->uridecodebin, "uri", uri, NULL); + self->factory = g_object_ref (factory); + self->num_loops = num_loops; + + return GST_ELEMENT_CAST (self); +} + +struct _GstRTSPMediaFactoryReplay +{ + GstRTSPMediaFactory parent; + + gchar *uri; + + GList *demuxers; + GList *payloaders; + GList *decoders; + + gint64 num_loops; +}; + +enum +{ + PROP_0, + PROP_URI, + PROP_NUM_LOOPS, +}; + +#define DEFAULT_NUM_LOOPS (-1) + +static void gst_rtsp_media_factory_replay_get_property (GObject * object, + guint propid, GValue * value, GParamSpec * pspec); +static void gst_rtsp_media_factory_replay_set_property (GObject * object, + guint propid, const GValue * value, GParamSpec * pspec); +static void gst_rtsp_media_factory_replay_finalize (GObject * object); + +static GstElement + * gst_rtsp_media_factory_replay_create_element (GstRTSPMediaFactory * + factory, const GstRTSPUrl * url); + +typedef struct +{ + GList *demux; + GList *payload; + GList *decode; +} FilterData; + +static gboolean +payloader_filter (GstPluginFeature * feature, FilterData * self); + +#define gst_rtsp_media_factory_replay_parent_class parent_class +G_DEFINE_TYPE (GstRTSPMediaFactoryReplay, + gst_rtsp_media_factory_replay, GST_TYPE_RTSP_MEDIA_FACTORY); + +static void +gst_rtsp_media_factory_replay_class_init (GstRTSPMediaFactoryReplayClass + * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstRTSPMediaFactoryClass *mf_class = GST_RTSP_MEDIA_FACTORY_CLASS (klass); + + gobject_class->get_property = gst_rtsp_media_factory_replay_get_property; + gobject_class->set_property = gst_rtsp_media_factory_replay_set_property; + gobject_class->finalize = gst_rtsp_media_factory_replay_finalize; + + g_object_class_install_property (gobject_class, PROP_URI, + g_param_spec_string ("uri", "URI", + "The URI of the resource to stream", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_NUM_LOOPS, + g_param_spec_int64 ("num-loops", "Num Loops", + "The number of loops (-1 = infiniate)", -1, G_MAXINT64, + DEFAULT_NUM_LOOPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + mf_class->create_element = + GST_DEBUG_FUNCPTR (gst_rtsp_media_factory_replay_create_element); +} + +static void +gst_rtsp_media_factory_replay_init (GstRTSPMediaFactoryReplay * self) +{ + FilterData data = { NULL, }; + + /* get the feature list using the filter */ + gst_registry_feature_filter (gst_registry_get (), (GstPluginFeatureFilter) + payloader_filter, FALSE, &data); + + /* sort */ + self->demuxers = + g_list_sort (data.demux, gst_plugin_feature_rank_compare_func); + self->payloaders = + g_list_sort (data.payload, gst_plugin_feature_rank_compare_func); + self->decoders = + g_list_sort (data.decode, gst_plugin_feature_rank_compare_func); + + self->num_loops = DEFAULT_NUM_LOOPS; +} + +static void +gst_rtsp_media_factory_replay_get_property (GObject * object, guint propid, + GValue * value, GParamSpec * pspec) +{ + GstRTSPMediaFactoryReplay *self = GST_RTSP_MEDIA_FACTORY_REPLAY (object); + + switch (propid) { + case PROP_URI: + g_value_take_string (value, self->uri); + break; + case PROP_NUM_LOOPS: + g_value_set_int64 (value, self->num_loops); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static void +gst_rtsp_media_factory_replay_set_property (GObject * object, guint propid, + const GValue * value, GParamSpec * pspec) +{ + GstRTSPMediaFactoryReplay *self = GST_RTSP_MEDIA_FACTORY_REPLAY (object); + + switch (propid) { + case PROP_URI: + g_free (self->uri); + self->uri = g_value_dup_string (value); + break; + case PROP_NUM_LOOPS: + self->num_loops = g_value_get_int64 (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); + } +} + +static void +gst_rtsp_media_factory_replay_finalize (GObject * object) +{ + GstRTSPMediaFactoryReplay *self = GST_RTSP_MEDIA_FACTORY_REPLAY (object); + + g_free (self->uri); + + gst_plugin_feature_list_free (self->demuxers); + gst_plugin_feature_list_free (self->payloaders); + gst_plugin_feature_list_free (self->decoders); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static GstElement * +gst_rtsp_media_factory_replay_create_element (GstRTSPMediaFactory * factory, + const GstRTSPUrl * url) +{ + GstRTSPMediaFactoryReplay *self = GST_RTSP_MEDIA_FACTORY_REPLAY (factory); + + return gst_replay_bin_new (self->uri, self->num_loops, self, + "GstRTSPMediaFactoryReplay"); +} + +static gboolean +payloader_filter (GstPluginFeature * feature, FilterData * data) +{ + const gchar *klass; + GstElementFactory *fact; + GList **list = NULL; + + /* we only care about element factories */ + if (G_UNLIKELY (!GST_IS_ELEMENT_FACTORY (feature))) + return FALSE; + + if (gst_plugin_feature_get_rank (feature) < GST_RANK_MARGINAL) + return FALSE; + + fact = GST_ELEMENT_FACTORY_CAST (feature); + + klass = gst_element_factory_get_metadata (fact, GST_ELEMENT_METADATA_KLASS); + + if (strstr (klass, "Decoder")) + list = &data->decode; + else if (strstr (klass, "Demux")) + list = &data->demux; + else if (strstr (klass, "Parser") && strstr (klass, "Codec")) + list = &data->demux; + else if (strstr (klass, "Payloader") && strstr (klass, "RTP")) + list = &data->payload; + + if (list) { + GST_LOG ("adding %s", GST_OBJECT_NAME (fact)); + *list = g_list_prepend (*list, gst_object_ref (fact)); + } + + return FALSE; +} + +static GList * +gst_rtsp_media_factory_replay_get_demuxers (GstRTSPMediaFactoryReplay * factory) +{ + return factory->demuxers; +} + +static GList * +gst_rtsp_media_factory_replay_get_payloaders (GstRTSPMediaFactoryReplay * + factory) +{ + return factory->payloaders; +} + +static GList * +gst_rtsp_media_factory_replay_get_decoders (GstRTSPMediaFactoryReplay * factory) +{ + return factory->decoders; +} + +static GstRTSPMediaFactory * +gst_rtsp_media_factory_replay_new (const gchar * uri, gint64 num_loops) +{ + GstRTSPMediaFactory *factory; + + factory = + GST_RTSP_MEDIA_FACTORY (g_object_new + (GST_TYPE_RTSP_MEDIA_FACTORY_REPLAY, "uri", uri, "num-loops", num_loops, + NULL)); + + return factory; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + GOptionContext *optctx; + GError *error = NULL; + gchar *service; + gchar *uri = NULL; + gint64 num_loops = -1; + GOptionEntry options[] = { + {"num-loops", 0, 0, G_OPTION_ARG_INT64, &num_loops, + "The number of loops (default = -1, infinate)", NULL}, + {NULL} + }; + + optctx = g_option_context_new ("RTSP Replay Server"); + g_option_context_add_main_entries (optctx, options, NULL); + g_option_context_add_group (optctx, gst_init_get_option_group ()); + if (!g_option_context_parse (optctx, &argc, &argv, &error)) { + g_printerr ("Error parsing options: %s\n", error->message); + g_option_context_free (optctx); + g_clear_error (&error); + return -1; + } + if (argc < 2) { + g_print ("%s\n", g_option_context_get_help (optctx, TRUE, NULL)); + return 1; + } + + g_option_context_free (optctx); + + /* check if URI is valid, otherwise convert filename to URI if it's a file */ + if (gst_uri_is_valid (argv[1])) { + uri = g_strdup (argv[1]); + } else if (g_file_test (argv[1], G_FILE_TEST_EXISTS)) { + uri = gst_filename_to_uri (argv[1], NULL); + } else { + g_printerr ("Unrecognised command line argument '%s'.\n" + "Please pass an URI or file as argument!\n", argv[1]); + return -1; + } + + if (num_loops < -1 || num_loops == 0) { + g_printerr ("num-loop should be non-zero or -1"); + return -1; + } + + GST_DEBUG_CATEGORY_INIT (replay_server_debug, "replay-server", 0, + "RTSP replay server"); + + if (num_loops != -1) + g_print ("Run loop %" G_GINT64_FORMAT " times\n", num_loops); + + loop = g_main_loop_new (NULL, FALSE); + + server = gst_rtsp_server_new (); + + mounts = gst_rtsp_server_get_mount_points (server); + factory = gst_rtsp_media_factory_replay_new (uri, num_loops); + g_free (uri); + + gst_rtsp_mount_points_add_factory (mounts, "/test", factory); + + g_object_unref (mounts); + + gst_rtsp_server_attach (server, NULL); + + service = gst_rtsp_server_get_service (server); + g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", service); + g_free (service); + g_main_loop_run (loop); + + return 0; +} diff --git a/examples/test-replay-server.h b/examples/test-replay-server.h new file mode 100644 index 0000000000..1204775fbe --- /dev/null +++ b/examples/test-replay-server.h @@ -0,0 +1,36 @@ +/* GStreamer + * Copyright (C) 2019 Mathieu Duponchelle + * Copyright (C) 2020 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_REPLAY_BIN (gst_replay_bin_get_type ()) +G_DECLARE_FINAL_TYPE (GstReplayBin, gst_replay_bin, GST, REPLAY_BIN, GstBin); + +#define GST_TYPE_RTSP_MEDIA_FACTORY_REPLAY (gst_rtsp_media_factory_replay_get_type ()) +G_DECLARE_FINAL_TYPE (GstRTSPMediaFactoryReplay, + gst_rtsp_media_factory_replay, GST, RTSP_MEDIA_FACTORY_REPLAY, + GstRTSPMediaFactory); + +G_END_DECLS From a446ba4fb06a5d8ffb532eb9a4e86dbadcc5b7fc Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 6 Oct 2020 00:04:17 +0200 Subject: [PATCH 1738/1776] rtsp-stream: collect rtp info when blocking We don't unblock the stream anymore before replying to the play request (883ddc72bb5bc57c95a9e167814d1ac53fe1b443), so the sinks don't have a last-sample after potentially flush seeking. seek_trickmode waits for preroll however, which means the stream will block and wait for a first buffer. Subsequent calls to get_rtpinfo() can thus make use of the information. See https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/115 Part-of: --- gst/rtsp-server/rtsp-stream.c | 59 +++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 323076585e..5da7105a4e 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -214,7 +214,12 @@ struct _GstRTSPStreamPrivate GstRTSPPublishClockMode publish_clock_mode; GThreadPool *send_pool; - guint32 last_seqnum; + + /* Used to provide accurate rtpinfo when the stream is blocking */ + gboolean blocked_buffer; + guint32 blocked_seqnum; + guint32 blocked_rtptime; + GstClockTime blocked_running_time; }; #define DEFAULT_CONTROL NULL @@ -4285,6 +4290,25 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, } else { gst_sample_unref (last_sample); } + } else if (priv->blocking) { + if (seq) { + if (!priv->blocked_buffer) + goto stats; + *seq = priv->blocked_seqnum; + } + + if (rtptime) { + if (!priv->blocked_buffer) + goto stats; + *rtptime = priv->blocked_rtptime; + } + + if (running_time) { + if (!GST_CLOCK_TIME_IS_VALID (priv->blocked_running_time)) + goto stats; + *running_time = priv->blocked_running_time; + } + goto done; } } @@ -5194,6 +5218,7 @@ pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) GstRTSPStream *stream; GstBuffer *buffer = NULL; GstPadProbeReturn ret = GST_PAD_PROBE_OK; + GstEvent *event; stream = user_data; priv = stream->priv; @@ -5201,11 +5226,27 @@ pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) g_mutex_lock (&priv->lock); if ((info->type & GST_PAD_PROBE_TYPE_BUFFER)) { + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + buffer = gst_pad_probe_info_get_buffer (info); + if (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp)) { + priv->blocked_buffer = TRUE; + priv->blocked_seqnum = gst_rtp_buffer_get_seq (&rtp); + priv->blocked_rtptime = gst_rtp_buffer_get_timestamp (&rtp); + gst_rtp_buffer_unmap (&rtp); + } priv->position = GST_BUFFER_TIMESTAMP (buffer); } else if ((info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST)) { + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + GstBufferList *list = gst_pad_probe_info_get_buffer_list (info); buffer = gst_buffer_list_get (list, 0); + if (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp)) { + priv->blocked_buffer = TRUE; + priv->blocked_seqnum = gst_rtp_buffer_get_seq (&rtp); + priv->blocked_rtptime = gst_rtp_buffer_get_timestamp (&rtp); + gst_rtp_buffer_unmap (&rtp); + } priv->position = GST_BUFFER_TIMESTAMP (buffer); } else if ((info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)) { if (GST_EVENT_TYPE (info->data) == GST_EVENT_GAP) { @@ -5219,6 +5260,16 @@ pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) g_assert_not_reached (); } + event = gst_pad_get_sticky_event (pad, GST_EVENT_SEGMENT, 0); + if (event) { + const GstSegment *segment; + + gst_event_parse_segment (event, &segment); + priv->blocked_running_time = + gst_segment_to_stream_time (segment, GST_FORMAT_TIME, priv->position); + gst_event_unref (event); + } + priv->blocking = TRUE; GST_DEBUG_OBJECT (pad, "Now blocking"); @@ -5257,6 +5308,8 @@ set_blocked (GstRTSPStream * stream, gboolean blocked) continue; if (priv->send_src[i]) { priv->blocking = FALSE; + priv->blocked_buffer = FALSE; + priv->blocked_running_time = GST_CLOCK_TIME_NONE; priv->blocked_id[i] = gst_pad_add_probe (priv->send_src[i], GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | @@ -6146,8 +6199,8 @@ gst_rtsp_stream_set_rate_control (GstRTSPStream * stream, gboolean enabled) if (stream->priv->appsink[0]) g_object_set (stream->priv->appsink[0], "sync", enabled, NULL); if (stream->priv->payloader - && g_object_class_find_property (G_OBJECT_GET_CLASS (stream->priv-> - payloader), "onvif-no-rate-control")) + && g_object_class_find_property (G_OBJECT_GET_CLASS (stream-> + priv->payloader), "onvif-no-rate-control")) g_object_set (stream->priv->payloader, "onvif-no-rate-control", !enabled, NULL); if (stream->priv->session) { From 6d319f8e4914909e43f737a13c4f3a464f406655 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 8 Oct 2020 22:17:16 +0200 Subject: [PATCH 1739/1776] rtsp-stream: make use of blocked_running_time in query_position When blocking, the sink element will not have received a buffer yet and the position query will fail. Instead, we make use of the running time of the buffer we blocked on. Part-of: --- gst/rtsp-server/rtsp-stream.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 5da7105a4e..7585a0c1db 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -5428,6 +5428,13 @@ gst_rtsp_stream_query_position (GstRTSPStream * stream, gint64 * position) priv = stream->priv; g_mutex_lock (&priv->lock); + + if (priv->blocking && GST_CLOCK_TIME_IS_VALID (priv->blocked_running_time)) { + *position = priv->blocked_running_time; + g_mutex_unlock (&priv->lock); + return TRUE; + } + /* depending on the transport type, it should query corresponding sink */ if (priv->configured_protocols & GST_RTSP_LOWER_TRANS_UDP) sink = priv->udpsink[0]; From 5029335dcb088b44f6f2dd090994888beeb9b37b Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 8 Oct 2020 23:45:24 +0200 Subject: [PATCH 1740/1776] git: use our standard pre commit hook Part-of: --- hooks/pre-commit.hook | 83 +++++++++++++++++++++++++++++++++++++++++++ meson.build | 3 ++ 2 files changed, 86 insertions(+) create mode 100755 hooks/pre-commit.hook diff --git a/hooks/pre-commit.hook b/hooks/pre-commit.hook new file mode 100755 index 0000000000..6f177402b3 --- /dev/null +++ b/hooks/pre-commit.hook @@ -0,0 +1,83 @@ +#!/bin/sh +# +# Check that the code follows a consistent code style +# + +# Check for existence of indent, and error out if not present. +# On some *bsd systems the binary seems to be called gnunindent, +# so check for that first. + +version=`gnuindent --version 2>/dev/null` +if test "x$version" = "x"; then + version=`gindent --version 2>/dev/null` + if test "x$version" = "x"; then + version=`indent --version 2>/dev/null` + if test "x$version" = "x"; then + echo "GStreamer git pre-commit hook:" + echo "Did not find GNU indent, please install it before continuing." + exit 1 + else + INDENT=indent + fi + else + INDENT=gindent + fi +else + INDENT=gnuindent +fi + +case `$INDENT --version` in + GNU*) + ;; + default) + echo "GStreamer git pre-commit hook:" + echo "Did not find GNU indent, please install it before continuing." + echo "(Found $INDENT, but it doesn't seem to be GNU indent)" + exit 1 + ;; +esac + +INDENT_PARAMETERS="--braces-on-if-line \ + --case-brace-indentation0 \ + --case-indentation2 \ + --braces-after-struct-decl-line \ + --line-length80 \ + --no-tabs \ + --cuddle-else \ + --dont-line-up-parentheses \ + --continuation-indentation4 \ + --honour-newlines \ + --tab-size8 \ + --indent-level2 \ + --leave-preprocessor-space" + +echo "--Checking style--" +for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "\.c$"` ; do + # nf is the temporary checkout. This makes sure we check against the + # revision in the index (and not the checked out version). + nf=`git checkout-index --temp ${file} | cut -f 1` + newfile=`mktemp /tmp/${nf}.XXXXXX` || exit 1 + $INDENT ${INDENT_PARAMETERS} \ + $nf -o $newfile 2>> /dev/null + # FIXME: Call indent twice as it tends to do line-breaks + # different for every second call. + $INDENT ${INDENT_PARAMETERS} \ + $newfile 2>> /dev/null + diff -u -p "${nf}" "${newfile}" + r=$? + rm "${newfile}" + rm "${nf}" + if [ $r != 0 ] ; then +echo "=================================================================================================" +echo " Code style error in: $file " +echo " " +echo " Please fix before committing. Don't forget to run git add before trying to commit again. " +echo " If the whole file is to be committed, this should work (run from the top-level directory): " +echo " " +echo " gst-indent $file; git add $file; git commit" +echo " " +echo "=================================================================================================" + exit 1 + fi +done +echo "--Checking style pass--" diff --git a/meson.build b/meson.build index 6bd6d1eebe..821aa3075c 100644 --- a/meson.build +++ b/meson.build @@ -211,3 +211,6 @@ if gst_version_nano == 0 endif configure_file(output: 'config.h', configuration: cdata) + +python3 = import('python').find_installation() +run_command(python3, '-c', 'import shutil; shutil.copy("hooks/pre-commit.hook", ".git/hooks/pre-commit")') From 1730940abd0f6dbdb69b4ab554403b70ac4fe810 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 4 Sep 2020 21:14:35 +0200 Subject: [PATCH 1741/1776] rtsp-media-factory: expose API to disable RTCP This is supported by the RFC, and can be useful on systems where allocating two consecutive ports is problematic, and RTCP is not necessary. Part-of: --- examples/test-launch.c | 5 ++ gst/rtsp-server/rtsp-media-factory.c | 81 +++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 7 ++ gst/rtsp-server/rtsp-media.c | 18 ++++ gst/rtsp-server/rtsp-server-internal.h | 3 + gst/rtsp-server/rtsp-stream.c | 116 ++++++++++++++++--------- tests/check/gst/client.c | 47 ++++++++-- 7 files changed, 232 insertions(+), 45 deletions(-) diff --git a/examples/test-launch.c b/examples/test-launch.c index 1675591bae..b21df8ed4c 100644 --- a/examples/test-launch.c +++ b/examples/test-launch.c @@ -22,12 +22,16 @@ #include #define DEFAULT_RTSP_PORT "8554" +#define DEFAULT_DISABLE_RTCP FALSE static char *port = (char *) DEFAULT_RTSP_PORT; +static gboolean disable_rtcp = DEFAULT_DISABLE_RTCP; static GOptionEntry entries[] = { {"port", 'p', 0, G_OPTION_ARG_STRING, &port, "Port to listen on (default: " DEFAULT_RTSP_PORT ")", "PORT"}, + {"disable-rtcp", '\0', 0, G_OPTION_ARG_NONE, &disable_rtcp, + "Whether RTCP should be disabled (default false)", NULL}, {NULL} }; @@ -70,6 +74,7 @@ main (int argc, char *argv[]) factory = gst_rtsp_media_factory_new (); gst_rtsp_media_factory_set_launch (factory, argv[1]); gst_rtsp_media_factory_set_shared (factory, TRUE); + gst_rtsp_media_factory_set_enable_rtcp (factory, !disable_rtcp); /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/test", factory); diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index a2d091d4cd..5dd9dc0a1b 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -41,6 +41,7 @@ #include "config.h" #endif +#include "rtsp-server-internal.h" #include "rtsp-media-factory.h" #define GST_RTSP_MEDIA_FACTORY_GET_LOCK(f) (&(GST_RTSP_MEDIA_FACTORY_CAST(f)->priv->lock)) @@ -65,6 +66,7 @@ struct _GstRTSPMediaFactoryPrivate gchar *multicast_iface; guint max_mcast_ttl; gboolean bind_mcast_address; + gboolean enable_rtcp; GstClockTime rtx_time; guint latency; @@ -95,6 +97,7 @@ struct _GstRTSPMediaFactoryPrivate #define DEFAULT_STOP_ON_DISCONNECT TRUE #define DEFAULT_DO_RETRANSMISSION FALSE #define DEFAULT_DSCP_QOS (-1) +#define DEFAULT_ENABLE_RTCP TRUE enum { @@ -113,6 +116,7 @@ enum PROP_MAX_MCAST_TTL, PROP_BIND_MCAST_ADDRESS, PROP_DSCP_QOS, + PROP_ENABLE_RTCP, PROP_LAST }; @@ -247,6 +251,18 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass) DEFAULT_BIND_MCAST_ADDRESS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPMediaFactory:enable-rtcp: + * + * Whether the created media should send and receive RTCP + * + * Since: 1.20 + */ + g_object_class_install_property (gobject_class, PROP_ENABLE_RTCP, + g_param_spec_boolean ("enable-rtcp", "Enable RTCP", + "Whether the created media should send and receive RTCP", + DEFAULT_ENABLE_RTCP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DSCP_QOS, g_param_spec_int ("dscp-qos", "DSCP QoS", "The IP DSCP field to use", -1, 63, @@ -295,6 +311,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS; + priv->enable_rtcp = DEFAULT_ENABLE_RTCP; priv->dscp_qos = DEFAULT_DSCP_QOS; g_mutex_init (&priv->lock); @@ -381,6 +398,10 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid, case PROP_DSCP_QOS: g_value_set_int (value, gst_rtsp_media_factory_get_dscp_qos (factory)); break; + case PROP_ENABLE_RTCP: + g_value_set_boolean (value, + gst_rtsp_media_factory_is_enable_rtcp (factory)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -442,6 +463,10 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid, case PROP_DSCP_QOS: gst_rtsp_media_factory_set_dscp_qos (factory, g_value_get_int (value)); break; + case PROP_ENABLE_RTCP: + gst_rtsp_media_factory_set_enable_rtcp (factory, + g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); } @@ -1686,6 +1711,57 @@ gst_rtsp_media_factory_is_bind_mcast_address (GstRTSPMediaFactory * factory) return result; } +/** + * gst_rtsp_media_factory_set_enable_rtcp: + * @factory: a #GstRTSPMediaFactory + * @enable: the new value + * + * Decide whether the created media should send and receive RTCP + * + * Since: 1.20 + */ +void +gst_rtsp_media_factory_set_enable_rtcp (GstRTSPMediaFactory * factory, + gboolean enable) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv->enable_rtcp = enable; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_is_enable_rtcp: + * @factory: a #GstRTSPMediaFactory + * + * Check if created media will send and receive RTCP + * + * Returns: %TRUE if created media will send and receive RTCP + * + * Since: 1.20 + */ +gboolean +gst_rtsp_media_factory_is_enable_rtcp (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + gboolean result; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + result = priv->enable_rtcp; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return result; +} + static gchar * default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) { @@ -1757,6 +1833,7 @@ default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) GstElement *element, *pipeline; GstRTSPMediaFactoryClass *klass; GType media_gtype; + gboolean enable_rtcp; klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory); @@ -1769,6 +1846,7 @@ default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) GST_RTSP_MEDIA_FACTORY_LOCK (factory); media_gtype = factory->priv->media_gtype; + enable_rtcp = factory->priv->enable_rtcp; GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); /* create a new empty media */ @@ -1776,6 +1854,9 @@ default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url) g_object_new (media_gtype, "element", element, "transport-mode", factory->priv->transport_mode, NULL); + /* We need to call this prior to collecting streams */ + gst_rtsp_media_set_enable_rtcp (media, enable_rtcp); + gst_rtsp_media_collect_streams (media); pipeline = klass->create_pipeline (factory, media); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index dd08498264..8e847fda33 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -258,6 +258,13 @@ void gst_rtsp_media_factory_set_dscp_qos (GstRTSPMediaFactory * GST_RTSP_SERVER_API gint gst_rtsp_media_factory_get_dscp_qos (GstRTSPMediaFactory * factory); +GST_RTSP_SERVER_API +void gst_rtsp_media_factory_set_enable_rtcp (GstRTSPMediaFactory * factory, + gboolean enable); + +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_factory_is_enable_rtcp (GstRTSPMediaFactory * factory); + /* creating the media from the factory and a url */ GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index eb9ead1f13..b22b95fbe0 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -112,6 +112,7 @@ struct _GstRTSPMediaPrivate gchar *multicast_iface; guint max_mcast_ttl; gboolean bind_mcast_address; + gboolean enable_rtcp; gboolean blocked; GstRTSPTransportMode transport_mode; gboolean stop_on_disconnect; @@ -180,6 +181,7 @@ struct _GstRTSPMediaPrivate #define DEFAULT_MAX_MCAST_TTL 255 #define DEFAULT_BIND_MCAST_ADDRESS FALSE #define DEFAULT_DO_RATE_CONTROL TRUE +#define DEFAULT_ENABLE_RTCP TRUE #define DEFAULT_DO_RETRANSMISSION FALSE @@ -492,6 +494,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS; + priv->enable_rtcp = DEFAULT_ENABLE_RTCP; priv->do_rate_control = DEFAULT_DO_RATE_CONTROL; priv->dscp_qos = DEFAULT_DSCP_QOS; priv->expected_async_done = FALSE; @@ -2104,6 +2107,20 @@ gst_rtsp_media_is_bind_mcast_address (GstRTSPMedia * media) return result; } +void +gst_rtsp_media_set_enable_rtcp (GstRTSPMedia * media, gboolean enable) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->enable_rtcp = enable; + g_mutex_unlock (&priv->lock); +} + static GList * _find_payload_types (GstRTSPMedia * media) { @@ -2425,6 +2442,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader, gst_rtsp_stream_set_multicast_iface (stream, priv->multicast_iface); gst_rtsp_stream_set_max_mcast_ttl (stream, priv->max_mcast_ttl); gst_rtsp_stream_set_bind_mcast_address (stream, priv->bind_mcast_address); + gst_rtsp_stream_set_enable_rtcp (stream, priv->enable_rtcp); gst_rtsp_stream_set_profiles (stream, priv->profiles); gst_rtsp_stream_set_protocols (stream, priv->protocols); gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time); diff --git a/gst/rtsp-server/rtsp-server-internal.h b/gst/rtsp-server/rtsp-server-internal.h index 008b7552dc..b5aaefffc7 100644 --- a/gst/rtsp-server/rtsp-server-internal.h +++ b/gst/rtsp-server/rtsp-server-internal.h @@ -58,6 +58,9 @@ gboolean gst_rtsp_stream_transport_check_back_pressure (GstRTSPS gboolean gst_rtsp_stream_is_tcp_receiver (GstRTSPStream * stream); +void gst_rtsp_media_set_enable_rtcp (GstRTSPMedia *media, gboolean enable); +void gst_rtsp_stream_set_enable_rtcp (GstRTSPStream *stream, gboolean enable); + G_END_DECLS #endif /* __GST_RTSP_SERVER_INTERNAL_H__ */ diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 7585a0c1db..3243e59519 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -220,6 +220,9 @@ struct _GstRTSPStreamPrivate guint32 blocked_seqnum; guint32 blocked_rtptime; GstClockTime blocked_running_time; + + /* Whether we should send and receive RTCP */ + gboolean enable_rtcp; }; #define DEFAULT_CONTROL NULL @@ -229,6 +232,7 @@ struct _GstRTSPStreamPrivate #define DEFAULT_MAX_MCAST_TTL 255 #define DEFAULT_BIND_MCAST_ADDRESS FALSE #define DEFAULT_DO_RATE_CONTROL TRUE +#define DEFAULT_ENABLE_RTCP TRUE enum { @@ -328,6 +332,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL; priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS; priv->do_rate_control = DEFAULT_DO_RATE_CONTROL; + priv->enable_rtcp = DEFAULT_ENABLE_RTCP; g_mutex_init (&priv->lock); @@ -1422,6 +1427,7 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, /* Start with random port */ tmp_rtp = 0; + tmp_rtcp = 0; if (use_transport_settings) { if (!multicast) @@ -1453,14 +1459,16 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, } } - rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, - G_SOCKET_PROTOCOL_UDP, NULL); - if (!rtcp_socket) - goto no_udp_protocol; - g_socket_set_multicast_loopback (rtcp_socket, FALSE); + if (priv->enable_rtcp) { + rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, + G_SOCKET_PROTOCOL_UDP, NULL); + if (!rtcp_socket) + goto no_udp_protocol; + g_socket_set_multicast_loopback (rtcp_socket, FALSE); + } - /* try to allocate 2 UDP ports, the RTP port should be an even - * number and the RTCP port should be the next (uneven) port */ + /* try to allocate UDP ports, the RTP port should be an even + * number and the RTCP port (if enabled) should be the next (uneven) port */ again: if (rtp_socket == NULL) { @@ -1496,7 +1504,8 @@ again: if (*server_addr_out) addr = *server_addr_out; else - addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2); + addr = gst_rtsp_address_pool_acquire_address (pool, flags, + priv->enable_rtcp ? 2 : 1); if (addr == NULL) goto no_address; @@ -1556,18 +1565,20 @@ again: g_object_unref (rtp_sockaddr); /* set port */ - tmp_rtcp = tmp_rtp + 1; + if (priv->enable_rtcp) { + tmp_rtcp = tmp_rtp + 1; - rtcp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtcp); - if (!g_socket_bind (rtcp_socket, rtcp_sockaddr, FALSE, NULL)) { - GST_DEBUG_OBJECT (stream, "rctp bind() failed, will try again"); + rtcp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtcp); + if (!g_socket_bind (rtcp_socket, rtcp_sockaddr, FALSE, NULL)) { + GST_DEBUG_OBJECT (stream, "rctp bind() failed, will try again"); + g_object_unref (rtcp_sockaddr); + g_clear_object (&rtp_socket); + if (transport_settings_defined) + goto transport_settings_error; + goto again; + } g_object_unref (rtcp_sockaddr); - g_clear_object (&rtp_socket); - if (transport_settings_defined) - goto transport_settings_error; - goto again; } - g_object_unref (rtcp_sockaddr); if (!addr) { addr = g_slice_new0 (GstRTSPAddress); @@ -1585,15 +1596,21 @@ again: if (multicast && (ct->ttl > 0) && (ct->ttl <= priv->max_mcast_ttl)) { GST_DEBUG ("setting mcast ttl to %d", ct->ttl); g_socket_set_multicast_ttl (rtp_socket, ct->ttl); - g_socket_set_multicast_ttl (rtcp_socket, ct->ttl); + if (rtcp_socket) + g_socket_set_multicast_ttl (rtcp_socket, ct->ttl); } socket_out[0] = rtp_socket; socket_out[1] = rtcp_socket; *server_addr_out = addr; - GST_DEBUG_OBJECT (stream, "allocated address: %s and ports: %d, %d", - addr->address, tmp_rtp, tmp_rtcp); + if (priv->enable_rtcp) { + GST_DEBUG_OBJECT (stream, "allocated address: %s and ports: %d, %d", + addr->address, tmp_rtp, tmp_rtcp); + } else { + GST_DEBUG_OBJECT (stream, "allocated address: %s and port: %d", + addr->address, tmp_rtp); + } g_list_free_full (rejected_addresses, (GDestroyNotify) gst_rtsp_address_free); @@ -1922,14 +1939,18 @@ gst_rtsp_stream_get_server_port (GstRTSPStream * stream, if (family == G_SOCKET_FAMILY_IPV4) { if (server_port && priv->server_addr_v4) { server_port->min = priv->server_addr_v4->port; - server_port->max = - priv->server_addr_v4->port + priv->server_addr_v4->n_ports - 1; + if (priv->enable_rtcp) { + server_port->max = + priv->server_addr_v4->port + priv->server_addr_v4->n_ports - 1; + } } } else { if (server_port && priv->server_addr_v6) { server_port->min = priv->server_addr_v6->port; - server_port->max = - priv->server_addr_v6->port + priv->server_addr_v6->n_ports - 1; + if (priv->enable_rtcp) { + server_port->max = + priv->server_addr_v6->port + priv->server_addr_v6->n_ports - 1; + } } } g_mutex_unlock (&priv->lock); @@ -2262,6 +2283,16 @@ gst_rtsp_stream_is_bind_mcast_address (GstRTSPStream * stream) return result; } +void +gst_rtsp_stream_set_enable_rtcp (GstRTSPStream * stream, gboolean enable) +{ + g_return_if_fail (GST_IS_RTSP_STREAM (stream)); + + g_mutex_lock (&stream->priv->lock); + stream->priv->enable_rtcp = enable; + g_mutex_unlock (&stream->priv->lock); +} + /* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) @@ -3518,10 +3549,10 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport) g_object_set (priv->payloader, "onvif-no-rate-control", !priv->do_rate_control, NULL); - for (i = 0; i < 2; i++) { + for (i = 0; i < (priv->enable_rtcp ? 2 : 1); i++) { gboolean link_tee = FALSE; /* For the sender we create this bit of pipeline for both - * RTP and RTCP. + * RTP and RTCP (when enabled). * Initially there will be only one active transport for * the stream, so the pipeline will look like this: * @@ -3674,9 +3705,9 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * "RTP caps: %" GST_PTR_FORMAT " RTCP caps: %" GST_PTR_FORMAT, rtp_caps, rtcp_caps); - for (i = 0; i < 2; i++) { + for (i = 0; i < (priv->enable_rtcp ? 2 : 1); i++) { /* For the receiver we create this bit of pipeline for both - * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc + * RTP and RTCP (when enabled). We receive RTP/RTCP on appsrc and udpsrc * and it is all funneled into the rtpbin receive pad. * * @@ -3938,12 +3969,15 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, g_free (name); } - name = g_strdup_printf ("send_rtcp_src_%u", idx); - priv->send_src[1] = gst_element_get_request_pad (rtpbin, name); - g_free (name); - name = g_strdup_printf ("recv_rtcp_sink_%u", idx); - priv->recv_sink[1] = gst_element_get_request_pad (rtpbin, name); - g_free (name); + if (priv->enable_rtcp) { + name = g_strdup_printf ("send_rtcp_src_%u", idx); + priv->send_src[1] = gst_element_get_request_pad (rtpbin, name); + g_free (name); + + name = g_strdup_printf ("recv_rtcp_sink_%u", idx); + priv->recv_sink[1] = gst_element_get_request_pad (rtpbin, name); + g_free (name); + } /* get the session */ g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &priv->session); @@ -4085,7 +4119,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->recv_rtp_src = NULL; } - for (i = 0; i < 2; i++) { + for (i = 0; i < (priv->enable_rtcp ? 2 : 1); i++) { clear_element (bin, &priv->udpsrc_v4[i]); clear_element (bin, &priv->udpsrc_v6[i]); clear_element (bin, &priv->udpqueue[i]); @@ -4115,9 +4149,11 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin, priv->send_src[0] = NULL; } - gst_element_release_request_pad (rtpbin, priv->send_src[1]); - gst_object_unref (priv->send_src[1]); - priv->send_src[1] = NULL; + if (priv->enable_rtcp) { + gst_element_release_request_pad (rtpbin, priv->send_src[1]); + gst_object_unref (priv->send_src[1]); + priv->send_src[1] = NULL; + } g_object_unref (priv->session); priv->session = NULL; @@ -6206,8 +6242,8 @@ gst_rtsp_stream_set_rate_control (GstRTSPStream * stream, gboolean enabled) if (stream->priv->appsink[0]) g_object_set (stream->priv->appsink[0], "sync", enabled, NULL); if (stream->priv->payloader - && g_object_class_find_property (G_OBJECT_GET_CLASS (stream-> - priv->payloader), "onvif-no-rate-control")) + && g_object_class_find_property (G_OBJECT_GET_CLASS (stream->priv-> + payloader), "onvif-no-rate-control")) g_object_set (stream->priv->payloader, "onvif-no-rate-control", !enabled, NULL); if (stream->priv->session) { diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index 6bf654419d..d506f9aed8 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -206,7 +206,7 @@ create_connection (GstRTSPConnection ** conn) } static GstRTSPClient * -setup_client (const gchar * launch_line) +setup_client (const gchar * launch_line, gboolean enable_rtcp) { GstRTSPClient *client; GstRTSPSessionPool *session_pool; @@ -227,6 +227,8 @@ setup_client (const gchar * launch_line) else gst_rtsp_media_factory_set_launch (factory, launch_line); + gst_rtsp_media_factory_set_enable_rtcp (factory, enable_rtcp); + gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); gst_rtsp_client_set_mount_points (client, mount_points); @@ -515,7 +517,7 @@ GST_START_TEST (test_describe) g_object_unref (client); /* simple DESCRIBE for an existing url */ - client = setup_client (NULL); + client = setup_client (NULL, TRUE); fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, "rtsp://localhost/test") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); @@ -688,7 +690,7 @@ GST_START_TEST (test_setup_tcp) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_client (NULL); + client = setup_client (NULL, TRUE); create_connection (&conn); fail_unless (gst_rtsp_client_set_connection (client, conn)); @@ -714,6 +716,40 @@ GST_START_TEST (test_setup_tcp) GST_END_TEST; +GST_START_TEST (test_setup_no_rtcp) +{ + GstRTSPClient *client; + GstRTSPConnection *conn; + GstRTSPMessage request = { 0, }; + gchar *str; + + client = setup_client (NULL, FALSE); + create_connection (&conn); + fail_unless (gst_rtsp_client_set_connection (client, conn)); + + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); + g_free (str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;unicast;client_port=5000-5001"); + + gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL); + /* We want to verify that server_port holds a single number, not a range */ + expected_transport = + "RTP/AVP;unicast;client_port=5000-5001;server_port=[0-9]+;ssrc=.*;mode=\"PLAY\""; + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + + gst_rtsp_message_unset (&request); + + send_teardown (client); + teardown_client (client); +} + +GST_END_TEST; + GST_START_TEST (test_setup_tcp_two_streams_same_channels) { GstRTSPClient *client; @@ -721,7 +757,7 @@ GST_START_TEST (test_setup_tcp_two_streams_same_channels) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_client (NULL); + client = setup_client (NULL, TRUE); create_connection (&conn); fail_unless (gst_rtsp_client_set_connection (client, conn)); @@ -1044,7 +1080,7 @@ test_client_sdp (const gchar * launch_line, guint * bandwidth_val) gchar *str; /* simple DESCRIBE for an existing url */ - client = setup_client (launch_line); + client = setup_client (launch_line, TRUE); fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, "rtsp://localhost/test") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); @@ -2044,6 +2080,7 @@ rtspclient_suite (void) tcase_add_test (tc, test_options); tcase_add_test (tc, test_describe); tcase_add_test (tc, test_setup_tcp); + tcase_add_test (tc, test_setup_no_rtcp); tcase_add_test (tc, test_setup_tcp_two_streams_same_channels); tcase_add_test (tc, test_client_multicast_transport_404); tcase_add_test (tc, test_client_multicast_transport); From e7e0343a5bee0cfa887429d1c7caf23d7d7e2d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 19 Oct 2020 11:25:25 +0300 Subject: [PATCH 1742/1776] meson: update glib minimum version to 2.56 Part-of: --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 821aa3075c..7ffef51ffa 100644 --- a/meson.build +++ b/meson.build @@ -15,7 +15,7 @@ else endif gst_version_is_dev = gst_version_minor % 2 == 1 and gst_version_micro < 90 -glib_req = '>= 2.44.0' +glib_req = '>= 2.56.0' gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor) api_version = '1.0' From 6f336227cd25017933c10da776964a3d4e52bc2f Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Mon, 29 Oct 2018 09:19:33 -0400 Subject: [PATCH 1743/1776] Meson: Use pkg-config generator Part-of: --- gst/rtsp-server/meson.build | 9 +++++++ meson.build | 3 ++- .../gstreamer-rtsp-server-uninstalled.pc.in | 12 ---------- pkgconfig/gstreamer-rtsp-server.pc.in | 11 --------- pkgconfig/meson.build | 24 ------------------- 5 files changed, 11 insertions(+), 48 deletions(-) delete mode 100644 pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in delete mode 100644 pkgconfig/gstreamer-rtsp-server.pc.in delete mode 100644 pkgconfig/meson.build diff --git a/gst/rtsp-server/meson.build b/gst/rtsp-server/meson.build index 6e40cc64de..24d7c39adb 100644 --- a/gst/rtsp-server/meson.build +++ b/gst/rtsp-server/meson.build @@ -66,6 +66,13 @@ gst_rtsp_server = library('gstrtspserver-@0@'.format(api_version), install : true, dependencies : gst_rtsp_server_deps) +pkgconfig.generate(gst_rtsp_server, + libraries : [gst_dep], + subdirs : pkgconfig_subdirs, + name : 'gstreamer-rtsp-server-1.0', + description : 'GStreamer based RTSP server', +) + rtsp_server_gen_sources = [] if build_gir gst_gir_extra_args = gir_init_section + ['--c-include=gst/rtsp-server/rtsp-server.h'] @@ -88,3 +95,5 @@ gst_rtsp_server_dep = declare_dependency(link_with : gst_rtsp_server, include_directories : rtspserver_incs, sources : rtsp_server_gen_sources, dependencies : [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_dep]) + +meson.override_dependency('gstreamer-rtsp-server-1.0', gst_rtsp_server_dep) diff --git a/meson.build b/meson.build index 7ffef51ffa..669286479c 100644 --- a/meson.build +++ b/meson.build @@ -186,6 +186,8 @@ if get_option('default_library') == 'shared' endif plugins = [] +pkgconfig_subdirs = ['gstreamer-1.0'] + subdir('gst') if not get_option('tests').disabled() subdir('tests') @@ -193,7 +195,6 @@ endif if not get_option('examples').disabled() subdir('examples') endif -subdir('pkgconfig') subdir('docs') # Set release date diff --git a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in b/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in deleted file mode 100644 index 38e1df819a..0000000000 --- a/pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -# the standard variables don't make sense for an uninstalled copy -prefix= -exec_prefix= -libdir=@rtspserverlibdir@ -includedir=@abs_top_builddir@ - -Name: gst-rtsp-server -Description: GStreamer based RTSP server -Version: @VERSION@ -Requires: gstreamer-@GST_API_VERSION@ gstreamer-plugins-base-@GST_API_VERSION@ -Libs: -L${libdir} -lgstrtspserver-@GST_API_VERSION@ -Cflags: -I@abs_top_srcdir@ -I@abs_top_builddir@ diff --git a/pkgconfig/gstreamer-rtsp-server.pc.in b/pkgconfig/gstreamer-rtsp-server.pc.in deleted file mode 100644 index 3a1d8206c7..0000000000 --- a/pkgconfig/gstreamer-rtsp-server.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@/gstreamer-@GST_API_VERSION@ - -Name: gst-rtsp-server -Description: GStreamer based RTSP server -Version: @VERSION@ -Requires: gstreamer-@GST_API_VERSION@ gstreamer-base-@GST_API_VERSION@ -Libs: -L${libdir} -lgstrtspserver-@GST_API_VERSION@ -Cflags: -I${includedir} diff --git a/pkgconfig/meson.build b/pkgconfig/meson.build deleted file mode 100644 index 8ed8299514..0000000000 --- a/pkgconfig/meson.build +++ /dev/null @@ -1,24 +0,0 @@ -pkgconf = configuration_data() - -pkgconf.set('prefix', get_option('prefix')) -pkgconf.set('exec_prefix', '${prefix}') -pkgconf.set('libdir', '${prefix}/@0@'.format(get_option('libdir'))) -pkgconf.set('includedir', '${prefix}/@0@'.format(get_option('includedir'))) -pkgconf.set('GST_API_VERSION', api_version) -pkgconf.set('VERSION', gst_version) - -# needed for generating -uninstalled.pc files -pkgconf.set('abs_top_builddir', join_paths(meson.current_build_dir(), '..')) -pkgconf.set('abs_top_srcdir', join_paths(meson.current_source_dir(), '..')) -pkgconf.set('rtspserverlibdir', join_paths(meson.build_root(), gst_rtsp_server.outdir())) - -pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir')) - -configure_file(input : 'gstreamer-rtsp-server.pc.in', - output : 'gstreamer-rtsp-server-1.0.pc', - configuration : pkgconf, - install_dir : pkg_install_dir) - -configure_file(input : 'gstreamer-rtsp-server-uninstalled.pc.in', - output : 'gstreamer-rtsp-server-1.0-uninstalled.pc', - configuration : pkgconf) From 1c8a6af13c24d6676cc311c4fe8ba4f7dfc36a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristofer=20Bj=C3=B6rkstr=C3=B6m?= Date: Wed, 28 Oct 2020 21:48:06 +0100 Subject: [PATCH 1744/1776] media test: Add test for seeking one active stream with a demuxer Add another seek_one_active_stream test but with a demuxer. The demuxer will flush both streams in opposed to the existing test which only flushes the active stream. This will help exposing problems with the prerolling process after a flushing seek. Part-of: --- tests/check/gst/media.c | 48 +++++++++++++++++++++++++++++++++------- tests/check/meson.build | 1 + tests/files/test.avi | Bin 0 -> 385006 bytes 3 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 tests/files/test.avi diff --git a/tests/check/gst/media.c b/tests/check/gst/media.c index 2cb2ba6d52..0284753d7f 100644 --- a/tests/check/gst/media.c +++ b/tests/check/gst/media.c @@ -140,8 +140,8 @@ GST_START_TEST (test_media_seek) GST_END_TEST; -/* case: media is complete and contains two streams but only one is active */ -GST_START_TEST (test_media_seek_one_active_stream) +static void +media_playback_seek_one_active_stream (const gchar * launch_line) { GstRTSPMediaFactory *factory; GstRTSPMedia *media; @@ -160,9 +160,7 @@ GST_START_TEST (test_media_seek_one_active_stream) fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url) == GST_RTSP_OK); - gst_rtsp_media_factory_set_launch (factory, - "( videotestsrc ! rtpvrawpay pt=96 name=pay0 " - " audiotestsrc ! audioconvert ! rtpL16pay name=pay1 )"); + gst_rtsp_media_factory_set_launch (factory, launch_line); media = gst_rtsp_media_factory_construct (factory, url); fail_unless (GST_IS_RTSP_MEDIA (media)); @@ -196,12 +194,12 @@ GST_START_TEST (test_media_seek_one_active_stream) fail_unless (gst_rtsp_stream_seekable (stream2)); fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK); - fail_unless (gst_rtsp_range_parse ("npt=3.0-", &range) == GST_RTSP_OK); + fail_unless (gst_rtsp_range_parse ("npt=3.0-5.0", &range) == GST_RTSP_OK); /* the media is seekable now */ fail_unless (gst_rtsp_media_seek (media, range)); - /* verify that we got the expected range, 'npt=3.0-' */ + /* verify that we got the expected range, 'npt=3.0-5.0' */ range_str = gst_rtsp_media_get_range_string (media, TRUE, GST_RTSP_RANGE_NPT); fail_unless (gst_rtsp_range_parse (range_str, &play_range) == GST_RTSP_OK); fail_unless (play_range->min.seconds == range->min.seconds); @@ -222,6 +220,30 @@ GST_START_TEST (test_media_seek_one_active_stream) gst_rtsp_thread_pool_cleanup (); } +/* case: media is complete and contains two streams but only one is active, + audio & video sources */ +GST_START_TEST (test_media_playback_seek_one_active_stream) +{ + media_playback_seek_one_active_stream + ("( videotestsrc ! rtpvrawpay pt=96 name=pay0 " + " audiotestsrc ! audioconvert ! rtpL16pay name=pay1 )"); +} + +GST_END_TEST; + +/* case: media is complete and contains two streams but only one is active, + demux */ +GST_START_TEST (test_media_playback_demux_seek_one_active_stream) +{ + /* FIXME: this test produces "Failed to push event" error messages in the + * GST_DEBUG logs because the incomplete stream has no sinks */ + media_playback_seek_one_active_stream ("( filesrc location=" + GST_TEST_FILES_PATH "/test.avi !" + " avidemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert !" + " audioresample ! rtpL16pay pt=97 name=pay1" + " demux.video_0 ! queue ! decodebin ! rtpvrawpay pt=96 name=pay0 )"); +} + GST_END_TEST; GST_START_TEST (test_media_seek_no_sinks) @@ -847,12 +869,22 @@ rtspmedia_suite (void) { Suite *s = suite_create ("rtspmedia"); TCase *tc = tcase_create ("general"); + gboolean has_avidemux; suite_add_tcase (s, tc); tcase_set_timeout (tc, 20); + + has_avidemux = gst_registry_check_feature_version (gst_registry_get (), + "avidemux", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); + tcase_add_test (tc, test_media_seek); tcase_add_test (tc, test_media_seek_no_sinks); - tcase_add_test (tc, test_media_seek_one_active_stream); + tcase_add_test (tc, test_media_playback_seek_one_active_stream); + if (has_avidemux) { + tcase_add_test (tc, test_media_playback_demux_seek_one_active_stream); + } else { + GST_INFO ("Skipping test, missing plugins: avidemux"); + } tcase_add_test (tc, test_media); tcase_add_test (tc, test_media_prepare); tcase_add_test (tc, test_media_shared_race_test_unsuspend_vs_set_state_null); diff --git a/tests/check/meson.build b/tests/check/meson.build index 26904307d7..860774af5d 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -17,6 +17,7 @@ test_c_args = [ '-UG_DISABLE_ASSERT', '-UG_DISABLE_CAST_CHECKS', '-DGST_CHECK_TEST_ENVIRONMENT_BEACON="GST_PLUGIN_LOADING_WHITELIST"', + '-DGST_TEST_FILES_PATH="' + meson.current_source_dir() + '/../files"', ] rtsp_server_tests = [ diff --git a/tests/files/test.avi b/tests/files/test.avi new file mode 100644 index 0000000000000000000000000000000000000000..8c83239cd92c7587ee29bf1be03ec80624dfca53 GIT binary patch literal 385006 zcmeHw2~bqonkMh{>x!P9o(cp-5?K@k#B@VsQ85)nN){0m6GcEt5tGFP1rZStL_sVz zWl>x}5D-m7QjtXg6%;U0$U;p)Hc22wnW%oz(NWVg(NQsMH#$#O=DD|~YZ4y!&-cpW zzxCa7P&wcE&v*W1mxH~%bl~q*Y}gKqogH?&$Ns&F3fJ#=ux~^F*Gff2Wy=i}mAI$l zUyOfL|D>W4Gxep)pQr!5Z2aHzr@xl{*Th&^Z&C1s zu73iPKj;7HXVdqDU)aRYqU>kF-l8}CBy{`-ZTbgF7B}&;sWuMz)A;`;uoM6MN#!5L zpZw;h(DWqy6i)wP!oO5hCVmQ4$NwNg{Eh~X|DQYY!!^Nx6VK~j{=Lf4kcfaa6F)QK z|Do_j*YHSpQ*pvU8xw7+olNx@ zdZtdn8G<(h(m_#GPMDjyK0{}vy?-*lwRdFbecg>y9_yECX`9#_Oek*Z9vSX>Q5fgV zGG3%*WbGN9-yj|u>1i%aJhYXmtz}^89+6wyDUtRG%TodzR_ihro4JH!RIx zbM^bz2f+id-hsD(f9boA5Ig|;JNPN!Z_(HPC3pb*c{rEA`HH^h-3euLLNOhi_;gNw z?oEC!O?(0;KW>vBlgSU@=Jub<T+wiy#MaIiHi$f!ie#PT-#|%q2ChA3e6Fg4M-1%gf?Pn3E7>~QZ z(5tD}Mz_HwBQ9>cs_Ood5}t*HP$=~D^!)2z|Ei27$-q?aNKPx;=WG7{PbxmJe zuZhP+Io?zAy~MfK&BNo0nk~=p0!u{Vb9kIvj=K0I>!1avUKzfMyg9&siIeZYz_|-} zYsPr1TM{{xkozgk^gW(G{PbEDHQbBP4+_HLYy&DTz6oFGe030ydvT93($pRx7~$Y? zUsiv9Icj)r^uRfJoT7|pz+1pupnH+)fmHn{syI9^RPeWK%*!^m(~ZL8hEKM}bn-^@ zQqAzV=(LOmz1saRya({OW&^|5h5~h;=uABB$iVgVV>RoFf(n$uQS#;h-crC@({XSR zj|Opd5a&qWcumlYKrfQ@>!|uARB?F!U`tK-)8dU=)R^<}xUCkMMx&qfI~oJ>|DOGMZ4xC@t8Ir)8R*EkX?&$m#97eXsp8Jb!e(X9RrcNK4+5gU6kI_}WLaS=?#uh{xHxUZ}a2(pp~r7LPl`X}Y-f zk(YMi9%XQpyg7ikfVX7*3W$@EA16iCkD`jh^Mdi7q#%}=I8?L`kBg{y>&SBy6f9hd z$F)8liduLmRA^a`$LSsSSsh*7*;aZNk5j+Oj1AwM6_TPQk5iQK40uZcZ%yk(kf#WF zqmchf-#lK>i$E`u_3NnmB~)>E|DfH<_qasUrOc}dkGtGeeW8^1s$GxdJmt4hYe{~I z{THnc{CKU4Uo1{&*q^(DBtF3BQIiv&)pGvZOJ(>f^5y{lMS=eUdJ*VFGo}}*ZvT9) zR41Mjegw}m6>FUh*rM~-7Yp&YN{7Dtdi)NJ7?N{WWW~E%UakcnEpOq++qLJ4I5W7j zAgfUxrzqnY@D}ivtX~0o(QMF*R=9E3U1&+s+e{MY!%Y+v53-XN7fbLwv+UZu^rAcQ zM66$@x>t;3#=>0BQ_NMF{q11-}-K# z7lB?R>(^1$fvDo}{y}(3-QlMiqUF`0c$|7xQ<8!G>Y-{99mu@zpm&q_#NtSjbC-j` z1Kq;;!ua)1@$)ho&-Qa0dishI<@pxMcn1E90{;c{BG8LwOfPc#a-V5fQN2l2hUX8C z>)qIm&uy;pM0i}fMhHt0nU2j^Q}{#MhJ?S$tKQ~vdubfN#Y@?&`1gBqqs(!z{oS4r|?e^@bg z`IOPFn9vLO@orm1eTg-8sF%Ev$0^Eq2D}Bl1-v!e@@OweEy~5w+lQnvc>b98{uYaO zv*&tm1s)gLyLbPm+{=fzC*pCtc6kMeQw0ZZYvXZ)x{(X6<94lG@@&H*!9m6WdA@}*o`L_Oz<&Xq8+7g& z)45On7`;5n=5WHgG$ z#in}Q6P$g$;o}E9u0phJ_r=4J!@(rF(%z`1-lsu!p{fv9@L#Ow|NpB_KlB@gzNygv zmA-v!K`#QmNY<~TssmBQ;r)mUUaNWyovH;FNb<~#1qmyb+>ksQUXCBnoY9+G=V&M1 zaRQI~VgHdZ^C4Dc)OI{h-QkC_-cl{5U8TG;kusjaxeLx+vg;GhU9;ibRhD~Jz4df# z{uqf4RM`5EmGf@5x|uDWXIAvtYUr8=-a0^%-^O`$w5k7`(?CDTymh8;3rbYYwmXL? zgQMil0lWpg1-v!e;)?>GcU@Waczbv#NgqbLF3)Q(wcg(eBdKqqr|O=)PhTKMzOCh8DDO<9jAwA}f^(Pb`UJgbHt0nSsqS|oxe>ctNa|hh^Dh{_ z#ogg?o+Qs~Ih$+6d{=+%(^1$fvDo}{((!}t?aCRF>f`=`RBMrio@b&)S?fZ{7im5^+zPj z1%C{0^~H>ewAZArWRv8*>ghBVo@wi9KYTPvAl844 z=MRQWtOci;lbg8%kGmV~Ww3U{b4MMCAGNF4apR*w16MAIpXcWif8l~joo~9oGB`@! z9Kc%&cxzfOvN@Pg+|)fX3~@FPXG7;W8@lSIpcjE&Bb&y_whK}D+|x$*I+!$kw-G$au6N*ac5bae{qPTX z+~qQ!WK+Cd!Tl6G&Z5#c^R>UN#-=zi)MpfR9MdQ%swBjdgcb6 zKhiEPNn(yPhy^75jtq65Bn2Jd_rEp6kGHMnQGwZ|`eOqt@Hl3r$!X0W4`~EKy~x>? zj|To0_**mPZ-wd3D=T&hP7Lb8^T$h5gB#&SMy|plJdWqkwDC*6l}XW7JkGh&$I$dG zM=x^(kL&r^;$yvW!TZe&dA^V`o`Jumz~7qIxrau2noAQ8ZDnd}8CbeUZQ^n!^gZQ+N$ol3L*X%CfagjyYAC8`IY;zyQr==1@gaV^A;XUg=I4kcM#XsCfabMrB?ccqJiVX{j*>SA@RkDJn%0W~99HWx7Mr<* zWLCC+mVR!p%!K$rh!2FkYP#sApcjE&B|wB*C)Z%0gqE#onm%r z^V-XHB=L?X_@W|pJ5HzxNj=!?A1pFWEMK|h8{+3}c+7E%7PaSbCGva=Wjq7_MS=eU zdJ*VFGo}~46s=0kSj}1CbqCKMep#!S;l63%LwoSJy`Sulb53pcl#s+1mAUR;n&s%~ zQg{|W-YzRE!^|<)Pc3(q!BO(&0Nw)LlJzSY8eKoT7|pz*`D(9I_AVf~pYk4k&14tV81g^h$Kwi8EkxJYnLI~4 zj=#KlWol;Neb-E7_$u<|0RKgS{{ngu=tVQ87mY60>*bwkmufrV`NORA-th5bIg$_( zeP`iY?UU(zYoq-g`0>_zJgQK;ZDz>Mz~dbJO=DK11ZAy!ERR!^@eFticuUr=0KI57 z=tV07&y*i!R4lOBiRX{&y>%QXBXLs9H#|=4>9xo&&+N*b7(6Z@YgG=rSEJOPB)`r3 zbj_G++WD3+u`)PH-WufaZe;P}2KJ(LmYp}OS+b7BwKi>Nj zjCOrd|88M}Jl{eY&%l3C;J<)g1bWeo=|#Y*j8O&=rnKO{H9*=vP zd;WN`#?i=iBZ+BdUzE$l6~)k_ZH$K$>q-Vkx?-k4Vc z9w$lfboz8@$2k}1>p0tZYg#W#IA~)6`B#vCMVI_5h^MO<2BiZK9|-Y*3|-KHQ5|@$uMg0<@#m1) zuJ8QO-yhZU6jdDFk9hY!R+M6?p~0@g<2ri^N%a zXg$2EBL7JlemvIw10iiarpNmrzG$}H(?eV&RzLZpd11DXN0pDL;_$rSbV)zT>!F%| zCds|qm%y@R+7-vVmXMsMhPDN@j+F)R3uE!~-uBVY`g*@Ic$E~7yLxXoSJm3Ld!?~5 z&RFv1fOD6Ea~JRy@YbY|HpxU&zf3LWz{$_#*HeE)vTOX0;Vq$O>Xy6+$F>xa?AX7( z-;YQ*ecb6#Q1PPuc$}%=jCKp_;zcG&o<eJKG<(UhBU>QaAVPj`(FJUc1!NS@JkV z8P9;X6!6xxUi4-_Iw-2j33D^oXXvbi_&|scgnD}!!A_=hskaAu5$Hv-_kdLW5~?`7 zzp=%zPVGVW(_*h0JWlI^`|8Lm;-8je<8f(Au!{a0W0;Z4z_JJa9c`6I&oQ4-HOs=8?f9+%UvDQ12C+BZU?D^*$V`C-|p-IB-Q`0+lA zU53`@59o0i@;F5q&w#fS@Yb|mbmNrA`lVXhCN>8XikrGehPz%A#zCA7#MyY9qF0;^ zU3F8?i)QEfXQuA+sh+2(;_&`~p>LR7gzBm7Op<=n>Xt0Ktr|xUKRS&c&)LIn2jgV( zf%rFgoRu&}>~l+fgiA87dqHJDMw^@HWV|wb6?t=j|DwQufpZs}yJqa%<;r%p>tagI z-yrGpA^O1CZkO)*?8sU?A06LZ-Nd|>$^9b2<4$aPyDlQ}Si*La`q}A{it|C7q-}Qg z@;F5q&w#gpw`A|3X3C$L?ekLgqp0HW{IOT8ug!O5hDu5D(H^bHbql5$Hv-ejQc6geng2A4oWFPCr`G_@&zrkGu2XTlk}}c|E-(aYI6@ zB8?+YJPf=a;KvKt&@nHICBA#=Bp$ct!%6JC;ivs@z^diuUW=t>2 zUmEWoT5jXDD+13S#VM&#@o8Cny;FGH+5XTc_pbP9emj82ecCHSA@D}ivtY0zPb(@*`{;2v=tKP2-dJo@wl~u*N4&;zBTn}lE*2^cm}+sfVZag zBFMjj{3|-;UqL+GYF)-+GnbIe%J$FF&+VWWfnFr**HQILsN(Scf%-zv%?EFn9w_j} zVPzQEjZZN@ygEmE`DBDW+UUwZkAEwQDyil z^5y{lMS=eUdJ*VFGo}|M54--LvwNZAgC}_Y(CfLr$@D%me$y}>clq$8L#D;rdnH+T z+?lSuw@y^%IPW6KZ+q%w@6a%2$P+lq;}m5)1KtAOlJzTQN{^ZC^HTMrsN(SaQGWM| zrenBfqd7^R*@Wizp*Kf4g~Dk3czddsxf^;r?#?8M=Qi1N$zl}Elb(hnJ2O`vrzqnY@RkDJn%221Geca=7DL`B@A0G%6jZdt#M>UoMP4(}g4F~~PIv=Kh@F2dtZKdn3BmofS&G6#PT|BewD*i21m)819(dTZxMO4 z+RUwo5=)zVMj$>A;scErDayBm_}RI+K0q%5y-3!tqw1GX#o_&f=+Ub9YUx;gP&pn~ zs`cg5{gCc?5^FrJLhD&nQ@C&YVqZM&Ou^2!*e@GiTq3#m=j5-Q|Mo#m!>Lp9d<$hf z1OG*V{{ngu=tVQ87qy=qKI~{Iyv8NTXH}1NNjA=Kw96^R^HI$8ij(WNOC@O}b%~O$ zSNT;H$Dj#~Sgq(4Bdk;l8G_7$aK zi07VdeUYa1qQVzl!z0~I#R&&(OtiI@u7@}qh_mSvmZtA6M=tZCx$@+Cv z{SvA;ydSZ)-XMSQ@)^_HB>8CEk1w51A3eZ)Nm5_-gVcW`pBvj3PLj9Q7G3lubd~xN zW;Oo%W5uaywpd*}SQResOr(rwaPES0m+bnS?dPAF`u?c$5mg+X7kCLr?lKMUr@9v4 zalK2$#i{`et4@;oMd`NDO;Pj0awLuT@luXC-__yr#Hm~HxZ~=gfU_UHKZ*R5!BO(& z0Nw)L0^XW!`Do5By>1GUo^iQiJb$chQ}6Te$mTu0hsQLLR3m;~DUl0^XX|i(2`~{`M<%7*L-b`dUuZ;hO9DS9H~d z6s>d6i$E`u_3Nmfr>Nra{=v;ld~UI-=GT4i@i_G)o!r=qckc|6)Fo;XnjU{`c(=Zr zB;MMl_4KWvth-Hj2k`Sov{ZW^c=IHI6{ieeMcy3XzbNouAifCVizbO{l8L5%nOe+& zlb^}2r~Zg!*Z3d9Tb%3ROa1*FPak|OJNDR=p{k;yGXB-#@sEF-KwLjhSoHZi9(ON- zVI6R#>dLVNc-+VQ-0&BxTGI}+;c*vgKiiBIsg~P-&OO`i>4CR^w`PpDj%e3>IA>sK zu{j3MA6xw$Hus8KGd7XvK-n(gN0ZebMrD)ePu2DFZePjZX6zK<=j9u|`6AdE(|T52 zo-d?~XW(xs@VBP*B0YwlsZ(%<0Q%kaG?ykG+RD_{GO%=y$c6l?xtV_j@pRHbQB_Wu zo4GziXQjPA=tZCx&75Au(u@$XuUot(yIzz~r8m^EydLjwNPe_d(_}syx@dsM zz0yoq4J`B8UT25LC1k%@U=^G7=A5B2d=+_ffd8Vve}QusoV#Z1++|wN)hm1zWzoA2 z&mSJKWp)eFKZ>iFc$`<8T2AQNxYUFzc-+FAFD0)X^j7tf^pnhpRqr+1d3wWHqx7~%d zO)HWX4B~OTJGoz3x|LhnHSoBoy(dB*h~A#hSfC7!k~atN7VsAE)@+N5Ouc#A!Y6%^ zWo8SWKh#6GQSrs$!q7N8?xrN|eqf3B?l-sbI1kq>b*@ujamyV%E}=vsZunX-dUiap zV7sd7{*n@&g@sTk^z`)n>tFw>jAy`G3V3T;=T7EB-YDdaMtfQtX)Q8ldB=ecjOxI1 zeSLt=4LY~1Uq|&kMHPql4{rRhRLwip-KBwx$Hg!1%MN!O`zj*o9~6|)S)9t(XS>$m z$Mb)rS6}SRC}+OHMZ&iv@s2M)j(#rH%d3j0!t+tlZISOAaqa0+l5>}Befu(QX=KitCV8Bq zjAy`Gz+19@#cbD`XX^W->PJz<;rT;@%~@_?U@Ek7#^X}0tk?(cnX1{H#^bJERA<^B zIJN8jB|J{zQXT$CTg!2^BOZ5R^TGDeA!aJ`CuMMyyg7ik6!6xxUexuXFwUC=_1RZD z1f-M;`=pZ2+S~|tO9RNabPLO=5)DcR-Uy(7!Q5RRpcjE&BiQG>OGwuKf3QFsoSwSsEpTi*!1&tef)S|y>#+_dh8eON)i`&_0i)ahKn1r zTB79n7Rq=A{)+oE;?>HHK=Jg#-m6TclN+wyfFE)w!+17-L3nbJjI-b>@3sT6I@5#)_RUrW%1MuzFCn}S{hdeO}JFXhiupMEnx z?_EohXU4JXz2VEvU-8un?{AbWOnR_WFUIUE8;{FP&>MRl+@Ric9FIHfxc6XvF;~+B z>VUwx3(j4W=@qk+FR7lVsN(Rvz+C(>&~=A#N#%1q?inXm?`}dy#6gmK^;?3?dK~ku zucG4d<3-%OU*vFb|B`Ja{n1jpwOEB}FKw#h<(-L?@eIyg3eH`ibA!%3V>&l)djdOx zb8_2AD4u5w`#*J5q(s=6Zo%Wa;`{ae??baNYOe6y=Zoxe`e}Fj_P@eDh}^Q zY^e7<+Voj)wc;2a$BSo6yWVaUEEnT(WtUjoN~wC3I0uj0y{!M8;P|>l*&;kHh3Qj& zExmfJYLz_SLK)A%e^KDSz_|;~T{Cv>l00i*n1%_S8j|FrsY*D{+OpXp!}IVw)8P7J zTK?7T7e~|ZxT0f*8822l>|OQ&k2A|WGHg-D)nwZ!gQMil0lWpgC3_DwQ~u0spO>m1 zMHPqV1uL%Fmi3*9t?Od(IM);9@2i*Ik8r zKc0sg*EDD2T8o$hd7Pq*XTVzucxzfOg8VD!Yq?ZQ+r;J|^tGg;ZVGx4=tZ)A9aX=C zDh}@-h$MaCMne+LOOo@HTTpPO;A5a<^GW=8pI`Ee7OFNLk0+_WXyVv-gsmSe)g8u< zXVRB`LDHdSy%74NL3|O!7eRc{I9*KiYrN3g?d+`o(W_p7=MTowqz}&+Biu`S@wok& z^UiT<>)2@|`DiIEhjYDR=CwRJhaXRU-SCcwt1oOj5UY$cmb^LO+@;{$1v)qA+%u+g zw}`4cSgY1pnvnE6;XqyTerPLai}= zywR*e({vvHYA;EBHapwvsmEhlUlfz%e+)`e2bsB_&YoVXj5C(JIpEv{=PudxIaBAF z**-5-KB9`l^Niz_wYkoR`V*VA@VJ)}ah45t-Iif(JZ^7@TFXvG@4EhHc$`(z%U6u1 zll2^uyxcP{jl9lUh3zW7Bac&*@eFticnf%Iw)J)F^4Av68>^rHkb~!$52+nnKfY>H z-$GKKE&H?e!f&m*$qRDv6uT(CbSacy`c9#^kp{NZ+N^FbdYdA@}* zo`L_Oz<+`GB8V@VB(6y&n)+pGF;5l4p8R_1k4Scn|1rGv{5s#!A-TRS}Nr|Q7bb++eL?jzx?JO0C`t-?QU$>@>CDav>TyrqD* zru8D|+XsCu%@#9sp|2%9byLubKrfQ@>!|uARB?DeqEanaqWh|jf8-h-SCH^ENWalp zRZ@w^ExY{gUZqarp-XCbTzOr7@(y8>=3agpoh0eknltqzKXm#z<*KTzkpr@ zdeMyOMFwoAi0fwzBg!=J{2^)a-?{5-?&zLwJnr4452kSuT+@cvc-#vA_q_A*{vWnp z#N&#`1e$v1x*uO3k;f^@cm})$yd~>b%#U7+aNuuW!}A$~kZ{{Y`nHK{?k2#@PDh?ut{iF?})`e@J6d^D)f zu4Q299+6wyDUtRG%TodzR_ihrL!3?Fi>~33Zs=by*VhN=MW7eS`gK(O5~?`7fAFfQ zVoir5N5am;j-1(I*!nyc_AK`QuM@QKx+k`MN;R;b(wD0cGJMF>IKT+D0y=LZvk(~ z`V}*!BhU7Esrpe=ad`e{$zQ%v*wOmpElIzlQDJYotKn9!v0D6iyP{7I&(FBowBHDi z>j|o}cZw|tFMfl^=~Y~g%g!IZ_Q6^nrzqnY@D}hE@YZb8xh+}M?wO}|tdgw2^T+WO zQOvTY@<{9bc$`^oaYN2k_7-Q7`0zEyZeH1wsrN+tD1JPP;?R8`?OtyPEmH)cSEy*8JQ_1U4`UTg2j(EGX@r##lvx!xY=+@N#I`gK&#Q&e$y|G?_)W9!~C z>NQVp;&CO1HhuERC@eYLg~z2jJLoaA3)>Ep=-2))JP&jitCu|?sRP3Qp`gw+(v_do zE6=x3#xw9=6!-9`7$eE*oixu@mxPb1lYM;GGuK#<)LnaXp^00xH+L|I zq+aB$A|CV3;;xFpQ2e|)!#OuQ2UUxOd}VNyyg7ikfVX7*irKC=&(!xv)sLcz!}G$G zFSeXk-UgGS8}Yci4TA0Z{sMjw$^Beu{k8n^G9N1mNqqRl<3Cos$&M;6A@R$^TE+v> z3&K17cF5xtWjq7kQovi&dJ*J}YArHmdB;KCsB}9y6UE&7lB?R>(^2BOQ_=T zeo3LQMF;+1@-;Yo+)F+A>YU1?*~{J2k%r|>w&tFaY~z$fKJ z19;pP^VkE8)pl%ihB7!x-W>OzXvIp{^87s>i{RQ(dF zIJ|$bdEU_3+*>F0;yUp-sbS>3w$mH;9(TawZaylI>W=Imct8?w?Y-=52Y{pt|WYvVQ-U=rG8GlNq`?O9K-hW+>)#ej*>SA z@D}ivtY0zP<9uf7`=fgAMiqzWkFXG1@mdWo_J`?n z4Yecjxb<5@s;;c{*LjzU$K8C>f0gSUY*kexk5iQK40uZcZ%yk(2?uRVw6&J5hk7

fr)ssM8Pk^ntSLWTws+Fz==D&r~UX*}o5} zd_)z8=Y@=icK_MG{!wto3XXFRT#eYsKd+3gBdCLR}O>yw)qZ*JId z0FS$7wIh(1&St$HRK^)g-W+i5QgH49of~xSN#dGhqN!h|7PAuii&U#$z06{#wHa){ z^M{1Jdq+}5{k8aOcwC9Cb~DGV{DL`&ZhqdYb>wYbBWIonKi;~s43?k4mHwu~@;F5q z&w#fS@Yb|mq;KvPmQy7fln%TRWCS~z>M`_8AQ5fgVGF}Ad#DJ7?VV{&P z=R|@Bpx+17A%Oc5`reliJkZKd_6L1P+r;KzLNV-%bKegJ{}=Ut2_AsBA-FH0lOGKJ zFY5miJV3+~fIdVoeF*kNbYG%&j9kQA-{w^aYO%kKO}en z>Qq9VO2{vvZ+;2E15kei;%OnjguZo~2_Aqx>Co2;>W|R39v8s_5Kl{wyfU~if%_79 z_ay`mKpj4)KLYtB^vy3JcmV2hL0v97*X5#no;AS(P=Dk`-TR@DUdX%jSie+@zWX9w z_d|jQpxzMFYlr$H^sUE5@Bq~1g1TIm?h(0)>etQnx?FVEPYE7?dX-RrgbsE1=)T?+ zt#g70psp*mx~{Mblpb?9sqr4NIa2$33->0cS*;*OM(aB+zaR4xp?lS>;C?G_jQ5?Ku3kR zb9r&+5N}S8cyodWKv#h}JwZY^0PKsfFT%bEeN3Q_3G^|6J|@t|1p1hC4Ucp;6+_-7~?)M_w7^lR-Y2 zynHf(2k2V29qP41y>_VA&d?=z0P1o&EyU4I#nBS}fTI2e(ANO^8br9$w@wdT>hlmh0P7vrJFIsd23_| z{vR0vy6%Sr4?z4p#Lq+Dcj#k6_j?n#FM<0KI^UNN{s81(LLU?8V?y7)?*tFbwYUh_ z-(i2J^Zx#O_jQ5?AnqLE&gI3OL%g}xB0A`&1P{>Vo|LY7FzCRb1LJgHf(PhYw;k%W zL%nvW*A9J5pk6!FYlnL6Bg2G00Q(~Bi?A<39~0OYVPAxO5&D?WwQf7qYlnL6P_MmD zN}LNI{}TF`Kpzw6V*>jk?2E83(zibY;SbF9J`K>H0s1pQe+I?<83-PLbpq=I)`{YE zGS}A!!2@)y+Ya^GpC2>YV830?O?!XJRV zGJ52dK|Yzsdbl6`?fodh1JK6=`j|i;lkyb0?uP^qK-~_g+W~buppOakF@ZiN(8r{- znXdaG;SbQYZaZ;rLRWo=u6{6G*Sn&1PVfNK>482b(8q+naRdYpz`h85Oz2RD5AI9k z-X;Cxiq<*71HZT4In+6a zI_FU5eD3stCU^k)n7D;OT`v08<)V8%E`kSOe~0}Y_V>B7zyIESo!|k`QRVBXpr3+% zN(cRv-~rHs=e8cKNFM@S2>RPj^tUB=AerCV3wb8=%`<`cI(p}q5Ig{VOrVbm^f7@x zCeX(O`k26d34QNN2!DX?_a<;(0{10!zAqto0Q#6f9}}q4^V>Q-bg9on@BqZqLOd-U z<7wf(Wa_?z-~s4k0{10-LbxxX>wZY^z+CUs0R0)X44~c+ed`S=sy{;19U*uC)(NbW zLy53X=(-;gJOFjMppOakF@ZiN(8mP&m_Q#B=wkx)Dxr^wQ*efWI4{CEkzVIS;#@$N zds4dU!E`ilmka80(YY=c-Rp4?JOKMU?C-F@d&kjrKO}en^dWlcL!b+RE(Co{4sC^c?NF~B z>a~vy6aE0?nb14W1oBJhonJ!m0PKsfFT%bEeN3Q_N!Kvc<)Uw0F1pv_BK!fm-^`M!kUfw>kJLD%~qxc7m3pK@WJ^!M)T1P?$T6X;_?$9P(Zqjd|L(1i#dfckZX zao#NBMUZz1d6#s|yCir3>J34?A?RZw8l>xfNbmsEb){C<73#S{J=eMDHxfKR_j{Ay ztE+&X0(#0^(o+Z?fIcSB#{~MAG>GZC9}+wO^=aus#0 zOV|DV_wMTi4?vy?z4J^Uzl7fTB?J#ZACrXQrf&M?nLvICz4J>59)R;AoEK%!i*Qb) z*Ex~k0qA1_eN3Q_3G^|6cv^_3rDHrT#L-U0(Gvc^T<_BWb@-qTAM|I4$W^q?2_ArT z0_z0UiQ;uK*VhNZ1CW0?m48XsJQK(-p?7`>!2?jY1NxXi9}`Ohy6%Sr4?tZmsLMs? zx?FUx$3^e})U$$mR{t;ctRU}lZsc7OJOF)e>DlL&u6{81zo`F9@Bs8Nfj%bMT1(f% z{ysPM_usp(6FdNUCiKoTf&3DB=a ^_#&NG4h5_;#C5Ig{Nxsv_uSL!feU!?cG zNZ0+4-~qbdo4|bu+?UY#zJ%Zb(1+-$4}mTOx)Ag+(Kdm2T6)LRLLBW>94+AwK>j84 zF@ZiN(8mP!Mc5ai?>l|_z7zfc)OD@Rg}PjDUqaXYkl+F6V*-6lppOakG5Njq&Y{jZ z)H%0wr*GYkxt5nf_ybU%mR|K~p)M`drIoEqOYi{f@36na{$AQl*Zq*-0f?uCc-qg> z&+T))4&Pk!=l>|)B6tAuOz53w0{JEM&MzT&0M3hWUX(pA!a0#%=R|@BppOakF@ZiN z@9XHg9}+yEsJ{W67oo2K^fj3K_oD<4z zkben%OrVbm^f7@t&S)KHsNW3ro9R@)neYdoE*I40qH|p?y4T|(c;NTeJBNB!P|s?j zo)z?kEsXPK887-AzXT7!{to*)?C&GPblndL9-wR8cBt2` zXA1R4=v#k;s5?UN0OXm_JI{o!@w5;}J0xz%kM<;Z0QN=L7o+oGU!?1PNbmsN?@i#o z1p2;D?2B~W4+$QC`=7aS|3g=u3-qo3TAyBm2cVA$^f7@xCiIPmAb5bTb=#p{JJf53 z`;rDR!2{681p1gj-*@`L_7gq?@i#o1p2=B3CmOHx*rle z@JH1@hPua4_Za#_{_XXNBzOSo)6%Ox?caKS9Ndrov3YR>4?rIi=wkwXOqz=6x*rle z0RBAq^We|_?fLV66mJFiMVe+TP*IuW0~HmOyuTm+F8?2>T{UmoUgO76 z8~?Ile5?wY_an5>{~oJ5{okkY76z#OvoZR9$qMxS@--;l-yF4dH=yr}S?K%ywkSU5 z2h?_PM&JL=4SoOnJt)3;A8NfZF|y z=y*9T=y-W;D4s1s?e9OJ?>Bd&@3;4%_(Tb6v%aA3|1yTY|LZ@a_^N+JZQlPz-#7Xd zeSg)T|1`CJrq_q`JJinm@6)#FNzVA2Ds0t1O|92yyw7|Tufag=b{*7C)JMl-8KdLb zGg17nt5LgZ9r`|RJ^FscCKSKQ7PY1J==*t2==&u*QM`{kYHRF6-*5Lu-xvF$_%wgi zwhuzz|1|`C|GRJ$-w=t~5izK}>MS~*G!Y%|=Zh%5BptPVve5T6a?$s7Z=!f{0cxj} zpzquB(f3^*p!n}9QM;iAeLtceeLwaEinnM+?Vp9{`z0Od`{nOYynh#J>-M3xcn}>g zO^S|}^9{wj{4;8Q_pj*t4gZF|-~8_=KK4(4M%JIjchmOtdi(hw|BS4+U%p5256>2wIqjszfI-Z3+Iv&dr#sA`h+U2{^ z_x<;x@AJG+ypbz&k01|&*PzZb{J}ZABn!-9F4x;9*5!+&!aZ$BKrO>Y3TdE zUPkd%S5TXG1GS9`(DC|<(eb2rQG8xGYO^1q?|)x|zOPY-;@h92cH%4aeU=b?-@YBi z|JsS#RUgs!dA;cS5uZ`~su9$densEU`x$+|mpJ!;!;LTwit z)Mjr(Z662J_TPcpJU7&i*n`@!`%pX48@1DXQ9I`_YUc%@cF9rHE1-{qn9_l2mfQG(jK_fXrY9JNvh!r?iOl)UxeBkrKqi2hT29GV#oOZ3H@YMC2CvLpf;-xwe6pyw#!S@X1AiY&l}YC z7oj%qJ!(gEp>}L9YA1e1?X+Rk&KX7Ry#I;XC4WWj@_$9`s((Z6hJQ!xW|eWlY5WoK z=hyxh)E55(YWM#WYD-m7`{((n{fj1Q|Ei7J-z`Dy?+sB~!vwW;SE9C&DQd4WM{SGs zsLk4h+V(c6?XnHE*$$}fvjesL-B6pi2el*ip?0h{YA5=lcG_Xo&Iv&6yrZaHatyW0 zPoQ?yDb#L=LG9*v)NVhI+Tvu??oUN+=_Sv_z7e%uny2jl3%8q~&Hw-a literal 0 HcmV?d00001 From 4f673af4b5bb2b29d38a4627f1f1a045fefc3192 Mon Sep 17 00:00:00 2001 From: David Phung Date: Tue, 3 Nov 2020 16:56:28 +0100 Subject: [PATCH 1745/1776] rtsp-media: Ignore GstRTSPStreamBlocking from incomplete streams To prevent cases with prerolling when the inactive stream prerolls first and the server proceeds without waiting for the active stream, we will ignore GstRTSPStreamBlocking messages from incomplete streams. When there are no complete streams (during DESCRIBE), we will listen to all streams. Part-of: --- gst/rtsp-server/rtsp-media.c | 26 ++++++++++++++++++++++---- gst/rtsp-server/rtsp-stream.c | 3 ++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b22b95fbe0..69f63d9720 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3288,12 +3288,30 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) s = gst_message_get_structure (message); if (gst_structure_has_name (s, "GstRTSPStreamBlocking")) { - GST_DEBUG ("media received blocking message"); - priv->blocking_msg_received++; + gboolean is_complete = FALSE; + guint n_active_streams; + guint expected_nbr_blocking_msg; + + /* to prevent problems when some streams are complete, some are not, + * we will ignore incomplete streams. When there are no complete + * streams (during DESCRIBE), we will listen to all streams. */ + + gst_structure_get_boolean (s, "is_complete", &is_complete); + n_active_streams = nbr_active_streams (media); + expected_nbr_blocking_msg = n_active_streams; + GST_DEBUG_OBJECT (media, "media received blocking message," + " n_active_streams = %d, is_complete = %d", + n_active_streams, is_complete); + + if (n_active_streams == 0 || is_complete) + priv->blocking_msg_received++; + + if (n_active_streams == 0) + expected_nbr_blocking_msg = priv->streams->len; + if (priv->blocked && media_streams_blocking (media) && priv->no_more_pads_pending == 0 && - (priv->blocking_msg_received == nbr_active_streams (media) || - priv->blocking_msg_received == priv->streams->len)) { + priv->blocking_msg_received == expected_nbr_blocking_msg) { GST_DEBUG_OBJECT (GST_MESSAGE_SRC (message), "media is blocking"); g_mutex_lock (&priv->lock); collect_media_stats (media); diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 3243e59519..ddf7ba4107 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -5317,7 +5317,8 @@ pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) gst_element_post_message (priv->payloader, gst_message_new_element (GST_OBJECT_CAST (priv->payloader), - gst_structure_new_empty ("GstRTSPStreamBlocking"))); + gst_structure_new ("GstRTSPStreamBlocking", "is_complete", + G_TYPE_BOOLEAN, priv->is_complete, NULL))); done: return ret; From c1ede049eb0c15e3a2452f461b05d7fc4273ff1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 16 Nov 2020 10:34:41 +0200 Subject: [PATCH 1746/1776] rtsp-media: Use guint64 for setting the size-time property on rtpstorage Otherwise this will cause memory corruption as the property expects a 64 bit integer. Part-of: --- gst/rtsp-server/rtsp-media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 69f63d9720..7e548ef971 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -1659,7 +1659,7 @@ update_stream_storage_size (GstRTSPMedia * media, GstRTSPStream * stream, sessid, &storage); if (storage) { - guint size_time = 0; + guint64 size_time = 0; if (!gst_rtsp_stream_is_tcp_receiver (stream)) size_time = (media->priv->latency + 50) * GST_MSECOND; From 5b08a6042d11b4278cf74c8912699c1854188ce0 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 18 Nov 2020 20:36:50 +0100 Subject: [PATCH 1747/1776] rtsp-stream: collect a clock_rate when blocking This lets us provide a clock_rate in a fashion similar to the other code paths in get_rtpinfo() Part-of: --- gst/rtsp-server/rtsp-stream.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index ddf7ba4107..c94e6eed95 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -220,6 +220,7 @@ struct _GstRTSPStreamPrivate guint32 blocked_seqnum; guint32 blocked_rtptime; GstClockTime blocked_running_time; + gint blocked_clock_rate; /* Whether we should send and receive RTCP */ gboolean enable_rtcp; @@ -4344,6 +4345,14 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream, goto stats; *running_time = priv->blocked_running_time; } + + if (clock_rate) { + *clock_rate = priv->blocked_clock_rate; + + if (*clock_rate == 0 && running_time) + *running_time = GST_CLOCK_TIME_NONE; + } + goto done; } } @@ -5306,6 +5315,17 @@ pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) gst_event_unref (event); } + event = gst_pad_get_sticky_event (pad, GST_EVENT_CAPS, 0); + if (event) { + GstCaps *caps; + GstStructure *s; + + gst_event_parse_caps (event, &caps); + s = gst_caps_get_structure (caps, 0); + gst_structure_get_int (s, "clock-rate", &priv->blocked_clock_rate); + gst_event_unref (event); + } + priv->blocking = TRUE; GST_DEBUG_OBJECT (pad, "Now blocking"); @@ -5347,6 +5367,7 @@ set_blocked (GstRTSPStream * stream, gboolean blocked) priv->blocking = FALSE; priv->blocked_buffer = FALSE; priv->blocked_running_time = GST_CLOCK_TIME_NONE; + priv->blocked_clock_rate = 0; priv->blocked_id[i] = gst_pad_add_probe (priv->send_src[i], GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | @@ -6243,8 +6264,8 @@ gst_rtsp_stream_set_rate_control (GstRTSPStream * stream, gboolean enabled) if (stream->priv->appsink[0]) g_object_set (stream->priv->appsink[0], "sync", enabled, NULL); if (stream->priv->payloader - && g_object_class_find_property (G_OBJECT_GET_CLASS (stream->priv-> - payloader), "onvif-no-rate-control")) + && g_object_class_find_property (G_OBJECT_GET_CLASS (stream-> + priv->payloader), "onvif-no-rate-control")) g_object_set (stream->priv->payloader, "onvif-no-rate-control", !enabled, NULL); if (stream->priv->session) { From 6bf45b5965d05b29a4d97576fc6075fcd69f4a7b Mon Sep 17 00:00:00 2001 From: Lawrence Troup Date: Mon, 14 Dec 2020 14:12:38 +1300 Subject: [PATCH 1748/1776] rtsp-client: Only unref client watch context on finalize, to avoid deadlock Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/127 Part-of: --- gst/rtsp-server/rtsp-client.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index f533c67b38..8a34e1da3c 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -765,9 +765,13 @@ gst_rtsp_client_finalize (GObject * obj) /* the watch and related state should be cleared before finalize * as the watch actually holds a strong reference to the client */ g_assert (priv->watch == NULL); - g_assert (priv->watch_context == NULL); g_assert (priv->rtsp_ctrl_timeout == NULL); + if (priv->watch_context) { + g_main_context_unref (priv->watch_context); + priv->watch_context = NULL; + } + gst_rtsp_client_set_send_func (client, NULL, NULL, NULL); gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); @@ -1308,11 +1312,6 @@ gst_rtsp_client_close (GstRTSPClient * client) rtsp_ctrl_timeout_remove (client); } - if (priv->watch_context) { - g_main_context_unref (priv->watch_context); - priv->watch_context = NULL; - } - g_mutex_unlock (&priv->watch_lock); } @@ -5071,11 +5070,6 @@ handle_tunnel (GstRTSPClient * client) rtsp_ctrl_timeout_remove (client); } - if (priv->watch_context) { - g_main_context_unref (priv->watch_context); - priv->watch_context = NULL; - } - return GST_RTSP_STS_OK; /* ERRORS */ @@ -5174,10 +5168,6 @@ client_watch_notify (GstRTSPClient * client) gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL); rtsp_ctrl_timeout_remove (client); gst_rtsp_client_session_filter (client, cleanup_session, &closed); - if (priv->watch_context) { - g_main_context_unref (priv->watch_context); - priv->watch_context = NULL; - } if (closed) g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL); @@ -5210,6 +5200,7 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) priv = client->priv; g_return_val_if_fail (priv->connection != NULL, 0); g_return_val_if_fail (priv->watch == NULL, 0); + g_return_val_if_fail (priv->watch_context == NULL, 0); /* make sure noone will free the context before the watch is destroyed */ priv->watch_context = g_main_context_ref (context); From d1783cf3810d693bf20e9582e91de0a5155acd04 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 21 Oct 2020 15:38:43 +0200 Subject: [PATCH 1749/1776] rtspclientsink add proper support for uri queries Part-of: --- gst/rtsp-sink/gstrtspclientsink.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 59c21252ef..1fbf2f6e8e 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -3586,7 +3586,8 @@ gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink) GstRTSPStreamContext *context; GList *walk; const gchar *base; - gboolean has_slash; + gchar *stream_path; + GstUri *base_uri, *uri; GST_DEBUG_OBJECT (sink, "Collecting stream information"); @@ -3594,8 +3595,13 @@ gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink) return FALSE; base = get_aggregate_control (sink); - /* check if the base ends with / */ - has_slash = g_str_has_suffix (base, "/"); + + base_uri = gst_uri_from_string (base); + if (!base_uri) { + GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, (NULL), + ("Could not parse uri %s", base)); + return FALSE; + } g_mutex_lock (&sink->preroll_lock); while (sink->contexts == NULL && !sink->conninfo.flushing) { @@ -3634,11 +3640,16 @@ gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink) gst_rtsp_client_sink_create_stream (sink, context, context->payloader, srcpad); - /* concatenate the two strings, insert / when not present */ + /* append stream index to uri path */ g_free (context->conninfo.location); - context->conninfo.location = - g_strdup_printf ("%s%sstream=%d", base, has_slash ? "" : "/", - context->index); + + stream_path = g_strdup_printf ("stream=%d", context->index); + uri = gst_uri_copy (base_uri); + gst_uri_append_path (uri, stream_path); + + context->conninfo.location = gst_uri_to_string (uri); + gst_uri_unref (uri); + g_free (stream_path); if (sink->rtx_time > 0) { /* enable retransmission by setting rtprtxsend as the "aux" element of rtpbin */ @@ -3675,10 +3686,12 @@ gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink) sink->streams_collected = TRUE; g_mutex_unlock (&sink->preroll_lock); + gst_uri_unref (base_uri); return TRUE; join_bin_failed: + gst_uri_unref (base_uri); GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL), ("Could not start stream %d", context->index)); return FALSE; From 07c009dc802c4e506a05b183ff94632322419061 Mon Sep 17 00:00:00 2001 From: Tobias Ronge Date: Thu, 17 Dec 2020 15:27:27 +0100 Subject: [PATCH 1750/1776] rtsp-media: Only count senders when counting blocked streams Only sender streams sends the GstRTSPStreamBlocking message, so only these should be counted before setting media status to prepared. Part-of: --- gst/rtsp-server/rtsp-media.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 7e548ef971..0313ed4445 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -3164,19 +3164,20 @@ set_target_state (GstRTSPMedia * media, GstState state, gboolean do_state) } static void -stream_collect_active (GstRTSPStream * stream, guint * active_streams) +stream_collect_active_sender (GstRTSPStream * stream, guint * active_streams) { - if (gst_rtsp_stream_is_complete (stream)) + if (gst_rtsp_stream_is_complete (stream) + && gst_rtsp_stream_is_sender (stream)) (*active_streams)++; } static guint -nbr_active_streams (GstRTSPMedia * media) +nbr_active_sender_streams (GstRTSPMedia * media) { guint ret = 0; - g_ptr_array_foreach (media->priv->streams, (GFunc) stream_collect_active, - &ret); + g_ptr_array_foreach (media->priv->streams, + (GFunc) stream_collect_active_sender, &ret); return ret; } @@ -3289,7 +3290,7 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) s = gst_message_get_structure (message); if (gst_structure_has_name (s, "GstRTSPStreamBlocking")) { gboolean is_complete = FALSE; - guint n_active_streams; + guint n_active_sender_streams; guint expected_nbr_blocking_msg; /* to prevent problems when some streams are complete, some are not, @@ -3297,16 +3298,16 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message) * streams (during DESCRIBE), we will listen to all streams. */ gst_structure_get_boolean (s, "is_complete", &is_complete); - n_active_streams = nbr_active_streams (media); - expected_nbr_blocking_msg = n_active_streams; + n_active_sender_streams = nbr_active_sender_streams (media); + expected_nbr_blocking_msg = n_active_sender_streams; GST_DEBUG_OBJECT (media, "media received blocking message," - " n_active_streams = %d, is_complete = %d", - n_active_streams, is_complete); + " n_active_sender_streams = %d, is_complete = %d", + n_active_sender_streams, is_complete); - if (n_active_streams == 0 || is_complete) + if (n_active_sender_streams == 0 || is_complete) priv->blocking_msg_received++; - if (n_active_streams == 0) + if (n_active_sender_streams == 0) expected_nbr_blocking_msg = priv->streams->len; if (priv->blocked && media_streams_blocking (media) && From 9f42f941d7cc579813e45444e37de76290cebe69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 15 Dec 2020 10:18:16 +0200 Subject: [PATCH 1751/1776] rtspclientsink: Use proper types instead of G_TYPE_POINTER for the RTSP messages in the "handle-request" signal Part-of: --- docs/gst_plugins_cache.json | 4 ++-- gst/rtsp-sink/gstrtspclientsink.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index a6cf43aa91..5d695dc20c 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -376,11 +376,11 @@ "args": [ { "name": "arg0", - "type": "gpointer" + "type": "GstRTSPMessage" }, { "name": "arg1", - "type": "gpointer" + "type": "GstRTSPMessage" } ], "return-type": "void" diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 1fbf2f6e8e..c420e46878 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -738,7 +738,9 @@ gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) */ gst_rtsp_client_sink_signals[SIGNAL_HANDLE_REQUEST] = g_signal_new ("handle-request", G_TYPE_FROM_CLASS (klass), 0, - 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); + 0, NULL, NULL, NULL, G_TYPE_NONE, 2, + GST_TYPE_RTSP_MESSAGE | G_SIGNAL_TYPE_STATIC_SCOPE, + GST_TYPE_RTSP_MESSAGE | G_SIGNAL_TYPE_STATIC_SCOPE); /** * GstRTSPClientSink::new-manager: From c4762da9b702a205c78d9ea6b75447d0edd0d0fd Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Thu, 5 Nov 2020 16:02:49 -0500 Subject: [PATCH 1752/1776] Make a mount point of "/" work correctly. As far as I can tell, this is neither explicitly allowed nor forbidden by RFC 7826. Meanwhile, URLs such as rtsp://:554 or rtsp://:554/ are in use in the wild (presumably with non-GStreamer servers). GStreamer's prior behavior was confusing, in that gst_rtsp_mount_points_add_factory() would appear to accept a mount path of "" or "/", but later connection attempts would fail with a "media not found" error. This commit makes a mount path of "/" work for either form of URL, while an empty mount path ("") is rejected and logs a warning. Part-of: --- gst/rtsp-server/rtsp-client.c | 20 +++++++++++++++----- gst/rtsp-server/rtsp-mount-points.c | 14 ++++++++++---- gst/rtsp-server/rtsp-session-media.c | 6 ++++++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8a34e1da3c..a83725cf61 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1320,10 +1320,12 @@ default_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri) { gchar *path; - if (uri->query) + if (uri->query) { path = g_strconcat (uri->abspath, "?", uri->query, NULL); - else - path = g_strdup (uri->abspath); + } else { + /* normalize rtsp://: to rtsp://:/ */ + path = g_strdup (uri->abspath[0] ? uri->abspath : "/"); + } return path; } @@ -2763,9 +2765,15 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) } } else { /* path is what matched. */ - path[matched] = '\0'; + gchar *newpath = g_strndup (path, matched); /* control is remainder */ - control = &path[matched + 1]; + if (matched == 1 && path[0] == '/') + control = g_strdup (&path[1]); + else + control = g_strdup (&path[matched + 1]); + + g_free (path); + path = newpath; /* find the stream now using the control part */ stream = gst_rtsp_media_find_stream (media, control); @@ -2977,6 +2985,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) g_object_unref (media); g_object_unref (session); g_free (path); + g_free (control); return TRUE; @@ -3109,6 +3118,7 @@ keymgmt_error: g_object_unref (session); cleanup_path: g_free (path); + g_free (control); return FALSE; } } diff --git a/gst/rtsp-server/rtsp-mount-points.c b/gst/rtsp-server/rtsp-mount-points.c index 10119839db..145c5ac7bf 100644 --- a/gst/rtsp-server/rtsp-mount-points.c +++ b/gst/rtsp-server/rtsp-mount-points.c @@ -171,7 +171,8 @@ gst_rtsp_mount_points_new (void) static gchar * default_make_path (GstRTSPMountPoints * mounts, const GstRTSPUrl * url) { - return g_strdup (url->abspath); + /* normalize rtsp://: to rtsp://:/ */ + return g_strdup (url->abspath[0] ? url->abspath : "/"); } /** @@ -210,6 +211,10 @@ has_prefix (DataItem * str, DataItem * prefix) if (str->len < prefix->len) return FALSE; + /* special case when "/" is the entire prefix */ + if (prefix->len == 1 && prefix->path[0] == '/' && str->path[0] == '/') + return TRUE; + /* if str is larger, it there should be a / following the prefix */ if (str->len > prefix->len && str->path[prefix->len] != '/') return FALSE; @@ -331,7 +336,8 @@ gst_rtsp_mount_points_remove_factory_unlocked (GstRTSPMountPoints * mounts, * * Attach @factory to the mount point @path in @mounts. * - * @path is of the form (/node)+. Any previous mount point will be freed. + * @path is either of the form (/node)+ or the root path '/'. (An empty path is + * not allowed.) Any previous mount point will be freed. * * Ownership is taken of the reference on @factory so that @factory should not be * used after calling this function. @@ -345,7 +351,7 @@ gst_rtsp_mount_points_add_factory (GstRTSPMountPoints * mounts, g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts)); g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); - g_return_if_fail (path != NULL); + g_return_if_fail (path != NULL && path[0] == '/'); priv = mounts->priv; @@ -374,7 +380,7 @@ gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints * mounts, GstRTSPMountPointsPrivate *priv; g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts)); - g_return_if_fail (path != NULL); + g_return_if_fail (path != NULL && path[0] == '/'); priv = mounts->priv; diff --git a/gst/rtsp-server/rtsp-session-media.c b/gst/rtsp-server/rtsp-session-media.c index 6b4bb149b2..8fdb7e211d 100644 --- a/gst/rtsp-server/rtsp-session-media.c +++ b/gst/rtsp-server/rtsp-session-media.c @@ -194,6 +194,12 @@ gst_rtsp_session_media_matches (GstRTSPSessionMedia * media, if (len < priv->path_len) return FALSE; + /* special case when "/" is the entire path */ + if (priv->path_len == 1 && priv->path[0] == '/' && path[0] == '/') { + *matched = 1; + return TRUE; + } + /* if media path is larger, it there should be a / following the path */ if (len > priv->path_len && path[priv->path_len] != '/') return FALSE; From d6d3ecaafb3d3027f081cfc167e05ea676acbbd7 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Wed, 23 Dec 2020 13:54:54 -0500 Subject: [PATCH 1753/1776] Add test cases for mountpoint of '/' Part-of: --- tests/check/gst/client.c | 150 ++++++++++++++++++++++++++++----------- 1 file changed, 108 insertions(+), 42 deletions(-) diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index d506f9aed8..c65ae01ae4 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -206,7 +206,8 @@ create_connection (GstRTSPConnection ** conn) } static GstRTSPClient * -setup_client (const gchar * launch_line, gboolean enable_rtcp) +setup_client (const gchar * launch_line, const gchar * mount_point, + gboolean enable_rtcp) { GstRTSPClient *client; GstRTSPSessionPool *session_pool; @@ -229,7 +230,7 @@ setup_client (const gchar * launch_line, gboolean enable_rtcp) gst_rtsp_media_factory_set_enable_rtcp (factory, enable_rtcp); - gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); + gst_rtsp_mount_points_add_factory (mount_points, mount_point, factory); gst_rtsp_client_set_mount_points (client, mount_points); thread_pool = gst_rtsp_thread_pool_new (); @@ -494,7 +495,8 @@ GST_START_TEST (test_options) GST_END_TEST; -GST_START_TEST (test_describe) +static void +test_describe_sub (const gchar * mount_point, const gchar * url) { GstRTSPClient *client; GstRTSPMessage request = { 0, }; @@ -504,7 +506,7 @@ GST_START_TEST (test_describe) /* simple DESCRIBE for non-existing url */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, - "rtsp://localhost/test") == GST_RTSP_OK); + url) == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); g_free (str); @@ -517,9 +519,9 @@ GST_START_TEST (test_describe) g_object_unref (client); /* simple DESCRIBE for an existing url */ - client = setup_client (NULL, TRUE); + client = setup_client (NULL, mount_point, TRUE); fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, - "rtsp://localhost/test") == GST_RTSP_OK); + url) == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); g_free (str); @@ -532,6 +534,18 @@ GST_START_TEST (test_describe) teardown_client (client); } +GST_START_TEST (test_describe) +{ + test_describe_sub ("/test", "rtsp://localhost/test"); +} + +GST_END_TEST; + +GST_START_TEST (test_describe_root_mount_point) +{ + test_describe_sub ("/", "rtsp://localhost"); +} + GST_END_TEST; static const gchar *expected_transport = NULL; @@ -663,14 +677,14 @@ test_teardown_response_200 (GstRTSPClient * client, } static void -send_teardown (GstRTSPClient * client) +send_teardown (GstRTSPClient * client, const gchar * url) { GstRTSPMessage request = { 0, }; gchar *str; fail_unless (session_id != NULL); fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_TEARDOWN, - "rtsp://localhost/test") == GST_RTSP_OK); + url) == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); @@ -683,19 +697,21 @@ send_teardown (GstRTSPClient * client) session_id = NULL; } -GST_START_TEST (test_setup_tcp) +static void +test_setup_tcp_sub (const gchar * mount_point, const gchar * url1, + const gchar * url2) { GstRTSPClient *client; GstRTSPConnection *conn; GstRTSPMessage request = { 0, }; gchar *str; - client = setup_client (NULL, TRUE); + client = setup_client (NULL, mount_point, TRUE); create_connection (&conn); fail_unless (gst_rtsp_client_set_connection (client, conn)); fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + url1) == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); g_free (str); @@ -710,10 +726,23 @@ GST_START_TEST (test_setup_tcp) gst_rtsp_message_unset (&request); - send_teardown (client); + send_teardown (client, url2); teardown_client (client); } +GST_START_TEST (test_setup_tcp) +{ + test_setup_tcp_sub ("/test", "rtsp://localhost/test/stream=0", + "rtsp://localhost/test"); +} + +GST_END_TEST; + +GST_START_TEST (test_setup_tcp_root_mount_point) +{ + test_setup_tcp_sub ("/", "rtsp://localhost/stream=0", "rtsp://localhost"); +} + GST_END_TEST; GST_START_TEST (test_setup_no_rtcp) @@ -723,7 +752,7 @@ GST_START_TEST (test_setup_no_rtcp) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_client (NULL, FALSE); + client = setup_client (NULL, "/test", FALSE); create_connection (&conn); fail_unless (gst_rtsp_client_set_connection (client, conn)); @@ -744,26 +773,28 @@ GST_START_TEST (test_setup_no_rtcp) gst_rtsp_message_unset (&request); - send_teardown (client); + send_teardown (client, "rtsp://localhost/test"); teardown_client (client); } GST_END_TEST; -GST_START_TEST (test_setup_tcp_two_streams_same_channels) +static void +test_setup_tcp_two_streams_same_channels_sub (const gchar * mount_point, + const gchar * url1, const gchar * url2, const gchar * url3) { GstRTSPClient *client; GstRTSPConnection *conn; GstRTSPMessage request = { 0, }; gchar *str; - client = setup_client (NULL, TRUE); + client = setup_client (NULL, mount_point, TRUE); create_connection (&conn); fail_unless (gst_rtsp_client_set_connection (client, conn)); /* test SETUP of a video stream with 0-1 as interleaved channels */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + url1) == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); g_free (str); @@ -779,7 +810,7 @@ GST_START_TEST (test_setup_tcp_two_streams_same_channels) /* test SETUP of an audio stream with *the same* interleaved channels. * we expect the server to allocate new channel numbers */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=1") == GST_RTSP_OK); + url2) == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str); g_free (str); @@ -793,14 +824,30 @@ GST_START_TEST (test_setup_tcp_two_streams_same_channels) &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - send_teardown (client); + send_teardown (client, url3); teardown_client (client); } +GST_START_TEST (test_setup_tcp_two_streams_same_channels) +{ + test_setup_tcp_two_streams_same_channels_sub ("/test", + "rtsp://localhost/test/stream=0", "rtsp://localhost/test/stream=1", + "rtsp://localhost/test"); +} + +GST_END_TEST; + +GST_START_TEST (test_setup_tcp_two_streams_same_channels_root_mount_point) +{ + test_setup_tcp_two_streams_same_channels_sub ("/", + "rtsp://localhost/stream=0", "rtsp://localhost/stream=1", + "rtsp://localhost"); +} + GST_END_TEST; static GstRTSPClient * -setup_multicast_client (guint max_ttl) +setup_multicast_client (guint max_ttl, const gchar * mount_point) { GstRTSPClient *client; GstRTSPSessionPool *session_pool; @@ -825,7 +872,7 @@ setup_multicast_client (guint max_ttl) gst_rtsp_media_factory_add_role (factory, "user", "media.factory.access", G_TYPE_BOOLEAN, TRUE, "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); - gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); + gst_rtsp_mount_points_add_factory (mount_points, mount_point, factory); gst_rtsp_client_set_mount_points (client, mount_points); gst_rtsp_media_factory_set_max_mcast_ttl (factory, max_ttl); @@ -846,7 +893,7 @@ GST_START_TEST (test_client_multicast_transport_404) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (1); + client = setup_multicast_client (1, "/test"); /* simple SETUP for non-existing url */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, @@ -879,7 +926,7 @@ GST_START_TEST (test_client_multicast_transport) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (1); + client = setup_multicast_client (1, "/test"); expected_session_timeout = 20; g_signal_connect (G_OBJECT (client), "new-session", @@ -902,7 +949,7 @@ GST_START_TEST (test_client_multicast_transport) expected_transport = NULL; expected_session_timeout = 60; - send_teardown (client); + send_teardown (client, "rtsp://localhost/test"); teardown_client (client); } @@ -915,7 +962,7 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (1); + client = setup_multicast_client (1, "/test"); /* simple SETUP with a valid URI and multicast and a specific dest, * but ignore it */ @@ -934,7 +981,7 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) gst_rtsp_message_unset (&request); expected_transport = NULL; - send_teardown (client); + send_teardown (client, "rtsp://localhost/test"); teardown_client (client); } @@ -950,7 +997,7 @@ multicast_transport_specific (void) GstRTSPSessionPool *session_pool; GstRTSPContext ctx = { NULL }; - client = setup_multicast_client (1); + client = setup_multicast_client (1, "/test"); ctx.client = client; ctx.auth = gst_rtsp_auth_new (); @@ -990,7 +1037,7 @@ multicast_transport_specific (void) &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - send_teardown (client); + send_teardown (client, "rtsp://localhost/test"); teardown_client (client); g_object_unref (ctx.auth); gst_rtsp_token_unref (ctx.token); @@ -1080,7 +1127,7 @@ test_client_sdp (const gchar * launch_line, guint * bandwidth_val) gchar *str; /* simple DESCRIBE for an existing url */ - client = setup_client (launch_line, TRUE); + client = setup_client (launch_line, "/test", TRUE); fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE, "rtsp://localhost/test") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); @@ -1303,12 +1350,12 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1, } g_free (client_addr); - send_teardown (client2); + send_teardown (client2, "rtsp://localhost/test"); gst_rtsp_context_pop_current (&ctx2); gst_rtsp_context_push_current (&ctx); session_id = session_id1; - send_teardown (client1); + send_teardown (client1, "rtsp://localhost/test"); gst_rtsp_context_pop_current (&ctx); teardown_client (client1); @@ -1452,7 +1499,7 @@ mcast_transport_two_clients_teardown_play (const gchar * transport1, /* the first client sends TEARDOWN request */ gst_rtsp_context_push_current (&ctx); session_id = session_id1; - send_teardown (client1); + send_teardown (client1, "rtsp://localhost/test"); gst_rtsp_context_pop_current (&ctx); teardown_client (client1); @@ -1470,7 +1517,7 @@ mcast_transport_two_clients_teardown_play (const gchar * transport1, gst_rtsp_message_unset (&request); /* client 2 sends TEARDOWN request */ - send_teardown (client2); + send_teardown (client2, "rtsp://localhost/test"); gst_rtsp_context_pop_current (&ctx2); teardown_client (client2); @@ -1756,7 +1803,7 @@ GST_START_TEST (test_client_multicast_invalid_ttl) GstRTSPSessionPool *session_pool; GstRTSPContext ctx = { NULL }; - client = setup_multicast_client (3); + client = setup_multicast_client (3, "/test"); ctx.client = client; ctx.auth = gst_rtsp_auth_new (); @@ -1895,7 +1942,7 @@ do_test_scale_and_speed (const gchar * scale, const gchar * speed, gchar *str; GstRTSPContext ctx = { NULL }; - client = setup_multicast_client (1); + client = setup_multicast_client (1, "/test"); ctx.client = client; ctx.auth = gst_rtsp_auth_new (); @@ -1948,7 +1995,7 @@ do_test_scale_and_speed (const gchar * scale, const gchar * speed, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - send_teardown (client); + send_teardown (client, "rtsp://localhost/test"); teardown_client (client); g_object_unref (ctx.auth); gst_rtsp_token_unref (ctx.token); @@ -2018,15 +2065,16 @@ GST_START_TEST (test_scale_and_speed) do_test_scale_and_speed (NULL, "-2", GST_RTSP_STS_BAD_REQUEST); } -GST_END_TEST -GST_START_TEST (test_client_play) +GST_END_TEST static void +test_client_play_sub (const gchar * mount_point, const gchar * url1, + const gchar * url2) { GstRTSPClient *client; GstRTSPMessage request = { 0, }; gchar *str; GstRTSPContext ctx = { NULL }; - client = setup_multicast_client (1); + client = setup_multicast_client (1, mount_point); ctx.client = client; ctx.auth = gst_rtsp_auth_new (); @@ -2036,7 +2084,7 @@ GST_START_TEST (test_client_play) gst_rtsp_context_push_current (&ctx); fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, - "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + url1) == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, @@ -2051,7 +2099,7 @@ GST_START_TEST (test_client_play) expected_transport = NULL; fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, - "rtsp://localhost/test") == GST_RTSP_OK); + url2) == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); @@ -2060,13 +2108,26 @@ GST_START_TEST (test_client_play) &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); - send_teardown (client); + send_teardown (client, url2); teardown_client (client); g_object_unref (ctx.auth); gst_rtsp_token_unref (ctx.token); gst_rtsp_context_pop_current (&ctx); } +GST_START_TEST (test_client_play) +{ + test_client_play_sub ("/test", "rtsp://localhost/test/stream=0", + "rtsp://localhost/test"); +} + +GST_END_TEST; + +GST_START_TEST (test_client_play_root_mount_point) +{ + test_client_play_sub ("/", "rtsp://localhost/stream=0", "rtsp://localhost"); +} + GST_END_TEST static Suite * rtspclient_suite (void) { @@ -2079,9 +2140,13 @@ rtspclient_suite (void) tcase_add_test (tc, test_request); tcase_add_test (tc, test_options); tcase_add_test (tc, test_describe); + tcase_add_test (tc, test_describe_root_mount_point); tcase_add_test (tc, test_setup_tcp); + tcase_add_test (tc, test_setup_tcp_root_mount_point); tcase_add_test (tc, test_setup_no_rtcp); tcase_add_test (tc, test_setup_tcp_two_streams_same_channels); + tcase_add_test (tc, + test_setup_tcp_two_streams_same_channels_root_mount_point); tcase_add_test (tc, test_client_multicast_transport_404); tcase_add_test (tc, test_client_multicast_transport); tcase_add_test (tc, test_client_multicast_ignore_transport_specific); @@ -2122,6 +2187,7 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_invalid_ttl); tcase_add_test (tc, test_scale_and_speed); tcase_add_test (tc, test_client_play); + tcase_add_test (tc, test_client_play_root_mount_point); return s; } From ac5213dcdf09f95c71329005a865a39867c3e7c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 15 Dec 2020 11:07:01 +0200 Subject: [PATCH 1754/1776] rtspclientsink: Add "update-sdp" signal that allows updating the SDP before sending it to the server Part-of: --- docs/gst_plugins_cache.json | 9 +++++++++ gst/rtsp-sink/gstrtspclientsink.c | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index 5d695dc20c..3df5ca65ea 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -414,6 +414,15 @@ ], "return-type": "GstCaps", "when": "last" + }, + "update-sdp": { + "args": [ + { + "name": "arg0", + "type": "GstSDPMessage" + } + ], + "return-type": "void" } } } diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index c420e46878..090a2643e4 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -246,6 +246,7 @@ enum SIGNAL_NEW_PAYLOADER, SIGNAL_REQUEST_RTCP_KEY, SIGNAL_ACCEPT_CERTIFICATE, + SIGNAL_UPDATE_SDP, LAST_SIGNAL }; @@ -805,6 +806,22 @@ gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) G_TYPE_BOOLEAN, 3, G_TYPE_TLS_CONNECTION, G_TYPE_TLS_CERTIFICATE, G_TYPE_TLS_CERTIFICATE_FLAGS); + /** + * GstRTSPClientSink::update-sdp: + * @rtsp_client_sink: a #GstRTSPClientSink + * @sdp: a #GstSDPMessage + * + * Emitted right before the ANNOUNCE request is sent to the server with the + * generated SDP. The SDP can be updated from signal handlers but the order + * and number of medias must not be changed. + * + * Since: 1.20 + */ + gst_rtsp_client_sink_signals[SIGNAL_UPDATE_SDP] = + g_signal_new_class_handler ("update-sdp", G_TYPE_FROM_CLASS (klass), + 0, 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, GST_TYPE_SDP_MESSAGE | G_SIGNAL_TYPE_STATIC_SCOPE); + gstelement_class->provide_clock = gst_rtsp_client_sink_provide_clock; gstelement_class->change_state = gst_rtsp_client_sink_change_state; gstelement_class->request_new_pad = @@ -4453,6 +4470,8 @@ gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async) if (res < 0) goto create_request_failed; + g_signal_emit (sink, gst_rtsp_client_sink_signals[SIGNAL_UPDATE_SDP], 0, sdp); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CONTENT_TYPE, "application/sdp"); From 2894640cc5a796eb27e5605b3932523bd1ab5982 Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Fri, 22 Jan 2021 08:58:23 +0100 Subject: [PATCH 1755/1776] rtsp-client: cleanup transports during TEARDOWN When tunneling RTP over RTSP the stream transports are stored in a hash table in the GstRTSPClientPrivate struct. They are used for, among other things, mapping channel id to stream transports when receiving data from the client. The stream tranports are created and added to the hash table in handle_setup_request(), but unfortuately they are not removed in handle_teardown_request(). This means that if the client sends data on the RTSP connection after it has sent the TEARDOWN, which is often the case when audio backchannel is enabled, handle_data() will still be able to map the channel to a session transport and pass the data along to it. Which eventually leads to a failing assert in gst_rtsp_stream_recv_rtp() because the stream is no longer joined to a bin. We avoid this by removing the stream transports from the hash table when we handle the TEARDOWN request. Part-of: --- gst/rtsp-server/rtsp-client.c | 60 +++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index a83725cf61..8312e3c30b 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1371,6 +1371,55 @@ pre_signal_accumulator (GSignalInvocationHint * ihint, GValue * return_accu, return TRUE; } +/* The cleanup_transports function is called from handle_teardown_request() to + * remove any stream transports from the newly closed session that were added to + * priv->transports in handle_setup_request(). This is done to avoid forwarding + * data from the client on a channel that we just closed. + */ +static void +cleanup_transports (GstRTSPClient * client, GPtrArray * transports) +{ + GstRTSPClientPrivate *priv = client->priv; + GstRTSPStreamTransport *stream_transport; + const GstRTSPTransport *rtsp_transport; + guint i; + + GST_LOG_OBJECT (client, "potentially removing %u transports", + transports->len); + + for (i = 0; i < transports->len; i++) { + stream_transport = g_ptr_array_index (transports, i); + if (stream_transport == NULL) { + GST_LOG_OBJECT (client, "stream transport %u is NULL, continue", i); + continue; + } + + rtsp_transport = gst_rtsp_stream_transport_get_transport (stream_transport); + if (rtsp_transport == NULL) { + GST_LOG_OBJECT (client, "RTSP transport %u is NULL, continue", i); + continue; + } + + /* priv->transport only stores transports where RTP is tunneled over RTSP */ + if (rtsp_transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { + if (!g_hash_table_remove (priv->transports, + GINT_TO_POINTER (rtsp_transport->interleaved.min))) { + GST_WARNING_OBJECT (client, + "failed removing transport with key '%d' from priv->transports", + rtsp_transport->interleaved.min); + } + if (!g_hash_table_remove (priv->transports, + GINT_TO_POINTER (rtsp_transport->interleaved.max))) { + GST_WARNING_OBJECT (client, + "failed removing transport with key '%d' from priv->transports", + rtsp_transport->interleaved.max); + } + } else { + GST_LOG_OBJECT (client, "transport %u not RTP/RTSP, skip it", i); + } + } +} + static gboolean handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) { @@ -1384,6 +1433,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) gint matched; gboolean keep_session; GstRTSPStatusCode sig_result; + GPtrArray *session_media_transports; if (!ctx->session) goto no_session; @@ -1419,6 +1469,10 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) goto sig_failed; } + /* get a reference to the transports in the session media so we can clean up + * our priv->transports before returning */ + session_media_transports = gst_rtsp_session_media_get_transports (sessmedia); + /* we emit the signal before closing the connection */ g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], 0, ctx); @@ -1444,6 +1498,12 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_media_unlock (media); g_object_unref (media); + /* remove all transports that were present in the session media which we just + * unmanaged from the priv->transports array, so we do not try to handle data + * on channels that were just closed */ + cleanup_transports (client, session_media_transports); + g_ptr_array_unref (session_media_transports); + return TRUE; /* ERRORS */ From 6fc8b963a595c0081788c551107478aaafd299d7 Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Mon, 1 Feb 2021 12:16:46 +0100 Subject: [PATCH 1756/1776] rtsp-stream: avoid deadlock in send_func Currently the send_func() runs in a thread of its own which is started the first time we enter handle_new_sample(). It runs in an outer loop until priv->continue_sending is FALSE, which happens when a TEARDOWN request is received. We use a local variable, cont, which is initialized to TRUE, meaning that we will always enter the outer loop, and at the end of the outer loop we assign it the value of priv->continue_sending. Within the outer loop there is an inner loop, where we wait to be signaled when there is more data to send. The inner loop is exited when priv->send_cookie has changed value, which it does when more data is available or when a TEARDOWN has been received. But if we get a TEARDOWN before send_func() is entered we will get stuck in the inner loop because no one will increase priv->session_cookie anymore. By not entering the outer loop in send_func() if priv->continue_sending is FALSE we make sure that we do not get stuck in send_func()'s inner loop should we receive a TEARDOWN before the send thread has started. Change-Id: I7338a0ea60ea435bb685f875965f5165839afa20 Part-of: --- gst/rtsp-server/rtsp-stream.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index c94e6eed95..c5656ca061 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2733,11 +2733,10 @@ static gpointer send_func (GstRTSPStream * stream) { GstRTSPStreamPrivate *priv = stream->priv; - gboolean cont = TRUE; g_mutex_lock (&priv->send_lock); - while (cont) { + while (priv->continue_sending) { int i; int idx = -1; guint cookie; @@ -2763,10 +2762,9 @@ send_func (GstRTSPStream * stream) g_mutex_unlock (&priv->lock); g_mutex_lock (&priv->send_lock); - while (cookie == priv->send_cookie) { + while (cookie == priv->send_cookie && priv->continue_sending) { g_cond_wait (&priv->send_cond, &priv->send_lock); } - cont = priv->continue_sending; } g_mutex_unlock (&priv->send_lock); From abacfb3792b271bc610bb61c53122d822ecfc200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 15 Feb 2021 12:01:34 +0000 Subject: [PATCH 1757/1776] rtspclientsink: fix deadlock on shutdown before preroll Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/130 Part-of: --- gst/rtsp-sink/gstrtspclientsink.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 090a2643e4..fa18e78ab9 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -4372,6 +4372,18 @@ done: return res; } +static gboolean +gst_rtsp_client_sink_is_stopping (GstRTSPClientSink * sink) +{ + gboolean is_stopping; + + GST_OBJECT_LOCK (sink); + is_stopping = sink->task == NULL; + GST_OBJECT_UNLOCK (sink); + + return is_stopping; +} + static GstRTSPResult gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async) { @@ -4406,14 +4418,25 @@ gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async) * parts yet. */ gst_rtsp_client_sink_collect_streams (sink); + if (gst_rtsp_client_sink_is_stopping (sink)) { + GST_INFO_OBJECT (sink, "task stopped, shutting down"); + return GST_RTSP_EINTR; + } + g_mutex_lock (&sink->block_streams_lock); /* Wait for streams to be blocked */ - while (sink->n_streams_blocked < g_list_length (sink->contexts)) { + while (sink->n_streams_blocked < g_list_length (sink->contexts) + && !gst_rtsp_client_sink_is_stopping (sink)) { GST_DEBUG_OBJECT (sink, "waiting for streams to be blocked"); g_cond_wait (&sink->block_streams_cond, &sink->block_streams_lock); } g_mutex_unlock (&sink->block_streams_lock); + if (gst_rtsp_client_sink_is_stopping (sink)) { + GST_INFO_OBJECT (sink, "task stopped, shutting down"); + return GST_RTSP_EINTR; + } + /* Send announce, then setup for all streams */ gst_sdp_message_init (&sink->cursdp); sdp = &sink->cursdp; @@ -4955,6 +4978,10 @@ gst_rtsp_client_sink_stop (GstRTSPClientSink * sink) gst_task_stop (task); + g_mutex_lock (&sink->block_streams_lock); + g_cond_broadcast (&sink->block_streams_cond); + g_mutex_unlock (&sink->block_streams_lock); + /* make sure it is not running */ GST_RTSP_STREAM_LOCK (sink); GST_RTSP_STREAM_UNLOCK (sink); From 015e4dc8100a310b95390a4465e2227b89c93fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 15 Feb 2021 12:07:45 +0000 Subject: [PATCH 1758/1776] rtspclientsink: add unit test for potential shutdown deadlock Part-of: --- tests/check/gst/rtspclientsink.c | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/check/gst/rtspclientsink.c b/tests/check/gst/rtspclientsink.c index 2647ce8ba3..c3e95b1907 100644 --- a/tests/check/gst/rtspclientsink.c +++ b/tests/check/gst/rtspclientsink.c @@ -238,6 +238,52 @@ GST_START_TEST (test_record) GST_END_TEST; +/* Make sure we can shut down rtspclientsink while it's still waiting for + * the initial preroll data */ +GST_START_TEST (test_record_no_data) +{ + + start_record_server ("( rtppcmadepay name=depay0 ! fakesink )"); + + /* Create an rtspclientsink and send some data */ + { + gchar *uri = get_server_uri (test_port, TEST_MOUNT_POINT); + gchar *pipe_str; + GstMessage *msg; + GstElement *pipeline; + GstBus *bus; + + pipe_str = g_strdup_printf ("appsrc caps=audio/x-alaw,rate=8000,channels=1" + " ! rtspclientsink name=sink location=%s", uri); + g_free (uri); + + pipeline = gst_parse_launch (pipe_str, NULL); + g_free (pipe_str); + + fail_unless (pipeline != NULL); + + bus = gst_element_get_bus (pipeline); + fail_if (bus == NULL); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + /* wait for a bit */ + msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, + 500 * GST_MSECOND); + fail_unless (msg == NULL); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + gst_object_unref (bus); + } + + /* clean up and iterate so the clean-up can finish */ + stop_server (); + iterate (); +} + +GST_END_TEST; + static Suite * rtspclientsink_suite (void) { @@ -248,6 +294,7 @@ rtspclientsink_suite (void) tcase_add_checked_fixture (tc, setup, teardown); tcase_set_timeout (tc, 120); tcase_add_test (tc, test_record); + tcase_add_test (tc, test_record_no_data); return s; } From 8c496762f44562ec68c5deffa98f0c8623bb4179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 15 Feb 2021 12:26:30 +0000 Subject: [PATCH 1759/1776] rtspclientsink: mark cached caps as maybe-leaked to make leaks tracer happy Part-of: --- gst/rtsp-sink/gstrtspclientsink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index fa18e78ab9..19ef7ec485 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -1090,6 +1090,8 @@ gst_rtsp_client_sink_get_all_payloaders_caps (void) goto out; } + GST_MINI_OBJECT_FLAG_SET (caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); + out: g_once_init_leave (&ret, caps); } From 247b17c0832d2fa7e97e278ee7ddce655e503c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 15 Feb 2021 12:07:15 +0000 Subject: [PATCH 1760/1776] tests: rtspclientsink: fix some leaks Part-of: --- tests/check/gst/rtspclientsink.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/check/gst/rtspclientsink.c b/tests/check/gst/rtspclientsink.c index c3e95b1907..63e799e965 100644 --- a/tests/check/gst/rtspclientsink.c +++ b/tests/check/gst/rtspclientsink.c @@ -214,6 +214,7 @@ GST_START_TEST (test_record) gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); + gst_object_unref (bus); } iterate (); @@ -227,9 +228,12 @@ GST_START_TEST (test_record) g_signal_emit_by_name (G_OBJECT (server_sink), "pull-sample", &sample); GST_INFO ("%2d recv sample: %p", i, sample); - if (sample) + if (sample) { gst_sample_unref (sample); + sample = NULL; + } } + gst_object_unref (server_sink); /* clean up and iterate so the clean-up can finish */ stop_server (); From 747eaf3634062df850955833299182c4ada97390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 19 Mar 2021 10:36:01 +0200 Subject: [PATCH 1761/1776] rtspclientsink: Don't run signal class handlers during the CLEANUP stage It's sufficient to run them during the FIRST stage instead of in both. Part-of: --- gst/rtsp-sink/gstrtspclientsink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 19ef7ec485..96b6044b38 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -754,7 +754,7 @@ gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) */ gst_rtsp_client_sink_signals[SIGNAL_NEW_MANAGER] = g_signal_new_class_handler ("new-manager", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, 0, NULL, NULL, NULL, + G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); /** @@ -768,7 +768,7 @@ gst_rtsp_client_sink_class_init (GstRTSPClientSinkClass * klass) */ gst_rtsp_client_sink_signals[SIGNAL_NEW_PAYLOADER] = g_signal_new_class_handler ("new-payloader", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, 0, NULL, NULL, NULL, + G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); /** From 7cbc183044c04dd14a099de8e12479da21ae0087 Mon Sep 17 00:00:00 2001 From: Doug Nazar Date: Fri, 16 Apr 2021 14:35:02 -0400 Subject: [PATCH 1762/1776] rtsp-media: Improve skipping trickmode seek. We can also skip the seek if the end range is already correct. Avoids initial seek on play start if playing full stream. Part-of: --- gst/rtsp-server/rtsp-media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 0313ed4445..98c719d744 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2946,8 +2946,8 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, } } - if (start == current_position && stop_type == GST_SEEK_TYPE_NONE && - !force_seek) { + if (!force_seek && start == current_position && + (stop_type == GST_SEEK_TYPE_NONE || stop == priv->range_stop)) { GST_DEBUG ("no position change, no flags set by caller, so not seeking"); res = TRUE; } else { From 338db31c4a0ad618058f4e464dd51959e1f2534c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 23 Apr 2021 07:18:48 +0200 Subject: [PATCH 1763/1776] rtsp-media: Add one more case to seek avoidance This is an extension to the previous commit. There can also be cases where the start position is not specified, in those cases we should also avoid doing seeking unless it's forced. Part-of: --- gst/rtsp-server/rtsp-media.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 98c719d744..55d2b31305 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -2946,7 +2946,8 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media, } } - if (!force_seek && start == current_position && + if (!force_seek && + (start_type == GST_SEEK_TYPE_NONE || start == current_position) && (stop_type == GST_SEEK_TYPE_NONE || stop == priv->range_stop)) { GST_DEBUG ("no position change, no flags set by caller, so not seeking"); res = TRUE; From 846442c256aa0257ab62b6a24754ba1930636a01 Mon Sep 17 00:00:00 2001 From: Doug Nazar Date: Thu, 22 Apr 2021 23:26:02 -0400 Subject: [PATCH 1764/1776] tests: Don't fail tests if IPv6 not available. On computers with IPv6 disabled it shouldn't result in a test failure. Part-of: --- tests/check/gst/stream.c | 47 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/tests/check/gst/stream.c b/tests/check/gst/stream.c index 112e80fc38..3da4f9b25c 100644 --- a/tests/check/gst/stream.c +++ b/tests/check/gst/stream.c @@ -140,17 +140,29 @@ get_sockets (GstRTSPLowerTrans lower_transport, GSocketFamily socket_family) gst_object_unref (stream); } -GST_START_TEST (test_get_sockets_udp) +GST_START_TEST (test_get_sockets_udp_ipv4) { get_sockets (GST_RTSP_LOWER_TRANS_UDP, G_SOCKET_FAMILY_IPV4); +} + +GST_END_TEST; + +GST_START_TEST (test_get_sockets_udp_ipv6) +{ get_sockets (GST_RTSP_LOWER_TRANS_UDP, G_SOCKET_FAMILY_IPV6); } GST_END_TEST; -GST_START_TEST (test_get_sockets_mcast) +GST_START_TEST (test_get_sockets_mcast_ipv4) { get_sockets (GST_RTSP_LOWER_TRANS_UDP_MCAST, G_SOCKET_FAMILY_IPV4); +} + +GST_END_TEST; + +GST_START_TEST (test_get_sockets_mcast_ipv6) +{ get_sockets (GST_RTSP_LOWER_TRANS_UDP_MCAST, G_SOCKET_FAMILY_IPV6); } @@ -641,15 +653,42 @@ GST_START_TEST (test_remove_transport_twice) GST_END_TEST; +static gboolean +is_ipv6_supported (void) +{ + GError *err = NULL; + GSocket *sock; + + sock = + g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_DATAGRAM, + G_SOCKET_PROTOCOL_DEFAULT, &err); + if (sock) { + g_object_unref (sock); + return TRUE; + } + + if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) { + GST_WARNING ("Unabled to create IPv6 socket: %s", err->message); + } + g_clear_error (&err); + + return FALSE; +} + static Suite * rtspstream_suite (void) { Suite *s = suite_create ("rtspstream"); TCase *tc = tcase_create ("general"); + gboolean have_ipv6 = is_ipv6_supported (); suite_add_tcase (s, tc); - tcase_add_test (tc, test_get_sockets_udp); - tcase_add_test (tc, test_get_sockets_mcast); + tcase_add_test (tc, test_get_sockets_udp_ipv4); + tcase_add_test (tc, test_get_sockets_mcast_ipv4); + if (have_ipv6) { + tcase_add_test (tc, test_get_sockets_udp_ipv6); + tcase_add_test (tc, test_get_sockets_mcast_ipv6); + } tcase_add_test (tc, test_allocate_udp_ports_fail); tcase_add_test (tc, test_get_multicast_address); tcase_add_test (tc, test_multicast_address_and_unicast_udp); From 5df7f9a7e01b152463a9e22c684632c86b446aec Mon Sep 17 00:00:00 2001 From: Marc Leeman Date: Tue, 27 Apr 2021 09:05:39 +0200 Subject: [PATCH 1765/1776] test-replay-server: minor spelling corrections Bumped on these while investigating the example code. Part-of: --- examples/test-replay-server.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/test-replay-server.c b/examples/test-replay-server.c index 493ca7ede5..69f1afe582 100644 --- a/examples/test-replay-server.c +++ b/examples/test-replay-server.c @@ -361,7 +361,7 @@ replay_bin_sink_probe (GstPad * pad, GstPadProbeInfo * info, switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: - /* Ideally this shouldn't happen because we are responsing + /* Ideally this shouldn't happen because we are responding * seeking query with non-seekable */ GST_DEBUG_OBJECT (pad, "Drop seek event"); ret = GST_PAD_PROBE_DROP; @@ -496,7 +496,7 @@ pad_added_cb (GstElement * dbin, GstPad * pad, GstReplayBin * self) /* block data for initial segment seeking */ bin_pad = g_new0 (GstReplayBinPad, 1); - /* Move owenership of pad to this struct */ + /* Move ownership of pad to this struct */ bin_pad->srcpad = gst_object_ref (dpad); bin_pad->block_id = gst_pad_add_probe (dpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, @@ -697,7 +697,7 @@ gst_rtsp_media_factory_replay_class_init (GstRTSPMediaFactoryReplayClass g_object_class_install_property (gobject_class, PROP_NUM_LOOPS, g_param_spec_int64 ("num-loops", "Num Loops", - "The number of loops (-1 = infiniate)", -1, G_MAXINT64, + "The number of loops (-1 = infinite)", -1, G_MAXINT64, DEFAULT_NUM_LOOPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); mf_class->create_element = @@ -866,7 +866,7 @@ main (int argc, char *argv[]) gint64 num_loops = -1; GOptionEntry options[] = { {"num-loops", 0, 0, G_OPTION_ARG_INT64, &num_loops, - "The number of loops (default = -1, infinate)", NULL}, + "The number of loops (default = -1, infinite)", NULL}, {NULL} }; From a8a45b577651d693505e01ea6971deee1d7de78b Mon Sep 17 00:00:00 2001 From: Marc Leeman Date: Tue, 27 Apr 2021 09:22:21 +0200 Subject: [PATCH 1766/1776] docs: minor spelling correction in README Part-of: --- docs/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README b/docs/README index baf7f0b22f..b4f0c358d8 100644 --- a/docs/README +++ b/docs/README @@ -426,7 +426,7 @@ GstRTSPClient are called by this object. GstRTSPContext - - Helper structure contaning the current state of the request + - Helper structure containing the current state of the request handled by the client. From 274c8e6b978f71c4fcd7082dbffaf786167394b7 Mon Sep 17 00:00:00 2001 From: Doug Nazar Date: Thu, 29 Apr 2021 03:07:42 -0400 Subject: [PATCH 1767/1776] rtsp-media: Ensure the bus watch is removed during unprepare It's possible for the destruction of the source to be delayed. Instead of relying on the dispose() to remove the bus watch, do it ourselves. Part-of: --- gst/rtsp-server/rtsp-media.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 55d2b31305..63f43bc00b 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -131,7 +131,6 @@ struct _GstRTSPMediaPrivate /* the pipeline for the media */ GstElement *pipeline; GSource *source; - guint id; GstRTSPThread *thread; GList *pending_pipeline_elements; @@ -3811,7 +3810,7 @@ default_prepare (GstRTSPMedia * media, GstRTSPThread * thread) g_source_set_callback (priv->source, (GSourceFunc) bus_message, g_object_ref (media), (GDestroyNotify) watch_destroyed); - priv->id = g_source_attach (priv->source, context); + g_source_attach (priv->source, context); /* add stuff to the bin */ gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin); @@ -4034,9 +4033,17 @@ finish_unprepare (GstRTSPMedia * media) /* the source has the last ref to the media */ if (priv->source) { + GstBus *bus; + + GST_DEBUG ("removing bus watch"); + bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline)); + gst_bus_remove_watch (bus); + gst_object_unref (bus); + GST_DEBUG ("destroy source"); g_source_destroy (priv->source); g_source_unref (priv->source); + priv->source = NULL; } if (priv->thread) { GST_DEBUG ("stop thread"); From 5f5b812844aff139960a453828018e7bf6bf3c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Laignel?= Date: Wed, 21 Apr 2021 10:43:41 +0200 Subject: [PATCH 1768/1776] Use gst_element_request_pad_simple... Instead of the deprecated gst_element_get_request_pad. Part-of: --- gst/rtsp-server/rtsp-stream.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index c5656ca061..b0b7ceee4b 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -2841,7 +2841,7 @@ request_rtp_encoder (GstElement * rtpbin, guint session, GstRTSPStream * stream) oldenc = priv->srtpenc; enc = get_rtp_encoder (stream, session); name = g_strdup_printf ("rtp_sink_%d", session); - pad = gst_element_get_request_pad (enc, name); + pad = gst_element_request_pad_simple (enc, name); g_free (name); gst_object_unref (pad); @@ -2869,7 +2869,7 @@ request_rtcp_encoder (GstElement * rtpbin, guint session, oldenc = priv->srtpenc; enc = get_rtp_encoder (stream, session); name = g_strdup_printf ("rtcp_sink_%d", session); - pad = gst_element_get_request_pad (enc, name); + pad = gst_element_request_pad_simple (enc, name); g_free (name); gst_object_unref (pad); @@ -3263,7 +3263,7 @@ create_and_plug_queue_to_unlinked_stream (GstRTSPStream * stream, gst_bin_add (priv->joined_bin, *queue); /* link tee to queue */ - tee_pad = gst_element_get_request_pad (tee, "src_%u"); + tee_pad = gst_element_request_pad_simple (tee, "src_%u"); queue_pad = gst_element_get_static_pad (*queue, "sink"); gst_pad_link (tee_pad, queue_pad); gst_object_unref (queue_pad); @@ -3425,7 +3425,7 @@ plug_udp_sink (GstRTSPStream * stream, GstElement * sink_to_plug, GST_DEBUG_OBJECT (stream, "creating first stream"); /* no need to add queues */ - tee_pad = gst_element_get_request_pad (priv->tee[index], "src_%u"); + tee_pad = gst_element_request_pad_simple (priv->tee[index], "src_%u"); sink_pad = gst_element_get_static_pad (sink_to_plug, "sink"); gst_pad_link (tee_pad, sink_pad); gst_object_unref (tee_pad); @@ -3474,7 +3474,7 @@ plug_tcp_sink (GstRTSPStream * stream, guint index) GstPad *sink_pad; /* no need to add queues */ - tee_pad = gst_element_get_request_pad (priv->tee[index], "src_%u"); + tee_pad = gst_element_request_pad_simple (priv->tee[index], "src_%u"); sink_pad = gst_element_get_static_pad (priv->appsink[index], "sink"); gst_pad_link (tee_pad, sink_pad); gst_object_unref (tee_pad); @@ -3657,7 +3657,7 @@ plug_src (GstRTSPStream * stream, GstBin * bin, GstElement * src, } /* and link to the funnel */ - selpad = gst_element_get_request_pad (funnel, "sink_%u"); + selpad = gst_element_request_pad_simple (funnel, "sink_%u"); gst_pad_link (pad, selpad); if (id != 0) gst_pad_remove_probe (pad, id); @@ -3945,7 +3945,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, if (priv->srcpad) { /* get a pad for sending RTP */ name = g_strdup_printf ("send_rtp_sink_%u", idx); - priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name); + priv->send_rtp_sink = gst_element_request_pad_simple (rtpbin, name); g_free (name); /* link the RTP pad to the session manager, it should not really fail unless @@ -3964,17 +3964,17 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin, g_signal_connect (rtpbin, "on-npt-stop", (GCallback) on_npt_stop, stream); name = g_strdup_printf ("recv_rtp_sink_%u", idx); - priv->recv_sink[0] = gst_element_get_request_pad (rtpbin, name); + priv->recv_sink[0] = gst_element_request_pad_simple (rtpbin, name); g_free (name); } if (priv->enable_rtcp) { name = g_strdup_printf ("send_rtcp_src_%u", idx); - priv->send_src[1] = gst_element_get_request_pad (rtpbin, name); + priv->send_src[1] = gst_element_request_pad_simple (rtpbin, name); g_free (name); name = g_strdup_printf ("recv_rtcp_sink_%u", idx); - priv->recv_sink[1] = gst_element_get_request_pad (rtpbin, name); + priv->recv_sink[1] = gst_element_request_pad_simple (rtpbin, name); g_free (name); } From 4c6e57ad33ca99cb3913a96a86c53926ba5abf32 Mon Sep 17 00:00:00 2001 From: Doug Nazar Date: Tue, 4 May 2021 20:45:19 -0400 Subject: [PATCH 1769/1776] rtsp-client: fix leak adding headers gst_rtsp_message_add_header() makes a copy of the header, instead of taking ownership. Part-of: --- gst/rtsp-server/rtsp-client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 8312e3c30b..e5a62c0cd9 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -3018,7 +3018,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) (gdouble) seekable / GST_SECOND); gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_MEDIA_PROPERTIES, - g_string_free (media_properties, FALSE)); + media_properties->str); + g_string_free (media_properties, TRUE); /* TODO Check how Accept-Ranges should be filled */ gst_rtsp_message_add_header (ctx->request, GST_RTSP_HDR_ACCEPT_RANGES, "npt, clock, smpte, clock"); From 6c9d6fd986303c3173cb2a8ef25e12d8bb18a102 Mon Sep 17 00:00:00 2001 From: Doug Nazar Date: Tue, 4 May 2021 20:47:18 -0400 Subject: [PATCH 1770/1776] rtsp-media: fix leak when adding converter Free the previous caps before reusing the variable for the converter caps. Part-of: --- gst/rtsp-server/rtsp-media-factory-uri.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/rtsp-server/rtsp-media-factory-uri.c b/gst/rtsp-server/rtsp-media-factory-uri.c index 67cdc3e30b..50089fc9cb 100644 --- a/gst/rtsp-server/rtsp-media-factory-uri.c +++ b/gst/rtsp-server/rtsp-media-factory-uri.c @@ -504,6 +504,7 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element) /* unref old pad, we reffed before */ gst_object_unref (pad); + gst_caps_unref (caps); /* continue with new pad and caps */ pad = gst_element_get_static_pad (convert, "src"); From a5b30f179b933e588644a58dd93bbcf3c234109c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 24 May 2021 18:58:00 +0100 Subject: [PATCH 1771/1776] rtsp-stream: use new gst_buffer_new_memdup() Part-of: --- gst/rtsp-server/rtsp-stream.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index b0b7ceee4b..1495b733c0 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -5986,9 +5986,7 @@ handle_mikey_data (GstRTSPStream * stream, guint8 * data, gsize size) pkd = (const GstMIKEYPayloadKeyData *) gst_mikey_payload_kemac_get_sub (&kemac->pt, 0); - key = - gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len), - pkd->key_len); + key = gst_buffer_new_memdup (pkd->key_data, pkd->key_len); /* go over all crypto sessions and create the security policy for each * SSRC */ From a3c3afbf560b3c7fc9fd5e1cfbb80150c0ee2963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 1 Jun 2021 00:15:08 +0100 Subject: [PATCH 1772/1776] Release 1.19.1 --- ChangeLog | 402 ++++++- NEWS | 2056 ++--------------------------------- RELEASE | 15 +- docs/gst_plugins_cache.json | 2 +- gst-rtsp-server.doap | 10 + meson.build | 2 +- 6 files changed, 492 insertions(+), 1995 deletions(-) diff --git a/ChangeLog b/ChangeLog index 19b8cce367..fb59edd157 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,409 @@ -=== release 1.18.0 === +=== release 1.19.1 === -2020-09-08 00:08:29 +0100 Tim-Philipp Müller +2021-06-01 00:15:08 +0100 Tim-Philipp Müller * ChangeLog: * NEWS: * RELEASE: * gst-rtsp-server.doap: + * meson.build: + Release 1.19.1 + +2021-05-24 18:58:00 +0100 Tim-Philipp Müller + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: use new gst_buffer_new_memdup() + Part-of: + +2021-05-04 20:47:18 -0400 Doug Nazar + + * gst/rtsp-server/rtsp-media-factory-uri.c: + rtsp-media: fix leak when adding converter + Free the previous caps before reusing the variable for the converter caps. + Part-of: + +2021-05-04 20:45:19 -0400 Doug Nazar + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: fix leak adding headers + gst_rtsp_message_add_header() makes a copy of the header, instead + of taking ownership. + Part-of: + +2021-04-21 10:43:41 +0200 François Laignel + + * gst/rtsp-server/rtsp-stream.c: + Use gst_element_request_pad_simple... + Instead of the deprecated gst_element_get_request_pad. + Part-of: + +2021-04-29 03:07:42 -0400 Doug Nazar + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Ensure the bus watch is removed during unprepare + It's possible for the destruction of the source to be delayed. + Instead of relying on the dispose() to remove the bus watch, do + it ourselves. + Part-of: + +2021-04-27 09:22:21 +0200 Marc Leeman + + * docs/README: + docs: minor spelling correction in README + Part-of: + +2021-04-27 09:05:39 +0200 Marc Leeman + + * examples/test-replay-server.c: + test-replay-server: minor spelling corrections + Bumped on these while investigating the example code. + Part-of: + +2021-04-22 23:26:02 -0400 Doug Nazar + + * tests/check/gst/stream.c: + tests: Don't fail tests if IPv6 not available. + On computers with IPv6 disabled it shouldn't result in a test failure. + Part-of: + +2021-04-23 07:18:48 +0200 Edward Hervey + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Add one more case to seek avoidance + This is an extension to the previous commit. There can also be cases where the + start position is not specified, in those cases we should also avoid doing + seeking unless it's forced. + Part-of: + +2021-04-16 14:35:02 -0400 Doug Nazar + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Improve skipping trickmode seek. + We can also skip the seek if the end range is already + correct. + Avoids initial seek on play start if playing full stream. + Part-of: + +2021-03-19 10:36:01 +0200 Sebastian Dröge + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Don't run signal class handlers during the CLEANUP stage + It's sufficient to run them during the FIRST stage instead of in both. + Part-of: + +2021-02-15 12:07:15 +0000 Tim-Philipp Müller + + * tests/check/gst/rtspclientsink.c: + tests: rtspclientsink: fix some leaks + Part-of: + +2021-02-15 12:26:30 +0000 Tim-Philipp Müller + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: mark cached caps as maybe-leaked to make leaks tracer happy + Part-of: + +2021-02-15 12:07:45 +0000 Tim-Philipp Müller + + * tests/check/gst/rtspclientsink.c: + rtspclientsink: add unit test for potential shutdown deadlock + Part-of: + +2021-02-15 12:01:34 +0000 Tim-Philipp Müller + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: fix deadlock on shutdown before preroll + Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/130 + Part-of: + +2021-02-01 12:16:46 +0100 Branko Subasic + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: avoid deadlock in send_func + Currently the send_func() runs in a thread of its own which is started + the first time we enter handle_new_sample(). It runs in an outer loop + until priv->continue_sending is FALSE, which happens when a TEARDOWN + request is received. We use a local variable, cont, which is initialized + to TRUE, meaning that we will always enter the outer loop, and at the + end of the outer loop we assign it the value of priv->continue_sending. + Within the outer loop there is an inner loop, where we wait to be + signaled when there is more data to send. The inner loop is exited when + priv->send_cookie has changed value, which it does when more data is + available or when a TEARDOWN has been received. + But if we get a TEARDOWN before send_func() is entered we will get stuck + in the inner loop because no one will increase priv->session_cookie + anymore. + By not entering the outer loop in send_func() if priv->continue_sending + is FALSE we make sure that we do not get stuck in send_func()'s inner + loop should we receive a TEARDOWN before the send thread has started. + Change-Id: I7338a0ea60ea435bb685f875965f5165839afa20 + Part-of: + +2021-01-22 08:58:23 +0100 Branko Subasic + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: cleanup transports during TEARDOWN + When tunneling RTP over RTSP the stream transports are stored in a hash + table in the GstRTSPClientPrivate struct. They are used for, among other + things, mapping channel id to stream transports when receiving data from + the client. The stream tranports are created and added to the hash table + in handle_setup_request(), but unfortuately they are not removed in + handle_teardown_request(). This means that if the client sends data on + the RTSP connection after it has sent the TEARDOWN, which is often the + case when audio backchannel is enabled, handle_data() will still be able + to map the channel to a session transport and pass the data along to it. + Which eventually leads to a failing assert in gst_rtsp_stream_recv_rtp() + because the stream is no longer joined to a bin. + We avoid this by removing the stream transports from the hash table when + we handle the TEARDOWN request. + Part-of: + +2020-12-15 11:07:01 +0200 Sebastian Dröge + + * docs/gst_plugins_cache.json: + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Add "update-sdp" signal that allows updating the SDP before sending it to the server + Part-of: + +2020-12-23 13:54:54 -0500 John Lindgren + + * tests/check/gst/client.c: + Add test cases for mountpoint of '/' + Part-of: + +2020-11-05 16:02:49 -0500 John Lindgren + + * gst/rtsp-server/rtsp-client.c: + * gst/rtsp-server/rtsp-mount-points.c: + * gst/rtsp-server/rtsp-session-media.c: + Make a mount point of "/" work correctly. + As far as I can tell, this is neither explicitly allowed nor + forbidden by RFC 7826. + Meanwhile, URLs such as rtsp://:554 or rtsp://:554/ are in + use in the wild (presumably with non-GStreamer servers). + GStreamer's prior behavior was confusing, in that + gst_rtsp_mount_points_add_factory() would appear to accept a mount + path of "" or "/", but later connection attempts would fail with a + "media not found" error. + This commit makes a mount path of "/" work for either form of URL, + while an empty mount path ("") is rejected and logs a warning. + Part-of: + +2020-12-15 10:18:16 +0200 Sebastian Dröge + + * docs/gst_plugins_cache.json: + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink: Use proper types instead of G_TYPE_POINTER for the RTSP messages in the "handle-request" signal + Part-of: + +2020-12-17 15:27:27 +0100 Tobias Ronge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Only count senders when counting blocked streams + Only sender streams sends the GstRTSPStreamBlocking message, so only + these should be counted before setting media status to prepared. + Part-of: + +2020-10-21 15:38:43 +0200 Jimmi Holst Christensen + + * gst/rtsp-sink/gstrtspclientsink.c: + rtspclientsink add proper support for uri queries + Part-of: + +2020-12-14 14:12:38 +1300 Lawrence Troup + + * gst/rtsp-server/rtsp-client.c: + rtsp-client: Only unref client watch context on finalize, to avoid deadlock + Fixes https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/127 + Part-of: + +2020-11-18 20:36:50 +0100 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: collect a clock_rate when blocking + This lets us provide a clock_rate in a fashion similar to the + other code paths in get_rtpinfo() + Part-of: + +2020-11-16 10:34:41 +0200 Sebastian Dröge + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Use guint64 for setting the size-time property on rtpstorage + Otherwise this will cause memory corruption as the property expects a 64 + bit integer. + Part-of: + +2020-11-03 16:56:28 +0100 David Phung + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + rtsp-media: Ignore GstRTSPStreamBlocking from incomplete streams + To prevent cases with prerolling when the inactive stream prerolls first + and the server proceeds without waiting for the active stream, we will + ignore GstRTSPStreamBlocking messages from incomplete streams. When + there are no complete streams (during DESCRIBE), we will listen to all + streams. + Part-of: + +2020-10-28 21:48:06 +0100 Kristofer Björkström + + * tests/check/gst/media.c: + * tests/check/meson.build: + * tests/files/test.avi: + media test: Add test for seeking one active stream with a demuxer + Add another seek_one_active_stream test but with a demuxer. The demuxer + will flush both streams in opposed to the existing test which only + flushes the active stream. This will help exposing problems with the + prerolling process after a flushing seek. + Part-of: + +2018-10-29 09:19:33 -0400 Xavier Claessens + + * gst/rtsp-server/meson.build: + * meson.build: + * pkgconfig/gstreamer-rtsp-server-uninstalled.pc.in: + * pkgconfig/gstreamer-rtsp-server.pc.in: + * pkgconfig/meson.build: + Meson: Use pkg-config generator + Part-of: + +2020-10-19 11:25:25 +0300 Sebastian Dröge + + * meson.build: + meson: update glib minimum version to 2.56 + Part-of: + +2020-09-04 21:14:35 +0200 Mathieu Duponchelle + + * examples/test-launch.c: + * gst/rtsp-server/rtsp-media-factory.c: + * gst/rtsp-server/rtsp-media-factory.h: + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-server-internal.h: + * gst/rtsp-server/rtsp-stream.c: + * tests/check/gst/client.c: + rtsp-media-factory: expose API to disable RTCP + This is supported by the RFC, and can be useful on systems where + allocating two consecutive ports is problematic, and RTCP is not + necessary. + Part-of: + +2020-10-08 23:45:24 +0200 Mathieu Duponchelle + + * hooks/pre-commit.hook: + * meson.build: + git: use our standard pre commit hook + Part-of: + +2020-10-08 22:17:16 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: make use of blocked_running_time in query_position + When blocking, the sink element will not have received a buffer + yet and the position query will fail. Instead, we make use of + the running time of the buffer we blocked on. + Part-of: + +2020-10-06 00:04:17 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: collect rtp info when blocking + We don't unblock the stream anymore before replying to the + play request (883ddc72bb5bc57c95a9e167814d1ac53fe1b443), + so the sinks don't have a last-sample after potentially flush + seeking. seek_trickmode waits for preroll however, which means + the stream will block and wait for a first buffer. Subsequent + calls to get_rtpinfo() can thus make use of the information. + See https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/issues/115 + Part-of: + +2020-09-27 20:09:22 +0900 Seungha Yang + + * examples/meson.build: + * examples/test-replay-server.c: + * examples/test-replay-server.h: + examples: Add an example for loop playback + This demo example shows a way of file loop playback of a given source. + Note that client seek request is not properly implemented yet. + Part-of: + +2020-09-28 22:03:47 +0200 David Phung + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Plug memory leak + The get-storage signal of rtpbin increases the ref count of the storage. + So we have to unref it after usage. + Part-of: + +2020-09-11 15:46:41 +0200 Guiqin Zou + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: Get rates only on sender streams + When play a media with both sender and receiver stream, like ONVIF + back channel audio in, gst_rtsp_media_get_rates call + gst_rtsp_stream_get_rates for each stream to set the rates. But + gst_rtsp_stream_get_rates return false for the receiver steam, which + lead a g_assert crash. + Instead to get rates on all streams, now just get rates on sender + streams. + Part-of: + +2020-09-05 00:30:42 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-server-internal.h: + * gst/rtsp-server/rtsp-stream.c: + rtsp-media: set a 0 storage size for TCP receivers + ulpfec correction is obviously useless when receiving a stream + over TCP, and in TCP modes the rtp storage receives non + timestamped buffers, causing it to queue buffers indefinitely, + until the queue grows so large that sanity checks kick in and + warnings start to get emitted. + Part-of: + +2020-08-21 03:02:40 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-stream.c: + rtsp-stream: preroll on gap events + This allows negotiating a SDP with all streams present, but only + start sending packets at some later point in time + Part-of: + +2020-08-25 16:10:36 +0200 Mathieu Duponchelle + + * gst/rtsp-server/rtsp-media.c: + rtsp-media: do not unblock on unsuspend + rtsp_media_unsuspend() is called from handle_play_request() + before sending the play response. Unblocking the streams here + was causing data to be sent out before the client was ready + to handle it, with obvious side effects such as initial packets + getting discarded, causing decoding errors. + Instead we can simply let the media streams be unblocked when + the state of the media is set to PLAYING, which occurs after + sending the play response. + Part-of: + +2020-09-08 17:30:49 +0100 Tim-Philipp Müller + + * .gitlab-ci.yml: + ci: include template from gst-ci master branch again + +2020-09-08 16:58:58 +0100 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * meson.build: + Back to development + +=== release 1.18.0 === + +2020-09-08 00:08:29 +0100 Tim-Philipp Müller + + * .gitlab-ci.yml: + * ChangeLog: + * NEWS: + * RELEASE: + * docs/gst_plugins_cache.json: + * gst-rtsp-server.doap: * meson.build: Release 1.18.0 diff --git a/NEWS b/NEWS index dba9c7c471..cc6c3b4a8e 100644 --- a/NEWS +++ b/NEWS @@ -1,11 +1,23 @@ -GStreamer 1.18 Release Notes +GStreamer 1.20 Release Notes -GStreamer 1.18.0 was originally released on 7 September 2020. +GStreamer 1.20 has not been released yet. It is scheduled for release +around July 2021. -See https://gstreamer.freedesktop.org/releases/1.18/ for the latest +1.19.x is the unstable development version that is being developed in +the git master branch and which will eventually result in 1.20, and +1.19.1 is the current development release in that series + +It is expected that feature freeze will be around June/July 2021, +followed by several 1.19 pre-releases and the new 1.20 stable release +around July 2021. + +1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, +1.10, 1.8, 1.6,, 1.4, 1.2 and 1.0 release series. + +See https://gstreamer.freedesktop.org/releases/1.20/ for the latest version of this document. -Last updated: Monday 7 September 2020, 10:30 UTC (log) +Last updated: Sunday 30 May 2021, 16:00 UTC (log) Introduction @@ -18,1639 +30,87 @@ fixes and other improvements. Highlights -- GstTranscoder: new high level API for applications to transcode - media files from one format to another - -- High Dynamic Range (HDR) video information representation and - signalling enhancements - -- Instant playback rate change support - -- Active Format Description (AFD) and Bar Data support - -- ONVIF trick modes support in both GStreamer RTSP server and client - -- Hardware-accelerated video decoding on Windows via DXVA2 / - Direct3D11 - -- Microsoft Media Foundation plugin for video capture and - hardware-accelerated video encoding on Windows - -- qmlgloverlay: New overlay element that renders a QtQuick scene over - the top of an input video stream - -- New imagesequencesrc element to easily create a video stream from a - sequence of jpeg or png images - -- dashsink: Add new sink to produce DASH content - -- dvbsubenc: DVB Subtitle encoder element - -- TV broadcast compliant MPEG-TS muxing with constant bitrate muxing - and SCTE-35 support - -- rtmp2: new RTMP client source and sink element implementation - -- svthevcenc: new SVT-HEVC-based H.265 video encoder - -- vaapioverlay compositor element using VA-API - -- rtpmanager support for Google’s Transport-Wide Congestion Control - (twcc) RTP extension - -- splitmuxsink and splitmuxsrc gained support for auxiliary video - streams - -- webrtcbin now contains some initial support for renegotiation - involving stream addition and removal - -- New RTP source and sink elements to easily set up RTP streaming via - rtp:// URIs - -- New Audio Video Transport Protocol (AVTP) plugin for Time-Sensitive - Applications - -- Support for the Video Services Forum’s Reliable Internet Stream - Transport (RIST) TR-06-1 Simple Profile - -- Universal Windows Platform (UWP) support - -- rpicamsrc element for capturing from the Raspberry Pi camera - -- RTSP Server TCP interleaved backpressure handling improvements as - well as support for Scale/Speed headers - -- GStreamer Editing Services gained support for nested timelines, - per-clip speed rate control and the OpenTimelineIO format. - -- Autotools build system has been removed in favour of Meson +- this section will be completed in due course Major new features and changes Noteworthy new features and API -Instant playback rate changes - -Changing the playback rate as quickly as possible so far always required -a flushing seek. This generally works, but has the disadvantage of -flushing all data from the playback pipeline and requiring the demuxer -or parser to do a full-blown seek including resetting its internal state -and resetting the position of the data source. It might also require -considerable decoding effort to get to the right position to resume -playback from at the higher rate. - -This release adds a new mechanism to achieve quasi-instant rate changes -in certain playback pipelines without interrupting the flow of data in -the pipeline. This is activated by sending a seek with the -GST_SEEK_FLAG_INSTANT_RATE_CHANGE flag and start_type = stop_type = -GST_SEEK_TYPE_NONE. This flag does not work for all pipelines, in which -case it is necessary to fall back to sending a full flushing seek to -change the playback rate. When using this flag, the seek event is only -allowed to change the current rate and can modify the trickmode flags -(e.g. keyframe only or not), but it is not possible to change the -current playback position, playback direction or do a flush. - -This is particularly useful for streaming use cases like HLS or DASH -where the streaming download should not be interrupted when changing -rate. - -Instant rate changing is handled in the pipeline in a specific sequence -which is detailed in the seeking design docs. Most elements don’t need -to worry about this, only elements that sync to the clock need some -special handling which is implemented in the GstBaseSink base class, so -should be taken care of automatically in most normal playback pipelines -and sink elements. - -See Jan’s GStreamer Conference 2019 talk “Changing Playback Rate -Instantly” for more information. - -You can try this feature by passing the -i command line option to -gst-play-1.0. It is supported at least by qtdemux, tsdemux, hlsdemux, -and dashdemux. - -Google Transport-Wide Congestion Control - -rtpmanager now supports the parsing and generating of RTCP messages for -the Google Transport-Wide Congestion Control RTP Extension, as described -in: -https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01. - -This “just” provides the required plumbing/infrastructure, it does not -actually make effect any actual congestion control on the sender side, -but rather provides information for applications to use to make such -decisions. - -See Håvard’s “Google Transport-Wide Congestion Control” talk for more -information about this feature. - -GstTranscoder: a new high-level transcoding API for applications - -The new GstTranscoder library, along with transcodebin and -uritranscodebin elements, provides high level API for applications to -transcode media files from one format to another. Watch Thibault’s talk -“GstTranscoder: A High Level API to Quickly Implement Transcoding -Capabilities in your Applications” for more information. - -This also comes with a gst-transcoder-1.0 command line utility to -transcode one URI into another URI based on the specified encoding -profile. - -Active Format Description (AFD) and Bar Data support - -The GstVideo Ancillary Data API has gained support for Active Format -Description (AFD) and Bar data. - -This includes various two new buffer metas: GstVideoAFDMeta and -GstVideoBarMeta. - -GStreamer now also parses and extracts AFD/Bar data in the h264/h265 -video parsers, and supports both capturing them and outputting them in -the decklink elements. See Aaron’s lightning talk at the GStreamer -Conference for more background. - -ONVIF trick modes support in both GStreamer RTSP server and client - -- Support for the various trick modes described in section 6 of the - ONVIF streaming spec has been implemented in both gst-rtsp-server - and rtspsrc. -- Various new properties in rtspsrc must be set to take advantage of - the ONVIF support -- Examples are available here: test-onvif-server.c and - test-onvif-client.c -- Watch Mathieu Duponchelle’s talk “Implementing a Trickmode Player - with ONVIF, RTSP and GStreamer” for more information and a live - demo. - -GStreamer Codecs library with decoder base classes - -This introduces a new library in gst-plugins-bad which contains a set of -base classes that handle bitstream parsing and state tracking for the -purpose of decoding different codecs. Currently H264, H265, VP8 and VP9 -are supported. These bases classes are meant primarily for internal use -in GStreamer and are used in various decoder elements in connection with -low level decoding APIs like DXVA, NVDEC, VAAPI and V4L2 State Less -decoders. The new library is named gstreamer-codecs-1.0 / -libgstcodecs-1.0 and is not yet guaranteed to be API stable across major -versions. - -MPEG-TS muxing improvements - -The GStreamer MPEG-TS muxer has seen major improvements on various -fronts in this cycle: - -- It has been ported to the GstAggregator base class which means it - can work in defined-latency mode with live input sources and - continue streaming if one of the inputs stops producing data. - -- atscmux, a new ATSC-specific tsmux subclass - -- Constant Bit Rate (CBR) muxing support via the new bitrate property - which allows setting the target bitrate in bps. If this is set the - muxer will insert null packets as padding to achieve the desired - multiplex-wide constant bitrate. - -- compliance fixes for TV broadcasting use cases (esp. ATSC). See - Jan’s talk “TV Broadcast compliant MPEG-TS” for details. - -- Streams can now be added and removed at runtime: Until now, any - streams in tsmux had to be present when the element started - outputting its first buffer. Now they can appear at any point during - the stream, or even disappear and reappear later using the same PID. - -- new pcr-interval property allows applications to configure the - desired interval instead of hardcoding it - -- basic SCTE-35 support. This is enabled by setting the scte-35-pid - property on the muxer. Sending SCTE-35 commands is then done by - creating the appropriate SCTE-35 GstMpegtsSection and sending them - on the muxer. - -- MPEG-2 AAC handling improvements +- this section will be filled in in due course New elements -- New qmlgloverlay element for rendering a QtQuick scene over the top - of a video stream. qmlgloverlay requires that Qt support adopting an - external OpenGL context and is known to work on X11 and Windows. - Wayland is known not to work due to limitations within Qt. Check out - the example to see how it works. - -- The clocksync element is a generic element that can be placed in a - pipeline to synchronise passing buffers to the clock at that point. - This is similar to identity sync=true, but because it isn’t - GstBaseTransform-based, it can process GstBufferLists without - breaking them into separate GstBuffers. It is also more discoverable - than the identity option. Note that you do not need to insert this - element into your pipeline to make GStreamer sync to the pipeline - clock, this is usually handled automatically by the elements in the - pipeline (sources and sinks mostly). This element is useful to feed - non-live input such as local files into elements that expect live - input such as webrtcbin.` - -- New imagesequencesrc element to easily create a video stream from a - sequence of JPEG or PNG images (or any other encoding where the type - can be detected), basically a multifilesrc made specifically for - image sequences. - -- rpicamsrc element for capturing raw or encoded video (H.264, MJPEG) - from the Raspberry Pi camera. This works much like the popular - raspivid command line utility but outputs data nicely timestamped - and formatted in order to integrate nicely with other GStreamer - elements. Also comes with a device provider so applications can - discover the camera if available. - -- aatv and cacatv video filters that transform video ASCII art style - -- avtp: new Audio Video Transport Protocol (AVTP) plugin for Linux. - See Andre Guedes’ talk “Audio/Video Bridging (AVB) support in - GStreamer” for more details. - -- clockselect: a pipeline element that enables clock selection/forcing - via gst-launch pipeline syntax. - -- dashsink: Add new sink to produce DASH content. See Stéphane’s talk - or blog post for details. - -- dvbsubenc: a DVB subtitle encoder element - -- microdns: a libmicrodns-based mdns device provider to discover RTSP - cameras on the local network - -- mlaudiosink: new audio sink element for the Magic Leap platform, - accompanied by an MLSDK implementation in the amc plugin - -- msdkvp9enc: VP9 encoder element for the Intel MediaSDK - -- rist: new plugin implementing support for the Video Services Forum’s - Reliable Internet Stream Transport (RIST) TR-06-1 Simple Profile. - See Nicolas’ blog post “GStreamer support for the RIST - Specification” for more details. - -- rtmp2: new RTMP client source and sink elements with fully - asynchronous network operations, better robustness and additional - features such as handling ping and stats messages, and adobe-style - authentication. The new rtmp2src and rtmp2sink elements should be - API-compatible with the old rtmpsrc / rtmpsink elements and should - work as drop-in replacements. - -- new RTP source and sink elements to easily set up RTP streaming via - rtp:// URIs: The rtpsink and rtpsrc elements add an URI interface so - that streams can be decoded with decodebin using rtp:// URIs. These - can be used as follows: ``` gst-launch-1.0 videotestsrc ! x264enc ! - rtph264pay config-interval=3 ! rtpsink uri=rtp://239.1.1.1:1234 - - gst-launch-1.0 videotestsrc ! x264enc ! rtph264pay config-interval=1 - ! rtpsink uri=rtp://239.1.2.3:5000 gst-launch-1.0 rtpsrc - uri=rtp://239.1.2.3:5000?encoding-name=H264 ! rtph264depay ! - avdec_h264 ! videoconvert ! xvimagesink - - gst-launch-1.0 videotestsrc ! avenc_mpeg4 ! rtpmp4vpay - config-interval=1 ! rtpsink uri=rtp://239.1.2.3:5000 gst-launch-1.0 - rtpsrc uri=rtp://239.1.2.3:5000?encoding-name=MP4V-ES ! rtpmp4vdepay - ! avdec_mpeg4 ! videoconvert ! xvimagesink ``` - -- svthevcenc: new SVT-HEVC-based H.265 video encoder - -- switchbin: new helper element which chooses between a set of - processing chains (paths) based on input caps, and changes the - active chain if new caps arrive. Paths are child objects, which are - accessed by the GstChildProxy interface. See the switchbin - documentation for a usage example. - -- vah264dec: new experimental va plugin with an element for H.264 - decoding with VA-API using GStreamer’s new stateless decoder - infrastructure (see Linux section below). - -- v4l2codecs: introduce an V4L2 CODECs Accelerator supporting the new - CODECs uAPI in the Linux kernel (see Linux section below) - -- zxing new plugin to detect QR codes and barcodes, based on libzxing - -- also see the Rust plugins section below which contains plenty of new - exciting plugins written in Rust! +- this section will be filled in in due course New element features and additions -GStreamer core - -- filesink: Add a new “full” buffer mode. Previously the default and - full modes were the same. Now the default mode is like before: it - accumulates all buffers in a buffer list until the threshold is - reached and then writes them all out, potentially in multiple - writes. The new full mode works by always copying memory to a single - memory area and writing everything out with a single write once the - threshold is reached. - -- multiqueue: Add stats property and - current-level-{buffers, bytes, time} pad properties to query the - current levels of the corresponding internal queue. - -Plugins Base - -- alsa: implement a device provider - -- alsasrc: added use-driver-timestamp property to force use of - pipeline timestamps (and disable driver timestamps) if so desired - -- audioconvert: fix changing the mix-matrix property at runtime - -- appsrc: added support for segment forwarding or custom GstSegments - via GstSample, enabled via the handle-segment-change property. This - only works for segments in TIME format for now. - -- compositor: various performance optimisations, checkerboard drawing - fixes, and support for VUYA format - -- encodebin: Fix and refactor smart encoding; ensure that a single - segment is pushed into encoders; improve force-key-unit event - handling. - -- opusenc: Add low delay option (audio-type=restricted-lowdelay) to - disable the SILK layer and achieve only 5ms delay. - -- opusdec: add stats property to retrieve various decoder statistics. - -- uridecodebin3: Let decodebin3 do its stream selection if no one - answers - -- decodebin3: Avoid overriding explicit user selection of streams - -- playbin: add flag to force use of software decoders over any - hardware decoders that might also be available - -- playbin3, playbin: propagate sink context - -- rawvideoparse: Fix tiling support, allow setting colorimetry - -- subparse: output plain utf8 text instead of pango-markup formatted - text if downstream requires it, useful for interop with elements - that only accept utf8-formatted subtitles such as muxers or closed - caption converters. - -- tcpserversrc, tcpclientsrc: add stats property with TCP connection - stats (some are only available on Linux though) - -- timeoverlay: add show-times-as-dates, datetime-format and - datetime-epoch properties to display times with dates - -- videorate: Fix changing rate property during playback; reverse - playback fixes; update QoS events taking into account our rate - -- videoscale: pass through and transform size sensitive metas instead - of just dropping them - -Plugins Good - -- avidemux can handle H.265 video now. Our advice remains to - immediately cease all contact and communication with anyone who - hands you H.265 video in an AVI container, however. - -- avimux: Add support for S24LE and S32LE raw audio and v210 raw video - formats; support more than 2 channels of raw audio. - -- souphttpsrc: disable session sharing and cookie jar when the cookies - property is set; correctly handle seeks past the end of the content - -- deinterlace: new YADIF deinterlace method which should provide - better quality than the existing methods and is LGPL licensed; - alternate fields are supported as input to the deinterlacer as well - now, and there were also fixes for switching the deinterlace mode on - the fly. - -- flvmux: in streamable mode allow adding new pads even if the initial - header has already been written. Old clients will only process the - initial stream, new clients will get a header with the new streams. - The skip-backwards-streams property can be used to force flvmux to - skip and drop a few buffers rather than produce timestamps that go - backward and confuse librtmp-based clients. There’s also better - handling for timestamp rollover when streaming for a long time. - -- imagefreeze: Add live mode, which can be enabled via the new is-live - property. In this mode frames will only be output in PLAYING state - according to the negotiated framerate, skipping frames if the output - can’t keep up (e.g. because it’s blocked downstream). This makes it - possible to actually use imagefreeze in live pipelines without - having to manually ensure somehow that it starts outputting at the - current running time and without still risking to fall behind - without recovery. - -- matroskademux, qtdemux: Provide audio lead-in for some lossy formats - when doing accurate seeks, to make sure we can actually decode - samples at the desired position. This is especially important for - non-linear audio/video editing use-cases. - -- matroskademux, matroskamux: Handle interlaced field order (tff, bff) - -- matroskamux: - - - new offset-to-zero property to offset all streams to start at - zero. This takes the timestamp of the earliest stream and - offsets it so that it starts at 0. Some software (VLC, - ffmpeg-based) does not properly handle Matroska files that start - at timestamps much bigger than zero, which could happen with - live streams. - - added a creation-time property to explicitly set the creation - time to write into the file headers. Useful when remuxing, for - example, but also for live feeds where the DateUTC header can be - set a UTC timestamp corresponding to the beginning of the file. - - the muxer now also always waits for caps on sparse streams, and - warns if caps arrive after the header has already been sent, - otherwise the subtitle track might be silently absent in the - final file. This might affect applications that send sparse data - into matroskamux via an appsrc element, which will usually not - send out the initial caps before it sends out the first buffer. - -- pulseaudio: device provider improvements: fix discovery of - newly-added devices and hide the alsa device provider if we provide - alsa devices - -- qtdemux: raw audio handling improvements, support for AC4 audio, and - key-units trickmode interval support - -- qtmux: - - - was ported to the GstAggregator base class which allows for - better handling of live inputs, but might entail minor - behavioural changes for sparse inputs if inputs are not live. - - has also gained a force-create-timecode-trak property to create - a timecode trak in non-mov flavors, which may not be supported - by Apple but is supported by other software such as Final Cut - Pro X - - also a force-chunks property to force the creation of chunks - even in single-stream files, which is required for Apple ProRes - certification. - - also supports 8k resolutions in prefill mode with ProRes. - -- rtpbin gained a request-jitterbuffer signal which allows - applications to plug in their own jitterbuffer implementation such - as the threadsharing jitterbuffer from the Rust plugins, for - example. - -- rtprtxsend: add clock-rate-map property to allow generic RTP input - caps without a clock-rate whilst still supporting the max-size-time - property for bundled streams. - -- rtpssrcdemux: introduce max-streams property to guard against - attacks where the sender changes SSRC for every RTP packet. - -- rtph264pay, rtph264pay: implement STAP-A and various aggregation - modes controled by the new aggegrate-mode property: none to not - aggregate NAL units (as before), zero-latency to aggregate NAL units - until a VCL or suffix unit is included, or max to aggregate all NAL - units with the same timestamp (which adds one frame of latency). The - default has been kept at none for backwards compatibility reasons - and because various RTP/RTSP implementions don’t handle aggregation - well. For WebRTC use cases this should be set to zero-latency, - however. - -- rtpmp4vpay: add support for config-interval=-1 to resend headers - with each IDR keyframe, like other video payloaders. - -- rtpvp8depay: Add wait-for-keyframe property for waiting until the - next keyframe after packet loss. Useful if the video stream was not - encoded with error resilience enabled, in which case packet loss - tends to cause very bad artefacts when decoding, and waiting for the - next keyframe instead improves user experience considerably. - -- splitmuxsink and splitmuxsrc can now handle auxiliary video streams - in addition to the primary video stream. The primary video stream is - still used to select fragment cut points at keyframe boundaries. - Auxilliary video streams may be broken up at any packet - so - fragments may not start with a keyframe for those streams. - -- splitmuxsink: - - - new muxer-preset and sink-preset properties for setting - muxer/sink presets - - a new start-index property to set the initial fragment id - - and a new muxer-pad-map property which explicitly maps - splitmuxsink pads to the muxer pads they should connect to, - overriding the implicit logic that tries to match pads but - yields arbitrary names. - - Also includes the actual sink element in the fragment-opened and - fragment-closed element messages now, which is especially useful - for sinks without a location property or when finalisation of - the fragments is done asynchronously. - -- videocrop: add support for Y444, Y41B and Y42B pixel formats - -- vp8enc, vp9enc: change default value of VP8E_SET_STATIC_THRESHOLD - from 0 to 1 which matches what Google WebRTC does and results in - lower CPU usage; also added a new bit-per-pixel property to select a - better default bitrate - -- v4l2: add support for ABGR, xBGR, RGBA, and RGBx formats and for - handling interlaced video in alternate fields interlace mode (one - field per buffer instead of one frame per picture with both fields - interleaved) - -- v4l2: Profile and level probing support for H264, H265, MPEG-4, - MPEG-2, VP8, and VP9 video encoders and decoders - -Plugins Ugly - -- asfdemux: extract more metadata: disc number and disc count - -- x264enc: - - - respect YouTube bitrate recommendation when user sets the - YouTube profile preset - - separate high-10 video formats from 8-bit formats to improve - depth negotiation and only advertise suitable input raw formats - for the desired output depth - - forward downstream colorimetry and chroma-site restrictions to - upstream elements - - support more color primaries/mappings - -Plugins Bad - -- av1enc: add threads, row-mt and tile-{columns,rows} properties for - this AOMedia AV1 encoder - -- ccconverter: implement support for CDP framerate conversions - -- ccextractor: Add remove-caption-meta property to remove caption - metas from the outgoing video buffers - -- decklink: add support for 2K DCI video modes, widescreen NTSC/PAL, - and for parsing/outputting AFD/Bar data. Also implement a simple - device provider for Decklink devices. - -- dtlsrtpenc: add rtp-sync property which synchronises RTP streams to - the pipeline clock before passing them to funnel for merging with - RTCP. - -- fdkaac: also decode MPEG-2 AAC; encoder now supports more - multichannel/surround sound layouts - -- hlssink2: add action signals for custom playlist/fragment handling: - Instead of always going through the file system API we allow the - application to modify the behaviour. For the playlist itself and - fragments, the application can provide a GOutputStream. In addition - the sink notifies the application whenever a fragment can be - deleted. - -- interlace: can now output data in alternate fields mode; added field - switching mode for 2:2 field pattern - -- iqa: Add a mode property to enable strict mode that checks that all - the input streams have the exact same number of frames; also - implement the child proxy interface - -- mpeg2enc: add disable-encode-retries property for lower CPU usage - -- mpeg4videoparse: allow re-sending codec config at IDR via - config-interval=-1 - -- mpegtsparse: new alignment property to determine number of TS - packets per output buffer, useful for feeding an MPEG-TS stream for - sending via udpsink. This can be used in combination with the - split-on-rai property that makes sure to start a new output buffer - for any TS packet with the Random Access Indicator set. Also set - delta unit buffer flag on non-random-access buffers. - -- mpegdemux: add an ignore-scr property to ignore the SCR in - non-compliant MPEG-PS streams with a broken SCR, which will work as - long as PTS/DTS in the PES header is consistently increasing. - -- tsdemux: - - - add an ignore-pcr property to ignore MPEG-TS streams with broken - PCR streams on which we can’t reliably recover correct - timestamps. - - new latency property to allow applications to lower the - advertised worst-case latency of 700ms if they know their - streams support this (must have timestamps in higher frequency - than required by the spec) - - support for AC4 audio - -- msdk - Intel Media SDK plugin for hardware-accelerated video - decoding and encoding on Windows and Linux: - - - mappings for more video formats: Y210, Y410, P012_LE, Y212_LE - - encoders now support bitrate changes and input format changes in - playing state - - msdkh264enc, msdkh265enc: add support for CEA708 closed caption - insertion - - msdkh264enc, msdkh265enc: set Region of Interest (ROI) region - from ROI metas - - msdkh264enc, msdkh265enc: new tune property to enable low-power - mode - - msdkh265enc: add support 12-bit 4:2:0 encoding and 8-bit 4:2:2 - encoding and VUYA, Y210, and Y410 as input formats - - msdkh265enc: add support for screen content coding extension - - msdkh265dec: add support for main-12/main-12-intra, - main-422-10/main-422-10-intra 10bit, - main-422-10/main-422-10-intra 8bit, - main-422-12/main-422-12-intra, main-444-10/main-444-10-intra, - main-444-12/main-444-12-intra, and main-444 profiles - - msdkvp9dec: add support for 12-bit 4:4:4 - - msdkvpp: add support for Y410 and Y210 formats, cropping via - properties, and a new video-direction property. - -- mxf: Add support for CEA-708 CDP from S436 essence tracks. mxfdemux - can now handle Apple ProRes - -- nvdec: add H264 + H265 stateless codec implementation nvh264sldec - and nvh265sldec with fewer features but improved latency. You can - set the environment variable GST_USE_NV_STATELESS_CODEC=h264 to use - the stateless decoder variant as nvh264dec instead of the “normal” - NVDEC decoder implementation. - -- nvdec: add support for 12-bit 4:4:4/4:2:0 and 10-bit 4:2:0 decoding - -- nvenc: - - - add more rate-control options, support for B-frame encoding (if - device supports it), an aud property to toggle Access Unit - Delimiter insertion, and qp-{min,max,const}-{i,p,b} properties. - - the weighted-pred property enables weighted prediction. - - support for more input formats, namely 8-bit and 10-bit RGB - formats (BGRA, RGBA, RGB10A2, BGR10A2) and YV12 and VUYA. - - on-the-fly resolution changes are now supported as well. - - in case there are multiple GPUs on the system, there are also - per-GPU elements registered now, since different devices will - have different capabilities. - - nvh265enc can now support 10-bit YUV 4:4:4 encoding and 8-bit - 4:4:4 / 10-bit 4:2:0 formats up to 8K resolution (with some - devices). In case of HDR content HDR related SEI nals will be - inserted automatically. - -- openjpeg: enable multi-threaded decoding and add support for - sub-frame encoding (for lower latency) - -- rtponviftimestamp: add opt-out “drop-out-of-segment” property - -- spanplc: new stats property - -- srt: add support for IPv6 and for using hostnames instead of IP - addresses; add streamid property, but also allow passing the id via - the stream URI; add wait-for-connection property to srtsink - -- timecodestamper: this element was rewritten with an updated API - (properties); it has gained many new properties, seeking support and - support for linear timecode (LTC) from an audio stream. - -- uvch264src now comes with a device provider to advertise available - camera sources that support this interface (mostly Logitech C920s) - -- wpe: Add software rendering support and support for mouse scroll - events - -- x265enc: support more 8/10/12 bits 4:2:0, 4:2:2 and 4:4:4 profiles; - add support for mastering display info and content light level - encoding SEIs - -gst-libav - -- Add mapping for SpeedHQ video codec used by NDI - -- Add mapping for aptX and aptX-HD - -- avivf_mux: support VP9 and AV1 - -- avvidenc: shift output buffer timestamps and output segment by 1h - just like x264enc does, to allow for negative DTS. - -- avviddec: Limit default number of decoder threads on systems with - more than 16 cores, as the number of threads used in avdec has a - direct impact on the latency of the decoder, which is of as many - frames as threads, so a large numbers of threads can make for - latency levels that can be problematic in some applications. - -- avviddec: Add thread-type property that allows applications to - specify the preferred multithreading method (auto, frame, slice). - Note that thread-type=frame may introduce additional latency - especially in live pipelines, since it introduces a decoding delay - of number of thread frames. +- this section will be filled in in due course Plugin and library moves -- There were no plugin moves or library moves in this cycle. +- this section will be filled in in due course -- The rpicamsrc element was moved into -good from an external - repository on github. +- There were no plugin moves or library moves in this cycle. Plugin removals The following elements or plugins have been removed: -- The yadif video deinterlacing plugin from gst-plugins-bad, which was - one of the few GPL licensed plugins, has been removed in favour of - deinterlace method=yadif. - -- The avdec_cdgraphics CD Graphics video decoder element from - gst-libav was never usable in GStreamer and we now have a cdgdec - element written in Rust in gst-plugins-rs to replace it. - -- The VDPAU plugin has been unmaintained and unsupported for a very - long time and does not have the feature set we expect from - hardware-accelerated video decoders. It’s been superseded by the - nvcodec plugin leveraging NVIDIA’s NVDEC API. +- this section will be filled in in due course Miscellaneous API additions -GStreamer core - -- gst_task_resume(): This new API allows resuming a task if it was - paused, while leaving it in stopped state if it was stopped or not - started yet. This can be useful for callback-based driver workflows, - where you basically want to pause and resume the task when buffers - are notified while avoiding the race with a gst_task_stop() coming - from another thread. - -- info: add printf extensions GST_TIMEP_FORMAT and GST_STIMEP_FORMAT - for printing GstClockTime/GstClockTimeDiff pointers, which is much - more convenient to use in debug log statements than the usual - GST_TIME_FORMAT-followed-by-GST_TIME_ARGS dance. Also add an - explicit GST_STACK_TRACE_SHOW_NONE enum value. - -- gst_element_get_current_clock_time() and - gst_element_get_current_running_time(): new helper functions for - getting an element clock’s time, and the clock time minus base time, - respectively. Useful when adding additional input branches to - elements such as compositor, audiomixer, flvmux, interleave or - input-selector to determine initial pad offsets and such. - -- seeking: Add GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED to just skip - B-frames during trick mode, showing both keyframes + P-frame, and - add support for it in h264parse and h265parse. - -- elementfactory: add GST_ELEMENT_FACTORY_TYPE_HARDWARE to allow - elements to advertise that they are hardware-based or interact with - hardware. This has multiple applications: - - - it makes it possible to easily differentiate hardware and - software based element implementations such as audio or video - encoders and decoders. This is useful in order to force the use - of software decoders for specific use cases, or to check if a - selected decoder is actually hardware-accelerated or not. - - elements interacting with hardware and their respective drivers - typically don’t know the actually supported capabilities until - the element is set into at least READY state and can open a - device handle and probe the hardware. - -- gst_uri_from_string_escaped(): identical to gst_uri_from_string() - except that the userinfo and fragment components of the URI will not - be unescaped while parsing. This is needed for correctly parsing - usernames or passwords with : in them . - -- paramspecs: new GstParamSpec flag GST_PARAM_CONDITIONALLY_AVAILABLE - to indicate that a property might not always exist. - -- gst_bin_iterate_all_by_element_factory_name() finds elements in a - bin by factory name - -- pad: gst_pad_get_single_internal_link() is a new convenience - function to return the single internal link of a pad, which is - useful e.g. to retrieve the output pad of a new multiqueue request - pad. - -- datetime: Add constructors to create datetimes with timestamps in - microseconds, gst_date_time_new_from_unix_epoch_local_time_usecs() - and gst_date_time_new_from_unix_epoch_utc_usecs(). - -- gst_debug_log_get_lines() gets debug log lines formatted in the same - way the default log handler would print them - -- GstSystemClock: Add GST_CLOCK_TYPE_TAI as GStreamer abstraction for - CLOCK_TAI, to support transmission offloading features where network - packets are timestamped with the time they are deemed to be actually - transmitted. Useful in combination with the new AVTP plugin. - -- miscellaneous utility functions: gst_clear_uri(), - gst_structure_take(). - -- harness: Added gst_harness_pull_until_eos() - -- GstBaseSrc: - - - gst_base_src_new_segment() allows subclasses to update the - segment to be used at runtime from the ::create() function. This - deprecates gst_base_src_new_seamless_segment() - - gst_base_src_negotiate() allows subclasses to trigger format - renegotiation at runtime from inside the ::create() or ::alloc() - function - -- GstBaseSink: new stats property and gst_base_sink_get_stats() method - to retrieve various statistics such as average frame rate and - dropped/rendered buffers. - -- GstBaseTransform: gst_base_transform_reconfigure() is now public - API, useful for subclasses that need to completely re-implement the - ::submit_input_buffer() virtual method - -- GstAggregator: - - - gst_aggregator_update_segment() allows subclasses to update the - output segment at runtime. Subclasses should use this function - rather than push a segment event onto the source pad directly. - - new sample selection API: - - subclasses should now call gst_aggregator_selected_samples() - from their ::aggregate() implementation to signal that they - have selected the next samples they will aggregate - - GstAggregator will then emit the samples-selected signal - where handlers can then look up samples per pad via - gst_aggregator_peek_next_sample(). - - This is useful for example to atomically update input pad - properties in mixer subclasses such as compositor. - Applications can now update properties with precise control - of when these changes will take effect, and for which input - buffer(s). - - gst_aggregator_finish_buffer_list() allows subclasses to push - out a buffer list, improving efficiency in some cases. - - a ::negotiate() virtual method was added, for consistency with - other base classes and to allow subclasses to completely - override the negotiation behaviour. - - the new ::sink_event_pre_queue() and ::sink_query_pre_queue() - virtual methods allow subclasses to intercept or handle - serialized events and queries before they’re queued up - internally. - -GStreamer Plugins Base Libraries - -Audio library - -- audioaggregator, audiomixer: new output-buffer-duration-fraction - property which allows use cases such as keeping the buffers output - by compositor on one branch and audiomixer on another perfectly - aligned, by requiring the compositor to output a n/d frame rate, and - setting output-buffer-duration-fraction to d/n on the audiomixer. - -- GstAudioDecoder: new max-errors property so applications can - configure at what point the decoder should error out, or tell it to - just keep going - -- gst_audio_make_raw_caps() and gst_audio_formats_raw() are - bindings-friendly versions of the GST_AUDIO_CAPS_MAKE() C macro. - -- gst_audio_info_from_caps() now handles encoded audio formats as well - -PbUtils library - -- GstEncodingProfile: - - Do not restrict number of similar profiles in a container - - add GstValue serialization function -- codec utils now support more H.264/H.265 profiles/levels and have - improved extension handling - -RTP library - -- rtpbasepayloader: Add scale-rtptime property for scaling RTP - timestamp according to the segment rate (equivalent to RTSP speed - parameter). This is useful for ONVIF trickmodes via RTSP. - -- rtpbasepayload: add experimental property for embedding twcc - sequencenumbers for Transport-Wide Congestion Control (gated behind - the GST_RTP_ENABLE_EXPERIMENTAL_TWCC_PROPERTY environment - variable) - more generic API for enabling this is expected to land - in the next development cycle. - -- rtcpbuffer: add RTPFB_TYPE_TWCC for Transport-Wide Congestion - Control - -- rtpbuffer: add - gst_rtp_buffer_get_extension_onebyte_header_from_bytes()``, so that one can parse theGBytes` - returned by gst_rtp_buffer_get_extension_bytes() - -- rtpbasedepayload: Add max-reorder property to make the - previously-hardcoded value when to consider a sender to have - restarted configurable. In some scenarios it’s particularly useful - to set max-reorder=0 to disable the behaviour that the depayloader - will drop packets: when max-reorder is set to 0 all - reordered/duplicate packets are considered coming from a restarted - sender. - -RTSP library - -- add gst_rtsp_url_get_request_uri_with_control() to create request - uri combined with control url - -- GstRTSPConnection: add the possibility to limit the Content-Length - for RTSP messages via - gst_rtsp_connection_set_content_length_limit(). The same - functionality is also exposed in gst-rtsp-server. - -SDP library - -- add support for parsing the extmap attribute from caps and storing - inside caps The extmap attribute allows mapping RTP extension header - IDs to well-known RTP extension header specifications. See RFC8285 - for details. - -Tags library - -- update to latest iso-code and support more languages - -- add tags for acoustid id & acoustid fingerprint, plus MusicBrainz ID - handling fixes - -Video library - -- High Dynamic Range (HDR) video information representation and - signalling enhancements: - - - New APIs for HDR video information representation and - signalling: - - GstVideoMasteringDisplayInfo: display color volume info as - per SMPTE ST 2086 - - GstVideoContentLightLevel: content light level specified in - CEA-861.3, Appendix A. - - plus functions to serialise/deserialise and add them to or - parse them from caps - - gst_video_color_{matrix,primaries,transfer}_{to,from}_iso(): - new utilility functions for conversion from/to ISO/IEC - 23001-8 - - add ARIB STD-B67 transfer chracteristic function - - add SMPTE ST 2084 support and BT 2100 colorimetry - - define bt2020-10 transfer characteristics for clarity: - bt707, bt2020-10, and bt2020-12 transfer characteristics are - functionally identical but have their own unique values in - the specification. - - h264parse, h265parse: Parse mastering display info and content - light level from SEIs. - - matroskademux: parse HDR metadata - - matroskamux: Write MasteringMetadata and Max{CLL,FALL}. Enable - muxing with HDR meta data if upstream provided it - - avviddec: Extract HDR information if any and map bt2020-10, PQ - and HLG transfer functions - -- added bt601 transfer function (for completeness) - -- support for more pixel formats: - - - Y412 (packed 12 bits 4:4:4:4) - - Y212 (packed 12 bits 4:2:2) - - P012 (semi-planar 4:2:0) - - P016_{LE,BE} (semi-planar 16 bits 4:2:0) - - Y444_16{LE,BE} (planar 16 bits 4:4:4) - - RGB10A2_LE (packed 10-bit RGB with 2-bit alpha channel) - - NV12_32L32 (NV12 with 32x32 tiles in linear order) - - NV12_4L4 (NV12 with 4x4 tiles in linear order) - -- GstVideoDecoder: - - - new max-errors property so applications can configure at what - point the decoder should error out, or tell it to just keep - going - - - new qos property to disable dropping frames because of QoS, and - post QoS messages on the bus when dropping frames. This is - useful for example in a scenario where the decoded video is - tee-ed off to go into a live sink that syncs to the clock in one - branch, and an encoding and save to file pipeline in the other - branch. In that case one wouldn’t want QoS events from the video - sink make the decoder drop frames because that would also leave - gaps in the encoding branch then. - -- GstVideoEncoder: - - - gst_video_encoder_finish_subframe() is new API to push out - subframes (e.g. slices), so encoders can split the encoding into - subframes, which can be useful to reduce the overall end-to-end - latency as we no longer need to wait for the full frame to be - encoded to start decoding or sending out the data. - - new min-force-key-unit-interval property allows configuring the - minimum interval between force-key-unit requests and prevents a - big bitrate increase if a lot of key-units are requested in a - short period of time (as might happen in live streaming RTP - pipelines when packet loss is detected). - - various force-key-unit event handling fixes - -- GstVideoAggregator, compositor, glvideomixer: expose - max-last-buffer-repeat property on pads. This can be used to have a - compositor display either the background or a stream on a lower - zorder after a live input stream freezes for a certain amount of - time, for example because of network issues. - -- gst_video_format_info_component() is new API to find out which - components are packed into a given plane, which is useful to prevent - us from assuming a 1-1 mapping between planes and components. - -- gst_video_make_raw_caps() and gst_video_formats_raw() are - bindings-friendly versions of the GST_VIDEO_CAPS_MAKE() C macro. - -- video-blend: Add support for blending on top of 16 bit per component - formats, which makes sure we can support every currently supported - raw video format for blending subtitles or logos on top of video. - -- GST_VIDEO_BUFFER_IS_TOP_FIELD() and - GST_VIDEO_BUFFER_IS_BOTTOM_FIELD() convenience macros to check - whether the video buffer contains only the top field or bottom field - of an interlaced picture. - -- GstVideoMeta now includes an alignment field with the - GstVideoAlignment so buffer producers can explicitly specify the - exact geometry of the planes, allowing users to easily know the - padded size and height of each plane. Default values will be used if - this is not set. - - Use gst_video_meta_set_alignment() to set the alignment and - gst_video_meta_get_plane_size() or gst_video_meta_get_plane_height() - to compute the plane sizes or plane heights based on the information - in the video meta. - -- gst_video_info_align_full() works like gst_video_info_align() but - also retrieves the plane sizes. - -MPEG-TS library - -- support for SCTE-35 sections - -- extend support for ATSC tables: - - - System Time Table (STT) - - Master Guide Table (MGT) - - Rating Region Table (RRT) +- this section will be filled in in due course Miscellaneous performance, latency and memory optimisations -As always there have been many performance and memory usage improvements -across all components and modules. Some of them have already been -mentioned elsewhere so won’t be repeated here. - -The following list is only a small snapshot of some of the more -interesting optimisations that haven’t been mentioned in other contexts -yet: - -- caps negotiation, structure and GValue performance optimizations - -- systemclock: clock waiting performance improvements (moved from - GstPoll to GCond for waiting), especially on Windows. - -- rtpsession: add support for buffer lists on the recv path for better - performance with higher packet rate streams. - -- rtpjitterbuffer: internal timer handling has been rewritten for - better performance, see Nicolas’ talk “Revisiting RTP Jitter Buffer - Timers” for more details. - -- H.264/H.265 parsers and RTP payloaders/depayloaders have been - optimised for latency to make sure data is processed and pushed out - as quickly as possible - -- video-scaler: correctness and performance improvements, esp. for - interlaced formats and GBRA - -- GstVideoEncoder has gained new API to push out subframes - (e.g. slices), so encoders can split the encoding into subframes, - which can be useful to reduce the overall end-to-end latency as we - no longer need to wait for the full frame to be encoded to start - decoding or sending out the data. - - This is complemented by the new GST_VIDEO_BUFFER_FLAG_MARKER which - is a video-specific buffer flag to mark the end of a video frame, so - elements can know that they have received all data for a frame - without waiting for the beginning of the next frame. This is similar - to how the RTP marker flag is used in many RTP video mappings. - - The video encoder base class now also releases the internal stream - lock before pushing out data, so as to not block the input side of - things from processing more data in the meantime. +- this section will be filled in in due course Miscellaneous other changes and enhancements -- it is now possible to modify the initial rank of plugin features - without modifying the source code or writing code to do so - programmatically via the GST_PLUGIN_FEATURE_RANK environment - variable. Users can adjust the rank of plugin(s) by passing a - comma-separated list of feature:rank pairs where rank can be a - numerical value or one of NONE, MARGINAL, SECONDARY, PRIMARY, and - MAX. Example: GST_PLUGIN_FEATURE_RANK=myh264dec:MAX,avdec_h264:NONE - sets the rank of the myh264dec element feature to the maximum and - that of avdec_h264 to 0 (none), thus ensuring that myh264dec is - prefered as H264 decoder in an autoplugging context. - -- GstDeviceProvider now does a static probe on start as fallback for - providers that don’t support dynamic probing to make things easier - for users - -WebRTC - -- webrtcbin now contains initial support for renegotiation involving - stream addition and removal. There are a number of caveats to this - initial renegotiation support and many complex scenarios are known - to require some work. - -- webrtcbin now exposes the internal ICE object for advanced - configuration options. Using the internal ICE object, it is possible - to toggle UDP or TCP connection usage as well as provide local - network addresses. - -- Fix a number of call flows within webrtcbin’s GstPromise handling - where a promise was never replied to. This has been fixed and now a - promise will always receive a reply. - -- webrtcbin now exposes a latency property for configuring the - internal rtpjitterbuffer latency and buffering when receiving - streams. - -- webrtcbin now only synchronises the RTP part of a stream, allowing - RTCP messages to skip synchronisation entirely. - -- Fixed most of the webrtcbin state properties (connection-state, - ice-connection-state, signaling-state, but not ice-gathering-state - as that requires newer API in libnice and will be fixed in the next - release series) to advance through the state values correctly. Also - implemented DTLS connection states in the DTLS elements so that - peer-connection-state is not always new. - -- webrtcbin now accounts for the a=ice-lite attribute in a remote SDP - offer and will configure the internal ICE implementation - accordingly. - -- webrtcbin will now resolve .local candidate addresses using the - system DNS resolver. .local candidate addresses are now produced by - web browsers to help protect the privacy of users. - -- webrtcbin will now add candidates found in the SDP to the internal - ICE agent. This was previously unsupported and required using the - add-ice-candidate signal manually from the application. - -- webrtcbin will now correctly parse a TURN URI that contains a - username or password with a : in it. - -- The GStreamer WebRTC library gained a GstWebRTCDataChannel object - roughly matching the interface exposed by the WebRTC specification - to allow for easier binding generation and use of data channels. - -OpenGL integration - -GStreamer OpenGL bindings/build related changes - -- The GStreamer OpenGL library (libgstgl) now ships pkg-config files - for platform-specific API where libgstgl provides a public - integration interface and a pkg-config file for a dependency on the - detected OpenGL headers. The new list of pkg-config files in - addition to the original gstreamer-gl-1.0 are gstreamer-gl-x11-1.0, - gstreamer-gl-wayland-1.0, gstreamer-gl-egl-1.0, and - gstreamer-gl-prototypes-1.0 (for OpenGL headers when including - gst/gl/gstglfuncs.h). - -- GStreamer OpenGL now ships some platform-specific introspection data - for platforms that have a public interface. This should allow for - easier integration with bindings involving platform specific - functionality. The new introspection data files are named - GstGLX11-1.0, GstGLWayland-1.0, and GstGLEGL-1.0. - -GStreamer OpenGL Features - -- The iOS implementation no longer accesses UIKit objects off the main - thread fixing a loud warning message when used in iOS applications. - -- Support for mouse and keyboard handling using the GstNavigation - interface was added for the wayland implementation complementing the - already existing support for the X11 and Windows implementations. - -- A new helper base class for source elements, GstGLBaseSrc is - provided to ease writing source elements producing OpenGL video - frames. - -- Support for some more 12-bit and 16-bit video formats (Y412_LE, - Y412_BE, Y212_LE, Y212_BE, P012_LE, P012_BE, P016, NV16, NV61) was - added to glcolorconvert. - -- glupload can now import dma-buf’s into external-oes textures. - -- A new display type for EGLDevice-based systems was added. It is - currently opt-in by using either the GST_GL_PLATFORM=egl-device - environment variable or manual construction - (gst_gl_display_egl_device_new*()) due to compatibility issues with - some platforms. - -- Support was added for WinRT/UWP using the ANGLE project for running - OpenGL-based pipelines within a UWP application. - -- Various elements now support changing the GstGLDisplay to be used at - runtime in simple cases. This is primarily helpful for changing or - adding an OpenGL-based video sink that must share an OpenGL context - with an external source to an already running pipeline. - -GStreamer Vulkan integration - -- There is now a GStreamer Vulkan library to provide integration - points and helpers with applications and external GStreamer Vulkan - based elements. The structure of the library is modelled similarly - to the already existing GStreamer OpenGL library. Please note that - the API is still unstable and may change in future releases, - particularly around memory handling. The GStreamer Vulkan library - contains objects for sharing the vkInstance, vkDevice, vkQueue, - vkImage, VkMemory, etc with other elements and/or the application as - well as some helper objects for using Vulkan in an application or - element. - -- Added support for building and running on/for the Android and - Windows systems to complement the existing XCB, Wayland, MacOS, and - iOS implementations. - -- XCB gained support for mouse/keyboard events using the GstNavigation - API. - -- New vulkancolorconvert element for converting between color formats. - vulkancolorconvert can currently convert to/from all 8-bit RGBA - formats as well as 8-bit RGBA formats to/from the YUV formats AYUV, - NV12, and YUY2. - -- New vulkanviewconvert element for converting between stereo view - layouts. vulkanviewconvert can currently convert between all of the - single memory formats (side-by-side, top-bottom, column-interleaved, - row-interleaved, checkerboard, left, right, mono). - -- New vulkanimageidentity element for a blit from the input vulkan - image/s to a new vulkan image/s. - -- The vulkansink element can now scale the input image to the output - window/surface size where that information is available. - -- The vulkanupload element can now configure a transfer from system - memory to VulkanImage-based memory. Previously, this required two - vulkanupload elements. +- this section will be filled in in due course Tracing framework and debugging improvements -- gst_tracing_get_active_tracers() returns a list of active tracer - objects. This can be used to interact with tracers at runtime using - GObject API such as action signals. This has been implemented in the - leaks tracer for snapshotting and retrieving leaked/active objects - at runtime. - -- The leaks tracer can now be interacted with programmatically at - runtime via GObject action signals: - - - get-live-object returns a list of live (allocated) traced - objects - - log-live-objects logs a list of live objects into the debug log. - This is the same as sending the SIGUSR1 signal on unix systems, - but works on all operating systems including Windows. - - activity-start-tracking, activity-get-checkpoint, - activity-log-checkpoint, activity-stop-tracking: add support for - tracking and checkpointing objects, similar to what was - previously available via SIGUSR2 on unix systems, but works on - all operating systems including Windows. - -- various GStreamer gdb debug helper improvements: - - - new ‘gst-pipeline-tree’ command - - more gdb helper functions: gst_element_pad(), gst_pipeline() and - gst_bin_get() - - support for queries and buffers - - print more info for segment events, print event seqnums, object - pointers and structures - - improve gst-print command to show more pad and element - information +- this section will be filled in in due course Tools -gst-launch-1.0 - -- now prints the pipeline position and duration if available when the - pipeline is advancing. This is hopefully more user-friendly and - gives visual feedback on the terminal that the pipeline is actually - up and running. This can be disabled with the --no-position command - line option. - -- the parse-launch pipeline syntax now has support for presets: - use@preset=" after an element to load a preset. - -gst-inspect-1.0 - -- new --color command line option to force coloured output even if not - connected to a tty - -gst-tester-1.0 (new) - -- gst-tester-1.0 is a new tool for plugin developers to launch - .validatetest files with TAP compatible output, meaning it can - easily and cleanly be integrated with the meson test harness. It - allows you to use gst-validate (from the gst-devtools module) to - write integration tests in any GStreamer repository whilst keeping - the tests as close as possible to the code. The tool transparently - handles gst-validate being installed or not: if it is not installed - those integration tests will simply be skipped. - -gst-play-1.0 - -- interactive keyboard controls now also work on Windows - -gst-transcoder-1.0 (new) - -- gst-transcoder-1.0 is a new command line tool to transcode one URI - into another URI based on the specified encoding profile using the - new GstTranscoder API (see above). +- this section will be filled in in due course GStreamer RTSP server -- Fix issue where the first few packets (i.e. keyframes) could - sometimes be dropped if the rtsp media pipeline had a live input. - This was a regression from GStreamer 1.14. There are more fixes - pending for that which will hopefully land in 1.18.1. - -- Fix backpressure handling when sending data in TCP interleave mode - where RTSP requests and responses and RTP/RTCP packets flow over the - same RTSP TCP connection: The previous implementation would at some - point stop sending data to other clients when a single client - stopped consuming data or did not consume data fast enough. This - obviously created problems for shared media, where the same stream - from a single producer pipeline is sent to multiple clients. Instead - we now manage a backlog in the server’s stream-transport component - and remove slow clients once this backlog exceeds a maximum duration - (which is currently hardcoded). - -- Onvif Streaming Specification trick modes support (see section at - the beginning) - -- Scale/Speed header support: Speed will deliver the data at the - requested speed, which means increasing the data bandwidth for - speeds > 1.0. Scale will attempt to do the same without affecting - the overall bandwidth requirement vis-a-vis normal playback speed - (e.g. it might drop data for fast-forward playback). - -- rtspclientsink: send buffer lists in one go for better performance +- this section will be filled in in due course GStreamer VAAPI -- A lot of work was done adding support for media-driver (iHD), the - new VAAPI driver for Intel, mostly for Gen9 onwards. - -- Available color formats and frame sizes are now detected at run-time - according to the context configuration. - -- Gallium drivers have been re-enabled in the allowed drivers list - -- Improved the mapping between VA formats and GStreamer formats by - generating a mapping table at run-time since even among different - drivers the mapping might be different, particularly for RGB with - little endianness. - -- The experimental Flexible Encoding Infrastructure (FEI) elements - have been removed since they were not really actively maintained or - tested. - -- Enhanced the juggling of DMABuf buffers and VASurface metas - -- New vaapioverlay element: a compositor element using VA VPP blend - capabilities to accelerate overlaying and compositing. Example - pipeline: - - gst-launch-1.0 -vf videotestsrc ! vaapipostproc ! tee name=testsrc ! queue \ - ! vaapioverlay sink_1::xpos=300 sink_1::alpha=0.75 name=overlay ! vaapisink \ - testsrc. ! queue ! overlay. - -vaapipostproc - -- added video-orientation support, supporting frame mirroring and - rotation - -- added cropping support, either via properties (crop-left, - crop-right, crop-bottom and crop-top) or buffer meta. - -- new skin-tone-enhancenment-level property which is the iHD - replacement of the i965 driver’s sink-tone-level. Both are - incompatible with each other, so both were kept. - -- handle video colorimetry - -- support HDR10 tone mapping - -vaapisink - -- resurrected wayland backend for non-weston compositors by extracting - the DMABuf from the VASurface and rendering it. - -- merged the video overlay API for wayland. Now applications can - define the “window” to render on. - -- demoted the vaapisink element to secondary rank since libva - considers rendering as a second-class feature. - -VAAPI Encoders - -- new common target-percentage property which is the desired target - percentage of bitrate for variable rate control. - -- encoders now extract their caps from the driver at registration - time. - -- vaapivp9enc: added support for low power mode and support for - profile 2 (profile 0 by default) - -- vaapih264enc: new max-qp property that sets the maximum quantization - value. Support for ICQ and QBVR bitrate control mode, adding a - quality-factor property for these modes. Support baseline profile as - constrained-baseline - -- vaapih265enc: - - - support for main-444 and main-12 encoding profiles. - - new max-qp property that sets the maximum quantization value. - - support for ICQ and QBVR bitrate control mode, adding a - quality-factor property for these modes. - - handle SCC profiles. - - num-tile-cols and num-tile-row properties to specify the number - of tiles to use. - - the low-delay-b property was deprecated and is now determined - automatically. - - improved profile selection through caps. - -VAAPI Decoders - -- Decoder surfaces are not bound to their context any longer and can - thus be created and used dynamically, removing the deadlock - headache. - -- Reverse playback is now fluid - -- Forward Region-of-Interest (ROI) metas downstream - -- GLTextureUploadMeta uses DMABuf when GEM is not available. Now - Gallium drivers can use this meta for rendering with EGL. - -- vaapivp9dec: support for 4:2:2 and 4:4:4 chroma type streams - -- vaapih265dec: skip all pictures prior to the first I-frame. Enable - passing range extension flags to the driver. Handle SCC profiles. - -- vaapijpegdec: support for 4:0:0, 4:1:1, 4:2:2 and 4:4:4 chroma types - pictures - -- vaapih264dec: handle baseline streams as constrained-baseline if - possible and make it more tolerant when encountering unknown NALs +- this section will be filled in in due course GStreamer OMX -- omxvideoenc: use new video encoder subframe API to push out slices - as soon as they’re ready - -- omxh264enc, omxh265enc: negotiate subframe mode via caps. To enable - it, force downstream caps to video/x-h264,alignment=nal or - video/x-h265,alignment=nal. - -- omxh264enc: Add ref-frames property - -- Zynq ultrascale+ specific video encoder/decoder improvements: - - - GRAY8 format support - - support for alternate fields interlacing mode - - video encoder: look-ahead, long-term-ref, and long-term-freq - properties +- this section will be filled in in due course GStreamer Editing Services and NLE -- Added nested timelines and subproject support so that GES projects - can be used as clips, potentially serializing nested projects in the - main file or referencing external project files. - -- Implemented an OpenTimelineIO GES formatter. This means GES and - GStreamer can now load and save projects in all the formats - supported by otio. - -- Implemented a GESMarkerList object which allow setting timed - metadata on any GES object. - -- Fixed audio rendering issues during clip transition by ensuring that - a single segment is pushed into encoders. - -- The GESUriClipAsset API is now MT safe. - -- Added ges_meta_container_register_static_meta() to allow fixing a - type for a specific metadata without actually setting a value. - -- The framepositioner element now handles resizing the project and - keeps the same positioning when the aspect ratio is not changed . - -- Reworked the documentation, making it more comprehensive and much - more detailed. - -- Added APIs to retrieve natural size and framerate of a clip (for - example in the case of URIClip it is the framerate/size of the - underlying file). - -- ges_container_edit() is now deprecated and GESTimelineElement gained - the ges_timeline_element_edit() method so the editing API is now - usable from any element in the timeline. - -- GESProject::loading was added so applications can be notified about - when a new timeline starts loading. - -- Implemented the GstStream API in GESTimeline. - -- Added a way to add a timeoverlay inside the test source (potentially - with timecodes). - -- Added APIs to convert times to frame numbers and vice versa: - - - ges_timeline_get_frame_time() - - - ges_timeline_get_frame_at() - - - ges_clip_asset_get_frame_time() - - - ges_clip_get_timeline_time_from_source_frame() - - Quite a few validate tests have been implemented to check the - behavior for various demuxer/codec formats - -- Added ges_layer_set_active_for_tracks() which allows muting layers - for the specified tracks - -- Deprecated GESImageSource and GESMultiFileSource now that we have - imagesequencesrc which handles the imagesequence “protocol” - -- Stopped exposing ‘deinterlacing’ children properties for clip types - where they do not make sense. - -- Added support for simple time remapping effects +- this section will be filled in in due course GStreamer validate -- Introduced the concept of “Test files” allowing to implement “all - included” test cases, meaning that inside the file the following can - be defined: - - - The application arguments - - The validate configurations - - The validate scenario - - This replaces the previous big dictionary file in - gst-validate-launcher to implement specific test cases. - - We set several variables inside the files (as well as inside - scenarios and config files) to make them relocatable. - - The file format has been enhanced so it is easier to read and write, - for example line ending with a coma or (curly) brackets can now be - used as continuation marker so you do not need to add \ at the end - of lines to write a structure on several lines. - -- Support the imagesequence “protocol” and added integration tests for - it. - -- Added action types to allow the scenario to run the Test Clock for - better reproducibility of tests. - -- Support generating tests to check that seeking is frame accurate - (base on ssim). - -- Added ways to record buffers checksum (in different ways) in the - validateflow module. - -- Added vp9 encoding tests. - -- Enhanced seeking action types implementation to allow support for - segment seeks. - -- Output improvements: - - - Logs are now in markdown formats (and bat is used to dump them - if available). - - File format issues in scenarios/configs/tests files are nicely - reported with the line numbers now. +- this section will be filled in in due course GStreamer Python Bindings -- Python 2.x is no longer supported - -- Support mapping buffers without any memcpy: - - - Added a ContextManager to make the API more pythonic - - with buf.map(Gst.MapFlags.READ | Gst.MapFlags.WRITE) as info: - info.data[42] = 0 - -- Added high-level helper API for constructing pipelines: - - - Gst.Bin.make_and_add(factory_name, instance_name=None) - - Gst.Element.link_many(element, ...) +- this section will be filled in in due course GStreamer C# Bindings -- Bind gst_buffer_new_wrapped() manually to fix memory handling. - -- Fix gst_promise_new_with_change_func() where bindgen didn’t properly - detect the func as a closure. - -- Declare GstVideoOverlayComposition and GstVideoOverlayRectangle as - opaque type and subclasses of Gst.MiniObject. This changes the API - but without this all usage will cause memory corruption or simply - not work. - -- on Windows, look for gstreamer, glib and gobject DLLs using the MSVC - naming convention (i.e. gstvideo-1.0-0.dll instead of - libgstvideo-1.0-0.dll). - - The names of these DLLs have to be hardcoded in the bindings, and - most C# users will probably be using the Microsoft toolchain anyway. - - This means that the MSVC compiler is now required to build the - bindings, MingW will no longer work out of the box. +- this section will be filled in in due course GStreamer Rust Bindings and Rust Plugins The GStreamer Rust bindings are released separately with a different release cadence that’s tied to gtk-rs, but the latest release has -already been updated for the new GStreamer 1.18 API, so there’s -absolutely no excuse why your next GStreamer application can’t be -written in Rust anymore. +already been updated for the upcoming new GStreamer 1.20 API. gst-plugins-rs, the module containing GStreamer plugins written in Rust, has also seen lots of activity with many new elements and plugins. @@ -1659,6 +119,8 @@ What follows is a list of elements and plugins available in gst-plugins-rs, so people don’t miss out on all those potentially useful elements that have no C equivalent. +- FIXME: add new elements + Rust audio plugins - audiornnoise: New element for audio denoising which implements the @@ -1724,73 +186,11 @@ Generic Rust plugins Build and Dependencies -- The Autotools build system has finally been removed in favour of the - Meson build system. Developers who currently use gst-uninstalled - should move to gst-build. - -- API and plugin documentation are no longer built with gtk_doc. The - gtk_doc documentation has been removed in favour of a new unified - documentation module built with hotdoc (also see “Documentation - improvements” section below). Distributors should use the - documentation release tarball instead of trying to package hotdoc - and building the documentation from scratch. - -- gst-plugins-bad now includes an internal copy of libusrsctp, as - there are problems in usrsctp with global shared state, lack of API - stability guarantees, and the absence of any kind of release - process. We also can’t rely on distros shipping a version with the - fixes we need. Both firefox and Chrome bundle their own copies too. - It is still possible to build against an external copy of usrsctp if - so desired. - -- nvcodec no longer needs the NVIDIA NVDEC/NVENC SDKs available at - build time, only at runtime. This allows distributions to ship this - plugin by default and it will just start to work when the required - run-time SDK libraries are installed by the user, without users - needing to build and install the plugin from source. - -- the gst-editing-services tarball is now named gst-editing-services - for consistency (used to be gstreamer-editing-services). - -- the gst-validate tarball has been superseded by the gst-devtools - tarball for consistency with the git module name. +- this section will be filled in in due course gst-build -gst-build is a meta-module and serves primarily as our uninstalled -development environment. It makes it easy to build most of GStreamer, -but unlike Cerbero it only comes with a limited number of external -dependencies that can be built as subprojects if they are not found on -the system. - -gst-build is based on Meson and replaces the old autotools -gst-uninstalled script. - -- The ‘uninstalled’ target has been renamed to ‘devenv’ - -- Experimental gstreamer-full library containing all built plugins and - their deps when building with -Ddefault_library=static. A monolithic - library is easier to distribute, and may be required in some - environments. GStreamer core, GLib and GObject are always included, - but external dependencies are still dynamically linked. The - gst-full-libraries meson option allows adding other GStreamer - libraries to the gstreamer-full build. This is an experiment for now - and its behaviour or API may still change in future releases. - -- Add glib-networking as a subproject when glib is a subproject and - load gio modules in the devenv, tls option control whether to use - openssl or gnutls. - -- git-worktree: Allow multiple worktrees for subproject branches - -- Guard against meson being run from inside the uninstalled devenv, as - this might have unexpected consequences. - -- our ffmpeg and x264 meson ports have been updated to the latest - stable version (you might need to update the subprojects checkout - manually though, or just remove the checkouts so meson checks out - the latest version again; improvements for this are pending in - meson, but not merged yet). +- this section will be filled in in due course Cerbero @@ -1800,405 +200,97 @@ Windows, Android, iOS and macOS. General improvements -- Recipe build steps are done in parallel wherever possible. This - leads to massive improvements in overall build time. -- Several recipes were ported to Meson, which improved build times -- Moved from using both GnuTLS and OpenSSL to only OpenSSL -- Moved from yasm to nasm for all assembly compilation -- Support zsh when running the cerbero shell command -- Numerous version upgrades for dependencies -- Default to xz for tarball binary packages. bz2 can be selected with - the --compress-method option to package. -- Added boolean variant for controlling the optimization level: - -v optimization -- Ship .pc pkgconfig files for all plugins in the binary packages -- CMake and nasm will only be built by Cerbero if the system versions - are unusable -- The nvcodec variant was removed and the nvcodec plugin is built by - default now (as it no longer requires the SDK to be installed at - build time, only at runtime) +- this section will be filled in in due course macOS / iOS -- Minimum iOS SDK version bumped to 11.0 -- Minimum macOS SDK version bumped to 10.11 -- No longer need to manually add support for newer iOS SDK versions -- Added Vulkan elements via MoltenVK -- Build times were improved by code-signing all build tools -- macOS framework ships all gstreamer libraries instead of an outdated - subset -- Ship pkg-config in the macOS framework package -- fontconfig: Fix EXC_BAD_ACCESS crash on iOS ARM64 -- Improved App Store compatibility by setting LC_VERSION_MIN_MACOSX, - fixing relocations, and improved bitcode support +- this section will be filled in in due course Windows -- MinGW-GCC toolchain was updated to 8.2. It uses the Universal CRT - instead of MSVCRT which eliminates cross-CRT issues in the Visual - Studio build. -- Require Windows 7 or newer for running binaries produced by Cerbero -- Require Windows x86_64 for running Cerbero to build binary packages -- Cerbero no longer uses C:/gstreamer/1.0 as a prefix when building. - That prefix is reserved for use by the MSI installers. -- Several recipes can now be buit with Visual Studio instead of MinGW. - Ported to meson: opus, libsrtp, harfbuzz, cairo, openh264, libsoup, - libusrsctp. Existing build system: libvpx, openssl. -- Support building using Visual Studio for 32-bit x86. Previously we - only supported building for 32-bit x86 using the MinGW toolchain. -- Fixed annoying msgmerge popups in the middle of cerbero builds -- Added configuration options vs_install_path and vs_install_version - for specifying custom search locations for older Visual Studio - versions that do not support vswhere. You can set these in - ~/.cerbero/cerbero.cbc where ~ is the MSYS homedir, not your Windows - homedir. -- New Windows-specific plugins: d3d11, mediafoundation, wasapi2 -- Numerous compatibility and reliability fixes when running Cerbero on - Windows, especially non-English locales -- proxy-libintl now exports the same symbols as gettext, which makes - it a drop-in replacement -- New mapping variant for selecting the Visual Studio CRT to use: - -v vscrt=. Valid values are md, mdd, and auto (default). A - separate prefix is used when building with either md (release) or - mdd (debug), and the outputted package will have +debug in the - filename. This variant is also used for selecting the correct Qt - libraries (debug vs release) to use when building with -v qt5 on - Windows. -- Support cross-compile on Windows to Windows ARM64 and ARMv7 -- Support cross-compile on Windows to the Universal Windows Platform - (UWP). Only the subset of plugins that can be built entirely with - Visual Studio will be selected in this case. To do so, use the - config/cross-uwp-universal.cbc configuration, which will build - ARM64, x86, and x86_64 binaries linked to the release CRT, with - optimizations enabled, and debugging turned on. You can combine this - with -v vscrt=mdd to produce binaries linked to the debug CRT. You - can turn off optimizations with the -v nooptimization variant. +- this section will be filled in in due course Windows MSI installer -- Require Windows 7 or newer for running GStreamer -- Fixed some issues with shipping of pkg-config in the Windows - installers -- Plugin PDB debug files are now shipped in the development package, - not the runtime package -- Ship installers for 32-bit binaries built with Visual Studio -- Ship debug and release “universal” (ARM64, X86, and X86_64) tarballs - built for the Universal Windows Platform -- Windows MSI installers now install into separate prefixes when - building with MSVC and MinGW. Previously both would be installed - into C:/gstreamer/1.0/x86 or C:/gstreamer/1.0/x86_64. Now, the - installation prefixes are: - - ---------------------------------------------------------------------------------------------------------------- - Target Path Build options - --------------------------- ------------------------------------ ----------------------------------------------- - MinGW 32-bit C:/gstreamer/1.0/mingw_x86 -c config/win32.cbc - - MinGW 64-bit C:/gstreamer/1.0/mingw_x86_64 -c config/win64.cbc - - MSVC 32-bit C:/gstreamer/1.0/msvc_x86 -c config/win32.cbc -v visualstudio - - MSVC 64-bit C:/gstreamer/1.0/msvc_x86_64 -c config/win64.cbc -v visualstudio - - MSVC 32-bit (debug) C:/gstreamer/1.0/msvc-debug_x86 -c config/win32.cbc -v visualstudio,vscrt=mdd - - MSVC 64-bit (debug) C:/gstreamer/1.0/msvc-debug_x86_64 -c config/win64.cbc -v visualstudio,vscrt=mdd - ---------------------------------------------------------------------------------------------------------------- - -Note: UWP binary packages are tarballs, not MSI installers. +- this section will be filled in in due course Linux -- Support creating MSI installers using WiX when cross-compiling to - Windows -- Support running cross-windows binaries with Wine when using the - shell and runit cerbero commands -- Added bash-completion support inside the cerbero shell on Linux -- Require a system-wide installation of openssl on Linux -- Added variant -v vaapi to build gstreamer-vaapi and the new gstva - plugin -- Debian packaging was disabled because it does not work. Help in - fixing this is appreciated. -- Trimmed the list of packages needed for bootstrap on Linux +- this section will be filled in in due course Android -- Updated to NDK r21 -- Support Vulkan -- Support Qt 5.14+ binary package layout +- this section will be filled in in due course Platform-specific changes and improvements Android -- opensles: Remove hard-coded buffer-/latency-time values and allow - openslessink to handle 48kHz streams. - -- photography interface and camera source: Add additional settings - relevant to Android such as: Exposure mode property, extra colour - tone values (aqua, emboss, sketch, neon), extra scene modes - (backlight, flowers, AR, HDR), and missing virtual methods for - exposure mode, analog gain, lens focus, colour temperature, min & - max exposure time. Add new effects and scene modes to Camera - parameters. +- this section will be filled in in due course macOS and iOS -- vtdec can now output to Vulkan-backed memory for zerocopy support - with the Vulkan elements. +- this section will be filled in in due course Windows -- d3d11videosink: new Direct3D11-based video sink with support for - HDR10 rendering if supported. - -- Hardware-accelerated video decoding on Windows via DXVA2 / - Direct3D11 using native Windows APIs rather than per-vendor SDKs - (like MSDK for Intel or NVCODEC for NVidia). Plus modern Direct3D11 - integration rather than the almost 20-year old Direct3D9 from - Windows XP times used in d3dvideosink. Formats supported for - decoding are H.264, H.265, VP8, and VP9, and zero-copy operation - should be supported in combination with the new d3d11videosink. See - Seungha’s blog post “Windows DXVA2 (via Direct3D 11) Support in - GStreamer 1.17” for more details. - -- Microsoft Media Foundation plugin for hardware-accelerated video - encoding on Windows using native Windows APIs rather than per-vendor - SDKs. Formats supported for encoding are H.264, H.265 and VP9. Also - includes audio encoders for AAC and MP3. See Seungha’s blog post - “Bringing Microsoft Media Foundation to GStreamer” for some more - details about this. - -- new mfvideosrc video capture source element using the latest Windows - APIs rather than ancient APIs used by ksvideosrc/winks. ksvideosrc - should be considered deprecated going forward. - -- d3d11: add d3d11convert, a color space conversion and rescaling - element using shaders, and introduce d3d11upload and d3d11download - elements that work just like glupload and gldownload but for D3D11. - -- Universal Windows Platform (UWP) support, including official - GStreamer binary packages for it. Check out Nirbheek’s latest blog - post “GStreamer 1.18 supports the Universal Windows Platform” for - more details. - -- systemclock correctness and reliability fixes, and also don’t start - the system clock at 0 any longer (which shouldn’t make any - difference to anyone, as absolute clock time values are supposed to - be meaningless in themselves, only the rate of increase matters). - -- toolchain specific plugin registry: the registry cache is now named - differently for MSVC and MinGW toolchains/packages, which should - avoid problems when switching between binaries built with a - different toolchain. - -- new wasapi2 plugin mainly to support UWP applications. The core - logic of this plugin is almost identical to existing wasapi plugin, - but the main target is Windows 10 and UWP. This plugin uses WinRT - APIs, so will likely not work on Windows 8 or older. Unlike the - existing wasapi plugin, this plugin supports automatic stream - routing (auto fallback when device was removed) and device level - mute/volume control. Exclusive streaming mode is not supported, - however, and loopback features are not implemented yet. It is also - only possible to build this plugin with MSVC and the Windows 10 SDK, - it can’t be cross-compiled with the MingW toolchain. - -- new dxgiscreencapsrc element which uses the Desktop Duplication API - to capture the desktop screen at high speed. This is only supported - on Windows 8 or later. Compared to the existing elements - dxgiscreencapsrc offers much better performance, works in High DPI - environments and draws an accurate mouse cursor. - -- d3dvideosink was downgraded to secondary rank, d3d11videosink is - preferred now. Support OverlayComposition for GPU overlay - compositing of subtitles and logos. - -- debug log output fixes, esp. with a non-UTF8 locale/codepage - -- speex, jack: fixed crashes on Windows caused by cross-CRT issues - -- gst-play-1.0 interactive keyboard controls now also work on Windows +- this section will be filled in in due course Linux -- kmssink: Add support for P010 and P016 formats - -- vah264dec: new experimental va plugin with an element for H.264 - decoding with VA-API. This novel approach, different from - gstreamer-vaapi, uses the gstcodecs library for decoder state - handling, which it is hoped will make for cleaner code because it - uses VA-API without further layers or wrappers. Check out Víctor’s - blog post “New VA-API H.264 decoder in gst-plugins-bad” for the full - lowdown and the limitations of this new plugin, and how to give it a - spin. - -- v4l2codecs: introduce a V4L2 CODECs Accelerator. This plugin will - support the new CODECs uAPI in the Linux kernel, which consists of - an accelerator interface similar to DXVA, NVDEC, VDPAU and VAAPI. So - far H.264 and VP8 are supported. This is used on certain embedded - systems such as i.mx8m, rk3288, rk3399, Allwinner H-series SoCs. +- this section will be filled in in due course Documentation improvements -- unified documentation containing tutorials, API docs, plugin docs, - etc. all under one roof, shipped in form of a documentation release - tarball containing both devhelp and html documentation. - -- all documentation is now generated using hotdoc, gtk-doc is no - longer used. Distributors should use the above-mentioned - documentation release tarball instead of trying to package hotdoc - and building the documentation from scratch. - -- there is now documentation for wrapper plugins like gst-libav and - frei0r, as well as tracer plugins. - -- for more info, check out Thibault’s “GStreamer Documentation” - lightning talk from the 2019 GStreamer Conference. - -- new API for plugins to support the documentation system: - - - new GParamSpecFlag GST_PARAM_DOC_SHOW_DEFAULT to make - gst-inspect-1.0 (and the documentation) show the paramspec’s - default value rather than the actually set value as default - - GstPadTemplate getter and setter for “documentation caps”, - gst_pad_template_set_documentation_caps() and - gst_pad_template_get_documentation_caps(): This can be used in - elements where the caps of pad templates are dynamically - generated and/or dependent on the environment, to override the - caps shown in the documentation (usually to advertise the full - set of possible caps). - - gst_type_mark_as_plugin_api() for marking types as plugin API, - used for plugin-internal types like enums, flags, pad - subclasses, boxed types, and such. +- this section will be filled in in due course Possibly Breaking Changes -- GstVideo: the canonical list of raw video formats (for use in caps) - has been reordered, so video elements such as videotestsrc or - videoconvert might negotiate to a different format now than before. - The new format might be a higher-quality format or require more - processing overhead, which might affect pipeline performance. - -- mpegtsdemux used to wrongly advertise H.264 and H.265 video - elementary streams as alignment=nal. This has now been fixed and - changed to alignment=none, which means an h264parse or h265parse - element is now required after tsdemux for some pipelines where there - wasn’t one before, e.g. in transmuxing scenarios (tsdemux ! tsmux). - Pipelines without such a parser may now fail to link or error out at - runtime. As parsers after demuxers and before muxers have been - generally required for a long time now it is hoped that this will - only affect a small number of applications or pipelines. - -- The Android opensles audio source and sink used to have hard-coded - buffer-/latency-time values of 20ms. This is no longer needed with - newer Android versions and has now been removed. This means a higher - or lower value might now be negotiated by default, which can affect - pipeline performance and latency. +- this section will be filled in in due course Known Issues -- None in particular +- this section will be filled in in due course + +- There are a couple of known WebRTC-related regressions/blockers: + + - webrtc: DTLS setup with Chrome is broken + - webrtcbin: First keyframe is usually lost Contributors -Aaron Boxer, Adam Duskett, Adam x Nilsson, Adrian Negreanu, Akinobu -Mita, Alban Browaeys, Alcaro, Alexander Lapajne, Alexandru Băluț, Alex -Ashley, Alex Hoenig, Alicia Boya García, Alistair Buxton, Ali Yousuf, -Ambareesh “Amby” Balaji, Amr Mahdi, Andoni Morales Alastruey, Andreas -Frisch, Andre Guedes, Andrew Branson, Andrey Sazonov, Antonio Ospite, -aogun, Arun Raghavan, Askar Safin, AsociTon, A. Wilcox, Axel Mårtensson, -Ayush Mittal, Bastian Bouchardon, Benjamin Otte, Bilal Elmoussaoui, -Brady J. Garvin, Branko Subasic, Camilo Celis Guzman, Carlos Rafael -Giani, Charlie Turner, Cheng-Chang Wu, Chris Ayoup, Chris Lord, -Christoph Reiter, cketti, Damian Hobson-Garcia, Daniel Klamt, Daniel -Molkentin, Danny Smith, David Bender, David Gunzinger, David Ing, David -Svensson Fors, David Trussel, Debarshi Ray, Derek Lesho, Devarsh -Thakkar, dhilshad, Dimitrios Katsaros, Dmitriy Purgin, Dmitry Shusharin, -Dominique Leuenberger, Dong Il Park, Doug Nazar, dudengke, Dylan McCall, -Dylan Yip, Ederson de Souza, Edward Hervey, Eero Nurkkala, Eike Hein, -ekwange, Eric Marks, Fabian Greffrath, Fabian Orccon, Fabio D’Urso, -Fabrice Bellet, Fabrice Fontaine, Fanchao L, Felix Yan, Fernando -Herrrera, Francisco Javier Velázquez-García, Freyr, Fuwei Tang, Gaurav -Kalra, George Kiagiadakis, Georgii Staroselskii, Georg Lippitsch, Georg -Ottinger, gla, Göran Jönsson, Gordon Hart, Gregor Boirie, Guillaume -Desmottes, Guillermo Rodríguez, Haakon Sporsheim, Haihao Xiang, Haihua -Hu, Havard Graff, Håvard Graff, Heinrich Kruger, He Junyan, Henry -Wilkes, Hosang Lee, Hou Qi, Hu Qian, Hyunjun Ko, ibauer, Ignacio Casal -Quinteiro, Ilya Smelykh, Jake Barnes, Jakub Adam, James Cowgill, James -Westman, Jan Alexander Steffens, Jan Schmidt, Jan Tojnar, Javier Celaya, -Jeffy Chen, Jennifer Berringer, Jens Göpfert, Jérôme Laheurte, Jim -Mason, Jimmy Ohn, J. Kim, Joakim Johansson, Jochen Henneberg, Johan -Bjäreholt, Johan Sternerup, John Bassett, Jonas Holmberg, Jonas Larsson, -Jonathan Matthew, Jordan Petridis, Jose Antonio Santos Cadenas, Josep -Torra, Jose Quaresma, Josh Matthews, Joshua M. Doe, Juan Navarro, -Juergen Werner, Julian Bouzas, Julien Isorce, Jun-ichi OKADA, Justin -Chadwell, Justin Kim, Keri Henare, Kevin JOLY, Kevin King, Kevin Song, -Knut Andre Tidemann, Kristofer Björkström, krivoguzovVlad, Kyrylo -Polezhaiev, Lenny Jorissen, Linus Svensson, Loïc Le Page, Loïc Minier, -Lucas Stach, Ludvig Rappe, Luka Blaskovic, luke.lin, Luke Yelavich, -Marcin Kolny, Marc Leeman, Marco Felsch, Marcos Kintschner, Marek -Olejnik, Mark Nauwelaerts, Markus Ebner, Martin Liska, Martin Theriault, -Mart Raudsepp, Matej Knopp, Mathieu Duponchelle, Mats Lindestam, Matthew -Read, Matthew Waters, Matus Gajdos, Maxim Paymushkin, Maxim P. -Dementiev, Michael Bunk, Michael Gruner, Michael Olbrich, Miguel París -Díaz, Mikhail Fludkov, Milian Wolff, Millan Castro, Muhammet Ilendemli, -Nacho García, Nayana Topolsky, Nian Yan, Nicola Murino, Nicolas -Dufresne, Nicolas Pernas Maradei, Niels De Graef, Nikita Bobkov, Niklas -Hambüchen, Nirbheek Chauhan, Ognyan Tonchev, okuoku, Oleksandr -Kvl,Olivier Crête, Ondřej Hruška, Pablo Marcos Oltra, Patricia Muscalu, -Peter Seiderer, Peter Workman, Philippe Normand, Philippe Renon, Philipp -Zabel, Pieter Willem Jordaan, Piotr Drąg, Ralf Sippl, Randy Li, Rasmus -Thomsen, Ratchanan Srirattanamet, Raul Tambre, Ray Tiley, Richard -Kreckel, Rico Tzschichholz, R Kh, Robert Rosengren, Robert Tiemann, -Roman Shpuntov, Roman Sivriver, Ruben Gonzalez, Rubén Gonzalez, -rubenrua, Ryan Huang, Sam Gigliotti, Santiago Carot-Nemesio, Saunier -Thibault, Scott Kanowitz, Sebastian Dröge, Sebastiano Barrera, Seppo -Yli-Olli, Sergey Nazaryev, Seungha Yang, Shinya Saito, Silvio -Lazzeretti, Simon Arnling Bååth, Siwon Kang, sohwan.park, Song Bing, -Soohyun Lee, Srimanta Panda, Stefano Buora, Stefan Sauer, Stéphane -Cerveau, Stian Selnes, Sumaid Syed, Swayamjeet, Thiago Santos, Thibault -Saunier, Thomas Bluemel, Thomas Coldrick, Thor Andreassen, Tim-Philipp -Müller, Ting-Wei Lan, Tobias Ronge, trilene, Tulio Beloqui, U. Artie -Eoff, VaL Doroshchuk, Varunkumar Allagadapa, Vedang Patel, Veerabadhran -G, Víctor Manuel Jáquez Leal, Vivek R, Vivia Nikolaidou, Wangfei, Wang -Zhanjun, Wim Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier -Claessens, Xidorn Quan, Xu Guangxin, Yan Wang, Yatin Maan, Yeongjin -Jeong, yychao, Zebediah Figura, Zeeshan Ali, Zeid Bekli, Zhiyuan Sraf, -Zoltán Imets, +- this section will be filled in in due course … and many others who have contributed bug reports, translations, sent suggestions or helped testing. -Stable 1.18 branch +Stable 1.20 branch -After the 1.18.0 release there will be several 1.18.x bug-fix releases +After the 1.20.0 release there will be several 1.20.x bug-fix releases which will contain bug fixes which have been deemed suitable for a stable branch, but no new features or intrusive changes will be added to -a bug-fix release usually. The 1.18.x bug-fix releases will be made from -the git 1.18 branch, which will be a stable branch. +a bug-fix release usually. The 1.20.x bug-fix releases will be made from +the git 1.20 branch, which will be a stable branch. -1.18.0 +1.20.0 -1.18.0 was released on 7 September 2020. +1.20.0 is scheduled to be released around July 2021. -Schedule for 1.20 +Schedule for 1.22 -Our next major feature release will be 1.20, and 1.19 will be the -unstable development version leading up to the stable 1.20 release. The -development of 1.19/1.20 will happen in the git master branch. +Our next major feature release will be 1.22, and 1.21 will be the +unstable development version leading up to the stable 1.22 release. The +development of 1.21/1.22 will happen in the git master branch. -The plan for the 1.20 development cycle is yet to be confirmed, but it -is now expected that feature freeze will take place some time in January -2021, with the first 1.20 stable release around February/March 2021. +The plan for the 1.22 development cycle is yet to be confirmed, but it +is hoped that feature freeze will take place some time in December 2021. -1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, -1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. +1.22 will be backwards-compatible to the stable 1.20, 1.18, 1.16, 1.14, +1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. ------------------------------------------------------------------------ These release notes have been prepared by Tim-Philipp Müller with -contributions from Mathieu Duponchelle, Matthew Waters, Nirbheek -Chauhan, Sebastian Dröge, Thibault Saunier, and Víctor Manuel Jáquez -Leal. +contributions from … License: CC BY-SA 4.0 diff --git a/RELEASE b/RELEASE index b68f1e77b9..01e68dd1db 100644 --- a/RELEASE +++ b/RELEASE @@ -1,18 +1,15 @@ -This is GStreamer gst-rtsp-server 1.18.0. +This is GStreamer gst-rtsp-server 1.19.1. -The GStreamer team is thrilled to announce a new major feature release -of your favourite cross-platform multimedia framework! +GStreamer 1.19 is the development branch leading up to the next major +stable version which will be 1.20. -As always, this release is again packed with new features, bug fixes and -other improvements. - -The 1.18 release series adds new features on top of the 1.16 series and is +The 1.19 development series adds new features on top of the 1.18 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. -Full release notes can be found at: +Full release notes will one day be found at: - https://gstreamer.freedesktop.org/releases/1.18/ + https://gstreamer.freedesktop.org/releases/1.20/ Binaries for Android, iOS, Mac OS X and Windows will usually be provided shortly after the release. diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index 3df5ca65ea..de62463bb3 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -321,7 +321,7 @@ "construct": false, "construct-only": false, "controllable": false, - "default": "GStreamer/1.19.0.1", + "default": "GStreamer/1.19.1", "mutable": "null", "readable": true, "type": "gchararray", diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index cd72528bf2..381e9fcb07 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.19.1 + master + + 2021-06-01 + + + + 1.18.0 diff --git a/meson.build b/meson.build index 669286479c..f3c0f7a6ce 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.19.0.1', + version : '1.19.1', meson_version : '>= 0.54', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From b3327b9f69fbc7c1925797717ec30e22855687e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 1 Jun 2021 15:29:07 +0100 Subject: [PATCH 1773/1776] Back to development --- docs/gst_plugins_cache.json | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index de62463bb3..68b43a315d 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -321,7 +321,7 @@ "construct": false, "construct-only": false, "controllable": false, - "default": "GStreamer/1.19.1", + "default": "GStreamer/1.19.1.1", "mutable": "null", "readable": true, "type": "gchararray", diff --git a/meson.build b/meson.build index f3c0f7a6ce..ea36a8165a 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.19.1', + version : '1.19.1.1', meson_version : '>= 0.54', default_options : ['warning_level=1', 'buildtype=debugoptimized']) From cc5cdab0165e3bdf5f4f748b3ba2a3493d304e70 Mon Sep 17 00:00:00 2001 From: Corentin Damman Date: Mon, 21 Jun 2021 08:34:35 +0000 Subject: [PATCH 1774/1776] Update COPYING.LIB, COPYING files Part-of: --- COPYING | 200 +++++++++++++++++++++++++++++----------------------- COPYING.LIB | 200 +++++++++++++++++++++++++++++----------------------- 2 files changed, 222 insertions(+), 178 deletions(-) diff --git a/COPYING b/COPYING index c87cfe8c99..efce2a87c3 100644 --- a/COPYING +++ b/COPYING @@ -1,13 +1,14 @@ - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 - Copyright (C) 1991 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + 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 library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] +[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 @@ -16,97 +17,109 @@ 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 Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. + 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, 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 or use pieces of it -in new free programs; and that you know you can do these things. + 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 -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if -you distribute copies of the library, or if you modify it. +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 a program 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 +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. - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal + 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. - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. + 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, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary 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. - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. + 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. - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. + 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. - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. + 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, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. - GNU LIBRARY GENERAL PUBLIC LICENSE + GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -General Public License (also called "this License"). Each licensee is -addressed as "you". + 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 @@ -255,7 +268,7 @@ distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. - 6. As an exception to the Sections above, you may also compile or + 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 @@ -282,23 +295,31 @@ of these things: Library will not necessarily be able to recompile the application to use the modified definitions.) - b) Accompany the work with a written offer, valid for at + 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. - c) If distribution of the work is made by offering access to copy + 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. - d) Verify that the user has already received a copy of these + 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 source code distributed need not include anything that is normally -distributed (in either source or binary form) with the major +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. @@ -347,7 +368,7 @@ 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 to +You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent @@ -390,7 +411,7 @@ 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 Library General Public License from time to time. +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. @@ -436,7 +457,7 @@ DAMAGES. END OF TERMS AND CONDITIONS - Appendix: How to Apply These Terms to Your New Libraries + 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 @@ -453,18 +474,18 @@ convey the exclusion of warranty; and each file should have at least the Copyright (C) This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public + modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. + version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + 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. @@ -479,3 +500,4 @@ necessary. Here is a sample; alter the names: Ty Coon, President of Vice That's all there is to it! + diff --git a/COPYING.LIB b/COPYING.LIB index c87cfe8c99..efce2a87c3 100644 --- a/COPYING.LIB +++ b/COPYING.LIB @@ -1,13 +1,14 @@ - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 - Copyright (C) 1991 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + 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 library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] +[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 @@ -16,97 +17,109 @@ 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 Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. + 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, 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 or use pieces of it -in new free programs; and that you know you can do these things. + 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 -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if -you distribute copies of the library, or if you modify it. +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 a program 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 +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. - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal + 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. - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. + 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, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary 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. - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. + 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. - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. + 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. - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. + 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, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. - GNU LIBRARY GENERAL PUBLIC LICENSE + GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -General Public License (also called "this License"). Each licensee is -addressed as "you". + 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 @@ -255,7 +268,7 @@ distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. - 6. As an exception to the Sections above, you may also compile or + 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 @@ -282,23 +295,31 @@ of these things: Library will not necessarily be able to recompile the application to use the modified definitions.) - b) Accompany the work with a written offer, valid for at + 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. - c) If distribution of the work is made by offering access to copy + 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. - d) Verify that the user has already received a copy of these + 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 source code distributed need not include anything that is normally -distributed (in either source or binary form) with the major +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. @@ -347,7 +368,7 @@ 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 to +You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent @@ -390,7 +411,7 @@ 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 Library General Public License from time to time. +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. @@ -436,7 +457,7 @@ DAMAGES. END OF TERMS AND CONDITIONS - Appendix: How to Apply These Terms to Your New Libraries + 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 @@ -453,18 +474,18 @@ convey the exclusion of warranty; and each file should have at least the Copyright (C) This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public + modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. + version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + 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. @@ -479,3 +500,4 @@ necessary. Here is a sample; alter the names: Ty Coon, President of Vice That's all there is to it! + From 43572a8943497d70f40d083de853f8356c38c6e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20J=C3=B6nsson?= Date: Mon, 5 Jul 2021 11:54:18 +0200 Subject: [PATCH 1775/1776] Protection against early RTCP packets. When receiving RTCP packets early the funnel is not ready yet and GST_FLOW_FLUSHING will be returned when pushing data to it's srcpad. This causes the thread that handle RTCP packets to go to pause mode. Since this thread is in pause mode there will be no further callbacks to handle keep-alive for incoming RTCP packets. This will make the session time out if the client is not using another keep-alive mechanism. Change-Id: Idb29db05f59c06423fa693a2aeeacbe3a1883fc5 Part-of: --- gst/rtsp-server/rtsp-media.c | 16 +++++++ gst/rtsp-server/rtsp-stream.c | 74 +++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 3 ++ gst/rtsp-sink/gstrtspclientsink.c | 5 +++ 4 files changed, 98 insertions(+) diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 63f43bc00b..f2d498ac2f 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -4683,6 +4683,21 @@ preroll_failed: } } +static void +gst_rtsp_media_unblock_rtcp (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + guint i; + + priv = media->priv; + g_mutex_lock (&priv->lock); + for (i = 0; i < priv->streams->len; i++) { + GstRTSPStream *stream = g_ptr_array_index (priv->streams, i); + gst_rtsp_stream_unblock_rtcp (stream); + } + g_mutex_unlock (&priv->lock); +} + /** * gst_rtsp_media_unsuspend: * @media: a #GstRTSPMedia @@ -4711,6 +4726,7 @@ gst_rtsp_media_unsuspend (GstRTSPMedia * media) } done: + gst_rtsp_media_unblock_rtcp (media); g_rec_mutex_unlock (&priv->state_lock); return TRUE; diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 1495b733c0..92ef358797 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -224,6 +224,12 @@ struct _GstRTSPStreamPrivate /* Whether we should send and receive RTCP */ gboolean enable_rtcp; + + /* blocking early rtcp packets */ + GstPad *block_early_rtcp_pad; + gulong block_early_rtcp_probe; + GstPad *block_early_rtcp_pad_ipv6; + gulong block_early_rtcp_probe_ipv6; }; #define DEFAULT_CONTROL NULL @@ -347,6 +353,10 @@ gst_rtsp_stream_init (GstRTSPStream * stream) priv->ptmap = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) gst_caps_unref); priv->send_pool = NULL; + priv->block_early_rtcp_pad = NULL; + priv->block_early_rtcp_probe = 0; + priv->block_early_rtcp_pad_ipv6 = NULL; + priv->block_early_rtcp_probe_ipv6 = 0; } typedef struct _UdpClientAddrInfo UdpClientAddrInfo; @@ -431,6 +441,18 @@ gst_rtsp_stream_finalize (GObject * obj) g_mutex_clear (&priv->send_lock); g_cond_clear (&priv->send_cond); + if (priv->block_early_rtcp_probe != 0) { + gst_pad_remove_probe + (priv->block_early_rtcp_pad, priv->block_early_rtcp_probe); + gst_object_unref (priv->block_early_rtcp_pad); + } + + if (priv->block_early_rtcp_probe_ipv6 != 0) { + gst_pad_remove_probe + (priv->block_early_rtcp_pad_ipv6, priv->block_early_rtcp_probe_ipv6); + gst_object_unref (priv->block_early_rtcp_pad_ipv6); + } + G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj); } @@ -3755,6 +3777,15 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * g_object_set (priv->udpsrc_v4[i], "caps", rtp_caps, NULL); } else { g_object_set (priv->udpsrc_v4[i], "caps", rtcp_caps, NULL); + + /* block early rtcp packets, pipeline not ready */ + g_assert (priv->block_early_rtcp_pad == NULL); + priv->block_early_rtcp_pad = gst_element_get_static_pad + (priv->udpsrc_v4[i], "src"); + priv->block_early_rtcp_probe = gst_pad_add_probe + (priv->block_early_rtcp_pad, + GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER, NULL, NULL, + NULL); } plug_src (stream, bin, priv->udpsrc_v4[i], priv->funnel[i]); @@ -3770,6 +3801,15 @@ create_receiver_part (GstRTSPStream * stream, const GstRTSPTransport * g_object_set (priv->udpsrc_v6[i], "caps", rtp_caps, NULL); } else { g_object_set (priv->udpsrc_v6[i], "caps", rtcp_caps, NULL); + + /* block early rtcp packets, pipeline not ready */ + g_assert (priv->block_early_rtcp_pad_ipv6 == NULL); + priv->block_early_rtcp_pad_ipv6 = gst_element_get_static_pad + (priv->udpsrc_v6[i], "src"); + priv->block_early_rtcp_probe_ipv6 = gst_pad_add_probe + (priv->block_early_rtcp_pad_ipv6, + GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER, NULL, NULL, + NULL); } plug_src (stream, bin, priv->udpsrc_v6[i], priv->funnel[i]); @@ -6290,3 +6330,37 @@ gst_rtsp_stream_get_rate_control (GstRTSPStream * stream) return ret; } + +/** + * gst_rtsp_stream_unblock_rtcp: + * + * Remove blocking probe from the RTCP source. When creating an UDP source for + * RTCP it is initially blocked until this function is called. + * This functions should be called once the pipeline is ready for handling RTCP + * packets. + * + * Since: 1.20 + */ +void +gst_rtsp_stream_unblock_rtcp (GstRTSPStream * stream) +{ + GstRTSPStreamPrivate *priv; + + priv = stream->priv; + g_mutex_lock (&priv->lock); + if (priv->block_early_rtcp_probe != 0) { + gst_pad_remove_probe + (priv->block_early_rtcp_pad, priv->block_early_rtcp_probe); + priv->block_early_rtcp_probe = 0; + gst_object_unref (priv->block_early_rtcp_pad); + priv->block_early_rtcp_pad = NULL; + } + if (priv->block_early_rtcp_probe_ipv6 != 0) { + gst_pad_remove_probe + (priv->block_early_rtcp_pad_ipv6, priv->block_early_rtcp_probe_ipv6); + priv->block_early_rtcp_probe_ipv6 = 0; + gst_object_unref (priv->block_early_rtcp_pad_ipv6); + priv->block_early_rtcp_pad_ipv6 = NULL; + } + g_mutex_unlock (&priv->lock); +} diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index dcb5d7a9a4..5e6ff2151a 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -365,6 +365,9 @@ void gst_rtsp_stream_set_rate_control (GstRTSPStream * stream, gbo GST_RTSP_SERVER_API gboolean gst_rtsp_stream_get_rate_control (GstRTSPStream * stream); +GST_RTSP_SERVER_API +void gst_rtsp_stream_unblock_rtcp (GstRTSPStream * stream); + /** * GstRTSPStreamTransportFilterFunc: * @stream: a #GstRTSPStream object diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c index 96b6044b38..3573e2088b 100644 --- a/gst/rtsp-sink/gstrtspclientsink.c +++ b/gst/rtsp-sink/gstrtspclientsink.c @@ -4580,6 +4580,11 @@ gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async) gst_rtsp_client_sink_set_state (sink, GST_STATE_PLAYING); sink->state = GST_RTSP_STATE_PLAYING; + for (walk = sink->contexts; walk; walk = g_list_next (walk)) { + GstRTSPStreamContext *context = (GstRTSPStreamContext *) walk->data; + + gst_rtsp_stream_unblock_rtcp (context->stream); + } /* clean up any messages */ gst_rtsp_message_unset (&request); From 0b037e35e7ed3259ca05be748c382bc40e2cdd91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 23 Sep 2021 01:35:27 +0100 Subject: [PATCH 1776/1776] Release 1.19.2 --- ChangeLog | 41 +++++++++++++++++++++++++++++++++++++ NEWS | 25 ++++++++++++---------- RELEASE | 2 +- docs/gst_plugins_cache.json | 2 +- gst-rtsp-server.doap | 10 +++++++++ meson.build | 2 +- 6 files changed, 68 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index fb59edd157..aca54deba1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,43 @@ +=== release 1.19.2 === + +2021-09-23 01:35:27 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-rtsp-server.doap: + * meson.build: + Release 1.19.2 + +2021-07-05 11:54:18 +0200 Göran Jönsson + + * gst/rtsp-server/rtsp-media.c: + * gst/rtsp-server/rtsp-stream.c: + * gst/rtsp-server/rtsp-stream.h: + * gst/rtsp-sink/gstrtspclientsink.c: + Protection against early RTCP packets. + When receiving RTCP packets early the funnel is not ready yet and + GST_FLOW_FLUSHING will be returned when pushing data to it's srcpad. + This causes the thread that handle RTCP packets to go to pause mode. + Since this thread is in pause mode there will be no further callbacks to + handle keep-alive for incoming RTCP packets. This will make the session + time out if the client is not using another keep-alive mechanism. + Change-Id: Idb29db05f59c06423fa693a2aeeacbe3a1883fc5 + Part-of: + +2021-06-21 08:34:35 +0000 Corentin Damman + + * COPYING: + * COPYING.LIB: + Update COPYING.LIB, COPYING files + Part-of: + +2021-06-01 15:29:07 +0100 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * meson.build: + Back to development + === release 1.19.1 === 2021-06-01 00:15:08 +0100 Tim-Philipp Müller @@ -5,6 +45,7 @@ * ChangeLog: * NEWS: * RELEASE: + * docs/gst_plugins_cache.json: * gst-rtsp-server.doap: * meson.build: Release 1.19.1 diff --git a/NEWS b/NEWS index cc6c3b4a8e..0e581c39b8 100644 --- a/NEWS +++ b/NEWS @@ -1,15 +1,15 @@ GStreamer 1.20 Release Notes GStreamer 1.20 has not been released yet. It is scheduled for release -around July 2021. +around October/November 2021. 1.19.x is the unstable development version that is being developed in -the git master branch and which will eventually result in 1.20, and -1.19.1 is the current development release in that series +the git main branch and which will eventually result in 1.20, and 1.19.2 +is the current development release in that series -It is expected that feature freeze will be around June/July 2021, -followed by several 1.19 pre-releases and the new 1.20 stable release -around July 2021. +It is expected that feature freeze will be in early October 2021, +followed by one or two 1.19.9x pre-releases and the new 1.20 stable +release around October/November 2021. 1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, 1.10, 1.8, 1.6,, 1.4, 1.2 and 1.0 release series. @@ -17,7 +17,7 @@ around July 2021. See https://gstreamer.freedesktop.org/releases/1.20/ for the latest version of this document. -Last updated: Sunday 30 May 2021, 16:00 UTC (log) +Last updated: Wednesday 22 September 2021, 18:00 UTC (log) Introduction @@ -247,6 +247,10 @@ Documentation improvements Possibly Breaking Changes - this section will be filled in in due course +- MPEG-TS SCTE-35 API changes (FIXME: flesh out) +- gst_parse_launch() and friends now error out on non-existing + properties on top-level bins where they would silently fail and + ignore those before. Known Issues @@ -274,16 +278,15 @@ the git 1.20 branch, which will be a stable branch. 1.20.0 -1.20.0 is scheduled to be released around July 2021. +1.20.0 is scheduled to be released around October/November 2021. Schedule for 1.22 Our next major feature release will be 1.22, and 1.21 will be the unstable development version leading up to the stable 1.22 release. The -development of 1.21/1.22 will happen in the git master branch. +development of 1.21/1.22 will happen in the git main branch. -The plan for the 1.22 development cycle is yet to be confirmed, but it -is hoped that feature freeze will take place some time in December 2021. +The plan for the 1.22 development cycle is yet to be confirmed. 1.22 will be backwards-compatible to the stable 1.20, 1.18, 1.16, 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. diff --git a/RELEASE b/RELEASE index 01e68dd1db..97a4fa313e 100644 --- a/RELEASE +++ b/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-rtsp-server 1.19.1. +This is GStreamer gst-rtsp-server 1.19.2. GStreamer 1.19 is the development branch leading up to the next major stable version which will be 1.20. diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index 68b43a315d..bbeb067a9b 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -321,7 +321,7 @@ "construct": false, "construct-only": false, "controllable": false, - "default": "GStreamer/1.19.1.1", + "default": "GStreamer/1.19.2", "mutable": "null", "readable": true, "type": "gchararray", diff --git a/gst-rtsp-server.doap b/gst-rtsp-server.doap index 381e9fcb07..6d323ac90d 100644 --- a/gst-rtsp-server.doap +++ b/gst-rtsp-server.doap @@ -30,6 +30,16 @@ RTSP server library based on GStreamer + + + 1.19.2 + master + + 2021-09-23 + + + + 1.19.1 diff --git a/meson.build b/meson.build index ea36a8165a..0e55878b33 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-rtsp-server', 'c', - version : '1.19.1.1', + version : '1.19.2', meson_version : '>= 0.54', default_options : ['warning_level=1', 'buildtype=debugoptimized'])